From a687b24e8a4cd8ee5fc3f27612e2d1ef788c48f0 Mon Sep 17 00:00:00 2001
From: Bezak <bezak@netgrif.com>
Date: Mon, 12 Sep 2022 21:47:54 +0200
Subject: [PATCH 01/21] [NAE-1678] User impersonation - add components and
 services for user impersonation - extend UserResource, User and
 UserTransformer classes - add demo component to example app

---
 nae.json                                      | 17 ++++-
 .../nae-example-app/src/app/app.module.ts     |  4 +-
 .../impersonation.component.html              |  1 +
 .../impersonation.component.scss              |  0
 .../impersonation.component.spec.ts           | 25 +++++++
 .../impersonation/impersonation.component.ts  | 24 ++++++
 .../src/app/nae-example-app-view.service.ts   |  2 +
 .../authentication/models/user.transformer.ts |  3 +-
 .../src/lib/filter/filter.repository.ts       |  7 ++
 .../src/lib/impersonation/public-api.ts       |  6 ++
 .../impersonation-user-list.service.ts        | 22 ++++++
 .../impersonation-user-resource.service.ts    | 24 ++++++
 .../impersonation-user-select.service.ts      | 30 ++++++++
 .../services/impersonation.service.ts         | 68 +++++++++++++++++
 .../lib/resources/interface/user-resource.ts  |  1 +
 .../content-components/injection-tokens.ts    |  1 +
 .../src/lib/user/models/user.ts               | 10 ++-
 .../netgrif-components-core/src/public-api.ts |  1 +
 .../content-components/public-api.ts          |  2 +
 .../side-menu-content-component.module.ts     |  8 +-
 ...-menu-user-impersonate-component.module.ts | 34 +++++++++
 .../user-assign-item.component.theme.scss     | 15 ++++
 .../user-impersonate-item.component.html      |  9 +++
 .../user-impersonate-item.component.scss      | 24 ++++++
 .../user-impersonate-item.component.spec.ts   | 42 +++++++++++
 .../user-impersonate-item.component.ts        | 17 +++++
 .../user-impersonate-list.component.html      | 27 +++++++
 .../user-impersonate-list.component.scss      | 13 ++++
 .../user-impersonate-list.component.spec.ts   | 74 +++++++++++++++++++
 .../user-impersonate-list.component.ts        | 17 +++++
 .../user-impersonate.component.html           | 29 ++++++++
 .../user-impersonate.component.scss           | 15 ++++
 .../user-impersonate.component.spec.ts        | 61 +++++++++++++++
 .../user-impersonate.component.ts             | 22 ++++++
 34 files changed, 649 insertions(+), 6 deletions(-)
 create mode 100644 projects/nae-example-app/src/app/doc/impersonation/impersonation.component.html
 create mode 100644 projects/nae-example-app/src/app/doc/impersonation/impersonation.component.scss
 create mode 100644 projects/nae-example-app/src/app/doc/impersonation/impersonation.component.spec.ts
 create mode 100644 projects/nae-example-app/src/app/doc/impersonation/impersonation.component.ts
 create mode 100644 projects/netgrif-components-core/src/lib/impersonation/public-api.ts
 create mode 100644 projects/netgrif-components-core/src/lib/impersonation/services/impersonation-user-list.service.ts
 create mode 100644 projects/netgrif-components-core/src/lib/impersonation/services/impersonation-user-resource.service.ts
 create mode 100644 projects/netgrif-components-core/src/lib/impersonation/services/impersonation-user-select.service.ts
 create mode 100644 projects/netgrif-components-core/src/lib/impersonation/services/impersonation.service.ts
 create mode 100644 projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/side-menu-user-impersonate-component.module.ts
 create mode 100644 projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate-list/user-impersonate-item/theme/user-assign-item.component.theme.scss
 create mode 100644 projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate-list/user-impersonate-item/user-impersonate-item.component.html
 create mode 100644 projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate-list/user-impersonate-item/user-impersonate-item.component.scss
 create mode 100644 projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate-list/user-impersonate-item/user-impersonate-item.component.spec.ts
 create mode 100644 projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate-list/user-impersonate-item/user-impersonate-item.component.ts
 create mode 100644 projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate-list/user-impersonate-list.component.html
 create mode 100644 projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate-list/user-impersonate-list.component.scss
 create mode 100644 projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate-list/user-impersonate-list.component.spec.ts
 create mode 100644 projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate-list/user-impersonate-list.component.ts
 create mode 100644 projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate.component.html
 create mode 100644 projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate.component.scss
 create mode 100644 projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate.component.spec.ts
 create mode 100644 projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate.component.ts

diff --git a/nae.json b/nae.json
index 377ed82d78..d0a0778275 100644
--- a/nae.json
+++ b/nae.json
@@ -164,6 +164,17 @@
                 "path": "recover/:token"
             }
         },
+        "demo-impersonation": {
+            "component": {
+                "class": "ImpersonationComponent",
+                "from": "./doc/impersonation/impersonation.component"
+            },
+            "access": "private",
+            "navigation": true,
+            "routing": {
+                "path": "impersonation-view"
+            }
+        },
         "demo-drawer": {
             "component": {
                 "class": "DrawerExampleComponent",
@@ -216,7 +227,9 @@
                         "from": "./doc/workflow-view-example/workflow-view-example.component"
                     },
                     "access": {
-                        "authority": ["ROLE_ADMIN"]
+                        "authority": [
+                            "ROLE_ADMIN"
+                        ]
                     },
                     "navigation": {
                         "title": "Workflow view",
@@ -1257,4 +1270,4 @@
             "groupNavigationRoute": "group-nav"
         }
     }
-}
+}
\ No newline at end of file
diff --git a/projects/nae-example-app/src/app/app.module.ts b/projects/nae-example-app/src/app/app.module.ts
index fbb2a08c88..334c09d5a0 100644
--- a/projects/nae-example-app/src/app/app.module.ts
+++ b/projects/nae-example-app/src/app/app.module.ts
@@ -98,6 +98,7 @@ import { WrapperEmptyViewComponent } from './views/wrapper/wrapper-empty-view.co
 import {DoubleDrawerExampleComponent} from './doc/double-drawer-example/double-drawer-example.component';
 import { PublicSingleTaskViewComponent } from './doc/public-single-task-view/public-single-task-view.component';
 import { BreadcrumbsExampleComponent } from './doc/breadcrumbs-example/breadcrumbs-example.component';
+import { ImpersonationComponent } from './doc/impersonation/impersonation.component';
 
 export function HttpLoaderFactory(http: HttpClient) {
     return new TranslateHttpLoader(http);
@@ -152,7 +153,8 @@ export function HttpLoaderFactory(http: HttpClient) {
         WrapperEmptyViewComponent,
         DoubleDrawerExampleComponent,
         PublicSingleTaskViewComponent,
-        BreadcrumbsExampleComponent
+        BreadcrumbsExampleComponent,
+        ImpersonationComponent,
     ],
     imports: [
         BrowserModule,
diff --git a/projects/nae-example-app/src/app/doc/impersonation/impersonation.component.html b/projects/nae-example-app/src/app/doc/impersonation/impersonation.component.html
new file mode 100644
index 0000000000..17bf23a84b
--- /dev/null
+++ b/projects/nae-example-app/src/app/doc/impersonation/impersonation.component.html
@@ -0,0 +1 @@
+<p (click)="test()">impersonation works!</p>
diff --git a/projects/nae-example-app/src/app/doc/impersonation/impersonation.component.scss b/projects/nae-example-app/src/app/doc/impersonation/impersonation.component.scss
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/projects/nae-example-app/src/app/doc/impersonation/impersonation.component.spec.ts b/projects/nae-example-app/src/app/doc/impersonation/impersonation.component.spec.ts
new file mode 100644
index 0000000000..3a89b2fd51
--- /dev/null
+++ b/projects/nae-example-app/src/app/doc/impersonation/impersonation.component.spec.ts
@@ -0,0 +1,25 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { ImpersonationComponent } from './impersonation.component';
+
+describe('ImpersonationComponent', () => {
+  let component: ImpersonationComponent;
+  let fixture: ComponentFixture<ImpersonationComponent>;
+
+  beforeEach(async () => {
+    await TestBed.configureTestingModule({
+      declarations: [ ImpersonationComponent ]
+    })
+    .compileComponents();
+  });
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(ImpersonationComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});
diff --git a/projects/nae-example-app/src/app/doc/impersonation/impersonation.component.ts b/projects/nae-example-app/src/app/doc/impersonation/impersonation.component.ts
new file mode 100644
index 0000000000..8ef7ffcba6
--- /dev/null
+++ b/projects/nae-example-app/src/app/doc/impersonation/impersonation.component.ts
@@ -0,0 +1,24 @@
+import { Component, OnInit } from '@angular/core';
+import {
+    ImpersonationUserSelectService
+} from '../../../../../netgrif-components-core/src/lib/impersonation/services/impersonation-user-select.service';
+
+@Component({
+  selector: 'nae-app-impersonation',
+  templateUrl: './impersonation.component.html',
+  styleUrls: ['./impersonation.component.scss']
+})
+export class ImpersonationComponent implements OnInit {
+
+  constructor(
+      private _impersonate: ImpersonationUserSelectService
+  ) { }
+
+  ngOnInit(): void {
+  }
+
+  public test(): void {
+      this._impersonate.selectImpersonate();
+  }
+
+}
diff --git a/projects/nae-example-app/src/app/nae-example-app-view.service.ts b/projects/nae-example-app/src/app/nae-example-app-view.service.ts
index 11000737c3..c36a439ef8 100644
--- a/projects/nae-example-app/src/app/nae-example-app-view.service.ts
+++ b/projects/nae-example-app/src/app/nae-example-app-view.service.ts
@@ -39,6 +39,7 @@ import {WrapperEmptyViewComponent} from './views/wrapper/wrapper-empty-view.comp
 import {DoubleDrawerExampleComponent} from './doc/double-drawer-example/double-drawer-example.component';
 import {PublicSingleTaskViewComponent} from './doc/public-single-task-view/public-single-task-view.component';
 import {BreadcrumbsExampleComponent} from './doc/breadcrumbs-example/breadcrumbs-example.component';
+import { ImpersonationComponent } from './doc/impersonation/impersonation.component';
 
 @Injectable({
     providedIn: 'root'
@@ -48,6 +49,7 @@ export class NaeExampleAppViewService extends ViewService {
         // This class is managed by schematics. Do not modify it by hand.
         // If you want to add views to the application run the 'create-view' schematic.
         super([
+			{id: 'ImpersonationComponent', class: ImpersonationComponent},
             {id: 'BreadcrumbsExampleComponent', class: BreadcrumbsExampleComponent},
             {id: 'TitleConfigComponent', class: TitleConfigComponent},
             {id: 'PublicSingleTaskViewComponent', class: PublicSingleTaskViewComponent},
diff --git a/projects/netgrif-components-core/src/lib/authentication/models/user.transformer.ts b/projects/netgrif-components-core/src/lib/authentication/models/user.transformer.ts
index fc87921153..8a61e5ddde 100644
--- a/projects/netgrif-components-core/src/lib/authentication/models/user.transformer.ts
+++ b/projects/netgrif-components-core/src/lib/authentication/models/user.transformer.ts
@@ -24,7 +24,8 @@ export class UserTransformer implements Transformer<UserResource, User> {
             this.transformAuthorities(user.authorities),
             user.processRoles,
             groups,
-            user.nextGroups);
+            user.nextGroups,
+            user.impersonated ? this.transform(user.impersonated) : undefined);
 
     }
 
diff --git a/projects/netgrif-components-core/src/lib/filter/filter.repository.ts b/projects/netgrif-components-core/src/lib/filter/filter.repository.ts
index 4a8b20afc1..eae192747e 100644
--- a/projects/netgrif-components-core/src/lib/filter/filter.repository.ts
+++ b/projects/netgrif-components-core/src/lib/filter/filter.repository.ts
@@ -138,4 +138,11 @@ export class FilterRepository {
         });
         return result;
     }
+
+    /**
+     * Removes all stored filters from the repository
+     */
+    public removeAllFilters(): void {
+        this._filters = new Map<string, Filter>();
+    }
 }
diff --git a/projects/netgrif-components-core/src/lib/impersonation/public-api.ts b/projects/netgrif-components-core/src/lib/impersonation/public-api.ts
new file mode 100644
index 0000000000..7ec0e29cf5
--- /dev/null
+++ b/projects/netgrif-components-core/src/lib/impersonation/public-api.ts
@@ -0,0 +1,6 @@
+
+/* SERVICES */
+export * from './services/impersonation.service';
+export * from './services/impersonation-user-select.service';
+export * from './services/impersonation-user-list.service';
+export * from './services/impersonation-user-resource.service';
diff --git a/projects/netgrif-components-core/src/lib/impersonation/services/impersonation-user-list.service.ts b/projects/netgrif-components-core/src/lib/impersonation/services/impersonation-user-list.service.ts
new file mode 100644
index 0000000000..23e674ca9b
--- /dev/null
+++ b/projects/netgrif-components-core/src/lib/impersonation/services/impersonation-user-list.service.ts
@@ -0,0 +1,22 @@
+import {UserListItem, UserListService} from '../../user/services/user-list.service';
+import {Injectable} from '@angular/core';
+import {SnackBarService} from '../../snack-bar/services/snack-bar.service';
+import {TranslateService} from '@ngx-translate/core';
+import {LoggerService} from '../../logger/services/logger.service';
+import {ImpersonationUserResourceService} from './impersonation-user-resource.service';
+import {Observable} from 'rxjs';
+
+@Injectable()
+export class ImpersonationUserListService extends UserListService {
+
+    constructor(_resources: ImpersonationUserResourceService,
+                protected _logService: LoggerService,
+                _snackbar: SnackBarService,
+                _translate: TranslateService) {
+        super(_resources, _logService, _snackbar, _translate);
+    }
+
+    public loadPage(page: number): Observable<{ [k: string]: UserListItem }> {
+        return super.loadPage(page);
+    }
+}
diff --git a/projects/netgrif-components-core/src/lib/impersonation/services/impersonation-user-resource.service.ts b/projects/netgrif-components-core/src/lib/impersonation/services/impersonation-user-resource.service.ts
new file mode 100644
index 0000000000..88d6bf191f
--- /dev/null
+++ b/projects/netgrif-components-core/src/lib/impersonation/services/impersonation-user-resource.service.ts
@@ -0,0 +1,24 @@
+import {Injectable} from '@angular/core';
+import {UserResourceService} from '../../resources/engine-endpoint/user-resource.service';
+import {ResourceProvider} from '../../resources/resource-provider.service';
+import {ConfigurationService} from '../../configuration/configuration.service';
+import {Params} from '@angular/router';
+import {Observable} from 'rxjs';
+import {Page} from '../../resources/interface/page';
+import {UserResource} from '../../resources/interface/user-resource';
+import {map} from 'rxjs/operators';
+
+@Injectable({
+    providedIn: 'root'
+})
+export class ImpersonationUserResourceService extends UserResourceService {
+
+    constructor(protected provider: ResourceProvider, protected _configService: ConfigurationService) {
+        super(provider, _configService);
+    }
+
+    public search(body: object, params?: Params): Observable<Page<UserResource>> {
+        return this.provider.post$('/impersonate/search', this.SERVER_URL, {query: (body as any).fulltext}, params)
+            .pipe(map((r) => this.getResourcePage<UserResource>(r, 'users')));
+    }
+}
diff --git a/projects/netgrif-components-core/src/lib/impersonation/services/impersonation-user-select.service.ts b/projects/netgrif-components-core/src/lib/impersonation/services/impersonation-user-select.service.ts
new file mode 100644
index 0000000000..398b9d002f
--- /dev/null
+++ b/projects/netgrif-components-core/src/lib/impersonation/services/impersonation-user-select.service.ts
@@ -0,0 +1,30 @@
+import {Inject, Injectable, Optional} from '@angular/core';
+import {ImpersonationService} from "./impersonation.service";
+import {NAE_USER_IMPERSONATE_COMPONENT} from '../../side-menu/content-components/injection-tokens';
+import {LoggerService} from '../../logger/services/logger.service';
+import {SnackBarService} from '../../snack-bar/services/snack-bar.service';
+import {SideMenuService} from '../../side-menu/services/side-menu.service';
+import {SideMenuSize} from '../../side-menu/models/side-menu-size';
+
+@Injectable({
+  providedIn: 'root'
+})
+export class ImpersonationUserSelectService {
+
+    constructor(protected _log: LoggerService,
+                protected _sideMenuService: SideMenuService,
+                protected _snackBar: SnackBarService,
+                protected _impersonation: ImpersonationService,
+                @Optional() @Inject(NAE_USER_IMPERSONATE_COMPONENT) protected _userImpersonateComponent: any,
+    ) {}
+
+    public selectImpersonate(): void {
+        this._sideMenuService.open(this._userImpersonateComponent, SideMenuSize.MEDIUM).onClose.subscribe(event => {
+            this._log.debug('Impersonable user select :' + event);
+            if (event.data === undefined) {
+                return;
+            }
+            this._impersonation.impersonate(event.data._id);
+        });
+    }
+}
diff --git a/projects/netgrif-components-core/src/lib/impersonation/services/impersonation.service.ts b/projects/netgrif-components-core/src/lib/impersonation/services/impersonation.service.ts
new file mode 100644
index 0000000000..bd9d906a76
--- /dev/null
+++ b/projects/netgrif-components-core/src/lib/impersonation/services/impersonation.service.ts
@@ -0,0 +1,68 @@
+import {Injectable} from '@angular/core';
+import {Router} from '@angular/router';
+import {take} from 'rxjs/operators';
+import {TranslateService} from '@ngx-translate/core';
+import {AbstractResourceService, ResourceProvider} from '../../resources/public-api';
+import {ConfigurationService} from '../../configuration/configuration.service';
+import {UserService} from '../../user/services/user.service';
+import {SnackBarService} from '../../snack-bar/services/snack-bar.service';
+import {FilterRepository} from '../../filter/filter.repository';
+import {LoggerService} from '../../logger/services/logger.service';
+
+@Injectable({
+    providedIn: 'root'
+})
+export class ImpersonationService extends AbstractResourceService {
+
+    public constructor(protected provider: ResourceProvider,
+                       protected _router: Router,
+                       protected _configService: ConfigurationService,
+                       protected _userService: UserService,
+                       protected _snackbar: SnackBarService,
+                       protected _filter: FilterRepository,
+                       protected _log: LoggerService,
+                       private _translate: TranslateService) {
+        super('impersonation', provider, _configService);
+    }
+
+    public impersonate(userId: number): void {
+        this.provider.post$('impersonate/' + userId, this.SERVER_URL, {}).subscribe(user => {
+            this._triggerReload();
+            this._snackbar.openSuccessSnackBar(this._translate.instant('impersonation.user.successfullyRepresented'));
+        }, (response => {
+            if (response.status === 400) {
+                response.error.alreadyImpersonated ?
+                    this._snackbar.openErrorSnackBar(this._translate.instant('impersonation.user.currentlyAlreadyRepresented')) :
+                    this._snackbar.openErrorSnackBar(this._translate.instant('impersonation.user.currentlyLogged'));
+            } else {
+                this._snackbar.openErrorSnackBar(this._translate.instant('impersonation.action.failed'));
+            }
+        }));
+    }
+
+    public cease(): void {
+        this.provider.post$('impersonate/clear', this.SERVER_URL, {}).subscribe(user => {
+            this._snackbar.openSuccessSnackBar(this._translate.instant('impersonation.action.deactivated'));
+            return this._triggerReload();
+        }, (error => {
+            this._snackbar.openErrorSnackBar(this._translate.instant('impersonation.action.failed'));
+        }));
+    }
+
+    private _triggerReload(): void {
+        this._userService.user$.pipe(take(1)).subscribe(user => {
+            this._filter.removeAllFilters();
+            // TODO 1678 return observable
+        });
+        this._userService.reload();
+    }
+
+}
+
+export class UserQuery {
+    protected search;
+
+    constructor(search) {
+        this.search = search;
+    }
+}
diff --git a/projects/netgrif-components-core/src/lib/resources/interface/user-resource.ts b/projects/netgrif-components-core/src/lib/resources/interface/user-resource.ts
index 6c44dec3b2..4f13336f87 100644
--- a/projects/netgrif-components-core/src/lib/resources/interface/user-resource.ts
+++ b/projects/netgrif-components-core/src/lib/resources/interface/user-resource.ts
@@ -13,5 +13,6 @@ export interface UserResource extends UserResourceSmall {
     authorities: Array<Authority>;
     nextGroups: Array<string>;
     processRoles: Array<ProcessRole>;
+    impersonated?: UserResource;
     _links?: any;
 }
diff --git a/projects/netgrif-components-core/src/lib/side-menu/content-components/injection-tokens.ts b/projects/netgrif-components-core/src/lib/side-menu/content-components/injection-tokens.ts
index 46ae2c03c0..c81c9e7173 100644
--- a/projects/netgrif-components-core/src/lib/side-menu/content-components/injection-tokens.ts
+++ b/projects/netgrif-components-core/src/lib/side-menu/content-components/injection-tokens.ts
@@ -7,3 +7,4 @@ export const NAE_NEW_CASE_COMPONENT = new InjectionToken<ComponentType<unknown>>
 export const NAE_OPTION_SELECTOR_COMPONENT = new InjectionToken<ComponentType<unknown>>('NaeOptionSelectorComponent');
 export const NAE_SAVE_FILTER_COMPONENT = new InjectionToken<ComponentType<unknown>>('NaeSaveFilterComponent');
 export const NAE_LOAD_FILTER_COMPONENT = new InjectionToken<ComponentType<unknown>>('NaeLoadFilterComponent');
+export const NAE_USER_IMPERSONATE_COMPONENT = new InjectionToken<ComponentType<unknown>>('NaeUserImpersonateComponent');
diff --git a/projects/netgrif-components-core/src/lib/user/models/user.ts b/projects/netgrif-components-core/src/lib/user/models/user.ts
index a592e2ad63..16cccd9d38 100644
--- a/projects/netgrif-components-core/src/lib/user/models/user.ts
+++ b/projects/netgrif-components-core/src/lib/user/models/user.ts
@@ -14,7 +14,8 @@ export class User implements IUser {
         public authorities: Array<string>,
         public roles: Array<ProcessRole>,
         public groups?: Array<string>,
-        public nextGroups?: Array<string>
+        public nextGroups?: Array<string>,
+        public impersonated?: User
     ) {
     }
 
@@ -42,4 +43,11 @@ export class User implements IUser {
     public isEmpty(): boolean {
         return this.id === '';
     }
+
+    /**
+     * @returns self if no impersonated user is present, or impersonated user otherwise
+     */
+    public getSelfOrImpersonated(): User {
+        return this.impersonated ? this.impersonated : this;
+    }
 }
diff --git a/projects/netgrif-components-core/src/public-api.ts b/projects/netgrif-components-core/src/public-api.ts
index 5ffdb13257..87547e4c88 100644
--- a/projects/netgrif-components-core/src/public-api.ts
+++ b/projects/netgrif-components-core/src/public-api.ts
@@ -44,3 +44,4 @@ export * from './lib/allowed-nets/public-api';
 export * from './lib/event-queue/public-api';
 export * from './lib/changed-fields/public-api';
 export * from './lib/event/public-api';
+export * from './lib/impersonation/public-api';
diff --git a/projects/netgrif-components/src/lib/side-menu/content-components/public-api.ts b/projects/netgrif-components/src/lib/side-menu/content-components/public-api.ts
index d6874a82be..11265f40e8 100644
--- a/projects/netgrif-components/src/lib/side-menu/content-components/public-api.ts
+++ b/projects/netgrif-components/src/lib/side-menu/content-components/public-api.ts
@@ -3,6 +3,7 @@ export * from './side-menu-content-component.module';
 export * from './import-net/side-menu-import-net-component.module';
 export * from './new-case/side-menu-new-case-component.module';
 export * from './user-assign/side-menu-user-assign-component.module';
+export * from './user-impersonate/side-menu-user-impersonate-component.module';
 export * from './filter-selector/side-menu-filter-selector-component.module';
 export * from './option-selector/side-menu-option-selector-component.module';
 export * from './save-filter/side-menu-save-filter-component.module';
@@ -12,6 +13,7 @@ export * from './load-filter/side-menu-load-filter-component.module';
 export * from './import-net/import-net.component';
 export * from './new-case/new-case.component';
 export * from './user-assign/user-assign.component';
+export * from './user-impersonate/user-impersonate.component';
 export * from './filter-selector/filter-selector.component';
 export * from './option-selector/option-selector.component';
 export {SaveFilterComponent} from './save-filter/save-filter.component';
diff --git a/projects/netgrif-components/src/lib/side-menu/content-components/side-menu-content-component.module.ts b/projects/netgrif-components/src/lib/side-menu/content-components/side-menu-content-component.module.ts
index 611b5b3ca2..98c5d4d9ae 100644
--- a/projects/netgrif-components/src/lib/side-menu/content-components/side-menu-content-component.module.ts
+++ b/projects/netgrif-components/src/lib/side-menu/content-components/side-menu-content-component.module.ts
@@ -12,19 +12,23 @@ import {
     NAE_OPTION_SELECTOR_COMPONENT,
     NAE_SAVE_FILTER_COMPONENT,
     NAE_USER_ASSIGN_COMPONENT,
-    NAE_LOAD_FILTER_COMPONENT
+    NAE_LOAD_FILTER_COMPONENT,
+    NAE_USER_IMPERSONATE_COMPONENT
 } from '@netgrif/components-core';
 import {UserAssignComponent} from './user-assign/user-assign.component';
 import {NewCaseComponent} from './new-case/new-case.component';
 import {OptionSelectorComponent} from './option-selector/option-selector.component';
 import {SaveFilterComponent} from './save-filter/save-filter.component';
 import {LoadFilterComponent} from './load-filter/load-filter.component';
+import {SideMenuUserImpersonateComponentModule} from './user-impersonate/side-menu-user-impersonate-component.module';
+import {UserImpersonateComponent} from './user-impersonate/user-impersonate.component';
 
 
 @NgModule({
     imports: [
         CommonModule,
         SideMenuUserAssignComponentModule,
+        SideMenuUserImpersonateComponentModule,
         SideMenuNewCaseComponentModule,
         SideMenuImportNetComponentModule,
         SideMenuFilterSelectorComponentModule,
@@ -34,6 +38,7 @@ import {LoadFilterComponent} from './load-filter/load-filter.component';
     ],
     exports: [
         SideMenuUserAssignComponentModule,
+        SideMenuUserImpersonateComponentModule,
         SideMenuNewCaseComponentModule,
         SideMenuImportNetComponentModule,
         SideMenuFilterSelectorComponentModule,
@@ -43,6 +48,7 @@ import {LoadFilterComponent} from './load-filter/load-filter.component';
     ],
     providers: [
         {provide: NAE_USER_ASSIGN_COMPONENT, useValue: UserAssignComponent},
+        {provide: NAE_USER_IMPERSONATE_COMPONENT, useValue: UserImpersonateComponent},
         {provide: NAE_NEW_CASE_COMPONENT, useValue: NewCaseComponent},
         {provide: NAE_OPTION_SELECTOR_COMPONENT, useValue: OptionSelectorComponent},
         {provide: NAE_SAVE_FILTER_COMPONENT, useValue: SaveFilterComponent},
diff --git a/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/side-menu-user-impersonate-component.module.ts b/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/side-menu-user-impersonate-component.module.ts
new file mode 100644
index 0000000000..5a95758312
--- /dev/null
+++ b/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/side-menu-user-impersonate-component.module.ts
@@ -0,0 +1,34 @@
+import {NgModule} from '@angular/core';
+import {CommonModule} from '@angular/common';
+import {UserImpersonateComponent} from './user-impersonate.component';
+import {FlexLayoutModule, FlexModule} from '@angular/flex-layout';
+import {FormsModule} from '@angular/forms';
+import {CovalentModule, MaterialModule, TranslateLibModule, NAE_USER_IMPERSONATE_COMPONENT} from '@netgrif/components-core';
+import {MatFormFieldModule} from '@angular/material/form-field';
+import {UserImpersonateListComponent} from './user-impersonate-list/user-impersonate-list.component';
+import {UserImpersonateItemComponent} from './user-impersonate-list/user-impersonate-item/user-impersonate-item.component';
+
+
+@NgModule({
+    declarations: [
+        UserImpersonateComponent,
+        UserImpersonateItemComponent,
+        UserImpersonateListComponent
+    ],
+    imports: [
+        CommonModule,
+        MaterialModule,
+        CovalentModule,
+        FlexLayoutModule,
+        FlexModule,
+        FormsModule,
+        TranslateLibModule,
+        MatFormFieldModule
+    ],
+    exports: [UserImpersonateComponent],
+    providers: [
+        { provide: NAE_USER_IMPERSONATE_COMPONENT, useValue: UserImpersonateComponent },
+    ]
+})
+export class SideMenuUserImpersonateComponentModule {
+}
diff --git a/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate-list/user-impersonate-item/theme/user-assign-item.component.theme.scss b/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate-list/user-impersonate-item/theme/user-assign-item.component.theme.scss
new file mode 100644
index 0000000000..95ab82f00e
--- /dev/null
+++ b/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate-list/user-impersonate-item/theme/user-assign-item.component.theme.scss
@@ -0,0 +1,15 @@
+@use '@angular/material' as mat;
+
+@mixin user-assign-item-component-theme($theme) {
+    $primary: map-get($theme, primary);
+
+    .user-assign-item-selected {
+        background-color: mat.get-color-from-palette($primary, 300);
+        color: mat.get-contrast-color-from-palette($primary, 300) !important;
+    }
+
+    .user-assign-item-selected:hover {
+        background-color: mat.get-color-from-palette($primary, 500) !important;
+        color: mat.get-contrast-color-from-palette($primary, 500) !important;
+    }
+}
diff --git a/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate-list/user-impersonate-item/user-impersonate-item.component.html b/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate-list/user-impersonate-item/user-impersonate-item.component.html
new file mode 100644
index 0000000000..8da847494d
--- /dev/null
+++ b/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate-list/user-impersonate-item/user-impersonate-item.component.html
@@ -0,0 +1,9 @@
+<div fxLayout="row" fxLayoutAlign="start center" class="user-item" [ngClass]="{
+            'user-assign-item-selected': (selectedId$ | async) === user.id
+        }">
+    <mat-icon class="icon">account_circle</mat-icon>
+    <div fxLayout="column">
+        <span>{{user.fullName}}</span>
+        <span>{{user.email}}</span>
+    </div>
+</div>
diff --git a/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate-list/user-impersonate-item/user-impersonate-item.component.scss b/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate-list/user-impersonate-item/user-impersonate-item.component.scss
new file mode 100644
index 0000000000..a7674e4e5d
--- /dev/null
+++ b/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate-list/user-impersonate-item/user-impersonate-item.component.scss
@@ -0,0 +1,24 @@
+.user-item {
+    padding: 10px 15px;
+    cursor: pointer;
+}
+
+.user-item:hover {
+    background-color: rgba(0, 0, 0, .14);
+    border-radius: 2.5px;
+}
+
+.icon {
+    margin-right: 16px;
+    height: 40px;
+    width: 40px;
+    font-size: 40px;
+}
+
+.email-selected {
+    font-size: 0.9em;
+}
+
+.email-unselected {
+    font-size: 0.9em;
+}
diff --git a/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate-list/user-impersonate-item/user-impersonate-item.component.spec.ts b/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate-list/user-impersonate-item/user-impersonate-item.component.spec.ts
new file mode 100644
index 0000000000..ed71ac2686
--- /dev/null
+++ b/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate-list/user-impersonate-item/user-impersonate-item.component.spec.ts
@@ -0,0 +1,42 @@
+import {waitForAsync, ComponentFixture, TestBed} from '@angular/core/testing';
+import {UserImpersonateItemComponent} from './user-impersonate-item.component';
+import {Component} from '@angular/core';
+import {MaterialModule, TranslateLibModule, UserValue} from '@netgrif/components-core';
+import {NoopAnimationsModule} from '@angular/platform-browser/animations';
+
+describe('UserAssignItemComponent', () => {
+    let component: UserImpersonateItemComponent;
+    let fixture: ComponentFixture<TestWrapperComponent>;
+
+    beforeEach(waitForAsync(() => {
+        TestBed.configureTestingModule({
+            imports: [MaterialModule,
+                TranslateLibModule,
+                NoopAnimationsModule],
+            declarations: [
+                UserImpersonateItemComponent,
+                TestWrapperComponent
+            ]
+        })
+            .compileComponents();
+        fixture = TestBed.createComponent(TestWrapperComponent);
+        component = fixture.debugElement.children[0].componentInstance;
+        fixture.detectChanges();
+    }));
+
+    it('should create', () => {
+        expect(component).toBeTruthy();
+    });
+
+    afterEach(() => {
+        TestBed.resetTestingModule();
+    });
+});
+
+@Component({
+    selector: 'nc-test-wrapper',
+    template: '<nc-user-impersonate-item [user]="user"></nc-user-impersonate-item>'
+})
+class TestWrapperComponent {
+    user = new UserValue('0', '', '', '');
+}
diff --git a/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate-list/user-impersonate-item/user-impersonate-item.component.ts b/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate-list/user-impersonate-item/user-impersonate-item.component.ts
new file mode 100644
index 0000000000..4fe5a20c84
--- /dev/null
+++ b/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate-list/user-impersonate-item/user-impersonate-item.component.ts
@@ -0,0 +1,17 @@
+import {Component} from '@angular/core';
+import {AbstractUserAssignItemComponent} from '@netgrif/components-core';
+
+/**
+ * Includes avatar user icon and full username in the side menu.
+ */
+@Component({
+    selector: 'nc-user-impersonate-item',
+    templateUrl: './user-impersonate-item.component.html',
+    styleUrls: ['./user-impersonate-item.component.scss']
+})
+export class UserImpersonateItemComponent extends AbstractUserAssignItemComponent {
+
+    constructor() {
+        super();
+    }
+}
diff --git a/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate-list/user-impersonate-list.component.html b/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate-list/user-impersonate-list.component.html
new file mode 100644
index 0000000000..0ce3b6a176
--- /dev/null
+++ b/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate-list/user-impersonate-list.component.html
@@ -0,0 +1,27 @@
+<div fxLayout="column" fxLayoutAlign="start center" fxFlex>
+    <ng-container *ngIf="users$ | async as users">
+        <div *ngIf="!loading && users.length === 0" fxFlex="100" fxLayout="column" fxLayoutAlign="center center">
+            <mat-icon color="accent" class="margin-bottom-default">person_add_disabled</mat-icon>
+            <span class="font-size-20">{{ 'side-menu.user.noUser' | translate }}</span>
+        </div>
+
+        <div class="full-height full-width" fxFlex="100">
+            <cdk-virtual-scroll-viewport itemSize="60" (scrolledIndexChange)="loadNextPage()"
+                                         class="full-height full-width">
+                <nc-user-impersonate-item
+                    *cdkVirtualFor="let user of users;
+                                    trackBy: trackBy;
+                                    templateCacheSize: 0"
+                    [user]="user"
+                    [selectedId$]="selectedUser$"
+                    (click)="select(user)">
+                </nc-user-impersonate-item>
+
+                <div *ngIf="loading" fxLayout="column" fxLayoutAlign="center center"
+                     class="margin-top-default">
+                    <mat-spinner color="primary" diameter="40"></mat-spinner>
+                </div>
+            </cdk-virtual-scroll-viewport>
+        </div>
+    </ng-container>
+</div>
diff --git a/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate-list/user-impersonate-list.component.scss b/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate-list/user-impersonate-list.component.scss
new file mode 100644
index 0000000000..943757ceb4
--- /dev/null
+++ b/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate-list/user-impersonate-list.component.scss
@@ -0,0 +1,13 @@
+@import '../../../../../styles/core';
+
+.font-size-20 {
+    font-size: 20px;
+}
+
+.margin-bottom-default {
+    margin-bottom: 8px;
+}
+
+.margin-top-default {
+    margin-top: 8px;
+}
diff --git a/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate-list/user-impersonate-list.component.spec.ts b/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate-list/user-impersonate-list.component.spec.ts
new file mode 100644
index 0000000000..6c1d5700d6
--- /dev/null
+++ b/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate-list/user-impersonate-list.component.spec.ts
@@ -0,0 +1,74 @@
+import {waitForAsync, ComponentFixture, TestBed} from '@angular/core/testing';
+import {UserImpersonateListComponent} from './user-impersonate-list.component';
+import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
+import {Component, NO_ERRORS_SCHEMA} from '@angular/core';
+import {FormControl} from '@angular/forms';
+import {HttpClientTestingModule} from '@angular/common/http/testing';
+import {BrowserDynamicTestingModule} from '@angular/platform-browser-dynamic/testing';
+import {
+    ConfigurationService,
+    ErrorSnackBarComponent,
+    MaterialModule,
+    TestConfigurationService,
+    TranslateLibModule,
+    UserListInjectedData,
+    UserListService,
+    UserValue
+} from '@netgrif/components-core';
+import {UserImpersonateItemComponent} from './user-impersonate-item/user-impersonate-item.component';
+
+describe('UserImpersonateListComponent', () => {
+    let component: UserImpersonateListComponent;
+    let fixture: ComponentFixture<TestWrapperComponent>;
+
+    beforeEach(waitForAsync(() => {
+        TestBed.configureTestingModule({
+            imports: [
+                MaterialModule,
+                BrowserAnimationsModule,
+                HttpClientTestingModule,
+                TranslateLibModule
+            ],
+            providers: [
+                UserListService,
+                {provide: ConfigurationService, useClass: TestConfigurationService}
+            ],
+            declarations: [
+                UserImpersonateListComponent,
+                UserImpersonateItemComponent,
+                ErrorSnackBarComponent,
+                TestWrapperComponent
+            ],
+            schemas: [NO_ERRORS_SCHEMA]
+        })
+            .overrideModule(BrowserDynamicTestingModule, {
+                set: {
+                    entryComponents: [
+                        ErrorSnackBarComponent
+                    ]
+                }
+            })
+            .compileComponents();
+
+        fixture = TestBed.createComponent(TestWrapperComponent);
+        component = fixture.debugElement.children[0].componentInstance;
+        fixture.detectChanges();
+    }));
+
+    it('should create', () => {
+        expect(component).toBeTruthy();
+    });
+
+    afterEach(() => {
+        TestBed.resetTestingModule();
+    });
+});
+
+@Component({
+    selector: 'nc-test-wrapper',
+    template: '<nc-user-impersonate-list [searchUserControl]="formControl" [roles]="injectedData.roles"></nc-user-impersonate-list>'
+})
+class TestWrapperComponent {
+    injectedData = {roles: [], value: new UserValue('5', 'admin', 'netgrif', 'super@netgrif.com')} as UserListInjectedData;
+    formControl = new FormControl();
+}
diff --git a/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate-list/user-impersonate-list.component.ts b/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate-list/user-impersonate-list.component.ts
new file mode 100644
index 0000000000..5e6cb1c84d
--- /dev/null
+++ b/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate-list/user-impersonate-list.component.ts
@@ -0,0 +1,17 @@
+import {Component} from '@angular/core';
+import {AbstractUserAssignListComponent, UserListService} from '@netgrif/components-core';
+
+/**
+ * Is responsible for displaying, filtering, loading and selecting users.
+ */
+@Component({
+    selector: 'nc-user-impersonate-list',
+    templateUrl: './user-impersonate-list.component.html',
+    styleUrls: ['./user-impersonate-list.component.scss']
+})
+export class UserImpersonateListComponent extends AbstractUserAssignListComponent {
+
+    constructor(protected _userListService: UserListService) {
+        super(_userListService);
+    }
+}
diff --git a/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate.component.html b/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate.component.html
new file mode 100644
index 0000000000..e53469c0cf
--- /dev/null
+++ b/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate.component.html
@@ -0,0 +1,29 @@
+<div class="full-width full-height" fxLayout="column" fxLayoutAlign="start stretch">
+    <mat-toolbar color="primary">{{ 'side-menu.user.assign' | translate | uppercase }}</mat-toolbar>
+    <div class="user-assign-container side-menu-root" fxLayout="column" fxFlex>
+        <div fxLayout="row" fxLayoutAlign="start center" class="netgrif-input netgrif-input-fix">
+            <mat-icon fxFlex class="search-icon">search</mat-icon>
+            <mat-form-field fxFlex="100" class="user-assign-search" color="primary" appearance="outline">
+                <input matInput placeholder="{{ 'side-menu.user.choose' | translate }}"
+                       [formControl]="searchUserControl">
+                <button mat-button *ngIf="searchUserControl.value" matSuffix mat-icon-button
+                        (click)="searchUserControl.setValue('')">
+                    <mat-icon>close</mat-icon>
+                </button>
+            </mat-form-field>
+        </div>
+
+        <nc-user-impersonate-list fxFlex
+                             [searchUserControl]="searchUserControl"
+                             [roles]="roles"
+                             [negativeRoles]="negativeRoles"
+                             [initiallySelectedUser]="initiallySelectedUser"
+                             (userSelected)="userWasSelected($event)">
+        </nc-user-impersonate-list>
+
+        <div fxLayout="row" fxLayoutAlign="end center">
+            <button mat-raised-button color="primary"
+                    (click)="assign()">{{ 'tasks.view.assign' | translate | uppercase }}</button>
+        </div>
+    </div>
+</div>
diff --git a/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate.component.scss b/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate.component.scss
new file mode 100644
index 0000000000..d5e7c575f9
--- /dev/null
+++ b/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate.component.scss
@@ -0,0 +1,15 @@
+@import '../../side-menu.theme';
+@import '../../../../styles/core';
+
+.user-assign-container {
+    padding: 16px;
+    position: relative;
+}
+
+.user-assign-search {
+    width: 100%;
+}
+
+.search-icon {
+    margin-right: 10px;
+}
diff --git a/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate.component.spec.ts b/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate.component.spec.ts
new file mode 100644
index 0000000000..45381aa26e
--- /dev/null
+++ b/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate.component.spec.ts
@@ -0,0 +1,61 @@
+import {waitForAsync, ComponentFixture, TestBed} from '@angular/core/testing';
+import {
+    ConfigurationService,
+    MaterialModule,
+    NAE_SIDE_MENU_CONTROL,
+    SideMenuControl,
+    SnackBarModule,
+    TestConfigurationService,
+    TranslateLibModule,
+    UserListService
+} from '@netgrif/components-core';
+import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
+import {HttpClientTestingModule} from '@angular/common/http/testing';
+import {Observable} from 'rxjs';
+import {UserImpersonateComponent} from './user-impersonate.component';
+import {UserImpersonateListComponent} from './user-impersonate-list/user-impersonate-list.component';
+import {UserImpersonateItemComponent} from './user-impersonate-list/user-impersonate-item/user-impersonate-item.component';
+
+describe('UserImpersonateComponent', () => {
+    let component: UserImpersonateComponent;
+    let fixture: ComponentFixture<UserImpersonateComponent>;
+
+    beforeEach(waitForAsync(() => {
+        TestBed.configureTestingModule({
+            imports: [
+                MaterialModule,
+                BrowserAnimationsModule,
+                HttpClientTestingModule,
+                TranslateLibModule,
+                SnackBarModule
+            ],
+            providers: [
+                UserListService,
+                {
+                    provide: NAE_SIDE_MENU_CONTROL, useValue: new SideMenuControl(() => {
+                    }, new Observable<boolean>(), null)
+                },
+                {provide: ConfigurationService, useClass: TestConfigurationService}
+            ],
+            declarations: [
+                UserImpersonateComponent,
+                UserImpersonateListComponent,
+                UserImpersonateItemComponent
+            ]
+        }).compileComponents();
+    }));
+
+    beforeEach(() => {
+        fixture = TestBed.createComponent(UserImpersonateComponent);
+        component = fixture.componentInstance;
+        fixture.detectChanges();
+    });
+
+    it('should create', () => {
+        expect(component).toBeTruthy();
+    });
+
+    afterEach(() => {
+        TestBed.resetTestingModule();
+    });
+});
diff --git a/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate.component.ts b/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate.component.ts
new file mode 100644
index 0000000000..6aa7f16c6e
--- /dev/null
+++ b/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate.component.ts
@@ -0,0 +1,22 @@
+import {Component, Inject} from '@angular/core';
+import {AbstractUserAssignComponent, NAE_SIDE_MENU_CONTROL, SideMenuControl, UserListService, ImpersonationUserListService} from '@netgrif/components-core';
+
+/**
+ * Is the main - parent component of the entire user assignment in the side menu.
+ *
+ * Holds logic link of the [UserAssignListComponent]{@link UserAssignListComponent}
+ * along with searching, selecting, and then assigning to the user field.
+ */
+@Component({
+    selector: 'nc-user-impersonate',
+    templateUrl: './user-impersonate.component.html',
+    styleUrls: ['./user-impersonate.component.scss'],
+    providers: [{
+        provide: UserListService, useClass: ImpersonationUserListService
+    }]
+})
+export class UserImpersonateComponent extends AbstractUserAssignComponent {
+    constructor(@Inject(NAE_SIDE_MENU_CONTROL) protected _sideMenuControl: SideMenuControl) {
+        super(_sideMenuControl);
+    }
+}

From 9b83ec4fbb093baef06257e77236d5547f16cfde Mon Sep 17 00:00:00 2001
From: Bezak <bezak@netgrif.com>
Date: Mon, 12 Sep 2022 23:09:00 +0200
Subject: [PATCH 02/21] [NAE-1678] User impersonation - fix example app
 component

---
 nae.json                                      | 11 +++++---
 .../nae-example-app/src/app/app.module.ts     |  4 +--
 .../impersonation-demo.component.html         |  1 +
 .../impersonation-demo.component.scss}        |  0
 .../impersonation-demo.component.spec.ts      | 25 +++++++++++++++++++
 .../impersonation-demo.component.ts           | 21 ++++++++++++++++
 .../impersonation.component.html              |  1 -
 .../impersonation.component.spec.ts           | 25 -------------------
 .../impersonation/impersonation.component.ts  | 24 ------------------
 .../src/app/nae-example-app-view.service.ts   |  4 +--
 10 files changed, 59 insertions(+), 57 deletions(-)
 create mode 100644 projects/nae-example-app/src/app/doc/impersonation-demo/impersonation-demo.component.html
 rename projects/nae-example-app/src/app/doc/{impersonation/impersonation.component.scss => impersonation-demo/impersonation-demo.component.scss} (100%)
 create mode 100644 projects/nae-example-app/src/app/doc/impersonation-demo/impersonation-demo.component.spec.ts
 create mode 100644 projects/nae-example-app/src/app/doc/impersonation-demo/impersonation-demo.component.ts
 delete mode 100644 projects/nae-example-app/src/app/doc/impersonation/impersonation.component.html
 delete mode 100644 projects/nae-example-app/src/app/doc/impersonation/impersonation.component.spec.ts
 delete mode 100644 projects/nae-example-app/src/app/doc/impersonation/impersonation.component.ts

diff --git a/nae.json b/nae.json
index d0a0778275..f8e92209eb 100644
--- a/nae.json
+++ b/nae.json
@@ -48,6 +48,11 @@
                 "name": "filter",
                 "address": "http://localhost:8080/api/",
                 "format": "json"
+            },
+            {
+                "name": "impersonation",
+                "address": "http://localhost:8080/api/",
+                "format": "json"
             }
         ]
     },
@@ -166,8 +171,8 @@
         },
         "demo-impersonation": {
             "component": {
-                "class": "ImpersonationComponent",
-                "from": "./doc/impersonation/impersonation.component"
+                "class": "ImpersonationDemoComponent",
+                "from": "./doc/impersonation-demo/impersonation-demo.component"
             },
             "access": "private",
             "navigation": true,
@@ -1270,4 +1275,4 @@
             "groupNavigationRoute": "group-nav"
         }
     }
-}
\ No newline at end of file
+}
diff --git a/projects/nae-example-app/src/app/app.module.ts b/projects/nae-example-app/src/app/app.module.ts
index 334c09d5a0..f0101bc4f2 100644
--- a/projects/nae-example-app/src/app/app.module.ts
+++ b/projects/nae-example-app/src/app/app.module.ts
@@ -98,7 +98,7 @@ import { WrapperEmptyViewComponent } from './views/wrapper/wrapper-empty-view.co
 import {DoubleDrawerExampleComponent} from './doc/double-drawer-example/double-drawer-example.component';
 import { PublicSingleTaskViewComponent } from './doc/public-single-task-view/public-single-task-view.component';
 import { BreadcrumbsExampleComponent } from './doc/breadcrumbs-example/breadcrumbs-example.component';
-import { ImpersonationComponent } from './doc/impersonation/impersonation.component';
+import {ImpersonationDemoComponent} from './doc/impersonation-demo/impersonation-demo.component';
 
 export function HttpLoaderFactory(http: HttpClient) {
     return new TranslateHttpLoader(http);
@@ -131,6 +131,7 @@ export function HttpLoaderFactory(http: HttpClient) {
         DashboardExampleComponent,
         FilterRepositoryExampleComponent,
         ProfileComponent,
+        ImpersonationDemoComponent,
         NavigationExampleComponent,
         ButtonsNavComponent,
         RolesAssignComponent,
@@ -154,7 +155,6 @@ export function HttpLoaderFactory(http: HttpClient) {
         DoubleDrawerExampleComponent,
         PublicSingleTaskViewComponent,
         BreadcrumbsExampleComponent,
-        ImpersonationComponent,
     ],
     imports: [
         BrowserModule,
diff --git a/projects/nae-example-app/src/app/doc/impersonation-demo/impersonation-demo.component.html b/projects/nae-example-app/src/app/doc/impersonation-demo/impersonation-demo.component.html
new file mode 100644
index 0000000000..3bd48fa3fc
--- /dev/null
+++ b/projects/nae-example-app/src/app/doc/impersonation-demo/impersonation-demo.component.html
@@ -0,0 +1 @@
+<div (click)="impersonate()">TEST</div>
diff --git a/projects/nae-example-app/src/app/doc/impersonation/impersonation.component.scss b/projects/nae-example-app/src/app/doc/impersonation-demo/impersonation-demo.component.scss
similarity index 100%
rename from projects/nae-example-app/src/app/doc/impersonation/impersonation.component.scss
rename to projects/nae-example-app/src/app/doc/impersonation-demo/impersonation-demo.component.scss
diff --git a/projects/nae-example-app/src/app/doc/impersonation-demo/impersonation-demo.component.spec.ts b/projects/nae-example-app/src/app/doc/impersonation-demo/impersonation-demo.component.spec.ts
new file mode 100644
index 0000000000..dedc1adf9d
--- /dev/null
+++ b/projects/nae-example-app/src/app/doc/impersonation-demo/impersonation-demo.component.spec.ts
@@ -0,0 +1,25 @@
+import {waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing';
+import {ImpersonationDemoComponent} from './impersonation-demo.component';
+
+
+describe('ImpersonationDemoComponent', () => {
+  let component: ImpersonationDemoComponent;
+  let fixture: ComponentFixture<ImpersonationDemoComponent>;
+
+  beforeEach(waitForAsync(() => {
+    TestBed.configureTestingModule({
+      declarations: [ ImpersonationDemoComponent ]
+    })
+    .compileComponents();
+  }));
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(ImpersonationDemoComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});
diff --git a/projects/nae-example-app/src/app/doc/impersonation-demo/impersonation-demo.component.ts b/projects/nae-example-app/src/app/doc/impersonation-demo/impersonation-demo.component.ts
new file mode 100644
index 0000000000..f3552539ba
--- /dev/null
+++ b/projects/nae-example-app/src/app/doc/impersonation-demo/impersonation-demo.component.ts
@@ -0,0 +1,21 @@
+import {Component, OnInit} from '@angular/core';
+import {ImpersonationUserSelectService} from 'netgrif-components-core';
+
+@Component({
+    selector: 'nae-app-impersonation-demo',
+    templateUrl: './impersonation-demo.component.html',
+    styleUrls: ['./impersonation-demo.component.scss']
+})
+export class ImpersonationDemoComponent implements OnInit {
+
+    constructor(private _impersonation: ImpersonationUserSelectService) {
+    }
+
+    ngOnInit(): void {
+    }
+
+    public impersonate(): void {
+        this._impersonation.selectImpersonate();
+    }
+
+}
diff --git a/projects/nae-example-app/src/app/doc/impersonation/impersonation.component.html b/projects/nae-example-app/src/app/doc/impersonation/impersonation.component.html
deleted file mode 100644
index 17bf23a84b..0000000000
--- a/projects/nae-example-app/src/app/doc/impersonation/impersonation.component.html
+++ /dev/null
@@ -1 +0,0 @@
-<p (click)="test()">impersonation works!</p>
diff --git a/projects/nae-example-app/src/app/doc/impersonation/impersonation.component.spec.ts b/projects/nae-example-app/src/app/doc/impersonation/impersonation.component.spec.ts
deleted file mode 100644
index 3a89b2fd51..0000000000
--- a/projects/nae-example-app/src/app/doc/impersonation/impersonation.component.spec.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-import { ComponentFixture, TestBed } from '@angular/core/testing';
-
-import { ImpersonationComponent } from './impersonation.component';
-
-describe('ImpersonationComponent', () => {
-  let component: ImpersonationComponent;
-  let fixture: ComponentFixture<ImpersonationComponent>;
-
-  beforeEach(async () => {
-    await TestBed.configureTestingModule({
-      declarations: [ ImpersonationComponent ]
-    })
-    .compileComponents();
-  });
-
-  beforeEach(() => {
-    fixture = TestBed.createComponent(ImpersonationComponent);
-    component = fixture.componentInstance;
-    fixture.detectChanges();
-  });
-
-  it('should create', () => {
-    expect(component).toBeTruthy();
-  });
-});
diff --git a/projects/nae-example-app/src/app/doc/impersonation/impersonation.component.ts b/projects/nae-example-app/src/app/doc/impersonation/impersonation.component.ts
deleted file mode 100644
index 8ef7ffcba6..0000000000
--- a/projects/nae-example-app/src/app/doc/impersonation/impersonation.component.ts
+++ /dev/null
@@ -1,24 +0,0 @@
-import { Component, OnInit } from '@angular/core';
-import {
-    ImpersonationUserSelectService
-} from '../../../../../netgrif-components-core/src/lib/impersonation/services/impersonation-user-select.service';
-
-@Component({
-  selector: 'nae-app-impersonation',
-  templateUrl: './impersonation.component.html',
-  styleUrls: ['./impersonation.component.scss']
-})
-export class ImpersonationComponent implements OnInit {
-
-  constructor(
-      private _impersonate: ImpersonationUserSelectService
-  ) { }
-
-  ngOnInit(): void {
-  }
-
-  public test(): void {
-      this._impersonate.selectImpersonate();
-  }
-
-}
diff --git a/projects/nae-example-app/src/app/nae-example-app-view.service.ts b/projects/nae-example-app/src/app/nae-example-app-view.service.ts
index c36a439ef8..4da0090089 100644
--- a/projects/nae-example-app/src/app/nae-example-app-view.service.ts
+++ b/projects/nae-example-app/src/app/nae-example-app-view.service.ts
@@ -39,7 +39,7 @@ import {WrapperEmptyViewComponent} from './views/wrapper/wrapper-empty-view.comp
 import {DoubleDrawerExampleComponent} from './doc/double-drawer-example/double-drawer-example.component';
 import {PublicSingleTaskViewComponent} from './doc/public-single-task-view/public-single-task-view.component';
 import {BreadcrumbsExampleComponent} from './doc/breadcrumbs-example/breadcrumbs-example.component';
-import { ImpersonationComponent } from './doc/impersonation/impersonation.component';
+import {ImpersonationDemoComponent} from './doc/impersonation-demo/impersonation-demo.component';
 
 @Injectable({
     providedIn: 'root'
@@ -49,7 +49,7 @@ export class NaeExampleAppViewService extends ViewService {
         // This class is managed by schematics. Do not modify it by hand.
         // If you want to add views to the application run the 'create-view' schematic.
         super([
-			{id: 'ImpersonationComponent', class: ImpersonationComponent},
+            {id: 'ImpersonationDemoComponent', class: ImpersonationDemoComponent},
             {id: 'BreadcrumbsExampleComponent', class: BreadcrumbsExampleComponent},
             {id: 'TitleConfigComponent', class: TitleConfigComponent},
             {id: 'PublicSingleTaskViewComponent', class: PublicSingleTaskViewComponent},

From 418eedbfcf3364492110e128c9797cbeb3453e80 Mon Sep 17 00:00:00 2001
From: Bezak <bezak@netgrif.com>
Date: Tue, 13 Sep 2022 15:03:05 +0200
Subject: [PATCH 03/21] [NAE-1678] User impersonation - override permission
 with impersonated user

---
 .../impersonation-demo.component.html         |  4 ++-
 .../impersonation-demo.component.ts           | 16 +++++++++--
 .../permission/permission.service.ts          |  2 +-
 .../impersonation-user-select.service.ts      |  3 ++
 .../services/impersonation.service.ts         | 28 +++++++++----------
 .../user/services/user-comparator.service.ts  |  5 ++--
 .../src/lib/user/services/user.service.ts     | 27 ++++++++++--------
 7 files changed, 53 insertions(+), 32 deletions(-)

diff --git a/projects/nae-example-app/src/app/doc/impersonation-demo/impersonation-demo.component.html b/projects/nae-example-app/src/app/doc/impersonation-demo/impersonation-demo.component.html
index 3bd48fa3fc..369812408a 100644
--- a/projects/nae-example-app/src/app/doc/impersonation-demo/impersonation-demo.component.html
+++ b/projects/nae-example-app/src/app/doc/impersonation-demo/impersonation-demo.component.html
@@ -1 +1,3 @@
-<div (click)="impersonate()">TEST</div>
+<button (click)="impersonate()">IMPERSONATE</button>
+
+<button (click)="stopImpersonate()">STOP IMPERSONATE</button>
diff --git a/projects/nae-example-app/src/app/doc/impersonation-demo/impersonation-demo.component.ts b/projects/nae-example-app/src/app/doc/impersonation-demo/impersonation-demo.component.ts
index f3552539ba..c7136a65aa 100644
--- a/projects/nae-example-app/src/app/doc/impersonation-demo/impersonation-demo.component.ts
+++ b/projects/nae-example-app/src/app/doc/impersonation-demo/impersonation-demo.component.ts
@@ -1,5 +1,5 @@
 import {Component, OnInit} from '@angular/core';
-import {ImpersonationUserSelectService} from 'netgrif-components-core';
+import {ImpersonationService, ImpersonationUserSelectService} from 'netgrif-components-core';
 
 @Component({
     selector: 'nae-app-impersonation-demo',
@@ -8,14 +8,24 @@ import {ImpersonationUserSelectService} from 'netgrif-components-core';
 })
 export class ImpersonationDemoComponent implements OnInit {
 
-    constructor(private _impersonation: ImpersonationUserSelectService) {
+    constructor(
+        private _impersonationSelect: ImpersonationUserSelectService,
+        private _impersonation: ImpersonationService,
+    ) {
+        this._impersonation.impersonating.subscribe((isImpersonating: boolean) => {
+            console.log("Is impersonating " + isImpersonating);
+        });
     }
 
     ngOnInit(): void {
     }
 
     public impersonate(): void {
-        this._impersonation.selectImpersonate();
+        this._impersonationSelect.selectImpersonate();
+    }
+
+    public stopImpersonate(): void {
+        this._impersonation.cease();
     }
 
 }
diff --git a/projects/netgrif-components-core/src/lib/authorization/permission/permission.service.ts b/projects/netgrif-components-core/src/lib/authorization/permission/permission.service.ts
index bf2c91c338..209fd8189f 100644
--- a/projects/netgrif-components-core/src/lib/authorization/permission/permission.service.ts
+++ b/projects/netgrif-components-core/src/lib/authorization/permission/permission.service.ts
@@ -108,7 +108,7 @@ export class PermissionService {
     public checkUserPerms(users: UserPermissions, permission): boolean | undefined {
         let userPermValue: boolean;
         if (!!users) {
-            const loggedUserId = this._userService.user.id;
+            const loggedUserId = this._userService.user.getSelfOrImpersonated().id;
             Object.keys(users).forEach(user => {
                 if (user === loggedUserId && users[user][permission] !== undefined) {
                     userPermValue = userPermValue === undefined ?
diff --git a/projects/netgrif-components-core/src/lib/impersonation/services/impersonation-user-select.service.ts b/projects/netgrif-components-core/src/lib/impersonation/services/impersonation-user-select.service.ts
index 398b9d002f..0b84c0e1d1 100644
--- a/projects/netgrif-components-core/src/lib/impersonation/services/impersonation-user-select.service.ts
+++ b/projects/netgrif-components-core/src/lib/impersonation/services/impersonation-user-select.service.ts
@@ -18,6 +18,9 @@ export class ImpersonationUserSelectService {
                 @Optional() @Inject(NAE_USER_IMPERSONATE_COMPONENT) protected _userImpersonateComponent: any,
     ) {}
 
+    /**
+     * Opens side menu with users who can be impersonated by logged user
+     */
     public selectImpersonate(): void {
         this._sideMenuService.open(this._userImpersonateComponent, SideMenuSize.MEDIUM).onClose.subscribe(event => {
             this._log.debug('Impersonable user select :' + event);
diff --git a/projects/netgrif-components-core/src/lib/impersonation/services/impersonation.service.ts b/projects/netgrif-components-core/src/lib/impersonation/services/impersonation.service.ts
index bd9d906a76..2b59b0abfe 100644
--- a/projects/netgrif-components-core/src/lib/impersonation/services/impersonation.service.ts
+++ b/projects/netgrif-components-core/src/lib/impersonation/services/impersonation.service.ts
@@ -2,18 +2,21 @@ import {Injectable} from '@angular/core';
 import {Router} from '@angular/router';
 import {take} from 'rxjs/operators';
 import {TranslateService} from '@ngx-translate/core';
-import {AbstractResourceService, ResourceProvider} from '../../resources/public-api';
+import {AbstractResourceService, ResourceProvider, UserResource} from '../../resources/public-api';
 import {ConfigurationService} from '../../configuration/configuration.service';
 import {UserService} from '../../user/services/user.service';
 import {SnackBarService} from '../../snack-bar/services/snack-bar.service';
 import {FilterRepository} from '../../filter/filter.repository';
 import {LoggerService} from '../../logger/services/logger.service';
+import {Observable, Subject} from 'rxjs';
 
 @Injectable({
     providedIn: 'root'
 })
 export class ImpersonationService extends AbstractResourceService {
 
+    private _impersonating$ = new Subject<boolean>();
+
     public constructor(protected provider: ResourceProvider,
                        protected _router: Router,
                        protected _configService: ConfigurationService,
@@ -25,10 +28,14 @@ export class ImpersonationService extends AbstractResourceService {
         super('impersonation', provider, _configService);
     }
 
+    public get impersonating(): Observable<boolean> {
+        return this._impersonating$.asObservable();
+    }
+
     public impersonate(userId: number): void {
-        this.provider.post$('impersonate/' + userId, this.SERVER_URL, {}).subscribe(user => {
-            this._triggerReload();
+        this.provider.post$('impersonate/' + userId, this.SERVER_URL, {}).subscribe((user: UserResource) => {
             this._snackbar.openSuccessSnackBar(this._translate.instant('impersonation.user.successfullyRepresented'));
+            this._triggerReload(true);
         }, (response => {
             if (response.status === 400) {
                 response.error.alreadyImpersonated ?
@@ -37,32 +44,25 @@ export class ImpersonationService extends AbstractResourceService {
             } else {
                 this._snackbar.openErrorSnackBar(this._translate.instant('impersonation.action.failed'));
             }
+            this._impersonating$.next(false);
         }));
     }
 
     public cease(): void {
         this.provider.post$('impersonate/clear', this.SERVER_URL, {}).subscribe(user => {
             this._snackbar.openSuccessSnackBar(this._translate.instant('impersonation.action.deactivated'));
-            return this._triggerReload();
+            return this._triggerReload(false);
         }, (error => {
             this._snackbar.openErrorSnackBar(this._translate.instant('impersonation.action.failed'));
         }));
     }
 
-    private _triggerReload(): void {
+    private _triggerReload(isImpersonating: boolean): void {
         this._userService.user$.pipe(take(1)).subscribe(user => {
             this._filter.removeAllFilters();
-            // TODO 1678 return observable
+            this._impersonating$.next(isImpersonating);
         });
         this._userService.reload();
     }
 
 }
-
-export class UserQuery {
-    protected search;
-
-    constructor(search) {
-        this.search = search;
-    }
-}
diff --git a/projects/netgrif-components-core/src/lib/user/services/user-comparator.service.ts b/projects/netgrif-components-core/src/lib/user/services/user-comparator.service.ts
index 120b6fa5df..e422b6cb2d 100644
--- a/projects/netgrif-components-core/src/lib/user/services/user-comparator.service.ts
+++ b/projects/netgrif-components-core/src/lib/user/services/user-comparator.service.ts
@@ -9,8 +9,9 @@ export class UserComparatorService {
 
   constructor(private _userService: UserService) { }
 
-  public compareUsers(user: IUser): boolean {
-      return user.email === this._userService.user.email ||
+  public compareUsers(user: IUser, acceptImpersonator: boolean = true): boolean {
+      const loggedUser = acceptImpersonator ? this._userService.user.getSelfOrImpersonated() : this._userService.user;
+      return user.email === loggedUser.email ||
           user.email.includes('anonymous') && this._userService.user.email.includes('anonymous');
   }
 }
diff --git a/projects/netgrif-components-core/src/lib/user/services/user.service.ts b/projects/netgrif-components-core/src/lib/user/services/user.service.ts
index 517faeecaa..84c3783470 100644
--- a/projects/netgrif-components-core/src/lib/user/services/user.service.ts
+++ b/projects/netgrif-components-core/src/lib/user/services/user.service.ts
@@ -82,21 +82,23 @@ export class UserService implements OnDestroy {
      *                    If calculated intersection isn't empty returns true, otherwise false.
      */
     public hasAuthority(authority: Array<string> | string): boolean {
-        if (!authority || !this._user.authorities) {
+        const user = this._user.getSelfOrImpersonated();
+        if (!authority || !user.authorities) {
             return false;
         }
         if (authority instanceof Array) {
-            return authority.some(a => this._user.authorities.some(u => u === a));
+            return authority.some(a => user.authorities.some(u => u === a));
         } else {
-            return this._user.authorities.some(a => a === authority);
+            return user.authorities.some(a => a === authority);
         }
     }
 
     public hasRole(role: ProcessRole): boolean {
-        if (!role || !this._user.roles) {
+        const user = this._user.getSelfOrImpersonated();
+        if (!role || !user.roles) {
             return false;
         }
-        return this._user.roles.some(r => r === role);
+        return user.roles.some(r => r === role);
     }
 
     /**
@@ -104,10 +106,11 @@ export class UserService implements OnDestroy {
      * @param roleStringId ID of the role we want to check
      */
     public hasRoleById(roleStringId: string): boolean {
-        if (!roleStringId || !this._user.roles) {
+        const user = this._user.getSelfOrImpersonated();
+        if (!roleStringId || !user.roles) {
             return false;
         }
-        return this._user.roles.some(r => r.stringId === roleStringId);
+        return user.roles.some(r => r.stringId === roleStringId);
     }
 
     /**
@@ -116,10 +119,11 @@ export class UserService implements OnDestroy {
      * @param netIdentifier identifier (import ID) of the process the role is defined in
      */
     public hasRoleByIdentifier(roleIdentifier: string, netIdentifier: string): boolean {
-        if (!roleIdentifier || !netIdentifier || !this._user.roles) {
+        const user = this._user.getSelfOrImpersonated();
+        if (!roleIdentifier || !netIdentifier || !user.roles) {
             return false;
         }
-        return this._user.roles.some(r => r.netImportId === netIdentifier && r.importId === roleIdentifier);
+        return user.roles.some(r => r.netImportId === netIdentifier && r.importId === roleIdentifier);
     }
 
     /**
@@ -128,10 +132,11 @@ export class UserService implements OnDestroy {
      * @param netIdentifier identifier (import ID) of the process the role is defined in
      */
     public hasRoleByName(roleName: string, netIdentifier: string): boolean {
-        if (!roleName || !netIdentifier || !this._user.roles) {
+        const user = this._user.getSelfOrImpersonated();
+        if (!roleName || !netIdentifier || !user.roles) {
             return false;
         }
-        return this._user.roles.some(r => r.netImportId === netIdentifier && r.name === roleName);
+        return user.roles.some(r => r.netImportId === netIdentifier && r.name === roleName);
     }
 
     public login(credentials: Credentials): Observable<User> {

From 6683ca3e2ca3a806850f5d3dfeef87892c9c7c83 Mon Sep 17 00:00:00 2001
From: Bezak <bezak@netgrif.com>
Date: Fri, 16 Sep 2022 15:56:31 +0200
Subject: [PATCH 04/21] [NAE-1678] User impersonation - improve impersonation
 stream

---
 .../impersonation-demo.component.ts           |  2 +-
 .../services/impersonation.service.ts         | 36 ++++++++++++-------
 .../src/lib/user/models/user.ts               |  9 ++++-
 3 files changed, 33 insertions(+), 14 deletions(-)

diff --git a/projects/nae-example-app/src/app/doc/impersonation-demo/impersonation-demo.component.ts b/projects/nae-example-app/src/app/doc/impersonation-demo/impersonation-demo.component.ts
index c7136a65aa..fcd16a0f43 100644
--- a/projects/nae-example-app/src/app/doc/impersonation-demo/impersonation-demo.component.ts
+++ b/projects/nae-example-app/src/app/doc/impersonation-demo/impersonation-demo.component.ts
@@ -12,7 +12,7 @@ export class ImpersonationDemoComponent implements OnInit {
         private _impersonationSelect: ImpersonationUserSelectService,
         private _impersonation: ImpersonationService,
     ) {
-        this._impersonation.impersonating.subscribe((isImpersonating: boolean) => {
+        this._impersonation.impersonating$.subscribe((isImpersonating: boolean) => {
             console.log("Is impersonating " + isImpersonating);
         });
     }
diff --git a/projects/netgrif-components-core/src/lib/impersonation/services/impersonation.service.ts b/projects/netgrif-components-core/src/lib/impersonation/services/impersonation.service.ts
index 2b59b0abfe..f57e236a86 100644
--- a/projects/netgrif-components-core/src/lib/impersonation/services/impersonation.service.ts
+++ b/projects/netgrif-components-core/src/lib/impersonation/services/impersonation.service.ts
@@ -1,4 +1,4 @@
-import {Injectable} from '@angular/core';
+import {Injectable, OnDestroy} from '@angular/core';
 import {Router} from '@angular/router';
 import {take} from 'rxjs/operators';
 import {TranslateService} from '@ngx-translate/core';
@@ -8,15 +8,19 @@ import {UserService} from '../../user/services/user.service';
 import {SnackBarService} from '../../snack-bar/services/snack-bar.service';
 import {FilterRepository} from '../../filter/filter.repository';
 import {LoggerService} from '../../logger/services/logger.service';
-import {Observable, Subject} from 'rxjs';
+import {Observable, Subject, Subscription} from 'rxjs';
+import {User} from '../../user/models/user';
 
 @Injectable({
     providedIn: 'root'
 })
-export class ImpersonationService extends AbstractResourceService {
+export class ImpersonationService extends AbstractResourceService implements OnDestroy {
 
     private _impersonating$ = new Subject<boolean>();
 
+    private _lastUser: User;
+    private _sub: Subscription;
+
     public constructor(protected provider: ResourceProvider,
                        protected _router: Router,
                        protected _configService: ConfigurationService,
@@ -26,16 +30,23 @@ export class ImpersonationService extends AbstractResourceService {
                        protected _log: LoggerService,
                        private _translate: TranslateService) {
         super('impersonation', provider, _configService);
+        this._sub = this._userService.user$.subscribe(user => {
+            if (this._lastUser && this._lastUser.isImpersonating() != user.isImpersonating()) {
+                this._filter.removeAllFilters();
+                this._impersonating$.next(user.isImpersonating());
+            }
+            this._lastUser = user;
+        });
     }
 
-    public get impersonating(): Observable<boolean> {
+    public get impersonating$(): Observable<boolean> {
         return this._impersonating$.asObservable();
     }
 
     public impersonate(userId: number): void {
         this.provider.post$('impersonate/' + userId, this.SERVER_URL, {}).subscribe((user: UserResource) => {
             this._snackbar.openSuccessSnackBar(this._translate.instant('impersonation.user.successfullyRepresented'));
-            this._triggerReload(true);
+            this._triggerReload();
         }, (response => {
             if (response.status === 400) {
                 response.error.alreadyImpersonated ?
@@ -44,25 +55,26 @@ export class ImpersonationService extends AbstractResourceService {
             } else {
                 this._snackbar.openErrorSnackBar(this._translate.instant('impersonation.action.failed'));
             }
-            this._impersonating$.next(false);
         }));
     }
 
     public cease(): void {
         this.provider.post$('impersonate/clear', this.SERVER_URL, {}).subscribe(user => {
             this._snackbar.openSuccessSnackBar(this._translate.instant('impersonation.action.deactivated'));
-            return this._triggerReload(false);
+            return this._triggerReload();
         }, (error => {
             this._snackbar.openErrorSnackBar(this._translate.instant('impersonation.action.failed'));
         }));
     }
 
-    private _triggerReload(isImpersonating: boolean): void {
-        this._userService.user$.pipe(take(1)).subscribe(user => {
-            this._filter.removeAllFilters();
-            this._impersonating$.next(isImpersonating);
-        });
+    private _triggerReload(): void {
         this._userService.reload();
     }
 
+    ngOnDestroy(): void {
+        if (this._sub) {
+            this._sub.unsubscribe();
+        }
+    }
+
 }
diff --git a/projects/netgrif-components-core/src/lib/user/models/user.ts b/projects/netgrif-components-core/src/lib/user/models/user.ts
index 16cccd9d38..4f3a09b50e 100644
--- a/projects/netgrif-components-core/src/lib/user/models/user.ts
+++ b/projects/netgrif-components-core/src/lib/user/models/user.ts
@@ -48,6 +48,13 @@ export class User implements IUser {
      * @returns self if no impersonated user is present, or impersonated user otherwise
      */
     public getSelfOrImpersonated(): User {
-        return this.impersonated ? this.impersonated : this;
+        return this.isImpersonating() ? this.impersonated : this;
+    }
+
+    /**
+     * @returns true if user is impersonating another user
+     */
+    public isImpersonating(): boolean {
+        return !!this.impersonated;
     }
 }

From 01e4d2e41405e0cfa0a6cf0b892f54045bf3185a Mon Sep 17 00:00:00 2001
From: Bezak <bezak@netgrif.com>
Date: Sun, 18 Sep 2022 20:54:40 +0200
Subject: [PATCH 05/21] [NAE-1678] User impersonation - rename and move
 component

---
 .../admin-impersonate-item.component.html}    |  0
 .../admin-impersonate-item.component.scss}    |  0
 .../admin-impersonate-item.component.spec.ts} |  6 +--
 .../admin-impersonate-item.component.ts}      |  8 ++--
 .../user-assign-item.component.theme.scss     |  0
 .../admin-impersonate-list.component.html}    |  4 +-
 .../admin-impersonate-list.component.scss}    |  0
 .../admin-impersonate-list.component.spec.ts} |  6 +--
 .../admin-impersonate-list.component.ts}      |  8 ++--
 .../admin-impersonate.component.html}         |  4 +-
 .../admin-impersonate.component.scss}         |  0
 .../admin-impersonate.component.spec.ts}      | 10 ++---
 .../admin-impersonate.component.ts}           |  8 ++--
 ...menu-admin-impersonate-component.module.ts | 41 +++++++++++++++++++
 .../content-components/public-api.ts          |  4 +-
 .../side-menu-content-component.module.ts     | 12 +++---
 ...-menu-user-impersonate-component.module.ts | 34 ---------------
 17 files changed, 77 insertions(+), 68 deletions(-)
 rename projects/netgrif-components/src/lib/side-menu/content-components/{user-impersonate/user-impersonate-list/user-impersonate-item/user-impersonate-item.component.html => admin-impersonate/admin-impersonate-list/admin-impersonate-item/admin-impersonate-item.component.html} (100%)
 rename projects/netgrif-components/src/lib/side-menu/content-components/{user-impersonate/user-impersonate-list/user-impersonate-item/user-impersonate-item.component.scss => admin-impersonate/admin-impersonate-list/admin-impersonate-item/admin-impersonate-item.component.scss} (100%)
 rename projects/netgrif-components/src/lib/side-menu/content-components/{user-impersonate/user-impersonate-list/user-impersonate-item/user-impersonate-item.component.spec.ts => admin-impersonate/admin-impersonate-list/admin-impersonate-item/admin-impersonate-item.component.spec.ts} (87%)
 rename projects/netgrif-components/src/lib/side-menu/content-components/{user-impersonate/user-impersonate-list/user-impersonate-item/user-impersonate-item.component.ts => admin-impersonate/admin-impersonate-list/admin-impersonate-item/admin-impersonate-item.component.ts} (50%)
 rename projects/netgrif-components/src/lib/side-menu/content-components/{user-impersonate/user-impersonate-list/user-impersonate-item => admin-impersonate/admin-impersonate-list/admin-impersonate-item}/theme/user-assign-item.component.theme.scss (100%)
 rename projects/netgrif-components/src/lib/side-menu/content-components/{user-impersonate/user-impersonate-list/user-impersonate-list.component.html => admin-impersonate/admin-impersonate-list/admin-impersonate-list.component.html} (93%)
 rename projects/netgrif-components/src/lib/side-menu/content-components/{user-impersonate/user-impersonate-list/user-impersonate-list.component.scss => admin-impersonate/admin-impersonate-list/admin-impersonate-list.component.scss} (100%)
 rename projects/netgrif-components/src/lib/side-menu/content-components/{user-impersonate/user-impersonate-list/user-impersonate-list.component.spec.ts => admin-impersonate/admin-impersonate-list/admin-impersonate-list.component.spec.ts} (93%)
 rename projects/netgrif-components/src/lib/side-menu/content-components/{user-impersonate/user-impersonate-list/user-impersonate-list.component.ts => admin-impersonate/admin-impersonate-list/admin-impersonate-list.component.ts} (57%)
 rename projects/netgrif-components/src/lib/side-menu/content-components/{user-impersonate/user-impersonate.component.html => admin-impersonate/admin-impersonate.component.html} (95%)
 rename projects/netgrif-components/src/lib/side-menu/content-components/{user-impersonate/user-impersonate.component.scss => admin-impersonate/admin-impersonate.component.scss} (100%)
 rename projects/netgrif-components/src/lib/side-menu/content-components/{user-impersonate/user-impersonate.component.spec.ts => admin-impersonate/admin-impersonate.component.spec.ts} (86%)
 rename projects/netgrif-components/src/lib/side-menu/content-components/{user-impersonate/user-impersonate.component.ts => admin-impersonate/admin-impersonate.component.ts} (75%)
 create mode 100644 projects/netgrif-components/src/lib/side-menu/content-components/admin-impersonate/side-menu-admin-impersonate-component.module.ts
 delete mode 100644 projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/side-menu-user-impersonate-component.module.ts

diff --git a/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate-list/user-impersonate-item/user-impersonate-item.component.html b/projects/netgrif-components/src/lib/side-menu/content-components/admin-impersonate/admin-impersonate-list/admin-impersonate-item/admin-impersonate-item.component.html
similarity index 100%
rename from projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate-list/user-impersonate-item/user-impersonate-item.component.html
rename to projects/netgrif-components/src/lib/side-menu/content-components/admin-impersonate/admin-impersonate-list/admin-impersonate-item/admin-impersonate-item.component.html
diff --git a/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate-list/user-impersonate-item/user-impersonate-item.component.scss b/projects/netgrif-components/src/lib/side-menu/content-components/admin-impersonate/admin-impersonate-list/admin-impersonate-item/admin-impersonate-item.component.scss
similarity index 100%
rename from projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate-list/user-impersonate-item/user-impersonate-item.component.scss
rename to projects/netgrif-components/src/lib/side-menu/content-components/admin-impersonate/admin-impersonate-list/admin-impersonate-item/admin-impersonate-item.component.scss
diff --git a/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate-list/user-impersonate-item/user-impersonate-item.component.spec.ts b/projects/netgrif-components/src/lib/side-menu/content-components/admin-impersonate/admin-impersonate-list/admin-impersonate-item/admin-impersonate-item.component.spec.ts
similarity index 87%
rename from projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate-list/user-impersonate-item/user-impersonate-item.component.spec.ts
rename to projects/netgrif-components/src/lib/side-menu/content-components/admin-impersonate/admin-impersonate-list/admin-impersonate-item/admin-impersonate-item.component.spec.ts
index ed71ac2686..1fa62e957f 100644
--- a/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate-list/user-impersonate-item/user-impersonate-item.component.spec.ts
+++ b/projects/netgrif-components/src/lib/side-menu/content-components/admin-impersonate/admin-impersonate-list/admin-impersonate-item/admin-impersonate-item.component.spec.ts
@@ -1,11 +1,11 @@
 import {waitForAsync, ComponentFixture, TestBed} from '@angular/core/testing';
-import {UserImpersonateItemComponent} from './user-impersonate-item.component';
+import {AdminImpersonateItemComponent} from './admin-impersonate-item.component';
 import {Component} from '@angular/core';
 import {MaterialModule, TranslateLibModule, UserValue} from '@netgrif/components-core';
 import {NoopAnimationsModule} from '@angular/platform-browser/animations';
 
 describe('UserAssignItemComponent', () => {
-    let component: UserImpersonateItemComponent;
+    let component: AdminImpersonateItemComponent;
     let fixture: ComponentFixture<TestWrapperComponent>;
 
     beforeEach(waitForAsync(() => {
@@ -14,7 +14,7 @@ describe('UserAssignItemComponent', () => {
                 TranslateLibModule,
                 NoopAnimationsModule],
             declarations: [
-                UserImpersonateItemComponent,
+                AdminImpersonateItemComponent,
                 TestWrapperComponent
             ]
         })
diff --git a/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate-list/user-impersonate-item/user-impersonate-item.component.ts b/projects/netgrif-components/src/lib/side-menu/content-components/admin-impersonate/admin-impersonate-list/admin-impersonate-item/admin-impersonate-item.component.ts
similarity index 50%
rename from projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate-list/user-impersonate-item/user-impersonate-item.component.ts
rename to projects/netgrif-components/src/lib/side-menu/content-components/admin-impersonate/admin-impersonate-list/admin-impersonate-item/admin-impersonate-item.component.ts
index 4fe5a20c84..0242374ee7 100644
--- a/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate-list/user-impersonate-item/user-impersonate-item.component.ts
+++ b/projects/netgrif-components/src/lib/side-menu/content-components/admin-impersonate/admin-impersonate-list/admin-impersonate-item/admin-impersonate-item.component.ts
@@ -5,11 +5,11 @@ import {AbstractUserAssignItemComponent} from '@netgrif/components-core';
  * Includes avatar user icon and full username in the side menu.
  */
 @Component({
-    selector: 'nc-user-impersonate-item',
-    templateUrl: './user-impersonate-item.component.html',
-    styleUrls: ['./user-impersonate-item.component.scss']
+    selector: 'nc-admin-impersonate-item',
+    templateUrl: './admin-impersonate-item.component.html',
+    styleUrls: ['./admin-impersonate-item.component.scss']
 })
-export class UserImpersonateItemComponent extends AbstractUserAssignItemComponent {
+export class AdminImpersonateItemComponent extends AbstractUserAssignItemComponent {
 
     constructor() {
         super();
diff --git a/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate-list/user-impersonate-item/theme/user-assign-item.component.theme.scss b/projects/netgrif-components/src/lib/side-menu/content-components/admin-impersonate/admin-impersonate-list/admin-impersonate-item/theme/user-assign-item.component.theme.scss
similarity index 100%
rename from projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate-list/user-impersonate-item/theme/user-assign-item.component.theme.scss
rename to projects/netgrif-components/src/lib/side-menu/content-components/admin-impersonate/admin-impersonate-list/admin-impersonate-item/theme/user-assign-item.component.theme.scss
diff --git a/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate-list/user-impersonate-list.component.html b/projects/netgrif-components/src/lib/side-menu/content-components/admin-impersonate/admin-impersonate-list/admin-impersonate-list.component.html
similarity index 93%
rename from projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate-list/user-impersonate-list.component.html
rename to projects/netgrif-components/src/lib/side-menu/content-components/admin-impersonate/admin-impersonate-list/admin-impersonate-list.component.html
index 0ce3b6a176..9971328fe0 100644
--- a/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate-list/user-impersonate-list.component.html
+++ b/projects/netgrif-components/src/lib/side-menu/content-components/admin-impersonate/admin-impersonate-list/admin-impersonate-list.component.html
@@ -8,14 +8,14 @@
         <div class="full-height full-width" fxFlex="100">
             <cdk-virtual-scroll-viewport itemSize="60" (scrolledIndexChange)="loadNextPage()"
                                          class="full-height full-width">
-                <nc-user-impersonate-item
+                <nc-admin-impersonate-item
                     *cdkVirtualFor="let user of users;
                                     trackBy: trackBy;
                                     templateCacheSize: 0"
                     [user]="user"
                     [selectedId$]="selectedUser$"
                     (click)="select(user)">
-                </nc-user-impersonate-item>
+                </nc-admin-impersonate-item>
 
                 <div *ngIf="loading" fxLayout="column" fxLayoutAlign="center center"
                      class="margin-top-default">
diff --git a/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate-list/user-impersonate-list.component.scss b/projects/netgrif-components/src/lib/side-menu/content-components/admin-impersonate/admin-impersonate-list/admin-impersonate-list.component.scss
similarity index 100%
rename from projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate-list/user-impersonate-list.component.scss
rename to projects/netgrif-components/src/lib/side-menu/content-components/admin-impersonate/admin-impersonate-list/admin-impersonate-list.component.scss
diff --git a/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate-list/user-impersonate-list.component.spec.ts b/projects/netgrif-components/src/lib/side-menu/content-components/admin-impersonate/admin-impersonate-list/admin-impersonate-list.component.spec.ts
similarity index 93%
rename from projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate-list/user-impersonate-list.component.spec.ts
rename to projects/netgrif-components/src/lib/side-menu/content-components/admin-impersonate/admin-impersonate-list/admin-impersonate-list.component.spec.ts
index 6c1d5700d6..6b8e6bffc8 100644
--- a/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate-list/user-impersonate-list.component.spec.ts
+++ b/projects/netgrif-components/src/lib/side-menu/content-components/admin-impersonate/admin-impersonate-list/admin-impersonate-list.component.spec.ts
@@ -1,5 +1,5 @@
 import {waitForAsync, ComponentFixture, TestBed} from '@angular/core/testing';
-import {UserImpersonateListComponent} from './user-impersonate-list.component';
+import {AdminImpersonateListComponent} from './admin-impersonate-list.component';
 import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
 import {Component, NO_ERRORS_SCHEMA} from '@angular/core';
 import {FormControl} from '@angular/forms';
@@ -18,7 +18,7 @@ import {
 import {UserImpersonateItemComponent} from './user-impersonate-item/user-impersonate-item.component';
 
 describe('UserImpersonateListComponent', () => {
-    let component: UserImpersonateListComponent;
+    let component: AdminImpersonateListComponent;
     let fixture: ComponentFixture<TestWrapperComponent>;
 
     beforeEach(waitForAsync(() => {
@@ -34,7 +34,7 @@ describe('UserImpersonateListComponent', () => {
                 {provide: ConfigurationService, useClass: TestConfigurationService}
             ],
             declarations: [
-                UserImpersonateListComponent,
+                AdminImpersonateListComponent,
                 UserImpersonateItemComponent,
                 ErrorSnackBarComponent,
                 TestWrapperComponent
diff --git a/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate-list/user-impersonate-list.component.ts b/projects/netgrif-components/src/lib/side-menu/content-components/admin-impersonate/admin-impersonate-list/admin-impersonate-list.component.ts
similarity index 57%
rename from projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate-list/user-impersonate-list.component.ts
rename to projects/netgrif-components/src/lib/side-menu/content-components/admin-impersonate/admin-impersonate-list/admin-impersonate-list.component.ts
index 5e6cb1c84d..e633cde714 100644
--- a/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate-list/user-impersonate-list.component.ts
+++ b/projects/netgrif-components/src/lib/side-menu/content-components/admin-impersonate/admin-impersonate-list/admin-impersonate-list.component.ts
@@ -5,11 +5,11 @@ import {AbstractUserAssignListComponent, UserListService} from '@netgrif/compone
  * Is responsible for displaying, filtering, loading and selecting users.
  */
 @Component({
-    selector: 'nc-user-impersonate-list',
-    templateUrl: './user-impersonate-list.component.html',
-    styleUrls: ['./user-impersonate-list.component.scss']
+    selector: 'nc-admin-impersonate-list',
+    templateUrl: './admin-impersonate-list.component.html',
+    styleUrls: ['./admin-impersonate-list.component.scss']
 })
-export class UserImpersonateListComponent extends AbstractUserAssignListComponent {
+export class AdminImpersonateListComponent extends AbstractUserAssignListComponent {
 
     constructor(protected _userListService: UserListService) {
         super(_userListService);
diff --git a/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate.component.html b/projects/netgrif-components/src/lib/side-menu/content-components/admin-impersonate/admin-impersonate.component.html
similarity index 95%
rename from projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate.component.html
rename to projects/netgrif-components/src/lib/side-menu/content-components/admin-impersonate/admin-impersonate.component.html
index e53469c0cf..ea83696f6c 100644
--- a/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate.component.html
+++ b/projects/netgrif-components/src/lib/side-menu/content-components/admin-impersonate/admin-impersonate.component.html
@@ -13,13 +13,13 @@
             </mat-form-field>
         </div>
 
-        <nc-user-impersonate-list fxFlex
+        <nc-admin-impersonate-list fxFlex
                              [searchUserControl]="searchUserControl"
                              [roles]="roles"
                              [negativeRoles]="negativeRoles"
                              [initiallySelectedUser]="initiallySelectedUser"
                              (userSelected)="userWasSelected($event)">
-        </nc-user-impersonate-list>
+        </nc-admin-impersonate-list>
 
         <div fxLayout="row" fxLayoutAlign="end center">
             <button mat-raised-button color="primary"
diff --git a/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate.component.scss b/projects/netgrif-components/src/lib/side-menu/content-components/admin-impersonate/admin-impersonate.component.scss
similarity index 100%
rename from projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate.component.scss
rename to projects/netgrif-components/src/lib/side-menu/content-components/admin-impersonate/admin-impersonate.component.scss
diff --git a/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate.component.spec.ts b/projects/netgrif-components/src/lib/side-menu/content-components/admin-impersonate/admin-impersonate.component.spec.ts
similarity index 86%
rename from projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate.component.spec.ts
rename to projects/netgrif-components/src/lib/side-menu/content-components/admin-impersonate/admin-impersonate.component.spec.ts
index 45381aa26e..0a4a776a75 100644
--- a/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate.component.spec.ts
+++ b/projects/netgrif-components/src/lib/side-menu/content-components/admin-impersonate/admin-impersonate.component.spec.ts
@@ -12,13 +12,13 @@ import {
 import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
 import {HttpClientTestingModule} from '@angular/common/http/testing';
 import {Observable} from 'rxjs';
-import {UserImpersonateComponent} from './user-impersonate.component';
+import {AdminImpersonateComponent} from './admin-impersonate.component';
 import {UserImpersonateListComponent} from './user-impersonate-list/user-impersonate-list.component';
 import {UserImpersonateItemComponent} from './user-impersonate-list/user-impersonate-item/user-impersonate-item.component';
 
 describe('UserImpersonateComponent', () => {
-    let component: UserImpersonateComponent;
-    let fixture: ComponentFixture<UserImpersonateComponent>;
+    let component: AdminImpersonateComponent;
+    let fixture: ComponentFixture<AdminImpersonateComponent>;
 
     beforeEach(waitForAsync(() => {
         TestBed.configureTestingModule({
@@ -38,7 +38,7 @@ describe('UserImpersonateComponent', () => {
                 {provide: ConfigurationService, useClass: TestConfigurationService}
             ],
             declarations: [
-                UserImpersonateComponent,
+                AdminImpersonateComponent,
                 UserImpersonateListComponent,
                 UserImpersonateItemComponent
             ]
@@ -46,7 +46,7 @@ describe('UserImpersonateComponent', () => {
     }));
 
     beforeEach(() => {
-        fixture = TestBed.createComponent(UserImpersonateComponent);
+        fixture = TestBed.createComponent(AdminImpersonateComponent);
         component = fixture.componentInstance;
         fixture.detectChanges();
     });
diff --git a/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate.component.ts b/projects/netgrif-components/src/lib/side-menu/content-components/admin-impersonate/admin-impersonate.component.ts
similarity index 75%
rename from projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate.component.ts
rename to projects/netgrif-components/src/lib/side-menu/content-components/admin-impersonate/admin-impersonate.component.ts
index 6aa7f16c6e..32ec8220da 100644
--- a/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate.component.ts
+++ b/projects/netgrif-components/src/lib/side-menu/content-components/admin-impersonate/admin-impersonate.component.ts
@@ -8,14 +8,14 @@ import {AbstractUserAssignComponent, NAE_SIDE_MENU_CONTROL, SideMenuControl, Use
  * along with searching, selecting, and then assigning to the user field.
  */
 @Component({
-    selector: 'nc-user-impersonate',
-    templateUrl: './user-impersonate.component.html',
-    styleUrls: ['./user-impersonate.component.scss'],
+    selector: 'nc-admin-impersonate',
+    templateUrl: './admin-impersonate.component.html',
+    styleUrls: ['./admin-impersonate.component.scss'],
     providers: [{
         provide: UserListService, useClass: ImpersonationUserListService
     }]
 })
-export class UserImpersonateComponent extends AbstractUserAssignComponent {
+export class AdminImpersonateComponent extends AbstractUserAssignComponent {
     constructor(@Inject(NAE_SIDE_MENU_CONTROL) protected _sideMenuControl: SideMenuControl) {
         super(_sideMenuControl);
     }
diff --git a/projects/netgrif-components/src/lib/side-menu/content-components/admin-impersonate/side-menu-admin-impersonate-component.module.ts b/projects/netgrif-components/src/lib/side-menu/content-components/admin-impersonate/side-menu-admin-impersonate-component.module.ts
new file mode 100644
index 0000000000..7c6f7d352d
--- /dev/null
+++ b/projects/netgrif-components/src/lib/side-menu/content-components/admin-impersonate/side-menu-admin-impersonate-component.module.ts
@@ -0,0 +1,41 @@
+import {NgModule} from '@angular/core';
+import {CommonModule} from '@angular/common';
+import {AdminImpersonateComponent} from './admin-impersonate.component';
+import {FlexLayoutModule, FlexModule} from '@angular/flex-layout';
+import {FormsModule} from '@angular/forms';
+import {
+    CovalentModule,
+    MaterialModule,
+    NAE_USER_IMPERSONATE_COMPONENT,
+    TranslateLibModule
+} from '@netgrif/components-core';
+import {MatFormFieldModule} from '@angular/material/form-field';
+import {AdminImpersonateListComponent} from './admin-impersonate-list/admin-impersonate-list.component';
+import {
+    AdminImpersonateItemComponent
+} from './admin-impersonate-list/admin-impersonate-item/admin-impersonate-item.component';
+
+
+@NgModule({
+    declarations: [
+        AdminImpersonateComponent,
+        AdminImpersonateListComponent,
+        AdminImpersonateItemComponent,
+    ],
+    imports: [
+        CommonModule,
+        MaterialModule,
+        CovalentModule,
+        FlexLayoutModule,
+        FlexModule,
+        FormsModule,
+        TranslateLibModule,
+        MatFormFieldModule
+    ],
+    exports: [AdminImpersonateComponent],
+    providers: [
+        { provide: NAE_USER_IMPERSONATE_COMPONENT, useValue: AdminImpersonateComponent },
+    ]
+})
+export class SideMenuAdminImpersonateComponentModule {
+}
diff --git a/projects/netgrif-components/src/lib/side-menu/content-components/public-api.ts b/projects/netgrif-components/src/lib/side-menu/content-components/public-api.ts
index 11265f40e8..949f44fd7d 100644
--- a/projects/netgrif-components/src/lib/side-menu/content-components/public-api.ts
+++ b/projects/netgrif-components/src/lib/side-menu/content-components/public-api.ts
@@ -3,7 +3,7 @@ export * from './side-menu-content-component.module';
 export * from './import-net/side-menu-import-net-component.module';
 export * from './new-case/side-menu-new-case-component.module';
 export * from './user-assign/side-menu-user-assign-component.module';
-export * from './user-impersonate/side-menu-user-impersonate-component.module';
+export * from './admin-impersonate/side-menu-admin-impersonate-component.module';
 export * from './filter-selector/side-menu-filter-selector-component.module';
 export * from './option-selector/side-menu-option-selector-component.module';
 export * from './save-filter/side-menu-save-filter-component.module';
@@ -13,7 +13,7 @@ export * from './load-filter/side-menu-load-filter-component.module';
 export * from './import-net/import-net.component';
 export * from './new-case/new-case.component';
 export * from './user-assign/user-assign.component';
-export * from './user-impersonate/user-impersonate.component';
+export * from './admin-impersonate/admin-impersonate.component';
 export * from './filter-selector/filter-selector.component';
 export * from './option-selector/option-selector.component';
 export {SaveFilterComponent} from './save-filter/save-filter.component';
diff --git a/projects/netgrif-components/src/lib/side-menu/content-components/side-menu-content-component.module.ts b/projects/netgrif-components/src/lib/side-menu/content-components/side-menu-content-component.module.ts
index 98c5d4d9ae..1000cef41b 100644
--- a/projects/netgrif-components/src/lib/side-menu/content-components/side-menu-content-component.module.ts
+++ b/projects/netgrif-components/src/lib/side-menu/content-components/side-menu-content-component.module.ts
@@ -20,15 +20,17 @@ import {NewCaseComponent} from './new-case/new-case.component';
 import {OptionSelectorComponent} from './option-selector/option-selector.component';
 import {SaveFilterComponent} from './save-filter/save-filter.component';
 import {LoadFilterComponent} from './load-filter/load-filter.component';
-import {SideMenuUserImpersonateComponentModule} from './user-impersonate/side-menu-user-impersonate-component.module';
-import {UserImpersonateComponent} from './user-impersonate/user-impersonate.component';
+import {
+    SideMenuAdminImpersonateComponentModule
+} from './admin-impersonate/side-menu-admin-impersonate-component.module';
+import {AdminImpersonateComponent} from './admin-impersonate/admin-impersonate.component';
 
 
 @NgModule({
     imports: [
         CommonModule,
         SideMenuUserAssignComponentModule,
-        SideMenuUserImpersonateComponentModule,
+        SideMenuAdminImpersonateComponentModule,
         SideMenuNewCaseComponentModule,
         SideMenuImportNetComponentModule,
         SideMenuFilterSelectorComponentModule,
@@ -38,7 +40,7 @@ import {UserImpersonateComponent} from './user-impersonate/user-impersonate.comp
     ],
     exports: [
         SideMenuUserAssignComponentModule,
-        SideMenuUserImpersonateComponentModule,
+        SideMenuAdminImpersonateComponentModule,
         SideMenuNewCaseComponentModule,
         SideMenuImportNetComponentModule,
         SideMenuFilterSelectorComponentModule,
@@ -48,7 +50,7 @@ import {UserImpersonateComponent} from './user-impersonate/user-impersonate.comp
     ],
     providers: [
         {provide: NAE_USER_ASSIGN_COMPONENT, useValue: UserAssignComponent},
-        {provide: NAE_USER_IMPERSONATE_COMPONENT, useValue: UserImpersonateComponent},
+        {provide: NAE_USER_IMPERSONATE_COMPONENT, useValue: AdminImpersonateComponent},
         {provide: NAE_NEW_CASE_COMPONENT, useValue: NewCaseComponent},
         {provide: NAE_OPTION_SELECTOR_COMPONENT, useValue: OptionSelectorComponent},
         {provide: NAE_SAVE_FILTER_COMPONENT, useValue: SaveFilterComponent},
diff --git a/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/side-menu-user-impersonate-component.module.ts b/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/side-menu-user-impersonate-component.module.ts
deleted file mode 100644
index 5a95758312..0000000000
--- a/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/side-menu-user-impersonate-component.module.ts
+++ /dev/null
@@ -1,34 +0,0 @@
-import {NgModule} from '@angular/core';
-import {CommonModule} from '@angular/common';
-import {UserImpersonateComponent} from './user-impersonate.component';
-import {FlexLayoutModule, FlexModule} from '@angular/flex-layout';
-import {FormsModule} from '@angular/forms';
-import {CovalentModule, MaterialModule, TranslateLibModule, NAE_USER_IMPERSONATE_COMPONENT} from '@netgrif/components-core';
-import {MatFormFieldModule} from '@angular/material/form-field';
-import {UserImpersonateListComponent} from './user-impersonate-list/user-impersonate-list.component';
-import {UserImpersonateItemComponent} from './user-impersonate-list/user-impersonate-item/user-impersonate-item.component';
-
-
-@NgModule({
-    declarations: [
-        UserImpersonateComponent,
-        UserImpersonateItemComponent,
-        UserImpersonateListComponent
-    ],
-    imports: [
-        CommonModule,
-        MaterialModule,
-        CovalentModule,
-        FlexLayoutModule,
-        FlexModule,
-        FormsModule,
-        TranslateLibModule,
-        MatFormFieldModule
-    ],
-    exports: [UserImpersonateComponent],
-    providers: [
-        { provide: NAE_USER_IMPERSONATE_COMPONENT, useValue: UserImpersonateComponent },
-    ]
-})
-export class SideMenuUserImpersonateComponentModule {
-}

From 74d0108ca22b216b92efb8bb47e2a2a116ae862d Mon Sep 17 00:00:00 2001
From: Bezak <bezak@netgrif.com>
Date: Sun, 18 Sep 2022 22:09:03 +0200
Subject: [PATCH 06/21] [NAE-1678] User impersonation - implement impersonation
 by config (alternative to impersonation directly by user id)

---
 .../user-impersonate-config-metadata.ts       |  3 +
 .../models/user-impersonation-constants.ts    |  8 +++
 .../src/lib/impersonation/public-api.ts       |  2 +
 .../impersonation-user-select.service.ts      | 57 ++++++++++++++---
 .../services/impersonation.service.ts         | 40 ++++++++----
 .../content-components/injection-tokens.ts    |  1 +
 .../content-components/public-api.ts          |  2 +
 .../abstract-user-impersonate.component.ts    | 37 +++++++++++
 .../model/user-impersonate-injection-data.ts  |  9 +++
 ...menu-admin-impersonate-component.module.ts |  4 +-
 .../content-components/public-api.ts          |  2 +
 .../side-menu-content-component.module.ts     |  6 +-
 ...-menu-user-impersonate-component.module.ts | 28 +++++++++
 .../user-impersonate.component.html           |  6 ++
 .../user-impersonate.component.scss           | 16 +++++
 .../user-impersonate.component.spec.ts        | 25 ++++++++
 .../user-impersonate.component.ts             | 62 +++++++++++++++++++
 17 files changed, 285 insertions(+), 23 deletions(-)
 create mode 100644 projects/netgrif-components-core/src/lib/impersonation/models/user-impersonate-config-metadata.ts
 create mode 100644 projects/netgrif-components-core/src/lib/impersonation/models/user-impersonation-constants.ts
 create mode 100644 projects/netgrif-components-core/src/lib/side-menu/content-components/user-impersonate/abstract-user-impersonate.component.ts
 create mode 100644 projects/netgrif-components-core/src/lib/side-menu/content-components/user-impersonate/model/user-impersonate-injection-data.ts
 create mode 100644 projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/side-menu-user-impersonate-component.module.ts
 create mode 100644 projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate.component.html
 create mode 100644 projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate.component.scss
 create mode 100644 projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate.component.spec.ts
 create mode 100644 projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate.component.ts

diff --git a/projects/netgrif-components-core/src/lib/impersonation/models/user-impersonate-config-metadata.ts b/projects/netgrif-components-core/src/lib/impersonation/models/user-impersonate-config-metadata.ts
new file mode 100644
index 0000000000..4176a5ce7e
--- /dev/null
+++ b/projects/netgrif-components-core/src/lib/impersonation/models/user-impersonate-config-metadata.ts
@@ -0,0 +1,3 @@
+export interface UserImpersonateConfigMetadata {
+    stringId: string
+}
diff --git a/projects/netgrif-components-core/src/lib/impersonation/models/user-impersonation-constants.ts b/projects/netgrif-components-core/src/lib/impersonation/models/user-impersonation-constants.ts
new file mode 100644
index 0000000000..574eec62f0
--- /dev/null
+++ b/projects/netgrif-components-core/src/lib/impersonation/models/user-impersonation-constants.ts
@@ -0,0 +1,8 @@
+/**
+ * Holds all identifiers of the Impersonation config process in an accessible manner
+ */
+export enum UserImpersonationConstants {
+
+    IMPERSONATION_CONFIG_NET_IDENTIFIER = 'impersonation_config',
+
+}
diff --git a/projects/netgrif-components-core/src/lib/impersonation/public-api.ts b/projects/netgrif-components-core/src/lib/impersonation/public-api.ts
index 7ec0e29cf5..bbd42db6c5 100644
--- a/projects/netgrif-components-core/src/lib/impersonation/public-api.ts
+++ b/projects/netgrif-components-core/src/lib/impersonation/public-api.ts
@@ -1,3 +1,5 @@
+/* MODELS */
+export * from './models/user-impersonation-constants';
 
 /* SERVICES */
 export * from './services/impersonation.service';
diff --git a/projects/netgrif-components-core/src/lib/impersonation/services/impersonation-user-select.service.ts b/projects/netgrif-components-core/src/lib/impersonation/services/impersonation-user-select.service.ts
index 0b84c0e1d1..089d8cbe89 100644
--- a/projects/netgrif-components-core/src/lib/impersonation/services/impersonation-user-select.service.ts
+++ b/projects/netgrif-components-core/src/lib/impersonation/services/impersonation-user-select.service.ts
@@ -1,10 +1,18 @@
 import {Inject, Injectable, Optional} from '@angular/core';
 import {ImpersonationService} from "./impersonation.service";
-import {NAE_USER_IMPERSONATE_COMPONENT} from '../../side-menu/content-components/injection-tokens';
+import {NAE_USER_IMPERSONATE_COMPONENT, NAE_ADMIN_IMPERSONATE_COMPONENT} from '../../side-menu/content-components/injection-tokens';
 import {LoggerService} from '../../logger/services/logger.service';
 import {SnackBarService} from '../../snack-bar/services/snack-bar.service';
 import {SideMenuService} from '../../side-menu/services/side-menu.service';
 import {SideMenuSize} from '../../side-menu/models/side-menu-size';
+import {UserImpersonateConfigMetadata} from '../models/user-impersonate-config-metadata';
+import {
+    UserImpersonateInjectionData
+} from '../../side-menu/content-components/user-impersonate/model/user-impersonate-injection-data';
+import {SimpleFilter} from '../../filter/models/simple-filter';
+import {UserImpersonationConstants} from '../models/user-impersonation-constants';
+import moment from 'moment';
+import {UserService} from '../../user/services/user.service';
 
 @Injectable({
   providedIn: 'root'
@@ -15,19 +23,54 @@ export class ImpersonationUserSelectService {
                 protected _sideMenuService: SideMenuService,
                 protected _snackBar: SnackBarService,
                 protected _impersonation: ImpersonationService,
+                protected _user: UserService,
                 @Optional() @Inject(NAE_USER_IMPERSONATE_COMPONENT) protected _userImpersonateComponent: any,
+                @Optional() @Inject(NAE_ADMIN_IMPERSONATE_COMPONENT) protected _adminImpersonateComponent: any,
     ) {}
 
     /**
      * Opens side menu with users who can be impersonated by logged user
      */
     public selectImpersonate(): void {
-        this._sideMenuService.open(this._userImpersonateComponent, SideMenuSize.MEDIUM).onClose.subscribe(event => {
-            this._log.debug('Impersonable user select :' + event);
-            if (event.data === undefined) {
-                return;
-            }
-            this._impersonation.impersonate(event.data._id);
+        if (this.isAdmin()) {
+            this._sideMenuService.open(this._adminImpersonateComponent, SideMenuSize.LARGE, this.injectedData()).onClose.subscribe(event => {
+                this._log.debug('Impersonable user select :' + event);
+                if (event.data === undefined) {
+                    return;
+                }
+                this._impersonation.impersonateUser(event.data._id);
+            });
+        } else {
+            this._sideMenuService.open(this._userImpersonateComponent, SideMenuSize.LARGE, this.injectedData()).onClose.subscribe(event => {
+                this._log.debug('Impersonable config select :' + event);
+                if (event.data === undefined) {
+                    return;
+                }
+                this._impersonation.impersonateByConfig((event.data as UserImpersonateConfigMetadata).stringId);
+            });
+        }
+    }
+
+    protected injectedData(): UserImpersonateInjectionData {
+        const currentTime = moment();
+        let filterCasesFilter = SimpleFilter.fromCaseQuery({
+            process: {
+                identifier: UserImpersonationConstants.IMPERSONATION_CONFIG_NET_IDENTIFIER
+            },
+            query: `
+            (dataSet.impersonators.keyValue:${this._user.user.id}) AND
+            (dataSet.is_active.booleanValue:true) AND
+            ((!(_exists_:dataSet.valid_from.timestampValue)) OR (dataSet.valid_from.timestampValue:< ${currentTime.valueOf()})) AND
+            ((!(_exists_:dataSet.valid_to.timestampValue)) OR (dataSet.valid_to.timestampValue:>${currentTime.valueOf()}))
+            `
         });
+        return {
+            filter: filterCasesFilter
+        } as UserImpersonateInjectionData
     }
+
+    protected isAdmin(): boolean {
+        return this._user.hasAuthority('ROLE_ADMIN');
+    }
+
 }
diff --git a/projects/netgrif-components-core/src/lib/impersonation/services/impersonation.service.ts b/projects/netgrif-components-core/src/lib/impersonation/services/impersonation.service.ts
index f57e236a86..1fdcfdaa2d 100644
--- a/projects/netgrif-components-core/src/lib/impersonation/services/impersonation.service.ts
+++ b/projects/netgrif-components-core/src/lib/impersonation/services/impersonation.service.ts
@@ -43,18 +43,19 @@ export class ImpersonationService extends AbstractResourceService implements OnD
         return this._impersonating$.asObservable();
     }
 
-    public impersonate(userId: number): void {
-        this.provider.post$('impersonate/' + userId, this.SERVER_URL, {}).subscribe((user: UserResource) => {
-            this._snackbar.openSuccessSnackBar(this._translate.instant('impersonation.user.successfullyRepresented'));
-            this._triggerReload();
+    public impersonateUser(userId: string): void {
+        this.provider.post$('impersonate/user/' + userId, this.SERVER_URL, {}).subscribe((user: UserResource) => {
+            this.resolveSuccess(user);
         }, (response => {
-            if (response.status === 400) {
-                response.error.alreadyImpersonated ?
-                    this._snackbar.openErrorSnackBar(this._translate.instant('impersonation.user.currentlyAlreadyRepresented')) :
-                    this._snackbar.openErrorSnackBar(this._translate.instant('impersonation.user.currentlyLogged'));
-            } else {
-                this._snackbar.openErrorSnackBar(this._translate.instant('impersonation.action.failed'));
-            }
+            this.resolveError(response);
+        }));
+    }
+
+    public impersonateByConfig(configId: string): void {
+        this.provider.post$('impersonate/config/' + configId, this.SERVER_URL, {}).subscribe((user: UserResource) => {
+            this.resolveSuccess(user);
+        }, (response => {
+            this.resolveError(response);
         }));
     }
 
@@ -67,7 +68,22 @@ export class ImpersonationService extends AbstractResourceService implements OnD
         }));
     }
 
-    private _triggerReload(): void {
+    protected resolveSuccess(user: UserResource) {
+        this._snackbar.openSuccessSnackBar(this._translate.instant('impersonation.user.successfullyRepresented'));
+        this._triggerReload();
+    }
+
+    protected resolveError(response: any) {
+        if (response.status === 400) {
+            response.error.alreadyImpersonated ?
+                this._snackbar.openErrorSnackBar(this._translate.instant('impersonation.user.currentlyAlreadyRepresented')) :
+                this._snackbar.openErrorSnackBar(this._translate.instant('impersonation.user.currentlyLogged'));
+        } else {
+            this._snackbar.openErrorSnackBar(this._translate.instant('impersonation.action.failed'));
+        }
+    }
+
+    protected _triggerReload(): void {
         this._userService.reload();
     }
 
diff --git a/projects/netgrif-components-core/src/lib/side-menu/content-components/injection-tokens.ts b/projects/netgrif-components-core/src/lib/side-menu/content-components/injection-tokens.ts
index c81c9e7173..4168ffa040 100644
--- a/projects/netgrif-components-core/src/lib/side-menu/content-components/injection-tokens.ts
+++ b/projects/netgrif-components-core/src/lib/side-menu/content-components/injection-tokens.ts
@@ -8,3 +8,4 @@ export const NAE_OPTION_SELECTOR_COMPONENT = new InjectionToken<ComponentType<un
 export const NAE_SAVE_FILTER_COMPONENT = new InjectionToken<ComponentType<unknown>>('NaeSaveFilterComponent');
 export const NAE_LOAD_FILTER_COMPONENT = new InjectionToken<ComponentType<unknown>>('NaeLoadFilterComponent');
 export const NAE_USER_IMPERSONATE_COMPONENT = new InjectionToken<ComponentType<unknown>>('NaeUserImpersonateComponent');
+export const NAE_ADMIN_IMPERSONATE_COMPONENT = new InjectionToken<ComponentType<unknown>>('NaeAdminImpersonateComponent');
diff --git a/projects/netgrif-components-core/src/lib/side-menu/content-components/public-api.ts b/projects/netgrif-components-core/src/lib/side-menu/content-components/public-api.ts
index d71103e2ab..12b66ddb3b 100644
--- a/projects/netgrif-components-core/src/lib/side-menu/content-components/public-api.ts
+++ b/projects/netgrif-components-core/src/lib/side-menu/content-components/public-api.ts
@@ -9,6 +9,7 @@ export * from './filter-selector/filter-selector-list-item/abstract-filter-selec
 export * from './option-selector/abstract-option-selector.component';
 export * from './save-filter/abstract-save-filter.component';
 export * from './load-filter/abstract-load-filter.component';
+export * from './user-impersonate/abstract-user-impersonate.component';
 
 /* MODELS */
 export * from './filter-selector/model/filter-selector-injection-data';
@@ -18,3 +19,4 @@ export * from './save-filter/model/save-filter-injection-data';
 export * from './load-filter/model/load-filter-injection-data';
 export * from './injection-tokens';
 export * from './new-case/model/new-case-injection-data';
+export * from './user-impersonate/model/user-impersonate-injection-data';
diff --git a/projects/netgrif-components-core/src/lib/side-menu/content-components/user-impersonate/abstract-user-impersonate.component.ts b/projects/netgrif-components-core/src/lib/side-menu/content-components/user-impersonate/abstract-user-impersonate.component.ts
new file mode 100644
index 0000000000..0a3ab5113a
--- /dev/null
+++ b/projects/netgrif-components-core/src/lib/side-menu/content-components/user-impersonate/abstract-user-impersonate.component.ts
@@ -0,0 +1,37 @@
+import {SideMenuControl} from '../../models/side-menu-control';
+import {Component, Inject} from '@angular/core';
+import {LoadFilterInjectionData} from '../load-filter/model/load-filter-injection-data';
+import {NAE_SIDE_MENU_CONTROL} from '../../side-menu-injection-token';
+import {LoggerService} from '../../../logger/services/logger.service';
+import {CaseViewService} from '../../../view/case-view/service/case-view-service';
+import {Case} from '../../../resources/interface/case';
+import {AbstractCaseViewComponent} from '../../../view/case-view/abstract-case-view';
+import {UserImpersonateConfigMetadata} from '../../../impersonation/models/user-impersonate-config-metadata';
+
+@Component({
+    selector: 'ncc-abstract-user-impersonate',
+    template: ''
+})
+export abstract class AbstractUserImpersonateComponent extends AbstractCaseViewComponent {
+
+    protected _injectedData: LoadFilterInjectionData;
+
+    protected constructor(@Inject(NAE_SIDE_MENU_CONTROL) protected _sideMenuControl: SideMenuControl,
+                          protected _log: LoggerService,
+                          caseViewService: CaseViewService) {
+        super(caseViewService);
+        if (this._sideMenuControl.data) {
+            this._injectedData = this._sideMenuControl.data as LoadFilterInjectionData;
+        }
+    }
+
+    handleCaseClick(clickedCase: Case) {
+        this._sideMenuControl.close({
+            opened: false,
+            message: 'User selected',
+            data: {
+                stringId: clickedCase.stringId
+            } as UserImpersonateConfigMetadata
+        });
+    }
+}
diff --git a/projects/netgrif-components-core/src/lib/side-menu/content-components/user-impersonate/model/user-impersonate-injection-data.ts b/projects/netgrif-components-core/src/lib/side-menu/content-components/user-impersonate/model/user-impersonate-injection-data.ts
new file mode 100644
index 0000000000..8e757ff898
--- /dev/null
+++ b/projects/netgrif-components-core/src/lib/side-menu/content-components/user-impersonate/model/user-impersonate-injection-data.ts
@@ -0,0 +1,9 @@
+import {SideMenuInjectionData} from '../../../models/side-menu-injection-data';
+import {Filter} from '../../../../filter/models/filter';
+
+export interface UserImpersonateInjectionData extends SideMenuInjectionData {
+    /**
+     * A case filter of the filter cases
+     */
+    filter: Filter;
+}
diff --git a/projects/netgrif-components/src/lib/side-menu/content-components/admin-impersonate/side-menu-admin-impersonate-component.module.ts b/projects/netgrif-components/src/lib/side-menu/content-components/admin-impersonate/side-menu-admin-impersonate-component.module.ts
index 7c6f7d352d..f2e526910c 100644
--- a/projects/netgrif-components/src/lib/side-menu/content-components/admin-impersonate/side-menu-admin-impersonate-component.module.ts
+++ b/projects/netgrif-components/src/lib/side-menu/content-components/admin-impersonate/side-menu-admin-impersonate-component.module.ts
@@ -6,7 +6,7 @@ import {FormsModule} from '@angular/forms';
 import {
     CovalentModule,
     MaterialModule,
-    NAE_USER_IMPERSONATE_COMPONENT,
+    NAE_ADMIN_IMPERSONATE_COMPONENT,
     TranslateLibModule
 } from '@netgrif/components-core';
 import {MatFormFieldModule} from '@angular/material/form-field';
@@ -34,7 +34,7 @@ import {
     ],
     exports: [AdminImpersonateComponent],
     providers: [
-        { provide: NAE_USER_IMPERSONATE_COMPONENT, useValue: AdminImpersonateComponent },
+        { provide: NAE_ADMIN_IMPERSONATE_COMPONENT, useValue: AdminImpersonateComponent },
     ]
 })
 export class SideMenuAdminImpersonateComponentModule {
diff --git a/projects/netgrif-components/src/lib/side-menu/content-components/public-api.ts b/projects/netgrif-components/src/lib/side-menu/content-components/public-api.ts
index 949f44fd7d..60a246267c 100644
--- a/projects/netgrif-components/src/lib/side-menu/content-components/public-api.ts
+++ b/projects/netgrif-components/src/lib/side-menu/content-components/public-api.ts
@@ -4,6 +4,7 @@ export * from './import-net/side-menu-import-net-component.module';
 export * from './new-case/side-menu-new-case-component.module';
 export * from './user-assign/side-menu-user-assign-component.module';
 export * from './admin-impersonate/side-menu-admin-impersonate-component.module';
+export * from './user-impersonate/side-menu-user-impersonate-component.module';
 export * from './filter-selector/side-menu-filter-selector-component.module';
 export * from './option-selector/side-menu-option-selector-component.module';
 export * from './save-filter/side-menu-save-filter-component.module';
@@ -18,5 +19,6 @@ export * from './filter-selector/filter-selector.component';
 export * from './option-selector/option-selector.component';
 export {SaveFilterComponent} from './save-filter/save-filter.component';
 export {LoadFilterComponent} from './load-filter/load-filter.component';
+export {UserImpersonateComponent} from './user-impersonate/user-impersonate.component';
 
 /* MODELS */
diff --git a/projects/netgrif-components/src/lib/side-menu/content-components/side-menu-content-component.module.ts b/projects/netgrif-components/src/lib/side-menu/content-components/side-menu-content-component.module.ts
index 1000cef41b..189df8fde6 100644
--- a/projects/netgrif-components/src/lib/side-menu/content-components/side-menu-content-component.module.ts
+++ b/projects/netgrif-components/src/lib/side-menu/content-components/side-menu-content-component.module.ts
@@ -13,7 +13,7 @@ import {
     NAE_SAVE_FILTER_COMPONENT,
     NAE_USER_ASSIGN_COMPONENT,
     NAE_LOAD_FILTER_COMPONENT,
-    NAE_USER_IMPERSONATE_COMPONENT
+    NAE_USER_IMPERSONATE_COMPONENT, NAE_ADMIN_IMPERSONATE_COMPONENT
 } from '@netgrif/components-core';
 import {UserAssignComponent} from './user-assign/user-assign.component';
 import {NewCaseComponent} from './new-case/new-case.component';
@@ -24,6 +24,7 @@ import {
     SideMenuAdminImpersonateComponentModule
 } from './admin-impersonate/side-menu-admin-impersonate-component.module';
 import {AdminImpersonateComponent} from './admin-impersonate/admin-impersonate.component';
+import {UserImpersonateComponent} from './user-impersonate/user-impersonate.component';
 
 
 @NgModule({
@@ -50,7 +51,8 @@ import {AdminImpersonateComponent} from './admin-impersonate/admin-impersonate.c
     ],
     providers: [
         {provide: NAE_USER_ASSIGN_COMPONENT, useValue: UserAssignComponent},
-        {provide: NAE_USER_IMPERSONATE_COMPONENT, useValue: AdminImpersonateComponent},
+        {provide: NAE_ADMIN_IMPERSONATE_COMPONENT, useValue: AdminImpersonateComponent},
+        {provide: NAE_USER_IMPERSONATE_COMPONENT, useValue: UserImpersonateComponent},
         {provide: NAE_NEW_CASE_COMPONENT, useValue: NewCaseComponent},
         {provide: NAE_OPTION_SELECTOR_COMPONENT, useValue: OptionSelectorComponent},
         {provide: NAE_SAVE_FILTER_COMPONENT, useValue: SaveFilterComponent},
diff --git a/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/side-menu-user-impersonate-component.module.ts b/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/side-menu-user-impersonate-component.module.ts
new file mode 100644
index 0000000000..ea3c9fa672
--- /dev/null
+++ b/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/side-menu-user-impersonate-component.module.ts
@@ -0,0 +1,28 @@
+import {NgModule} from '@angular/core';
+import {CommonModule} from '@angular/common';
+import {UserImpersonateComponent} from './user-impersonate.component';
+import {
+    MaterialModule,
+    NAE_USER_IMPERSONATE_COMPONENT,
+    TranslateLibModule
+} from '@netgrif/components-core';
+import {CaseViewComponentModule} from '../../../view/case-view/case-view.module';
+import {HeaderComponentModule} from '../../../header/header.module';
+
+
+@NgModule({
+    imports: [
+        CommonModule,
+        MaterialModule,
+        TranslateLibModule,
+        CaseViewComponentModule,
+        HeaderComponentModule,
+    ],
+    declarations: [UserImpersonateComponent],
+    exports: [UserImpersonateComponent],
+    providers: [
+        { provide: NAE_USER_IMPERSONATE_COMPONENT, useValue: UserImpersonateComponent }
+    ]
+})
+export class SideMenuUserImpersonateComponentModule {
+}
diff --git a/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate.component.html b/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate.component.html
new file mode 100644
index 0000000000..e7d1e76c8b
--- /dev/null
+++ b/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate.component.html
@@ -0,0 +1,6 @@
+<mat-toolbar color="primary">{{'search.tooltip.load' | translate}}</mat-toolbar>
+<div class="load-filter-container side-menu-root" fxLayout="column" fxLayoutAlign="start stretch">
+    <nc-header #header [type]="headerType" [maxHeaderColumns]="3" [responsiveHeaders]="true" [hideEditMode]="true" class="case-header-padding" [ngStyle]="{'width': getWidth()}"></nc-header>
+    <nc-case-list [selectedHeaders$]="selectedHeaders$" [showDeleteMenu]="false" [width]="getWidth()"
+                  (caseClick)="handleCaseClick($event)" [responsiveBody]="true" fxFlex [textEllipsis]="true" class="virtual-scroll-list-padding"></nc-case-list>
+</div>
diff --git a/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate.component.scss b/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate.component.scss
new file mode 100644
index 0000000000..aa2944751e
--- /dev/null
+++ b/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate.component.scss
@@ -0,0 +1,16 @@
+@import '../../side-menu.theme';
+
+.load-filter-container {
+    height: calc(100% - 64px);
+    padding-left: 8px;
+    padding-right: 8px;
+}
+
+.case-header-padding {
+    padding-bottom: 16px;
+    padding-top: 4px;
+}
+
+.virtual-scroll-list-padding {
+    padding-right: 4px;
+}
diff --git a/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate.component.spec.ts b/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate.component.spec.ts
new file mode 100644
index 0000000000..603b331f25
--- /dev/null
+++ b/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate.component.spec.ts
@@ -0,0 +1,25 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { UserImpersonateComponent } from './user-impersonate.component';
+
+describe('UserImpersonateComponent', () => {
+  let component: UserImpersonateComponent;
+  let fixture: ComponentFixture<UserImpersonateComponent>;
+
+  beforeEach(async () => {
+    await TestBed.configureTestingModule({
+      declarations: [ UserImpersonateComponent ]
+    })
+    .compileComponents();
+  });
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(UserImpersonateComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});
diff --git a/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate.component.ts b/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate.component.ts
new file mode 100644
index 0000000000..e14f283362
--- /dev/null
+++ b/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate.component.ts
@@ -0,0 +1,62 @@
+import {AfterViewInit, Component, Inject, ViewChild} from '@angular/core';
+import {
+    NAE_SIDE_MENU_CONTROL,
+    AbstractUserImpersonateComponent,
+    SideMenuControl,
+    LoggerService,
+    CaseViewService,
+    BaseFilter,
+    AllowedNetsServiceFactory,
+    AllowedNetsService,
+    SearchService,
+    NAE_BASE_FILTER,
+    NAE_DEFAULT_HEADERS,
+    UserImpersonationConstants,
+    UserImpersonateInjectionData
+} from '@netgrif/components-core';
+import {HeaderComponent} from '../../../header/header.component';
+
+function baseFilterFactory(sideMenuControl: SideMenuControl): BaseFilter {
+    if (!sideMenuControl.data) {
+        throw new Error('NewFilterCaseId was not provided in the side menu injection data');
+    }
+    const injectedData = sideMenuControl.data as UserImpersonateInjectionData;
+
+    return {filter: injectedData.filter};
+}
+
+function localAllowedNetsFactory(factory: AllowedNetsServiceFactory): AllowedNetsService {
+    return factory.createFromArray([UserImpersonationConstants.IMPERSONATION_CONFIG_NET_IDENTIFIER]);
+}
+
+@Component({
+    selector: 'nc-user-impersonate',
+    templateUrl: './user-impersonate.component.html',
+    styleUrls: ['./user-impersonate.component.scss'],
+    providers: [
+        CaseViewService,
+        SearchService,
+        {   provide: NAE_BASE_FILTER,
+            useFactory: baseFilterFactory,
+            deps: [NAE_SIDE_MENU_CONTROL]},
+        {   provide: AllowedNetsService,
+            useFactory: localAllowedNetsFactory,
+            deps: [AllowedNetsServiceFactory]},
+        {   provide: NAE_DEFAULT_HEADERS,
+            useValue: ['meta-title', `${UserImpersonationConstants.IMPERSONATION_CONFIG_NET_IDENTIFIER}-impersonated`]}
+    ]
+})
+export class UserImpersonateComponent extends AbstractUserImpersonateComponent implements AfterViewInit {
+
+    @ViewChild('header') public caseHeaderComponent: HeaderComponent;
+
+    constructor(@Inject(NAE_SIDE_MENU_CONTROL) sideMenuControl: SideMenuControl,
+                log: LoggerService,
+                caseViewService: CaseViewService) {
+        super(sideMenuControl, log, caseViewService);
+    }
+
+    ngAfterViewInit(): void {
+        this.initializeHeader(this.caseHeaderComponent);
+    }
+}

From 307bfd7f299956a908d0286025f0f806e656312d Mon Sep 17 00:00:00 2001
From: Bezak <bezak@netgrif.com>
Date: Mon, 19 Sep 2022 22:01:45 +0200
Subject: [PATCH 07/21] [NAE-1678] User impersonation - add buttons for
 impersonation into drawer components - add localization (german todo)

---
 .../drawer-example.component.html             |  2 +-
 .../src/assets/i18n/de.json                   | 17 ++++++++++
 .../src/assets/i18n/en.json                   | 17 ++++++++++
 .../src/assets/i18n/sk.json                   | 17 ++++++++++
 .../abstract-navigation-double-drawer.ts      | 13 ++++++++
 .../abstract-navigation-drawer.component.ts   |  2 +-
 .../abstract-quick-panel.component.ts         |  2 +-
 .../navigation-double-drawer.component.html   | 11 ++++++-
 .../navigation-double-drawer.component.ts     |  6 ++--
 .../impersonate-quick-panel.component.html    |  6 ++++
 .../impersonate-quick-panel.component.scss    |  0
 .../impersonate-quick-panel.component.spec.ts | 25 +++++++++++++++
 .../impersonate-quick-panel.component.ts      | 32 +++++++++++++++++++
 .../components/quick-panel.component.html     |  1 +
 .../lib/navigation/quick-panel/public-api.ts  |  1 +
 .../quick-panel/quick-panel.module.ts         |  7 ++--
 .../admin-impersonate.component.html          |  4 +--
 .../user/user-card/user-card.component.html   |  1 +
 .../user/user-card/user-card.component.scss   |  4 +++
 19 files changed, 158 insertions(+), 10 deletions(-)
 create mode 100644 projects/netgrif-components/src/lib/navigation/quick-panel/components/impersonate-quick-panel/impersonate-quick-panel.component.html
 create mode 100644 projects/netgrif-components/src/lib/navigation/quick-panel/components/impersonate-quick-panel/impersonate-quick-panel.component.scss
 create mode 100644 projects/netgrif-components/src/lib/navigation/quick-panel/components/impersonate-quick-panel/impersonate-quick-panel.component.spec.ts
 create mode 100644 projects/netgrif-components/src/lib/navigation/quick-panel/components/impersonate-quick-panel/impersonate-quick-panel.component.ts

diff --git a/projects/nae-example-app/src/app/doc/drawer-example/drawer-example.component.html b/projects/nae-example-app/src/app/doc/drawer-example/drawer-example.component.html
index 720d54b6af..ba3c9b5002 100644
--- a/projects/nae-example-app/src/app/doc/drawer-example/drawer-example.component.html
+++ b/projects/nae-example-app/src/app/doc/drawer-example/drawer-example.component.html
@@ -1,4 +1,4 @@
-<nc-navigation-drawer #sidenav [fixed]="fixed" [user]="true" [quickPanel]="true" [navigation]="true"
+<nc-navigation-drawer #sidenav [fixed]="fixed" [user]="true" [quickPanel]="true" [navigation]="true" [panelItems]="['language', 'settings', 'logout', 'impersonation']"
                        (openedChange)="openStatusChanged($event)">
 
     <div fxLayout="column" fxLayoutAlign="start start" style="padding: 16px; height: 1000px;">
diff --git a/projects/netgrif-components-core/src/assets/i18n/de.json b/projects/netgrif-components-core/src/assets/i18n/de.json
index c14e97963b..8ce110e46c 100644
--- a/projects/netgrif-components-core/src/assets/i18n/de.json
+++ b/projects/netgrif-components-core/src/assets/i18n/de.json
@@ -108,6 +108,12 @@
         "option-selector": {
             "select": "Auswählen",
             "choose-one-option": "Wählen Sie eine Option aus"
+        },
+        "impersonation": {
+            "title": "Impersonate user",
+            "submit": "Impersonate",
+            "cease": "Cancel impersonation",
+            "impersonating": "impersonating"
         }
     },
     "search": {
@@ -456,5 +462,16 @@
     },
     "dynamicNavigation": {
         "couldNotResolveView": "Ein Fehler ist aufgetreten während des Ansichtauflösungsprocess. Der Ansicht kann nicht angezeigt werden"
+    },
+    "impersonation": {
+        "user": {
+            "successfullyRepresented": "User successfully represented",
+            "currentlyAlreadyRepresented": "User is already currently represented",
+            "currentlyLogged": "User is currently logged in"
+        },
+        "action": {
+            "failed": "Action failed",
+            "deactivated": "Representation was successfully deactivated"
+        }
     }
 }
diff --git a/projects/netgrif-components-core/src/assets/i18n/en.json b/projects/netgrif-components-core/src/assets/i18n/en.json
index 282f16bc26..b02295e3f8 100644
--- a/projects/netgrif-components-core/src/assets/i18n/en.json
+++ b/projects/netgrif-components-core/src/assets/i18n/en.json
@@ -108,6 +108,12 @@
         "option-selector": {
             "select": "Select",
             "choose-one-option": "Choose one of the provided options"
+        },
+        "impersonation": {
+            "title": "Impersonate user",
+            "submit": "Impersonate",
+            "cease": "Cancel impersonation",
+            "impersonating": "impersonating"
         }
     },
     "search": {
@@ -456,5 +462,16 @@
     },
     "dynamicNavigation": {
         "couldNotResolveView": "An error has occurred during the view resolution process. The view could not be displayed"
+    },
+    "impersonation": {
+        "user": {
+            "successfullyRepresented": "User successfully represented",
+            "currentlyAlreadyRepresented": "User is already currently represented",
+            "currentlyLogged": "User is currently logged in"
+        },
+        "action": {
+            "failed": "Action failed",
+            "deactivated": "Representation was successfully deactivated"
+        }
     }
 }
diff --git a/projects/netgrif-components-core/src/assets/i18n/sk.json b/projects/netgrif-components-core/src/assets/i18n/sk.json
index 301f860f33..1112ca61fa 100644
--- a/projects/netgrif-components-core/src/assets/i18n/sk.json
+++ b/projects/netgrif-components-core/src/assets/i18n/sk.json
@@ -108,6 +108,12 @@
         "option-selector": {
             "select": "Zvoliť",
             "choose-one-option": "Vyberte jednu z možností"
+        },
+        "impersonation": {
+            "title": "Zastúpenie používateľa",
+            "submit": "Zastúpiť",
+            "cease": "Zrušiť zastúpenie",
+            "impersonating": "v zastúpení"
         }
     },
     "search": {
@@ -456,5 +462,16 @@
     },
     "dynamicNavigation": {
         "couldNotResolveView": "Počas načítania zobrazenia sa vyskytla chyba. Zobrazenie nie je možné zobraziť"
+    },
+    "impersonation": {
+        "user": {
+            "successfullyRepresented": "Používateľ bol úspešne zastúpený",
+            "currentlyAlreadyRepresented": "Používateľ je momentálne už zastúpený",
+            "currentlyLogged": "Používateľ je momentálne prihlásený"
+        },
+        "action": {
+            "failed": "Akciu sa nepodarilo vykonať",
+            "deactivated": "Zastupovanie bolo úspešne deaktivované"
+        }
     }
 }
diff --git a/projects/netgrif-components-core/src/lib/navigation/navigation-double-drawer/abstract-navigation-double-drawer.ts b/projects/netgrif-components-core/src/lib/navigation/navigation-double-drawer/abstract-navigation-double-drawer.ts
index e96c93bfde..81cd95f45e 100644
--- a/projects/netgrif-components-core/src/lib/navigation/navigation-double-drawer/abstract-navigation-double-drawer.ts
+++ b/projects/netgrif-components-core/src/lib/navigation/navigation-double-drawer/abstract-navigation-double-drawer.ts
@@ -19,6 +19,8 @@ import {User} from "../../user/models/user";
 import {RoleAccess, View} from "../../../commons/schema";
 import {NAE_ROUTING_CONFIGURATION_PATH} from "../../routing/routing-builder/routing-builder.service";
 import {AccessService} from "../../authorization/permission/access.service";
+import {ImpersonationUserSelectService} from '../../impersonation/services/impersonation-user-select.service';
+import {ImpersonationService} from '../../impersonation/services/impersonation.service';
 
 export interface ConfigDoubleMenu {
     mode: MatDrawerMode;
@@ -57,6 +59,7 @@ export abstract class AbstractNavigationDoubleDrawerComponent implements OnInit,
     @Input() includeUser: boolean = true;
     @Input() includeLanguage: boolean = true;
     @Input() includeMoreMenu: boolean = true;
+    @Input() includeImpersonation: boolean = true;
     @Input() allClosable: boolean = true;
     @Input() folderIcon: string = "folder";
     @Input() openedFolderIcon: string = "folder_open";
@@ -121,6 +124,8 @@ export abstract class AbstractNavigationDoubleDrawerComponent implements OnInit,
                           protected _log: LoggerService,
                           protected _config: ConfigurationService,
                           protected _uriService: UriService,
+                          protected _impersonationUserSelect: ImpersonationUserSelectService,
+                          protected _impersonation: ImpersonationService,
                           protected _dynamicRoutingService: DynamicNavigationRouteProviderService) {
         this.leftNodes = new Array<UriNodeResource>();
         this.rightNodes = new Array<UriNodeResource>();
@@ -269,6 +274,14 @@ export abstract class AbstractNavigationDoubleDrawerComponent implements OnInit,
         });
     }
 
+    impersonate(): void {
+        this._impersonationUserSelect.selectImpersonate();
+    }
+
+    stopImpersonating(): void {
+        this._impersonation.cease();
+    }
+
     get user(): User {
         return this._userService.user;
     }
diff --git a/projects/netgrif-components-core/src/lib/navigation/navigation-drawer/abstract-navigation-drawer.component.ts b/projects/netgrif-components-core/src/lib/navigation/navigation-drawer/abstract-navigation-drawer.component.ts
index 7d0df1d65c..dfd86c2e62 100644
--- a/projects/netgrif-components-core/src/lib/navigation/navigation-drawer/abstract-navigation-drawer.component.ts
+++ b/projects/netgrif-components-core/src/lib/navigation/navigation-drawer/abstract-navigation-drawer.component.ts
@@ -47,7 +47,7 @@ export abstract class AbstractNavigationDrawerComponent implements OnInit, After
         this.openedChange = new EventEmitter<boolean>();
         this._fixed = true;
         this.opened = true;
-        this.quickPanelItems = ['language', 'settings', 'logout'];
+        this.quickPanelItems = ['language', 'settings', 'logout', 'impersonation'];
         if (this.userPreferenceService.drawerWidth !== undefined) {
             this.contentWidth = new BehaviorSubject<number>(this.userPreferenceService.drawerWidth);
         } else {
diff --git a/projects/netgrif-components-core/src/lib/navigation/quick-panel/components/abstract-quick-panel.component.ts b/projects/netgrif-components-core/src/lib/navigation/quick-panel/components/abstract-quick-panel.component.ts
index 385e887f4d..c4bce49683 100644
--- a/projects/netgrif-components-core/src/lib/navigation/quick-panel/components/abstract-quick-panel.component.ts
+++ b/projects/netgrif-components-core/src/lib/navigation/quick-panel/components/abstract-quick-panel.component.ts
@@ -3,7 +3,7 @@ import {LanguageService} from '../../../translate/language.service';
 import {PaperViewService} from './paper-view.service';
 import {AbstractNavigationResizableDrawerComponent} from '../../navigation-drawer/abstract-navigation-resizable-drawer.component';
 
-export type QuickPanelItem = 'language' | 'settings' | 'logout';
+export type QuickPanelItem = 'language' | 'settings' | 'logout' | 'impersonation';
 
 @Component({
     selector: 'ncc-abstract-quick-panel',
diff --git a/projects/netgrif-components/src/lib/navigation/navigation-double-drawer/navigation-double-drawer.component.html b/projects/netgrif-components/src/lib/navigation/navigation-double-drawer/navigation-double-drawer.component.html
index b795aed865..ca006ab48e 100644
--- a/projects/netgrif-components/src/lib/navigation/navigation-double-drawer/navigation-double-drawer.component.html
+++ b/projects/netgrif-components/src/lib/navigation/navigation-double-drawer/navigation-double-drawer.component.html
@@ -34,10 +34,19 @@
                     [routerLink]="profileRouterLink" routerLinkActive="active">
                     <mat-icon class="margin-auto" fxFlex>face</mat-icon>
                     <div class="large-menu-item" fxLayout="column" fxFlexAlign="start center" fxFlex>
-                        <span class="large-menu-item-text" fxFlex="50">{{user.fullName}}</span>
+                        <span *ngIf="!user.isImpersonating()"  class="large-menu-item-text" fxFlex="50">{{user.fullName}}</span>
+                        <span *ngIf="user.isImpersonating()" class="large-menu-item-text" fxFlex="50">{{user.fullName}} ({{user.getSelfOrImpersonated().fullName}})</span>
                         <span class="large-menu-item-text" style="font-size: 12px;" fxFlex="50">{{user.email}}</span>
                     </div>
                 </div>
+                <button *ngIf="includeImpersonation && !user.isImpersonating()" mat-menu-item (click)="impersonate()">
+                    <mat-icon>supervisor_account</mat-icon>
+                    <span>{{'side-menu.impersonation.submit' | translate}}</span>
+                </button>
+                <button *ngIf="includeImpersonation && user.isImpersonating()" mat-menu-item (click)="stopImpersonating()">
+                    <mat-icon>clear</mat-icon>
+                    <span>{{'side-menu.impersonation.cease' | translate }}</span>
+                </button>
                 <button mat-menu-item (click)="logout()">
                     <mat-icon>exit_to_app</mat-icon>
                     <span>{{ 'toolbar.menu.logout' | translate }}</span>
diff --git a/projects/netgrif-components/src/lib/navigation/navigation-double-drawer/navigation-double-drawer.component.ts b/projects/netgrif-components/src/lib/navigation/navigation-double-drawer/navigation-double-drawer.component.ts
index 0fbba5648a..bfe1957f51 100644
--- a/projects/netgrif-components/src/lib/navigation/navigation-double-drawer/navigation-double-drawer.component.ts
+++ b/projects/netgrif-components/src/lib/navigation/navigation-double-drawer/navigation-double-drawer.component.ts
@@ -8,7 +8,7 @@ import {
     LoggerService,
     UserService,
     AbstractNavigationDoubleDrawerComponent,
-    DynamicNavigationRouteProviderService, AccessService
+    DynamicNavigationRouteProviderService, AccessService, ImpersonationUserSelectService, ImpersonationService
 } from '@netgrif/components-core';
 import {animate, state, style, transition, trigger} from "@angular/animations";
 
@@ -59,9 +59,11 @@ export class NavigationDoubleDrawerComponent extends AbstractNavigationDoubleDra
                 _log: LoggerService,
                 _config: ConfigurationService,
                 _uriService: UriService,
+                _impersonationUserSelect: ImpersonationUserSelectService,
+                _impersonation: ImpersonationService,
                 _dynamicRouteProviderService: DynamicNavigationRouteProviderService) {
         super(_router, _activatedRoute, _breakpoint, _languageService, _userService, _accessService, _log, _config, _uriService,
-            _dynamicRouteProviderService)
+            _impersonationUserSelect, _impersonation, _dynamicRouteProviderService)
     }
 
     public toggleSection(section: string): void {
diff --git a/projects/netgrif-components/src/lib/navigation/quick-panel/components/impersonate-quick-panel/impersonate-quick-panel.component.html b/projects/netgrif-components/src/lib/navigation/quick-panel/components/impersonate-quick-panel/impersonate-quick-panel.component.html
new file mode 100644
index 0000000000..43a6808704
--- /dev/null
+++ b/projects/netgrif-components/src/lib/navigation/quick-panel/components/impersonate-quick-panel/impersonate-quick-panel.component.html
@@ -0,0 +1,6 @@
+<button *ngIf="!isImpersonating()" [matTooltip]="'side-menu.impersonation.submit' | translate" (click)="impersonate()" mat-icon-button>
+    <mat-icon>supervisor_account</mat-icon>
+</button>
+<button *ngIf="isImpersonating()" [matTooltip]="'side-menu.impersonation.cease' | translate" (click)="stopImpersonating()" mat-icon-button>
+    <mat-icon>clear</mat-icon>
+</button>
diff --git a/projects/netgrif-components/src/lib/navigation/quick-panel/components/impersonate-quick-panel/impersonate-quick-panel.component.scss b/projects/netgrif-components/src/lib/navigation/quick-panel/components/impersonate-quick-panel/impersonate-quick-panel.component.scss
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/projects/netgrif-components/src/lib/navigation/quick-panel/components/impersonate-quick-panel/impersonate-quick-panel.component.spec.ts b/projects/netgrif-components/src/lib/navigation/quick-panel/components/impersonate-quick-panel/impersonate-quick-panel.component.spec.ts
new file mode 100644
index 0000000000..8b9ea30998
--- /dev/null
+++ b/projects/netgrif-components/src/lib/navigation/quick-panel/components/impersonate-quick-panel/impersonate-quick-panel.component.spec.ts
@@ -0,0 +1,25 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { ImpersonateQuickPanelComponent } from './impersonate-quick-panel.component';
+
+describe('ImpersonateQuickPanelComponent', () => {
+  let component: ImpersonateQuickPanelComponent;
+  let fixture: ComponentFixture<ImpersonateQuickPanelComponent>;
+
+  beforeEach(async () => {
+    await TestBed.configureTestingModule({
+      declarations: [ ImpersonateQuickPanelComponent ]
+    })
+    .compileComponents();
+  });
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(ImpersonateQuickPanelComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});
diff --git a/projects/netgrif-components/src/lib/navigation/quick-panel/components/impersonate-quick-panel/impersonate-quick-panel.component.ts b/projects/netgrif-components/src/lib/navigation/quick-panel/components/impersonate-quick-panel/impersonate-quick-panel.component.ts
new file mode 100644
index 0000000000..f9a8ab41b0
--- /dev/null
+++ b/projects/netgrif-components/src/lib/navigation/quick-panel/components/impersonate-quick-panel/impersonate-quick-panel.component.ts
@@ -0,0 +1,32 @@
+import {Component, OnInit} from '@angular/core';
+import {ImpersonationService, ImpersonationUserSelectService, UserService} from 'netgrif-components-core';
+
+@Component({
+    selector: 'nc-impersonate-quick-panel',
+    templateUrl: './impersonate-quick-panel.component.html',
+    styleUrls: ['./impersonate-quick-panel.component.scss']
+})
+export class ImpersonateQuickPanelComponent implements OnInit {
+
+    constructor(
+        private impersonateUserSelect: ImpersonationUserSelectService,
+        private impersonationService: ImpersonationService,
+        private user: UserService,
+    ) {}
+
+    ngOnInit(): void {
+    }
+
+    public impersonate(): void {
+        this.impersonateUserSelect.selectImpersonate();
+    }
+
+    public stopImpersonating(): void {
+        this.impersonationService.cease();
+    }
+
+    public isImpersonating(): boolean {
+        return this.user.user.isImpersonating();
+    }
+
+}
diff --git a/projects/netgrif-components/src/lib/navigation/quick-panel/components/quick-panel.component.html b/projects/netgrif-components/src/lib/navigation/quick-panel/components/quick-panel.component.html
index 23970a8f09..9e374a7e43 100644
--- a/projects/netgrif-components/src/lib/navigation/quick-panel/components/quick-panel.component.html
+++ b/projects/netgrif-components/src/lib/navigation/quick-panel/components/quick-panel.component.html
@@ -1,6 +1,7 @@
 <div fxLayout="row" fxLayoutAlign="space-between center" class="quick-panel" [style.width.px]="width">
     <nc-language-selector *ngIf="items.includes('language')" [language]="getLang()"></nc-language-selector>
     <nc-internal-link *ngIf="items.includes('settings')" icon="settings" link="/settings"></nc-internal-link>
+    <nc-impersonate-quick-panel *ngIf="items.includes('impersonation')"></nc-impersonate-quick-panel>
     <nc-logout-shortcut *ngIf="items.includes('logout')"></nc-logout-shortcut>
 
     <button mat-icon-button [matMenuTriggerFor]="quickPanelMoreMenu">
diff --git a/projects/netgrif-components/src/lib/navigation/quick-panel/public-api.ts b/projects/netgrif-components/src/lib/navigation/quick-panel/public-api.ts
index 804c1fd06f..a24c766078 100644
--- a/projects/netgrif-components/src/lib/navigation/quick-panel/public-api.ts
+++ b/projects/netgrif-components/src/lib/navigation/quick-panel/public-api.ts
@@ -6,5 +6,6 @@ export * from './components/quick-panel.component';
 export * from './components/internal-link/internal-link.component';
 export * from './components/logout-shortcut/logout-shortcut.component';
 export * from './components/language-selector/language-selector.component';
+export * from './components/impersonate-quick-panel/impersonate-quick-panel.component';
 
 /* SERVICES */
diff --git a/projects/netgrif-components/src/lib/navigation/quick-panel/quick-panel.module.ts b/projects/netgrif-components/src/lib/navigation/quick-panel/quick-panel.module.ts
index 95d009241d..38a14bb4f9 100644
--- a/projects/netgrif-components/src/lib/navigation/quick-panel/quick-panel.module.ts
+++ b/projects/netgrif-components/src/lib/navigation/quick-panel/quick-panel.module.ts
@@ -6,6 +6,7 @@ import {LanguageSelectorComponent} from './components/language-selector/language
 import {InternalLinkComponent} from './components/internal-link/internal-link.component';
 import {RouterModule} from '@angular/router';
 import {MaterialModule, TranslateLibModule} from '@netgrif/components-core';
+import { ImpersonateQuickPanelComponent } from './components/impersonate-quick-panel/impersonate-quick-panel.component';
 
 
 @NgModule({
@@ -13,13 +14,15 @@ import {MaterialModule, TranslateLibModule} from '@netgrif/components-core';
         QuickPanelComponent,
         LogoutShortcutComponent,
         LanguageSelectorComponent,
-        InternalLinkComponent
+        InternalLinkComponent,
+        ImpersonateQuickPanelComponent
     ],
     exports: [
         QuickPanelComponent,
         LogoutShortcutComponent,
         LanguageSelectorComponent,
-        InternalLinkComponent
+        InternalLinkComponent,
+        ImpersonateQuickPanelComponent
     ],
     imports: [
         CommonModule,
diff --git a/projects/netgrif-components/src/lib/side-menu/content-components/admin-impersonate/admin-impersonate.component.html b/projects/netgrif-components/src/lib/side-menu/content-components/admin-impersonate/admin-impersonate.component.html
index ea83696f6c..b2bc228a1f 100644
--- a/projects/netgrif-components/src/lib/side-menu/content-components/admin-impersonate/admin-impersonate.component.html
+++ b/projects/netgrif-components/src/lib/side-menu/content-components/admin-impersonate/admin-impersonate.component.html
@@ -1,5 +1,5 @@
 <div class="full-width full-height" fxLayout="column" fxLayoutAlign="start stretch">
-    <mat-toolbar color="primary">{{ 'side-menu.user.assign' | translate | uppercase }}</mat-toolbar>
+    <mat-toolbar color="primary">{{ 'side-menu.impersonation.title' | translate | uppercase }}</mat-toolbar>
     <div class="user-assign-container side-menu-root" fxLayout="column" fxFlex>
         <div fxLayout="row" fxLayoutAlign="start center" class="netgrif-input netgrif-input-fix">
             <mat-icon fxFlex class="search-icon">search</mat-icon>
@@ -23,7 +23,7 @@
 
         <div fxLayout="row" fxLayoutAlign="end center">
             <button mat-raised-button color="primary"
-                    (click)="assign()">{{ 'tasks.view.assign' | translate | uppercase }}</button>
+                    (click)="assign()">{{ 'side-menu.impersonation.submit' | translate | uppercase }}</button>
         </div>
     </div>
 </div>
diff --git a/projects/netgrif-components/src/lib/user/user-card/user-card.component.html b/projects/netgrif-components/src/lib/user/user-card/user-card.component.html
index e73918109a..10aacd7d62 100644
--- a/projects/netgrif-components/src/lib/user/user-card/user-card.component.html
+++ b/projects/netgrif-components/src/lib/user/user-card/user-card.component.html
@@ -19,6 +19,7 @@
         </div>
         <div fxLayout="column" fxLayoutAlign="center center" class="full-width full-showcase-text padding-default">
             <span>{{user.fullName}}</span>
+            <span class="impersonated-user-name" *ngIf="user.isImpersonating()">{{'side-menu.impersonation.impersonating' | translate }} {{user.getSelfOrImpersonated().fullName}}</span>
             <span>{{user.email}}</span>
         </div>
     </div>
diff --git a/projects/netgrif-components/src/lib/user/user-card/user-card.component.scss b/projects/netgrif-components/src/lib/user/user-card/user-card.component.scss
index b972d1292c..514749658c 100644
--- a/projects/netgrif-components/src/lib/user/user-card/user-card.component.scss
+++ b/projects/netgrif-components/src/lib/user/user-card/user-card.component.scss
@@ -62,6 +62,10 @@
     }
 }
 
+.impersonated-user-name {
+    font-size: 16px;
+}
+
 .horizontal-showcase-container {
     height: 80px;
     border: 1px solid #fd971f;

From 2edb35845c2d21441832a9bca9bc5fdccc3b49cf Mon Sep 17 00:00:00 2001
From: Bezak <bezak@netgrif.com>
Date: Tue, 20 Sep 2022 23:55:19 +0200
Subject: [PATCH 08/21] [NAE-1678] User impersonation - improve visual (bigger
 menu for impersonation) - change impersonation case view headers

---
 .../impersonation/models/user-impersonation-constants.ts    | 4 ++++
 .../services/impersonation-user-select.service.ts           | 4 ++--
 .../src/lib/side-menu/models/side-menu-size.ts              | 3 ++-
 .../user-impersonate/user-impersonate.component.html        | 2 +-
 .../user-impersonate/user-impersonate.component.ts          | 6 +++++-
 .../side-menu-container/side-menu-container.component.scss  | 4 ++++
 6 files changed, 18 insertions(+), 5 deletions(-)

diff --git a/projects/netgrif-components-core/src/lib/impersonation/models/user-impersonation-constants.ts b/projects/netgrif-components-core/src/lib/impersonation/models/user-impersonation-constants.ts
index 574eec62f0..47097d36c2 100644
--- a/projects/netgrif-components-core/src/lib/impersonation/models/user-impersonation-constants.ts
+++ b/projects/netgrif-components-core/src/lib/impersonation/models/user-impersonation-constants.ts
@@ -5,4 +5,8 @@ export enum UserImpersonationConstants {
 
     IMPERSONATION_CONFIG_NET_IDENTIFIER = 'impersonation_config',
 
+    IMPERSONATION_CONFIG_FIELD_IMPERSONATED = 'impersonated',
+    IMPERSONATION_CONFIG_FIELD_ROLES = 'impersonated_roles',
+    IMPERSONATION_CONFIG_FIELD_AUTHS = 'impersonated_authorities',
+
 }
diff --git a/projects/netgrif-components-core/src/lib/impersonation/services/impersonation-user-select.service.ts b/projects/netgrif-components-core/src/lib/impersonation/services/impersonation-user-select.service.ts
index 089d8cbe89..c28fc4b224 100644
--- a/projects/netgrif-components-core/src/lib/impersonation/services/impersonation-user-select.service.ts
+++ b/projects/netgrif-components-core/src/lib/impersonation/services/impersonation-user-select.service.ts
@@ -41,7 +41,7 @@ export class ImpersonationUserSelectService {
                 this._impersonation.impersonateUser(event.data._id);
             });
         } else {
-            this._sideMenuService.open(this._userImpersonateComponent, SideMenuSize.LARGE, this.injectedData()).onClose.subscribe(event => {
+            this._sideMenuService.open(this._userImpersonateComponent, SideMenuSize.XL, this.injectedData()).onClose.subscribe(event => {
                 this._log.debug('Impersonable config select :' + event);
                 if (event.data === undefined) {
                     return;
@@ -60,7 +60,7 @@ export class ImpersonationUserSelectService {
             query: `
             (dataSet.impersonators.keyValue:${this._user.user.id}) AND
             (dataSet.is_active.booleanValue:true) AND
-            ((!(_exists_:dataSet.valid_from.timestampValue)) OR (dataSet.valid_from.timestampValue:< ${currentTime.valueOf()})) AND
+            ((!(_exists_:dataSet.valid_from.timestampValue)) OR (dataSet.valid_from.timestampValue:<` + currentTime.valueOf() + `)) AND
             ((!(_exists_:dataSet.valid_to.timestampValue)) OR (dataSet.valid_to.timestampValue:>${currentTime.valueOf()}))
             `
         });
diff --git a/projects/netgrif-components-core/src/lib/side-menu/models/side-menu-size.ts b/projects/netgrif-components-core/src/lib/side-menu/models/side-menu-size.ts
index dcbbe04625..5098229ad2 100644
--- a/projects/netgrif-components-core/src/lib/side-menu/models/side-menu-size.ts
+++ b/projects/netgrif-components-core/src/lib/side-menu/models/side-menu-size.ts
@@ -1,5 +1,6 @@
 export enum SideMenuSize {
     SMALL = 'side-menu-width-small',
     MEDIUM = 'side-menu-width-medium',
-    LARGE = 'side-menu-width-large'
+    LARGE = 'side-menu-width-large',
+    XL = 'side-menu-width-xl',
 }
diff --git a/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate.component.html b/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate.component.html
index e7d1e76c8b..397e251e78 100644
--- a/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate.component.html
+++ b/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate.component.html
@@ -1,4 +1,4 @@
-<mat-toolbar color="primary">{{'search.tooltip.load' | translate}}</mat-toolbar>
+<mat-toolbar color="primary">{{'side-menu.impersonation.title' | translate}}</mat-toolbar>
 <div class="load-filter-container side-menu-root" fxLayout="column" fxLayoutAlign="start stretch">
     <nc-header #header [type]="headerType" [maxHeaderColumns]="3" [responsiveHeaders]="true" [hideEditMode]="true" class="case-header-padding" [ngStyle]="{'width': getWidth()}"></nc-header>
     <nc-case-list [selectedHeaders$]="selectedHeaders$" [showDeleteMenu]="false" [width]="getWidth()"
diff --git a/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate.component.ts b/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate.component.ts
index e14f283362..8885a47a65 100644
--- a/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate.component.ts
+++ b/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate.component.ts
@@ -43,7 +43,11 @@ function localAllowedNetsFactory(factory: AllowedNetsServiceFactory): AllowedNet
             useFactory: localAllowedNetsFactory,
             deps: [AllowedNetsServiceFactory]},
         {   provide: NAE_DEFAULT_HEADERS,
-            useValue: ['meta-title', `${UserImpersonationConstants.IMPERSONATION_CONFIG_NET_IDENTIFIER}-impersonated`]}
+            useValue: [
+                `${UserImpersonationConstants.IMPERSONATION_CONFIG_NET_IDENTIFIER}-${UserImpersonationConstants.IMPERSONATION_CONFIG_FIELD_IMPERSONATED}`,
+                `${UserImpersonationConstants.IMPERSONATION_CONFIG_NET_IDENTIFIER}-${UserImpersonationConstants.IMPERSONATION_CONFIG_FIELD_ROLES}`,
+                `${UserImpersonationConstants.IMPERSONATION_CONFIG_NET_IDENTIFIER}-${UserImpersonationConstants.IMPERSONATION_CONFIG_FIELD_AUTHS}`,
+            ]}
     ]
 })
 export class UserImpersonateComponent extends AbstractUserImpersonateComponent implements AfterViewInit {
diff --git a/projects/netgrif-components/src/lib/side-menu/side-menu-container/side-menu-container.component.scss b/projects/netgrif-components/src/lib/side-menu/side-menu-container/side-menu-container.component.scss
index 949e73dd90..9f17572285 100644
--- a/projects/netgrif-components/src/lib/side-menu/side-menu-container/side-menu-container.component.scss
+++ b/projects/netgrif-components/src/lib/side-menu/side-menu-container/side-menu-container.component.scss
@@ -22,6 +22,10 @@
     width: 496px;
 }
 
+.side-menu-width-xl {
+    width: 600px;
+}
+
 .side-menu-size-mobile {
     width: 246px;
 }

From ce8b0000a930b07ccddd5d69f8d9515632826bf0 Mon Sep 17 00:00:00 2001
From: Bezak <bezak@netgrif.com>
Date: Wed, 21 Sep 2022 13:30:57 +0200
Subject: [PATCH 09/21] [NAE-1678] User impersonation - clean up

---
 .../impersonation-user-list.service.ts         |  6 +-----
 .../impersonation-user-resource.service.ts     |  5 ++++-
 .../abstract-user-impersonate.component.ts     |  6 +++---
 projects/netgrif-components/nae-theme.scss     |  2 ++
 .../admin-impersonate-item.component.html      |  2 +-
 .../admin-impersonate-item.component.spec.ts   |  2 +-
 ...dmin-impersonate-item.component.theme.scss} |  6 +++---
 .../admin-impersonate-list.component.spec.ts   | 12 ++++++------
 .../admin-impersonate.component.spec.ts        | 18 ++++++++++--------
 .../admin-impersonate.component.ts             |  2 +-
 10 files changed, 32 insertions(+), 29 deletions(-)
 rename projects/netgrif-components/src/lib/side-menu/content-components/admin-impersonate/admin-impersonate-list/admin-impersonate-item/theme/{user-assign-item.component.theme.scss => admin-impersonate-item.component.theme.scss} (73%)

diff --git a/projects/netgrif-components-core/src/lib/impersonation/services/impersonation-user-list.service.ts b/projects/netgrif-components-core/src/lib/impersonation/services/impersonation-user-list.service.ts
index 23e674ca9b..8c8cc1fd13 100644
--- a/projects/netgrif-components-core/src/lib/impersonation/services/impersonation-user-list.service.ts
+++ b/projects/netgrif-components-core/src/lib/impersonation/services/impersonation-user-list.service.ts
@@ -1,10 +1,9 @@
-import {UserListItem, UserListService} from '../../user/services/user-list.service';
+import {UserListService} from '../../user/services/user-list.service';
 import {Injectable} from '@angular/core';
 import {SnackBarService} from '../../snack-bar/services/snack-bar.service';
 import {TranslateService} from '@ngx-translate/core';
 import {LoggerService} from '../../logger/services/logger.service';
 import {ImpersonationUserResourceService} from './impersonation-user-resource.service';
-import {Observable} from 'rxjs';
 
 @Injectable()
 export class ImpersonationUserListService extends UserListService {
@@ -16,7 +15,4 @@ export class ImpersonationUserListService extends UserListService {
         super(_resources, _logService, _snackbar, _translate);
     }
 
-    public loadPage(page: number): Observable<{ [k: string]: UserListItem }> {
-        return super.loadPage(page);
-    }
 }
diff --git a/projects/netgrif-components-core/src/lib/impersonation/services/impersonation-user-resource.service.ts b/projects/netgrif-components-core/src/lib/impersonation/services/impersonation-user-resource.service.ts
index 88d6bf191f..60aebbf06b 100644
--- a/projects/netgrif-components-core/src/lib/impersonation/services/impersonation-user-resource.service.ts
+++ b/projects/netgrif-components-core/src/lib/impersonation/services/impersonation-user-resource.service.ts
@@ -13,12 +13,15 @@ import {map} from 'rxjs/operators';
 })
 export class ImpersonationUserResourceService extends UserResourceService {
 
+    protected _IMPERSONATION_SERVER_URL: string;
+
     constructor(protected provider: ResourceProvider, protected _configService: ConfigurationService) {
         super(provider, _configService);
+        this._IMPERSONATION_SERVER_URL = this.getResourceAddress('impersonation');
     }
 
     public search(body: object, params?: Params): Observable<Page<UserResource>> {
-        return this.provider.post$('/impersonate/search', this.SERVER_URL, {query: (body as any).fulltext}, params)
+        return this.provider.post$('/impersonate/search', this._IMPERSONATION_SERVER_URL, {query: (body as any).fulltext}, params)
             .pipe(map((r) => this.getResourcePage<UserResource>(r, 'users')));
     }
 }
diff --git a/projects/netgrif-components-core/src/lib/side-menu/content-components/user-impersonate/abstract-user-impersonate.component.ts b/projects/netgrif-components-core/src/lib/side-menu/content-components/user-impersonate/abstract-user-impersonate.component.ts
index 0a3ab5113a..7ac1b4cfca 100644
--- a/projects/netgrif-components-core/src/lib/side-menu/content-components/user-impersonate/abstract-user-impersonate.component.ts
+++ b/projects/netgrif-components-core/src/lib/side-menu/content-components/user-impersonate/abstract-user-impersonate.component.ts
@@ -1,12 +1,12 @@
 import {SideMenuControl} from '../../models/side-menu-control';
 import {Component, Inject} from '@angular/core';
-import {LoadFilterInjectionData} from '../load-filter/model/load-filter-injection-data';
 import {NAE_SIDE_MENU_CONTROL} from '../../side-menu-injection-token';
 import {LoggerService} from '../../../logger/services/logger.service';
 import {CaseViewService} from '../../../view/case-view/service/case-view-service';
 import {Case} from '../../../resources/interface/case';
 import {AbstractCaseViewComponent} from '../../../view/case-view/abstract-case-view';
 import {UserImpersonateConfigMetadata} from '../../../impersonation/models/user-impersonate-config-metadata';
+import {UserImpersonateInjectionData} from './model/user-impersonate-injection-data';
 
 @Component({
     selector: 'ncc-abstract-user-impersonate',
@@ -14,14 +14,14 @@ import {UserImpersonateConfigMetadata} from '../../../impersonation/models/user-
 })
 export abstract class AbstractUserImpersonateComponent extends AbstractCaseViewComponent {
 
-    protected _injectedData: LoadFilterInjectionData;
+    protected _injectedData: UserImpersonateInjectionData;
 
     protected constructor(@Inject(NAE_SIDE_MENU_CONTROL) protected _sideMenuControl: SideMenuControl,
                           protected _log: LoggerService,
                           caseViewService: CaseViewService) {
         super(caseViewService);
         if (this._sideMenuControl.data) {
-            this._injectedData = this._sideMenuControl.data as LoadFilterInjectionData;
+            this._injectedData = this._sideMenuControl.data as UserImpersonateInjectionData;
         }
     }
 
diff --git a/projects/netgrif-components/nae-theme.scss b/projects/netgrif-components/nae-theme.scss
index 53cd2740a6..32c1728c20 100644
--- a/projects/netgrif-components/nae-theme.scss
+++ b/projects/netgrif-components/nae-theme.scss
@@ -6,6 +6,7 @@
 @import "src/lib/navigation/navigation.theme";
 @import "src/lib/admin/role-assignment/role-assignment.component.theme";
 @import "src/lib/side-menu/content-components/user-assign/user-assign-list/user-assign-item/theme/user-assign-item.component.theme";
+@import "src/lib/side-menu/content-components/admin-impersonate/admin-impersonate-list/admin-impersonate-item/theme/admin-impersonate-item.component.theme";
 @import 'src/lib/view/view.theme';
 @import 'src/lib/tabs/tabs.theme';
 @import "src/lib/search/advanced-search/search-predicate-component/search-predicate.component.theme";
@@ -21,6 +22,7 @@
     @include header-component($app-theme);
     @include roles-assignment-theme($app-theme);
     @include user-assign-item-component-theme($app-theme);
+    @include admin-impersonate-item-component-theme($app-theme);
     @include view-theme($app-theme);
     @include tabs-theme($app-theme);
     @include search-predicate-theme($app-theme);
diff --git a/projects/netgrif-components/src/lib/side-menu/content-components/admin-impersonate/admin-impersonate-list/admin-impersonate-item/admin-impersonate-item.component.html b/projects/netgrif-components/src/lib/side-menu/content-components/admin-impersonate/admin-impersonate-list/admin-impersonate-item/admin-impersonate-item.component.html
index 8da847494d..40274c6bbc 100644
--- a/projects/netgrif-components/src/lib/side-menu/content-components/admin-impersonate/admin-impersonate-list/admin-impersonate-item/admin-impersonate-item.component.html
+++ b/projects/netgrif-components/src/lib/side-menu/content-components/admin-impersonate/admin-impersonate-list/admin-impersonate-item/admin-impersonate-item.component.html
@@ -1,5 +1,5 @@
 <div fxLayout="row" fxLayoutAlign="start center" class="user-item" [ngClass]="{
-            'user-assign-item-selected': (selectedId$ | async) === user.id
+            'admin-impersonate-item-selected': (selectedId$ | async) === user.id
         }">
     <mat-icon class="icon">account_circle</mat-icon>
     <div fxLayout="column">
diff --git a/projects/netgrif-components/src/lib/side-menu/content-components/admin-impersonate/admin-impersonate-list/admin-impersonate-item/admin-impersonate-item.component.spec.ts b/projects/netgrif-components/src/lib/side-menu/content-components/admin-impersonate/admin-impersonate-list/admin-impersonate-item/admin-impersonate-item.component.spec.ts
index 1fa62e957f..8f762bd528 100644
--- a/projects/netgrif-components/src/lib/side-menu/content-components/admin-impersonate/admin-impersonate-list/admin-impersonate-item/admin-impersonate-item.component.spec.ts
+++ b/projects/netgrif-components/src/lib/side-menu/content-components/admin-impersonate/admin-impersonate-list/admin-impersonate-item/admin-impersonate-item.component.spec.ts
@@ -4,7 +4,7 @@ import {Component} from '@angular/core';
 import {MaterialModule, TranslateLibModule, UserValue} from '@netgrif/components-core';
 import {NoopAnimationsModule} from '@angular/platform-browser/animations';
 
-describe('UserAssignItemComponent', () => {
+describe('AdminImpersonateItemComponent', () => {
     let component: AdminImpersonateItemComponent;
     let fixture: ComponentFixture<TestWrapperComponent>;
 
diff --git a/projects/netgrif-components/src/lib/side-menu/content-components/admin-impersonate/admin-impersonate-list/admin-impersonate-item/theme/user-assign-item.component.theme.scss b/projects/netgrif-components/src/lib/side-menu/content-components/admin-impersonate/admin-impersonate-list/admin-impersonate-item/theme/admin-impersonate-item.component.theme.scss
similarity index 73%
rename from projects/netgrif-components/src/lib/side-menu/content-components/admin-impersonate/admin-impersonate-list/admin-impersonate-item/theme/user-assign-item.component.theme.scss
rename to projects/netgrif-components/src/lib/side-menu/content-components/admin-impersonate/admin-impersonate-list/admin-impersonate-item/theme/admin-impersonate-item.component.theme.scss
index 95ab82f00e..bfaac70599 100644
--- a/projects/netgrif-components/src/lib/side-menu/content-components/admin-impersonate/admin-impersonate-list/admin-impersonate-item/theme/user-assign-item.component.theme.scss
+++ b/projects/netgrif-components/src/lib/side-menu/content-components/admin-impersonate/admin-impersonate-list/admin-impersonate-item/theme/admin-impersonate-item.component.theme.scss
@@ -1,14 +1,14 @@
 @use '@angular/material' as mat;
 
-@mixin user-assign-item-component-theme($theme) {
+@mixin admin-impersonate-item-component-theme($theme) {
     $primary: map-get($theme, primary);
 
-    .user-assign-item-selected {
+    .admin-impersonate-item-selected {
         background-color: mat.get-color-from-palette($primary, 300);
         color: mat.get-contrast-color-from-palette($primary, 300) !important;
     }
 
-    .user-assign-item-selected:hover {
+    .admin-impersonate-item-selected:hover {
         background-color: mat.get-color-from-palette($primary, 500) !important;
         color: mat.get-contrast-color-from-palette($primary, 500) !important;
     }
diff --git a/projects/netgrif-components/src/lib/side-menu/content-components/admin-impersonate/admin-impersonate-list/admin-impersonate-list.component.spec.ts b/projects/netgrif-components/src/lib/side-menu/content-components/admin-impersonate/admin-impersonate-list/admin-impersonate-list.component.spec.ts
index 6b8e6bffc8..45151a9c05 100644
--- a/projects/netgrif-components/src/lib/side-menu/content-components/admin-impersonate/admin-impersonate-list/admin-impersonate-list.component.spec.ts
+++ b/projects/netgrif-components/src/lib/side-menu/content-components/admin-impersonate/admin-impersonate-list/admin-impersonate-list.component.spec.ts
@@ -1,4 +1,4 @@
-import {waitForAsync, ComponentFixture, TestBed} from '@angular/core/testing';
+import {ComponentFixture, TestBed, waitForAsync} from '@angular/core/testing';
 import {AdminImpersonateListComponent} from './admin-impersonate-list.component';
 import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
 import {Component, NO_ERRORS_SCHEMA} from '@angular/core';
@@ -7,7 +7,7 @@ import {HttpClientTestingModule} from '@angular/common/http/testing';
 import {BrowserDynamicTestingModule} from '@angular/platform-browser-dynamic/testing';
 import {
     ConfigurationService,
-    ErrorSnackBarComponent,
+    ErrorSnackBarComponent, ImpersonationUserListService,
     MaterialModule,
     TestConfigurationService,
     TranslateLibModule,
@@ -15,9 +15,9 @@ import {
     UserListService,
     UserValue
 } from '@netgrif/components-core';
-import {UserImpersonateItemComponent} from './user-impersonate-item/user-impersonate-item.component';
+import {AdminImpersonateItemComponent} from './admin-impersonate-item/admin-impersonate-item.component';
 
-describe('UserImpersonateListComponent', () => {
+describe('AdminImpersonateListComponent', () => {
     let component: AdminImpersonateListComponent;
     let fixture: ComponentFixture<TestWrapperComponent>;
 
@@ -30,12 +30,12 @@ describe('UserImpersonateListComponent', () => {
                 TranslateLibModule
             ],
             providers: [
-                UserListService,
+                {provide: UserListService, useClass: ImpersonationUserListService},
                 {provide: ConfigurationService, useClass: TestConfigurationService}
             ],
             declarations: [
                 AdminImpersonateListComponent,
-                UserImpersonateItemComponent,
+                AdminImpersonateItemComponent,
                 ErrorSnackBarComponent,
                 TestWrapperComponent
             ],
diff --git a/projects/netgrif-components/src/lib/side-menu/content-components/admin-impersonate/admin-impersonate.component.spec.ts b/projects/netgrif-components/src/lib/side-menu/content-components/admin-impersonate/admin-impersonate.component.spec.ts
index 0a4a776a75..4dbe01d49f 100644
--- a/projects/netgrif-components/src/lib/side-menu/content-components/admin-impersonate/admin-impersonate.component.spec.ts
+++ b/projects/netgrif-components/src/lib/side-menu/content-components/admin-impersonate/admin-impersonate.component.spec.ts
@@ -1,6 +1,6 @@
-import {waitForAsync, ComponentFixture, TestBed} from '@angular/core/testing';
+import {ComponentFixture, TestBed, waitForAsync} from '@angular/core/testing';
 import {
-    ConfigurationService,
+    ConfigurationService, ImpersonationUserListService,
     MaterialModule,
     NAE_SIDE_MENU_CONTROL,
     SideMenuControl,
@@ -13,10 +13,12 @@ import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
 import {HttpClientTestingModule} from '@angular/common/http/testing';
 import {Observable} from 'rxjs';
 import {AdminImpersonateComponent} from './admin-impersonate.component';
-import {UserImpersonateListComponent} from './user-impersonate-list/user-impersonate-list.component';
-import {UserImpersonateItemComponent} from './user-impersonate-list/user-impersonate-item/user-impersonate-item.component';
+import {AdminImpersonateListComponent} from './admin-impersonate-list/admin-impersonate-list.component';
+import {
+    AdminImpersonateItemComponent
+} from './admin-impersonate-list/admin-impersonate-item/admin-impersonate-item.component';
 
-describe('UserImpersonateComponent', () => {
+describe('AdminImpersonateComponent', () => {
     let component: AdminImpersonateComponent;
     let fixture: ComponentFixture<AdminImpersonateComponent>;
 
@@ -30,7 +32,7 @@ describe('UserImpersonateComponent', () => {
                 SnackBarModule
             ],
             providers: [
-                UserListService,
+                {provide: UserListService, useClass: ImpersonationUserListService},
                 {
                     provide: NAE_SIDE_MENU_CONTROL, useValue: new SideMenuControl(() => {
                     }, new Observable<boolean>(), null)
@@ -39,8 +41,8 @@ describe('UserImpersonateComponent', () => {
             ],
             declarations: [
                 AdminImpersonateComponent,
-                UserImpersonateListComponent,
-                UserImpersonateItemComponent
+                AdminImpersonateListComponent,
+                AdminImpersonateItemComponent
             ]
         }).compileComponents();
     }));
diff --git a/projects/netgrif-components/src/lib/side-menu/content-components/admin-impersonate/admin-impersonate.component.ts b/projects/netgrif-components/src/lib/side-menu/content-components/admin-impersonate/admin-impersonate.component.ts
index 32ec8220da..ae4fcb8869 100644
--- a/projects/netgrif-components/src/lib/side-menu/content-components/admin-impersonate/admin-impersonate.component.ts
+++ b/projects/netgrif-components/src/lib/side-menu/content-components/admin-impersonate/admin-impersonate.component.ts
@@ -4,7 +4,7 @@ import {AbstractUserAssignComponent, NAE_SIDE_MENU_CONTROL, SideMenuControl, Use
 /**
  * Is the main - parent component of the entire user assignment in the side menu.
  *
- * Holds logic link of the [UserAssignListComponent]{@link UserAssignListComponent}
+ * Holds logic link of the [AdminImpersonateListComponent]{@link AdminImpersonateListComponent}
  * along with searching, selecting, and then assigning to the user field.
  */
 @Component({

From 38d6fdff29df35f1e4b4bbd91b886a2bbcba4ce1 Mon Sep 17 00:00:00 2001
From: Bezak <bezak@netgrif.com>
Date: Wed, 21 Sep 2022 14:16:19 +0200
Subject: [PATCH 10/21] [NAE-1678] User impersonation - fix test

---
 .../src/lib/task/services/cancel-task.service.spec.ts    | 9 +++------
 1 file changed, 3 insertions(+), 6 deletions(-)

diff --git a/projects/netgrif-components-core/src/lib/task/services/cancel-task.service.spec.ts b/projects/netgrif-components-core/src/lib/task/services/cancel-task.service.spec.ts
index 66fca26b51..f400c6b646 100644
--- a/projects/netgrif-components-core/src/lib/task/services/cancel-task.service.spec.ts
+++ b/projects/netgrif-components-core/src/lib/task/services/cancel-task.service.spec.ts
@@ -33,6 +33,8 @@ import {TaskEventOutcome} from '../../event/model/event-outcomes/task-outcomes/t
 import {createMockCase} from '../../utility/tests/utility/create-mock-case';
 import {createMockNet} from '../../utility/tests/utility/create-mock-net';
 import {ChangedFieldsService} from '../../changed-fields/services/changed-fields.service';
+import {User} from '../../user/models/user';
+import {ProcessRole} from '../../resources/interface/process-role';
 
 describe('CancelTaskService', () => {
     let service: CancelTaskService;
@@ -249,12 +251,7 @@ class TestTaskResourceService {
 
 class TestUserService {
     public get user() {
-        return {
-            email: 'mail',
-            roles: [{
-                stringId: 'role'
-            }]
-        };
+        return new User('id', 'mail', '', '', [], [{stringId: 'role'} as ProcessRole]);
     }
 
     public hasRoleById(): boolean {

From 7c8c326552f6474ecaccc99b81c6779aa44ff83a Mon Sep 17 00:00:00 2001
From: Bezak <bezak@netgrif.com>
Date: Wed, 21 Sep 2022 14:28:10 +0200
Subject: [PATCH 11/21] [NAE-1678] User impersonation - fix for lint

---
 .../doc/impersonation-demo/impersonation-demo.component.ts   | 5 +----
 .../impersonate-quick-panel.component.ts                     | 5 +----
 2 files changed, 2 insertions(+), 8 deletions(-)

diff --git a/projects/nae-example-app/src/app/doc/impersonation-demo/impersonation-demo.component.ts b/projects/nae-example-app/src/app/doc/impersonation-demo/impersonation-demo.component.ts
index fcd16a0f43..fcc030fd67 100644
--- a/projects/nae-example-app/src/app/doc/impersonation-demo/impersonation-demo.component.ts
+++ b/projects/nae-example-app/src/app/doc/impersonation-demo/impersonation-demo.component.ts
@@ -6,7 +6,7 @@ import {ImpersonationService, ImpersonationUserSelectService} from 'netgrif-comp
     templateUrl: './impersonation-demo.component.html',
     styleUrls: ['./impersonation-demo.component.scss']
 })
-export class ImpersonationDemoComponent implements OnInit {
+export class ImpersonationDemoComponent {
 
     constructor(
         private _impersonationSelect: ImpersonationUserSelectService,
@@ -17,9 +17,6 @@ export class ImpersonationDemoComponent implements OnInit {
         });
     }
 
-    ngOnInit(): void {
-    }
-
     public impersonate(): void {
         this._impersonationSelect.selectImpersonate();
     }
diff --git a/projects/netgrif-components/src/lib/navigation/quick-panel/components/impersonate-quick-panel/impersonate-quick-panel.component.ts b/projects/netgrif-components/src/lib/navigation/quick-panel/components/impersonate-quick-panel/impersonate-quick-panel.component.ts
index f9a8ab41b0..136123029c 100644
--- a/projects/netgrif-components/src/lib/navigation/quick-panel/components/impersonate-quick-panel/impersonate-quick-panel.component.ts
+++ b/projects/netgrif-components/src/lib/navigation/quick-panel/components/impersonate-quick-panel/impersonate-quick-panel.component.ts
@@ -6,7 +6,7 @@ import {ImpersonationService, ImpersonationUserSelectService, UserService} from
     templateUrl: './impersonate-quick-panel.component.html',
     styleUrls: ['./impersonate-quick-panel.component.scss']
 })
-export class ImpersonateQuickPanelComponent implements OnInit {
+export class ImpersonateQuickPanelComponent {
 
     constructor(
         private impersonateUserSelect: ImpersonationUserSelectService,
@@ -14,9 +14,6 @@ export class ImpersonateQuickPanelComponent implements OnInit {
         private user: UserService,
     ) {}
 
-    ngOnInit(): void {
-    }
-
     public impersonate(): void {
         this.impersonateUserSelect.selectImpersonate();
     }

From f229a5fcca8f82b6841eee9512f84fcabca41327 Mon Sep 17 00:00:00 2001
From: Bezak <bezak@netgrif.com>
Date: Wed, 21 Sep 2022 15:32:48 +0200
Subject: [PATCH 12/21] [NAE-1678] User impersonation - fix test

---
 .../impersonate-quick-panel.component.spec.ts | 64 ++++++++++----
 .../user-impersonate.component.spec.ts        | 85 +++++++++++++------
 2 files changed, 106 insertions(+), 43 deletions(-)

diff --git a/projects/netgrif-components/src/lib/navigation/quick-panel/components/impersonate-quick-panel/impersonate-quick-panel.component.spec.ts b/projects/netgrif-components/src/lib/navigation/quick-panel/components/impersonate-quick-panel/impersonate-quick-panel.component.spec.ts
index 8b9ea30998..80b9aad0ea 100644
--- a/projects/netgrif-components/src/lib/navigation/quick-panel/components/impersonate-quick-panel/impersonate-quick-panel.component.spec.ts
+++ b/projects/netgrif-components/src/lib/navigation/quick-panel/components/impersonate-quick-panel/impersonate-quick-panel.component.spec.ts
@@ -1,25 +1,53 @@
-import { ComponentFixture, TestBed } from '@angular/core/testing';
+import {ComponentFixture, TestBed} from '@angular/core/testing';
 
-import { ImpersonateQuickPanelComponent } from './impersonate-quick-panel.component';
+import {ImpersonateQuickPanelComponent} from './impersonate-quick-panel.component';
+import {
+    AuthenticationMethodService,
+    ConfigurationService,
+    MaterialModule,
+    MockAuthenticationMethodService,
+    SnackBarService,
+    TranslateLibModule
+} from 'netgrif-components-core';
+import {
+    NaeExampleAppConfigurationService
+} from '../../../../../../../nae-example-app/src/app/nae-example-app-configuration.service';
+import {CommonModule} from '@angular/common';
+import {RouterTestingModule} from '@angular/router/testing';
+import {HttpClientTestingModule} from '@angular/common/http/testing';
+import {NoopAnimationsModule} from '@angular/platform-browser/animations';
 
 describe('ImpersonateQuickPanelComponent', () => {
-  let component: ImpersonateQuickPanelComponent;
-  let fixture: ComponentFixture<ImpersonateQuickPanelComponent>;
+    let component: ImpersonateQuickPanelComponent;
+    let fixture: ComponentFixture<ImpersonateQuickPanelComponent>;
 
-  beforeEach(async () => {
-    await TestBed.configureTestingModule({
-      declarations: [ ImpersonateQuickPanelComponent ]
-    })
-    .compileComponents();
-  });
+    beforeEach(async () => {
+        await TestBed.configureTestingModule({
+            imports: [
+                CommonModule,
+                RouterTestingModule.withRoutes([]),
+                MaterialModule,
+                TranslateLibModule,
+                HttpClientTestingModule,
+                NoopAnimationsModule
+            ],
+            declarations: [ImpersonateQuickPanelComponent],
+            providers: [
+                SnackBarService,
+                {provide: AuthenticationMethodService, useClass: MockAuthenticationMethodService},
+                {provide: ConfigurationService, useClass: NaeExampleAppConfigurationService},
+            ]
+        })
+            .compileComponents();
+    });
 
-  beforeEach(() => {
-    fixture = TestBed.createComponent(ImpersonateQuickPanelComponent);
-    component = fixture.componentInstance;
-    fixture.detectChanges();
-  });
+    beforeEach(() => {
+        fixture = TestBed.createComponent(ImpersonateQuickPanelComponent);
+        component = fixture.componentInstance;
+        fixture.detectChanges();
+    });
 
-  it('should create', () => {
-    expect(component).toBeTruthy();
-  });
+    it('should create', () => {
+        expect(component).toBeTruthy();
+    });
 });
diff --git a/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate.component.spec.ts b/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate.component.spec.ts
index 603b331f25..30c4da292c 100644
--- a/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate.component.spec.ts
+++ b/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate.component.spec.ts
@@ -1,25 +1,60 @@
-import { ComponentFixture, TestBed } from '@angular/core/testing';
-
-import { UserImpersonateComponent } from './user-impersonate.component';
-
-describe('UserImpersonateComponent', () => {
-  let component: UserImpersonateComponent;
-  let fixture: ComponentFixture<UserImpersonateComponent>;
-
-  beforeEach(async () => {
-    await TestBed.configureTestingModule({
-      declarations: [ UserImpersonateComponent ]
-    })
-    .compileComponents();
-  });
-
-  beforeEach(() => {
-    fixture = TestBed.createComponent(UserImpersonateComponent);
-    component = fixture.componentInstance;
-    fixture.detectChanges();
-  });
-
-  it('should create', () => {
-    expect(component).toBeTruthy();
-  });
-});
+// import {ComponentFixture, TestBed} from '@angular/core/testing';
+//
+// import {UserImpersonateComponent} from './user-impersonate.component';
+// import {Observable} from 'rxjs';
+// import {
+//     ConfigurationService,
+//     FilterType,
+//     MaterialModule,
+//     NAE_SIDE_MENU_CONTROL,
+//     SideMenuControl,
+//     SimpleFilter,
+//     SnackBarService,
+//     TranslateLibModule
+// } from 'netgrif-components-core';
+// import {
+//     NaeExampleAppConfigurationService
+// } from '../../../../../../nae-example-app/src/app/nae-example-app-configuration.service';
+// import {CommonModule} from '@angular/common';
+// import {RouterTestingModule} from '@angular/router/testing';
+// import {HttpClientTestingModule} from '@angular/common/http/testing';
+// import {NoopAnimationsModule} from '@angular/platform-browser/animations';
+//
+// describe('UserImpersonateComponent', () => {
+//     let component: UserImpersonateComponent;
+//     let fixture: ComponentFixture<UserImpersonateComponent>;
+//
+//     beforeEach(async () => {
+//         await TestBed.configureTestingModule({
+//             imports: [
+//                 CommonModule,
+//                 RouterTestingModule.withRoutes([]),
+//                 MaterialModule,
+//                 TranslateLibModule,
+//                 HttpClientTestingModule,
+//                 NoopAnimationsModule
+//             ],
+//             declarations: [UserImpersonateComponent],
+//             providers: [
+//                 SnackBarService,
+//                 {provide: ConfigurationService, useClass: NaeExampleAppConfigurationService},
+//                 {
+//                     provide: NAE_SIDE_MENU_CONTROL,
+//                     useValue: new SideMenuControl(() => {
+//                     }, new Observable<boolean>(), null, {filter: new SimpleFilter('', FilterType.CASE, {process: {identifier: '__EMPTY__'}})})
+//                 }
+//             ]
+//         })
+//             .compileComponents();
+//     });
+//
+//     beforeEach(() => {
+//         fixture = TestBed.createComponent(UserImpersonateComponent);
+//         component = fixture.componentInstance;
+//         fixture.detectChanges();
+//     });
+//
+//     it('should create', () => {
+//         expect(component).toBeTruthy();
+//     });
+// });

From 2f140adc011d00d405b96dab69b4e2a9f9b022d8 Mon Sep 17 00:00:00 2001
From: Bezak <bezak@netgrif.com>
Date: Fri, 23 Sep 2022 15:48:32 +0200
Subject: [PATCH 13/21] [NAE-1678] User impersonation - code smell - add tests
 for impersonation.service

---
 .../services/impersonation.service.spec.ts    | 151 ++++++++++++++++++
 .../services/impersonation.service.ts         |  30 ++--
 .../src/lib/utility/tests/test-config.ts      |   5 +
 .../impersonate-quick-panel.component.scss    |   0
 .../impersonate-quick-panel.component.ts      |   4 +-
 5 files changed, 173 insertions(+), 17 deletions(-)
 create mode 100644 projects/netgrif-components-core/src/lib/impersonation/services/impersonation.service.spec.ts
 delete mode 100644 projects/netgrif-components/src/lib/navigation/quick-panel/components/impersonate-quick-panel/impersonate-quick-panel.component.scss

diff --git a/projects/netgrif-components-core/src/lib/impersonation/services/impersonation.service.spec.ts b/projects/netgrif-components-core/src/lib/impersonation/services/impersonation.service.spec.ts
new file mode 100644
index 0000000000..ef4ebbfff0
--- /dev/null
+++ b/projects/netgrif-components-core/src/lib/impersonation/services/impersonation.service.spec.ts
@@ -0,0 +1,151 @@
+import {inject, TestBed} from '@angular/core/testing';
+import {HttpClientTestingModule, HttpTestingController} from '@angular/common/http/testing';
+import {ConfigurationService} from '../../configuration/configuration.service';
+import {TestConfigurationService} from '../../utility/tests/test-config';
+import {NoopAnimationsModule} from '@angular/platform-browser/animations';
+import {ImpersonationService} from './impersonation.service';
+import {UserService} from '../../user/services/user.service';
+import {SnackBarService} from '../../snack-bar/services/snack-bar.service';
+import {FilterRepository} from '../../filter/filter.repository';
+import {LoggerService} from '../../logger/services/logger.service';
+import {TranslateService} from '@ngx-translate/core';
+import {MaterialModule} from '../../material/material.module';
+import {TranslateLibModule} from '../../translate/translate-lib.module';
+import {SnackBarModule} from '../../snack-bar/snack-bar.module';
+import {RouterTestingModule} from '@angular/router/testing';
+import {MockAuthenticationService} from '../../utility/tests/mocks/mock-authentication.service';
+import {MockAuthenticationMethodService} from '../../utility/tests/mocks/mock-authentication-method-service';
+import {AuthenticationService} from '../../authentication/services/authentication/authentication.service';
+import {AuthenticationMethodService} from '../../authentication/services/authentication-method.service';
+import {User} from '../../user/models/user';
+import {ProcessRole} from '../../resources/interface/process-role';
+import {Observable, ReplaySubject} from 'rxjs';
+import {UserPreferenceService} from '../../user/services/user-preference.service';
+import {MockUserPreferenceService} from '../../utility/tests/mocks/mock-user-preference.service';
+
+describe('ImpersonationService', () => {
+    let service: ImpersonationService;
+    let userService: TestUserService;
+
+    beforeEach(() => {
+        TestBed.configureTestingModule({
+            imports: [HttpClientTestingModule, MaterialModule, TranslateLibModule, NoopAnimationsModule, SnackBarModule, RouterTestingModule],
+            providers: [
+                SnackBarService,
+                FilterRepository,
+                LoggerService,
+                TranslateService,
+                ImpersonationService,
+                {provide: UserPreferenceService, useClass: MockUserPreferenceService},
+                {provide: UserService, useClass: TestUserService},
+                {provide: AuthenticationMethodService, useClass: MockAuthenticationMethodService},
+                {provide: AuthenticationService, useClass: MockAuthenticationService},
+                {provide: ConfigurationService, useClass: TestConfigurationService}]
+        });
+        service = TestBed.inject(ImpersonationService);
+        userService = (TestBed.inject(UserService) as any) as TestUserService;
+    });
+
+    it('should be created', () => {
+        expect(service).toBeTruthy();
+    });
+
+    it('should impersonate user', (done) => {
+            inject([HttpTestingController],
+                (httpMock: HttpTestingController) => {
+                    userService.mimicUserLoaded();
+                    service.impersonating$.subscribe(bool => {
+                        expect(bool).toBeTrue();
+                        done();
+                    })
+                    service.impersonateUser('testId');
+
+                    const reqLog = httpMock.expectOne('http://localhost:8080/api/impersonate/user/testId');
+                    expect(reqLog.request.method).toEqual('POST');
+
+                    reqLog.flush({});
+                })();
+        }
+    );
+
+    it('should impersonate config', (done) => {
+            inject([HttpTestingController],
+                (httpMock: HttpTestingController) => {
+                    userService.mimicUserLoaded();
+                    service.impersonating$.subscribe(bool => {
+                        expect(bool).toBeTrue();
+                        done();
+                    })
+                    service.impersonateByConfig('configId');
+
+                    const reqLog = httpMock.expectOne('http://localhost:8080/api/impersonate/config/configId');
+                    expect(reqLog.request.method).toEqual('POST');
+
+                    reqLog.flush({});
+                })();
+        }
+    );
+
+    it('should stop impersonating', (done) => {
+            inject([HttpTestingController],
+                (httpMock: HttpTestingController) => {
+                    userService.reverse();
+                    userService.mimicUserLoaded();
+
+                    service.impersonating$.subscribe(bool => {
+                        expect(bool).toBeFalse();
+                        done();
+                    })
+                    service.cease();
+
+                    const reqLog = httpMock.expectOne('http://localhost:8080/api/impersonate/clear');
+                    expect(reqLog.request.method).toEqual('POST');
+
+                    reqLog.flush({});
+                })();
+        }
+    );
+
+    afterEach(inject([HttpTestingController], (mock: HttpTestingController) => {
+        mock.verify();
+        TestBed.resetTestingModule();
+    }));
+});
+
+
+class TestUserService {
+
+    protected mockUser$ = new ReplaySubject<User>();
+
+    public userObj = new User('id', 'mail', '', '', [], [{stringId: 'role'} as ProcessRole], [], []);
+    public userObjAfter = new User(
+        this.userObj.id, this.userObj.email, this.userObj.firstName, this.userObj.lastName, this.userObj.authorities, this.userObj.roles, this.userObj.groups, this.userObj.nextGroups,
+        new User('impId', 'mail', '', '', [], [{stringId: 'role'} as ProcessRole], [], [])
+    );
+
+    public get user(): User {
+        return this.userObj;
+    }
+
+    public get user$(): Observable<User> {
+        return this.mockUser$.asObservable();
+    }
+
+    public get anonymousUser$(): Observable<User> {
+        return this.mockUser$.asObservable();
+    }
+
+    public reload(): void {
+        this.mockUser$.next( this.userObjAfter);
+    }
+
+    public mimicUserLoaded(): void {
+        this.mockUser$.next(this.user);
+    }
+
+    public reverse(): void {
+        const temp = this.userObjAfter;
+        this.userObjAfter = this.userObj;
+        this.userObj = temp;
+    }
+}
diff --git a/projects/netgrif-components-core/src/lib/impersonation/services/impersonation.service.ts b/projects/netgrif-components-core/src/lib/impersonation/services/impersonation.service.ts
index 1fdcfdaa2d..0521090ad0 100644
--- a/projects/netgrif-components-core/src/lib/impersonation/services/impersonation.service.ts
+++ b/projects/netgrif-components-core/src/lib/impersonation/services/impersonation.service.ts
@@ -1,6 +1,5 @@
 import {Injectable, OnDestroy} from '@angular/core';
 import {Router} from '@angular/router';
-import {take} from 'rxjs/operators';
 import {TranslateService} from '@ngx-translate/core';
 import {AbstractResourceService, ResourceProvider, UserResource} from '../../resources/public-api';
 import {ConfigurationService} from '../../configuration/configuration.service';
@@ -30,13 +29,7 @@ export class ImpersonationService extends AbstractResourceService implements OnD
                        protected _log: LoggerService,
                        private _translate: TranslateService) {
         super('impersonation', provider, _configService);
-        this._sub = this._userService.user$.subscribe(user => {
-            if (this._lastUser && this._lastUser.isImpersonating() != user.isImpersonating()) {
-                this._filter.removeAllFilters();
-                this._impersonating$.next(user.isImpersonating());
-            }
-            this._lastUser = user;
-        });
+        this._sub = this._userService.user$.subscribe(user => this._resolveUserChange(user));
     }
 
     public get impersonating$(): Observable<boolean> {
@@ -45,17 +38,17 @@ export class ImpersonationService extends AbstractResourceService implements OnD
 
     public impersonateUser(userId: string): void {
         this.provider.post$('impersonate/user/' + userId, this.SERVER_URL, {}).subscribe((user: UserResource) => {
-            this.resolveSuccess(user);
+            this._resolveSuccess(user);
         }, (response => {
-            this.resolveError(response);
+            this._resolveError(response);
         }));
     }
 
     public impersonateByConfig(configId: string): void {
         this.provider.post$('impersonate/config/' + configId, this.SERVER_URL, {}).subscribe((user: UserResource) => {
-            this.resolveSuccess(user);
+            this._resolveSuccess(user);
         }, (response => {
-            this.resolveError(response);
+            this._resolveError(response);
         }));
     }
 
@@ -68,12 +61,12 @@ export class ImpersonationService extends AbstractResourceService implements OnD
         }));
     }
 
-    protected resolveSuccess(user: UserResource) {
+    protected _resolveSuccess(user: UserResource) {
         this._snackbar.openSuccessSnackBar(this._translate.instant('impersonation.user.successfullyRepresented'));
         this._triggerReload();
     }
 
-    protected resolveError(response: any) {
+    protected _resolveError(response: any) {
         if (response.status === 400) {
             response.error.alreadyImpersonated ?
                 this._snackbar.openErrorSnackBar(this._translate.instant('impersonation.user.currentlyAlreadyRepresented')) :
@@ -87,10 +80,17 @@ export class ImpersonationService extends AbstractResourceService implements OnD
         this._userService.reload();
     }
 
+    protected _resolveUserChange(user: User) {
+        if (this._lastUser && this._lastUser.isImpersonating() != user.isImpersonating()) {
+            this._filter.removeAllFilters();
+            this._impersonating$.next(user.isImpersonating());
+        }
+        this._lastUser = user;
+    }
+
     ngOnDestroy(): void {
         if (this._sub) {
             this._sub.unsubscribe();
         }
     }
-
 }
diff --git a/projects/netgrif-components-core/src/lib/utility/tests/test-config.ts b/projects/netgrif-components-core/src/lib/utility/tests/test-config.ts
index b4036aa1cc..e002026dd2 100644
--- a/projects/netgrif-components-core/src/lib/utility/tests/test-config.ts
+++ b/projects/netgrif-components-core/src/lib/utility/tests/test-config.ts
@@ -46,6 +46,11 @@ export class TestConfigurationService extends ConfigurationService {
                         name: 'dashboard',
                         address: 'http://localhost:8080/api/',
                         format: 'json'
+                    },
+                    {
+                        name: 'impersonation',
+                        address: 'http://localhost:8080/api/',
+                        format: 'json'
                     }
                 ]
             },
diff --git a/projects/netgrif-components/src/lib/navigation/quick-panel/components/impersonate-quick-panel/impersonate-quick-panel.component.scss b/projects/netgrif-components/src/lib/navigation/quick-panel/components/impersonate-quick-panel/impersonate-quick-panel.component.scss
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/projects/netgrif-components/src/lib/navigation/quick-panel/components/impersonate-quick-panel/impersonate-quick-panel.component.ts b/projects/netgrif-components/src/lib/navigation/quick-panel/components/impersonate-quick-panel/impersonate-quick-panel.component.ts
index 136123029c..1209b904b7 100644
--- a/projects/netgrif-components/src/lib/navigation/quick-panel/components/impersonate-quick-panel/impersonate-quick-panel.component.ts
+++ b/projects/netgrif-components/src/lib/navigation/quick-panel/components/impersonate-quick-panel/impersonate-quick-panel.component.ts
@@ -1,10 +1,10 @@
-import {Component, OnInit} from '@angular/core';
+import {Component} from '@angular/core';
 import {ImpersonationService, ImpersonationUserSelectService, UserService} from 'netgrif-components-core';
 
 @Component({
     selector: 'nc-impersonate-quick-panel',
     templateUrl: './impersonate-quick-panel.component.html',
-    styleUrls: ['./impersonate-quick-panel.component.scss']
+    styleUrls: []
 })
 export class ImpersonateQuickPanelComponent {
 

From d95de901b256ec146a22c1abe1b2b9caa321dda9 Mon Sep 17 00:00:00 2001
From: Bezak <bezak@netgrif.com>
Date: Fri, 23 Sep 2022 15:55:22 +0200
Subject: [PATCH 14/21] [NAE-1678] User impersonation - fix test

---
 .../src/lib/configuration/configuration.service.spec.ts      | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/projects/netgrif-components-core/src/lib/configuration/configuration.service.spec.ts b/projects/netgrif-components-core/src/lib/configuration/configuration.service.spec.ts
index c97b762f00..944c5754db 100644
--- a/projects/netgrif-components-core/src/lib/configuration/configuration.service.spec.ts
+++ b/projects/netgrif-components-core/src/lib/configuration/configuration.service.spec.ts
@@ -72,6 +72,11 @@ describe('ConfigurationService', () => {
                         name: 'dashboard',
                         address: 'http://localhost:8080/api/',
                         format: 'json'
+                    },
+                    {
+                        name: 'impersonation',
+                        address: 'http://localhost:8080/api/',
+                        format: 'json'
                     }
                 ]
             });

From b83f72e88c41f13591a62dbcde831c3cbfac319f Mon Sep 17 00:00:00 2001
From: Bezak <bezak@netgrif.com>
Date: Mon, 26 Sep 2022 10:47:53 +0200
Subject: [PATCH 15/21] [NAE-1678] User impersonation - add de locale for
 impersonation

---
 .../netgrif-components-core/src/assets/i18n/de.json    | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/projects/netgrif-components-core/src/assets/i18n/de.json b/projects/netgrif-components-core/src/assets/i18n/de.json
index 8ce110e46c..82d721d409 100644
--- a/projects/netgrif-components-core/src/assets/i18n/de.json
+++ b/projects/netgrif-components-core/src/assets/i18n/de.json
@@ -465,13 +465,13 @@
     },
     "impersonation": {
         "user": {
-            "successfullyRepresented": "User successfully represented",
-            "currentlyAlreadyRepresented": "User is already currently represented",
-            "currentlyLogged": "User is currently logged in"
+            "successfullyRepresented": "Benutzer erfolgreich vertreten",
+            "currentlyAlreadyRepresented": "Benutzer ist bereits aktuell vertreten",
+            "currentlyLogged": "Benutzer ist derzeit angemeldet"
         },
         "action": {
-            "failed": "Action failed",
-            "deactivated": "Representation was successfully deactivated"
+            "failed": "Aktion ist fehlgeschlagen",
+            "deactivated": "Vertretung wurde erfolgreich deaktiviert"
         }
     }
 }

From 537f78fcd6c3ba31b484b1d8e328ff1b31839806 Mon Sep 17 00:00:00 2001
From: Bezak <bezak@netgrif.com>
Date: Mon, 26 Sep 2022 12:37:12 +0200
Subject: [PATCH 16/21] [NAE-1678] User impersonation - add de locale for
 impersonation

---
 projects/netgrif-components-core/src/assets/i18n/de.json | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/projects/netgrif-components-core/src/assets/i18n/de.json b/projects/netgrif-components-core/src/assets/i18n/de.json
index 82d721d409..7014f86272 100644
--- a/projects/netgrif-components-core/src/assets/i18n/de.json
+++ b/projects/netgrif-components-core/src/assets/i18n/de.json
@@ -110,10 +110,10 @@
             "choose-one-option": "Wählen Sie eine Option aus"
         },
         "impersonation": {
-            "title": "Impersonate user",
-            "submit": "Impersonate",
-            "cease": "Cancel impersonation",
-            "impersonating": "impersonating"
+            "title": "Benutzer vertreten",
+            "submit": "Vertreten",
+            "cease": "Vertretung abbrechen",
+            "impersonating": "in Vertretung als"
         }
     },
     "search": {

From 4d7e7bde98464c861726042ffd57885bae31b30e Mon Sep 17 00:00:00 2001
From: Bezak <bezak@netgrif.com>
Date: Tue, 27 Sep 2022 15:31:12 +0200
Subject: [PATCH 17/21] [NAE-1678] User impersonation - update according to PR
 comments

---
 .../impersonation-demo/impersonation-demo.component.ts   | 5 +++--
 .../lib/impersonation/services/impersonation.service.ts  | 2 +-
 .../impersonate-quick-panel.component.spec.ts            | 9 +++------
 .../impersonate-quick-panel.component.ts                 | 2 +-
 .../user-impersonate/user-impersonate.component.spec.ts  | 2 +-
 5 files changed, 9 insertions(+), 11 deletions(-)

diff --git a/projects/nae-example-app/src/app/doc/impersonation-demo/impersonation-demo.component.ts b/projects/nae-example-app/src/app/doc/impersonation-demo/impersonation-demo.component.ts
index fcc030fd67..fc77cd5b0a 100644
--- a/projects/nae-example-app/src/app/doc/impersonation-demo/impersonation-demo.component.ts
+++ b/projects/nae-example-app/src/app/doc/impersonation-demo/impersonation-demo.component.ts
@@ -1,5 +1,5 @@
 import {Component, OnInit} from '@angular/core';
-import {ImpersonationService, ImpersonationUserSelectService} from 'netgrif-components-core';
+import {ImpersonationService, ImpersonationUserSelectService, LoggerService} from '@netgrif/components-core';
 
 @Component({
     selector: 'nae-app-impersonation-demo',
@@ -11,9 +11,10 @@ export class ImpersonationDemoComponent {
     constructor(
         private _impersonationSelect: ImpersonationUserSelectService,
         private _impersonation: ImpersonationService,
+        private _log: LoggerService,
     ) {
         this._impersonation.impersonating$.subscribe((isImpersonating: boolean) => {
-            console.log("Is impersonating " + isImpersonating);
+            this._log.debug("Is impersonating " + isImpersonating);
         });
     }
 
diff --git a/projects/netgrif-components-core/src/lib/impersonation/services/impersonation.service.ts b/projects/netgrif-components-core/src/lib/impersonation/services/impersonation.service.ts
index 0521090ad0..f585e528d7 100644
--- a/projects/netgrif-components-core/src/lib/impersonation/services/impersonation.service.ts
+++ b/projects/netgrif-components-core/src/lib/impersonation/services/impersonation.service.ts
@@ -27,7 +27,7 @@ export class ImpersonationService extends AbstractResourceService implements OnD
                        protected _snackbar: SnackBarService,
                        protected _filter: FilterRepository,
                        protected _log: LoggerService,
-                       private _translate: TranslateService) {
+                       protected _translate: TranslateService) {
         super('impersonation', provider, _configService);
         this._sub = this._userService.user$.subscribe(user => this._resolveUserChange(user));
     }
diff --git a/projects/netgrif-components/src/lib/navigation/quick-panel/components/impersonate-quick-panel/impersonate-quick-panel.component.spec.ts b/projects/netgrif-components/src/lib/navigation/quick-panel/components/impersonate-quick-panel/impersonate-quick-panel.component.spec.ts
index 80b9aad0ea..8428295c61 100644
--- a/projects/netgrif-components/src/lib/navigation/quick-panel/components/impersonate-quick-panel/impersonate-quick-panel.component.spec.ts
+++ b/projects/netgrif-components/src/lib/navigation/quick-panel/components/impersonate-quick-panel/impersonate-quick-panel.component.spec.ts
@@ -6,12 +6,9 @@ import {
     ConfigurationService,
     MaterialModule,
     MockAuthenticationMethodService,
-    SnackBarService,
+    SnackBarService, TestConfigurationService,
     TranslateLibModule
-} from 'netgrif-components-core';
-import {
-    NaeExampleAppConfigurationService
-} from '../../../../../../../nae-example-app/src/app/nae-example-app-configuration.service';
+} from '@netgrif/components-core';
 import {CommonModule} from '@angular/common';
 import {RouterTestingModule} from '@angular/router/testing';
 import {HttpClientTestingModule} from '@angular/common/http/testing';
@@ -35,7 +32,7 @@ describe('ImpersonateQuickPanelComponent', () => {
             providers: [
                 SnackBarService,
                 {provide: AuthenticationMethodService, useClass: MockAuthenticationMethodService},
-                {provide: ConfigurationService, useClass: NaeExampleAppConfigurationService},
+                {provide: ConfigurationService, useClass: TestConfigurationService},
             ]
         })
             .compileComponents();
diff --git a/projects/netgrif-components/src/lib/navigation/quick-panel/components/impersonate-quick-panel/impersonate-quick-panel.component.ts b/projects/netgrif-components/src/lib/navigation/quick-panel/components/impersonate-quick-panel/impersonate-quick-panel.component.ts
index 1209b904b7..96389761e9 100644
--- a/projects/netgrif-components/src/lib/navigation/quick-panel/components/impersonate-quick-panel/impersonate-quick-panel.component.ts
+++ b/projects/netgrif-components/src/lib/navigation/quick-panel/components/impersonate-quick-panel/impersonate-quick-panel.component.ts
@@ -1,5 +1,5 @@
 import {Component} from '@angular/core';
-import {ImpersonationService, ImpersonationUserSelectService, UserService} from 'netgrif-components-core';
+import {ImpersonationService, ImpersonationUserSelectService, UserService} from '@netgrif/components-core';
 
 @Component({
     selector: 'nc-impersonate-quick-panel',
diff --git a/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate.component.spec.ts b/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate.component.spec.ts
index 30c4da292c..1482c702ee 100644
--- a/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate.component.spec.ts
+++ b/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate.component.spec.ts
@@ -11,7 +11,7 @@
 //     SimpleFilter,
 //     SnackBarService,
 //     TranslateLibModule
-// } from 'netgrif-components-core';
+// } from '@netgrif/components-core';
 // import {
 //     NaeExampleAppConfigurationService
 // } from '../../../../../../nae-example-app/src/app/nae-example-app-configuration.service';

From 24160b0f08d46fad9f2932c1404008024319cb11 Mon Sep 17 00:00:00 2001
From: Bezak <bezak@netgrif.com>
Date: Wed, 28 Sep 2022 22:05:31 +0200
Subject: [PATCH 18/21] [NAE-1678] User impersonation - improvements based on
 PR comments

---
 projects/netgrif-components-core/src/assets/i18n/en.json      | 2 +-
 projects/netgrif-components-core/src/assets/i18n/sk.json      | 2 +-
 .../services/impersonation-user-resource.service.ts           | 4 ++--
 .../admin-impersonate-list.component.ts                       | 4 ++--
 .../admin-impersonate/admin-impersonate.component.ts          | 4 ++--
 5 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/projects/netgrif-components-core/src/assets/i18n/en.json b/projects/netgrif-components-core/src/assets/i18n/en.json
index b02295e3f8..e061830d9c 100644
--- a/projects/netgrif-components-core/src/assets/i18n/en.json
+++ b/projects/netgrif-components-core/src/assets/i18n/en.json
@@ -466,7 +466,7 @@
     "impersonation": {
         "user": {
             "successfullyRepresented": "User successfully represented",
-            "currentlyAlreadyRepresented": "User is already currently represented",
+            "currentlyAlreadyRepresented": "User is already being represented by someone else",
             "currentlyLogged": "User is currently logged in"
         },
         "action": {
diff --git a/projects/netgrif-components-core/src/assets/i18n/sk.json b/projects/netgrif-components-core/src/assets/i18n/sk.json
index 1112ca61fa..7a5e55a52b 100644
--- a/projects/netgrif-components-core/src/assets/i18n/sk.json
+++ b/projects/netgrif-components-core/src/assets/i18n/sk.json
@@ -466,7 +466,7 @@
     "impersonation": {
         "user": {
             "successfullyRepresented": "Používateľ bol úspešne zastúpený",
-            "currentlyAlreadyRepresented": "Používateľ je momentálne už zastúpený",
+            "currentlyAlreadyRepresented": "Používateľ je momentálne zastupovaný",
             "currentlyLogged": "Používateľ je momentálne prihlásený"
         },
         "action": {
diff --git a/projects/netgrif-components-core/src/lib/impersonation/services/impersonation-user-resource.service.ts b/projects/netgrif-components-core/src/lib/impersonation/services/impersonation-user-resource.service.ts
index 60aebbf06b..4e5fafb8ff 100644
--- a/projects/netgrif-components-core/src/lib/impersonation/services/impersonation-user-resource.service.ts
+++ b/projects/netgrif-components-core/src/lib/impersonation/services/impersonation-user-resource.service.ts
@@ -20,8 +20,8 @@ export class ImpersonationUserResourceService extends UserResourceService {
         this._IMPERSONATION_SERVER_URL = this.getResourceAddress('impersonation');
     }
 
-    public search(body: object, params?: Params): Observable<Page<UserResource>> {
-        return this.provider.post$('/impersonate/search', this._IMPERSONATION_SERVER_URL, {query: (body as any).fulltext}, params)
+    public search(body: {fulltext: string}, params?: Params): Observable<Page<UserResource>> {
+        return this.provider.post$('/impersonate/search', this._IMPERSONATION_SERVER_URL, {query: body.fulltext}, params)
             .pipe(map((r) => this.getResourcePage<UserResource>(r, 'users')));
     }
 }
diff --git a/projects/netgrif-components/src/lib/side-menu/content-components/admin-impersonate/admin-impersonate-list/admin-impersonate-list.component.ts b/projects/netgrif-components/src/lib/side-menu/content-components/admin-impersonate/admin-impersonate-list/admin-impersonate-list.component.ts
index e633cde714..07784b34bf 100644
--- a/projects/netgrif-components/src/lib/side-menu/content-components/admin-impersonate/admin-impersonate-list/admin-impersonate-list.component.ts
+++ b/projects/netgrif-components/src/lib/side-menu/content-components/admin-impersonate/admin-impersonate-list/admin-impersonate-list.component.ts
@@ -11,7 +11,7 @@ import {AbstractUserAssignListComponent, UserListService} from '@netgrif/compone
 })
 export class AdminImpersonateListComponent extends AbstractUserAssignListComponent {
 
-    constructor(protected _userListService: UserListService) {
-        super(_userListService);
+    constructor(userListService: UserListService) {
+        super(userListService);
     }
 }
diff --git a/projects/netgrif-components/src/lib/side-menu/content-components/admin-impersonate/admin-impersonate.component.ts b/projects/netgrif-components/src/lib/side-menu/content-components/admin-impersonate/admin-impersonate.component.ts
index ae4fcb8869..c242f69c6e 100644
--- a/projects/netgrif-components/src/lib/side-menu/content-components/admin-impersonate/admin-impersonate.component.ts
+++ b/projects/netgrif-components/src/lib/side-menu/content-components/admin-impersonate/admin-impersonate.component.ts
@@ -16,7 +16,7 @@ import {AbstractUserAssignComponent, NAE_SIDE_MENU_CONTROL, SideMenuControl, Use
     }]
 })
 export class AdminImpersonateComponent extends AbstractUserAssignComponent {
-    constructor(@Inject(NAE_SIDE_MENU_CONTROL) protected _sideMenuControl: SideMenuControl) {
-        super(_sideMenuControl);
+    constructor(@Inject(NAE_SIDE_MENU_CONTROL) sideMenuControl: SideMenuControl) {
+        super(sideMenuControl);
     }
 }

From 759be9064e72388bdae82d14b5f4ffebd1bfc727 Mon Sep 17 00:00:00 2001
From: Bezak <bezak@netgrif.com>
Date: Thu, 29 Sep 2022 14:17:53 +0200
Subject: [PATCH 19/21] [NAE-1678] User impersonation - improvements based on
 machacjozef PR comments

---
 projects/nae-example-app/src/app/app.module.ts                  | 2 +-
 .../netgrif-components-core/src/lib/impersonation/public-api.ts | 1 +
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/projects/nae-example-app/src/app/app.module.ts b/projects/nae-example-app/src/app/app.module.ts
index f0101bc4f2..f66b6b7259 100644
--- a/projects/nae-example-app/src/app/app.module.ts
+++ b/projects/nae-example-app/src/app/app.module.ts
@@ -154,7 +154,7 @@ export function HttpLoaderFactory(http: HttpClient) {
         WrapperEmptyViewComponent,
         DoubleDrawerExampleComponent,
         PublicSingleTaskViewComponent,
-        BreadcrumbsExampleComponent,
+        BreadcrumbsExampleComponent
     ],
     imports: [
         BrowserModule,
diff --git a/projects/netgrif-components-core/src/lib/impersonation/public-api.ts b/projects/netgrif-components-core/src/lib/impersonation/public-api.ts
index bbd42db6c5..78934e3a35 100644
--- a/projects/netgrif-components-core/src/lib/impersonation/public-api.ts
+++ b/projects/netgrif-components-core/src/lib/impersonation/public-api.ts
@@ -1,5 +1,6 @@
 /* MODELS */
 export * from './models/user-impersonation-constants';
+export * from './models/user-impersonate-config-metadata';
 
 /* SERVICES */
 export * from './services/impersonation.service';

From 2c054b770057eb2423ca53feefc3b92f468f5619 Mon Sep 17 00:00:00 2001
From: Bezak <bezak@netgrif.com>
Date: Thu, 29 Sep 2022 14:41:30 +0200
Subject: [PATCH 20/21] [NAE-1678] User impersonation - fix test after merge

---
 .../abstract-navigation-double-drawer.spec.ts               | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/projects/netgrif-components-core/src/lib/navigation/navigation-double-drawer/abstract-navigation-double-drawer.spec.ts b/projects/netgrif-components-core/src/lib/navigation/navigation-double-drawer/abstract-navigation-double-drawer.spec.ts
index e39d61716f..e82ec8eb9e 100644
--- a/projects/netgrif-components-core/src/lib/navigation/navigation-double-drawer/abstract-navigation-double-drawer.spec.ts
+++ b/projects/netgrif-components-core/src/lib/navigation/navigation-double-drawer/abstract-navigation-double-drawer.spec.ts
@@ -30,6 +30,8 @@ import {
     DynamicNavigationRouteProviderService
 } from '../../routing/dynamic-navigation-route-provider/dynamic-navigation-route-provider.service';
 import { AuthenticationModule } from '../../authentication/authentication.module';
+import {ImpersonationUserSelectService} from '../../impersonation/services/impersonation-user-select.service';
+import {ImpersonationService} from '../../impersonation/services/impersonation.service';
 
 describe('AbstractNavigationDoubleDrawerComponent', () => {
     let component: TestDrawerComponent;
@@ -105,9 +107,11 @@ class TestDrawerComponent extends AbstractNavigationDoubleDrawerComponent {
                 _log: LoggerService,
                 _config: ConfigurationService,
                 _uriService: UriService,
+                _impersonationUserSelect: ImpersonationUserSelectService,
+                _impersonation: ImpersonationService,
                 _dynamicRouteProviderService: DynamicNavigationRouteProviderService) {
         super(_router, _activatedRoute, _breakpoint, _languageService, _userService, _accessService, _log, _config, _uriService,
-            _dynamicRouteProviderService)
+            _impersonationUserSelect, _impersonation, _dynamicRouteProviderService)
     }
 }
 

From 4ffd177e187e3e2cea05a7f72fbd86c909365632 Mon Sep 17 00:00:00 2001
From: Bezak <bezak@netgrif.com>
Date: Sat, 1 Oct 2022 10:37:28 +0200
Subject: [PATCH 21/21] [NAE-1678] User impersonation - changes based on PR
 comments

---
 projects/netgrif-components-core/src/assets/i18n/de.json    | 6 +++---
 .../src/lib/authentication/public-api.ts                    | 2 ++
 .../services/impersonation-user-resource.service.ts         | 6 +++---
 .../user-impersonate/abstract-user-impersonate.component.ts | 2 --
 .../load-filter/load-filter.component.spec.ts               | 1 +
 .../side-menu-content-component.module.ts                   | 3 +++
 .../user-impersonate/user-impersonate.component.spec.ts     | 1 +
 .../user-impersonate/user-impersonate.component.ts          | 2 +-
 8 files changed, 14 insertions(+), 9 deletions(-)

diff --git a/projects/netgrif-components-core/src/assets/i18n/de.json b/projects/netgrif-components-core/src/assets/i18n/de.json
index 799ed7bcfc..fda9b56a95 100644
--- a/projects/netgrif-components-core/src/assets/i18n/de.json
+++ b/projects/netgrif-components-core/src/assets/i18n/de.json
@@ -466,9 +466,9 @@
     },
     "impersonation": {
         "user": {
-            "successfullyRepresented": "Benutzer erfolgreich vertreten",
-            "currentlyAlreadyRepresented": "Benutzer ist bereits aktuell vertreten",
-            "currentlyLogged": "Benutzer ist derzeit angemeldet"
+            "successfullyRepresented": "Benutzer wird jetzt vertreten",
+            "currentlyAlreadyRepresented": "Für den Benutzer existiert bereits eine Vertretung",
+            "currentlyLogged": "Benutzer ist bereits angemeldet"
         },
         "action": {
             "failed": "Aktion ist fehlgeschlagen",
diff --git a/projects/netgrif-components-core/src/lib/authentication/public-api.ts b/projects/netgrif-components-core/src/lib/authentication/public-api.ts
index f17499ed0b..d2d9a4ca4a 100644
--- a/projects/netgrif-components-core/src/lib/authentication/public-api.ts
+++ b/projects/netgrif-components-core/src/lib/authentication/public-api.ts
@@ -12,6 +12,8 @@ export * from './authentication.factory';
 
 /* SERVICES */
 export * from './anonymous/anonymous.service';
+export * from './services/anonymous-authentication-interceptor'
+export * from './services/authentication-interceptor'
 
 /* COMPONENTS */
 export * from './components/abstract-authentication-overlay';
diff --git a/projects/netgrif-components-core/src/lib/impersonation/services/impersonation-user-resource.service.ts b/projects/netgrif-components-core/src/lib/impersonation/services/impersonation-user-resource.service.ts
index 4e5fafb8ff..9c5ae65bc2 100644
--- a/projects/netgrif-components-core/src/lib/impersonation/services/impersonation-user-resource.service.ts
+++ b/projects/netgrif-components-core/src/lib/impersonation/services/impersonation-user-resource.service.ts
@@ -15,13 +15,13 @@ export class ImpersonationUserResourceService extends UserResourceService {
 
     protected _IMPERSONATION_SERVER_URL: string;
 
-    constructor(protected provider: ResourceProvider, protected _configService: ConfigurationService) {
-        super(provider, _configService);
+    constructor(provider: ResourceProvider, configService: ConfigurationService) {
+        super(provider, configService);
         this._IMPERSONATION_SERVER_URL = this.getResourceAddress('impersonation');
     }
 
     public search(body: {fulltext: string}, params?: Params): Observable<Page<UserResource>> {
-        return this.provider.post$('/impersonate/search', this._IMPERSONATION_SERVER_URL, {query: body.fulltext}, params)
+        return this._resourceProvider.post$('/impersonate/search', this._IMPERSONATION_SERVER_URL, {query: body.fulltext}, params)
             .pipe(map((r) => this.getResourcePage<UserResource>(r, 'users')));
     }
 }
diff --git a/projects/netgrif-components-core/src/lib/side-menu/content-components/user-impersonate/abstract-user-impersonate.component.ts b/projects/netgrif-components-core/src/lib/side-menu/content-components/user-impersonate/abstract-user-impersonate.component.ts
index 7ac1b4cfca..6865b1af46 100644
--- a/projects/netgrif-components-core/src/lib/side-menu/content-components/user-impersonate/abstract-user-impersonate.component.ts
+++ b/projects/netgrif-components-core/src/lib/side-menu/content-components/user-impersonate/abstract-user-impersonate.component.ts
@@ -1,7 +1,6 @@
 import {SideMenuControl} from '../../models/side-menu-control';
 import {Component, Inject} from '@angular/core';
 import {NAE_SIDE_MENU_CONTROL} from '../../side-menu-injection-token';
-import {LoggerService} from '../../../logger/services/logger.service';
 import {CaseViewService} from '../../../view/case-view/service/case-view-service';
 import {Case} from '../../../resources/interface/case';
 import {AbstractCaseViewComponent} from '../../../view/case-view/abstract-case-view';
@@ -17,7 +16,6 @@ export abstract class AbstractUserImpersonateComponent extends AbstractCaseViewC
     protected _injectedData: UserImpersonateInjectionData;
 
     protected constructor(@Inject(NAE_SIDE_MENU_CONTROL) protected _sideMenuControl: SideMenuControl,
-                          protected _log: LoggerService,
                           caseViewService: CaseViewService) {
         super(caseViewService);
         if (this._sideMenuControl.data) {
diff --git a/projects/netgrif-components/src/lib/side-menu/content-components/load-filter/load-filter.component.spec.ts b/projects/netgrif-components/src/lib/side-menu/content-components/load-filter/load-filter.component.spec.ts
index dc60202510..aeff43a455 100644
--- a/projects/netgrif-components/src/lib/side-menu/content-components/load-filter/load-filter.component.spec.ts
+++ b/projects/netgrif-components/src/lib/side-menu/content-components/load-filter/load-filter.component.spec.ts
@@ -1,3 +1,4 @@
+// TODO TEST 30.9.2022
 // import {ComponentFixture, TestBed} from '@angular/core/testing';
 // import {LoadFilterComponent} from './load-filter.component';
 // import {
diff --git a/projects/netgrif-components/src/lib/side-menu/content-components/side-menu-content-component.module.ts b/projects/netgrif-components/src/lib/side-menu/content-components/side-menu-content-component.module.ts
index 189df8fde6..c7e6ed80e7 100644
--- a/projects/netgrif-components/src/lib/side-menu/content-components/side-menu-content-component.module.ts
+++ b/projects/netgrif-components/src/lib/side-menu/content-components/side-menu-content-component.module.ts
@@ -25,6 +25,7 @@ import {
 } from './admin-impersonate/side-menu-admin-impersonate-component.module';
 import {AdminImpersonateComponent} from './admin-impersonate/admin-impersonate.component';
 import {UserImpersonateComponent} from './user-impersonate/user-impersonate.component';
+import {SideMenuUserImpersonateComponentModule} from './user-impersonate/side-menu-user-impersonate-component.module';
 
 
 @NgModule({
@@ -32,6 +33,7 @@ import {UserImpersonateComponent} from './user-impersonate/user-impersonate.comp
         CommonModule,
         SideMenuUserAssignComponentModule,
         SideMenuAdminImpersonateComponentModule,
+        SideMenuUserImpersonateComponentModule,
         SideMenuNewCaseComponentModule,
         SideMenuImportNetComponentModule,
         SideMenuFilterSelectorComponentModule,
@@ -42,6 +44,7 @@ import {UserImpersonateComponent} from './user-impersonate/user-impersonate.comp
     exports: [
         SideMenuUserAssignComponentModule,
         SideMenuAdminImpersonateComponentModule,
+        SideMenuUserImpersonateComponentModule,
         SideMenuNewCaseComponentModule,
         SideMenuImportNetComponentModule,
         SideMenuFilterSelectorComponentModule,
diff --git a/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate.component.spec.ts b/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate.component.spec.ts
index 1482c702ee..442355b5a4 100644
--- a/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate.component.spec.ts
+++ b/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate.component.spec.ts
@@ -1,3 +1,4 @@
+// TODO TEST 30.9.2022
 // import {ComponentFixture, TestBed} from '@angular/core/testing';
 //
 // import {UserImpersonateComponent} from './user-impersonate.component';
diff --git a/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate.component.ts b/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate.component.ts
index 8885a47a65..9eaddb3884 100644
--- a/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate.component.ts
+++ b/projects/netgrif-components/src/lib/side-menu/content-components/user-impersonate/user-impersonate.component.ts
@@ -57,7 +57,7 @@ export class UserImpersonateComponent extends AbstractUserImpersonateComponent i
     constructor(@Inject(NAE_SIDE_MENU_CONTROL) sideMenuControl: SideMenuControl,
                 log: LoggerService,
                 caseViewService: CaseViewService) {
-        super(sideMenuControl, log, caseViewService);
+        super(sideMenuControl, caseViewService);
     }
 
     ngAfterViewInit(): void {
