Merge remote-tracking branch 'origin/ui-redesign' into ui-redesign

This commit is contained in:
George Kalampokis 2020-07-21 16:05:50 +03:00
commit 9000da0ee4
55 changed files with 3327 additions and 134 deletions

View File

@ -139,6 +139,14 @@ const appRoutes: Routes = [
title: 'GENERAL.TITLES.PRIVACY'
}
},
{
path: 'opensource-licences',
loadChildren: () => import('./ui/sidebar/sidebar-footer/opensource-licences/opensource-licenses.module').then(m => m.OpensourceLicencesModule),
data: {
breadcrumb: true,
title: 'GENERAL.TITLES.OPENSOURCE-LICENCES'
}
},
{
path: 'terms-and-conditions',
loadChildren: () => import('./ui/sidebar/sidebar-footer/terms/terms.module').then(m => m.TermsModule),

View File

@ -10,6 +10,7 @@ import { DmpStatus } from '../../common/enum/dmp-status';
import { ValidationType } from '../../common/enum/validation-type';
import { DatasetProfileInternalDmpEntitiesType } from '../../common/enum/dataset-profile-internal-dmp-entities-type';
import { RecentActivityOrder } from '@app/core/common/enum/recent-activity-order';
import { Role } from '@app/core/common/enum/role';
@Injectable()
export class EnumUtils {
@ -111,4 +112,11 @@ export class EnumUtils {
case RecentActivityOrder.STATUS: return this.language.instant('TYPES.RECENT-ACTIVITY-ORDER.STATUS');
}
}
toRoleString(status: Role): string {
switch (status) {
case Role.Owner: return this.language.instant('FACET-SEARCH.ROLE.OWNER');
case Role.Member: return this.language.instant('FACET-SEARCH.ROLE.MEMBER');
}
}
}

View File

@ -20,7 +20,7 @@ import { SnackBarNotificationLevel } from '@app/core/services/notification/ui-no
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.component';
import { DmpInvitationDialogComponent } from '@app/ui/dmp/invitation/dmp-invitation-dialog.component';
import { RecentActivityOrder } from '@app/core/common/enum/recent-activity-order';
@Component({

View File

@ -15,7 +15,7 @@ import { BaseComponent } from '@common/base/base.component';
import { TranslateService } from '@ngx-translate/core';
import * as FileSaver from 'file-saver';
import { takeUntil } from 'rxjs/operators';
import { DmpInvitationDialogComponent } from '@app/ui/dmp/invitation/dmp-invitation.component';
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';

View File

@ -20,7 +20,7 @@ import { ValidationErrorModel } from '@common/forms/validation/error-model/valid
import { UiNotificationService } from '@app/core/services/notification/ui-notification-service';
import { SnackBarNotificationLevel } from '@common/modules/notification/ui-notification-service';
import { DatasetStatus } from '@app/core/common/enum/dataset-status';
import { DmpInvitationDialogComponent } from '@app/ui/dmp/invitation/dmp-invitation.component';
import { DmpInvitationDialogComponent } from '@app/ui/dmp/invitation/dmp-invitation-dialog.component';
import { RecentActivityOrder } from '@app/core/common/enum/recent-activity-order';
@Component({

View File

@ -15,7 +15,7 @@ import { BaseComponent } from '@common/base/base.component';
import { TranslateService } from '@ngx-translate/core';
import * as FileSaver from 'file-saver';
import { takeUntil } from 'rxjs/operators';
import { DmpInvitationDialogComponent } from '@app/ui/dmp/invitation/dmp-invitation.component';
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';

View File

@ -47,7 +47,7 @@
<div *ngFor="let item of listingItems; let i = index">
<app-dataset-listing-item-component [isPublic]="isPublic" [dataset]="item" [showDivider]="i != (listingItems.length - 1)"></app-dataset-listing-item-component>
</div>
<div *ngIf="listingItems && listingItems.length > 0 && this.startIndex < this.totalCount - 1 && this.pageSize < this.totalCount - 1" class="d-flex justify-content-center">
<div *ngIf="listingItems && listingItems.length > 0 && listingItems.length >= startIndex + pageSize" class="d-flex justify-content-center">
<button type="button" class="btn-load-more" (click)="loadMore()">{{'GENERAL.ACTIONS.LOAD-MORE' | translate}}</button>
</div>
</div>

View File

@ -7,7 +7,7 @@ import { DatasetWizardService } from '@app/core/services/dataset-wizard/dataset-
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.component';
import { DmpInvitationDialogComponent } from '@app/ui/dmp/invitation/dmp-invitation-dialog.component';
import { MatDialog } from '@angular/material';
import { DatasetCopyDialogueComponent } from '../../dataset-wizard/dataset-copy-dialogue/dataset-copy-dialogue.component';
import { FormControl } from '@angular/forms';

View File

@ -49,8 +49,8 @@
matTooltipPosition="above">
<mat-icon class="mat-mini-fab-icon">content_copy</mat-icon>
</button>
<button *ngIf="isDraftDataset(dataset) && isUserOwner && !lockStatus" (click)="editClicked(dataset)"
mat-mini-fab class="mr-3 actions-btn"
<button *ngIf="isDraftDataset(dataset) && isUserOwner && !lockStatus"
(click)="editClicked(dataset)" mat-mini-fab class="mr-3 actions-btn"
matTooltip="{{'DMP-LISTING.ACTIONS.EDIT' | translate}}" matTooltipPosition="above">
<mat-icon class="mat-mini-fab-icon">create</mat-icon>
</button>
@ -76,7 +76,8 @@
<div class="row header">{{'DMP-OVERVIEW.RESEARCHERS' | translate}}</div>
<div class="row">
<div *ngFor="let researcher of researchers; let last = last">
<a href="{{ getOrcidPathForResearcher(researcher.reference) }}" target="blank" class="researcher">
<a href="{{ getOrcidPathForResearcher(researcher.reference) }}" target="blank"
class="researcher">
<div class="id-btn">&nbsp;</div>
<div *ngIf="!last">{{ researcher.name }}, </div>
<div *ngIf="last">{{ researcher.name }}</div>
@ -102,6 +103,12 @@
<hr class="hr-line">
</div>
</div>
<div *ngIf="hasReversableStatus(dataset) && !lockStatus" class="row ml-0 mr-0 pl-4 pb-3 d-flex align-items-center" (click)="reverse(dataset)">
<button mat-mini-fab class="frame-btn">
<mat-icon class="mat-mini-fab-icon">unarchive</mat-icon>
</button>
<p class="mb-0 mr-0 pl-2 frame-txt">{{ 'DATASET-WIZARD.ACTIONS.REVERSE' | translate }}</p>
</div>
<div class="row ml-0 mr-0 pl-4 pb-3 d-flex align-items-center">
<button mat-mini-fab class="frame-btn" [matMenuTriggerFor]="exportMenu">
<mat-icon class="mat-mini-fab-icon">open_in_new</mat-icon>
@ -109,12 +116,12 @@
<p class="mb-0 mr-0 pl-2 frame-txt" [matMenuTriggerFor]="exportMenu">
{{ 'DMP-LISTING.ACTIONS.EXPORT' | translate }}</p>
</div>
<div *ngIf="!dataset.public && showPublishButton(dataset) && isUserOwner && dataset.dmp.isPublic" class="row ml-0 mr-0 pl-4 pb-3 d-flex align-items-center" (click)="publish(dataset.id)">
<!-- <div *ngIf="!dataset.public && showPublishButton(dataset) && isUserOwner" class="row ml-0 mr-0 pl-4 pb-3 d-flex align-items-center" (click)="publish(dataset.id)">
<button mat-mini-fab class="frame-btn">
<mat-icon class="mat-mini-fab-icon">public</mat-icon>
</button>
<p class="mb-0 pl-2 frame-txt">{{ 'DMP-LISTING.ACTIONS.MAKE-PUBLIC' | translate }}</p>
</div>
</div> -->
<mat-menu #exportMenu="matMenu" xPosition="before">
<button mat-menu-item (click)="downloadPDF(dataset.id)">
<i class="fa fa-file-pdf-o pr-2"></i>
@ -153,7 +160,8 @@
<p class="authors-role">{{ roleDisplay(user) }}</p>
</div>
</div>
<button *ngIf="isUserOwner && !dataset.status && user.role" (click)="removeUserFromDmp(user)"
<button *ngIf="isUserOwner && !dataset.status && user.role"
(click)="removeUserFromDmp(user)"
class="remove-btn">{{ 'GENERAL.CONFIRMATION-DIALOG.ACTIONS.REMOVE' | translate}}</button>
</div>
</div>
@ -169,4 +177,4 @@
</div>
</div>
</div>
</div>
</div>

View File

@ -20,7 +20,7 @@ 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.component';
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 { FormControl } from '@angular/forms';
@ -31,6 +31,7 @@ import { LockService } from '@app/core/services/lock/lock.service';
import { DatasetsToBeFinalized } from '@app/core/model/dataset/datasets-toBeFinalized';
import { DatasetModel } from '@app/core/model/dataset/dataset';
import { DatasetWizardModel } from '@app/core/model/dataset/dataset-wizard';
import { DmpStatus } from '@app/core/common/enum/dmp-status';
@Component({
@ -301,15 +302,15 @@ export class DatasetOverviewComponent extends BaseComponent implements OnInit {
this.router.navigate(['/datasets']);
}
onDeleteCallbackError(error) {
this.uiNotificationService.snackBarNotification(error.error.message ? error.error.message : this.language.instant('GENERAL.SNACK-BAR.UNSUCCESSFUL-DELETE'), SnackBarNotificationLevel.Error);
}
onUpdateCallbackSuccess(): void {
this.uiNotificationService.snackBarNotification(this.language.instant('GENERAL.SNACK-BAR.SUCCESSFUL-UPDATE'), SnackBarNotificationLevel.Success);
this.reloadPage();
}
onDeleteCallbackError(error) {
this.uiNotificationService.snackBarNotification(error.error.message ? error.error.message : this.language.instant('GENERAL.SNACK-BAR.UNSUCCESSFUL-DELETE'), SnackBarNotificationLevel.Error);
}
onUpdateCallbackError(error) {
this.uiNotificationService.snackBarNotification(error.error.message ? error.error.message : this.language.instant('DATASET-UPLOAD.SNACK-BAR.UNSUCCESSFUL'), SnackBarNotificationLevel.Error);
}
@ -358,15 +359,15 @@ export class DatasetOverviewComponent extends BaseComponent implements OnInit {
}
//GK: NO
// downloadJson(id: string) {
// this.datasetService.downloadJson(id)
// .pipe(takeUntil(this._destroyed))
// .subscribe(response => {
// const blob = new Blob([response.body], { type: 'application/json' });
// const filename = this.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
// FileSaver.saveAs(blob, filename);
// })
// }
// downloadJson(id: string) {
// this.datasetService.downloadJson(id)
// .pipe(takeUntil(this._destroyed))
// .subscribe(response => {
// const blob = new Blob([response.body], { type: 'application/json' });
// const filename = this.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
// FileSaver.saveAs(blob, filename);
// })
// }
getFilenameFromContentDispositionHeader(header: string): string {
const regex: RegExp = new RegExp(/filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/g);
@ -444,29 +445,29 @@ export class DatasetOverviewComponent extends BaseComponent implements OnInit {
return this.isFinalizedDataset(dataset) && !dataset.public && this.hasPublishButton;
}
publish(id: String) {
const dialogRef = this.dialog.open(ConfirmationDialogComponent, {
maxWidth: '500px',
restoreFocus: false,
data: {
message: this.language.instant('GENERAL.CONFIRMATION-DIALOG.PUBLISH-ITEM'),
privacyPolicyNames: this.language.instant('GENERAL.CONFIRMATION-DIALOG.PRIVACY-POLICY-NAMES'),
confirmButton: this.language.instant('GENERAL.CONFIRMATION-DIALOG.ACTIONS.CONFIRM'),
cancelButton: this.language.instant('GENERAL.CONFIRMATION-DIALOG.ACTIONS.CANCEL'),
isDeleteConfirmation: false
}
});
dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(result => {
if (result) {
this.datasetService.publish(id)
.pipe(takeUntil(this._destroyed))
.subscribe(() => {
this.hasPublishButton = false;
this.reloadPage();
});
}
});
}
// publish(id: String) {
// const dialogRef = this.dialog.open(ConfirmationDialogComponent, {
// maxWidth: '500px',
// restoreFocus: false,
// data: {
// message: this.language.instant('GENERAL.CONFIRMATION-DIALOG.PUBLISH-ITEM'),
// privacyPolicyNames: this.language.instant('GENERAL.CONFIRMATION-DIALOG.PRIVACY-POLICY-NAMES'),
// confirmButton: this.language.instant('GENERAL.CONFIRMATION-DIALOG.ACTIONS.CONFIRM'),
// cancelButton: this.language.instant('GENERAL.CONFIRMATION-DIALOG.ACTIONS.CANCEL'),
// isDeleteConfirmation: false
// }
// });
// dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(result => {
// if (result) {
// this.datasetService.publish(id)
// .pipe(takeUntil(this._destroyed))
// .subscribe(() => {
// this.hasPublishButton = false;
// this.reloadPage();
// });
// }
// });
// }
finalize(dataset: DatasetOverviewModel) {
const dialogRef = this.dialog.open(ConfirmationDialogComponent, {
@ -492,4 +493,32 @@ export class DatasetOverviewComponent extends BaseComponent implements OnInit {
});
}
hasReversableStatus(dataset: DatasetOverviewModel): boolean {
return dataset.dmp.status == DmpStatus.Draft && dataset.status == DatasetStatus.Finalized
}
reverse(dataset: DatasetOverviewModel) {
const dialogRef = this.dialog.open(ConfirmationDialogComponent, {
restoreFocus: false,
data: {
message: this.language.instant('GENERAL.CONFIRMATION-DIALOG.UNFINALIZE-ITEM'),
confirmButton: this.language.instant('QUICKWIZARD.SAVE-DIALOG.ACTIONS.AFFIRMATIVE'),
cancelButton: this.language.instant('QUICKWIZARD.SAVE-DIALOG.ACTIONS.NEGATIVE'),
isDeleteConfirmation: false
}
});
dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(result => {
if (result) {
this.getDatasetWizardModel(this.dataset.id);
this.datasetWizardModel.status = DatasetStatus.Draft;
this.datasetWizardService.createDataset(this.datasetWizardModel)
.pipe(takeUntil(this._destroyed))
.subscribe(
data => this.onUpdateCallbackSuccess(),
error => this.onUpdateCallbackError(error)
);
}
});
}
}

View File

@ -18,7 +18,7 @@ import { GeneralTabComponent } from '@app/ui/dmp/editor/general-tab/general-tab.
import { GrantTabComponent } from '@app/ui/dmp/editor/grant-tab/grant-tab.component';
import { PeopleTabComponent } from '@app/ui/dmp/editor/people-tab/people-tab.component';
import { InvitationAcceptedComponent } from '@app/ui/dmp/invitation/accepted/dmp-invitation-accepted.component';
import { DmpInvitationDialogComponent } from '@app/ui/dmp/invitation/dmp-invitation.component';
import { DmpInvitationDialogComponent } from '@app/ui/dmp/invitation/dmp-invitation-dialog.component';
import { DmpCriteriaComponent } from '@app/ui/dmp/listing/criteria/dmp-criteria.component';
import { DmpUploadDialogue } from '@app/ui/dmp/listing/upload-dialogue/dmp-upload-dialogue.component';
import { DmpListingComponent } from '@app/ui/dmp/listing/dmp-listing.component';
@ -36,6 +36,9 @@ import { AddCostComponent } from './editor/cost-editor/add-cost/add-cost.compone
import { CostListingComponent } from './editor/cost-editor/cost-listing/cost-listing.component';
import { DmpCriteriaDialogComponent } from './listing/criteria/dmp-criteria-dialog.component';
import { StartNewDmpDialogComponent } from './start-new-dmp-dialogue/start-new-dmp-dialog.component';
import { MainInfoComponent } from './editor/main-info/main-info.component';
import { FundingInfoComponent } from './editor/funding-info/funding-info.component';
import { DatasetInfoComponent } from './editor/dataset-info/dataset-info.component';
@NgModule({
@ -79,7 +82,10 @@ import { StartNewDmpDialogComponent } from './start-new-dmp-dialogue/start-new-d
AddOrganizationComponent,
AddCostComponent,
CostListingComponent,
StartNewDmpDialogComponent
StartNewDmpDialogComponent,
MainInfoComponent,
FundingInfoComponent,
DatasetInfoComponent
],
entryComponents: [
DmpInvitationDialogComponent,

View File

@ -1,6 +1,6 @@
<form *ngIf="formGroup" [formGroup]="formGroup">
<h1 mat-dialog-title>{{'ADDORGANIZATION-EDITOR.TITLE' | translate}}</h1>
<div mat-dialog-content class="row">
<div mat-dialog-content class="row pb-2">
<mat-form-field class="col-12">
<input matInput formControlName="name" placeholder="{{'ADDORGANIZATION-EDITOR.NAME' | translate}}" required>
<mat-error *ngIf="formGroup.get('name').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>

View File

@ -1,6 +1,6 @@
<form *ngIf="formGroup" [formGroup]="formGroup">
<h1 mat-dialog-title>{{'ADDRESEARCHERS-EDITOR.TITLE' | translate}}</h1>
<div mat-dialog-content class="row">
<div mat-dialog-content class="row pb-2">
<mat-form-field class="col-12">
<input matInput formControlName="firstName" placeholder="{{'ADDRESEARCHERS-EDITOR.FIRST_NAME' | translate}}" required>
<mat-error *ngIf="formGroup.get('firstName').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>

View File

@ -0,0 +1,34 @@
<div class="main-info" [formGroup]="formGroup">
<div class="col-12 intro">
<p>{{'DMP-EDITOR.DATASET-INFO.INTRO' | translate}}</p>
<p>{{'DMP-EDITOR.DATASET-INFO.SECOND-INTRO' | translate}}</p>
</div>
<div class="col-12 card">
<div class="row">
<div class="col-12">
<div class="heading">3 {{'DMP-EDITOR.STEPPER.DATASET-INFO' | translate}}*</div>
<div class="hint">
<div class="pb-1">{{'DMP-EDITOR.MAIN-INFO.HINT' | translate}}</div>
<div><span class="material-icons-outlined align-bottom">info</span> {{'DMP-EDITOR.MAIN-INFO.TYPING' | translate}}</div>
</div>
<div class="profile-form">
<mat-form-field appearance="outline">
<app-multiple-auto-complete required='true' [formControl]="formGroup.get('profiles')" placeholder="{{'DMP-EDITOR.FIELDS.DATASET-TEMPLATES' | translate}}" [configuration]="profilesAutoCompleteConfiguration">
</app-multiple-auto-complete>
<mat-error *ngIf="formGroup.get('profiles').hasError('backendError')">
{{formGroup.get('profiles').getError('backendError').message}}</mat-error>
<mat-error *ngIf="formGroup.get('profiles').hasError('required')">
{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
<button matSuffix class="input-btn" [disabled]="formGroup.get('profiles').disabled" (click)="availableProfiles($event)">
<mat-icon class="icon-btn">view_list</mat-icon>
</button>
</mat-form-field>
</div>
<div class="col pb-3 d-flex">
<span class="not-found">{{'DMP-EDITOR.DATASET-INFO.FIND' | translate}}</span>
<span class="insert" (click)="addDataset(dmp.id)">{{'DMP-EDITOR.ACTIONS.CREATE-DATASET' | translate}}</span>
</div>
</div>
</div>
</div>
</div>

View File

@ -0,0 +1,85 @@
.main-info {
// position: relative;
// left: 362px;
// width: calc(100% - 366px);
.intro {
text-align: left;
font-weight: 400;
letter-spacing: 0px;
color: #212121;
opacity: 1;
margin: 3rem 0rem 3rem 0rem;
}
.heading {
text-align: left;
font-weight: 700;
font-size: 18px;
letter-spacing: 0px;
color: #212121;
opacity: 0.81;
margin-top: 1.625rem;
margin-bottom: 0.625rem;
}
.hint {
text-align: left;
font-weight: 400;
font-size: 16px;
letter-spacing: 0px;
color: #212121;
opacity: 0.81;
margin-bottom: 2.125rem;
}
.title-form,
.description-form {
text-align: left;
font-weight: 400;
font-size: 16px;
letter-spacing: 0.15px;
color: #7d7d7d;
opacity: 1;
margin-bottom: 1rem;
}
// textarea::placeholder {
// font-style: oblique;
// }
.input-btn {
border: none;
color: #aaaaaa;
background-color: #ffffff00;
cursor: pointer;
}
.input-btn :hover {
color: #00b29f !important;
}
.insert {
text-decoration: underline;
color: #00b29f;
cursor: pointer;
font-size: 1rem;
font-weight: 400;
}
.not-found {
cursor: pointer;
font-size: 1rem;
font-weight: 400;
padding: 0rem 0.5rem 0rem 0rem;
}
}
::ng-deep .profile-form .mat-form-field-appearance-outline .mat-form-field-outline {
background: #fafafa !important;
}
::ng-deep .profile-form .mat-form-field-appearance-outline .mat-form-field-infix {
font-size: 1rem;
padding: 0.6em 0 1em 0 !important;
}

View File

@ -0,0 +1,131 @@
import { BaseComponent } from '@common/base/base.component';
import { OnInit, Component, Input, Output, EventEmitter } from '@angular/core';
import { FormGroup } from '@angular/forms';
import { TranslateService } from '@ngx-translate/core';
import { ConfigurationService } from '@app/core/services/configuration/configuration.service';
import { MultipleAutoCompleteConfiguration } from '@app/library/auto-complete/multiple/multiple-auto-complete-configuration';
import { map, takeUntil } from 'rxjs/operators';
import { Observable } from 'rxjs';
import { ExternalSourcesService } from '@app/core/services/external-sources/external-sources.service';
import { isNullOrUndefined } from 'util';
import { MatDialog } from '@angular/material';
import { DatasetProfileModel } from '@app/core/model/dataset/dataset-profile';
import { DatasetProfileCriteria } from '@app/core/query/dataset-profile/dataset-profile-criteria';
import { DataTableRequest } from '@app/core/model/data-table/data-table-request';
import { DmpService } from '@app/core/services/dmp/dmp.service';
import { DmpProfileDefinition } from '@app/core/model/dmp-profile/dmp-profile';
import { DmpProfileService } from '@app/core/services/dmp/dmp-profile.service';
import { AvailableProfilesComponent } from '../available-profiles/available-profiles.component';
import { DmpEditorModel } from '../dmp-editor.model';
import { Router } from '@angular/router';
@Component({
selector: 'dataset-info',
templateUrl: './dataset-info.component.html',
styleUrls: ['./dataset-info.component.scss']
})
export class DatasetInfoComponent extends BaseComponent implements OnInit {
@Input() formGroup: FormGroup = null;
@Input() isUserOwner: boolean;
@Input() dmp: DmpEditorModel;
@Input() isPublic: boolean;
@Input() isFinalized: boolean;
@Input() isNewVersion: boolean;
@Input() isClone: boolean;
@Output() onFormChanged: EventEmitter<any> = new EventEmitter();
selectedDmpProfileDefinition: DmpProfileDefinition;
profilesAutoCompleteConfiguration: MultipleAutoCompleteConfiguration;
constructor(
private language: TranslateService,
private configurationService: ConfigurationService,
private externalSourcesService: ExternalSourcesService,
private dialog: MatDialog,
private _service: DmpService,
private dmpProfileService: DmpProfileService,
private router: Router
) {
super();
}
ngOnInit() {
this.profilesAutoCompleteConfiguration = {
filterFn: this.filterProfiles.bind(this),
initialItems: (excludedItems: any[]) => this.filterProfiles('').pipe(map(result => result.filter(resultItem => (excludedItems || []).map(x => x.id).indexOf(resultItem.id) === -1))),
displayFn: (item) => item['label'],
titleFn: (item) => item['label'],
subtitleFn: (item) => item['description']
};
if (this.formGroup.get('definition')) { this.selectedDmpProfileDefinition = this.formGroup.get('definition').value; }
this.registerFormEventsForDmpProfile();
if (this.isNewVersion) {
this.formGroup.get('label').disable();
}
if (!this.isUserOwner && !this.isClone) {
this.formGroup.disable();
}
if (isNullOrUndefined(this.formGroup.get('extraProperties').get('publicDate').value)) {
this.formGroup.get('extraProperties').get('publicDate').patchValue(new Date());
}
this.formGroup.valueChanges.pipe(takeUntil(this._destroyed))
.subscribe(x => {
this.profilesAutoCompleteConfiguration = {
filterFn: this.filterProfiles.bind(this),
initialItems: (excludedItems: any[]) => this.filterProfiles('').pipe(map(result => result.filter(resultItem => (excludedItems || []).map(x => x.id).indexOf(resultItem.id) === -1))),
displayFn: (item) => item['label'],
titleFn: (item) => item['label'],
subtitleFn: (item) => item['description']
};
this.onFormChanged.emit();
});
}
// Researchers
filterProfiles(value: string): Observable<DatasetProfileModel[]> {
const request = new DataTableRequest<DatasetProfileCriteria>(null, null, { fields: ['+label'] });
const criteria = new DatasetProfileCriteria();
criteria.like = value;
request.criteria = criteria;
return this._service.searchDMPProfiles(request);
}
registerFormEventsForDmpProfile(definitionProperties?: DmpProfileDefinition): void {
this.formGroup.get('profile').valueChanges
.pipe(
takeUntil(this._destroyed))
.subscribe(Option => {
if (Option instanceof Object) {
this.selectedDmpProfileDefinition = null;
this.dmpProfileService.getSingle(Option.id)
.pipe(takeUntil(this._destroyed))
.subscribe(result => {
this.selectedDmpProfileDefinition = result.definition;
});
} else {
this.selectedDmpProfileDefinition = null;
}
this.selectedDmpProfileDefinition = definitionProperties;
})
}
availableProfiles(event: MouseEvent) {
event.stopPropagation();
const dialogRef = this.dialog.open(AvailableProfilesComponent, {
data: {
profiles: this.formGroup.get('profiles')
}
});
return false;
}
addDataset(id: String) {
this.router.navigate(['/datasets/new/' + id]);
}
}

View File

@ -1,4 +1,68 @@
<div class="main-content">
<div *ngIf="dmp" class="container-fluid">
<form *ngIf="formGroup" [formGroup]="formGroup" (ngSubmit)="formSubmit()">
<div class="fixed-editor-header">
<div class="card editor-header">
<div class="col">
<div class="row">
<div class="col-auto">
<div class="title">{{'DMP-EDITOR.TITLE.EDIT-DMP' | translate}}</div>
<div class="subtitle">{{ formGroup.get('label').value }} <span *ngIf="isDirty()" class="changes">({{'DMP-EDITOR.CHANGES' | translate}})</span></div>
</div>
<div class="ml-auto d-flex flex-row">
<button *ngIf="isDirty()" type="button" class="discard-btn mr-3" (click)="discardChanges()">
{{'DMP-EDITOR.ACTIONS.DISCARD' | translate}}
</button>
<div *ngIf="isNew" mat-raised-button type="button" (click)="addDataset()" class="save-btn">
<div>{{'DMP-EDITOR.ACTIONS.SAVE' | translate}}</div>
</div>
<div *ngIf="!isNew && formGroup.enabled && !lockStatus">
<button *ngIf="!isFinalized" mat-raised-button type="submit" class="save-btn">
{{'DMP-EDITOR.ACTIONS.SAVE' | translate}}
</button>
</div>
<!-- <div *ngIf="!isNew && formGroup.enabled && !lockStatus">
<div *ngIf="!isFinalized" mat-raised-button type="submit" mat-raised-button type="button" (click)="addDataset()" class="save-btn">
<div>{{'DMP-EDITOR.ACTIONS.SAVE' | translate}}</div>
</div>
</div> -->
</div>
</div>
</div>
</div>
</div>
<div class="row editor-content">
<div class="col-auto stepper">
<div class="stepper-title">{{'DMP-EDITOR.STEPPER.USER-GUIDE' | translate}}</div>
<div class="stepper-options">
<ol class="stepper-list">
<li (click)="changeStep(0)" [ngClass]="{'active': this.step === 0}">{{'DMP-EDITOR.STEPPER.MAIN-INFO' | translate}} (4)</li>
<li (click)="changeStep(1)" [ngClass]="{'active': this.step === 1}">{{'DMP-EDITOR.STEPPER.FUNDING-INFO' | translate}} (3)</li>
<li (click)="changeStep(2)" [ngClass]="{'active': this.step === 2}">{{'DMP-EDITOR.STEPPER.DATASET-INFO' | translate}}</li>
</ol>
</div>
<div class="stepper-actions">
<div mat-raised-button type="button" class="col-auto previous stepper-btn mr-2 ml-auto" [ngClass]="{'previous-disabled': this.step === 0}" (click)="previousStep()">
<span class="material-icons">chevron_left</span>
<div>{{'DMP-EDITOR.STEPPER.PREVIOUS' | translate}}</div>
</div>
<div mat-raised-button type="button" class="col-auto next stepper-btn ml-auto" [ngClass]="{'next-disabled': this.step === this.maxStep}" (click)="nextStep()">
<span class="material-icons">chevron_right</span>
<div>{{'DMP-EDITOR.STEPPER.NEXT' | translate}}</div>
</div>
</div>
</div>
<div class="col-auto form">
<main-info [hidden]="this.step !== 0" [formGroup]="formGroup" [isUserOwner]="isUserOwner" (onFormChanged)="formChanged()"></main-info>
<funding-info [hidden]="this.step !== 1" [formGroup]="formGroup" [grantformGroup]="formGroup.get('grant')" [projectFormGroup]="formGroup.get('project')" [funderFormGroup]="formGroup.get('funder')" [isFinalized]="isFinalized || lockStatus" [isNew]="isNew" [isUserOwner]="isUserOwner" (onFormChanged)="formChanged()"></funding-info>
<dataset-info [hidden]="this.step !== 2" [formGroup]="formGroup" [dmp]="dmp" [isPublic]="isPublic" [isFinalized]="isFinalized || lockStatus" [isUserOwner]="isUserOwner" (onFormChanged)="formChanged()"></dataset-info>
</div>
</div>
</form>
</div>
</div>
<!-- <div class="main-content">
<div class="container-fluid">
<div *ngIf="dmp" class="card">
<div class="card-header card-header-plain d-flex">
@ -87,12 +151,6 @@
<mat-tab *ngIf="isNew" disabled>
<ng-template mat-tab-label></ng-template>
</mat-tab>
<!-- <mat-tab>
<ng-template mat-tab-label>
<mat-icon class="mr-2">settings</mat-icon>
{{ 'DMP-LISTING.ACTIONS.SETTINGS' | translate }}
</ng-template>
</mat-tab> -->
</mat-tab-group>
<div class="d-flex justify-content-end pt-2 pb-4 pl-2">
@ -129,4 +187,4 @@
</form>
</div>
</div>
</div>
</div> -->

View File

@ -8,6 +8,14 @@
}
}
form {
height: calc(100vh - 124px);
}
.main-content {
height: 100vh !important;
}
.menu-item {
width: 248px;
}
@ -29,6 +37,175 @@
padding-right: 6px;
}
.fixed-editor-header {
// position: fixed;
// width: calc(100% - 310px);
z-index: 3;
background-color: whitesmoke;
}
.editor-header {
height: 64px;
background: var(--unnamed-color-129d99) 0% 0% no-repeat padding-box;
background: #129d99 0% 0% no-repeat padding-box;
box-shadow: 0px 3px 6px #00000029;
padding: 0.6rem;
margin: 30px 0px 0px 0px;
border-radius: 4px;
opacity: 1;
}
.editor-content {
.form {
// position: relative;
// left: 362px;
// width: calc(100% - 366px);
position: relative;
left: 362px;
width: calc(100% - 366px);
overflow-y: auto;
height: calc(100vh - 172px);
}
}
.title {
text-align: left;
font-weight: 400;
font-size: 14px;
color: #ffffff;
opacity: 0.75;
}
.subtitle {
text-align: left;
color: #ffffff;
font-weight: 700;
font-size: 16px;
opacity: 1;
}
.discard-btn {
background: transparent;
border: 1px solid #ffffff;
color: white;
border-radius: 30px;
opacity: 1;
width: 110px;
height: 40px;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
}
.save-btn {
background: #ffffff 0% 0% no-repeat padding-box;
border-radius: 30px;
opacity: 1;
width: 110px;
height: 40px;
display: flex;
justify-content: center;
align-items: center;
font-weight: 700;
color: #129d99;
cursor: pointer;
}
.changes {
font-weight: 400;
color: #ffffff;
}
.stepper {
position: fixed;
// height: 100%;
display: flex;
flex-direction: column;
height: calc(100vh - 205px);
}
.stepper-title {
text-align: left;
font-weight: 300;
font-size: 20px;
letter-spacing: 0px;
color: #212121;
opacity: 0.6;
margin: 2.875rem 0rem 2.875rem 0rem;
padding-left: 1rem;
}
.stepper-list li {
text-align: left;
font-weight: 400;
letter-spacing: 0px;
color: #212121;
padding: 0.3rem 0.1rem;
opacity: 0.6;
cursor: pointer;
}
.stepper-list .active {
color: #212121;
font-weight: 700;
opacity: 1;
}
.stepper-options {
// flex-grow: 1;
}
.stepper-actions {
display: flex;
padding-left: 1rem;
margin-top: auto;
// margin-top: 5rem;
// flex-grow: 8;
}
.stepper-btn {
border-radius: 30px;
opacity: 1;
width: 154px;
height: 40px;
display: flex;
justify-content: center;
align-items: center;
font-size: 14px;
}
.previous {
color: #212121;
background: #f5f5f5 0% 0% no-repeat padding-box;
box-shadow: 0px 3px 6px #1e202029;
border: 2px solid #212121;
font-weight: 500;
cursor: pointer;
}
.next {
background: #129d99 0% 0% no-repeat padding-box;
color: white;
box-shadow: 0px 3px 6px #1e202029;
font-weight: 400;
cursor: pointer;
}
.previous-disabled {
border: 1px solid #b5b5b5;
color: #b5b5b5;
cursor: auto !important;
}
.next-disabled {
background: #cbcbcb 0% 0% no-repeat padding-box;
box-shadow: 0px 3px 6px #1e202029;
color: white;
cursor: auto !important;
}
::ng-deep .mat-tab-labels {
justify-content: space-between;
}

View File

@ -1,11 +1,11 @@
import { Component, OnInit } from '@angular/core';
import { FormGroup } from '@angular/forms';
import { Component, OnInit, SimpleChanges } from '@angular/core';
import { FormGroup, AbstractControl, FormControl, FormArray } from '@angular/forms';
import { MatDialog } from '@angular/material/dialog';
import { ActivatedRoute, Params, Router } from '@angular/router';
import { DmpStatus } from '@app/core/common/enum/dmp-status';
import { DataTableRequest } from '@app/core/model/data-table/data-table-request';
import { DmpProfileDefinition } from '@app/core/model/dmp-profile/dmp-profile';
import { DmpProfileDefinition, DmpProfile } from '@app/core/model/dmp-profile/dmp-profile';
import { DmpProfileListing } from '@app/core/model/dmp-profile/dmp-profile-listing';
import { DmpModel } from '@app/core/model/dmp/dmp';
import { UserModel } from '@app/core/model/user/user';
@ -37,11 +37,8 @@ import { map, takeUntil } from 'rxjs/operators';
import { Principal } from "@app/core/model/auth/principal";
import { Role } from "@app/core/common/enum/role";
import { LockService } from '@app/core/services/lock/lock.service';
import { Location } from '@angular/common';
import { LockModel } from '@app/core/model/lock/lock.model';
import { Guid } from '@common/types/guid';
import { isNullOrUndefined } from 'util';
import { environment } from 'environments/environment';
import { ConfigurationService } from '@app/core/services/configuration/configuration.service';
import { ExtraPropertiesFormModel } from './general-tab/extra-properties-form.model';
@ -61,8 +58,10 @@ export class DmpEditorComponent extends BaseComponent implements OnInit, IBreadC
isFinalized = false;
dmp: DmpEditorModel;
formGroup: FormGroup = null;
selectedTab = 0;
formGroupRawValue: any;
hasChanges = false;
selectedTab = 0;
createNewVersion;
associatedUsers: Array<UserModel>;
people: Array<UserInfoListingModel>;
@ -72,6 +71,8 @@ export class DmpEditorComponent extends BaseComponent implements OnInit, IBreadC
isUserOwner: boolean = true;
lock: LockModel;
lockStatus: Boolean;
step: number = 0;
maxStep: number = 2;
constructor(
private dmpProfileService: DmpProfileService,
@ -138,6 +139,9 @@ export class DmpEditorComponent extends BaseComponent implements OnInit, IBreadC
this.dmp.extraProperties = new ExtraPropertiesFormModel();
this.dmp.fromModel(data);
this.formGroup = this.dmp.buildForm();
this.formGroupRawValue = JSON.parse(JSON.stringify(this.formGroup.getRawValue()));
this.setIsUserOwner();
if (!this.isUserOwner) {
this.isFinalized = true;
@ -195,6 +199,9 @@ export class DmpEditorComponent extends BaseComponent implements OnInit, IBreadC
this.dmp.extraProperties = new ExtraPropertiesFormModel();
this.dmp.fromModel(data);
this.formGroup = this.dmp.buildForm();
this.formGroupRawValue = JSON.parse(JSON.stringify(this.formGroup.getRawValue()));
//this.registerFormEventsForDmpProfile(this.dmp.definition);
this.formGroup.disable();
// if (!this.isAuthenticated) {
@ -231,6 +238,9 @@ export class DmpEditorComponent extends BaseComponent implements OnInit, IBreadC
this.dmp.extraProperties.visible = false;
this.dmp.extraProperties.contact = this.authService.current().id;
this.formGroup = this.dmp.buildForm();
this.formGroupRawValue = JSON.parse(JSON.stringify(this.formGroup.getRawValue()));
this.registerFormEventsForNewItem();
if (this.isAuthenticated) {
this.language.get('NAV-BAR.MY-DMPS').pipe(takeUntil(this._destroyed)).subscribe(x => {
@ -259,6 +269,28 @@ export class DmpEditorComponent extends BaseComponent implements OnInit, IBreadC
});
}
copyFormControl(control: AbstractControl) {
if (control instanceof FormControl) {
return new FormControl(control.value);
} else if (control instanceof FormGroup) {
const copy = new FormGroup({});
Object.keys(control.getRawValue()).forEach(key => {
copy.addControl(key, this.copyFormControl(control.controls[key]));
});
return copy;
} else if (control instanceof FormArray) {
const copy = new FormArray([]);
control.controls.forEach(control => {
copy.push(this.copyFormControl(control));
})
return copy;
}
}
public formChanged() {
this.hasChanges = true;
}
isAuthenticated() {
return this.authService.current() != null;
}
@ -576,6 +608,29 @@ export class DmpEditorComponent extends BaseComponent implements OnInit, IBreadC
this.lockService.createOrUpdate(this.lock).pipe(takeUntil(this._destroyed)).subscribe(async result => this.lock.id = Guid.parse(result));
}
public changeStep(index: number) {
this.step = index;
}
public nextStep() {
this.step = this.step < this.maxStep ? this.step + 1 : this.step;
}
public previousStep() {
this.step = this.step !== 0 ? this.step - 1 : this.step;
}
public isDirty(): boolean {
return this.formGroup.dirty && this.hasChanges;
}
public discardChanges() {
// this.formGroup.reset();
this.formGroup.patchValue(JSON.parse(JSON.stringify(this.formGroupRawValue)));
this.hasChanges = false;
}
// advancedClicked() {
// const dialogRef = this.dialog.open(ExportMethodDialogComponent, {
// maxWidth: '500px',

View File

@ -0,0 +1,143 @@
<div class="funding-info">
<form *ngIf="grantformGroup" [formGroup]="grantformGroup">
<div class="col-12 intro">
{{'DMP-EDITOR.FUNDING-INFO.INTRO' | translate}}
</div>
<div class="col-12 card">
<!-- Funder Field -->
<div class="row">
<div class="col-12">
<div class="heading">2.1 {{'DMP-EDITOR.FIELDS.FUNDING-ORGANIZATIONS' | translate}}*</div>
<div class="hint">
<div class="pb-1">{{'DMP-EDITOR.FIELDS.EXTERNAL-SOURCE-HINT' | translate}}</div>
<div><span class="material-icons-outlined align-bottom">info</span> {{'DMP-EDITOR.MAIN-INFO.TYPING' | translate}}</div>
</div>
<div class="funder-form">
<div *ngIf="!isCreateNewFunder">
<mat-form-field appearance="outline">
<app-single-auto-complete required='true' [formControl]="funderFormGroup.get('existFunder')" placeholder="{{'DMP-EDITOR.FIELDS.FUNDER' | translate}}" [configuration]="funderAutoCompleteConfiguration">
</app-single-auto-complete>
</mat-form-field>
</div>
<!-- Create New Funder -->
<div *ngIf="isCreateNewFunder">
<mat-form-field appearance="outline">
<input matInput placeholder="{{'QUICKWIZARD.CREATE-ADD.CREATE.QUICKWIZARD_CREATE.FIRST-STEP.FIELDS.FUNDER-LABEL' | translate}}" type="text" name="label" [formControl]="funderFormGroup.get('label')" required>
<mat-error *ngIf="funderFormGroup.get('label').hasError('backendError')">
{{funderFormGroup.get('label').getError('backendError').message}}</mat-error>
<mat-error *ngIf="funderFormGroup.get('label').hasError('required')">
{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
</div>
</div>
<!-- Toggle Between Add Funder or Use Existing -->
<div class="col d-flex">
<div class="row" *ngIf="showToggleButton()">
<div *ngIf="isCreateNewFunder" (click)="createFunder()">
<span class="insert">{{'QUICKWIZARD.CREATE-ADD.CREATE.QUICKWIZARD_CREATE.ACTIONS.EXIST-FUNDER' | translate}}</span>
</div>
<div *ngIf="!isCreateNewFunder" (click)="createFunder()">
<span [ngClass]="isNewVersion?'disabled-toggle':'not-found'">{{'DMP-EDITOR.FUNDING-INFO.FIND' | translate}}</span>
<span [ngClass]="isNewVersion?'disabled-toggle':'insert'">{{'DMP-EDITOR.ACTIONS.INSERT-MANUALLY' | translate}}</span>
</div>
</div>
</div>
</div>
</div>
<!-- Grant field -->
<div class="row">
<div class="col-12">
<div class="heading">2.2 {{'DMP-EDITOR.FIELDS.GRANTS' | translate}}*</div>
<div class="hint">
<div class="pb-1">{{'DMP-EDITOR.FIELDS.EXTERNAL-SOURCE-HINT' | translate}}</div>
<div><span class="material-icons-outlined align-bottom">info</span> {{'DMP-EDITOR.MAIN-INFO.TYPING' | translate}}</div>
</div>
<div class="grant-form">
<div *ngIf="!isCreateNew">
<mat-form-field appearance="outline">
<app-single-auto-complete required='true' [formControl]="grantformGroup.get('existGrant')" placeholder="{{'DMP-EDITOR.FIELDS.GRANT' | translate}}" [configuration]="grantAutoCompleteConfiguration">
</app-single-auto-complete>
</mat-form-field>
</div>
<!-- Create New Grant -->
<div *ngIf="isCreateNew">
<mat-form-field appearance="outline">
<input matInput placeholder="{{'QUICKWIZARD.CREATE-ADD.CREATE.QUICKWIZARD_CREATE.FIRST-STEP.FIELDS.GRANT-LABEL' | translate}}" type="text" name="label" [formControl]="grantformGroup.get('label')" required>
<mat-error *ngIf="grantformGroup.get('label').hasError('backendError')">
{{grantformGroup.get('label').getError('backendError').message}}</mat-error>
<mat-error *ngIf="grantformGroup.get('label').hasError('required')">
{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
<mat-form-field appearance="outline">
<textarea matInput class="description-area" placeholder="{{'QUICKWIZARD.CREATE-ADD.CREATE.QUICKWIZARD_CREATE.FIRST-STEP.FIELDS.DESCRIPTION' | translate}}" [formControl]="grantformGroup.get('description')" [required]="true"></textarea>
<mat-error *ngIf="grantformGroup.get('description').hasError('backendError')">
{{projectFormGroup.get('description').getError('backendError').message}}</mat-error>
<mat-error *ngIf="grantformGroup.get('description').hasError('required')">
{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
</div>
<!-- Toggle Between Add Grant or Use Existing -->
<div class="col d-flex">
<div class="row" *ngIf="showToggleButton()">
<div *ngIf="isCreateNew" (click)="createGrant()">
<span class="insert">{{'QUICKWIZARD.CREATE-ADD.CREATE.QUICKWIZARD_CREATE.ACTIONS.EXIST-GRANT' | translate}}</span>
</div>
<div *ngIf="!isCreateNew" (click)="createGrant()">
<span [ngClass]="isNewVersion || isGrantDisabled()?'disabled-toggle':'not-found'">{{'DMP-EDITOR.FUNDING-INFO.FIND' | translate}}</span>
<span [ngClass]="isNewVersion || isGrantDisabled()?'disabled-toggle':'insert'">{{'DMP-EDITOR.ACTIONS.INSERT-MANUALLY' | translate}}</span>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Project field-->
<div class="row">
<div class="col-12">
<div class="heading">2.3 {{'DMP-EDITOR.FIELDS.PROJECT' | translate}}</div>
<div class="hint">
<div class="pb-1">{{'DMP-EDITOR.FIELDS.EXTERNAL-SOURCE-HINT' | translate}}</div>
<div><span class="material-icons-outlined align-bottom">info</span> {{'DMP-EDITOR.MAIN-INFO.TYPING' | translate}}</div>
</div>
<div class="project-form">
<div *ngIf="!isCreateNewProject">
<mat-form-field appearance="outline">
<app-single-auto-complete [formControl]="projectFormGroup.get('existProject')" placeholder="{{'DMP-EDITOR.FIELDS.PROJECT' | translate}}" [configuration]="projectAutoCompleteConfiguration">
</app-single-auto-complete>
</mat-form-field>
</div>
<!-- Create New Project -->
<div *ngIf="isCreateNewProject">
<mat-form-field appearance="outline">
<input matInput placeholder="{{'QUICKWIZARD.CREATE-ADD.CREATE.QUICKWIZARD_CREATE.FIRST-STEP.FIELDS.PROJECT-LABEL' | translate}}" type="text" name="label" [formControl]="projectFormGroup.get('label')" required>
<mat-error *ngIf="projectFormGroup.get('label').hasError('backendError')">
{{projectFormGroup.get('label').getError('backendError').message}}</mat-error>
<mat-error *ngIf="projectFormGroup.get('label').hasError('required')">
{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
<mat-form-field appearance="outline">
<textarea matInput class="description-area" placeholder="{{'QUICKWIZARD.CREATE-ADD.CREATE.QUICKWIZARD_CREATE.FIRST-STEP.FIELDS.DESCRIPTION' | translate}}" [formControl]="projectFormGroup.get('description')" [required]="true"></textarea>
<mat-error *ngIf="projectFormGroup.get('description').hasError('backendError')">
{{projectFormGroup.get('description').getError('backendError').message}}</mat-error>
<mat-error *ngIf="projectFormGroup.get('description').hasError('required')">
{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
</div>
<!-- Toggle Between Add Project or Use Existing -->
<div class="col pb-3 d-flex">
<div class="row" *ngIf="showToggleButton()">
<div *ngIf="isCreateNewProject" (click)="createProject()">
<span class="insert">{{'QUICKWIZARD.CREATE-ADD.CREATE.QUICKWIZARD_CREATE.ACTIONS.EXIST-PROJECT' | translate}}</span>
</div>
<div *ngIf="!isCreateNewProject" (click)="createProject()">
<span [ngClass]="isNewVersion?'disabled-toggle':'not-found'">{{'DMP-EDITOR.FUNDING-INFO.FIND' | translate}}</span>
<span [ngClass]="isNewVersion?'disabled-toggle':'insert'">{{'DMP-EDITOR.ACTIONS.INSERT-MANUALLY' | translate}}</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</form>
</div>

View File

@ -0,0 +1,112 @@
.funding-info {
// position: relative;
// left: 362px;
// width: calc(100% - 366px);
.intro {
text-align: left;
font-weight: 400;
letter-spacing: 0px;
color: #212121;
opacity: 1;
margin: 3rem 0rem 3rem 0rem;
}
.heading {
text-align: left;
font-weight: 700;
font-size: 18px;
letter-spacing: 0px;
color: #212121;
opacity: 0.81;
margin-top: 1.625rem;
margin-bottom: 0.625rem;
}
.hint {
text-align: left;
font-weight: 400;
font-size: 16px;
letter-spacing: 0px;
color: #212121;
opacity: 0.81;
margin-bottom: 2.125rem;
}
.title-form,
.description-form {
text-align: left;
font-weight: 400;
font-size: 16px;
letter-spacing: 0.15px;
color: #7d7d7d;
opacity: 1;
margin-bottom: 1rem;
}
// textarea::placeholder {
// font-style: oblique;
// }
.input-btn {
border: none;
color: #aaaaaa;
background-color: #ffffff00;
cursor: pointer;
}
.input-btn :hover {
color: #00b29f !important;
}
.insert {
text-decoration: underline;
color: #00b29f;
cursor: pointer;
font-size: 1rem;
font-weight: 400;
}
.not-found {
cursor: pointer;
font-size: 1rem;
font-weight: 400;
padding: 0rem 0.5rem 0rem 0rem;
}
.disabled-toggle {
font-size: 1rem;
font-weight: 400;
padding: 0rem 0.5rem 0rem 0rem;
color: #e0e0e0 !important;
text-decoration: none;
}
}
::ng-deep .funder-form .mat-form-field-appearance-outline .mat-form-field-outline {
background: #fafafa !important;
}
::ng-deep .grant-form .mat-form-field-appearance-outline .mat-form-field-outline {
background: #fafafa !important;
}
::ng-deep .project-form .mat-form-field-appearance-outline .mat-form-field-outline {
background: #fafafa !important;
}
::ng-deep .funder-form .mat-form-field-appearance-outline .mat-form-field-infix {
font-size: 1rem;
padding: 0.6em 0 1em 0 !important;
}
::ng-deep .grant-form .mat-form-field-appearance-outline .mat-form-field-infix {
font-size: 1rem;
padding: 0.6em 0 1em 0 !important;
}
::ng-deep .project-form .mat-form-field-appearance-outline .mat-form-field-infix {
font-size: 1rem;
padding: 0.6em 0 1em 0 !important;
}

View File

@ -0,0 +1,255 @@
import { BaseComponent } from '@common/base/base.component';
import { OnInit, Component, Input, EventEmitter, Output } from '@angular/core';
import { FormGroup } from '@angular/forms';
import { TranslateService } from '@ngx-translate/core';
import { GrantTabModel } from '../grant-tab/grant-tab-model';
import { SingleAutoCompleteConfiguration } from '@app/library/auto-complete/single/single-auto-complete-configuration';
import { FunderService } from '@app/core/services/funder/funder.service';
import { ProjectService } from '@app/core/services/project/project.service';
import { GrantService } from '@app/core/services/grant/grant.service';
import { RequestItem } from '@app/core/query/request-item';
import { GrantCriteria } from '@app/core/query/grant/grant-criteria';
import { ProjectCriteria } from '@app/core/query/project/project-criteria';
import { FunderCriteria } from '@app/core/query/funder/funder-criteria';
import { takeUntil } from 'rxjs/operators';
@Component({
selector: 'funding-info',
templateUrl: './funding-info.component.html',
styleUrls: ['./funding-info.component.scss']
})
export class FundingInfoComponent extends BaseComponent implements OnInit {
// @Input() formGroup: FormGroup = null;
@Input() isUserOwner: boolean;
@Input() isNew: boolean;
@Input() isFinalized: boolean;
@Input() isClone: boolean = false;
@Input() isNewVersion: boolean;
@Input() formGroup: FormGroup;
@Input() grantformGroup: FormGroup;
@Input() projectFormGroup: FormGroup;
@Input() funderFormGroup: FormGroup = null;
@Output() onFormChanged: EventEmitter<any> = new EventEmitter();
isCreateNew = false;
isCreateNewProject = false;
isCreateNewFunder = false;
grant: GrantTabModel;
grantAutoCompleteConfiguration: SingleAutoCompleteConfiguration;
projectAutoCompleteConfiguration: SingleAutoCompleteConfiguration;
funderAutoCompleteConfiguration: SingleAutoCompleteConfiguration;
constructor(
private grantService: GrantService,
private projectService: ProjectService,
private funderService: FunderService,
private language: TranslateService
) {
super();
}
getGrantIdText(item) {
if (item.reference != null && typeof item.reference == 'string') {
const parts = (item.reference as String).split('::');
return parts.length > 1 ? ' (' + parts[parts.length - 1] + ')' : '';
}
return '';
}
ngOnInit() {
const grantRequestItem: RequestItem<GrantCriteria> = new RequestItem();
grantRequestItem.criteria = new GrantCriteria();
this.configureAutoCompletes();
this.isCreateNew = (this.grantformGroup.get('label').value != null && this.grantformGroup.get('label').value.length > 0);
this.isCreateNewProject = (this.projectFormGroup.get('label').value != null && this.projectFormGroup.get('label').value.length > 0);
this.isCreateNewFunder = (this.funderFormGroup.get('label').value != null && this.funderFormGroup.get('label').value.length > 0);
this.setGrantValidators();
this.setProjectValidators();
this.setFunderValidators();
this.registerFormListeners();
if (this.isNew && !this.isClone) {
this.grantformGroup.reset();
this.grantformGroup.disable();
}
this.formGroup.valueChanges.pipe(takeUntil(this._destroyed))
.subscribe(x => {
this.configureAutoCompletes();
this.onFormChanged.emit();
});
}
configureAutoCompletes(): void {
this.funderAutoCompleteConfiguration = {
filterFn: this.searchFunder.bind(this),
initialItems: () => this.searchFunder(''),
displayFn: (item) => item['label'],
titleFn: (item) => item['label'],
subtitleFn: (item) => item['source'] ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item['source'] : (item['key'] ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item['key'] : this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.NO-SOURCE'))
}
this.grantAutoCompleteConfiguration = {
filterFn: this.searchGrant.bind(this),
initialItems: () => this.searchGrant(''),
displayFn: (item) => item['label'] + this.getGrantIdText(item),
titleFn: (item) => item['label'] + this.getGrantIdText(item),
subtitleFn: (item) => item['source'] ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item['source'] : (item['key'] ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item['key'] : this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.NO-SOURCE'))
};
this.projectAutoCompleteConfiguration = {
filterFn: this.searchProject.bind(this),
initialItems: () => this.searchProject(''),
displayFn: (item) => item['label'],
titleFn: (item) => item['label'],
subtitleFn: (item) => item['source'] ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item['source'] : (item['key'] ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item['key'] : this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.NO-SOURCE'))
}
}
searchGrant(query: any) {
const grantRequestItem: RequestItem<GrantCriteria> = new RequestItem();
grantRequestItem.criteria = new GrantCriteria();
grantRequestItem.criteria.like = query;
if (this.funderFormGroup.get('existFunder').value) {
grantRequestItem.criteria.funderReference = this.funderFormGroup.controls['existFunder'].value.reference;
}
return this.grantService.getWithExternal(grantRequestItem);
}
searchProject(query: string) {
const projectRequestItem: RequestItem<ProjectCriteria> = new RequestItem();
projectRequestItem.criteria = new ProjectCriteria();
projectRequestItem.criteria.like = query;
return this.projectService.getWithExternal(projectRequestItem);
}
searchFunder(query: string) {
const funderRequestItem: RequestItem<FunderCriteria> = new RequestItem();
funderRequestItem.criteria = new FunderCriteria();
funderRequestItem.criteria.like = query;
return this.funderService.getWithExternal(funderRequestItem)
}
createGrant() {
if (this.isNewVersion) { return };
if (this.isGrantDisabled()) return;
this.isCreateNew = !this.isCreateNew;
this.setGrantValidators();
}
createProject() {
if (this.isNewVersion) { return };
this.isCreateNewProject = !this.isCreateNewProject;
this.setProjectValidators();
}
createFunder() {
if (this.isNewVersion) { return };
this.isCreateNewFunder = !this.isCreateNewFunder;
this.setFunderValidators();
}
setGrantValidators() {
if (this.isCreateNew) {
this.grantformGroup.get('existGrant').disable();
this.grantformGroup.get('label').enable();
this.grantformGroup.get('description').enable();
} else if (this.isClone && !this.isNewVersion) {
this.grantformGroup.get('existGrant').enable();
this.grantformGroup.get('label').disable();
this.grantformGroup.get('label').reset();
this.grantformGroup.get('description').disable();
this.grantformGroup.get('description').reset();
} else if (this.isFinalized || this.isNewVersion || !this.isUserOwner) {
this.grantformGroup.get('existGrant').disable();
this.grantformGroup.get('label').disable();
this.grantformGroup.get('description').disable();
} else {
this.grantformGroup.get('existGrant').enable();
this.grantformGroup.get('label').disable();
this.grantformGroup.get('label').reset();
this.grantformGroup.get('description').disable();
this.grantformGroup.get('description').reset();
}
}
setProjectValidators() {
if (this.isCreateNewProject) {
this.projectFormGroup.get('existProject').disable();
this.projectFormGroup.get('label').enable();
this.projectFormGroup.get('description').enable();
} else if (this.isClone && !this.isNewVersion) {
this.projectFormGroup.get('existProject').enable();
this.projectFormGroup.get('label').disable()
this.projectFormGroup.get('label').reset();
this.projectFormGroup.get('description').disable();
this.projectFormGroup.get('description').reset();
} else if (this.isFinalized || this.isNewVersion || !this.isUserOwner) {
this.projectFormGroup.get('existProject').disable();
this.projectFormGroup.get('label').disable();
this.projectFormGroup.get('description').disable();
} else {
this.projectFormGroup.get('existProject').enable();
this.projectFormGroup.get('label').disable();
this.projectFormGroup.get('label').reset();
this.projectFormGroup.get('description').disable();
this.projectFormGroup.get('description').reset();
}
}
setFunderValidators() {
if (this.isCreateNewFunder) {
this.funderFormGroup.get('existFunder').disable();
this.funderFormGroup.get('label').enable();
} else if (this.isClone && !this.isNewVersion) {
if (this.funderFormGroup.get('existFunder')) {
this.funderFormGroup.get('existFunder').enable();
this.funderFormGroup.get('label').disable();
this.funderFormGroup.get('label').reset();
} else {
this.funderFormGroup.get('label').enable();
}
} else if (this.isFinalized || this.isNewVersion || !this.isUserOwner) {
this.funderFormGroup.get('existFunder').disable();
this.funderFormGroup.get('label').disable();
} else {
this.funderFormGroup.enable();
this.funderFormGroup.get('label').disable();
this.funderFormGroup.get('label').reset();
}
}
registerFormListeners() {
this.funderFormGroup.valueChanges
.pipe(takeUntil(this._destroyed))
.subscribe(x => {
this.funderValueChanged(x);
})
}
funderValueChanged(funder: any) {
if ((funder.label !== "" && funder.label != null && funder.label !== undefined)
|| (funder.existFunder !== null && funder.existFunder !== undefined && funder.existFunder.id !== undefined)) {
this.grantformGroup.reset();
this.grantformGroup.enable();
this.setGrantValidators();
} else {
this.grantformGroup.reset();
this.grantformGroup.disable();
if (this.isCreateNew) this.isCreateNew = !this.isCreateNew;
}
}
isGrantDisabled() {
return this.grantformGroup.disabled;
}
showToggleButton() {
return (!this.isFinalized && this.isUserOwner) || this.isClone;
}
}

View File

@ -177,7 +177,6 @@ export class GeneralTabComponent extends BaseComponent implements OnInit {
}
filterProfiles(value: string): Observable<DatasetProfileModel[]> {
const request = new DataTableRequest<DatasetProfileCriteria>(null, null, { fields: ['+label'] });
const criteria = new DatasetProfileCriteria();
criteria.like = value;

View File

@ -0,0 +1,80 @@
<div class="main-info" [formGroup]="formGroup">
<div class="col-12 intro">
{{'DMP-EDITOR.MAIN-INFO.INTRO' | translate}}
</div>
<div class="col-12 card">
<!-- Title Field -->
<div class="row">
<div class="col-12">
<div class="heading">1.1 {{'DMP-EDITOR.FIELDS.NAME' | translate}}*</div>
<div class="hint">{{'DMP-EDITOR.MAIN-INFO.HINT' | translate}}</div>
<div class="title-form">
<mat-form-field appearance="outline">
<input matInput placeholder="{{'DMP-EDITOR.FIELDS.NAME' | translate}}" type="text" name="label" formControlName="label" required>
<mat-error *ngIf="formGroup.get('label').hasError('backendError')">
{{formGroup.get('label').getError('backendError').message}}</mat-error>
<mat-error *ngIf="formGroup.get('label').hasError('required')">
{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
</div>
</div>
</div>
<!-- Description field -->
<div class="row">
<div class="col-12">
<div class="heading">1.2 {{'DMP-EDITOR.FIELDS.DESCRIPTION' | translate}}</div>
<div class="hint">{{'DMP-EDITOR.MAIN-INFO.HINT' | translate}}</div>
<div class="description-form">
<mat-form-field appearance="outline">
<textarea rows="3" matInput class="description-area" placeholder="{{'DMP-EDITOR.PLACEHOLDER.DESCRIPTION' | translate}}" formControlName="description"></textarea>
</mat-form-field>
</div>
</div>
</div>
<!-- Researchers field-->
<div class="row">
<div class="col-12">
<div class="heading">1.3 {{'DMP-EDITOR.FIELDS.RESEARCHERS' | translate}}</div>
<div class="hint">
<div class="pb-1">{{'DMP-EDITOR.MAIN-INFO.HINT' | translate}}</div>
<div><span class="material-icons-outlined align-bottom">info</span> {{'DMP-EDITOR.MAIN-INFO.TYPING' | translate}}</div>
</div>
<div class="author-form">
<mat-form-field appearance="outline">
<app-multiple-auto-complete [formControl]="formGroup.get('researchers')" placeholder="{{'DMP-EDITOR.PLACEHOLDER.RESEARCHERS' | translate}}" [configuration]="researchersAutoCompleteConfiguration">
</app-multiple-auto-complete>
<mat-error *ngIf="formGroup.get('researchers').hasError('backendError')">
{{formGroup.get('researchers').getError('backendError').message}}</mat-error>
<mat-error *ngIf="formGroup.get('researchers').hasError('required')">
{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
<button matSuffix class="input-btn" [disabled]="formGroup.get('researchers').disabled" type="button" (click)="addResearcher($event)">
<mat-icon class="icon-btn">add_circle</mat-icon>
</button>
</mat-form-field>
</div>
</div>
</div>
<!-- Organizations Field -->
<div class="row">
<div class="col-12">
<div class="heading">1.4 {{'DMP-EDITOR.FIELDS.ORGANISATIONS' | translate}}</div>
<div class="hint">
<div class="pb-1">{{'DMP-EDITOR.FIELDS.ORGANISATIONS-HINT' | translate}}</div>
<div><span class="material-icons-outlined align-bottom">info</span> {{'DMP-EDITOR.MAIN-INFO.TYPING' | translate}}</div>
</div>
<div class="organizations-form">
<mat-form-field appearance="outline">
<app-multiple-auto-complete [formControl]="formGroup.get('organisations')" placeholder="{{'DMP-EDITOR.PLACEHOLDER.ORGANIZATION' | translate}}" [configuration]="organisationsAutoCompleteConfiguration">
</app-multiple-auto-complete>
<mat-error *ngIf="formGroup.get('organisations').hasError('backendError')">
{{formGroup.get('organisations').getError('backendError').message}}</mat-error>
<mat-error *ngIf="formGroup.get('organisations').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
<button *ngIf="showOrganizationCreator()" matSuffix class="input-btn" [disabled]="canAddOrganizations()" type="button" (click)="addOrganization($event)">
<mat-icon class="icon-btn">add_circle</mat-icon>
</button>
</mat-form-field>
</div>
</div>
</div>
</div>
</div>

View File

@ -0,0 +1,97 @@
.main-info {
// position: relative;
// left: 362px;
// width: calc(100% - 366px);
.intro {
text-align: left;
font-weight: 400;
letter-spacing: 0px;
color: #212121;
opacity: 1;
margin: 3rem 0rem 3rem 0rem;
}
.heading {
text-align: left;
font-weight: 700;
font-size: 18px;
letter-spacing: 0px;
color: #212121;
opacity: 0.81;
margin-top: 1.625rem;
margin-bottom: 0.625rem;
}
.hint {
text-align: left;
font-weight: 400;
font-size: 16px;
letter-spacing: 0px;
color: #212121;
opacity: 0.81;
margin-bottom: 2.125rem;
}
.title-form,
.description-form {
text-align: left;
font-weight: 400;
font-size: 16px;
letter-spacing: 0.15px;
color: #7d7d7d;
opacity: 1;
margin-bottom: 1rem;
}
// textarea::placeholder {
// font-style: oblique;
// }
.input-btn {
border: none;
color: #aaaaaa;
background-color: #ffffff00;
cursor: pointer;
}
.input-btn :hover {
color: #00b29f !important;
}
}
::ng-deep .title-form .mat-form-field-appearance-outline .mat-form-field-outline {
background: #fafafa !important;
}
::ng-deep .description-form .mat-form-field-appearance-outline .mat-form-field-outline {
background: #fafafa !important;
}
::ng-deep .organizations-form .mat-form-field-appearance-outline .mat-form-field-outline {
background: #fafafa !important;
}
::ng-deep .author-form .mat-form-field-appearance-outline .mat-form-field-outline {
background: #fafafa !important;
}
::ng-deep .title-form .mat-form-field-appearance-outline .mat-form-field-infix {
font-size: 1rem;
padding: 0.6em 0 1em 0 !important;
}
::ng-deep .description-form .mat-form-field-appearance-outline .mat-form-field-infix {
font-size: 1rem;
padding: 0.6em 0 1em 0 !important;
}
::ng-deep .organizations-form .mat-form-field-appearance-outline .mat-form-field-infix {
font-size: 1rem;
padding: 0.6em 0 1em 0 !important;
}
::ng-deep .author-form .mat-form-field-appearance-outline .mat-form-field-infix {
font-size: 1rem;
padding: 0.6em 0 1em 0 !important;
}

View File

@ -0,0 +1,139 @@
import { BaseComponent } from '@common/base/base.component';
import { OnInit, Component, Input, Output, EventEmitter } from '@angular/core';
import { FormGroup } from '@angular/forms';
import { TranslateService } from '@ngx-translate/core';
import { ConfigurationService } from '@app/core/services/configuration/configuration.service';
import { MultipleAutoCompleteConfiguration } from '@app/library/auto-complete/multiple/multiple-auto-complete-configuration';
import { map, takeUntil } from 'rxjs/operators';
import { ExternalSourceItemModel } from '@app/core/model/external-sources/external-source-item';
import { Observable } from 'rxjs';
import { ExternalSourcesService } from '@app/core/services/external-sources/external-sources.service';
import { isNullOrUndefined } from 'util';
import { MatDialog } from '@angular/material';
import { AddOrganizationComponent } from '../add-organization/add-organization.component';
import { AddResearcherComponent } from '../add-researcher/add-researcher.component';
@Component({
selector: 'main-info',
templateUrl: './main-info.component.html',
styleUrls: ['./main-info.component.scss']
})
export class MainInfoComponent extends BaseComponent implements OnInit {
@Input() formGroup: FormGroup = null;
@Input() isNewVersion: boolean;
@Input() isUserOwner: boolean;
@Input() isClone: boolean;
@Output() onFormChanged: EventEmitter<any> = new EventEmitter();
organisationsAutoCompleteConfiguration: MultipleAutoCompleteConfiguration = {
filterFn: this.filterOrganisations.bind(this),
initialItems: (excludedItems: any[]) => this.filterOrganisations('').pipe(map(result => result.filter(resultItem => (excludedItems || []).map(x => x.id).indexOf(resultItem.id) === -1))),
displayFn: (item) => item['name'],
titleFn: (item) => item['name'],
subtitleFn: (item) => item['tag'] ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item['tag'] : (item['key'] ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item['key'] : this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.NO-SOURCE'))
};
researchersAutoCompleteConfiguration: MultipleAutoCompleteConfiguration = {
filterFn: this.filterResearchers.bind(this),
initialItems: (excludedItems: any[]) => this.filterResearchers('').pipe(map(result => result.filter(resultItem => (excludedItems || []).map(x => x.id).indexOf(resultItem.id) === -1))),
displayFn: (item) => item['name'],
titleFn: (item) => item['name'],
subtitleFn: (item) => item['tag'] ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item['tag'] : (item['key'] ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item['key'] : this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.NO-SOURCE'))
};
constructor(
private language: TranslateService,
private configurationService: ConfigurationService,
private externalSourcesService: ExternalSourcesService,
private dialog: MatDialog
) {
super();
}
ngOnInit() {
// if (this.formGroup.get('definition')) { this.selectedDmpProfileDefinition = this.formGroup.get('definition').value; }
// this.registerFormEventsForDmpProfile();
if (this.isNewVersion) {
this.formGroup.get('label').disable();
}
if (!this.isUserOwner && !this.isClone) {
this.formGroup.disable();
}
if (isNullOrUndefined(this.formGroup.get('extraProperties').get('publicDate').value)) {
this.formGroup.get('extraProperties').get('publicDate').patchValue(new Date());
}
this.formGroup.valueChanges.pipe(takeUntil(this._destroyed))
.subscribe(x => {
this.onFormChanged.emit();
});
}
// Researchers
filterResearchers(value: string): Observable<ExternalSourceItemModel[]> {
return this.externalSourcesService.searchDMPResearchers({ criteria: { name: value, like: null } });
}
addResearcher(event: MouseEvent) {
event.stopPropagation();
const dialogRef = this.dialog.open(AddResearcherComponent, {
data: this.formGroup.get('researchers')
});
dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(result => {
if (result) {
const fullName = result.firstName + " " + result.lastName;
const newItem = {
label: null,
name: fullName,
id: null,
status: 0,
key: "Internal",
};
const researchersArray = this.formGroup.get('researchers').value || [];
researchersArray.push(newItem);
this.formGroup.get('researchers').setValue(researchersArray);
}
});
}
// Organizations
showOrganizationCreator(): boolean {
return this.configurationService.allowOrganizationCreator;
}
filterOrganisations(value: string): Observable<ExternalSourceItemModel[]> {
return this.externalSourcesService.searchDMPOrganizations(value);
}
canAddOrganizations(): boolean {
if (!isNullOrUndefined(this.formGroup.get('organizations'))) {
return this.formGroup.get('organiztions').disabled;
} else {
return false;
}
}
addOrganization(event: MouseEvent) {
event.stopPropagation();
const dialogRef = this.dialog.open(AddOrganizationComponent, {
data: this.formGroup.get('organisations')
});
dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(result => {
if (result) {
const fullName = result.name;
const newItem = {
label: null,
name: fullName,
id: null,
status: 0,
key: "Internal",
};
const organizationsArray = this.formGroup.get('organisations').value || [];
organizationsArray.push(newItem);
this.formGroup.get('organisations').setValue(organizationsArray);
}
});
}
}

View File

@ -7,7 +7,7 @@ import { Principal } from '../../../../core/model/auth/principal';
import { UserInfoListingModel } from '../../../../core/model/user/user-info-listing';
import { AuthService } from '../../../../core/services/auth/auth.service';
import { DmpService } from '../../../../core/services/dmp/dmp.service';
import { DmpInvitationDialogComponent } from '../../invitation/dmp-invitation.component';
import { DmpInvitationDialogComponent } from '../../invitation/dmp-invitation-dialog.component';
import { DmpEditorModel } from '../dmp-editor.model';
@Component({

View File

@ -0,0 +1,70 @@
<div class="form-container">
<form *ngIf="formGroup" [formGroup]="formGroup" class="m-0">
<div class="row d-flex justify-content-end m-0" (click)="closeDialog()">
<mat-icon class="close-icon">close</mat-icon>
</div>
<div class="row m-0">
<h1 mat-dialog-title class="title">{{'DMP-LISTING.ACTIONS.INVITE-AUTHORS' | translate}}</h1>
</div>
<div mat-dialog-content class="row content">
<mat-form-field class="col pt-0 pb-2 mb-4" appearance="standard">
<app-multiple-auto-complete [formControl]="formGroup.get('users')"
placeholder="{{'INVITATION-EDITOR.AUTOCOMPLETE-USER-EMAIL' | translate}}"
[configuration]="usersAutoCompleteConfiguration">
</app-multiple-auto-complete>
</mat-form-field>
<div class="col-12 d-flex justify-content-end align-items-center row m-0 pr-0">
<mat-form-field class="select-role">
<mat-select [formControl]="formGroup.get('role')">
<mat-option [value]="roles.Owner">{{enumUtils.toRoleString(roles.Owner)}}</mat-option>
<mat-option [value]="roles.Member">{{enumUtils.toRoleString(roles.Member)}}</mat-option>
</mat-select>
</mat-form-field>
<button mat-raised-button (click)="send()" type="button"
class="invite-btn">{{'DMP-LISTING.ACTIONS.INVITE-SHORT' | translate}}</button>
</div>
</div>
</form>
</div>
<!-- <form *ngIf="formGroup" [formGroup]="formGroup">
<h1 mat-dialog-title>{{'INVITATION-EDITOR.TITLE' | translate}} {{data.dmpName}}</h1>
<div mat-dialog-content> -->
<!-- User -->
<!-- <mat-form-field class="col">
<app-multiple-auto-complete [formControl]="formGroup.get('users')"
placeholder="{{'INVITATION-EDITOR.AUTOCOMPLETE-USER' | translate}}"
[configuration]="usersAutoCompleteConfiguration">
</app-multiple-auto-complete>
</mat-form-field> -->
<!-- Email -->
<!-- <mat-form-field class="example-chip-list col">
<mat-chip-list #chipList>
<mat-chip *ngFor="let email of emails" [selectable]="selectable" [removable]="removable"
(removed)="remove(email)">
{{email}}
<mat-icon matChipRemove *ngIf="removable">cancel</mat-icon>
</mat-chip>
<input placeholder="{{'INVITATION-EDITOR.AUTOCOMPLETE-EMAIL' | translate}}" [matChipInputFor]="chipList"
[matChipInputSeparatorKeyCodes]="separatorKeysCodes" [matChipInputAddOnBlur]="addOnBlur"
(matChipInputTokenEnd)="add($event)">
</mat-chip-list>
</mat-form-field> -->
<!-- <mat-form-field class="col">
<app-multiple-auto-complete required='false' [formControl]="formGroup.get('users').get('email')"
placeholder="{{'INVITATION-EDITOR.AUTOCOMPLETE-EMAIL' | translate}}"
[configuration]="emailAutoCompleteConfiguration" ()>
</app-multiple-auto-complete>
<mat-error *ngIf="formGroup.get('users').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}
</mat-error>
</mat-form-field> -->
<!-- <div class="col-12 d-flex">
<button mat-raised-button color="primary" (click)="send()" type="button" class="ml-auto">{{'INVITATION-EDITOR.ACTIONS.SEND-INVITATION' | translate}}</button>
</div>
</div>
</form> -->

View File

@ -0,0 +1,71 @@
.form-container {
width: 33em;
min-height: 14em;
padding: 0.28em 0.34em 0.875em 1.125em;
}
.close-icon {
cursor: pointer;
}
.title {
font-size: 2.375em;
font-weight: lighter;
color: #000000;
opacity: 0.8;
margin-bottom: 0.842em;
}
.content {
width: 31em;
margin: 0px;
padding: 0px;
}
.mat-form-field {
background: #FAFAFA;
border: 1px solid #D1D1D1;
border-radius: 4px;
}
::ng-deep .mat-dialog-container {
border-radius: 8px;
}
::ng-deep .mat-form-field-underline {
display: none;
}
::ng-deep .mat-form-field-wrapper {
padding: 0em !important;
}
::ng-deep .mat-form-field-infix {
border: none;
}
::ng-deep .align-arrow-right {
display: none;
}
.invite-btn {
width: 6.64em;
height: 2.93em;
background: #FFFFFF;
border: 1px solid #B5B5B5;
border-radius: 30px;
font-weight: bold;
letter-spacing: -0.35px;
color: #B5B5B5;
margin-bottom: 0.25em;
}
.select-role {
width: 16% !important;
font-size: 14px;
color: #848484;
height: min-content;
margin-right: 2.5rem;
border: none;
background-color: transparent;
}

View File

@ -0,0 +1,130 @@
import { COMMA, ENTER } from '@angular/cdk/keycodes';
import { Component, Inject, OnInit, ViewChild } from '@angular/core';
import { FormGroup } from '@angular/forms';
import { MatChipInputEvent } from '@angular/material/chips';
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
import { ActivatedRoute, Router } from '@angular/router';
import { DmpInvitation } from '@app/core/model/dmp/invitation/dmp-invitation';
import { DmpInvitationUser } from '@app/core/model/dmp/invitation/dmp-invitation-user';
import { DmpInvitationUserCriteria } from '@app/core/query/dmp/dmp-invitation-user-criteria';
import { RequestItem } from '@app/core/query/request-item';
import { DmpInvitationService } from '@app/core/services/dmp/dmp-invitation.service';
import { MultipleAutoCompleteConfiguration } from '@app/library/auto-complete/multiple/multiple-auto-complete-configuration';
import { BaseComponent } from '@common/base/base.component';
import { Observable } from 'rxjs';
import { map, takeUntil } from 'rxjs/operators';
import { Role } from '@app/core/common/enum/role';
import { EnumUtils } from '@app/core/services/utilities/enum-utils.service';
@Component({
selector: 'app-invitation-dialog-component',
templateUrl: 'dmp-invitation-dialog.component.html',
styleUrls: ['./dmp-invitation-dialog.component.scss'],
})
export class DmpInvitationDialogComponent extends BaseComponent implements OnInit {
public formGroup: FormGroup;
public filteredUsersAsync = false;
public filteredUsers: DmpInvitationUser[];
public emails: string[] = [];
public roles = Role;
public roleNames: string[];
visible = true;
selectable = true;
removable = true;
addOnBlur = true;
readonly separatorKeysCodes: number[] = [ENTER, COMMA];
constructor(
public invitationService: DmpInvitationService,
public enumUtils: EnumUtils,
public route: ActivatedRoute,
public router: Router,
public dialogRef: MatDialogRef<DmpInvitationDialogComponent>,
@Inject(MAT_DIALOG_DATA) public data: any
) {
super();
this.roleNames = Object.keys(this.roles).filter(key => key.length > 1);
}
ngOnInit(): void {
const invitation = new DmpInvitation();
invitation.dataManagementPlan = this.data.dmpId;
invitation.role = Role.Member;
this.formGroup = invitation.buildForm();
}
usersAutoCompleteConfiguration: MultipleAutoCompleteConfiguration = {
filterFn: this.filterUsers.bind(this),
initialItems: (excludedItems: any[]) => this.filterUsers('').pipe(map(result => result.filter(resultItem => (excludedItems || []).map(x => x.id).indexOf(resultItem.id) === -1))),
displayFn: (item) => typeof(item) === 'string' ? item : item.name,
titleFn: (item) => typeof(item) === 'string' ? item : item.name,
valueAssign: (item) => {
const result = typeof(item) === 'string' ? item : item.email;
return result;
}
};
add(event: MatChipInputEvent): void {
const input = event.input;
const value = event.value;
if ((value || '').trim()) {
this.emails.push(value.trim());
}
if (input) {
input.value = '';
}
}
remove(email: string): void {
const index = this.emails.indexOf(email);
if (index >= 0) {
this.emails.splice(index, 1);
}
}
send(value: any) {
let invitationObject: any = {};
invitationObject.dataManagementPlan = this.data.dmpId;
invitationObject.role = this.formGroup.get('role').value;
invitationObject.users = [];
invitationObject.users.push(...(<any[]>this.formGroup.get('users').value).filter(user => typeof(user) === 'string').map(email => ({ email: email, name: email })));
invitationObject.users.push(...(<any[]>this.formGroup.get('users').value).filter(user => typeof(user) !== 'string'));
//invitationObject.users.push(...this.formGroup.get('users').value);
this.emails.forEach(email => {
invitationObject.users.push({ email: email, name: email });
});
this.invitationService.inviteDmpInvitationUsers(invitationObject)
.pipe(takeUntil(this._destroyed))
.subscribe(
null, null, () => this.dialogRef.close()
);
}
closeDialog(): void {
this.dialogRef.close();
}
filterUsers(value: string): Observable<DmpInvitationUser[]> {
this.filteredUsers = undefined;
this.filteredUsersAsync = true;
const request = new RequestItem<DmpInvitationUserCriteria>();
request.criteria = { like: value };
return this.invitationService.getDmpInvitationUsers(request)
.pipe(takeUntil(this._destroyed));
// .subscribe(items => {
// this.filteredUsers = new JsonSerializer<DmpInvitationUser>(DmpInvitationUser).fromJSONArray(items);
// if (!this.filteredUsers || this.filteredUsers.length === 0) {
// const user = new DmpInvitationUser();
// user.email = value;
// user.name = value;
// this.filteredUsers.push(user);
// }
// this.filteredUsersAsync = false;
// });
}
}

View File

@ -42,7 +42,7 @@ export class DmpInvitationDialogComponent extends BaseComponent implements OnIni
public router: Router,
public dialogRef: MatDialogRef<DmpInvitationDialogComponent>,
@Inject(MAT_DIALOG_DATA) public data: any
) {
) {
super();
this.roleNames = Object.keys(this.roles).filter(key => key.length > 1);
}
@ -60,7 +60,6 @@ export class DmpInvitationDialogComponent extends BaseComponent implements OnIni
titleFn: (item) => typeof(item) === 'string' ? item : item.name,
valueAssign: (item) => {
const result = typeof(item) === 'string' ? item : item.email;
console.log(result);
return result;
}
};
@ -124,5 +123,5 @@ export class DmpInvitationDialogComponent extends BaseComponent implements OnIni
// this.filteredUsersAsync = false;
// });
}
}
}

View File

@ -10,7 +10,7 @@ import { GrantListingModel } from '@app/core/model/grant/grant-listing';
import { DmpCriteria } from '@app/core/query/dmp/dmp-criteria';
import { DmpService } from '@app/core/services/dmp/dmp.service';
import { EnumUtils } from '@app/core/services/utilities/enum-utils.service';
import { DmpInvitationDialogComponent } from '@app/ui/dmp/invitation/dmp-invitation.component';
import { DmpInvitationDialogComponent } from '@app/ui/dmp/invitation/dmp-invitation-dialog.component';
import { DmpCriteriaComponent } from '@app/ui/dmp/listing/criteria/dmp-criteria.component';
import { BreadcrumbItem } from '@app/ui/misc/breadcrumb/definition/breadcrumb-item';
import { IBreadCrumbComponent } from '@app/ui/misc/breadcrumb/definition/IBreadCrumbComponent';

View File

@ -1,7 +1,7 @@
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.component';
import { DmpInvitationDialogComponent } from '../../invitation/dmp-invitation-dialog.component';
import { Router, ActivatedRoute } from '@angular/router';
import { DatasetService } from '../../../../core/services/dataset/dataset.service';
import { AuthService } from '../../../../core/services/auth/auth.service';

View File

@ -33,8 +33,10 @@
</div>
<span>.</span>
<mat-form-field appearance="outline" class="versions-select ml-2 mr-4">
<mat-select placeholder="{{'DMP-LISTING.VERSION' | translate}} {{dmp.version}}" [(ngModel)]="version" (ngModelChange)="versionChanged(version.id)">
<mat-option *ngFor="let version of versions" [value]="version">{{'DMP-LISTING.VERSION' | translate}} {{version.version}}</mat-option>
<mat-select placeholder="{{'DMP-LISTING.VERSION' | translate}} {{dmp.version}}"
[(ngModel)]="version" (ngModelChange)="versionChanged(version.id)">
<mat-option *ngFor="let version of versions" [value]="version">
{{'DMP-LISTING.VERSION' | translate}} {{version.version}}</mat-option>
</mat-select>
</mat-form-field>
<div class="d-flex mr-4">{{'GENERAL.STATUSES.EDIT' | translate}} :
@ -48,13 +50,19 @@
</div>
</div>
<div class="row">
<button *ngIf="isAuthenticated()" (click)="cloneClicked(dmp)" mat-mini-fab class="mr-3 d-flex justify-content-center align-items-center" matTooltip="{{'DMP-LISTING.ACTIONS.CLONE' | translate}}" matTooltipPosition="above">
<button *ngIf="isAuthenticated()" (click)="cloneClicked(dmp)" mat-mini-fab
class="mr-3 d-flex justify-content-center align-items-center"
matTooltip="{{'DMP-LISTING.ACTIONS.CLONE' | translate}}" matTooltipPosition="above">
<mat-icon class="mat-mini-fab-icon">content_copy</mat-icon>
</button>
<button *ngIf="isDraftDmp(dmp) && isUserOwner && !lockStatus" (click)="editClicked(dmp)" mat-mini-fab class="mr-3 d-flex justify-content-center align-items-center" matTooltip="{{'DMP-LISTING.ACTIONS.EDIT' | translate}}" matTooltipPosition="above">
<button *ngIf="isDraftDmp(dmp) && isUserOwner && !lockStatus" (click)="editClicked(dmp)"
mat-mini-fab class="mr-3 d-flex justify-content-center align-items-center"
matTooltip="{{'DMP-LISTING.ACTIONS.EDIT' | translate}}" matTooltipPosition="above">
<mat-icon class="mat-mini-fab-icon">create</mat-icon>
</button>
<button *ngIf="isUserOwner && !lockStatus" (click)="deleteClicked()" mat-mini-fab class="mr-3 d-flex justify-content-center align-items-center" matTooltip="{{'DMP-LISTING.ACTIONS.DELETE' | translate}}" matTooltipPosition="above">
<button *ngIf="isUserOwner && !lockStatus" (click)="deleteClicked()" mat-mini-fab
class="mr-3 d-flex justify-content-center align-items-center"
matTooltip="{{'DMP-LISTING.ACTIONS.DELETE' | translate}}" matTooltipPosition="above">
<mat-icon class="mat-mini-fab-icon">delete</mat-icon>
</button>
</div>
@ -63,7 +71,8 @@
<div class="row header">{{'DMP-OVERVIEW.RESEARCHERS' | translate}}</div>
<div class="row">
<div *ngFor="let researcher of dmp.researchers; let last = last">
<a href="{{ getOrcidPathForResearcher(researcher.reference) }}" target="blank" class="researcher">
<a href="{{ getOrcidPathForResearcher(researcher.reference) }}" target="blank"
class="researcher">
<div class="id-btn">&nbsp;</div>
<div *ngIf="!last">{{ researcher.name }}, </div>
<div *ngIf="last">{{ researcher.name }}</div>
@ -79,7 +88,8 @@
<div *ngFor="let dataset of dmp.datasets; let i=index">
<div class="row" *ngIf="i < 3" (click)="datasetClicked(dataset.id)">
<button mat-raised-button class="mb-2 mr-2 pl-0 pr-0">
<div matTooltip="{{ dataset.label }} : {{ dataset.datasetTemplate.label }}" class="col-auto dataset-btn">
<div matTooltip="{{ dataset.label }} : {{ dataset.datasetTemplate.label }}"
class="col-auto dataset-btn">
<div class="dataset-btn-label">{{ dataset.label }}:
{{ dataset.datasetTemplate.label }}</div>
<mat-icon>launch</mat-icon>
@ -95,7 +105,8 @@
</div>
</div>
<div class="row mt-2 add-dataset-txt">
<button class="add-dataset-btn" *ngIf="isDraftDmp(dmp) && isUserOwner" (click)="addDataset(dmp.id)">
<button class="add-dataset-btn" *ngIf="isDraftDmp(dmp) && isUserOwner"
(click)="addDataset(dmp.id)">
<mat-icon>add</mat-icon>
{{'DMP-LISTING.ACTIONS.ADD-DATASET-SHORT' | translate}}
</button>
@ -109,10 +120,14 @@
<textarea #doi class="doi-txt">{{ dmp.doi }}</textarea>
</p>
<div class="d-flex justify-content-end">
<button (click)="copyDoi(doi)" mat-mini-fab class="mr-2 d-flex justify-content-center align-items-center" matTooltip="{{'DMP-LISTING.ACTIONS.CLONE' | translate}}" matTooltipPosition="above">
<button (click)="copyDoi(doi)" mat-mini-fab
class="mr-2 d-flex justify-content-center align-items-center"
matTooltip="{{'DMP-LISTING.ACTIONS.CLONE' | translate}}" matTooltipPosition="above">
<mat-icon class="mat-mini-fab-icon">content_copy</mat-icon>
</button>
<button mat-mini-fab class="mr-2 d-flex justify-content-center align-items-center" matTooltip="{{'GRANT-EDITOR.ACTIONS.VISIT-WEBSITE' | translate}}" matTooltipPosition="above">
<button mat-mini-fab class="mr-2 d-flex justify-content-center align-items-center"
matTooltip="{{'GRANT-EDITOR.ACTIONS.VISIT-WEBSITE' | translate}}"
matTooltipPosition="above">
<a [href]="createDoiLink(dmp.doi)" class="doi-link" target="_blank">
<mat-icon class="mat-mini-fab-icon">launch</mat-icon>
</a>
@ -132,12 +147,20 @@
<hr class="hr-line">
</div>
</div>
<div *ngIf="isFinalizedDmp(dmp) && !this.isPublicView && isUserOwner" (click)="getDoi(dmp)" class="row ml-0 mr-0 pl-4 pb-3 d-flex align-items-center">
<div *ngIf="hasDoi(dmp) && isFinalizedDmp(dmp) && !this.isPublicView && isUserOwner"
(click)="getDoi(dmp)" class="row ml-0 mr-0 pl-4 pb-3 d-flex align-items-center">
<button mat-mini-fab class="frame-btn">
<mat-icon class="mat-mini-fab-icon">archive</mat-icon>
</button>
<p class="mb-0 pl-2 frame-txt">{{ 'DMP-LISTING.ACTIONS.DEPOSIT' | translate }}</p>
</div>
<div *ngIf="(isFinalizedDmp(dmp) && hasDoi(dmp) && !isPublishedDMP(dmp)) && isUserOwner"
(click)="reverse(dmp)" class="row ml-0 mr-0 pl-4 pb-3 d-flex align-items-center">
<button mat-mini-fab class="frame-btn">
<mat-icon class="mat-mini-fab-icon">unarchive</mat-icon>
</button>
<p class="mb-0 pl-2 frame-txt">{{ 'DMP-LISTING.ACTIONS.UNFINALIZE' | translate }}</p>
</div>
<div class="row ml-0 mr-0 pl-4 pb-3 d-flex align-items-center">
<button mat-mini-fab class="frame-btn" [matMenuTriggerFor]="exportMenu">
<mat-icon class="mat-mini-fab-icon">open_in_new</mat-icon>
@ -145,14 +168,16 @@
<p class="mb-0 mr-0 pl-2 frame-txt" [matMenuTriggerFor]="exportMenu">
{{ 'DMP-LISTING.ACTIONS.EXPORT' | translate }}</p>
</div>
<div *ngIf="isUserOwner" class="row ml-0 mr-0 pl-4 pb-3 d-flex align-items-center" (click)="newVersion(dmp.id, dmp.label)">
<div *ngIf="isUserOwner" class="row ml-0 mr-0 pl-4 pb-3 d-flex align-items-center"
(click)="newVersion(dmp.id, dmp.label)">
<button mat-mini-fab class="frame-btn">
<mat-icon class="mat-mini-fab-icon">add_to_photos</mat-icon>
</button>
<p class="mb-0 pl-2 frame-txt">{{ 'DMP-LISTING.ACTIONS.START-NEW-VERSION' | translate }}
</p>
</div>
<div *ngIf="!dmp.isPublic && showPublishButton(dmp) && isUserOwner" class="row ml-0 mr-0 pl-4 pb-3 d-flex align-items-center" (click)="publish(dmp.id)">
<div *ngIf="!dmp.isPublic && showPublishButton(dmp) && isUserOwner"
class="row ml-0 mr-0 pl-4 pb-3 d-flex align-items-center" (click)="publish(dmp.id)">
<button mat-mini-fab class="frame-btn">
<mat-icon class="mat-mini-fab-icon">public</mat-icon>
</button>
@ -195,10 +220,13 @@
<p class="authors-role">{{ roleDisplay(user) }}</p>
</div>
</div>
<button *ngIf="isUserOwner && !dmp.status && user.role" (click)="removeUserFromDmp(user)" class="remove-btn">{{ 'GENERAL.CONFIRMATION-DIALOG.ACTIONS.REMOVE' | translate}}</button>
<button *ngIf="isUserOwner && !dmp.status && user.role"
(click)="removeUserFromDmp(user)"
class="remove-btn">{{ 'GENERAL.CONFIRMATION-DIALOG.ACTIONS.REMOVE' | translate}}</button>
</div>
</div>
<div *ngIf="isUserOwner" (click)="openShareDialog(dmp.id,dmp.label)" class="row mt-3 mb-3 d-flex align-items-center justify-content-center">
<div *ngIf="isUserOwner" (click)="openShareDialog(dmp.id,dmp.label)"
class="row mt-3 mb-3 d-flex align-items-center justify-content-center">
<button mat-raised-button class="invite-btn">
<mat-icon>group_add</mat-icon>
{{'DMP-LISTING.ACTIONS.INVITE-SHORT' | translate}}
@ -413,4 +441,4 @@
</div>
</div>
</div>
-->
-->

View File

@ -21,7 +21,7 @@ import * as FileSaver from 'file-saver';
import { Observable, of as observableOf, interval } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { Role } from "@app/core/common/enum/role";
import { DmpInvitationDialogComponent } from '../invitation/dmp-invitation.component';
import { DmpInvitationDialogComponent } from '../invitation/dmp-invitation-dialog.component';
import { MultipleChoiceDialogModule } from '@common/modules/multiple-choice-dialog/multiple-choice-dialog.module';
import { MultipleChoiceDialogComponent } from '@common/modules/multiple-choice-dialog/multiple-choice-dialog.component';
import { ConfigurationService } from '@app/core/services/configuration/configuration.service';
@ -221,15 +221,15 @@ export class DmpOverviewComponent extends BaseComponent implements OnInit {
this.dmpService.delete(this.dmp.id)
.pipe(takeUntil(this._destroyed))
.subscribe(
complete => { this.onCallbackSuccess() },
complete => { this.onDeleteCallbackSuccess() },
error => this.onDeleteCallbackError(error)
);
}
});
}
onCallbackSuccess(): void {
this.uiNotificationService.snackBarNotification(this.isNew ? this.language.instant('GENERAL.SNACK-BAR.SUCCESSFUL-CREATION') : this.language.instant('GENERAL.SNACK-BAR.SUCCESSFUL-UPDATE'), SnackBarNotificationLevel.Success);
onDeleteCallbackSuccess(): void {
this.uiNotificationService.snackBarNotification(this.language.instant('GENERAL.SNACK-BAR.SUCCESSFUL-DATASET-PROFILE-DELETE'), SnackBarNotificationLevel.Success);
this.router.navigate(['/plans']);
}
@ -237,6 +237,15 @@ export class DmpOverviewComponent extends BaseComponent implements OnInit {
this.uiNotificationService.snackBarNotification(error.error.message ? error.error.message : this.language.instant('GENERAL.SNACK-BAR.UNSUCCESSFUL-DELETE'), SnackBarNotificationLevel.Error);
}
onUpdateCallbackSuccess(): void {
this.uiNotificationService.snackBarNotification(this.language.instant('GENERAL.SNACK-BAR.SUCCESSFUL-UPDATE'), SnackBarNotificationLevel.Success);
this.reloadPage();
}
onUpdateCallbackError(error) {
this.uiNotificationService.snackBarNotification(error.error.message ? error.error.message : this.language.instant('DATASET-UPLOAD.SNACK-BAR.UNSUCCESSFUL'), SnackBarNotificationLevel.Error);
}
downloadXml(id: string) {
this.dmpService.downloadXML(id)
.pipe(takeUntil(this._destroyed))
@ -478,7 +487,7 @@ export class DmpOverviewComponent extends BaseComponent implements OnInit {
if (result) {
this.dmpService.publish(dmpId)
.pipe(takeUntil(this._destroyed))
.subscribe(() => {
.subscribe(() => {
this.hasPublishButton = false;
this.reloadPage();
});
@ -516,18 +525,14 @@ export class DmpOverviewComponent extends BaseComponent implements OnInit {
.subscribe(
complete => {
this.dmp.status = DmpStatus.Finalized;
this.onCallbackSuccess()
this.onUpdateCallbackSuccess();
},
error => this.onFinalizeCallbackError(error)
error => this.onUpdateCallbackError(error)
);
}
});
}
onFinalizeCallbackError(error) {
this.uiNotificationService.snackBarNotification(error.error.message ? error.error.message : this.language.instant('DMP-EDITOR.SNACK-BAR.UNSUCCESSFUL-FINALIZE'), SnackBarNotificationLevel.Error);
}
newVersion(id: String, label: String) {
this.router.navigate(['/plans/new_version/' + id, { dmpLabel: label }]);
}
@ -571,14 +576,27 @@ export class DmpOverviewComponent extends BaseComponent implements OnInit {
}
reverse() {
this.dmpService.unfinalize(this.dmp.id).pipe(takeUntil(this._destroyed))
.subscribe(
complete => {
this.dmp.status = DmpStatus.Draft;
this.onCallbackSuccess()
},
error => this.onFinalizeCallbackError(error)
);
const dialogRef = this.dialog.open(ConfirmationDialogComponent, {
restoreFocus: false,
data: {
message: this.language.instant('GENERAL.CONFIRMATION-DIALOG.UNFINALIZE-ITEM'),
confirmButton: this.language.instant('QUICKWIZARD.SAVE-DIALOG.ACTIONS.AFFIRMATIVE'),
cancelButton: this.language.instant('QUICKWIZARD.SAVE-DIALOG.ACTIONS.NEGATIVE'),
isDeleteConfirmation: false
}
});
dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(result => {
if (result) {
this.dmpService.unfinalize(this.dmp.id).pipe(takeUntil(this._destroyed))
.subscribe(
complete => {
this.dmp.status = DmpStatus.Draft;
this.onUpdateCallbackSuccess()
},
error => this.onUpdateCallbackError(error)
);
}
});
}
goBack(): void {
@ -595,10 +613,9 @@ export class DmpOverviewComponent extends BaseComponent implements OnInit {
return this.dmpService.updateUsers(this.dmp.id, this.dmp.users).pipe(takeUntil(this._destroyed))
.subscribe(
complete => {
this.onCallbackSuccess();
this.reloadPage();
this.onUpdateCallbackSuccess();
},
error => this.onDeleteCallbackError(error)
error => this.onUpdateCallbackError(error)
);
}

View File

@ -12,7 +12,7 @@ import { DATASETS_ROUTES, DMP_ROUTES, GENERAL_ROUTES } from '../sidebar/sidebar.
import { LanguageService } from '@app/core/services/language/language.service';
import { UserService } from '@app/core/services/user/user.service';
import { FaqDialogComponent } from '../faq/dialog/faq-dialog.component';
import { DmpInvitationDialogComponent } from '../dmp/invitation/dmp-invitation.component';
import { DmpInvitationDialogComponent } from '../dmp/invitation/dmp-invitation-dialog.component';
import { StartNewDmpDialogComponent } from '../dmp/start-new-dmp-dialogue/start-new-dmp-dialog.component';
import { UserListingModel } from '@app/core/model/user/user-listing';
import { Principal } from '@app/core/model/auth/principal';

View File

@ -0,0 +1,21 @@
h1 {
text-align: center;
margin: 2rem 0 1rem 0;
}
h4 {
margin: 1rem 0rem 0.5rem 0rem;
}
img {
height: 150px;
width: 100%;
}
.terms-component {
margin-top: 80px;
}
p {
margin: 0.5rem 0rem;
}

View File

@ -0,0 +1,15 @@
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-opensource-licences',
templateUrl: './opensource-licences.component.html',
styleUrls: ['./opensource-licences.component.scss']
})
export class OpensourceLicencesComponent implements OnInit {
constructor() { }
ngOnInit() {
}
}

View File

@ -0,0 +1,16 @@
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { OpensourceLicencesComponent } from './opensource-licences.component';
const routes: Routes = [
{
path: '',
component: OpensourceLicencesComponent,
},
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class OpensourceLicencesRoutingModule { }

View File

@ -0,0 +1,15 @@
import { NgModule } from '@angular/core';
import { CommonUiModule } from '@common/ui/common-ui.module';
import { OpensourceLicencesRoutingModule } from './opensource-licences.routing';
import { OpensourceLicencesComponent } from './opensource-licences.component';
@NgModule({
imports: [
CommonUiModule,
OpensourceLicencesRoutingModule
],
declarations: [
OpensourceLicencesComponent
],
})
export class OpensourceLicencesModule { }

View File

@ -1,5 +1,6 @@
h1 {
text-align: center;
margin: 2rem 0 1rem 0;
}
img {

View File

@ -50,6 +50,7 @@
"DELETE-ITEM": "Delete this item?",
"DELETE-USER": "Remove this collaborator?",
"FINALIZE-ITEM": "Finalize this item?",
"UNFINALIZE-ITEM": "Undo Finalization?",
"PUBLISH-ITEM": "Publish this item?",
"ADD-DATASET": "Do you want to continue by adding a Dataset Description to your DMP? You can always add more Dataset Descriptions using \"Add Dataset Description (Wizard)\" menu.",
"ZENODO-DOI": "Would you like to create digital object identifier (DOI) with {{username}} account for the DMP?",
@ -89,6 +90,7 @@
"GENERAL": "Data Management Plans Creator",
"ABOUT": "About",
"PRIVACY": "Privacy Policy",
"OPENSOURCE-LICENCES": "Opensource Licences",
"TERMS": "Terms Of Service",
"COOKIES-POLICY": "Cookies Policy",
"PLANS": "My DMPs",
@ -127,7 +129,7 @@
"LANGUAGE-EDITOR": "Language Editor",
"GUIDE-EDITOR": "User Guide Editor",
"LANGUAGE": "Language",
"SIGN-IN":"Sign in to account"
"SIGN-IN": "Sign in to account"
},
"FILE-TYPES": {
"PDF": "PDF",
@ -748,6 +750,7 @@
"TITLE": {
"NEW": "New Data Management Plan",
"EDIT": "Edit",
"EDIT-DMP": "Editing DMP",
"SUBTITLE": "DOI"
},
"FIELDS": {
@ -757,13 +760,16 @@
"ORGANISATIONS": "Organizations",
"ORGANISATIONS-HINT": "Add here the names of the organizations contributing to the creation and revision of the DMPs",
"RESEARCHERS": "Researchers",
"AUTHORS": "Authors",
"TEMPLATES": "Templates",
"TEMPLATE": "DMP Template",
"DATASET-TEMPLATES": "Related Dataset Description Templates",
"PROFILE": "DMP Template",
"PROJECT": "Project",
"GRANT": "Grant",
"GRANTS": "Grants",
"FUNDER": "Funder",
"FUNDING-ORGANIZATIONS": "Funding organizations",
"STATUS": "DMP Status",
"EXTERNAL-SOURCE-HINT": "List of values provided by external source(s)",
"COLLABORATORS": "Collaborators",
@ -780,9 +786,18 @@
"SAVE": "Save",
"CANCEL": "Cancel",
"DELETE": "Delete",
"DISCARD": "Discard",
"FINALISE": "Finalize",
"LOCK": "DMP is locked by another user",
"PERMISSION": "You have no permission to edit this DMP"
"PERMISSION": "You have no permission to edit this DMP",
"INSERT-MANUALLY": "Insert it manually",
"CREATE-DATASET": "Create new one"
},
"PLACEHOLDER": {
"DESCRIPTION": "Fill with description",
"ORGANIZATION": "Select organization",
"AUTHORS": "Select authors",
"RESEARCHERS": "Select researchers"
},
"SNACK-BAR": {
"UNSUCCESSFUL-DOI": "Unsuccessful DOI creation",
@ -797,7 +812,31 @@
"VISIBILITY": {
"PUBLIC": "Public",
"RESTRICTED": "Restricted"
}
},
"STEPPER": {
"USER-GUIDE": "Guide steps",
"MAIN-INFO": "Main info",
"FUNDING-INFO": "Funding info",
"DATASET-SELECTION": "Dataset selection",
"DATASET-INFO": "Dataset info",
"PREVIOUS": "Previous",
"NEXT": "Next"
},
"MAIN-INFO": {
"INTRO": "A DMP in Argos consists of key information about research, such as purpose, objectives and researchers involved, but also about documentation of research datasets, namely dataset descriptions, that highlight the steps followed and the means used across data management activities.",
"HINT": "A brief description of what the DMP is about, its scope and objectives.",
"TYPING": "Type more letters of the name so its more possible to find the correct one."
},
"FUNDING-INFO": {
"INTRO": "A Data Management Plan (DMP) consist of your Data Management Plans closer to where they are generated, analysed and stored. argos is an open, extensible, collaborative tool supporting Open and FAIR Data Management Plans.",
"FIND": "Couldn't find the correct one?"
},
"DATASET-INFO": {
"INTRO": "A DMP in Argos consists of key information about research, such as purpose, objectives and researchers involved, but also about documentation of research datasets, namely dataset descriptions, that highlight the steps followed and the means used across data management activities.",
"SECOND-INTRO": "Datasets are documented following pre-defined templates which set the content of dataset descriptions. In Argos, a DMP can contain as many dataset descriptions as the datasets it documents.",
"FIND": "Couldn't find a suitable one?"
},
"CHANGES": "unsaved changes"
},
"DMP-PROFILE-LISTING": {
"TITLE": "DMP Templates",
@ -910,6 +949,9 @@
"DELETE": "Delete",
"UPDATE": "Update"
},
"PLACEHOLDER": {
"DESCRIPTION": "Fill with description"
},
"VERSION-DIALOG": {
"ABOUT": "Versioning is automated.",
"QUESTION": "It seems your Dataset Description Template is outdated. Do you want to update it to the latest version?"
@ -1154,6 +1196,10 @@
"TITLE": "-Privacy Policy-",
"MAIN-CONTENT": ""
},
"OPENSOURCE-LICENCES": {
"TITLE": "Opensource licences",
"MAIN-CONTENT": ""
},
"TERMS-OF-SERVICE": {
"TITLE": "Terms of Service",
"MAIN-CONTENT": ""

View File

@ -50,6 +50,7 @@
"DELETE-ITEM": "¿Borrar este item?",
"DELETE-USER": "¿Borrar este colaborador?",
"FINALIZE-ITEM": "¿Finalizar este item?",
"UNFINALIZE-ITEM": "Undo Finalization?",
"PUBLISH-ITEM": "¿Publicar este item?",
"ADD-DATASET": "¿Quiere continuar añadiendo una descripción al Dataset de su PGD? Siempre puede añadir más descripciones al Dataset utilizado el menú\"(Asistente) Añadir una decripción del Dataset\".",
"ZENODO-DOI": "¿Quiere crear un Identificación de Objeto Digital (DOI) para el PGD?",
@ -88,6 +89,7 @@
"GENERAL": "Crear Planes de Gestión de Datos",
"ABOUT": "Acerca de",
"PRIVACY": "Política de privacidad",
"OPENSOURCE-LICENCES": "Opensource Licences",
"TERMS": "Términos de servicio",
"COOKIES-POLICY": "Cookies Policy",
"PLANS": "Mis PGDs",
@ -744,6 +746,7 @@
"TITLE": {
"NEW": "Nuevo Plan de Gestión de Datos",
"EDIT": "Editar",
"EDIT-DMP": "Editing DMP",
"SUBTITLE": "DOI"
},
"FIELDS": {
@ -753,13 +756,16 @@
"ORGANISATIONS": "Organizaciones",
"ORGANISATIONS-HINT": "Añadir aquí los nombre de las organizaciones participantes en la creación y revisión de los PGDs",
"RESEARCHERS": "Investigadores",
"AUTHORS": "Authors",
"TEMPLATES": "Plantillas",
"TEMPLATE": "Plantilla del PGD",
"DATASET-TEMPLATES": "Related Dataset Description Templates",
"PROFILE": "Plantilla del PGD",
"PROJECT": "Proyecto",
"GRANT": "Subvención",
"GRANTS": "Grants",
"FUNDER": "Financiador",
"FUNDING-ORGANIZATIONS": "Funding organizations",
"STATUS": "Estado del PGD",
"EXTERNAL-SOURCE-HINT": "Lista de valores proporcioador por fuente(s) externa(s)",
"COLLABORATORS": "Collaborators",
@ -774,10 +780,18 @@
"SAVE-CHANGES": "Guardar cambios",
"SAVE": "Grabar",
"CANCEL": "Cancelar",
"DISCARD": "Discard",
"DELETE": "Borrar",
"FINALISE": "Finalizar",
"LOCK": "DMP is locked by another user",
"PERMISSION": "You have no permission to edit this DMP"
"PERMISSION": "You have no permission to edit this DMP",
"INSERT-MANUALLY": "Insert it manually",
"CREATE-DATASET": "Create new one"
},
"PLACEHOLDER": {
"DESCRIPTION": "Fill with description",
"ORGANIZATION": "Select organization",
"AUTHORS": "Select authors"
},
"SNACK-BAR": {
"UNSUCCESSFUL-DOI": "Fallo en la creación del DOI",
@ -792,7 +806,31 @@
"VISIBILITY": {
"PUBLIC": "Public",
"RESTRICTED": "Restricted"
}
},
"STEPPER": {
"USER-GUIDE": "Guide steps",
"MAIN-INFO": "Main info",
"FUNDING-INFO": "Funding info",
"DATASET-SELECTION": "Dataset selection",
"DATASET-INFO": "Dataset info",
"PREVIOUS": "Previous",
"NEXT": "Next"
},
"MAIN-INFO": {
"INTRO": "A DMP in Argos consists of key information about research, such as purpose, objectives and researchers involved, but also about documentation of research datasets, namely dataset descriptions, that highlight the steps followed and the means used across data management activities.",
"HINT": "A brief description of what the DMP is about, its scope and objectives.",
"TYPING": "Type more letters of the name so its more possible to find the correct one."
},
"FUNDING-INFO": {
"INTRO": "A Data Management Plan (DMP) consist of your Data Management Plans closer to where they are generated, analysed and stored. argos is an open, extensible, collaborative tool supporting Open and FAIR Data Management Plans.",
"FIND": "Couldn't find the correct one?"
},
"DATASET-INFO": {
"INTRO": "A DMP in Argos consists of key information about research, such as purpose, objectives and researchers involved, but also about documentation of research datasets, namely dataset descriptions, that highlight the steps followed and the means used across data management activities.",
"SECOND-INTRO": "Datasets are documented following pre-defined templates which set the content of dataset descriptions. In Argos, a DMP can contain as many dataset descriptions as the datasets it documents.",
"FIND": "Couldn't find a suitable one?"
},
"CHANGES": "unsaved changes"
},
"DMP-PROFILE-LISTING": {
"TITLE": "Plantilla del PGD",
@ -1137,6 +1175,10 @@
"TITLE": "-Política de privacidad-",
"MAIN-CONTENT": ""
},
"OPENSOURCE-LICENCES": {
"TITLE": "Opensource licences",
"MAIN-CONTENT": ""
},
"TERMS-OF-SERVICE": {
"TITLE": "-Términos del servicio-",
"MAIN-CONTENT": ""

View File

@ -50,6 +50,7 @@
"DELETE-ITEM": "Διαγραφή αυτού του στοιχείου;",
"DELETE-USER": "Αφαίρεση αυτού του συνεργάτη;",
"FINALIZE-ITEM": "Ολοκλήρωση αυτού του στοιχείου;",
"UNFINALIZE-ITEM": "Undo Finalization?",
"PUBLISH-ITEM": "Δημοσίευση αυτού του στοιχείου;",
"ADD-DATASET": "Θέλετε να συνεχίσετε προσθέτοντας μια Περιγραφή Συνόλου Δεδομένων στο Σχέδιο Διαχείρισης Δεδομένων σας; Μπορείτε πάντα να προσθέσετε περισσότερες Περιγραφές Συνόλων Δεδομένων χρησιμοποιώντας \"Add Dataset Description (Wizard)\" menu.",
"ZENODO-DOI": "Θέλετε να δημιουργήσετε μονοσήμαντο αναγνωριστικό ψηφιακού αντικειμένου (DOI) για το Σχέδιο Διαχείρισης Δεδομένων σας;",
@ -88,6 +89,7 @@
"GENERAL": "Δημιουργός Σχεδίου Διαχείρισης Δεδομένων",
"ABOUT": "Σχετικά",
"PRIVACY": "Πολιτική Απορρήτου και Προστασίας Προσωπικών Δεδομένων",
"OPENSOURCE-LICENCES": "Opensource Licences",
"TERMS": "Όροι χρήσης",
"COOKIES-POLICY": "Cookies Policy",
"PLANS": "Τα Σχέδια Διαχείρισης Δεδομένων Μου",
@ -745,6 +747,7 @@
"TITLE": {
"NEW": "Νέα Σχέδιο Διαχείρισης Δεδομένων",
"EDIT": "Επεξεργασία",
"EDIT-DMP": "Editing DMP",
"SUBTITLE": "Μονοσήμαντο Αναγνωριστικό Ψηφιακού Αντικειμένου (DOI)"
},
"FIELDS": {
@ -754,13 +757,16 @@
"ORGANISATIONS": "Οργανισμοί",
"ORGANISATIONS-HINT": "Προσθήκη ονομάτων των οργανισμών που συνεισφέρουν στη δημιουργία και αναθεώρηση των Σχεδίων Διαχείρισης Δεδομένων",
"RESEARCHERS": "Ερευνητές",
"AUTHORS": "Authors",
"TEMPLATES": "Templates",
"TEMPLATE": "Template Σχεδίου Διαχείρισης Δεδομένων",
"DATASET-TEMPLATES": "Σχετικά Templates Περιγραφής Συνόλου Δεδομένων",
"PROFILE": "Template Σχεδίου Διαχείρισης Δεδομένων",
"PROJECT": "Έργο",
"GRANT": "Επιχορήγηση",
"GRANTS": "Grants",
"FUNDER": "Χορηγός",
"FUNDING-ORGANIZATIONS": "Funding organizations",
"STATUS": "Κατάσταση Σχεδίου Διαχείρισης Δεδομένων",
"EXTERNAL-SOURCE-HINT": "Κατάλογος των τιμών που παρέχονται από εξωτερικές πηγές",
"COLLABORATORS": "Συνεργάτες",
@ -776,9 +782,17 @@
"SAVE": "Αποθήκευση",
"CANCEL": "Ακύρωση",
"DELETE": "Διαγραφή",
"DISCARD": "Discard",
"FINALISE": "Οριστικοποίηση",
"LOCK": "Κλειδωμένο Σχέδιο Διαχείρισης Δεδομένων",
"PERMISSION": "Δεν έχετε άδεια να επεξεργαστείτε αυτό το Σχέδιο Διαχείρισης Δεδομένων"
"PERMISSION": "Δεν έχετε άδεια να επεξεργαστείτε αυτό το Σχέδιο Διαχείρισης Δεδομένων",
"INSERT-MANUALLY": "Insert it manually",
"CREATE-DATASET": "Create new one"
},
"PLACEHOLDER": {
"DESCRIPTION": "Fill with description",
"ORGANIZATION": "Select organization",
"AUTHORS": "Select authors"
},
"SNACK-BAR": {
"UNSUCCESSFUL-DOI": "Αποτυχία δημιουργίας Μονοσήμαντων Αναγνωριστικών Ψηφιακών Αντικειμένων (DOI)",
@ -793,7 +807,31 @@
"VISIBILITY": {
"PUBLIC": "Public",
"RESTRICTED": "Restricted"
}
},
"STEPPER": {
"USER-GUIDE": "Guide steps",
"MAIN-INFO": "Main info",
"FUNDING-INFO": "Funding info",
"DATASET-SELECTION": "Dataset selection",
"DATASET-INFO": "Dataset info",
"PREVIOUS": "Previous",
"NEXT": "Next"
},
"MAIN-INFO": {
"INTRO": "A DMP in Argos consists of key information about research, such as purpose, objectives and researchers involved, but also about documentation of research datasets, namely dataset descriptions, that highlight the steps followed and the means used across data management activities.",
"HINT": "A brief description of what the DMP is about, its scope and objectives.",
"TYPING": "Type more letters of the name so its more possible to find the correct one."
},
"FUNDING-INFO": {
"INTRO": "A Data Management Plan (DMP) consist of your Data Management Plans closer to where they are generated, analysed and stored. argos is an open, extensible, collaborative tool supporting Open and FAIR Data Management Plans.",
"FIND": "Couldn't find the correct one?"
},
"DATASET-INFO": {
"INTRO": "A DMP in Argos consists of key information about research, such as purpose, objectives and researchers involved, but also about documentation of research datasets, namely dataset descriptions, that highlight the steps followed and the means used across data management activities.",
"SECOND-INTRO": "Datasets are documented following pre-defined templates which set the content of dataset descriptions. In Argos, a DMP can contain as many dataset descriptions as the datasets it documents.",
"FIND": "Couldn't find a suitable one?"
},
"CHANGES": "unsaved changes"
},
"DMP-PROFILE-LISTING": {
"TITLE": "Templates Σχεδίων Διαχείρισης Δεδομένων",
@ -1138,6 +1176,10 @@
"TITLE": "-Πολιτική Απορρήτου-",
"MAIN-CONTENT": ""
},
"OPENSOURCE-LICENCES": {
"TITLE": "Opensource licences",
"MAIN-CONTENT": ""
},
"TERMS-OF-SERVICE": {
"TITLE": "-Όροι Χρήσης-",
"MAIN-CONTENT": ""

View File

@ -116,7 +116,7 @@
</div>
</div>
<div class="row justify-content-center pt-5">
<a class="col-auto conditions-policy" href="https://creativecommons.org/licenses/by/4.0/">Οpensource licences</a>
<a class="col-auto conditions-policy" href="/opensource-licences">Οpensource licences</a>
<a class="col-auto conditions-policy" href="/terms-and-conditions">Terms and conditions</a>
<a class="col-auto conditions-policy" href="/cookies-policy">Cookies policy</a>
</div>

View File

@ -189,7 +189,7 @@
</div>
</div>
<div class="row justify-content-center pt-5">
<a class="col-auto conditions-policy" href="https://creativecommons.org/licenses/by/4.0/">Οpensource licences</a>
<a class="col-auto conditions-policy" href="/opensource-licences">Οpensource licences</a>
<a class="col-auto conditions-policy" href="/terms-and-conditions">Terms and conditions</a>
<a class="col-auto conditions-policy" href="/cookies-policy">Cookies policy</a>
</div>

View File

@ -143,7 +143,7 @@
</div>
</div>
<div class="row justify-content-center pt-5">
<a class="col-auto conditions-policy" href="https://creativecommons.org/licenses/by/4.0/">Οpensource licences</a>
<a class="col-auto conditions-policy" href="/opensource-licences">Οpensource licences</a>
<a class="col-auto conditions-policy" href="/terms-and-conditions">Terms and conditions</a>
<a class="col-auto conditions-policy" href="/cookies-policy">Cookies policy</a>
</div>

View File

@ -125,7 +125,7 @@
</div>
</div>
<div class="row justify-content-center pt-5">
<a class="col-auto conditions-policy" href="https://creativecommons.org/licenses/by/4.0/">Οpensource licences</a>
<a class="col-auto conditions-policy" href="/opensource-licences">Οpensource licences</a>
<a class="col-auto conditions-policy" href="/terms-and-conditions">Terms and conditions</a>
<a class="col-auto conditions-policy" href="/cookies-policy">Cookies policy</a>
</div>

View File

@ -372,7 +372,7 @@
</div>
</div>
<div class="row justify-content-center pt-5">
<a class="col-auto conditions-policy" href="https://creativecommons.org/licenses/by/4.0/">Οpensource licences</a>
<a class="col-auto conditions-policy" href="/opensource-licences">Οpensource licences</a>
<a class="col-auto conditions-policy" href="/terms-and-conditions">Terms and conditions</a>
<a class="col-auto conditions-policy" href="/cookies-policy">Cookies policy</a>
</div>

View File

@ -2,7 +2,6 @@ function toggleClass(ids, option) {
ids.forEach(id => {
var element = document.getElementById(id);
var className = element.getAttribute("class").replace(/ .*/, '');
console.log(className);
if (id === option) {
element.classList.replace(className, "selected");
} else {

View File

@ -121,8 +121,7 @@
</div>
</div>
<div class="row justify-content-center pt-5">
<a class="col-auto conditions-policy" href="https://creativecommons.org/licenses/by/4.0/">Οpensource
licences</a>
<a class="col-auto conditions-policy" href="/opensource-licences">Οpensource licences</a>
<a class="col-auto conditions-policy" href="/terms-and-conditions">Terms and conditions</a>
<a class="col-auto conditions-policy" href="/cookies-policy">Cookies policy</a>
</div>

View File

@ -209,8 +209,7 @@
</div>
</div>
<div class="row justify-content-center pt-5">
<a class="col-auto conditions-policy" href="https://creativecommons.org/licenses/by/4.0/">Οpensource
licences</a>
<a class="col-auto conditions-policy" href="/opensource-licences">Οpensource licences</a>
<a class="col-auto conditions-policy" href="/terms-and-conditions">Terms and conditions</a>
<a class="col-auto conditions-policy" href="/cookies-policy">Cookies policy</a>
</div>

View File

@ -123,8 +123,7 @@
</div>
</div>
<div class="row justify-content-center pt-5">
<a class="col-auto conditions-policy" href="https://creativecommons.org/licenses/by/4.0/">Οpensource
licences</a>
<a class="col-auto conditions-policy" href="/opensource-licences">Οpensource licences</a>
<a class="col-auto conditions-policy" href="/terms-and-conditions">Terms and conditions</a>
<a class="col-auto conditions-policy" href="/cookies-policy">Cookies policy</a>
</div>

View File

@ -0,0 +1,47 @@
-- Angular
https://github.com/angular/angular/blob/master/LICENSE
-- NGX-Translate
https://github.com/ngx-translate/core/blob/master/LICENSE
-- Swimlane
https://github.com/swimlane/ngx-datatable/blob/master/LICENSE
-- TinyMCE
https://github.com/tinymce/tinymce/blob/develop/LICENSE.TXT
-- W11K GmbH
https://github.com/w11k/angular-sticky-things/blob/master/LICENSE
-- Bootstrap
https://github.com/twbs/bootstrap/blob/main/LICENSE
-- Cookie Consent
https://github.com/osano/cookieconsent/blob/dev/LICENSE
-- Core-js
https://github.com/zloirock/core-js/blob/master/LICENSE
-- File Saver
https://github.com/eligrey/FileSaver.js/blob/master/LICENSE.md
-- Moment
https://github.com/moment/moment/blob/develop/LICENSE
-- Ngx-Cookie-Service
https://github.com/stevermeister/ngx-cookie-service/blob/master/LICENSE
-- Ngx-cookieconsent
https://github.com/tinesoft/ngx-cookieconsent/blob/master/LICENSE
-- Rxjs
https://github.com/ReactiveX/rxjs/blob/master/LICENSE.txt
-- Tslib
https://github.com/microsoft/tslib/blob/master/LICENSE.txt
-- Web-animations-js
https://github.com/web-animations/web-animations-js/blob/dev/COPYING
-- Zone.js
https://github.com/angular/zone.js/blob/master/LICENSE