mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-12 07:57:32 +00:00
fix(console): apply labelpolicy if icon is provided, signout page (#4499)
* label policy as observable * signedout policy via state * add caching * disable loading spinner on signedout * cleanup * catch error * update deps * move policy to localstorage * handle labelpolicy for users without org Co-authored-by: Livio Spring <livio.a@gmail.com> Co-authored-by: Fabi <38692350+hifabienne@users.noreply.github.com>
This commit is contained in:
@@ -5,7 +5,6 @@
|
||||
[org]="org"
|
||||
[user]="$any(user)"
|
||||
[isDarkTheme]="componentCssClass === 'dark-theme'"
|
||||
[labelpolicy]="labelpolicy"
|
||||
(changedActiveOrg)="changedOrg($event)"
|
||||
></cnsl-header>
|
||||
|
||||
@@ -17,7 +16,6 @@
|
||||
[org]="org"
|
||||
[user]="$any(user)"
|
||||
[isDarkTheme]="componentCssClass === 'dark-theme'"
|
||||
[labelpolicy]="labelpolicy"
|
||||
></cnsl-nav>
|
||||
</ng-container>
|
||||
|
||||
@@ -27,5 +25,5 @@
|
||||
</div>
|
||||
</div>
|
||||
<span class="fill-space"></span>
|
||||
<cnsl-footer [privateLabelPolicy]="labelpolicy"></cnsl-footer>
|
||||
<cnsl-footer></cnsl-footer>
|
||||
</div>
|
||||
|
@@ -8,11 +8,11 @@ import { DomSanitizer } from '@angular/platform-browser';
|
||||
import { ActivatedRoute, Router, RouterOutlet } from '@angular/router';
|
||||
import { LangChangeEvent, TranslateService } from '@ngx-translate/core';
|
||||
import { Observable, of, Subject } from 'rxjs';
|
||||
import { map, take, takeUntil } from 'rxjs/operators';
|
||||
import { map, takeUntil } from 'rxjs/operators';
|
||||
|
||||
import { accountCard, adminLineAnimation, navAnimations, routeAnimations, toolbarAnimation } from './animations';
|
||||
import { Org } from './proto/generated/zitadel/org_pb';
|
||||
import { LabelPolicy, PrivacyPolicy } from './proto/generated/zitadel/policy_pb';
|
||||
import { PrivacyPolicy } from './proto/generated/zitadel/policy_pb';
|
||||
import { AuthenticationService } from './services/authentication.service';
|
||||
import { GrpcAuthService } from './services/grpc-auth.service';
|
||||
import { KeyboardShortcutsService } from './services/keyboard-shortcuts/keyboard-shortcuts.service';
|
||||
@@ -47,7 +47,6 @@ export class AppComponent implements OnDestroy {
|
||||
public showProjectSection: boolean = false;
|
||||
|
||||
private destroy$: Subject<void> = new Subject();
|
||||
public labelpolicy: LabelPolicy.AsObject | undefined = undefined;
|
||||
|
||||
public language: string = 'en';
|
||||
public privacyPolicy!: PrivacyPolicy.AsObject;
|
||||
@@ -69,7 +68,6 @@ export class AppComponent implements OnDestroy {
|
||||
private activatedRoute: ActivatedRoute,
|
||||
@Inject(DOCUMENT) private document: Document,
|
||||
) {
|
||||
this.themeService.loadPrivateLabelling(true);
|
||||
console.log(
|
||||
'%cWait!',
|
||||
'text-shadow: -1px 0 black, 0 1px black, 1px 0 black, 0 -1px black; color: #5469D4; font-size: 50px',
|
||||
@@ -187,8 +185,10 @@ export class AppComponent implements OnDestroy {
|
||||
this.getProjectCount();
|
||||
|
||||
this.authService.activeOrgChanged.pipe(takeUntil(this.destroy$)).subscribe((org) => {
|
||||
this.org = org;
|
||||
this.getProjectCount();
|
||||
if (org) {
|
||||
this.org = org;
|
||||
this.getProjectCount();
|
||||
}
|
||||
});
|
||||
|
||||
this.authenticationService.authenticationChanged.pipe(takeUntil(this.destroy$)).subscribe((authenticated) => {
|
||||
@@ -197,10 +197,7 @@ export class AppComponent implements OnDestroy {
|
||||
.getActiveOrg()
|
||||
.then(async (org) => {
|
||||
this.org = org;
|
||||
const policy = await this.themeService.loadPrivateLabelling();
|
||||
if (policy) {
|
||||
this.labelpolicy = policy;
|
||||
}
|
||||
|
||||
// TODO add when console storage is implemented
|
||||
// this.startIntroWorkflow();
|
||||
})
|
||||
@@ -252,7 +249,6 @@ export class AppComponent implements OnDestroy {
|
||||
}
|
||||
|
||||
public changedOrg(org: Org.AsObject): void {
|
||||
this.themeService.loadPrivateLabelling();
|
||||
this.router.navigate(['/org']);
|
||||
}
|
||||
|
||||
|
@@ -64,6 +64,9 @@ export class AccountsCardComponent implements OnInit {
|
||||
}
|
||||
|
||||
public logout(): void {
|
||||
const lP = JSON.stringify(this.userService.labelpolicy.getValue());
|
||||
localStorage.setItem('labelPolicyOnSignout', lP);
|
||||
|
||||
this.authService.signout();
|
||||
this.closedCard.emit();
|
||||
}
|
||||
|
@@ -11,22 +11,24 @@
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="footer-socials" *ngIf="!privateLabelPolicy || privateLabelPolicy?.disableWatermark === false">
|
||||
<a target="_blank" rel="noreferrer" href="https://github.com/zitadel">
|
||||
<i class="text-3xl lab la-github"></i>
|
||||
</a>
|
||||
<a target="_blank" rel="noreferrer" href="https://twitter.com/zitadel">
|
||||
<i class="text-3xl lab la-twitter"></i>
|
||||
</a>
|
||||
<a target="_blank" rel="noreferrer" href="https://www.linkedin.com/company/zitadel/">
|
||||
<i class="text-3xl lab la-linkedin"></i>
|
||||
</a>
|
||||
<a target="_blank" rel="noreferrer" href="https://zitadel.com/chat">
|
||||
<i class="text-3xl lab la-discord"></i>
|
||||
</a>
|
||||
<a target="_blank" rel="noreferrer" href="https://www.youtube.com/channel/UCUAWJUNYaRn1yIVrZxEfsuA">
|
||||
<i class="text-3xl lab la-youtube"></i>
|
||||
</a>
|
||||
<div class="footer-socials" *ngIf="authService.labelpolicy | async as lP">
|
||||
<ng-container *ngIf="lP?.disableWatermark === false">
|
||||
<a target="_blank" rel="noreferrer" href="https://github.com/zitadel">
|
||||
<i class="text-3xl lab la-github"></i>
|
||||
</a>
|
||||
<a target="_blank" rel="noreferrer" href="https://twitter.com/zitadel">
|
||||
<i class="text-3xl lab la-twitter"></i>
|
||||
</a>
|
||||
<a target="_blank" rel="noreferrer" href="https://www.linkedin.com/company/zitadel/">
|
||||
<i class="text-3xl lab la-linkedin"></i>
|
||||
</a>
|
||||
<a target="_blank" rel="noreferrer" href="https://zitadel.com/chat">
|
||||
<i class="text-3xl lab la-discord"></i>
|
||||
</a>
|
||||
<a target="_blank" rel="noreferrer" href="https://www.youtube.com/channel/UCUAWJUNYaRn1yIVrZxEfsuA">
|
||||
<i class="text-3xl lab la-youtube"></i>
|
||||
</a>
|
||||
</ng-container>
|
||||
</div>
|
||||
|
||||
<div class="theme">
|
||||
|
@@ -9,8 +9,7 @@ import { GrpcAuthService } from 'src/app/services/grpc-auth.service';
|
||||
})
|
||||
export class FooterComponent {
|
||||
public policy?: PrivacyPolicy.AsObject;
|
||||
@Input() public privateLabelPolicy?: LabelPolicy.AsObject;
|
||||
constructor(authService: GrpcAuthService) {
|
||||
constructor(public authService: GrpcAuthService) {
|
||||
authService.getMyPrivacyPolicy().then((policyResp) => {
|
||||
if (policyResp.policy) {
|
||||
this.policy = policyResp.policy;
|
||||
|
@@ -1,26 +1,27 @@
|
||||
<mat-toolbar class="header-wrapper">
|
||||
<div class="header-content">
|
||||
<a
|
||||
class="title custom"
|
||||
[routerLink]="['/']"
|
||||
*ngIf="org && labelpolicy && labelpolicy.disableWatermark; else defaultHome"
|
||||
>
|
||||
<img
|
||||
class="logo"
|
||||
alt="home logo"
|
||||
*ngIf="isDarkTheme; else customlighttheme"
|
||||
[src]="labelpolicy.iconUrlDark ? labelpolicy.iconUrlDark : './assets/images/zitadel-logo-solo-light.svg'"
|
||||
(error)="errorHandler($event, './assets/images/zitadel-logo-solo-light.svg')"
|
||||
/>
|
||||
<ng-template #customlighttheme>
|
||||
<div *ngIf="authService.labelPolicyLoading$ | async; else logo" class="logo-placeholder">
|
||||
<mat-spinner [diameter]="20"></mat-spinner>
|
||||
</div>
|
||||
<ng-template #logo>
|
||||
<a class="title custom" [routerLink]="['/']" *ngIf="authService.labelpolicy | async as lP; else defaultHome">
|
||||
<img
|
||||
alt="home logo"
|
||||
class="logo"
|
||||
[src]="labelpolicy.iconUrl ? labelpolicy.iconUrl : './assets/images/zitadel-logo-solo-dark.svg'"
|
||||
(error)="errorHandler($event, './assets/images/zitadel-logo-solo-dark.svg')"
|
||||
alt="home logo"
|
||||
*ngIf="isDarkTheme; else customlighttheme"
|
||||
[src]="lP.iconUrlDark ? lP.iconUrlDark : './assets/images/zitadel-logo-solo-light.svg'"
|
||||
(error)="errorHandler($event, './assets/images/zitadel-logo-solo-light.svg')"
|
||||
/>
|
||||
</ng-template>
|
||||
</a>
|
||||
<ng-template #customlighttheme>
|
||||
<img
|
||||
alt="home logo"
|
||||
class="logo"
|
||||
[src]="lP.iconUrl ? lP.iconUrl : './assets/images/zitadel-logo-solo-dark.svg'"
|
||||
(error)="errorHandler($event, './assets/images/zitadel-logo-solo-dark.svg')"
|
||||
/>
|
||||
</ng-template>
|
||||
</a>
|
||||
</ng-template>
|
||||
|
||||
<ng-template #defaultHome>
|
||||
<a class="title" [routerLink]="authService.zitadelPermissions.getValue().length === 0 ? ['/users', 'me'] : ['/']">
|
||||
|
@@ -181,6 +181,16 @@
|
||||
}
|
||||
}
|
||||
|
||||
.logo-placeholder {
|
||||
height: 40px;
|
||||
width: 40px;
|
||||
border-radius: 50%;
|
||||
background-color: if($is-dark-theme, #00000020, #00000010);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.title {
|
||||
text-decoration: none;
|
||||
color: white;
|
||||
|
@@ -22,7 +22,6 @@ export class HeaderComponent implements OnDestroy {
|
||||
|
||||
@Input() public isDarkTheme: boolean = true;
|
||||
@Input() public user?: User.AsObject;
|
||||
@Input() public labelpolicy?: LabelPolicy.AsObject;
|
||||
public showOrgContext: boolean = false;
|
||||
|
||||
public orgs$: Observable<Org.AsObject[]> = of([]);
|
||||
|
@@ -6,10 +6,10 @@ import { UntypedFormControl } from '@angular/forms';
|
||||
import { Router } from '@angular/router';
|
||||
import { BehaviorSubject, map, Observable, Subject, take } from 'rxjs';
|
||||
import { Org } from 'src/app/proto/generated/zitadel/org_pb';
|
||||
import { LabelPolicy } from 'src/app/proto/generated/zitadel/policy_pb';
|
||||
import { User } from 'src/app/proto/generated/zitadel/user_pb';
|
||||
import { AuthenticationService } from 'src/app/services/authentication.service';
|
||||
import { BreadcrumbService, BreadcrumbType } from 'src/app/services/breadcrumb.service';
|
||||
import { GrpcAuthService } from 'src/app/services/grpc-auth.service';
|
||||
import { KeyboardShortcutsService } from 'src/app/services/keyboard-shortcuts/keyboard-shortcuts.service';
|
||||
import { ManagementService } from 'src/app/services/mgmt.service';
|
||||
|
||||
@@ -73,7 +73,6 @@ export class NavComponent implements OnDestroy {
|
||||
|
||||
@Input() public isDarkTheme: boolean = true;
|
||||
@Input() public user!: User.AsObject;
|
||||
@Input() public labelpolicy?: LabelPolicy.AsObject;
|
||||
public isHandset$: Observable<boolean> = this.breakpointObserver.observe('(max-width: 599px)').pipe(
|
||||
map((result) => {
|
||||
return result.matches;
|
||||
@@ -91,6 +90,7 @@ export class NavComponent implements OnDestroy {
|
||||
public customerPortalLink: string = '';
|
||||
|
||||
constructor(
|
||||
public authService: GrpcAuthService,
|
||||
public authenticationService: AuthenticationService,
|
||||
public breadcrumbService: BreadcrumbService,
|
||||
public mgmtService: ManagementService,
|
||||
|
@@ -57,7 +57,6 @@ export class OrgTableComponent {
|
||||
private router: Router,
|
||||
private toast: ToastService,
|
||||
private _liveAnnouncer: LiveAnnouncer,
|
||||
private themeService: ThemeService,
|
||||
) {
|
||||
this.requestOrgs$.next({ limit: this.initialLimit, offset: 0, queries: this.searchQueries });
|
||||
this.authService.getActiveOrg().then((org) => (this.activeOrg = org));
|
||||
@@ -137,7 +136,6 @@ export class OrgTableComponent {
|
||||
|
||||
public setAndNavigateToOrg(org: Org.AsObject): void {
|
||||
this.authService.setActiveOrg(org);
|
||||
this.themeService.loadPrivateLabelling();
|
||||
this.router.navigate(['/org']);
|
||||
}
|
||||
|
||||
|
@@ -1,13 +1,23 @@
|
||||
<div class="signed-out-wrap">
|
||||
<div class="block">
|
||||
<div class="signed-out-header">
|
||||
<img alt="zitadel logo" *ngIf="dark; else lighttheme" src="./assets/images/zitadel-logo-light.svg" />
|
||||
<ng-template #lighttheme>
|
||||
<img alt="zitadel logo" src="./assets/images/zitadel-logo-dark.svg" />
|
||||
<ng-container *ngIf="labelpolicy; else zitadelLogo">
|
||||
<img alt="logo" *ngIf="dark && labelpolicy.logoUrlDark; else lighttheme" [src]="labelpolicy.logoUrlDark" />
|
||||
<ng-template #lighttheme>
|
||||
<img *ngIf="labelpolicy.logoUrl; else zitadelLogo" alt="logo" [src]="labelpolicy.logoUrl" />
|
||||
</ng-template>
|
||||
</ng-container>
|
||||
|
||||
<ng-template #zitadelLogo>
|
||||
<img alt="zitadel logo" *ngIf="dark; else zitadellighttheme" src="./assets/images/zitadel-logo-light.svg" />
|
||||
<ng-template #zitadellighttheme>
|
||||
<img alt="zitadel logo" src="./assets/images/zitadel-logo-dark.svg" />
|
||||
</ng-template>
|
||||
</ng-template>
|
||||
|
||||
<p class="cnsl-secondary-text">{{ 'USER.SIGNEDOUT' | translate }}</p>
|
||||
|
||||
<button
|
||||
<a
|
||||
class="cnsl-action-button"
|
||||
matTooltip="{{ 'ACTIONS.LOGIN' | translate }}"
|
||||
color="primary"
|
||||
@@ -16,7 +26,7 @@
|
||||
>
|
||||
<i class="las la-sign-in-alt"></i>
|
||||
<span>{{ 'USER.SIGNEDOUT_BTN' | translate }}</span>
|
||||
</button>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@@ -18,8 +18,7 @@
|
||||
p {
|
||||
text-align: center;
|
||||
font-size: 14px;
|
||||
margin: 0;
|
||||
margin-bottom: 3rem;
|
||||
margin: 2rem 0 3rem 0;
|
||||
}
|
||||
|
||||
img {
|
||||
|
@@ -1,5 +1,8 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { LabelPolicy } from 'src/app/proto/generated/zitadel/policy_pb';
|
||||
import { GrpcAuthService } from 'src/app/services/grpc-auth.service';
|
||||
import { ThemeService } from 'src/app/services/theme.service';
|
||||
const LABELPOLICY_LOCALSTORAGE_KEY = 'labelPolicyOnSignout';
|
||||
|
||||
@Component({
|
||||
selector: 'cnsl-signedout',
|
||||
@@ -9,10 +12,25 @@ import { ThemeService } from 'src/app/services/theme.service';
|
||||
export class SignedoutComponent {
|
||||
public dark: boolean = true;
|
||||
|
||||
constructor(themeService: ThemeService) {
|
||||
themeService.loadPrivateLabelling();
|
||||
|
||||
public labelpolicy?: LabelPolicy.AsObject;
|
||||
public queryParams = { state: '' };
|
||||
constructor(themeService: ThemeService, authService: GrpcAuthService) {
|
||||
const theme = localStorage.getItem('theme');
|
||||
this.dark = theme === 'dark-theme' ? true : theme === 'light-theme' ? false : true;
|
||||
|
||||
const lP = localStorage.getItem(LABELPOLICY_LOCALSTORAGE_KEY);
|
||||
|
||||
if (lP) {
|
||||
const parsed = JSON.parse(lP);
|
||||
localStorage.removeItem(LABELPOLICY_LOCALSTORAGE_KEY);
|
||||
if (parsed) {
|
||||
this.labelpolicy = parsed;
|
||||
themeService.applyLabelPolicy(parsed);
|
||||
authService.labelpolicy.next(parsed);
|
||||
authService.labelPolicyLoading$.next(false);
|
||||
}
|
||||
} else {
|
||||
authService.labelPolicyLoading$.next(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,6 +1,7 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { AuthConfig, OAuthService } from 'angular-oauth2-oidc';
|
||||
import { BehaviorSubject, from, lastValueFrom, Observable } from 'rxjs';
|
||||
import { GrpcAuthService } from './grpc-auth.service';
|
||||
|
||||
import { StatehandlerService } from './statehandler/statehandler.service';
|
||||
|
||||
|
@@ -9,8 +9,10 @@ import {
|
||||
finalize,
|
||||
map,
|
||||
mergeMap,
|
||||
pairwise,
|
||||
switchMap,
|
||||
take,
|
||||
tap,
|
||||
timeout,
|
||||
withLatestFrom,
|
||||
} from 'rxjs/operators';
|
||||
@@ -103,15 +105,17 @@ import { ChangeQuery } from '../proto/generated/zitadel/change_pb';
|
||||
import { MetadataQuery } from '../proto/generated/zitadel/metadata_pb';
|
||||
import { ListQuery } from '../proto/generated/zitadel/object_pb';
|
||||
import { Org, OrgFieldName, OrgQuery } from '../proto/generated/zitadel/org_pb';
|
||||
import { LabelPolicy } from '../proto/generated/zitadel/policy_pb';
|
||||
import { Gender, MembershipQuery, User, WebAuthNVerification } from '../proto/generated/zitadel/user_pb';
|
||||
import { GrpcService } from './grpc.service';
|
||||
import { StorageKey, StorageLocation, StorageService } from './storage.service';
|
||||
import { ThemeService } from './theme.service';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class GrpcAuthService {
|
||||
private _activeOrgChanged: Subject<Org.AsObject> = new Subject();
|
||||
private _activeOrgChanged: Subject<Org.AsObject | undefined> = new Subject();
|
||||
public user!: Observable<User.AsObject | undefined>;
|
||||
public userSubject: BehaviorSubject<User.AsObject | undefined> = new BehaviorSubject<User.AsObject | undefined>(undefined);
|
||||
private triggerPermissionsRefresh: Subject<void> = new Subject();
|
||||
@@ -132,18 +136,47 @@ export class GrpcAuthService {
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
public labelpolicy$!: Observable<LabelPolicy.AsObject>;
|
||||
public labelpolicy: BehaviorSubject<LabelPolicy.AsObject | undefined> = new BehaviorSubject<
|
||||
LabelPolicy.AsObject | undefined
|
||||
>(undefined);
|
||||
labelPolicyLoading$: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(true);
|
||||
|
||||
public zitadelPermissions: BehaviorSubject<string[]> = new BehaviorSubject<string[]>([]);
|
||||
public readonly fetchedZitadelPermissions: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
|
||||
|
||||
private cachedOrgs: Org.AsObject[] = [];
|
||||
private cachedLabelPolicies: { [orgId: string]: LabelPolicy.AsObject } = {};
|
||||
|
||||
constructor(
|
||||
private readonly grpcService: GrpcService,
|
||||
private oauthService: OAuthService,
|
||||
private storage: StorageService,
|
||||
themeService: ThemeService,
|
||||
) {
|
||||
this.zitadelPermissions$.subscribe(this.zitadelPermissions);
|
||||
|
||||
this.labelpolicy$ = this.activeOrgChanged.pipe(
|
||||
switchMap((org) => {
|
||||
this.labelPolicyLoading$.next(true);
|
||||
return from(this.getMyLabelPolicy(org ? org.id : ''));
|
||||
}),
|
||||
filter((policy) => !!policy),
|
||||
);
|
||||
|
||||
this.labelpolicy$.subscribe({
|
||||
next: (policy) => {
|
||||
themeService.applyLabelPolicy(policy);
|
||||
this.labelpolicy.next(policy);
|
||||
this.labelPolicyLoading$.next(false);
|
||||
},
|
||||
error: (error) => {
|
||||
console.error(error);
|
||||
this.labelPolicyLoading$.next(false);
|
||||
},
|
||||
});
|
||||
|
||||
this.user = merge(
|
||||
of(this.oauthService.getAccessToken()).pipe(filter((token) => (token ? true : false))),
|
||||
this.oauthService.events.pipe(
|
||||
@@ -225,10 +258,12 @@ export class GrpcAuthService {
|
||||
const org = this.storage.getItem<Org.AsObject>(StorageKey.organization, StorageLocation.local);
|
||||
if (org && orgs.find((tmp) => tmp.id === org.id)) {
|
||||
this.storage.setItem(StorageKey.organization, org, StorageLocation.session);
|
||||
return org;
|
||||
this.setActiveOrg(org);
|
||||
return Promise.resolve(org);
|
||||
}
|
||||
|
||||
if (orgs.length === 0) {
|
||||
this._activeOrgChanged.next(undefined);
|
||||
return Promise.reject(new Error('No organizations found!'));
|
||||
}
|
||||
const orgToSet = orgs.find((element) => element.id !== '0' && element.name !== '');
|
||||
@@ -241,7 +276,7 @@ export class GrpcAuthService {
|
||||
}
|
||||
}
|
||||
|
||||
public get activeOrgChanged(): Observable<Org.AsObject> {
|
||||
public get activeOrgChanged(): Observable<Org.AsObject | undefined> {
|
||||
return this._activeOrgChanged;
|
||||
}
|
||||
|
||||
@@ -605,8 +640,24 @@ export class GrpcAuthService {
|
||||
return this.grpcService.auth.listMyUserChanges(req, null).then((resp) => resp.toObject());
|
||||
}
|
||||
|
||||
public getMyLabelPolicy(): Promise<GetMyLabelPolicyResponse.AsObject> {
|
||||
return this.grpcService.auth.getMyLabelPolicy(new GetMyLabelPolicyRequest(), null).then((resp) => resp.toObject());
|
||||
public getMyLabelPolicy(orgIdForCache?: string): Promise<LabelPolicy.AsObject> {
|
||||
if (orgIdForCache && this.cachedLabelPolicies[orgIdForCache]) {
|
||||
return Promise.resolve(this.cachedLabelPolicies[orgIdForCache]);
|
||||
} else {
|
||||
return this.grpcService.auth
|
||||
.getMyLabelPolicy(new GetMyLabelPolicyRequest(), null)
|
||||
.then((resp) => resp.toObject())
|
||||
.then((resp) => {
|
||||
if (resp.policy) {
|
||||
if (orgIdForCache) {
|
||||
this.cachedLabelPolicies[orgIdForCache] = resp.policy;
|
||||
}
|
||||
return Promise.resolve(resp.policy);
|
||||
} else {
|
||||
return Promise.reject();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public getMyPrivacyPolicy(): Promise<GetMyPrivacyPolicyResponse.AsObject> {
|
||||
|
@@ -13,16 +13,28 @@ export interface Color {
|
||||
contrastColor: string;
|
||||
}
|
||||
|
||||
const DARK_PRIMARY = '#bbbafa';
|
||||
const PRIMARY = '#5469d4';
|
||||
|
||||
const DARK_WARN = '#ff3b5b';
|
||||
const WARN = '#cd3d56';
|
||||
|
||||
const DARK_BACKGROUND = '#111827';
|
||||
const BACKGROUND = '#fafafa';
|
||||
|
||||
const DARK_TEXT = '#ffffff';
|
||||
const TEXT = '#000000';
|
||||
|
||||
@Injectable()
|
||||
export class ThemeService {
|
||||
private _darkTheme: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(true);
|
||||
public isDarkTheme: Observable<boolean> = this._darkTheme.asObservable();
|
||||
|
||||
public loading: boolean = false;
|
||||
private primaryColorPalette: Color[] = [];
|
||||
private warnColorPalette: Color[] = [];
|
||||
private backgroundColorPalette: Color[] = [];
|
||||
|
||||
constructor(private authService: GrpcAuthService) {
|
||||
constructor() {
|
||||
const theme = localStorage.getItem('theme');
|
||||
if (theme) {
|
||||
if (theme === 'light-theme') {
|
||||
@@ -31,6 +43,7 @@ export class ThemeService {
|
||||
this.setDarkTheme(true);
|
||||
}
|
||||
}
|
||||
this.applyLabelPolicy(); // apply default
|
||||
}
|
||||
|
||||
setDarkTheme(isDarkTheme: boolean): void {
|
||||
@@ -116,105 +129,68 @@ export class ThemeService {
|
||||
}
|
||||
|
||||
public setDefaultColors = () => {
|
||||
const darkPrimary = '#bbbafa';
|
||||
const lightPrimary = '#5469d4';
|
||||
this.savePrimaryColor(DARK_PRIMARY, true);
|
||||
this.savePrimaryColor(PRIMARY, false);
|
||||
|
||||
const darkWarn = '#ff3b5b';
|
||||
const lightWarn = '#cd3d56';
|
||||
this.saveWarnColor(DARK_WARN, true);
|
||||
this.saveWarnColor(WARN, false);
|
||||
|
||||
const darkBackground = '#111827';
|
||||
const lightBackground = '#fafafa';
|
||||
this.saveBackgroundColor(DARK_BACKGROUND, true);
|
||||
this.saveBackgroundColor(BACKGROUND, false);
|
||||
|
||||
const darkText = '#ffffff';
|
||||
const lightText = '#000000';
|
||||
|
||||
this.savePrimaryColor(darkPrimary, true);
|
||||
this.savePrimaryColor(lightPrimary, false);
|
||||
|
||||
this.saveWarnColor(darkWarn, true);
|
||||
this.saveWarnColor(lightWarn, false);
|
||||
|
||||
this.saveBackgroundColor(darkBackground, true);
|
||||
this.saveBackgroundColor(lightBackground, false);
|
||||
|
||||
this.saveTextColor(darkText, true);
|
||||
this.saveTextColor(lightText, false);
|
||||
this.saveTextColor(DARK_TEXT, true);
|
||||
this.saveTextColor(TEXT, false);
|
||||
};
|
||||
|
||||
public loadPrivateLabelling(forceDefault: boolean = false): Promise<LabelPolicy.AsObject | undefined> {
|
||||
if (forceDefault) {
|
||||
this.setDefaultColors();
|
||||
return Promise.resolve(undefined);
|
||||
public applyLabelPolicy(labelpolicy?: LabelPolicy.AsObject) {
|
||||
if (labelpolicy) {
|
||||
const darkPrimary = labelpolicy?.primaryColorDark ?? DARK_PRIMARY;
|
||||
const lightPrimary = labelpolicy?.primaryColor ?? PRIMARY;
|
||||
|
||||
const darkWarn = labelpolicy?.warnColorDark ?? DARK_WARN;
|
||||
const lightWarn = labelpolicy?.warnColor ?? WARN;
|
||||
|
||||
let darkBackground = labelpolicy?.backgroundColorDark ?? DARK_BACKGROUND;
|
||||
let lightBackground = labelpolicy?.backgroundColor ?? BACKGROUND;
|
||||
|
||||
let darkText = labelpolicy?.fontColorDark ?? DARK_TEXT;
|
||||
let lightText = labelpolicy?.fontColor ?? TEXT;
|
||||
|
||||
this.savePrimaryColor(darkPrimary, true);
|
||||
this.savePrimaryColor(lightPrimary, false);
|
||||
|
||||
this.saveWarnColor(darkWarn, true);
|
||||
this.saveWarnColor(lightWarn, false);
|
||||
|
||||
if (darkBackground && !this.isDark(darkBackground)) {
|
||||
console.info(
|
||||
`Background (${darkBackground}) is not dark enough for a dark theme. Falling back to zitadel background`,
|
||||
);
|
||||
darkBackground = '#111827';
|
||||
}
|
||||
this.saveBackgroundColor(darkBackground || '#111827', true);
|
||||
|
||||
if (lightBackground && !this.isLight(lightBackground)) {
|
||||
console.info(
|
||||
`Background (${lightBackground}) is not light enough for a light theme. Falling back to zitadel background`,
|
||||
);
|
||||
lightBackground = '#fafafa';
|
||||
}
|
||||
this.saveBackgroundColor(lightBackground || '#fafafa', false);
|
||||
|
||||
if (darkText && !this.isLight(darkText)) {
|
||||
console.info(`Text color (${darkText}) is not light enough for a dark theme. Falling back to zitadel's text color`);
|
||||
darkText = '#ffffff';
|
||||
}
|
||||
this.saveTextColor(darkText || '#ffffff', true);
|
||||
|
||||
if (lightText && !this.isDark(lightText)) {
|
||||
console.info(`Text color (${lightText}) is not dark enough for a light theme. Falling back to zitadel's text color`);
|
||||
lightText = '#000000';
|
||||
}
|
||||
this.saveTextColor(lightText || '#000000', false);
|
||||
} else {
|
||||
const isDark = (color: string) => this.isDark(color);
|
||||
const isLight = (color: string) => this.isLight(color);
|
||||
|
||||
return this.authService
|
||||
.getMyLabelPolicy()
|
||||
.then((lpresp) => {
|
||||
const labelpolicy = lpresp.policy;
|
||||
|
||||
const darkPrimary = labelpolicy?.primaryColorDark || '#bbbafa';
|
||||
const lightPrimary = labelpolicy?.primaryColor || '#5469d4';
|
||||
|
||||
const darkWarn = labelpolicy?.warnColorDark || '#ff3b5b';
|
||||
const lightWarn = labelpolicy?.warnColor || '#cd3d56';
|
||||
|
||||
let darkBackground = labelpolicy?.backgroundColorDark;
|
||||
let lightBackground = labelpolicy?.backgroundColor;
|
||||
|
||||
let darkText = labelpolicy?.fontColorDark ?? '#ffffff';
|
||||
let lightText = labelpolicy?.fontColor ?? '#000000';
|
||||
|
||||
this.savePrimaryColor(darkPrimary, true);
|
||||
this.savePrimaryColor(lightPrimary, false);
|
||||
|
||||
this.saveWarnColor(darkWarn, true);
|
||||
this.saveWarnColor(lightWarn, false);
|
||||
|
||||
if (darkBackground && !isDark(darkBackground)) {
|
||||
console.info(
|
||||
`Background (${darkBackground}) is not dark enough for a dark theme. Falling back to zitadel background`,
|
||||
);
|
||||
darkBackground = '#111827';
|
||||
}
|
||||
this.saveBackgroundColor(darkBackground || '#111827', true);
|
||||
|
||||
if (lightBackground && !isLight(lightBackground)) {
|
||||
console.info(
|
||||
`Background (${lightBackground}) is not light enough for a light theme. Falling back to zitadel background`,
|
||||
);
|
||||
lightBackground = '#fafafa';
|
||||
}
|
||||
this.saveBackgroundColor(lightBackground || '#fafafa', false);
|
||||
|
||||
if (darkText && !isLight(darkText)) {
|
||||
console.info(
|
||||
`Text color (${darkText}) is not light enough for a dark theme. Falling back to zitadel's text color`,
|
||||
);
|
||||
darkText = '#ffffff';
|
||||
}
|
||||
this.saveTextColor(darkText || '#ffffff', true);
|
||||
|
||||
if (lightText && !isDark(lightText)) {
|
||||
console.info(
|
||||
`Text color (${lightText}) is not dark enough for a light theme. Falling back to zitadel's text color`,
|
||||
);
|
||||
lightText = '#000000';
|
||||
}
|
||||
this.saveTextColor(lightText || '#000000', false);
|
||||
|
||||
if (labelpolicy) {
|
||||
return labelpolicy;
|
||||
} else {
|
||||
return Promise.reject();
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('could not load private labelling policy!', error);
|
||||
this.setDefaultColors();
|
||||
return Promise.reject();
|
||||
});
|
||||
this.setDefaultColors();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user