aboutsummaryrefslogtreecommitdiffstats
path: root/archiva-modules/archiva-web
diff options
context:
space:
mode:
authorMartin Stockhammer <martin_s@apache.org>2020-12-21 21:38:49 +0100
committerMartin Stockhammer <martin_s@apache.org>2020-12-21 21:38:49 +0100
commitb247e09a9e06a92b3d304950276834ebba48c0e2 (patch)
tree9637aeb2b2b306317630458e1038e5487896f8e3 /archiva-modules/archiva-web
parentb988a30f2c3f9b718953b70e2130337ec4ffe6d2 (diff)
downloadarchiva-b247e09a9e06a92b3d304950276834ebba48c0e2.tar.gz
archiva-b247e09a9e06a92b3d304950276834ebba48c0e2.zip
Adding user role assignment
Diffstat (limited to 'archiva-modules/archiva-web')
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/security/roles/manage-roles-edit/manage-roles-edit.component.html179
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/security/roles/manage-roles-edit/manage-roles-edit.component.ts65
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/security/users/manage-users-list/manage-users-list.component.html10
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/shared/paginated-entities/paginated-entities.component.html10
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/shared/paginated-entities/paginated-entities.component.ts28
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/shared/shared.module.ts9
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/services/role.service.ts39
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/assets/i18n/en.json12
8 files changed, 297 insertions, 55 deletions
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/security/roles/manage-roles-edit/manage-roles-edit.component.html b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/security/roles/manage-roles-edit/manage-roles-edit.component.html
index b146c72b6..bf6dd1e09 100644
--- a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/security/roles/manage-roles-edit/manage-roles-edit.component.html
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/security/roles/manage-roles-edit/manage-roles-edit.component.html
@@ -18,9 +18,9 @@
<form class="mt-3 mb-3" [formGroup]="userForm" (ngSubmit)="onSubmit()">
<div class="form-group row col-md-8">
- <div class="col-md-1" >{{'form.edit' |translate}}&nbsp;<span
+ <div class="col-md-1">{{'form.edit' |translate}}&nbsp;<span
class="fas fa-edit"></span></div>
- <div class="col-md-6" >
+ <div class="col-md-6">
<input class="form-check-input" type="checkbox" [value]="editMode" [checked]="editMode"
(change)="editMode=!editMode"
>
@@ -75,14 +75,14 @@
</div>
</div>
<div class="col-md-2" *ngIf="editMode">
- <button class="btn btn-primary" type="submit"
- [disabled]="userForm.invalid || !userForm.dirty">{{'form.button.save'|translate}}</button>
+ <button class="btn btn-primary" type="submit"
+ [disabled]="userForm.invalid || !userForm.dirty">{{'form.button.save'|translate}}</button>
</div>
</div>
</form>
<hr/>
<ngb-accordion activeIds="parents,children,permissions">
- <ngb-panel id="parents" >
+ <ngb-panel id="parents">
<ng-template ngbPanelHeader let-opened="opened">
<div class="d-flex align-items-center justify-content-between">
<button ngbPanelToggle class="btn btn-link text-left shadow-none">
@@ -92,27 +92,28 @@
</div>
</ng-template>
<ng-template ngbPanelContent>
- <ng-container *ngIf="editRole?.parents.length>0">
- <ul class="list-group" *ngFor="let parentRole of editRole?.parents">
- <li class="list-group-item"><a routerLink="../{{parentRole?.id}}">{{parentRole?.name}}</a></li>
- </ul>
- </ng-container>
+ <ng-container *ngIf="editRole?.parents.length>0">
+ <ul class="list-group" *ngFor="let parentRole of editRole?.parents">
+ <li class="list-group-item"><a routerLink="../{{parentRole?.id}}">{{parentRole?.name}}</a></li>
+ </ul>
+ </ng-container>
</ng-template>
</ngb-panel>
<ngb-panel id="children">
<ng-template ngbPanelHeader let-opened="opened">
<div class="d-flex align-items-center justify-content-between">
- <button ngbPanelToggle class="btn btn-link text-left shadow-none"><h3>{{'roles.edit.children'|translate}}</h3></button>
- <ng-container *ngIf="!opened"><i class="fa fa-eye-slash"></i></ng-container>
- <ng-container *ngIf="opened"><i class="fa fa-eye"></i></ng-container>
+ <button ngbPanelToggle class="btn btn-link text-left shadow-none">
+ <h3>{{'roles.edit.children'|translate}}</h3></button>
+ <ng-container *ngIf="!opened"><i class="fa fa-eye-slash"></i></ng-container>
+ <ng-container *ngIf="opened"><i class="fa fa-eye"></i></ng-container>
</div>
</ng-template>
<ng-template ngbPanelContent>
- <ng-container *ngIf="editRole?.children.length>0">
- <ul class="list-group" *ngFor="let childRole of editRole?.children">
- <li class="list-group-item"><a routerLink="../{{childRole?.id}}">{{childRole?.name}}</a></li>
- </ul>
- </ng-container>
+ <ng-container *ngIf="editRole?.children.length>0">
+ <ul class="list-group" *ngFor="let childRole of editRole?.children">
+ <li class="list-group-item"><a routerLink="../{{childRole?.id}}">{{childRole?.name}}</a></li>
+ </ul>
+ </ng-container>
</ng-template>
</ngb-panel>
@@ -120,44 +121,138 @@
<ng-template ngbPanelHeader let-opened="opened">
<div class="d-flex align-items-center justify-content-between">
- <button ngbPanelToggle class="btn btn-link text-left shadow-none"><h3>{{'roles.edit.permissions'|translate}}</h3></button>
- <ng-container *ngIf="!opened"><i class="fa fa-eye-slash"></i></ng-container>
- <ng-container *ngIf="opened"><i class="fa fa-eye"></i></ng-container>
+ <button ngbPanelToggle class="btn btn-link text-left shadow-none">
+ <h3>{{'roles.edit.permissions'|translate}}</h3></button>
+ <ng-container *ngIf="!opened"><i class="fa fa-eye-slash"></i></ng-container>
+ <ng-container *ngIf="opened"><i class="fa fa-eye"></i></ng-container>
</div>
</ng-template>
<ng-template ngbPanelContent>
- <ng-container *ngIf="editRole">
- <table class="table">
- <thead>
- <tr>
- <th>{{'permissions.attributes.permission'|translate}}</th>
- <th>{{'permissions.attributes.operation'|translate}}</th>
- <th>{{'permissions.attributes.resource'|translate}}</th>
- </tr>
- </thead>
- <tbody *ngFor="let perm of editRole.permissions">
- <tr>
- <td>{{perm.name}}</td>
- <td>{{perm.operation.name}}</td>
- <td>{{perm.resource.identifier}}</td>
- </tr>
- </tbody>
+ <ng-container *ngIf="editRole">
+ <table class="table">
+ <thead>
+ <tr>
+ <th>{{'permissions.attributes.permission'|translate}}</th>
+ <th>{{'permissions.attributes.operation'|translate}}</th>
+ <th>{{'permissions.attributes.resource'|translate}}</th>
+ </tr>
+ </thead>
+ <tbody *ngFor="let perm of editRole.permissions">
+ <tr>
+ <td>{{perm.name}}</td>
+ <td>{{perm.operation.name}}</td>
+ <td>{{perm.resource.identifier}}</td>
+ </tr>
+ </tbody>
- </table>
- </ng-container>
+ </table>
+ </ng-container>
</ng-template>
</ngb-panel>
<ngb-panel>
<ng-template ngbPanelHeader let-opened="opened">
<div class="d-flex align-items-center justify-content-between">
- <button ngbPanelToggle class="btn btn-link text-left shadow-none"><h3>{{'roles.edit.users'|translate}}</h3></button>
+ <button ngbPanelToggle class="btn btn-link text-left shadow-none">
+ <h3>{{'roles.edit.users'|translate}}</h3></button>
<ng-container *ngIf="!opened"><i class="fa fa-eye-slash"></i></ng-container>
<ng-container *ngIf="opened"><i class="fa fa-eye"></i></ng-container>
</div>
</ng-template>
- <ng-template ngbPanelContent >
- <h3>There are the users</h3>
+ <ng-template ngbPanelContent>
+ <h4>{{'roles.edit.usersParents'|translate}}</h4>
+ <app-paginated-entities [service]="roleUserParentService" pageSize="5" [(sortField)]="userParentSortField"
+ [(sortOrder)]="userParentSortOrder" [displayControlsIfSinglePage]="false"
+ #userParentSection>
+
+ <ng-container *ngIf="userParentSection.items$ |async as itemLoader">
+ <ng-template [ngIf]="itemLoader.loading">
+ <div class="spinner-border text-primary" role="status">
+ <span class="sr-only">Loading...</span>
+ </div>
+ </ng-template>
+ </ng-container>
+ <ng-container *ngIf="userParentSection.items$ |stripLoading|async as userItem">
+ <table class="table table-striped table-bordered">
+ <thead class="thead-light">
+ <tr sorted [sortFieldEmitter]="userParentSection.sortFieldChange"
+ [sortOrderEmitter]="userParentSection.sortOrderChange"
+ [toggleObserver]="userParentSection">
+ <app-th-sorted [fieldArray]="['user_id']"
+ contentText="users.attributes.user_id"></app-th-sorted>
+ <app-th-sorted [fieldArray]="['full_name']"
+ contentText="users.attributes.full_name"></app-th-sorted>
+ </tr>
+ </thead>
+ <tbody>
+ <tr *ngFor="let user of userItem.data">
+ <td><span data-toggle="tooltip" placement="left"
+ ngbTooltip="{{user.id}}">{{user.user_id}}</span>
+ </td>
+ <td>{{user.full_name}}</td>
+ </tr>
+ </tbody>
+ </table>
+ </ng-container>
+ </app-paginated-entities>
+ <hr/>
+ <h4>{{'roles.edit.usersInstance'|translate}}</h4>
+ <app-paginated-entities [service]="roleUserService" pageSize="5" [(sortField)]="userSortField"
+ [(sortOrder)]="userSortOrder"
+ [displayIfEmpty]="false" [displayKeyIfEmpty]="'roles.edit.noUsersAssigned'"
+ #userSection>
+
+ <ng-container *ngIf="userSection.items$ |async as itemLoader">
+ <ng-template [ngIf]="itemLoader.loading">
+ <div class="spinner-border text-primary" role="status">
+ <span class="sr-only">Loading...</span>
+ </div>
+ </ng-template>
+ </ng-container>
+ <ng-container *ngIf="userSection.items$ |stripLoading|async as userItem">
+ <table class="table table-striped table-bordered">
+ <thead class="thead-light">
+ <tr sorted [sortFieldEmitter]="userSection.sortFieldChange"
+ [sortOrderEmitter]="userSection.sortOrderChange"
+ [toggleObserver]="userSection">
+ <app-th-sorted [fieldArray]="['user_id']"
+ contentText="users.attributes.user_id"></app-th-sorted>
+ <app-th-sorted [fieldArray]="['full_name']"
+ contentText="users.attributes.full_name"></app-th-sorted>
+ </tr>
+ </thead>
+ <tbody>
+ <tr *ngFor="let user of userItem.data">
+ <td><span data-toggle="tooltip" placement="left"
+ ngbTooltip="{{user.id}}">{{user.user_id}}</span>
+ </td>
+ <td>{{user.full_name}}</td>
+ </tr>
+ </tbody>
+ </table>
+ </ng-container>
+ </app-paginated-entities>
+ <hr/>
+ <form class="mt-2">
+ <ng-template #userResultTemplate let-r="result" let-t="term">
+ <ngb-highlight [result]="r.user_id + '-' + r.full_name" [term]="t"></ngb-highlight>
+ </ng-template>
+ <div class="form-group">
+ <label for="typeahead-http">{{'roles.edit.assignUserSearch'|translate}}</label>
+ <input id="typeahead-http" type="text" class="form-control col-md-2"
+ name="userSearchField"
+ [class.is-invalid]="userSearchFailed" [resultTemplate]="userResultTemplate"
+ [inputFormatter]="getUserId"
+ [placement]="'top'"
+ [(ngModel)]="userSearchModel" [ngbTypeahead]="searchUser" placeholder="User Search"/>
+ <small *ngIf="userSearching"
+ class="form-text text-muted">{{'form.searching' |translate}}</small>
+ <div class="invalid-feedback"
+ *ngIf="userSearchFailed">{{'roles.edit.userSearchFailed'|translate}}</div>
+ </div>
+ <button class="btn btn-primary" (click)="assignUserRole()">{{'roles.edit.assignButton'|translate}}</button>
+ </form>
+
</ng-template>
</ngb-panel>
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/security/roles/manage-roles-edit/manage-roles-edit.component.ts b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/security/roles/manage-roles-edit/manage-roles-edit.component.ts
index b5d033f01..71655fe19 100644
--- a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/security/roles/manage-roles-edit/manage-roles-edit.component.ts
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/security/roles/manage-roles-edit/manage-roles-edit.component.ts
@@ -20,12 +20,17 @@ import {AfterContentInit, Component, EventEmitter, OnInit, Output} from '@angula
import {ActivatedRoute} from "@angular/router";
import {FormBuilder, Validators} from "@angular/forms";
import {RoleService} from "@app/services/role.service";
-import {catchError, filter, map, switchMap, tap} from "rxjs/operators";
+import {catchError, debounceTime, distinctUntilChanged, filter, map, switchMap, tap} from "rxjs/operators";
import {Role} from '@app/model/role';
import {ErrorResult} from "@app/model/error-result";
import {EditBaseComponent} from "@app/modules/shared/edit-base.component";
-import {forkJoin, iif, Observable, of, pipe, zip} from 'rxjs';
+import {forkJoin, Observable, of, zip} from 'rxjs';
import {RoleUpdate} from "@app/model/role-update";
+import {EntityService} from "@app/model/entity-service";
+import {User} from '@app/model/user';
+import {PagedResult} from "@app/model/paged-result";
+import {UserService} from "@app/services/user.service";
+import {UserInfo} from '@app/model/user-info';
@Component({
selector: 'app-manage-roles-edit',
@@ -38,12 +43,23 @@ export class ManageRolesEditComponent extends EditBaseComponent<Role> implements
editProperties = ['id', 'name', 'description', 'template_instance', 'resource', 'assignable'];
originRole;
roleCache: Map<string, Role> = new Map<string, Role>();
+ roleUserService: EntityService<User>
+ roleUserParentService: EntityService<User>;
+ userSortField = ["id"];
+ userSortOrder = "asc";
+ userParentSortField = ["id"];
+ userParentSortOrder = "asc";
+
+ userSearching:boolean=false;
+ userSearchFailed:boolean=false;
+
+ public userSearchModel:any;
@Output()
roleIdEvent: EventEmitter<string> = new EventEmitter<string>(true);
- constructor(private route: ActivatedRoute, private roleService: RoleService, public fb: FormBuilder) {
+ constructor(private route: ActivatedRoute, public roleService: RoleService, private userService: UserService, public fb: FormBuilder) {
super(fb);
super.init(fb.group({
id: [''],
@@ -53,6 +69,7 @@ export class ManageRolesEditComponent extends EditBaseComponent<Role> implements
template_instance: [''],
assignable: ['']
}, {}));
+
}
createEntity(): Role {
@@ -75,6 +92,14 @@ export class ManageRolesEditComponent extends EditBaseComponent<Role> implements
this.editRole = role;
this.originRole = role;
this.copyToForm(this.editProperties, this.editRole);
+ const fRoleService = this.roleService;
+ const roleId = role.id;
+ this.roleUserService = function (searchTerm: string, offset: number, limit: number, orderBy: string[], order: string): Observable<PagedResult<User>> {
+ return fRoleService.queryAssignedUsers(roleId, searchTerm, offset, limit, orderBy, order);
+ };
+ this.roleUserParentService = function (searchTerm: string, offset: number, limit: number, orderBy: string[], order: string): Observable<PagedResult<User>> {
+ return fRoleService.queryAssignedParentUsers(roleId, searchTerm, offset, limit, orderBy, order, true);
+ };
}, error => {
this.editRole = new Role();
});
@@ -165,5 +190,39 @@ export class ManageRolesEditComponent extends EditBaseComponent<Role> implements
}
}
+ searchUser = (text$: Observable<string>) =>
+ text$.pipe(
+ debounceTime(300),
+ distinctUntilChanged(),
+ tap(() => this.userSearching = true),
+ switchMap(term =>
+ this.userService.query(term, 0, 10).pipe(
+ tap(() => this.userSearchFailed = false),
+ map(pagedResult=>
+ pagedResult.data),
+ catchError(() => {
+ this.userSearchFailed = true;
+ return of([]);
+ }))
+ ),
+ tap(() => this.userSearching = false)
+ )
+
+ getUserId(item:UserInfo) : string {
+ return item.user_id;
+ }
+
+ assignUserRole() {
+ let userId;
+ if (typeof(this.userSearchModel)=='string') {
+ userId=this.userSearchModel;
+ } else {
+ if (this.userSearchModel.user_id) {
+ userId = this.userSearchModel.user_id;
+ }
+ }
+ console.log("Assigning user " + userId)
+ }
+
}
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/security/users/manage-users-list/manage-users-list.component.html b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/security/users/manage-users-list/manage-users-list.component.html
index d87fc57ef..f72b3e702 100644
--- a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/security/users/manage-users-list/manage-users-list.component.html
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/security/users/manage-users-list/manage-users-list.component.html
@@ -19,14 +19,14 @@
<app-paginated-entities [service]="service" pageSize="10" [(sortField)]="sortField" [(sortOrder)]="sortOrder"
#parent>
- <ng-container *ngIf="parent.items$ |async as roleItemLoader">
- <ng-template [ngIf]="roleItemLoader.loading">
+ <ng-container *ngIf="parent.items$ |async as itemLoader">
+ <ng-template [ngIf]="itemLoader.loading">
<div class="spinner-border text-primary" role="status">
<span class="sr-only">Loading...</span>
</div>
</ng-template>
</ng-container>
- <ng-container *ngIf="parent.items$ |stripLoading|async as roleItem">
+ <ng-container *ngIf="parent.items$ |stripLoading|async as userItem">
<table class="table table-striped table-bordered">
<thead class="thead-light">
@@ -54,11 +54,11 @@
<app-th-sorted [fieldArray]="['created']" contentText="users.attributes.created"></app-th-sorted>
<app-th-sorted [fieldArray]="['last_password_change']"
contentText="users.attributes.last_password_change"></app-th-sorted>
- <th>Action</th>
+ <th>{{'headers.action'|translate}}</th>
</tr>
</thead>
<tbody>
- <tr *ngFor="let user of roleItem.data"
+ <tr *ngFor="let user of userItem.data"
[ngClass]="(user.permanent||user.readOnly)?'table-secondary':''">
<td><span data-toggle="tooltip" placement="left" ngbTooltip="{{user.id}}">{{user.user_id}}</span>
</td>
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/shared/paginated-entities/paginated-entities.component.html b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/shared/paginated-entities/paginated-entities.component.html
index ce0a6a50a..879ff98bc 100644
--- a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/shared/paginated-entities/paginated-entities.component.html
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/shared/paginated-entities/paginated-entities.component.html
@@ -16,8 +16,9 @@
~ under the License.
-->
+<ng-template [ngIf]="(displayIfEmpty || (total$|async)>0)" [ngIfElse]="noContent" >
<form class="mt-3 mb-3">
- <div class="form-row align-items-center">
+ <div class="form-row align-items-center" *ngIf="displayControlsIfSinglePage||(multiplePages$|async)">
<div class="col-lg-4 col-md-2 col-sm-1">
<label class="sr-only" for="searchQuery">{{'search.label' |translate}}</label>
<input type="text" class="form-control" id="searchQuery" placeholder="{{'search.input'|translate}}" #searchTerm
@@ -33,6 +34,11 @@
<ng-content></ng-content>
-<ngb-pagination [collectionSize]="total$|async" [pageSize]="pageSize" [maxSize]="pagination.maxSize" [rotate]="pagination.rotate"
+<ngb-pagination *ngIf="displayControlsIfSinglePage||(multiplePages$|async)"
+ [collectionSize]="total$|async" [pageSize]="pageSize" [maxSize]="pagination.maxSize" [rotate]="pagination.rotate"
[boundaryLinks]="pagination.boundaryLinks" [ellipses]="pagination.ellipses"
[(page)]="page" (pageChange)="changePage($event)" aria-label="Pagination"></ngb-pagination>
+</ng-template>
+<ng-template #noContent>
+ {{displayKeyIfEmpty|translate}}
+</ng-template> \ No newline at end of file
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/shared/paginated-entities/paginated-entities.component.ts b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/shared/paginated-entities/paginated-entities.component.ts
index cc62ac6a8..d2157d804 100644
--- a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/shared/paginated-entities/paginated-entities.component.ts
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/shared/paginated-entities/paginated-entities.component.ts
@@ -94,6 +94,26 @@ export class PaginatedEntitiesComponent<T> implements OnInit, FieldToggle, After
}
/**
+ * If true, all controls are displayed, if the total count is 0
+ */
+ @Input()
+ displayIfEmpty:boolean=true;
+ /**
+ * Sets the translation key, for the text to display, if displayIfEmpty=false and the total count is 0.
+ */
+ @Input()
+ displayKeyIfEmpty:string='form.emptyContent';
+
+ /**
+ * If set to true, all controls are displayed, even if there is only one page to display.
+ * Otherwise the controls are not displayed, if there is only a single page of results.
+ */
+ @Input()
+ displayControlsIfSinglePage:boolean=true;
+
+
+
+ /**
* The current page that is selected
*/
page = 1;
@@ -124,6 +144,13 @@ export class PaginatedEntitiesComponent<T> implements OnInit, FieldToggle, After
*/
items$: Observable<LoadingValue<PagedResult<T>>>;
+ /**
+ * true, if the current page result value represents a result with multiple pages,
+ * otherwise false.
+ */
+ multiplePages$:Observable<boolean>;
+
+
private pageStream: Subject<number> = new Subject<number>();
private searchTermStream: Subject<string> = new Subject<string>();
@@ -153,6 +180,7 @@ export class PaginatedEntitiesComponent<T> implements OnInit, FieldToggle, After
), share());
this.total$ = source.pipe(filter(val=>val.hasValue()),map(val=>val.value),pluck('pagination', 'total_count'));
this.items$ = source;
+ this.multiplePages$ = source.pipe(filter(val => val.hasValue()), map(val => val.value.pagination.total_count >= val.value.pagination.limit));
}
search(terms: string) {
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/shared/shared.module.ts b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/shared/shared.module.ts
index 042057637..76bd9845f 100644
--- a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/shared/shared.module.ts
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/shared/shared.module.ts
@@ -21,7 +21,13 @@ import {CommonModule} from '@angular/common';
import {PaginatedEntitiesComponent} from "./paginated-entities/paginated-entities.component";
import {SortedTableHeaderComponent} from "./sorted-table-header/sorted-table-header.component";
import {SortedTableHeaderRowComponent} from "./sorted-table-header-row/sorted-table-header-row.component";
-import {NgbAccordionModule, NgbModalModule, NgbPaginationModule, NgbTooltipModule} from "@ng-bootstrap/ng-bootstrap";
+import {
+ NgbAccordionModule,
+ NgbModalModule,
+ NgbPaginationModule,
+ NgbTooltipModule,
+ NgbTypeaheadModule
+} from "@ng-bootstrap/ng-bootstrap";
import {TranslateCompiler, TranslateLoader, TranslateModule} from "@ngx-translate/core";
import {TranslateMessageFormatCompiler} from "ngx-translate-messageformat-compiler";
import {HttpClient} from "@angular/common/http";
@@ -49,6 +55,7 @@ export { PageQuery } from './model/page-query';
NgbTooltipModule,
NgbAccordionModule,
NgbModalModule,
+ NgbTypeaheadModule,
PaginatedEntitiesComponent,
SortedTableHeaderComponent,
SortedTableHeaderRowComponent,
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/services/role.service.ts b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/services/role.service.ts
index 99424a0df..aeabc33d7 100644
--- a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/services/role.service.ts
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/services/role.service.ts
@@ -25,6 +25,7 @@ import {HttpResponse} from "@angular/common/http";
import {PagedResult} from "@app/model/paged-result";
import {UserInfo} from "@app/model/user-info";
import {RoleUpdate} from "@app/model/role-update";
+import { User } from '@app/model/user';
@Injectable({
providedIn: 'root'
@@ -61,6 +62,44 @@ export class RoleService {
});
}
+ public queryAssignedUsers(roleId: string,
+ searchTerm: string, offset: number = 0, limit: number = 5,
+ orderBy: string[] = ['id'], order: string = 'asc'): Observable<PagedResult<User>> {
+ if (searchTerm == null) {
+ searchTerm = ""
+ }
+ if (orderBy == null || orderBy.length == 0) {
+ orderBy = ['id'];
+ }
+ return this.rest.executeRestCall<PagedResult<User>>("get", "redback", "roles/" + roleId + "/user", {
+ 'q': searchTerm,
+ 'offset': offset,
+ 'limit': limit,
+ 'orderBy': orderBy,
+ 'order': order
+ });
+ }
+
+ public queryAssignedParentUsers(roleId: string,
+ searchTerm: string, offset: number = 0, limit: number = 5,
+ orderBy: string[] = ['id'], order: string = 'asc', parentsOnly:boolean=true): Observable<PagedResult<User>> {
+ if (searchTerm == null) {
+ searchTerm = ""
+ }
+ if (orderBy == null || orderBy.length == 0) {
+ orderBy = ['id'];
+ }
+ const recurseFlag = parentsOnly ? 'parentsOnly' : 'true';
+ return this.rest.executeRestCall<PagedResult<User>>("get", "redback", "roles/" + roleId + "/user", {
+ 'recurse':recurseFlag,
+ 'q': searchTerm,
+ 'offset': offset,
+ 'limit': limit,
+ 'orderBy': orderBy,
+ 'order': order
+ });
+ }
+
public getRole(roleId:string) : Observable<Role> {
return this.rest.executeRestCall("get", "redback", "roles/" + roleId, null);
}
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/assets/i18n/en.json b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/assets/i18n/en.json
index d094e3976..297c9f21d 100644
--- a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/assets/i18n/en.json
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/assets/i18n/en.json
@@ -136,7 +136,13 @@
"parents": "Parents",
"children": "Children",
"permissions": "Permissions",
- "users": "Users"
+ "users": "Users",
+ "usersInstance": "Users Assigned to this Role",
+ "usersParents": "Users Assigned to Parent Roles",
+ "noUsersAssigned": "There are no users assigned to this role",
+ "assignUserSearch": "Search and assign users to this role",
+ "userSearchFailed": "Sorry, could not load users",
+ "assignButton": "Assign"
},
"attributes": {
"id": "Identifier",
@@ -172,7 +178,9 @@
"no": "No",
"save": "Save Changes"
},
- "edit": "Edit"
+ "edit": "Edit",
+ "emptyContent": "No values",
+ "searching": "Searching ..."
},
"headers": {
"action": "Action"