Skip to content

Commit

Permalink
PRIME-2711 Able to manage Admin users (#2503)
Browse files Browse the repository at this point in the history
* initial commit

* bug fix

* bug fix

* add site and enrollee assignment count

* Fix PR issues

* more changes

* fix PR issue

* change icon

* fix pr issue

* fix PR issues

* disable switch if admin user does not have super_admin role

* Minor fixes

* Redo merge

* fix admin record creating issue

* initial commit

* bug fix

* bug fix

* add site and enrollee assignment count

* Fix PR issues

* more changes

* fix PR issue

* change icon

* fix pr issue

* fix PR issues

* Minor fixes

* disable switch if admin user does not have super_admin role

* Redo merge

* fix admin record creating issue

* fix PR issue

* fix PR issue

* Stronger data typing

---------

Co-authored-by: Alan Leung <[email protected]>
  • Loading branch information
bergomi02 and neophyte57 authored Aug 21, 2024
1 parent b84582c commit e7ec6dc
Show file tree
Hide file tree
Showing 32 changed files with 18,897 additions and 45 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ import { SiteOverviewPageComponent } from './pages/health-authorities/site-overv
import { SiteEventsPageComponent } from './pages/health-authorities/site-events-page/site-events-page.component';
import { SiteNotesPageComponent } from './pages/health-authorities/site-notes-page/site-notes-page.component';
import { SiteDocumentsPageComponent } from './pages/health-authorities/site-documents-page/site-documents-page.component';
import { AdminUsersPageComponent } from './pages/admin-users-page/admin-users-page.component';

const routes: Routes = [
{
Expand Down Expand Up @@ -410,6 +411,11 @@ const routes: Routes = [
}
]
},
{
path: AdjudicationRoutes.ADMIN_USERS,
component: AdminUsersPageComponent,
data: { title: 'Administrator User List' }
},
{
path: AdjudicationRoutes.METABASE_REPORTS,
component: MetabaseReportsComponent,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,9 @@ import { SiteOverviewPageComponent } from './pages/health-authorities/site-overv
import { SiteEventsPageComponent } from './pages/health-authorities/site-events-page/site-events-page.component';
import { SiteNotesPageComponent } from './pages/health-authorities/site-notes-page/site-notes-page.component';
import { SiteDocumentsPageComponent } from './pages/health-authorities/site-documents-page/site-documents-page.component';
import { AdminUsersContainerComponent } from './shared/components/admin-users-container/admin-users-container.component';
import { AdminUsersPageComponent } from './pages/admin-users-page/admin-users-page.component';
import { AdminUsersTableComponent } from './shared/components/admin-users-table/admin-users-table.component';

@NgModule({
declarations: [
Expand Down Expand Up @@ -157,7 +160,10 @@ import { SiteDocumentsPageComponent } from './pages/health-authorities/site-docu
SiteOverviewPageComponent,
SiteEventsPageComponent,
SiteNotesPageComponent,
SiteDocumentsPageComponent
SiteDocumentsPageComponent,
AdminUsersContainerComponent,
AdminUsersPageComponent,
AdminUsersTableComponent,
],
imports: [
AdjudicationRoutingModule,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ export class AdjudicationRoutes {

public static METABASE_REPORTS = 'metabase-reports';

public static ADMIN_USERS = "admin-users";

public static routePath(route: string): string {
return `/${AdjudicationRoutes.MODULE_PATH}/${route}`;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<app-admin-users-container>

<app-page-header>Admin Users</app-page-header>

</app-admin-users-container>
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing';
import { HttpClientTestingModule } from '@angular/common/http/testing';
import { RouterTestingModule } from '@angular/router/testing';

import { KeycloakService } from 'keycloak-angular';

import { APP_CONFIG, APP_DI_CONFIG } from 'app/app-config.module';
import { AdjudicationModule } from '@adjudication/adjudication.module';
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { AdminUsersPageComponent } from './admin-users-page.component';

describe('AdminUsersPageComponent', () => {
let component: AdminUsersPageComponent;
let fixture: ComponentFixture<AdminUsersPageComponent>;

beforeEach(waitForAsync(() => {
TestBed.configureTestingModule(
{
imports: [
HttpClientTestingModule,
RouterTestingModule,
AdjudicationModule
],
declarations: [],
providers: [
{
provide: APP_CONFIG,
useValue: APP_DI_CONFIG
},
KeycloakService
],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
}
).compileComponents();
}));

beforeEach(() => {
fixture = TestBed.createComponent(AdminUsersPageComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { Component, OnInit } from '@angular/core';

@Component({
selector: 'app-admin-users',
templateUrl: './admin-users-page.component.html',
styleUrls: ['./admin-users-page.component.scss']
})
export class AdminUsersPageComponent implements OnInit {
constructor() { }

public ngOnInit() { }
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export class AdjudicationDashboardComponent implements OnInit, IDashboard {
constructor(
@Inject(APP_CONFIG) protected config: AppConfig
) {
this.logoutRedirectUrl = `${ this.config.loginRedirectUrl }/${ AdjudicationRoutes.LOGIN_PAGE }`;
this.logoutRedirectUrl = `${this.config.loginRedirectUrl}/${AdjudicationRoutes.LOGIN_PAGE}`;
}

public ngOnInit(): void {
Expand All @@ -31,6 +31,7 @@ export class AdjudicationDashboardComponent implements OnInit, IDashboard {
return of([
new DashboardRouteMenuItem('PRIME Enrollees', AdjudicationRoutes.ENROLLEES, 'people'),
new DashboardRouteMenuItem('Site Registrations', AdjudicationRoutes.SITE_REGISTRATIONS, 'store'),
new DashboardRouteMenuItem('Admin Users', AdjudicationRoutes.ADMIN_USERS, 'admin_panel_settings'),
new DashboardRouteMenuItem('Metabase Reports', AdjudicationRoutes.METABASE_REPORTS, 'show_chart')
]);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<app-page [busy]="busy">

<ng-content select="app-page-header"></ng-content>

<ng-content select="app-page-subheader"></ng-content>

<app-admin-users-table></app-admin-users-table>

</app-page>
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing';
import { HttpClientTestingModule } from '@angular/common/http/testing';
import { RouterTestingModule } from '@angular/router/testing';

import { KeycloakService } from 'keycloak-angular';

import { APP_CONFIG, APP_DI_CONFIG } from 'app/app-config.module';
import { AdjudicationModule } from '@adjudication/adjudication.module';
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { AdminUsersContainerComponent } from './admin-users-container.component';

describe('AdminUsersContainerComponent', () => {
let component: AdminUsersContainerComponent;
let fixture: ComponentFixture<AdminUsersContainerComponent>;

beforeEach(waitForAsync(() => {
TestBed.configureTestingModule(
{
imports: [
HttpClientTestingModule,
RouterTestingModule,
AdjudicationModule
],
declarations: [],
providers: [
{
provide: APP_CONFIG,
useValue: APP_DI_CONFIG
},
KeycloakService
],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
}
).compileComponents();
}));

beforeEach(() => {
fixture = TestBed.createComponent(AdminUsersContainerComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Component, OnInit } from '@angular/core';
import { Subscription } from 'rxjs';

@Component({
selector: 'app-admin-users-container',
templateUrl: './admin-users-container.component.html',
styleUrls: ['./admin-users-container.component.scss']
})
export class AdminUsersContainerComponent implements OnInit {
public busy: Subscription;

constructor(
) {
}

ngOnInit(): void {
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<div class="row">
<div class="col">
<table mat-table
class="w-100"
[dataSource]="dataSource">

<ng-container matColumnDef="username">
<th mat-header-cell
*matHeaderCellDef> Username
</th>
<td mat-cell
*matCellDef="let row;"> {{ row.username }} </td>
</ng-container>

<ng-container matColumnDef="firstname">
<th mat-header-cell
*matHeaderCellDef> First Name
</th>
<td mat-cell
*matCellDef="let row;"> {{ row.firstName }} </td>
</ng-container>

<ng-container matColumnDef="lastname">
<th mat-header-cell
*matHeaderCellDef> Last Name
</th>
<td mat-cell
*matCellDef="let row;"> {{ row.lastName }} </td>
</ng-container>

<ng-container matColumnDef="siteassigned">
<th mat-header-cell
*matHeaderCellDef> Sites Assigned
</th>
<td mat-cell
*matCellDef="let row;"> {{ row.sitesAssigned }} </td>
</ng-container>

<ng-container matColumnDef="enrolleeassigned">
<th mat-header-cell
*matHeaderCellDef> Enrollees Assigned
</th>
<td mat-cell
*matCellDef="let row;"> {{ row.enrolleesAssigned }} </td>
</ng-container>

<ng-container matColumnDef="status">
<th mat-header-cell
*matHeaderCellDef> Status
</th>
<td mat-cell
*matCellDef="let row;">
<mat-slide-toggle color="primary"
(change)="toggleStatus(row.id, $event)"
[checked]="isEnabled(row.status)"
[disabled]="!(Role.SUPER_ADMIN | inRole)">
{{ isEnabled(row.status) ? 'Enabled' : 'Disabled' }}
</mat-slide-toggle>
</td>
</ng-container>

<tr mat-header-row
*matHeaderRowDef="displayColumns"></tr>
<tr mat-row
*matRowDef="let row; columns: displayColumns;">
</tr>
</table>
</div>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing';
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { ReactiveFormsModule } from '@angular/forms';
import { RouterTestingModule } from '@angular/router/testing';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';

import { KeycloakService } from 'keycloak-angular';

import { APP_CONFIG, APP_DI_CONFIG } from 'app/app-config.module';
import { NgxMaterialModule } from '@lib/modules/ngx-material/ngx-material.module';
import { PermissionService } from '@auth/shared/services/permission.service';
import { InRolePipe } from '@shared/pipes/in-role-pipe';
import { MockPermissionService } from 'test/mocks/mock-permission.service';
import { AdminUsersTableComponent } from './admin-users-table.component';
import { HttpClientTestingModule } from '@angular/common/http/testing';

describe('AdminUsersTableComponent', () => {
let component: AdminUsersTableComponent;
let fixture: ComponentFixture<AdminUsersTableComponent>;

beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
imports: [
RouterTestingModule,
ReactiveFormsModule,
NgxMaterialModule,
BrowserAnimationsModule,
HttpClientTestingModule
],
declarations: [
InRolePipe
],
providers: [
KeycloakService,
{
provide: APP_CONFIG,
useValue: APP_DI_CONFIG
},
{
provide: PermissionService,
useClass: MockPermissionService
}
],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
}).compileComponents();
}));

beforeEach(() => {
fixture = TestBed.createComponent(AdminUsersTableComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { AdjudicationResource } from '@adjudication/shared/services/adjudication-resource.service';
import { Component, OnInit } from '@angular/core';
import { MatSlideToggleChange } from '@angular/material/slide-toggle';
import { Admin, AdminUser } from '@auth/shared/models/admin.model';
import { AdminStatusType } from '@adjudication/shared/models/admin-status.enum';
import { Role } from '@auth/shared/enum/role.enum';

@Component({
selector: 'app-admin-users-table',
templateUrl: './admin-users-table.component.html',
styleUrls: ['./admin-users-table.component.scss']
})
export class AdminUsersTableComponent implements OnInit {

public dataSource: AdminUser[];
public displayColumns: string[] = ['username', 'firstname', 'lastname', 'siteassigned', 'enrolleeassigned', 'status'];
public AdminStatus: AdminStatusType;
public Role = Role;

constructor(
private adjudicationResource: AdjudicationResource,
) {
}

public toggleStatus(adminId: number, change: MatSlideToggleChange) {
if (change.checked) {
this.adjudicationResource.enableAdmin(adminId).subscribe((admin: Admin) => {
this.dataSource.find(admin => admin.id === adminId).status = admin.status;
});
} else {
this.adjudicationResource.disableAdmin(adminId).subscribe((admin: Admin) => {
this.dataSource.find(admin => admin.id === adminId).status = admin.status;
});
}
}

public ngOnInit(): void {
this.getAdjudicators();
}

private getAdjudicators(): void {
this.adjudicationResource.getAdminUsers()
.subscribe((adminUsers: AdminUser[]) => this.dataSource = adminUsers);
}

public isEnabled(status: number) {
return status === AdminStatusType.ENABLED;
}
}
Loading

0 comments on commit e7ec6dc

Please sign in to comment.