mirror of
https://github.com/andwati/zitadel.git
synced 2026-11-02 20:32:19 +00:00
fix(console): Idp settings, settings reset warn dialog, Accept-Language header interceptor, i18n (#3727)
* fix idp table, settings reset warn dialog, fix i18n interceptor, i18n * fix label policy on org change * fallback * fix preview button styles * footer, login-policy null check * org create btn alignment * show error with toast * error toast
This commit is contained in:
@@ -216,9 +216,9 @@ export class GrpcAuthService {
|
||||
* returns true if user has one of the provided roles
|
||||
* @param roles roles of the user
|
||||
*/
|
||||
public isAllowed(roles: string[] | RegExp[]): Observable<boolean> {
|
||||
public isAllowed(roles: string[] | RegExp[], requiresAll: boolean = false): Observable<boolean> {
|
||||
if (roles && roles.length > 0) {
|
||||
return this.zitadelPermissions.pipe(switchMap((zroles) => of(this.hasRoles(zroles, roles))));
|
||||
return this.zitadelPermissions.pipe(switchMap((zroles) => of(this.hasRoles(zroles, roles, requiresAll))));
|
||||
} else {
|
||||
return of(false);
|
||||
}
|
||||
@@ -228,17 +228,18 @@ export class GrpcAuthService {
|
||||
* returns true if user has one of the provided roles
|
||||
* @param userRoles roles of the user
|
||||
* @param requestedRoles required roles for accessing the respective component
|
||||
* @param requiresAll true - if all regexes must match, false - if only one regex must match
|
||||
*/
|
||||
public hasRoles(userRoles: string[], requestedRoles: string[] | RegExp[]): boolean {
|
||||
return (
|
||||
requestedRoles.findIndex((regexp: any) => {
|
||||
return (
|
||||
userRoles.findIndex((role) => {
|
||||
return new RegExp(regexp).test(role);
|
||||
}) > -1
|
||||
);
|
||||
}) > -1
|
||||
);
|
||||
public hasRoles(userRoles: string[], requestedRoles: string[] | RegExp[], requiresAll: boolean = false): boolean {
|
||||
const test = (reqRegexp: string | RegExp) =>
|
||||
userRoles.some((role) => {
|
||||
return new RegExp(reqRegexp).test(role);
|
||||
});
|
||||
|
||||
const allCheck = requestedRoles.map(test).every((x) => !!x);
|
||||
const oneCheck = requestedRoles.some(test);
|
||||
|
||||
return requiresAll ? allCheck : oneCheck;
|
||||
}
|
||||
|
||||
public getMyProfile(): Promise<GetMyProfileResponse.AsObject> {
|
||||
|
||||
@@ -2,6 +2,7 @@ import { PlatformLocation } from '@angular/common';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { AuthConfig } from 'angular-oauth2-oidc';
|
||||
|
||||
import { AdminServiceClient } from '../proto/generated/zitadel/AdminServiceClientPb';
|
||||
@@ -27,6 +28,7 @@ export class GrpcService {
|
||||
private authenticationService: AuthenticationService,
|
||||
private storageService: StorageService,
|
||||
private dialog: MatDialog,
|
||||
private translate: TranslateService,
|
||||
) {}
|
||||
|
||||
public async loadAppEnvironment(): Promise<any> {
|
||||
@@ -39,7 +41,7 @@ export class GrpcService {
|
||||
unaryInterceptors: [
|
||||
new OrgInterceptor(this.storageService),
|
||||
new AuthInterceptor(this.authenticationService, this.storageService, this.dialog),
|
||||
new I18nInterceptor(),
|
||||
new I18nInterceptor(this.translate),
|
||||
],
|
||||
};
|
||||
|
||||
|
||||
@@ -1,27 +1,29 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { Request, UnaryInterceptor, UnaryResponse } from 'grpc-web';
|
||||
|
||||
|
||||
const i18nHeader = 'Accept-Language';
|
||||
@Injectable({ providedIn: 'root' })
|
||||
/**
|
||||
* Set the navigator language as header to all grpc requests
|
||||
*/
|
||||
export class I18nInterceptor<TReq = unknown, TResp = unknown> implements UnaryInterceptor<TReq, TResp> {
|
||||
constructor() { }
|
||||
constructor(private translate: TranslateService) {}
|
||||
|
||||
public async intercept(request: Request<TReq, TResp>, invoker: any): Promise<UnaryResponse<TReq, TResp>> {
|
||||
const metadata = request.getMetadata();
|
||||
public async intercept(request: Request<TReq, TResp>, invoker: any): Promise<UnaryResponse<TReq, TResp>> {
|
||||
const metadata = request.getMetadata();
|
||||
|
||||
const navLang = navigator.language;
|
||||
if (navLang) {
|
||||
metadata[i18nHeader] = navLang;
|
||||
}
|
||||
|
||||
return invoker(request).then((response: any) => {
|
||||
return response;
|
||||
}).catch((error: any) => {
|
||||
return Promise.reject(error);
|
||||
});
|
||||
const navLang = this.translate.currentLang ?? navigator.language;
|
||||
if (navLang) {
|
||||
metadata[i18nHeader] = navLang;
|
||||
}
|
||||
|
||||
return invoker(request)
|
||||
.then((response: any) => {
|
||||
return response;
|
||||
})
|
||||
.catch((error: any) => {
|
||||
return Promise.reject(error);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,12 +98,6 @@ export class KeyboardShortcutsService implements OnDestroy {
|
||||
this.router.navigate(DOMAINS.link);
|
||||
}
|
||||
}
|
||||
|
||||
// if (secondKey.shiftKey && (secondKey.code === 'Digit7' || secondKey.key==='/')) {
|
||||
|
||||
// }
|
||||
|
||||
// SIDEWIDESHORTCUTS.f
|
||||
} else if (secondKey && exclude.indexOf(secondTagname?.toLowerCase()) === -1) {
|
||||
if (secondKey.key === '?') {
|
||||
this.openOverviewDialog();
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { BehaviorSubject, Observable } from 'rxjs';
|
||||
|
||||
import { ManagementService } from './mgmt.service';
|
||||
|
||||
declare const tinycolor: any;
|
||||
|
||||
export interface Color {
|
||||
@@ -19,7 +21,7 @@ export class ThemeService {
|
||||
private warnColorPalette: Color[] = [];
|
||||
private backgroundColorPalette: Color[] = [];
|
||||
|
||||
constructor() {
|
||||
constructor(private mgmtService: ManagementService) {
|
||||
const theme = localStorage.getItem('theme');
|
||||
if (theme) {
|
||||
if (theme === 'light-theme') {
|
||||
@@ -111,4 +113,97 @@ export class ThemeService {
|
||||
return '#ffffff';
|
||||
}
|
||||
}
|
||||
|
||||
public setDefaultColors = () => {
|
||||
const darkPrimary = '#bbbafa';
|
||||
const lightPrimary = '#5469d4';
|
||||
|
||||
const darkWarn = '#ff3b5b';
|
||||
const lightWarn = '#cd3d56';
|
||||
|
||||
const darkBackground = '#111827';
|
||||
const lightBackground = '#fafafa';
|
||||
|
||||
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);
|
||||
};
|
||||
|
||||
public loadPrivateLabelling(): void {
|
||||
this.setDefaultColors();
|
||||
|
||||
const isDark = (color: string) => this.isDark(color);
|
||||
const isLight = (color: string) => this.isLight(color);
|
||||
|
||||
this.mgmtService
|
||||
.getLabelPolicy()
|
||||
.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);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('could not load private labelling policy!', error);
|
||||
this.setDefaultColors();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user