You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@archiva.apache.org by ma...@apache.org on 2020/11/13 22:57:29 UTC

[archiva] branch master updated: organizing components into modules

This is an automated email from the ASF dual-hosted git repository.

martin_s pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/archiva.git


The following commit(s) were added to refs/heads/master by this push:
     new 4a85876  organizing components into modules
4a85876 is described below

commit 4a85876aaa145225537cc65ca93ef96df2d02d1d
Author: Martin Stockhammer <ma...@apache.org>
AuthorDate: Fri Nov 13 23:57:21 2020 +0100

    organizing components into modules
---
 .../main/archiva-web/src/app/app-routing.module.ts |  10 +-
 .../src/main/archiva-web/src/app/app.module.ts     |  79 ++++---------
 .../modules/core/errors/error-handler.module.ts    |   2 +-
 .../{general => shared}/about/about.component.html |   0
 .../{general => shared}/about/about.component.scss |   0
 .../about/about.component.spec.ts                  |   0
 .../{general => shared}/about/about.component.ts   |   0
 .../contact/contact.component.html                 |   0
 .../contact/contact.component.scss                 |   0
 .../contact/contact.component.spec.ts              |   0
 .../contact/contact.component.ts                   |   0
 .../{general => shared}/home/home.component.html   |   0
 .../{general => shared}/home/home.component.scss   |   0
 .../home/home.component.spec.ts                    |   0
 .../{general => shared}/home/home.component.ts     |   0
 .../{general => shared}/login/login.component.html |   0
 .../{general => shared}/login/login.component.scss |   0
 .../login/login.component.spec.ts                  |   0
 .../{general => shared}/login/login.component.ts   |   0
 .../not-found/not-found.component.html             |   0
 .../not-found/not-found.component.scss             |   0
 .../not-found/not-found.component.spec.ts          |   0
 .../not-found/not-found.component.ts               |   0
 .../paginated-entities.component.html              |   0
 .../paginated-entities.component.scss              |   0
 .../paginated-entities.component.spec.ts           |   0
 .../paginated-entities.component.ts                |   0
 .../src/app/modules/shared/shared.module.ts        |  71 ++++++++++++
 .../sidemenu/sidemenu.component.html               |   0
 .../sidemenu/sidemenu.component.scss               |   0
 .../sidemenu/sidemenu.component.spec.ts            |   0
 .../sidemenu/sidemenu.component.ts                 |   0
 .../sorted-table-header-row.component.html         |   0
 .../sorted-table-header-row.component.scss         |   0
 .../sorted-table-header-row.component.spec.ts      |   0
 .../sorted-table-header-row.component.ts           |   0
 .../sorted-table-header.component.html             |   0
 .../sorted-table-header.component.scss             |   0
 .../sorted-table-header.component.spec.ts          |   0
 .../sorted-table-header.component.ts               |   0
 .../user.module.ts}                                |  35 ++++--
 .../manage-users-add/manage-users-add.component.ts | 125 +--------------------
 ...component.ts => manage-users-base.component.ts} | 103 ++++-------------
 .../manage-users-edit.component.ts                 |   7 +-
 .../src/app/services/authentication.service.ts     |  20 +++-
 .../src/app/services/routing-guard.service.ts      |  40 +++++--
 .../archiva-web/src/app/services/user.service.ts   |  74 +++++++-----
 47 files changed, 251 insertions(+), 315 deletions(-)

diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/app-routing.module.ts b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/app-routing.module.ts
index 15fcbd7..084b0c1 100644
--- a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/app-routing.module.ts
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/app-routing.module.ts
@@ -19,11 +19,11 @@
 import { NgModule } from '@angular/core';
 import { Routes, RouterModule } from '@angular/router';
 
-import { AboutComponent } from './modules/general/about/about.component';
-import { ContactComponent } from './modules/general/contact/contact.component';
-import { HomeComponent } from './modules/general/home/home.component';
-import { NotFoundComponent } from './modules/general/not-found/not-found.component';
-import { LoginComponent } from "./modules/general/login/login.component";
+import { AboutComponent } from './modules/shared/about/about.component';
+import { ContactComponent } from './modules/shared/contact/contact.component';
+import { HomeComponent } from './modules/shared/home/home.component';
+import { NotFoundComponent } from './modules/shared/not-found/not-found.component';
+import { LoginComponent } from "./modules/shared/login/login.component";
 import { SearchComponent } from './modules/repo/search/search.component';
 import {BrowseComponent} from "./modules/repo/browse/browse.component";
 import {UploadComponent} from "./modules/repo/upload/upload.component";
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 d07e42f..73bfc21 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
@@ -16,39 +16,29 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-import { BrowserModule } from '@angular/platform-browser';
-import { NgModule } from '@angular/core';
-import { HttpClient, HttpClientModule } from '@angular/common/http';
-import { TranslateLoader, TranslateModule, TranslateCompiler } from '@ngx-translate/core';
-import { TranslateHttpLoader } from '@ngx-translate/http-loader';
-import { TranslateMessageFormatCompiler, MESSAGE_FORMAT_CONFIG } from 'ngx-translate-messageformat-compiler';
+import {BrowserModule} from '@angular/platform-browser';
+import {NgModule} from '@angular/core';
+import {HttpClientModule} from '@angular/common/http';
+import {MESSAGE_FORMAT_CONFIG} from 'ngx-translate-messageformat-compiler';
 
-import { AppRoutingModule } from './app-routing.module';
-import { AppComponent } from './app.component';
-import { HomeComponent } from './modules/general/home/home.component';
-import { ContactComponent } from './modules/general/contact/contact.component';
-import { AboutComponent } from './modules/general/about/about.component';
-import { NotFoundComponent } from './modules/general/not-found/not-found.component';
-import { SidemenuComponent } from './modules/general/sidemenu/sidemenu.component';
+import {AppRoutingModule} from './app-routing.module';
+import {AppComponent} from './app.component';
+import {HomeComponent} from './modules/shared/home/home.component';
+import {ContactComponent} from './modules/shared/contact/contact.component';
+import {AboutComponent} from './modules/shared/about/about.component';
+import {NotFoundComponent} from './modules/shared/not-found/not-found.component';
+import {SidemenuComponent} from './modules/shared/sidemenu/sidemenu.component';
 import {FormsModule, ReactiveFormsModule} from "@angular/forms";
-import { LoginComponent } from './modules/general/login/login.component';
-import { ViewPermissionDirective } from './directives/view-permission.directive';
-import { NavSubgroupDirective } from './directives/nav-subgroup.directive';
-import { SearchComponent } from './modules/repo/search/search.component';
-import { BrowseComponent } from './modules/repo/browse/browse.component';
-import { UploadComponent } from './modules/repo/upload/upload.component';
-import { ManageUsersComponent } from './modules/user/manage-users/manage-users.component';
-import { ManageRolesComponent } from './modules/user/manage-roles/manage-roles.component';
-import { SecurityConfigurationComponent } from './modules/user/security-configuration/security-configuration.component';
-import { ManageUsersListComponent } from './modules/user/users/manage-users-list/manage-users-list.component';
-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';
-import { ManageUsersEditComponent } from './modules/user/users/manage-users-edit/manage-users-edit.component';
-import {ErrorHandlerModule} from "./modules/core/errors/error-handler.module";
+import {LoginComponent} from './modules/shared/login/login.component';
+import {ViewPermissionDirective} from './directives/view-permission.directive';
+import {NavSubgroupDirective} from './directives/nav-subgroup.directive';
+import {SearchComponent} from './modules/repo/search/search.component';
+import {BrowseComponent} from './modules/repo/browse/browse.component';
+import {UploadComponent} from './modules/repo/upload/upload.component';
+import {SecurityConfigurationComponent} from './modules/user/security-configuration/security-configuration.component';
 import {CoreModule} from "./modules/core/core.module";
+import {SharedModule} from "./modules/shared/shared.module";
+import {UserModule} from "./modules/user/user.module";
 
 
 @NgModule({
@@ -65,15 +55,7 @@ import {CoreModule} from "./modules/core/core.module";
     SearchComponent,
     BrowseComponent,
     UploadComponent,
-    ManageUsersComponent,
-    ManageRolesComponent,
     SecurityConfigurationComponent,
-    ManageUsersListComponent,
-    ManageUsersAddComponent,
-    PaginatedEntitiesComponent,
-    SortedTableHeaderComponent,
-    SortedTableHeaderRowComponent,
-    ManageUsersEditComponent,
   ],
   imports: [
     BrowserModule,
@@ -81,20 +63,10 @@ import {CoreModule} from "./modules/core/core.module";
     FormsModule,
     ReactiveFormsModule,
     HttpClientModule,
-    TranslateModule.forRoot({
-      compiler: {
-        provide: TranslateCompiler,
-        useClass: TranslateMessageFormatCompiler
-      },
-      loader: {
-        provide: TranslateLoader,
-        useFactory: httpTranslateLoader,
-        deps: [HttpClient]
-      }
-    }),
-      NgbPaginationModule,
-      NgbTooltipModule,
-      CoreModule
+
+      CoreModule,
+      SharedModule,
+      UserModule
   ],
   providers: [
     { provide: MESSAGE_FORMAT_CONFIG, useValue: { locales: ['en', 'de'] }}
@@ -103,6 +75,3 @@ import {CoreModule} from "./modules/core/core.module";
 })
 export class AppModule { }
 
-export function httpTranslateLoader(http: HttpClient) {
-  return new TranslateHttpLoader(http);
-}
\ No newline at end of file
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/core/errors/error-handler.module.ts b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/core/errors/error-handler.module.ts
index 12e16de..e54c0bd 100644
--- a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/core/errors/error-handler.module.ts
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/core/errors/error-handler.module.ts
@@ -30,7 +30,7 @@ import { HttpErrorInterceptor } from './http-error-interceptor';
     CommonModule,
   ],
   providers: [
-    { provide: ErrorHandler, useClass: GlobalErrorHandler },
+    // { provide: ErrorHandler, useClass: GlobalErrorHandler },
     { provide: HTTP_INTERCEPTORS, useClass: HttpErrorInterceptor, multi: true }
     ]
 })
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/about/about.component.html b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/shared/about/about.component.html
similarity index 100%
rename from archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/about/about.component.html
rename to archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/shared/about/about.component.html
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/about/about.component.scss b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/shared/about/about.component.scss
similarity index 100%
rename from archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/about/about.component.scss
rename to archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/shared/about/about.component.scss
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/about/about.component.spec.ts b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/shared/about/about.component.spec.ts
similarity index 100%
rename from archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/about/about.component.spec.ts
rename to archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/shared/about/about.component.spec.ts
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/about/about.component.ts b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/shared/about/about.component.ts
similarity index 100%
rename from archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/about/about.component.ts
rename to archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/shared/about/about.component.ts
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/contact/contact.component.html b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/shared/contact/contact.component.html
similarity index 100%
rename from archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/contact/contact.component.html
rename to archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/shared/contact/contact.component.html
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/contact/contact.component.scss b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/shared/contact/contact.component.scss
similarity index 100%
rename from archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/contact/contact.component.scss
rename to archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/shared/contact/contact.component.scss
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/contact/contact.component.spec.ts b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/shared/contact/contact.component.spec.ts
similarity index 100%
rename from archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/contact/contact.component.spec.ts
rename to archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/shared/contact/contact.component.spec.ts
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/contact/contact.component.ts b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/shared/contact/contact.component.ts
similarity index 100%
rename from archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/contact/contact.component.ts
rename to archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/shared/contact/contact.component.ts
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/home/home.component.html b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/shared/home/home.component.html
similarity index 100%
rename from archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/home/home.component.html
rename to archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/shared/home/home.component.html
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/home/home.component.scss b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/shared/home/home.component.scss
similarity index 100%
rename from archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/home/home.component.scss
rename to archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/shared/home/home.component.scss
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/home/home.component.spec.ts b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/shared/home/home.component.spec.ts
similarity index 100%
rename from archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/home/home.component.spec.ts
rename to archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/shared/home/home.component.spec.ts
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/home/home.component.ts b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/shared/home/home.component.ts
similarity index 100%
rename from archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/home/home.component.ts
rename to archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/shared/home/home.component.ts
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/login/login.component.html b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/shared/login/login.component.html
similarity index 100%
rename from archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/login/login.component.html
rename to archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/shared/login/login.component.html
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/login/login.component.scss b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/shared/login/login.component.scss
similarity index 100%
rename from archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/login/login.component.scss
rename to archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/shared/login/login.component.scss
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/login/login.component.spec.ts b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/shared/login/login.component.spec.ts
similarity index 100%
rename from archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/login/login.component.spec.ts
rename to archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/shared/login/login.component.spec.ts
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/login/login.component.ts b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/shared/login/login.component.ts
similarity index 100%
rename from archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/login/login.component.ts
rename to archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/shared/login/login.component.ts
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/not-found/not-found.component.html b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/shared/not-found/not-found.component.html
similarity index 100%
rename from archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/not-found/not-found.component.html
rename to archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/shared/not-found/not-found.component.html
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/not-found/not-found.component.scss b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/shared/not-found/not-found.component.scss
similarity index 100%
rename from archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/not-found/not-found.component.scss
rename to archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/shared/not-found/not-found.component.scss
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/not-found/not-found.component.spec.ts b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/shared/not-found/not-found.component.spec.ts
similarity index 100%
rename from archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/not-found/not-found.component.spec.ts
rename to archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/shared/not-found/not-found.component.spec.ts
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/not-found/not-found.component.ts b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/shared/not-found/not-found.component.ts
similarity index 100%
rename from archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/not-found/not-found.component.ts
rename to archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/shared/not-found/not-found.component.ts
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/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
similarity index 100%
rename from archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/paginated-entities/paginated-entities.component.html
rename to archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/shared/paginated-entities/paginated-entities.component.html
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/paginated-entities/paginated-entities.component.scss b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/shared/paginated-entities/paginated-entities.component.scss
similarity index 100%
rename from archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/paginated-entities/paginated-entities.component.scss
rename to archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/shared/paginated-entities/paginated-entities.component.scss
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/paginated-entities/paginated-entities.component.spec.ts b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/shared/paginated-entities/paginated-entities.component.spec.ts
similarity index 100%
rename from archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/paginated-entities/paginated-entities.component.spec.ts
rename to archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/shared/paginated-entities/paginated-entities.component.spec.ts
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/shared/paginated-entities/paginated-entities.component.ts
similarity index 100%
rename from archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/paginated-entities/paginated-entities.component.ts
rename to archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/shared/paginated-entities/paginated-entities.component.ts
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
new file mode 100644
index 0000000..93ae0df
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/shared/shared.module.ts
@@ -0,0 +1,71 @@
+/*
+ * 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 { NgModule } from '@angular/core';
+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 {NgbPaginationModule, NgbTooltipModule} 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";
+import {TranslateHttpLoader} from "@ngx-translate/http-loader";
+import {RouterModule} from "@angular/router";
+import {FormsModule} from "@angular/forms";
+
+
+
+@NgModule({
+  declarations: [
+    PaginatedEntitiesComponent,
+    SortedTableHeaderComponent,
+    SortedTableHeaderRowComponent
+  ],
+  exports: [
+      CommonModule,
+      RouterModule,
+      TranslateModule,
+      NgbPaginationModule,
+      NgbTooltipModule,
+      PaginatedEntitiesComponent,
+      SortedTableHeaderComponent,
+      SortedTableHeaderRowComponent
+  ],
+  imports: [
+    CommonModule,
+      RouterModule,
+      NgbPaginationModule,
+      NgbTooltipModule,
+    TranslateModule.forRoot({
+      compiler: {
+        provide: TranslateCompiler,
+        useClass: TranslateMessageFormatCompiler
+      },
+      loader: {
+        provide: TranslateLoader,
+        useFactory: httpTranslateLoader,
+        deps: [HttpClient]
+      }
+    }),
+  ]
+})
+export class SharedModule { }
+export function httpTranslateLoader(http: HttpClient) {
+  return new TranslateHttpLoader(http);
+}
\ No newline at end of file
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/sidemenu/sidemenu.component.html b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/shared/sidemenu/sidemenu.component.html
similarity index 100%
rename from archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/sidemenu/sidemenu.component.html
rename to archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/shared/sidemenu/sidemenu.component.html
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/sidemenu/sidemenu.component.scss b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/shared/sidemenu/sidemenu.component.scss
similarity index 100%
rename from archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/sidemenu/sidemenu.component.scss
rename to archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/shared/sidemenu/sidemenu.component.scss
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/sidemenu/sidemenu.component.spec.ts b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/shared/sidemenu/sidemenu.component.spec.ts
similarity index 100%
rename from archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/sidemenu/sidemenu.component.spec.ts
rename to archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/shared/sidemenu/sidemenu.component.spec.ts
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/sidemenu/sidemenu.component.ts b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/shared/sidemenu/sidemenu.component.ts
similarity index 100%
rename from archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/sidemenu/sidemenu.component.ts
rename to archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/shared/sidemenu/sidemenu.component.ts
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/shared/sorted-table-header-row/sorted-table-header-row.component.html
similarity index 100%
rename from archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/sorted-table-header-row/sorted-table-header-row.component.html
rename to archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/shared/sorted-table-header-row/sorted-table-header-row.component.html
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/shared/sorted-table-header-row/sorted-table-header-row.component.scss
similarity index 100%
rename from archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/sorted-table-header-row/sorted-table-header-row.component.scss
rename to archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/shared/sorted-table-header-row/sorted-table-header-row.component.scss
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/shared/sorted-table-header-row/sorted-table-header-row.component.spec.ts
similarity index 100%
rename from 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
rename to archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/shared/sorted-table-header-row/sorted-table-header-row.component.spec.ts
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/shared/sorted-table-header-row/sorted-table-header-row.component.ts
similarity index 100%
rename from archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/sorted-table-header-row/sorted-table-header-row.component.ts
rename to archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/shared/sorted-table-header-row/sorted-table-header-row.component.ts
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/shared/sorted-table-header/sorted-table-header.component.html
similarity index 100%
rename from archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/sorted-table-header/sorted-table-header.component.html
rename to archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/shared/sorted-table-header/sorted-table-header.component.html
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/shared/sorted-table-header/sorted-table-header.component.scss
similarity index 100%
rename from archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/sorted-table-header/sorted-table-header.component.scss
rename to archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/shared/sorted-table-header/sorted-table-header.component.scss
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/shared/sorted-table-header/sorted-table-header.component.spec.ts
similarity index 100%
rename from archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/sorted-table-header/sorted-table-header.component.spec.ts
rename to archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/shared/sorted-table-header/sorted-table-header.component.spec.ts
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/shared/sorted-table-header/sorted-table-header.component.ts
similarity index 100%
rename from archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/general/sorted-table-header/sorted-table-header.component.ts
rename to archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/shared/sorted-table-header/sorted-table-header.component.ts
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/core/errors/error-handler.module.ts b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/user/user.module.ts
similarity index 50%
copy from archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/core/errors/error-handler.module.ts
copy to archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/user/user.module.ts
index 12e16de..1ca65cc 100644
--- a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/core/errors/error-handler.module.ts
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/user/user.module.ts
@@ -16,22 +16,35 @@
  * under the License.
  */
 
-import { NgModule, ErrorHandler } from '@angular/core';
+import { NgModule } from '@angular/core';
 import { CommonModule } from '@angular/common';
-import { GlobalErrorHandler } from './global-error-handler';
-import { HTTP_INTERCEPTORS } from '@angular/common/http';
-import { HttpErrorInterceptor } from './http-error-interceptor';
+import {ManageUsersComponent} from "./manage-users/manage-users.component";
+import {ManageUsersListComponent} from "./users/manage-users-list/manage-users-list.component";
+import {ManageUsersAddComponent} from "./users/manage-users-add/manage-users-add.component";
+import {ManageUsersEditComponent} from "./users/manage-users-edit/manage-users-edit.component";
+import {SharedModule} from "../shared/shared.module";
+import {FormsModule, ReactiveFormsModule} from "@angular/forms";
 
 
 
 @NgModule({
-  declarations: [],
+  declarations: [
+      ManageUsersComponent,
+      ManageUsersListComponent,
+      ManageUsersAddComponent,
+      ManageUsersEditComponent
+  ],
+  exports: [
+    ManageUsersComponent,
+    ManageUsersListComponent,
+    ManageUsersAddComponent,
+    ManageUsersEditComponent
+  ],
   imports: [
     CommonModule,
-  ],
-  providers: [
-    { provide: ErrorHandler, useClass: GlobalErrorHandler },
-    { provide: HTTP_INTERCEPTORS, useClass: HttpErrorInterceptor, multi: true }
-    ]
+    SharedModule,
+      FormsModule,
+      ReactiveFormsModule
+  ]
 })
-export class ErrorHandlerModule { }
+export class UserModule { }
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/user/users/manage-users-add/manage-users-add.component.ts b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/user/users/manage-users-add/manage-users-add.component.ts
index f148d18..d77f598 100644
--- a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/user/users/manage-users-add/manage-users-add.component.ts
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/user/users/manage-users-add/manage-users-add.component.ts
@@ -18,54 +18,22 @@
  */
 
 import {Component, OnInit} from '@angular/core';
-import {
-    FormBuilder,
-    FormGroup,
-    Validators,
-    FormControl,
-    AsyncValidator,
-    AbstractControl,
-    ValidationErrors,
-    ValidatorFn
-} from '@angular/forms';
+import {AbstractControl, FormBuilder, FormControl, FormGroup, ValidationErrors, ValidatorFn} from '@angular/forms';
 import {UserService} from "../../../../services/user.service";
-import {User} from "../../../../model/user";
 import {ErrorResult} from "../../../../model/error-result";
-import {catchError, debounceTime, distinctUntilChanged, map, switchMap} from "rxjs/operators";
-import {throwError, Observable, of, pipe, timer} from 'rxjs';
-import {environment} from "../../../../../environments/environment";
+import {catchError} from "rxjs/operators";
 import {UserInfo} from "../../../../model/user-info";
+import {ManageUsersBaseComponent} from "../manage-users-base.component";
 
 @Component({
     selector: 'app-manage-users-add',
     templateUrl: './manage-users-add.component.html',
     styleUrls: ['./manage-users-add.component.scss']
 })
-export class ManageUsersAddComponent implements OnInit {
+export class ManageUsersAddComponent extends ManageUsersBaseComponent implements OnInit {
 
-    editProperties = ['user_id', 'full_name', 'email', 'locked', 'password_change_required',
-        'password', 'confirm_password', 'validated'];
-    minUserIdSize = environment.application.minUserIdLength;
-    success: boolean = false;
-    error: boolean = false;
-    errorResult: ErrorResult;
-    result: UserInfo;
-    user: string;
-
-    userForm = this.fb.group({
-        user_id: ['', [Validators.required, Validators.minLength(this.minUserIdSize), whitespaceValidator()],this.userUidExistsValidator()],
-        full_name: ['', Validators.required],
-        email: ['', [Validators.required, Validators.email]],
-        locked: [false],
-        password_change_required: [true],
-        password: [''],
-        confirm_password: [''],
-        validated: [true]
-    }, {
-        validator: MustMatch('password', 'confirm_password')
-    })
-
-    constructor(public userService: UserService, public fb: FormBuilder) {
+    constructor(userService: UserService, fb: FormBuilder) {
+        super(userService, fb);
 
     }
 
@@ -104,40 +72,6 @@ export class ManageUsersAddComponent implements OnInit {
         }
     }
 
-
-    public copyFromForm(properties: string[]): User {
-        let user: any = new User();
-        for (let prop of properties) {
-            user[prop] = this.userForm.get(prop).value;
-        }
-        console.log("User " + user);
-        return user;
-    }
-
-    public copyToForm(properties: string[], user: User): void {
-        let propMap = {};
-        for (let prop of properties) {
-            let propValue = user[prop] == null ? '' : user[prop];
-            propMap[prop] = propValue;
-        }
-        this.userForm.patchValue(propMap);
-        console.log("User " + user);
-    }
-
-
-    valid(field: string): string[] {
-        let formField = this.userForm.get(field);
-        if (formField.dirty || formField.touched) {
-            if (formField.valid) {
-                return ['is-valid']
-            } else {
-                return ['is-invalid']
-            }
-        } else {
-            return ['']
-        }
-    }
-
     getAllErrors(formGroup: FormGroup, errors: string[] = []) : string[] {
         Object.keys(formGroup.controls).forEach(field => {
             const control = formGroup.get(field);
@@ -155,56 +89,9 @@ export class ManageUsersAddComponent implements OnInit {
         return Object.keys(this.userForm.get(control).errors);
     }
 
-    /**
-     * Async validator with debounce time
-     * @constructor
-     */
-    userUidExistsValidator() {
-
-        return (ctrl : FormControl) => {
-            // debounceTimer() does not work here, as the observable is created with each keystroke
-            // but angular does unsubscribe on previous started async observables.
-            return timer(500).pipe(
-                switchMap((userid) => this.userService.userExists(ctrl.value)),
-                catchError(() => of(null)),
-                map(exists => (exists ? {userexists: true} : null))
-            );
-        }
-    }
-
-    forbiddenNameValidator(nameRe: RegExp): ValidatorFn {
-        return (control: AbstractControl): {[key: string]: any} | null => {
-            const forbidden = nameRe.test(control.value);
-            return forbidden ? {forbiddenName: {value: control.value}} : null;
-        };
-    }
-
 
 
 }
 
-export function whitespaceValidator(): ValidatorFn {
-    return (control: AbstractControl): ValidationErrors | null => {
-        const hasWhitespace =  /\s/g.test(control.value);
-        return hasWhitespace ? {containsWhitespace: {value: control.value}} : null;
-    };
-}
-export function MustMatch(controlName: string, matchingControlName: string) : ValidatorFn  {
-    return (formGroup: FormGroup): ValidationErrors | null => {
-        const control = formGroup.controls[controlName];
-        const matchingControl = formGroup.controls[matchingControlName];
-
-        if (matchingControl.errors && !matchingControl.errors.mustMatch) {
-            // return if another validator has already found an error on the matchingControl
-            return;
-        }
 
-        // set error on matchingControl if validation fails
-        if (control.value !== matchingControl.value) {
-            matchingControl.setErrors({mustMatch: true});
-        } else {
-            matchingControl.setErrors(null);
-        }
-    }
-}
 
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/user/users/manage-users-add/manage-users-add.component.ts b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/user/users/manage-users-base.component.ts
similarity index 59%
copy from archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/user/users/manage-users-add/manage-users-add.component.ts
copy to archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/user/users/manage-users-base.component.ts
index f148d18..c6ea8a9 100644
--- a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/user/users/manage-users-add/manage-users-add.component.ts
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/user/users/manage-users-base.component.ts
@@ -8,7 +8,6 @@
  * 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
@@ -17,31 +16,24 @@
  * under the License.
  */
 
-import {Component, OnInit} from '@angular/core';
+import {environment} from "../../../../environments/environment";
+import {ErrorResult} from "../../../model/error-result";
+import {UserInfo} from "../../../model/user-info";
 import {
-    FormBuilder,
-    FormGroup,
-    Validators,
-    FormControl,
-    AsyncValidator,
     AbstractControl,
+    FormControl,
+    ValidatorFn,
+    Validators,
+    FormBuilder,
     ValidationErrors,
-    ValidatorFn
-} from '@angular/forms';
-import {UserService} from "../../../../services/user.service";
-import {User} from "../../../../model/user";
-import {ErrorResult} from "../../../../model/error-result";
-import {catchError, debounceTime, distinctUntilChanged, map, switchMap} from "rxjs/operators";
-import {throwError, Observable, of, pipe, timer} from 'rxjs';
-import {environment} from "../../../../../environments/environment";
-import {UserInfo} from "../../../../model/user-info";
-
-@Component({
-    selector: 'app-manage-users-add',
-    templateUrl: './manage-users-add.component.html',
-    styleUrls: ['./manage-users-add.component.scss']
-})
-export class ManageUsersAddComponent implements OnInit {
+    FormGroup
+} from "@angular/forms";
+import {User} from "../../../model/user";
+import {of, timer} from "rxjs";
+import {catchError, map, switchMap} from "rxjs/operators";
+import { UserService } from 'src/app/services/user.service';
+
+export class ManageUsersBaseComponent {
 
     editProperties = ['user_id', 'full_name', 'email', 'locked', 'password_change_required',
         'password', 'confirm_password', 'validated'];
@@ -53,7 +45,7 @@ export class ManageUsersAddComponent implements OnInit {
     user: string;
 
     userForm = this.fb.group({
-        user_id: ['', [Validators.required, Validators.minLength(this.minUserIdSize), whitespaceValidator()],this.userUidExistsValidator()],
+        user_id: ['', [Validators.required, Validators.minLength(this.minUserIdSize), whitespaceValidator()], this.userUidExistsValidator()],
         full_name: ['', Validators.required],
         email: ['', [Validators.required, Validators.email]],
         locked: [false],
@@ -66,42 +58,6 @@ export class ManageUsersAddComponent implements OnInit {
     })
 
     constructor(public userService: UserService, public fb: FormBuilder) {
-
-    }
-
-    ngOnInit(): void {
-    }
-
-    onSubmit() {
-        // Process checkout data here
-        this.result = null;
-        if (this.userForm.valid) {
-            let user = this.copyFromForm(this.editProperties);
-            console.info('Adding user ' + user);
-            this.userService.addUser(user).pipe(catchError((error: ErrorResult) => {
-                // console.log("Error " + error + " - " + typeof (error) + " - " + JSON.stringify(error));
-                if (error.status == 422) {
-                    // console.warn("Validation error");
-                    let pwdErrors = {};
-                    for (let message of error.error_messages) {
-                        if (message.error_key.startsWith('user.password.violation')) {
-                            pwdErrors[message.error_key] = message.message;
-                        }
-                    }
-                    this.userForm.get('password').setErrors(pwdErrors);
-
-                }
-                this.errorResult = error;
-                this.success = false;
-                this.error = true;
-                return [];
-                // return throwError(error);
-            })).subscribe((user: UserInfo) => {
-                this.result = user;
-                this.success = true;
-                this.error = false;
-            });
-        }
     }
 
 
@@ -138,30 +94,13 @@ export class ManageUsersAddComponent implements OnInit {
         }
     }
 
-    getAllErrors(formGroup: FormGroup, errors: string[] = []) : string[] {
-        Object.keys(formGroup.controls).forEach(field => {
-            const control = formGroup.get(field);
-            if (control instanceof FormControl && control.errors != null) {
-                let keys = Object.keys(control.errors).map(errorKey=>field+'.'+errorKey);
-                errors = errors.concat(keys);
-            } else if (control instanceof FormGroup) {
-                errors = errors.concat(this.getAllErrors(control));
-            }
-        });
-        return errors;
-    }
-
-    getAttributeErrors(control:string):string[] {
-        return Object.keys(this.userForm.get(control).errors);
-    }
-
     /**
      * Async validator with debounce time
      * @constructor
      */
     userUidExistsValidator() {
 
-        return (ctrl : FormControl) => {
+        return (ctrl: FormControl) => {
             // debounceTimer() does not work here, as the observable is created with each keystroke
             // but angular does unsubscribe on previous started async observables.
             return timer(500).pipe(
@@ -173,14 +112,11 @@ export class ManageUsersAddComponent implements OnInit {
     }
 
     forbiddenNameValidator(nameRe: RegExp): ValidatorFn {
-        return (control: AbstractControl): {[key: string]: any} | null => {
+        return (control: AbstractControl): { [key: string]: any } | null => {
             const forbidden = nameRe.test(control.value);
             return forbidden ? {forbiddenName: {value: control.value}} : null;
         };
     }
-
-
-
 }
 
 export function whitespaceValidator(): ValidatorFn {
@@ -206,5 +142,4 @@ export function MustMatch(controlName: string, matchingControlName: string) : Va
             matchingControl.setErrors(null);
         }
     }
-}
-
+}
\ No newline at end of file
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/user/users/manage-users-edit/manage-users-edit.component.ts b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/user/users/manage-users-edit/manage-users-edit.component.ts
index 7a01f25..f7eead0 100644
--- a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/user/users/manage-users-edit/manage-users-edit.component.ts
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/user/users/manage-users-edit/manage-users-edit.component.ts
@@ -19,17 +19,16 @@
 import { Component, OnInit } from '@angular/core';
 import { ActivatedRoute } from '@angular/router';
 import {UserService} from "../../../../services/user.service";
-import {FormBuilder, FormControl, Validators} from "@angular/forms";
-import {ManageUsersAddComponent, MustMatch} from "../manage-users-add/manage-users-add.component";
-import {environment} from "../../../../../environments/environment";
+import {FormBuilder, FormControl} from "@angular/forms";
 import {map, switchMap} from 'rxjs/operators';
+import {ManageUsersBaseComponent} from "../manage-users-base.component";
 
 @Component({
   selector: 'app-manage-users-edit',
   templateUrl: './manage-users-edit.component.html',
   styleUrls: ['./manage-users-edit.component.scss']
 })
-export class ManageUsersEditComponent extends ManageUsersAddComponent implements OnInit {
+export class ManageUsersEditComponent extends ManageUsersBaseComponent implements OnInit {
 
   editProperties = ['user_id', 'full_name', 'email', 'locked', 'password_change_required',
     'password', 'confirm_password', 'validated'];
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/services/authentication.service.ts b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/services/authentication.service.ts
index 978aa44..519eb27 100644
--- a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/services/authentication.service.ts
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/services/authentication.service.ts
@@ -34,6 +34,7 @@ import {UserInfo} from "../model/user-info";
 })
 export class AuthenticationService {
     authenticated: boolean;
+    authenticating: boolean;
 
     /**
      * The LoginEvent is emitted, when a successful login happened. And the corresponding user info was retrieved.
@@ -49,10 +50,17 @@ export class AuthenticationService {
     constructor(private rest: ArchivaRequestService,
                 private userService: UserService) {
         this.authenticated = false;
+        this.LoginEvent.subscribe((info)=>{
+            this.authenticating=false;
+        })
+        this.LogoutEvent.subscribe(()=>{
+            this.authenticating=false;
+        })
         this.restoreLoginData();
     }
 
     private restoreLoginData() {
+        console.debug("Restoring login data");
         let accessToken = localStorage.getItem("access_token");
         if (accessToken != null) {
             let expirationDate = localStorage.getItem("token_expire");
@@ -60,6 +68,8 @@ export class AuthenticationService {
                 let expDate = new Date(expirationDate);
                 let currentDate = new Date();
                 if (currentDate < expDate) {
+                    console.debug("Retrieving user information");
+                    this.authenticating=true;
                     let observer = this.userService.retrieveUserInfo();
                     observer.subscribe({
                             next: (userInfo: UserInfo) => {
@@ -80,6 +90,9 @@ export class AuthenticationService {
                             error: (err: HttpErrorResponse) => {
                                 console.debug("Error retrieving user info: " + JSON.stringify(err));
                                 this.logout();
+                            },
+                            complete: () => {
+                                this.authenticating=false;
                             }
                         }
                     );
@@ -104,7 +117,7 @@ export class AuthenticationService {
      * @param resultHandler A result handler that is executed, after calling the login service
      */
     login(userid: string, password: string, resultHandler: (n: string, err?: ErrorMessage[]) => void) {
-
+        this.authenticating=true;
         const data = {
             'grant_type': 'authorization_code',
             'client_id': environment.application.client_id,
@@ -134,6 +147,7 @@ export class AuthenticationService {
                 resultHandler("OK");
             },
             error: (err: HttpErrorResponse) => {
+                this.authenticating = false;
                 console.log("Error " + (JSON.stringify(err)));
                 let result = err.error as ErrorResult
                 if (result.error_messages != null) {
@@ -146,7 +160,9 @@ export class AuthenticationService {
                 }
 
             },
-            // complete: () => console.log('Observer got a complete notification'),
+            complete: () => {
+                this.authenticating = false;
+            }
         };
         authObserver.subscribe(tokenObserver)
 
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/services/routing-guard.service.ts b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/services/routing-guard.service.ts
index 0e7a079..24f932f 100644
--- a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/services/routing-guard.service.ts
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/services/routing-guard.service.ts
@@ -16,9 +16,13 @@
  * under the License.
  */
 
-import { Injectable } from '@angular/core';
+import {Injectable, OnInit} from '@angular/core';
 import {UserService} from "./user.service";
 import {CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, Router} from "@angular/router";
+import {AuthenticationService} from "./authentication.service";
+import {first, timeout, tap, map, take} from "rxjs/operators";
+import { Observable } from 'rxjs';
+import { UserInfo } from '../model/user-info';
 
 /**
  * Guard for the routes, that checks permissions by querying the uiPermission map of the UserService.
@@ -28,18 +32,37 @@ import {CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, Router} from "
 @Injectable({
   providedIn: 'root'
 })
-export class RoutingGuardService implements CanActivate {
+export class RoutingGuardService implements CanActivate, OnInit {
 
-  constructor(private userService:UserService, public router: Router) {
+  constructor(private userService:UserService, public router: Router, private authService: AuthenticationService) {
 
   }
 
-  canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
+  canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
     const permString = route.data.perm;
     if (permString==null || permString=='') {
       console.error("Guard active, but permissions not set for route " + state.url);
       return false;
     }
+    if (this.authService.authenticating) {
+      console.debug("Guard: Authentication service is in authentication process");
+      return this.authService.LoginEvent.pipe(take(1),timeout(1000), map(()=>{
+        const myPerm = this.getPermission(permString);
+        if (!myPerm) {
+          this.router.navigate(['']);
+        }
+        return myPerm;
+      }));
+    }
+    let perm = this.getPermission(permString);
+    console.debug("Permission for " + state.url + ": " + perm);
+    if (!perm) {
+      this.router.navigate(['']);
+    }
+    return perm;
+  }
+
+  private getPermission(permString: string) {
     let perm = this.userService.uiPermissions;
     for (let permPath of permString.split(/\./)) {
       perm = perm[permPath];
@@ -48,10 +71,11 @@ export class RoutingGuardService implements CanActivate {
         break;
       }
     }
-    console.debug("Permission for " + state.url + ": " + perm);
-    if (!perm) {
-      this.router.navigate(['']);
-    }
     return perm;
   }
+
+
+  ngOnInit(): void {
+  }
 }
+
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 5205bfc..f6eccab 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
@@ -88,7 +88,7 @@ export class UserService implements OnInit, OnDestroy {
                     console.log("Could not retrieve permissions " + err);
                 }
             }
-            this.retrievePermissionInfo().subscribe(observer);
+            this.retrievePermissionInfo("guest").subscribe(observer);
         }
     }
 
@@ -138,34 +138,56 @@ export class UserService implements OnInit, OnDestroy {
     /**
      * Retrieves the permission list from the REST service
      */
-    public retrievePermissionInfo(): Observable<Permission[]> {
-        return new Observable<Permission[]>((resultObserver) => {
-            let userName = this.authenticated ? "me" : "guest";
-            let infoObserver = this.rest.executeRestCall<Permission[]>("get", "redback", "users/" + userName + "/permissions", null);
-            let permissionObserver = {
-                next: (x: Permission[]) => {
-                    this.permissions = x;
-                    this.parsePermissions(x);
-                    resultObserver.next(this.permissions);
-                },
-                error: (err: HttpErrorResponse) => {
-                    console.log("Error " + (JSON.stringify(err)));
-                    let result = err.error as ErrorResult
-                    if (result.error_messages != null) {
-                        for (let msg of result.error_messages) {
-                            console.debug('Observer got an error: ' + msg.error_key)
-                        }
+    public retrievePermissionInfo(userNameParam?:string): Observable<Permission[]> {
+        let userName;
+        if (userNameParam==null||userNameParam=='') {
+            userName = this.authenticated ? "me" : "guest";
+        } else {
+            userName = userNameParam;
+        }
+        return this.rest.executeRestCall<Permission[]>("get", "redback", "users/" + userName + "/permissions", null).pipe(
+            catchError((err:HttpErrorResponse)=> {
+                console.log("Error " + (JSON.stringify(err)));
+                let result = err.error as ErrorResult
+                if (result.error_messages != null) {
+                    for (let msg of result.error_messages) {
+                        console.debug('Observer got an error: ' + msg.error_key)
                     }
-                    this.resetPermissions();
-                    resultObserver.error(err);
-                },
-                complete: () => {
-                    resultObserver.complete();
                 }
-            };
-            infoObserver.subscribe(permissionObserver);
+                this.resetPermissions();
+                return [];
+            }), map((perm:Permission[])=>{
+                this.permissions = perm;
+                this.parsePermissions(perm);
+                return perm;
+                })
+        );
 
-        });
+        // return new Observable<Permission[]>((resultObserver) => {
+        //     let permissionObserver = {
+        //         next: (x: Permission[]) => {
+        //             this.permissions = x;
+        //             this.parsePermissions(x);
+        //             resultObserver.next(this.permissions);
+        //         },
+        //         error: (err: HttpErrorResponse) => {
+        //             console.log("Error " + (JSON.stringify(err)));
+        //             let result = err.error as ErrorResult
+        //             if (result.error_messages != null) {
+        //                 for (let msg of result.error_messages) {
+        //                     console.debug('Observer got an error: ' + msg.error_key)
+        //                 }
+        //             }
+        //             this.resetPermissions();
+        //             resultObserver.error(err);
+        //         },
+        //         complete: () => {
+        //             resultObserver.complete();
+        //         }
+        //     };
+        //     infoObserver.subscribe(permissionObserver);
+        //
+        // });
     }
 
     resetPermissions() {