mirror of
https://github.com/andwati/zitadel.git
synced 2026-11-13 17:35:12 +00:00
feat(cnsl): docs link can be customized and custom button is available (#7840)
* feat: customize doc link and additional custom link * feat: add e2e tests * fix: update docs * fix: add @peintnermax changes about cache * fix: golangci-lint complains preparation.PrepareCommands --------- Co-authored-by: Max Peintner <[email protected]>
This commit is contained in:
co-authored by
Max Peintner
parent
6942324741
commit
15d5338b91
@@ -1,11 +1,11 @@
|
||||
<div class="footer-wrapper">
|
||||
<div class="footer-row">
|
||||
<div class="footer-links">
|
||||
<a target="_blank" *ngIf="policy?.tosLink" rel="noreferrer" [href]="policy?.tosLink" external>
|
||||
<div class="footer-links" *ngIf="authService.privacypolicy | async as pP">
|
||||
<a target="_blank" *ngIf="pP?.tosLink" rel="noreferrer" [href]="pP?.tosLink" external>
|
||||
<span>{{ 'FOOTER.LINKS.TOS' | translate }}</span>
|
||||
<i class="las la-external-link-alt"></i>
|
||||
</a>
|
||||
<a target="_blank" *ngIf="policy?.privacyLink" rel="noreferrer" [href]="policy?.privacyLink" external>
|
||||
<a target="_blank" *ngIf="pP?.privacyLink" rel="noreferrer" [href]="pP?.privacyLink" external>
|
||||
<span>{{ 'FOOTER.LINKS.PP' | translate }}</span>
|
||||
<i class="las la-external-link-alt"></i>
|
||||
</a>
|
||||
|
||||
@@ -8,16 +8,7 @@ import { faXTwitter } from '@fortawesome/free-brands-svg-icons';
|
||||
templateUrl: './footer.component.html',
|
||||
styleUrls: ['./footer.component.scss'],
|
||||
})
|
||||
export class FooterComponent implements OnInit {
|
||||
public policy?: PrivacyPolicy.AsObject;
|
||||
export class FooterComponent {
|
||||
public faXTwitter = faXTwitter;
|
||||
constructor(public authService: GrpcAuthService) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.authService.getMyPrivacyPolicy().then((policyResp) => {
|
||||
if (policyResp.policy) {
|
||||
this.policy = policyResp.policy;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -168,7 +168,11 @@
|
||||
|
||||
<span class="fill-space"></span>
|
||||
|
||||
<a class="doc-link" href="https://zitadel.com/docs" mat-stroked-button target="_blank">
|
||||
<a class="custom-link" *ngIf="customLink && customLinkText" href="{{ customLink }}" mat-stroked-button target="_blank">
|
||||
{{ customLinkText }}
|
||||
</a>
|
||||
|
||||
<a class="doc-link" *ngIf="docsLink" href="{{ docsLink }}" mat-stroked-button target="_blank">
|
||||
{{ 'MENU.DOCUMENTATION' | translate }}
|
||||
</a>
|
||||
|
||||
|
||||
@@ -224,7 +224,8 @@
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.doc-link {
|
||||
.doc-link,
|
||||
.custom-link {
|
||||
margin-right: 1rem;
|
||||
|
||||
@media only screen and (max-width: 800px) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { ConnectedPosition, ConnectionPositionPair } from '@angular/cdk/overlay';
|
||||
import { Component, ElementRef, EventEmitter, Input, OnDestroy, Output, ViewChild } from '@angular/core';
|
||||
import { Component, ElementRef, EventEmitter, Input, OnDestroy, OnInit, Output, ViewChild } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
import { BehaviorSubject, Observable, of, Subject } from 'rxjs';
|
||||
import { Org } from 'src/app/proto/generated/zitadel/org_pb';
|
||||
@@ -8,8 +8,8 @@ import { AuthenticationService } from 'src/app/services/authentication.service';
|
||||
import { BreadcrumbService, BreadcrumbType } from 'src/app/services/breadcrumb.service';
|
||||
import { GrpcAuthService } from 'src/app/services/grpc-auth.service';
|
||||
import { ManagementService } from 'src/app/services/mgmt.service';
|
||||
|
||||
import { ActionKeysType } from '../action-keys/action-keys.component';
|
||||
import { GetPrivacyPolicyResponse } from 'src/app/proto/generated/zitadel/management_pb';
|
||||
|
||||
@Component({
|
||||
selector: 'cnsl-header',
|
||||
@@ -31,6 +31,9 @@ export class HeaderComponent implements OnDestroy {
|
||||
private destroy$: Subject<void> = new Subject();
|
||||
public BreadcrumbType: any = BreadcrumbType;
|
||||
public ActionKeysType: any = ActionKeysType;
|
||||
public docsLink = 'https://zitadel.com/docs';
|
||||
public customLink = '';
|
||||
public customLinkText = '';
|
||||
|
||||
public positions: ConnectedPosition[] = [
|
||||
new ConnectionPositionPair({ originX: 'start', originY: 'bottom' }, { overlayX: 'start', overlayY: 'top' }, 0, 10),
|
||||
@@ -47,7 +50,25 @@ export class HeaderComponent implements OnDestroy {
|
||||
public mgmtService: ManagementService,
|
||||
public breadcrumbService: BreadcrumbService,
|
||||
public router: Router,
|
||||
) {}
|
||||
) {
|
||||
this.loadData();
|
||||
}
|
||||
|
||||
public async loadData(): Promise<any> {
|
||||
const getData = (): Promise<GetPrivacyPolicyResponse.AsObject> => {
|
||||
return this.mgmtService.getPrivacyPolicy();
|
||||
};
|
||||
|
||||
getData()
|
||||
.then((resp) => {
|
||||
if (resp.policy) {
|
||||
this.docsLink = resp.policy.docsLink;
|
||||
this.customLink = resp.policy.customLink;
|
||||
this.customLinkText = resp.policy.customLinkText;
|
||||
}
|
||||
})
|
||||
.catch(() => {});
|
||||
}
|
||||
|
||||
public ngOnDestroy() {
|
||||
this.destroy$.next();
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
color="warn"
|
||||
(click)="resetDefault()"
|
||||
mat-stroked-button
|
||||
data-e2e="reset-button"
|
||||
>
|
||||
{{ 'POLICY.RESET' | translate }}
|
||||
</button>
|
||||
@@ -40,7 +41,23 @@
|
||||
<cnsl-form-field class="privacy-policy-formfield">
|
||||
<cnsl-label>{{ 'POLICY.PRIVACY_POLICY.SUPPORTEMAIL' | translate }}</cnsl-label>
|
||||
<input cnslInput name="supportEmail" formControlName="supportEmail" />
|
||||
<template [ngTemplateOutlet]="templateRef" [ngTemplateOutletContext]="{ key: 'supportEmail' }"></template>
|
||||
</cnsl-form-field>
|
||||
|
||||
<cnsl-form-field class="privacy-policy-formfield">
|
||||
<cnsl-label>{{ 'POLICY.PRIVACY_POLICY.CUSTOMLINK' | translate }}</cnsl-label>
|
||||
<input cnslInput name="customLink" formControlName="customLink" />
|
||||
<template [ngTemplateOutlet]="templateRef" [ngTemplateOutletContext]="{ key: 'customLink' }"></template>
|
||||
</cnsl-form-field>
|
||||
|
||||
<cnsl-form-field class="privacy-policy-formfield">
|
||||
<cnsl-label>{{ 'POLICY.PRIVACY_POLICY.CUSTOMLINKTEXT' | translate }}</cnsl-label>
|
||||
<input cnslInput name="customLinkText" formControlName="customLinkText" />
|
||||
</cnsl-form-field>
|
||||
|
||||
<cnsl-form-field class="privacy-policy-formfield">
|
||||
<cnsl-label>{{ 'POLICY.PRIVACY_POLICY.DOCSLINK' | translate }}</cnsl-label>
|
||||
<input cnslInput name="docsLink" formControlName="docsLink" />
|
||||
<template [ngTemplateOutlet]="templateRef" [ngTemplateOutletContext]="{ key: 'docsLink' }"></template>
|
||||
</cnsl-form-field>
|
||||
</form>
|
||||
</div>
|
||||
@@ -53,6 +70,7 @@
|
||||
color="primary"
|
||||
type="submit"
|
||||
mat-raised-button
|
||||
data-e2e="save-button"
|
||||
>
|
||||
{{ 'ACTIONS.SAVE' | translate }}
|
||||
</button>
|
||||
|
||||
@@ -61,6 +61,9 @@ export class PrivacyPolicyComponent implements OnInit, OnDestroy {
|
||||
privacyLink: ['', []],
|
||||
helpLink: ['', []],
|
||||
supportEmail: ['', []],
|
||||
docsLink: ['', []],
|
||||
customLink: ['', []],
|
||||
customLinkText: ['', []],
|
||||
});
|
||||
|
||||
this.canWrite$.pipe(take(1)).subscribe((canWrite) => {
|
||||
@@ -107,6 +110,9 @@ export class PrivacyPolicyComponent implements OnInit, OnDestroy {
|
||||
privacyLink: '',
|
||||
helpLink: '',
|
||||
supportEmail: '',
|
||||
docsLink: '',
|
||||
customLink: '',
|
||||
customLinkText: '',
|
||||
});
|
||||
}
|
||||
})
|
||||
@@ -117,6 +123,9 @@ export class PrivacyPolicyComponent implements OnInit, OnDestroy {
|
||||
privacyLink: '',
|
||||
helpLink: '',
|
||||
supportEmail: '',
|
||||
docsLink: '',
|
||||
customLink: '',
|
||||
customLinkText: '',
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -129,11 +138,16 @@ export class PrivacyPolicyComponent implements OnInit, OnDestroy {
|
||||
req.setTosLink(this.form.get('tosLink')?.value);
|
||||
req.setHelpLink(this.form.get('helpLink')?.value);
|
||||
req.setSupportEmail(this.form.get('supportEmail')?.value);
|
||||
req.setDocsLink(this.form.get('docsLink')?.value);
|
||||
req.setCustomLink(this.form.get('customLink')?.value);
|
||||
req.setCustomLinkText(this.form.get('customLinkText')?.value);
|
||||
(this.service as ManagementService)
|
||||
.addCustomPrivacyPolicy(req)
|
||||
.then(() => {
|
||||
this.toast.showInfo('POLICY.PRIVACY_POLICY.SAVED', true);
|
||||
this.loadData();
|
||||
// Reload console as links may have changed
|
||||
this.reloadConsole();
|
||||
})
|
||||
.catch((error) => this.toast.showError(error));
|
||||
} else {
|
||||
@@ -142,12 +156,17 @@ export class PrivacyPolicyComponent implements OnInit, OnDestroy {
|
||||
req.setTosLink(this.form.get('tosLink')?.value);
|
||||
req.setHelpLink(this.form.get('helpLink')?.value);
|
||||
req.setSupportEmail(this.form.get('supportEmail')?.value);
|
||||
req.setDocsLink(this.form.get('docsLink')?.value);
|
||||
req.setCustomLink(this.form.get('customLink')?.value);
|
||||
req.setCustomLinkText(this.form.get('customLinkText')?.value);
|
||||
|
||||
(this.service as ManagementService)
|
||||
.updateCustomPrivacyPolicy(req)
|
||||
.then(() => {
|
||||
this.toast.showInfo('POLICY.PRIVACY_POLICY.SAVED', true);
|
||||
this.loadData();
|
||||
// Reload console as links may have changed
|
||||
this.reloadConsole();
|
||||
})
|
||||
.catch((error) => this.toast.showError(error));
|
||||
}
|
||||
@@ -157,12 +176,17 @@ export class PrivacyPolicyComponent implements OnInit, OnDestroy {
|
||||
req.setTosLink(this.form.get('tosLink')?.value);
|
||||
req.setHelpLink(this.form.get('helpLink')?.value);
|
||||
req.setSupportEmail(this.form.get('supportEmail')?.value);
|
||||
req.setDocsLink(this.form.get('docsLink')?.value);
|
||||
req.setCustomLink(this.form.get('customLink')?.value);
|
||||
req.setCustomLinkText(this.form.get('customLinkText')?.value);
|
||||
|
||||
(this.service as AdminService)
|
||||
.updatePrivacyPolicy(req)
|
||||
.then(() => {
|
||||
this.toast.showInfo('POLICY.PRIVACY_POLICY.SAVED', true);
|
||||
this.loadData();
|
||||
// Reload console as links may have changed
|
||||
this.reloadConsole();
|
||||
})
|
||||
.catch((error) => this.toast.showError(error));
|
||||
}
|
||||
@@ -188,6 +212,7 @@ export class PrivacyPolicyComponent implements OnInit, OnDestroy {
|
||||
.then(() => {
|
||||
setTimeout(() => {
|
||||
this.loadData();
|
||||
window.location.reload();
|
||||
}, 1000);
|
||||
})
|
||||
.catch((error) => {
|
||||
@@ -209,4 +234,10 @@ export class PrivacyPolicyComponent implements OnInit, OnDestroy {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private reloadConsole(): void {
|
||||
setTimeout(() => {
|
||||
window.location.reload();
|
||||
}, 1000);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ export const APPEARANCE_GROUP: SettingLinks = {
|
||||
};
|
||||
|
||||
export const PRIVACY_POLICY: SettingLinks = {
|
||||
i18nTitle: 'SETTINGS.LIST.PRIVACYPOLICY',
|
||||
i18nTitle: 'DESCRIPTIONS.SETTINGS.PRIVACY_POLICY.TITLE',
|
||||
i18nDesc: 'POLICY.PRIVACY_POLICY.DESCRIPTION',
|
||||
iamRouterLink: ['/settings'],
|
||||
orgRouterLink: ['/org-settings'],
|
||||
|
||||
@@ -187,7 +187,7 @@ export const LOGINTEXTS: SidenavSetting = {
|
||||
|
||||
export const PRIVACYPOLICY: SidenavSetting = {
|
||||
id: 'privacypolicy',
|
||||
i18nKey: 'SETTINGS.LIST.PRIVACYPOLICY',
|
||||
i18nKey: 'DESCRIPTIONS.SETTINGS.PRIVACY_POLICY.TITLE',
|
||||
groupI18nKey: 'SETTINGS.GROUPS.OTHER',
|
||||
requiredRoles: {
|
||||
[PolicyComponentServiceType.MGMT]: ['policy.read'],
|
||||
|
||||
Reference in New Issue
Block a user