feat: manage tenant appearance defaults
This commit is contained in:
@@ -3,7 +3,8 @@ import type {
|
||||
DeltaDeletedItem,
|
||||
NavigationPreferences,
|
||||
PrivacyRetentionPolicy,
|
||||
TenantAdminItem
|
||||
TenantAdminItem,
|
||||
UserUiPalette
|
||||
} from "@govoplan/core-webui";
|
||||
import {
|
||||
apiFetch,
|
||||
@@ -43,6 +44,12 @@ export type TenantSettingsItem = {
|
||||
system_enabled_language_codes: string[];
|
||||
enabled_language_codes: string[];
|
||||
navigation?: NavigationPreferences | null;
|
||||
appearance_palette: UserUiPalette | null;
|
||||
appearance_palette_locked: boolean;
|
||||
system_appearance_palette: UserUiPalette;
|
||||
system_appearance_palette_locked: boolean;
|
||||
effective_appearance_palette: UserUiPalette;
|
||||
effective_appearance_source: "tenant" | "system" | "tenant_lock" | "system_lock";
|
||||
settings: Record<string, unknown>;
|
||||
};
|
||||
|
||||
@@ -54,6 +61,7 @@ export type TenantSettingsDeltaSections = Partial<{
|
||||
"available_languages" | "system_enabled_language_codes" | "enabled_language_codes"
|
||||
>;
|
||||
navigation: TenantSettingsItem["navigation"];
|
||||
appearance: Pick<TenantSettingsItem, "appearance_palette" | "appearance_palette_locked" | "system_appearance_palette" | "system_appearance_palette_locked" | "effective_appearance_palette" | "effective_appearance_source">;
|
||||
settings: TenantSettingsItem["settings"];
|
||||
}>;
|
||||
|
||||
@@ -151,6 +159,8 @@ export function updateTenantSettings(
|
||||
default_locale: string;
|
||||
enabled_language_codes?: string[] | null;
|
||||
navigation?: NavigationPreferences | null;
|
||||
appearance_palette?: UserUiPalette | null;
|
||||
appearance_palette_locked?: boolean;
|
||||
}
|
||||
): Promise<TenantSettingsItem> {
|
||||
return apiFetch(settings, "/api/v1/admin/tenant/settings", {
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import {
|
||||
DescriptionList,
|
||||
AppearancePalettePreview,
|
||||
AppearancePaletteSelect,
|
||||
NavigationPreferenceEditor,
|
||||
configurableNavigationItemsForModules,
|
||||
dispatchPlatformModulesChanged,
|
||||
@@ -14,6 +16,7 @@ import {
|
||||
Card,
|
||||
DocumentationHelpLink,
|
||||
FormField,
|
||||
ToggleSwitch,
|
||||
adminErrorMessage,
|
||||
useDeltaWatermarks,
|
||||
useUnsavedChanges,
|
||||
@@ -42,18 +45,25 @@ const fallback: TenantSettingsItem = {
|
||||
system_enabled_language_codes: ["de", "en"],
|
||||
enabled_language_codes: ["de", "en"],
|
||||
navigation: null,
|
||||
settings: {}
|
||||
settings: {},
|
||||
appearance_palette: null,
|
||||
appearance_palette_locked: false,
|
||||
system_appearance_palette: "default",
|
||||
system_appearance_palette_locked: false,
|
||||
effective_appearance_palette: "default",
|
||||
effective_appearance_source: "system"
|
||||
};
|
||||
|
||||
export default function TenantSettingsPanel({
|
||||
settings,
|
||||
canWrite,
|
||||
canWritePolicy,
|
||||
onAuthRefresh
|
||||
|
||||
|
||||
|
||||
|
||||
}: {settings: ApiSettings;canWrite: boolean;onAuthRefresh: () => Promise<void>;}) {
|
||||
}: {settings: ApiSettings;canWrite: boolean;canWritePolicy: boolean;onAuthRefresh: () => Promise<void>;}) {
|
||||
const { requestDiscard } = useUnsavedChanges();
|
||||
const { modules } = usePlatformModules();
|
||||
const navigationItems = configurableNavigationItemsForModules(modules);
|
||||
@@ -115,7 +125,9 @@ export default function TenantSettingsPanel({
|
||||
const saved = await updateTenantSettings(settings, {
|
||||
default_locale: draft.default_locale,
|
||||
enabled_language_codes: draft.enabled_language_codes,
|
||||
navigation: draft.navigation
|
||||
navigation: draft.navigation,
|
||||
appearance_palette: draft.appearance_palette,
|
||||
appearance_palette_locked: draft.appearance_palette_locked
|
||||
});
|
||||
setDraft(saved);
|
||||
setSavedDraft(saved);
|
||||
@@ -197,6 +209,33 @@ export default function TenantSettingsPanel({
|
||||
onChange={(navigation) => setDraft({ ...draft, navigation })}
|
||||
/>
|
||||
</Card>
|
||||
<Card title="i18n:govoplan-tenancy.appearance_defaults">
|
||||
<FormField label="i18n:govoplan-tenancy.tenant_palette_default" help="i18n:govoplan-tenancy.tenant_palette_default_help">
|
||||
<AppearancePaletteSelect
|
||||
value={draft.appearance_palette}
|
||||
onChange={(appearance_palette) => setDraft({
|
||||
...draft,
|
||||
appearance_palette,
|
||||
effective_appearance_palette: appearance_palette ?? draft.system_appearance_palette,
|
||||
effective_appearance_source: appearance_palette ? "tenant" : "system"
|
||||
})}
|
||||
allowInherit
|
||||
disabled={!canWrite || busy || draft.system_appearance_palette_locked || (draft.appearance_palette_locked && !canWritePolicy)}
|
||||
/>
|
||||
</FormField>
|
||||
<ToggleSwitch
|
||||
checked={draft.appearance_palette_locked}
|
||||
onChange={(appearance_palette_locked) => setDraft({ ...draft, appearance_palette_locked })}
|
||||
disabled={!canWrite || !canWritePolicy || busy || draft.system_appearance_palette_locked}
|
||||
help={!canWritePolicy ? "i18n:govoplan-tenancy.appearance_lock_policy_permission" : draft.system_appearance_palette_locked ? "i18n:govoplan-tenancy.system_palette_is_locked" : undefined}
|
||||
label="i18n:govoplan-tenancy.lock_tenant_palette"
|
||||
/>
|
||||
<AppearancePalettePreview palette={draft.system_appearance_palette_locked ? draft.system_appearance_palette : draft.appearance_palette ?? draft.system_appearance_palette} />
|
||||
<DescriptionList variant="inline">
|
||||
<div><dt>i18n:govoplan-tenancy.effective_source</dt><dd>{draft.system_appearance_palette_locked ? "i18n:govoplan-tenancy.system_lock" : draft.appearance_palette ? "i18n:govoplan-tenancy.tenant_default" : "i18n:govoplan-tenancy.system_default"}</dd></div>
|
||||
<div><dt>i18n:govoplan-tenancy.user_override</dt><dd>{draft.system_appearance_palette_locked || draft.appearance_palette_locked ? "i18n:govoplan-tenancy.blocked_by_policy" : "i18n:govoplan-tenancy.allowed"}</dd></div>
|
||||
</DescriptionList>
|
||||
</Card>
|
||||
</div>
|
||||
</AdminPageLayout>);
|
||||
|
||||
@@ -214,7 +253,9 @@ function tenantSettingsDraftKey(item: TenantSettingsItem): string {
|
||||
return JSON.stringify({
|
||||
default_locale: item.default_locale,
|
||||
enabled_language_codes: item.enabled_language_codes,
|
||||
navigation: item.navigation
|
||||
navigation: item.navigation,
|
||||
appearance_palette: item.appearance_palette,
|
||||
appearance_palette_locked: item.appearance_palette_locked
|
||||
});
|
||||
}
|
||||
|
||||
@@ -225,6 +266,7 @@ function applyTenantSettingsSections(item: TenantSettingsItem, sections: TenantS
|
||||
...(sections.locale ?? {}),
|
||||
...(sections.languages ?? {}),
|
||||
...(sections.navigation !== undefined ? { navigation: sections.navigation } : {}),
|
||||
...(sections.appearance ?? {}),
|
||||
...(sections.settings ? { settings: sections.settings } : {})
|
||||
};
|
||||
}
|
||||
|
||||
@@ -2,6 +2,19 @@ import type { PlatformTranslations } from "@govoplan/core-webui";
|
||||
|
||||
export const generatedTranslations: PlatformTranslations = {
|
||||
"en": {
|
||||
"i18n:govoplan-tenancy.appearance_defaults": "Appearance defaults",
|
||||
"i18n:govoplan-tenancy.tenant_palette_default": "Tenant palette default",
|
||||
"i18n:govoplan-tenancy.tenant_palette_default_help": "Inherit the system palette or select the default for this tenant.",
|
||||
"i18n:govoplan-tenancy.appearance_lock_policy_permission": "Policy-write permission is required to change this lock.",
|
||||
"i18n:govoplan-tenancy.system_palette_is_locked": "The system palette is locked and takes precedence.",
|
||||
"i18n:govoplan-tenancy.lock_tenant_palette": "Lock the tenant palette",
|
||||
"i18n:govoplan-tenancy.effective_source": "Effective source",
|
||||
"i18n:govoplan-tenancy.system_lock": "System policy lock",
|
||||
"i18n:govoplan-tenancy.tenant_default": "Tenant default",
|
||||
"i18n:govoplan-tenancy.system_default": "System default",
|
||||
"i18n:govoplan-tenancy.user_override": "Personal choice",
|
||||
"i18n:govoplan-tenancy.blocked_by_policy": "Blocked by policy",
|
||||
"i18n:govoplan-tenancy.allowed": "Allowed",
|
||||
"i18n:govoplan-tenancy.tenant_information_is_loading.7c9a1001": "Tenant information is loading.",
|
||||
"i18n:govoplan-tenancy.a_tenant_change_is_in_progress.7c9a1002": "A tenant change is in progress.",
|
||||
"i18n:govoplan-tenancy.tenant_creation_permission_is_required.7c9a1003": "Tenant creation permission is required.",
|
||||
@@ -101,6 +114,19 @@ export const generatedTranslations: PlatformTranslations = {
|
||||
"i18n:govoplan-tenancy.value_value.c189e8bc": "{value0} ({value1})"
|
||||
},
|
||||
"de": {
|
||||
"i18n:govoplan-tenancy.appearance_defaults": "Darstellungsstandards",
|
||||
"i18n:govoplan-tenancy.tenant_palette_default": "Mandantenstandard für die Farbpalette",
|
||||
"i18n:govoplan-tenancy.tenant_palette_default_help": "Systempalette übernehmen oder einen Standard für diesen Mandanten auswählen.",
|
||||
"i18n:govoplan-tenancy.appearance_lock_policy_permission": "Zum Ändern dieser Sperre ist das Recht zum Bearbeiten von Richtlinien erforderlich.",
|
||||
"i18n:govoplan-tenancy.system_palette_is_locked": "Die Systempalette ist verbindlich und hat Vorrang.",
|
||||
"i18n:govoplan-tenancy.lock_tenant_palette": "Mandantenpalette verbindlich festlegen",
|
||||
"i18n:govoplan-tenancy.effective_source": "Wirksame Quelle",
|
||||
"i18n:govoplan-tenancy.system_lock": "Systemrichtlinie",
|
||||
"i18n:govoplan-tenancy.tenant_default": "Mandantenstandard",
|
||||
"i18n:govoplan-tenancy.system_default": "Systemstandard",
|
||||
"i18n:govoplan-tenancy.user_override": "Persönliche Auswahl",
|
||||
"i18n:govoplan-tenancy.blocked_by_policy": "Durch Richtlinie gesperrt",
|
||||
"i18n:govoplan-tenancy.allowed": "Zulässig",
|
||||
"i18n:govoplan-tenancy.tenant_information_is_loading.7c9a1001": "Mandanteninformationen werden geladen.",
|
||||
"i18n:govoplan-tenancy.a_tenant_change_is_in_progress.7c9a1002": "Eine Mandantenänderung wird gerade ausgeführt.",
|
||||
"i18n:govoplan-tenancy.tenant_creation_permission_is_required.7c9a1003": "Die Berechtigung zum Erstellen von Mandanten ist erforderlich.",
|
||||
|
||||
@@ -44,6 +44,7 @@ const adminSections: AdminSectionsUiCapability = {
|
||||
createElement(TenantSettingsPanel, {
|
||||
settings,
|
||||
canWrite: auth.scopes.includes("admin:settings:write"),
|
||||
canWritePolicy: auth.scopes.includes("admin:policies:write"),
|
||||
onAuthRefresh: refreshAuth
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user