diff --git a/src/portal/src/app/base/left-side-nav/group/add-group-modal/add-group-modal.component.spec.ts b/src/portal/src/app/base/left-side-nav/group/add-group-modal/add-group-modal.component.spec.ts index 1c50479f2..e1877fe3a 100644 --- a/src/portal/src/app/base/left-side-nav/group/add-group-modal/add-group-modal.component.spec.ts +++ b/src/portal/src/app/base/left-side-nav/group/add-group-modal/add-group-modal.component.spec.ts @@ -1,14 +1,11 @@ import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing'; -import { ClarityModule } from '@clr/angular'; -import { TranslateModule } from '@ngx-translate/core'; -import { CUSTOM_ELEMENTS_SCHEMA, ChangeDetectorRef } from '@angular/core'; -import { FormsModule } from '@angular/forms'; -import { GroupService } from "../group.service"; +import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; import { MessageHandlerService } from "../../../../shared/services/message-handler.service"; import { SessionService } from "../../../../shared/services/session.service"; import { AppConfigService } from "../../../../services/app-config.service"; import { AddGroupModalComponent } from './add-group-modal.component'; -import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; +import { UsergroupService } from "../../../../../../ng-swagger-gen/services/usergroup.service"; +import { SharedTestingModule } from "../../../../shared/shared.module"; describe('AddGroupModalComponent', () => { let component: AddGroupModalComponent; @@ -36,20 +33,16 @@ describe('AddGroupModalComponent', () => { TestBed.configureTestingModule({ declarations: [AddGroupModalComponent], imports: [ - ClarityModule, - FormsModule, - BrowserAnimationsModule, - TranslateModule.forRoot() + SharedTestingModule ], schemas: [ CUSTOM_ELEMENTS_SCHEMA ], providers: [ - ChangeDetectorRef, { provide: MessageHandlerService, useValue: fakeMessageHandlerService }, { provide: SessionService, useValue: fakeSessionService }, { provide: AppConfigService, useValue: fakeAppConfigService }, - { provide: GroupService, useValue: fakeGroupService }, + { provide: UsergroupService, useValue: fakeGroupService }, ] }) .compileComponents(); diff --git a/src/portal/src/app/base/left-side-nav/group/add-group-modal/add-group-modal.component.ts b/src/portal/src/app/base/left-side-nav/group/add-group-modal/add-group-modal.component.ts index 8f4d4188a..d9e312df5 100644 --- a/src/portal/src/app/base/left-side-nav/group/add-group-modal/add-group-modal.component.ts +++ b/src/portal/src/app/base/left-side-nav/group/add-group-modal/add-group-modal.component.ts @@ -1,14 +1,12 @@ - import { finalize } from 'rxjs/operators'; -import { Subscription } from "rxjs"; -import { Component, OnInit, EventEmitter, Output, ChangeDetectorRef, OnDestroy, ViewChild } from "@angular/core"; +import { Component, OnInit, EventEmitter, Output, OnDestroy, ViewChild } from "@angular/core"; import { NgForm } from "@angular/forms"; -import { GroupService } from "../group.service"; import { MessageHandlerService } from "../../../../shared/services/message-handler.service"; import { SessionService } from "../../../../shared/services/session.service"; -import { UserGroup } from "../group"; import { AppConfigService } from "../../../../services/app-config.service"; import { GroupType } from "../../../../shared/entities/shared.const"; +import { UserGroup } from 'ng-swagger-gen/models/user-group'; +import { UsergroupService } from "../../../../../../ng-swagger-gen/services/usergroup.service"; @Component({ selector: "hbr-add-group-modal", @@ -21,9 +19,6 @@ export class AddGroupModalComponent implements OnInit, OnDestroy { dnTooltip = 'TOOLTIP.ITEM_REQUIRED'; group: UserGroup; - - formChangeSubscription: Subscription; - @ViewChild('groupForm', { static: true }) groupForm: NgForm; @@ -38,8 +33,7 @@ export class AddGroupModalComponent implements OnInit, OnDestroy { private session: SessionService, private msgHandler: MessageHandlerService, private appConfigService: AppConfigService, - private groupService: GroupService, - private cdr: ChangeDetectorRef + private groupService: UsergroupService, ) { } ngOnInit() { @@ -52,7 +46,9 @@ export class AddGroupModalComponent implements OnInit, OnDestroy { if (this.appConfigService.isOidcMode()) { this.isOidcMode = true; } - this.group = new UserGroup(this.isLdapMode ? GroupType.LDAP_TYPE : this.isHttpAuthMode ? GroupType.HTTP_TYPE : GroupType.OIDC_TYPE); + this.group = { + group_type: this.isLdapMode ? GroupType.LDAP_TYPE : this.isHttpAuthMode ? GroupType.HTTP_TYPE : GroupType.OIDC_TYPE + }; } @@ -88,8 +84,9 @@ export class AddGroupModalComponent implements OnInit, OnDestroy { createGroup() { let groupCopy = Object.assign({}, this.group); - this.groupService - .createGroup(groupCopy).pipe( + this.groupService.createUserGroup({ + usergroup: groupCopy + }).pipe( finalize(() => this.close())) .subscribe( res => { @@ -103,7 +100,10 @@ export class AddGroupModalComponent implements OnInit, OnDestroy { editGroup() { let groupCopy = Object.assign({}, this.group); this.groupService - .editGroup(groupCopy).pipe( + .updateUserGroup({ + groupId: groupCopy.id, + usergroup: groupCopy + }).pipe( finalize(() => this.close())) .subscribe( res => { @@ -115,7 +115,9 @@ export class AddGroupModalComponent implements OnInit, OnDestroy { } resetGroup() { - this.group = new UserGroup(this.isLdapMode ? GroupType.LDAP_TYPE : this.isHttpAuthMode ? GroupType.HTTP_TYPE : GroupType.OIDC_TYPE); + this.group = { + group_type: this.isLdapMode ? GroupType.LDAP_TYPE : this.isHttpAuthMode ? GroupType.HTTP_TYPE : GroupType.OIDC_TYPE + }; this.groupForm.reset(); } } diff --git a/src/portal/src/app/base/left-side-nav/group/group.component.html b/src/portal/src/app/base/left-side-nav/group/group.component.html index 5039a76a9..906604c01 100644 --- a/src/portal/src/app/base/left-side-nav/group/group.component.html +++ b/src/portal/src/app/base/left-side-nav/group/group.component.html @@ -1,4 +1,4 @@ -
+

{{'GROUP.GROUP' | translate}}

@@ -9,7 +9,7 @@
- + @@ -23,21 +23,22 @@ {{'GROUP.TYPE' | translate}} {{'GROUP.DN' | translate}} - + {{group.group_name}} {{groupToSring(group.group_type) | translate}} {{group.ldap_group_dn}} - - + + {{"PAGINATION.PAGE_SIZE" | translate}} + {{pagination.firstItem + 1}} - {{pagination.lastItem + 1}} {{'GROUP.OF' | translate}} - {{groups?.length}} {{'GROUP.ITEMS' | translate}} + {{totalCount}} {{'GROUP.ITEMS' | translate}}
- +
diff --git a/src/portal/src/app/base/left-side-nav/group/group.component.scss b/src/portal/src/app/base/left-side-nav/group/group.component.scss index 0d3b56629..13349265b 100644 --- a/src/portal/src/app/base/left-side-nav/group/group.component.scss +++ b/src/portal/src/app/base/left-side-nav/group/group.component.scss @@ -39,7 +39,9 @@ .rightPos { position: absolute; right: 20px; - margin-top: -7px; - height: 32px; + height:32px; z-index: 100; -} \ No newline at end of file +} +.relative { + position: relative; +} diff --git a/src/portal/src/app/base/left-side-nav/group/group.component.spec.ts b/src/portal/src/app/base/left-side-nav/group/group.component.spec.ts index dc907d3ca..0a4244cf5 100644 --- a/src/portal/src/app/base/left-side-nav/group/group.component.spec.ts +++ b/src/portal/src/app/base/left-side-nav/group/group.component.spec.ts @@ -1,16 +1,17 @@ import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing'; import { GroupComponent } from './group.component'; -import { ClarityModule } from '@clr/angular'; -import { TranslateModule, TranslateService } from '@ngx-translate/core'; -import { FormsModule } from '@angular/forms'; import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; import { SessionService } from "../../../shared/services/session.service"; -import { GroupService } from "./group.service"; import { of } from "rxjs"; import { MessageHandlerService } from '../../../shared/services/message-handler.service'; import { AppConfigService } from '../../../services/app-config.service'; import { OperationService } from "../../../shared/components/operation/operation.service"; import { ConfirmationDialogService } from "../../global-confirmation-dialog/confirmation-dialog.service"; +import { UsergroupService } from "../../../../../ng-swagger-gen/services/usergroup.service"; +import { SharedTestingModule } from "../../../shared/shared.module"; +import { HttpHeaders, HttpResponse } from "@angular/common/http"; +import { delay } from "rxjs/operators"; +import { UserGroup } from "../../../../../ng-swagger-gen/models/user-group"; describe('GroupComponent', () => { let component: GroupComponent; @@ -18,12 +19,16 @@ describe('GroupComponent', () => { let fakeMessageHandlerService = null; let fakeOperationService = null; let fakeGroupService = { - getUserGroups: function () { - return of([{ - group_name: '' - }, { - group_name: 'abc' - }]); + listUserGroupsResponse: function () { + const res: HttpResponse> = new HttpResponse>({ + headers: new HttpHeaders({'x-total-count': '3'}), + body: [{ + group_name: '' + }, { + group_name: 'abc' + }] + }); + return of(res).pipe(delay(0)); } }; let fakeConfirmationDialogService = { @@ -47,18 +52,15 @@ describe('GroupComponent', () => { TestBed.configureTestingModule({ declarations: [GroupComponent], imports: [ - ClarityModule, - FormsModule, - TranslateModule.forRoot() + SharedTestingModule ], schemas: [ CUSTOM_ELEMENTS_SCHEMA ], providers: [ - TranslateService, { provide: MessageHandlerService, useValue: fakeMessageHandlerService }, { provide: OperationService, useValue: fakeOperationService }, - { provide: GroupService, useValue: fakeGroupService }, + { provide: UsergroupService, useValue: fakeGroupService }, { provide: ConfirmationDialogService, useValue: fakeConfirmationDialogService }, { provide: SessionService, useValue: fakeSessionService }, { provide: AppConfigService, useValue: fakeAppConfigService } diff --git a/src/portal/src/app/base/left-side-nav/group/group.component.ts b/src/portal/src/app/base/left-side-nav/group/group.component.ts index fbfdbd5bb..a84b9a8ce 100644 --- a/src/portal/src/app/base/left-side-nav/group/group.component.ts +++ b/src/portal/src/app/base/left-side-nav/group/group.component.ts @@ -1,11 +1,9 @@ import { of, Subscription, forkJoin } from "rxjs"; -import { flatMap, catchError } from "rxjs/operators"; +import { flatMap, catchError, finalize, debounceTime, switchMap, filter } from "rxjs/operators"; import { SessionService } from "../../../shared/services/session.service"; import { TranslateService } from "@ngx-translate/core"; import { Component, OnInit, ViewChild, OnDestroy } from "@angular/core"; import { AddGroupModalComponent } from "./add-group-modal/add-group-modal.component"; -import { UserGroup } from "./group"; -import { GroupService } from "./group.service"; import { MessageHandlerService } from "../../../shared/services/message-handler.service"; import { throwError as observableThrowError } from "rxjs"; import { AppConfigService } from '../../../services/app-config.service'; @@ -20,6 +18,11 @@ import { import { ConfirmationDialogService } from "../../global-confirmation-dialog/confirmation-dialog.service"; import { errorHandler } from "../../../shared/units/shared.utils"; import { ConfirmationMessage } from "../../global-confirmation-dialog/confirmation-message"; +import { ClrDatagridStateInterface } from "@clr/angular"; +import { DEFAULT_PAGE_SIZE } from "../../../shared/units/utils"; +import { UsergroupService } from "../../../../../ng-swagger-gen/services/usergroup.service"; +import { UserGroup } from "../../../../../ng-swagger-gen/models/user-group"; +import { FilterComponent } from "../../../shared/components/filter/filter.component"; @Component({ selector: "app-group", @@ -27,25 +30,26 @@ import { ConfirmationMessage } from "../../global-confirmation-dialog/confirmati styleUrls: ["./group.component.scss"] }) export class GroupComponent implements OnInit, OnDestroy { - searchTerm = ""; loading = true; groups: UserGroup[] = []; - currentPage = 1; - totalCount = 0; + currentPage: number = 1; + totalCount: number = 0; + pageSize: number = DEFAULT_PAGE_SIZE; selectedGroups: UserGroup[] = []; currentTerm = ""; delSub: Subscription; batchOps = 'idle'; - batchInfos = new Map(); isLdapMode: boolean; @ViewChild(AddGroupModalComponent) newGroupModal: AddGroupModalComponent; - + searchSub: Subscription; + @ViewChild(FilterComponent, {static: true}) + filterComponent: FilterComponent; constructor( private operationService: OperationService, private translate: TranslateService, private operateDialogService: ConfirmationDialogService, - private groupService: GroupService, + private groupService: UsergroupService, private msgHandler: MessageHandlerService, private session: SessionService, private translateService: TranslateService, @@ -53,7 +57,6 @@ export class GroupComponent implements OnInit, OnDestroy { ) { } ngOnInit() { - this.loadData(); if (this.appConfigService.isLdapMode()) { this.isLdapMode = true; } @@ -70,25 +73,87 @@ export class GroupComponent implements OnInit, OnDestroy { } } ); + if (!this.searchSub) { + this.searchSub = this.filterComponent.filterTerms.pipe( + filter(groupName => !!groupName), + debounceTime(500), + switchMap(groupName => { + this.currentPage = 1; + this.selectedGroups = []; + this.loading = true; + return this.groupService.searchUserGroupsResponse({ + groupname: groupName, + pageSize: this.pageSize, + page: this.currentPage + }) + .pipe(finalize(() => { + this.loading = false; + })); + })).subscribe(response => { + this.totalCount = Number.parseInt( + response.headers.get('x-total-count'), 10 + ); + this.groups = response.body as UserGroup[]; + }, error => { + this.msgHandler.handleError(error); + }); + } } ngOnDestroy(): void { this.delSub.unsubscribe(); + if (this.searchSub) { + this.searchSub.unsubscribe(); + this.searchSub = null; + } } refresh(): void { + this.currentPage = 1; + this.selectedGroups = []; + this.currentTerm = ''; + this.filterComponent.currentValue = ''; this.loadData(); } - loadData(): void { + loadData(state?: ClrDatagridStateInterface): void { + if (state && state.page) { + this.pageSize = state.page.size; + } this.loading = true; - this.groupService.getUserGroups().subscribe(groups => { - this.groups = groups.filter(group => { - if (!group.group_name) { group.group_name = ''; } - return group.group_name.includes(this.searchTerm); - } - ); - this.loading = false; - }); + if (this.currentTerm) { + this.groupService.searchUserGroupsResponse({ + groupname: encodeURIComponent(this.currentTerm), + page: this.currentPage, + pageSize: this.pageSize + }) + .pipe(finalize(() => this.loading = false)) + .subscribe( + response => { + this.totalCount = Number.parseInt( + response.headers.get('x-total-count'), 10 + ); + this.groups = response.body as UserGroup[]; + }, + err => { + this.msgHandler.error(err); + }); + } else { + this.groupService.listUserGroupsResponse({ + page: this.currentPage, + pageSize: this.pageSize + }) + .pipe(finalize(() => this.loading = false)) + .subscribe( + response => { + this.totalCount = Number.parseInt( + response.headers.get('x-total-count'), 10 + ); + this.groups = response.body as UserGroup[]; + }, + err => { + this.msgHandler.error(err); + }); + } } addGroup(): void { @@ -130,7 +195,9 @@ export class GroupComponent implements OnInit, OnDestroy { this.operationService.publishInfo(operMessage); return this.groupService - .deleteGroup(group.id) + .deleteUserGroup({ + groupId: group.id + }) .pipe(flatMap(response => { return this.translate.get("BATCH.DELETED_SUCCESS").pipe(flatMap(res => { operateChanges(operMessage, OperationState.success); @@ -169,8 +236,10 @@ export class GroupComponent implements OnInit, OnDestroy { } doFilter(groupName: string): void { - this.searchTerm = groupName; - this.loadData(); + if (!groupName) { + this.currentTerm = groupName; + this.loadData(); + } } get canAddGroup(): boolean { return this.session.currentUser.has_admin_role; diff --git a/src/portal/src/app/base/left-side-nav/group/group.service.spec.ts b/src/portal/src/app/base/left-side-nav/group/group.service.spec.ts deleted file mode 100644 index d609acc67..000000000 --- a/src/portal/src/app/base/left-side-nav/group/group.service.spec.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { TestBed, inject } from '@angular/core/testing'; -import { HttpClientTestingModule } from '@angular/common/http/testing'; -import { GroupService } from './group.service'; - -describe('GroupService', () => { - beforeEach(() => { - TestBed.configureTestingModule({ - providers: [GroupService], - imports: [ - HttpClientTestingModule - ] - }); - }); - - it('should be created', inject([GroupService], (service: GroupService) => { - expect(service).toBeTruthy(); - })); -}); diff --git a/src/portal/src/app/base/left-side-nav/group/group.service.ts b/src/portal/src/app/base/left-side-nav/group/group.service.ts deleted file mode 100644 index 4d042473a..000000000 --- a/src/portal/src/app/base/left-side-nav/group/group.service.ts +++ /dev/null @@ -1,67 +0,0 @@ -import {throwError as observableThrowError, Observable} from "rxjs"; -import {catchError, map} from 'rxjs/operators'; -import { Injectable } from "@angular/core"; -import { HttpClient } from "@angular/common/http"; -import { UserGroup } from "./group"; -import { CURRENT_BASE_HREF, HTTP_GET_OPTIONS, HTTP_JSON_OPTIONS } from "../../../shared/units/utils"; - -const userGroupEndpoint = CURRENT_BASE_HREF + "/usergroups"; -const ldapGroupSearchEndpoint = CURRENT_BASE_HREF + "/ldap/groups/search?groupname="; - -@Injectable({ - providedIn: 'root', -}) -export class GroupService { - constructor(private http: HttpClient) {} - - private handleErrorObservable(error: Response | any) { - console.error(error.error || error); - return observableThrowError(error.error || error); - } - - getUserGroups(): Observable { - return this.http.get(userGroupEndpoint, HTTP_GET_OPTIONS).pipe( - map(response => { - return response || []; - }), - catchError(error => { - return this.handleErrorObservable(error); - }), ); - } - - createGroup(group: UserGroup): Observable { - return this.http - .post(userGroupEndpoint, group, HTTP_JSON_OPTIONS).pipe( - map(response => { - return response || []; - }), - catchError(this.handleErrorObservable), ); - } - - editGroup(group: UserGroup): Observable { - return this.http - .put(`${userGroupEndpoint}/${group.id}`, group, HTTP_JSON_OPTIONS).pipe( - map(response => { - return response || []; - }), - catchError(this.handleErrorObservable), ); - } - - deleteGroup(group_id: number): Observable { - return this.http - .delete(`${userGroupEndpoint}/${group_id}`).pipe( - map(response => { - return response || []; - }), - catchError(this.handleErrorObservable), ); - } - - searchGroup(group_name: string): Observable { - return this.http - .get(`${ldapGroupSearchEndpoint}${group_name}`, HTTP_GET_OPTIONS).pipe( - map(response => { - return response || []; - }), - catchError(this.handleErrorObservable), ); - } -} diff --git a/src/portal/src/app/base/left-side-nav/group/group.ts b/src/portal/src/app/base/left-side-nav/group/group.ts deleted file mode 100644 index 2c3e417ba..000000000 --- a/src/portal/src/app/base/left-side-nav/group/group.ts +++ /dev/null @@ -1,12 +0,0 @@ -export class UserGroup { - id?: number; - group_name?: string; - group_type: number; - ldap_group_dn?: string; - - constructor(groupType) { - { - this.group_type = groupType; - } - } -} diff --git a/src/portal/src/app/base/left-side-nav/user/user.component.html b/src/portal/src/app/base/left-side-nav/user/user.component.html index 41784d06f..5cef53c99 100644 --- a/src/portal/src/app/base/left-side-nav/user/user.component.html +++ b/src/portal/src/app/base/left-side-nav/user/user.component.html @@ -1,4 +1,4 @@ -
+

{{'SIDE_NAV.SYSTEM_MGMT.USER' | translate}}

diff --git a/src/portal/src/app/base/left-side-nav/user/user.component.scss b/src/portal/src/app/base/left-side-nav/user/user.component.scss index e1d94b136..c83c419b1 100644 --- a/src/portal/src/app/base/left-side-nav/user/user.component.scss +++ b/src/portal/src/app/base/left-side-nav/user/user.component.scss @@ -42,8 +42,6 @@ height:32px; z-index: 100; } -::ng-deep harbor-user{ - >div{ - position: relative; - } -} \ No newline at end of file +.relative { + position: relative; +}