feat: add attribute to only enable specific themes (#6798)

* feat: enable only specific themes in label policy

* feat: enable only specific themes in label policy

* feat: enable only specific themes in label policy

* feat: enable only specific themes in label policy

* add management in console

* pass enabledTheme

* render login ui based on enabled theme

* add in branding / settings service and name consistently

* update console to latest proto state

* fix console linting

* fix linting

* cleanup

* add translations

---------

Co-authored-by: Livio Spring <livio.a@gmail.com>
Co-authored-by: Tim Möhlmann <tim+github@zitadel.com>
This commit is contained in:
Stefan Benz 2023-10-26 07:54:09 +02:00 committed by GitHub
parent 7b0506c19c
commit cb7b50b513
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
43 changed files with 527 additions and 100 deletions

View File

@ -7,27 +7,11 @@
</div> </div>
<div class="privatelabeling-top-row"> <div class="privatelabeling-top-row">
<mat-button-toggle-group class="buttongroup" [(ngModel)]="theme" name="theme" aria-label="Theme">
<mat-button-toggle [value]="Theme.LIGHT">
<div class="toggle-row">
<i class="icon las la-sun"></i>
<span>{{ 'POLICY.PRIVATELABELING.LIGHT' | translate }}</span>
<div *ngIf="theme === Theme.LIGHT" class="current-dot"></div>
</div>
</mat-button-toggle>
<mat-button-toggle [value]="Theme.DARK">
<div class="toggle-row">
<i class="icon las la-moon"></i>
<span> {{ 'POLICY.PRIVATELABELING.DARK' | translate }}</span>
<div *ngIf="theme === Theme.DARK" class="current-dot"></div>
</div>
</mat-button-toggle>
</mat-button-toggle-group>
<mat-button-toggle-group <mat-button-toggle-group
class="theme-toggle" class="theme-toggle"
class="buttongroup" class="buttongroup"
[(ngModel)]="view" [(ngModel)]="view"
(change)="toggleView(view)"
name="displayview" name="displayview"
aria-label="Display View" aria-label="Display View"
> >
@ -48,6 +32,109 @@
</div> </div>
</mat-button-toggle> </mat-button-toggle>
</mat-button-toggle-group> </mat-button-toggle-group>
</div>
<div class="privatelabeling-top-row">
<mat-button-toggle-group
*ngIf="previewData && data"
class="buttongroup"
[(ngModel)]="view === View.CURRENT ? data.themeMode : previewData.themeMode"
(change)="toggleThemeMode()"
[disabled]="
view === View.CURRENT ||
([
serviceType === PolicyComponentServiceType.ADMIN
? 'iam.policy.write'
: serviceType === PolicyComponentServiceType.MGMT
? 'policy.write'
: ''
]
| hasRole
| async) === false
"
name="thememode"
aria-label="Theme Mode"
>
<mat-button-toggle [value]="ThemeMode.THEME_MODE_AUTO">
<div class="toggle-row">
<i class="icon las la-adjust"></i>
<span>{{ 'POLICY.PRIVATELABELING.THEMEMODE.THEME_MODE_AUTO' | translate }}</span>
<div
*ngIf="
view === View.PREVIEW
? previewData.themeMode === ThemeMode.THEME_MODE_AUTO
: data.themeMode === ThemeMode.THEME_MODE_AUTO
"
class="current-dot"
></div>
</div>
</mat-button-toggle>
<mat-button-toggle [value]="ThemeMode.THEME_MODE_LIGHT">
<div class="toggle-row">
<i class="icon las la-sun"></i>
<span> {{ 'POLICY.PRIVATELABELING.THEMEMODE.THEME_MODE_LIGHT' | translate }}</span>
<div
*ngIf="
view === View.PREVIEW
? previewData.themeMode === ThemeMode.THEME_MODE_LIGHT
: data.themeMode === ThemeMode.THEME_MODE_LIGHT
"
class="current-dot"
></div>
</div>
</mat-button-toggle>
<mat-button-toggle [value]="ThemeMode.THEME_MODE_DARK">
<div class="toggle-row">
<i class="icon las la-moon"></i>
<span> {{ 'POLICY.PRIVATELABELING.THEMEMODE.THEME_MODE_DARK' | translate }}</span>
<div
*ngIf="
view === View.PREVIEW
? previewData.themeMode === ThemeMode.THEME_MODE_DARK
: data.themeMode === ThemeMode.THEME_MODE_DARK
"
class="current-dot"
></div>
</div>
</mat-button-toggle>
</mat-button-toggle-group>
<mat-button-toggle-group
class="buttongroup"
[(ngModel)]="theme"
name="theme"
aria-label="Theme"
*ngIf="previewData && data"
>
<mat-button-toggle
[value]="Theme.LIGHT"
[disabled]="
view === View.PREVIEW
? previewData.themeMode === ThemeMode.THEME_MODE_DARK
: data.themeMode === ThemeMode.THEME_MODE_DARK
"
>
<div class="toggle-row">
<i class="icon las la-sun"></i>
<span>{{ 'POLICY.PRIVATELABELING.LIGHT' | translate }}</span>
<div *ngIf="theme === Theme.LIGHT" class="current-dot"></div>
</div>
</mat-button-toggle>
<mat-button-toggle
[value]="Theme.DARK"
[disabled]="
view === View.PREVIEW
? previewData.themeMode === ThemeMode.THEME_MODE_LIGHT
: data.themeMode === ThemeMode.THEME_MODE_LIGHT
"
>
<div class="toggle-row">
<i class="icon las la-moon"></i>
<span> {{ 'POLICY.PRIVATELABELING.DARK' | translate }}</span>
<div *ngIf="theme === Theme.DARK" class="current-dot"></div>
</div>
</mat-button-toggle>
</mat-button-toggle-group>
<span class="fill-space"></span> <span class="fill-space"></span>

View File

@ -15,7 +15,7 @@ import {
UpdateCustomLabelPolicyRequest, UpdateCustomLabelPolicyRequest,
} from 'src/app/proto/generated/zitadel/management_pb'; } from 'src/app/proto/generated/zitadel/management_pb';
import { Org } from 'src/app/proto/generated/zitadel/org_pb'; import { Org } from 'src/app/proto/generated/zitadel/org_pb';
import { LabelPolicy } from 'src/app/proto/generated/zitadel/policy_pb'; import { LabelPolicy, ThemeMode } from 'src/app/proto/generated/zitadel/policy_pb';
import { AdminService } from 'src/app/services/admin.service'; import { AdminService } from 'src/app/services/admin.service';
import { AssetEndpoint, AssetService, AssetType } from 'src/app/services/asset.service'; import { AssetEndpoint, AssetService, AssetType } from 'src/app/services/asset.service';
import { ManagementService } from 'src/app/services/mgmt.service'; import { ManagementService } from 'src/app/services/mgmt.service';
@ -88,6 +88,7 @@ export class PrivateLabelingPolicyComponent implements OnInit, OnDestroy {
public View: any = View; public View: any = View;
public ColorType: any = ColorType; public ColorType: any = ColorType;
public AssetType: any = AssetType; public AssetType: any = AssetType;
public ThemeMode: any = ThemeMode;
public fontName = ''; public fontName = '';
@ -106,6 +107,32 @@ export class PrivateLabelingPolicyComponent implements OnInit, OnDestroy {
private dialog: MatDialog, private dialog: MatDialog,
) {} ) {}
public toggleThemeMode(): void {
if (this.view === View.CURRENT) {
return;
}
if (this.previewData?.themeMode === ThemeMode.THEME_MODE_LIGHT) {
this.theme = Theme.LIGHT;
}
if (this.previewData?.themeMode === ThemeMode.THEME_MODE_DARK) {
this.theme = Theme.DARK;
}
this.savePolicy();
}
public toggleView(view: View): void {
let themeMode = this.data?.themeMode;
if (view === View.PREVIEW) {
themeMode = this.previewData?.themeMode;
}
if (themeMode === ThemeMode.THEME_MODE_LIGHT) {
this.theme = Theme.LIGHT;
}
if (themeMode === ThemeMode.THEME_MODE_DARK) {
this.theme = Theme.DARK;
}
}
public toggleHoverLogo(theme: Theme, isHovering: boolean): void { public toggleHoverLogo(theme: Theme, isHovering: boolean): void {
if (theme === Theme.DARK) { if (theme === Theme.DARK) {
this.isHoveringOverDarkLogo = isHovering; this.isHoveringOverDarkLogo = isHovering;
@ -614,6 +641,8 @@ export class PrivateLabelingPolicyComponent implements OnInit, OnDestroy {
req.setDisableWatermark(this.previewData.disableWatermark); req.setDisableWatermark(this.previewData.disableWatermark);
req.setHideLoginNameSuffix(this.previewData.hideLoginNameSuffix); req.setHideLoginNameSuffix(this.previewData.hideLoginNameSuffix);
req.setThemeMode(this.previewData.themeMode);
} }
} }

View File

@ -9,6 +9,7 @@ import { MatLegacyButtonModule as MatButtonModule } from '@angular/material/lega
import { MatLegacyCheckboxModule as MatCheckboxModule } from '@angular/material/legacy-checkbox'; import { MatLegacyCheckboxModule as MatCheckboxModule } from '@angular/material/legacy-checkbox';
import { MatLegacyDialogModule as MatDialogModule } from '@angular/material/legacy-dialog'; import { MatLegacyDialogModule as MatDialogModule } from '@angular/material/legacy-dialog';
import { MatLegacyProgressSpinnerModule as MatProgressSpinnerModule } from '@angular/material/legacy-progress-spinner'; import { MatLegacyProgressSpinnerModule as MatProgressSpinnerModule } from '@angular/material/legacy-progress-spinner';
import { MatLegacySelectModule as MatSelectModule } from '@angular/material/legacy-select';
import { MatLegacyTooltipModule as MatTooltipModule } from '@angular/material/legacy-tooltip'; import { MatLegacyTooltipModule as MatTooltipModule } from '@angular/material/legacy-tooltip';
import { TranslateModule } from '@ngx-translate/core'; import { TranslateModule } from '@ngx-translate/core';
import { ColorChromeModule } from 'ngx-color/chrome'; import { ColorChromeModule } from 'ngx-color/chrome';
@ -49,6 +50,7 @@ import { PrivateLabelingPolicyComponent } from './private-labeling-policy.compon
WarnDialogModule, WarnDialogModule,
HasRolePipeModule, HasRolePipeModule,
MatProgressSpinnerModule, MatProgressSpinnerModule,
MatSelectModule,
MatExpansionModule, MatExpansionModule,
InfoSectionModule, InfoSectionModule,
], ],

View File

@ -1197,6 +1197,11 @@
"ERROR": "Потребителят не може да бъде намерен!", "ERROR": "Потребителят не може да бъде намерен!",
"PRIMARYBUTTON": "следващия", "PRIMARYBUTTON": "следващия",
"SECONDARYBUTTON": "регистрирам" "SECONDARYBUTTON": "регистрирам"
},
"THEMEMODE": {
"THEME_MODE_AUTO": "Автоматичен режим",
"THEME_MODE_LIGHT": "Само светъл режим",
"THEME_MODE_DARK": "Само тъмен режим"
} }
}, },
"PWD_AGE": { "PWD_AGE": {

View File

@ -1203,6 +1203,11 @@
"ERROR": "Benutzer konnte nicht gefunden werden!", "ERROR": "Benutzer konnte nicht gefunden werden!",
"PRIMARYBUTTON": "weiter", "PRIMARYBUTTON": "weiter",
"SECONDARYBUTTON": "registrieren" "SECONDARYBUTTON": "registrieren"
},
"THEMEMODE": {
"THEME_MODE_AUTO": "Automatischer Modus",
"THEME_MODE_LIGHT": "Nur heller Modus",
"THEME_MODE_DARK": "Nur dunkler Modus"
} }
}, },
"PWD_AGE": { "PWD_AGE": {

View File

@ -1204,6 +1204,11 @@
"ERROR": "User could not be found!", "ERROR": "User could not be found!",
"PRIMARYBUTTON": "next", "PRIMARYBUTTON": "next",
"SECONDARYBUTTON": "register" "SECONDARYBUTTON": "register"
},
"THEMEMODE": {
"THEME_MODE_AUTO": "Auto Mode",
"THEME_MODE_LIGHT": "Light Mode only",
"THEME_MODE_DARK": "Dark Mode only"
} }
}, },
"PWD_AGE": { "PWD_AGE": {

View File

@ -1204,6 +1204,11 @@
"ERROR": "¡No se encontró el usuario!", "ERROR": "¡No se encontró el usuario!",
"PRIMARYBUTTON": "siguiente", "PRIMARYBUTTON": "siguiente",
"SECONDARYBUTTON": "registrar" "SECONDARYBUTTON": "registrar"
},
"THEMEMODE": {
"THEME_MODE_AUTO": "Modo automático",
"THEME_MODE_LIGHT": "Sólo modo claro",
"THEME_MODE_DARK": "Sólo modo oscuro"
} }
}, },
"PWD_AGE": { "PWD_AGE": {

View File

@ -1203,6 +1203,11 @@
"ERROR": "L'utilisateur n'a pas pu être trouvé !", "ERROR": "L'utilisateur n'a pas pu être trouvé !",
"PRIMARYBUTTON": "suivant", "PRIMARYBUTTON": "suivant",
"SECONDARYBUTTON": "enregistrez-vous" "SECONDARYBUTTON": "enregistrez-vous"
},
"THEMEMODE": {
"THEME_MODE_AUTO": "Mode automatique",
"THEME_MODE_LIGHT": "Mode clair uniquement",
"THEME_MODE_DARK": "Mode sombre uniquement"
} }
}, },
"PWD_AGE": { "PWD_AGE": {

View File

@ -1203,6 +1203,11 @@
"ERROR": "L'utente non \u00e8 stato trovato!", "ERROR": "L'utente non \u00e8 stato trovato!",
"PRIMARYBUTTON": "Avanti", "PRIMARYBUTTON": "Avanti",
"SECONDARYBUTTON": "Registra" "SECONDARYBUTTON": "Registra"
},
"THEMEMODE": {
"THEME_MODE_AUTO": "Modalità automatica",
"THEME_MODE_LIGHT": "Solo modalità luminosa",
"THEME_MODE_DARK": "Solo modalità oscura"
} }
}, },
"PWD_AGE": { "PWD_AGE": {

View File

@ -1200,6 +1200,11 @@
"ERROR": "ユーザーは見つかりません!", "ERROR": "ユーザーは見つかりません!",
"PRIMARYBUTTON": "次へ", "PRIMARYBUTTON": "次へ",
"SECONDARYBUTTON": "登録" "SECONDARYBUTTON": "登録"
},
"THEMEMODE": {
"THEME_MODE_AUTO": "自動モード",
"THEME_MODE_LIGHT": "ライトモードのみ",
"THEME_MODE_DARK": "ダークモードのみ"
} }
}, },
"PWD_AGE": { "PWD_AGE": {

View File

@ -1205,6 +1205,11 @@
"ERROR": "Корисникот не е пронајден!", "ERROR": "Корисникот не е пронајден!",
"PRIMARYBUTTON": "следно", "PRIMARYBUTTON": "следно",
"SECONDARYBUTTON": "регистрирај се" "SECONDARYBUTTON": "регистрирај се"
},
"THEMEMODE": {
"THEME_MODE_AUTO": "Автоматски режим",
"THEME_MODE_LIGHT": "Само светлосен режим",
"THEME_MODE_DARK": "Само темен режим"
} }
}, },
"PWD_AGE": { "PWD_AGE": {

View File

@ -1203,6 +1203,11 @@
"ERROR": "Nie znaleziono użytkownika!", "ERROR": "Nie znaleziono użytkownika!",
"PRIMARYBUTTON": "Dalej", "PRIMARYBUTTON": "Dalej",
"SECONDARYBUTTON": "Zarejestruj" "SECONDARYBUTTON": "Zarejestruj"
},
"THEMEMODE": {
"THEME_MODE_AUTO": "Tryb automatyczny",
"THEME_MODE_LIGHT": "Tylko tryb jasny",
"THEME_MODE_DARK": "Tylko tryb ciemny"
} }
}, },
"PWD_AGE": { "PWD_AGE": {

View File

@ -1205,6 +1205,11 @@
"ERROR": "Usuário não encontrado!", "ERROR": "Usuário não encontrado!",
"PRIMARYBUTTON": "próximo", "PRIMARYBUTTON": "próximo",
"SECONDARYBUTTON": "registrar" "SECONDARYBUTTON": "registrar"
},
"THEMEMODE": {
"THEME_MODE_AUTO": "Modo Automático",
"THEME_MODE_LIGHT": "Somente modo claro",
"THEME_MODE_DARK": "Somente modo escuro"
} }
}, },
"PWD_AGE": { "PWD_AGE": {

View File

@ -1202,6 +1202,11 @@
"ERROR": "找不到用户!", "ERROR": "找不到用户!",
"PRIMARYBUTTON": "下一步", "PRIMARYBUTTON": "下一步",
"SECONDARYBUTTON": "注册" "SECONDARYBUTTON": "注册"
},
"THEMEMODE": {
"THEME_MODE_AUTO": "自动模式",
"THEME_MODE_LIGHT": "仅限灯光模式",
"THEME_MODE_DARK": "仅限深色模式"
} }
}, },
"PWD_AGE": { "PWD_AGE": {

View File

@ -3,6 +3,7 @@ package admin
import ( import (
"github.com/zitadel/zitadel/internal/domain" "github.com/zitadel/zitadel/internal/domain"
admin_pb "github.com/zitadel/zitadel/pkg/grpc/admin" admin_pb "github.com/zitadel/zitadel/pkg/grpc/admin"
policy_pb "github.com/zitadel/zitadel/pkg/grpc/policy"
) )
func updateLabelPolicyToDomain(policy *admin_pb.UpdateLabelPolicyRequest) *domain.LabelPolicy { func updateLabelPolicyToDomain(policy *admin_pb.UpdateLabelPolicyRequest) *domain.LabelPolicy {
@ -17,5 +18,21 @@ func updateLabelPolicyToDomain(policy *admin_pb.UpdateLabelPolicyRequest) *domai
FontColorDark: policy.FontColorDark, FontColorDark: policy.FontColorDark,
HideLoginNameSuffix: policy.HideLoginNameSuffix, HideLoginNameSuffix: policy.HideLoginNameSuffix,
DisableWatermark: policy.DisableWatermark, DisableWatermark: policy.DisableWatermark,
ThemeMode: themeModeToDomain(policy.ThemeMode),
}
}
func themeModeToDomain(theme policy_pb.ThemeMode) domain.LabelPolicyThemeMode {
switch theme {
case policy_pb.ThemeMode_THEME_MODE_AUTO:
return domain.LabelPolicyThemeAuto
case policy_pb.ThemeMode_THEME_MODE_DARK:
return domain.LabelPolicyThemeDark
case policy_pb.ThemeMode_THEME_MODE_LIGHT:
return domain.LabelPolicyThemeLight
case policy_pb.ThemeMode_THEME_MODE_UNSPECIFIED:
return domain.LabelPolicyThemeAuto
default:
return domain.LabelPolicyThemeAuto
} }
} }

View File

@ -3,6 +3,7 @@ package management
import ( import (
"github.com/zitadel/zitadel/internal/domain" "github.com/zitadel/zitadel/internal/domain"
mgmt_pb "github.com/zitadel/zitadel/pkg/grpc/management" mgmt_pb "github.com/zitadel/zitadel/pkg/grpc/management"
policy_pb "github.com/zitadel/zitadel/pkg/grpc/policy"
) )
func AddLabelPolicyToDomain(p *mgmt_pb.AddCustomLabelPolicyRequest) *domain.LabelPolicy { func AddLabelPolicyToDomain(p *mgmt_pb.AddCustomLabelPolicyRequest) *domain.LabelPolicy {
@ -17,6 +18,22 @@ func AddLabelPolicyToDomain(p *mgmt_pb.AddCustomLabelPolicyRequest) *domain.Labe
FontColorDark: p.FontColorDark, FontColorDark: p.FontColorDark,
HideLoginNameSuffix: p.HideLoginNameSuffix, HideLoginNameSuffix: p.HideLoginNameSuffix,
DisableWatermark: p.DisableWatermark, DisableWatermark: p.DisableWatermark,
ThemeMode: themeModeToDomain(p.ThemeMode),
}
}
func themeModeToDomain(theme policy_pb.ThemeMode) domain.LabelPolicyThemeMode {
switch theme {
case policy_pb.ThemeMode_THEME_MODE_AUTO:
return domain.LabelPolicyThemeAuto
case policy_pb.ThemeMode_THEME_MODE_DARK:
return domain.LabelPolicyThemeDark
case policy_pb.ThemeMode_THEME_MODE_LIGHT:
return domain.LabelPolicyThemeLight
case policy_pb.ThemeMode_THEME_MODE_UNSPECIFIED:
return domain.LabelPolicyThemeAuto
default:
return domain.LabelPolicyThemeAuto
} }
} }
@ -32,5 +49,6 @@ func updateLabelPolicyToDomain(p *mgmt_pb.UpdateCustomLabelPolicyRequest) *domai
FontColorDark: p.FontColorDark, FontColorDark: p.FontColorDark,
HideLoginNameSuffix: p.HideLoginNameSuffix, HideLoginNameSuffix: p.HideLoginNameSuffix,
DisableWatermark: p.DisableWatermark, DisableWatermark: p.DisableWatermark,
ThemeMode: themeModeToDomain(p.ThemeMode),
} }
} }

View File

@ -26,6 +26,7 @@ func ModelLabelPolicyToPb(policy *query.LabelPolicy, assetPrefix string) *policy
DisableWatermark: policy.WatermarkDisabled, DisableWatermark: policy.WatermarkDisabled,
HideLoginNameSuffix: policy.HideLoginNameSuffix, HideLoginNameSuffix: policy.HideLoginNameSuffix,
ThemeMode: themeModeToPb(policy.ThemeMode),
Details: object.ToViewDetailsPb( Details: object.ToViewDetailsPb(
policy.Sequence, policy.Sequence,
policy.CreationDate, policy.CreationDate,
@ -34,3 +35,16 @@ func ModelLabelPolicyToPb(policy *query.LabelPolicy, assetPrefix string) *policy
), ),
} }
} }
func themeModeToPb(theme domain.LabelPolicyThemeMode) policy_pb.ThemeMode {
switch theme {
case domain.LabelPolicyThemeAuto:
return policy_pb.ThemeMode_THEME_MODE_AUTO
case domain.LabelPolicyThemeDark:
return policy_pb.ThemeMode_THEME_MODE_DARK
case domain.LabelPolicyThemeLight:
return policy_pb.ThemeMode_THEME_MODE_LIGHT
default:
return policy_pb.ThemeMode_THEME_MODE_AUTO
}
}

View File

@ -107,6 +107,20 @@ func brandingSettingsToPb(current *query.LabelPolicy, assetPrefix string) *setti
DisableWatermark: current.WatermarkDisabled, DisableWatermark: current.WatermarkDisabled,
HideLoginNameSuffix: current.HideLoginNameSuffix, HideLoginNameSuffix: current.HideLoginNameSuffix,
ResourceOwnerType: isDefaultToResourceOwnerTypePb(current.IsDefault), ResourceOwnerType: isDefaultToResourceOwnerTypePb(current.IsDefault),
ThemeMode: themeModeToPb(current.ThemeMode),
}
}
func themeModeToPb(themeMode domain.LabelPolicyThemeMode) settings.ThemeMode {
switch themeMode {
case domain.LabelPolicyThemeAuto:
return settings.ThemeMode_THEME_MODE_AUTO
case domain.LabelPolicyThemeLight:
return settings.ThemeMode_THEME_MODE_LIGHT
case domain.LabelPolicyThemeDark:
return settings.ThemeMode_THEME_MODE_DARK
default:
return settings.ThemeMode_THEME_MODE_AUTO
} }
} }

View File

@ -258,6 +258,7 @@ func Test_brandingSettingsToPb(t *testing.T) {
FontURL: "fonts", FontURL: "fonts",
WatermarkDisabled: true, WatermarkDisabled: true,
HideLoginNameSuffix: true, HideLoginNameSuffix: true,
ThemeMode: domain.LabelPolicyThemeDark,
IsDefault: true, IsDefault: true,
} }
want := &settings.BrandingSettings{ want := &settings.BrandingSettings{
@ -281,6 +282,7 @@ func Test_brandingSettingsToPb(t *testing.T) {
DisableWatermark: true, DisableWatermark: true,
HideLoginNameSuffix: true, HideLoginNameSuffix: true,
ResourceOwnerType: settings.ResourceOwnerType_RESOURCE_OWNER_TYPE_INSTANCE, ResourceOwnerType: settings.ResourceOwnerType_RESOURCE_OWNER_TYPE_INSTANCE,
ThemeMode: settings.ThemeMode_THEME_MODE_DARK,
} }
got := brandingSettingsToPb(arg, "http://example.com") got := brandingSettingsToPb(arg, "http://example.com")

View File

@ -381,8 +381,6 @@ func (l *Login) getBaseData(r *http.Request, authReq *domain.AuthRequest, titleI
Title: title, Title: title,
Description: description, Description: description,
Theme: l.getTheme(r), Theme: l.getTheme(r),
ThemeMode: l.getThemeMode(r),
DarkMode: l.isDarkMode(r),
PrivateLabelingOrgID: l.getPrivateLabelingID(r, authReq), PrivateLabelingOrgID: l.getPrivateLabelingID(r, authReq),
OrgID: l.getOrgID(r, authReq), OrgID: l.getOrgID(r, authReq),
OrgName: l.getOrgName(authReq), OrgName: l.getOrgName(authReq),
@ -412,6 +410,9 @@ func (l *Login) getBaseData(r *http.Request, authReq *domain.AuthRequest, titleI
} }
privacyPolicy = policy.ToDomain() privacyPolicy = policy.ToDomain()
} }
baseData.ThemeMode = l.getThemeMode(baseData.LabelPolicy)
baseData.ThemeClass = l.getThemeClass(r, baseData.LabelPolicy)
baseData.DarkMode = l.isDarkMode(r, baseData.LabelPolicy)
baseData = l.setLinksOnBaseData(baseData, privacyPolicy) baseData = l.setLinksOnBaseData(baseData, privacyPolicy)
return baseData return baseData
} }
@ -480,14 +481,22 @@ func (l *Login) getTheme(r *http.Request) string {
return "zitadel" return "zitadel"
} }
func (l *Login) getThemeMode(r *http.Request) string { // getThemeClass returns the css class for the login html.
if l.isDarkMode(r) { // Possible values are `lgn-light-theme` and `lgn-dark-theme` and are based on the policy first
// and if it's set to auto the cookie is checked.
func (l *Login) getThemeClass(r *http.Request, policy *domain.LabelPolicy) string {
if l.isDarkMode(r, policy) {
return "lgn-dark-theme" return "lgn-dark-theme"
} }
return "lgn-light-theme" return "lgn-light-theme"
} }
func (l *Login) isDarkMode(r *http.Request) bool { // isDarkMode checks policy first and if not set to specifically use dark or light only,
// it will also check the cookie.
func (l *Login) isDarkMode(r *http.Request, policy *domain.LabelPolicy) bool {
if mode := l.getThemeMode(policy); mode != domain.LabelPolicyThemeAuto {
return mode == domain.LabelPolicyThemeDark
}
cookie, err := r.Cookie("mode") cookie, err := r.Cookie("mode")
if err != nil { if err != nil {
return false return false
@ -495,6 +504,13 @@ func (l *Login) isDarkMode(r *http.Request) bool {
return strings.HasSuffix(cookie.Value, "dark") return strings.HasSuffix(cookie.Value, "dark")
} }
func (l *Login) getThemeMode(policy *domain.LabelPolicy) domain.LabelPolicyThemeMode {
if policy != nil {
return policy.ThemeMode
}
return domain.LabelPolicyThemeAuto
}
func (l *Login) getOrgID(r *http.Request, authReq *domain.AuthRequest) string { func (l *Login) getOrgID(r *http.Request, authReq *domain.AuthRequest) string {
if authReq == nil { if authReq == nil {
return r.FormValue(queryOrgID) return r.FormValue(queryOrgID)
@ -607,7 +623,8 @@ type baseData struct {
Title string Title string
Description string Description string
Theme string Theme string
ThemeMode string ThemeMode domain.LabelPolicyThemeMode
ThemeClass string
DarkMode bool DarkMode bool
PrivateLabelingOrgID string PrivateLabelingOrgID string
OrgID string OrgID string

View File

@ -1,10 +1,16 @@
const usesDarkTheme = hasDarkModeOverwriteCookie() || (!hasLightModeOverwriteCookie() && window.matchMedia('(prefers-color-scheme: dark)').matches); if (isAutoMode()) {
if (usesDarkTheme) { const usesDarkTheme = hasDarkModeOverwriteCookie() || (!hasLightModeOverwriteCookie() && window.matchMedia('(prefers-color-scheme: dark)').matches);
document.documentElement.classList.replace('lgn-light-theme', 'lgn-dark-theme'); if (usesDarkTheme) {
writeModeCookie('dark'); document.documentElement.classList.replace('lgn-light-theme', 'lgn-dark-theme');
} else { writeModeCookie('dark');
document.documentElement.classList.replace('lgn-dark-theme', 'lgn-light-theme'); } else {
writeModeCookie('light'); document.documentElement.classList.replace('lgn-dark-theme', 'lgn-light-theme');
writeModeCookie('light');
}
}
function isAutoMode() {
return document.documentElement.dataset["themeMode"] === "0"
} }
function hasDarkModeOverwriteCookie() { function hasDarkModeOverwriteCookie() {

View File

@ -1,6 +1,6 @@
{{define "main-top"}} {{define "main-top"}}
<!DOCTYPE html> <!DOCTYPE html>
<html lang="{{ .Lang }}" class="{{.ThemeMode}}"> <html lang="{{ .Lang }}" class="{{.ThemeClass}}" data-theme-mode="{{.ThemeMode}}">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">

View File

@ -1335,6 +1335,7 @@ func labelPolicyToDomain(p *query.LabelPolicy) *domain.LabelPolicy {
HideLoginNameSuffix: p.HideLoginNameSuffix, HideLoginNameSuffix: p.HideLoginNameSuffix,
ErrorMsgPopup: p.ShouldErrorPopup, ErrorMsgPopup: p.ShouldErrorPopup,
DisableWatermark: p.WatermarkDisabled, DisableWatermark: p.WatermarkDisabled,
ThemeMode: p.ThemeMode,
} }
} }

View File

@ -97,6 +97,7 @@ type InstanceSetup struct {
HideLoginNameSuffix bool HideLoginNameSuffix bool
ErrorMsgPopup bool ErrorMsgPopup bool
DisableWatermark bool DisableWatermark bool
ThemeMode domain.LabelPolicyThemeMode
} }
LockoutPolicy struct { LockoutPolicy struct {
MaxAttempts uint64 MaxAttempts uint64
@ -276,6 +277,7 @@ func (c *Commands) SetUpInstance(ctx context.Context, setup *InstanceSetup) (str
setup.LabelPolicy.HideLoginNameSuffix, setup.LabelPolicy.HideLoginNameSuffix,
setup.LabelPolicy.ErrorMsgPopup, setup.LabelPolicy.ErrorMsgPopup,
setup.LabelPolicy.DisableWatermark, setup.LabelPolicy.DisableWatermark,
setup.LabelPolicy.ThemeMode,
), ),
prepareActivateDefaultLabelPolicy(instanceAgg), prepareActivateDefaultLabelPolicy(instanceAgg),

View File

@ -59,6 +59,7 @@ func writeModelToLabelPolicy(wm *LabelPolicyWriteModel) *domain.LabelPolicy {
HideLoginNameSuffix: wm.HideLoginNameSuffix, HideLoginNameSuffix: wm.HideLoginNameSuffix,
ErrorMsgPopup: wm.ErrorMsgPopup, ErrorMsgPopup: wm.ErrorMsgPopup,
DisableWatermark: wm.DisableWatermark, DisableWatermark: wm.DisableWatermark,
ThemeMode: wm.ThemeMode,
} }
} }

View File

@ -15,7 +15,7 @@ import (
func (c *Commands) AddDefaultLabelPolicy( func (c *Commands) AddDefaultLabelPolicy(
ctx context.Context, ctx context.Context,
primaryColor, backgroundColor, warnColor, fontColor, primaryColorDark, backgroundColorDark, warnColorDark, fontColorDark string, primaryColor, backgroundColor, warnColor, fontColor, primaryColorDark, backgroundColorDark, warnColorDark, fontColorDark string,
hideLoginNameSuffix, errorMsgPopup, disableWatermark bool, hideLoginNameSuffix, errorMsgPopup, disableWatermark bool, themeMode domain.LabelPolicyThemeMode,
) (*domain.ObjectDetails, error) { ) (*domain.ObjectDetails, error) {
instanceAgg := instance.NewAggregate(authz.GetInstance(ctx).InstanceID()) instanceAgg := instance.NewAggregate(authz.GetInstance(ctx).InstanceID())
cmds, err := preparation.PrepareCommands(ctx, c.eventstore.Filter, cmds, err := preparation.PrepareCommands(ctx, c.eventstore.Filter,
@ -32,6 +32,7 @@ func (c *Commands) AddDefaultLabelPolicy(
hideLoginNameSuffix, hideLoginNameSuffix,
errorMsgPopup, errorMsgPopup,
disableWatermark, disableWatermark,
themeMode,
)) ))
if err != nil { if err != nil {
return nil, err return nil, err
@ -69,7 +70,8 @@ func (c *Commands) ChangeDefaultLabelPolicy(ctx context.Context, policy *domain.
policy.FontColorDark, policy.FontColorDark,
policy.HideLoginNameSuffix, policy.HideLoginNameSuffix,
policy.ErrorMsgPopup, policy.ErrorMsgPopup,
policy.DisableWatermark) policy.DisableWatermark,
policy.ThemeMode)
if !hasChanged { if !hasChanged {
return nil, caos_errs.ThrowPreconditionFailed(nil, "INSTANCE-28fHe", "Errors.IAM.LabelPolicy.NotChanged") return nil, caos_errs.ThrowPreconditionFailed(nil, "INSTANCE-28fHe", "Errors.IAM.LabelPolicy.NotChanged")
} }
@ -384,6 +386,7 @@ func prepareAddDefaultLabelPolicy(
hideLoginNameSuffix, hideLoginNameSuffix,
errorMsgPopup, errorMsgPopup,
disableWatermark bool, disableWatermark bool,
themeMode domain.LabelPolicyThemeMode,
) preparation.Validation { ) preparation.Validation {
return func() (preparation.CreateCommands, error) { return func() (preparation.CreateCommands, error) {
return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) { return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
@ -412,6 +415,7 @@ func prepareAddDefaultLabelPolicy(
hideLoginNameSuffix, hideLoginNameSuffix,
errorMsgPopup, errorMsgPopup,
disableWatermark, disableWatermark,
themeMode,
), ),
}, nil }, nil
}, nil }, nil

View File

@ -4,6 +4,7 @@ import (
"context" "context"
"github.com/zitadel/zitadel/internal/api/authz" "github.com/zitadel/zitadel/internal/api/authz"
"github.com/zitadel/zitadel/internal/domain"
"github.com/zitadel/zitadel/internal/eventstore" "github.com/zitadel/zitadel/internal/eventstore"
"github.com/zitadel/zitadel/internal/repository/instance" "github.com/zitadel/zitadel/internal/repository/instance"
"github.com/zitadel/zitadel/internal/repository/policy" "github.com/zitadel/zitadel/internal/repository/policy"
@ -97,6 +98,7 @@ func (wm *InstanceLabelPolicyWriteModel) NewChangedEvent(
hideLoginNameSuffix, hideLoginNameSuffix,
errorMsgPopup, errorMsgPopup,
disableWatermark bool, disableWatermark bool,
themeMode domain.LabelPolicyThemeMode,
) (*instance.LabelPolicyChangedEvent, bool) { ) (*instance.LabelPolicyChangedEvent, bool) {
changes := make([]policy.LabelPolicyChanges, 0) changes := make([]policy.LabelPolicyChanges, 0)
if wm.PrimaryColor != primaryColor { if wm.PrimaryColor != primaryColor {
@ -132,6 +134,9 @@ func (wm *InstanceLabelPolicyWriteModel) NewChangedEvent(
if wm.DisableWatermark != disableWatermark { if wm.DisableWatermark != disableWatermark {
changes = append(changes, policy.ChangeDisableWatermark(disableWatermark)) changes = append(changes, policy.ChangeDisableWatermark(disableWatermark))
} }
if wm.ThemeMode != themeMode {
changes = append(changes, policy.ChangeThemeMode(themeMode))
}
if len(changes) == 0 { if len(changes) == 0 {
return nil, false return nil, false
} }

View File

@ -36,6 +36,7 @@ func TestCommandSide_AddDefaultLabelPolicy(t *testing.T) {
hideLoginNameSuffix bool hideLoginNameSuffix bool
errorMsgPopup bool errorMsgPopup bool
disableWatermark bool disableWatermark bool
themeMode domain.LabelPolicyThemeMode
} }
type res struct { type res struct {
want *domain.ObjectDetails want *domain.ObjectDetails
@ -67,6 +68,7 @@ func TestCommandSide_AddDefaultLabelPolicy(t *testing.T) {
true, true,
true, true,
true, true,
domain.LabelPolicyThemeAuto,
), ),
), ),
), ),
@ -85,6 +87,7 @@ func TestCommandSide_AddDefaultLabelPolicy(t *testing.T) {
hideLoginNameSuffix: true, hideLoginNameSuffix: true,
errorMsgPopup: true, errorMsgPopup: true,
disableWatermark: true, disableWatermark: true,
themeMode: domain.LabelPolicyThemeAuto,
}, },
res: res{ res: res{
err: caos_errs.IsErrorAlreadyExists, err: caos_errs.IsErrorAlreadyExists,
@ -110,6 +113,7 @@ func TestCommandSide_AddDefaultLabelPolicy(t *testing.T) {
true, true,
true, true,
true, true,
domain.LabelPolicyThemeDark,
), ),
), ),
), ),
@ -127,6 +131,7 @@ func TestCommandSide_AddDefaultLabelPolicy(t *testing.T) {
hideLoginNameSuffix: true, hideLoginNameSuffix: true,
errorMsgPopup: true, errorMsgPopup: true,
disableWatermark: true, disableWatermark: true,
themeMode: domain.LabelPolicyThemeDark,
}, },
res: res{ res: res{
want: &domain.ObjectDetails{ want: &domain.ObjectDetails{
@ -153,6 +158,7 @@ func TestCommandSide_AddDefaultLabelPolicy(t *testing.T) {
tt.args.hideLoginNameSuffix, tt.args.hideLoginNameSuffix,
tt.args.errorMsgPopup, tt.args.errorMsgPopup,
tt.args.disableWatermark, tt.args.disableWatermark,
tt.args.themeMode,
) )
if tt.res.err == nil { if tt.res.err == nil {
assert.NoError(t, err) assert.NoError(t, err)
@ -225,6 +231,7 @@ func TestCommandSide_ChangeDefaultLabelPolicy(t *testing.T) {
true, true,
true, true,
true, true,
domain.LabelPolicyThemeAuto,
), ),
), ),
), ),
@ -244,6 +251,7 @@ func TestCommandSide_ChangeDefaultLabelPolicy(t *testing.T) {
HideLoginNameSuffix: true, HideLoginNameSuffix: true,
ErrorMsgPopup: true, ErrorMsgPopup: true,
DisableWatermark: true, DisableWatermark: true,
ThemeMode: domain.LabelPolicyThemeAuto,
}, },
}, },
res: res{ res: res{
@ -270,6 +278,7 @@ func TestCommandSide_ChangeDefaultLabelPolicy(t *testing.T) {
true, true,
true, true,
true, true,
domain.LabelPolicyThemeAuto,
), ),
), ),
), ),
@ -286,7 +295,8 @@ func TestCommandSide_ChangeDefaultLabelPolicy(t *testing.T) {
"#000000", "#000000",
false, false,
false, false,
false), false,
domain.LabelPolicyThemeDark),
), ),
), ),
}, },
@ -304,6 +314,7 @@ func TestCommandSide_ChangeDefaultLabelPolicy(t *testing.T) {
HideLoginNameSuffix: false, HideLoginNameSuffix: false,
ErrorMsgPopup: false, ErrorMsgPopup: false,
DisableWatermark: false, DisableWatermark: false,
ThemeMode: domain.LabelPolicyThemeDark,
}, },
}, },
res: res{ res: res{
@ -324,6 +335,7 @@ func TestCommandSide_ChangeDefaultLabelPolicy(t *testing.T) {
HideLoginNameSuffix: false, HideLoginNameSuffix: false,
ErrorMsgPopup: false, ErrorMsgPopup: false,
DisableWatermark: false, DisableWatermark: false,
ThemeMode: domain.LabelPolicyThemeDark,
}, },
}, },
}, },
@ -399,6 +411,7 @@ func TestCommandSide_ActivateDefaultLabelPolicy(t *testing.T) {
true, true,
true, true,
true, true,
domain.LabelPolicyThemeAuto,
), ),
), ),
), ),
@ -500,6 +513,7 @@ func TestCommandSide_AddLogoDefaultLabelPolicy(t *testing.T) {
true, true,
true, true,
true, true,
domain.LabelPolicyThemeAuto,
), ),
), ),
), ),
@ -541,6 +555,7 @@ func TestCommandSide_AddLogoDefaultLabelPolicy(t *testing.T) {
true, true,
true, true,
true, true,
domain.LabelPolicyThemeAuto,
), ),
), ),
), ),
@ -645,6 +660,7 @@ func TestCommandSide_RemoveLogoDefaultLabelPolicy(t *testing.T) {
true, true,
true, true,
true, true,
domain.LabelPolicyThemeAuto,
), ),
), ),
eventFromEventPusher( eventFromEventPusher(
@ -684,6 +700,7 @@ func TestCommandSide_RemoveLogoDefaultLabelPolicy(t *testing.T) {
true, true,
true, true,
true, true,
domain.LabelPolicyThemeAuto,
), ),
), ),
eventFromEventPusher( eventFromEventPusher(
@ -793,6 +810,7 @@ func TestCommandSide_AddIconDefaultLabelPolicy(t *testing.T) {
true, true,
true, true,
true, true,
domain.LabelPolicyThemeAuto,
), ),
), ),
), ),
@ -834,6 +852,7 @@ func TestCommandSide_AddIconDefaultLabelPolicy(t *testing.T) {
true, true,
true, true,
true, true,
domain.LabelPolicyThemeAuto,
), ),
), ),
), ),
@ -938,6 +957,7 @@ func TestCommandSide_RemoveIconDefaultLabelPolicy(t *testing.T) {
true, true,
true, true,
true, true,
domain.LabelPolicyThemeAuto,
), ),
), ),
eventFromEventPusher( eventFromEventPusher(
@ -1049,6 +1069,7 @@ func TestCommandSide_AddLogoDarkDefaultLabelPolicy(t *testing.T) {
true, true,
true, true,
true, true,
domain.LabelPolicyThemeAuto,
), ),
), ),
), ),
@ -1091,6 +1112,7 @@ func TestCommandSide_AddLogoDarkDefaultLabelPolicy(t *testing.T) {
true, true,
true, true,
true, true,
domain.LabelPolicyThemeAuto,
), ),
), ),
), ),
@ -1195,6 +1217,7 @@ func TestCommandSide_RemoveLogoDarkDefaultLabelPolicy(t *testing.T) {
true, true,
true, true,
true, true,
domain.LabelPolicyThemeAuto,
), ),
), ),
eventFromEventPusher( eventFromEventPusher(
@ -1234,6 +1257,7 @@ func TestCommandSide_RemoveLogoDarkDefaultLabelPolicy(t *testing.T) {
true, true,
true, true,
true, true,
domain.LabelPolicyThemeAuto,
), ),
), ),
eventFromEventPusher( eventFromEventPusher(
@ -1343,6 +1367,7 @@ func TestCommandSide_AddIconDarkDefaultLabelPolicy(t *testing.T) {
true, true,
true, true,
true, true,
domain.LabelPolicyThemeAuto,
), ),
), ),
), ),
@ -1384,6 +1409,7 @@ func TestCommandSide_AddIconDarkDefaultLabelPolicy(t *testing.T) {
true, true,
true, true,
true, true,
domain.LabelPolicyThemeAuto,
), ),
), ),
), ),
@ -1488,6 +1514,7 @@ func TestCommandSide_RemoveIconDarkDefaultLabelPolicy(t *testing.T) {
true, true,
true, true,
true, true,
domain.LabelPolicyThemeAuto,
), ),
), ),
eventFromEventPusher( eventFromEventPusher(
@ -1527,6 +1554,7 @@ func TestCommandSide_RemoveIconDarkDefaultLabelPolicy(t *testing.T) {
true, true,
true, true,
true, true,
domain.LabelPolicyThemeAuto,
), ),
), ),
eventFromEventPusher( eventFromEventPusher(
@ -1636,6 +1664,7 @@ func TestCommandSide_AddFontDefaultLabelPolicy(t *testing.T) {
true, true,
true, true,
true, true,
domain.LabelPolicyThemeAuto,
), ),
), ),
), ),
@ -1677,6 +1706,7 @@ func TestCommandSide_AddFontDefaultLabelPolicy(t *testing.T) {
true, true,
true, true,
true, true,
domain.LabelPolicyThemeAuto,
), ),
), ),
), ),
@ -1781,6 +1811,7 @@ func TestCommandSide_RemoveFontDefaultLabelPolicy(t *testing.T) {
true, true,
true, true,
true, true,
domain.LabelPolicyThemeAuto,
), ),
), ),
eventFromEventPusher( eventFromEventPusher(
@ -1820,6 +1851,7 @@ func TestCommandSide_RemoveFontDefaultLabelPolicy(t *testing.T) {
true, true,
true, true,
true, true,
domain.LabelPolicyThemeAuto,
), ),
), ),
eventFromEventPusher( eventFromEventPusher(
@ -1867,7 +1899,7 @@ func TestCommandSide_RemoveFontDefaultLabelPolicy(t *testing.T) {
} }
} }
func newDefaultLabelPolicyChangedEvent(ctx context.Context, primaryColor, backgroundColor, warnColor, fontColor, primaryColorDark, backgroundColorDark, warnColorDark, fontColorDark string, hideLoginNameSuffix, errMsgPopup, disableWatermark bool) *instance.LabelPolicyChangedEvent { func newDefaultLabelPolicyChangedEvent(ctx context.Context, primaryColor, backgroundColor, warnColor, fontColor, primaryColorDark, backgroundColorDark, warnColorDark, fontColorDark string, hideLoginNameSuffix, errMsgPopup, disableWatermark bool, theme domain.LabelPolicyThemeMode) *instance.LabelPolicyChangedEvent {
event, _ := instance.NewLabelPolicyChangedEvent(ctx, event, _ := instance.NewLabelPolicyChangedEvent(ctx,
&instance.NewAggregate("INSTANCE").Aggregate, &instance.NewAggregate("INSTANCE").Aggregate,
[]policy.LabelPolicyChanges{ []policy.LabelPolicyChanges{
@ -1882,6 +1914,7 @@ func newDefaultLabelPolicyChangedEvent(ctx context.Context, primaryColor, backgr
policy.ChangeHideLoginNameSuffix(hideLoginNameSuffix), policy.ChangeHideLoginNameSuffix(hideLoginNameSuffix),
policy.ChangeErrorMsgPopup(errMsgPopup), policy.ChangeErrorMsgPopup(errMsgPopup),
policy.ChangeDisableWatermark(disableWatermark), policy.ChangeDisableWatermark(disableWatermark),
policy.ChangeThemeMode(theme),
}, },
) )
return event return event

View File

@ -39,7 +39,8 @@ func (c *Commands) AddLabelPolicy(ctx context.Context, resourceOwner string, pol
policy.FontColorDark, policy.FontColorDark,
policy.HideLoginNameSuffix, policy.HideLoginNameSuffix,
policy.ErrorMsgPopup, policy.ErrorMsgPopup,
policy.DisableWatermark)) policy.DisableWatermark,
policy.ThemeMode))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -80,7 +81,8 @@ func (c *Commands) ChangeLabelPolicy(ctx context.Context, resourceOwner string,
policy.FontColorDark, policy.FontColorDark,
policy.HideLoginNameSuffix, policy.HideLoginNameSuffix,
policy.ErrorMsgPopup, policy.ErrorMsgPopup,
policy.DisableWatermark) policy.DisableWatermark,
policy.ThemeMode)
if !hasChanged { if !hasChanged {
return nil, caos_errs.ThrowPreconditionFailed(nil, "Org-8nfSr", "Errors.Org.LabelPolicy.NotChanged") return nil, caos_errs.ThrowPreconditionFailed(nil, "Org-8nfSr", "Errors.Org.LabelPolicy.NotChanged")
} }

View File

@ -3,6 +3,7 @@ package command
import ( import (
"context" "context"
"github.com/zitadel/zitadel/internal/domain"
"github.com/zitadel/zitadel/internal/eventstore" "github.com/zitadel/zitadel/internal/eventstore"
"github.com/zitadel/zitadel/internal/repository/org" "github.com/zitadel/zitadel/internal/repository/org"
@ -98,6 +99,7 @@ func (wm *OrgLabelPolicyWriteModel) NewChangedEvent(
hideLoginNameSuffix, hideLoginNameSuffix,
errorMsgPopup, errorMsgPopup,
disableWatermark bool, disableWatermark bool,
themeMode domain.LabelPolicyThemeMode,
) (*org.LabelPolicyChangedEvent, bool) { ) (*org.LabelPolicyChangedEvent, bool) {
changes := make([]policy.LabelPolicyChanges, 0) changes := make([]policy.LabelPolicyChanges, 0)
if wm.PrimaryColor != primaryColor { if wm.PrimaryColor != primaryColor {
@ -133,6 +135,9 @@ func (wm *OrgLabelPolicyWriteModel) NewChangedEvent(
if wm.DisableWatermark != disableWatermark { if wm.DisableWatermark != disableWatermark {
changes = append(changes, policy.ChangeDisableWatermark(disableWatermark)) changes = append(changes, policy.ChangeDisableWatermark(disableWatermark))
} }
if wm.ThemeMode != themeMode {
changes = append(changes, policy.ChangeThemeMode(themeMode))
}
if len(changes) == 0 { if len(changes) == 0 {
return nil, false return nil, false
} }

View File

@ -75,6 +75,7 @@ func TestCommandSide_AddLabelPolicy(t *testing.T) {
true, true,
true, true,
true, true,
domain.LabelPolicyThemeAuto,
), ),
), ),
), ),
@ -121,6 +122,7 @@ func TestCommandSide_AddLabelPolicy(t *testing.T) {
true, true,
true, true,
true, true,
domain.LabelPolicyThemeDark,
), ),
), ),
), ),
@ -140,6 +142,7 @@ func TestCommandSide_AddLabelPolicy(t *testing.T) {
HideLoginNameSuffix: true, HideLoginNameSuffix: true,
ErrorMsgPopup: true, ErrorMsgPopup: true,
DisableWatermark: true, DisableWatermark: true,
ThemeMode: domain.LabelPolicyThemeDark,
}, },
}, },
res: res{ res: res{
@ -159,6 +162,7 @@ func TestCommandSide_AddLabelPolicy(t *testing.T) {
HideLoginNameSuffix: true, HideLoginNameSuffix: true,
ErrorMsgPopup: true, ErrorMsgPopup: true,
DisableWatermark: true, DisableWatermark: true,
ThemeMode: domain.LabelPolicyThemeDark,
}, },
}, },
}, },
@ -260,6 +264,7 @@ func TestCommandSide_ChangeLabelPolicy(t *testing.T) {
true, true,
true, true,
true, true,
domain.LabelPolicyThemeAuto,
), ),
), ),
), ),
@ -280,6 +285,7 @@ func TestCommandSide_ChangeLabelPolicy(t *testing.T) {
HideLoginNameSuffix: true, HideLoginNameSuffix: true,
ErrorMsgPopup: true, ErrorMsgPopup: true,
DisableWatermark: true, DisableWatermark: true,
ThemeMode: domain.LabelPolicyThemeAuto,
}, },
}, },
res: res{ res: res{
@ -306,6 +312,7 @@ func TestCommandSide_ChangeLabelPolicy(t *testing.T) {
true, true,
true, true,
true, true,
domain.LabelPolicyThemeAuto,
), ),
), ),
), ),
@ -323,7 +330,8 @@ func TestCommandSide_ChangeLabelPolicy(t *testing.T) {
"#000000", "#000000",
false, false,
false, false,
false), false,
domain.LabelPolicyThemeDark),
), ),
), ),
}, },
@ -342,6 +350,7 @@ func TestCommandSide_ChangeLabelPolicy(t *testing.T) {
HideLoginNameSuffix: false, HideLoginNameSuffix: false,
ErrorMsgPopup: false, ErrorMsgPopup: false,
DisableWatermark: false, DisableWatermark: false,
ThemeMode: domain.LabelPolicyThemeDark,
}, },
}, },
res: res{ res: res{
@ -361,6 +370,7 @@ func TestCommandSide_ChangeLabelPolicy(t *testing.T) {
HideLoginNameSuffix: false, HideLoginNameSuffix: false,
ErrorMsgPopup: false, ErrorMsgPopup: false,
DisableWatermark: false, DisableWatermark: false,
ThemeMode: domain.LabelPolicyThemeDark,
}, },
}, },
}, },
@ -451,6 +461,7 @@ func TestCommandSide_ActivateLabelPolicy(t *testing.T) {
true, true,
true, true,
true, true,
domain.LabelPolicyThemeAuto,
), ),
), ),
), ),
@ -551,6 +562,7 @@ func TestCommandSide_RemoveLabelPolicy(t *testing.T) {
true, true,
true, true,
true, true,
domain.LabelPolicyThemeAuto,
), ),
), ),
), ),
@ -672,6 +684,7 @@ func TestCommandSide_AddLogoLabelPolicy(t *testing.T) {
true, true,
true, true,
true, true,
domain.LabelPolicyThemeAuto,
), ),
), ),
), ),
@ -714,6 +727,7 @@ func TestCommandSide_AddLogoLabelPolicy(t *testing.T) {
true, true,
true, true,
true, true,
domain.LabelPolicyThemeAuto,
), ),
), ),
), ),
@ -838,6 +852,7 @@ func TestCommandSide_RemoveLogoLabelPolicy(t *testing.T) {
true, true,
true, true,
true, true,
domain.LabelPolicyThemeAuto,
), ),
), ),
eventFromEventPusher( eventFromEventPusher(
@ -974,6 +989,7 @@ func TestCommandSide_AddIconLabelPolicy(t *testing.T) {
true, true,
true, true,
true, true,
domain.LabelPolicyThemeAuto,
), ),
), ),
), ),
@ -1016,6 +1032,7 @@ func TestCommandSide_AddIconLabelPolicy(t *testing.T) {
true, true,
true, true,
true, true,
domain.LabelPolicyThemeAuto,
), ),
), ),
), ),
@ -1138,6 +1155,7 @@ func TestCommandSide_RemoveIconLabelPolicy(t *testing.T) {
true, true,
true, true,
true, true,
domain.LabelPolicyThemeAuto,
), ),
), ),
eventFromEventPusher( eventFromEventPusher(
@ -1273,6 +1291,7 @@ func TestCommandSide_AddLogoDarkLabelPolicy(t *testing.T) {
true, true,
true, true,
true, true,
domain.LabelPolicyThemeAuto,
), ),
), ),
), ),
@ -1315,6 +1334,7 @@ func TestCommandSide_AddLogoDarkLabelPolicy(t *testing.T) {
true, true,
true, true,
true, true,
domain.LabelPolicyThemeAuto,
), ),
), ),
), ),
@ -1439,6 +1459,7 @@ func TestCommandSide_RemoveLogoDarkLabelPolicy(t *testing.T) {
true, true,
true, true,
true, true,
domain.LabelPolicyThemeAuto,
), ),
), ),
eventFromEventPusher( eventFromEventPusher(
@ -1575,6 +1596,7 @@ func TestCommandSide_AddIconDarkLabelPolicy(t *testing.T) {
true, true,
true, true,
true, true,
domain.LabelPolicyThemeAuto,
), ),
), ),
), ),
@ -1617,6 +1639,7 @@ func TestCommandSide_AddIconDarkLabelPolicy(t *testing.T) {
true, true,
true, true,
true, true,
domain.LabelPolicyThemeAuto,
), ),
), ),
), ),
@ -1737,6 +1760,7 @@ func TestCommandSide_RemoveIconDarkLabelPolicy(t *testing.T) {
true, true,
true, true,
true, true,
domain.LabelPolicyThemeAuto,
), ),
), ),
eventFromEventPusher( eventFromEventPusher(
@ -1864,6 +1888,7 @@ func TestCommandSide_AddFontLabelPolicy(t *testing.T) {
true, true,
true, true,
true, true,
domain.LabelPolicyThemeAuto,
), ),
), ),
), ),
@ -1906,6 +1931,7 @@ func TestCommandSide_AddFontLabelPolicy(t *testing.T) {
true, true,
true, true,
true, true,
domain.LabelPolicyThemeAuto,
), ),
), ),
), ),
@ -2026,6 +2052,7 @@ func TestCommandSide_RemoveFontLabelPolicy(t *testing.T) {
true, true,
true, true,
true, true,
domain.LabelPolicyThemeAuto,
), ),
), ),
eventFromEventPusher( eventFromEventPusher(
@ -2074,7 +2101,7 @@ func TestCommandSide_RemoveFontLabelPolicy(t *testing.T) {
} }
} }
func newLabelPolicyChangedEvent(ctx context.Context, orgID, primaryColor, backgroundColor, warnColor, fontColor, primaryColorDark, backgroundColorDark, warnColorDark, fontColorDark string, hideLoginNameSuffix, errMsgPopup, disableWatermark bool) *org.LabelPolicyChangedEvent { func newLabelPolicyChangedEvent(ctx context.Context, orgID, primaryColor, backgroundColor, warnColor, fontColor, primaryColorDark, backgroundColorDark, warnColorDark, fontColorDark string, hideLoginNameSuffix, errMsgPopup, disableWatermark bool, theme domain.LabelPolicyThemeMode) *org.LabelPolicyChangedEvent {
event, _ := org.NewLabelPolicyChangedEvent(ctx, event, _ := org.NewLabelPolicyChangedEvent(ctx,
&org.NewAggregate(orgID).Aggregate, &org.NewAggregate(orgID).Aggregate,
[]policy.LabelPolicyChanges{ []policy.LabelPolicyChanges{
@ -2089,6 +2116,7 @@ func newLabelPolicyChangedEvent(ctx context.Context, orgID, primaryColor, backgr
policy.ChangeHideLoginNameSuffix(hideLoginNameSuffix), policy.ChangeHideLoginNameSuffix(hideLoginNameSuffix),
policy.ChangeErrorMsgPopup(errMsgPopup), policy.ChangeErrorMsgPopup(errMsgPopup),
policy.ChangeDisableWatermark(disableWatermark), policy.ChangeDisableWatermark(disableWatermark),
policy.ChangeThemeMode(theme),
}, },
) )
return event return event

View File

@ -28,6 +28,7 @@ type LabelPolicyWriteModel struct {
HideLoginNameSuffix bool HideLoginNameSuffix bool
ErrorMsgPopup bool ErrorMsgPopup bool
DisableWatermark bool DisableWatermark bool
ThemeMode domain.LabelPolicyThemeMode
State domain.PolicyState State domain.PolicyState
} }
@ -47,6 +48,7 @@ func (wm *LabelPolicyWriteModel) Reduce() error {
wm.HideLoginNameSuffix = e.HideLoginNameSuffix wm.HideLoginNameSuffix = e.HideLoginNameSuffix
wm.ErrorMsgPopup = e.ErrorMsgPopup wm.ErrorMsgPopup = e.ErrorMsgPopup
wm.DisableWatermark = e.DisableWatermark wm.DisableWatermark = e.DisableWatermark
wm.ThemeMode = e.ThemeMode
wm.State = domain.PolicyStateActive wm.State = domain.PolicyStateActive
case *policy.LabelPolicyChangedEvent: case *policy.LabelPolicyChangedEvent:
if e.PrimaryColor != nil { if e.PrimaryColor != nil {
@ -82,6 +84,9 @@ func (wm *LabelPolicyWriteModel) Reduce() error {
if e.DisableWatermark != nil { if e.DisableWatermark != nil {
wm.DisableWatermark = *e.DisableWatermark wm.DisableWatermark = *e.DisableWatermark
} }
if e.ThemeMode != nil {
wm.ThemeMode = *e.ThemeMode
}
case *policy.LabelPolicyLogoAddedEvent: case *policy.LabelPolicyLogoAddedEvent:
wm.LogoKey = e.StoreKey wm.LogoKey = e.StoreKey
case *policy.LabelPolicyLogoRemovedEvent: case *policy.LabelPolicyLogoRemovedEvent:

View File

@ -34,6 +34,7 @@ type LabelPolicy struct {
HideLoginNameSuffix bool HideLoginNameSuffix bool
ErrorMsgPopup bool ErrorMsgPopup bool
DisableWatermark bool DisableWatermark bool
ThemeMode LabelPolicyThemeMode
} }
type LabelPolicyState int32 type LabelPolicyState int32
@ -47,6 +48,14 @@ const (
labelPolicyStateCount labelPolicyStateCount
) )
type LabelPolicyThemeMode int32
const (
LabelPolicyThemeAuto LabelPolicyThemeMode = iota
LabelPolicyThemeLight
LabelPolicyThemeDark
)
func (f LabelPolicy) IsValid() error { func (f LabelPolicy) IsValid() error {
if !colorRegex.MatchString(f.PrimaryColor) { if !colorRegex.MatchString(f.PrimaryColor) {
return caos_errs.ThrowInvalidArgument(nil, "POLICY-391dG", "Errors.Policy.Label.Invalid.PrimaryColor") return caos_errs.ThrowInvalidArgument(nil, "POLICY-391dG", "Errors.Policy.Label.Invalid.PrimaryColor")

View File

@ -28,6 +28,7 @@ type LabelPolicy struct {
FontURL string FontURL string
WatermarkDisabled bool WatermarkDisabled bool
ShouldErrorPopup bool ShouldErrorPopup bool
ThemeMode domain.LabelPolicyThemeMode
Dark Theme Dark Theme
Light Theme Light Theme
@ -234,6 +235,9 @@ var (
LabelPolicyOwnerRemoved = Column{ LabelPolicyOwnerRemoved = Column{
name: projection.LabelPolicyOwnerRemovedCol, name: projection.LabelPolicyOwnerRemovedCol,
} }
LabelPolicyThemeMode = Column{
name: projection.LabelPolicyThemeModeCol,
}
) )
func prepareLabelPolicyQuery(ctx context.Context, db prepareDatabase) (sq.SelectBuilder, func(*sql.Row) (*LabelPolicy, error)) { func prepareLabelPolicyQuery(ctx context.Context, db prepareDatabase) (sq.SelectBuilder, func(*sql.Row) (*LabelPolicy, error)) {
@ -250,6 +254,7 @@ func prepareLabelPolicyQuery(ctx context.Context, db prepareDatabase) (sq.Select
LabelPolicyColFontURL.identifier(), LabelPolicyColFontURL.identifier(),
LabelPolicyColWatermarkDisabled.identifier(), LabelPolicyColWatermarkDisabled.identifier(),
LabelPolicyColShouldErrorPopup.identifier(), LabelPolicyColShouldErrorPopup.identifier(),
LabelPolicyThemeMode.identifier(),
LabelPolicyColLightPrimaryColor.identifier(), LabelPolicyColLightPrimaryColor.identifier(),
LabelPolicyColLightWarnColor.identifier(), LabelPolicyColLightWarnColor.identifier(),
@ -299,6 +304,7 @@ func prepareLabelPolicyQuery(ctx context.Context, db prepareDatabase) (sq.Select
&fontURL, &fontURL,
&policy.WatermarkDisabled, &policy.WatermarkDisabled,
&policy.ShouldErrorPopup, &policy.ShouldErrorPopup,
&policy.ThemeMode,
&lightPrimaryColor, &lightPrimaryColor,
&lightWarnColor, &lightWarnColor,
@ -358,5 +364,6 @@ func (p *LabelPolicy) ToDomain() *domain.LabelPolicy {
HideLoginNameSuffix: p.HideLoginNameSuffix, HideLoginNameSuffix: p.HideLoginNameSuffix,
ErrorMsgPopup: p.ShouldErrorPopup, ErrorMsgPopup: p.ShouldErrorPopup,
DisableWatermark: p.WatermarkDisabled, DisableWatermark: p.WatermarkDisabled,
ThemeMode: p.ThemeMode,
} }
} }

View File

@ -14,7 +14,7 @@ import (
) )
const ( const (
LabelPolicyTable = "projections.label_policies2" LabelPolicyTable = "projections.label_policies3"
LabelPolicyIDCol = "id" LabelPolicyIDCol = "id"
LabelPolicyCreationDateCol = "creation_date" LabelPolicyCreationDateCol = "creation_date"
@ -29,6 +29,7 @@ const (
LabelPolicyShouldErrorPopupCol = "should_error_popup" LabelPolicyShouldErrorPopupCol = "should_error_popup"
LabelPolicyFontURLCol = "font_url" LabelPolicyFontURLCol = "font_url"
LabelPolicyOwnerRemovedCol = "owner_removed" LabelPolicyOwnerRemovedCol = "owner_removed"
LabelPolicyThemeModeCol = "theme_mode"
LabelPolicyLightPrimaryColorCol = "light_primary_color" LabelPolicyLightPrimaryColorCol = "light_primary_color"
LabelPolicyLightWarnColorCol = "light_warn_color" LabelPolicyLightWarnColorCol = "light_warn_color"
@ -83,6 +84,7 @@ func (*labelPolicyProjection) Init() *old_handler.Check {
handler.NewColumn(LabelPolicyDarkLogoURLCol, handler.ColumnTypeText, handler.Nullable()), handler.NewColumn(LabelPolicyDarkLogoURLCol, handler.ColumnTypeText, handler.Nullable()),
handler.NewColumn(LabelPolicyDarkIconURLCol, handler.ColumnTypeText, handler.Nullable()), handler.NewColumn(LabelPolicyDarkIconURLCol, handler.ColumnTypeText, handler.Nullable()),
handler.NewColumn(LabelPolicyOwnerRemovedCol, handler.ColumnTypeBool, handler.Default(false)), handler.NewColumn(LabelPolicyOwnerRemovedCol, handler.ColumnTypeBool, handler.Default(false)),
handler.NewColumn(LabelPolicyThemeModeCol, handler.ColumnTypeEnum, handler.Default(0)),
}, },
handler.NewPrimaryKey(LabelPolicyInstanceIDCol, LabelPolicyIDCol, LabelPolicyStateCol), handler.NewPrimaryKey(LabelPolicyInstanceIDCol, LabelPolicyIDCol, LabelPolicyStateCol),
handler.WithIndex(handler.NewIndex("owner_removed", []string{LabelPolicyOwnerRemovedCol})), handler.WithIndex(handler.NewIndex("owner_removed", []string{LabelPolicyOwnerRemovedCol})),
@ -264,6 +266,7 @@ func (p *labelPolicyProjection) reduceAdded(event eventstore.Event) (*handler.St
handler.NewCol(LabelPolicyHideLoginNameSuffixCol, policyEvent.HideLoginNameSuffix), handler.NewCol(LabelPolicyHideLoginNameSuffixCol, policyEvent.HideLoginNameSuffix),
handler.NewCol(LabelPolicyShouldErrorPopupCol, policyEvent.ErrorMsgPopup), handler.NewCol(LabelPolicyShouldErrorPopupCol, policyEvent.ErrorMsgPopup),
handler.NewCol(LabelPolicyWatermarkDisabledCol, policyEvent.DisableWatermark), handler.NewCol(LabelPolicyWatermarkDisabledCol, policyEvent.DisableWatermark),
handler.NewCol(LabelPolicyThemeModeCol, policyEvent.ThemeMode),
}), nil }), nil
} }
@ -314,6 +317,9 @@ func (p *labelPolicyProjection) reduceChanged(event eventstore.Event) (*handler.
if policyEvent.DisableWatermark != nil { if policyEvent.DisableWatermark != nil {
cols = append(cols, handler.NewCol(LabelPolicyWatermarkDisabledCol, *policyEvent.DisableWatermark)) cols = append(cols, handler.NewCol(LabelPolicyWatermarkDisabledCol, *policyEvent.DisableWatermark))
} }
if policyEvent.ThemeMode != nil {
cols = append(cols, handler.NewCol(LabelPolicyThemeModeCol, *policyEvent.ThemeMode))
}
return handler.NewUpdateStatement( return handler.NewUpdateStatement(
&policyEvent, &policyEvent,
cols, cols,
@ -376,6 +382,7 @@ func (p *labelPolicyProjection) reduceActivated(event eventstore.Event) (*handle
handler.NewCol(LabelPolicyDarkFontColorCol, nil), handler.NewCol(LabelPolicyDarkFontColorCol, nil),
handler.NewCol(LabelPolicyDarkLogoURLCol, nil), handler.NewCol(LabelPolicyDarkLogoURLCol, nil),
handler.NewCol(LabelPolicyDarkIconURLCol, nil), handler.NewCol(LabelPolicyDarkIconURLCol, nil),
handler.NewCol(LabelPolicyThemeModeCol, nil),
}, },
[]handler.Column{ []handler.Column{
handler.NewCol(LabelPolicyChangeDateCol, nil), handler.NewCol(LabelPolicyChangeDateCol, nil),
@ -402,6 +409,7 @@ func (p *labelPolicyProjection) reduceActivated(event eventstore.Event) (*handle
handler.NewCol(LabelPolicyDarkFontColorCol, nil), handler.NewCol(LabelPolicyDarkFontColorCol, nil),
handler.NewCol(LabelPolicyDarkLogoURLCol, nil), handler.NewCol(LabelPolicyDarkLogoURLCol, nil),
handler.NewCol(LabelPolicyDarkIconURLCol, nil), handler.NewCol(LabelPolicyDarkIconURLCol, nil),
handler.NewCol(LabelPolicyThemeModeCol, nil),
}, },
[]handler.NamespacedCondition{ []handler.NamespacedCondition{
handler.NewNamespacedCondition(LabelPolicyIDCol, event.Aggregate().ID), handler.NewNamespacedCondition(LabelPolicyIDCol, event.Aggregate().ID),

View File

@ -28,7 +28,7 @@ func TestLabelPolicyProjection_reduces(t *testing.T) {
testEvent( testEvent(
org.LabelPolicyAddedEventType, org.LabelPolicyAddedEventType,
org.AggregateType, org.AggregateType,
[]byte(`{"backgroundColor": "#141735", "fontColor": "#ffffff", "primaryColor": "#5282c1", "warnColor": "#ff3b5b"}`), []byte(`{"backgroundColor": "#141735", "fontColor": "#ffffff", "primaryColor": "#5282c1", "warnColor": "#ff3b5b", "themeMode": 1}`),
), org.LabelPolicyAddedEventMapper), ), org.LabelPolicyAddedEventMapper),
}, },
reduce: (&labelPolicyProjection{}).reduceAdded, reduce: (&labelPolicyProjection{}).reduceAdded,
@ -38,7 +38,7 @@ func TestLabelPolicyProjection_reduces(t *testing.T) {
executer: &testExecuter{ executer: &testExecuter{
executions: []execution{ executions: []execution{
{ {
expectedStmt: "INSERT INTO projections.label_policies2 (creation_date, change_date, sequence, id, state, is_default, resource_owner, instance_id, light_primary_color, light_background_color, light_warn_color, light_font_color, dark_primary_color, dark_background_color, dark_warn_color, dark_font_color, hide_login_name_suffix, should_error_popup, watermark_disabled) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19)", expectedStmt: "INSERT INTO projections.label_policies3 (creation_date, change_date, sequence, id, state, is_default, resource_owner, instance_id, light_primary_color, light_background_color, light_warn_color, light_font_color, dark_primary_color, dark_background_color, dark_warn_color, dark_font_color, hide_login_name_suffix, should_error_popup, watermark_disabled, theme_mode) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20)",
expectedArgs: []interface{}{ expectedArgs: []interface{}{
anyArg{}, anyArg{},
anyArg{}, anyArg{},
@ -59,6 +59,7 @@ func TestLabelPolicyProjection_reduces(t *testing.T) {
false, false,
false, false,
false, false,
domain.LabelPolicyThemeLight,
}, },
}, },
}, },
@ -72,7 +73,7 @@ func TestLabelPolicyProjection_reduces(t *testing.T) {
testEvent( testEvent(
org.LabelPolicyChangedEventType, org.LabelPolicyChangedEventType,
org.AggregateType, org.AggregateType,
[]byte(`{"backgroundColor": "#141735", "fontColor": "#ffffff", "primaryColor": "#5282c1", "warnColor": "#ff3b5b"}`), []byte(`{"backgroundColor": "#141735", "fontColor": "#ffffff", "primaryColor": "#5282c1", "warnColor": "#ff3b5b", "themeMode": 1}`),
), org.LabelPolicyChangedEventMapper), ), org.LabelPolicyChangedEventMapper),
}, },
reduce: (&labelPolicyProjection{}).reduceChanged, reduce: (&labelPolicyProjection{}).reduceChanged,
@ -82,7 +83,7 @@ func TestLabelPolicyProjection_reduces(t *testing.T) {
executer: &testExecuter{ executer: &testExecuter{
executions: []execution{ executions: []execution{
{ {
expectedStmt: "UPDATE projections.label_policies2 SET (change_date, sequence, light_primary_color, light_background_color, light_warn_color, light_font_color) = ($1, $2, $3, $4, $5, $6) WHERE (id = $7) AND (state = $8) AND (instance_id = $9)", expectedStmt: "UPDATE projections.label_policies3 SET (change_date, sequence, light_primary_color, light_background_color, light_warn_color, light_font_color, theme_mode) = ($1, $2, $3, $4, $5, $6, $7) WHERE (id = $8) AND (state = $9) AND (instance_id = $10)",
expectedArgs: []interface{}{ expectedArgs: []interface{}{
anyArg{}, anyArg{},
uint64(15), uint64(15),
@ -90,6 +91,7 @@ func TestLabelPolicyProjection_reduces(t *testing.T) {
"#141735", "#141735",
"#ff3b5b", "#ff3b5b",
"#ffffff", "#ffffff",
domain.LabelPolicyThemeLight,
"agg-id", "agg-id",
domain.LabelPolicyStatePreview, domain.LabelPolicyStatePreview,
"instance-id", "instance-id",
@ -116,7 +118,7 @@ func TestLabelPolicyProjection_reduces(t *testing.T) {
executer: &testExecuter{ executer: &testExecuter{
executions: []execution{ executions: []execution{
{ {
expectedStmt: "DELETE FROM projections.label_policies2 WHERE (id = $1) AND (instance_id = $2)", expectedStmt: "DELETE FROM projections.label_policies3 WHERE (id = $1) AND (instance_id = $2)",
expectedArgs: []interface{}{ expectedArgs: []interface{}{
"agg-id", "agg-id",
"instance-id", "instance-id",
@ -143,7 +145,7 @@ func TestLabelPolicyProjection_reduces(t *testing.T) {
executer: &testExecuter{ executer: &testExecuter{
executions: []execution{ executions: []execution{
{ {
expectedStmt: "DELETE FROM projections.label_policies2 WHERE (instance_id = $1)", expectedStmt: "DELETE FROM projections.label_policies3 WHERE (instance_id = $1)",
expectedArgs: []interface{}{ expectedArgs: []interface{}{
"agg-id", "agg-id",
}, },
@ -169,7 +171,7 @@ func TestLabelPolicyProjection_reduces(t *testing.T) {
executer: &testExecuter{ executer: &testExecuter{
executions: []execution{ executions: []execution{
{ {
expectedStmt: "INSERT INTO projections.label_policies2 (change_date, sequence, state, creation_date, resource_owner, instance_id, id, is_default, hide_login_name_suffix, font_url, watermark_disabled, should_error_popup, light_primary_color, light_warn_color, light_background_color, light_font_color, light_logo_url, light_icon_url, dark_primary_color, dark_warn_color, dark_background_color, dark_font_color, dark_logo_url, dark_icon_url) SELECT $1, $2, $3, creation_date, resource_owner, instance_id, id, is_default, hide_login_name_suffix, font_url, watermark_disabled, should_error_popup, light_primary_color, light_warn_color, light_background_color, light_font_color, light_logo_url, light_icon_url, dark_primary_color, dark_warn_color, dark_background_color, dark_font_color, dark_logo_url, dark_icon_url FROM projections.label_policies2 AS copy_table WHERE (copy_table.id = $4) AND (copy_table.state = $5) AND (copy_table.instance_id = $6) ON CONFLICT (instance_id, id, state) DO UPDATE SET (change_date, sequence, state, creation_date, resource_owner, instance_id, id, is_default, hide_login_name_suffix, font_url, watermark_disabled, should_error_popup, light_primary_color, light_warn_color, light_background_color, light_font_color, light_logo_url, light_icon_url, dark_primary_color, dark_warn_color, dark_background_color, dark_font_color, dark_logo_url, dark_icon_url) = ($1, $2, $3, EXCLUDED.creation_date, EXCLUDED.resource_owner, EXCLUDED.instance_id, EXCLUDED.id, EXCLUDED.is_default, EXCLUDED.hide_login_name_suffix, EXCLUDED.font_url, EXCLUDED.watermark_disabled, EXCLUDED.should_error_popup, EXCLUDED.light_primary_color, EXCLUDED.light_warn_color, EXCLUDED.light_background_color, EXCLUDED.light_font_color, EXCLUDED.light_logo_url, EXCLUDED.light_icon_url, EXCLUDED.dark_primary_color, EXCLUDED.dark_warn_color, EXCLUDED.dark_background_color, EXCLUDED.dark_font_color, EXCLUDED.dark_logo_url, EXCLUDED.dark_icon_url)", expectedStmt: "INSERT INTO projections.label_policies3 (change_date, sequence, state, creation_date, resource_owner, instance_id, id, is_default, hide_login_name_suffix, font_url, watermark_disabled, should_error_popup, light_primary_color, light_warn_color, light_background_color, light_font_color, light_logo_url, light_icon_url, dark_primary_color, dark_warn_color, dark_background_color, dark_font_color, dark_logo_url, dark_icon_url, theme_mode) SELECT $1, $2, $3, creation_date, resource_owner, instance_id, id, is_default, hide_login_name_suffix, font_url, watermark_disabled, should_error_popup, light_primary_color, light_warn_color, light_background_color, light_font_color, light_logo_url, light_icon_url, dark_primary_color, dark_warn_color, dark_background_color, dark_font_color, dark_logo_url, dark_icon_url, theme_mode FROM projections.label_policies3 AS copy_table WHERE (copy_table.id = $4) AND (copy_table.state = $5) AND (copy_table.instance_id = $6) ON CONFLICT (instance_id, id, state) DO UPDATE SET (change_date, sequence, state, creation_date, resource_owner, instance_id, id, is_default, hide_login_name_suffix, font_url, watermark_disabled, should_error_popup, light_primary_color, light_warn_color, light_background_color, light_font_color, light_logo_url, light_icon_url, dark_primary_color, dark_warn_color, dark_background_color, dark_font_color, dark_logo_url, dark_icon_url, theme_mode) = ($1, $2, $3, EXCLUDED.creation_date, EXCLUDED.resource_owner, EXCLUDED.instance_id, EXCLUDED.id, EXCLUDED.is_default, EXCLUDED.hide_login_name_suffix, EXCLUDED.font_url, EXCLUDED.watermark_disabled, EXCLUDED.should_error_popup, EXCLUDED.light_primary_color, EXCLUDED.light_warn_color, EXCLUDED.light_background_color, EXCLUDED.light_font_color, EXCLUDED.light_logo_url, EXCLUDED.light_icon_url, EXCLUDED.dark_primary_color, EXCLUDED.dark_warn_color, EXCLUDED.dark_background_color, EXCLUDED.dark_font_color, EXCLUDED.dark_logo_url, EXCLUDED.dark_icon_url, EXCLUDED.theme_mode)",
expectedArgs: []interface{}{ expectedArgs: []interface{}{
anyArg{}, anyArg{},
uint64(15), uint64(15),
@ -200,7 +202,7 @@ func TestLabelPolicyProjection_reduces(t *testing.T) {
executer: &testExecuter{ executer: &testExecuter{
executions: []execution{ executions: []execution{
{ {
expectedStmt: "UPDATE projections.label_policies2 SET (change_date, sequence, light_logo_url) = ($1, $2, $3) WHERE (id = $4) AND (state = $5) AND (instance_id = $6)", expectedStmt: "UPDATE projections.label_policies3 SET (change_date, sequence, light_logo_url) = ($1, $2, $3) WHERE (id = $4) AND (state = $5) AND (instance_id = $6)",
expectedArgs: []interface{}{ expectedArgs: []interface{}{
anyArg{}, anyArg{},
uint64(15), uint64(15),
@ -231,7 +233,7 @@ func TestLabelPolicyProjection_reduces(t *testing.T) {
executer: &testExecuter{ executer: &testExecuter{
executions: []execution{ executions: []execution{
{ {
expectedStmt: "UPDATE projections.label_policies2 SET (change_date, sequence, dark_logo_url) = ($1, $2, $3) WHERE (id = $4) AND (state = $5) AND (instance_id = $6)", expectedStmt: "UPDATE projections.label_policies3 SET (change_date, sequence, dark_logo_url) = ($1, $2, $3) WHERE (id = $4) AND (state = $5) AND (instance_id = $6)",
expectedArgs: []interface{}{ expectedArgs: []interface{}{
anyArg{}, anyArg{},
uint64(15), uint64(15),
@ -262,7 +264,7 @@ func TestLabelPolicyProjection_reduces(t *testing.T) {
executer: &testExecuter{ executer: &testExecuter{
executions: []execution{ executions: []execution{
{ {
expectedStmt: "UPDATE projections.label_policies2 SET (change_date, sequence, light_icon_url) = ($1, $2, $3) WHERE (id = $4) AND (state = $5) AND (instance_id = $6)", expectedStmt: "UPDATE projections.label_policies3 SET (change_date, sequence, light_icon_url) = ($1, $2, $3) WHERE (id = $4) AND (state = $5) AND (instance_id = $6)",
expectedArgs: []interface{}{ expectedArgs: []interface{}{
anyArg{}, anyArg{},
uint64(15), uint64(15),
@ -293,7 +295,7 @@ func TestLabelPolicyProjection_reduces(t *testing.T) {
executer: &testExecuter{ executer: &testExecuter{
executions: []execution{ executions: []execution{
{ {
expectedStmt: "UPDATE projections.label_policies2 SET (change_date, sequence, dark_icon_url) = ($1, $2, $3) WHERE (id = $4) AND (state = $5) AND (instance_id = $6)", expectedStmt: "UPDATE projections.label_policies3 SET (change_date, sequence, dark_icon_url) = ($1, $2, $3) WHERE (id = $4) AND (state = $5) AND (instance_id = $6)",
expectedArgs: []interface{}{ expectedArgs: []interface{}{
anyArg{}, anyArg{},
uint64(15), uint64(15),
@ -324,7 +326,7 @@ func TestLabelPolicyProjection_reduces(t *testing.T) {
executer: &testExecuter{ executer: &testExecuter{
executions: []execution{ executions: []execution{
{ {
expectedStmt: "UPDATE projections.label_policies2 SET (change_date, sequence, light_logo_url) = ($1, $2, $3) WHERE (id = $4) AND (state = $5) AND (instance_id = $6)", expectedStmt: "UPDATE projections.label_policies3 SET (change_date, sequence, light_logo_url) = ($1, $2, $3) WHERE (id = $4) AND (state = $5) AND (instance_id = $6)",
expectedArgs: []interface{}{ expectedArgs: []interface{}{
anyArg{}, anyArg{},
uint64(15), uint64(15),
@ -355,7 +357,7 @@ func TestLabelPolicyProjection_reduces(t *testing.T) {
executer: &testExecuter{ executer: &testExecuter{
executions: []execution{ executions: []execution{
{ {
expectedStmt: "UPDATE projections.label_policies2 SET (change_date, sequence, dark_logo_url) = ($1, $2, $3) WHERE (id = $4) AND (state = $5) AND (instance_id = $6)", expectedStmt: "UPDATE projections.label_policies3 SET (change_date, sequence, dark_logo_url) = ($1, $2, $3) WHERE (id = $4) AND (state = $5) AND (instance_id = $6)",
expectedArgs: []interface{}{ expectedArgs: []interface{}{
anyArg{}, anyArg{},
uint64(15), uint64(15),
@ -386,7 +388,7 @@ func TestLabelPolicyProjection_reduces(t *testing.T) {
executer: &testExecuter{ executer: &testExecuter{
executions: []execution{ executions: []execution{
{ {
expectedStmt: "UPDATE projections.label_policies2 SET (change_date, sequence, light_icon_url) = ($1, $2, $3) WHERE (id = $4) AND (state = $5) AND (instance_id = $6)", expectedStmt: "UPDATE projections.label_policies3 SET (change_date, sequence, light_icon_url) = ($1, $2, $3) WHERE (id = $4) AND (state = $5) AND (instance_id = $6)",
expectedArgs: []interface{}{ expectedArgs: []interface{}{
anyArg{}, anyArg{},
uint64(15), uint64(15),
@ -417,7 +419,7 @@ func TestLabelPolicyProjection_reduces(t *testing.T) {
executer: &testExecuter{ executer: &testExecuter{
executions: []execution{ executions: []execution{
{ {
expectedStmt: "UPDATE projections.label_policies2 SET (change_date, sequence, dark_icon_url) = ($1, $2, $3) WHERE (id = $4) AND (state = $5) AND (instance_id = $6)", expectedStmt: "UPDATE projections.label_policies3 SET (change_date, sequence, dark_icon_url) = ($1, $2, $3) WHERE (id = $4) AND (state = $5) AND (instance_id = $6)",
expectedArgs: []interface{}{ expectedArgs: []interface{}{
anyArg{}, anyArg{},
uint64(15), uint64(15),
@ -448,7 +450,7 @@ func TestLabelPolicyProjection_reduces(t *testing.T) {
executer: &testExecuter{ executer: &testExecuter{
executions: []execution{ executions: []execution{
{ {
expectedStmt: "UPDATE projections.label_policies2 SET (change_date, sequence, font_url) = ($1, $2, $3) WHERE (id = $4) AND (state = $5) AND (instance_id = $6)", expectedStmt: "UPDATE projections.label_policies3 SET (change_date, sequence, font_url) = ($1, $2, $3) WHERE (id = $4) AND (state = $5) AND (instance_id = $6)",
expectedArgs: []interface{}{ expectedArgs: []interface{}{
anyArg{}, anyArg{},
uint64(15), uint64(15),
@ -479,7 +481,7 @@ func TestLabelPolicyProjection_reduces(t *testing.T) {
executer: &testExecuter{ executer: &testExecuter{
executions: []execution{ executions: []execution{
{ {
expectedStmt: "UPDATE projections.label_policies2 SET (change_date, sequence, font_url) = ($1, $2, $3) WHERE (id = $4) AND (state = $5) AND (instance_id = $6)", expectedStmt: "UPDATE projections.label_policies3 SET (change_date, sequence, font_url) = ($1, $2, $3) WHERE (id = $4) AND (state = $5) AND (instance_id = $6)",
expectedArgs: []interface{}{ expectedArgs: []interface{}{
anyArg{}, anyArg{},
uint64(15), uint64(15),
@ -510,7 +512,7 @@ func TestLabelPolicyProjection_reduces(t *testing.T) {
executer: &testExecuter{ executer: &testExecuter{
executions: []execution{ executions: []execution{
{ {
expectedStmt: "UPDATE projections.label_policies2 SET (change_date, sequence, light_logo_url, light_icon_url, dark_logo_url, dark_icon_url, font_url) = ($1, $2, $3, $4, $5, $6, $7) WHERE (id = $8) AND (state = $9) AND (instance_id = $10)", expectedStmt: "UPDATE projections.label_policies3 SET (change_date, sequence, light_logo_url, light_icon_url, dark_logo_url, dark_icon_url, font_url) = ($1, $2, $3, $4, $5, $6, $7) WHERE (id = $8) AND (state = $9) AND (instance_id = $10)",
expectedArgs: []interface{}{ expectedArgs: []interface{}{
anyArg{}, anyArg{},
uint64(15), uint64(15),
@ -535,7 +537,7 @@ func TestLabelPolicyProjection_reduces(t *testing.T) {
testEvent( testEvent(
instance.LabelPolicyAddedEventType, instance.LabelPolicyAddedEventType,
instance.AggregateType, instance.AggregateType,
[]byte(`{"backgroundColor": "#141735", "fontColor": "#ffffff", "primaryColor": "#5282c1", "warnColor": "#ff3b5b"}`), []byte(`{"backgroundColor": "#141735", "fontColor": "#ffffff", "primaryColor": "#5282c1", "warnColor": "#ff3b5b", "themeMode": 1}`),
), instance.LabelPolicyAddedEventMapper), ), instance.LabelPolicyAddedEventMapper),
}, },
reduce: (&labelPolicyProjection{}).reduceAdded, reduce: (&labelPolicyProjection{}).reduceAdded,
@ -545,7 +547,7 @@ func TestLabelPolicyProjection_reduces(t *testing.T) {
executer: &testExecuter{ executer: &testExecuter{
executions: []execution{ executions: []execution{
{ {
expectedStmt: "INSERT INTO projections.label_policies2 (creation_date, change_date, sequence, id, state, is_default, resource_owner, instance_id, light_primary_color, light_background_color, light_warn_color, light_font_color, dark_primary_color, dark_background_color, dark_warn_color, dark_font_color, hide_login_name_suffix, should_error_popup, watermark_disabled) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19)", expectedStmt: "INSERT INTO projections.label_policies3 (creation_date, change_date, sequence, id, state, is_default, resource_owner, instance_id, light_primary_color, light_background_color, light_warn_color, light_font_color, dark_primary_color, dark_background_color, dark_warn_color, dark_font_color, hide_login_name_suffix, should_error_popup, watermark_disabled, theme_mode) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20)",
expectedArgs: []interface{}{ expectedArgs: []interface{}{
anyArg{}, anyArg{},
anyArg{}, anyArg{},
@ -566,6 +568,7 @@ func TestLabelPolicyProjection_reduces(t *testing.T) {
false, false,
false, false,
false, false,
domain.LabelPolicyThemeLight,
}, },
}, },
}, },
@ -579,7 +582,7 @@ func TestLabelPolicyProjection_reduces(t *testing.T) {
testEvent( testEvent(
instance.LabelPolicyChangedEventType, instance.LabelPolicyChangedEventType,
instance.AggregateType, instance.AggregateType,
[]byte(`{"backgroundColor": "#141735", "fontColor": "#ffffff", "primaryColor": "#5282c1", "warnColor": "#ff3b5b", "primaryColorDark": "#ffffff","backgroundColorDark": "#ffffff", "warnColorDark": "#ffffff", "fontColorDark": "#ffffff", "hideLoginNameSuffix": true, "errorMsgPopup": true, "disableWatermark": true}`), []byte(`{"backgroundColor": "#141735", "fontColor": "#ffffff", "primaryColor": "#5282c1", "warnColor": "#ff3b5b", "primaryColorDark": "#ffffff","backgroundColorDark": "#ffffff", "warnColorDark": "#ffffff", "fontColorDark": "#ffffff", "hideLoginNameSuffix": true, "errorMsgPopup": true, "disableWatermark": true, "themeMode": 1}`),
), instance.LabelPolicyChangedEventMapper), ), instance.LabelPolicyChangedEventMapper),
}, },
reduce: (&labelPolicyProjection{}).reduceChanged, reduce: (&labelPolicyProjection{}).reduceChanged,
@ -589,7 +592,7 @@ func TestLabelPolicyProjection_reduces(t *testing.T) {
executer: &testExecuter{ executer: &testExecuter{
executions: []execution{ executions: []execution{
{ {
expectedStmt: "UPDATE projections.label_policies2 SET (change_date, sequence, light_primary_color, light_background_color, light_warn_color, light_font_color, dark_primary_color, dark_background_color, dark_warn_color, dark_font_color, hide_login_name_suffix, should_error_popup, watermark_disabled) = ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13) WHERE (id = $14) AND (state = $15) AND (instance_id = $16)", expectedStmt: "UPDATE projections.label_policies3 SET (change_date, sequence, light_primary_color, light_background_color, light_warn_color, light_font_color, dark_primary_color, dark_background_color, dark_warn_color, dark_font_color, hide_login_name_suffix, should_error_popup, watermark_disabled, theme_mode) = ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14) WHERE (id = $15) AND (state = $16) AND (instance_id = $17)",
expectedArgs: []interface{}{ expectedArgs: []interface{}{
anyArg{}, anyArg{},
uint64(15), uint64(15),
@ -604,6 +607,7 @@ func TestLabelPolicyProjection_reduces(t *testing.T) {
true, true,
true, true,
true, true,
domain.LabelPolicyThemeLight,
"agg-id", "agg-id",
domain.LabelPolicyStatePreview, domain.LabelPolicyStatePreview,
"instance-id", "instance-id",
@ -630,7 +634,7 @@ func TestLabelPolicyProjection_reduces(t *testing.T) {
executer: &testExecuter{ executer: &testExecuter{
executions: []execution{ executions: []execution{
{ {
expectedStmt: "INSERT INTO projections.label_policies2 (change_date, sequence, state, creation_date, resource_owner, instance_id, id, is_default, hide_login_name_suffix, font_url, watermark_disabled, should_error_popup, light_primary_color, light_warn_color, light_background_color, light_font_color, light_logo_url, light_icon_url, dark_primary_color, dark_warn_color, dark_background_color, dark_font_color, dark_logo_url, dark_icon_url) SELECT $1, $2, $3, creation_date, resource_owner, instance_id, id, is_default, hide_login_name_suffix, font_url, watermark_disabled, should_error_popup, light_primary_color, light_warn_color, light_background_color, light_font_color, light_logo_url, light_icon_url, dark_primary_color, dark_warn_color, dark_background_color, dark_font_color, dark_logo_url, dark_icon_url FROM projections.label_policies2 AS copy_table WHERE (copy_table.id = $4) AND (copy_table.state = $5) AND (copy_table.instance_id = $6) ON CONFLICT (instance_id, id, state) DO UPDATE SET (change_date, sequence, state, creation_date, resource_owner, instance_id, id, is_default, hide_login_name_suffix, font_url, watermark_disabled, should_error_popup, light_primary_color, light_warn_color, light_background_color, light_font_color, light_logo_url, light_icon_url, dark_primary_color, dark_warn_color, dark_background_color, dark_font_color, dark_logo_url, dark_icon_url) = ($1, $2, $3, EXCLUDED.creation_date, EXCLUDED.resource_owner, EXCLUDED.instance_id, EXCLUDED.id, EXCLUDED.is_default, EXCLUDED.hide_login_name_suffix, EXCLUDED.font_url, EXCLUDED.watermark_disabled, EXCLUDED.should_error_popup, EXCLUDED.light_primary_color, EXCLUDED.light_warn_color, EXCLUDED.light_background_color, EXCLUDED.light_font_color, EXCLUDED.light_logo_url, EXCLUDED.light_icon_url, EXCLUDED.dark_primary_color, EXCLUDED.dark_warn_color, EXCLUDED.dark_background_color, EXCLUDED.dark_font_color, EXCLUDED.dark_logo_url, EXCLUDED.dark_icon_url)", expectedStmt: "INSERT INTO projections.label_policies3 (change_date, sequence, state, creation_date, resource_owner, instance_id, id, is_default, hide_login_name_suffix, font_url, watermark_disabled, should_error_popup, light_primary_color, light_warn_color, light_background_color, light_font_color, light_logo_url, light_icon_url, dark_primary_color, dark_warn_color, dark_background_color, dark_font_color, dark_logo_url, dark_icon_url, theme_mode) SELECT $1, $2, $3, creation_date, resource_owner, instance_id, id, is_default, hide_login_name_suffix, font_url, watermark_disabled, should_error_popup, light_primary_color, light_warn_color, light_background_color, light_font_color, light_logo_url, light_icon_url, dark_primary_color, dark_warn_color, dark_background_color, dark_font_color, dark_logo_url, dark_icon_url, theme_mode FROM projections.label_policies3 AS copy_table WHERE (copy_table.id = $4) AND (copy_table.state = $5) AND (copy_table.instance_id = $6) ON CONFLICT (instance_id, id, state) DO UPDATE SET (change_date, sequence, state, creation_date, resource_owner, instance_id, id, is_default, hide_login_name_suffix, font_url, watermark_disabled, should_error_popup, light_primary_color, light_warn_color, light_background_color, light_font_color, light_logo_url, light_icon_url, dark_primary_color, dark_warn_color, dark_background_color, dark_font_color, dark_logo_url, dark_icon_url, theme_mode) = ($1, $2, $3, EXCLUDED.creation_date, EXCLUDED.resource_owner, EXCLUDED.instance_id, EXCLUDED.id, EXCLUDED.is_default, EXCLUDED.hide_login_name_suffix, EXCLUDED.font_url, EXCLUDED.watermark_disabled, EXCLUDED.should_error_popup, EXCLUDED.light_primary_color, EXCLUDED.light_warn_color, EXCLUDED.light_background_color, EXCLUDED.light_font_color, EXCLUDED.light_logo_url, EXCLUDED.light_icon_url, EXCLUDED.dark_primary_color, EXCLUDED.dark_warn_color, EXCLUDED.dark_background_color, EXCLUDED.dark_font_color, EXCLUDED.dark_logo_url, EXCLUDED.dark_icon_url, EXCLUDED.theme_mode)",
expectedArgs: []interface{}{ expectedArgs: []interface{}{
anyArg{}, anyArg{},
uint64(15), uint64(15),
@ -661,7 +665,7 @@ func TestLabelPolicyProjection_reduces(t *testing.T) {
executer: &testExecuter{ executer: &testExecuter{
executions: []execution{ executions: []execution{
{ {
expectedStmt: "UPDATE projections.label_policies2 SET (change_date, sequence, light_logo_url) = ($1, $2, $3) WHERE (id = $4) AND (state = $5) AND (instance_id = $6)", expectedStmt: "UPDATE projections.label_policies3 SET (change_date, sequence, light_logo_url) = ($1, $2, $3) WHERE (id = $4) AND (state = $5) AND (instance_id = $6)",
expectedArgs: []interface{}{ expectedArgs: []interface{}{
anyArg{}, anyArg{},
uint64(15), uint64(15),
@ -692,7 +696,7 @@ func TestLabelPolicyProjection_reduces(t *testing.T) {
executer: &testExecuter{ executer: &testExecuter{
executions: []execution{ executions: []execution{
{ {
expectedStmt: "UPDATE projections.label_policies2 SET (change_date, sequence, dark_logo_url) = ($1, $2, $3) WHERE (id = $4) AND (state = $5) AND (instance_id = $6)", expectedStmt: "UPDATE projections.label_policies3 SET (change_date, sequence, dark_logo_url) = ($1, $2, $3) WHERE (id = $4) AND (state = $5) AND (instance_id = $6)",
expectedArgs: []interface{}{ expectedArgs: []interface{}{
anyArg{}, anyArg{},
uint64(15), uint64(15),
@ -723,7 +727,7 @@ func TestLabelPolicyProjection_reduces(t *testing.T) {
executer: &testExecuter{ executer: &testExecuter{
executions: []execution{ executions: []execution{
{ {
expectedStmt: "UPDATE projections.label_policies2 SET (change_date, sequence, light_icon_url) = ($1, $2, $3) WHERE (id = $4) AND (state = $5) AND (instance_id = $6)", expectedStmt: "UPDATE projections.label_policies3 SET (change_date, sequence, light_icon_url) = ($1, $2, $3) WHERE (id = $4) AND (state = $5) AND (instance_id = $6)",
expectedArgs: []interface{}{ expectedArgs: []interface{}{
anyArg{}, anyArg{},
uint64(15), uint64(15),
@ -754,7 +758,7 @@ func TestLabelPolicyProjection_reduces(t *testing.T) {
executer: &testExecuter{ executer: &testExecuter{
executions: []execution{ executions: []execution{
{ {
expectedStmt: "UPDATE projections.label_policies2 SET (change_date, sequence, dark_icon_url) = ($1, $2, $3) WHERE (id = $4) AND (state = $5) AND (instance_id = $6)", expectedStmt: "UPDATE projections.label_policies3 SET (change_date, sequence, dark_icon_url) = ($1, $2, $3) WHERE (id = $4) AND (state = $5) AND (instance_id = $6)",
expectedArgs: []interface{}{ expectedArgs: []interface{}{
anyArg{}, anyArg{},
uint64(15), uint64(15),
@ -785,7 +789,7 @@ func TestLabelPolicyProjection_reduces(t *testing.T) {
executer: &testExecuter{ executer: &testExecuter{
executions: []execution{ executions: []execution{
{ {
expectedStmt: "UPDATE projections.label_policies2 SET (change_date, sequence, light_logo_url) = ($1, $2, $3) WHERE (id = $4) AND (state = $5) AND (instance_id = $6)", expectedStmt: "UPDATE projections.label_policies3 SET (change_date, sequence, light_logo_url) = ($1, $2, $3) WHERE (id = $4) AND (state = $5) AND (instance_id = $6)",
expectedArgs: []interface{}{ expectedArgs: []interface{}{
anyArg{}, anyArg{},
uint64(15), uint64(15),
@ -816,7 +820,7 @@ func TestLabelPolicyProjection_reduces(t *testing.T) {
executer: &testExecuter{ executer: &testExecuter{
executions: []execution{ executions: []execution{
{ {
expectedStmt: "UPDATE projections.label_policies2 SET (change_date, sequence, dark_logo_url) = ($1, $2, $3) WHERE (id = $4) AND (state = $5) AND (instance_id = $6)", expectedStmt: "UPDATE projections.label_policies3 SET (change_date, sequence, dark_logo_url) = ($1, $2, $3) WHERE (id = $4) AND (state = $5) AND (instance_id = $6)",
expectedArgs: []interface{}{ expectedArgs: []interface{}{
anyArg{}, anyArg{},
uint64(15), uint64(15),
@ -847,7 +851,7 @@ func TestLabelPolicyProjection_reduces(t *testing.T) {
executer: &testExecuter{ executer: &testExecuter{
executions: []execution{ executions: []execution{
{ {
expectedStmt: "UPDATE projections.label_policies2 SET (change_date, sequence, light_icon_url) = ($1, $2, $3) WHERE (id = $4) AND (state = $5) AND (instance_id = $6)", expectedStmt: "UPDATE projections.label_policies3 SET (change_date, sequence, light_icon_url) = ($1, $2, $3) WHERE (id = $4) AND (state = $5) AND (instance_id = $6)",
expectedArgs: []interface{}{ expectedArgs: []interface{}{
anyArg{}, anyArg{},
uint64(15), uint64(15),
@ -878,7 +882,7 @@ func TestLabelPolicyProjection_reduces(t *testing.T) {
executer: &testExecuter{ executer: &testExecuter{
executions: []execution{ executions: []execution{
{ {
expectedStmt: "UPDATE projections.label_policies2 SET (change_date, sequence, dark_icon_url) = ($1, $2, $3) WHERE (id = $4) AND (state = $5) AND (instance_id = $6)", expectedStmt: "UPDATE projections.label_policies3 SET (change_date, sequence, dark_icon_url) = ($1, $2, $3) WHERE (id = $4) AND (state = $5) AND (instance_id = $6)",
expectedArgs: []interface{}{ expectedArgs: []interface{}{
anyArg{}, anyArg{},
uint64(15), uint64(15),
@ -909,7 +913,7 @@ func TestLabelPolicyProjection_reduces(t *testing.T) {
executer: &testExecuter{ executer: &testExecuter{
executions: []execution{ executions: []execution{
{ {
expectedStmt: "UPDATE projections.label_policies2 SET (change_date, sequence, font_url) = ($1, $2, $3) WHERE (id = $4) AND (state = $5) AND (instance_id = $6)", expectedStmt: "UPDATE projections.label_policies3 SET (change_date, sequence, font_url) = ($1, $2, $3) WHERE (id = $4) AND (state = $5) AND (instance_id = $6)",
expectedArgs: []interface{}{ expectedArgs: []interface{}{
anyArg{}, anyArg{},
uint64(15), uint64(15),
@ -940,7 +944,7 @@ func TestLabelPolicyProjection_reduces(t *testing.T) {
executer: &testExecuter{ executer: &testExecuter{
executions: []execution{ executions: []execution{
{ {
expectedStmt: "UPDATE projections.label_policies2 SET (change_date, sequence, font_url) = ($1, $2, $3) WHERE (id = $4) AND (state = $5) AND (instance_id = $6)", expectedStmt: "UPDATE projections.label_policies3 SET (change_date, sequence, font_url) = ($1, $2, $3) WHERE (id = $4) AND (state = $5) AND (instance_id = $6)",
expectedArgs: []interface{}{ expectedArgs: []interface{}{
anyArg{}, anyArg{},
uint64(15), uint64(15),
@ -971,7 +975,7 @@ func TestLabelPolicyProjection_reduces(t *testing.T) {
executer: &testExecuter{ executer: &testExecuter{
executions: []execution{ executions: []execution{
{ {
expectedStmt: "UPDATE projections.label_policies2 SET (change_date, sequence, light_logo_url, light_icon_url, dark_logo_url, dark_icon_url, font_url) = ($1, $2, $3, $4, $5, $6, $7) WHERE (id = $8) AND (state = $9) AND (instance_id = $10)", expectedStmt: "UPDATE projections.label_policies3 SET (change_date, sequence, light_logo_url, light_icon_url, dark_logo_url, dark_icon_url, font_url) = ($1, $2, $3, $4, $5, $6, $7) WHERE (id = $8) AND (state = $9) AND (instance_id = $10)",
expectedArgs: []interface{}{ expectedArgs: []interface{}{
anyArg{}, anyArg{},
uint64(15), uint64(15),
@ -1006,7 +1010,7 @@ func TestLabelPolicyProjection_reduces(t *testing.T) {
executer: &testExecuter{ executer: &testExecuter{
executions: []execution{ executions: []execution{
{ {
expectedStmt: "DELETE FROM projections.label_policies2 WHERE (instance_id = $1) AND (resource_owner = $2)", expectedStmt: "DELETE FROM projections.label_policies3 WHERE (instance_id = $1) AND (resource_owner = $2)",
expectedArgs: []interface{}{ expectedArgs: []interface{}{
"instance-id", "instance-id",
"agg-id", "agg-id",

View File

@ -3,6 +3,7 @@ package instance
import ( import (
"context" "context"
"github.com/zitadel/zitadel/internal/domain"
"github.com/zitadel/zitadel/internal/eventstore" "github.com/zitadel/zitadel/internal/eventstore"
"github.com/zitadel/zitadel/internal/repository/policy" "github.com/zitadel/zitadel/internal/repository/policy"
) )
@ -45,6 +46,7 @@ func NewLabelPolicyAddedEvent(
hideLoginNameSuffix, hideLoginNameSuffix,
errorMsgPopup, errorMsgPopup,
disableWatermark bool, disableWatermark bool,
themeMode domain.LabelPolicyThemeMode,
) *LabelPolicyAddedEvent { ) *LabelPolicyAddedEvent {
return &LabelPolicyAddedEvent{ return &LabelPolicyAddedEvent{
LabelPolicyAddedEvent: *policy.NewLabelPolicyAddedEvent( LabelPolicyAddedEvent: *policy.NewLabelPolicyAddedEvent(
@ -62,7 +64,8 @@ func NewLabelPolicyAddedEvent(
fontColorDark, fontColorDark,
hideLoginNameSuffix, hideLoginNameSuffix,
errorMsgPopup, errorMsgPopup,
disableWatermark), disableWatermark,
themeMode),
} }
} }

View File

@ -3,6 +3,7 @@ package org
import ( import (
"context" "context"
"github.com/zitadel/zitadel/internal/domain"
"github.com/zitadel/zitadel/internal/eventstore" "github.com/zitadel/zitadel/internal/eventstore"
"github.com/zitadel/zitadel/internal/repository/policy" "github.com/zitadel/zitadel/internal/repository/policy"
) )
@ -46,6 +47,7 @@ func NewLabelPolicyAddedEvent(
hideLoginNameSuffix, hideLoginNameSuffix,
errorMsgPopup, errorMsgPopup,
disableWatermark bool, disableWatermark bool,
themeMode domain.LabelPolicyThemeMode,
) *LabelPolicyAddedEvent { ) *LabelPolicyAddedEvent {
return &LabelPolicyAddedEvent{ return &LabelPolicyAddedEvent{
LabelPolicyAddedEvent: *policy.NewLabelPolicyAddedEvent( LabelPolicyAddedEvent: *policy.NewLabelPolicyAddedEvent(
@ -63,7 +65,8 @@ func NewLabelPolicyAddedEvent(
fontColorDark, fontColorDark,
hideLoginNameSuffix, hideLoginNameSuffix,
errorMsgPopup, errorMsgPopup,
disableWatermark), disableWatermark,
themeMode),
} }
} }

View File

@ -1,6 +1,7 @@
package policy package policy
import ( import (
"github.com/zitadel/zitadel/internal/domain"
"github.com/zitadel/zitadel/internal/errors" "github.com/zitadel/zitadel/internal/errors"
"github.com/zitadel/zitadel/internal/eventstore" "github.com/zitadel/zitadel/internal/eventstore"
"github.com/zitadel/zitadel/internal/repository/asset" "github.com/zitadel/zitadel/internal/repository/asset"
@ -32,17 +33,18 @@ const (
type LabelPolicyAddedEvent struct { type LabelPolicyAddedEvent struct {
eventstore.BaseEvent `json:"-"` eventstore.BaseEvent `json:"-"`
PrimaryColor string `json:"primaryColor,omitempty"` PrimaryColor string `json:"primaryColor,omitempty"`
BackgroundColor string `json:"backgroundColor,omitempty"` BackgroundColor string `json:"backgroundColor,omitempty"`
WarnColor string `json:"warnColor,omitempty"` WarnColor string `json:"warnColor,omitempty"`
FontColor string `json:"fontColor,omitempty"` FontColor string `json:"fontColor,omitempty"`
PrimaryColorDark string `json:"primaryColorDark,omitempty"` PrimaryColorDark string `json:"primaryColorDark,omitempty"`
BackgroundColorDark string `json:"backgroundColorDark,omitempty"` BackgroundColorDark string `json:"backgroundColorDark,omitempty"`
WarnColorDark string `json:"warnColorDark,omitempty"` WarnColorDark string `json:"warnColorDark,omitempty"`
FontColorDark string `json:"fontColorDark,omitempty"` FontColorDark string `json:"fontColorDark,omitempty"`
HideLoginNameSuffix bool `json:"hideLoginNameSuffix,omitempty"` HideLoginNameSuffix bool `json:"hideLoginNameSuffix,omitempty"`
ErrorMsgPopup bool `json:"errorMsgPopup,omitempty"` ErrorMsgPopup bool `json:"errorMsgPopup,omitempty"`
DisableWatermark bool `json:"disableMsgPopup,omitempty"` DisableWatermark bool `json:"disableMsgPopup,omitempty"`
ThemeMode domain.LabelPolicyThemeMode `json:"themeMode,omitempty"`
} }
func (e *LabelPolicyAddedEvent) Payload() interface{} { func (e *LabelPolicyAddedEvent) Payload() interface{} {
@ -66,6 +68,7 @@ func NewLabelPolicyAddedEvent(
hideLoginNameSuffix, hideLoginNameSuffix,
errorMsgPopup, errorMsgPopup,
disableWatermark bool, disableWatermark bool,
themeMode domain.LabelPolicyThemeMode,
) *LabelPolicyAddedEvent { ) *LabelPolicyAddedEvent {
return &LabelPolicyAddedEvent{ return &LabelPolicyAddedEvent{
@ -81,6 +84,7 @@ func NewLabelPolicyAddedEvent(
HideLoginNameSuffix: hideLoginNameSuffix, HideLoginNameSuffix: hideLoginNameSuffix,
ErrorMsgPopup: errorMsgPopup, ErrorMsgPopup: errorMsgPopup,
DisableWatermark: disableWatermark, DisableWatermark: disableWatermark,
ThemeMode: themeMode,
} }
} }
@ -100,17 +104,18 @@ func LabelPolicyAddedEventMapper(event eventstore.Event) (eventstore.Event, erro
type LabelPolicyChangedEvent struct { type LabelPolicyChangedEvent struct {
eventstore.BaseEvent `json:"-"` eventstore.BaseEvent `json:"-"`
PrimaryColor *string `json:"primaryColor,omitempty"` PrimaryColor *string `json:"primaryColor,omitempty"`
BackgroundColor *string `json:"backgroundColor,omitempty"` BackgroundColor *string `json:"backgroundColor,omitempty"`
WarnColor *string `json:"warnColor,omitempty"` WarnColor *string `json:"warnColor,omitempty"`
FontColor *string `json:"fontColor,omitempty"` FontColor *string `json:"fontColor,omitempty"`
PrimaryColorDark *string `json:"primaryColorDark,omitempty"` PrimaryColorDark *string `json:"primaryColorDark,omitempty"`
BackgroundColorDark *string `json:"backgroundColorDark,omitempty"` BackgroundColorDark *string `json:"backgroundColorDark,omitempty"`
WarnColorDark *string `json:"warnColorDark,omitempty"` WarnColorDark *string `json:"warnColorDark,omitempty"`
FontColorDark *string `json:"fontColorDark,omitempty"` FontColorDark *string `json:"fontColorDark,omitempty"`
HideLoginNameSuffix *bool `json:"hideLoginNameSuffix,omitempty"` HideLoginNameSuffix *bool `json:"hideLoginNameSuffix,omitempty"`
ErrorMsgPopup *bool `json:"errorMsgPopup,omitempty"` ErrorMsgPopup *bool `json:"errorMsgPopup,omitempty"`
DisableWatermark *bool `json:"disableWatermark,omitempty"` DisableWatermark *bool `json:"disableWatermark,omitempty"`
ThemeMode *domain.LabelPolicyThemeMode `json:"themeMode,omitempty"`
} }
func (e *LabelPolicyChangedEvent) Payload() interface{} { func (e *LabelPolicyChangedEvent) Payload() interface{} {
@ -205,6 +210,12 @@ func ChangeDisableWatermark(disableWatermark bool) func(*LabelPolicyChangedEvent
} }
} }
func ChangeThemeMode(themeMode domain.LabelPolicyThemeMode) func(*LabelPolicyChangedEvent) {
return func(e *LabelPolicyChangedEvent) {
e.ThemeMode = &themeMode
}
}
func LabelPolicyChangedEventMapper(event eventstore.Event) (eventstore.Event, error) { func LabelPolicyChangedEventMapper(event eventstore.Event) (eventstore.Event, error) {
e := &LabelPolicyChangedEvent{ e := &LabelPolicyChangedEvent{
BaseEvent: *eventstore.BaseEventFromRepo(event), BaseEvent: *eventstore.BaseEventFromRepo(event),

View File

@ -6230,6 +6230,11 @@ message UpdateLabelPolicyRequest {
} }
]; ];
bool disable_watermark = 11; bool disable_watermark = 11;
zitadel.policy.v1.ThemeMode theme_mode = 12 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
description: "setting if there should be a restriction on which themes are available";
}
];
} }
message UpdateLabelPolicyResponse { message UpdateLabelPolicyResponse {

View File

@ -10583,6 +10583,11 @@ message AddCustomLabelPolicyRequest {
} }
]; ];
bool disable_watermark = 11; bool disable_watermark = 11;
zitadel.policy.v1.ThemeMode theme_mode = 12 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
description: "setting if there should be a restriction on which themes are available";
}
];
} }
message AddCustomLabelPolicyResponse { message AddCustomLabelPolicyResponse {
@ -10653,6 +10658,11 @@ message UpdateCustomLabelPolicyRequest {
} }
]; ];
bool disable_watermark = 11; bool disable_watermark = 11;
zitadel.policy.v1.ThemeMode theme_mode = 12 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
description: "setting if there should be a restriction on which themes are available";
}
];
} }
message UpdateCustomLabelPolicyResponse { message UpdateCustomLabelPolicyResponse {

View File

@ -145,6 +145,14 @@ message LabelPolicy {
} }
]; ];
string font_url = 18; string font_url = 18;
ThemeMode theme_mode = 19;
}
enum ThemeMode {
THEME_MODE_UNSPECIFIED = 0;
THEME_MODE_AUTO = 1;
THEME_MODE_DARK = 2;
THEME_MODE_LIGHT = 3;
} }
message LoginPolicy { message LoginPolicy {

View File

@ -33,6 +33,11 @@ message BrandingSettings {
description: "resource_owner_type returns if the setting is managed on the organization or on the instance"; description: "resource_owner_type returns if the setting is managed on the organization or on the instance";
} }
]; ];
ThemeMode theme_mode = 7 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
description: "states whether both or only dark or light theme will be used";
}
];
} }
message Theme { message Theme {
@ -79,3 +84,10 @@ message Theme {
} }
]; ];
} }
enum ThemeMode {
THEME_MODE_UNSPECIFIED = 0;
THEME_MODE_AUTO = 1;
THEME_MODE_LIGHT = 2;
THEME_MODE_DARK = 3;
}