diff --git a/ui/src/app/user/user-detail.component.html b/ui/src/app/user/user-detail.component.html new file mode 100644 index 000000000..75bc1e768 --- /dev/null +++ b/ui/src/app/user/user-detail.component.html @@ -0,0 +1,82 @@ +
+
+
+

User Settings

+
+ +
+
+
Email
+
+ {{user.email}} +
+
First Name
+
+ {{user.firstName}} +
+
Last Name
+
+ {{user.lastName}} +
+
Main Contact
+
+ True + False + + +
+
Salesforce Id
+
+ {{user.memberName}} +
+
Activated
+
+ True + False + + +
+ +
Admin
+
+ True + False + + +
+
+
Created Date
+
+ {{user.createdDate!.toString() | date:'medium'}} by {{user.createdBy}} +
+
Last Modified Date
+
+ {{user.lastModifiedDate!.toString() | date:'medium'}} by {{user.lastModifiedBy}} +
+
+
+
+
+ + + +
+
+
+
diff --git a/ui/src/app/user/user-detail.component.scss b/ui/src/app/user/user-detail.component.scss new file mode 100644 index 000000000..e69de29bb diff --git a/ui/src/app/user/user-detail.component.spec.ts b/ui/src/app/user/user-detail.component.spec.ts new file mode 100644 index 000000000..ec8476b4b --- /dev/null +++ b/ui/src/app/user/user-detail.component.spec.ts @@ -0,0 +1,67 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing' + +import { UserDetailComponent } from './user-detail.component' +import { RouterTestingModule } from '@angular/router/testing' +import { HttpClientModule } from '@angular/common/http' +import { AlertService } from '../shared/service/alert.service' +import { UserService } from './service/user.service' +import { MemberService } from '../member/service/member.service' +import { User } from './model/user.model' +import { of } from 'rxjs' +import { Member } from '../member/model/member.model' + +describe('UserDetailComponent', () => { + let component: UserDetailComponent + let fixture: ComponentFixture + let userServiceSpy: jasmine.SpyObj + let alertServiceSpy: jasmine.SpyObj + let memberServiceSpy: jasmine.SpyObj + + beforeEach(() => { + memberServiceSpy = jasmine.createSpyObj('MemberService', ['find']) + userServiceSpy = jasmine.createSpyObj('UserService', ['find', 'sendActivate']) + alertServiceSpy = jasmine.createSpyObj('AlertService', ['broadcast']) + + TestBed.configureTestingModule({ + declarations: [UserDetailComponent], + imports: [RouterTestingModule, HttpClientModule], + providers: [ + { provide: UserService, useValue: userServiceSpy }, + { provide: MemberService, useValue: memberServiceSpy }, + { provide: AlertService, useValue: alertServiceSpy }, + ], + }).compileComponents() + + fixture = TestBed.createComponent(UserDetailComponent) + component = fixture.componentInstance + fixture.detectChanges() + + userServiceSpy = TestBed.inject(UserService) as jasmine.SpyObj + memberServiceSpy = TestBed.inject(MemberService) as jasmine.SpyObj + alertServiceSpy = TestBed.inject(AlertService) as jasmine.SpyObj + }) + + it('should create', () => { + expect(component).toBeTruthy() + }) + + it('when user exists, sendActivate should call userService and alertService', () => { + component.user = new User() + userServiceSpy.sendActivate.and.returnValue(of(new User())) + + component.sendActivate() + + expect(userServiceSpy.sendActivate).toHaveBeenCalled() + expect(alertServiceSpy.broadcast).toHaveBeenCalled() + }) + + it('when user does not exist, sendActivate should not call userService or alertService', () => { + component.user = null + userServiceSpy.sendActivate.and.returnValue(of(new User())) + + component.sendActivate() + + expect(userServiceSpy.sendActivate).toHaveBeenCalledTimes(0) + expect(alertServiceSpy.broadcast).toHaveBeenCalledTimes(0) + }) +}) diff --git a/ui/src/app/user/user-detail.component.ts b/ui/src/app/user/user-detail.component.ts new file mode 100644 index 000000000..0ea664451 --- /dev/null +++ b/ui/src/app/user/user-detail.component.ts @@ -0,0 +1,57 @@ +import { Component } from '@angular/core' +import { IUser } from './model/user.model' +import { faCheckCircle, faTimesCircle, faPencilAlt, faArrowLeft } from '@fortawesome/free-solid-svg-icons' +import { ActivatedRoute } from '@angular/router' +import { map, switchMap, tap } from 'rxjs' +import { UserService } from './service/user.service' +import { AlertService } from '../shared/service/alert.service' +import { MemberService } from '../member/service/member.service' + +@Component({ + selector: 'app-user-detail', + templateUrl: './user-detail.component.html', + styleUrls: ['./user-detail.component.scss'], +}) +export class UserDetailComponent { + user: IUser | null = null + faTimesCircle = faTimesCircle + faCheckCircle = faCheckCircle + faPencilAlt = faPencilAlt + faArrowLeft = faArrowLeft + + DEFAULT_ADMIN = 'admin' + superAdmin: boolean | undefined = false + + constructor( + protected activatedRoute: ActivatedRoute, + protected userService: UserService, + protected alertService: AlertService, + protected memberService: MemberService + ) {} + + ngOnInit() { + this.activatedRoute.data.subscribe(({ user }) => { + this.user = user + }) + } + + sendActivate() { + if (this.user) { + this.userService.sendActivate(this.user).subscribe((res) => { + this.alertService.broadcast('gatewayApp.msUserServiceMSUser.sendActivate.success.string') + this.previousState() + }) + } + } + + isDefaultAdmin(user: IUser) { + if (user.email === this.DEFAULT_ADMIN) { + return true + } + return false + } + + previousState() { + window.history.back() + } +} diff --git a/ui/src/app/user/user.module.ts b/ui/src/app/user/user.module.ts index eeff10e57..f9635aece 100644 --- a/ui/src/app/user/user.module.ts +++ b/ui/src/app/user/user.module.ts @@ -8,10 +8,11 @@ import { BrowserModule } from '@angular/platform-browser' import { NgbModule } from '@ng-bootstrap/ng-bootstrap' import { FontAwesomeModule } from '@fortawesome/angular-fontawesome' import { FormsModule } from '@angular/forms' -import { HasAnyAuthorityDirective } from '../shared/directive/has-any-authority.directive' +import { HasAnyAuthorityDirective } from '../shared/directive/has-any-authority.directive'; +import { UserDetailComponent } from './user-detail.component' @NgModule({ - declarations: [UsersComponent], + declarations: [UsersComponent, UserDetailComponent], imports: [CommonModule, SharedModule, RouterModule.forChild(routes), FontAwesomeModule, FormsModule], }) export class UserModule {} diff --git a/ui/src/app/user/user.route.ts b/ui/src/app/user/user.route.ts index c15f45b10..000b800ca 100644 --- a/ui/src/app/user/user.route.ts +++ b/ui/src/app/user/user.route.ts @@ -1,6 +1,26 @@ -import { Routes } from '@angular/router' +import { ActivatedRouteSnapshot, ResolveFn, RouterStateSnapshot, Routes } from '@angular/router' import { UsersComponent } from './users.component' import { AuthGuard } from '../account/auth.guard' +import { UserDetailComponent } from './user-detail.component' +import { EMPTY, Observable, filter, take } from 'rxjs' +import { User } from './model/user.model' +import { UserService } from './service/user.service' +import { Injectable, inject } from '@angular/core' + +export const UserResolver: ResolveFn = ( + route: ActivatedRouteSnapshot, + state: RouterStateSnapshot, + userService: UserService = inject(UserService) +): Observable => { + if (route.paramMap.get('id')) { + return userService.find(route.paramMap.get('id')!).pipe( + filter((user: User) => !!user), + take(1) + ) + } else { + return EMPTY + } +} export const routes: Routes = [ { @@ -10,6 +30,19 @@ export const routes: Routes = [ authorities: ['ROLE_ADMIN', 'ROLE_ORG_OWNER', 'ROLE_CONSORTIUM_LEAD'], defaultSort: 'id,asc', pageTitle: 'gatewayApp.msUserServiceMSUser.home.title.string', + ascending: true, + }, + canActivate: [AuthGuard], + }, + { + path: ':id/view', + component: UserDetailComponent, + resolve: { + user: UserResolver, + }, + data: { + authorities: ['ROLE_ADMIN', 'ROLE_ORG_OWNER', 'ROLE_CONSORTIUM_LEAD'], + pageTitle: 'gatewayApp.msUserServiceMSUser.home.title.string', }, canActivate: [AuthGuard], }, diff --git a/ui/src/app/user/users.component.html b/ui/src/app/user/users.component.html index e71091b66..084207c66 100644 --- a/ui/src/app/user/users.component.html +++ b/ui/src/app/user/users.component.html @@ -127,7 +127,7 @@

{{ user.email }} + {{ user.email }} {{ user.firstName }} {{ user.lastName }}