diff --git a/cmd/admin/start/config.go b/cmd/admin/start/config.go index d460dc2507c..42ed801ebb4 100644 --- a/cmd/admin/start/config.go +++ b/cmd/admin/start/config.go @@ -51,6 +51,7 @@ type Config struct { DefaultInstance command.InstanceSetup AuditLogRetention time.Duration SystemAPIUsers map[string]*internal_authz.SystemAPIUser + CustomerPortal string } func MustNewConfig(v *viper.Viper) *Config { diff --git a/cmd/admin/start/start.go b/cmd/admin/start/start.go index 3b68e349cf3..878d257981b 100644 --- a/cmd/admin/start/start.go +++ b/cmd/admin/start/start.go @@ -194,7 +194,7 @@ func startAPIs(ctx context.Context, router *mux.Router, commands *command.Comman return fmt.Errorf("unable to start oidc provider: %w", err) } - c, err := console.Start(config.Console, config.ExternalSecure, oidcProvider.IssuerFromRequest, instanceInterceptor.Handler) + c, err := console.Start(config.Console, config.ExternalSecure, oidcProvider.IssuerFromRequest, instanceInterceptor.Handler, config.CustomerPortal) if err != nil { return fmt.Errorf("unable to start console: %w", err) } diff --git a/console/src/app/modules/nav/nav.component.html b/console/src/app/modules/nav/nav.component.html index c43a1c9873a..1b60a4c0ca1 100644 --- a/console/src/app/modules/nav/nav.component.html +++ b/console/src/app/modules/nav/nav.component.html @@ -70,6 +70,19 @@ {{ 'MENU.SETTINGS' | translate }} + + +
+ {{ 'MENU.CUSTOMERPORTAL' | translate }} +
+ +
diff --git a/console/src/app/modules/nav/nav.component.scss b/console/src/app/modules/nav/nav.component.scss index 4761ae13c7c..e16f5502cb3 100644 --- a/console/src/app/modules/nav/nav.component.scss +++ b/console/src/app/modules/nav/nav.component.scss @@ -63,6 +63,7 @@ font-weight: 500; margin: 0.25rem 2px; white-space: nowrap; + position: relative; .c_label { display: flex; @@ -75,6 +76,16 @@ } } + &.external-link { + padding-right: 2rem; + + i { + position: absolute; + right: 8px; + font-size: 1.2rem; + } + } + &:hover { background: if($is-dark-theme, #ffffff40, #00000010); } diff --git a/console/src/app/modules/nav/nav.component.ts b/console/src/app/modules/nav/nav.component.ts index 0307045a459..b1300cdafd2 100644 --- a/console/src/app/modules/nav/nav.component.ts +++ b/console/src/app/modules/nav/nav.component.ts @@ -1,9 +1,10 @@ import { animate, keyframes, style, transition, trigger } from '@angular/animations'; import { BreakpointObserver } from '@angular/cdk/layout'; +import { HttpClient } from '@angular/common/http'; import { Component, ElementRef, Input, OnDestroy, ViewChild } from '@angular/core'; import { FormControl } from '@angular/forms'; import { Router } from '@angular/router'; -import { BehaviorSubject, map, Observable, Subject } from 'rxjs'; +import { BehaviorSubject, map, Observable, Subject, take } from 'rxjs'; import { Org } from 'src/app/proto/generated/zitadel/org_pb'; import { LabelPolicy } from 'src/app/proto/generated/zitadel/policy_pb'; import { User } from 'src/app/proto/generated/zitadel/user_pb'; @@ -87,6 +88,7 @@ export class NavComponent implements OnDestroy { private destroy$: Subject = new Subject(); public BreadcrumbType: any = BreadcrumbType; + public customerPortalLink: string = ''; constructor( public authenticationService: AuthenticationService, @@ -94,9 +96,22 @@ export class NavComponent implements OnDestroy { public mgmtService: ManagementService, private router: Router, private breakpointObserver: BreakpointObserver, + private http: HttpClient, private shortcutService: KeyboardShortcutsService, ) { this.hideAdminWarn = localStorage.getItem('hideAdministratorWarning') === 'true' ? true : false; + this.loadEnvironment(); + } + + public loadEnvironment(): void { + this.http + .get('./assets/environment.json') + .pipe(take(1)) + .subscribe((data: any) => { + if (data && data.customer_portal) { + this.customerPortalLink = data.customer_portal; + } + }); } public toggleAdminHide(): void { diff --git a/console/src/assets/environment.json b/console/src/assets/environment.json index 06a610eae6b..26dc1a2b62b 100644 --- a/console/src/assets/environment.json +++ b/console/src/assets/environment.json @@ -1 +1,6 @@ -{ "api": "https://zitadel.cloud", "issuer": "https://zitadel.cloud/oauth/v2", "clientid": "163447659854627073@zitadel" } +{ + "api": "https://bringmos-jv1jqo.zitadel.app", + "issuer": "https://bringmos-jv1jqo.zitadel.app", + "clientid": "163706959596355841@zitadel", + "customer_portal": "https://zitadel.cloud" +} diff --git a/console/src/assets/i18n/de.json b/console/src/assets/i18n/de.json index 512bca21a5d..a5559b61ac5 100644 --- a/console/src/assets/i18n/de.json +++ b/console/src/assets/i18n/de.json @@ -68,7 +68,8 @@ "PRIVACY": "Datenschutz", "TOS": "AGB", "OPENSHORTCUTSTOOLTIP": "Tippe ? um die Tastaturkürzel anzuzeigen", - "SETTINGS": "Einstellungen" + "SETTINGS": "Einstellungen", + "CUSTOMERPORTAL": "Customer Portal" }, "ACTIONS": { "ACTIONS": "Aktionen", diff --git a/console/src/assets/i18n/en.json b/console/src/assets/i18n/en.json index adf0ede3f29..5860808cda5 100644 --- a/console/src/assets/i18n/en.json +++ b/console/src/assets/i18n/en.json @@ -68,7 +68,8 @@ "PRIVACY": "Privacy", "TOS": "Terms of Service", "OPENSHORTCUTSTOOLTIP": "Type ? to show keyboard shortcuts", - "SETTINGS": "Settings" + "SETTINGS": "Settings", + "CUSTOMERPORTAL": "Customer Portal" }, "ACTIONS": { "ACTIONS": "Actions", diff --git a/console/src/assets/i18n/it.json b/console/src/assets/i18n/it.json index bd784e064bb..62821e1bd02 100644 --- a/console/src/assets/i18n/it.json +++ b/console/src/assets/i18n/it.json @@ -68,7 +68,8 @@ "PRIVACY": "Informativa sulla privacy", "TOS": "Termini di servizio", "OPENSHORTCUTSTOOLTIP": "Premi ? per mostrare le scorciatoie da tastiera", - "SETTINGS": "Impostazioni" + "SETTINGS": "Impostazioni", + "CUSTOMERPORTAL": "Customer Portal" }, "ACTIONS": { "ACTIONS": "Azioni", diff --git a/internal/api/ui/console/console.go b/internal/api/ui/console/console.go index e219edd6b06..ede686fc04e 100644 --- a/internal/api/ui/console/console.go +++ b/internal/api/ui/console/console.go @@ -84,7 +84,7 @@ func (f *file) Stat() (_ fs.FileInfo, err error) { return f, nil } -func Start(config Config, externalSecure bool, issuer op.IssuerFromRequest, instanceHandler func(http.Handler) http.Handler) (http.Handler, error) { +func Start(config Config, externalSecure bool, issuer op.IssuerFromRequest, instanceHandler func(http.Handler) http.Handler, customerPortal string) (http.Handler, error) { fSys, err := fs.Sub(static, "static") if err != nil { return nil, err @@ -106,7 +106,7 @@ func Start(config Config, externalSecure bool, issuer op.IssuerFromRequest, inst return } url := http_util.BuildOrigin(r.Host, externalSecure) - environmentJSON, err := createEnvironmentJSON(url, issuer(r), instance.ConsoleClientID()) + environmentJSON, err := createEnvironmentJSON(url, issuer(r), instance.ConsoleClientID(), customerPortal) if err != nil { http.Error(w, fmt.Sprintf("unable to marshal env for console: %v", err), http.StatusInternalServerError) return @@ -127,15 +127,17 @@ func csp() *middleware.CSP { return &csp } -func createEnvironmentJSON(api, issuer, clientID string) ([]byte, error) { +func createEnvironmentJSON(api, issuer, clientID, customerPortal string) ([]byte, error) { environment := struct { - API string `json:"api,omitempty"` - Issuer string `json:"issuer,omitempty"` - ClientID string `json:"clientid,omitempty"` + API string `json:"api,omitempty"` + Issuer string `json:"issuer,omitempty"` + ClientID string `json:"clientid,omitempty"` + CustomerPortal string `json:"customer_portal,omitempty"` }{ - API: api, - Issuer: issuer, - ClientID: clientID, + API: api, + Issuer: issuer, + ClientID: clientID, + CustomerPortal: customerPortal, } return json.Marshal(environment) }