diff --git a/api/api-iam/iam-internal/src/main/config/dev-vitam/keystore_ihm-demo.p12 b/api/api-iam/iam-internal/src/main/config/dev-vitam/keystore_ihm-demo.p12 old mode 100755 new mode 100644 index 6307b111d22ae85d636ea1a7d9f2d1fd26727cdd..d7f10231ca9b52c255c9ab0964b3d6942b0998ad Binary files a/api/api-iam/iam-internal/src/main/config/dev-vitam/keystore_ihm-demo.p12 and b/api/api-iam/iam-internal/src/main/config/dev-vitam/keystore_ihm-demo.p12 differ diff --git a/api/api-iam/iam-internal/src/main/config/dev-vitam/truststore_ihm-demo.jks b/api/api-iam/iam-internal/src/main/config/dev-vitam/truststore_ihm-demo.jks old mode 100755 new mode 100644 index cc137286b97dfba8fa84a03aaed764c9c5b7e7dc..329e4dd7b6f7febbaec09d5fca8b459a01bb8295 Binary files a/api/api-iam/iam-internal/src/main/config/dev-vitam/truststore_ihm-demo.jks and b/api/api-iam/iam-internal/src/main/config/dev-vitam/truststore_ihm-demo.jks differ diff --git a/ui/ui-frontend-common/src/app/modules/index.ts b/ui/ui-frontend-common/src/app/modules/index.ts index d66849962534bc127adf2dc3370ae42f5e5fe7f4..8662db557fcc953475b95fd31e1b5d75db3ea1fa 100644 --- a/ui/ui-frontend-common/src/app/modules/index.ts +++ b/ui/ui-frontend-common/src/app/modules/index.ts @@ -88,6 +88,7 @@ export * from './components/role-toggle/index'; export * from './components/search-bar/index'; export * from './components/stepper/index'; export * from './components/table-filter/index'; +export * from './components/order-by-button/index'; export * from './directives/collapse/index'; export * from './directives/drag-and-drop/index'; diff --git a/ui/ui-frontend/projects/identity/src/app/core/api/group-api.service.ts b/ui/ui-frontend/projects/identity/src/app/core/api/group-api.service.ts index 6d7019cd32f2808ea0ce3a3f70efc8dd9f571edb..b686c941bbdff1d21423b98fed7ebf5cd90f605a 100644 --- a/ui/ui-frontend/projects/identity/src/app/core/api/group-api.service.ts +++ b/ui/ui-frontend/projects/identity/src/app/core/api/group-api.service.ts @@ -38,7 +38,7 @@ import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http'; import { Inject, Injectable } from '@angular/core'; import { Observable } from 'rxjs'; -import { BASE_URL, BaseHttpClient, Group, PageRequest, PaginatedResponse } from 'ui-frontend-common'; +import {BASE_URL, BaseHttpClient, Group, PageRequest, PaginatedResponse, SearchQuery} from 'ui-frontend-common'; @Injectable({ providedIn: 'root' @@ -77,4 +77,12 @@ export class GroupApiService extends BaseHttpClient<Group> { return super.patch(groupPartial, headers); } + getLevels(query?: SearchQuery, headers?: HttpHeaders): Observable<string[]> { + let params = new HttpParams(); + if (query) { + params = params.set('criteria', JSON.stringify(query)); + } + + return this.http.get<string[]>(this.apiUrl + '/levels', { params, headers }); + } } diff --git a/ui/ui-frontend/projects/identity/src/app/subrogation/subrogate-user/user-search/user-search.component.ts b/ui/ui-frontend/projects/identity/src/app/group/group-list/group-criteria-builder.util.ts similarity index 62% rename from ui/ui-frontend/projects/identity/src/app/subrogation/subrogate-user/user-search/user-search.component.ts rename to ui/ui-frontend/projects/identity/src/app/group/group-list/group-criteria-builder.util.ts index 6cf73450c280b1b7ce42d1d6e9e146d2a378d3cc..32a12e339cf477ca3cf97a23f2cfec58baa98478 100644 --- a/ui/ui-frontend/projects/identity/src/app/subrogation/subrogate-user/user-search/user-search.component.ts +++ b/ui/ui-frontend/projects/identity/src/app/group/group-list/group-criteria-builder.util.ts @@ -34,18 +34,41 @@ * The fact that you are presently reading this means that you have had * knowledge of the CeCILL-C license and that you accept its terms. */ -import { Component, OnInit } from '@angular/core'; +import { buildCriteriaFromFilters, Criterion, Operators, SearchQuery } from 'ui-frontend-common'; -@Component({ - selector: 'app-user-search', - templateUrl: './user-search.component.html', - styleUrls: ['./user-search.component.scss'] -}) -export class UserSearchComponent implements OnInit { +const GROUP_FILTER_CONVERTER: Readonly<{ [key: string]: (values: any[]) => Array<Criterion | SearchQuery> }> = { - constructor() { } + status: (statusList: string[]): Criterion[] => { + if (statusList.length === 0) { + return []; + } - ngOnInit() { + const mappedList: boolean[] = []; + statusList.forEach((status) => { + switch (status) { + case 'ENABLED': + mappedList.push(true); + break; + case 'DISABLED': + mappedList.push(false); + break; + } + }); + return [{ key: 'enabled', value: mappedList, operator: Operators.in }]; + }, + level: (levelList: string[]): Criterion[] => { + if (levelList.length === 0) { + return []; + } + + if (levelList.some((level) => level === null)) { + levelList.push(''); + } + + return [{ key: 'level', value: levelList, operator: Operators.in }]; } +}; +export function buildCriteriaFromGroupFilters(filterMap: { [key: string]: any[] }): Array<Criterion | SearchQuery> { + return buildCriteriaFromFilters(filterMap, GROUP_FILTER_CONVERTER); } diff --git a/ui/ui-frontend/projects/identity/src/app/group/group-list/group-list.component.html b/ui/ui-frontend/projects/identity/src/app/group/group-list/group-list.component.html index dc5600b097cc8c2aae45e5513ea4b06aa60e6860..3e6e799d3c9d7b885701ce7b3c5d7e4957f6ba76 100644 --- a/ui/ui-frontend/projects/identity/src/app/group/group-list/group-list.component.html +++ b/ui/ui-frontend/projects/identity/src/app/group/group-list/group-list.component.html @@ -5,11 +5,81 @@ > <thead> <tr> - <th><i class="vitamui-icon vitamui-icon-keys vitamui-row-icon"></i></th> - <th i18n="Group name@@profileGroupListHeaderName">Nom du groupe</th> - <th i18n="Group ID@@profileGroupListHeaderID">Identifiant</th> - <th i18n="Description@@profileGroupListHeaderDescription">Description</th> - <th i18n="Description@@profileGroupListHeaderLevel">Niveau</th> + <th> + <div class="vitamui-table-header"> + <button + class="vitamui-filter-button" + [vitamuiCommonTableFilter]="statusFilterTemplate" + > + <i class="material-icons vitamui-row-icon">filter_list</i> + </button> + + <ng-template #statusFilterTemplate> + <vitamui-common-table-filter [(filter)]="this.filterMap['status']" (filterChange)="onFilterChange('status', $event)"> + <vitamui-common-table-filter-option value="ENABLED"> + <div class="table-filter-icon" i18n="@@groupStatusEnabled"> + <i class="vitamui-icon vitamui-icon-user status-badge status-badge-green close"></i> + <span class="badge-state">Actif</span> + </div> + </vitamui-common-table-filter-option> + <vitamui-common-table-filter-option value="DISABLED"> + <div class="table-filter-icon" i18n="@@groupStatusDisabled"> + <i class="vitamui-icon vitamui-icon-user status-badge status-badge-grey close"></i> + <span class="badge-state">Désactivé</span> + </div> + </vitamui-common-table-filter-option> + </vitamui-common-table-filter> + </ng-template> + + <i class="vitamui-icon vitamui-icon-keys vitamui-row-icon"></i> + <vitamui-common-order-by-button orderByKey="status" [(orderBy)]="orderBy" [(direction)]="direction" + (orderChange)="emitOrderChange()"></vitamui-common-order-by-button> + </div> + </th> + <th> + <div class="vitamui-table-header"> + <span i18n="Group name@@profileGroupListHeaderName">Nom du groupe</span> + <vitamui-common-order-by-button orderByKey="name" [(orderBy)]="orderBy" [(direction)]="direction" + (orderChange)="emitOrderChange()"></vitamui-common-order-by-button> + </div> + </th> + <th> + <div class="vitamui-table-header"> + <span i18n="Group ID@@profileGroupListHeaderID">Identifiant</span> + <vitamui-common-order-by-button orderByKey="identifier" [(orderBy)]="orderBy" [(direction)]="direction" + (orderChange)="emitOrderChange()"></vitamui-common-order-by-button> + </div> + </th> + <th> + <div class="vitamui-table-header"> + <span i18n="Description@@profileGroupListHeaderDescription">Description</span> + <vitamui-common-order-by-button orderByKey="description" [(orderBy)]="orderBy" [(direction)]="direction" + (orderChange)="emitOrderChange()"></vitamui-common-order-by-button> + </div> + </th> + <th> + <div class="vitamui-table-header"> + <button class="vitamui-filter-button" [vitamuiCommonTableFilter]="levelFilterTemplate" + [class.active]="filterMap['level'] && filterMap['level'].length > 0" #levelFilterTrigger="vitamuiCommonTableFilter"> + <i class="material-icons vitamui-row-icon">filter_list</i> + </button> + + <ng-template #levelFilterTemplate> + <vitamui-common-table-filter-search + [(filter)]="filterMap['level']" + [options]="levelFilterOptions" + (filterChange)="onFilterChange('level', $event)" + (filterClose)="levelFilterTrigger?.close()" + emptyValueOption="-Niveau vide-" + i18n-emptyValueOption="@@groupsListLevelFilterEmpty" + ></vitamui-common-table-filter-search> + </ng-template> + + <span i18n="Description@@profileGroupListHeaderLevel">Niveau</span> + <vitamui-common-order-by-button orderByKey="level" [(orderBy)]="orderBy" [(direction)]="direction" + (orderChange)="emitOrderChange()"></vitamui-common-order-by-button> + </div> + </th> </tr> </thead> diff --git a/ui/ui-frontend/projects/identity/src/app/group/group-list/group-list.component.spec.ts b/ui/ui-frontend/projects/identity/src/app/group/group-list/group-list.component.spec.ts index 1f9b3436ad6f808e0042f0493c834a3de68f4b58..8d7103a9d5f8b9b41dcc6922865bbcd78e745735 100644 --- a/ui/ui-frontend/projects/identity/src/app/group/group-list/group-list.component.spec.ts +++ b/ui/ui-frontend/projects/identity/src/app/group/group-list/group-list.component.spec.ts @@ -43,9 +43,10 @@ import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; import { By } from '@angular/platform-browser'; import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { Router } from '@angular/router'; -import { of, Subject } from 'rxjs'; +import {of, Subject} from 'rxjs'; -import { Group } from 'ui-frontend-common'; +import {Group, TableFilterModule} from 'ui-frontend-common'; +import {OrderByButtonModule} from 'ui-frontend-common'; import { InfiniteScrollStubDirective, VitamUICommonTestModule } from 'ui-frontend-common/testing'; import { GroupService } from '../group.service'; import { GroupListComponent } from './group-list.component'; @@ -82,6 +83,7 @@ class Page { let page: Page; let groups: Group[]; +const levels: string[] = ['level1', 'level2']; describe('GroupListComponent', () => { @@ -116,7 +118,8 @@ describe('GroupListComponent', () => { search: () => of(groups), canLoadMore: true, loadMore: () => of(groups), - updated: new Subject() + updated: new Subject(), + getNonEmptyLevels: () => of(levels) }; const matDialogSpy = jasmine.createSpyObj('MatDialog', ['open']); const routerSpy = jasmine.createSpyObj('Router', ['navigate']); @@ -127,6 +130,8 @@ describe('GroupListComponent', () => { MatProgressSpinnerModule, NoopAnimationsModule, VitamUICommonTestModule, + TableFilterModule, + OrderByButtonModule ], declarations: [ GroupListComponent, @@ -145,6 +150,7 @@ describe('GroupListComponent', () => { const groupService = TestBed.get(GroupService); spyOn(groupService, 'search').and.callThrough(); spyOn(groupService, 'loadMore').and.callThrough(); + spyOn(groupService, 'getNonEmptyLevels').and.callFake(groupListServiceSpy.getNonEmptyLevels); })); diff --git a/ui/ui-frontend/projects/identity/src/app/group/group-list/group-list.component.ts b/ui/ui-frontend/projects/identity/src/app/group/group-list/group-list.component.ts index ec2a9a12e6c88c4f9dedeb2a39aa5cc4c0f5d592..1fafb74060adae2bdba3ef84b5e70da83e21c81c 100644 --- a/ui/ui-frontend/projects/identity/src/app/group/group-list/group-list.component.ts +++ b/ui/ui-frontend/projects/identity/src/app/group/group-list/group-list.component.ts @@ -35,11 +35,19 @@ * knowledge of the CeCILL-C license and that you accept its terms. */ import { animate, state, style, transition, trigger } from '@angular/animations'; -import { Component, EventEmitter, OnDestroy, OnInit, Output } from '@angular/core'; -import { Subscription } from 'rxjs'; +import {Component, EventEmitter, Inject, Input, LOCALE_ID, OnDestroy, OnInit, Output} from '@angular/core'; +import {merge, Subject, Subscription} from 'rxjs'; -import { Group, InfiniteScrollTable } from 'ui-frontend-common'; +import { + buildCriteriaFromSearch, + DEFAULT_PAGE_SIZE, Direction, + Group, + InfiniteScrollTable, + PageRequest, + SearchQuery +} from 'ui-frontend-common'; import { GroupService } from '../group.service'; +import {buildCriteriaFromGroupFilters} from './group-criteria-builder.util'; @Component({ selector: 'app-group-list', @@ -65,22 +73,89 @@ export class GroupListComponent extends InfiniteScrollTable<Group> implements On private updatedGroupSub: Subscription; - constructor(public groupService: GroupService) { + @Input('search') + set searchText(text: string) { + this._search = text; + this.searchChange.next(text); + } + // tslint:disable-next-line:variable-name + private _search: string; + private readonly searchKeys = [ + 'identifier', + 'name', + 'level', + 'description' + ]; + + filterMap: { [key: string]: any[] } = { + status: ['ENABLED'], + level: null + }; + + orderBy = 'name'; + direction = Direction.ASCENDANT; + + private readonly filterChange = new Subject<{ [key: string]: any[] }>(); + private readonly orderChange = new Subject<string>(); + private readonly searchChange = new Subject<string>(); + + levelFilterOptions: Array<{ value: string, label: string }> = []; + + constructor(public groupService: GroupService, + @Inject(LOCALE_ID) private locale: string) { super(groupService); } ngOnInit() { this.search(); + this.refreshLevelOptions(); + this.updatedGroupSub = this.groupService.updated.subscribe((updatedGroup: Group) => { const profileGroupIndex = this.dataSource.findIndex((group) => updatedGroup.id === group.id); if (profileGroupIndex > -1) { this.dataSource[profileGroupIndex] = updatedGroup; } + + }); + + const searchCriteriaChange = merge(this.searchChange, this.filterChange, this.orderChange); + + searchCriteriaChange.subscribe(() => { + const query: SearchQuery = { + criteria: [ + ...buildCriteriaFromGroupFilters(this.filterMap), + ...buildCriteriaFromSearch(this._search, this.searchKeys) + ] + }; + const pageRequest = new PageRequest(0, DEFAULT_PAGE_SIZE, this.orderBy, this.direction, JSON.stringify(query)); + + this.search(pageRequest); }); + + } + + onFilterChange(key: string, values: any[]) { + this.filterMap[key] = values; + this.filterChange.next(this.filterMap); + } + + emitOrderChange() { + this.orderChange.next(); } ngOnDestroy() { this.updatedGroupSub.unsubscribe(); } + private refreshLevelOptions(query?: SearchQuery) { + this.groupService.getNonEmptyLevels(query).subscribe((levels: string[]) => { + this.levelFilterOptions = levels.map((level: string) => ({value: level, label: level })); + this.levelFilterOptions.sort(sortByLabel(this.locale)); + }); + } +} + + +function sortByLabel(locale: string): (a: { label: string }, b: { label: string }) => number { + return (a: { label: string }, b: { label: string }) => a.label.localeCompare(b.label, locale); } diff --git a/ui/ui-frontend/projects/identity/src/app/group/group.component.html b/ui/ui-frontend/projects/identity/src/app/group/group.component.html index 289680d80e1ba2bdf67d3f37a0fab14d3f5eeade..5a74c50b8dac8b1c1ed61015a84bddef4bab9c67 100644 --- a/ui/ui-frontend/projects/identity/src/app/group/group.component.html +++ b/ui/ui-frontend/projects/identity/src/app/group/group.component.html @@ -16,10 +16,11 @@ </h2> <div class="controls"> - <div class="search disabled"> - <input type="search" placeholder="Nom du groupe" i18n-placeholder="Group name@@profileGroupSearchInputPlaceholder" disabled> - <button type="submit" class="btn-circle primary btn-search"><i class="material-icons">search</i></button> - </div> + <vitamui-common-search-bar + name="group-search" + (search)="onSearchSubmit($event)" + placeholder="Nom du groupe" i18n-placeholder="Group name@@profileGroupSearchInputPlaceholder" + ></vitamui-common-search-bar> <div class="actions"> <button class="btn secondary" (click)="openCreateGroupDialog()"> @@ -38,7 +39,7 @@ </div> <div class="vitamui-body vitamui-container"> - <app-group-list (groupClick)="openPanel($event)"></app-group-list> + <app-group-list [search]="search" (groupClick)="openPanel($event)"></app-group-list> </div> </mat-sidenav-content> diff --git a/ui/ui-frontend/projects/identity/src/app/group/group.component.spec.ts b/ui/ui-frontend/projects/identity/src/app/group/group.component.spec.ts index 628c73bc1309b2aaaa43316e7fb7480302652d04..ed1512d84da6e620bcfcf96469cb1f7d98ad48c6 100644 --- a/ui/ui-frontend/projects/identity/src/app/group/group.component.spec.ts +++ b/ui/ui-frontend/projects/identity/src/app/group/group.component.spec.ts @@ -36,11 +36,11 @@ */ /* tslint:disable:no-magic-numbers no-use-before-declare max-classes-per-file */ -import { Component, Input } from '@angular/core'; +import {Component, Input} from '@angular/core'; import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { ActivatedRoute } from '@angular/router'; import { EMPTY, of } from 'rxjs'; -import { ENVIRONMENT, Group, InjectorModule, LoggerModule } from 'ui-frontend-common'; +import {ENVIRONMENT, Group, InjectorModule, LoggerModule, SearchBarModule} from 'ui-frontend-common'; import { environment } from './../../environments/environment'; import { MatDialog } from '@angular/material/dialog'; @@ -65,6 +65,10 @@ let page: Page; @Component({ selector: 'app-group-list', template: '' }) class GroupListStubComponent { + + // tslint:disable-next-line:no-input-rename + @Input('search') searchText: string; + search() { } } @@ -87,6 +91,7 @@ describe('GroupComponent', () => { NoopAnimationsModule, VitamUICommonTestModule, InjectorModule, + SearchBarModule, LoggerModule.forRoot() ], declarations: [ diff --git a/ui/ui-frontend/projects/identity/src/app/group/group.component.ts b/ui/ui-frontend/projects/identity/src/app/group/group.component.ts index da6c9d2fb5499327fc1b642b305d4c4459f3f11a..143004144d33a66e363b188567646d068d7eb769 100644 --- a/ui/ui-frontend/projects/identity/src/app/group/group.component.ts +++ b/ui/ui-frontend/projects/identity/src/app/group/group.component.ts @@ -51,6 +51,8 @@ export class GroupComponent extends SidenavPage<Group> implements OnInit { groups: Group[]; + search: string; + @ViewChild(GroupListComponent, { static: true }) groupListComponent: GroupListComponent; constructor(public dialog: MatDialog, route: ActivatedRoute, globalEventService: GlobalEventService) { @@ -71,4 +73,9 @@ export class GroupComponent extends SidenavPage<Group> implements OnInit { if (!this.groupListComponent) { return; } this.groupListComponent.search(); } + + onSearchSubmit(search: string) { + this.search = search; + + } } diff --git a/ui/ui-frontend/projects/identity/src/app/group/group.service.ts b/ui/ui-frontend/projects/identity/src/app/group/group.service.ts index 3d4bbd923a55b4654e1b83a5dbbd3a4a980871bf..e91f87ddd6c3d4da6ed3195f758feb0417a44c84 100644 --- a/ui/ui-frontend/projects/identity/src/app/group/group.service.ts +++ b/ui/ui-frontend/projects/identity/src/app/group/group.service.ts @@ -35,7 +35,7 @@ * knowledge of the CeCILL-C license and that you accept its terms. */ import { Observable, Subject } from 'rxjs'; -import { tap } from 'rxjs/operators'; +import {map, tap} from 'rxjs/operators'; import { Criterion, Group, Operators, SearchQuery, SearchService } from 'ui-frontend-common'; import { HttpClient, HttpParams } from '@angular/common/http'; @@ -133,4 +133,11 @@ export class GroupService extends SearchService<Group> { return this.groupApi.getAllByParams(params); } + + getNonEmptyLevels(query: SearchQuery) { + return this.groupApi.getLevels(query) + .pipe( + map((levels) => levels.filter((l) => !!l)) + ); + } } diff --git a/ui/ui-frontend/projects/identity/src/app/subrogation/subrogate-user/subrogate-user-list/subrogate-user-list.component.ts b/ui/ui-frontend/projects/identity/src/app/subrogation/subrogate-user/subrogate-user-list/subrogate-user-list.component.ts index 17d44e134e68335be7b28ea392183293d4a78578..b3bf9dfabea2a718d4b3079a01e79b5c470a13b3 100644 --- a/ui/ui-frontend/projects/identity/src/app/subrogation/subrogate-user/subrogate-user-list/subrogate-user-list.component.ts +++ b/ui/ui-frontend/projects/identity/src/app/subrogation/subrogate-user/subrogate-user-list/subrogate-user-list.component.ts @@ -34,10 +34,10 @@ * The fact that you are presently reading this means that you have had * knowledge of the CeCILL-C license and that you accept its terms. */ -import { forkJoin, Observable } from 'rxjs'; +import { forkJoin, Observable, Subject } from 'rxjs'; import { - ApplicationId, AuthService, AuthUser, DEFAULT_PAGE_SIZE, Direction, Group, InfiniteScrollTable, - Operators, PageRequest, Profile, SearchQuery, SubrogationModalService, SubrogationUser + ApplicationId, AuthService, AuthUser, buildCriteriaFromSearch, Criterion, DEFAULT_PAGE_SIZE, Direction, + Group, InfiniteScrollTable, Operators, PageRequest, Profile, SearchQuery, SubrogationModalService, SubrogationUser } from 'ui-frontend-common'; import { Component, Input, OnDestroy, OnInit } from '@angular/core'; @@ -59,12 +59,32 @@ export class SubrogateUserListComponent extends InfiniteScrollTable<SubrogationU @Input() emailDomains: string[]; + // tslint:disable-next-line:no-input-rename + @Input('search') + set searchText(searchText: string) { + this._searchText = searchText; + this.searchChange.next(searchText); + } + // tslint:disable-next-line:variable-name + private _searchText: string; + private groups: Array<{id: string, group: any}> = []; overridePendingChange: true; loaded = false; customerId: string; currenteUser: AuthUser; + private readonly searchChange = new Subject<string>(); + private readonly searchKeys = [ + 'firstname', + 'lastname', + 'email', + 'mobile', + 'phone', + 'identifier' + ]; + + constructor( public subrogationService: SubrogationService, public dialog: MatDialog, @@ -76,12 +96,12 @@ export class SubrogateUserListComponent extends InfiniteScrollTable<SubrogationU } ngOnInit() { - // this.customerId = this.activatedRoute.snapshot.paramMap.get('customerId') + this.currenteUser = this.authService.user; this.refreshDataList(); this.activatedRoute.params.subscribe(() => this.refreshDataList()); - // When the list is reloaded, we retrieve the groups . + // when the list is reloaded, we retrieve the groups . this.updatedData.subscribe(() => { // get the groupId of every user @@ -98,7 +118,7 @@ export class SubrogateUserListComponent extends InfiniteScrollTable<SubrogationU if (observables && observables.length > 0) { // fetch remaining groups - forkJoin([forkJoin(observables), this.subrogationService.getAllByCustomerId(this.getCustomerId())]).subscribe((results) => { + forkJoin([forkJoin(observables), this.subrogationService.getAllByCustomerId(this._getCustomerId())]).subscribe((results) => { results[0].forEach((group) => { this.groups.push({ id: group.id, group }); }); @@ -129,38 +149,55 @@ export class SubrogateUserListComponent extends InfiniteScrollTable<SubrogationU this.pending = false; } }); + + this._onSearchChange(); } - ngOnDestroy() { - this.updatedData.unsubscribe(); + openUserSubrogationDialog(subrogateUser: SubrogationUser): void { + this.subrogationModalService.open(this.emailDomains, subrogateUser); + } + + getGroup(subrogateUser: SubrogationUser): any { + const subrogateUserGroup = this.groups.find((group) => group.id === subrogateUser.groupId); + + return subrogateUserGroup ? subrogateUserGroup.group : undefined; + } + + refreshDataList(): void { + this._search({ criteria: this._getCriterionArrayToCustomer() }); } - refreshDataList() { + private _getCriterionArrayToCustomer(): Array<Criterion> { const criterionArray = []; criterionArray.push({ key: 'customerId', - value: this.getCustomerId(), + value: this._getCustomerId(), operator: Operators.equals }); - - const query: SearchQuery = { criteria: criterionArray }; - - this.search(new PageRequest(0, DEFAULT_PAGE_SIZE, 'lastname', Direction.ASCENDANT, JSON.stringify(query))); + return criterionArray; } - openUserSubrogationDialog(subrogateUser: SubrogationUser) { - this.subrogationModalService.open(this.emailDomains, subrogateUser); - } + private _onSearchChange(): void { + this.searchChange.subscribe(() => { + const query: SearchQuery = { + criteria: [ + ...this._getCriterionArrayToCustomer(), + ...buildCriteriaFromSearch(this._searchText, this.searchKeys) + ] + }; - getGroup(subrogateUser: SubrogationUser) { - const subrogateUserGroup = this.groups.find((group) => group.id === subrogateUser.groupId); + this._search(query); + }); + } - return subrogateUserGroup ? subrogateUserGroup.group : undefined; + private _search(query: SearchQuery): void { + this.search(new PageRequest(0, DEFAULT_PAGE_SIZE, 'lastname', Direction.ASCENDANT, JSON.stringify(query))); } - getCustomerId(): string { + private _getCustomerId(): string { return this.activatedRoute.snapshot.paramMap.get('customerId'); } + private computeCriticality(profiles: Profile[]): number { let criticality = MINIMUM_CRITICALITY; for (const profile of profiles) { @@ -179,4 +216,9 @@ export class SubrogateUserListComponent extends InfiniteScrollTable<SubrogationU return criticality; } + + ngOnDestroy(): void { + this.updatedData.unsubscribe(); + } + } diff --git a/ui/ui-frontend/projects/identity/src/app/subrogation/subrogate-user/subrogate-user.component.html b/ui/ui-frontend/projects/identity/src/app/subrogation/subrogate-user/subrogate-user.component.html index 40cfe7fe32ceeaabcbf354f47ee326bedd3cb582..4f7fa164e145cccc84d5fbeeb828ce81cfe8dca8 100644 --- a/ui/ui-frontend/projects/identity/src/app/subrogation/subrogate-user/subrogate-user.component.html +++ b/ui/ui-frontend/projects/identity/src/app/subrogation/subrogate-user/subrogate-user.component.html @@ -7,7 +7,11 @@ </h2> <div class="controls"> - <app-user-search></app-user-search> + <vitamui-common-search-bar + name="user-search" + (search)="onSearchSubmit($event)" + i18n-placeholder="subrogation profileSearch@@SearchSubrogationProfile" placeholder="Saisissez le nom du profil de subrogation"> + </vitamui-common-search-bar> <div class="actions"> <button class="btn secondary" (click)="openUserSubrogationDialog()"> @@ -26,6 +30,6 @@ </div> <div class="vitamui-body vitamui-container"> - <app-subrogate-user-list [emailDomains]="customer?.emailDomains"></app-subrogate-user-list> + <app-subrogate-user-list [search]="search" [emailDomains]="customer?.emailDomains"></app-subrogate-user-list> </div> diff --git a/ui/ui-frontend/projects/identity/src/app/subrogation/subrogate-user/subrogate-user.component.ts b/ui/ui-frontend/projects/identity/src/app/subrogation/subrogate-user/subrogate-user.component.ts index 25766bf8a763d3a2c009f23b799fac45804248e3..253d3cdfdf5712ada38e2ad4c2e1e3ca38967209 100644 --- a/ui/ui-frontend/projects/identity/src/app/subrogation/subrogate-user/subrogate-user.component.ts +++ b/ui/ui-frontend/projects/identity/src/app/subrogation/subrogate-user/subrogate-user.component.ts @@ -52,6 +52,7 @@ export class SubrogateUserComponent extends AppRootComponent implements OnInit { customer: Customer; customers: MenuOption[]; + search: string; constructor( public dialog: MatDialog, @@ -87,4 +88,8 @@ export class SubrogateUserComponent extends AppRootComponent implements OnInit { this.router.navigate(['..', customerId], { relativeTo: this.route }); } + onSearchSubmit(search: string) { + this.search = search; + } + } diff --git a/ui/ui-frontend/projects/identity/src/app/subrogation/subrogate-user/user-search/user-search.component.html b/ui/ui-frontend/projects/identity/src/app/subrogation/subrogate-user/user-search/user-search.component.html deleted file mode 100644 index b21cddba4d8a63550f25455dae61813e7e77fea0..0000000000000000000000000000000000000000 --- a/ui/ui-frontend/projects/identity/src/app/subrogation/subrogate-user/user-search/user-search.component.html +++ /dev/null @@ -1,13 +0,0 @@ -<div class="search-result"> - <!-- <a *ngFor="let option of options | async" class="search-result-item"> - <i class="material-icons search-result-icon">help</i> <span [innerHTML]="option.label | strongify:search.value"></span> <i class="material-icons search-result-arrow">keyboard_arrow_right</i> - </a> --> -</div> - -<div class="search-control"> - <input - type="search" - i18n-placeholder="subrogation profileSearch@@SearchSubrogationProfile" placeholder="Saisissez le nom du profil de subrogation" - > - <i class="material-icons">search</i> -</div> diff --git a/ui/ui-frontend/projects/identity/src/app/subrogation/subrogate-user/user-search/user-search.component.scss b/ui/ui-frontend/projects/identity/src/app/subrogation/subrogate-user/user-search/user-search.component.scss deleted file mode 100644 index 1ae9c1820a20114c4c2c717fd755ac715922edbb..0000000000000000000000000000000000000000 --- a/ui/ui-frontend/projects/identity/src/app/subrogation/subrogate-user/user-search/user-search.component.scss +++ /dev/null @@ -1,87 +0,0 @@ -@import '~ui-frontend-common/sass/variables/colors'; - -$input-height: 70px; - -:host { - display: block; - position: relative; - width: 763px; -} - -.search-result { - position: absolute; - top: $input-height * 0.5; - left: 20px; - padding: $input-height * 0.5 30px 0 30px; - background: white; - border-radius: 0 0 10px 10px; - box-shadow: 0 0 20px 0 rgba(171, 169, 169, 0.3); - - &:not(.show) { - display: none; - } - - .search-result-item { - cursor: pointer; - text-decoration: none; - padding: 20px 0; - display: flex; - align-items: center; - color: #808080; - - ::ng-deep strong { - color: $charcoal-grey; - } - - .search-result-icon { - margin-right: 20px; - } - - &:not(:last-child) { - border-bottom: 1px solid #e5e5e5; - } - - .search-result-arrow { - color: $white-four; - margin-left: 5px; - font-size: 16px; - } - } -} - -.search-control { - position: relative; - - input[type=search] { - border: none; - width: 100%; - height: $input-height; - border-radius: $input-height / 2; - background-color: $white; - box-shadow: 0 0 20px 0 rgba(171, 169, 169, 0.3); - border: none; - padding: 10px $input-height 10px 36px; - display: flex; - outline: none; - font-size: 18px; - - &::placeholder { - color: $greyish-two; - font-weight: normal; - } - } - - i { - position: absolute; - top: 10px; - right: 10px; - width: $input-height - 20px; - height: $input-height - 20px; - border-radius: 50%; - background-color: var(--vitamui-primary); - color: $white; - line-height: $input-height - 20px; - text-align: center; - font-size: $input-height * 0.4; - } -} diff --git a/ui/ui-frontend/projects/identity/src/app/subrogation/subrogate-user/user-search/user-search.component.spec.ts b/ui/ui-frontend/projects/identity/src/app/subrogation/subrogate-user/user-search/user-search.component.spec.ts deleted file mode 100644 index 531e2189bdd4bc4136987b25b118e9f88585b64c..0000000000000000000000000000000000000000 --- a/ui/ui-frontend/projects/identity/src/app/subrogation/subrogate-user/user-search/user-search.component.spec.ts +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright French Prime minister Office/SGMAP/DINSIC/Vitam Program (2019-2020) - * and the signatories of the "VITAM - Accord du Contributeur" agreement. - * - * contact@programmevitam.fr - * - * This software is a computer program whose purpose is to implement - * implement a digital archiving front-office system for the secure and - * efficient high volumetry VITAM solution. - * - * This software is governed by the CeCILL-C license under French law and - * abiding by the rules of distribution of free software. You can use, - * modify and/ or redistribute the software under the terms of the CeCILL-C - * license as circulated by CEA, CNRS and INRIA at the following URL - * "http://www.cecill.info". - * - * As a counterpart to the access to the source code and rights to copy, - * modify and redistribute granted by the license, users are provided only - * with a limited warranty and the software's author, the holder of the - * economic rights, and the successive licensors have only limited - * liability. - * - * In this respect, the user's attention is drawn to the risks associated - * with loading, using, modifying and/or developing or reproducing the - * software by the user in light of its specific status of free software, - * that may mean that it is complicated to manipulate, and that also - * therefore means that it is reserved for developers and experienced - * professionals having in-depth computer knowledge. Users are therefore - * encouraged to load and test the software's suitability as regards their - * requirements in conditions enabling the security of their systems and/or - * data to be ensured and, more generally, to use and operate it in the - * same conditions as regards security. - * - * The fact that you are presently reading this means that you have had - * knowledge of the CeCILL-C license and that you accept its terms. - */ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; - -import { UserSearchComponent } from './user-search.component'; - -describe('UserSearchComponent', () => { - // let component: UserSearchComponent; - let fixture: ComponentFixture<UserSearchComponent>; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ UserSearchComponent ] - }) - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(UserSearchComponent); - // component = fixture.componentInstance; - fixture.detectChanges(); - }); - - // it('should create', () => { - // expect(component).toBeTruthy(); - // }); -}); diff --git a/ui/ui-frontend/projects/identity/src/app/subrogation/subrogation.module.ts b/ui/ui-frontend/projects/identity/src/app/subrogation/subrogation.module.ts index 26d3c4a8b8f1ecf6dc68fb75b806cbe850fa309c..9d8f2d7db5c73a1120e0b35ead8598790fa068c2 100644 --- a/ui/ui-frontend/projects/identity/src/app/subrogation/subrogation.module.ts +++ b/ui/ui-frontend/projects/identity/src/app/subrogation/subrogation.module.ts @@ -47,7 +47,6 @@ import { VitamUICommonModule } from 'ui-frontend-common'; import { SharedModule } from '../shared/shared.module'; import { SubrogateUserListComponent } from './subrogate-user/subrogate-user-list/subrogate-user-list.component'; import { SubrogateUserComponent } from './subrogate-user/subrogate-user.component'; -import { UserSearchComponent } from './subrogate-user/user-search/user-search.component'; import { SubrogationResolver } from './subrogation-resolver.service'; import { SubrogationRoutingModule } from './subrogation-routing.module'; import { SubrogationService } from './subrogation.service'; @@ -67,8 +66,7 @@ import { SubrogationService } from './subrogation.service'; ], declarations: [ SubrogateUserListComponent, - SubrogateUserComponent, - UserSearchComponent, + SubrogateUserComponent ], providers: [ SubrogationResolver, diff --git a/ui/ui-frontend/projects/identity/src/app/user/user-list/user-list.component.ts b/ui/ui-frontend/projects/identity/src/app/user/user-list/user-list.component.ts index 5e18ca33153a9c909b63927a38af1dd74db2403b..416d835d79252e401a7acd8141df593dc5f2ea81 100644 --- a/ui/ui-frontend/projects/identity/src/app/user/user-list/user-list.component.ts +++ b/ui/ui-frontend/projects/identity/src/app/user/user-list/user-list.component.ts @@ -139,7 +139,7 @@ export class UserListComponent extends InfiniteScrollTable<User> implements OnDe } ngOnInit() { - this.search(new PageRequest(0, DEFAULT_PAGE_SIZE, 'lastname', Direction.ASCENDANT)); + this.search(new PageRequest(0, DEFAULT_PAGE_SIZE, this.orderBy, Direction.ASCENDANT)); this.refreshLevelOptions(); this.updatedUserSub = this.userService.userUpdated.subscribe((updatedUser: User) => { diff --git a/ui/ui-frontend/projects/identity/src/app/user/user.component.ts b/ui/ui-frontend/projects/identity/src/app/user/user.component.ts index 07bd0febe6f3aef4db98497a59e34a677ebd5a77..2b8563d2733d5cdfb68c36e1330ac82bad71793b 100644 --- a/ui/ui-frontend/projects/identity/src/app/user/user.component.ts +++ b/ui/ui-frontend/projects/identity/src/app/user/user.component.ts @@ -56,7 +56,6 @@ export class UserComponent extends SidenavPage<User> implements OnInit { connectedUserInfo: AdminUserProfile; customer: Customer; search: string; - searchText: string; @ViewChild(UserListComponent, { static: true }) userListComponent: UserListComponent;