aboutsummaryrefslogtreecommitdiffstats
path: root/archiva-modules
diff options
context:
space:
mode:
authorMartin Stockhammer <martin_s@apache.org>2020-11-09 00:35:36 +0100
committerMartin Stockhammer <martin_s@apache.org>2020-11-09 00:35:36 +0100
commitec828c8745637e7cc51ea4cb3a1717f0588f0f1a (patch)
treeff9f36e95e1856cdeefc572e9d3945bff8111aa5 /archiva-modules
parent0e2187bf0efde67e9e51289f224183164b570ca0 (diff)
downloadarchiva-ec828c8745637e7cc51ea4cb3a1717f0588f0f1a.tar.gz
archiva-ec828c8745637e7cc51ea4cb3a1717f0588f0f1a.zip
Components for new angular app
Diffstat (limited to 'archiva-modules')
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/app.module.ts4
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/model/entity-service.ts2
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/model/field-toggle.ts21
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/paginated-entities/paginated-entities.component.ts240
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/sorted-table-header-row/sorted-table-header-row.component.html19
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/sorted-table-header-row/sorted-table-header-row.component.scss18
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/sorted-table-header-row/sorted-table-header-row.component.spec.ts43
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/sorted-table-header-row/sorted-table-header-row.component.ts79
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/sorted-table-header/sorted-table-header.component.html24
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/sorted-table-header/sorted-table-header.component.scss18
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/sorted-table-header/sorted-table-header.component.spec.ts43
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/sorted-table-header/sorted-table-header.component.ts90
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/user/users/manage-users-list/manage-users-list.component.html22
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/user/users/manage-users-list/manage-users-list.component.ts26
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/services/user.service.ts7
15 files changed, 551 insertions, 105 deletions
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<T> {
- (searchTerm:string,offset:number,limit:number,orderBy:string,order:string):Observable<PagedResult<T>>
+ (searchTerm:string,offset:number,limit:number,orderBy:string[],order:string):Observable<PagedResult<T>>
}
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<T> implements OnInit {
-
- /**
- * This must be set, if you use the component. This service retrieves the entity data.
- */
- @Input() service : EntityService<T>;
-
- /**
- * The number of elements per page retrieved
- */
- @Input() pageSize = 10;
-
- /**
- * Pagination controls
- */
- @Input() pagination = {
- maxSize:5,
- rotate:true,
- boundaryLinks:true,
- ellipses:false
- }
-
- /**
- * The current page that is selected
- */
- page = 1;
- /**
- * The current search term entered in the search field
- */
- searchTerm: string;
-
- /**
- * Event thrown, if the page value changes
- */
- @Output() pageEvent : EventEmitter<number> = new EventEmitter<number>();
- /**
- * Event thrown, if the search term changes
- */
- @Output() searchTermEvent: EventEmitter<string> = new EventEmitter<string>();
-
- /**
- * The total number of elements available for the given search term
- */
- total$: Observable<number>;
- /**
- * The entity items retrieved from the service
- */
- items$: Observable<T[]>;
-
- private pageStream: Subject<number> = new Subject<number>();
- private searchTermStream: Subject<string> = new Subject<string>();
-
- 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 searchSource = this.searchTermStream.pipe(
- debounceTime(1000),
- distinctUntilChanged(),
- map(searchTerm => {
- this.searchTerm = searchTerm;
- return {search: searchTerm, page: 1}
+export class PaginatedEntitiesComponent<T> implements OnInit, FieldToggle {
+
+ /**
+ * This must be set, if you use the component. This service retrieves the entity data.
+ */
+ @Input() service: EntityService<T>;
+
+ /**
+ * The number of elements per page retrieved
+ */
+ @Input() pageSize = 10;
+
+ /**
+ * Two-Way-Binding attribute for sorting field
+ */
+ @Input() sortField = [];
+ /**
+ * Two-Way Binding attribute for sort order
+ */
+ @Input() sortOrder = "asc";
+
+ /**
+ * Pagination controls
+ */
+ @Input() pagination = {
+ maxSize: 5,
+ rotate: true,
+ boundaryLinks: true,
+ ellipses: false
+ }
+
+ /**
+ * The current page that is selected
+ */
+ page = 1;
+ /**
+ * The current search term entered in the search field
+ */
+ searchTerm: string;
+
+ /**
+ * Event thrown, if the page value changes
+ */
+ @Output() pageChange: EventEmitter<number> = new EventEmitter<number>();
+ /**
+ * Event thrown, if the search term changes
+ */
+ @Output() searchTermChange: EventEmitter<string> = new EventEmitter<string>();
+
+ @Output() sortFieldChange: EventEmitter<string[]> = new EventEmitter<string[]>();
+
+ @Output() sortOrderChange: EventEmitter<string> = new EventEmitter<string>();
+
+ /**
+ * The total number of elements available for the given search term
+ */
+ total$: Observable<number>;
+ /**
+ * The entity items retrieved from the service
+ */
+ items$: Observable<T[]>;
+
+ private pageStream: Subject<number> = new Subject<number>();
+ private searchTermStream: Subject<string> = new Subject<string>();
+
+ 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'));
- }
-
- search(terms: string) {
- // console.log("Keystroke " + terms);
- this.searchTermEvent.emit(terms);
- this.searchTermStream.next(terms)
- }
-
- changePage(pageNumber : number) {
- // console.log("Page change " +pageNumber);
- this.pageEvent.emit(pageNumber);
- this.pageStream.next(pageNumber);
- }
+ 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.searchTermChange.emit(terms);
+ this.searchTermStream.next(terms)
+ }
+
+ 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 @@
+<!--
+ ~ 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.
+ -->
+
+<ng-content ></ng-content>
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<SortedTableHeaderRowComponent>;
+
+ 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<string[]>;
+ @Input() sortOrderEmitter: EventEmitter<string>;
+ @Input() sortFields: string[];
+ @Input() sortOrder: string;
+ @Input() toggleObserver: FieldToggle;
+
+ @ContentChildren(SortedTableHeaderComponent, { descendants: true }) contentChilds: QueryList<SortedTableHeaderComponent>;
+
+ 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 @@
+<!--
+ ~ 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.
+ -->
+
+<ng-template #content>
+<th scope="col" (click)="toggleSortField()">
+ <ng-container *ngIf="contentText!=null && contentText!=''" >{{contentText | translate}}</ng-container>
+ <ng-content></ng-content>
+ <span *ngIf="sortCheck()" class="fas" [ngClass]="isAscending()?'fa-sort-alpha-up':'fa-sort-alpha-down'"></span></th>
+</ng-template> \ 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<SortedTableHeaderComponent>;
+
+ 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<string>) {
+ emitter.subscribe((field) => this.sortOrder = field);
+ }
+
+ registerSortFieldEmitter(emitter : EventEmitter<string[]>) {
+ 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.
-->
-<app-paginated-entities [service]="service" pageSize="5"We #parent>
+<app-paginated-entities [service]="service" pageSize="5" [(sortField)]="sortField" [(sortOrder)]="sortOrder"
+ #parent>
<table class="table table-striped table-bordered">
<thead class="thead-light">
- <tr>
- <th scope="col">{{'users.list.table.head.user_id' | translate}}</th>
- <th scope="col">{{'users.list.table.head.fullName' | translate}}</th>
- <th scope="col">{{'users.list.table.head.email' | translate}}</th>
- <th scope="col"><span class="fas fa-check" placement="top"
- [ngbTooltip]="heads.validated" [attr.aria-label]="heads.validated"></span>
- </th>
+ <tr sorted [sortFieldEmitter]="parent.sortFieldChange" [sortOrder]="sortOrder" [sortFields]="sortField"
+ [sortOrderEmitter]="parent.sortOrderChange" [toggleObserver]="parent" >
+ <app-th-sorted [fieldArray]="['user_id']" contentText="users.list.table.head.user_id"></app-th-sorted>
+ <app-th-sorted contentText="users.list.table.head.fullName" [fieldArray]="['fullName']" ></app-th-sorted>
+ <app-th-sorted contentText="users.list.table.head.email" [fieldArray]="['email']"></app-th-sorted>
+ <app-th-sorted [fieldArray]="['validated','user_id']">
+ <span class="fas fa-check" placement="top"
+ [ngbTooltip]="heads.validated" [attr.aria-label]="heads.validated">
+ </span>
+ </app-th-sorted>
<th scope="col"><span class="fas fa-lock" placement="top"
[ngbTooltip]="heads.locked" [attr.aria-label]="heads.locked"></span></th>
<th scope="col"><span class="fa fa-chevron-circle-right" placement="top"
[ngbTooltip]="heads.pwchange" [attr.aria-label]="heads.pwchange"></span>
</th>
<th scope="col">{{'users.list.table.head.lastLogin' | translate}}</th>
- <th scope="col">{{'users.list.table.head.created' | translate}}</th>
+ <app-th-sorted contentText="users.list.table.head.created" [fieldArray]="['created']" ></app-th-sorted>
<th scope="col">{{'users.list.table.head.lastPwChange' | translate}}</th>
</tr>
</thead>
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<UserInfo>;
+ 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<PagedResult<UserInfo>> {
+ this.service = function (searchTerm: string, offset: number, limit: number, orderBy: string[], order: string) : Observable<PagedResult<UserInfo>> {
+ 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<PagedResult<UserInfo>> {
+ public query(searchTerm : string, offset : number = 0, limit : number = 10, orderBy : string[] = ['user_id'], order: string = 'asc') : Observable<PagedResult<UserInfo>> {
console.log("getUserList " + searchTerm + "," + offset + "," + limit + "," + orderBy + "," + order);
if (searchTerm==null) {
searchTerm=""
}
- return this.rest.executeRestCall<PagedResult<UserInfo>>("get", "redback", "users", {'q':searchTerm, 'offset':offset,'limit':limit});
+ if (orderBy==null || orderBy.length==0) {
+ orderBy = ['user_id'];
+ }
+ return this.rest.executeRestCall<PagedResult<UserInfo>>("get", "redback", "users", {'q':searchTerm, 'offset':offset,'limit':limit,'orderBy':orderBy,'order':order});
}
}