Skip to content

Commit f85647d

Browse files
authored
Merge pull request #342 from ngageoint/feature/mage-1686
Add Filter Functionality Back to User List
2 parents 16a9260 + b76072c commit f85647d

File tree

4 files changed

+160
-22
lines changed

4 files changed

+160
-22
lines changed

web-app/admin/src/app/admin/admin-users/dashboard/user-dashboard.component.html

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,27 @@ <h2 class="page-title">Users</h2>
99
<div
1010
class="integrated-navbar d-flex align-items-center justify-content-between"
1111
>
12-
<mage-card-navbar
13-
[isSearchable]="true"
14-
[searchPlaceholder]="'Search users...'"
15-
(searchTermChanged)="onSearchTermChanged($event)"
16-
(searchCleared)="onSearchCleared()"
17-
></mage-card-navbar>
12+
<div class="filters">
13+
<mage-card-navbar
14+
[isSearchable]="true"
15+
[searchPlaceholder]="'Search users...'"
16+
(searchTermChanged)="onSearchTermChanged($event)"
17+
(searchCleared)="onSearchCleared()"
18+
></mage-card-navbar>
19+
20+
<mat-form-field appearance="outline" class="ml-3 status-filter">
21+
<mat-label>Status</mat-label>
22+
<mat-select
23+
[(value)]="userStatusFilter"
24+
(selectionChange)="onStatusFilterChange($event.value)"
25+
>
26+
<mat-option value="all">All</mat-option>
27+
<mat-option value="active">Active</mat-option>
28+
<mat-option value="inactive">Inactive</mat-option>
29+
<mat-option value="disabled">Disabled</mat-option>
30+
</mat-select>
31+
</mat-form-field>
32+
</div>
1833

1934
<div class="button-group">
2035
<button

web-app/admin/src/app/admin/admin-users/dashboard/user-dashboard.component.scss

Lines changed: 41 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ $max-height: 72.8vh;
8686
flex-wrap: wrap;
8787
padding: 1rem 1.5rem;
8888
border-bottom: 2px solid #e5e7eb;
89+
height: 85px;
8990

9091
mage-card-navbar {
9192
flex: 1;
@@ -146,49 +147,49 @@ $max-height: 72.8vh;
146147
.table-scroll {
147148
height: 65.2vh;
148149
@media (max-width: 768px) {
149-
height: 63.2vh
150+
height: 63.2vh;
150151
}
151152
overflow-y: auto;
152153
max-height: 100%;
153154

154155
@media (max-height: 1100px) {
155156
height: 62vh;
156157
@media (max-width: 768px) {
157-
height: 60vh
158+
height: 60vh;
158159
}
159160
}
160161

161162
@media (max-height: 1000px) {
162163
height: 57vh;
163164
@media (max-width: 768px) {
164-
height: 55vh
165+
height: 55vh;
165166
}
166167
}
167168

168169
@media (max-height: 900px) {
169170
height: 52vh;
170171
@media (max-width: 768px) {
171-
height: 50vh
172+
height: 50vh;
172173
}
173174
}
174175

175176
@media (max-height: 800px) {
176177
height: 45vh;
177178
@media (max-width: 768px) {
178-
height: 43vh
179+
height: 43vh;
179180
}
180181
}
181182

182183
@media (max-height: 700px) {
183184
height: 35vh;
184185
@media (max-width: 768px) {
185-
height: 33vh
186+
height: 33vh;
186187
}
187188
}
188189
@media (max-height: 600px) {
189190
height: 23vh;
190191
@media (max-width: 768px) {
191-
height: 21vh
192+
height: 21vh;
192193
}
193194
}
194195

@@ -396,12 +397,44 @@ $max-height: 72.8vh;
396397
}
397398

398399
.button-group {
400+
margin-top: -20px;;
399401
button {
402+
height: 43px;
400403
white-space: nowrap;
401404
}
402405

403406
button:not(:last-child) {
404407
margin-right: 40px;
405-
margin-top: 10px;
406408
}
407409
}
410+
411+
.filters {
412+
margin-top: -10px;
413+
align-items: center !important;
414+
display: flex !important;
415+
}
416+
417+
:host {
418+
.status-filter {
419+
width: 150px;
420+
margin-left: 1rem;
421+
margin-top: 10px;
422+
font-size: 14px;
423+
424+
::ng-deep .mat-form-field-appearance-outline .mat-form-field-infix {
425+
padding: 10px;
426+
}
427+
::ng-deep .mat-form-field-infix {
428+
padding: 10px;
429+
}
430+
431+
::ng-deep .mat-form-field-label-wrapper {
432+
top: -12px;
433+
left: -7px;
434+
}
435+
}
436+
::ng-deep input.search-input.ng-untouched.ng-pristine.ng-valid {
437+
height: 43px;
438+
margin-top: -10px;
439+
}
440+
}

web-app/admin/src/app/admin/admin-users/dashboard/user-dashboard.component.spec.ts

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ describe('UserDashboardComponent', () => {
132132
MatCardModule,
133133
MatProgressSpinnerModule,
134134
MatDividerModule,
135-
MatListModule,
135+
MatListModule
136136
],
137137
declarations: [UserDashboardComponent],
138138
providers: [
@@ -229,4 +229,56 @@ describe('UserDashboardComponent', () => {
229229
userId: '1'
230230
});
231231
});
232+
233+
it('should set userStatusFilter and refresh users when filter changes', fakeAsync(() => {
234+
spyOn(component, 'refreshUsers').and.callThrough();
235+
236+
component.onStatusFilterChange('active');
237+
expect(component.userStatusFilter).toBe('active');
238+
expect(component.pageIndex).toBe(0);
239+
expect(component.refreshUsers).toHaveBeenCalled();
240+
flush();
241+
}));
242+
243+
it('should apply "active" filter in refreshUsers()', fakeAsync(() => {
244+
component.userStatusFilter = 'active';
245+
component.refreshUsers();
246+
tick();
247+
248+
const state = component.stateAndData['all'];
249+
expect(state.userFilter.active).toBeTrue();
250+
expect(pagingServiceSpy.refresh).toHaveBeenCalled();
251+
flush();
252+
}));
253+
254+
it('should apply "inactive" filter in refreshUsers()', fakeAsync(() => {
255+
component.userStatusFilter = 'inactive';
256+
component.refreshUsers();
257+
tick();
258+
259+
const state = component.stateAndData['all'];
260+
expect(state.userFilter.active).toBeFalse();
261+
flush();
262+
}));
263+
264+
it('should apply "disabled" filter in refreshUsers()', fakeAsync(() => {
265+
component.userStatusFilter = 'disabled';
266+
component.refreshUsers();
267+
tick();
268+
269+
const state = component.stateAndData['all'];
270+
expect(state.userFilter.enabled).toBeFalse();
271+
flush();
272+
}));
273+
274+
it('should clear filters for "all" option in refreshUsers()', fakeAsync(() => {
275+
component.userStatusFilter = 'all';
276+
component.refreshUsers();
277+
tick();
278+
279+
const state = component.stateAndData['all'];
280+
expect(state.userFilter.active).toBeUndefined();
281+
expect(state.userFilter.disabled).toBeUndefined();
282+
flush();
283+
}));
232284
});

web-app/admin/src/app/admin/admin-users/dashboard/user-dashboard.component.ts

Lines changed: 45 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,13 @@ import { Team } from '../../admin-teams/team';
1818
import pLimit from 'p-limit';
1919
import { AdminBreadcrumb } from '../../admin-breadcrumb/admin-breadcrumb.model';
2020

21+
type UserFilter = {
22+
limit?: number;
23+
page?: number;
24+
enabled?: boolean;
25+
active?: boolean;
26+
};
27+
2128
@Component({
2229
selector: 'admin-users',
2330
templateUrl: './user-dashboard.component.html',
@@ -55,10 +62,14 @@ export class UserDashboardComponent implements OnInit {
5562
isFinalizing = false;
5663
isFinished = false;
5764

58-
breadcrumbs: AdminBreadcrumb[] = [{
59-
title: 'Users',
60-
iconClass: 'fa fa-user'
61-
}]
65+
breadcrumbs: AdminBreadcrumb[] = [
66+
{
67+
title: 'Users',
68+
iconClass: 'fa fa-user'
69+
}
70+
];
71+
72+
userStatusFilter: 'all' | 'active' | 'inactive' | 'disabled' = 'all';
6273

6374
/**
6475
* Constructs the UserDashboardComponent with necessary services.
@@ -141,6 +152,25 @@ export class UserDashboardComponent implements OnInit {
141152
});
142153
}
143154

155+
getFilter(): UserFilter {
156+
const filterObject: UserFilter = {};
157+
158+
filterObject.limit = this.pageSize;
159+
filterObject.page = this.pageIndex;
160+
if (this.userStatusFilter === 'all') return filterObject;
161+
162+
if (this.userStatusFilter === 'disabled') {
163+
filterObject.active = true;
164+
filterObject.enabled = false;
165+
} else if (this.userStatusFilter === 'active') {
166+
filterObject.active = true;
167+
} else {
168+
filterObject.active = false;
169+
}
170+
171+
return filterObject;
172+
}
173+
144174
/**
145175
* Refreshes the paginated list of users.
146176
*/
@@ -150,9 +180,7 @@ export class UserDashboardComponent implements OnInit {
150180
state.pageSize = this.pageSize;
151181
state.pageIndex = this.pageIndex;
152182

153-
state.userFilter = state.userFilter || {};
154-
state.userFilter.limit = this.pageSize;
155-
state.userFilter.page = this.pageIndex;
183+
state.userFilter = this.getFilter();
156184

157185
return this.userPagingService.refresh(this.stateAndData).then(() => {
158186
const users = this.userPagingService.users(state);
@@ -183,6 +211,8 @@ export class UserDashboardComponent implements OnInit {
183211
* Executes a search query on the user list.
184212
*/
185213
search(): void {
214+
this.stateAndData['all'].userFilter.active = this.getFilter();
215+
186216
this.userPagingService
187217
.search(this.stateAndData['all'], this.userSearch)
188218
.then((users) => {
@@ -314,6 +344,14 @@ export class UserDashboardComponent implements OnInit {
314344
});
315345
}
316346

347+
onStatusFilterChange(
348+
value: 'all' | 'active' | 'inactive' | 'disabled'
349+
): void {
350+
this.userStatusFilter = value;
351+
this.pageIndex = 0;
352+
this.refreshUsers();
353+
}
354+
317355
/**
318356
* Creates users in bulk via the user service.
319357
* @param users Array of user data to create

0 commit comments

Comments
 (0)