RED-6713: show previous signed in domains
This commit is contained in:
parent
721d3e3b1a
commit
223fbe688c
@ -1,74 +1,74 @@
|
|||||||
@use 'common-mixins';
|
@use 'common-mixins';
|
||||||
|
|
||||||
.top-bar {
|
.top-bar {
|
||||||
height: var(--iqser-top-bar-height);
|
height: var(--iqser-top-bar-height);
|
||||||
width: 100vw;
|
width: 100vw;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0 24px;
|
||||||
|
border-bottom: 1px solid var(--iqser-separator);
|
||||||
|
box-sizing: border-box;
|
||||||
|
background-color: var(--iqser-background);
|
||||||
|
|
||||||
|
> *:not(:last-child) {
|
||||||
|
margin-right: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 0 24px;
|
|
||||||
border-bottom: 1px solid var(--iqser-separator);
|
&.right {
|
||||||
box-sizing: border-box;
|
justify-content: flex-end;
|
||||||
background-color: var(--iqser-background);
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-placeholder {
|
||||||
|
display: flex;
|
||||||
|
flex: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.buttons {
|
||||||
|
display: flex;
|
||||||
|
margin-right: 8px;
|
||||||
|
|
||||||
> *:not(:last-child) {
|
> *:not(:last-child) {
|
||||||
margin-right: 50px;
|
margin-right: 14px;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.logo {
|
.logo {
|
||||||
@include common-mixins.clear-a;
|
@include common-mixins.clear-a;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.app-name {
|
.app-name {
|
||||||
font-family: var(--iqser-app-name-font-family);
|
font-family: var(--iqser-app-name-font-family);
|
||||||
font-size: var(--iqser-app-name-font-size);
|
font-size: var(--iqser-app-name-font-size);
|
||||||
color: var(--iqser-app-name-color);
|
color: var(--iqser-app-name-color);
|
||||||
font-weight: 800;
|
font-weight: 800;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
|
||||||
|
|
||||||
.menu {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
&.right {
|
|
||||||
justify-content: flex-end;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.menu-placeholder {
|
|
||||||
display: flex;
|
|
||||||
flex: 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
.buttons {
|
|
||||||
display: flex;
|
|
||||||
margin-right: 8px;
|
|
||||||
|
|
||||||
> *:not(:last-child) {
|
|
||||||
margin-right: 14px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.dev-mode {
|
.dev-mode {
|
||||||
background-color: var(--iqser-primary);
|
background-color: var(--iqser-primary);
|
||||||
color: var(--iqser-white);
|
color: var(--iqser-white);
|
||||||
font-size: 22px;
|
font-size: 22px;
|
||||||
line-height: 16px;
|
line-height: 16px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 0;
|
top: 0;
|
||||||
z-index: 100;
|
z-index: 100;
|
||||||
right: 0;
|
right: 0;
|
||||||
height: var(--iqser-top-bar-height);
|
height: var(--iqser-top-bar-height);
|
||||||
word-break: break-all;
|
word-break: break-all;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
font-family: monospace;
|
font-family: monospace;
|
||||||
width: 24px;
|
width: 24px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -85,10 +85,10 @@ export class IqserPermissionsGuard implements CanActivate, CanMatch, CanActivate
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (Array.isArray(_redirectTo)) {
|
if (Array.isArray(_redirectTo)) {
|
||||||
return this._router.navigate([this._tenantsService.currentTenant, ..._redirectTo]);
|
return this._router.navigate([this._tenantsService.activeTenantId, ..._redirectTo]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return this._router.navigate([`${this._tenantsService.currentTenant}${_redirectTo}`]);
|
return this._router.navigate([`${this._tenantsService.activeTenantId}${_redirectTo}`]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#checkRedirect(permissions: IqserPermissionsData, route: ActivatedRouteSnapshot | Route, state?: RouterStateSnapshot) {
|
#checkRedirect(permissions: IqserPermissionsData, route: ActivatedRouteSnapshot | Route, state?: RouterStateSnapshot) {
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
|
|||||||
import { MatIconModule } from '@angular/material/icon';
|
import { MatIconModule } from '@angular/material/icon';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'iqser-logo [icon]',
|
selector: 'iqser-logo',
|
||||||
template: ` <mat-icon [svgIcon]="icon"></mat-icon>`,
|
template: ` <mat-icon [svgIcon]="icon"></mat-icon>`,
|
||||||
styles: [
|
styles: [
|
||||||
`
|
`
|
||||||
@ -21,5 +21,5 @@ import { MatIconModule } from '@angular/material/icon';
|
|||||||
imports: [MatIconModule],
|
imports: [MatIconModule],
|
||||||
})
|
})
|
||||||
export class LogoComponent {
|
export class LogoComponent {
|
||||||
@Input() icon!: string;
|
@Input({ required: true }) icon!: string;
|
||||||
}
|
}
|
||||||
|
|||||||
15
src/lib/shared/spacer/spacer.component.scss
Normal file
15
src/lib/shared/spacer/spacer.component.scss
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
:host {
|
||||||
|
--height: 20px;
|
||||||
|
|
||||||
|
div {
|
||||||
|
height: #{var(--height)};
|
||||||
|
|
||||||
|
@media screen and (max-width: 1600px) {
|
||||||
|
height: calc(#{var(--height)} * 0.9);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 1200px) {
|
||||||
|
height: calc(#{var(--height)} * 0.85);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
16
src/lib/shared/spacer/spacer.component.ts
Normal file
16
src/lib/shared/spacer/spacer.component.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import { Component, HostBinding, Input } from '@angular/core';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'iqser-spacer [height]',
|
||||||
|
template: ' <div></div> ',
|
||||||
|
styleUrls: ['./spacer.component.scss'],
|
||||||
|
standalone: true,
|
||||||
|
})
|
||||||
|
export class SpacerComponent {
|
||||||
|
@Input({ required: true }) height!: number;
|
||||||
|
|
||||||
|
@HostBinding('style.--height')
|
||||||
|
get heightStyle() {
|
||||||
|
return this.height + 'px';
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -4,5 +4,5 @@ export * from './guards/if-not-logged-in.guard';
|
|||||||
export * from './services';
|
export * from './services';
|
||||||
export * from './tenant.pipe';
|
export * from './tenant.pipe';
|
||||||
export * from './tenants.module';
|
export * from './tenants.module';
|
||||||
export * from './tenant-resolve/tenant-resolve.component';
|
export * from './tenant-select/tenant-select.component';
|
||||||
export * from './services/keycloak-status.service';
|
export * from './services/keycloak-status.service';
|
||||||
|
|||||||
@ -30,7 +30,7 @@ export class KeycloakStatusService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
createLoginUrl() {
|
createLoginUrl() {
|
||||||
const currentTenant = this.#tenantsService.currentTenant;
|
const currentTenant = this.#tenantsService.activeTenantId;
|
||||||
if (currentTenant && window.location.href.indexOf('/' + currentTenant) > 0) {
|
if (currentTenant && window.location.href.indexOf('/' + currentTenant) > 0) {
|
||||||
return window.location.href;
|
return window.location.href;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,9 +8,9 @@ export class TenantIdInterceptor implements HttpInterceptor {
|
|||||||
protected readonly _tenantsService = inject(TenantsService);
|
protected readonly _tenantsService = inject(TenantsService);
|
||||||
|
|
||||||
intercept(req: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {
|
intercept(req: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {
|
||||||
if (this._tenantsService.currentTenant) {
|
if (this._tenantsService.activeTenantId) {
|
||||||
const updatedRequest = req.clone({
|
const updatedRequest = req.clone({
|
||||||
setHeaders: { 'X-TENANT-ID': this._tenantsService.currentTenant },
|
setHeaders: { 'X-TENANT-ID': this._tenantsService.activeTenantId },
|
||||||
});
|
});
|
||||||
|
|
||||||
return next.handle(updatedRequest);
|
return next.handle(updatedRequest);
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import { computed, inject, Injectable, signal } from '@angular/core';
|
|||||||
import { HttpClient } from '@angular/common/http';
|
import { HttpClient } from '@angular/common/http';
|
||||||
import { firstValueFrom } from 'rxjs';
|
import { firstValueFrom } from 'rxjs';
|
||||||
import { NGXLogger } from 'ngx-logger';
|
import { NGXLogger } from 'ngx-logger';
|
||||||
import { BASE_HREF } from '../../utils';
|
import { BASE_HREF, List } from '../../utils';
|
||||||
import { Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
|
|
||||||
export interface IBaseTenant {
|
export interface IBaseTenant {
|
||||||
@ -11,6 +11,22 @@ export interface IBaseTenant {
|
|||||||
readonly guid: string;
|
readonly guid: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface IStoredTenantId {
|
||||||
|
readonly tenantId: string;
|
||||||
|
readonly email: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type StoredTenantIds = List<IStoredTenantId>;
|
||||||
|
|
||||||
|
export interface IStoredTenant {
|
||||||
|
readonly tenant: IBaseTenant;
|
||||||
|
readonly email: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type StoredTenants = IStoredTenant[];
|
||||||
|
|
||||||
|
const STORED_TENANTS_KEY = 'red-stored-tenants';
|
||||||
|
|
||||||
@Injectable({ providedIn: 'root' })
|
@Injectable({ providedIn: 'root' })
|
||||||
export class TenantsService {
|
export class TenantsService {
|
||||||
readonly tenants = signal<IBaseTenant[] | undefined>(undefined);
|
readonly tenants = signal<IBaseTenant[] | undefined>(undefined);
|
||||||
@ -31,8 +47,11 @@ export class TenantsService {
|
|||||||
key: localStorage.key.bind(localStorage),
|
key: localStorage.key.bind(localStorage),
|
||||||
};
|
};
|
||||||
readonly #activeTenantId = signal<string>('');
|
readonly #activeTenantId = signal<string>('');
|
||||||
|
readonly activeTenant = computed(() => {
|
||||||
|
return this.tenants()?.find(t => t.tenantId === this.#activeTenantId());
|
||||||
|
});
|
||||||
|
|
||||||
get currentTenant() {
|
get activeTenantId() {
|
||||||
return this.#activeTenantId();
|
return this.#activeTenantId();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,11 +101,61 @@ export class TenantsService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.#mutateStorage(tenantId);
|
this.#mutateStorage(tenantId);
|
||||||
this.#setCurrentTenantId(tenantId);
|
this.#setActiveTenantId(tenantId);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#setCurrentTenantId(tenantId: string) {
|
storeTenant(email: string) {
|
||||||
|
if (!email) {
|
||||||
|
this.#logger.warn('[TENANTS] Email is null, skip storing');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const storedTenants = this.getStoredTenants();
|
||||||
|
const activeTenant = this.activeTenant();
|
||||||
|
const existing = storedTenants.find(s => s.email === email && s.tenant.tenantId === activeTenant?.tenantId);
|
||||||
|
if (existing) {
|
||||||
|
this.#logger.info('[TENANTS] Stored tenant exists: ', storedTenants);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!activeTenant) {
|
||||||
|
this.#logger.error('[TENANTS] Active tenant is null when storing tenants');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
storedTenants.push({ tenant: activeTenant, email: email });
|
||||||
|
const serializableTenants = storedTenants.map(s => ({
|
||||||
|
tenantId: s.tenant.tenantId,
|
||||||
|
email: s.email,
|
||||||
|
}));
|
||||||
|
this.#storageReference.setItem(STORED_TENANTS_KEY, JSON.stringify(serializableTenants));
|
||||||
|
this.#logger.info('[TENANTS] Stored tenants: ', storedTenants);
|
||||||
|
}
|
||||||
|
|
||||||
|
getStoredTenants(): StoredTenants {
|
||||||
|
const rawStoredTenants = this.#storageReference.getItem(STORED_TENANTS_KEY);
|
||||||
|
const stored = JSON.parse(rawStoredTenants ?? '[]') as StoredTenantIds;
|
||||||
|
const tenants = this.tenants();
|
||||||
|
if (!tenants) {
|
||||||
|
this.#logger.error('[TENANTS] Tenants data is null when retrieving stored tenants');
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const trueStored: StoredTenants = [];
|
||||||
|
for (const s of stored) {
|
||||||
|
const tenant = tenants.find(t => t.tenantId === s.tenantId);
|
||||||
|
if (!tenant) {
|
||||||
|
this.#logger.warn(`[TENANTS] Stored tenant with id ${tenant} not found, skipping`);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
trueStored.push({ tenant, email: s.email });
|
||||||
|
}
|
||||||
|
|
||||||
|
return trueStored;
|
||||||
|
}
|
||||||
|
|
||||||
|
#setActiveTenantId(tenantId: string) {
|
||||||
this.#logger.info('[TENANTS] Set current tenant id: ', tenantId);
|
this.#logger.info('[TENANTS] Set current tenant id: ', tenantId);
|
||||||
this.#activeTenantId.set(tenantId);
|
this.#activeTenantId.set(tenantId);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,25 +0,0 @@
|
|||||||
<div class="tenant-section">
|
|
||||||
<form (submit)="updateTenantSelection()" [formGroup]="form">
|
|
||||||
<div class="heading-l" translate="tenant-resolve.header"></div>
|
|
||||||
|
|
||||||
<div class="iqser-input-group required w-400">
|
|
||||||
<mat-form-field *ngIf="_tenantsService.tenants() as tenants">
|
|
||||||
<mat-select
|
|
||||||
[placeholder]="'tenant-resolve.form.tenant-placeholder' | translate"
|
|
||||||
class="full-width"
|
|
||||||
formControlName="tenantId"
|
|
||||||
>
|
|
||||||
<mat-option *ngFor="let option of tenants" [value]="option.tenantId">
|
|
||||||
{{ option.displayName || option.tenantId }}
|
|
||||||
</mat-option>
|
|
||||||
</mat-select>
|
|
||||||
</mat-form-field>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<iqser-icon-button
|
|
||||||
[label]="'tenant-resolve.actions.save' | translate"
|
|
||||||
[submit]="true"
|
|
||||||
[type]="iconButtonTypes.primary"
|
|
||||||
></iqser-icon-button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
@ -1,13 +0,0 @@
|
|||||||
.tenant-section {
|
|
||||||
display: flex;
|
|
||||||
align-items: flex-start;
|
|
||||||
justify-content: center;
|
|
||||||
width: 100vw;
|
|
||||||
height: 100vh;
|
|
||||||
|
|
||||||
margin-top: 32px;
|
|
||||||
|
|
||||||
> form > * {
|
|
||||||
padding: 8px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
55
src/lib/tenants/tenant-select/tenant-select.component.html
Normal file
55
src/lib/tenants/tenant-select/tenant-select.component.html
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
<div class="tenant-section">
|
||||||
|
<a class="logo">
|
||||||
|
<div class="actions">
|
||||||
|
<iqser-logo icon="red:logo"></iqser-logo>
|
||||||
|
<div class="app-name">{{ titleService.getTitle() }}</div>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<iqser-spacer [height]="100"></iqser-spacer>
|
||||||
|
|
||||||
|
<div *ngIf="storedTenants.length" class="pb-30 subheading" translate="tenant-resolve.header.sign-in-previous-domain"></div>
|
||||||
|
|
||||||
|
<div *ngIf="storedTenants.length" style="display: flex; flex-direction: column">
|
||||||
|
<div
|
||||||
|
*ngFor="let stored of storedTenants"
|
||||||
|
[routerLink]="[stored.tenant.tenantId]"
|
||||||
|
class="pointer mat-elevation-z2 card stored-tenant-card mt-10"
|
||||||
|
>
|
||||||
|
<iqser-logo class="card-icon" icon="red:logo" mat-card-image></iqser-logo>
|
||||||
|
|
||||||
|
<div class="card-content">
|
||||||
|
<span class="heading">{{ stored.tenant.displayName }}</span>
|
||||||
|
<span>{{ stored.email }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<mat-icon class="card-icon upside-down" svgIcon="iqser:expand"></mat-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div *ngIf="storedTenants.length === 0" class="heading pb-30" translate="tenant-resolve.header.first-time"></div>
|
||||||
|
|
||||||
|
<ng-container *ngIf="storedTenants.length">
|
||||||
|
<iqser-spacer [height]="100"></iqser-spacer>
|
||||||
|
<div class="pb-30 subheading" translate="tenant-resolve.header.join-another-domain"></div>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<div class="mat-elevation-z16 card input-card">
|
||||||
|
<span class="heading url">{{ url }}</span>
|
||||||
|
|
||||||
|
<form (submit)="updateTenantSelection()" [formGroup]="form" class="w-full">
|
||||||
|
<div class="iqser-input-group required w-full">
|
||||||
|
<mat-form-field>
|
||||||
|
<input [placeholder]="'tenant-resolve.input-placeholder' | translate" formControlName="tenantId" matInput />
|
||||||
|
</mat-form-field>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button class="card-icon upside-down" mat-icon-button type="submit">
|
||||||
|
<mat-icon svgIcon="iqser:expand"></mat-icon>
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<iqser-spacer [height]="50"></iqser-spacer>
|
||||||
|
<div [innerHTML]="'tenant-resolve.contact-administrator' | translate"></div>
|
||||||
|
</div>
|
||||||
65
src/lib/tenants/tenant-select/tenant-select.component.scss
Normal file
65
src/lib/tenants/tenant-select/tenant-select.component.scss
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
.tenant-section {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
flex-direction: column;
|
||||||
|
width: 100vw;
|
||||||
|
height: 100vh;
|
||||||
|
|
||||||
|
margin-top: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.actions {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stored-tenant-card {
|
||||||
|
width: 450px;
|
||||||
|
height: 90px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
border-radius: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-icon {
|
||||||
|
margin-right: 20px;
|
||||||
|
margin-left: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.upside-down {
|
||||||
|
transform: rotate(180deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pb-30 {
|
||||||
|
padding-bottom: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-card {
|
||||||
|
width: 600px;
|
||||||
|
height: 65px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.url {
|
||||||
|
margin-left: 20px;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
form {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subheading {
|
||||||
|
font-size: 17px;
|
||||||
|
}
|
||||||
@ -4,26 +4,27 @@ import { FormBuilder, Validators } from '@angular/forms';
|
|||||||
import { TenantsService } from '../services';
|
import { TenantsService } from '../services';
|
||||||
import { IconButtonTypes } from '../../buttons';
|
import { IconButtonTypes } from '../../buttons';
|
||||||
import { LoadingService } from '../../loading';
|
import { LoadingService } from '../../loading';
|
||||||
|
import { Title } from '@angular/platform-browser';
|
||||||
|
import { getConfig } from '../../services';
|
||||||
|
import { BASE_HREF } from '../../utils';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
templateUrl: './tenant-resolve.component.html',
|
templateUrl: './tenant-select.component.html',
|
||||||
styleUrls: ['./tenant-resolve.component.scss'],
|
styleUrls: ['./tenant-select.component.scss'],
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
})
|
})
|
||||||
export class TenantResolveComponent {
|
export class TenantSelectComponent {
|
||||||
readonly loadingService = inject(LoadingService);
|
readonly loadingService = inject(LoadingService);
|
||||||
readonly iconButtonTypes = IconButtonTypes;
|
readonly iconButtonTypes = IconButtonTypes;
|
||||||
readonly form;
|
readonly form = inject(FormBuilder).group({
|
||||||
|
// eslint-disable-next-line @typescript-eslint/unbound-method
|
||||||
|
tenantId: ['', Validators.required],
|
||||||
|
});
|
||||||
|
readonly url = getConfig().OAUTH_URL.replace('https://', '').replace('/auth', '') + inject(BASE_HREF) + '/';
|
||||||
protected readonly _tenantsService = inject(TenantsService);
|
protected readonly _tenantsService = inject(TenantsService);
|
||||||
|
protected readonly storedTenants = this._tenantsService.getStoredTenants();
|
||||||
|
protected readonly titleService = inject(Title);
|
||||||
readonly #router = inject(Router);
|
readonly #router = inject(Router);
|
||||||
readonly #formBuilder = inject(FormBuilder);
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
this.form = this.#formBuilder.group({
|
|
||||||
// eslint-disable-next-line @typescript-eslint/unbound-method
|
|
||||||
tenantId: ['', Validators.required],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
updateTenantSelection() {
|
updateTenantSelection() {
|
||||||
const tenant = this.form.controls.tenantId.value;
|
const tenant = this.form.controls.tenantId.value;
|
||||||
@ -14,6 +14,6 @@ export class TenantPipe implements PipeTransform {
|
|||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
const _value = Array.isArray(value) ? value.join('/') : value;
|
const _value = Array.isArray(value) ? value.join('/') : value;
|
||||||
return '/' + this.#tenantsService.currentTenant + _value;
|
return '/' + this.#tenantsService.activeTenantId + _value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,14 +3,20 @@ import { CommonModule } from '@angular/common';
|
|||||||
import { TranslateModule } from '@ngx-translate/core';
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
import { MatDialogModule } from '@angular/material/dialog';
|
import { MatDialogModule } from '@angular/material/dialog';
|
||||||
import { CircleButtonComponent, IconButtonComponent } from '../buttons';
|
import { CircleButtonComponent, IconButtonComponent } from '../buttons';
|
||||||
import { TenantResolveComponent } from './tenant-resolve/tenant-resolve.component';
|
import { TenantSelectComponent } from './tenant-select/tenant-select.component';
|
||||||
import { MatInputModule } from '@angular/material/input';
|
import { MatInputModule } from '@angular/material/input';
|
||||||
import { MatSelectModule } from '@angular/material/select';
|
import { MatSelectModule } from '@angular/material/select';
|
||||||
import { ReactiveFormsModule } from '@angular/forms';
|
import { ReactiveFormsModule } from '@angular/forms';
|
||||||
import { TenantIdInterceptor, TenantIdResponseInterceptor, TenantsService } from './services';
|
import { TenantIdInterceptor, TenantIdResponseInterceptor, TenantsService } from './services';
|
||||||
import { HTTP_INTERCEPTORS } from '@angular/common/http';
|
import { HTTP_INTERCEPTORS } from '@angular/common/http';
|
||||||
|
import { MatCardModule } from '@angular/material/card';
|
||||||
|
import { LogoComponent } from '../shared/logo/logo.component';
|
||||||
|
import { SpacerComponent } from '../shared/spacer/spacer.component';
|
||||||
|
import { MatIconModule } from '@angular/material/icon';
|
||||||
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
|
import { RouterLink } from '@angular/router';
|
||||||
|
|
||||||
const components = [TenantResolveComponent];
|
const components = [TenantSelectComponent];
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [...components],
|
declarations: [...components],
|
||||||
@ -23,6 +29,12 @@ const components = [TenantResolveComponent];
|
|||||||
MatSelectModule,
|
MatSelectModule,
|
||||||
IconButtonComponent,
|
IconButtonComponent,
|
||||||
ReactiveFormsModule,
|
ReactiveFormsModule,
|
||||||
|
MatCardModule,
|
||||||
|
LogoComponent,
|
||||||
|
SpacerComponent,
|
||||||
|
MatIconModule,
|
||||||
|
MatButtonModule,
|
||||||
|
RouterLink,
|
||||||
],
|
],
|
||||||
exports: [...components],
|
exports: [...components],
|
||||||
})
|
})
|
||||||
|
|||||||
@ -35,7 +35,7 @@ export class IqserAuthGuard extends KeycloakAuthGuard {
|
|||||||
|
|
||||||
const user = await this._userService.loadCurrentUser();
|
const user = await this._userService.loadCurrentUser();
|
||||||
if (user?.hasAnyRole && route.routeConfig?.path === 'auth-error') {
|
if (user?.hasAnyRole && route.routeConfig?.path === 'auth-error') {
|
||||||
await this._router.navigate([`/${this._tenantsService.currentTenant}/main`]);
|
await this._router.navigate([`/${this._tenantsService.activeTenantId}/main`]);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -14,7 +14,7 @@ export class IqserRoleGuard implements CanActivate {
|
|||||||
async canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
|
async canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
|
||||||
const currentUser = this._userService.currentUser;
|
const currentUser = this._userService.currentUser;
|
||||||
if (!currentUser || !currentUser.hasAnyRole) {
|
if (!currentUser || !currentUser.hasAnyRole) {
|
||||||
await this._router.navigate([`/${this._tenantsService.currentTenant}/auth-error`]);
|
await this._router.navigate([`/${this._tenantsService.activeTenantId}/auth-error`]);
|
||||||
this._loadingService.stop();
|
this._loadingService.stop();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user