remove emails from stored tenants
This commit is contained in:
parent
c851ab1394
commit
04a69f5e68
@ -1,11 +1,10 @@
|
||||
import { inject, Injectable, signal } from '@angular/core';
|
||||
import dayjs from 'dayjs';
|
||||
import { NGXLogger } from 'ngx-logger';
|
||||
import { List } from '../../utils';
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
export interface IStoredTenantId {
|
||||
readonly tenantId: string;
|
||||
readonly email: string;
|
||||
readonly created: string;
|
||||
}
|
||||
|
||||
@ -24,7 +23,7 @@ export class TenantsService {
|
||||
removeItem: localStorage.removeItem.bind(localStorage),
|
||||
key: localStorage.key.bind(localStorage),
|
||||
};
|
||||
readonly #activeTenantId = signal<string>('');
|
||||
readonly #activeTenantId = signal('');
|
||||
protected readonly _serviceName: string = 'tenant-user-management';
|
||||
|
||||
get activeTenantId() {
|
||||
@ -37,15 +36,10 @@ export class TenantsService {
|
||||
return true;
|
||||
}
|
||||
|
||||
storeTenant(emailOrUsername: string) {
|
||||
if (!emailOrUsername) {
|
||||
this.#logger.warn('[TENANTS] Email or username is null, skip storing');
|
||||
return;
|
||||
}
|
||||
|
||||
storeTenant() {
|
||||
const storedTenants = this.getStoredTenants();
|
||||
const activeTenantId = this.#activeTenantId();
|
||||
const existing = storedTenants.find(s => s.email === emailOrUsername && s.tenantId === activeTenantId);
|
||||
const existing = storedTenants.find(s => s.tenantId === activeTenantId);
|
||||
if (existing) {
|
||||
this.#logger.info('[TENANTS] Stored tenant exists: ', storedTenants);
|
||||
return;
|
||||
@ -56,7 +50,7 @@ export class TenantsService {
|
||||
return;
|
||||
}
|
||||
|
||||
storedTenants.push({ tenantId: activeTenantId, email: emailOrUsername, created: new Date().toISOString() });
|
||||
storedTenants.push({ tenantId: activeTenantId, created: new Date().toISOString() });
|
||||
this.#storageReference.setItem(STORED_TENANTS_KEY, JSON.stringify(storedTenants));
|
||||
this.#logger.info('[TENANTS] Stored tenants: ', storedTenants);
|
||||
}
|
||||
@ -72,8 +66,8 @@ export class TenantsService {
|
||||
const diff = date2.diff(date1, 'days');
|
||||
const is90DaysOld = diff >= 90;
|
||||
if (is90DaysOld) {
|
||||
this.#logger.warn(`[TENANTS] Saved tenant ${s.tenantId} - ${s.email} is 90 days old, delete it`);
|
||||
this.removeStored(s.email);
|
||||
this.#logger.warn(`[TENANTS] Saved tenant ${s.tenantId} is 90 days old, delete it`);
|
||||
this.removeStored(s.tenantId);
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -83,17 +77,16 @@ export class TenantsService {
|
||||
return validStoredTenants;
|
||||
}
|
||||
|
||||
removeStored(email: string) {
|
||||
if (!email) {
|
||||
this.#logger.warn('[TENANTS] Email is null, skip storing');
|
||||
removeStored(tenantId: string) {
|
||||
if (!tenantId) {
|
||||
this.#logger.warn('[TENANTS] Tenant Id is null, skip removing');
|
||||
return;
|
||||
}
|
||||
|
||||
const storedTenants = this.getStoredTenants();
|
||||
const activeTenantId = this.#activeTenantId();
|
||||
const existing = storedTenants.find(s => s.email === email && s.tenantId === activeTenantId);
|
||||
const existing = storedTenants.find(s => s.tenantId === tenantId);
|
||||
if (!existing) {
|
||||
this.#logger.info('[TENANTS] No stored tenant for ', email);
|
||||
this.#logger.info('[TENANTS] No stored tenant for ', tenantId);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@ -17,7 +17,7 @@
|
||||
|
||||
<div *ngIf="storedTenants.length">
|
||||
<div
|
||||
(click)="select(stored.tenantId, stored.email)"
|
||||
(click)="select(stored.tenantId)"
|
||||
*ngFor="let stored of storedTenants"
|
||||
class="d-flex pointer mat-elevation-z2 card stored-tenant-card mt-10"
|
||||
>
|
||||
@ -25,10 +25,12 @@
|
||||
|
||||
<div class="card-content flex-column">
|
||||
<span class="heading">{{ stored.tenantId }}</span>
|
||||
<span>{{ stored.email }}</span>
|
||||
</div>
|
||||
|
||||
<mat-icon class="card-icon upside-down" svgIcon="iqser:expand"></mat-icon>
|
||||
<div class="remove" iqserStopPropagation>
|
||||
<mat-icon (click)="removeStored(stored.tenantId)" svgIcon="iqser:close"></mat-icon>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@ -23,6 +23,13 @@
|
||||
.stored-tenant-card {
|
||||
width: 450px;
|
||||
height: 90px;
|
||||
position: relative;
|
||||
|
||||
&:hover {
|
||||
.remove {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.card {
|
||||
@ -66,3 +73,24 @@
|
||||
line-height: 29px;
|
||||
font-family: 'Inter', sans-serif;
|
||||
}
|
||||
|
||||
.remove {
|
||||
display: none;
|
||||
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
border-radius: 50%;
|
||||
background-color: var(--iqser-accent);
|
||||
color: var(--iqser-white);
|
||||
position: absolute;
|
||||
right: -8px;
|
||||
top: -8px;
|
||||
line-height: 6px;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
mat-icon {
|
||||
width: 6px;
|
||||
height: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,14 +1,14 @@
|
||||
import { ChangeDetectionStrategy, Component, inject, Input } from '@angular/core';
|
||||
import { FormBuilder, Validators } from '@angular/forms';
|
||||
import { TenantsService } from '../services';
|
||||
import { LoadingService } from '../../loading';
|
||||
import { Title } from '@angular/platform-browser';
|
||||
import { KeycloakService } from 'keycloak-angular';
|
||||
import { NGXLogger } from 'ngx-logger';
|
||||
import { LoadingService } from '../../loading';
|
||||
import { getConfig } from '../../services';
|
||||
import { BASE_HREF } from '../../utils';
|
||||
import { getKeycloakOptions } from '../keycloak-initializer';
|
||||
import { IStoredTenantId, TenantsService } from '../services';
|
||||
import { KeycloakStatusService } from '../services/keycloak-status.service';
|
||||
import { NGXLogger } from 'ngx-logger';
|
||||
import { getConfig } from '../../services';
|
||||
|
||||
@Component({
|
||||
templateUrl: './tenant-select.component.html',
|
||||
@ -18,9 +18,8 @@ import { getConfig } from '../../services';
|
||||
export class TenantSelectComponent {
|
||||
protected readonly baseHref = inject(BASE_HREF);
|
||||
protected readonly logger = inject(NGXLogger);
|
||||
protected readonly storedTenants = inject(TenantsService)
|
||||
.getStoredTenants()
|
||||
.sort((a, b) => a.tenantId.localeCompare(b.tenantId));
|
||||
protected readonly tenantsService = inject(TenantsService);
|
||||
protected storedTenants: IStoredTenantId[] = [];
|
||||
protected readonly titleService = inject(Title);
|
||||
protected readonly config = getConfig();
|
||||
protected readonly loadingService = inject(LoadingService);
|
||||
@ -32,6 +31,10 @@ export class TenantSelectComponent {
|
||||
});
|
||||
@Input() isLoggedOut = false;
|
||||
|
||||
constructor() {
|
||||
this.#loadStoredTenants();
|
||||
}
|
||||
|
||||
updateTenantSelection() {
|
||||
const tenantId = this.form.controls.tenantId.value;
|
||||
if (!tenantId) {
|
||||
@ -39,12 +42,10 @@ export class TenantSelectComponent {
|
||||
}
|
||||
|
||||
this.loadingService.start();
|
||||
|
||||
const email = this.#getEmail(tenantId);
|
||||
return this.select(tenantId, email);
|
||||
return this.select(tenantId);
|
||||
}
|
||||
|
||||
async select(tenantId: string, email?: string) {
|
||||
async select(tenantId: string) {
|
||||
try {
|
||||
this.logger.info('[KEYCLOAK] Initializing keycloak for tenant', tenantId);
|
||||
await this.keycloakService.init(getKeycloakOptions(this.baseHref, this.config, tenantId));
|
||||
@ -55,15 +56,18 @@ export class TenantSelectComponent {
|
||||
const url = this.keycloakService.getKeycloakInstance().createLoginUrl({
|
||||
redirectUri: this.keycloakStatusService.createLoginUrl(tenantId),
|
||||
idpHint: this.config.OAUTH_IDP_HINT,
|
||||
loginHint: email ?? undefined,
|
||||
});
|
||||
|
||||
this.logger.info('[KEYCLOAK] Init succeeded. Logout and redirect to', url);
|
||||
return this.keycloakService.logout(url);
|
||||
}
|
||||
|
||||
#getEmail(tenantId: string) {
|
||||
const existingStored = this.storedTenants.filter(s => s.tenantId === tenantId);
|
||||
return existingStored.length === 1 ? existingStored[0].email : undefined;
|
||||
removeStored(tenantId: string) {
|
||||
this.tenantsService.removeStored(tenantId);
|
||||
this.#loadStoredTenants();
|
||||
}
|
||||
|
||||
#loadStoredTenants() {
|
||||
this.storedTenants = this.tenantsService.getStoredTenants().sort((a, b) => a.tenantId.localeCompare(b.tenantId));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,20 +1,21 @@
|
||||
import { ModuleWithProviders, NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { HTTP_INTERCEPTORS } from '@angular/common/http';
|
||||
import { ModuleWithProviders, NgModule } from '@angular/core';
|
||||
import { ReactiveFormsModule } from '@angular/forms';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatCardModule } from '@angular/material/card';
|
||||
import { MatDialogModule } from '@angular/material/dialog';
|
||||
import { CircleButtonComponent, IconButtonComponent } from '../buttons';
|
||||
import { TenantSelectComponent } from './tenant-select/tenant-select.component';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatInputModule } from '@angular/material/input';
|
||||
import { MatSelectModule } from '@angular/material/select';
|
||||
import { ReactiveFormsModule } from '@angular/forms';
|
||||
import { TenantIdInterceptor, TenantIdResponseInterceptor } from './services';
|
||||
import { HTTP_INTERCEPTORS } from '@angular/common/http';
|
||||
import { MatCardModule } from '@angular/material/card';
|
||||
import { RouterLink } from '@angular/router';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { CircleButtonComponent, IconButtonComponent } from '../buttons';
|
||||
import { StopPropagationDirective } from '../directives';
|
||||
import { LogoComponent } from '../shared';
|
||||
import { SpacerComponent } from '../shared/spacer/spacer.component';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { RouterLink } from '@angular/router';
|
||||
import { TenantIdInterceptor, TenantIdResponseInterceptor } from './services';
|
||||
import { TenantSelectComponent } from './tenant-select/tenant-select.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [TenantSelectComponent],
|
||||
@ -33,6 +34,7 @@ import { RouterLink } from '@angular/router';
|
||||
MatIconModule,
|
||||
MatButtonModule,
|
||||
RouterLink,
|
||||
StopPropagationDirective,
|
||||
],
|
||||
exports: [TenantSelectComponent],
|
||||
})
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user