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 { UserSettingsHttpService } from './services/user-settings/user-settings-http.service';
import { UserSettingsService } from './services/user-settings/user-settings.service'; import { UserSettingsService } from './services/user-settings/user-settings.service';
import { QueryParamsService } from './services/utilities/query-params.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. // This is shared module that provides all the services. Its imported only once on the AppModule.
@ -128,7 +129,8 @@ export class CoreServiceModule {
QueryParamsService, QueryParamsService,
UserSettingsService, UserSettingsService,
UserSettingsHttpService, UserSettingsHttpService,
FilterService FilterService,
FileUtils
], ],
}; };
} }

View File

@ -25,11 +25,9 @@ import { Observable, throwError } from 'rxjs';
@Injectable() @Injectable()
export class DmpBlueprintService { export class DmpBlueprintService {
private actionUrl: string;
private headers = new HttpHeaders(); private headers = new HttpHeaders();
constructor(private http: BaseHttpV2Service, private httpClient: HttpClient, private configurationService: ConfigurationService, private filterService: FilterService) { 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`; } 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 { RoleOrganizationType } from '@app/core/common/enum/role-organization-type';
import { ViewStyleType } from '@app/ui/admin/dataset-profile/editor/components/field/view-style-enum'; 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 { DescriptionTemplateTypeStatus } from '@app/core/common/enum/description-template-type-status';
import { DmpBlueprintSystemFieldType } from '@app/core/common/enum/dmp-blueprint-system-field-type';
@Injectable() @Injectable()
export class EnumUtils { export class EnumUtils {
@ -193,4 +194,29 @@ export class EnumUtils {
case DescriptionTemplateTypeStatus.Finalized: return this.language.instant('TYPES.DESCRIPTION-TEMPLATE-TYPE-STATUS.FINALIZED'); 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 { DescriptionTemplateTypeStatus } from '@app/core/common/enum/description-template-type-status';
import { DescriptionTemplateTypeLookup } from '@app/core/query/description-template-type.lookup'; import { DescriptionTemplateTypeLookup } from '@app/core/query/description-template-type.lookup';
import { nameof } from 'ts-simple-nameof'; import { nameof } from 'ts-simple-nameof';
import { FileUtils } from '@app/core/services/utilities/file-utils.service';
const skipDisable: any[] = require('../../../../../assets/resources/skipDisable.json'); const skipDisable: any[] = require('../../../../../assets/resources/skipDisable.json');
@ -119,7 +120,8 @@ export class DatasetProfileEditorComponent extends CheckDeactivateBaseComponent
private fb: UntypedFormBuilder, private fb: UntypedFormBuilder,
private sidenavService: SideNavService, private sidenavService: SideNavService,
private userService: UserService, private userService: UserService,
private descriptionTemplateTypeService: DescriptionTemplateTypeService private descriptionTemplateTypeService: DescriptionTemplateTypeService,
private fileUtils: FileUtils
) { ) {
super(); super();
// this.profileID = route.snapshot.params['id']; // this.profileID = route.snapshot.params['id'];
@ -584,30 +586,12 @@ export class DatasetProfileEditorComponent extends CheckDeactivateBaseComponent
.pipe(takeUntil(this._destroyed)) .pipe(takeUntil(this._destroyed))
.subscribe(response => { .subscribe(response => {
const blob = new Blob([response.body], { type: 'application/xml' }); 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); 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[] { getDescriptionTemplateTypes(): DescriptionTemplateType[] {
let lookup: DescriptionTemplateTypeLookup = new DescriptionTemplateTypeLookup(); let lookup: DescriptionTemplateTypeLookup = new DescriptionTemplateTypeLookup();
lookup.project = { 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 { SnackBarNotificationLevel, UiNotificationService } from '@app/core/services/notification/ui-notification-service';
import { DatasetProfileCriteriaComponent } from '@app/ui/admin/dataset-profile/listing/criteria/dataset-profile.component'; import { DatasetProfileCriteriaComponent } from '@app/ui/admin/dataset-profile/listing/criteria/dataset-profile.component';
// import { BreadcrumbItem } from '@app/ui/misc/breadcrumb/definition/breadcrumb-item'; // 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 { BaseComponent } from '@common/base/base.component';
import { ConfirmationDialogComponent } from '@common/modules/confirmation-dialog/confirmation-dialog.component'; import { ConfirmationDialogComponent } from '@common/modules/confirmation-dialog/confirmation-dialog.component';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import * as FileSaver from 'file-saver'; 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 { map, startWith, switchMap, takeUntil } from 'rxjs/operators';
import { DialogConfirmationUploadDatasetProfiles } from './criteria/dialog-confirmation-upload-profile/dialog-confirmation-upload-profiles.component'; 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 matomoService: MatomoService,
private dialog: MatDialog, private dialog: MatDialog,
private datasetProfileService: DatasetProfileService, private datasetProfileService: DatasetProfileService,
private fileUtils: FileUtils
) { ) {
super(); super();
} }
@ -160,28 +162,11 @@ export class DatasetProfileListingComponent extends BaseComponent implements OnI
.pipe(takeUntil(this._destroyed)) .pipe(takeUntil(this._destroyed))
.subscribe(response => { .subscribe(response => {
const blob = new Blob([response.body], { type: 'application/xml' }); 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); 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) { deleteTemplate(id: string) {
if (id) { 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> <button mat-button class="finalize-btn" (click)="finalize()" [disabled]="!this.isFormValid()" type="button">{{'DMP-BLUEPRINT-EDITOR.ACTIONS.FINALIZE' | translate }}</button>
</div> </div>
</div> </div>
<form *ngIf="formGroup" (ngSubmit)="formSubmit()" [formGroup]="formGroup"> <form *ngIf="formGroup" (ngSubmit)="formSubmit()">
<mat-card> <mat-card>
<!-- <mat-card-header> <!-- <mat-card-header>
<mat-card-title *ngIf="isNew"> <mat-card-title *ngIf="isNew">
@ -35,206 +35,167 @@
</mat-card-header> --> </mat-card-header> -->
<mat-card-content> <mat-card-content>
<div class="row"> <div class="row">
<mat-form-field class="col-lg-6"> <div class="col-6">
<mat-label>Name</mat-label> <mat-form-field class="w-100">
<input matInput type="text" name="label" formControlName="label" required> <mat-label>{{'DMP-BLUEPRINT-EDITOR.FIELDS.NAME' | translate}}</mat-label>
<mat-error *ngIf="formGroup.get('label').hasError('required')"> <input matInput type="text" name="label" [formControl]="formGroup.get('label')" required>
{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error> <mat-error *ngIf="formGroup.get('label').hasError('required')">
</mat-form-field> {{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
<h4 class="col-12">Sections</h4> </mat-form-field>
</div>
<h4 class="col-12">{{'DMP-BLUEPRINT-EDITOR.FIELDS.SECTIONS' | translate}}</h4>
<div class="col-12" cdkDropList (cdkDropListDropped)="dropSections($event)"> <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"> <div class="col-12">
<mat-card> <mat-card>
<mat-card-header> <mat-card-header>
<mat-card-title>Section {{sectionIndex + 1}}</mat-card-title> <div class="row mb-3 d-flex align-items-center">
<mat-icon cdkDragHandle style="cursor: move; color: #129d99;">drag_indicator</mat-icon> <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-header>
<div class="row"> <mat-card-content>
<div class="row">
<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>
</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>
<div class="col-6">
<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')">
{{'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>
<mat-form-field class="col-6">
<mat-label>Section name</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>
<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 cdkDropList class="col-12" (cdkDropListDropped)="dropFields($event, sectionIndex)">
<div class="row"> <div *ngFor="let field of section.get('fields').controls; let fieldIndex=index;" cdkDrag class="row align-items-center" [cdkDragDisabled]="viewOnly">
<div class="col-12"> <div class="col-auto">
<div class="row"> <span style="font-size: 15px;">{{fieldIndex + 1}}</span>
<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-select>
<mat-error *ngIf="fieldsArray(sectionIndex).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> <div class="col-auto">
<mat-icon cdkDragHandle style="cursor: move; color: #129d99;">drag_indicator</mat-icon>
<div class="col-12"> </div>
<div class="col-auto" *ngIf="field.get('category').value === dmpBlueprintSectionFieldCategory.SYSTEM">
<div cdkDropList (cdkDropListDropped)="drop($event, sectionIndex)"> <mat-form-field class="w-100">
<div *ngFor="let field of section.get('fields').controls; let fieldIndex=index;" cdkDrag [cdkDragDisabled]="viewOnly"> <mat-label>{{'DMP-BLUEPRINT-EDITOR.FIELDS.SYSTEM-FIELD' | translate}}</mat-label>
<div class="col-12"> <input matInput disabled value="{{enumUtils.toDmpBlueprintSystemFieldTypeString(field.get('systemFieldType').value)}}" type="text" name="name">
<div class="row"> </mat-form-field>
<div class="col-xx-1" style="padding-left: 0;"> </div>
<div class="row"> <div class="col-auto" *ngIf="field.get('category').value === dmpBlueprintSectionFieldCategory.EXTRA">
<div class="col-4"> <mat-form-field class="w-100">
<span style="font-size: 15px;">{{fieldIndex + 1}}</span> <mat-label>{{'DMP-BLUEPRINT-EDITOR.FIELDS.FIELD-DATA-TYPE' | translate}}</mat-label>
</div> <mat-select [formControl]="field.get('dataType')" required>
<div class="col-8"> <mat-option *ngFor="let extraFieldDataType of dmpBlueprintExtraFieldDataTypeEnum" [value]="extraFieldDataType">
<mat-icon cdkDragHandle style="cursor: move; color: #129d99;">drag_indicator</mat-icon> {{enumUtils.toDmpBlueprintExtraFieldDataTypeString(extraFieldDataType)}}
</div> </mat-option>
</div> </mat-select>
</div> <mat-error *ngIf="field.get('dataType').hasError('required')">
{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
<ng-container *ngIf="field.get('category').value === dmpBlueprintSectionFieldCategory.SYSTEM"> </div>
<div class="col-2"> <div class="col">
<mat-form-field> <mat-form-field class="w-100">
<mat-label>System Field</mat-label> <mat-label>{{'DMP-BLUEPRINT-EDITOR.FIELDS.FIELD-LABEL' | translate}}</mat-label>
<input matInput disabled value="{{transfromEnumToString(field.get('type').value)}}" type="text" name="name"> <input matInput type="text" name="label" [formControl]="field.get('label')" required>
</mat-form-field> <mat-error *ngIf="field.get('label').hasError('required')">
</div> {{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
<div class="col-2"> </mat-form-field>
<mat-form-field> </div>
<mat-label>Label</mat-label> <div class="col">
<input matInput type="text" name="label" [formControl]="field.get('label')" required> <mat-form-field class="w-100">
<mat-error *ngIf="field.get('label').hasError('required')"> <mat-label>{{'DMP-BLUEPRINT-EDITOR.FIELDS.FIELD-PLACEHOLDER' | translate}}</mat-label>
{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error> <input matInput type="text" name="placeholder" [formControl]="field.get('placeholder')">
</mat-form-field> </mat-form-field>
</div> </div>
<div class="col-2"> <div class="col">
<mat-form-field> <mat-form-field class="w-100">
<mat-label>Placeholder</mat-label> <mat-label>{{'DMP-BLUEPRINT-EDITOR.FIELDS.FIELD-DESCRIPTION' | translate}}</mat-label>
<input matInput type="text" name="placeholder" [formControl]="field.get('placeholder')"> <input matInput type="text" name="description" [formControl]="field.get('description')">
</mat-form-field> </mat-form-field>
</div> </div>
<div class="col-2"> <div class="centered-row-item col-auto">
<mat-form-field> <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>
<mat-label>Description</mat-label> </div>
<input matInput type="text" name="description" [formControl]="field.get('description')"> <div *ngIf="field.get('category').value === dmpBlueprintSectionFieldCategory.SYSTEM" [hidden]="viewOnly" class="field-delete col-auto" (click)="removeSystemField(sectionIndex, fieldIndex)">
</mat-form-field> <mat-icon class="field-delete-icon">delete</mat-icon>
</div> <span class="field-delete-text">{{'DMP-BLUEPRINT-EDITOR.ACTIONS.REMOVE-SYSTEM-FIELD' | translate}}</span>
<div class="centered-row-item col-1"> </div>
<mat-checkbox [disabled]="field.get('type').value === 0 || field.get('type').value === 1" [formControl]="field.get('required')">Required</mat-checkbox> <div *ngIf="field.get('category').value === dmpBlueprintSectionFieldCategory.EXTRA" [hidden]="viewOnly" class="field-delete col-auto" (click)="removeExtraField(sectionIndex, fieldIndex)">
</div> <mat-icon class="field-delete-icon">delete</mat-icon>
<div [hidden]="viewOnly" class="field-delete col-1" (click)="removeSystemFieldWithIndex(sectionIndex, fieldIndex)"> <span class="field-delete-text">{{'DMP-BLUEPRINT-EDITOR.ACTIONS.REMOVE-EXTRA-FIELD' | translate}}</span>
<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>
<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)">
<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>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </mat-card-content>
<div class="col-12"> <div class="col-12">
<div class="row"> <div class="row">
<div class="col-12"> <div class="col-auto">
<mat-checkbox [formControl]="section.get('hasTemplates')" (change)="checkForBlueprints($event, sectionIndex)"> <mat-checkbox [formControl]="section.get('hasTemplates')" (change)="checkForBlueprints($event, sectionIndex)">
Description Templates {{'DMP-BLUEPRINT-EDITOR.FIELDS.DESCRIPTION-TEMPLATES' | translate}}
</mat-checkbox> </mat-checkbox>
</div> </div>
</div> </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="row">
<div class="col-12"> <div class="col-12">
<mat-form-field> <mat-form-field class="w-100">
<mat-label>Description Templates</mat-label> <mat-label>{{'DMP-BLUEPRINT-EDITOR.FIELDS.DESCRIPTION-TEMPLATES' | translate}}</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)"> <app-multiple-auto-complete [disabled]="viewOnly" [hidePlaceholder]="true" required='false' [configuration]="blueprintsAutoCompleteConfiguration" (optionRemoved)="onRemoveDescritionTemplate($event, sectionIndex)" (optionSelected)="onSelectDescritionTemplate($event, sectionIndex)">
</app-multiple-auto-complete> </app-multiple-auto-complete>
</mat-form-field> </mat-form-field>
</div> </div>
</div> </div>
</div> --> </div>
<div *ngFor="let descriptionTemplate of section.get('descriptionTemplates').controls; let j=index;" class="section-input" style="width: 100%;"> <div *ngFor="let descriptionTemplate of section.get('descriptionTemplates').controls; let j=index;" class="col-12">
<div class="col-12"> <div class="col-12">
<div class="row"> <div class="row">
<div class="col-4"> <div class="col-4">
<mat-form-field> <mat-form-field class="w-100">
<mat-label>Label</mat-label> <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')"> <input matInput type="text" value="descriptionTemplate.get('label')" name="label" [formControl]="descriptionTemplate.get('label')">
</mat-form-field> </mat-form-field>
</div> </div>
<div class="col-4"> <div class="col-4">
<mat-form-field> <mat-form-field class="w-100">
<mat-label>Min Multiplicity</mat-label> <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')"> <input matInput type="number" min="0" name="minMultiplicity" [formControl]="descriptionTemplate.get('minMultiplicity')">
</mat-form-field> </mat-form-field>
</div> </div>
<div class="col-4"> <div class="col-4">
<mat-form-field> <mat-form-field class="w-100">
<mat-label>Max Multiplicity</mat-label> <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')"> <input matInput type="number" min="1" name="maxMultiplicity" [formControl]="descriptionTemplate.get('maxMultiplicity')">
</mat-form-field> </mat-form-field>
</div> </div>
@ -242,17 +203,7 @@
</div> </div>
</div> </div>
</mat-card> </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>
</div> </div>
@ -262,7 +213,7 @@
<div class="col-12"> <div class="col-12">
<div class="row"> <div class="row">
<div class="col-auto"> <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> </div>
</div> </div>
@ -281,5 +232,4 @@
</mat-card-content> </mat-card-content>
</mat-card> </mat-card>
</form> </form>
</div> </div>
<!-- </div> -->

View File

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

View File

@ -182,7 +182,7 @@ export class DmpBlueprintListingComponent extends BaseListingComponent<DmpBluepr
// .pipe(takeUntil(this._destroyed)) // .pipe(takeUntil(this._destroyed))
// .subscribe(response => { // .subscribe(response => {
// const blob = new Blob([response.body], { type: 'application/xml' }); // 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); // FileSaver.saveAs(blob, filename);
// }); // });
} }
@ -209,27 +209,10 @@ export class DmpBlueprintListingComponent extends BaseListingComponent<DmpBluepr
// .pipe(takeUntil(this._destroyed)) // .pipe(takeUntil(this._destroyed))
// .subscribe(response => { // .subscribe(response => {
// const blob = new Blob([response.body], { type: 'application/xml' }); // 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); // 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) { // deleteTemplate(id: string) {
// if (id) { // 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 { UserService } from '../../../../core/services/user/user.service';
import { SnackBarNotificationComponent } from '../../../../library/notification/snack-bar/snack-bar-notification.component'; import { SnackBarNotificationComponent } from '../../../../library/notification/snack-bar/snack-bar-notification.component';
// import { BreadcrumbItem } from '../../../misc/breadcrumb/definition/breadcrumb-item'; // import { BreadcrumbItem } from '../../../misc/breadcrumb/definition/breadcrumb-item';
import { FileUtils } from '@app/core/services/utilities/file-utils.service';
import { UserCriteriaComponent } from './criteria/user-criteria.component'; import { UserCriteriaComponent } from './criteria/user-criteria.component';
export class UsersDataSource extends DataSource<UserListingModel> { export class UsersDataSource extends DataSource<UserListingModel> {
@ -111,7 +112,8 @@ export class UserListingComponent extends BaseComponent implements OnInit, After
private languageService: TranslateService, private languageService: TranslateService,
public snackBar: MatSnackBar, public snackBar: MatSnackBar,
private httpClient: HttpClient, private httpClient: HttpClient,
private matomoService: MatomoService private matomoService: MatomoService,
private fileUtils: FileUtils
) { ) {
super(); super();
} }
@ -151,29 +153,11 @@ export class UserListingComponent extends BaseComponent implements OnInit, After
.pipe(takeUntil(this._destroyed)) .pipe(takeUntil(this._destroyed))
.subscribe(response => { .subscribe(response => {
const blob = new Blob([response.body], { type: 'application/csv' }); 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); 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) { public setDefaultAvatar(ev: Event) {
(ev.target as HTMLImageElement).src = 'assets/images/profile-placeholder.png'; (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 { 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 { 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 { LockService } from '@app/core/services/lock/lock.service';
import { MatomoService } from '@app/core/services/matomo/matomo-service'; import { MatomoService } from '@app/core/services/matomo/matomo-service';
import { HttpClient } from '@angular/common/http'; import { SnackBarNotificationLevel, UiNotificationService } from '@app/core/services/notification/ui-notification-service';
import {RecentActivityModel} from "@app/core/model/recent-activity/recent-activity.model"; import { EnumUtils } from '@app/core/services/utilities/enum-utils.service';
import {DmpEditorModel} from "@app/ui/dmp/editor/dmp-editor.model"; import { FileUtils } from '@app/core/services/utilities/file-utils.service';
import {DmpService} from "@app/core/services/dmp/dmp.service"; import { DatasetCopyDialogueComponent } from '@app/ui/dataset/dataset-wizard/dataset-copy-dialogue/dataset-copy-dialogue.component';
import {DashboardService} from "@app/core/services/dashboard/dashboard.service"; import { CloneDialogComponent } from "@app/ui/dmp/clone/clone-dialog/clone-dialog.component";
import {RecentActivityCriteria} from "@app/core/query/recent-activity/recent-activity-criteria"; import { DmpEditorModel } from "@app/ui/dmp/editor/dmp-editor.model";
import {RecentDmpModel} from "@app/core/model/recent-activity/recent-dmp-activity.model"; import { ExtraPropertiesFormModel } from "@app/ui/dmp/editor/general-tab/extra-properties-form.model";
import {DatasetUrlListing} from "@app/core/model/dataset/dataset-url-listing"; import { FunderFormModel } from "@app/ui/dmp/editor/grant-tab/funder-form-model";
import {RecentDatasetModel} from "@app/core/model/recent-activity/recent-dataset-activity.model"; import { GrantTabModel } from "@app/ui/dmp/editor/grant-tab/grant-tab-model";
import {DmpListingModel} from "@app/core/model/dmp/dmp-listing"; import { ProjectFormModel } from "@app/ui/dmp/editor/grant-tab/project-form-model";
import {DmpModel} from "@app/core/model/dmp/dmp"; import { DmpInvitationDialogComponent } from '@app/ui/dmp/invitation/dmp-invitation-dialog.component';
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 { isNullOrUndefined } from '@app/utilities/enhancers/utils'; import { isNullOrUndefined } from '@app/utilities/enhancers/utils';
import { DmpBlueprintService } from '@app/core/services/dmp/dmp-blueprint.service'; import { BaseComponent } from '@common/base/base.component';
import { DmpBlueprintDefinition } from '@app/core/model/dmp-blueprint/dmp-blueprint'; import { ConfirmationDialogComponent } from '@common/modules/confirmation-dialog/confirmation-dialog.component';
import { DmpBlueprintSystemFieldType } from '@app/core/common/enum/dmp-blueprint-system-field-type'; 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({ @Component({
selector: 'app-drafts', selector: 'app-drafts',
@ -67,7 +65,7 @@ export class DraftsComponent extends BaseComponent implements OnInit {
offsetLess: number = 0; offsetLess: number = 0;
pageSize: number = 5; pageSize: number = 5;
dmpFormGroup: UntypedFormGroup; dmpFormGroup: UntypedFormGroup;
hasMoreActivity:boolean = true; hasMoreActivity: boolean = true;
public formGroup = new UntypedFormBuilder().group({ public formGroup = new UntypedFormBuilder().group({
like: new UntypedFormControl(), like: new UntypedFormControl(),
order: new UntypedFormControl() order: new UntypedFormControl()
@ -94,7 +92,8 @@ export class DraftsComponent extends BaseComponent implements OnInit {
private location: Location, private location: Location,
private lockService: LockService, private lockService: LockService,
private httpClient: HttpClient, private httpClient: HttpClient,
private matomoService: MatomoService private matomoService: MatomoService,
private fileUtils: FileUtils
) { ) {
super(); super();
} }
@ -102,18 +101,18 @@ export class DraftsComponent extends BaseComponent implements OnInit {
ngOnInit() { ngOnInit() {
this.matomoService.trackPageView('Drafts'); this.matomoService.trackPageView('Drafts');
this.route.queryParams.subscribe(params => { this.route.queryParams.subscribe(params => {
if(this.isActive) { if (this.isActive) {
let page = (params['page'] === undefined) ? 1 : +params['page']; let page = (params['page'] === undefined) ? 1 : +params['page'];
this.page = (page <= 0) ? 1 : page; this.page = (page <= 0) ? 1 : page;
this.datasetOffset = (this.page-1)*this.pageSize; this.datasetOffset = (this.page - 1) * this.pageSize;
this.dmpOffset = (this.page-1)*this.pageSize; this.dmpOffset = (this.page - 1) * this.pageSize;
if(this.page > 1) { if (this.page > 1) {
this.offsetLess = (this.page-2)*this.pageSize; this.offsetLess = (this.page - 2) * this.pageSize;
} }
let order = params['order']; let order = params['order'];
if(order === undefined || (order != this.order.MODIFIED && order != this.order.LABEL)) { if (order === undefined || (order != this.order.MODIFIED && order != this.order.LABEL)) {
order = this.order.MODIFIED; order = this.order.MODIFIED;
} }
this.formGroup.get('order').setValue(order); this.formGroup.get('order').setValue(order);
@ -129,7 +128,7 @@ export class DraftsComponent extends BaseComponent implements OnInit {
this.formGroup.get('order').setValue(this.order.MODIFIED); this.formGroup.get('order').setValue(this.order.MODIFIED);
} }
const fields: Array<string> = [((this.formGroup.get('order').value === 'status') || (this.formGroup.get('order').value === 'label') ? '+' : "-") + this.formGroup.get('order').value]; const fields: Array<string> = [((this.formGroup.get('order').value === 'status') || (this.formGroup.get('order').value === 'label') ? '+' : "-") + this.formGroup.get('order').value];
const allDataTableRequest: DataTableMultiTypeRequest<RecentActivityCriteria> = new DataTableMultiTypeRequest(this.dmpOffset, this.datasetOffset, 5, {fields: fields}); const allDataTableRequest: DataTableMultiTypeRequest<RecentActivityCriteria> = new DataTableMultiTypeRequest(this.dmpOffset, this.datasetOffset, 5, { fields: fields });
allDataTableRequest.criteria = new RecentActivityCriteria(); allDataTableRequest.criteria = new RecentActivityCriteria();
allDataTableRequest.criteria.like = this.formGroup.get('like').value; allDataTableRequest.criteria.like = this.formGroup.get('like').value;
allDataTableRequest.criteria.order = this.formGroup.get('order').value; allDataTableRequest.criteria.order = this.formGroup.get('order').value;
@ -151,11 +150,11 @@ export class DraftsComponent extends BaseComponent implements OnInit {
}); });
this.totalCountRecentEdited.emit(this.allRecentActivities.length); this.totalCountRecentEdited.emit(this.allRecentActivities.length);
if (this.allRecentActivities.length == 0 && this.page > 1) { if (this.allRecentActivities.length == 0 && this.page > 1) {
let queryParams = {type: "recent", page: 1, order: this.formGroup.get("order").value}; let queryParams = { type: "recent", page: 1, order: this.formGroup.get("order").value };
if (this.formGroup.get("like").value) { if (this.formGroup.get("like").value) {
queryParams['keyword'] = this.formGroup.get("like").value; queryParams['keyword'] = this.formGroup.get("like").value;
} }
this.router.navigate(["/home"], {queryParams: queryParams}) this.router.navigate(["/home"], { queryParams: queryParams })
} }
}); });
this.formGroup.get('like').valueChanges this.formGroup.get('like').valueChanges
@ -172,17 +171,17 @@ export class DraftsComponent extends BaseComponent implements OnInit {
} }
ngOnChanges() { ngOnChanges() {
if(this.isActive) { if (this.isActive) {
this.updateUrl(); this.updateUrl();
} }
} }
updateUrl() { updateUrl() {
let parameters = "?type=drafts"+ let parameters = "?type=drafts" +
(this.page != 1 ? "&page="+this.page : "") + (this.page != 1 ? "&page=" + this.page : "") +
(this.formGroup.get("order").value != this.order.MODIFIED ? "&order="+this.formGroup.get("order").value : "") + (this.formGroup.get("order").value != this.order.MODIFIED ? "&order=" + this.formGroup.get("order").value : "") +
(this.formGroup.get("like").value ? ("&keyword="+this.formGroup.get("like").value) : ""); (this.formGroup.get("like").value ? ("&keyword=" + this.formGroup.get("like").value) : "");
this.location.go(this.router.url.split('?')[0]+parameters); this.location.go(this.router.url.split('?')[0] + parameters);
} }
getDatasets(activity: RecentDmpModel): DatasetUrlListing[] { getDatasets(activity: RecentDmpModel): DatasetUrlListing[] {
@ -492,7 +491,7 @@ export class DraftsComponent extends BaseComponent implements OnInit {
.pipe(takeUntil(this._destroyed)) .pipe(takeUntil(this._destroyed))
.subscribe(response => { .subscribe(response => {
const blob = new Blob([response.body], { type: 'application/xml' }); 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); FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('dmps', "xml", id); this.matomoService.trackDownload('dmps', "xml", id);
@ -504,7 +503,7 @@ export class DraftsComponent extends BaseComponent implements OnInit {
.pipe(takeUntil(this._destroyed)) .pipe(takeUntil(this._destroyed))
.subscribe(response => { .subscribe(response => {
const blob = new Blob([response.body], { type: 'application/msword' }); 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); FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('dmps', "docx", id); this.matomoService.trackDownload('dmps', "docx", id);
@ -516,7 +515,7 @@ export class DraftsComponent extends BaseComponent implements OnInit {
.pipe(takeUntil(this._destroyed)) .pipe(takeUntil(this._destroyed))
.subscribe(response => { .subscribe(response => {
const blob = new Blob([response.body], { type: 'application/pdf' }); 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); FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('dmps', "pdf", id); this.matomoService.trackDownload('dmps', "pdf", id);
@ -528,7 +527,7 @@ export class DraftsComponent extends BaseComponent implements OnInit {
.pipe(takeUntil(this._destroyed)) .pipe(takeUntil(this._destroyed))
.subscribe(response => { .subscribe(response => {
const blob = new Blob([response.body], { type: 'application/json' }); 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); FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('dmps', "json", id); this.matomoService.trackDownload('dmps', "json", id);
}, async error => { }, async error => {
@ -547,7 +546,7 @@ export class DraftsComponent extends BaseComponent implements OnInit {
.pipe(takeUntil(this._destroyed)) .pipe(takeUntil(this._destroyed))
.subscribe(response => { .subscribe(response => {
const blob = new Blob([response.body], { type: 'application/pdf' }); 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); FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('datasets', "pdf", dataset.id); this.matomoService.trackDownload('datasets', "pdf", dataset.id);
@ -559,7 +558,7 @@ export class DraftsComponent extends BaseComponent implements OnInit {
.pipe(takeUntil(this._destroyed)) .pipe(takeUntil(this._destroyed))
.subscribe(response => { .subscribe(response => {
const blob = new Blob([response.body], { type: 'application/msword' }); 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); FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('datasets', "docx", dataset.id); this.matomoService.trackDownload('datasets', "docx", dataset.id);
@ -572,31 +571,13 @@ export class DraftsComponent extends BaseComponent implements OnInit {
.pipe(takeUntil(this._destroyed)) .pipe(takeUntil(this._destroyed))
.subscribe(response => { .subscribe(response => {
const blob = new Blob([response.body], { type: 'application/xml' }); 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); FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('datasets', "xml", dataset.id); 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) { viewVersions(rowId: String, rowLabel: String, activity: DmpListingModel) {
if (activity.public && !this.isUserOwner(activity)) { if (activity.public && !this.isUserOwner(activity)) {
let url = this.router.createUrlTree(['/explore-plans/versions/', rowId, { groupLabel: rowLabel }]); let url = this.router.createUrlTree(['/explore-plans/versions/', rowId, { groupLabel: rowLabel }]);
@ -702,14 +683,14 @@ export class DraftsComponent extends BaseComponent implements OnInit {
this.allRecentActivities.forEach(recentActivity => { this.allRecentActivities.forEach(recentActivity => {
if (recentActivity.type === RecentActivityType.Dataset) { if (recentActivity.type === RecentActivityType.Dataset) {
// this.datasetOffset = this.datasetOffset + 1; // this.datasetOffset = this.datasetOffset + 1;
this.datasetOffset = this.page*this.pageSize; this.datasetOffset = this.page * this.pageSize;
} else if (recentActivity.type === RecentActivityType.Dmp) { } else if (recentActivity.type === RecentActivityType.Dmp) {
// this.dmpOffset = this.dmpOffset + 1; // this.dmpOffset = this.dmpOffset + 1;
this.dmpOffset = this.page*this.pageSize; this.dmpOffset = this.page * this.pageSize;
} }
}); });
if(response.length< this.pageSize) { if (response.length < this.pageSize) {
this.hasMoreActivity = false; this.hasMoreActivity = false;
} else { } else {
this.hasMoreActivity = true; this.hasMoreActivity = true;
@ -722,10 +703,10 @@ export class DraftsComponent extends BaseComponent implements OnInit {
const fields: Array<string> = [((this.formGroup.get('order').value === 'status') || (this.formGroup.get('order').value === 'label') ? '+' : "-") + this.formGroup.get('order').value]; const fields: Array<string> = [((this.formGroup.get('order').value === 'status') || (this.formGroup.get('order').value === 'label') ? '+' : "-") + this.formGroup.get('order').value];
// const fields: Array<string> = ["-modified"]; // const fields: Array<string> = ["-modified"];
let request; let request;
if(more) { if (more) {
request = new DataTableMultiTypeRequest<RecentActivityCriteria>(this.dmpOffset, this.datasetOffset, this.pageSize, {fields: fields}); request = new DataTableMultiTypeRequest<RecentActivityCriteria>(this.dmpOffset, this.datasetOffset, this.pageSize, { fields: fields });
} else { } else {
request = new DataTableMultiTypeRequest<RecentActivityCriteria>(this.offsetLess, this.offsetLess, this.pageSize, {fields: fields}); request = new DataTableMultiTypeRequest<RecentActivityCriteria>(this.offsetLess, this.offsetLess, this.pageSize, { fields: fields });
} }
request.criteria = new RecentActivityCriteria(); request.criteria = new RecentActivityCriteria();
request.criteria.like = this.formGroup.get("like").value ? this.formGroup.get("like").value : ""; request.criteria.like = this.formGroup.get("like").value ? this.formGroup.get("like").value : "";
@ -754,7 +735,7 @@ export class DraftsComponent extends BaseComponent implements OnInit {
this.offsetLess = (this.page - 2) * this.pageSize; this.offsetLess = (this.page - 2) * this.pageSize;
} }
if(result.length < this.pageSize) { if (result.length < this.pageSize) {
this.hasMoreActivity = false; this.hasMoreActivity = false;
} else { } else {
this.hasMoreActivity = true; this.hasMoreActivity = true;

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 { MatDialog } from '@angular/material/dialog';
import {ActivatedRoute, Router} from '@angular/router'; 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 { 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 { 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 { 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 { 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 { SnackBarNotificationLevel, UiNotificationService } from '@app/core/services/notification/ui-notification-service';
import { EnumUtils } from '@app/core/services/utilities/enum-utils.service'; import { EnumUtils } from '@app/core/services/utilities/enum-utils.service';
import { ConfirmationDialogComponent } from '@common/modules/confirmation-dialog/confirmation-dialog.component'; import { FileUtils } from '@app/core/services/utilities/file-utils.service';
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 { DatasetCopyDialogueComponent } from '@app/ui/dataset/dataset-wizard/dataset-copy-dialogue/dataset-copy-dialogue.component'; 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 { CloneDialogComponent } from '@app/ui/dmp/clone/clone-dialog/clone-dialog.component';
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 { DmpEditorModel } from '@app/ui/dmp/editor/dmp-editor.model'; 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 { GrantTabModel } from '@app/ui/dmp/editor/grant-tab/grant-tab-model';
import { ProjectFormModel } from '@app/ui/dmp/editor/grant-tab/project-form-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 { DmpInvitationDialogComponent } from '@app/ui/dmp/invitation/dmp-invitation-dialog.component';
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 { isNullOrUndefined } from '@app/utilities/enhancers/utils'; import { isNullOrUndefined } from '@app/utilities/enhancers/utils';
import { DmpBlueprintService } from '@app/core/services/dmp/dmp-blueprint.service'; import { BaseComponent } from '@common/base/base.component';
import { DmpBlueprintSystemFieldType } from '@app/core/common/enum/dmp-blueprint-system-field-type'; import { ConfirmationDialogComponent } from '@common/modules/confirmation-dialog/confirmation-dialog.component';
import { DescriptionTemplatesInSection, DmpBlueprint, DmpBlueprintDefinition, DmpBlueprintDefinitionSection, FieldInSection } from '@app/core/model/dmp-blueprint/dmp-blueprint';
import { nameof } from 'ts-simple-nameof';
import { Guid } from '@common/types/guid'; 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({ @Component({
selector: 'app-recent-edited-activity', selector: 'app-recent-edited-activity',
@ -69,7 +67,7 @@ export class RecentEditedActivityComponent extends BaseComponent implements OnIn
offsetLess: number = 0; offsetLess: number = 0;
pageSize: number = 5; pageSize: number = 5;
dmpFormGroup: UntypedFormGroup; dmpFormGroup: UntypedFormGroup;
hasMoreActivity:boolean = true; hasMoreActivity: boolean = true;
public formGroup = new UntypedFormBuilder().group({ public formGroup = new UntypedFormBuilder().group({
like: new UntypedFormControl(), like: new UntypedFormControl(),
order: new UntypedFormControl() order: new UntypedFormControl()
@ -96,7 +94,8 @@ export class RecentEditedActivityComponent extends BaseComponent implements OnIn
private location: Location, private location: Location,
private lockService: LockService, private lockService: LockService,
private httpClient: HttpClient, private httpClient: HttpClient,
private matomoService: MatomoService private matomoService: MatomoService,
private fileUtils: FileUtils
) { ) {
super(); super();
} }
@ -104,23 +103,23 @@ export class RecentEditedActivityComponent extends BaseComponent implements OnIn
ngOnInit() { ngOnInit() {
this.matomoService.trackPageView('Recent Edited Activity'); this.matomoService.trackPageView('Recent Edited Activity');
this.route.queryParams.subscribe(params => { this.route.queryParams.subscribe(params => {
if(this.isActive) { if (this.isActive) {
let page = (params['page'] === undefined) ? 1 : +params['page']; let page = (params['page'] === undefined) ? 1 : +params['page'];
this.page = (page <= 0) ? 1 : page; this.page = (page <= 0) ? 1 : page;
this.datasetOffset = (this.page-1)*this.pageSize; this.datasetOffset = (this.page - 1) * this.pageSize;
this.dmpOffset = (this.page-1)*this.pageSize; this.dmpOffset = (this.page - 1) * this.pageSize;
if(this.page > 1) { if (this.page > 1) {
this.offsetLess = (this.page-2)*this.pageSize; this.offsetLess = (this.page - 2) * this.pageSize;
} }
let order = params['order']; let order = params['order'];
if (this.isAuthenticated()) { if (this.isAuthenticated()) {
if(order === undefined || (order != this.order.MODIFIED && order != this.order.LABEL && order != this.order.STATUS)) { if (order === undefined || (order != this.order.MODIFIED && order != this.order.LABEL && order != this.order.STATUS)) {
order = this.order.MODIFIED; order = this.order.MODIFIED;
} }
} else { } else {
if(order === undefined || (order != this.order.PUBLISHED && order != this.order.LABEL)) { if (order === undefined || (order != this.order.PUBLISHED && order != this.order.LABEL)) {
order = this.order.PUBLISHED; order = this.order.PUBLISHED;
} }
} }
@ -133,7 +132,7 @@ export class RecentEditedActivityComponent extends BaseComponent implements OnIn
} }
}); });
if (this.isAuthenticated()) { if (this.isAuthenticated()) {
if(!this.formGroup.get('order').value) { if (!this.formGroup.get('order').value) {
this.formGroup.get('order').setValue(this.order.MODIFIED); this.formGroup.get('order').setValue(this.order.MODIFIED);
} }
const fields: Array<string> = [((this.formGroup.get('order').value === 'status') || (this.formGroup.get('order').value === 'label') ? '+' : "-") + this.formGroup.get('order').value]; const fields: Array<string> = [((this.formGroup.get('order').value === 'status') || (this.formGroup.get('order').value === 'label') ? '+' : "-") + this.formGroup.get('order').value];
@ -150,19 +149,19 @@ export class RecentEditedActivityComponent extends BaseComponent implements OnIn
this.allRecentActivities.forEach(recentActivity => { this.allRecentActivities.forEach(recentActivity => {
if (recentActivity.type === RecentActivityType.Dataset) { if (recentActivity.type === RecentActivityType.Dataset) {
// this.datasetOffset = this.datasetOffset + 1; // this.datasetOffset = this.datasetOffset + 1;
this.datasetOffset = this.page*this.pageSize; this.datasetOffset = this.page * this.pageSize;
} else if (recentActivity.type === RecentActivityType.Dmp) { } else if (recentActivity.type === RecentActivityType.Dmp) {
// this.dmpOffset = this.dmpOffset + 1; // this.dmpOffset = this.dmpOffset + 1;
this.dmpOffset = this.page*this.pageSize; this.dmpOffset = this.page * this.pageSize;
} }
}); });
this.totalCountRecentEdited.emit(this.allRecentActivities.length); this.totalCountRecentEdited.emit(this.allRecentActivities.length);
if(this.allRecentActivities.length == 0 && this.page > 1) { if (this.allRecentActivities.length == 0 && this.page > 1) {
let queryParams = { type: "recent", page: 1, order: this.formGroup.get("order").value }; let queryParams = { type: "recent", page: 1, order: this.formGroup.get("order").value };
if(this.formGroup.get("like").value) { if (this.formGroup.get("like").value) {
queryParams['keyword'] = this.formGroup.get("like").value; queryParams['keyword'] = this.formGroup.get("like").value;
} }
this.router.navigate(["/home"], { queryParams: queryParams }) this.router.navigate(["/home"], { queryParams: queryParams })
} }
}); });
this.formGroup.get('like').valueChanges this.formGroup.get('like').valueChanges
@ -177,7 +176,7 @@ export class RecentEditedActivityComponent extends BaseComponent implements OnIn
}); });
} else { } else {
this.publicMode = true; this.publicMode = true;
if(!this.formGroup.get('order').value) { if (!this.formGroup.get('order').value) {
this.formGroup.get('order').setValue(this.order.PUBLISHED); this.formGroup.get('order').setValue(this.order.PUBLISHED);
} }
const allDataTableRequest = this.setPublicDataTableRequest(); const allDataTableRequest = this.setPublicDataTableRequest();
@ -189,19 +188,19 @@ export class RecentEditedActivityComponent extends BaseComponent implements OnIn
this.allRecentActivities.forEach(recentActivity => { this.allRecentActivities.forEach(recentActivity => {
if (recentActivity.type === RecentActivityType.Dataset) { if (recentActivity.type === RecentActivityType.Dataset) {
// this.datasetOffset = this.datasetOffset + 1; // this.datasetOffset = this.datasetOffset + 1;
this.datasetOffset = this.page*this.pageSize; this.datasetOffset = this.page * this.pageSize;
} else if (recentActivity.type === RecentActivityType.Dmp) { } else if (recentActivity.type === RecentActivityType.Dmp) {
// this.dmpOffset = this.dmpOffset + 1; // this.dmpOffset = this.dmpOffset + 1;
this.dmpOffset = this.page*this.pageSize; this.dmpOffset = this.page * this.pageSize;
} }
}); });
this.totalCountRecentEdited.emit(this.allRecentActivities.length); this.totalCountRecentEdited.emit(this.allRecentActivities.length);
if(this.allRecentActivities.length == 0 && this.page > 1) { if (this.allRecentActivities.length == 0 && this.page > 1) {
let queryParams = { type: "recent", page: 1, order: this.formGroup.get("order").value }; let queryParams = { type: "recent", page: 1, order: this.formGroup.get("order").value };
if(this.formGroup.get("like").value) { if (this.formGroup.get("like").value) {
queryParams['keyword'] = this.formGroup.get("like").value; queryParams['keyword'] = this.formGroup.get("like").value;
} }
this.router.navigate(["/home"], { queryParams: queryParams }) this.router.navigate(["/home"], { queryParams: queryParams })
} }
}); });
this.formGroup.get('like').valueChanges this.formGroup.get('like').valueChanges
@ -218,20 +217,20 @@ export class RecentEditedActivityComponent extends BaseComponent implements OnIn
} }
ngOnChanges() { ngOnChanges() {
if(this.isActive) { if (this.isActive) {
this.updateUrl(); this.updateUrl();
} }
} }
updateUrl() { updateUrl() {
let parameters = ""; let parameters = "";
parameters += (this.page != 1 ? "&page="+this.page : ""); parameters += (this.page != 1 ? "&page=" + this.page : "");
parameters += (((this.formGroup.get("order").value != this.order.MODIFIED && !this.publicMode) || (this.formGroup.get("order").value != this.order.PUBLISHED && this.publicMode)) ? "&order="+this.formGroup.get("order").value : ""); parameters += (((this.formGroup.get("order").value != this.order.MODIFIED && !this.publicMode) || (this.formGroup.get("order").value != this.order.PUBLISHED && this.publicMode)) ? "&order=" + this.formGroup.get("order").value : "");
parameters += (this.formGroup.get("like").value ? ("&keyword="+this.formGroup.get("like").value) : ""); parameters += (this.formGroup.get("like").value ? ("&keyword=" + this.formGroup.get("like").value) : "");
if(parameters) { if (parameters) {
parameters = "?type=recent" + parameters; parameters = "?type=recent" + parameters;
} }
this.location.go(this.router.url.split('?')[0]+parameters); this.location.go(this.router.url.split('?')[0] + parameters);
} }
getDatasets(activity: RecentDmpModel): DatasetUrlListing[] { getDatasets(activity: RecentDmpModel): DatasetUrlListing[] {
@ -348,10 +347,10 @@ export class RecentEditedActivityComponent extends BaseComponent implements OnIn
[nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.descriptionTemplates), nameof<DescriptionTemplatesInSection>(x => x.maxMultiplicity)].join('.'), [nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.descriptionTemplates), nameof<DescriptionTemplatesInSection>(x => x.maxMultiplicity)].join('.'),
] ]
) )
.pipe(map(data => data as DmpBlueprint), takeUntil(this._destroyed)) .pipe(map(data => data as DmpBlueprint), takeUntil(this._destroyed))
.subscribe( .subscribe(
data => successFunction(data), data => successFunction(data),
); );
} }
@ -596,7 +595,7 @@ export class RecentEditedActivityComponent extends BaseComponent implements OnIn
.pipe(takeUntil(this._destroyed)) .pipe(takeUntil(this._destroyed))
.subscribe(response => { .subscribe(response => {
const blob = new Blob([response.body], { type: 'application/xml' }); 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); FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('dmps', "xml", id); this.matomoService.trackDownload('dmps', "xml", id);
@ -608,7 +607,7 @@ export class RecentEditedActivityComponent extends BaseComponent implements OnIn
.pipe(takeUntil(this._destroyed)) .pipe(takeUntil(this._destroyed))
.subscribe(response => { .subscribe(response => {
const blob = new Blob([response.body], { type: 'application/msword' }); 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); FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('dmps', "docx", id); this.matomoService.trackDownload('dmps', "docx", id);
@ -620,7 +619,7 @@ export class RecentEditedActivityComponent extends BaseComponent implements OnIn
.pipe(takeUntil(this._destroyed)) .pipe(takeUntil(this._destroyed))
.subscribe(response => { .subscribe(response => {
const blob = new Blob([response.body], { type: 'application/pdf' }); 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); FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('dmps', "pdf", id); this.matomoService.trackDownload('dmps', "pdf", id);
@ -632,7 +631,7 @@ export class RecentEditedActivityComponent extends BaseComponent implements OnIn
.pipe(takeUntil(this._destroyed)) .pipe(takeUntil(this._destroyed))
.subscribe(response => { .subscribe(response => {
const blob = new Blob([response.body], { type: 'application/json' }); 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); FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('dmps', "json", id); this.matomoService.trackDownload('dmps', "json", id);
}, async error => { }, async error => {
@ -651,7 +650,7 @@ export class RecentEditedActivityComponent extends BaseComponent implements OnIn
.pipe(takeUntil(this._destroyed)) .pipe(takeUntil(this._destroyed))
.subscribe(response => { .subscribe(response => {
const blob = new Blob([response.body], { type: 'application/pdf' }); 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); FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('datasets', "pdf", dataset.id); this.matomoService.trackDownload('datasets', "pdf", dataset.id);
@ -663,7 +662,7 @@ export class RecentEditedActivityComponent extends BaseComponent implements OnIn
.pipe(takeUntil(this._destroyed)) .pipe(takeUntil(this._destroyed))
.subscribe(response => { .subscribe(response => {
const blob = new Blob([response.body], { type: 'application/msword' }); 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); FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('datasets', "docx", dataset.id); this.matomoService.trackDownload('datasets', "docx", dataset.id);
@ -676,31 +675,13 @@ export class RecentEditedActivityComponent extends BaseComponent implements OnIn
.pipe(takeUntil(this._destroyed)) .pipe(takeUntil(this._destroyed))
.subscribe(response => { .subscribe(response => {
const blob = new Blob([response.body], { type: 'application/xml' }); 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); FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('datasets', "xml", dataset.id); 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) { // newVersion(id: String, label: String) {
// let url = this.router.createUrlTree(['/plans/new_version/', id, { dmpLabel: label }]); // let url = this.router.createUrlTree(['/plans/new_version/', id, { dmpLabel: label }]);
// window.open(url.toString(), '_blank'); // window.open(url.toString(), '_blank');
@ -809,14 +790,14 @@ export class RecentEditedActivityComponent extends BaseComponent implements OnIn
this.allRecentActivities.forEach(recentActivity => { this.allRecentActivities.forEach(recentActivity => {
if (recentActivity.type === RecentActivityType.Dataset) { if (recentActivity.type === RecentActivityType.Dataset) {
// this.datasetOffset = this.datasetOffset + 1; // this.datasetOffset = this.datasetOffset + 1;
this.datasetOffset = this.page*this.pageSize; this.datasetOffset = this.page * this.pageSize;
} else if (recentActivity.type === RecentActivityType.Dmp) { } else if (recentActivity.type === RecentActivityType.Dmp) {
// this.dmpOffset = this.dmpOffset + 1; // this.dmpOffset = this.dmpOffset + 1;
this.dmpOffset = this.page*this.pageSize; this.dmpOffset = this.page * this.pageSize;
} }
}); });
if(response.length< this.pageSize) { if (response.length < this.pageSize) {
this.hasMoreActivity = false; this.hasMoreActivity = false;
} else { } else {
this.hasMoreActivity = true; this.hasMoreActivity = true;
@ -829,10 +810,10 @@ export class RecentEditedActivityComponent extends BaseComponent implements OnIn
const fields: Array<string> = [((this.formGroup.get('order').value === 'status') || (this.formGroup.get('order').value === 'label') ? '+' : "-") + this.formGroup.get('order').value]; const fields: Array<string> = [((this.formGroup.get('order').value === 'status') || (this.formGroup.get('order').value === 'label') ? '+' : "-") + this.formGroup.get('order').value];
// const fields: Array<string> = ["-modified"]; // const fields: Array<string> = ["-modified"];
let request; let request;
if(more) { if (more) {
request = new DataTableMultiTypeRequest<RecentActivityCriteria>(this.dmpOffset, this.datasetOffset, this.pageSize, {fields: fields}); request = new DataTableMultiTypeRequest<RecentActivityCriteria>(this.dmpOffset, this.datasetOffset, this.pageSize, { fields: fields });
} else { } else {
request = new DataTableMultiTypeRequest<RecentActivityCriteria>(this.offsetLess, this.offsetLess, this.pageSize, {fields: fields}); request = new DataTableMultiTypeRequest<RecentActivityCriteria>(this.offsetLess, this.offsetLess, this.pageSize, { fields: fields });
} }
request.criteria = new RecentActivityCriteria(); request.criteria = new RecentActivityCriteria();
request.criteria.like = this.formGroup.get("like").value ? this.formGroup.get("like").value : ""; request.criteria.like = this.formGroup.get("like").value ? this.formGroup.get("like").value : "";
@ -860,7 +841,7 @@ export class RecentEditedActivityComponent extends BaseComponent implements OnIn
this.offsetLess = (this.page - 2) * this.pageSize; this.offsetLess = (this.page - 2) * this.pageSize;
} }
if(result.length < this.pageSize) { if (result.length < this.pageSize) {
this.hasMoreActivity = false; this.hasMoreActivity = false;
} else { } else {
this.hasMoreActivity = true; this.hasMoreActivity = true;

View File

@ -1,31 +1,32 @@
import {Component, OnInit, Output, EventEmitter, Input, ViewChild} from '@angular/core'; import { Location } from '@angular/common';
import { DatasetListingModel } from '@app/core/model/dataset/dataset-listing'; import { HttpClient } from '@angular/common/http';
import { DatasetService } from '@app/core/services/dataset/dataset.service'; import { Component, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core';
import { DataTableRequest } from '@app/core/model/data-table/data-table-request'; import { UntypedFormBuilder, UntypedFormControl } from '@angular/forms';
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 { MatDialog } from '@angular/material/dialog'; import { MatDialog } from '@angular/material/dialog';
import { debounceTime, takeUntil } from 'rxjs/operators'; import { ActivatedRoute, Router } from '@angular/router';
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 { 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 { RecentActivityOrder } from '@app/core/common/enum/recent-activity-order';
import { Role } from '@app/core/common/enum/role'; 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 { LockService } from '@app/core/services/lock/lock.service';
import { MatomoService } from '@app/core/services/matomo/matomo-service'; import { MatomoService } from '@app/core/services/matomo/matomo-service';
import { HttpClient } from '@angular/common/http'; import { SnackBarNotificationLevel, UiNotificationService } from '@app/core/services/notification/ui-notification-service';
import {ConfigurationService} from "@app/core/services/configuration/configuration.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({ @Component({
selector: 'app-recent-edited-dataset-activity', selector: 'app-recent-edited-dataset-activity',
@ -42,7 +43,7 @@ export class RecentEditedDatasetActivityComponent extends BaseComponent implemen
totalCount: number; totalCount: number;
startIndex: number = 0; startIndex: number = 0;
offsetLess: number = 0; offsetLess: number = 0;
hasMoreResults:boolean = true; hasMoreResults: boolean = true;
pageSize: number = 5; pageSize: number = 5;
public formGroup = new UntypedFormBuilder().group({ public formGroup = new UntypedFormBuilder().group({
like: new UntypedFormControl(), like: new UntypedFormControl(),
@ -69,7 +70,8 @@ export class RecentEditedDatasetActivityComponent extends BaseComponent implemen
private lockService: LockService, private lockService: LockService,
private httpClient: HttpClient, private httpClient: HttpClient,
private matomoService: MatomoService, private matomoService: MatomoService,
private configurationService: ConfigurationService private configurationService: ConfigurationService,
private fileUtils: FileUtils
) { ) {
super(); super();
} }
@ -77,22 +79,22 @@ export class RecentEditedDatasetActivityComponent extends BaseComponent implemen
ngOnInit() { ngOnInit() {
this.matomoService.trackPageView('Recent Dataset Activity'); this.matomoService.trackPageView('Recent Dataset Activity');
this.route.queryParams.subscribe(params => { this.route.queryParams.subscribe(params => {
if(this.isActive) { if (this.isActive) {
let page = (params['page'] === undefined) ? 1 : +params['page']; let page = (params['page'] === undefined) ? 1 : +params['page'];
this.page = (page <= 0) ? 1 : page; this.page = (page <= 0) ? 1 : page;
this.startIndex = (this.page-1)*this.pageSize; this.startIndex = (this.page - 1) * this.pageSize;
if(this.page > 1) { if (this.page > 1) {
this.offsetLess = (this.page-2)*this.pageSize; this.offsetLess = (this.page - 2) * this.pageSize;
} }
let order = params['order']; let order = params['order'];
if (this.isAuthenticated()) { if (this.isAuthenticated()) {
if(order === undefined || (order != this.order.MODIFIED && order != this.order.LABEL && order != this.order.STATUS)) { if (order === undefined || (order != this.order.MODIFIED && order != this.order.LABEL && order != this.order.STATUS)) {
order = this.order.MODIFIED; order = this.order.MODIFIED;
} }
} else { } else {
if(order === undefined || (order != this.order.DATASETPUBLISHED && order != this.order.LABEL)) { if (order === undefined || (order != this.order.DATASETPUBLISHED && order != this.order.LABEL)) {
order = this.order.DATASETPUBLISHED; order = this.order.DATASETPUBLISHED;
} }
} }
@ -106,7 +108,7 @@ export class RecentEditedDatasetActivityComponent extends BaseComponent implemen
}); });
if (this.isAuthenticated()) { if (this.isAuthenticated()) {
// const fields: Array<string> = ["-modified"]; // const fields: Array<string> = ["-modified"];
if(!this.formGroup.get('order').value) { if (!this.formGroup.get('order').value) {
this.formGroup.get('order').setValue(this.order.MODIFIED); this.formGroup.get('order').setValue(this.order.MODIFIED);
} }
const fields: Array<string> = [((this.formGroup.get('order').value === 'status') || (this.formGroup.get('order').value === 'label') ? '+' : "-") + this.formGroup.get('order').value]; const fields: Array<string> = [((this.formGroup.get('order').value === 'status') || (this.formGroup.get('order').value === 'label') ? '+' : "-") + this.formGroup.get('order').value];
@ -120,15 +122,15 @@ export class RecentEditedDatasetActivityComponent extends BaseComponent implemen
this.datasetActivities = response.data; this.datasetActivities = response.data;
this.totalCount = response.totalCount; this.totalCount = response.totalCount;
this.totalCountDatasets.emit(this.datasetActivities.length) this.totalCountDatasets.emit(this.datasetActivities.length)
if(this.totalCount > 0 && this.totalCount <= (this.page-1)*this.pageSize && this.page > 1) { if (this.totalCount > 0 && this.totalCount <= (this.page - 1) * this.pageSize && this.page > 1) {
let queryParams = { type: "datasets", page: 1, order: this.formGroup.get("order").value }; let queryParams = { type: "datasets", page: 1, order: this.formGroup.get("order").value };
if(this.formGroup.get("like").value) { if (this.formGroup.get("like").value) {
queryParams['keyword'] = this.formGroup.get("like").value; queryParams['keyword'] = this.formGroup.get("like").value;
} }
this.router.navigate(["/home"], { queryParams: queryParams }) this.router.navigate(["/home"], { queryParams: queryParams })
} }
}); });
this.formGroup.get('like').valueChanges this.formGroup.get('like').valueChanges
.pipe(takeUntil(this._destroyed), debounceTime(500)) .pipe(takeUntil(this._destroyed), debounceTime(500))
.subscribe(x => this.refresh()); .subscribe(x => this.refresh());
this.formGroup.get('order').valueChanges this.formGroup.get('order').valueChanges
@ -136,7 +138,7 @@ export class RecentEditedDatasetActivityComponent extends BaseComponent implemen
.subscribe(x => this.refresh()); .subscribe(x => this.refresh());
} else { } else {
this.publicMode = true; this.publicMode = true;
if(!this.formGroup.get('order').value) { if (!this.formGroup.get('order').value) {
this.formGroup.get('order').setValue(this.order.DATASETPUBLISHED); this.formGroup.get('order').setValue(this.order.DATASETPUBLISHED);
} }
const dataTableRequest = this.setPublicDataTableRequest(); const dataTableRequest = this.setPublicDataTableRequest();
@ -144,12 +146,12 @@ export class RecentEditedDatasetActivityComponent extends BaseComponent implemen
this.datasetActivities = response.data; this.datasetActivities = response.data;
this.totalCount = response.totalCount; this.totalCount = response.totalCount;
this.totalCountDatasets.emit(this.datasetActivities.length); this.totalCountDatasets.emit(this.datasetActivities.length);
if(this.totalCount > 0 && this.totalCount <= (this.page-1)*this.pageSize && this.page > 1) { if (this.totalCount > 0 && this.totalCount <= (this.page - 1) * this.pageSize && this.page > 1) {
let queryParams = { type: "datasets", page: 1, order: this.formGroup.get("order").value }; let queryParams = { type: "datasets", page: 1, order: this.formGroup.get("order").value };
if(this.formGroup.get("like").value) { if (this.formGroup.get("like").value) {
queryParams['keyword'] = this.formGroup.get("like").value; queryParams['keyword'] = this.formGroup.get("like").value;
} }
this.router.navigate(["/home"], { queryParams: queryParams }) this.router.navigate(["/home"], { queryParams: queryParams })
} }
}); });
this.formGroup.get('like').valueChanges this.formGroup.get('like').valueChanges
@ -162,17 +164,17 @@ export class RecentEditedDatasetActivityComponent extends BaseComponent implemen
} }
ngOnChanges() { ngOnChanges() {
if(this.isActive) { if (this.isActive) {
this.updateUrl(); this.updateUrl();
} }
} }
updateUrl() { updateUrl() {
let parameters = "?type=datasets"+ let parameters = "?type=datasets" +
(this.page != 1 ? "&page="+this.page : "") + (this.page != 1 ? "&page=" + this.page : "") +
(((this.formGroup.get("order").value != this.order.MODIFIED && !this.publicMode) || (this.formGroup.get("order").value != this.order.DATASETPUBLISHED && this.publicMode)) ? "&order="+this.formGroup.get("order").value : "") + (((this.formGroup.get("order").value != this.order.MODIFIED && !this.publicMode) || (this.formGroup.get("order").value != this.order.DATASETPUBLISHED && this.publicMode)) ? "&order=" + this.formGroup.get("order").value : "") +
(this.formGroup.get("like").value ? ("&keyword="+this.formGroup.get("like").value) : ""); (this.formGroup.get("like").value ? ("&keyword=" + this.formGroup.get("like").value) : "");
this.location.go(this.router.url.split('?')[0]+parameters); this.location.go(this.router.url.split('?')[0] + parameters);
} }
setPublicDataTableRequest(fields?: Array<string>, more: boolean = true): DataTableRequest<DatasetCriteria> { setPublicDataTableRequest(fields?: Array<string>, more: boolean = true): DataTableRequest<DatasetCriteria> {
@ -207,7 +209,7 @@ export class RecentEditedDatasetActivityComponent extends BaseComponent implemen
this.datasetActivities = response.data; this.datasetActivities = response.data;
this.totalCount = response.totalCount; this.totalCount = response.totalCount;
this.totalCountDatasets.emit(this.datasetActivities.length); this.totalCountDatasets.emit(this.datasetActivities.length);
if(response.data.length< this.pageSize) { if (response.data.length < this.pageSize) {
this.hasMoreResults = false; this.hasMoreResults = false;
} else { } else {
this.hasMoreResults = true; this.hasMoreResults = true;
@ -220,12 +222,12 @@ export class RecentEditedDatasetActivityComponent extends BaseComponent implemen
const fields: Array<string> = [((this.formGroup.get('order').value === 'status') || (this.formGroup.get('order').value === 'label') ? '+' : "-") + this.formGroup.get('order').value]; const fields: Array<string> = [((this.formGroup.get('order').value === 'status') || (this.formGroup.get('order').value === 'label') ? '+' : "-") + this.formGroup.get('order').value];
let request; let request;
this.startIndex = (this.page)*this.pageSize; this.startIndex = (this.page) * this.pageSize;
if(this.page > 1) { if (this.page > 1) {
this.offsetLess = (this.page-2)*this.pageSize; this.offsetLess = (this.page - 2) * this.pageSize;
} }
if(this.isAuthenticated()) { if (this.isAuthenticated()) {
if(more) { if (more) {
request = new DataTableRequest<DatasetCriteria>(this.startIndex, this.pageSize, { fields: fields }); request = new DataTableRequest<DatasetCriteria>(this.startIndex, this.pageSize, { fields: fields });
} else { } else {
request = new DataTableRequest<DatasetCriteria>(this.offsetLess, this.pageSize, { fields: fields }); request = new DataTableRequest<DatasetCriteria>(this.offsetLess, this.pageSize, { fields: fields });
@ -249,7 +251,7 @@ export class RecentEditedDatasetActivityComponent extends BaseComponent implemen
// this.datasetActivities = this.datasetActivities.length > 0 ? this.mergeTwoSortedLists(this.datasetActivities, result.data, this.formGroup.get('order').value) : result.data; // this.datasetActivities = this.datasetActivities.length > 0 ? this.mergeTwoSortedLists(this.datasetActivities, result.data, this.formGroup.get('order').value) : result.data;
this.datasetActivities = result.data; this.datasetActivities = result.data;
if(result.data.length < this.pageSize) { if (result.data.length < this.pageSize) {
this.hasMoreResults = false; this.hasMoreResults = false;
} else { } else {
this.hasMoreResults = true; this.hasMoreResults = true;
@ -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 { downloadPDF(dataset: DatasetListingModel): void {
this.datasetWizardService.downloadPDF(dataset.id as string) this.datasetWizardService.downloadPDF(dataset.id as string)
.pipe(takeUntil(this._destroyed)) .pipe(takeUntil(this._destroyed))
.subscribe(response => { .subscribe(response => {
const blob = new Blob([response.body], { type: 'application/pdf' }); 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); FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('datasets', "pdf", dataset.id); this.matomoService.trackDownload('datasets', "pdf", dataset.id);
@ -419,7 +403,7 @@ export class RecentEditedDatasetActivityComponent extends BaseComponent implemen
.pipe(takeUntil(this._destroyed)) .pipe(takeUntil(this._destroyed))
.subscribe(response => { .subscribe(response => {
const blob = new Blob([response.body], { type: 'application/msword' }); 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); FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('datasets', "docx", dataset.id); this.matomoService.trackDownload('datasets', "docx", dataset.id);
@ -432,7 +416,7 @@ export class RecentEditedDatasetActivityComponent extends BaseComponent implemen
.pipe(takeUntil(this._destroyed)) .pipe(takeUntil(this._destroyed))
.subscribe(response => { .subscribe(response => {
const blob = new Blob([response.body], { type: 'application/xml' }); 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); FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('datasets', "xml", dataset.id); 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 { MatDialog } from '@angular/material/dialog';
import {ActivatedRoute, Router} from '@angular/router'; 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 { 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 { 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 { DmpListingModel } from '@app/core/model/dmp/dmp-listing';
import { DmpCriteria } from '@app/core/query/dmp/dmp-criteria'; import { DmpCriteria } from '@app/core/query/dmp/dmp-criteria';
import { AuthService } from '@app/core/services/auth/auth.service'; 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 { 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 { SnackBarNotificationLevel, UiNotificationService } from '@app/core/services/notification/ui-notification-service';
import { EnumUtils } from '@app/core/services/utilities/enum-utils.service'; import { EnumUtils } from '@app/core/services/utilities/enum-utils.service';
import { ConfirmationDialogComponent } from '@common/modules/confirmation-dialog/confirmation-dialog.component'; import { FileUtils } from '@app/core/services/utilities/file-utils.service';
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 { CloneDialogComponent } from '@app/ui/dmp/clone/clone-dialog/clone-dialog.component'; import { CloneDialogComponent } from '@app/ui/dmp/clone/clone-dialog/clone-dialog.component';
import { DmpEditorModel } from '@app/ui/dmp/editor/dmp-editor.model'; 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 { 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 { 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 { ProjectFormModel } from '@app/ui/dmp/editor/grant-tab/project-form-model';
import { MatomoService } from '@app/core/services/matomo/matomo-service'; import { DmpInvitationDialogComponent } from '@app/ui/dmp/invitation/dmp-invitation-dialog.component';
import { HttpClient } from '@angular/common/http';
import { isNullOrUndefined } from '@app/utilities/enhancers/utils'; import { isNullOrUndefined } from '@app/utilities/enhancers/utils';
import { DmpBlueprintService } from '@app/core/services/dmp/dmp-blueprint.service'; import { BaseComponent } from '@common/base/base.component';
import { DmpBlueprintSystemFieldType } from '@app/core/common/enum/dmp-blueprint-system-field-type'; import { ConfirmationDialogComponent } from '@common/modules/confirmation-dialog/confirmation-dialog.component';
import { DescriptionTemplatesInSection, DmpBlueprint, DmpBlueprintDefinition, DmpBlueprintDefinitionSection, FieldInSection } from '@app/core/model/dmp-blueprint/dmp-blueprint';
import { Guid } from '@common/types/guid'; 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'; import { nameof } from 'ts-simple-nameof';
@Component({ @Component({
@ -60,7 +60,7 @@ export class RecentEditedDmpActivityComponent extends BaseComponent implements O
totalCount: number; totalCount: number;
startIndex: number = 0; startIndex: number = 0;
offsetLess: number = 0; offsetLess: number = 0;
hasMoreResults:boolean = true; hasMoreResults: boolean = true;
pageSize: number = 5; pageSize: number = 5;
dmpFormGroup: UntypedFormGroup; dmpFormGroup: UntypedFormGroup;
public formGroup = new UntypedFormBuilder().group({ public formGroup = new UntypedFormBuilder().group({
@ -88,7 +88,8 @@ export class RecentEditedDmpActivityComponent extends BaseComponent implements O
private location: Location, private location: Location,
private lockService: LockService, private lockService: LockService,
private httpClient: HttpClient, private httpClient: HttpClient,
private matomoService: MatomoService private matomoService: MatomoService,
private fileUtils: FileUtils
) { ) {
super(); super();
} }
@ -96,22 +97,22 @@ export class RecentEditedDmpActivityComponent extends BaseComponent implements O
ngOnInit() { ngOnInit() {
this.matomoService.trackPageView('Recent DMP Activity'); this.matomoService.trackPageView('Recent DMP Activity');
this.route.queryParams.subscribe(params => { this.route.queryParams.subscribe(params => {
if(this.isActive) { if (this.isActive) {
let page = (params['page'] === undefined) ? 1 : +params['page']; let page = (params['page'] === undefined) ? 1 : +params['page'];
this.page = (page <= 0) ? 1 : page; this.page = (page <= 0) ? 1 : page;
this.startIndex = (this.page-1)*this.pageSize; this.startIndex = (this.page - 1) * this.pageSize;
if(this.page > 1) { if (this.page > 1) {
this.offsetLess = (this.page-2)*this.pageSize; this.offsetLess = (this.page - 2) * this.pageSize;
} }
let order = params['order']; let order = params['order'];
if (this.isAuthenticated()) { if (this.isAuthenticated()) {
if(order === undefined || (order != this.order.MODIFIED && order != this.order.LABEL && order != this.order.STATUS)) { if (order === undefined || (order != this.order.MODIFIED && order != this.order.LABEL && order != this.order.STATUS)) {
order = this.order.MODIFIED; order = this.order.MODIFIED;
} }
} else { } else {
if(order === undefined || (order != this.order.PUBLISHED && order != this.order.LABEL)) { if (order === undefined || (order != this.order.PUBLISHED && order != this.order.LABEL)) {
order = this.order.PUBLISHED; order = this.order.PUBLISHED;
} }
} }
@ -125,7 +126,7 @@ export class RecentEditedDmpActivityComponent extends BaseComponent implements O
}); });
if (this.isAuthenticated()) { if (this.isAuthenticated()) {
// const fields: Array<string> = ["-modified"]; // const fields: Array<string> = ["-modified"];
if(!this.formGroup.get('order').value) { if (!this.formGroup.get('order').value) {
this.formGroup.get('order').setValue(this.order.MODIFIED); this.formGroup.get('order').setValue(this.order.MODIFIED);
} }
const fields: Array<string> = [((this.formGroup.get('order').value === 'status') || (this.formGroup.get('order').value === 'label') ? '+' : "-") + this.formGroup.get('order').value]; const fields: Array<string> = [((this.formGroup.get('order').value === 'status') || (this.formGroup.get('order').value === 'label') ? '+' : "-") + this.formGroup.get('order').value];
@ -139,12 +140,12 @@ export class RecentEditedDmpActivityComponent extends BaseComponent implements O
this.dmpActivities = response.data; this.dmpActivities = response.data;
this.totalCount = response.totalCount; this.totalCount = response.totalCount;
this.totalCountDmps.emit(this.dmpActivities.length); this.totalCountDmps.emit(this.dmpActivities.length);
if(this.totalCount > 0 && this.totalCount <= (this.page-1)*this.pageSize && this.page > 1) { if (this.totalCount > 0 && this.totalCount <= (this.page - 1) * this.pageSize && this.page > 1) {
let queryParams = { type: "dmps", page: 1, order: this.formGroup.get("order").value }; let queryParams = { type: "dmps", page: 1, order: this.formGroup.get("order").value };
if(this.formGroup.get("like").value) { if (this.formGroup.get("like").value) {
queryParams['keyword'] = this.formGroup.get("like").value; queryParams['keyword'] = this.formGroup.get("like").value;
} }
this.router.navigate(["/home"], { queryParams: queryParams }) this.router.navigate(["/home"], { queryParams: queryParams })
} }
// this.totalCount < this.pageSize ? this.totalCountDmps.emit(response.totalCount) : this.totalCountDmps.emit(this.pageSize); // this.totalCount < this.pageSize ? this.totalCountDmps.emit(response.totalCount) : this.totalCountDmps.emit(this.pageSize);
// this.totalCountDmps.emit(this.totalCount); // this.totalCountDmps.emit(this.totalCount);
@ -179,7 +180,7 @@ export class RecentEditedDmpActivityComponent extends BaseComponent implements O
// }); // });
} else { } else {
this.publicMode = true; this.publicMode = true;
if(!this.formGroup.get('order').value) { if (!this.formGroup.get('order').value) {
this.formGroup.get('order').setValue(this.order.PUBLISHED); this.formGroup.get('order').setValue(this.order.PUBLISHED);
} }
const dataTableRequest = this.setPublicDataTableRequest(); const dataTableRequest = this.setPublicDataTableRequest();
@ -188,12 +189,12 @@ export class RecentEditedDmpActivityComponent extends BaseComponent implements O
this.dmpActivities = response.data; this.dmpActivities = response.data;
this.totalCount = response.totalCount; this.totalCount = response.totalCount;
this.totalCountDmps.emit(this.dmpActivities.length); this.totalCountDmps.emit(this.dmpActivities.length);
if(this.totalCount > 0 && this.totalCount <= (this.page-1)*this.pageSize && this.page > 1) { if (this.totalCount > 0 && this.totalCount <= (this.page - 1) * this.pageSize && this.page > 1) {
let queryParams = { type: "dmps", page: 1, order: this.formGroup.get("order").value }; let queryParams = { type: "dmps", page: 1, order: this.formGroup.get("order").value };
if(this.formGroup.get("like").value) { if (this.formGroup.get("like").value) {
queryParams['keyword'] = this.formGroup.get("like").value; queryParams['keyword'] = this.formGroup.get("like").value;
} }
this.router.navigate(["/home"], { queryParams: queryParams }) this.router.navigate(["/home"], { queryParams: queryParams })
} }
}); });
this.formGroup.get('like').valueChanges this.formGroup.get('like').valueChanges
@ -206,17 +207,17 @@ export class RecentEditedDmpActivityComponent extends BaseComponent implements O
} }
ngOnChanges() { ngOnChanges() {
if(this.isActive) { if (this.isActive) {
this.updateUrl(); this.updateUrl();
} }
} }
updateUrl() { updateUrl() {
let parameters = "?type=dmps"+ let parameters = "?type=dmps" +
(this.page != 1 ? "&page="+this.page : "") + (this.page != 1 ? "&page=" + this.page : "") +
(((this.formGroup.get("order").value != this.order.MODIFIED && !this.publicMode) || (this.formGroup.get("order").value != this.order.PUBLISHED && this.publicMode)) ? "&order="+this.formGroup.get("order").value : "") + (((this.formGroup.get("order").value != this.order.MODIFIED && !this.publicMode) || (this.formGroup.get("order").value != this.order.PUBLISHED && this.publicMode)) ? "&order=" + this.formGroup.get("order").value : "") +
(this.formGroup.get("like").value ? ("&keyword="+this.formGroup.get("like").value) : ""); (this.formGroup.get("like").value ? ("&keyword=" + this.formGroup.get("like").value) : "");
this.location.go(this.router.url.split('?')[0]+parameters); this.location.go(this.router.url.split('?')[0] + parameters);
} }
public isAuthenticated(): boolean { public isAuthenticated(): boolean {
@ -299,10 +300,10 @@ export class RecentEditedDmpActivityComponent extends BaseComponent implements O
[nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.descriptionTemplates), nameof<DescriptionTemplatesInSection>(x => x.maxMultiplicity)].join('.'), [nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.descriptionTemplates), nameof<DescriptionTemplatesInSection>(x => x.maxMultiplicity)].join('.'),
] ]
) )
.pipe(map(data => data as DmpBlueprint), takeUntil(this._destroyed)) .pipe(map(data => data as DmpBlueprint), takeUntil(this._destroyed))
.subscribe( .subscribe(
data => successFunction(data), data => successFunction(data),
); );
} }
private checkForGrant(blueprint: DmpBlueprintDefinition) { private checkForGrant(blueprint: DmpBlueprintDefinition) {
@ -522,7 +523,7 @@ export class RecentEditedDmpActivityComponent extends BaseComponent implements O
.pipe(takeUntil(this._destroyed)) .pipe(takeUntil(this._destroyed))
.subscribe(response => { .subscribe(response => {
const blob = new Blob([response.body], { type: 'application/xml' }); 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); FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('dmps', "xml", id); this.matomoService.trackDownload('dmps', "xml", id);
@ -534,7 +535,7 @@ export class RecentEditedDmpActivityComponent extends BaseComponent implements O
.pipe(takeUntil(this._destroyed)) .pipe(takeUntil(this._destroyed))
.subscribe(response => { .subscribe(response => {
const blob = new Blob([response.body], { type: 'application/msword' }); 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); FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('dmps', "docx", id); this.matomoService.trackDownload('dmps', "docx", id);
@ -546,7 +547,7 @@ export class RecentEditedDmpActivityComponent extends BaseComponent implements O
.pipe(takeUntil(this._destroyed)) .pipe(takeUntil(this._destroyed))
.subscribe(response => { .subscribe(response => {
const blob = new Blob([response.body], { type: 'application/pdf' }); 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); FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('dmps', "pdf", id); this.matomoService.trackDownload('dmps', "pdf", id);
@ -558,7 +559,7 @@ export class RecentEditedDmpActivityComponent extends BaseComponent implements O
.pipe(takeUntil(this._destroyed)) .pipe(takeUntil(this._destroyed))
.subscribe(response => { .subscribe(response => {
const blob = new Blob([response.body], { type: 'application/json' }); 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); FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('dmps', "json", id); this.matomoService.trackDownload('dmps', "json", id);
}, async error => { }, async error => {
@ -572,24 +573,6 @@ export class RecentEditedDmpActivityComponent extends BaseComponent implements O
this.uiNotificationService.snackBarNotification(errorObj.message, SnackBarNotificationLevel.Error); 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) { // newVersion(id: String, label: String) {
// let url = this.router.createUrlTree(['/plans/new_version/', id, { dmpLabel: label }]); // let url = this.router.createUrlTree(['/plans/new_version/', id, { dmpLabel: label }]);
// window.open(url.toString(), '_blank'); // window.open(url.toString(), '_blank');
@ -624,7 +607,7 @@ export class RecentEditedDmpActivityComponent extends BaseComponent implements O
this.dmpActivities = response.data; this.dmpActivities = response.data;
this.totalCount = response.totalCount; this.totalCount = response.totalCount;
this.totalCountDmps.emit(this.dmpActivities.length); this.totalCountDmps.emit(this.dmpActivities.length);
if(response.data.length< this.pageSize) { if (response.data.length < this.pageSize) {
this.hasMoreResults = false; this.hasMoreResults = false;
} else { } else {
this.hasMoreResults = true; this.hasMoreResults = true;
@ -637,15 +620,15 @@ export class RecentEditedDmpActivityComponent extends BaseComponent implements O
const fields: Array<string> = [((this.formGroup.get('order').value === 'status') || (this.formGroup.get('order').value === 'label') ? '+' : "-") + this.formGroup.get('order').value]; const fields: Array<string> = [((this.formGroup.get('order').value === 'status') || (this.formGroup.get('order').value === 'label') ? '+' : "-") + this.formGroup.get('order').value];
let request; let request;
this.startIndex = (this.page)*this.pageSize; this.startIndex = (this.page) * this.pageSize;
if(this.page > 1) { if (this.page > 1) {
this.offsetLess = (this.page-2)*this.pageSize; this.offsetLess = (this.page - 2) * this.pageSize;
} }
if(this.isAuthenticated()) { if (this.isAuthenticated()) {
if(more) { if (more) {
request = new DataTableRequest<DmpCriteria>(this.startIndex, this.pageSize, {fields: fields}) request = new DataTableRequest<DmpCriteria>(this.startIndex, this.pageSize, { fields: fields })
} else { } else {
request = new DataTableRequest<DmpCriteria>(this.offsetLess, this.pageSize, {fields: fields}) request = new DataTableRequest<DmpCriteria>(this.offsetLess, this.pageSize, { fields: fields })
} }
} else { } else {
request = this.setPublicDataTableRequest(fields, more); request = this.setPublicDataTableRequest(fields, more);
@ -666,7 +649,7 @@ export class RecentEditedDmpActivityComponent extends BaseComponent implements O
// this.dmpActivities = this.dmpActivities.length > 0 ? this.mergeTwoSortedLists(this.dmpActivities, result.data, this.formGroup.get('order').value) : result.data; // this.dmpActivities = this.dmpActivities.length > 0 ? this.mergeTwoSortedLists(this.dmpActivities, result.data, this.formGroup.get('order').value) : result.data;
this.dmpActivities = result.data; this.dmpActivities = result.data;
if(result.data.length < this.pageSize) { if (result.data.length < this.pageSize) {
this.hasMoreResults = false; this.hasMoreResults = false;
} else { } else {
this.hasMoreResults = true; this.hasMoreResults = true;

View File

@ -32,6 +32,7 @@ import {
SnackBarNotificationLevel, SnackBarNotificationLevel,
UiNotificationService UiNotificationService
} from '@app/core/services/notification/ui-notification-service'; } 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 { SingleAutoCompleteConfiguration } from '@app/library/auto-complete/single/single-auto-complete-configuration';
import { CheckDeactivateBaseComponent } from '@app/library/deactivate/deactivate.component'; import { CheckDeactivateBaseComponent } from '@app/library/deactivate/deactivate.component';
import { PopupNotificationDialogComponent } from '@app/library/notification/popup/popup-notification.component'; import { PopupNotificationDialogComponent } from '@app/library/notification/popup/popup-notification.component';
@ -68,7 +69,7 @@ import { catchError, debounceTime, filter, map, takeUntil } from 'rxjs/operators
templateUrl: 'dataset-wizard.component.html', templateUrl: 'dataset-wizard.component.html',
styleUrls: ['./dataset-wizard.component.scss'] styleUrls: ['./dataset-wizard.component.scss']
}) })
export class DatasetWizardComponent extends CheckDeactivateBaseComponent implements OnInit {//IBreadCrumbComponent export class DatasetWizardComponent extends CheckDeactivateBaseComponent implements OnInit {//IBreadCrumbComponent
canDeactivate(): boolean { canDeactivate(): boolean {
return !this.isDirty(); return !this.isDirty();
} }
@ -141,7 +142,8 @@ export class DatasetWizardComponent extends CheckDeactivateBaseComponent impleme
private authService: AuthService, private authService: AuthService,
private configurationService: ConfigurationService, private configurationService: ConfigurationService,
private httpClient: HttpClient, private httpClient: HttpClient,
private matomoService: MatomoService private matomoService: MatomoService,
private fileUtils: FileUtils
) { ) {
super(); super();
} }
@ -1026,7 +1028,7 @@ export class DatasetWizardComponent extends CheckDeactivateBaseComponent impleme
.pipe(takeUntil(this._destroyed)) .pipe(takeUntil(this._destroyed))
.subscribe(response => { .subscribe(response => {
const blob = new Blob([response.body], { type: 'application/pdf' }); 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); FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('datasets', "pdf", id); this.matomoService.trackDownload('datasets', "pdf", id);
@ -1038,7 +1040,7 @@ export class DatasetWizardComponent extends CheckDeactivateBaseComponent impleme
.pipe(takeUntil(this._destroyed)) .pipe(takeUntil(this._destroyed))
.subscribe(response => { .subscribe(response => {
const blob = new Blob([response.body], { type: 'application/msword' }); 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); FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('datasets', "docx", id); this.matomoService.trackDownload('datasets', "docx", id);
@ -1051,7 +1053,7 @@ export class DatasetWizardComponent extends CheckDeactivateBaseComponent impleme
.pipe(takeUntil(this._destroyed)) .pipe(takeUntil(this._destroyed))
.subscribe(response => { .subscribe(response => {
const blob = new Blob([response.body], { type: 'application/xml' }); 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); FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('datasets', "xml", id); 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() { public redirectToGrant() {
this.router.navigate(['grants/edit/' + this.datasetWizardModel.dmp.grant.id]); 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 { Location } from '@angular/common';
import { MatomoService } from '@app/core/services/matomo/matomo-service';
import { HttpClient } from '@angular/common/http'; 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({ @Component({
selector: 'app-dataset-listing-item-component', selector: 'app-dataset-listing-item-component',
@ -49,7 +49,8 @@ export class DatasetListingItemComponent extends BaseComponent implements OnInit
private lockService: LockService, private lockService: LockService,
private location: Location, private location: Location,
private httpClient: HttpClient, private httpClient: HttpClient,
private matomoService: MatomoService private matomoService: MatomoService,
private fileUtils: FileUtils
) { ) {
super(); super();
} }
@ -95,7 +96,7 @@ export class DatasetListingItemComponent extends BaseComponent implements OnInit
.pipe(takeUntil(this._destroyed)) .pipe(takeUntil(this._destroyed))
.subscribe(response => { .subscribe(response => {
const blob = new Blob([response.body], { type: 'application/pdf' }); 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); FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('datasets', "pdf", dataset.id); this.matomoService.trackDownload('datasets', "pdf", dataset.id);
@ -107,7 +108,7 @@ export class DatasetListingItemComponent extends BaseComponent implements OnInit
.pipe(takeUntil(this._destroyed)) .pipe(takeUntil(this._destroyed))
.subscribe(response => { .subscribe(response => {
const blob = new Blob([response.body], { type: 'application/msword' }); 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); FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('datasets', "docx", dataset.id); this.matomoService.trackDownload('datasets', "docx", dataset.id);
@ -120,31 +121,13 @@ export class DatasetListingItemComponent extends BaseComponent implements OnInit
.pipe(takeUntil(this._destroyed)) .pipe(takeUntil(this._destroyed))
.subscribe(response => { .subscribe(response => {
const blob = new Blob([response.body], { type: 'application/xml' }); 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); FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('datasets', "xml", dataset.id); 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) { openShareDialog(dmpRowId: any, dmpRowName: any) {
const dialogRef = this.dialog.open(DmpInvitationDialogComponent, { const dialogRef = this.dialog.open(DmpInvitationDialogComponent, {
// height: '250px', // height: '250px',

View File

@ -1,38 +1,37 @@
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { BaseComponent } from '@common/base/base.component';
import { DatasetOverviewModel } from '@app/core/model/dataset/dataset-overview'; 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 { 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 { 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 { 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 { 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({ @Component({
@ -73,7 +72,8 @@ export class DatasetOverviewComponent extends BaseComponent implements OnInit {
private datasetWizardService: DatasetWizardService, private datasetWizardService: DatasetWizardService,
private lockService: LockService, private lockService: LockService,
private httpClient: HttpClient, private httpClient: HttpClient,
private matomoService: MatomoService private matomoService: MatomoService,
private fileUtils: FileUtils
) { ) {
super(); super();
} }
@ -140,11 +140,13 @@ export class DatasetOverviewComponent extends BaseComponent implements OnInit {
this.lockService.checkLockStatus(id).pipe(takeUntil(this._destroyed)) this.lockService.checkLockStatus(id).pipe(takeUntil(this._destroyed))
.subscribe(lockStatus => { .subscribe(lockStatus => {
this.lockStatus = lockStatus this.lockStatus = lockStatus
if(lockStatus){ if (lockStatus) {
this.dialog.open(PopupNotificationDialogComponent,{data:{ this.dialog.open(PopupNotificationDialogComponent, {
title:this.language.instant('DATASET-OVERVIEW.LOCKED.TITLE'), data: {
message:this.language.instant('DATASET-OVERVIEW.LOCKED.MESSAGE') title: this.language.instant('DATASET-OVERVIEW.LOCKED.TITLE'),
}, maxWidth:'30em'}); message: this.language.instant('DATASET-OVERVIEW.LOCKED.MESSAGE')
}, maxWidth: '30em'
});
} }
}); });
} }
@ -308,9 +310,9 @@ export class DatasetOverviewComponent extends BaseComponent implements OnInit {
} }
onUpdateCallbackError(error) { onUpdateCallbackError(error) {
this.uiNotificationService.snackBarNotification(error.error.message ? this.tryTranslate( error.error.message) : this.language.instant('DATASET-UPLOAD.SNACK-BAR.UNSUCCESSFUL'), SnackBarNotificationLevel.Error); this.uiNotificationService.snackBarNotification(error.error.message ? this.tryTranslate(error.error.message) : this.language.instant('DATASET-UPLOAD.SNACK-BAR.UNSUCCESSFUL'), SnackBarNotificationLevel.Error);
} }
tryTranslate(errorMessage: string): string{ tryTranslate(errorMessage: string): string {
return errorMessage.replace('Field value of', this.language.instant('Field value of')) return errorMessage.replace('Field value of', this.language.instant('Field value of'))
.replace('must be filled', this.language.instant('must be filled')); .replace('must be filled', this.language.instant('must be filled'));
} }
@ -335,7 +337,7 @@ export class DatasetOverviewComponent extends BaseComponent implements OnInit {
.pipe(takeUntil(this._destroyed)) .pipe(takeUntil(this._destroyed))
.subscribe(response => { .subscribe(response => {
const blob = new Blob([response.body], { type: 'application/pdf' }); 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); FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('datasets', "pdf", id); this.matomoService.trackDownload('datasets', "pdf", id);
@ -347,7 +349,7 @@ export class DatasetOverviewComponent extends BaseComponent implements OnInit {
.pipe(takeUntil(this._destroyed)) .pipe(takeUntil(this._destroyed))
.subscribe(response => { .subscribe(response => {
const blob = new Blob([response.body], { type: 'application/msword' }); 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); FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('datasets', "docx", id); this.matomoService.trackDownload('datasets', "docx", id);
@ -359,7 +361,7 @@ export class DatasetOverviewComponent extends BaseComponent implements OnInit {
.pipe(takeUntil(this._destroyed)) .pipe(takeUntil(this._destroyed))
.subscribe(response => { .subscribe(response => {
const blob = new Blob([response.body], { type: 'application/xml' }); 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); FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('datasets', "xml", id); this.matomoService.trackDownload('datasets', "xml", id);
@ -372,29 +374,11 @@ export class DatasetOverviewComponent extends BaseComponent implements OnInit {
// .pipe(takeUntil(this._destroyed)) // .pipe(takeUntil(this._destroyed))
// .subscribe(response => { // .subscribe(response => {
// const blob = new Blob([response.body], { type: 'application/json' }); // 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); // 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() { openDmpSearchDialogue() {
const formControl = new UntypedFormControl(); const formControl = new UntypedFormControl();
const dialogRef = this.dialog.open(DatasetCopyDialogueComponent, { const dialogRef = this.dialog.open(DatasetCopyDialogueComponent, {
@ -490,14 +474,14 @@ export class DatasetOverviewComponent extends BaseComponent implements OnInit {
}, },
maxWidth: '30em' maxWidth: '30em'
}) })
.afterClosed() .afterClosed()
.pipe( .pipe(
filter(x => x), filter(x => x),
takeUntil(this._destroyed) takeUntil(this._destroyed)
) )
.subscribe( _ =>{ .subscribe(_ => {
this.router.navigate(['datasets','edit',dataset.id, 'finalize']); this.router.navigate(['datasets', 'edit', dataset.id, 'finalize']);
}) })
@ -547,17 +531,17 @@ export class DatasetOverviewComponent extends BaseComponent implements OnInit {
dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(result => { dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(result => {
if (result) { if (result) {
this.datasetWizardService.getSingle(dataset.id) this.datasetWizardService.getSingle(dataset.id)
.pipe(takeUntil(this._destroyed))
.subscribe(data => {
this.datasetWizardModel = data;
this.datasetWizardModel.status = DatasetStatus.Draft;
this.datasetWizardService.createDataset(this.datasetWizardModel)
.pipe(takeUntil(this._destroyed)) .pipe(takeUntil(this._destroyed))
.subscribe( .subscribe(data => {
data => this.onUpdateCallbackSuccess(), this.datasetWizardModel = data;
error => this.onUpdateCallbackError(error) this.datasetWizardModel.status = DatasetStatus.Draft;
); this.datasetWizardService.createDataset(this.datasetWizardModel)
}); .pipe(takeUntil(this._destroyed))
.subscribe(
data => this.onUpdateCallbackSuccess(),
error => this.onUpdateCallbackError(error)
);
});
} }
}); });
} }

View File

@ -2,11 +2,13 @@ import { Component, OnInit } from '@angular/core';
import { AbstractControl, UntypedFormArray, UntypedFormBuilder, UntypedFormControl, UntypedFormGroup } from '@angular/forms'; import { AbstractControl, UntypedFormArray, UntypedFormBuilder, UntypedFormControl, UntypedFormGroup } from '@angular/forms';
import { MatDialog } from '@angular/material/dialog'; import { MatDialog } from '@angular/material/dialog';
import { ActivatedRoute, Params, Router } from '@angular/router'; 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 { DmpStatus } from '@app/core/common/enum/dmp-status';
import { Role } from '@app/core/common/enum/role'; import { Role } from '@app/core/common/enum/role';
import { DataTableRequest } from '@app/core/model/data-table/data-table-request'; import { DataTableRequest } from '@app/core/model/data-table/data-table-request';
import { DatasetProfileModel } from '@app/core/model/dataset/dataset-profile'; 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 { DmpModel } from '@app/core/model/dmp/dmp';
import { DmpDatasetProfile } from '@app/core/model/dmp/dmp-dataset-profile/dmp-dataset-profile'; 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'; 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 { UserModel } from '@app/core/model/user/user';
import { UserInfoListingModel } from '@app/core/model/user/user-info-listing'; import { UserInfoListingModel } from '@app/core/model/user/user-info-listing';
import { DatasetProfileCriteria } from '@app/core/query/dataset-profile/dataset-profile-criteria'; 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 { LicenseCriteria } from '@app/core/query/license/license-criteria';
import { RequestItem } from '@app/core/query/request-item'; import { RequestItem } from '@app/core/query/request-item';
import { AuthService } from '@app/core/services/auth/auth.service'; 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 { TranslateService } from '@ngx-translate/core';
import { Observable, interval } from 'rxjs'; import { Observable, interval } from 'rxjs';
import { map, takeUntil } from 'rxjs/operators'; import { map, takeUntil } from 'rxjs/operators';
import { nameof } from 'ts-simple-nameof';
import { DatasetPreviewDialogComponent } from '../dataset-preview/dataset-preview-dialog.component'; import { DatasetPreviewDialogComponent } from '../dataset-preview/dataset-preview-dialog.component';
import { DmpToDatasetDialogComponent } from '../dmp-to-dataset/dmp-to-dataset-dialog.component'; import { DmpToDatasetDialogComponent } from '../dmp-to-dataset/dmp-to-dataset-dialog.component';
import { AddOrganizationComponent } from '../editor/add-organization/add-organization.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 { FunderFormModel } from '../editor/grant-tab/funder-form-model';
import { GrantTabModel } from '../editor/grant-tab/grant-tab-model'; import { GrantTabModel } from '../editor/grant-tab/grant-tab-model';
import { ProjectFormModel } from '../editor/grant-tab/project-form-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 { interface Visible {
value: boolean; value: boolean;

View File

@ -5,13 +5,11 @@ import { MatDialog } from '@angular/material/dialog';
import { ActivatedRoute, Params, Router } from '@angular/router'; import { ActivatedRoute, Params, Router } from '@angular/router';
import { DmpStatus } from '@app/core/common/enum/dmp-status'; import { DmpStatus } from '@app/core/common/enum/dmp-status';
import { Role } from "@app/core/common/enum/role"; 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 { DmpModel } from '@app/core/model/dmp/dmp';
import { LockModel } from '@app/core/model/lock/lock.model'; import { LockModel } from '@app/core/model/lock/lock.model';
import { UserModel } from '@app/core/model/user/user'; import { UserModel } from '@app/core/model/user/user';
import { UserInfoListingModel } from '@app/core/model/user/user-info-listing'; import { UserInfoListingModel } from '@app/core/model/user/user-info-listing';
import { BaseCriteria } from '@app/core/query/base-criteria'; 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 { GrantCriteria } from '@app/core/query/grant/grant-criteria';
import { RequestItem } from '@app/core/query/request-item'; import { RequestItem } from '@app/core/query/request-item';
import { AuthService } from '@app/core/services/auth/auth.service'; 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 { GrantEditorModel } from '@app/ui/grant/editor/grant-editor.model';
// import { IBreadCrumbComponent } from '@app/ui/misc/breadcrumb/definition/IBreadCrumbComponent'; // import { IBreadCrumbComponent } from '@app/ui/misc/breadcrumb/definition/IBreadCrumbComponent';
// import { BreadcrumbItem } from '@app/ui/misc/breadcrumb/definition/breadcrumb-item'; // 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 { FormService } from '@common/forms/form-service';
import { FormValidationErrorsDialogComponent } from '@common/forms/form-validation-errors-dialog/form-validation-errors-dialog.component'; import { FormValidationErrorsDialogComponent } from '@common/forms/form-validation-errors-dialog/form-validation-errors-dialog.component';
import { ValidationErrorModel } from '@common/forms/validation/error-model/validation-error-model'; import { 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 { Guid } from '@common/types/guid';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import * as FileSaver from 'file-saver'; 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 { map, takeUntil } from 'rxjs/operators';
import { DmpToDatasetDialogComponent } from '../dmp-to-dataset/dmp-to-dataset-dialog.component'; import { DmpToDatasetDialogComponent } from '../dmp-to-dataset/dmp-to-dataset-dialog.component';
import { ExtraPropertiesFormModel } from './general-tab/extra-properties-form.model'; import { ExtraPropertiesFormModel } from './general-tab/extra-properties-form.model';
import { DmpBlueprint, DmpBlueprintDefinition } from '@app/core/model/dmp-blueprint/dmp-blueprint';
@Component({ @Component({
selector: 'app-dmp-editor-component', selector: 'app-dmp-editor-component',
@ -111,7 +110,8 @@ export class DmpEditorComponent extends CheckDeactivateBaseComponent implements
private formService: FormService, private formService: FormService,
private lockService: LockService, private lockService: LockService,
private configurationService: ConfigurationService, private configurationService: ConfigurationService,
private matomoService: MatomoService private matomoService: MatomoService,
private fileUtils: FileUtils
) { ) {
super(); super();
} }
@ -697,7 +697,7 @@ export class DmpEditorComponent extends CheckDeactivateBaseComponent implements
.pipe(takeUntil(this._destroyed)) .pipe(takeUntil(this._destroyed))
.subscribe(response => { .subscribe(response => {
const blob = new Blob([response.body], { type: 'application/xml' }); 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); FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('dmps', "xml", id); this.matomoService.trackDownload('dmps', "xml", id);
}); });
@ -708,7 +708,7 @@ export class DmpEditorComponent extends CheckDeactivateBaseComponent implements
.pipe(takeUntil(this._destroyed)) .pipe(takeUntil(this._destroyed))
.subscribe(response => { .subscribe(response => {
const blob = new Blob([response.body], { type: 'application/msword' }); 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); FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('dmps', "docx", id); this.matomoService.trackDownload('dmps', "docx", id);
}); });
@ -719,7 +719,7 @@ export class DmpEditorComponent extends CheckDeactivateBaseComponent implements
.pipe(takeUntil(this._destroyed)) .pipe(takeUntil(this._destroyed))
.subscribe(response => { .subscribe(response => {
const blob = new Blob([response.body], { type: 'application/pdf' }); 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); FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('dmps', "pdf", id); this.matomoService.trackDownload('dmps', "pdf", id);
}); });
@ -730,7 +730,7 @@ export class DmpEditorComponent extends CheckDeactivateBaseComponent implements
.pipe(takeUntil(this._destroyed)) .pipe(takeUntil(this._destroyed))
.subscribe(response => { .subscribe(response => {
const blob = new Blob([response.body], { type: 'application/json' }); 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); FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('dmps', "json", id); this.matomoService.trackDownload('dmps', "json", id);
}, async error => { }, async error => {
@ -744,24 +744,6 @@ export class DmpEditorComponent extends CheckDeactivateBaseComponent implements
this.uiNotificationService.snackBarNotification(errorObj.message, SnackBarNotificationLevel.Error); 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() { public enableForm() {
if (this.formGroup.get('status').value !== DmpStatus.Finalized) { if (this.formGroup.get('status').value !== DmpStatus.Finalized) {
this.editMode = true; 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 { 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 { HttpClient } from '@angular/common/http';
import { isNullOrUndefined } from '@app/utilities/enhancers/utils'; import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
import { DmpBlueprintService } from '@app/core/services/dmp/dmp-blueprint.service'; 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 { 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 { 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 { 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({ @Component({
selector: 'app-dmp-listing-item-component', selector: 'app-dmp-listing-item-component',
@ -63,7 +64,8 @@ export class DmpListingItemComponent extends BaseComponent implements OnInit {
private lockService: LockService, private lockService: LockService,
private location: Location, private location: Location,
private httpClient: HttpClient, private httpClient: HttpClient,
private matomoService: MatomoService) { private matomoService: MatomoService,
private fileUtils: FileUtils) {
super(); super();
} }
@ -180,10 +182,10 @@ export class DmpListingItemComponent extends BaseComponent implements OnInit {
if (!isNullOrUndefined(this.dmpFormGroup.get('profile').value)) { if (!isNullOrUndefined(this.dmpFormGroup.get('profile').value)) {
this.getBlueprintDefinition(Guid.parse(this.dmpFormGroup.get('profile').value), result => { this.getBlueprintDefinition(Guid.parse(this.dmpFormGroup.get('profile').value), result => {
this.checkForGrant(result.definition); this.checkForGrant(result.definition);
this.checkForFunder(result.definition); this.checkForFunder(result.definition);
this.checkForProject(result.definition); this.checkForProject(result.definition);
}); });
} }
if (!isNewVersion) { if (!isNewVersion) {
@ -218,10 +220,10 @@ export class DmpListingItemComponent extends BaseComponent implements OnInit {
[nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.descriptionTemplates), nameof<DescriptionTemplatesInSection>(x => x.maxMultiplicity)].join('.'), [nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.descriptionTemplates), nameof<DescriptionTemplatesInSection>(x => x.maxMultiplicity)].join('.'),
] ]
) )
.pipe(map(data => data as DmpBlueprint), takeUntil(this._destroyed)) .pipe(map(data => data as DmpBlueprint), takeUntil(this._destroyed))
.subscribe( .subscribe(
data => successFunction(data), data => successFunction(data),
); );
} }
private checkForGrant(blueprint: DmpBlueprintDefinition) { private checkForGrant(blueprint: DmpBlueprintDefinition) {
@ -309,7 +311,7 @@ export class DmpListingItemComponent extends BaseComponent implements OnInit {
.pipe(takeUntil(this._destroyed)) .pipe(takeUntil(this._destroyed))
.subscribe(response => { .subscribe(response => {
const blob = new Blob([response.body], { type: 'application/xml' }); 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); FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('dmps', "xml", id); this.matomoService.trackDownload('dmps', "xml", id);
@ -321,7 +323,7 @@ export class DmpListingItemComponent extends BaseComponent implements OnInit {
.pipe(takeUntil(this._destroyed)) .pipe(takeUntil(this._destroyed))
.subscribe(response => { .subscribe(response => {
const blob = new Blob([response.body], { type: 'application/msword' }); 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); FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('dmps', "docx", id); this.matomoService.trackDownload('dmps', "docx", id);
@ -333,7 +335,7 @@ export class DmpListingItemComponent extends BaseComponent implements OnInit {
.pipe(takeUntil(this._destroyed)) .pipe(takeUntil(this._destroyed))
.subscribe(response => { .subscribe(response => {
const blob = new Blob([response.body], { type: 'application/pdf' }); 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); FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('dmps', "pdf", id); this.matomoService.trackDownload('dmps', "pdf", id);
@ -345,7 +347,7 @@ export class DmpListingItemComponent extends BaseComponent implements OnInit {
.pipe(takeUntil(this._destroyed)) .pipe(takeUntil(this._destroyed))
.subscribe(response => { .subscribe(response => {
const blob = new Blob([response.body], { type: 'application/json' }); 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); FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('dmps', "json", id); this.matomoService.trackDownload('dmps', "json", id);
}, async error => { }, async error => {
@ -359,24 +361,6 @@ export class DmpListingItemComponent extends BaseComponent implements OnInit {
this.uiNotificationService.snackBarNotification(errorObj.message, SnackBarNotificationLevel.Error); 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) { deleteClicked(id: string) {
this.lockService.checkLockStatus(id).pipe(takeUntil(this._destroyed)) this.lockService.checkLockStatus(id).pipe(takeUntil(this._destroyed))
.subscribe(lockStatus => { .subscribe(lockStatus => {

View File

@ -1,56 +1,57 @@
import {Component, ElementRef, OnInit, ViewChild} from '@angular/core'; import { Component, ElementRef, OnInit, ViewChild } from '@angular/core';
import {MatDialog} from '@angular/material/dialog'; import { MatDialog } from '@angular/material/dialog';
import {ActivatedRoute, Params, Router} from '@angular/router'; import { ActivatedRoute, Params, Router } from '@angular/router';
import {DatasetStatus} from '@app/core/common/enum/dataset-status'; import { DatasetStatus } from '@app/core/common/enum/dataset-status';
import {DmpStatus} from '@app/core/common/enum/dmp-status'; import { DmpStatus } from '@app/core/common/enum/dmp-status';
import {DatasetOverviewModel} from '@app/core/model/dataset/dataset-overview'; import { DatasetOverviewModel } from '@app/core/model/dataset/dataset-overview';
import {DatasetsToBeFinalized} from '@app/core/model/dataset/datasets-toBeFinalized'; import { DatasetsToBeFinalized } from '@app/core/model/dataset/datasets-toBeFinalized';
import {DmpOverviewModel} from '@app/core/model/dmp/dmp-overview'; import { DmpOverviewModel } from '@app/core/model/dmp/dmp-overview';
import {UserInfoListingModel} from '@app/core/model/user/user-info-listing'; import { UserInfoListingModel } from '@app/core/model/user/user-info-listing';
import {AuthService} from '@app/core/services/auth/auth.service'; import { AuthService } from '@app/core/services/auth/auth.service';
import {DmpService} from '@app/core/services/dmp/dmp.service'; import { DmpService } from '@app/core/services/dmp/dmp.service';
import { import {
SnackBarNotificationLevel, SnackBarNotificationLevel,
UiNotificationService UiNotificationService
} from '@app/core/services/notification/ui-notification-service'; } from '@app/core/services/notification/ui-notification-service';
import {ConfirmationDialogComponent} from '@common/modules/confirmation-dialog/confirmation-dialog.component';
import { import {
DmpFinalizeDialogComponent, DmpFinalizeDialogComponent,
DmpFinalizeDialogInput, DmpFinalizeDialogInput,
DmpFinalizeDialogOutput DmpFinalizeDialogOutput
} from '@app/ui/dmp/editor/dmp-finalize-dialog/dmp-finalize-dialog.component'; } 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 {BreadcrumbItem} from '@app/ui/misc/breadcrumb/definition/breadcrumb-item';
import {BaseComponent} from '@common/base/base.component'; import { Location } from '@angular/common';
import {TranslateService} from '@ngx-translate/core'; import { UntypedFormGroup } from '@angular/forms';
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 { 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 { 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({ @Component({
selector: 'app-dmp-overview', selector: 'app-dmp-overview',
@ -95,7 +96,8 @@ export class DmpOverviewComponent extends BaseComponent implements OnInit {
private configurationService: ConfigurationService, private configurationService: ConfigurationService,
private location: Location, private location: Location,
private lockService: LockService, private lockService: LockService,
private matomoService: MatomoService private matomoService: MatomoService,
private fileUtils: FileUtils
) { ) {
super(); super();
} }
@ -115,7 +117,7 @@ export class DmpOverviewComponent extends BaseComponent implements OnInit {
.pipe(takeUntil(this._destroyed)) .pipe(takeUntil(this._destroyed))
.subscribe(data => { .subscribe(data => {
this.dmp = data; this.dmp = data;
if(!this.hasDoi()) { if (!this.hasDoi()) {
this.selectedModel = this.dmp.dois[0]; this.selectedModel = this.dmp.dois[0];
} }
this.checkLockStatus(this.dmp.id); this.checkLockStatus(this.dmp.id);
@ -142,7 +144,7 @@ export class DmpOverviewComponent extends BaseComponent implements OnInit {
.pipe(takeUntil(this._destroyed)) .pipe(takeUntil(this._destroyed))
.subscribe(data => { .subscribe(data => {
this.dmp = data; this.dmp = data;
if(!this.hasDoi()) { if (!this.hasDoi()) {
this.selectedModel = this.dmp.dois[0]; this.selectedModel = this.dmp.dois[0];
} }
// this.checkLockStatus(this.dmp.id); // this.checkLockStatus(this.dmp.id);
@ -162,12 +164,12 @@ export class DmpOverviewComponent extends BaseComponent implements OnInit {
} }
}); });
this.depositRepositoriesService.getAvailableRepos() this.depositRepositoriesService.getAvailableRepos()
.pipe(takeUntil(this._destroyed)) .pipe(takeUntil(this._destroyed))
.subscribe( .subscribe(
repos => { repos => {
this.depositRepos = repos; this.depositRepos = repos;
}, },
error => this.depositRepos = []); error => this.depositRepos = []);
} }
onFetchingDeletedCallbackError(redirectRoot: string) { onFetchingDeletedCallbackError(redirectRoot: string) {
@ -252,11 +254,11 @@ export class DmpOverviewComponent extends BaseComponent implements OnInit {
[nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.descriptionTemplates), nameof<DescriptionTemplatesInSection>(x => x.maxMultiplicity)].join('.'), [nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.descriptionTemplates), nameof<DescriptionTemplatesInSection>(x => x.maxMultiplicity)].join('.'),
] ]
) )
.pipe(map(data => data as DmpBlueprint), takeUntil(this._destroyed)) .pipe(map(data => data as DmpBlueprint), takeUntil(this._destroyed))
.subscribe( .subscribe(
data => successFunction(data), data => successFunction(data),
error => this.onCallbackError(error) error => this.onCallbackError(error)
); );
} }
private checkForGrant(blueprint: DmpBlueprintDefinition) { private checkForGrant(blueprint: DmpBlueprintDefinition) {
@ -426,7 +428,7 @@ export class DmpOverviewComponent extends BaseComponent implements OnInit {
.pipe(takeUntil(this._destroyed)) .pipe(takeUntil(this._destroyed))
.subscribe(response => { .subscribe(response => {
const blob = new Blob([response.body], { type: 'application/xml' }); 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); FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('dmps', "xml", id); this.matomoService.trackDownload('dmps', "xml", id);
@ -438,7 +440,7 @@ export class DmpOverviewComponent extends BaseComponent implements OnInit {
.pipe(takeUntil(this._destroyed)) .pipe(takeUntil(this._destroyed))
.subscribe(response => { .subscribe(response => {
const blob = new Blob([response.body], { type: 'application/msword' }); 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); FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('dmps', "docx", id); this.matomoService.trackDownload('dmps', "docx", id);
@ -450,7 +452,7 @@ export class DmpOverviewComponent extends BaseComponent implements OnInit {
.pipe(takeUntil(this._destroyed)) .pipe(takeUntil(this._destroyed))
.subscribe(response => { .subscribe(response => {
const blob = new Blob([response.body], { type: 'application/pdf' }); 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); FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('dmps', "pdf", id); this.matomoService.trackDownload('dmps', "pdf", id);
@ -462,7 +464,7 @@ export class DmpOverviewComponent extends BaseComponent implements OnInit {
.pipe(takeUntil(this._destroyed)) .pipe(takeUntil(this._destroyed))
.subscribe(complete => { .subscribe(complete => {
const blob = new Blob([complete.body], { type: 'application/json' }); 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); FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('dmps', "json", id); this.matomoService.trackDownload('dmps', "json", id);
}, async error => { }, async error => {
@ -476,24 +478,6 @@ export class DmpOverviewComponent extends BaseComponent implements OnInit {
this.uiNotificationService.snackBarNotification(errorObj.message, SnackBarNotificationLevel.Error); 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[]) { roleDisplayFromList(value: UserInfoListingModel[]) {
const principalId: string = this.authentication.userId()?.toString(); const principalId: string = this.authentication.userId()?.toString();
let role: number; let role: number;
@ -603,7 +587,7 @@ export class DmpOverviewComponent extends BaseComponent implements OnInit {
return this.depositRepos.filter(repo => !this.dmp.dois.find(doi => doi.repositoryId === repo.repositoryId)); return this.depositRepos.filter(repo => !this.dmp.dois.find(doi => doi.repositoryId === repo.repositoryId));
} }
moreDeposit(){ moreDeposit() {
return (this.dmp.dois.length < this.depositRepos.length); return (this.dmp.dois.length < this.depositRepos.length);
} }
@ -648,17 +632,17 @@ export class DmpOverviewComponent extends BaseComponent implements OnInit {
.pipe(takeUntil(this._destroyed)) .pipe(takeUntil(this._destroyed))
.subscribe( .subscribe(
complete => { complete => {
if(extraProperties.visible){ if (extraProperties.visible) {
//this.publish(this.dmp.id); //this.publish(this.dmp.id);
this.dmpService.publish(this.dmp.id) this.dmpService.publish(this.dmp.id)
.pipe(takeUntil(this._destroyed)) .pipe(takeUntil(this._destroyed))
.subscribe(() => { .subscribe(() => {
//this.hasPublishButton = false; //this.hasPublishButton = false;
this.dmp.status = DmpStatus.Finalized; this.dmp.status = DmpStatus.Finalized;
this.onUpdateCallbackSuccess(); this.onUpdateCallbackSuccess();
}); });
} }
else{ else {
this.dmp.status = DmpStatus.Finalized; this.dmp.status = DmpStatus.Finalized;
this.onUpdateCallbackSuccess(); this.onUpdateCallbackSuccess();
} }
@ -679,22 +663,22 @@ export class DmpOverviewComponent extends BaseComponent implements OnInit {
return this.dmpBlueprintService.getSingle(Guid.parse(blueprintId)) return this.dmpBlueprintService.getSingle(Guid.parse(blueprintId))
.pipe(map(result => { .pipe(map(result => {
return result.definition.sections.some(section => { return result.definition.sections.some(section => {
if(!section.hasTemplates) if (!section.hasTemplates)
return false; return false;
return section.descriptionTemplates.some(template => { return section.descriptionTemplates.some(template => {
if(!(template.minMultiplicity > 0)) if (!(template.minMultiplicity > 0))
return false; return false;
let count = 0; let count = 0;
dmpModel.datasets.filter(dataset => dataset.dmpSectionIndex === (section.ordinal - 1)).forEach(dataset => { dmpModel.datasets.filter(dataset => dataset.dmpSectionIndex === (section.ordinal - 1)).forEach(dataset => {
if(Guid.parse(dataset.profile.id) === template.descriptionTemplateId){ if (Guid.parse(dataset.profile.id) === template.descriptionTemplateId) {
count++; count++;
} }
}) })
if(count < template.minMultiplicity){ if (count < template.minMultiplicity) {
this.dialog.open(PopupNotificationDialogComponent, { this.dialog.open(PopupNotificationDialogComponent, {
data: { data: {
title: this.language.instant('DMP-OVERVIEW.MIN-DESCRIPTIONS-DIALOG.TITLE', {'minMultiplicity': template.minMultiplicity}), title: this.language.instant('DMP-OVERVIEW.MIN-DESCRIPTIONS-DIALOG.TITLE', { 'minMultiplicity': template.minMultiplicity }),
message: this.language.instant('DMP-OVERVIEW.MIN-DESCRIPTIONS-DIALOG.MESSAGE', ) message: this.language.instant('DMP-OVERVIEW.MIN-DESCRIPTIONS-DIALOG.MESSAGE',)
}, maxWidth: '30em' }, maxWidth: '30em'
}); });
return true; return true;
@ -766,7 +750,7 @@ export class DmpOverviewComponent extends BaseComponent implements OnInit {
this.router.navigate(['/datasets', 'new', this.dmp.id]); this.router.navigate(['/datasets', 'new', this.dmp.id]);
} }
selectDoi(doiModel: DoiModel){ selectDoi(doiModel: DoiModel) {
this.selectedModel = doiModel; this.selectedModel = doiModel;
const foundIdx = this.dmp.dois.findIndex(el => el.id == doiModel.id); const foundIdx = this.dmp.dois.findIndex(el => el.id == doiModel.id);
this.dmp.dois.splice(foundIdx, 1); this.dmp.dois.splice(foundIdx, 1);
@ -775,17 +759,17 @@ export class DmpOverviewComponent extends BaseComponent implements OnInit {
createDoiLink(doiModel: DoiModel): string { createDoiLink(doiModel: DoiModel): string {
const repository = this.depositRepos.find(r => r.repositoryId == doiModel.repositoryId); const repository = this.depositRepos.find(r => r.repositoryId == doiModel.repositoryId);
if(typeof repository !== "undefined"){ if (typeof repository !== "undefined") {
if(doiModel.repositoryId == "Zenodo"){ if (doiModel.repositoryId == "Zenodo") {
const doiarr = doiModel.doi.split('.'); const doiarr = doiModel.doi.split('.');
const id = doiarr[doiarr.length - 1]; const id = doiarr[doiarr.length - 1];
return repository.repositoryRecordUrl + id; return repository.repositoryRecordUrl + id;
} }
else{ else {
return repository.repositoryRecordUrl + doiModel.doi; return repository.repositoryRecordUrl + doiModel.doi;
} }
} }
else{ else {
return ""; return "";
} }
} }
@ -888,11 +872,13 @@ export class DmpOverviewComponent extends BaseComponent implements OnInit {
this.lockService.checkLockStatus(id).pipe(takeUntil(this._destroyed)) this.lockService.checkLockStatus(id).pipe(takeUntil(this._destroyed))
.subscribe(lockStatus => { .subscribe(lockStatus => {
this.lockStatus = lockStatus this.lockStatus = lockStatus
if(lockStatus){ if (lockStatus) {
this.dialog.open(PopupNotificationDialogComponent,{data:{ this.dialog.open(PopupNotificationDialogComponent, {
title:this.language.instant('DMP-OVERVIEW.LOCKED-DIALOG.TITLE'), data: {
message:this.language.instant('DMP-OVERVIEW.LOCKED-DIALOG.MESSAGE') title: this.language.instant('DMP-OVERVIEW.LOCKED-DIALOG.TITLE'),
}, maxWidth:'30em'}); message: this.language.instant('DMP-OVERVIEW.LOCKED-DIALOG.MESSAGE')
}, maxWidth: '30em'
});
} }
}); });
} }

View File

@ -50,6 +50,7 @@ import {HttpErrorResponse} from "@angular/common/http";
import * as FileSaver from "file-saver"; import * as FileSaver from "file-saver";
import { FetcherExternalReference } from '@app/core/model/external-reference/external-reference'; import { FetcherExternalReference } from '@app/core/model/external-reference/external-reference';
import { ExternalReferencesType } from '@app/core/common/enum/external-references-type'; import { ExternalReferencesType } from '@app/core/common/enum/external-references-type';
import { FileUtils } from '@app/core/services/utilities/file-utils.service';
@Component({ @Component({
selector: 'app-form-field', selector: 'app-form-field',
@ -129,7 +130,8 @@ export class FormFieldComponent extends BaseComponent implements OnInit {
private fileService: FileService, private fileService: FileService,
private cdr: ChangeDetectorRef, private cdr: ChangeDetectorRef,
private uiNotificationService: UiNotificationService, private uiNotificationService: UiNotificationService,
public dialog: MatDialog public dialog: MatDialog,
private fileUtils: FileUtils
) { ) {
super(); super();
@ -704,31 +706,12 @@ export class FormFieldComponent extends BaseComponent implements OnInit {
.pipe(takeUntil(this._destroyed)) .pipe(takeUntil(this._destroyed))
.subscribe(response => { .subscribe(response => {
const blob = new Blob([response.body], {type: this.form.value.value.type}); 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); 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) { // isImageFile(fileType: string) {
// if(!fileType) { // if(!fileType) {
// return false; // return false;

View File

@ -200,13 +200,13 @@
}, },
"COMMONS": { "COMMONS": {
"LISTING-COMPONENT": { "LISTING-COMPONENT": {
"SEARCH-FILTER-BTN":"Filter Results", "SEARCH-FILTER-BTN": "Filter Results",
"CLEAR-ALL-FILTERS": "clear all filters", "CLEAR-ALL-FILTERS": "clear all filters",
"FILTERS-SAVE-AS":"Save as", "FILTERS-SAVE-AS": "Save as",
"CANCEL":"Cancel", "CANCEL": "Cancel",
"APPLY-FILTERS":"Apply Filters", "APPLY-FILTERS": "Apply Filters",
"TITLE":"Filters", "TITLE": "Filters",
"ADD-NEW":"Add new", "ADD-NEW": "Add new",
"SETTINGS": { "SETTINGS": {
"TITLE": "Settings", "TITLE": "Settings",
"APPLY": "Apply", "APPLY": "Apply",
@ -221,15 +221,15 @@
}, },
"SETTINGS-PICKER": { "SETTINGS-PICKER": {
"DRAFT-FILTERS": "Draft profile", "DRAFT-FILTERS": "Draft profile",
"RENAME":"Rename", "RENAME": "Rename",
"NAME":"Name", "NAME": "Name",
"USER":"User", "USER": "User",
"SHARE":"Share", "SHARE": "Share",
"CANCEL":"Cancel" "CANCEL": "Cancel"
}, },
"BREADCRUMBS": { "BREADCRUMBS": {
"OVERVIEW":"Overview", "OVERVIEW": "Overview",
"HOME":"Board", "HOME": "Board",
"DESCRIPTION-TEMPLATE-TYPES": "Description Types", "DESCRIPTION-TEMPLATE-TYPES": "Description Types",
"NEW-DESCRIPTION-TEMPLATE-TYPE": "New", "NEW-DESCRIPTION-TEMPLATE-TYPE": "New",
"EDIT-DESCRIPTION-TEMPLATE-TYPE": "Edit", "EDIT-DESCRIPTION-TEMPLATE-TYPE": "Edit",
@ -362,8 +362,8 @@
"UNTITLED": "Untitled", "UNTITLED": "Untitled",
"QUESTION": "Question", "QUESTION": "Question",
"TEMPLATE-OUTLINE": "Template outline", "TEMPLATE-OUTLINE": "Template outline",
"ERRORS":{ "ERRORS": {
"USER-NOT-FOUND":"User not found." "USER-NOT-FOUND": "User not found."
} }
}, },
"PAGE-INFO": { "PAGE-INFO": {
@ -539,7 +539,7 @@
"FIELD-VALIDATOR-TITLE": "Validator Data", "FIELD-VALIDATOR-TITLE": "Validator Data",
"FIELD-VALIDATOR-PLACEHOLDER": "Input placeholder Text", "FIELD-VALIDATOR-PLACEHOLDER": "Input placeholder Text",
"EXTERNAL-DATASET-TYPE-NAME": "Type", "EXTERNAL-DATASET-TYPE-NAME": "Type",
"EXTERNAL-DATASET-TYPES":{ "EXTERNAL-DATASET-TYPES": {
"PRODUCED": "Produced dataset", "PRODUCED": "Produced dataset",
"REUSED": "Reused dataset", "REUSED": "Reused dataset",
"OTHER": "Other" "OTHER": "Other"
@ -564,9 +564,9 @@
"ACTIONS": { "ACTIONS": {
"ADD-RULE": "Add Visibility Rule +" "ADD-RULE": "Add Visibility Rule +"
}, },
"STATUS":{ "STATUS": {
"CALCULATING-PREVIEW":"... calculating preview", "CALCULATING-PREVIEW": "... calculating preview",
"PREVIEW-UPDATED":"Preview updated!" "PREVIEW-UPDATED": "Preview updated!"
} }
}, },
"RULE": { "RULE": {
@ -805,9 +805,9 @@
"DOWNLOAD-DOCX": "Download DOCX", "DOWNLOAD-DOCX": "Download DOCX",
"COPY-DESCRIPTION": "Copy Description", "COPY-DESCRIPTION": "Copy Description",
"UPDATE-DATASET-PROFILE": "Update Template", "UPDATE-DATASET-PROFILE": "Update Template",
"VALIDATE":"Validate", "VALIDATE": "Validate",
"UNDO-FINALIZATION-QUESTION" :"Undo finalization?", "UNDO-FINALIZATION-QUESTION": "Undo finalization?",
"CONFIRM" : "Yes", "CONFIRM": "Yes",
"REJECT": "No" "REJECT": "No"
}, },
"MESSAGES": { "MESSAGES": {
@ -843,8 +843,8 @@
"NEXT": "Next", "NEXT": "Next",
"ERROR-MESSAGE": "Does not contain this Dataset Template" "ERROR-MESSAGE": "Does not contain this Dataset Template"
}, },
"LOCKED":{ "LOCKED": {
"TITLE":"Dataset is locked", "TITLE": "Dataset is locked",
"MESSAGE": "Somebody else is modifying the dataset at this moment. You may view the dataset but you cannot make any changes. If you would like to modify it please come back later." "MESSAGE": "Somebody else is modifying the dataset at this moment. You may view the dataset but you cannot make any changes. If you would like to modify it please come back later."
} }
}, },
@ -881,9 +881,9 @@
"AUTHORIZE": "Proceed to authorization", "AUTHORIZE": "Proceed to authorization",
"CANCEL": "Cancel" "CANCEL": "Cancel"
}, },
"LOCKED-DIALOG":{ "LOCKED-DIALOG": {
"TITLE": "DMP is locked", "TITLE": "DMP is locked",
"MESSAGE":"Somebody else is modifying the DMP at this moment. If you would like to modify or view it, please come back later." "MESSAGE": "Somebody else is modifying the DMP at this moment. If you would like to modify or view it, please come back later."
}, },
"MIN-DESCRIPTIONS-DIALOG": { "MIN-DESCRIPTIONS-DIALOG": {
"TITLE": "Min({{minMultiplicity}}) datasets needed using this template.", "TITLE": "Min({{minMultiplicity}}) datasets needed using this template.",
@ -896,14 +896,14 @@
"DELETED-DATASET": "The requested dataset is deleted", "DELETED-DATASET": "The requested dataset is deleted",
"FORBIDEN-DATASET": "You are not allowed to access this dataset" "FORBIDEN-DATASET": "You are not allowed to access this dataset"
}, },
"LOCKED":{ "LOCKED": {
"TITLE": "Dataset is locked", "TITLE": "Dataset is locked",
"MESSAGE": "Somebody else is modifying the dataset at this moment. If you would like to modify or view it, please come back later." "MESSAGE": "Somebody else is modifying the dataset at this moment. If you would like to modify or view it, please come back later."
}, },
"FINALISE-POPUP":{ "FINALISE-POPUP": {
"MESSAGE":"You will be directed to Dataset Editor where you can finalize the selected dataset. Would you like to proceed?", "MESSAGE": "You will be directed to Dataset Editor where you can finalize the selected dataset. Would you like to proceed?",
"CONFIRM":"OK", "CONFIRM": "OK",
"CANCEL":"Cancel" "CANCEL": "Cancel"
} }
}, },
"DATASET-LISTING": { "DATASET-LISTING": {
@ -1023,18 +1023,17 @@
"CANCEL": "Cancel", "CANCEL": "Cancel",
"APPLY-FILTERS": "Apply filters" "APPLY-FILTERS": "Apply filters"
}, },
"CONFIRM-DELETE-DIALOG":{ "CONFIRM-DELETE-DIALOG": {
"MESSAGE": "Would you like to delete this Description Type?", "MESSAGE": "Would you like to delete this Description Type?",
"CONFIRM-BUTTON": "Yes, delete", "CONFIRM-BUTTON": "Yes, delete",
"CANCEL-BUTTON": "No" "CANCEL-BUTTON": "No"
}, },
"ACTIONS": { "ACTIONS": {
"DELETE": "Delete", "DELETE": "Delete",
"EDIT":"Edit" "EDIT": "Edit"
}, },
"SUCCESSFUL-DELETE": "Successful Delete", "SUCCESSFUL-DELETE": "Successful Delete",
"UNSUCCESSFUL-DELETE": "This item could not be deleted." "UNSUCCESSFUL-DELETE": "This item could not be deleted."
}, },
"DATASET-UPLOAD": { "DATASET-UPLOAD": {
"TITLE": "Import Dataset", "TITLE": "Import Dataset",
@ -1072,10 +1071,23 @@
}, },
"FIELDS": { "FIELDS": {
"TITLE": "Fields", "TITLE": "Fields",
"LABEL": "Name", "NAME": "Name",
"TYPE": "Type", "SECTIONS": "Sections",
"DATATYPE": "Data Type", "SECTION-PREFIX": "Section",
"REQUIRED": "Required", "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": { "EXTERNAL-AUTOCOMPLETE": {
"TITLE": "Autocomplete Data", "TITLE": "Autocomplete Data",
"MULTIPLE-AUTOCOMPLETE": "Multiple Autocomplete", "MULTIPLE-AUTOCOMPLETE": "Multiple Autocomplete",
@ -1087,13 +1099,18 @@
} }
}, },
"ACTIONS": { "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", "SAVE": "Save",
"CANCEL": "Cancel", "CANCEL": "Cancel",
"DELETE": "Delete", "DELETE": "Delete",
"FINALIZE": "Finalize", "FINALIZE": "Finalize",
"DOWNLOAD-XML": "Download XML" "DOWNLOAD-XML": "Download XML"
}, },
"CONFIRM-DELETE-DIALOG":{ "CONFIRM-DELETE-DIALOG": {
"MESSAGE": "Would you like to delete this DMP template?", "MESSAGE": "Would you like to delete this DMP template?",
"CONFIRM-BUTTON": "Yes, delete", "CONFIRM-BUTTON": "Yes, delete",
"CANCEL-BUTTON": "No" "CANCEL-BUTTON": "No"
@ -1226,7 +1243,7 @@
"ORGANISATION-IDENTIFIER-EXSTS": "Organization identifier already exists.", "ORGANISATION-IDENTIFIER-EXSTS": "Organization identifier already exists.",
"IDENTIFIER-EXISTS-RESEARCHER-LIST": "This identifier is already used by a researcher in the researchers list.", "IDENTIFIER-EXISTS-RESEARCHER-LIST": "This identifier is already used by a researcher in the researchers list.",
"IDENTIFIER-EXISTS-ORGANISATION-LIST": "This identifier is already used by an organization in the organizations list.", "IDENTIFIER-EXISTS-ORGANISATION-LIST": "This identifier is already used by an organization in the organizations list.",
"SAVE":"Save", "SAVE": "Save",
"CANCEL": "Cancel" "CANCEL": "Cancel"
}, },
"FUNDING-INFO": { "FUNDING-INFO": {
@ -1257,9 +1274,9 @@
"SAVE": "Save", "SAVE": "Save",
"CANCEL": "Cancel" "CANCEL": "Cancel"
}, },
"LOCKED":{ "LOCKED": {
"TITLE":"DMP is locked", "TITLE": "DMP is locked",
"MESSAGE":"Somebody else is modifying the DMP at this moment. You may view the dataset but you cannot make any changes." "MESSAGE": "Somebody else is modifying the DMP at this moment. You may view the dataset but you cannot make any changes."
} }
}, },
"DMP-BLUEPRINT-LISTING": { "DMP-BLUEPRINT-LISTING": {
@ -1278,16 +1295,16 @@
"CANCEL": "Cancel", "CANCEL": "Cancel",
"APPLY-FILTERS": "Apply filters" "APPLY-FILTERS": "Apply filters"
}, },
"CONFIRM-DELETE-DIALOG":{ "CONFIRM-DELETE-DIALOG": {
"MESSAGE": "Would you like to delete this DMP Blueprint?", "MESSAGE": "Would you like to delete this DMP Blueprint?",
"CONFIRM-BUTTON": "Yes, delete", "CONFIRM-BUTTON": "Yes, delete",
"CANCEL-BUTTON": "No" "CANCEL-BUTTON": "No"
}, },
"ACTIONS": { "ACTIONS": {
"DELETE": "Delete", "DELETE": "Delete",
"EDIT":"Edit", "EDIT": "Edit",
"CLONE": "Clone", "CLONE": "Clone",
"DOWNLOAD-XML":"Download XML" "DOWNLOAD-XML": "Download XML"
}, },
"IMPORT": { "IMPORT": {
"UPLOAD-XML": "Import", "UPLOAD-XML": "Import",
@ -1298,7 +1315,7 @@
}, },
"SUCCESSFUL-DELETE": "Successful Delete", "SUCCESSFUL-DELETE": "Successful Delete",
"UNSUCCESSFUL-DELETE": "This item could not be deleted.", "UNSUCCESSFUL-DELETE": "This item could not be deleted.",
"TEMPLATE-UPLOAD-SUCCESS":"Template successfully uploaded" "TEMPLATE-UPLOAD-SUCCESS": "Template successfully uploaded"
}, },
"DYNAMIC-FORM": { "DYNAMIC-FORM": {
"FIELDS": { "FIELDS": {
@ -1426,7 +1443,7 @@
"ABOUT": "Versioning is automated.", "ABOUT": "Versioning is automated.",
"QUESTION": "It seems your Dataset Template is outdated. Do you want to update it to the latest version?" "QUESTION": "It seems your Dataset Template is outdated. Do you want to update it to the latest version?"
}, },
"ERRORS":{ "ERRORS": {
"ERROR-OCCURED": "An error occurred.", "ERROR-OCCURED": "An error occurred.",
"MESSAGE": "Message: " "MESSAGE": "Message: "
}, },
@ -1603,9 +1620,28 @@
"PUBLISHED": "Published", "PUBLISHED": "Published",
"STATUS": "Status" "STATUS": "Status"
}, },
"DESCRIPTION-TEMPLATE-TYPE-STATUS":{ "DESCRIPTION-TEMPLATE-TYPE-STATUS": {
"FINALIZED": "Finalized", "FINALIZED": "Finalized",
"DRAFT": "Draft" "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": { "ADDRESEARCHERS-EDITOR": {
@ -2050,4 +2086,4 @@
"FINALIZED": "Finalized", "FINALIZED": "Finalized",
"DELETED": "Deleted" "DELETED": "Deleted"
} }
} }