fix(console): new colorpicker, remove icons logo font (#1826)

* custom color picker, delete font

* delete asset, i18n

* escape deep styles

* ts, proto

* remove fallback img, color clickable, remove font

* stylelint

* fix spinner

* fix deprecated chipinput.input

* improve logo on login

* fix qr code

* always use black on white for qr code

* fix header and footer css

Co-authored-by: Livio Amstutz <livio.a@gmail.com>
This commit is contained in:
Max Peintner 2021-06-09 11:55:16 +02:00 committed by GitHub
parent 255139862d
commit 59af02b2f3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 1242 additions and 933 deletions

View File

@ -34,6 +34,7 @@
"grpc-web": "^1.2.1",
"libphonenumber-js": "^1.9.16",
"moment": "^2.29.1",
"ngx-color": "^7.0.0",
"ngx-quicklink": "^0.2.6",
"rxjs": "~6.6.7",
"ts-protoc-gen": "^0.14.0",
@ -2915,6 +2916,14 @@
"node": ">=4.0.0"
}
},
"node_modules/@ctrl/tinycolor": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-3.4.0.tgz",
"integrity": "sha512-JZButFdZ1+/xAfpguQHoabIXkcqRRKpMrWKBkpEZZyxfY9C1DpADFB8PEqGSTeFr135SaTRfKqGKx5xSCLI7ZQ==",
"engines": {
"node": ">=10"
}
},
"node_modules/@discoveryjs/json-ext": {
"version": "0.5.2",
"resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.2.tgz",
@ -10058,6 +10067,11 @@
"node": ">=0.10.0"
}
},
"node_modules/material-colors": {
"version": "1.2.6",
"resolved": "https://registry.npmjs.org/material-colors/-/material-colors-1.2.6.tgz",
"integrity": "sha512-6qE4B9deFBIa9YSpOc9O0Sgc43zTeVYbgDT5veRKSlB2+ZuHNoVVxA1L/ckMUayV9Ay9y7Z/SZCLcGteW9i7bg=="
},
"node_modules/mathml-tag-names": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/mathml-tag-names/-/mathml-tag-names-2.1.3.tgz",
@ -10690,6 +10704,20 @@
"integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==",
"dev": true
},
"node_modules/ngx-color": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/ngx-color/-/ngx-color-7.0.0.tgz",
"integrity": "sha512-BiTapBTT/f3sFSEFqet3xe06bpqmBm7hmA24s09ogRYYVGL1J69U13XfLwTQG8PhX4qNBceh7p5nhKA1zczHMg==",
"dependencies": {
"@ctrl/tinycolor": "^3.4.0",
"material-colors": "^1.2.6",
"tslib": "^2.1.0"
},
"peerDependencies": {
"@angular/common": ">=12.0.0-0",
"@angular/core": ">=12.0.0-0"
}
},
"node_modules/ngx-quicklink": {
"version": "0.2.6",
"resolved": "https://registry.npmjs.org/ngx-quicklink/-/ngx-quicklink-0.2.6.tgz",
@ -19366,6 +19394,11 @@
"integrity": "sha512-5a6wqoJV/xEdbRNKVo6I4hO3VjyDq//8q2f9I6PBAvMesJHFauXDorcNCsr9RzvsZnaWi5NYCcfyqP1QeFHFbw==",
"dev": true
},
"@ctrl/tinycolor": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-3.4.0.tgz",
"integrity": "sha512-JZButFdZ1+/xAfpguQHoabIXkcqRRKpMrWKBkpEZZyxfY9C1DpADFB8PEqGSTeFr135SaTRfKqGKx5xSCLI7ZQ=="
},
"@discoveryjs/json-ext": {
"version": "0.5.2",
"resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.2.tgz",
@ -25200,6 +25233,11 @@
"object-visit": "^1.0.0"
}
},
"material-colors": {
"version": "1.2.6",
"resolved": "https://registry.npmjs.org/material-colors/-/material-colors-1.2.6.tgz",
"integrity": "sha512-6qE4B9deFBIa9YSpOc9O0Sgc43zTeVYbgDT5veRKSlB2+ZuHNoVVxA1L/ckMUayV9Ay9y7Z/SZCLcGteW9i7bg=="
},
"mathml-tag-names": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/mathml-tag-names/-/mathml-tag-names-2.1.3.tgz",
@ -25710,6 +25748,16 @@
"integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==",
"dev": true
},
"ngx-color": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/ngx-color/-/ngx-color-7.0.0.tgz",
"integrity": "sha512-BiTapBTT/f3sFSEFqet3xe06bpqmBm7hmA24s09ogRYYVGL1J69U13XfLwTQG8PhX4qNBceh7p5nhKA1zczHMg==",
"requires": {
"@ctrl/tinycolor": "^3.4.0",
"material-colors": "^1.2.6",
"tslib": "^2.1.0"
}
},
"ngx-quicklink": {
"version": "0.2.6",
"resolved": "https://registry.npmjs.org/ngx-quicklink/-/ngx-quicklink-0.2.6.tgz",

View File

@ -37,6 +37,7 @@
"grpc-web": "^1.2.1",
"libphonenumber-js": "^1.9.16",
"moment": "^2.29.1",
"ngx-color": "^7.0.0",
"ngx-quicklink": "^0.2.6",
"rxjs": "~6.6.7",
"ts-protoc-gen": "^0.14.0",

View File

@ -25,8 +25,8 @@ import { QuicklinkModule } from 'ngx-quicklink';
import { from, Observable } from 'rxjs';
import { OnboardingModule } from 'src/app/modules/onboarding/onboarding.module';
import { RegExpPipeModule } from 'src/app/pipes/regexp-pipe/regexp-pipe.module';
import { AssetService } from 'src/app/services/asset.service';
import { SubscriptionService } from 'src/app/services/subscription.service';
import { UploadService } from 'src/app/services/upload.service';
import { environment } from '../environments/environment';
import { AppRoutingModule } from './app-routing.module';
@ -181,7 +181,7 @@ const authConfig: AuthConfig = {
AuthenticationService,
GrpcAuthService,
SubscriptionService,
UploadService,
AssetService,
{ provide: 'windowObject', useValue: window },
],
bootstrap: [AppComponent],

View File

@ -16,171 +16,171 @@ import { ToastService } from 'src/app/services/toast.service';
import { PolicyComponentServiceType } from '../policies/policy-component-types.enum';
@Component({
selector: 'app-idp-create',
templateUrl: './idp-create.component.html',
styleUrls: ['./idp-create.component.scss'],
selector: 'app-idp-create',
templateUrl: './idp-create.component.html',
styleUrls: ['./idp-create.component.scss'],
})
export class IdpCreateComponent implements OnInit, OnDestroy {
public serviceType: PolicyComponentServiceType = PolicyComponentServiceType.MGMT;
private service!: ManagementService | AdminService;
public readonly separatorKeysCodes: number[] = [ENTER, COMMA, SPACE];
public mappingFields: OIDCMappingField[] = [];
public serviceType: PolicyComponentServiceType = PolicyComponentServiceType.MGMT;
private service!: ManagementService | AdminService;
public readonly separatorKeysCodes: number[] = [ENTER, COMMA, SPACE];
public mappingFields: OIDCMappingField[] = [];
private subscription?: Subscription;
public projectId: string = '';
private subscription?: Subscription;
public projectId: string = '';
public formGroup!: FormGroup;
public createSteps: number = 1;
public currentCreateStep: number = 1;
public loading: boolean = false;
constructor(
private router: Router,
private route: ActivatedRoute,
private toast: ToastService,
private injector: Injector,
private _location: Location,
) {
this.formGroup = new FormGroup({
name: new FormControl('', [Validators.required]),
clientId: new FormControl('', [Validators.required]),
clientSecret: new FormControl('', [Validators.required]),
issuer: new FormControl('', [Validators.required]),
scopesList: new FormControl(['openid', 'profile', 'email'], []),
idpDisplayNameMapping: new FormControl(0),
usernameMapping: new FormControl(0),
});
public formGroup!: FormGroup;
public createSteps: number = 1;
public currentCreateStep: number = 1;
public loading: boolean = false;
constructor(
private router: Router,
private route: ActivatedRoute,
private toast: ToastService,
private injector: Injector,
private _location: Location,
) {
this.formGroup = new FormGroup({
name: new FormControl('', [Validators.required]),
clientId: new FormControl('', [Validators.required]),
clientSecret: new FormControl('', [Validators.required]),
issuer: new FormControl('', [Validators.required]),
scopesList: new FormControl(['openid', 'profile', 'email'], []),
idpDisplayNameMapping: new FormControl(0),
usernameMapping: new FormControl(0),
});
this.route.data.pipe(take(1)).subscribe(data => {
this.serviceType = data.serviceType;
switch (this.serviceType) {
case PolicyComponentServiceType.MGMT:
this.service = this.injector.get(ManagementService as Type<ManagementService>);
this.mappingFields = [
OIDCMappingField.OIDC_MAPPING_FIELD_PREFERRED_USERNAME,
OIDCMappingField.OIDC_MAPPING_FIELD_EMAIL];
break;
case PolicyComponentServiceType.ADMIN:
this.service = this.injector.get(AdminService as Type<AdminService>);
this.mappingFields = [
OIDCMappingField.OIDC_MAPPING_FIELD_PREFERRED_USERNAME,
OIDCMappingField.OIDC_MAPPING_FIELD_EMAIL];
break;
}
});
this.route.data.pipe(take(1)).subscribe(data => {
this.serviceType = data.serviceType;
switch (this.serviceType) {
case PolicyComponentServiceType.MGMT:
this.service = this.injector.get(ManagementService as Type<ManagementService>);
this.mappingFields = [
OIDCMappingField.OIDC_MAPPING_FIELD_PREFERRED_USERNAME,
OIDCMappingField.OIDC_MAPPING_FIELD_EMAIL];
break;
case PolicyComponentServiceType.ADMIN:
this.service = this.injector.get(AdminService as Type<AdminService>);
this.mappingFields = [
OIDCMappingField.OIDC_MAPPING_FIELD_PREFERRED_USERNAME,
OIDCMappingField.OIDC_MAPPING_FIELD_EMAIL];
break;
}
});
}
public ngOnInit(): void {
this.subscription = this.route.params.subscribe(params => this.getData(params));
}
public ngOnDestroy(): void {
this.subscription?.unsubscribe();
}
private getData({ projectid }: Params): void {
this.projectId = projectid;
}
public addIdp(): void {
if (this.serviceType === PolicyComponentServiceType.MGMT) {
const req = new AddOrgOIDCIDPRequest();
req.setName(this.name?.value);
req.setClientId(this.clientId?.value);
req.setClientSecret(this.clientSecret?.value);
req.setIssuer(this.issuer?.value);
req.setScopesList(this.scopesList?.value);
req.setDisplayNameMapping(this.idpDisplayNameMapping?.value);
req.setUsernameMapping(this.usernameMapping?.value);
this.loading = true;
(this.service as ManagementService).addOrgOIDCIDP(req).then((idp) => {
setTimeout(() => {
this.loading = false;
this.router.navigate([
(this.serviceType === PolicyComponentServiceType.MGMT ? 'org' :
this.serviceType === PolicyComponentServiceType.ADMIN ? 'iam' : ''),
'policy', 'login']);
}, 2000);
}).catch(error => {
this.toast.showError(error);
});
} else if (PolicyComponentServiceType.ADMIN) {
const req = new AddOIDCIDPRequest();
req.setName(this.name?.value);
req.setClientId(this.clientId?.value);
req.setClientSecret(this.clientSecret?.value);
req.setIssuer(this.issuer?.value);
req.setScopesList(this.scopesList?.value);
req.setDisplayNameMapping(this.idpDisplayNameMapping?.value);
req.setUsernameMapping(this.usernameMapping?.value);
this.loading = true;
(this.service as AdminService).addOIDCIDP(req).then((idp) => {
setTimeout(() => {
this.loading = false;
this.router.navigate([
(this.serviceType === PolicyComponentServiceType.MGMT ? 'org' :
this.serviceType === PolicyComponentServiceType.ADMIN ? 'iam' : ''),
'policy', 'login']);
}, 2000);
}).catch(error => {
this.toast.showError(error);
});
}
}
public ngOnInit(): void {
this.subscription = this.route.params.subscribe(params => this.getData(params));
}
public close(): void {
this._location.back();
}
public ngOnDestroy(): void {
this.subscription?.unsubscribe();
}
public addScope(event: MatChipInputEvent): void {
const input = event.chipInput?.inputElement;
const value = event.value.trim();
private getData({ projectid }: Params): void {
this.projectId = projectid;
}
public addIdp(): void {
if (this.serviceType === PolicyComponentServiceType.MGMT) {
const req = new AddOrgOIDCIDPRequest();
req.setName(this.name?.value);
req.setClientId(this.clientId?.value);
req.setClientSecret(this.clientSecret?.value);
req.setIssuer(this.issuer?.value);
req.setScopesList(this.scopesList?.value);
req.setDisplayNameMapping(this.idpDisplayNameMapping?.value);
req.setUsernameMapping(this.usernameMapping?.value);
this.loading = true;
(this.service as ManagementService).addOrgOIDCIDP(req).then((idp) => {
setTimeout(() => {
this.loading = false;
this.router.navigate([
(this.serviceType === PolicyComponentServiceType.MGMT ? 'org' :
this.serviceType === PolicyComponentServiceType.ADMIN ? 'iam' : ''),
'policy', 'login']);
}, 2000);
}).catch(error => {
this.toast.showError(error);
});
} else if (PolicyComponentServiceType.ADMIN) {
const req = new AddOIDCIDPRequest();
req.setName(this.name?.value);
req.setClientId(this.clientId?.value);
req.setClientSecret(this.clientSecret?.value);
req.setIssuer(this.issuer?.value);
req.setScopesList(this.scopesList?.value);
req.setDisplayNameMapping(this.idpDisplayNameMapping?.value);
req.setUsernameMapping(this.usernameMapping?.value);
this.loading = true;
(this.service as AdminService).addOIDCIDP(req).then((idp) => {
setTimeout(() => {
this.loading = false;
this.router.navigate([
(this.serviceType === PolicyComponentServiceType.MGMT ? 'org' :
this.serviceType === PolicyComponentServiceType.ADMIN ? 'iam' : ''),
'policy', 'login']);
}, 2000);
}).catch(error => {
this.toast.showError(error);
});
if (value !== '') {
if (this.scopesList?.value) {
this.scopesList.value.push(value);
if (input) {
input.value = '';
}
}
}
}
public close(): void {
this._location.back();
public removeScope(uri: string): void {
if (this.scopesList?.value) {
const index = this.scopesList.value.indexOf(uri);
if (index !== undefined && index >= 0) {
this.scopesList.value.splice(index, 1);
}
}
}
public addScope(event: MatChipInputEvent): void {
const input = event.input;
const value = event.value.trim();
public get name(): AbstractControl | null {
return this.formGroup.get('name');
}
if (value !== '') {
if (this.scopesList?.value) {
this.scopesList.value.push(value);
if (input) {
input.value = '';
}
}
}
}
public get clientId(): AbstractControl | null {
return this.formGroup.get('clientId');
}
public removeScope(uri: string): void {
if (this.scopesList?.value) {
const index = this.scopesList.value.indexOf(uri);
public get clientSecret(): AbstractControl | null {
return this.formGroup.get('clientSecret');
}
if (index !== undefined && index >= 0) {
this.scopesList.value.splice(index, 1);
}
}
}
public get issuer(): AbstractControl | null {
return this.formGroup.get('issuer');
}
public get scopesList(): AbstractControl | null {
return this.formGroup.get('scopesList');
}
public get name(): AbstractControl | null {
return this.formGroup.get('name');
}
public get idpDisplayNameMapping(): AbstractControl | null {
return this.formGroup.get('idpDisplayNameMapping');
}
public get clientId(): AbstractControl | null {
return this.formGroup.get('clientId');
}
public get clientSecret(): AbstractControl | null {
return this.formGroup.get('clientSecret');
}
public get issuer(): AbstractControl | null {
return this.formGroup.get('issuer');
}
public get scopesList(): AbstractControl | null {
return this.formGroup.get('scopesList');
}
public get idpDisplayNameMapping(): AbstractControl | null {
return this.formGroup.get('idpDisplayNameMapping');
}
public get usernameMapping(): AbstractControl | null {
return this.formGroup.get('usernameMapping');
}
public get usernameMapping(): AbstractControl | null {
return this.formGroup.get('usernameMapping');
}
}

View File

@ -16,245 +16,245 @@ import { ToastService } from 'src/app/services/toast.service';
import { PolicyComponentServiceType } from '../policies/policy-component-types.enum';
@Component({
selector: 'app-idp',
templateUrl: './idp.component.html',
styleUrls: ['./idp.component.scss'],
selector: 'app-idp',
templateUrl: './idp.component.html',
styleUrls: ['./idp.component.scss'],
})
export class IdpComponent implements OnInit, OnDestroy {
public mappingFields: OIDCMappingField[] = [];
public styleFields: IDPStylingType[] = [];
public mappingFields: OIDCMappingField[] = [];
public styleFields: IDPStylingType[] = [];
public showIdSecretSection: boolean = false;
public serviceType: PolicyComponentServiceType = PolicyComponentServiceType.MGMT;
private service!: ManagementService | AdminService;
public readonly separatorKeysCodes: number[] = [ENTER, COMMA, SPACE];
public showIdSecretSection: boolean = false;
public serviceType: PolicyComponentServiceType = PolicyComponentServiceType.MGMT;
private service!: ManagementService | AdminService;
public readonly separatorKeysCodes: number[] = [ENTER, COMMA, SPACE];
private subscription?: Subscription;
public projectId: string = '';
private subscription?: Subscription;
public projectId: string = '';
public idpForm!: FormGroup;
public oidcConfigForm!: FormGroup;
public idpForm!: FormGroup;
public oidcConfigForm!: FormGroup;
constructor(
private toast: ToastService,
private injector: Injector,
private route: ActivatedRoute,
private _location: Location,
) {
this.idpForm = new FormGroup({
id: new FormControl({ disabled: true, value: '' }, [Validators.required]),
name: new FormControl('', [Validators.required]),
stylingType: new FormControl('', [Validators.required]),
});
constructor(
private toast: ToastService,
private injector: Injector,
private route: ActivatedRoute,
private _location: Location,
) {
this.idpForm = new FormGroup({
id: new FormControl({ disabled: true, value: '' }, [Validators.required]),
name: new FormControl('', [Validators.required]),
stylingType: new FormControl('', [Validators.required]),
});
this.oidcConfigForm = new FormGroup({
clientId: new FormControl('', [Validators.required]),
clientSecret: new FormControl(''),
issuer: new FormControl('', [Validators.required]),
scopesList: new FormControl([], []),
idpDisplayNameMapping: new FormControl(0),
usernameMapping: new FormControl(0),
});
this.oidcConfigForm = new FormGroup({
clientId: new FormControl('', [Validators.required]),
clientSecret: new FormControl(''),
issuer: new FormControl('', [Validators.required]),
scopesList: new FormControl([], []),
idpDisplayNameMapping: new FormControl(0),
usernameMapping: new FormControl(0),
});
this.route.data.pipe(switchMap(data => {
this.serviceType = data.serviceType;
switch (this.serviceType) {
case PolicyComponentServiceType.MGMT:
this.service = this.injector.get(ManagementService as Type<ManagementService>);
this.route.data.pipe(switchMap(data => {
this.serviceType = data.serviceType;
switch (this.serviceType) {
case PolicyComponentServiceType.MGMT:
this.service = this.injector.get(ManagementService as Type<ManagementService>);
break;
case PolicyComponentServiceType.ADMIN:
this.service = this.injector.get(AdminService as Type<AdminService>);
break;
case PolicyComponentServiceType.ADMIN:
this.service = this.injector.get(AdminService as Type<AdminService>);
break;
}
break;
}
this.mappingFields = [
OIDCMappingField.OIDC_MAPPING_FIELD_PREFERRED_USERNAME,
OIDCMappingField.OIDC_MAPPING_FIELD_EMAIL];
this.styleFields = [
IDPStylingType.STYLING_TYPE_UNSPECIFIED,
IDPStylingType.STYLING_TYPE_GOOGLE];
this.mappingFields = [
OIDCMappingField.OIDC_MAPPING_FIELD_PREFERRED_USERNAME,
OIDCMappingField.OIDC_MAPPING_FIELD_EMAIL];
this.styleFields = [
IDPStylingType.STYLING_TYPE_UNSPECIFIED,
IDPStylingType.STYLING_TYPE_GOOGLE];
return this.route.params.pipe(take(1));
})).subscribe((params) => {
const { id } = params;
if (id) {
if (this.serviceType === PolicyComponentServiceType.MGMT) {
(this.service as ManagementService).getOrgIDPByID(id).then(resp => {
if (resp.idp) {
const idpObject = resp.idp;
this.idpForm.patchValue(idpObject);
if (idpObject.oidcConfig) {
this.oidcConfigForm.patchValue(idpObject.oidcConfig);
}
}
});
} else if (this.serviceType === PolicyComponentServiceType.ADMIN) {
(this.service as AdminService).getIDPByID(id).then(resp => {
if (resp.idp) {
const idpObject = resp.idp;
this.idpForm.patchValue(idpObject);
if (idpObject.oidcConfig) {
this.oidcConfigForm.patchValue(idpObject.oidcConfig);
}
}
});
}
}
});
}
public ngOnInit(): void {
this.subscription = this.route.params.subscribe(params => this.getData(params));
}
public ngOnDestroy(): void {
this.subscription?.unsubscribe();
}
private getData({ projectid }: Params): void {
this.projectId = projectid;
}
public updateIdp(): void {
return this.route.params.pipe(take(1));
})).subscribe((params) => {
const { id } = params;
if (id) {
if (this.serviceType === PolicyComponentServiceType.MGMT) {
const req = new UpdateOrgIDPRequest();
req.setIdpId(this.id?.value);
req.setName(this.name?.value);
req.setStylingType(this.stylingType?.value);
(this.service as ManagementService).updateOrgIDP(req).then(() => {
this.toast.showInfo('IDP.TOAST.SAVED', true);
// this.router.navigate(['idp', ]);
}).catch(error => {
this.toast.showError(error);
});
} else if (this.serviceType === PolicyComponentServiceType.ADMIN) {
const req = new UpdateIDPRequest();
req.setIdpId(this.id?.value);
req.setName(this.name?.value);
req.setStylingType(this.stylingType?.value);
(this.service as AdminService).updateIDP(req).then(() => {
this.toast.showInfo('IDP.TOAST.SAVED', true);
// this.router.navigate(['idp', ]);
}).catch(error => {
this.toast.showError(error);
});
}
}
public updateOidcConfig(): void {
if (this.serviceType === PolicyComponentServiceType.MGMT) {
const req = new UpdateOrgIDPOIDCConfigRequest();
req.setIdpId(this.id?.value);
req.setClientId(this.clientId?.value);
req.setClientSecret(this.clientSecret?.value);
req.setIssuer(this.issuer?.value);
req.setScopesList(this.scopesList?.value);
req.setUsernameMapping(this.usernameMapping?.value);
req.setDisplayNameMapping(this.idpDisplayNameMapping?.value);
(this.service as ManagementService).updateOrgIDPOIDCConfig(req).then((oidcConfig) => {
this.toast.showInfo('IDP.TOAST.SAVED', true);
// this.router.navigate(['idp', ]);
}).catch(error => {
this.toast.showError(error);
});
} else if (this.serviceType === PolicyComponentServiceType.ADMIN) {
const req = new UpdateIDPOIDCConfigRequest();
req.setIdpId(this.id?.value);
req.setClientId(this.clientId?.value);
req.setClientSecret(this.clientSecret?.value);
req.setIssuer(this.issuer?.value);
req.setScopesList(this.scopesList?.value);
req.setUsernameMapping(this.usernameMapping?.value);
req.setDisplayNameMapping(this.idpDisplayNameMapping?.value);
(this.service as AdminService).updateIDPOIDCConfig(req).then((oidcConfig) => {
this.toast.showInfo('IDP.TOAST.SAVED', true);
// this.router.navigate(['idp', ]);
}).catch(error => {
this.toast.showError(error);
});
}
}
public close(): void {
this._location.back();
}
public addScope(event: MatChipInputEvent): void {
const input = event.input;
const value = event.value.trim();
if (value !== '') {
if (this.scopesList?.value) {
this.scopesList.value.push(value);
if (input) {
input.value = '';
}
(this.service as ManagementService).getOrgIDPByID(id).then(resp => {
if (resp.idp) {
const idpObject = resp.idp;
this.idpForm.patchValue(idpObject);
if (idpObject.oidcConfig) {
this.oidcConfigForm.patchValue(idpObject.oidcConfig);
}
}
}
}
public removeScope(uri: string): void {
if (this.scopesList?.value) {
const index = this.scopesList?.value.indexOf(uri);
if (index !== undefined && index >= 0) {
this.scopesList?.value.splice(index, 1);
});
} else if (this.serviceType === PolicyComponentServiceType.ADMIN) {
(this.service as AdminService).getIDPByID(id).then(resp => {
if (resp.idp) {
const idpObject = resp.idp;
this.idpForm.patchValue(idpObject);
if (idpObject.oidcConfig) {
this.oidcConfigForm.patchValue(idpObject.oidcConfig);
}
}
});
}
}
}
});
}
public get backroutes(): string[] {
switch (this.serviceType) {
case PolicyComponentServiceType.MGMT:
return ['/org', 'policy', 'login'];
case PolicyComponentServiceType.ADMIN:
return ['/iam', 'policy', 'login'];
public ngOnInit(): void {
this.subscription = this.route.params.subscribe(params => this.getData(params));
}
public ngOnDestroy(): void {
this.subscription?.unsubscribe();
}
private getData({ projectid }: Params): void {
this.projectId = projectid;
}
public updateIdp(): void {
if (this.serviceType === PolicyComponentServiceType.MGMT) {
const req = new UpdateOrgIDPRequest();
req.setIdpId(this.id?.value);
req.setName(this.name?.value);
req.setStylingType(this.stylingType?.value);
(this.service as ManagementService).updateOrgIDP(req).then(() => {
this.toast.showInfo('IDP.TOAST.SAVED', true);
// this.router.navigate(['idp', ]);
}).catch(error => {
this.toast.showError(error);
});
} else if (this.serviceType === PolicyComponentServiceType.ADMIN) {
const req = new UpdateIDPRequest();
req.setIdpId(this.id?.value);
req.setName(this.name?.value);
req.setStylingType(this.stylingType?.value);
(this.service as AdminService).updateIDP(req).then(() => {
this.toast.showInfo('IDP.TOAST.SAVED', true);
// this.router.navigate(['idp', ]);
}).catch(error => {
this.toast.showError(error);
});
}
}
public updateOidcConfig(): void {
if (this.serviceType === PolicyComponentServiceType.MGMT) {
const req = new UpdateOrgIDPOIDCConfigRequest();
req.setIdpId(this.id?.value);
req.setClientId(this.clientId?.value);
req.setClientSecret(this.clientSecret?.value);
req.setIssuer(this.issuer?.value);
req.setScopesList(this.scopesList?.value);
req.setUsernameMapping(this.usernameMapping?.value);
req.setDisplayNameMapping(this.idpDisplayNameMapping?.value);
(this.service as ManagementService).updateOrgIDPOIDCConfig(req).then((oidcConfig) => {
this.toast.showInfo('IDP.TOAST.SAVED', true);
// this.router.navigate(['idp', ]);
}).catch(error => {
this.toast.showError(error);
});
} else if (this.serviceType === PolicyComponentServiceType.ADMIN) {
const req = new UpdateIDPOIDCConfigRequest();
req.setIdpId(this.id?.value);
req.setClientId(this.clientId?.value);
req.setClientSecret(this.clientSecret?.value);
req.setIssuer(this.issuer?.value);
req.setScopesList(this.scopesList?.value);
req.setUsernameMapping(this.usernameMapping?.value);
req.setDisplayNameMapping(this.idpDisplayNameMapping?.value);
(this.service as AdminService).updateIDPOIDCConfig(req).then((oidcConfig) => {
this.toast.showInfo('IDP.TOAST.SAVED', true);
// this.router.navigate(['idp', ]);
}).catch(error => {
this.toast.showError(error);
});
}
}
public close(): void {
this._location.back();
}
public addScope(event: MatChipInputEvent): void {
const input = event.chipInput?.inputElement;
const value = event.value.trim();
if (value !== '') {
if (this.scopesList?.value) {
this.scopesList.value.push(value);
if (input) {
input.value = '';
}
}
}
}
public get id(): AbstractControl | null {
return this.idpForm.get('id');
}
public removeScope(uri: string): void {
if (this.scopesList?.value) {
const index = this.scopesList?.value.indexOf(uri);
public get name(): AbstractControl | null {
return this.idpForm.get('name');
if (index !== undefined && index >= 0) {
this.scopesList?.value.splice(index, 1);
}
}
}
public get stylingType(): AbstractControl | null {
return this.idpForm.get('stylingType');
public get backroutes(): string[] {
switch (this.serviceType) {
case PolicyComponentServiceType.MGMT:
return ['/org', 'policy', 'login'];
case PolicyComponentServiceType.ADMIN:
return ['/iam', 'policy', 'login'];
}
}
public get clientId(): AbstractControl | null {
return this.oidcConfigForm.get('clientId');
}
public get id(): AbstractControl | null {
return this.idpForm.get('id');
}
public get clientSecret(): AbstractControl | null {
return this.oidcConfigForm.get('clientSecret');
}
public get name(): AbstractControl | null {
return this.idpForm.get('name');
}
public get issuer(): AbstractControl | null {
return this.oidcConfigForm.get('issuer');
}
public get stylingType(): AbstractControl | null {
return this.idpForm.get('stylingType');
}
public get scopesList(): AbstractControl | null {
return this.oidcConfigForm.get('scopesList');
}
public get clientId(): AbstractControl | null {
return this.oidcConfigForm.get('clientId');
}
public get idpDisplayNameMapping(): AbstractControl | null {
return this.oidcConfigForm.get('idpDisplayNameMapping');
}
public get clientSecret(): AbstractControl | null {
return this.oidcConfigForm.get('clientSecret');
}
public get usernameMapping(): AbstractControl | null {
return this.oidcConfigForm.get('usernameMapping');
}
public get issuer(): AbstractControl | null {
return this.oidcConfigForm.get('issuer');
}
public get scopesList(): AbstractControl | null {
return this.oidcConfigForm.get('scopesList');
}
public get idpDisplayNameMapping(): AbstractControl | null {
return this.oidcConfigForm.get('idpDisplayNameMapping');
}
public get usernameMapping(): AbstractControl | null {
return this.oidcConfigForm.get('usernameMapping');
}
}

View File

@ -1,15 +1,19 @@
<div class="form-row">
<cnsl-form-field class="formfield">
<cnsl-label>{{name}} (current {{color}})</cnsl-label>
<input cnslInput [(ngModel)]="previewColor" (keydown.enter)="name ? emitPreview(previewColor) : null" />
</cnsl-form-field>
<button matTooltip="{{'ACTIONS.SET' | translate}}" (click)="emitPreview(previewColor)" mat-icon-button><mat-icon>check</mat-icon></button>
</div>
<div class="color-selector">
<div *ngFor="let c of colors" class="circle mat-elevation-z3"
[ngClass]="{'active': color == c.color || previewColor == c.color}"
(click)="emitPreview(c.color)" [ngStyle]="{'background-color': c.color}">
<span *ngIf="previewColor == c.color">P</span>
<span *ngIf="color == c.color">C</span>
<p class="name">{{name}} (current {{color}})</p>
<div class="wrapper">
<button class="mat-elevation-z3" [style.background-color]="previewColor" (click)="isOpen = !isOpen" cdkOverlayOrigin #trigger="cdkOverlayOrigin" matTooltip="{{'ACTIONS.SET' | translate}}"> </button>
<div class="hex-wrapper" (click)="isOpen = !isOpen">
<i class="las la-hashtag"></i>
<span class="hex">{{previewColorCropped}}</span>
</div>
</div>
</div>
<ng-template
cdkConnectedOverlay
[cdkConnectedOverlayOrigin]="trigger"
[cdkConnectedOverlayOpen]="isOpen"
(overlayOutsideClick)="isOpen = false"
>
<color-chrome class="picker" [color]="previewColor" (onChangeComplete)="changeComplete($event)"></color-chrome>
</ng-template>

View File

@ -1,52 +1,52 @@
.title {
// font-size: 1rem;
display: block;
font-size: 18px;
&.border {
border-top: 1px solid var(--grey);
padding-top: 1.5rem;
}
.name {
font-size: 14px;
margin-bottom: 0;
color: var(--grey);
}
.form-row {
.wrapper {
border-radius: .5rem;
padding: 0 1rem;
display: flex;
align-items: flex-end;
align-items: center;
.formfield {
flex: 1;
.hex-wrapper {
display: flex;
align-items: center;
flex-direction: row;
color: var(--grey);
font-size: 14px;
padding: 0 1rem;
cursor: pointer;
.hex {
font-size: 16px;
}
}
button {
margin-bottom: .9rem;
}
}
.color-selector {
display: flex;
align-items: center;
flex-wrap: wrap;
margin: 0 -.25rem;
width: 100%;
padding-bottom: 1rem;
.circle {
height: 30px;
width: 30px;
background-color: #cd5c5c;
border-radius: 50%;
margin: .25rem;
box-sizing: border-box;
cursor: pointer;
margin: .5rem 0;
border-radius: .5rem;
height: 35px;
width: 35px;
display: flex;
align-items: center;
justify-content: center;
span {
font-size: 18px;
}
&.active {
border: 3px solid #ffffff90;
}
border: none;
justify-content: space-between;
}
}
.picker {
margin: 1rem 0;
}
// stylelint-disable
::ng-deep .chrome-picker {
border-radius: .5rem !important;
}
::ng-deep .saturation {
border-radius: .5rem .5rem 0 0 !important;
}
// stylelint-enable

View File

@ -1,4 +1,5 @@
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
import { ColorEvent } from 'ngx-color';
import { ColorType } from '../private-labeling-policy.component';
@ -77,6 +78,7 @@ export class ColorComponent implements OnInit {
];
public colors: Array<{ name: string; color: string; }> = this.PRIMARY;
public isOpen: boolean = false;
@Input() colorType: ColorType = ColorType.PRIMARY;
@Input() color: string = '';
@ -89,8 +91,7 @@ export class ColorComponent implements OnInit {
this.previewChanged.emit(this.previewColor);
}
ngOnInit(): void {
public ngOnInit(): void {
switch (this.colorType) {
case ColorType.PRIMARY:
this.colors = this.PRIMARY;
@ -115,4 +116,16 @@ export class ColorComponent implements OnInit {
break;
}
}
public changeComplete(event: ColorEvent): void {
this.emitPreview(event.color.hex);
}
public get previewColorCropped(): string {
let s = this.previewColor;
while (s.charAt(0) === '#') {
s = s.substring(1);
}
return s;
}
}

View File

@ -3,10 +3,8 @@
<div class="dashed" [ngClass]="{'dark': theme === Theme.DARK, 'light': theme === Theme.LIGHT}" [style.background]="theme == Theme.DARK ? policy.backgroundColorDark : policy.backgroundColor">
<div class="login-wrapper" [style.color]="theme == Theme.DARK ? policy.fontColorDark : policy.fontColor">
<img *ngIf="images['previewLogo'] && theme == Theme.LIGHT" [src]="images['previewLogo']" alt="logo-mock" />
<img *ngIf="!images['previewLogo'] && theme == Theme.LIGHT" src="../../../../assets/images/zitadel-logo-dark.svg" alt="logo-mock" />
<img *ngIf="images['previewDarkLogo'] && theme == Theme.DARK" [src]="images['previewDarkLogo']" alt="logo-mock" />
<img *ngIf="!images['previewDarkLogo'] && theme == Theme.DARK" src="../../../../assets/images/zitadel-logo-light.svg" alt="logo-mock" />
<h1>{{'POLICY.PRIVATELABELING.PREVIEW.TITLE' | translate}}</h1>
<p class="desc-text">{{'POLICY.PRIVATELABELING.PREVIEW.SECOND' | translate}}</p>

View File

@ -15,13 +15,6 @@
<mat-spinner diameter="30" *ngIf="loading" color="primary"></mat-spinner>
</div>
<ng-template appHasRole [appHasRole]="['policy.delete']">
<button *ngIf="serviceType === PolicyComponentServiceType.MGMT && !isDefault"
matTooltip="{{'POLICY.RESET' | translate}}" color="warn" (click)="removePolicy()" mat-stroked-button>
{{'POLICY.RESET' | translate}}
</button>
</ng-template>
<div class="top-row">
<div>
<p>{{'POLICY.PRIVATELABELING.THEME' | translate}}</p>
@ -35,6 +28,15 @@
</div>
</div>
<span class="fill-space"></span>
<ng-template appHasRole [appHasRole]="['policy.delete']">
<button class="reset-button" *ngIf="serviceType === PolicyComponentServiceType.MGMT && !isDefault"
matTooltip="{{'POLICY.RESET' | translate}}" color="warn" (click)="removePolicy()" mat-stroked-button>
{{'POLICY.RESET' | translate}}
</button>
</ng-template>
<button class="activate-button" [disabled]="serviceType == PolicyComponentServiceType.MGMT && (['label_policy.private_label'] | hasFeature | async) == false" mat-raised-button color="primary" (click)="activatePolicy()">
{{'POLICY.PRIVATELABELING.ACTIVATEPREVIEW' | translate}}
</button>
@ -64,14 +66,26 @@
<mat-spinner class="spinner" color="primary" diameter="25" *ngIf="loadingImages"></mat-spinner>
<container [ngSwitch]="theme">
<div class="logo-view" *ngSwitchCase="Theme.DARK">
<img matTooltip="Preview" class="prev" *ngIf="images['previewDarkLogo']" [src]="images['previewDarkLogo']" alt="dark logo preview"/>
<div class="img-wrapper" *ngIf="images['previewDarkLogo']" >
<mat-icon matTooltip="{{'ACTIONS.DELETE' | translate}}" color="warn" class="dl-btn" (click)="deleteAsset(AssetType.LOGO, theme)">remove_circle</mat-icon>
<img matTooltip="Preview" class="prev" [src]="images['previewDarkLogo']" alt="dark logo preview"/>
</div>
<span class="fill-space"></span>
<img matTooltip="Current" class="curr" *ngIf="images['darkLogo']" [src]="images['darkLogo']" alt="dark logo"/>
<div class="img-wrapper" *ngIf="images['darkLogo']">
<!-- <mat-icon matTooltip="{{'ACTIONS.DELETE' | translate}}" color="warn" class="dl-btn" (click)="deleteAsset(AssetType.LOGO, theme, Preview.PREVIEW)">remove_circle</mat-icon> -->
<img matTooltip="Current" class="curr" [src]="images['darkLogo']" alt="dark logo"/>
</div>
</div>
<div class="logo-view" *ngSwitchCase="Theme.LIGHT">
<img matTooltip="Preview" class="prev" *ngIf="images['previewLogo']" [src]="images['previewLogo']" alt="logo preview"/>
<div class="img-wrapper" *ngIf="images['previewLogo']">
<mat-icon matTooltip="{{'ACTIONS.DELETE' | translate}}" color="warn" class="dl-btn" (click)="deleteAsset(AssetType.LOGO, theme)">remove_circle</mat-icon>
<img matTooltip="Preview" class="prev" [src]="images['previewLogo']" alt="logo preview"/>
</div>
<span class="fill-space"></span>
<img matTooltip="Current" class="curr" *ngIf="images['logo']" [src]="images['logo']" alt="logo"/>
<div class="img-wrapper" *ngIf="images['logo']">
<!-- <mat-icon matTooltip="{{'ACTIONS.DELETE' | translate}}" color="warn" class="dl-btn" (click)="deleteAsset(AssetType.LOGO, theme, Preview.PREVIEW)">remove_circle</mat-icon> -->
<img matTooltip="Current" class="curr" [src]="images['logo']" alt="logo"/>
</div>
</div>
</container>
<div class="dropzone" cnslDropzone (hovered)="toggleHoverLogo(theme, $event)"
@ -92,14 +106,26 @@
<mat-spinner class="spinner" color="primary" diameter="25" *ngIf="loadingImages"></mat-spinner>
<container [ngSwitch]="theme">
<div class="logo-view" *ngSwitchCase="Theme.DARK">
<img matTooltip="Preview" class="prev" *ngIf="images['previewDarkIcon']" [src]="images['previewDarkIcon']" alt="dark icon preview"/>
<div class="img-wrapper" *ngIf="images['previewDarkIcon']">
<mat-icon matTooltip="{{'ACTIONS.DELETE' | translate}}" color="warn" class="dl-btn" (click)="deleteAsset(AssetType.ICON, theme)">remove_circle</mat-icon>
<img matTooltip="Preview" class="prev" [src]="images['previewDarkIcon']" alt="dark icon preview"/>
</div>
<span class="fill-space"></span>
<img matTooltip="Current" class="curr" *ngIf="images['darkIcon']" [src]="images['darkIcon']" alt="dark icon"/>
<div class="img-wrapper" *ngIf="images['darkIcon']">
<!-- <mat-icon matTooltip="{{'ACTIONS.DELETE' | translate}}" color="warn" class="dl-btn" (click)="deleteAsset(AssetType.ICON,theme, Preview.CURRENT)">remove_circle</mat-icon> -->
<img matTooltip="Current" class="curr" [src]="images['darkIcon']" alt="dark icon"/>
</div>
</div>
<div class="logo-view" *ngSwitchCase="Theme.LIGHT">
<img matTooltip="Preview" class="prev" *ngIf="images['previewIcon']" [src]="images['previewIcon']" alt="icon preview"/>
<div class="img-wrapper" *ngIf="images['previewIcon']">
<mat-icon matTooltip="{{'ACTIONS.DELETE' | translate}}" color="warn" class="dl-btn" (click)="deleteAsset(AssetType.ICON,theme)">remove_circle</mat-icon>
<img matTooltip="Preview" class="prev" [src]="images['previewIcon']" alt="icon preview"/>
</div>
<span class="fill-space"></span>
<img matTooltip="Current" class="curr" *ngIf="images['icon']" [src]="images['icon']" alt="icon"/>
<div class="img-wrapper" *ngIf="images['icon']" >
<!-- <mat-icon matTooltip="{{'ACTIONS.DELETE' | translate}}" color="warn" class="dl-btn" (click)="deleteAsset(AssetType.ICON,theme, Preview.CURRENT)">remove_circle</mat-icon> -->
<img matTooltip="Current" class="curr"[src]="images['icon']" alt="icon"/>
</div>
</div>
</container>
<div class="dropzone" cnslDropzone (hovered)="toggleHoverIcon(theme, $event)"
@ -132,19 +158,19 @@
<ng-container *ngIf="theme==Theme.DARK">
<div class="colors" *ngIf="data && previewData">
<div class="color">
<cnsl-color [colorType]="ColorType.BACKGROUNDDARK"(previewChanged)="previewData.backgroundColorDark = $event; savePolicy()" name="Background Color Dark" [color]="data.backgroundColorDark" [previewColor]="previewData.backgroundColorDark"></cnsl-color>
<cnsl-color [colorType]="ColorType.BACKGROUNDDARK" (previewChanged)="previewData.backgroundColorDark = $event" name="Background Color Dark" [color]="data.backgroundColorDark" [previewColor]="previewData.backgroundColorDark"></cnsl-color>
</div>
<div class="color">
<cnsl-color [colorType]="ColorType.PRIMARY"(previewChanged)="previewData.primaryColorDark = $event; savePolicy()" name="Preview Primary Color Dark" [color]="data.primaryColorDark" [previewColor]="previewData.primaryColorDark"></cnsl-color>
<cnsl-color [colorType]="ColorType.PRIMARY"(previewChanged)="previewData.primaryColorDark = $event" name="Preview Primary Color Dark" [color]="data.primaryColorDark" [previewColor]="previewData.primaryColorDark"></cnsl-color>
</div>
<div class="color">
<cnsl-color [colorType]="ColorType.WARN" (previewChanged)="previewData.warnColorDark = $event; savePolicy()" name="Preview Warn Color Dark" [color]="data.warnColorDark" [previewColor]="previewData.warnColorDark"></cnsl-color>
<cnsl-color [colorType]="ColorType.WARN" (previewChanged)="previewData.warnColorDark = $event" name="Preview Warn Color Dark" [color]="data.warnColorDark" [previewColor]="previewData.warnColorDark"></cnsl-color>
</div>
<div class="color">
<cnsl-color [colorType]="ColorType.FONTDARK"(previewChanged)="previewData.fontColorDark = $event; savePolicy()" name="Font Color Dark" [color]="data.fontColorDark" [previewColor]="previewData.fontColorDark"></cnsl-color>
<cnsl-color [colorType]="ColorType.FONTDARK"(previewChanged)="previewData.fontColorDark = $event" name="Font Color Dark" [color]="data.fontColorDark" [previewColor]="previewData.fontColorDark"></cnsl-color>
</div>
</div>
</ng-container>
@ -152,22 +178,26 @@
<ng-container *ngIf="theme==Theme.LIGHT">
<div class="colors" *ngIf="data && previewData">
<div class="color">
<cnsl-color [colorType]="ColorType.BACKGROUNDLIGHT" (previewChanged)="previewData.backgroundColor = $event; savePolicy()" name="Background Color Light" [color]="data.backgroundColor" [previewColor]="previewData.backgroundColor"></cnsl-color>
<cnsl-color [colorType]="ColorType.BACKGROUNDLIGHT" (previewChanged)="previewData.backgroundColor = $event" name="Background Color Light" [color]="data.backgroundColor" [previewColor]="previewData.backgroundColor"></cnsl-color>
</div>
<div class="color">
<cnsl-color [colorType]="ColorType.PRIMARY" (previewChanged)="previewData.primaryColor = $event; savePolicy()" name="Preview Primary Color Light" [color]="data.primaryColor" [previewColor]="previewData.primaryColor"></cnsl-color>
<cnsl-color [colorType]="ColorType.PRIMARY" (previewChanged)="previewData.primaryColor = $event" name="Preview Primary Color Light" [color]="data.primaryColor" [previewColor]="previewData.primaryColor"></cnsl-color>
</div>
<div class="color">
<cnsl-color [colorType]="ColorType.WARN" name="Preview Warn Color Light" (previewChanged)="previewData.warnColor= $event; savePolicy()" [color]="data.warnColor" [previewColor]="previewData.warnColor"></cnsl-color>
<cnsl-color [colorType]="ColorType.WARN" name="Preview Warn Color Light" (previewChanged)="previewData.warnColor= $event" [color]="data.warnColor" [previewColor]="previewData.warnColor"></cnsl-color>
</div>
<div class="color">
<cnsl-color [colorType]="ColorType.FONTLIGHT" (previewChanged)="previewData.fontColor = $event; savePolicy()" name="Font Color" [color]="data.fontColor" [previewColor]="previewData.fontColor"></cnsl-color>
<cnsl-color [colorType]="ColorType.FONTLIGHT" (previewChanged)="previewData.fontColor = $event" name="Font Color" [color]="data.fontColor" [previewColor]="previewData.fontColor"></cnsl-color>
</div>
</div>
</ng-container>
<div class="clr-btn-wrapper">
<button color="primary" mat-raised-button (click)="savePolicy()">{{'ACTIONS.SAVE' | translate}}</button>
</div>
</mat-expansion-panel>
<mat-expansion-panel class="expansion">
@ -179,11 +209,12 @@
</mat-panel-title>
</mat-expansion-panel-header>
<div class="fonts">
<div class="font-preview">
<mat-icon>text_fields</mat-icon>
<div class="font-preview mat-elevation-z3" *ngIf="preview == Preview.PREVIEW && previewData.fontUrl || preview == Preview.CURRENT && data.fontUrl">
<mat-icon class="icon">text_fields</mat-icon>
<span>ABC • abc • 123</span>
<span>_</span>
<span>Upload your favorite font for the UI</span>
<span class="fill-space"></span>
<button matTooltip="{{'ACTIONS.REMOVE' | translate}}" mat-icon-button color="warn" (click)="deleteFont()"><mat-icon>remove_circle</mat-icon></button>
</div>
<div class="dropzone" cnslDropzone (hovered)="toggleHoverFont($event)"
@ -213,7 +244,7 @@
<ng-container
*ngIf="serviceType == PolicyComponentServiceType.MGMT && (['label_policy.private_label'] | hasFeature | async) == false">
<cnsl-info-section class="info" type="WARN">{{'FEATURES.NOTAVAILABLE' | translate: ({value:
<cnsl-info-section class="info" type="WARN">{{'FEATURES.NOTAVAILABLE' | translate: ({value:
'label_policy.private_label'})}}
</cnsl-info-section>
</ng-container>

View File

@ -83,7 +83,15 @@
.top-row {
display: flex;
justify-content: space-between;
.fill-space {
flex: 1;
}
.reset-button {
align-self: flex-end;
margin-right: 1rem;
}
.activate-button {
border-radius: 50%;
@ -180,7 +188,7 @@
outline: none;
height: 150px;
width: 100%;
border-radius: 16px;
border-radius: .5rem;
background: if($is-dark-theme, #2d2e30, #fff);
border: 1px solid if($is-dark-theme, #4a4b4b, #ddd);
display: flex;
@ -257,11 +265,39 @@
display: flex;
margin-bottom: 1rem;
.prev,
.curr {
height: 50px;
object-fit: contain;
.img-wrapper {
flex: 1;
position: relative;
min-height: 80px;
border: 1px solid if($is-dark-theme, #ffffff20, #00000020);
border-radius: .5rem;
max-width: 120px;
.dl-btn {
position: absolute;
top: -12px;
left: -12px;
cursor: pointer;
visibility: hidden;
}
.prev,
.curr {
position: absolute;
top: 50%;
transform: translateY(-50%);
left: 0;
max-height: 80px;
max-width: 120px;
object-fit: contain;
border-radius: .5rem;
}
&:hover {
.dl-btn {
visibility: visible;
}
}
}
.fill-space {
@ -280,6 +316,12 @@
}
}
.clr-btn-wrapper {
width: 100%;
display: flex;
justify-content: flex-end;
}
.fonts {
.title {
display: block;
@ -288,10 +330,19 @@
.font-preview {
display: flex;
flex-direction: column;
align-items: center;
padding: 30px 50px;
padding: .5rem;
text-align: center;
border-radius: .5rem;
margin-bottom: 1rem;
.icon {
margin-right: 1rem;
}
.fill-space {
flex: 1;
}
}
.font-selector {
@ -299,7 +350,6 @@
align-items: center;
flex-wrap: wrap;
margin: 0 -.25rem;
width: 100%;
padding-bottom: 1rem;
.font {

View File

@ -17,9 +17,9 @@ import {
} from 'src/app/proto/generated/zitadel/management_pb';
import { LabelPolicy } from 'src/app/proto/generated/zitadel/policy_pb';
import { AdminService } from 'src/app/services/admin.service';
import { AssetEndpoint, AssetService, AssetType } from 'src/app/services/asset.service';
import { ManagementService } from 'src/app/services/mgmt.service';
import { ToastService } from 'src/app/services/toast.service';
import { DownloadEndpoint, UploadEndpoint, UploadService } from 'src/app/services/upload.service';
import { CnslLinks } from '../../links/links.component';
import { IAM_COMPLEXITY_LINK, IAM_LOGIN_POLICY_LINK, IAM_POLICY_LINK } from '../../policy-grid/policy-links';
@ -82,6 +82,7 @@ export class PrivateLabelingPolicyComponent implements OnDestroy {
public Theme: any = Theme;
public Preview: any = Preview;
public ColorType: any = ColorType;
public AssetType: any = AssetType;
public refreshPreview: EventEmitter<void> = new EventEmitter();
public loadingImages: boolean = false;
@ -90,7 +91,7 @@ export class PrivateLabelingPolicyComponent implements OnDestroy {
private route: ActivatedRoute,
private toast: ToastService,
private injector: Injector,
private uploadService: UploadService,
private assetService: AssetService,
private sanitizer: DomSanitizer,
) {
this.sub = this.route.data.pipe(switchMap(data => {
@ -133,17 +134,17 @@ export class PrivateLabelingPolicyComponent implements OnDestroy {
if (theme === Theme.DARK) {
switch (this.serviceType) {
case PolicyComponentServiceType.MGMT:
return this.handleUploadPromise(this.uploadService.upload(UploadEndpoint.MGMTDARKLOGO, formData));
return this.handleUploadPromise(this.assetService.upload(AssetEndpoint.MGMTDARKLOGO, formData));
case PolicyComponentServiceType.ADMIN:
return this.handleUploadPromise(this.uploadService.upload(UploadEndpoint.IAMDARKLOGO, formData));
return this.handleUploadPromise(this.assetService.upload(AssetEndpoint.IAMDARKLOGO, formData));
}
}
if (theme === Theme.LIGHT) {
switch (this.serviceType) {
case PolicyComponentServiceType.MGMT:
return this.handleUploadPromise(this.uploadService.upload(UploadEndpoint.MGMTLIGHTLOGO, formData));
return this.handleUploadPromise(this.assetService.upload(AssetEndpoint.MGMTLOGO, formData));
case PolicyComponentServiceType.ADMIN:
return this.handleUploadPromise(this.uploadService.upload(UploadEndpoint.IAMLIGHTLOGO, formData));
return this.handleUploadPromise(this.assetService.upload(AssetEndpoint.IAMLOGO, formData));
}
}
@ -157,13 +158,87 @@ export class PrivateLabelingPolicyComponent implements OnDestroy {
formData.append('file', file);
switch (this.serviceType) {
case PolicyComponentServiceType.MGMT:
return this.uploadService.upload(UploadEndpoint.MGMTFONT, formData);
return this.handleFontUploadPromise(this.assetService.upload(AssetEndpoint.MGMTFONT, formData));
case PolicyComponentServiceType.ADMIN:
return this.uploadService.upload(UploadEndpoint.IAMFONT, formData);
return this.handleFontUploadPromise(this.assetService.upload(AssetEndpoint.IAMFONT, formData));
}
}
}
public deleteFont(): Promise<any> {
const handler = (prom: Promise<any>) => prom.then(() => {
this.toast.showInfo('POLICY.TOAST.DELETESUCCESS', true);
setTimeout(() => {
this.loadingImages = true;
this.getPreviewData().then(data => {
if (data.policy) {
this.previewData = data.policy;
this.loadPreviewImages();
}
});
}, 1000);
}).catch(error => this.toast.showError(error));
switch (this.serviceType) {
case PolicyComponentServiceType.MGMT:
return handler((this.service as ManagementService).removeLabelPolicyFont());
case PolicyComponentServiceType.ADMIN:
return handler((this.service as AdminService).removeLabelPolicyFont());
}
}
public deleteAsset(type: AssetType, theme: Theme): any {
const previewHandler = (prom: Promise<any>) => {
return prom.then(() => {
this.toast.showInfo('POLICY.TOAST.DELETESUCCESS', true);
setTimeout(() => {
this.loadingImages = true;
this.getPreviewData().then(data => {
if (data.policy) {
this.previewData = data.policy;
this.loadPreviewImages();
}
});
}, 1000);
}).catch(error => this.toast.showError(error));
};
switch (this.serviceType) {
case PolicyComponentServiceType.ADMIN:
if (type === AssetType.LOGO) {
if (theme === Theme.DARK) {
return previewHandler(this.service.removeLabelPolicyLogoDark());
} else if (theme === Theme.LIGHT) {
return previewHandler(this.service.removeLabelPolicyLogo());
}
} else if (type === AssetType.ICON) {
if (theme === Theme.DARK) {
return previewHandler(this.service.removeLabelPolicyIconDark());
} else if (theme === Theme.LIGHT) {
return previewHandler(this.service.removeLabelPolicyIcon());
}
}
break;
case PolicyComponentServiceType.MGMT:
if (type === AssetType.LOGO) {
if (theme === Theme.DARK) {
return previewHandler(this.service.removeLabelPolicyLogoDark());
} else if (theme === Theme.LIGHT) {
return previewHandler(this.service.removeLabelPolicyLogo());
}
} else if (type === AssetType.ICON) {
if (theme === Theme.DARK) {
return previewHandler(this.service.removeLabelPolicyIconDark());
} else if (theme === Theme.LIGHT) {
return previewHandler(this.service.removeLabelPolicyIcon());
}
}
break;
}
}
public toggleHoverIcon(theme: Theme, isHovering: boolean): void {
if (theme === Theme.DARK) {
this.isHoveringOverDarkIcon = isHovering;
@ -182,26 +257,39 @@ export class PrivateLabelingPolicyComponent implements OnDestroy {
if (theme === Theme.DARK) {
switch (this.serviceType) {
case PolicyComponentServiceType.MGMT:
this.handleUploadPromise(this.uploadService.upload(UploadEndpoint.MGMTDARKICON, formData));
this.handleUploadPromise(this.assetService.upload(AssetEndpoint.MGMTDARKICON, formData));
break;
case PolicyComponentServiceType.ADMIN:
this.handleUploadPromise(this.uploadService.upload(UploadEndpoint.IAMDARKICON, formData));
this.handleUploadPromise(this.assetService.upload(AssetEndpoint.IAMDARKICON, formData));
break;
}
}
if (theme === Theme.LIGHT) {
switch (this.serviceType) {
case PolicyComponentServiceType.MGMT:
this.handleUploadPromise(this.uploadService.upload(UploadEndpoint.MGMTLIGHTICON, formData));
this.handleUploadPromise(this.assetService.upload(AssetEndpoint.MGMTICON, formData));
break;
case PolicyComponentServiceType.ADMIN:
this.handleUploadPromise(this.uploadService.upload(UploadEndpoint.IAMLIGHTICON, formData));
this.handleUploadPromise(this.assetService.upload(AssetEndpoint.IAMICON, formData));
break;
}
}
}
}
private handleFontUploadPromise(task: Promise<any>): Promise<any> {
return task.then(() => {
this.toast.showInfo('POLICY.TOAST.UPLOADSUCCESS', true);
setTimeout(() => {
this.getPreviewData().then(data => {
if (data.policy) {
this.previewData = data.policy;
}
});
}, 1000);
}).catch(error => this.toast.showError(error));
}
private handleUploadPromise(task: Promise<any>): Promise<any> {
return task.then(() => {
this.toast.showInfo('POLICY.TOAST.UPLOADSUCCESS', true);
@ -250,63 +338,86 @@ export class PrivateLabelingPolicyComponent implements OnDestroy {
}
private loadImages(): void {
const promises: Promise<any>[] = [];
if (this.serviceType === PolicyComponentServiceType.ADMIN) {
if (this.data.logoUrlDark) {
this.loadAsset('darkLogo', DownloadEndpoint.IAMDARKLOGOPREVIEW);
promises.push(this.loadAsset('darkLogo', AssetEndpoint.IAMDARKLOGO));
}
if (this.data.iconUrlDark) {
this.loadAsset('darkIcon', DownloadEndpoint.IAMDARKICONPREVIEW);
promises.push(this.loadAsset('darkIcon', AssetEndpoint.IAMDARKICON));
}
if (this.data.logoUrl) {
this.loadAsset('logo', DownloadEndpoint.IAMLOGOPREVIEW);
promises.push(this.loadAsset('logo', AssetEndpoint.IAMLOGO));
}
if (this.data.iconUrl) {
this.loadAsset('icon', DownloadEndpoint.IAMICONPREVIEW);
promises.push(this.loadAsset('icon', AssetEndpoint.IAMICON));
}
} else if (this.serviceType === PolicyComponentServiceType.MGMT) {
if (this.data.logoUrlDark) {
this.loadAsset('darkLogo', DownloadEndpoint.MGMTDARKLOGOPREVIEW);
promises.push(this.loadAsset('darkLogo', AssetEndpoint.MGMTDARKLOGO));
}
if (this.data.iconUrlDark) {
this.loadAsset('darkIcon', DownloadEndpoint.MGMTDARKICONPREVIEW);
promises.push(this.loadAsset('darkIcon', AssetEndpoint.MGMTDARKICON));
}
if (this.data.logoUrl) {
this.loadAsset('logo', DownloadEndpoint.MGMTLOGOPREVIEW);
promises.push(this.loadAsset('logo', AssetEndpoint.MGMTLOGO));
}
if (this.data.iconUrl) {
this.loadAsset('icon', DownloadEndpoint.MGMTICONPREVIEW);
promises.push(this.loadAsset('icon', AssetEndpoint.MGMTICON));
}
}
if (promises.length) {
Promise.all(promises).then(() => {
this.loadingImages = false;
}).catch(error => {
this.loadingImages = false;
});
} else {
this.loadingImages = false;
}
}
private loadPreviewImages(): void {
const promises: Promise<any>[] = [];
if (this.serviceType === PolicyComponentServiceType.ADMIN) {
if (this.previewData.logoUrlDark) {
this.loadAsset('previewDarkLogo', DownloadEndpoint.IAMDARKLOGOPREVIEW);
promises.push(this.loadAsset('previewDarkLogo', AssetEndpoint.IAMDARKLOGOPREVIEW));
}
if (this.previewData.iconUrlDark) {
this.loadAsset('previewDarkIcon', DownloadEndpoint.IAMDARKICONPREVIEW);
promises.push(this.loadAsset('previewDarkIcon', AssetEndpoint.IAMDARKICONPREVIEW));
}
if (this.previewData.logoUrl) {
this.loadAsset('previewLogo', DownloadEndpoint.IAMLOGOPREVIEW);
promises.push(this.loadAsset('previewLogo', AssetEndpoint.IAMLOGOPREVIEW));
}
if (this.previewData.iconUrl) {
this.loadAsset('previewIcon', DownloadEndpoint.IAMICONPREVIEW);
promises.push(this.loadAsset('previewIcon', AssetEndpoint.IAMICONPREVIEW));
}
} else if (this.serviceType === PolicyComponentServiceType.MGMT) {
if (this.previewData.logoUrlDark) {
this.loadAsset('previewDarkLogo', DownloadEndpoint.MGMTDARKLOGOPREVIEW);
promises.push(this.loadAsset('previewDarkLogo', AssetEndpoint.MGMTDARKLOGOPREVIEW));
}
if (this.previewData.iconUrlDark) {
this.loadAsset('previewDarkIcon', DownloadEndpoint.MGMTDARKICONPREVIEW);
promises.push(this.loadAsset('previewDarkIcon', AssetEndpoint.MGMTDARKICONPREVIEW));
}
if (this.previewData.logoUrl) {
this.loadAsset('previewLogo', DownloadEndpoint.MGMTLOGOPREVIEW);
promises.push(this.loadAsset('previewLogo', AssetEndpoint.MGMTLOGOPREVIEW));
}
if (this.previewData.iconUrl) {
this.loadAsset('previewIcon', DownloadEndpoint.MGMTICONPREVIEW);
promises.push(this.loadAsset('previewIcon', AssetEndpoint.MGMTICONPREVIEW));
}
}
if (promises.length) {
Promise.all(promises).then(() => {
this.loadingImages = false;
}).catch(error => {
this.loadingImages = false;
});
} else {
this.loadingImages = false;
}
}
public ngOnDestroy(): void {
@ -340,14 +451,12 @@ export class PrivateLabelingPolicyComponent implements OnDestroy {
}
private loadAsset(imagekey: string, url: string): Promise<any> {
return this.uploadService.load(`${url}`).then(data => {
return this.assetService.load(`${url}`).then(data => {
const objectURL = URL.createObjectURL(data);
this.images[imagekey] = this.sanitizer.bypassSecurityTrustUrl(objectURL);
this.refreshPreview.emit();
this.loadingImages = false;
}).catch(error => {
this.toast.showError(error);
this.loadingImages = false;
});
}

View File

@ -1,3 +1,4 @@
import { OverlayModule } from '@angular/cdk/overlay';
import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
@ -8,6 +9,7 @@ import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
import { MatSlideToggleModule } from '@angular/material/slide-toggle';
import { MatTooltipModule } from '@angular/material/tooltip';
import { TranslateModule } from '@ngx-translate/core';
import { ColorChromeModule } from 'ngx-color/chrome';
import { HasRoleModule } from 'src/app/directives/has-role/has-role.module';
import { HasFeaturePipeModule } from 'src/app/pipes/has-feature-pipe/has-feature-pipe.module';
@ -28,12 +30,14 @@ import { PrivateLabelingPolicyComponent } from './private-labeling-policy.compon
ColorComponent,
],
imports: [
ColorChromeModule,
PrivateLabelingPolicyRoutingModule,
CommonModule,
FormsModule,
InputModule,
MatButtonModule,
MatSlideToggleModule,
OverlayModule,
MatIconModule,
HasRoleModule,
MatTooltipModule,

View File

@ -12,143 +12,143 @@ import { ManagementService } from 'src/app/services/mgmt.service';
export enum ProjectAutocompleteType {
PROJECT_OWNED = 0,
PROJECT_GRANTED = 1,
PROJECT_OWNED = 0,
PROJECT_GRANTED = 1,
}
@Component({
selector: 'app-search-project-autocomplete',
templateUrl: './search-project-autocomplete.component.html',
styleUrls: ['./search-project-autocomplete.component.scss'],
selector: 'app-search-project-autocomplete',
templateUrl: './search-project-autocomplete.component.html',
styleUrls: ['./search-project-autocomplete.component.scss'],
})
export class SearchProjectAutocompleteComponent implements OnDestroy {
public selectable: boolean = true;
public removable: boolean = true;
public addOnBlur: boolean = true;
public separatorKeysCodes: number[] = [ENTER, COMMA];
public myControl: FormControl = new FormControl();
public names: string[] = [];
public projects: Array<GrantedProject.AsObject | Project.AsObject | any> = [];
public filteredProjects: Array<GrantedProject.AsObject | Project.AsObject | any> = [];
public isLoading: boolean = false;
@ViewChild('nameInput') public nameInput!: ElementRef<HTMLInputElement>;
@ViewChild('auto') public matAutocomplete!: MatAutocomplete;
@Input() public singleOutput: boolean = false;
@Input() public autocompleteType!: ProjectAutocompleteType;
@Output() public selectionChanged: EventEmitter<
GrantedProject.AsObject[]
| GrantedProject.AsObject
| Project.AsObject
| Project.AsObject[]
> = new EventEmitter();
public selectable: boolean = true;
public removable: boolean = true;
public addOnBlur: boolean = true;
public separatorKeysCodes: number[] = [ENTER, COMMA];
public myControl: FormControl = new FormControl();
public names: string[] = [];
public projects: Array<GrantedProject.AsObject | Project.AsObject | any> = [];
public filteredProjects: Array<GrantedProject.AsObject | Project.AsObject | any> = [];
public isLoading: boolean = false;
@ViewChild('nameInput') public nameInput!: ElementRef<HTMLInputElement>;
@ViewChild('auto') public matAutocomplete!: MatAutocomplete;
@Input() public singleOutput: boolean = false;
@Input() public autocompleteType!: ProjectAutocompleteType;
@Output() public selectionChanged: EventEmitter<
GrantedProject.AsObject[]
| GrantedProject.AsObject
| Project.AsObject
| Project.AsObject[]
> = new EventEmitter();
private unsubscribed$: Subject<void> = new Subject();
constructor(private mgmtService: ManagementService) {
this.myControl.valueChanges
.pipe(
takeUntil(this.unsubscribed$),
debounceTime(200),
tap(() => this.isLoading = true),
switchMap(value => {
const query = new ProjectQuery();
const nameQuery = new ProjectNameQuery();
nameQuery.setName(value);
nameQuery.setMethod(TextQueryMethod.TEXT_QUERY_METHOD_CONTAINS_IGNORE_CASE);
query.setNameQuery(nameQuery);
private unsubscribed$: Subject<void> = new Subject();
constructor(private mgmtService: ManagementService) {
this.myControl.valueChanges
.pipe(
takeUntil(this.unsubscribed$),
debounceTime(200),
tap(() => this.isLoading = true),
switchMap(value => {
const query = new ProjectQuery();
const nameQuery = new ProjectNameQuery();
nameQuery.setName(value);
nameQuery.setMethod(TextQueryMethod.TEXT_QUERY_METHOD_CONTAINS_IGNORE_CASE);
query.setNameQuery(nameQuery);
switch (this.autocompleteType) {
case ProjectAutocompleteType.PROJECT_GRANTED:
return from(this.mgmtService.listGrantedProjects(10, 0, [query]));
case ProjectAutocompleteType.PROJECT_OWNED:
return from(this.mgmtService.listProjects(10, 0, [query]));
default:
return forkJoin([
from(this.mgmtService.listGrantedProjects(10, 0, [query])),
from(this.mgmtService.listProjects(10, 0, [query])),
]);
}
}),
).subscribe((returnValue) => {
switch (this.autocompleteType) {
case ProjectAutocompleteType.PROJECT_GRANTED:
this.isLoading = false;
this.filteredProjects = [...(returnValue as ListProjectGrantsResponse.AsObject).resultList];
break;
case ProjectAutocompleteType.PROJECT_OWNED:
this.isLoading = false;
this.filteredProjects = [...(returnValue as ListProjectsResponse.AsObject).resultList];
break;
default:
this.isLoading = false;
this.filteredProjects = [
...(returnValue as (ListProjectsResponse.AsObject | ListProjectGrantsResponse.AsObject)[])[0]
.resultList,
...(returnValue as (ListProjectsResponse.AsObject | ListProjectGrantsResponse.AsObject)[])[1]
.resultList,
];
break;
}
});
}
public ngOnDestroy(): void {
this.unsubscribed$.next();
}
public displayFn(project?: any): string | undefined {
return (project && project.projectName) ? `${project.projectName}` :
(project && project.name) ? `${project.name}` : undefined;
}
public add(event: MatChipInputEvent): void {
if (!this.matAutocomplete.isOpen) {
const input = event.input;
const value = event.value;
if ((value || '').trim()) {
const index = this.filteredProjects.findIndex((project) => {
if (project?.projectName) {
return project.projectName === value;
} else if (project?.name) {
return project.name === value;
}
});
if (index > -1) {
if (this.projects && this.projects.length > 0) {
this.projects.push(this.filteredProjects[index]);
} else {
this.projects = [this.filteredProjects[index]];
}
}
}
if (input) {
input.value = '';
}
switch (this.autocompleteType) {
case ProjectAutocompleteType.PROJECT_GRANTED:
return from(this.mgmtService.listGrantedProjects(10, 0, [query]));
case ProjectAutocompleteType.PROJECT_OWNED:
return from(this.mgmtService.listProjects(10, 0, [query]));
default:
return forkJoin([
from(this.mgmtService.listGrantedProjects(10, 0, [query])),
from(this.mgmtService.listProjects(10, 0, [query])),
]);
}
}),
).subscribe((returnValue) => {
switch (this.autocompleteType) {
case ProjectAutocompleteType.PROJECT_GRANTED:
this.isLoading = false;
this.filteredProjects = [...(returnValue as ListProjectGrantsResponse.AsObject).resultList];
break;
case ProjectAutocompleteType.PROJECT_OWNED:
this.isLoading = false;
this.filteredProjects = [...(returnValue as ListProjectsResponse.AsObject).resultList];
break;
default:
this.isLoading = false;
this.filteredProjects = [
...(returnValue as (ListProjectsResponse.AsObject | ListProjectGrantsResponse.AsObject)[])[0]
.resultList,
...(returnValue as (ListProjectsResponse.AsObject | ListProjectGrantsResponse.AsObject)[])[1]
.resultList,
];
break;
}
}
});
}
public remove(project: GrantedProject.AsObject): void {
const index = this.projects.indexOf(project);
public ngOnDestroy(): void {
this.unsubscribed$.next();
}
if (index >= 0) {
this.projects.splice(index, 1);
public displayFn(project?: any): string | undefined {
return (project && project.projectName) ? `${project.projectName}` :
(project && project.name) ? `${project.name}` : undefined;
}
public add(event: MatChipInputEvent): void {
if (!this.matAutocomplete.isOpen) {
const input = event.chipInput?.inputElement;
const value = event.value;
if ((value || '').trim()) {
const index = this.filteredProjects.findIndex((project) => {
if (project?.projectName) {
return project.projectName === value;
} else if (project?.name) {
return project.name === value;
}
});
if (index > -1) {
if (this.projects && this.projects.length > 0) {
this.projects.push(this.filteredProjects[index]);
} else {
this.projects = [this.filteredProjects[index]];
}
}
}
}
public selected(event: MatAutocompleteSelectedEvent): void {
if (this.singleOutput) {
this.selectionChanged.emit(event.option.value);
} else {
if (this.projects && this.projects.length > 0) {
this.projects.push(event.option.value);
} else {
this.projects = [event.option.value];
}
this.selectionChanged.emit(this.projects);
this.nameInput.nativeElement.value = '';
this.myControl.setValue(null);
}
if (input) {
input.value = '';
}
}
}
public remove(project: GrantedProject.AsObject): void {
const index = this.projects.indexOf(project);
if (index >= 0) {
this.projects.splice(index, 1);
}
}
public selected(event: MatAutocompleteSelectedEvent): void {
if (this.singleOutput) {
this.selectionChanged.emit(event.option.value);
} else {
if (this.projects && this.projects.length > 0) {
this.projects.push(event.option.value);
} else {
this.projects = [event.option.value];
}
this.selectionChanged.emit(this.projects);
this.nameInput.nativeElement.value = '';
this.myControl.setValue(null);
}
}
}

View File

@ -10,113 +10,113 @@ import { ManagementService } from 'src/app/services/mgmt.service';
@Component({
selector: 'app-search-roles-autocomplete',
templateUrl: './search-roles-autocomplete.component.html',
styleUrls: ['./search-roles-autocomplete.component.scss'],
selector: 'app-search-roles-autocomplete',
templateUrl: './search-roles-autocomplete.component.html',
styleUrls: ['./search-roles-autocomplete.component.scss'],
})
export class SearchRolesAutocompleteComponent implements OnDestroy {
public selectable: boolean = true;
public removable: boolean = true;
public addOnBlur: boolean = true;
public separatorKeysCodes: number[] = [ENTER, COMMA];
public myControl: FormControl = new FormControl();
public names: string[] = [];
public roles: Array<Role.AsObject> = [];
public filteredRoles: Array<Role.AsObject> = [];
public isLoading: boolean = false;
@ViewChild('nameInput') public nameInput!: ElementRef<HTMLInputElement>;
@ViewChild('auto') public matAutocomplete!: MatAutocomplete;
@Input() public projectId: string = '';
@Input() public singleOutput: boolean = false;
@Output() public selectionChanged: EventEmitter<Role.AsObject[] | Role.AsObject> = new EventEmitter();
public selectable: boolean = true;
public removable: boolean = true;
public addOnBlur: boolean = true;
public separatorKeysCodes: number[] = [ENTER, COMMA];
public myControl: FormControl = new FormControl();
public names: string[] = [];
public roles: Array<Role.AsObject> = [];
public filteredRoles: Array<Role.AsObject> = [];
public isLoading: boolean = false;
@ViewChild('nameInput') public nameInput!: ElementRef<HTMLInputElement>;
@ViewChild('auto') public matAutocomplete!: MatAutocomplete;
@Input() public projectId: string = '';
@Input() public singleOutput: boolean = false;
@Output() public selectionChanged: EventEmitter<Role.AsObject[] | Role.AsObject> = new EventEmitter();
private unsubscribed$: Subject<void> = new Subject();
constructor(private mgmtService: ManagementService) {
this.myControl.valueChanges
.pipe(
takeUntil(this.unsubscribed$),
debounceTime(200),
tap(() => this.isLoading = true),
switchMap(value => {
const query = new RoleQuery();
private unsubscribed$: Subject<void> = new Subject();
constructor(private mgmtService: ManagementService) {
this.myControl.valueChanges
.pipe(
takeUntil(this.unsubscribed$),
debounceTime(200),
tap(() => this.isLoading = true),
switchMap(value => {
const query = new RoleQuery();
// const key = new RoleKeyQuery();
// key.setKey(key)
// query.setKey(key)
// const key = new RoleKeyQuery();
// key.setKey(key)
// query.setKey(key)
const dQuery = new RoleDisplayNameQuery();
dQuery.setDisplayName(value);
query.setDisplayNameQuery(dQuery);
const dQuery = new RoleDisplayNameQuery();
dQuery.setDisplayName(value);
query.setDisplayNameQuery(dQuery);
return from(this.mgmtService.listProjectRoles(this.projectId, 10, 0, [query]));
}),
).subscribe((resp) => {
this.isLoading = false;
this.filteredRoles = resp.resultList;
}, error => {
this.isLoading = false;
});
}
return from(this.mgmtService.listProjectRoles(this.projectId, 10, 0, [query]));
}),
).subscribe((resp) => {
this.isLoading = false;
this.filteredRoles = resp.resultList;
}, error => {
this.isLoading = false;
});
}
public ngOnDestroy(): void {
this.unsubscribed$.next();
}
public ngOnDestroy(): void {
this.unsubscribed$.next();
}
public displayFn(project?: Role.AsObject): string | undefined {
return project ? `${project.displayName}` : undefined;
}
public displayFn(project?: Role.AsObject): string | undefined {
return project ? `${project.displayName}` : undefined;
}
public add(event: MatChipInputEvent): void {
if (!this.matAutocomplete.isOpen) {
const input = event.input;
const value = event.value;
public add(event: MatChipInputEvent): void {
if (!this.matAutocomplete.isOpen) {
const input = event.chipInput?.inputElement;
const value = event.value;
if ((value || '').trim()) {
const index = this.filteredRoles.findIndex((role) => {
if (role.key) {
return role.key === value;
}
});
if (index > -1) {
if (this.roles && this.roles.length > 0) {
this.roles.push(this.filteredRoles[index]);
} else {
this.roles = [this.filteredRoles[index]];
}
}
}
if (input) {
input.value = '';
}
if ((value || '').trim()) {
const index = this.filteredRoles.findIndex((role) => {
if (role.key) {
return role.key === value;
}
});
if (index > -1) {
if (this.roles && this.roles.length > 0) {
this.roles.push(this.filteredRoles[index]);
} else {
this.roles = [this.filteredRoles[index]];
}
}
}
if (input) {
input.value = '';
}
}
}
public remove(role: Role.AsObject): void {
const index = this.roles.indexOf(role);
if (index >= 0) {
this.roles.splice(index, 1);
}
}
public selected(event: MatAutocompleteSelectedEvent): void {
const index = this.filteredRoles.findIndex((role) => role.key === event.option.value);
if (index !== -1) {
if (this.singleOutput) {
this.selectionChanged.emit(this.filteredRoles[index]);
} else {
if (this.roles && this.roles.length > 0) {
this.roles.push(this.filteredRoles[index]);
} else {
this.roles = [this.filteredRoles[index]];
}
this.selectionChanged.emit(this.roles);
this.nameInput.nativeElement.value = '';
this.myControl.setValue(null);
}
public remove(role: Role.AsObject): void {
const index = this.roles.indexOf(role);
if (index >= 0) {
this.roles.splice(index, 1);
}
}
public selected(event: MatAutocompleteSelectedEvent): void {
const index = this.filteredRoles.findIndex((role) => role.key === event.option.value);
if (index !== -1) {
if (this.singleOutput) {
this.selectionChanged.emit(this.filteredRoles[index]);
} else {
if (this.roles && this.roles.length > 0) {
this.roles.push(this.filteredRoles[index]);
} else {
this.roles = [this.filteredRoles[index]];
}
this.selectionChanged.emit(this.roles);
this.nameInput.nativeElement.value = '';
this.myControl.setValue(null);
}
}
}
}

View File

@ -1,14 +1,14 @@
import { COMMA, ENTER } from '@angular/cdk/keycodes';
import {
AfterContentChecked,
ChangeDetectorRef,
Component,
ElementRef,
EventEmitter,
Input,
OnInit,
Output,
ViewChild,
AfterContentChecked,
ChangeDetectorRef,
Component,
ElementRef,
EventEmitter,
Input,
OnInit,
Output,
ViewChild,
} from '@angular/core';
import { FormControl } from '@angular/forms';
import { MatAutocomplete, MatAutocompleteSelectedEvent } from '@angular/material/autocomplete';
@ -22,163 +22,163 @@ import { ManagementService } from 'src/app/services/mgmt.service';
import { ToastService } from 'src/app/services/toast.service';
export enum UserTarget {
SELF = 'self',
EXTERNAL = 'external',
SELF = 'self',
EXTERNAL = 'external',
}
@Component({
selector: 'app-search-user-autocomplete',
templateUrl: './search-user-autocomplete.component.html',
styleUrls: ['./search-user-autocomplete.component.scss'],
selector: 'app-search-user-autocomplete',
templateUrl: './search-user-autocomplete.component.html',
styleUrls: ['./search-user-autocomplete.component.scss'],
})
export class SearchUserAutocompleteComponent implements OnInit, AfterContentChecked {
public selectable: boolean = true;
public removable: boolean = true;
public addOnBlur: boolean = true;
public separatorKeysCodes: number[] = [ENTER, COMMA];
public selectable: boolean = true;
public removable: boolean = true;
public addOnBlur: boolean = true;
public separatorKeysCodes: number[] = [ENTER, COMMA];
public myControl: FormControl = new FormControl();
public globalLoginNameControl: FormControl = new FormControl();
public myControl: FormControl = new FormControl();
public globalLoginNameControl: FormControl = new FormControl();
public loginNames: string[] = [];
@Input() public users: Array<User.AsObject> = [];
public filteredUsers: Array<User.AsObject> = [];
public isLoading: boolean = false;
@Input() public target: UserTarget = UserTarget.SELF;
public hint: string = '';
public UserTarget: any = UserTarget;
@ViewChild('usernameInput') public usernameInput!: ElementRef<HTMLInputElement>;
@ViewChild('auto') public matAutocomplete!: MatAutocomplete;
@Output() public selectionChanged: EventEmitter<User.AsObject | User.AsObject[]> = new EventEmitter();
@Input() public singleOutput: boolean = false;
public loginNames: string[] = [];
@Input() public users: Array<User.AsObject> = [];
public filteredUsers: Array<User.AsObject> = [];
public isLoading: boolean = false;
@Input() public target: UserTarget = UserTarget.SELF;
public hint: string = '';
public UserTarget: any = UserTarget;
@ViewChild('usernameInput') public usernameInput!: ElementRef<HTMLInputElement>;
@ViewChild('auto') public matAutocomplete!: MatAutocomplete;
@Output() public selectionChanged: EventEmitter<User.AsObject | User.AsObject[]> = new EventEmitter();
@Input() public singleOutput: boolean = false;
private unsubscribed$: Subject<void> = new Subject();
constructor(private userService: ManagementService, private toast: ToastService, private cdref: ChangeDetectorRef) { }
private unsubscribed$: Subject<void> = new Subject();
constructor(private userService: ManagementService, private toast: ToastService, private cdref: ChangeDetectorRef) { }
public ngOnInit(): void {
if (this.target === UserTarget.EXTERNAL) {
this.filteredUsers = [];
this.unsubscribed$.next(); // clear old subscription
} else if (this.target === UserTarget.SELF) {
this.getFilteredResults(); // new subscription
}
public ngOnInit(): void {
if (this.target === UserTarget.EXTERNAL) {
this.filteredUsers = [];
this.unsubscribed$.next(); // clear old subscription
} else if (this.target === UserTarget.SELF) {
this.getFilteredResults(); // new subscription
}
}
public ngAfterContentChecked(): void {
this.cdref.detectChanges();
}
public ngAfterContentChecked(): void {
this.cdref.detectChanges();
}
private getFilteredResults(): void {
this.myControl.valueChanges.pipe(debounceTime(200),
takeUntil(this.unsubscribed$),
tap(() => this.isLoading = true),
switchMap(value => {
const query = new SearchQuery();
private getFilteredResults(): void {
this.myControl.valueChanges.pipe(debounceTime(200),
takeUntil(this.unsubscribed$),
tap(() => this.isLoading = true),
switchMap(value => {
const query = new SearchQuery();
const unQuery = new UserNameQuery();
unQuery.setMethod(TextQueryMethod.TEXT_QUERY_METHOD_CONTAINS_IGNORE_CASE);
unQuery.setUserName(value);
const unQuery = new UserNameQuery();
unQuery.setMethod(TextQueryMethod.TEXT_QUERY_METHOD_CONTAINS_IGNORE_CASE);
unQuery.setUserName(value);
query.setUserNameQuery(unQuery);
query.setUserNameQuery(unQuery);
if (this.target === UserTarget.SELF) {
return from(this.userService.listUsers(10, 0, [query]));
} else {
return of();
}
}),
).subscribe((userresp: ListUsersResponse.AsObject | unknown) => {
this.isLoading = false;
if (this.target === UserTarget.SELF && userresp) {
this.filteredUsers = (userresp as ListUsersResponse.AsObject).resultList;
}
});
}
public displayFn(user?: User.AsObject): string | undefined {
return user ? `${user.preferredLoginName}` : undefined;
}
public add(event: MatChipInputEvent): void {
if (!this.matAutocomplete.isOpen) {
const input = event.input;
const value = event.value;
if ((value || '').trim()) {
const index = this.filteredUsers.findIndex((user) => {
if (user.preferredLoginName) {
return user.preferredLoginName === value;
}
});
if (index > -1) {
if (this.users && this.users.length > 0) {
this.users.push(this.filteredUsers[index]);
} else {
this.users = [this.filteredUsers[index]];
}
}
}
if (input) {
input.value = '';
}
}
}
public remove(user: User.AsObject): void {
const index = this.users.indexOf(user);
if (index >= 0) {
this.users.splice(index, 1);
this.selectionChanged.emit(this.users);
}
}
public selected(event: MatAutocompleteSelectedEvent): void {
const index = this.filteredUsers.findIndex((user) => user === event.option.value);
if (index !== -1) {
if (this.singleOutput) {
this.selectionChanged.emit(this.filteredUsers[index]);
} else {
if (this.users && this.users.length > 0) {
this.users.push(this.filteredUsers[index]);
} else {
this.users = [this.filteredUsers[index]];
}
if (this.singleOutput) {
this.selectionChanged.emit(this.users[0]);
} else {
this.selectionChanged.emit(this.users);
}
this.usernameInput.nativeElement.value = '';
this.myControl.setValue(null);
}
}
}
public changeTarget(): void {
if (this.target === UserTarget.SELF) {
this.target = UserTarget.EXTERNAL;
this.filteredUsers = [];
this.unsubscribed$.next(); // clear old subscription
} else if (this.target === UserTarget.EXTERNAL) {
this.target = UserTarget.SELF;
this.getFilteredResults(); // new subscription
return from(this.userService.listUsers(10, 0, [query]));
} else {
return of();
}
}
}),
).subscribe((userresp: ListUsersResponse.AsObject | unknown) => {
this.isLoading = false;
if (this.target === UserTarget.SELF && userresp) {
this.filteredUsers = (userresp as ListUsersResponse.AsObject).resultList;
}
});
}
public getGlobalUser(): void {
this.userService.getUserByLoginNameGlobal(this.globalLoginNameControl.value).then(resp => {
if (this.singleOutput && resp.user) {
this.users = [resp.user];
this.selectionChanged.emit(this.users[0]);
} else if (resp.user) {
this.users.push(resp.user);
this.selectionChanged.emit(this.users);
}
}).catch(error => {
this.toast.showError(error);
public displayFn(user?: User.AsObject): string | undefined {
return user ? `${user.preferredLoginName}` : undefined;
}
public add(event: MatChipInputEvent): void {
if (!this.matAutocomplete.isOpen) {
const input = event.chipInput?.inputElement;
const value = event.value;
if ((value || '').trim()) {
const index = this.filteredUsers.findIndex((user) => {
if (user.preferredLoginName) {
return user.preferredLoginName === value;
}
});
if (index > -1) {
if (this.users && this.users.length > 0) {
this.users.push(this.filteredUsers[index]);
} else {
this.users = [this.filteredUsers[index]];
}
}
}
if (input) {
input.value = '';
}
}
}
public remove(user: User.AsObject): void {
const index = this.users.indexOf(user);
if (index >= 0) {
this.users.splice(index, 1);
this.selectionChanged.emit(this.users);
}
}
public selected(event: MatAutocompleteSelectedEvent): void {
const index = this.filteredUsers.findIndex((user) => user === event.option.value);
if (index !== -1) {
if (this.singleOutput) {
this.selectionChanged.emit(this.filteredUsers[index]);
} else {
if (this.users && this.users.length > 0) {
this.users.push(this.filteredUsers[index]);
} else {
this.users = [this.filteredUsers[index]];
}
if (this.singleOutput) {
this.selectionChanged.emit(this.users[0]);
} else {
this.selectionChanged.emit(this.users);
}
this.usernameInput.nativeElement.value = '';
this.myControl.setValue(null);
}
}
}
public changeTarget(): void {
if (this.target === UserTarget.SELF) {
this.target = UserTarget.EXTERNAL;
this.filteredUsers = [];
this.unsubscribed$.next(); // clear old subscription
} else if (this.target === UserTarget.EXTERNAL) {
this.target = UserTarget.SELF;
this.getFilteredResults(); // new subscription
}
}
public getGlobalUser(): void {
this.userService.getUserByLoginNameGlobal(this.globalLoginNameControl.value).then(resp => {
if (this.singleOutput && resp.user) {
this.users = [resp.user];
this.selectionChanged.emit(this.users[0]);
} else if (resp.user) {
this.users.push(resp.user);
this.selectionChanged.emit(this.users);
}
}).catch(error => {
this.toast.showError(error);
});
}
}

View File

@ -1,6 +1,8 @@
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { PolicyComponentServiceType } from '../modules/policies/policy-component-types.enum';
import { Theme } from '../modules/policies/private-labeling-policy/private-labeling-policy.component';
import { Org } from '../proto/generated/zitadel/org_pb';
import { StorageService } from './storage.service';
@ -11,22 +13,12 @@ const orgKey = 'x-zitadel-orgid';
const bearerPrefix = 'Bearer';
const accessTokenStorageKey = 'access_token';
export enum UploadEndpoint {
IAMFONT = 'iam/policy/label/font',
MGMTFONT = 'org/policy/label/font',
IAMDARKLOGO = 'iam/policy/label/logo/dark',
IAMLIGHTLOGO = 'iam/policy/label/logo',
IAMDARKICON = 'iam/policy/label/icon/dark',
IAMLIGHTICON = 'iam/policy/label/icon',
MGMTDARKLOGO = 'org/policy/label/logo/dark',
MGMTLIGHTLOGO = 'org/policy/label/logo',
MGMTDARKICON = 'org/policy/label/icon/dark',
MGMTLIGHTICON = 'org/policy/label/icon',
export enum AssetType {
LOGO,
ICON,
}
export enum DownloadEndpoint {
export enum AssetEndpoint {
IAMFONT = 'iam/policy/label/font',
MGMTFONT = 'org/policy/label/font',
@ -51,10 +43,33 @@ export enum DownloadEndpoint {
MGMTICONPREVIEW = 'org/policy/label/icon/_preview',
}
export const ENDPOINT = {
[Theme.DARK]: {
[PolicyComponentServiceType.ADMIN]: {
[AssetType.LOGO]: AssetEndpoint.IAMDARKLOGO,
[AssetType.ICON]: AssetEndpoint.IAMDARKICON,
},
[PolicyComponentServiceType.MGMT]: {
[AssetType.LOGO]: AssetEndpoint.MGMTDARKLOGO,
[AssetType.ICON]: AssetEndpoint.MGMTDARKICON,
},
},
[Theme.LIGHT]: {
[PolicyComponentServiceType.ADMIN]: {
[AssetType.LOGO]: AssetEndpoint.IAMLOGO,
[AssetType.ICON]: AssetEndpoint.IAMICON,
},
[PolicyComponentServiceType.MGMT]: {
[AssetType.LOGO]: AssetEndpoint.MGMTLOGO,
[AssetType.ICON]: AssetEndpoint.MGMTICON,
},
},
};
@Injectable({
providedIn: 'root',
})
export class UploadService {
export class AssetService {
private serviceUrl: string = '';
private accessToken: string = '';
private org!: Org.AsObject;
@ -81,7 +96,7 @@ export class UploadService {
});
}
public upload(endpoint: UploadEndpoint, body: any): Promise<any> {
public upload(endpoint: AssetEndpoint, body: any): Promise<any> {
return this.http.post(`${this.serviceUrl}/assets/v1/${endpoint}`,
body,
{
@ -103,4 +118,14 @@ export class UploadService {
},
}).toPromise();
}
public delete(endpoint: AssetEndpoint): Promise<any> {
return this.http.delete(`${this.serviceUrl}/assets/v1/${endpoint}`,
{
headers: {
[authorizationKey]: `${bearerPrefix} ${this.accessToken}`,
[orgKey]: `${this.org.id}`,
},
}).toPromise();
}
}

View File

@ -12,6 +12,8 @@ import {
RemoveLabelPolicyIconResponse,
RemoveLabelPolicyLogoDarkRequest,
RemoveLabelPolicyLogoDarkResponse,
RemoveLabelPolicyLogoRequest,
RemoveLabelPolicyLogoResponse,
} from '../proto/generated/zitadel/admin_pb';
import { AppQuery } from '../proto/generated/zitadel/app_pb';
import { KeyType } from '../proto/generated/zitadel/auth_n_key_pb';
@ -212,8 +214,6 @@ import {
RemoveAppKeyResponse,
RemoveAppRequest,
RemoveAppResponse,
RemoveCustomLabelPolicyLogoRequest,
RemoveCustomLabelPolicyLogoResponse,
RemoveHumanAuthFactorOTPRequest,
RemoveHumanAuthFactorOTPResponse,
RemoveHumanAuthFactorU2FRequest,
@ -783,31 +783,31 @@ export class ManagementService {
public removeLabelPolicyFont():
Promise<RemoveLabelPolicyFontResponse.AsObject> {
const req = new RemoveLabelPolicyFontRequest();
return this.grpcService.admin.removeLabelPolicyFont(req, null).then(resp => resp.toObject());
return this.grpcService.mgmt.removeCustomLabelPolicyFont(req, null).then(resp => resp.toObject());
}
public removeLabelPolicyIcon():
Promise<RemoveLabelPolicyIconResponse.AsObject> {
const req = new RemoveLabelPolicyIconRequest();
return this.grpcService.admin.removeLabelPolicyIcon(req, null).then(resp => resp.toObject());
return this.grpcService.mgmt.removeCustomLabelPolicyIcon(req, null).then(resp => resp.toObject());
}
public removeLabelPolicyIconDark():
Promise<RemoveLabelPolicyIconDarkResponse.AsObject> {
const req = new RemoveLabelPolicyIconDarkRequest();
return this.grpcService.admin.removeLabelPolicyIconDark(req, null).then(resp => resp.toObject());
return this.grpcService.mgmt.removeCustomLabelPolicyIconDark(req, null).then(resp => resp.toObject());
}
public removeCustomLabelPolicyLogo():
Promise<RemoveCustomLabelPolicyLogoResponse.AsObject> {
const req = new RemoveCustomLabelPolicyLogoRequest();
public removeLabelPolicyLogo():
Promise<RemoveLabelPolicyLogoResponse.AsObject> {
const req = new RemoveLabelPolicyLogoRequest();
return this.grpcService.mgmt.removeCustomLabelPolicyLogo(req, null).then(resp => resp.toObject());
}
public removeLabelPolicyLogoDark():
Promise<RemoveLabelPolicyLogoDarkResponse.AsObject> {
const req = new RemoveLabelPolicyLogoDarkRequest();
return this.grpcService.admin.removeLabelPolicyLogoDark(req, null).then(resp => resp.toObject());
return this.grpcService.mgmt.removeCustomLabelPolicyLogoDark(req, null).then(resp => resp.toObject());
}
public getOrgIAMPolicy(): Promise<GetOrgIAMPolicyResponse.AsObject> {

View File

@ -1,9 +1,9 @@
{
"authServiceUrl": "https://api.zitadel.io",
"mgmtServiceUrl": "https://api.zitadel.io",
"adminServiceUrl":"https://api.zitadel.io",
"subscriptionServiceUrl":"https://sub.zitadel.io",
"uploadServiceUrl":"https://api.zitadel.io",
"issuer": "https://issuer.zitadel.io",
"clientid": "69234247558357051@zitadel"
"authServiceUrl": "https://api.zitadel.dev",
"mgmtServiceUrl": "https://api.zitadel.dev",
"adminServiceUrl":"https://api.zitadel.dev",
"subscriptionServiceUrl":"https://sub.zitadel.dev",
"uploadServiceUrl":"https://api.zitadel.dev",
"issuer": "https://issuer.zitadel.dev",
"clientid": "70669160379706195@zitadel"
}

View File

@ -718,6 +718,7 @@
"SET": "Richtline erfolgreich gesetzt!",
"RESETSUCCESS": "Richtline zurückgesetzt!",
"UPLOADSUCCESS": "Upload erfolgreich",
"DELETESUCCESS": "Löschen erfolgreich",
"UPLOADFAILED":"Upload fehlgeschlagen!"
}
},

View File

@ -720,6 +720,7 @@
"SET": "Policy set successfully!",
"RESETSUCCESS": "Policy reset successfully!",
"UPLOADSUCCESS": "Uploaded successfully!",
"DELETESUCCESS": "Deleted successfully!",
"UPLOADFAILED":"Upload failed!"
}
},

View File

@ -14,7 +14,7 @@ $lgn-stroked-button-border-width: 1px;
$lgn-icon-button-size: 40px !default;
$lgn-icon-button-border-radius: 50% !default;
$lgn-icon-button-line-height: 24px !default;
$lgn-icon-button-line-height: 40px !default;
// adds base styles to all button types.
@mixin lgn-button-base {

View File

@ -100,7 +100,8 @@ $lgn-container-bottom-margin: 50px;
.lgn-left-action {
position: absolute;
left: 1rem;
top: -40px;
top: -75px;
transform: translateY(-50%);
}
.lgn-register-options {

View File

@ -30,8 +30,6 @@ footer {
.watermark {
display: flex;
position: relative;
width: 100%;
.powered {
font-size: 12px;
@ -39,9 +37,9 @@ footer {
}
.lgn-logo-watermark {
height: 34px;
width: 125px;
margin: 2px;
height: 40px;
min-width: 125px;
margin: auto 2px;
}
}

View File

@ -18,8 +18,8 @@
}
.lgn-logo-watermark {
background: var(--zitadel-logo-powered-by);
background-position: auto;
background: var(--zitadel-logo-powered-by) no-repeat;
background-position: center;
background-size: contain;
}
}

View File

@ -1,16 +1,22 @@
$lgn-header-padding: 0;
$lgn-header-margin: 1rem auto .5rem auto;
$lgn-header-margin: auto;
.lgn-header {
display: block;
display: flex;
position: relative;
margin: $lgn-header-margin;
padding: $lgn-header-padding;
width: 100%;
max-width: 250px;
min-height: 150px;
align-items: center;
justify-content: center;
.lgn-logo {
display: block;
max-height: 100px;
height: 100px;
margin: 0 auto;
max-width: 250px;
max-height: 150px;
object-fit: contain;
}
}

View File

@ -91,6 +91,7 @@
--zitadel-color-raised-button-background: var(--zitadel-color-white);
--zitadel-color-white: #ffffff;
--zitadel-color-black: #000000;
--zitadel-color-grey-50: #fafafa;
--zitadel-color-grey-100: #f5f5f5;
@ -109,8 +110,8 @@
--zitadel-color-google-text: #8b8d8d;
--zitadel-color-google-background: #ffffff;
--zitadel-color-qr: var(--zitadel-color-white);
--zitadel-color-qr-background: var(--zitadel-color-black);
--zitadel-color-qr: var(--zitadel-color-black);
--zitadel-color-qr-background: var(--zitadel-color-white);
}
.lgn-dark-theme {

View File

@ -77,6 +77,7 @@
--zitadel-color-button-selected-background: var(--zitadel-color-grey-900);
--zitadel-color-button-disabled-selected-background: var(--zitadel-color-grey-800);
--zitadel-color-raised-button-background: var(--zitadel-color-white);
--zitadel-color-white: #ffffff;
--zitadel-color-black: #000000;
--zitadel-color-grey-50: #fafafa;
--zitadel-color-grey-100: #f5f5f5;
@ -92,8 +93,8 @@
--zitadel-logo-powered-by: url("../logo-dark.svg");
--zitadel-color-google-text: #8b8d8d;
--zitadel-color-google-background: #ffffff;
--zitadel-color-qr: var(--zitadel-color-white);
--zitadel-color-qr-background: var(--zitadel-color-black);
--zitadel-color-qr: var(--zitadel-color-black);
--zitadel-color-qr-background: var(--zitadel-color-white);
}
.lgn-dark-theme {
@ -221,30 +222,34 @@ footer a {
}
footer .watermark {
display: flex;
position: relative;
width: 100%;
}
footer .watermark .powered {
font-size: 12px;
margin: auto 2px;
}
footer .watermark .lgn-logo-watermark {
height: 34px;
width: 125px;
margin: 2px;
height: 40px;
min-width: 125px;
margin: auto 2px;
}
.lgn-header {
display: block;
display: flex;
position: relative;
margin: 1rem auto 0.5rem auto;
margin: auto;
padding: 0;
width: 100%;
max-width: 250px;
min-height: 150px;
align-items: center;
justify-content: center;
}
.lgn-header .lgn-logo {
display: block;
max-height: 100px;
height: 100px;
margin: 0 auto;
max-width: 250px;
max-height: 150px;
object-fit: contain;
}
.lgn-button, .lgn-stroked-button, .lgn-icon-button {
@ -310,7 +315,7 @@ footer .watermark .lgn-logo-watermark {
border-radius: 50%;
}
.lgn-icon-button i, .lgn-icon-button .mat-icon {
line-height: 24px;
line-height: 40px;
}
.lgn-stroked-button {
@ -621,7 +626,8 @@ a.block {
.content-container .lgn-left-action {
position: absolute;
left: 1rem;
top: -40px;
top: -75px;
transform: translateY(-50%);
}
.content-container .lgn-register-options {
display: flex;
@ -1105,30 +1111,34 @@ footer a {
}
footer .watermark {
display: flex;
position: relative;
width: 100%;
}
footer .watermark .powered {
font-size: 12px;
margin: auto 2px;
}
footer .watermark .lgn-logo-watermark {
height: 34px;
width: 125px;
margin: 2px;
height: 40px;
min-width: 125px;
margin: auto 2px;
}
.lgn-header {
display: block;
display: flex;
position: relative;
margin: 1rem auto 0.5rem auto;
margin: auto;
padding: 0;
width: 100%;
max-width: 250px;
min-height: 150px;
align-items: center;
justify-content: center;
}
.lgn-header .lgn-logo {
display: block;
max-height: 100px;
height: 100px;
margin: 0 auto;
max-width: 250px;
max-height: 150px;
object-fit: contain;
}
.lgn-button, .lgn-stroked-button, .lgn-icon-button {
@ -1194,7 +1204,7 @@ footer .watermark .lgn-logo-watermark {
border-radius: 50%;
}
.lgn-icon-button i, .lgn-icon-button .mat-icon {
line-height: 24px;
line-height: 40px;
}
.lgn-stroked-button {
@ -1505,7 +1515,8 @@ a.block {
.content-container .lgn-left-action {
position: absolute;
left: 1rem;
top: -40px;
top: -75px;
transform: translateY(-50%);
}
.content-container .lgn-register-options {
display: flex;
@ -2307,7 +2318,8 @@ i {
.content-container .lgn-left-action {
position: absolute;
left: 1rem;
top: -40px;
top: -75px;
transform: translateY(-50%);
}
.content-container .lgn-register-options {
display: flex;
@ -2342,16 +2354,22 @@ i {
}
.lgn-header {
display: block;
display: flex;
position: relative;
margin: 1rem auto 0.5rem auto;
margin: auto;
padding: 0;
width: 100%;
max-width: 250px;
min-height: 150px;
align-items: center;
justify-content: center;
}
.lgn-header .lgn-logo {
display: block;
max-height: 100px;
height: 100px;
margin: 0 auto;
max-width: 250px;
max-height: 150px;
object-fit: contain;
}
@keyframes shake {
@ -2705,8 +2723,8 @@ footer a {
color: var(--zitadel-color-primary);
}
footer .lgn-logo-watermark {
background: var(--zitadel-logo-powered-by);
background-position: auto;
background: var(--zitadel-logo-powered-by) no-repeat;
background-position: center;
background-size: contain;
}

File diff suppressed because one or more lines are too long