From ec828c8745637e7cc51ea4cb3a1717f0588f0f1a Mon Sep 17 00:00:00 2001 From: Martin Stockhammer Date: Mon, 9 Nov 2020 00:35:36 +0100 Subject: [PATCH] Components for new angular app --- .../main/archiva-web/src/app/app.module.ts | 4 + .../src/app/model/entity-service.ts | 2 +- .../archiva-web/src/app/model/field-toggle.ts | 21 ++ .../paginated-entities.component.ts | 218 +++++++++++------- .../sorted-table-header-row.component.html | 19 ++ .../sorted-table-header-row.component.scss | 18 ++ .../sorted-table-header-row.component.spec.ts | 43 ++++ .../sorted-table-header-row.component.ts | 79 +++++++ .../sorted-table-header.component.html | 24 ++ .../sorted-table-header.component.scss | 18 ++ .../sorted-table-header.component.spec.ts | 43 ++++ .../sorted-table-header.component.ts | 90 ++++++++ .../manage-users-list.component.html | 22 +- .../manage-users-list.component.ts | 26 ++- .../src/app/services/user.service.ts | 7 +- 15 files changed, 540 insertions(+), 94 deletions(-) create mode 100644 archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/model/field-toggle.ts create mode 100644 archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/sorted-table-header-row/sorted-table-header-row.component.html create mode 100644 archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/sorted-table-header-row/sorted-table-header-row.component.scss create mode 100644 archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/sorted-table-header-row/sorted-table-header-row.component.spec.ts create mode 100644 archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/sorted-table-header-row/sorted-table-header-row.component.ts create mode 100644 archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/sorted-table-header/sorted-table-header.component.html create mode 100644 archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/sorted-table-header/sorted-table-header.component.scss create mode 100644 archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/sorted-table-header/sorted-table-header.component.spec.ts create mode 100644 archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/sorted-table-header/sorted-table-header.component.ts diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/app.module.ts b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/app.module.ts index 9e351627c..f3ddcc7f9 100644 --- a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/app.module.ts +++ b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/app.module.ts @@ -43,6 +43,8 @@ import { ManageUsersListComponent } from './modules/user/users/manage-users-list import { ManageUsersAddComponent } from './modules/user/users/manage-users-add/manage-users-add.component'; import { NgbPaginationModule, NgbTooltipModule} from "@ng-bootstrap/ng-bootstrap"; import { PaginatedEntitiesComponent } from './modules/general/paginated-entities/paginated-entities.component'; +import { SortedTableHeaderComponent } from './modules/general/sorted-table-header/sorted-table-header.component'; +import { SortedTableHeaderRowComponent } from './modules/general/sorted-table-header-row/sorted-table-header-row.component'; @NgModule({ @@ -65,6 +67,8 @@ import { PaginatedEntitiesComponent } from './modules/general/paginated-entities ManageUsersListComponent, ManageUsersAddComponent, PaginatedEntitiesComponent, + SortedTableHeaderComponent, + SortedTableHeaderRowComponent, ], imports: [ BrowserModule, diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/model/entity-service.ts b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/model/entity-service.ts index a9e7ce8b0..bdf649edc 100644 --- a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/model/entity-service.ts +++ b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/model/entity-service.ts @@ -24,5 +24,5 @@ import {Observable} from "rxjs"; * @typeparam T The type of the entity that is returned from the service */ export interface EntityService { - (searchTerm:string,offset:number,limit:number,orderBy:string,order:string):Observable> + (searchTerm:string,offset:number,limit:number,orderBy:string[],order:string):Observable> } diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/model/field-toggle.ts b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/model/field-toggle.ts new file mode 100644 index 000000000..e0d0e3f0a --- /dev/null +++ b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/model/field-toggle.ts @@ -0,0 +1,21 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +export interface FieldToggle { + toggleField(fieldName: string[]); +} diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/paginated-entities/paginated-entities.component.ts b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/paginated-entities/paginated-entities.component.ts index 2e5123bb0..1d0cba1e2 100644 --- a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/paginated-entities/paginated-entities.component.ts +++ b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/paginated-entities/paginated-entities.component.ts @@ -16,12 +16,11 @@ * under the License. */ -import {Component, OnInit, Input, Output, EventEmitter} from '@angular/core'; +import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core'; import {merge, Observable, Subject} from "rxjs"; -import {UserInfo} from "../../../model/user-info"; -import {TranslateService} from "@ngx-translate/core"; import {debounceTime, distinctUntilChanged, map, mergeMap, pluck, share, startWith} from "rxjs/operators"; import {EntityService} from "../../../model/entity-service"; +import {FieldToggle} from "../../../model/field-toggle"; /** @@ -44,95 +43,154 @@ import {EntityService} from "../../../model/entity-service"; * @typeparam T The type of the retrieved entity elements. */ @Component({ - selector: 'app-paginated-entities', - templateUrl: './paginated-entities.component.html', - styleUrls: ['./paginated-entities.component.scss'] + selector: 'app-paginated-entities', + templateUrl: './paginated-entities.component.html', + styleUrls: ['./paginated-entities.component.scss'] }) -export class PaginatedEntitiesComponent implements OnInit { +export class PaginatedEntitiesComponent implements OnInit, FieldToggle { - /** - * This must be set, if you use the component. This service retrieves the entity data. - */ - @Input() service : EntityService; + /** + * This must be set, if you use the component. This service retrieves the entity data. + */ + @Input() service: EntityService; - /** - * The number of elements per page retrieved - */ - @Input() pageSize = 10; + /** + * The number of elements per page retrieved + */ + @Input() pageSize = 10; - /** - * Pagination controls - */ - @Input() pagination = { - maxSize:5, - rotate:true, - boundaryLinks:true, - ellipses:false - } + /** + * Two-Way-Binding attribute for sorting field + */ + @Input() sortField = []; + /** + * Two-Way Binding attribute for sort order + */ + @Input() sortOrder = "asc"; - /** - * The current page that is selected - */ - page = 1; - /** - * The current search term entered in the search field - */ - searchTerm: string; + /** + * Pagination controls + */ + @Input() pagination = { + maxSize: 5, + rotate: true, + boundaryLinks: true, + ellipses: false + } - /** - * Event thrown, if the page value changes - */ - @Output() pageEvent : EventEmitter = new EventEmitter(); - /** - * Event thrown, if the search term changes - */ - @Output() searchTermEvent: EventEmitter = new EventEmitter(); + /** + * The current page that is selected + */ + page = 1; + /** + * The current search term entered in the search field + */ + searchTerm: string; - /** - * The total number of elements available for the given search term - */ - total$: Observable; - /** - * The entity items retrieved from the service - */ - items$: Observable; + /** + * Event thrown, if the page value changes + */ + @Output() pageChange: EventEmitter = new EventEmitter(); + /** + * Event thrown, if the search term changes + */ + @Output() searchTermChange: EventEmitter = new EventEmitter(); - private pageStream: Subject = new Subject(); - private searchTermStream: Subject = new Subject(); + @Output() sortFieldChange: EventEmitter = new EventEmitter(); - constructor() { } + @Output() sortOrderChange: EventEmitter = new EventEmitter(); - ngOnInit(): void { - // We combine the sources for the page and the search input field to a observable 'source' - const pageSource = this.pageStream.pipe(map(pageNumber => { - return {search: this.searchTerm, page: pageNumber} - })); - const searchSource = this.searchTermStream.pipe( - debounceTime(1000), - distinctUntilChanged(), - map(searchTerm => { - this.searchTerm = searchTerm; - return {search: searchTerm, page: 1} + /** + * The total number of elements available for the given search term + */ + total$: Observable; + /** + * The entity items retrieved from the service + */ + items$: Observable; + + private pageStream: Subject = new Subject(); + private searchTermStream: Subject = new Subject(); + + constructor() { + } + + ngOnInit(): void { + // We combine the sources for the page and the search input field to a observable 'source' + const pageSource = this.pageStream.pipe(map(pageNumber => { + return {search: this.searchTerm, page: pageNumber} })); - const source = merge(pageSource, searchSource).pipe( - startWith({search: this.searchTerm, page: this.page}), - mergeMap((params: { search: string, page: number }) => { - return this.service(params.search, (params.page - 1) * this.pageSize, this.pageSize, "", "asc"); - }),share()); - this.total$ = source.pipe(pluck('pagination','totalCount')); - this.items$ = source.pipe(pluck('data')); - } + const searchSource = this.searchTermStream.pipe( + debounceTime(1000), + distinctUntilChanged(), + map(searchTerm => { + this.searchTerm = searchTerm; + return {search: searchTerm, page: 1} + })); + const source = merge(pageSource, searchSource).pipe( + startWith({search: this.searchTerm, page: this.page}), + mergeMap((params: { search: string, page: number }) => { + return this.service(params.search, (params.page - 1) * this.pageSize, this.pageSize, this.sortField, this.sortOrder); + }), share()); + this.total$ = source.pipe(pluck('pagination', 'totalCount')); + this.items$ = source.pipe(pluck('data')); + } - search(terms: string) { - // console.log("Keystroke " + terms); - this.searchTermEvent.emit(terms); - this.searchTermStream.next(terms) - } + search(terms: string) { + // console.log("Keystroke " + terms); + this.searchTermChange.emit(terms); + this.searchTermStream.next(terms) + } - changePage(pageNumber : number) { - // console.log("Page change " +pageNumber); - this.pageEvent.emit(pageNumber); - this.pageStream.next(pageNumber); - } + changePage(pageNumber: number) { + // console.log("Page change " +pageNumber); + this.pageChange.emit(pageNumber); + this.pageStream.next(pageNumber); + } + + private compareArrays(a1: string[], a2: string[]) { + let i = a1.length; + while (i--) { + if (a1[i] !== a2[i]) return false; + } + return true + } + + toggleSortField(fieldName: string) { + this.toggleField([fieldName]); + } + + toggleField(fieldArray: string[]) { + console.log("Changing sort field " + fieldArray); + let sortOrderChanged: boolean = false; + let sortFieldChanged: boolean = false; + if (!this.compareArrays(this.sortField, fieldArray)) { + console.log("Fields differ: " + this.sortField + " - " + fieldArray); + this.sortField = fieldArray; + if (this.sortOrder != 'asc') { + this.sortOrder = 'asc'; + sortOrderChanged = true; + } + sortFieldChanged = true; + } else { + if (this.sortOrder == "asc") { + this.sortOrder = "desc"; + } else { + this.sortOrder = "asc"; + } + console.log("Toggled sort order: " + this.sortOrder); + sortOrderChanged = true; + } + if (sortOrderChanged) { + console.log("Sort order changed: "+this.sortOrder) + this.sortOrderChange.emit(this.sortOrder); + } + if (sortFieldChanged) { + this.sortFieldChange.emit(this.sortField); + } + if (sortFieldChanged || sortOrderChanged) { + this.changePage(1); + } + } } diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/sorted-table-header-row/sorted-table-header-row.component.html b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/sorted-table-header-row/sorted-table-header-row.component.html new file mode 100644 index 000000000..ff210c900 --- /dev/null +++ b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/sorted-table-header-row/sorted-table-header-row.component.html @@ -0,0 +1,19 @@ + + + diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/sorted-table-header-row/sorted-table-header-row.component.scss b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/sorted-table-header-row/sorted-table-header-row.component.scss new file mode 100644 index 000000000..343c3b1c0 --- /dev/null +++ b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/sorted-table-header-row/sorted-table-header-row.component.scss @@ -0,0 +1,18 @@ +/*! + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/sorted-table-header-row/sorted-table-header-row.component.spec.ts b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/sorted-table-header-row/sorted-table-header-row.component.spec.ts new file mode 100644 index 000000000..a8cb6fb56 --- /dev/null +++ b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/sorted-table-header-row/sorted-table-header-row.component.spec.ts @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { SortedTableHeaderRowComponent } from './sorted-table-header-row.component'; + +describe('SortedTableHeaderRowComponent', () => { + let component: SortedTableHeaderRowComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ SortedTableHeaderRowComponent ] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(SortedTableHeaderRowComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/sorted-table-header-row/sorted-table-header-row.component.ts b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/sorted-table-header-row/sorted-table-header-row.component.ts new file mode 100644 index 000000000..4de4c74ff --- /dev/null +++ b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/sorted-table-header-row/sorted-table-header-row.component.ts @@ -0,0 +1,79 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { + AfterViewChecked, AfterViewInit, + Component, + Input, + OnInit, + QueryList, + TemplateRef, + ViewChild, + ViewChildren, + ViewContainerRef, + ContentChildren, AfterContentInit, AfterContentChecked, ChangeDetectorRef, Output, EventEmitter +} from '@angular/core'; +import {FieldToggle} from "../../../model/field-toggle"; +import {SortedTableHeaderComponent} from "../sorted-table-header/sorted-table-header.component"; +import { delay, startWith } from 'rxjs/operators'; + +@Component({ + selector: 'tr[sorted]', + templateUrl: './sorted-table-header-row.component.html', + styleUrls: ['./sorted-table-header-row.component.scss'] +}) +export class SortedTableHeaderRowComponent implements OnInit, AfterViewInit, AfterContentInit, AfterContentChecked { + + @Input() sortFieldEmitter: EventEmitter; + @Input() sortOrderEmitter: EventEmitter; + @Input() sortFields: string[]; + @Input() sortOrder: string; + @Input() toggleObserver: FieldToggle; + + @ContentChildren(SortedTableHeaderComponent, { descendants: true }) contentChilds: QueryList; + + constructor(private readonly viewContainer: ViewContainerRef) { + } + + ngAfterContentChecked(): void { + + + } + + ngAfterContentInit(): void { + this.contentChilds.changes.pipe(startWith(this.contentChilds), delay(0)).subscribe(() => { + this.contentChilds.forEach((colComponent, index) => { + console.log("Children " + colComponent); + colComponent.registerSortFieldEmitter(this.sortFieldEmitter); + colComponent.registerSortOrderEmitter(this.sortOrderEmitter); + colComponent.sortOrder = this.sortOrder; + colComponent.currentFieldArray = this.sortFields; + colComponent.toggleObserver = this.toggleObserver; + }); + }); + + } + + ngOnInit(): void { + } + + ngAfterViewInit(): void { + + } + +} diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/sorted-table-header/sorted-table-header.component.html b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/sorted-table-header/sorted-table-header.component.html new file mode 100644 index 000000000..ff896b26b --- /dev/null +++ b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/sorted-table-header/sorted-table-header.component.html @@ -0,0 +1,24 @@ + + + + + {{contentText | translate}} + + + \ No newline at end of file diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/sorted-table-header/sorted-table-header.component.scss b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/sorted-table-header/sorted-table-header.component.scss new file mode 100644 index 000000000..343c3b1c0 --- /dev/null +++ b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/sorted-table-header/sorted-table-header.component.scss @@ -0,0 +1,18 @@ +/*! + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/sorted-table-header/sorted-table-header.component.spec.ts b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/sorted-table-header/sorted-table-header.component.spec.ts new file mode 100644 index 000000000..96bbe92fc --- /dev/null +++ b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/sorted-table-header/sorted-table-header.component.spec.ts @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { SortedTableHeaderComponent } from './sorted-table-header.component'; + +describe('SortedTableHeaderComponent', () => { + let component: SortedTableHeaderComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ SortedTableHeaderComponent ] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(SortedTableHeaderComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/sorted-table-header/sorted-table-header.component.ts b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/sorted-table-header/sorted-table-header.component.ts new file mode 100644 index 000000000..bc297d576 --- /dev/null +++ b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/sorted-table-header/sorted-table-header.component.ts @@ -0,0 +1,90 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { + Component, + OnInit, + Input, + ViewContainerRef, + ViewChild, + TemplateRef, + ChangeDetectorRef, + AfterViewChecked, EventEmitter, Output +} from '@angular/core'; +import {FieldToggle} from "../../../model/field-toggle"; +import { ChangeDetectionStrategy } from '@angular/core'; + +@Component({ + host: { style: 'display:none' }, + selector: 'app-th-sorted', + templateUrl: './sorted-table-header.component.html', + styleUrls: ['./sorted-table-header.component.scss'] +}) +export class SortedTableHeaderComponent implements OnInit, AfterViewChecked { + + @Input() fieldArray: string[]; + currentFieldArray: string[]; + sortOrder: string; + toggleObserver: FieldToggle; + @Input() contentText:string; + + @ViewChild('content', { static: true }) content: TemplateRef<{}>; + + + constructor(private readonly viewContainer: ViewContainerRef) { } + + ngOnInit(): void { + this.viewContainer.createEmbeddedView(this.content); + } + ngAfterViewChecked() { + } + + toggleSortField() { + console.log("Toggling sort field " + this.fieldArray); + this.toggleObserver.toggleField(this.fieldArray); + } + + private compareArrays(a1: string[], a2: string[]) { + if (a1==null || a2==null) { + return false; + } + let i = a1.length; + while (i--) { + if (a1[i] !== a2[i]) return false; + } + return true + } + + sortCheck() { + return this.compareArrays(this.fieldArray, this.currentFieldArray); + } + + isAscending() :boolean { + console.log("Is ascending: " + this.sortOrder); + return this.sortOrder == 'asc'; + } + + registerSortOrderEmitter(emitter : EventEmitter) { + emitter.subscribe((field) => this.sortOrder = field); + } + + registerSortFieldEmitter(emitter : EventEmitter) { + emitter.subscribe((field) => this.currentFieldArray = field); + } + +} diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/user/users/manage-users-list/manage-users-list.component.html b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/user/users/manage-users-list/manage-users-list.component.html index 56b02aee5..bfdc6fbaa 100644 --- a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/user/users/manage-users-list/manage-users-list.component.html +++ b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/user/users/manage-users-list/manage-users-list.component.html @@ -17,24 +17,28 @@ ~ under the License. --> - + - - - - - + + + + + + + + - + diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/user/users/manage-users-list/manage-users-list.component.ts b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/user/users/manage-users-list/manage-users-list.component.ts index 8e91dd32e..d2a073a2f 100644 --- a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/user/users/manage-users-list/manage-users-list.component.ts +++ b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/user/users/manage-users-list/manage-users-list.component.ts @@ -25,7 +25,6 @@ import {EntityService} from "../../../../model/entity-service"; import {Observable, of} from "rxjs"; import {PagedResult} from "../../../../model/paged-result"; - @Component({ selector: 'app-manage-users-list', templateUrl: './manage-users-list.component.html', @@ -35,10 +34,13 @@ export class ManageUsersListComponent implements OnInit { @Input() heads: any; service : EntityService; + sortField = ["user_id"]; + sortOrder = "asc"; constructor(private translator: TranslateService, private userService : UserService) { - this.service = function (searchTerm: string, offset: number, limit: number, orderBy: string, order: string) : Observable> { + this.service = function (searchTerm: string, offset: number, limit: number, orderBy: string[], order: string) : Observable> { + console.log("Retrieving data " + searchTerm + "," + offset + "," + limit + "," + orderBy + "," + order); return userService.query(searchTerm, offset, limit, orderBy, order); } @@ -53,9 +55,29 @@ export class ManageUsersListComponent implements OnInit { this.heads[suffix] = this.translator.instant('users.list.table.head.' + suffix); } }); + } + changeSortOrder(order:string) { + if (this.sortOrder!=order) { + this.sortOrder = order; + } + } + private compareArrays(a1: string[], a2: string[]) { + let i = a1.length; + while (i--) { + if (a1[i] !== a2[i]) return false; + } + return true + } + + sortCheck(fieldArray:string[]) { + return this.compareArrays(this.sortField, fieldArray); + } + + isAscending() : boolean { + return this.sortOrder == "asc"; } diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/services/user.service.ts b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/services/user.service.ts index bdeeafac4..68f9857fc 100644 --- a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/services/user.service.ts +++ b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/services/user.service.ts @@ -258,12 +258,15 @@ export class UserService implements OnInit, OnDestroy { this.authenticated = false; } - public query(searchTerm : string, offset : number = 0, limit : number = 10, orderBy : string = 'user_id', order: string = 'asc') : Observable> { + public query(searchTerm : string, offset : number = 0, limit : number = 10, orderBy : string[] = ['user_id'], order: string = 'asc') : Observable> { console.log("getUserList " + searchTerm + "," + offset + "," + limit + "," + orderBy + "," + order); if (searchTerm==null) { searchTerm="" } - return this.rest.executeRestCall>("get", "redback", "users", {'q':searchTerm, 'offset':offset,'limit':limit}); + if (orderBy==null || orderBy.length==0) { + orderBy = ['user_id']; + } + return this.rest.executeRestCall>("get", "redback", "users", {'q':searchTerm, 'offset':offset,'limit':limit,'orderBy':orderBy,'order':order}); } }
{{'users.list.table.head.user_id' | translate}}{{'users.list.table.head.fullName' | translate}}{{'users.list.table.head.email' | translate}} -
{{'users.list.table.head.lastLogin' | translate}}{{'users.list.table.head.created' | translate}} {{'users.list.table.head.lastPwChange' | translate}}