more blueprint editor fixes

This commit is contained in:
Diamantis Tziotzios 2023-10-25 17:47:48 +03:00
parent 45f8f51288
commit d1bac40f0f
24 changed files with 1425 additions and 1642 deletions

View File

@ -55,6 +55,7 @@ import { SupportiveMaterialService } from './services/supportive-material/suppor
import { UserSettingsHttpService } from './services/user-settings/user-settings-http.service';
import { UserSettingsService } from './services/user-settings/user-settings.service';
import { QueryParamsService } from './services/utilities/query-params.service';
import { FileUtils } from './services/utilities/file-utils.service';
//
//
// This is shared module that provides all the services. Its imported only once on the AppModule.
@ -128,7 +129,8 @@ export class CoreServiceModule {
QueryParamsService,
UserSettingsService,
UserSettingsHttpService,
FilterService
FilterService,
FileUtils
],
};
}

View File

@ -25,11 +25,9 @@ import { Observable, throwError } from 'rxjs';
@Injectable()
export class DmpBlueprintService {
private actionUrl: string;
private headers = new HttpHeaders();
constructor(private http: BaseHttpV2Service, private httpClient: HttpClient, private configurationService: ConfigurationService, private filterService: FilterService) {
this.actionUrl = configurationService.server + 'dmpprofile/';
}
private get apiBase(): string { return `${this.configurationService.server}dmp-blueprint`; }

View File

@ -14,6 +14,7 @@ import { Role } from '@app/core/common/enum/role';
import { RoleOrganizationType } from '@app/core/common/enum/role-organization-type';
import { ViewStyleType } from '@app/ui/admin/dataset-profile/editor/components/field/view-style-enum';
import { DescriptionTemplateTypeStatus } from '@app/core/common/enum/description-template-type-status';
import { DmpBlueprintSystemFieldType } from '@app/core/common/enum/dmp-blueprint-system-field-type';
@Injectable()
export class EnumUtils {
@ -193,4 +194,29 @@ export class EnumUtils {
case DescriptionTemplateTypeStatus.Finalized: return this.language.instant('TYPES.DESCRIPTION-TEMPLATE-TYPE-STATUS.FINALIZED');
}
}
toDmpBlueprintSystemFieldTypeString(status: DmpBlueprintSystemFieldType): string {
switch (status) {
case DmpBlueprintSystemFieldType.TEXT: return this.language.instant('TYPES.DMP-BLUEPRINT-SYSTEM-FIELD-TYPE.TEXT');
case DmpBlueprintSystemFieldType.HTML_TEXT: return this.language.instant('TYPES.DMP-BLUEPRINT-SYSTEM-FIELD-TYPE.HTML_TEXT');
case DmpBlueprintSystemFieldType.RESEARCHERS: return this.language.instant('TYPES.DMP-BLUEPRINT-SYSTEM-FIELD-TYPE.RESEARCHERS');
case DmpBlueprintSystemFieldType.ORGANIZATIONS: return this.language.instant('TYPES.DMP-BLUEPRINT-SYSTEM-FIELD-TYPE.ORGANIZATIONS');
case DmpBlueprintSystemFieldType.LANGUAGE: return this.language.instant('TYPES.DMP-BLUEPRINT-SYSTEM-FIELD-TYPE.LANGUAGE');
case DmpBlueprintSystemFieldType.CONTACT: return this.language.instant('TYPES.DMP-BLUEPRINT-SYSTEM-FIELD-TYPE.CONTACT');
case DmpBlueprintSystemFieldType.FUNDER: return this.language.instant('TYPES.DMP-BLUEPRINT-SYSTEM-FIELD-TYPE.FUNDER');
case DmpBlueprintSystemFieldType.GRANT: return this.language.instant('TYPES.DMP-BLUEPRINT-SYSTEM-FIELD-TYPE.GRANT');
case DmpBlueprintSystemFieldType.PROJECT: return this.language.instant('TYPES.DMP-BLUEPRINT-SYSTEM-FIELD-TYPE.PROJECT');
case DmpBlueprintSystemFieldType.LICENSE: return this.language.instant('TYPES.DMP-BLUEPRINT-SYSTEM-FIELD-TYPE.LICENSE');
case DmpBlueprintSystemFieldType.ACCESS_RIGHTS: return this.language.instant('TYPES.DMP-BLUEPRINT-SYSTEM-FIELD-TYPE.ACCESS_RIGHTS');
}
}
toDmpBlueprintExtraFieldDataTypeString(status: DmpBlueprintExtraFieldDataType): string {
switch (status) {
case DmpBlueprintExtraFieldDataType.Date: return this.language.instant('TYPES.DMP-BLUEPRINT-EXTRA-FIELD-DATA-TYPE.DATE');
case DmpBlueprintExtraFieldDataType.Number: return this.language.instant('TYPES.DMP-BLUEPRINT-EXTRA-FIELD-DATA-TYPE.NUMBER');
case DmpBlueprintExtraFieldDataType.Text: return this.language.instant('TYPES.DMP-BLUEPRINT-EXTRA-FIELD-DATA-TYPE.TEXT');
case DmpBlueprintExtraFieldDataType.ExternalAutocomplete: return this.language.instant('TYPES.DMP-BLUEPRINT-EXTRA-FIELD-DATA-TYPE.EXTERNAL-AUTOCOMPLETE');
}
}
}

View File

@ -0,0 +1,24 @@
import { Injectable } from '@angular/core';
@Injectable()
export class FileUtils {
constructor() { }
getFilenameFromContentDispositionHeader(header: string): string {
const regex: RegExp = new RegExp(/filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/g);
const matches = header.match(regex);
let filename: string;
for (let i = 0; i < matches.length; i++) {
const match = matches[i];
if (match.includes('filename="')) {
filename = match.substring(10, match.length - 1);
break;
} else if (match.includes('filename=')) {
filename = match.substring(9);
break;
}
}
return filename;
}
}

View File

@ -50,6 +50,7 @@ import { DescriptionTemplateType } from '@app/core/model/description-template-ty
import { DescriptionTemplateTypeStatus } from '@app/core/common/enum/description-template-type-status';
import { DescriptionTemplateTypeLookup } from '@app/core/query/description-template-type.lookup';
import { nameof } from 'ts-simple-nameof';
import { FileUtils } from '@app/core/services/utilities/file-utils.service';
const skipDisable: any[] = require('../../../../../assets/resources/skipDisable.json');
@ -119,7 +120,8 @@ export class DatasetProfileEditorComponent extends CheckDeactivateBaseComponent
private fb: UntypedFormBuilder,
private sidenavService: SideNavService,
private userService: UserService,
private descriptionTemplateTypeService: DescriptionTemplateTypeService
private descriptionTemplateTypeService: DescriptionTemplateTypeService,
private fileUtils: FileUtils
) {
super();
// this.profileID = route.snapshot.params['id'];
@ -584,30 +586,12 @@ export class DatasetProfileEditorComponent extends CheckDeactivateBaseComponent
.pipe(takeUntil(this._destroyed))
.subscribe(response => {
const blob = new Blob([response.body], { type: 'application/xml' });
const filename = this.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
FileSaver.saveAs(blob, filename);
});
}
getFilenameFromContentDispositionHeader(header: string): string {
const regex: RegExp = new RegExp(/filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/g);
const matches = header.match(regex);
let filename: string;
for (let i = 0; i < matches.length; i++) {
const match = matches[i];
if (match.includes('filename="')) {
filename = match.substring(10, match.length - 1);
break;
} else if (match.includes('filename=')) {
filename = match.substring(9);
break;
}
}
return filename;
}
getDescriptionTemplateTypes(): DescriptionTemplateType[] {
let lookup: DescriptionTemplateTypeLookup = new DescriptionTemplateTypeLookup();
lookup.project = {

View File

@ -16,11 +16,12 @@ import { MatomoService } from '@app/core/services/matomo/matomo-service';
import { SnackBarNotificationLevel, UiNotificationService } from '@app/core/services/notification/ui-notification-service';
import { DatasetProfileCriteriaComponent } from '@app/ui/admin/dataset-profile/listing/criteria/dataset-profile.component';
// import { BreadcrumbItem } from '@app/ui/misc/breadcrumb/definition/breadcrumb-item';
import { FileUtils } from '@app/core/services/utilities/file-utils.service';
import { BaseComponent } from '@common/base/base.component';
import { ConfirmationDialogComponent } from '@common/modules/confirmation-dialog/confirmation-dialog.component';
import { TranslateService } from '@ngx-translate/core';
import * as FileSaver from 'file-saver';
import { Observable, merge as observableMerge, of as observableOf } from 'rxjs';
import { Observable, merge as observableMerge } from 'rxjs';
import { map, startWith, switchMap, takeUntil } from 'rxjs/operators';
import { DialogConfirmationUploadDatasetProfiles } from './criteria/dialog-confirmation-upload-profile/dialog-confirmation-upload-profiles.component';
@ -55,6 +56,7 @@ export class DatasetProfileListingComponent extends BaseComponent implements OnI
private matomoService: MatomoService,
private dialog: MatDialog,
private datasetProfileService: DatasetProfileService,
private fileUtils: FileUtils
) {
super();
}
@ -160,28 +162,11 @@ export class DatasetProfileListingComponent extends BaseComponent implements OnI
.pipe(takeUntil(this._destroyed))
.subscribe(response => {
const blob = new Blob([response.body], { type: 'application/xml' });
const filename = this.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
FileSaver.saveAs(blob, filename);
});
}
getFilenameFromContentDispositionHeader(header: string): string {
const regex: RegExp = new RegExp(/filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/g);
const matches = header.match(regex);
let filename: string;
for (let i = 0; i < matches.length; i++) {
const match = matches[i];
if (match.includes('filename="')) {
filename = match.substring(10, match.length - 1);
break;
} else if (match.includes('filename=')) {
filename = match.substring(9);
break;
}
}
return filename;
}
deleteTemplate(id: string) {
if (id) {

View File

@ -23,7 +23,7 @@
<button mat-button class="finalize-btn" (click)="finalize()" [disabled]="!this.isFormValid()" type="button">{{'DMP-BLUEPRINT-EDITOR.ACTIONS.FINALIZE' | translate }}</button>
</div>
</div>
<form *ngIf="formGroup" (ngSubmit)="formSubmit()" [formGroup]="formGroup">
<form *ngIf="formGroup" (ngSubmit)="formSubmit()">
<mat-card>
<!-- <mat-card-header>
<mat-card-title *ngIf="isNew">
@ -35,206 +35,167 @@
</mat-card-header> -->
<mat-card-content>
<div class="row">
<mat-form-field class="col-lg-6">
<mat-label>Name</mat-label>
<input matInput type="text" name="label" formControlName="label" required>
<div class="col-6">
<mat-form-field class="w-100">
<mat-label>{{'DMP-BLUEPRINT-EDITOR.FIELDS.NAME' | translate}}</mat-label>
<input matInput type="text" name="label" [formControl]="formGroup.get('label')" required>
<mat-error *ngIf="formGroup.get('label').hasError('required')">
{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
<h4 class="col-12">Sections</h4>
</div>
<h4 class="col-12">{{'DMP-BLUEPRINT-EDITOR.FIELDS.SECTIONS' | translate}}</h4>
<div class="col-12" cdkDropList (cdkDropListDropped)="dropSections($event)">
<div *ngFor="let section of formGroup.get('definition').get('sections').controls; let sectionIndex=index;" class="row section-input" cdkDrag [cdkDragDisabled]="viewOnly">
<div *ngFor="let section of formGroup.get('definition').get('sections').controls; let sectionIndex=index;" class="row mb-3" cdkDrag [cdkDragDisabled]="viewOnly">
<div class="col-12">
<mat-card>
<mat-card-header>
<mat-card-title>Section {{sectionIndex + 1}}</mat-card-title>
<mat-icon cdkDragHandle style="cursor: move; color: #129d99;">drag_indicator</mat-icon>
<div class="row mb-3 d-flex align-items-center">
<div class="col-auto d-flex">
<mat-card-title>{{'DMP-BLUEPRINT-EDITOR.FIELDS.SECTION-PREFIX' | translate}} {{sectionIndex + 1}}</mat-card-title>
</div>
<div class="col-auto d-flex"><mat-icon cdkDragHandle style="cursor: move; color: #129d99;">drag_indicator</mat-icon></div>
<div [hidden]="viewOnly" class="col-auto d-flex" (click)="removeSection(sectionIndex)" [disabled]="viewOnly">
<mat-icon class="action-list-icon" matTooltip="{{'DMP-BLUEPRINT-EDITOR.ACTIONS.REMOVE-SECTION' | translate}}">delete</mat-icon>
</div>
</div>
</mat-card-header>
<mat-card-content>
<div class="row">
<mat-form-field class="col-6">
<mat-label>Section name</mat-label>
<div class="col-6">
<mat-form-field class="w-100">
<mat-label>{{'DMP-BLUEPRINT-EDITOR.FIELDS.SECTION-NAME' | translate}}</mat-label>
<input matInput type="text" name="label" [formControl]="section.get('label')" required>
<mat-error *ngIf="section.get('label').hasError('required')">
{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
<mat-form-field class="col-6">
<mat-label>Section description</mat-label>
</div>
<div class="col-6">
<mat-form-field class="w-100">
<mat-label>{{'DMP-BLUEPRINT-EDITOR.FIELDS.SECTION-DESCRIPTION' | translate}}</mat-label>
<input matInput type="text" name="description" [formControl]="section.get('description')">
<mat-error *ngIf="section.get('description').hasError('required')">
{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
<div class="col-12">
<div class="row">
<div class="col-12">
<div class="row">
</div>
<div class="col-6">
<mat-form-field>
<mat-label>System fields</mat-label>
<mat-select multiple [disabled]="viewOnly" [value]="systemFieldListPerSection[sectionIndex]">
<mat-option *ngFor="let f of fieldList" [disabled]="systemFieldDisabled(f.type, sectionIndex)" [value]="f.type" (click)="selectedFieldType(f.type, sectionIndex)">{{f.label}}</mat-option>
<mat-form-field class="w-100">
<mat-label>{{'DMP-BLUEPRINT-EDITOR.FIELDS.SYSTEM-FIELDS' | translate}}</mat-label>
<mat-select multiple [disabled]="viewOnly" [(ngModel)]="selectedSystemFields" [ngModelOptions]="{standalone: true}">
<mat-option *ngFor="let systemFieldType of dmpBlueprintSystemFieldTypeEnum" [disabled]="systemFieldDisabled(systemFieldType)" [value]="systemFieldType">{{enumUtils.toDmpBlueprintSystemFieldTypeString(systemFieldType)}}</mat-option>
</mat-select>
<mat-error *ngIf="fieldsArray(sectionIndex).hasError('required')">
<!-- <mat-error *ngIf="fieldsArray(sectionIndex).hasError('required')">
{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error> -->
</mat-form-field>
</div>
<div class="col-auto">
<button mat-button class="action-btn" type="button" (click)="addExtraField(sectionIndex)" [disabled]="viewOnly">{{'DMP-BLUEPRINT-EDITOR.ACTIONS.ADD-EXTRA-FIELD' | translate}}</button>
</div>
<div cdkDropList class="col-12" (cdkDropListDropped)="dropFields($event, sectionIndex)">
<div *ngFor="let field of section.get('fields').controls; let fieldIndex=index;" cdkDrag class="row align-items-center" [cdkDragDisabled]="viewOnly">
<div class="col-auto">
<span style="font-size: 15px;">{{fieldIndex + 1}}</span>
</div>
<div class="col-auto">
<mat-icon cdkDragHandle style="cursor: move; color: #129d99;">drag_indicator</mat-icon>
</div>
<div class="col-auto" *ngIf="field.get('category').value === dmpBlueprintSectionFieldCategory.SYSTEM">
<mat-form-field class="w-100">
<mat-label>{{'DMP-BLUEPRINT-EDITOR.FIELDS.SYSTEM-FIELD' | translate}}</mat-label>
<input matInput disabled value="{{enumUtils.toDmpBlueprintSystemFieldTypeString(field.get('systemFieldType').value)}}" type="text" name="name">
</mat-form-field>
</div>
<div class="col-auto" *ngIf="field.get('category').value === dmpBlueprintSectionFieldCategory.EXTRA">
<mat-form-field class="w-100">
<mat-label>{{'DMP-BLUEPRINT-EDITOR.FIELDS.FIELD-DATA-TYPE' | translate}}</mat-label>
<mat-select [formControl]="field.get('dataType')" required>
<mat-option *ngFor="let extraFieldDataType of dmpBlueprintExtraFieldDataTypeEnum" [value]="extraFieldDataType">
{{enumUtils.toDmpBlueprintExtraFieldDataTypeString(extraFieldDataType)}}
</mat-option>
</mat-select>
<mat-error *ngIf="field.get('dataType').hasError('required')">
{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
</div>
<div class="col-6">
<button mat-button class="action-btn" type="button" (click)="addExtraField(sectionIndex)" [disabled]="viewOnly">Add extra field</button>
</div>
</div>
</div>
<div class="col-12">
<div cdkDropList (cdkDropListDropped)="drop($event, sectionIndex)">
<div *ngFor="let field of section.get('fields').controls; let fieldIndex=index;" cdkDrag [cdkDragDisabled]="viewOnly">
<div class="col-12">
<div class="row">
<div class="col-xx-1" style="padding-left: 0;">
<div class="row">
<div class="col-4">
<span style="font-size: 15px;">{{fieldIndex + 1}}</span>
</div>
<div class="col-8">
<mat-icon cdkDragHandle style="cursor: move; color: #129d99;">drag_indicator</mat-icon>
</div>
</div>
</div>
<ng-container *ngIf="field.get('category').value === dmpBlueprintSectionFieldCategory.SYSTEM">
<div class="col-2">
<mat-form-field>
<mat-label>System Field</mat-label>
<input matInput disabled value="{{transfromEnumToString(field.get('type').value)}}" type="text" name="name">
</mat-form-field>
</div>
<div class="col-2">
<mat-form-field>
<mat-label>Label</mat-label>
<div class="col">
<mat-form-field class="w-100">
<mat-label>{{'DMP-BLUEPRINT-EDITOR.FIELDS.FIELD-LABEL' | translate}}</mat-label>
<input matInput type="text" name="label" [formControl]="field.get('label')" required>
<mat-error *ngIf="field.get('label').hasError('required')">
{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
</div>
<div class="col-2">
<mat-form-field>
<mat-label>Placeholder</mat-label>
<div class="col">
<mat-form-field class="w-100">
<mat-label>{{'DMP-BLUEPRINT-EDITOR.FIELDS.FIELD-PLACEHOLDER' | translate}}</mat-label>
<input matInput type="text" name="placeholder" [formControl]="field.get('placeholder')">
</mat-form-field>
</div>
<div class="col-2">
<mat-form-field>
<mat-label>Description</mat-label>
<div class="col">
<mat-form-field class="w-100">
<mat-label>{{'DMP-BLUEPRINT-EDITOR.FIELDS.FIELD-DESCRIPTION' | translate}}</mat-label>
<input matInput type="text" name="description" [formControl]="field.get('description')">
</mat-form-field>
</div>
<div class="centered-row-item col-1">
<mat-checkbox [disabled]="field.get('type').value === 0 || field.get('type').value === 1" [formControl]="field.get('required')">Required</mat-checkbox>
<div class="centered-row-item col-auto">
<mat-checkbox [disabled]="field.get('systemFieldType')?.value === dmpBlueprintSystemFieldType.TEXT || field.get('systemFieldType')?.value === dmpBlueprintSystemFieldType.HTML_TEXT" [formControl]="field.get('required')">{{'DMP-BLUEPRINT-EDITOR.FIELDS.FIELD-REQUIRED' | translate}}</mat-checkbox>
</div>
<div [hidden]="viewOnly" class="field-delete col-1" (click)="removeSystemFieldWithIndex(sectionIndex, fieldIndex)">
<div *ngIf="field.get('category').value === dmpBlueprintSectionFieldCategory.SYSTEM" [hidden]="viewOnly" class="field-delete col-auto" (click)="removeSystemField(sectionIndex, fieldIndex)">
<mat-icon class="field-delete-icon">delete</mat-icon>
<span class="field-delete-text">{{'DMP-BLUEPRINT-EDITOR.STEPS.TOOLKIT.DELETE' | translate}}</span>
<span class="field-delete-text">{{'DMP-BLUEPRINT-EDITOR.ACTIONS.REMOVE-SYSTEM-FIELD' | translate}}</span>
</div>
</ng-container>
<ng-container *ngIf="field.get('category').value === dmpBlueprintSectionFieldCategory.EXTRA">
<div class="col-2">
<mat-form-field>
<mat-label>Type</mat-label>
<mat-select placeholder="Type" formControlName="type" required>
<mat-option *ngFor="let extraFieldType of getExtraFieldTypes()" [value]="extraFieldType">
{{getExtraFieldTypeValue(extraFieldType)}}
</mat-option>
</mat-select>
<mat-error *ngIf="field.get('type').hasError('required')">
{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
</div>
<div class="col-2">
<mat-form-field>
<mat-label>Label</mat-label>
<input matInput type="text" name="label" formControlName="label" required>
<mat-error *ngIf="field.get('label').hasError('required')">
{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
</div>
<div class="col-2">
<mat-form-field>
<mat-label>Placeholder</mat-label>
<input matInput type="text" name="placeholder" formControlName="placeholder">
</mat-form-field>
</div>
<div class="col-2">
<mat-form-field>
<mat-label>Description</mat-label>
<input matInput type="text" name="description" formControlName="description">
</mat-form-field>
</div>
<div class="centered-row-item col-1">
<mat-checkbox formControlName="required">
Required
</mat-checkbox>
</div>
<div [hidden]="viewOnly" class="field-delete col-1" (click)="removeExtraField(sectionIndex, fieldIndex)">
<div *ngIf="field.get('category').value === dmpBlueprintSectionFieldCategory.EXTRA" [hidden]="viewOnly" class="field-delete col-auto" (click)="removeExtraField(sectionIndex, fieldIndex)">
<mat-icon class="field-delete-icon">delete</mat-icon>
<span class="field-delete-text">{{'DMP-BLUEPRINT-EDITOR.STEPS.TOOLKIT.DELETE' | translate}}</span>
</div>
</ng-container>
</div>
</div>
</div>
<span class="field-delete-text">{{'DMP-BLUEPRINT-EDITOR.ACTIONS.REMOVE-EXTRA-FIELD' | translate}}</span>
</div>
</div>
</div>
</div>
</div>
</mat-card-content>
<div class="col-12">
<div class="row">
<div class="col-12">
<div class="col-auto">
<mat-checkbox [formControl]="section.get('hasTemplates')" (change)="checkForBlueprints($event, sectionIndex)">
Description Templates
{{'DMP-BLUEPRINT-EDITOR.FIELDS.DESCRIPTION-TEMPLATES' | translate}}
</mat-checkbox>
</div>
</div>
</div>
<!-- <div class="col-12" *ngIf="section.get('hasTemplates').value == true">
<div class="col-12" *ngIf="section.get('hasTemplates').value == true">
<div class="row">
<div class="col-12">
<mat-form-field>
<mat-label>Description Templates</mat-label>
<app-multiple-auto-complete placeholder="Description Templates" [disabled]="viewOnly" [value]="descriptionTemplatesPerSection[sectionIndex]" [hidePlaceholder]="true" required='false' [configuration]="blueprintsAutoCompleteConfiguration" (optionRemoved)="onRemoveTemplate($event, sectionIndex)" (optionSelected)="onOptionSelected($event, sectionIndex)">
<mat-form-field class="w-100">
<mat-label>{{'DMP-BLUEPRINT-EDITOR.FIELDS.DESCRIPTION-TEMPLATES' | translate}}</mat-label>
<app-multiple-auto-complete [disabled]="viewOnly" [hidePlaceholder]="true" required='false' [configuration]="blueprintsAutoCompleteConfiguration" (optionRemoved)="onRemoveDescritionTemplate($event, sectionIndex)" (optionSelected)="onSelectDescritionTemplate($event, sectionIndex)">
</app-multiple-auto-complete>
</mat-form-field>
</div>
</div>
</div> -->
<div *ngFor="let descriptionTemplate of section.get('descriptionTemplates').controls; let j=index;" class="section-input" style="width: 100%;">
</div>
<div *ngFor="let descriptionTemplate of section.get('descriptionTemplates').controls; let j=index;" class="col-12">
<div class="col-12">
<div class="row">
<div class="col-4">
<mat-form-field>
<mat-label>Label</mat-label>
<mat-form-field class="w-100">
<mat-label>{{'DMP-BLUEPRINT-EDITOR.FIELDS.DESCRIPTION-TEMPLATE-LABEL' | translate}}</mat-label>
<input matInput type="text" value="descriptionTemplate.get('label')" name="label" [formControl]="descriptionTemplate.get('label')">
</mat-form-field>
</div>
<div class="col-4">
<mat-form-field>
<mat-label>Min Multiplicity</mat-label>
<mat-form-field class="w-100">
<mat-label>{{'DMP-BLUEPRINT-EDITOR.FIELDS.DESCRIPTION-TEMPLATE-MIN-MULTIPLICITY' | translate}}</mat-label>
<input matInput type="number" min="0" name="minMultiplicity" [formControl]="descriptionTemplate.get('minMultiplicity')">
</mat-form-field>
</div>
<div class="col-4">
<mat-form-field>
<mat-label>Max Multiplicity</mat-label>
<mat-form-field class="w-100">
<mat-label>{{'DMP-BLUEPRINT-EDITOR.FIELDS.DESCRIPTION-TEMPLATE-MAX-MULTIPLICITY' | translate}}</mat-label>
<input matInput type="number" min="1" name="maxMultiplicity" [formControl]="descriptionTemplate.get('maxMultiplicity')">
</mat-form-field>
</div>
@ -242,17 +203,7 @@
</div>
</div>
</mat-card>
<div class="col-1">
<div class="row">
<!-- <div class="col-auto dlt-section-btn">
<button mat-button class="action-btn" type="button" click="removeSection(sectionIndex)">Delete</button>
</div> -->
<div [hidden]="viewOnly" class="action-list-item col-auto dlt-section-btn" (click)="removeSection(sectionIndex)" [disabled]="viewOnly">
<mat-icon class="action-list-icon">delete</mat-icon>
<span class="action-list-text">{{'DMP-BLUEPRINT-EDITOR.STEPS.TOOLKIT.DELETE' | translate}}</span>
</div>
</div>
</div>
</div>
</div>
@ -262,7 +213,7 @@
<div class="col-12">
<div class="row">
<div class="col-auto">
<button mat-button class="action-btn" type="button" (click)="addSection()" [disabled]="viewOnly">Add section</button>
<button mat-button class="action-btn" type="button" (click)="addSection()" [disabled]="viewOnly">{{'DMP-BLUEPRINT-EDITOR.ACTIONS.ADD-SECTION' | translate}}</button>
</div>
</div>
</div>
@ -282,4 +233,3 @@
</mat-card>
</form>
</div>
<!-- </div> -->

View File

@ -89,10 +89,10 @@
.action-list-icon{
font-size: 1.2em;
// padding-right: 1em;
width: 14px;
margin-right: 0.5em;
margin-left: -.09em;
height: auto;
// width: 14px;
// margin-right: 0.5em;
// margin-left: -.09em;
// height: auto;
color: var(--primary-color);
}

View File

@ -1,31 +1,45 @@
import { Component, OnInit } from '@angular/core';
import { UntypedFormGroup } from '@angular/forms';
import { FormArray, UntypedFormGroup } from '@angular/forms';
import { MatDialog } from '@angular/material/dialog';
import { ActivatedRoute, Router } from '@angular/router';
import { DmpBlueprintService } from '@app/core/services/dmp/dmp-blueprint.service';
import { SnackBarNotificationLevel, UiNotificationService } from '@app/core/services/notification/ui-notification-service';
import { EnumUtils } from '@app/core/services/utilities/enum-utils.service';
// import { BreadcrumbItem } from '@app/ui/misc/breadcrumb/definition/breadcrumb-item';
import { CdkDragDrop, moveItemInArray } from '@angular/cdk/drag-drop';
import { DatePipe } from '@angular/common';
import { DmpBlueprintExtraFieldDataType } from '@app/core/common/enum/dmp-blueprint-field-type';
import { DmpBlueprintSectionFieldCategory } from '@app/core/common/enum/dmp-blueprint-section-field-category';
import { DmpBlueprintStatus } from '@app/core/common/enum/dmp-blueprint-status';
import { DmpBlueprintSystemFieldType } from '@app/core/common/enum/dmp-blueprint-system-field-type';
import { IsActive } from '@app/core/common/enum/is-active.enum';
import { AppPermission } from '@app/core/common/enum/permission.enum';
import { DataTableRequest } from '@app/core/model/data-table/data-table-request';
import { DatasetProfileModel } from '@app/core/model/dataset/dataset-profile';
import { DmpBlueprint, DmpBlueprintPersist } from '@app/core/model/dmp-blueprint/dmp-blueprint';
import { DatasetProfileCriteria } from '@app/core/query/dataset-profile/dataset-profile-criteria';
import { AuthService } from '@app/core/services/auth/auth.service';
import { DmpService } from '@app/core/services/dmp/dmp.service';
import { LoggingService } from '@app/core/services/logging/logging-service';
import { MatomoService } from '@app/core/services/matomo/matomo-service';
import { FileUtils } from '@app/core/services/utilities/file-utils.service';
import { QueryParamsService } from '@app/core/services/utilities/query-params.service';
import { MultipleAutoCompleteConfiguration } from '@app/library/auto-complete/multiple/multiple-auto-complete-configuration';
import { BaseEditor } from '@common/base/base-editor';
import { FormService } from '@common/forms/form-service';
import { FormValidationErrorsDialogComponent } from '@common/forms/form-validation-errors-dialog/form-validation-errors-dialog.component';
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 * as FileSaver from 'file-saver';
import { Observable } from 'rxjs';
import { map, takeUntil } from 'rxjs/operators';
import { DmpBlueprintEditorModel } from './dmp-blueprint-editor.model';
import { DescriptionTemplatesInSectionEditorModel, DmpBlueprintDefinitionSectionEditorModel, DmpBlueprintEditorModel, FieldInSectionEditorModel } from './dmp-blueprint-editor.model';
import { DmpBlueprintEditorResolver } from './dmp-blueprint-editor.resolver';
import { DmpBlueprintEditorService } from './dmp-blueprint-editor.service';
import { DmpBlueprint, DmpBlueprintPersist } from '@app/core/model/dmp-blueprint/dmp-blueprint';
import { IsActive } from '@app/core/common/enum/is-active.enum';
import { DmpBlueprintSectionFieldCategory } from '@app/core/common/enum/dmp-blueprint-section-field-category';
@Component({
@ -40,8 +54,21 @@ export class DmpBlueprintEditorComponent extends BaseEditor<DmpBlueprintEditorMo
isDeleted = false;
formGroup: UntypedFormGroup = null;
showInactiveDetails = false;
selectedSystemFields: Array<DmpBlueprintSystemFieldType> = [];
dmpBlueprintSectionFieldCategory = DmpBlueprintSectionFieldCategory;
dmpBlueprintSystemFieldType = DmpBlueprintSystemFieldType;
public dmpBlueprintSystemFieldTypeEnum = this.enumUtils.getEnumValues(DmpBlueprintSystemFieldType);
dmpBlueprintExtraFieldDataType = DmpBlueprintExtraFieldDataType;
public dmpBlueprintExtraFieldDataTypeEnum = this.enumUtils.getEnumValues(DmpBlueprintExtraFieldDataType);
blueprintsAutoCompleteConfiguration: MultipleAutoCompleteConfiguration = {
filterFn: this.filterDescriptionTempaltes.bind(this),
initialItems: (excludedItems: any[]) => this.filterDescriptionTempaltes('').pipe(map(result => result.filter(resultItem => (excludedItems || []).map(x => x.id).indexOf(resultItem.id) === -1))),
displayFn: (item: DatasetProfileModel) => item.label,
titleFn: (item: DatasetProfileModel) => item.label,
subtitleFn: (item: DatasetProfileModel) => item.description,
popupItemActionIcon: 'visibility'
};
protected get canDelete(): boolean {
return !this.isDeleted && !this.isNew && this.hasPermission(this.authService.permissionEnum.DeleteDmpBlueprint);
@ -77,12 +104,16 @@ export class DmpBlueprintEditorComponent extends BaseEditor<DmpBlueprintEditorMo
public enumUtils: EnumUtils,
private dmpBlueprintService: DmpBlueprintService,
private logger: LoggingService,
private dmpBlueprintEditorService: DmpBlueprintEditorService
private dmpBlueprintEditorService: DmpBlueprintEditorService,
private fileUtils: FileUtils,
private matomoService: MatomoService,
private dmpService: DmpService
) {
super(dialog, language, formService, router, uiNotificationService, httpErrorHandlingService, filterService, datePipe, route, queryParamsService);
}
ngOnInit(): void {
this.matomoService.trackPageView('Admin: DMP Blueprints');
super.ngOnInit();
}
@ -108,6 +139,7 @@ export class DmpBlueprintEditorComponent extends BaseEditor<DmpBlueprintEditorMo
buildForm() {
this.formGroup = this.editorModel.buildForm(null, this.isDeleted || !this.authService.hasPermission(AppPermission.EditDmpBlueprint));
this.selectedSystemFields = this.selectedSystemFieldDisabled();
this.dmpBlueprintEditorService.setValidationErrorModel(this.editorModel.validationErrorModel);
}
@ -176,71 +208,140 @@ export class DmpBlueprintEditorComponent extends BaseEditor<DmpBlueprintEditorMo
this.editorModel.validationErrorModel.clear();
this.formService.validateAllFormFields(this.formGroup);
}
//
//
// Sections
//
//
addSection(): void {
const section: DmpBlueprintDefinitionSectionEditorModel = new DmpBlueprintDefinitionSectionEditorModel();
section.id = Guid.create();
section.ordinal = (this.formGroup.get('definition').get('sections') as FormArray).controls.length + 1;
section.hasTemplates = false;
(this.formGroup.get('definition').get('sections') as FormArray).push(section.buildForm()); //TODO: dtziotzios validation path
}
removeSection(sectionIndex: number): void {
(this.formGroup.get('definition').get('sections') as FormArray).removeAt(sectionIndex);
(this.formGroup.get('definition').get('sections') as FormArray).controls.forEach((section, index) => {
section.get('ordinal').setValue(index + 1);
});
}
dropSections(event: CdkDragDrop<string[]>) {
const sectionsFormArray = (this.formGroup.get('definition').get('sections') as FormArray);
moveItemInArray(sectionsFormArray.controls, event.previousIndex, event.currentIndex);
sectionsFormArray.updateValueAndValidity();
sectionsFormArray.controls.forEach((section, index) => {
section.get('ordinal').setValue(index + 1);
});
}
// extends BaseComponent implements AfterViewInit {
// isNew = true;
// isClone = false;
// viewOnly = false;
// dmpBlueprintEditorModel = new DmpBlueprintEditorModel();
// dmpBlueprintEditor = new DmpBlueprintEditor();
// formGroup: UntypedFormGroup = null;
// host: string;
// dmpBlueprintId: string;
// // breadCrumbs: Observable<BreadcrumbItem[]>;
// dmpBlueprintsFormGroup: UntypedFormGroup = null;
// blueprintsAutoCompleteConfiguration: MultipleAutoCompleteConfiguration;
// fieldList = [
// { label: 'Title', type: SystemFieldType.TEXT },
// { label: 'Description', type: SystemFieldType.HTML_TEXT },
// { label: 'Researchers', type: SystemFieldType.RESEARCHERS },
// { label: 'Organizations', type: SystemFieldType.ORGANIZATIONS },
// { label: 'Language', type: SystemFieldType.LANGUAGE },
// { label: 'Contact', type: SystemFieldType.CONTACT },
// { label: 'Funder', type: SystemFieldType.FUNDER },
// { label: 'Grant', type: SystemFieldType.GRANT },
// { label: 'Project', type: SystemFieldType.PROJECT },
// { label: 'License', type: SystemFieldType.LICENSE },
// { label: 'Access Rights', type: SystemFieldType.ACCESS_RIGHTS }
// ];
// systemFieldListPerSection: Array<Array<any>> = new Array();
// descriptionTemplatesPerSection: Array<Array<DatasetProfileModel>> = new Array<Array<DatasetProfileModel>>();
// constructor(
// private dmpBlueprintService: DmpBlueprintService,
// private _service: DmpService,
// private route: ActivatedRoute,
// private router: Router,
// private language: TranslateService,
// private enumUtils: EnumUtils,
// private uiNotificationService: UiNotificationService,
// private formService: FormService,
// private fb: UntypedFormBuilder,
// private configurationService: ConfigurationService,
// private httpClient: HttpClient,
// private matomoService: MatomoService,
// private dialog: MatDialog
// ) {
// super();
// this.host = configurationService.server;
//
//
// Fields
//
//
systemFieldDisabled(systemField: DmpBlueprintSystemFieldType) {
return (this.formGroup.get('definition').get('sections') as FormArray)?.controls.some(x => (x.get('fields') as FormArray).controls.some(y => (y as UntypedFormGroup).get('systemFieldType')?.value === systemField));
// for (let section in (this.formGroup.get('definition').get('sections')as FormArray)?.controls) {
// if (i != sectionIndex) {
// for (let f of this.fieldsArray(i).controls) {
// if ((f.get('category').value == FieldCategory.SYSTEM || f.get('category').value == 'SYSTEM') && f.get('type').value == systemField) {
// return true;
// }
// }
// }
// i++;
// }
// return false;
}
selectedSystemFieldDisabled(): Array<DmpBlueprintSystemFieldType> {
return (this.formGroup.get('definition').get('sections') as FormArray)?.controls.flatMap(x => (x.get('fields') as FormArray).controls.map(y => (y as UntypedFormGroup).get('systemFieldType')?.value as DmpBlueprintSystemFieldType));
}
addSystemField(sectionIndex: number, systemFieldType: DmpBlueprintSystemFieldType): void {
const field: FieldInSectionEditorModel = new FieldInSectionEditorModel();
field.id = Guid.create();
field.ordinal = ((this.formGroup.get('definition').get('sections') as FormArray).at(sectionIndex).get('fields') as FormArray).length + 1;
field.category = DmpBlueprintSectionFieldCategory.SYSTEM;
field.systemFieldType = systemFieldType;
field.required = (systemFieldType == DmpBlueprintSystemFieldType.TEXT || systemFieldType == DmpBlueprintSystemFieldType.HTML_TEXT) ? true : false;
((this.formGroup.get('definition').get('sections') as FormArray).at(sectionIndex).get('fields') as FormArray).push(field.buildForm()); //TODO: dtziotzios validation path
}
removeSystemField(sectionIndex: number, fieldIndex: number): void {
const formArray = ((this.formGroup.get('definition').get('sections') as FormArray).at(sectionIndex).get('fields') as FormArray);
formArray.removeAt(fieldIndex);
formArray.controls.forEach((section, index) => {
section.get('ordinal').setValue(index + 1);
});
}
addExtraField(sectionIndex: number): void {
const field: FieldInSectionEditorModel = new FieldInSectionEditorModel();
field.id = Guid.create();
field.ordinal = ((this.formGroup.get('definition').get('sections') as FormArray).at(sectionIndex).get('fields') as FormArray).length + 1;
field.category = DmpBlueprintSectionFieldCategory.EXTRA;
((this.formGroup.get('definition').get('sections') as FormArray).at(sectionIndex).get('fields') as FormArray).push(field.buildForm()); //TODO: dtziotzios validation path
}
removeExtraField(sectionIndex: number, fieldIndex: number): void {
const formArray = ((this.formGroup.get('definition').get('sections') as FormArray).at(sectionIndex).get('fields') as FormArray);
formArray.removeAt(fieldIndex);
formArray.controls.forEach((section, index) => {
section.get('ordinal').setValue(index + 1);
});
}
dropFields(event: CdkDragDrop<string[]>, sectionIndex: number) {
const fieldsFormArray = ((this.formGroup.get('definition').get('sections') as FormArray).at(sectionIndex).get('fields') as FormArray);
moveItemInArray(fieldsFormArray.controls, event.previousIndex, event.currentIndex);
fieldsFormArray.updateValueAndValidity();
fieldsFormArray.controls.forEach((section, index) => {
section.get('ordinal').setValue(index + 1);
});
}
//
//
// Autocomplete configuration
//
//
filterDescriptionTempaltes(value: string): Observable<DatasetProfileModel[]> {
const request = new DataTableRequest<DatasetProfileCriteria>(null, null, { fields: ['+label'] });
const criteria = new DatasetProfileCriteria();
criteria.like = value;
request.criteria = criteria;
return this.dmpService.searchDmpBlueprints(request);
}
onRemoveDescritionTemplate(event, sectionIndex: number) {
const descriptionTemplateFormArray = (this.formGroup.get('definition').get('sections') as FormArray).at(sectionIndex).get('descriptionTemplates') as FormArray;
const foundIndex = descriptionTemplateFormArray.controls.findIndex(blueprint => blueprint.get('descriptionTemplateId').value === event.id);
if (foundIndex !== -1) {
descriptionTemplateFormArray.removeAt(foundIndex);
}
}
onSelectDescritionTemplate(item, sectionIndex) {
const descriptionTemplate: DescriptionTemplatesInSectionEditorModel = new DescriptionTemplatesInSectionEditorModel();
descriptionTemplate.id = Guid.create();
descriptionTemplate.descriptionTemplateId = item.id;
descriptionTemplate.label = item.label;
((this.formGroup.get('definition').get('sections') as FormArray).at(sectionIndex).get('descriptionTemplates') as FormArray).push(descriptionTemplate.buildForm()); //TODO: dtziotzios validation path
}
// ngAfterViewInit() {
// this.matomoService.trackPageView('Admin: DMP Profile Edit');
// this.blueprintsAutoCompleteConfiguration = {
// filterFn: this.filterProfiles.bind(this),
// initialItems: (excludedItems: any[]) => this.filterProfiles('').pipe(map(result => result.filter(resultItem => (excludedItems || []).map(x => x.id).indexOf(resultItem.id) === -1))),
// displayFn: (item) => item['label'],
// titleFn: (item) => item['label'],
// subtitleFn: (item) => item['description'],
// popupItemActionIcon: 'visibility'
// };
// this.route.params
// .pipe(takeUntil(this._destroyed))
@ -331,51 +432,19 @@ export class DmpBlueprintEditorComponent extends BaseEditor<DmpBlueprintEditorMo
// }
// }
// filterProfiles(value: string): Observable<DatasetProfileModel[]> {
// const request = new DataTableRequest<DatasetProfileCriteria>(null, null, { fields: ['+label'] });
// const criteria = new DatasetProfileCriteria();
// criteria.like = value;
// request.criteria = criteria;
// return this._service.searchDmpBlueprints(request);
// }
// sectionsArray(): UntypedFormArray {
// //return this.dmpBlueprintsFormGroup.get('sections') as FormArray;
// return this.formGroup.get('definition').get('sections') as UntypedFormArray;
// }
// addSection(): void {
// const section: SectionDmpBlueprintEditor = new SectionDmpBlueprintEditor();
// section.id = Guid.create().toString();
// section.ordinal = this.sectionsArray().length + 1;
// section.hasTemplates = false;
// this.sectionsArray().push(section.buildForm());
// this.systemFieldListPerSection.push(new Array());
// }
// removeSection(sectionIndex: number): void {
// this.systemFieldListPerSection.splice(sectionIndex, 1);
// this.sectionsArray().removeAt(sectionIndex);
// this.sectionsArray().controls.forEach((section, index) => {
// section.get('ordinal').setValue(index + 1);
// });
// }
// fieldsArray(sectionIndex: number): UntypedFormArray {
// return this.sectionsArray().at(sectionIndex).get('fields') as UntypedFormArray;
// }
// addField(sectionIndex: number, fieldCategory: FieldCategory, fieldType?: number): void {
// const field: FieldInSectionEditor = new FieldInSectionEditor();
// field.id = Guid.create().toString();
// field.ordinal = this.fieldsArray(sectionIndex).length + 1;
// field.category = fieldCategory;
// if (!isNullOrUndefined(fieldType)) {
// field.type = fieldType
// }
// field.required = (!isNullOrUndefined(fieldType) && (fieldType == 0 || fieldType == 1)) ? true : false;
// this.fieldsArray(sectionIndex).push(field.buildForm());
// }
// removeField(sectionIndex: number, fieldIndex: number): void {
// this.fieldsArray(sectionIndex).removeAt(fieldIndex);
@ -417,38 +486,7 @@ export class DmpBlueprintEditorComponent extends BaseEditor<DmpBlueprintEditorMo
// }
// }
// systemFieldDisabled(systemField: SystemFieldType, sectionIndex: number) {
// let i = 0;
// for (let s in this.sectionsArray().controls) {
// if (i != sectionIndex) {
// for (let f of this.fieldsArray(i).controls) {
// if ((f.get('category').value == FieldCategory.SYSTEM || f.get('category').value == 'SYSTEM') && f.get('type').value == systemField) {
// return true;
// }
// }
// }
// i++;
// }
// return false;
// }
// removeSystemFieldWithIndex(sectionIndex: number, fieldIndex: number): void {
// let type: SystemFieldType = this.fieldsArray(sectionIndex).at(fieldIndex).get('type').value;
// let index = this.systemFieldListPerSection[sectionIndex].indexOf(type);
// this.systemFieldListPerSection[sectionIndex] = this.systemFieldListPerSection[sectionIndex].filter(types => types != type);
// this.fieldsArray(sectionIndex).removeAt(fieldIndex);
// }
// removeSystemField(sectionIndex: number, systemField: SystemFieldType): void {
// let i = 0;
// for (let f of this.fieldsArray(sectionIndex).controls) {
// if ((f.get('category').value == FieldCategory.SYSTEM || f.get('category').value == 'SYSTEM') && f.get('type').value == systemField) {
// this.fieldsArray(sectionIndex).removeAt(i);
// return;
// }
// i++;
// }
// }
// descriptionTemplatesArray(sectionIndex: number): UntypedFormArray {
// return this.sectionsArray().at(sectionIndex).get('descriptionTemplates') as UntypedFormArray;
@ -468,13 +506,11 @@ export class DmpBlueprintEditorComponent extends BaseEditor<DmpBlueprintEditorMo
// return this.sectionsArray().at(sectionIndex).get('extraFields') as UntypedFormArray;
// }
// addExtraField(sectionIndex: number): void {
// this.addField(sectionIndex, FieldCategory.EXTRA);
// }
// removeExtraField(sectionIndex: number, fieldIndex: number): void {
// this.fieldsArray(sectionIndex).removeAt(fieldIndex);
// }
// getExtraFieldTypes(): Number[] {
// let keys: string[] = Object.keys(ExtraFieldType);
@ -492,18 +528,7 @@ export class DmpBlueprintEditorComponent extends BaseEditor<DmpBlueprintEditorMo
// }
// }
// drop(event: CdkDragDrop<string[]>, sectionIndex: number) {
// moveItemInArray(this.fieldsArray(sectionIndex).controls, event.previousIndex, event.currentIndex);
// moveItemInArray(this.fieldsArray(sectionIndex).value, event.previousIndex, event.currentIndex);
// }
// dropSections(event: CdkDragDrop<string[]>) {
// moveItemInArray(this.sectionsArray().controls, event.previousIndex, event.currentIndex);
// moveItemInArray(this.sectionsArray().value, event.previousIndex, event.currentIndex);
// this.sectionsArray().controls.forEach((section, index) => {
// section.get('ordinal').setValue(index + 1);
// });
// }
// moveItemInFormArray(formArray: UntypedFormArray, fromIndex: number, toIndex: number): void {
// const dir = toIndex > fromIndex ? 1 : -1;
@ -520,11 +545,7 @@ export class DmpBlueprintEditorComponent extends BaseEditor<DmpBlueprintEditorMo
// // this.dmpBlueprintsFormGroup.reset();
// // }
// onRemoveTemplate(event, sectionIndex: number) {
// const blueprints = this.descriptionTemplatesArray(sectionIndex).controls;
// const foundIndex = blueprints.findIndex(blueprint => blueprint.get('descriptionTemplateId').value === event.id);
// foundIndex !== -1 && this.descriptionTemplatesArray(sectionIndex).removeAt(foundIndex);
// }
// // onPreviewTemplate(event, sectionIndex: number) {
// // const dialogRef = this.dialog.open(DatasetPreviewDialogComponent, {
@ -557,33 +578,27 @@ export class DmpBlueprintEditorComponent extends BaseEditor<DmpBlueprintEditorMo
// // });
// // }
// onOptionSelected(item, sectionIndex) {
// const blueprint: DescriptionTemplatesInSectionEditor = new DescriptionTemplatesInSectionEditor();
// blueprint.id = Guid.create().toString();
// blueprint.descriptionTemplateId = item.id;
// blueprint.label = item.label;
// this.descriptionTemplatesArray(sectionIndex).push(blueprint.buildForm());
// }
// checkValidity() {
// this.formService.touchAllFormFields(this.formGroup);
// if (!this.isFormValid()) { return false; }
// let errorMessages = [];
// if (!this.hasTitle()) {
// errorMessages.push("Title should be set.");
// }
// if (!this.hasDescription()) {
// errorMessages.push("Description should be set.");
// }
// if (!this.hasDescriptionTemplates()) {
// errorMessages.push("At least one section should have description templates.");
// }
// if (errorMessages.length > 0) {
// this.showValidationErrorsDialog(undefined, errorMessages);
// return false;
// }
// return true;
// }
checkValidity() {
this.formService.touchAllFormFields(this.formGroup);
if (!this.isFormValid()) { return false; }
let errorMessages = [];
if (!this.hasTitle()) {
errorMessages.push("Title should be set.");
}
if (!this.hasDescription()) {
errorMessages.push("Description should be set.");
}
if (!this.hasDescriptionTemplates()) {
errorMessages.push("At least one section should have description templates.");
}
if (errorMessages.length > 0) {
this.showValidationErrorsDialog(undefined, errorMessages);
return false;
}
return true;
}
// formSubmit(): void {
// if (this.checkValidity())
@ -594,34 +609,34 @@ export class DmpBlueprintEditorComponent extends BaseEditor<DmpBlueprintEditorMo
// return this.formGroup.valid;
// }
// hasTitle(): boolean {
// const dmpBlueprint: DmpBlueprint = this.formGroup.value;
// return dmpBlueprint.definition.sections.some(section => section.fields.some(field => (field.category === FieldCategory.SYSTEM || field.category as unknown === 'SYSTEM') && field.type === SystemFieldType.TEXT));
// }
hasTitle(): boolean {
const dmpBlueprint: DmpBlueprintPersist = this.formGroup.value;
return dmpBlueprint.definition.sections.some(section => section.fields.some(field => (field.category === DmpBlueprintSectionFieldCategory.SYSTEM || field.category as unknown === 'SYSTEM') && field.systemFieldType === DmpBlueprintSystemFieldType.TEXT));
}
// hasDescription(): boolean {
// const dmpBlueprint: DmpBlueprint = this.formGroup.value;
// return dmpBlueprint.definition.sections.some(section => section.fields.some(field => (field.category === FieldCategory.SYSTEM || field.category as unknown === 'SYSTEM') && field.type === SystemFieldType.HTML_TEXT));
// }
hasDescription(): boolean {
const dmpBlueprint: DmpBlueprintPersist = this.formGroup.value;
return dmpBlueprint.definition.sections.some(section => section.fields.some(field => (field.category === DmpBlueprintSectionFieldCategory.SYSTEM || field.category as unknown === 'SYSTEM') && field.systemFieldType === DmpBlueprintSystemFieldType.HTML_TEXT));
}
// hasDescriptionTemplates(): boolean {
// const dmpBlueprint: DmpBlueprint = this.formGroup.value;
// return dmpBlueprint.definition.sections.some(section => section.hasTemplates == true);
// }
hasDescriptionTemplates(): boolean {
const dmpBlueprint: DmpBlueprintPersist = this.formGroup.value;
return dmpBlueprint.definition.sections.some(section => section.hasTemplates == true);
}
// private showValidationErrorsDialog(projectOnly?: boolean, errmess?: string[]) {
private showValidationErrorsDialog(projectOnly?: boolean, errmess?: string[]) {
// const dialogRef = this.dialog.open(FormValidationErrorsDialogComponent, {
// disableClose: true,
// autoFocus: false,
// restoreFocus: false,
// data: {
// errorMessages: errmess,
// projectOnly: projectOnly
// },
// });
const dialogRef = this.dialog.open(FormValidationErrorsDialogComponent, {
disableClose: true,
autoFocus: false,
restoreFocus: false,
data: {
errorMessages: errmess,
projectOnly: projectOnly
},
});
// }
}
// onSubmit(): void {
// this.dmpBlueprintService.createBlueprint(this.formGroup.value)
@ -648,9 +663,9 @@ export class DmpBlueprintEditorComponent extends BaseEditor<DmpBlueprintEditorMo
// });
// }
// public cancel(): void {
// this.router.navigate(['/dmp-blueprints']);
// }
public cancel(): void {
this.router.navigate(['/dmp-blueprints']);
}
// // addField() {
// // (<FormArray>this.formGroup.get('definition').get('fields')).push(new DmpBlueprintFieldEditorModel().buildForm());
@ -736,42 +751,25 @@ export class DmpBlueprintEditorComponent extends BaseEditor<DmpBlueprintEditorMo
// }
// finalize() {
// if (this.checkValidity()) {
// this.formGroup.get('status').setValue(DmpBlueprintStatus.Finalized);
// this.onSubmit();
// }
// }
finalize() {
if (this.checkValidity()) {
this.formGroup.get('status').setValue(DmpBlueprintStatus.Finalized);
this.formSubmit();
}
}
// downloadXML(): void {
// this.dmpBlueprintService.downloadXML(this.dmpBlueprintId)
// .pipe(takeUntil(this._destroyed))
// .subscribe(response => {
// const blob = new Blob([response.body], { type: 'application/xml' });
// const filename = this.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
downloadXML(): void {
const blueprintId = this.formGroup.get('id').value;
if (blueprintId == null) return;
this.dmpBlueprintService.downloadXML(blueprintId)
.pipe(takeUntil(this._destroyed))
.subscribe(response => {
const blob = new Blob([response.body], { type: 'application/xml' });
const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
// FileSaver.saveAs(blob, filename);
// });
// }
// getFilenameFromContentDispositionHeader(header: string): string {
// const regex: RegExp = new RegExp(/filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/g);
// const matches = header.match(regex);
// let filename: string;
// for (let i = 0; i < matches.length; i++) {
// const match = matches[i];
// if (match.includes('filename="')) {
// filename = match.substring(10, match.length - 1);
// break;
// } else if (match.includes('filename=')) {
// filename = match.substring(9);
// break;
// }
// }
// return filename;
// }
FileSaver.saveAs(blob, filename);
});
}
// isExternalAutocomplete(formGroup: UntypedFormGroup) {
// if (formGroup.get('dataType').value == DmpBlueprintFieldDataType.ExternalAutocomplete) {
@ -792,4 +790,4 @@ export class DmpBlueprintEditorComponent extends BaseEditor<DmpBlueprintEditorMo
// if (formGroup.get('dataType').value != 3)
// formGroup.removeControl('externalAutocomplete');
// }
// }
}

View File

@ -182,7 +182,7 @@ export class DmpBlueprintListingComponent extends BaseListingComponent<DmpBluepr
// .pipe(takeUntil(this._destroyed))
// .subscribe(response => {
// const blob = new Blob([response.body], { type: 'application/xml' });
// const filename = this.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
// const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
// FileSaver.saveAs(blob, filename);
// });
}
@ -209,27 +209,10 @@ export class DmpBlueprintListingComponent extends BaseListingComponent<DmpBluepr
// .pipe(takeUntil(this._destroyed))
// .subscribe(response => {
// const blob = new Blob([response.body], { type: 'application/xml' });
// const filename = this.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
// const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
// FileSaver.saveAs(blob, filename);
// });
// }
// getFilenameFromContentDispositionHeader(header: string): string {
// const regex: RegExp = new RegExp(/filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/g);
// const matches = header.match(regex);
// let filename: string;
// for (let i = 0; i < matches.length; i++) {
// const match = matches[i];
// if (match.includes('filename="')) {
// filename = match.substring(10, match.length - 1);
// break;
// } else if (match.includes('filename=')) {
// filename = match.substring(9);
// break;
// }
// }
// return filename;
// }
// deleteTemplate(id: string) {
// if (id) {

View File

@ -18,6 +18,7 @@ import { UserCriteria } from '../../../../core/query/user/user-criteria';
import { UserService } from '../../../../core/services/user/user.service';
import { SnackBarNotificationComponent } from '../../../../library/notification/snack-bar/snack-bar-notification.component';
// import { BreadcrumbItem } from '../../../misc/breadcrumb/definition/breadcrumb-item';
import { FileUtils } from '@app/core/services/utilities/file-utils.service';
import { UserCriteriaComponent } from './criteria/user-criteria.component';
export class UsersDataSource extends DataSource<UserListingModel> {
@ -111,7 +112,8 @@ export class UserListingComponent extends BaseComponent implements OnInit, After
private languageService: TranslateService,
public snackBar: MatSnackBar,
private httpClient: HttpClient,
private matomoService: MatomoService
private matomoService: MatomoService,
private fileUtils: FileUtils
) {
super();
}
@ -151,29 +153,11 @@ export class UserListingComponent extends BaseComponent implements OnInit, After
.pipe(takeUntil(this._destroyed))
.subscribe(response => {
const blob = new Blob([response.body], { type: 'application/csv' });
const filename = this.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
FileSaver.saveAs(blob, filename);
});
}
getFilenameFromContentDispositionHeader(header: string): string {
const regex: RegExp = new RegExp(/filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/g);
const matches = header.match(regex);
let filename: string;
for (let i = 0; i < matches.length; i++) {
const match = matches[i];
if (match.includes('filename="')) {
filename = match.substring(10, match.length - 1);
break;
} else if (match.includes('filename=')) {
filename = match.substring(9);
break;
}
}
return filename;
}
public setDefaultAvatar(ev: Event) {
(ev.target as HTMLImageElement).src = 'assets/images/profile-placeholder.png';
}

View File

@ -1,50 +1,48 @@
import {Component, OnInit, Input, EventEmitter, Output, ViewChild} from '@angular/core';
import { DatasetService } from '../../../core/services/dataset/dataset.service';
import {DataTableMultiTypeRequest, DataTableRequest} from '../../../core/model/data-table/data-table-request';
import { DatasetCriteria } from '../../../core/query/dataset/dataset-criteria';
import { DatasetListingModel } from '../../../core/model/dataset/dataset-listing';
import { AuthService } from '../../../core/services/auth/auth.service';
import { RecentActivityType } from '../../../core/common/enum/recent-activity-type';
import {ActivatedRoute, Router} from '@angular/router';
import { DmpStatus } from '../../../core/common/enum/dmp-status';
import { TranslateService } from '@ngx-translate/core';
import {debounceTime, map, takeUntil} from 'rxjs/operators';
import { ConfirmationDialogComponent } from '@common/modules/confirmation-dialog/confirmation-dialog.component';
import { DatasetCopyDialogueComponent } from '@app/ui/dataset/dataset-wizard/dataset-copy-dialogue/dataset-copy-dialogue.component';
import {UntypedFormControl, UntypedFormBuilder, UntypedFormGroup} from '@angular/forms';
import { BaseComponent } from '@common/base/base.component';
import { MatDialog } from '@angular/material/dialog';
import { DatasetWizardService } from '@app/core/services/dataset-wizard/dataset-wizard.service';
import { SnackBarNotificationLevel } from '@app/core/services/notification/ui-notification-service';
import * as FileSaver from 'file-saver';
import { EnumUtils } from '@app/core/services/utilities/enum-utils.service';
import { UiNotificationService } from '@app/core/services/notification/ui-notification-service';
import { DmpInvitationDialogComponent } from '@app/ui/dmp/invitation/dmp-invitation-dialog.component';
import { RecentActivityOrder } from '@app/core/common/enum/recent-activity-order';
import { Location } from '@angular/common';
import { HttpClient } from '@angular/common/http';
import { Component, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core';
import { UntypedFormBuilder, UntypedFormControl, UntypedFormGroup } from '@angular/forms';
import { MatDialog } from '@angular/material/dialog';
import { ActivatedRoute, Router } from '@angular/router';
import { DmpBlueprintSystemFieldType } from '@app/core/common/enum/dmp-blueprint-system-field-type';
import { RecentActivityOrder } from '@app/core/common/enum/recent-activity-order';
import { Role } from '@app/core/common/enum/role';
import { DatasetUrlListing } from "@app/core/model/dataset/dataset-url-listing";
import { DmpBlueprintDefinition } from '@app/core/model/dmp-blueprint/dmp-blueprint';
import { DmpModel } from "@app/core/model/dmp/dmp";
import { DmpListingModel } from "@app/core/model/dmp/dmp-listing";
import { RecentActivityModel } from "@app/core/model/recent-activity/recent-activity.model";
import { RecentDatasetModel } from "@app/core/model/recent-activity/recent-dataset-activity.model";
import { RecentDmpModel } from "@app/core/model/recent-activity/recent-dmp-activity.model";
import { RecentActivityCriteria } from "@app/core/query/recent-activity/recent-activity-criteria";
import { DashboardService } from "@app/core/services/dashboard/dashboard.service";
import { DatasetWizardService } from '@app/core/services/dataset-wizard/dataset-wizard.service';
import { DmpBlueprintService } from '@app/core/services/dmp/dmp-blueprint.service';
import { DmpService } from "@app/core/services/dmp/dmp.service";
import { LockService } from '@app/core/services/lock/lock.service';
import { MatomoService } from '@app/core/services/matomo/matomo-service';
import { HttpClient } from '@angular/common/http';
import {RecentActivityModel} from "@app/core/model/recent-activity/recent-activity.model";
import { SnackBarNotificationLevel, UiNotificationService } from '@app/core/services/notification/ui-notification-service';
import { EnumUtils } from '@app/core/services/utilities/enum-utils.service';
import { FileUtils } from '@app/core/services/utilities/file-utils.service';
import { DatasetCopyDialogueComponent } from '@app/ui/dataset/dataset-wizard/dataset-copy-dialogue/dataset-copy-dialogue.component';
import { CloneDialogComponent } from "@app/ui/dmp/clone/clone-dialog/clone-dialog.component";
import { DmpEditorModel } from "@app/ui/dmp/editor/dmp-editor.model";
import {DmpService} from "@app/core/services/dmp/dmp.service";
import {DashboardService} from "@app/core/services/dashboard/dashboard.service";
import {RecentActivityCriteria} from "@app/core/query/recent-activity/recent-activity-criteria";
import {RecentDmpModel} from "@app/core/model/recent-activity/recent-dmp-activity.model";
import {DatasetUrlListing} from "@app/core/model/dataset/dataset-url-listing";
import {RecentDatasetModel} from "@app/core/model/recent-activity/recent-dataset-activity.model";
import {DmpListingModel} from "@app/core/model/dmp/dmp-listing";
import {DmpModel} from "@app/core/model/dmp/dmp";
import { ExtraPropertiesFormModel } from "@app/ui/dmp/editor/general-tab/extra-properties-form.model";
import { FunderFormModel } from "@app/ui/dmp/editor/grant-tab/funder-form-model";
import { GrantTabModel } from "@app/ui/dmp/editor/grant-tab/grant-tab-model";
import { ProjectFormModel } from "@app/ui/dmp/editor/grant-tab/project-form-model";
import {FunderFormModel} from "@app/ui/dmp/editor/grant-tab/funder-form-model";
import {ExtraPropertiesFormModel} from "@app/ui/dmp/editor/general-tab/extra-properties-form.model";
import {CloneDialogComponent} from "@app/ui/dmp/clone/clone-dialog/clone-dialog.component";
import { DmpInvitationDialogComponent } from '@app/ui/dmp/invitation/dmp-invitation-dialog.component';
import { isNullOrUndefined } from '@app/utilities/enhancers/utils';
import { DmpBlueprintService } from '@app/core/services/dmp/dmp-blueprint.service';
import { DmpBlueprintDefinition } from '@app/core/model/dmp-blueprint/dmp-blueprint';
import { DmpBlueprintSystemFieldType } from '@app/core/common/enum/dmp-blueprint-system-field-type';
import { BaseComponent } from '@common/base/base.component';
import { ConfirmationDialogComponent } from '@common/modules/confirmation-dialog/confirmation-dialog.component';
import { TranslateService } from '@ngx-translate/core';
import * as FileSaver from 'file-saver';
import { debounceTime, map, takeUntil } from 'rxjs/operators';
import { DmpStatus } from '../../../core/common/enum/dmp-status';
import { RecentActivityType } from '../../../core/common/enum/recent-activity-type';
import { DataTableMultiTypeRequest } from '../../../core/model/data-table/data-table-request';
import { DatasetListingModel } from '../../../core/model/dataset/dataset-listing';
import { AuthService } from '../../../core/services/auth/auth.service';
@Component({
selector: 'app-drafts',
@ -94,7 +92,8 @@ export class DraftsComponent extends BaseComponent implements OnInit {
private location: Location,
private lockService: LockService,
private httpClient: HttpClient,
private matomoService: MatomoService
private matomoService: MatomoService,
private fileUtils: FileUtils
) {
super();
}
@ -492,7 +491,7 @@ export class DraftsComponent extends BaseComponent implements OnInit {
.pipe(takeUntil(this._destroyed))
.subscribe(response => {
const blob = new Blob([response.body], { type: 'application/xml' });
const filename = this.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('dmps', "xml", id);
@ -504,7 +503,7 @@ export class DraftsComponent extends BaseComponent implements OnInit {
.pipe(takeUntil(this._destroyed))
.subscribe(response => {
const blob = new Blob([response.body], { type: 'application/msword' });
const filename = this.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('dmps', "docx", id);
@ -516,7 +515,7 @@ export class DraftsComponent extends BaseComponent implements OnInit {
.pipe(takeUntil(this._destroyed))
.subscribe(response => {
const blob = new Blob([response.body], { type: 'application/pdf' });
const filename = this.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('dmps', "pdf", id);
@ -528,7 +527,7 @@ export class DraftsComponent extends BaseComponent implements OnInit {
.pipe(takeUntil(this._destroyed))
.subscribe(response => {
const blob = new Blob([response.body], { type: 'application/json' });
const filename = this.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('dmps', "json", id);
}, async error => {
@ -547,7 +546,7 @@ export class DraftsComponent extends BaseComponent implements OnInit {
.pipe(takeUntil(this._destroyed))
.subscribe(response => {
const blob = new Blob([response.body], { type: 'application/pdf' });
const filename = this.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('datasets', "pdf", dataset.id);
@ -559,7 +558,7 @@ export class DraftsComponent extends BaseComponent implements OnInit {
.pipe(takeUntil(this._destroyed))
.subscribe(response => {
const blob = new Blob([response.body], { type: 'application/msword' });
const filename = this.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('datasets', "docx", dataset.id);
@ -572,31 +571,13 @@ export class DraftsComponent extends BaseComponent implements OnInit {
.pipe(takeUntil(this._destroyed))
.subscribe(response => {
const blob = new Blob([response.body], { type: 'application/xml' });
const filename = this.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('datasets', "xml", dataset.id);
});
}
getFilenameFromContentDispositionHeader(header: string): string {
const regex: RegExp = new RegExp(/filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/g);
const matches = header.match(regex);
let filename: string;
for (let i = 0; i < matches.length; i++) {
const match = matches[i];
if (match.includes('filename="')) {
filename = match.substring(10, match.length - 1);
break;
} else if (match.includes('filename=')) {
filename = match.substring(9);
break;
}
}
return filename;
}
viewVersions(rowId: String, rowLabel: String, activity: DmpListingModel) {
if (activity.public && !this.isUserOwner(activity)) {
let url = this.router.createUrlTree(['/explore-plans/versions/', rowId, { groupLabel: rowLabel }]);

View File

@ -1,52 +1,50 @@
import {Component, OnInit, Output, EventEmitter, Input, ViewChild} from '@angular/core';
import { Location } from '@angular/common';
import { HttpClient } from '@angular/common/http';
import { Component, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core';
import { UntypedFormBuilder, UntypedFormControl, UntypedFormGroup } from '@angular/forms';
import { MatDialog } from '@angular/material/dialog';
import { ActivatedRoute, Router } from '@angular/router';
import { DmpBlueprintSystemFieldType } from '@app/core/common/enum/dmp-blueprint-system-field-type';
import { DmpStatus } from '@app/core/common/enum/dmp-status';
import { RecentActivityOrder } from '@app/core/common/enum/recent-activity-order';
import { RecentActivityType } from '@app/core/common/enum/recent-activity-type';
import { DataTableRequest, DataTableMultiTypeRequest } from '@app/core/model/data-table/data-table-request';
import { Role } from '@app/core/common/enum/role';
import { DataTableMultiTypeRequest } from '@app/core/model/data-table/data-table-request';
import { DatasetListingModel } from '@app/core/model/dataset/dataset-listing';
import { DatasetUrlListing } from '@app/core/model/dataset/dataset-url-listing';
import { DescriptionTemplatesInSection, DmpBlueprint, DmpBlueprintDefinition, DmpBlueprintDefinitionSection, FieldInSection } from '@app/core/model/dmp-blueprint/dmp-blueprint';
import { DmpModel } from '@app/core/model/dmp/dmp';
import { DmpListingModel } from '@app/core/model/dmp/dmp-listing';
import { DmpCriteria } from '@app/core/query/dmp/dmp-criteria';
import { RecentActivityModel } from '@app/core/model/recent-activity/recent-activity.model';
import { RecentDatasetModel } from '@app/core/model/recent-activity/recent-dataset-activity.model';
import { RecentDmpModel } from '@app/core/model/recent-activity/recent-dmp-activity.model';
import { RecentActivityCriteria } from '@app/core/query/recent-activity/recent-activity-criteria';
import { AuthService } from '@app/core/services/auth/auth.service';
import { DashboardService } from '@app/core/services/dashboard/dashboard.service';
import { DatasetWizardService } from '@app/core/services/dataset-wizard/dataset-wizard.service';
import { DmpBlueprintService } from '@app/core/services/dmp/dmp-blueprint.service';
import { DmpService } from '@app/core/services/dmp/dmp.service';
import { LockService } from '@app/core/services/lock/lock.service';
import { MatomoService } from '@app/core/services/matomo/matomo-service';
import { SnackBarNotificationLevel, UiNotificationService } from '@app/core/services/notification/ui-notification-service';
import { EnumUtils } from '@app/core/services/utilities/enum-utils.service';
import { ConfirmationDialogComponent } from '@common/modules/confirmation-dialog/confirmation-dialog.component';
import { BaseComponent } from '@common/base/base.component';
import { TranslateService } from '@ngx-translate/core';
import * as FileSaver from 'file-saver';
import { takeUntil, map, debounceTime } from 'rxjs/operators';
import { DmpInvitationDialogComponent } from '@app/ui/dmp/invitation/dmp-invitation-dialog.component';
import { DmpStatus } from '@app/core/common/enum/dmp-status';
import { DatasetService } from '@app/core/services/dataset/dataset.service';
import { DatasetListingModel } from '@app/core/model/dataset/dataset-listing';
import { Role } from '@app/core/common/enum/role';
import { RecentActivityModel } from '@app/core/model/recent-activity/recent-activity.model';
import { DashboardService } from '@app/core/services/dashboard/dashboard.service';
import { RecentActivityCriteria } from '@app/core/query/recent-activity/recent-activity-criteria';
import { RecentDmpModel } from '@app/core/model/recent-activity/recent-dmp-activity.model';
import { RecentDatasetModel } from '@app/core/model/recent-activity/recent-dataset-activity.model';
import { UserInfoListingModel } from '@app/core/model/user/user-info-listing';
import { DatasetWizardService } from '@app/core/services/dataset-wizard/dataset-wizard.service';
import { UntypedFormControl, UntypedFormBuilder, UntypedFormGroup } from '@angular/forms';
import { FileUtils } from '@app/core/services/utilities/file-utils.service';
import { DatasetCopyDialogueComponent } from '@app/ui/dataset/dataset-wizard/dataset-copy-dialogue/dataset-copy-dialogue.component';
import { RecentActivityOrder } from '@app/core/common/enum/recent-activity-order';
import { Location } from '@angular/common';
import { LockService } from '@app/core/services/lock/lock.service';
import { DatasetUrlListing } from '@app/core/model/dataset/dataset-url-listing';
import { CloneDialogComponent } from '@app/ui/dmp/clone/clone-dialog/clone-dialog.component';
import { DmpEditorModel } from '@app/ui/dmp/editor/dmp-editor.model';
import { ExtraPropertiesFormModel } from '@app/ui/dmp/editor/general-tab/extra-properties-form.model';
import { FunderFormModel } from '@app/ui/dmp/editor/grant-tab/funder-form-model';
import { GrantTabModel } from '@app/ui/dmp/editor/grant-tab/grant-tab-model';
import { ProjectFormModel } from '@app/ui/dmp/editor/grant-tab/project-form-model';
import { FunderFormModel } from '@app/ui/dmp/editor/grant-tab/funder-form-model';
import { ExtraPropertiesFormModel } from '@app/ui/dmp/editor/general-tab/extra-properties-form.model';
import { DmpModel } from '@app/core/model/dmp/dmp';
import { CloneDialogComponent } from '@app/ui/dmp/clone/clone-dialog/clone-dialog.component';
import { MatomoService } from '@app/core/services/matomo/matomo-service';
import { HttpClient } from '@angular/common/http';
import { DmpInvitationDialogComponent } from '@app/ui/dmp/invitation/dmp-invitation-dialog.component';
import { isNullOrUndefined } from '@app/utilities/enhancers/utils';
import { DmpBlueprintService } from '@app/core/services/dmp/dmp-blueprint.service';
import { DmpBlueprintSystemFieldType } from '@app/core/common/enum/dmp-blueprint-system-field-type';
import { DescriptionTemplatesInSection, DmpBlueprint, DmpBlueprintDefinition, DmpBlueprintDefinitionSection, FieldInSection } from '@app/core/model/dmp-blueprint/dmp-blueprint';
import { nameof } from 'ts-simple-nameof';
import { BaseComponent } from '@common/base/base.component';
import { ConfirmationDialogComponent } from '@common/modules/confirmation-dialog/confirmation-dialog.component';
import { Guid } from '@common/types/guid';
import { TranslateService } from '@ngx-translate/core';
import * as FileSaver from 'file-saver';
import { debounceTime, map, takeUntil } from 'rxjs/operators';
import { nameof } from 'ts-simple-nameof';
@Component({
selector: 'app-recent-edited-activity',
@ -96,7 +94,8 @@ export class RecentEditedActivityComponent extends BaseComponent implements OnIn
private location: Location,
private lockService: LockService,
private httpClient: HttpClient,
private matomoService: MatomoService
private matomoService: MatomoService,
private fileUtils: FileUtils
) {
super();
}
@ -596,7 +595,7 @@ export class RecentEditedActivityComponent extends BaseComponent implements OnIn
.pipe(takeUntil(this._destroyed))
.subscribe(response => {
const blob = new Blob([response.body], { type: 'application/xml' });
const filename = this.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('dmps', "xml", id);
@ -608,7 +607,7 @@ export class RecentEditedActivityComponent extends BaseComponent implements OnIn
.pipe(takeUntil(this._destroyed))
.subscribe(response => {
const blob = new Blob([response.body], { type: 'application/msword' });
const filename = this.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('dmps', "docx", id);
@ -620,7 +619,7 @@ export class RecentEditedActivityComponent extends BaseComponent implements OnIn
.pipe(takeUntil(this._destroyed))
.subscribe(response => {
const blob = new Blob([response.body], { type: 'application/pdf' });
const filename = this.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('dmps', "pdf", id);
@ -632,7 +631,7 @@ export class RecentEditedActivityComponent extends BaseComponent implements OnIn
.pipe(takeUntil(this._destroyed))
.subscribe(response => {
const blob = new Blob([response.body], { type: 'application/json' });
const filename = this.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('dmps', "json", id);
}, async error => {
@ -651,7 +650,7 @@ export class RecentEditedActivityComponent extends BaseComponent implements OnIn
.pipe(takeUntil(this._destroyed))
.subscribe(response => {
const blob = new Blob([response.body], { type: 'application/pdf' });
const filename = this.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('datasets', "pdf", dataset.id);
@ -663,7 +662,7 @@ export class RecentEditedActivityComponent extends BaseComponent implements OnIn
.pipe(takeUntil(this._destroyed))
.subscribe(response => {
const blob = new Blob([response.body], { type: 'application/msword' });
const filename = this.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('datasets', "docx", dataset.id);
@ -676,31 +675,13 @@ export class RecentEditedActivityComponent extends BaseComponent implements OnIn
.pipe(takeUntil(this._destroyed))
.subscribe(response => {
const blob = new Blob([response.body], { type: 'application/xml' });
const filename = this.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('datasets', "xml", dataset.id);
});
}
getFilenameFromContentDispositionHeader(header: string): string {
const regex: RegExp = new RegExp(/filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/g);
const matches = header.match(regex);
let filename: string;
for (let i = 0; i < matches.length; i++) {
const match = matches[i];
if (match.includes('filename="')) {
filename = match.substring(10, match.length - 1);
break;
} else if (match.includes('filename=')) {
filename = match.substring(9);
break;
}
}
return filename;
}
// newVersion(id: String, label: String) {
// let url = this.router.createUrlTree(['/plans/new_version/', id, { dmpLabel: label }]);
// window.open(url.toString(), '_blank');

View File

@ -1,31 +1,32 @@
import {Component, OnInit, Output, EventEmitter, Input, ViewChild} from '@angular/core';
import { DatasetListingModel } from '@app/core/model/dataset/dataset-listing';
import { DatasetService } from '@app/core/services/dataset/dataset.service';
import { DataTableRequest } from '@app/core/model/data-table/data-table-request';
import { DatasetCriteria } from '@app/core/query/dataset/dataset-criteria';
import { AuthService } from '@app/core/services/auth/auth.service';
import { BaseComponent } from '@common/base/base.component';
import { TranslateService } from '@ngx-translate/core';
import { EnumUtils } from '@app/core/services/utilities/enum-utils.service';
import { UntypedFormControl, UntypedFormBuilder } from '@angular/forms';
import { DatasetCopyDialogueComponent } from '@app/ui/dataset/dataset-wizard/dataset-copy-dialogue/dataset-copy-dialogue.component';
import { Location } from '@angular/common';
import { HttpClient } from '@angular/common/http';
import { Component, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core';
import { UntypedFormBuilder, UntypedFormControl } from '@angular/forms';
import { MatDialog } from '@angular/material/dialog';
import { debounceTime, takeUntil } from 'rxjs/operators';
import { ActivatedRoute, Router } from '@angular/router';
import { DatasetWizardService } from '@app/core/services/dataset-wizard/dataset-wizard.service';
import * as FileSaver from 'file-saver';
import { ConfirmationDialogComponent } from '@common/modules/confirmation-dialog/confirmation-dialog.component';
import { ValidationErrorModel } from '@common/forms/validation/error-model/validation-error-model';
import { SnackBarNotificationLevel, UiNotificationService } from '@app/core/services/notification/ui-notification-service';
import { DatasetStatus } from '@app/core/common/enum/dataset-status';
import { DmpInvitationDialogComponent } from '@app/ui/dmp/invitation/dmp-invitation-dialog.component';
import { RecentActivityOrder } from '@app/core/common/enum/recent-activity-order';
import { Role } from '@app/core/common/enum/role';
import { Location } from '@angular/common';
import { DataTableRequest } from '@app/core/model/data-table/data-table-request';
import { DatasetListingModel } from '@app/core/model/dataset/dataset-listing';
import { DatasetCriteria } from '@app/core/query/dataset/dataset-criteria';
import { AuthService } from '@app/core/services/auth/auth.service';
import { ConfigurationService } from "@app/core/services/configuration/configuration.service";
import { DatasetWizardService } from '@app/core/services/dataset-wizard/dataset-wizard.service';
import { DatasetService } from '@app/core/services/dataset/dataset.service';
import { LockService } from '@app/core/services/lock/lock.service';
import { MatomoService } from '@app/core/services/matomo/matomo-service';
import { HttpClient } from '@angular/common/http';
import {ConfigurationService} from "@app/core/services/configuration/configuration.service";
import { SnackBarNotificationLevel, UiNotificationService } from '@app/core/services/notification/ui-notification-service';
import { EnumUtils } from '@app/core/services/utilities/enum-utils.service';
import { FileUtils } from '@app/core/services/utilities/file-utils.service';
import { DatasetCopyDialogueComponent } from '@app/ui/dataset/dataset-wizard/dataset-copy-dialogue/dataset-copy-dialogue.component';
import { DmpInvitationDialogComponent } from '@app/ui/dmp/invitation/dmp-invitation-dialog.component';
import { BaseComponent } from '@common/base/base.component';
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 * as FileSaver from 'file-saver';
import { debounceTime, takeUntil } from 'rxjs/operators';
@Component({
selector: 'app-recent-edited-dataset-activity',
@ -69,7 +70,8 @@ export class RecentEditedDatasetActivityComponent extends BaseComponent implemen
private lockService: LockService,
private httpClient: HttpClient,
private matomoService: MatomoService,
private configurationService: ConfigurationService
private configurationService: ConfigurationService,
private fileUtils: FileUtils
) {
super();
}
@ -384,30 +386,12 @@ export class RecentEditedDatasetActivityComponent extends BaseComponent implemen
});
}
getFilenameFromContentDispositionHeader(header: string): string {
const regex: RegExp = new RegExp(/filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/g);
const matches = header.match(regex);
let filename: string;
for (let i = 0; i < matches.length; i++) {
const match = matches[i];
if (match.includes('filename="')) {
filename = match.substring(10, match.length - 1);
break;
} else if (match.includes('filename=')) {
filename = match.substring(9);
break;
}
}
return filename;
}
downloadPDF(dataset: DatasetListingModel): void {
this.datasetWizardService.downloadPDF(dataset.id as string)
.pipe(takeUntil(this._destroyed))
.subscribe(response => {
const blob = new Blob([response.body], { type: 'application/pdf' });
const filename = this.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('datasets', "pdf", dataset.id);
@ -419,7 +403,7 @@ export class RecentEditedDatasetActivityComponent extends BaseComponent implemen
.pipe(takeUntil(this._destroyed))
.subscribe(response => {
const blob = new Blob([response.body], { type: 'application/msword' });
const filename = this.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('datasets', "docx", dataset.id);
@ -432,7 +416,7 @@ export class RecentEditedDatasetActivityComponent extends BaseComponent implemen
.pipe(takeUntil(this._destroyed))
.subscribe(response => {
const blob = new Blob([response.body], { type: 'application/xml' });
const filename = this.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('datasets', "xml", dataset.id);

View File

@ -1,43 +1,43 @@
import {Component, OnInit, Output, EventEmitter, Input, ViewChild} from '@angular/core';
import { Location } from '@angular/common';
import { HttpClient } from '@angular/common/http';
import { Component, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core';
import { UntypedFormBuilder, UntypedFormControl, UntypedFormGroup } from '@angular/forms';
import { MatDialog } from '@angular/material/dialog';
import { ActivatedRoute, Router } from '@angular/router';
import { DmpBlueprintSystemFieldType } from '@app/core/common/enum/dmp-blueprint-system-field-type';
import { DmpStatus } from '@app/core/common/enum/dmp-status';
import { RecentActivityOrder } from '@app/core/common/enum/recent-activity-order';
import { RecentActivityType } from '@app/core/common/enum/recent-activity-type';
import { Role } from '@app/core/common/enum/role';
import { DataTableRequest } from '@app/core/model/data-table/data-table-request';
import { DatasetListingModel } from '@app/core/model/dataset/dataset-listing';
import { DescriptionTemplatesInSection, DmpBlueprint, DmpBlueprintDefinition, DmpBlueprintDefinitionSection, FieldInSection } from '@app/core/model/dmp-blueprint/dmp-blueprint';
import { DmpModel } from '@app/core/model/dmp/dmp';
import { DmpListingModel } from '@app/core/model/dmp/dmp-listing';
import { DmpCriteria } from '@app/core/query/dmp/dmp-criteria';
import { AuthService } from '@app/core/services/auth/auth.service';
import { DatasetService } from '@app/core/services/dataset/dataset.service';
import { DmpBlueprintService } from '@app/core/services/dmp/dmp-blueprint.service';
import { DmpService } from '@app/core/services/dmp/dmp.service';
import { LockService } from '@app/core/services/lock/lock.service';
import { MatomoService } from '@app/core/services/matomo/matomo-service';
import { SnackBarNotificationLevel, UiNotificationService } from '@app/core/services/notification/ui-notification-service';
import { EnumUtils } from '@app/core/services/utilities/enum-utils.service';
import { ConfirmationDialogComponent } from '@common/modules/confirmation-dialog/confirmation-dialog.component';
import { BaseComponent } from '@common/base/base.component';
import { TranslateService } from '@ngx-translate/core';
import * as FileSaver from 'file-saver';
import { takeUntil, map, debounceTime } from 'rxjs/operators';
import { DmpInvitationDialogComponent } from '@app/ui/dmp/invitation/dmp-invitation-dialog.component';
import { DmpStatus } from '@app/core/common/enum/dmp-status';
import { DatasetService } from '@app/core/services/dataset/dataset.service';
import { DatasetListingModel } from '@app/core/model/dataset/dataset-listing';
import { Role } from '@app/core/common/enum/role';
import { UntypedFormBuilder, UntypedFormControl, UntypedFormGroup } from '@angular/forms';
import { RecentActivityOrder } from '@app/core/common/enum/recent-activity-order';
import { Location } from '@angular/common';
import { LockService } from '@app/core/services/lock/lock.service';
import { ExploreDmpCriteriaModel } from '@app/core/query/explore-dmp/explore-dmp-criteria';
import { DmpModel } from '@app/core/model/dmp/dmp';
import { FileUtils } from '@app/core/services/utilities/file-utils.service';
import { CloneDialogComponent } from '@app/ui/dmp/clone/clone-dialog/clone-dialog.component';
import { DmpEditorModel } from '@app/ui/dmp/editor/dmp-editor.model';
import { GrantTabModel } from '@app/ui/dmp/editor/grant-tab/grant-tab-model';
import { ExtraPropertiesFormModel } from '@app/ui/dmp/editor/general-tab/extra-properties-form.model';
import { FunderFormModel } from '@app/ui/dmp/editor/grant-tab/funder-form-model';
import { GrantTabModel } from '@app/ui/dmp/editor/grant-tab/grant-tab-model';
import { ProjectFormModel } from '@app/ui/dmp/editor/grant-tab/project-form-model';
import { MatomoService } from '@app/core/services/matomo/matomo-service';
import { HttpClient } from '@angular/common/http';
import { DmpInvitationDialogComponent } from '@app/ui/dmp/invitation/dmp-invitation-dialog.component';
import { isNullOrUndefined } from '@app/utilities/enhancers/utils';
import { DmpBlueprintService } from '@app/core/services/dmp/dmp-blueprint.service';
import { DmpBlueprintSystemFieldType } from '@app/core/common/enum/dmp-blueprint-system-field-type';
import { DescriptionTemplatesInSection, DmpBlueprint, DmpBlueprintDefinition, DmpBlueprintDefinitionSection, FieldInSection } from '@app/core/model/dmp-blueprint/dmp-blueprint';
import { BaseComponent } from '@common/base/base.component';
import { ConfirmationDialogComponent } from '@common/modules/confirmation-dialog/confirmation-dialog.component';
import { Guid } from '@common/types/guid';
import { TranslateService } from '@ngx-translate/core';
import * as FileSaver from 'file-saver';
import { debounceTime, map, takeUntil } from 'rxjs/operators';
import { nameof } from 'ts-simple-nameof';
@Component({
@ -88,7 +88,8 @@ export class RecentEditedDmpActivityComponent extends BaseComponent implements O
private location: Location,
private lockService: LockService,
private httpClient: HttpClient,
private matomoService: MatomoService
private matomoService: MatomoService,
private fileUtils: FileUtils
) {
super();
}
@ -522,7 +523,7 @@ export class RecentEditedDmpActivityComponent extends BaseComponent implements O
.pipe(takeUntil(this._destroyed))
.subscribe(response => {
const blob = new Blob([response.body], { type: 'application/xml' });
const filename = this.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('dmps', "xml", id);
@ -534,7 +535,7 @@ export class RecentEditedDmpActivityComponent extends BaseComponent implements O
.pipe(takeUntil(this._destroyed))
.subscribe(response => {
const blob = new Blob([response.body], { type: 'application/msword' });
const filename = this.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('dmps', "docx", id);
@ -546,7 +547,7 @@ export class RecentEditedDmpActivityComponent extends BaseComponent implements O
.pipe(takeUntil(this._destroyed))
.subscribe(response => {
const blob = new Blob([response.body], { type: 'application/pdf' });
const filename = this.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('dmps', "pdf", id);
@ -558,7 +559,7 @@ export class RecentEditedDmpActivityComponent extends BaseComponent implements O
.pipe(takeUntil(this._destroyed))
.subscribe(response => {
const blob = new Blob([response.body], { type: 'application/json' });
const filename = this.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('dmps', "json", id);
}, async error => {
@ -572,24 +573,6 @@ export class RecentEditedDmpActivityComponent extends BaseComponent implements O
this.uiNotificationService.snackBarNotification(errorObj.message, SnackBarNotificationLevel.Error);
}
getFilenameFromContentDispositionHeader(header: string): string {
const regex: RegExp = new RegExp(/filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/g);
const matches = header.match(regex);
let filename: string;
for (let i = 0; i < matches.length; i++) {
const match = matches[i];
if (match.includes('filename="')) {
filename = match.substring(10, match.length - 1);
break;
} else if (match.includes('filename=')) {
filename = match.substring(9);
break;
}
}
return filename;
}
// newVersion(id: String, label: String) {
// let url = this.router.createUrlTree(['/plans/new_version/', id, { dmpLabel: label }]);
// window.open(url.toString(), '_blank');

View File

@ -32,6 +32,7 @@ import {
SnackBarNotificationLevel,
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';
@ -141,7 +142,8 @@ export class DatasetWizardComponent extends CheckDeactivateBaseComponent impleme
private authService: AuthService,
private configurationService: ConfigurationService,
private httpClient: HttpClient,
private matomoService: MatomoService
private matomoService: MatomoService,
private fileUtils: FileUtils
) {
super();
}
@ -1026,7 +1028,7 @@ export class DatasetWizardComponent extends CheckDeactivateBaseComponent impleme
.pipe(takeUntil(this._destroyed))
.subscribe(response => {
const blob = new Blob([response.body], { type: 'application/pdf' });
const filename = this.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('datasets', "pdf", id);
@ -1038,7 +1040,7 @@ export class DatasetWizardComponent extends CheckDeactivateBaseComponent impleme
.pipe(takeUntil(this._destroyed))
.subscribe(response => {
const blob = new Blob([response.body], { type: 'application/msword' });
const filename = this.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('datasets', "docx", id);
@ -1051,7 +1053,7 @@ export class DatasetWizardComponent extends CheckDeactivateBaseComponent impleme
.pipe(takeUntil(this._destroyed))
.subscribe(response => {
const blob = new Blob([response.body], { type: 'application/xml' });
const filename = this.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('datasets', "xml", id);
@ -1079,24 +1081,6 @@ export class DatasetWizardComponent extends CheckDeactivateBaseComponent impleme
// });
// }
getFilenameFromContentDispositionHeader(header: string): string {
const regex: RegExp = new RegExp(/filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/g);
const matches = header.match(regex);
let filename: string;
for (let i = 0; i < matches.length; i++) {
const match = matches[i];
if (match.includes('filename="')) {
filename = match.substring(10, match.length - 1);
break;
} else if (match.includes('filename=')) {
filename = match.substring(9);
break;
}
}
return filename;
}
public redirectToGrant() {
this.router.navigate(['grants/edit/' + this.datasetWizardModel.dmp.grant.id]);
}

View File

@ -1,26 +1,26 @@
import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
import { DatasetListingModel } from '../../../../core/model/dataset/dataset-listing';
import { Router } from '@angular/router';
import { DatasetStatus } from '../../../../core/common/enum/dataset-status';
import { EnumUtils } from '@app/core/services/utilities/enum-utils.service';
import { DatasetWizardService } from '@app/core/services/dataset-wizard/dataset-wizard.service';
import { BaseComponent } from '@common/base/base.component';
import { takeUntil } from 'rxjs/operators';
import * as FileSaver from 'file-saver';
import { DmpInvitationDialogComponent } from '@app/ui/dmp/invitation/dmp-invitation-dialog.component';
import { MatDialog } from '@angular/material/dialog';
import { DatasetCopyDialogueComponent } from '../../dataset-wizard/dataset-copy-dialogue/dataset-copy-dialogue.component';
import { UntypedFormControl } from '@angular/forms';
import { TranslateService } from '@ngx-translate/core';
import { ConfirmationDialogComponent } from '@common/modules/confirmation-dialog/confirmation-dialog.component';
import { UiNotificationService, SnackBarNotificationLevel } from '@app/core/services/notification/ui-notification-service';
import { ValidationErrorModel } from '@common/forms/validation/error-model/validation-error-model';
import { AuthService } from '@app/core/services/auth/auth.service';
import { LockService } from '@app/core/services/lock/lock.service';
import { Role } from '@app/core/common/enum/role';
import { Location } from '@angular/common';
import { MatomoService } from '@app/core/services/matomo/matomo-service';
import { HttpClient } from '@angular/common/http';
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
import { UntypedFormControl } from '@angular/forms';
import { MatDialog } from '@angular/material/dialog';
import { Router } from '@angular/router';
import { Role } from '@app/core/common/enum/role';
import { AuthService } from '@app/core/services/auth/auth.service';
import { DatasetWizardService } from '@app/core/services/dataset-wizard/dataset-wizard.service';
import { LockService } from '@app/core/services/lock/lock.service';
import { MatomoService } from '@app/core/services/matomo/matomo-service';
import { SnackBarNotificationLevel, UiNotificationService } from '@app/core/services/notification/ui-notification-service';
import { EnumUtils } from '@app/core/services/utilities/enum-utils.service';
import { FileUtils } from '@app/core/services/utilities/file-utils.service';
import { DmpInvitationDialogComponent } from '@app/ui/dmp/invitation/dmp-invitation-dialog.component';
import { BaseComponent } from '@common/base/base.component';
import { ConfirmationDialogComponent } from '@common/modules/confirmation-dialog/confirmation-dialog.component';
import { TranslateService } from '@ngx-translate/core';
import * as FileSaver from 'file-saver';
import { takeUntil } from 'rxjs/operators';
import { DatasetStatus } from '../../../../core/common/enum/dataset-status';
import { DatasetListingModel } from '../../../../core/model/dataset/dataset-listing';
import { DatasetCopyDialogueComponent } from '../../dataset-wizard/dataset-copy-dialogue/dataset-copy-dialogue.component';
@Component({
selector: 'app-dataset-listing-item-component',
@ -49,7 +49,8 @@ export class DatasetListingItemComponent extends BaseComponent implements OnInit
private lockService: LockService,
private location: Location,
private httpClient: HttpClient,
private matomoService: MatomoService
private matomoService: MatomoService,
private fileUtils: FileUtils
) {
super();
}
@ -95,7 +96,7 @@ export class DatasetListingItemComponent extends BaseComponent implements OnInit
.pipe(takeUntil(this._destroyed))
.subscribe(response => {
const blob = new Blob([response.body], { type: 'application/pdf' });
const filename = this.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('datasets', "pdf", dataset.id);
@ -107,7 +108,7 @@ export class DatasetListingItemComponent extends BaseComponent implements OnInit
.pipe(takeUntil(this._destroyed))
.subscribe(response => {
const blob = new Blob([response.body], { type: 'application/msword' });
const filename = this.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('datasets', "docx", dataset.id);
@ -120,31 +121,13 @@ export class DatasetListingItemComponent extends BaseComponent implements OnInit
.pipe(takeUntil(this._destroyed))
.subscribe(response => {
const blob = new Blob([response.body], { type: 'application/xml' });
const filename = this.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('datasets', "xml", dataset.id);
});
}
getFilenameFromContentDispositionHeader(header: string): string {
const regex: RegExp = new RegExp(/filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/g);
const matches = header.match(regex);
let filename: string;
for (let i = 0; i < matches.length; i++) {
const match = matches[i];
if (match.includes('filename="')) {
filename = match.substring(10, match.length - 1);
break;
} else if (match.includes('filename=')) {
filename = match.substring(9);
break;
}
}
return filename;
}
openShareDialog(dmpRowId: any, dmpRowName: any) {
const dialogRef = this.dialog.open(DmpInvitationDialogComponent, {
// height: '250px',

View File

@ -1,38 +1,37 @@
import { Component, OnInit } from '@angular/core';
import { BaseComponent } from '@common/base/base.component';
import { DatasetOverviewModel } from '@app/core/model/dataset/dataset-overview';
import { BaseComponent } from '@common/base/base.component';
// import { BreadcrumbItem } from '@app/ui/misc/breadcrumb/definition/breadcrumb-item';
import { Observable, of as observableOf } from 'rxjs';
import { ActivatedRoute, Router, Params } from '@angular/router';
import { DatasetService } from '@app/core/services/dataset/dataset.service';
import { TranslateService } from '@ngx-translate/core';
import { AuthService } from '@app/core/services/auth/auth.service';
import { MatDialog } from '@angular/material/dialog';
import { SnackBarNotificationLevel, UiNotificationService } from '@app/core/services/notification/ui-notification-service';
import { ConfigurationService } from '@app/core/services/configuration/configuration.service';
import { Oauth2DialogService } from '@app/ui/misc/oauth2-dialog/service/oauth2-dialog.service';
import { UserService } from '@app/core/services/user/user.service';
import { filter, takeUntil } from 'rxjs/operators';
import { Role } from '@app/core/common/enum/role';
import { Location } from '@angular/common';
import { UserInfoListingModel } from '@app/core/model/user/user-info-listing';
import { DatasetStatus } from '@app/core/common/enum/dataset-status';
import { ConfirmationDialogComponent } from '@common/modules/confirmation-dialog/confirmation-dialog.component';
import * as FileSaver from 'file-saver';
import { DmpInvitationDialogComponent } from '@app/ui/dmp/invitation/dmp-invitation-dialog.component';
import { DatasetWizardEditorModel } from '../dataset-wizard/dataset-wizard-editor.model';
import { DatasetWizardService } from '@app/core/services/dataset-wizard/dataset-wizard.service';
import { UntypedFormControl } from '@angular/forms';
import { DatasetCopyDialogueComponent } from '../dataset-wizard/dataset-copy-dialogue/dataset-copy-dialogue.component';
import { DmpService } from '@app/core/services/dmp/dmp.service';
import { ResearcherModel } from '@app/core/model/researcher/researcher';
import { LockService } from '@app/core/services/lock/lock.service';
import { DatasetWizardModel } from '@app/core/model/dataset/dataset-wizard';
import { DmpStatus } from '@app/core/common/enum/dmp-status';
import { DmpOverviewModel } from '@app/core/model/dmp/dmp-overview';
import { MatomoService } from '@app/core/services/matomo/matomo-service';
import { HttpClient } from '@angular/common/http';
import { UntypedFormControl } from '@angular/forms';
import { MatDialog } from '@angular/material/dialog';
import { ActivatedRoute, Params, Router } from '@angular/router';
import { DatasetStatus } from '@app/core/common/enum/dataset-status';
import { DmpStatus } from '@app/core/common/enum/dmp-status';
import { Role } from '@app/core/common/enum/role';
import { DatasetWizardModel } from '@app/core/model/dataset/dataset-wizard';
import { DmpOverviewModel } from '@app/core/model/dmp/dmp-overview';
import { ResearcherModel } from '@app/core/model/researcher/researcher';
import { UserInfoListingModel } from '@app/core/model/user/user-info-listing';
import { AuthService } from '@app/core/services/auth/auth.service';
import { ConfigurationService } from '@app/core/services/configuration/configuration.service';
import { DatasetWizardService } from '@app/core/services/dataset-wizard/dataset-wizard.service';
import { DatasetService } from '@app/core/services/dataset/dataset.service';
import { DmpService } from '@app/core/services/dmp/dmp.service';
import { LockService } from '@app/core/services/lock/lock.service';
import { MatomoService } from '@app/core/services/matomo/matomo-service';
import { SnackBarNotificationLevel, UiNotificationService } from '@app/core/services/notification/ui-notification-service';
import { UserService } from '@app/core/services/user/user.service';
import { FileUtils } from '@app/core/services/utilities/file-utils.service';
import { PopupNotificationDialogComponent } from '@app/library/notification/popup/popup-notification.component';
import { DmpInvitationDialogComponent } from '@app/ui/dmp/invitation/dmp-invitation-dialog.component';
import { Oauth2DialogService } from '@app/ui/misc/oauth2-dialog/service/oauth2-dialog.service';
import { ConfirmationDialogComponent } from '@common/modules/confirmation-dialog/confirmation-dialog.component';
import { TranslateService } from '@ngx-translate/core';
import * as FileSaver from 'file-saver';
import { filter, takeUntil } from 'rxjs/operators';
import { DatasetCopyDialogueComponent } from '../dataset-wizard/dataset-copy-dialogue/dataset-copy-dialogue.component';
@Component({
@ -73,7 +72,8 @@ export class DatasetOverviewComponent extends BaseComponent implements OnInit {
private datasetWizardService: DatasetWizardService,
private lockService: LockService,
private httpClient: HttpClient,
private matomoService: MatomoService
private matomoService: MatomoService,
private fileUtils: FileUtils
) {
super();
}
@ -141,10 +141,12 @@ export class DatasetOverviewComponent extends BaseComponent implements OnInit {
.subscribe(lockStatus => {
this.lockStatus = lockStatus
if (lockStatus) {
this.dialog.open(PopupNotificationDialogComponent,{data:{
this.dialog.open(PopupNotificationDialogComponent, {
data: {
title: this.language.instant('DATASET-OVERVIEW.LOCKED.TITLE'),
message: this.language.instant('DATASET-OVERVIEW.LOCKED.MESSAGE')
}, maxWidth:'30em'});
}, maxWidth: '30em'
});
}
});
}
@ -335,7 +337,7 @@ export class DatasetOverviewComponent extends BaseComponent implements OnInit {
.pipe(takeUntil(this._destroyed))
.subscribe(response => {
const blob = new Blob([response.body], { type: 'application/pdf' });
const filename = this.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('datasets', "pdf", id);
@ -347,7 +349,7 @@ export class DatasetOverviewComponent extends BaseComponent implements OnInit {
.pipe(takeUntil(this._destroyed))
.subscribe(response => {
const blob = new Blob([response.body], { type: 'application/msword' });
const filename = this.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('datasets', "docx", id);
@ -359,7 +361,7 @@ export class DatasetOverviewComponent extends BaseComponent implements OnInit {
.pipe(takeUntil(this._destroyed))
.subscribe(response => {
const blob = new Blob([response.body], { type: 'application/xml' });
const filename = this.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('datasets', "xml", id);
@ -372,29 +374,11 @@ export class DatasetOverviewComponent extends BaseComponent implements OnInit {
// .pipe(takeUntil(this._destroyed))
// .subscribe(response => {
// const blob = new Blob([response.body], { type: 'application/json' });
// const filename = this.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
// const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
// FileSaver.saveAs(blob, filename);
// })
// }
getFilenameFromContentDispositionHeader(header: string): string {
const regex: RegExp = new RegExp(/filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/g);
const matches = header.match(regex);
let filename: string;
for (let i = 0; i < matches.length; i++) {
const match = matches[i];
if (match.includes('filename="')) {
filename = match.substring(10, match.length - 1);
break;
} else if (match.includes('filename=')) {
filename = match.substring(9);
break;
}
}
return filename;
}
openDmpSearchDialogue() {
const formControl = new UntypedFormControl();
const dialogRef = this.dialog.open(DatasetCopyDialogueComponent, {

View File

@ -2,11 +2,13 @@ import { Component, OnInit } from '@angular/core';
import { AbstractControl, UntypedFormArray, UntypedFormBuilder, UntypedFormControl, UntypedFormGroup } from '@angular/forms';
import { MatDialog } from '@angular/material/dialog';
import { ActivatedRoute, Params, Router } from '@angular/router';
import { DmpBlueprintStatus } from '@app/core/common/enum/dmp-blueprint-status';
import { DmpBlueprintExtraFieldDataType } from '@app/core/common/enum/dmp-blueprint-extra-field-data-type';
import { DmpBlueprintSystemFieldType } from '@app/core/common/enum/dmp-blueprint-system-field-type';
import { DmpStatus } from '@app/core/common/enum/dmp-status';
import { Role } from '@app/core/common/enum/role';
import { DataTableRequest } from '@app/core/model/data-table/data-table-request';
import { DatasetProfileModel } from '@app/core/model/dataset/dataset-profile';
import { DescriptionTemplatesInSection, DmpBlueprint, DmpBlueprintDefinition, DmpBlueprintDefinitionSection, FieldInSection } from '@app/core/model/dmp-blueprint/dmp-blueprint';
import { DmpModel } from '@app/core/model/dmp/dmp';
import { DmpDatasetProfile } from '@app/core/model/dmp/dmp-dataset-profile/dmp-dataset-profile';
import { DmpDatasetProfileSectionsFormModel } from '@app/core/model/dmp/dmp-dataset-profile/dmp-dataset-profile-sections-form.model';
@ -16,7 +18,6 @@ import { LockModel } from '@app/core/model/lock/lock.model';
import { UserModel } from '@app/core/model/user/user';
import { UserInfoListingModel } from '@app/core/model/user/user-info-listing';
import { DatasetProfileCriteria } from '@app/core/query/dataset-profile/dataset-profile-criteria';
import { DmpBlueprintCriteria } from '@app/core/query/dmp/dmp-blueprint-criteria';
import { LicenseCriteria } from '@app/core/query/license/license-criteria';
import { RequestItem } from '@app/core/query/request-item';
import { AuthService } from '@app/core/services/auth/auth.service';
@ -44,6 +45,7 @@ import { Guid } from '@common/types/guid';
import { TranslateService } from '@ngx-translate/core';
import { Observable, interval } from 'rxjs';
import { map, takeUntil } from 'rxjs/operators';
import { nameof } from 'ts-simple-nameof';
import { DatasetPreviewDialogComponent } from '../dataset-preview/dataset-preview-dialog.component';
import { DmpToDatasetDialogComponent } from '../dmp-to-dataset/dmp-to-dataset-dialog.component';
import { AddOrganizationComponent } from '../editor/add-organization/add-organization.component';
@ -54,10 +56,6 @@ import { ExtraPropertiesFormModel } from '../editor/general-tab/extra-properties
import { FunderFormModel } from '../editor/grant-tab/funder-form-model';
import { GrantTabModel } from '../editor/grant-tab/grant-tab-model';
import { ProjectFormModel } from '../editor/grant-tab/project-form-model';
import { DescriptionTemplatesInSection, DmpBlueprint, DmpBlueprintDefinition, DmpBlueprintDefinitionSection, FieldInSection } from '@app/core/model/dmp-blueprint/dmp-blueprint';
import { DmpBlueprintExtraFieldDataType } from '@app/core/common/enum/dmp-blueprint-extra-field-data-type';
import { DmpBlueprintSystemFieldType } from '@app/core/common/enum/dmp-blueprint-system-field-type';
import { nameof } from 'ts-simple-nameof';
interface Visible {
value: boolean;

View File

@ -5,13 +5,11 @@ import { MatDialog } from '@angular/material/dialog';
import { ActivatedRoute, Params, Router } from '@angular/router';
import { DmpStatus } from '@app/core/common/enum/dmp-status';
import { Role } from "@app/core/common/enum/role";
import { DataTableRequest } from '@app/core/model/data-table/data-table-request';
import { DmpModel } from '@app/core/model/dmp/dmp';
import { LockModel } from '@app/core/model/lock/lock.model';
import { UserModel } from '@app/core/model/user/user';
import { UserInfoListingModel } from '@app/core/model/user/user-info-listing';
import { BaseCriteria } from '@app/core/query/base-criteria';
import { DmpBlueprintCriteria } from '@app/core/query/dmp/dmp-blueprint-criteria';
import { GrantCriteria } from '@app/core/query/grant/grant-criteria';
import { RequestItem } from '@app/core/query/request-item';
import { AuthService } from '@app/core/services/auth/auth.service';
@ -34,6 +32,8 @@ import { ProjectFormModel } from '@app/ui/dmp/editor/grant-tab/project-form-mode
import { GrantEditorModel } from '@app/ui/grant/editor/grant-editor.model';
// import { IBreadCrumbComponent } from '@app/ui/misc/breadcrumb/definition/IBreadCrumbComponent';
// import { BreadcrumbItem } from '@app/ui/misc/breadcrumb/definition/breadcrumb-item';
import { DmpBlueprint, DmpBlueprintDefinition } from '@app/core/model/dmp-blueprint/dmp-blueprint';
import { FileUtils } from '@app/core/services/utilities/file-utils.service';
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';
@ -41,11 +41,10 @@ import { ConfirmationDialogComponent } from '@common/modules/confirmation-dialog
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 { interval } from 'rxjs';
import { map, takeUntil } from 'rxjs/operators';
import { DmpToDatasetDialogComponent } from '../dmp-to-dataset/dmp-to-dataset-dialog.component';
import { ExtraPropertiesFormModel } from './general-tab/extra-properties-form.model';
import { DmpBlueprint, DmpBlueprintDefinition } from '@app/core/model/dmp-blueprint/dmp-blueprint';
@Component({
selector: 'app-dmp-editor-component',
@ -111,7 +110,8 @@ export class DmpEditorComponent extends CheckDeactivateBaseComponent implements
private formService: FormService,
private lockService: LockService,
private configurationService: ConfigurationService,
private matomoService: MatomoService
private matomoService: MatomoService,
private fileUtils: FileUtils
) {
super();
}
@ -697,7 +697,7 @@ export class DmpEditorComponent extends CheckDeactivateBaseComponent implements
.pipe(takeUntil(this._destroyed))
.subscribe(response => {
const blob = new Blob([response.body], { type: 'application/xml' });
const filename = this.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('dmps', "xml", id);
});
@ -708,7 +708,7 @@ export class DmpEditorComponent extends CheckDeactivateBaseComponent implements
.pipe(takeUntil(this._destroyed))
.subscribe(response => {
const blob = new Blob([response.body], { type: 'application/msword' });
const filename = this.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('dmps', "docx", id);
});
@ -719,7 +719,7 @@ export class DmpEditorComponent extends CheckDeactivateBaseComponent implements
.pipe(takeUntil(this._destroyed))
.subscribe(response => {
const blob = new Blob([response.body], { type: 'application/pdf' });
const filename = this.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('dmps', "pdf", id);
});
@ -730,7 +730,7 @@ export class DmpEditorComponent extends CheckDeactivateBaseComponent implements
.pipe(takeUntil(this._destroyed))
.subscribe(response => {
const blob = new Blob([response.body], { type: 'application/json' });
const filename = this.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('dmps', "json", id);
}, async error => {
@ -744,24 +744,6 @@ export class DmpEditorComponent extends CheckDeactivateBaseComponent implements
this.uiNotificationService.snackBarNotification(errorObj.message, SnackBarNotificationLevel.Error);
}
getFilenameFromContentDispositionHeader(header: string): string {
const regex: RegExp = new RegExp(/filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/g);
const matches = header.match(regex);
let filename: string;
for (let i = 0; i < matches.length; i++) {
const match = matches[i];
if (match.includes('filename="')) {
filename = match.substring(10, match.length - 1);
break;
} else if (match.includes('filename=')) {
filename = match.substring(9);
break;
}
}
return filename;
}
public enableForm() {
if (this.formGroup.get('status').value !== DmpStatus.Finalized) {
this.editMode = true;

View File

@ -1,37 +1,38 @@
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
import { DmpListingModel } from '../../../../core/model/dmp/dmp-listing';
import { MatDialog } from '@angular/material/dialog';
import { DmpInvitationDialogComponent } from '../../invitation/dmp-invitation-dialog.component';
import { Router, ActivatedRoute } from '@angular/router';
import { AuthService } from '../../../../core/services/auth/auth.service';
import { LangChangeEvent, TranslateService } from '@ngx-translate/core';
import { DmpStatus } from '../../../../core/common/enum/dmp-status';
import { EnumUtils } from '@app/core/services/utilities/enum-utils.service';
import { DmpService } from '@app/core/services/dmp/dmp.service';
import { takeUntil, map } from 'rxjs/operators';
import { BaseComponent } from '@common/base/base.component';
import * as FileSaver from 'file-saver';
import { ConfirmationDialogComponent } from '@common/modules/confirmation-dialog/confirmation-dialog.component';
import { UiNotificationService, SnackBarNotificationLevel } from '@app/core/services/notification/ui-notification-service';
import { Role } from '@app/core/common/enum/role';
import { LockService } from '@app/core/services/lock/lock.service';
import { Location } from '@angular/common';
import { DmpModel } from '@app/core/model/dmp/dmp';
import { UntypedFormGroup } from '@angular/forms';
import { DmpEditorModel } from '../../editor/dmp-editor.model';
import { CloneDialogComponent } from '../../clone/clone-dialog/clone-dialog.component';
import { ProjectFormModel } from '../../editor/grant-tab/project-form-model';
import { FunderFormModel } from '../../editor/grant-tab/funder-form-model';
import { ExtraPropertiesFormModel } from '../../editor/general-tab/extra-properties-form.model';
import { GrantTabModel } from '../../editor/grant-tab/grant-tab-model';
import { MatomoService } from '@app/core/services/matomo/matomo-service';
import { HttpClient } from '@angular/common/http';
import { isNullOrUndefined } from '@app/utilities/enhancers/utils';
import { DmpBlueprintService } from '@app/core/services/dmp/dmp-blueprint.service';
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
import { UntypedFormGroup } from '@angular/forms';
import { MatDialog } from '@angular/material/dialog';
import { Router } from '@angular/router';
import { DmpBlueprintSystemFieldType } from '@app/core/common/enum/dmp-blueprint-system-field-type';
import { Role } from '@app/core/common/enum/role';
import { DescriptionTemplatesInSection, DmpBlueprint, DmpBlueprintDefinition, DmpBlueprintDefinitionSection, FieldInSection } from '@app/core/model/dmp-blueprint/dmp-blueprint';
import { nameof } from 'ts-simple-nameof';
import { DmpModel } from '@app/core/model/dmp/dmp';
import { DmpBlueprintService } from '@app/core/services/dmp/dmp-blueprint.service';
import { DmpService } from '@app/core/services/dmp/dmp.service';
import { LockService } from '@app/core/services/lock/lock.service';
import { MatomoService } from '@app/core/services/matomo/matomo-service';
import { SnackBarNotificationLevel, UiNotificationService } from '@app/core/services/notification/ui-notification-service';
import { EnumUtils } from '@app/core/services/utilities/enum-utils.service';
import { FileUtils } from '@app/core/services/utilities/file-utils.service';
import { isNullOrUndefined } from '@app/utilities/enhancers/utils';
import { BaseComponent } from '@common/base/base.component';
import { ConfirmationDialogComponent } from '@common/modules/confirmation-dialog/confirmation-dialog.component';
import { Guid } from '@common/types/guid';
import { TranslateService } from '@ngx-translate/core';
import * as FileSaver from 'file-saver';
import { map, takeUntil } from 'rxjs/operators';
import { nameof } from 'ts-simple-nameof';
import { DmpStatus } from '../../../../core/common/enum/dmp-status';
import { DmpListingModel } from '../../../../core/model/dmp/dmp-listing';
import { AuthService } from '../../../../core/services/auth/auth.service';
import { CloneDialogComponent } from '../../clone/clone-dialog/clone-dialog.component';
import { DmpEditorModel } from '../../editor/dmp-editor.model';
import { ExtraPropertiesFormModel } from '../../editor/general-tab/extra-properties-form.model';
import { FunderFormModel } from '../../editor/grant-tab/funder-form-model';
import { GrantTabModel } from '../../editor/grant-tab/grant-tab-model';
import { ProjectFormModel } from '../../editor/grant-tab/project-form-model';
import { DmpInvitationDialogComponent } from '../../invitation/dmp-invitation-dialog.component';
@Component({
selector: 'app-dmp-listing-item-component',
@ -63,7 +64,8 @@ export class DmpListingItemComponent extends BaseComponent implements OnInit {
private lockService: LockService,
private location: Location,
private httpClient: HttpClient,
private matomoService: MatomoService) {
private matomoService: MatomoService,
private fileUtils: FileUtils) {
super();
}
@ -309,7 +311,7 @@ export class DmpListingItemComponent extends BaseComponent implements OnInit {
.pipe(takeUntil(this._destroyed))
.subscribe(response => {
const blob = new Blob([response.body], { type: 'application/xml' });
const filename = this.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('dmps', "xml", id);
@ -321,7 +323,7 @@ export class DmpListingItemComponent extends BaseComponent implements OnInit {
.pipe(takeUntil(this._destroyed))
.subscribe(response => {
const blob = new Blob([response.body], { type: 'application/msword' });
const filename = this.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('dmps', "docx", id);
@ -333,7 +335,7 @@ export class DmpListingItemComponent extends BaseComponent implements OnInit {
.pipe(takeUntil(this._destroyed))
.subscribe(response => {
const blob = new Blob([response.body], { type: 'application/pdf' });
const filename = this.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('dmps', "pdf", id);
@ -345,7 +347,7 @@ export class DmpListingItemComponent extends BaseComponent implements OnInit {
.pipe(takeUntil(this._destroyed))
.subscribe(response => {
const blob = new Blob([response.body], { type: 'application/json' });
const filename = this.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('dmps', "json", id);
}, async error => {
@ -359,24 +361,6 @@ export class DmpListingItemComponent extends BaseComponent implements OnInit {
this.uiNotificationService.snackBarNotification(errorObj.message, SnackBarNotificationLevel.Error);
}
getFilenameFromContentDispositionHeader(header: string): string {
const regex: RegExp = new RegExp(/filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/g);
const matches = header.match(regex);
let filename: string;
for (let i = 0; i < matches.length; i++) {
const match = matches[i];
if (match.includes('filename="')) {
filename = match.substring(10, match.length - 1);
break;
} else if (match.includes('filename=')) {
filename = match.substring(9);
break;
}
}
return filename;
}
deleteClicked(id: string) {
this.lockService.checkLockStatus(id).pipe(takeUntil(this._destroyed))
.subscribe(lockStatus => {

View File

@ -13,44 +13,45 @@ import {
SnackBarNotificationLevel,
UiNotificationService
} from '@app/core/services/notification/ui-notification-service';
import {ConfirmationDialogComponent} from '@common/modules/confirmation-dialog/confirmation-dialog.component';
import {
DmpFinalizeDialogComponent,
DmpFinalizeDialogInput,
DmpFinalizeDialogOutput
} from '@app/ui/dmp/editor/dmp-finalize-dialog/dmp-finalize-dialog.component';
import { ConfirmationDialogComponent } from '@common/modules/confirmation-dialog/confirmation-dialog.component';
// import {BreadcrumbItem} from '@app/ui/misc/breadcrumb/definition/breadcrumb-item';
import {BaseComponent} from '@common/base/base.component';
import {TranslateService} from '@ngx-translate/core';
import * as FileSaver from 'file-saver';
import {Observable, of as observableOf} from 'rxjs';
import {map, takeUntil} from 'rxjs/operators';
import {Role} from "@app/core/common/enum/role";
import {DmpInvitationDialogComponent} from '../invitation/dmp-invitation-dialog.component';
import {ConfigurationService} from '@app/core/services/configuration/configuration.service';
import { Location } from '@angular/common';
import { UntypedFormGroup } from '@angular/forms';
import {LockService} from '@app/core/services/lock/lock.service';
import {VersionListingModel} from '@app/core/model/version/version-listing.model';
import {CloneDialogComponent} from '../clone/clone-dialog/clone-dialog.component';
import {DmpModel} from '@app/core/model/dmp/dmp';
import {DmpEditorModel} from '../editor/dmp-editor.model';
import {FunderFormModel} from '../editor/grant-tab/funder-form-model';
import {ProjectFormModel} from '../editor/grant-tab/project-form-model';
import {GrantTabModel} from '../editor/grant-tab/grant-tab-model';
import {ExtraPropertiesFormModel} from '../editor/general-tab/extra-properties-form.model';
import {StartNewDmpDialogComponent} from '../start-new-dmp-dialogue/start-new-dmp-dialog.component';
import {MatomoService} from '@app/core/services/matomo/matomo-service';
import {PopupNotificationDialogComponent} from '@app/library/notification/popup/popup-notification.component';
import {DepositRepositoriesService} from '@app/core/services/deposit-repositories/deposit-repositories.service';
import {DepositConfigurationModel} from '@app/core/model/deposit/deposit-configuration';
import {DoiModel} from '@app/core/model/doi/doi';
import {isNullOrUndefined} from '@app/utilities/enhancers/utils';
import { DmpBlueprintService } from '@app/core/services/dmp/dmp-blueprint.service';
import { Guid } from '@common/types/guid';
import { DescriptionTemplatesInSection, DmpBlueprint, DmpBlueprintDefinition, DmpBlueprintDefinitionSection, FieldInSection } from '@app/core/model/dmp-blueprint/dmp-blueprint';
import { DmpBlueprintSystemFieldType } from '@app/core/common/enum/dmp-blueprint-system-field-type';
import { Role } from "@app/core/common/enum/role";
import { DepositConfigurationModel } from '@app/core/model/deposit/deposit-configuration';
import { DescriptionTemplatesInSection, DmpBlueprint, DmpBlueprintDefinition, DmpBlueprintDefinitionSection, FieldInSection } from '@app/core/model/dmp-blueprint/dmp-blueprint';
import { DmpModel } from '@app/core/model/dmp/dmp';
import { DoiModel } from '@app/core/model/doi/doi';
import { VersionListingModel } from '@app/core/model/version/version-listing.model';
import { ConfigurationService } from '@app/core/services/configuration/configuration.service';
import { DepositRepositoriesService } from '@app/core/services/deposit-repositories/deposit-repositories.service';
import { DmpBlueprintService } from '@app/core/services/dmp/dmp-blueprint.service';
import { LockService } from '@app/core/services/lock/lock.service';
import { MatomoService } from '@app/core/services/matomo/matomo-service';
import { FileUtils } from '@app/core/services/utilities/file-utils.service';
import { PopupNotificationDialogComponent } from '@app/library/notification/popup/popup-notification.component';
import { isNullOrUndefined } from '@app/utilities/enhancers/utils';
import { BaseComponent } from '@common/base/base.component';
import { Guid } from '@common/types/guid';
import { TranslateService } from '@ngx-translate/core';
import * as FileSaver from 'file-saver';
import { Observable } from 'rxjs';
import { map, takeUntil } from 'rxjs/operators';
import { nameof } from 'ts-simple-nameof';
import { CloneDialogComponent } from '../clone/clone-dialog/clone-dialog.component';
import { DmpEditorModel } from '../editor/dmp-editor.model';
import { ExtraPropertiesFormModel } from '../editor/general-tab/extra-properties-form.model';
import { FunderFormModel } from '../editor/grant-tab/funder-form-model';
import { GrantTabModel } from '../editor/grant-tab/grant-tab-model';
import { ProjectFormModel } from '../editor/grant-tab/project-form-model';
import { DmpInvitationDialogComponent } from '../invitation/dmp-invitation-dialog.component';
import { StartNewDmpDialogComponent } from '../start-new-dmp-dialogue/start-new-dmp-dialog.component';
@Component({
selector: 'app-dmp-overview',
@ -95,7 +96,8 @@ export class DmpOverviewComponent extends BaseComponent implements OnInit {
private configurationService: ConfigurationService,
private location: Location,
private lockService: LockService,
private matomoService: MatomoService
private matomoService: MatomoService,
private fileUtils: FileUtils
) {
super();
}
@ -426,7 +428,7 @@ export class DmpOverviewComponent extends BaseComponent implements OnInit {
.pipe(takeUntil(this._destroyed))
.subscribe(response => {
const blob = new Blob([response.body], { type: 'application/xml' });
const filename = this.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('dmps', "xml", id);
@ -438,7 +440,7 @@ export class DmpOverviewComponent extends BaseComponent implements OnInit {
.pipe(takeUntil(this._destroyed))
.subscribe(response => {
const blob = new Blob([response.body], { type: 'application/msword' });
const filename = this.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('dmps', "docx", id);
@ -450,7 +452,7 @@ export class DmpOverviewComponent extends BaseComponent implements OnInit {
.pipe(takeUntil(this._destroyed))
.subscribe(response => {
const blob = new Blob([response.body], { type: 'application/pdf' });
const filename = this.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('dmps', "pdf", id);
@ -462,7 +464,7 @@ export class DmpOverviewComponent extends BaseComponent implements OnInit {
.pipe(takeUntil(this._destroyed))
.subscribe(complete => {
const blob = new Blob([complete.body], { type: 'application/json' });
const filename = this.getFilenameFromContentDispositionHeader(complete.headers.get('Content-Disposition'));
const filename = this.fileUtils.getFilenameFromContentDispositionHeader(complete.headers.get('Content-Disposition'));
FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('dmps', "json", id);
}, async error => {
@ -476,24 +478,6 @@ export class DmpOverviewComponent extends BaseComponent implements OnInit {
this.uiNotificationService.snackBarNotification(errorObj.message, SnackBarNotificationLevel.Error);
}
getFilenameFromContentDispositionHeader(header: string): string {
const regex: RegExp = new RegExp(/filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/g);
const matches = header.match(regex);
let filename: string;
for (let i = 0; i < matches.length; i++) {
const match = matches[i];
if (match.includes('filename="')) {
filename = match.substring(10, match.length - 1);
break;
} else if (match.includes('filename=')) {
filename = match.substring(9);
break;
}
}
return filename;
}
roleDisplayFromList(value: UserInfoListingModel[]) {
const principalId: string = this.authentication.userId()?.toString();
let role: number;
@ -889,10 +873,12 @@ export class DmpOverviewComponent extends BaseComponent implements OnInit {
.subscribe(lockStatus => {
this.lockStatus = lockStatus
if (lockStatus) {
this.dialog.open(PopupNotificationDialogComponent,{data:{
this.dialog.open(PopupNotificationDialogComponent, {
data: {
title: this.language.instant('DMP-OVERVIEW.LOCKED-DIALOG.TITLE'),
message: this.language.instant('DMP-OVERVIEW.LOCKED-DIALOG.MESSAGE')
}, maxWidth:'30em'});
}, maxWidth: '30em'
});
}
});
}

View File

@ -50,6 +50,7 @@ import {HttpErrorResponse} from "@angular/common/http";
import * as FileSaver from "file-saver";
import { FetcherExternalReference } from '@app/core/model/external-reference/external-reference';
import { ExternalReferencesType } from '@app/core/common/enum/external-references-type';
import { FileUtils } from '@app/core/services/utilities/file-utils.service';
@Component({
selector: 'app-form-field',
@ -129,7 +130,8 @@ export class FormFieldComponent extends BaseComponent implements OnInit {
private fileService: FileService,
private cdr: ChangeDetectorRef,
private uiNotificationService: UiNotificationService,
public dialog: MatDialog
public dialog: MatDialog,
private fileUtils: FileUtils
) {
super();
@ -704,31 +706,12 @@ export class FormFieldComponent extends BaseComponent implements OnInit {
.pipe(takeUntil(this._destroyed))
.subscribe(response => {
const blob = new Blob([response.body], {type: this.form.value.value.type});
const filename = this.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
FileSaver.saveAs(blob, filename);
});
}
// create a fileUtils/ fileHelper file and add this function (and any other possibly generic) there
getFilenameFromContentDispositionHeader(header: string): string {
const regex: RegExp = new RegExp(/filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/g);
const matches = header.match(regex);
let filename: string;
for (let i = 0; i < matches.length; i++) {
const match = matches[i];
if (match.includes('filename="')) {
filename = match.substring(10, match.length - 1);
break;
} else if (match.includes('filename=')) {
filename = match.substring(9);
break;
}
}
return filename;
}
// isImageFile(fileType: string) {
// if(!fileType) {
// return false;

View File

@ -1034,7 +1034,6 @@
},
"SUCCESSFUL-DELETE": "Successful Delete",
"UNSUCCESSFUL-DELETE": "This item could not be deleted."
},
"DATASET-UPLOAD": {
"TITLE": "Import Dataset",
@ -1072,10 +1071,23 @@
},
"FIELDS": {
"TITLE": "Fields",
"LABEL": "Name",
"TYPE": "Type",
"DATATYPE": "Data Type",
"REQUIRED": "Required",
"NAME": "Name",
"SECTIONS": "Sections",
"SECTION-PREFIX": "Section",
"SECTION-NAME": "Section Name",
"SECTION-DESCRIPTION": "Section Description",
"SYSTEM-FIELDS": "System Fields",
"SYSTEM-FIELD": "System Field",
"FIELD-TYPE": "Field Type",
"FIELD-LABEL": "Label",
"FIELD-PLACEHOLDER": "Placeholder",
"FIELD-DESCRIPTION": "Description",
"FIELD-DATA-TYPE": "Data Type",
"FIELD-REQUIRED": "Required",
"DESCRIPTION-TEMPLATES": "Description Templates",
"DESCRIPTION-TEMPLATE-LABEL": "Label",
"DESCRIPTION-TEMPLATE-MIN-MULTIPLICITY": "Min Multiplicity",
"DESCRIPTION-TEMPLATE-MAX-MULTIPLICITY": "Max Multiplicity",
"EXTERNAL-AUTOCOMPLETE": {
"TITLE": "Autocomplete Data",
"MULTIPLE-AUTOCOMPLETE": "Multiple Autocomplete",
@ -1087,6 +1099,11 @@
}
},
"ACTIONS": {
"ADD-EXTRA-FIELD": "Add extra field",
"REMOVE-SYSTEM-FIELD": "Delete",
"REMOVE-EXTRA-FIELD": "Delete",
"REMOVE-SECTION": "Remove Section",
"ADD-SECTION": "Add Section",
"SAVE": "Save",
"CANCEL": "Cancel",
"DELETE": "Delete",
@ -1606,6 +1623,25 @@
"DESCRIPTION-TEMPLATE-TYPE-STATUS": {
"FINALIZED": "Finalized",
"DRAFT": "Draft"
},
"DMP-BLUEPRINT-SYSTEM-FIELD-TYPE": {
"TEXT": "Title",
"HTML_TEXT": "Description",
"RESEARCHERS": "Researchers",
"ORGANIZATIONS": "Organizations",
"LANGUAGE": "Language",
"CONTACT": "Contact",
"FUNDER": "Funder",
"GRANT": "Grant",
"PROJECT": "Project",
"LICENSE": "License",
"ACCESS_RIGHTS": "Access"
},
"DMP-BLUEPRINT-EXTRA-FIELD-DATA-TYPE": {
"DATE": "Date",
"NUMBER": "Number",
"TEXT": "Text",
"EXTERNAL-AUTOCOMPLETE": "External AutoComplete"
}
},
"ADDRESEARCHERS-EDITOR": {