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 }} |