diff --git a/dmp-backend/web/src/main/java/eu/eudat/controllers/v2/DmpController.java b/dmp-backend/web/src/main/java/eu/eudat/controllers/v2/DmpController.java index 3d2d360c2..e2d21174f 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/controllers/v2/DmpController.java +++ b/dmp-backend/web/src/main/java/eu/eudat/controllers/v2/DmpController.java @@ -229,7 +229,7 @@ public class DmpController { @GetMapping("{id}/token/{token}/invite-accept") @Transactional - public ResponseEntity inviteUsers(@PathVariable("id") UUID id, @PathVariable("token") String token) throws InvalidApplicationException, JAXBException { + public ResponseEntity acceptInvitation(@PathVariable("id") UUID id, @PathVariable("token") String token) throws InvalidApplicationException, JAXBException { logger.debug(new MapLogEntry("inviting users to dmp").And("id", id)); this.dmpService.dmpInvitationAccept(token); diff --git a/dmp-frontend/src/app/core/model/dmp/dmp.ts b/dmp-frontend/src/app/core/model/dmp/dmp.ts index 764d103a7..aa6452d44 100644 --- a/dmp-frontend/src/app/core/model/dmp/dmp.ts +++ b/dmp-frontend/src/app/core/model/dmp/dmp.ts @@ -97,4 +97,15 @@ export interface DmpUserRemovePersist { id: Guid; dmpId: Guid; role: DmpUserRole; -} \ No newline at end of file +} + +export interface DmpUserInvitePersist { + users: DmpUserInviteTypePersist[]; + role: DmpUserRole; +} + +export interface DmpUserInviteTypePersist { + userId: Guid; + email: string; +} + diff --git a/dmp-frontend/src/app/core/services/dmp/dmp.service.ts b/dmp-frontend/src/app/core/services/dmp/dmp.service.ts index 9045ecf8d..722cd8ac9 100644 --- a/dmp-frontend/src/app/core/services/dmp/dmp.service.ts +++ b/dmp-frontend/src/app/core/services/dmp/dmp.service.ts @@ -3,7 +3,6 @@ import { Injectable } from '@angular/core'; import { DmpStatus } from '@app/core/common/enum/dmp-status'; import { DmpUserRole } from '@app/core/common/enum/dmp-user-role'; import { IsActive } from '@app/core/common/enum/is-active.enum'; -import { FileFormat } from '@app/core/model/file/file-format.model'; import { DmpDescriptionTemplateLookup } from '@app/core/query/dmp-description-template.lookup'; import { DmpLookup } from '@app/core/query/dmp.lookup'; import { MultipleAutoCompleteConfiguration } from '@app/library/auto-complete/multiple/multiple-auto-complete-configuration'; @@ -16,7 +15,7 @@ import { catchError, map } from 'rxjs/operators'; import { nameof } from 'ts-simple-nameof'; import { BaseHttpParams } from '../../../../common/http/base-http-params'; import { InterceptorType } from '../../../../common/http/interceptors/interceptor-type'; -import { CloneDmpPersist, Dmp, DmpPersist, DmpUser, DmpUserPersist, DmpUserRemovePersist, NewVersionDmpPersist } from '../../model/dmp/dmp'; +import { CloneDmpPersist, Dmp, DmpPersist, DmpUser, DmpUserInvitePersist, DmpUserPersist, DmpUserRemovePersist, NewVersionDmpPersist } from '../../model/dmp/dmp'; import { AuthService } from '../auth/auth.service'; import { ConfigurationService } from '../configuration/configuration.service'; import { BaseHttpV2Service } from '../http/base-http-v2.service'; @@ -111,6 +110,20 @@ export class DmpService { catchError((error: any) => throwError(error))); } + inviteUsers(dmpId: Guid, item: DmpUserInvitePersist): Observable { + const url = `${this.apiBase}/${dmpId}/invite-users`; + + return this.http + .post(url, item).pipe( + catchError((error: any) => throwError(error))); + } + + acceptInvitation(dmpId: Guid, token: string): Observable { + const url = `${this.apiBase}/${dmpId}/token/${token}/invite-accept`; + + return this.http.get(url).pipe(catchError((error: any) => throwError(error))); + } + public download(id: string, format: string): Observable> { //let headerDoc: HttpHeaders = this.headers.set('Content-Type', 'application/msword') return this.httpClient.get(`${this.apiBase}/${id}/export/${format}`, { responseType: 'blob', observe: 'response', headers: this.headers }); diff --git a/dmp-frontend/src/app/ui/description/listing/listing-item/description-listing-item.component.ts b/dmp-frontend/src/app/ui/description/listing/listing-item/description-listing-item.component.ts index 98146d878..f4c5e3bc9 100644 --- a/dmp-frontend/src/app/ui/description/listing/listing-item/description-listing-item.component.ts +++ b/dmp-frontend/src/app/ui/description/listing/listing-item/description-listing-item.component.ts @@ -17,7 +17,7 @@ import { SnackBarNotificationLevel, UiNotificationService } from '@app/core/serv import { ReferenceService } from '@app/core/services/reference/reference.service'; import { EnumUtils } from '@app/core/services/utilities/enum-utils.service'; import { FileUtils } from '@app/core/services/utilities/file-utils.service'; -import { DmpInvitationDialogComponent } from '@app/ui/dmp/invitation/dmp-invitation-dialog.component'; +import { DmpInvitationDialogComponent } from '@app/ui/dmp/invitation/dialog/dmp-invitation-dialog.component'; import { BaseComponent } from '@common/base/base.component'; import { ConfirmationDialogComponent } from '@common/modules/confirmation-dialog/confirmation-dialog.component'; import { Guid } from '@common/types/guid'; diff --git a/dmp-frontend/src/app/ui/dmp/dmp.module.ts b/dmp-frontend/src/app/ui/dmp/dmp.module.ts index 4162dbf3f..f1ab651c3 100644 --- a/dmp-frontend/src/app/ui/dmp/dmp.module.ts +++ b/dmp-frontend/src/app/ui/dmp/dmp.module.ts @@ -36,7 +36,6 @@ import { CommonUiModule } from '@common/ui/common-ui.module'; // DmpListingComponent, // DmpCriteriaComponent, // DmpEditorComponent, - // DmpInvitationDialogComponent, // InvitationAcceptedComponent, // DmpToDatasetDialogComponent, // DmpWizardComponent, diff --git a/dmp-frontend/src/app/ui/dmp/invitation/dialog/dmp-invitation-dialog.component.html b/dmp-frontend/src/app/ui/dmp/invitation/dialog/dmp-invitation-dialog.component.html new file mode 100644 index 000000000..a38fae529 --- /dev/null +++ b/dmp-frontend/src/app/ui/dmp/invitation/dialog/dmp-invitation-dialog.component.html @@ -0,0 +1,32 @@ +
+
+
+

{{'DMP-USER-INVITATION-DIALOG.TITLE' | translate}}

+
+
+ close +
+
+
+ + + + +

+ info_outlined + {{'DMP-USER-INVITATION-DIALOG.FIELDS.USERS-HINT' | translate}} +

+
+
+ + + {{enumUtils.toDmpUserRoleString(dmpUserRoleEnum.Owner)}} + {{enumUtils.toDmpUserRoleString(dmpUserRoleEnum.Member)}} + + +
+
+ +
+
+
\ No newline at end of file diff --git a/dmp-frontend/src/app/ui/dmp/invitation/dialog/dmp-invitation-dialog.component.scss b/dmp-frontend/src/app/ui/dmp/invitation/dialog/dmp-invitation-dialog.component.scss new file mode 100644 index 000000000..78ac33791 --- /dev/null +++ b/dmp-frontend/src/app/ui/dmp/invitation/dialog/dmp-invitation-dialog.component.scss @@ -0,0 +1,150 @@ +.dmp-invitation-dialog { + padding: 2.5rem; + + .form-container { + width: 33em; + min-height: 14em; + padding: 0.28em 0.34em 0em 1.125em; + } + + .close-icon { + cursor: pointer; + // margin-right: 20px; + padding: .4rem; + width: auto !important; + height: auto !important; + } + + .close-icon:hover { + background-color: #ECECED !important; + border-radius: 50%; + } + + .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; + // } + + .hint { + font-size: 0.875rem; + font-weight: 500; + color: #212121; + opacity: 0.81; + } + + ::ng-deep .mat-dialog-container { + border-radius: 8px; + } + + .search { + padding: 2px !important; + } + + ::ng-deep .search { + .mat-form-field-infix { + font-size: 1rem; + padding: 0.6em 0 1em 0 !important; + } + + // .mat-form-field-underline { + // display: none; + // } + // .mat-form-field-flex { + // padding: 0em; + // } + // .align-arrow-right { + // display: none; + // } + } + + .select-role { + width: 20% !important; + font-size: 14px; + color: #848484; + height: min-content; + margin-right: 2rem; + border: none; + background-color: transparent; + } + + ::ng-deep .select-role { + + .mat-form-field-outline-start, + .mat-form-field-outline-gap, + .mat-form-field-outline-end { + border: none !important; + } + + .mat-select-arrow-wrapper { + transform: none !important; + } + } + + ::ng-deep .select-role .mat-form-field-wrapper { + padding-bottom: 0 !important; + } + + .invite-btn { + background: #ffffff 0% 0% no-repeat padding-box; + border: 1px solid var(--primary-color); + border-radius: 30px; + opacity: 1; + min-width: 101px; + height: 43px; + color: var(--primary-color); + font-weight: 500; + } + + .invite-btn-disabled { + min-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; + cursor: default; + } + + .invite-btn:hover { + background: var(--primary-color); + color: #ffffff; + } + + @keyframes blink { + 0% { + border: 1px solid rgba(255, 0, 0, 0.2); + } + + 50% { + border: 1px solid rgba(255, 0, 0, 0.5); + } + + 100% { + border: 1px solid rgba(255, 0, 0, 0.2); + } + } + + :host ::ng-deep .invalid-email { + border: 1px solid red; + // animation: blink 1.4s infinite; + // animation-fill-mode: both; + } +} diff --git a/dmp-frontend/src/app/ui/dmp/invitation/dmp-invitation-dialog.component.ts b/dmp-frontend/src/app/ui/dmp/invitation/dialog/dmp-invitation-dialog.component.ts similarity index 56% rename from dmp-frontend/src/app/ui/dmp/invitation/dmp-invitation-dialog.component.ts rename to dmp-frontend/src/app/ui/dmp/invitation/dialog/dmp-invitation-dialog.component.ts index b7b19a9ff..3378c5425 100644 --- a/dmp-frontend/src/app/ui/dmp/invitation/dmp-invitation-dialog.component.ts +++ b/dmp-frontend/src/app/ui/dmp/invitation/dialog/dmp-invitation-dialog.component.ts @@ -2,19 +2,26 @@ import { COMMA, ENTER } from '@angular/cdk/keycodes'; import { Component, Inject, OnInit } from '@angular/core'; import { UntypedFormGroup } from '@angular/forms'; -import { MatChipInputEvent } from '@angular/material/chips'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import { ActivatedRoute, Router } from '@angular/router'; import { DmpUserRole } from '@app/core/common/enum/dmp-user-role'; +import { IsActive } from '@app/core/common/enum/is-active.enum'; +import { DmpUserInvitePersist } from '@app/core/model/dmp/dmp'; import { User } from '@app/core/model/user/user'; -import { RequestItem } from '@app/core/query/request-item'; +import { UserLookup } from '@app/core/query/user.lookup'; +import { DmpService } from '@app/core/services/dmp/dmp.service'; import { SnackBarNotificationLevel, UiNotificationService } from '@app/core/services/notification/ui-notification-service'; +import { UserService } from '@app/core/services/user/user.service'; import { EnumUtils } from '@app/core/services/utilities/enum-utils.service'; import { MultipleAutoCompleteConfiguration } from '@app/library/auto-complete/multiple/multiple-auto-complete-configuration'; import { BaseComponent } from '@common/base/base.component'; +import { FilterService } from '@common/modules/text-filter/filter-service'; +import { Guid } from '@common/types/guid'; import { TranslateService } from '@ngx-translate/core'; import { Observable } from 'rxjs'; import { map, takeUntil } from 'rxjs/operators'; +import { nameof } from 'ts-simple-nameof'; +import { DmpInvitationDialogEditorModel } from './dmp-invitation-dialog.editor.model'; @Component({ selector: 'app-invitation-dialog-component', @@ -23,37 +30,12 @@ import { map, takeUntil } from 'rxjs/operators'; }) export class DmpInvitationDialogComponent extends BaseComponent implements OnInit { - public formGroup: UntypedFormGroup; - public filteredUsersAsync = false; - public filteredUsers: User[]; - public emails: string[] = []; - public roles = DmpUserRole; - visible = true; - selectable = true; - removable = true; - addOnBlur = true; + dmpId: Guid; + editorModel: DmpInvitationDialogEditorModel; + formGroup: UntypedFormGroup; + dmpUserRoleEnum = DmpUserRole; readonly separatorKeysCodes: number[] = [ENTER, COMMA]; - constructor( - public enumUtils: EnumUtils, - public route: ActivatedRoute, - public router: Router, - private language: TranslateService, - public dialogRef: MatDialogRef, - private uiNotificationService: UiNotificationService, - @Inject(MAT_DIALOG_DATA) public data: any - ) { - super(); - } - - ngOnInit(): void { - //TODO refactor - // 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))), @@ -74,61 +56,67 @@ export class DmpInvitationDialogComponent extends BaseComponent implements OnIni }] }; - add(event: MatChipInputEvent): void { - const input = event.input; - const value = event.value; - if ((value || '').trim()) { - this.emails.push(value.trim()); - } - if (input) { - input.value = ''; - } + constructor( + public enumUtils: EnumUtils, + public route: ActivatedRoute, + public router: Router, + private language: TranslateService, + public dialogRef: MatDialogRef, + private uiNotificationService: UiNotificationService, + private dmpService: DmpService, + private userService: UserService, + private filterService: FilterService, + @Inject(MAT_DIALOG_DATA) public data: any + ) { + super(); + this.dmpId = data.dmpId; } - remove(email: string): void { - const index = this.emails.indexOf(email); - if (index >= 0) { - this.emails.splice(index, 1); - } + ngOnInit() { + this.editorModel = new DmpInvitationDialogEditorModel(); + this.formGroup = this.editorModel.buildForm(); } - send(value: any) { - let invitationObject: any = {}; - invitationObject.dataManagementPlan = this.data.dmpId; - invitationObject.role = this.formGroup.get('role').value; - invitationObject.users = []; - invitationObject.users.push(...(this.formGroup.get('users').value).filter(user => typeof (user) === 'string').map(email => ({ email: email, name: email }))); - invitationObject.users.push(...(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 }); - }); + send() { + if (!this.formGroup.valid) { return; } + const value: DmpUserInvitePersist = this.formGroup.value; + // invitationObject.users.push(...(this.formGroup.get('users').value).filter(user => typeof (user) === 'string').map(email => ({ email: email, name: email }))); + // invitationObject.users.push(...(this.formGroup.get('users').value).filter(user => typeof (user) !== 'string')); + // this.emails.forEach(email => { + // invitationObject.users.push({ email: email, name: email }); + // }); - //TODO refactor - // this.invitationService.inviteDmpInvitationUsers(invitationObject) - // .pipe(takeUntil(this._destroyed)) - // .subscribe( - // complete => { - // this.dialogRef.close(); - // this.onCallbackSuccess(); - // }, - // error => this.onCallbackError(error) - // ); + this.dmpService.inviteUsers(this.dmpId, value) + .pipe(takeUntil(this._destroyed)) + .subscribe( + complete => { + this.dialogRef.close(); + this.onCallbackSuccess(); + }, + error => this.onCallbackError(error) + ); } closeDialog(): void { this.dialogRef.close(); } - filterUsers(value: string): Observable { - this.filteredUsers = undefined; - this.filteredUsersAsync = true; - //TODO refactor - // const request = new RequestItem(); - // request.criteria = { like: value }; - // return this.invitationService.getDmpInvitationUsers(request) - // .pipe(takeUntil(this._destroyed)); - return null; + filterUsers(like: string): Observable { + //TODO: refactor. Change with a service that provides a list of the users assosiated with your account. + const lookup: UserLookup = new UserLookup(); + lookup.page = { size: 100, offset: 0 }; + // if (excludedIds && excludedIds.length > 0) { lookup.excludedIds = excludedIds; } + // if (ids && ids.length > 0) { lookup.ids = ids; } + lookup.isActive = [IsActive.Active]; + lookup.project = { + fields: [ + nameof(x => x.id), + nameof(x => x.name) + ] + }; + lookup.order = { items: [nameof(x => x.name)] }; + if (like) { lookup.like = this.filterService.transformLike(like); } + return this.userService.query(lookup).pipe(takeUntil(this._destroyed), map(x => x.items)); } hasValue(): boolean { @@ -142,5 +130,4 @@ export class DmpInvitationDialogComponent extends BaseComponent implements OnIni onCallbackError(errorResponse: any) { this.uiNotificationService.snackBarNotification(this.language.instant('GENERAL.INVITATION-DIALOG.ERROR'), SnackBarNotificationLevel.Error); } - } diff --git a/dmp-frontend/src/app/ui/dmp/invitation/dialog/dmp-invitation-dialog.editor.model.ts b/dmp-frontend/src/app/ui/dmp/invitation/dialog/dmp-invitation-dialog.editor.model.ts new file mode 100644 index 000000000..088131fdc --- /dev/null +++ b/dmp-frontend/src/app/ui/dmp/invitation/dialog/dmp-invitation-dialog.editor.model.ts @@ -0,0 +1,34 @@ +import { UntypedFormBuilder, UntypedFormGroup, Validators } from "@angular/forms"; +import { DmpUserRole } from "@app/core/common/enum/dmp-user-role"; +import { DmpUserInvitePersist, DmpUserInviteTypePersist } from "@app/core/model/dmp/dmp"; +import { BackendErrorValidator } from '@common/forms/validation/custom-validator'; +import { ValidationErrorModel } from '@common/forms/validation/error-model/validation-error-model'; +import { Validation, ValidationContext } from '@common/forms/validation/validation-context'; + +export class DmpInvitationDialogEditorModel implements DmpUserInvitePersist { + users: DmpUserInviteTypePersist[]; + role: DmpUserRole = DmpUserRole.User; + + public validationErrorModel: ValidationErrorModel = new ValidationErrorModel(); + protected formBuilder: UntypedFormBuilder = new UntypedFormBuilder(); + + constructor() { } + + buildForm(context: ValidationContext = null, disabled: boolean = false): UntypedFormGroup { + if (context == null) { context = this.createValidationContext(); } + + return this.formBuilder.group({ + users: [{ value: this.users, disabled: disabled }, context.getValidation('users').validators], + role: [{ value: this.role, disabled: disabled }, context.getValidation('role').validators], + }); + } + + createValidationContext(): ValidationContext { + const baseContext: ValidationContext = new ValidationContext(); + const baseValidationArray: Validation[] = new Array(); + baseValidationArray.push({ key: 'users', validators: [BackendErrorValidator(this.validationErrorModel, 'users')] }); + baseValidationArray.push({ key: 'role', validators: [Validators.required, BackendErrorValidator(this.validationErrorModel, 'role')] }); + baseContext.validation = baseValidationArray; + return baseContext; + } +} diff --git a/dmp-frontend/src/app/ui/dmp/invitation/dialog/dmp-invitation-dialog.module.ts b/dmp-frontend/src/app/ui/dmp/invitation/dialog/dmp-invitation-dialog.module.ts new file mode 100644 index 000000000..f3e47a248 --- /dev/null +++ b/dmp-frontend/src/app/ui/dmp/invitation/dialog/dmp-invitation-dialog.module.ts @@ -0,0 +1,15 @@ +import { NgModule } from '@angular/core'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { AutoCompleteModule } from '@app/library/auto-complete/auto-complete.module'; +import { RichTextEditorModule } from "@app/library/rich-text-editor/rich-text-editor.module"; +import { CommonUiModule } from '@common/ui/common-ui.module'; +import { DmpInvitationDialogComponent } from './dmp-invitation-dialog.component'; + +@NgModule({ + imports: [CommonUiModule, FormsModule, ReactiveFormsModule, AutoCompleteModule, RichTextEditorModule], + declarations: [DmpInvitationDialogComponent], + exports: [DmpInvitationDialogComponent] +}) +export class DmpInvitationDialogModule { + constructor() { } +} diff --git a/dmp-frontend/src/app/ui/dmp/invitation/dmp-invitation-dialog.component.html b/dmp-frontend/src/app/ui/dmp/invitation/dmp-invitation-dialog.component.html deleted file mode 100644 index 8d9829904..000000000 --- a/dmp-frontend/src/app/ui/dmp/invitation/dmp-invitation-dialog.component.html +++ /dev/null @@ -1,75 +0,0 @@ -
-
-
- close -
-
-

{{'DMP-LISTING.ACTIONS.INVITE-AUTHORS' | translate}}

-
-
- - - - - -

- info_outlined - {{'GENERAL.INVITATION-DIALOG.HINT' | translate}} -

-
- - - {{enumUtils.toRoleString(roles.Owner)}} - {{enumUtils.toRoleString(roles.Member)}} - - - - -
-
-
-
- - - - - - - - - - - - - diff --git a/dmp-frontend/src/app/ui/dmp/invitation/dmp-invitation-dialog.component.scss b/dmp-frontend/src/app/ui/dmp/invitation/dmp-invitation-dialog.component.scss deleted file mode 100644 index 6a4ec26e4..000000000 --- a/dmp-frontend/src/app/ui/dmp/invitation/dmp-invitation-dialog.component.scss +++ /dev/null @@ -1,135 +0,0 @@ -.form-container { - width: 33em; - min-height: 14em; - padding: 0.28em 0.34em 0em 1.125em; -} - -.close-icon { - cursor: pointer; - // margin-right: 20px; - padding: .4rem; - width: auto !important; - height: auto !important; -} - -.close-icon:hover { - background-color: #ECECED !important; - border-radius: 50%; -} - -.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; -// } - -.hint { - font-size: 0.875rem; - font-weight: 500; - color: #212121; - opacity: 0.81; -} - -::ng-deep .mat-dialog-container { - border-radius: 8px; -} - -.search { - padding: 2px !important; -} - -::ng-deep .search { - .mat-form-field-infix { - font-size: 1rem; - padding: 0.6em 0 1em 0 !important; - } - // .mat-form-field-underline { - // display: none; - // } - // .mat-form-field-flex { - // padding: 0em; - // } - // .align-arrow-right { - // display: none; - // } -} - -.select-role { - width: 20% !important; - font-size: 14px; - color: #848484; - height: min-content; - margin-right: 2rem; - border: none; - background-color: transparent; -} - -::ng-deep .select-role { - .mat-form-field-outline-start, - .mat-form-field-outline-gap, - .mat-form-field-outline-end { - border: none !important; - } - .mat-select-arrow-wrapper { - transform: none !important; - } -} - -::ng-deep .select-role .mat-form-field-wrapper { - padding-bottom: 0 !important; -} - -.invite-btn { - background: #ffffff 0% 0% no-repeat padding-box; - border: 1px solid var(--primary-color); - border-radius: 30px; - opacity: 1; - min-width: 101px; - height: 43px; - color: var(--primary-color); - font-weight: 500; -} - -.invite-btn-disabled { - min-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; - cursor: default; -} - -.invite-btn:hover { - background: var(--primary-color); - color: #ffffff; -} - -@keyframes blink{ - 0% {border: 1px solid rgba(255, 0, 0, 0.2);} - 50% {border: 1px solid rgba(255, 0, 0, 0.5);} - 100% {border: 1px solid rgba(255, 0, 0, 0.2);} -} - -:host ::ng-deep .invalid-email{ - border: 1px solid red; - // animation: blink 1.4s infinite; - // animation-fill-mode: both; -} diff --git a/dmp-frontend/src/app/ui/dmp/listing/dmp-listing.module.ts b/dmp-frontend/src/app/ui/dmp/listing/dmp-listing.module.ts index 148a6688e..3831394e5 100644 --- a/dmp-frontend/src/app/ui/dmp/listing/dmp-listing.module.ts +++ b/dmp-frontend/src/app/ui/dmp/listing/dmp-listing.module.ts @@ -7,6 +7,7 @@ import { CommonUiModule } from '@common/ui/common-ui.module'; import { CloneDmpDialogModule } from '../clone-dialog/dmp-clone-dialog.module'; import { NewVersionDmpDialogModule } from '../new-version-dialog/dmp-new-version-dialog.module'; import { DmpListingRoutingModule } from './dmp-listing.routing'; +import { DmpInvitationDialogModule } from '../invitation/dialog/dmp-invitation-dialog.module'; @NgModule({ imports: [ @@ -15,6 +16,7 @@ import { DmpListingRoutingModule } from './dmp-listing.routing'; FormattingModule, CloneDmpDialogModule, NewVersionDmpDialogModule, + DmpInvitationDialogModule, DmpListingRoutingModule ], declarations: [ diff --git a/dmp-frontend/src/app/ui/dmp/listing/listing-item/dmp-listing-item.component.html b/dmp-frontend/src/app/ui/dmp/listing/listing-item/dmp-listing-item.component.html index 876abaf1a..568017f76 100644 --- a/dmp-frontend/src/app/ui/dmp/listing/listing-item/dmp-listing-item.component.html +++ b/dmp-frontend/src/app/ui/dmp/listing/listing-item/dmp-listing-item.component.html @@ -30,7 +30,7 @@
open_in_new{{'DMP-LISTING.ACTIONS.EXPORT' | translate}} add{{'DMP-LISTING.ACTIONS.ADD-DESCRIPTION-SHORT' | translate}} - group_add{{'DMP-LISTING.ACTIONS.INVITE-SHORT' | translate}} + group_add{{'DMP-LISTING.ACTIONS.INVITE-SHORT' | translate}} filter_none{{'DMP-LISTING.ACTIONS.CLONE' | translate}} library_books{{'DMP-LISTING.ACTIONS.VIEW-VERSION' | translate}} diff --git a/dmp-frontend/src/app/ui/dmp/listing/listing-item/dmp-listing-item.component.ts b/dmp-frontend/src/app/ui/dmp/listing/listing-item/dmp-listing-item.component.ts index d5f2a7556..9cc02a874 100644 --- a/dmp-frontend/src/app/ui/dmp/listing/listing-item/dmp-listing-item.component.ts +++ b/dmp-frontend/src/app/ui/dmp/listing/listing-item/dmp-listing-item.component.ts @@ -27,6 +27,7 @@ import { FileFormat } from '@app/core/model/file/file-format.model'; import { FileTransformerService } from '@app/core/services/file-transformer/file-transformer.service'; import { CloneDmpDialogComponent } from '../../clone-dialog/dmp-clone-dialog.component'; import { NewVersionDmpDialogComponent } from '../../new-version-dialog/dmp-new-version-dialog.component'; +import { DmpInvitationDialogComponent } from '../../invitation/dialog/dmp-invitation-dialog.component'; @Component({ selector: 'app-dmp-listing-item-component', @@ -84,18 +85,16 @@ export class DmpListingItemComponent extends BaseComponent implements OnInit { return this.authentication.currentAccountIsAuthenticated(); } - openShareDialog(rowId: any, rowName: any) { - //TODO: add this. - // const dialogRef = this.dialog.open(DmpInvitationDialogComponent, { - // // height: '250px', - // // width: '700px', - // autoFocus: false, - // restoreFocus: false, - // data: { - // dmpId: rowId, - // dmpName: rowName - // } - // }); + inviteToDmp() { + const dialogRef = this.dialog.open(DmpInvitationDialogComponent, { + // height: '250px', + // width: '700px', + autoFocus: false, + restoreFocus: false, + data: { + dmpId: this.dmp.id + } + }); } editClicked(dmpId: String) { diff --git a/dmp-frontend/src/assets/i18n/en.json b/dmp-frontend/src/assets/i18n/en.json index d76411232..6cff527c2 100644 --- a/dmp-frontend/src/assets/i18n/en.json +++ b/dmp-frontend/src/assets/i18n/en.json @@ -1780,6 +1780,17 @@ "NEW-VERSION": "Create New Version" } }, + "DMP-USER-INVITATION-DIALOG": { + "TITLE": "Invite authors", + "FIELDS": { + "USERS": "Kat or kat@example.com", + "USERS-PLACEHOLDER": "Kat or kat@example.com", + "USERS-HINT": "Press comma or enter between authors" + }, + "ACTIONS": { + "INVITE": "Invite" + } + }, "DMP-BLUEPRINT-LISTING": { "TITLE": "DMP Blueprints", "CREATE-DMP-BLUEPRINT": "Create DMP Blueprint",