fix(enterprise-settings): remove the Hide Onyx Branding toggle (#15112)

This commit is contained in:
Nikolas Garza authored and GitHub committed 2026-09-24 21:20:41 +00:00
1 parent 0c6a8e3bcf
commit f61e05131f
32 files changed
+75 -194

No files matched your search

@@ -200,10 +200,8 @@ def admin_ee_put_settings(
settings: EnterpriseSettings,
_: User = Depends(require_permission(Permission.FULL_ADMIN_PANEL_ACCESS)),
) -> None:
# Custom help link and Onyx-branding toggle are Enterprise-only. Block
# writes to those fields when tier < ENTERPRISE so the FE disabled state
# cannot be bypassed by crafting a request. Uses FEATURE_NOT_AVAILABLE
# (402) to match the tier_gate middleware shape.
# Custom help link is Enterprise-only. Enforced here so a crafted request
# cannot bypass the disabled field in the UI.
if not tier_at_least(get_tier(), Tier.ENTERPRISE):
existing = load_settings()
if (
@@ -214,11 +212,6 @@ def admin_ee_put_settings(
OnyxErrorCode.FEATURE_NOT_AVAILABLE,
"Custom help link requires the Enterprise plan.",
)
if settings.hide_onyx_branding != existing.hide_onyx_branding:
raise OnyxError(
OnyxErrorCode.FEATURE_NOT_AVAILABLE,
"Hiding Onyx branding requires the Enterprise plan.",
)
store_settings(settings)
@@ -111,9 +111,6 @@ class EnterpriseSettings(BaseModel):
custom_help_link_url: str | None = None
custom_help_link_label: str | None = None
# hide the "Powered by Onyx" tagline under the sidebar logo
hide_onyx_branding: bool | None = None
@field_validator("custom_help_link_url")
@classmethod
def _validate_help_link_scheme(cls, v: str | None) -> str | None:
+4
View File
@@ -79,6 +79,10 @@ DISABLE_USER_KNOWLEDGE = os.environ.get("DISABLE_USER_KNOWLEDGE", "").lower() ==
# are disabled but core chat, tools, user file uploads, and Projects still work.
DISABLE_VECTOR_DB = os.environ.get("DISABLE_VECTOR_DB", "").lower() == "true"
# Hides the "Powered by Onyx" tagline on Enterprise deployments. Do not set
# without explicit permission from Onyx.
HIDE_ONYX_BRANDING = os.environ.get("HIDE_ONYX_BRANDING", "").lower() == "true"
# TEMPORARY (will be removed soon): operator-forced Search-UI scope (self-hosted only) —
# comma-separated document set NAMES. When set, the Onyx Search UI is restricted to those sets
# (AND'd on top of any persona/user scope; ACL still enforced) — chat/other flows are unaffected,
+8
View File
@@ -10,6 +10,7 @@ from onyx.auth.users import is_user_admin
from onyx.configs.app_configs import (
DEFAULT_USER_FILE_MAX_UPLOAD_SIZE_MB,
DISABLE_VECTOR_DB,
HIDE_ONYX_BRANDING,
MAX_ALLOWED_UPLOAD_SIZE_MB,
POSTHOG_API_KEY,
POSTHOG_HOST,
@@ -170,6 +171,11 @@ def fetch_settings(
apply_license_status_to_settings,
)
general_settings = apply_fn(general_settings)
# The EE apply_fn resolves tier on every path. On CE the stored value is
# client-writable, so it never counts.
resolved_tier = (
general_settings.tier if global_version.is_ee_version() else Tier.COMMUNITY
)
# Craft workspace instructions are visible to authenticated users (they
# appear in sandbox AGENTS.md anyway) but not to anonymous visitors.
@@ -202,6 +208,8 @@ def fetch_settings(
onyx_craft_available=onyx_craft_available,
opencode_debugging_enabled=ENABLE_OPENCODE_DEBUGGING,
vector_db_enabled=not DISABLE_VECTOR_DB,
hide_onyx_branding=HIDE_ONYX_BRANDING
and tier_at_least(resolved_tier, Tier.ENTERPRISE),
hooks_enabled=not MULTI_TENANT,
version=onyx_version,
max_allowed_upload_size_mb=MAX_ALLOWED_UPLOAD_SIZE_MB,
+2
View File
@@ -128,6 +128,8 @@ class UserSettings(Settings):
# False when DISABLE_VECTOR_DB is set — connectors, RAG search, and
# document sets are unavailable.
vector_db_enabled: bool = True
# HIDE_ONYX_BRANDING env var, honored only on the Enterprise tier.
hide_onyx_branding: bool = False
# True when hooks are available: single-tenant EE deployments only.
hooks_enabled: bool = False
# Application version, read from the ONYX_VERSION env var at startup.
@@ -0,0 +1,24 @@
from unittest.mock import MagicMock, patch
from ee.onyx.server.enterprise_settings.store import load_settings, store_settings
def test_legacy_hide_onyx_branding_is_dropped_on_load_and_save() -> None:
kv_store = MagicMock()
kv_store.load.return_value = {
"application_name": "Acme",
"hide_onyx_branding": True,
}
with patch(
"ee.onyx.server.enterprise_settings.store.get_kv_store",
return_value=kv_store,
):
settings = load_settings()
store_settings(settings)
assert settings.application_name == "Acme"
assert "hide_onyx_branding" not in settings.model_dump()
stored = kv_store.store.call_args.args[1]
assert "hide_onyx_branding" not in stored
assert stored["application_name"] == "Acme"
@@ -167,8 +167,6 @@ services:
- NEXT_PUBLIC_FORGOT_PASSWORD_ENABLED=${NEXT_PUBLIC_FORGOT_PASSWORD_ENABLED:-}
# Enterprise Edition only
- NEXT_PUBLIC_THEME=${NEXT_PUBLIC_THEME:-}
# DO NOT TURN ON unless you have EXPLICIT PERMISSION from Onyx.
- NEXT_PUBLIC_DO_NOT_USE_TOGGLE_OFF_DANSWER_POWERED=${NEXT_PUBLIC_DO_NOT_USE_TOGGLE_OFF_DANSWER_POWERED:-false}
- NODE_OPTIONS=${NODE_OPTIONS:-"--max-old-space-size=4096"}
env_file:
- path: .env
@@ -208,8 +208,6 @@ services:
- NEXT_PUBLIC_FORGOT_PASSWORD_ENABLED=${NEXT_PUBLIC_FORGOT_PASSWORD_ENABLED:-}
# Enterprise Edition only
- NEXT_PUBLIC_THEME=${NEXT_PUBLIC_THEME:-}
# DO NOT TURN ON unless you have EXPLICIT PERMISSION from Onyx.
- NEXT_PUBLIC_DO_NOT_USE_TOGGLE_OFF_DANSWER_POWERED=${NEXT_PUBLIC_DO_NOT_USE_TOGGLE_OFF_DANSWER_POWERED:-false}
- NODE_OPTIONS=${NODE_OPTIONS:-"--max-old-space-size=4096"}
env_file:
- path: .env
@@ -409,6 +409,8 @@ LOG_ONYX_MODEL_INTERACTIONS=False
# SALESFORCE_CLIENT_SECRET=
## Miscellaneous
# Hides "Powered by Onyx" on Enterprise. Do not set without explicit permission from Onyx.
# HIDE_ONYX_BRANDING=
# Kill switch for the gateway's native Anthropic passthrough (server tools,
# thinking-block signatures, fine-grained streaming); default on. Set to false
# to send Anthropic-backed providers back through the OpenAI-translation path.
@@ -428,7 +430,6 @@ LOG_ONYX_MODEL_INTERACTIONS=False
# NEXT_PUBLIC_DISABLE_LOGOUT=
# NEXT_PUBLIC_FORGOT_PASSWORD_ENABLED=
# NEXT_PUBLIC_THEME=
# NEXT_PUBLIC_DO_NOT_USE_TOGGLE_OFF_DANSWER_POWERED=
# NEXT_PUBLIC_CUSTOM_REFRESH_URL=
## Pointer to services
@@ -167,8 +167,6 @@ services:
- NEXT_PUBLIC_FORGOT_PASSWORD_ENABLED=${NEXT_PUBLIC_FORGOT_PASSWORD_ENABLED:-}
# Enterprise Edition only
- NEXT_PUBLIC_THEME=${NEXT_PUBLIC_THEME:-}
# DO NOT TURN ON unless you have EXPLICIT PERMISSION from Onyx.
- NEXT_PUBLIC_DO_NOT_USE_TOGGLE_OFF_DANSWER_POWERED=${NEXT_PUBLIC_DO_NOT_USE_TOGGLE_OFF_DANSWER_POWERED:-false}
- NODE_OPTIONS=${NODE_OPTIONS:-"--max-old-space-size=4096"}
env_file:
- path: .env
@@ -167,8 +167,6 @@ services:
- NEXT_PUBLIC_FORGOT_PASSWORD_ENABLED=${NEXT_PUBLIC_FORGOT_PASSWORD_ENABLED:-}
# Enterprise Edition only
- NEXT_PUBLIC_THEME=${NEXT_PUBLIC_THEME:-}
# DO NOT TURN ON unless you have EXPLICIT PERMISSION from Onyx.
- NEXT_PUBLIC_DO_NOT_USE_TOGGLE_OFF_DANSWER_POWERED=${NEXT_PUBLIC_DO_NOT_USE_TOGGLE_OFF_DANSWER_POWERED:-false}
- NODE_OPTIONS=${NODE_OPTIONS:-"--max-old-space-size=4096"}
env_file:
- path: .env
@@ -102,8 +102,6 @@ services:
# Enterprise Edition only
- NEXT_PUBLIC_THEME=${NEXT_PUBLIC_THEME:-}
# DO NOT TURN ON unless you have EXPLICIT PERMISSION from Onyx.
- NEXT_PUBLIC_DO_NOT_USE_TOGGLE_OFF_DANSWER_POWERED=${NEXT_PUBLIC_DO_NOT_USE_TOGGLE_OFF_DANSWER_POWERED:-false}
depends_on:
- api_server
restart: unless-stopped
@@ -251,8 +251,6 @@ services:
- NEXT_PUBLIC_FORGOT_PASSWORD_ENABLED=${NEXT_PUBLIC_FORGOT_PASSWORD_ENABLED:-}
# Enterprise Edition only
- NEXT_PUBLIC_THEME=${NEXT_PUBLIC_THEME:-}
# DO NOT TURN ON unless you have EXPLICIT PERMISSION from Onyx.
- NEXT_PUBLIC_DO_NOT_USE_TOGGLE_OFF_DANSWER_POWERED=${NEXT_PUBLIC_DO_NOT_USE_TOGGLE_OFF_DANSWER_POWERED:-false}
- NODE_OPTIONS=${NODE_OPTIONS:-"--max-old-space-size=4096"}
env_file:
- path: .env
@@ -208,8 +208,6 @@ services:
- NEXT_PUBLIC_FORGOT_PASSWORD_ENABLED=${NEXT_PUBLIC_FORGOT_PASSWORD_ENABLED:-}
# Enterprise Edition only
- NEXT_PUBLIC_THEME=${NEXT_PUBLIC_THEME:-}
# DO NOT TURN ON unless you have EXPLICIT PERMISSION from Onyx.
- NEXT_PUBLIC_DO_NOT_USE_TOGGLE_OFF_DANSWER_POWERED=${NEXT_PUBLIC_DO_NOT_USE_TOGGLE_OFF_DANSWER_POWERED:-false}
- NODE_OPTIONS=${NODE_OPTIONS:-"--max-old-space-size=4096"}
env_file:
- path: .env
+2 -1
View File
@@ -409,6 +409,8 @@ LOG_ONYX_MODEL_INTERACTIONS=False
# SALESFORCE_CLIENT_SECRET=
## Miscellaneous
# Hides "Powered by Onyx" on Enterprise. Do not set without explicit permission from Onyx.
# HIDE_ONYX_BRANDING=
# Kill switch for the gateway's native Anthropic passthrough (server tools,
# thinking-block signatures, fine-grained streaming); default on. Set to false
# to send Anthropic-backed providers back through the OpenAI-translation path.
@@ -428,7 +430,6 @@ LOG_ONYX_MODEL_INTERACTIONS=False
# NEXT_PUBLIC_DISABLE_LOGOUT=
# NEXT_PUBLIC_FORGOT_PASSWORD_ENABLED=
# NEXT_PUBLIC_THEME=
# NEXT_PUBLIC_DO_NOT_USE_TOGGLE_OFF_DANSWER_POWERED=
# NEXT_PUBLIC_CUSTOM_REFRESH_URL=
## Pointer to services
-6
View File
@@ -51,9 +51,6 @@ ENV NEXT_TELEMETRY_DISABLED=1
ARG NEXT_PUBLIC_THEME
ENV NEXT_PUBLIC_THEME=${NEXT_PUBLIC_THEME}
ARG NEXT_PUBLIC_DO_NOT_USE_TOGGLE_OFF_DANSWER_POWERED
ENV NEXT_PUBLIC_DO_NOT_USE_TOGGLE_OFF_DANSWER_POWERED=${NEXT_PUBLIC_DO_NOT_USE_TOGGLE_OFF_DANSWER_POWERED}
ARG NEXT_PUBLIC_DISABLE_LOGOUT
ENV NEXT_PUBLIC_DISABLE_LOGOUT=${NEXT_PUBLIC_DISABLE_LOGOUT}
@@ -140,9 +137,6 @@ COPY --from=builder --chown=node:node /app/.next/static ./.next/static
ARG NEXT_PUBLIC_THEME
ENV NEXT_PUBLIC_THEME=${NEXT_PUBLIC_THEME}
ARG NEXT_PUBLIC_DO_NOT_USE_TOGGLE_OFF_DANSWER_POWERED
ENV NEXT_PUBLIC_DO_NOT_USE_TOGGLE_OFF_DANSWER_POWERED=${NEXT_PUBLIC_DO_NOT_USE_TOGGLE_OFF_DANSWER_POWERED}
ARG NEXT_PUBLIC_DISABLE_LOGOUT
ENV NEXT_PUBLIC_DISABLE_LOGOUT=${NEXT_PUBLIC_DISABLE_LOGOUT}
@@ -581,36 +581,6 @@ export const AppearanceThemeSettings = forwardRef<
</div>
</Disabled>
<Disabled
disabled={!enterpriseTier}
tooltip={t("branding.enterpriseTooltip")}
>
<FormField state="idle" className="gap-0">
<div className="flex justify-between items-center">
<FormField.Label>
{t("branding.label")}
{!enterpriseTier && (
<Tag {...planTagProps("enterprise")} size="sm" />
)}
</FormField.Label>
<FormField.Control>
<InputSwitch
aria-label={t("branding.label")}
data-label="hide-onyx-branding-toggle"
checked={values.hide_onyx_branding}
onCheckedChange={(checked) =>
setFieldValue("hide_onyx_branding", checked)
}
disabled={!enterpriseTier}
/>
</FormField.Control>
</div>
<FormField.Description>
{t("branding.description")}
</FormField.Description>
</FormField>
</Disabled>
<Divider />
<div className="flex flex-col gap-4 p-4 bg-background-tint-00 rounded-16">
-3
View File
@@ -191,7 +191,6 @@ export default function ThemePage() {
Yup.string().url().isValidSync(value)
),
}),
hide_onyx_branding: Yup.boolean().nullable(),
system_announcement_enabled: Yup.boolean().nullable(),
system_announcement_header: Yup.string()
.trim()
@@ -245,7 +244,6 @@ export default function ThemePage() {
custom_help_link_url: enterpriseSettings?.custom_help_link_url || "",
custom_help_link_label:
enterpriseSettings?.custom_help_link_label || "",
hide_onyx_branding: enterpriseSettings?.hide_onyx_branding || false,
system_announcement_enabled: !!currentBanner,
system_announcement_header: currentBanner?.title || "",
system_announcement_content: currentBanner?.content || "",
@@ -298,7 +296,6 @@ export default function ThemePage() {
consent_screen_prompt: values.consent_screen_prompt || null,
custom_help_link_url: values.custom_help_link_url?.trim() || null,
custom_help_link_label: values.custom_help_link_label?.trim() || null,
hide_onyx_branding: values.hide_onyx_branding ?? null,
});
// Only touch the banner after the settings save succeeds, and only when
-5
View File
@@ -7511,11 +7511,6 @@
"description": "سيظهر هذا الاسم في جميع أنحاء التطبيق وسيحل محل \"Onyx\" في الواجهة.",
"label": "اسم عرض التطبيق"
},
"branding": {
"description": "أزل عبارة \"powered by Onyx\" وغيرها من عناصر علامة Onyx التجارية في التطبيق.",
"enterpriseTooltip": "إخفاء علامة Onyx التجارية هو ميزة في خطة Enterprise.",
"label": "إخفاء علامة Onyx التجارية"
},
"chatFooter": {
"description": "أضف محتوى ماركداون لإخلاء المسؤولية أو معلومات إضافية.",
"label": "نص تذييل الدردشة"
-5
View File
@@ -7511,11 +7511,6 @@
"description": "Dieser Name wird in der gesamten App angezeigt und ersetzt \"Onyx\" in der Benutzeroberfläche.",
"label": "Anzeigename der Anwendung"
},
"branding": {
"description": "Entfernen Sie \"powered by Onyx\" und andere Onyx-Branding-Elemente in der App.",
"enterpriseTooltip": "Das Ausblenden des Onyx-Brandings ist eine Funktion des Enterprise-Plans.",
"label": "Onyx-Branding ausblenden"
},
"chatFooter": {
"description": "Fügen Sie Markdown-Inhalte für Haftungsausschlüsse oder zusätzliche Informationen hinzu.",
"label": "Text der Chat-Fußzeile"
-5
View File
@@ -7511,11 +7511,6 @@
"description": "This name will show across the app and replace \"Onyx\" in the UI.",
"label": "Application Display Name"
},
"branding": {
"description": "Remove “powered by Onyx” and other Onyx branding presence in the app.",
"enterpriseTooltip": "Hiding Onyx branding is an Enterprise Plan feature.",
"label": "Hide Onyx Branding"
},
"chatFooter": {
"description": "Add markdown content for disclaimers or additional information.",
"label": "Chat Footer Text"
-5
View File
@@ -7511,11 +7511,6 @@
"description": "Este nombre se mostrará en toda la aplicación y reemplazará a \"Onyx\" en la interfaz.",
"label": "Nombre visible de la aplicación"
},
"branding": {
"description": "Elimina \"powered by Onyx\" y otras menciones de la marca Onyx en la aplicación.",
"enterpriseTooltip": "Ocultar la marca de Onyx es una función del plan Enterprise.",
"label": "Ocultar la marca de Onyx"
},
"chatFooter": {
"description": "Agrega contenido en markdown para avisos legales o información adicional.",
"label": "Texto del pie del chat"
-5
View File
@@ -7511,11 +7511,6 @@
"description": "Ce nom apparaîtra dans toute l'application et remplacera \"Onyx\" dans l'interface.",
"label": "Nom d'affichage de l'application"
},
"branding": {
"description": "Supprimez « powered by Onyx » et les autres présences de la marque Onyx dans l'application.",
"enterpriseTooltip": "Masquer la marque Onyx est une fonctionnalité du forfait Enterprise.",
"label": "Masquer la marque Onyx"
},
"chatFooter": {
"description": "Ajoutez du contenu markdown pour des avertissements ou des informations supplémentaires.",
"label": "Texte du pied de page du chat"
-5
View File
@@ -7511,11 +7511,6 @@
"description": "この名前はアプリ全体に表示され、UI内の「Onyx」を置き換えます。",
"label": "アプリケーションの表示名"
},
"branding": {
"description": "アプリ内の「powered by Onyx」やその他のOnyxブランディングを削除します。",
"enterpriseTooltip": "Onyxブランディングの非表示はEnterpriseプランの機能です。",
"label": "Onyxブランディングを非表示"
},
"chatFooter": {
"description": "免責事項や追加情報のためのマークダウンコンテンツを追加します。",
"label": "チャットフッターのテキスト"
-5
View File
@@ -7511,11 +7511,6 @@
"description": "이 이름은 앱 전체에 표시되며 UI에서 \"Onyx\"를 대체합니다.",
"label": "애플리케이션 표시 이름"
},
"branding": {
"description": "앱에서 \"powered by Onyx\" 및 기타 Onyx 브랜딩을 제거합니다.",
"enterpriseTooltip": "Onyx 브랜딩 숨기기는 Enterprise 플랜 기능입니다.",
"label": "Onyx 브랜딩 숨기기"
},
"chatFooter": {
"description": "면책 조항이나 추가 정보를 위한 마크다운 콘텐츠를 추가하세요.",
"label": "채팅 푸터 텍스트"
-5
View File
@@ -7511,11 +7511,6 @@
"description": "Este nome aparecerá em todo o aplicativo e substituirá \"Onyx\" na interface.",
"label": "Nome de exibição do aplicativo"
},
"branding": {
"description": "Remova \"powered by Onyx\" e outras presenças da marca Onyx no aplicativo.",
"enterpriseTooltip": "Ocultar a marca Onyx é um recurso do plano Enterprise.",
"label": "Ocultar a marca Onyx"
},
"chatFooter": {
"description": "Adicione conteúdo em markdown para avisos legais ou informações adicionais.",
"label": "Texto do rodapé do chat"
-5
View File
@@ -7511,11 +7511,6 @@
"description": "此名称将在整个应用中显示,并替换界面中的\"Onyx\"。",
"label": "应用显示名称"
},
"branding": {
"description": "移除应用中的\"powered by Onyx\"及其他 Onyx 品牌标识。",
"enterpriseTooltip": "隐藏 Onyx 品牌标识是企业版套餐的功能。",
"label": "隐藏 Onyx 品牌标识"
},
"chatFooter": {
"description": "添加用于免责声明或附加信息的 markdown 内容。",
"label": "聊天页脚文本"
+13 -16
View File
@@ -2,10 +2,7 @@
import { useTranslations } from "next-intl";
import { useSettings } from "@/lib/settings/hooks";
import {
DEFAULT_LOGO_SIZE_PX,
NEXT_PUBLIC_DO_NOT_USE_TOGGLE_OFF_DANSWER_POWERED,
} from "@/lib/constants";
import { DEFAULT_LOGO_SIZE_PX } from "@/lib/constants";
import { cn } from "@opal/utils";
import Text from "@/refresh-components/texts/Text";
import Truncated from "@/refresh-components/texts/Truncated";
@@ -72,7 +69,7 @@ export function FoldableLogo({
}: FoldableLogoProps) {
const t = useTranslations("common");
const resolvedSize = size ?? DEFAULT_LOGO_SIZE_PX;
const { enterprise } = useSettings();
const { enterprise, hide_onyx_branding, isLoading } = useSettings();
const logoDisplayStyle = enterprise?.logo_display_style;
const applicationName = enterprise?.application_name;
@@ -99,17 +96,17 @@ export function FoldableLogo({
{opts.includeName && (
<Truncated headingH3>{applicationName}</Truncated>
)}
{!NEXT_PUBLIC_DO_NOT_USE_TOGGLE_OFF_DANSWER_POWERED &&
!enterprise?.hide_onyx_branding && (
<Text
secondaryBody
text03
className={"line-clamp-1 truncate"}
nowrap
>
{t("logo.poweredBy.label")}
</Text>
)}
{/* Wait for settings so a hidden tagline never flashes. */}
{!isLoading && !hide_onyx_branding && (
<Text
secondaryBody
text03
className={"line-clamp-1 truncate"}
nowrap
>
{t("logo.poweredBy.label")}
</Text>
)}
</div>
)}
</div>
-4
View File
@@ -11,10 +11,6 @@ export const DOCS_ADMINS_PATH = `${DOCS_BASE_URL}/admins`;
export const MCP_INTERNAL_URL =
process.env.MCP_INTERNAL_URL || "http://127.0.0.1:8090";
export const NEXT_PUBLIC_DO_NOT_USE_TOGGLE_OFF_DANSWER_POWERED =
process.env.NEXT_PUBLIC_DO_NOT_USE_TOGGLE_OFF_DANSWER_POWERED?.toLowerCase() ===
"true";
// Name of the FastAPI-Users auth cookie. Configurable via env (shared with the
// backend's AUTH_COOKIE_NAME) so deployments sharing a hostname — e.g. parallel
// local worktrees on different ports of localhost — keep separate auth cookies.
+3 -3
View File
@@ -97,6 +97,9 @@ export interface Settings {
// are unavailable.
vector_db_enabled?: boolean;
// HIDE_ONYX_BRANDING env var, honored only on the Enterprise tier.
hide_onyx_branding?: boolean;
// True when hooks are available: single-tenant deployments only.
hooks_enabled?: boolean;
@@ -150,9 +153,6 @@ export interface EnterpriseSettings {
// Custom help link surfaced in the profile dropdown alongside "Help & FAQ".
custom_help_link_url: string | null;
custom_help_link_label: string | null;
// Hide the "Powered by Onyx" tagline under the sidebar logo.
hide_onyx_branding: boolean | null;
}
/**
@@ -2,7 +2,7 @@
* Page Object Model for the Admin Appearance / Theme page (/admin/theme).
*
* Encapsulates locators and interactions for the custom help link and
* hide-onyx-branding controls so specs stay declarative. Existing tests in
* "Powered by Onyx" tagline so specs stay declarative. Existing tests in
* `appearance_theme_settings.spec.ts` still use inline locators; new tests
* should drive the page through this class.
*/
@@ -37,7 +37,6 @@ export class AppearanceThemePage {
readonly applicationNameInput: Locator;
readonly customHelpLinkUrlInput: Locator;
readonly customHelpLinkLabelInput: Locator;
readonly hideBrandingToggle: Locator;
readonly saveButton: Locator;
// Sidebar / popover
@@ -54,9 +53,6 @@ export class AppearanceThemePage {
this.customHelpLinkLabelInput = page.locator(
'[data-label="custom-help-link-label-input"]'
);
this.hideBrandingToggle = page.locator(
'[data-label="hide-onyx-branding-toggle"]'
);
this.saveButton = page.getByRole("button", { name: "Apply Changes" });
this.userDropdownTrigger = page.locator("#onyx-user-dropdown");
@@ -96,11 +92,6 @@ export class AppearanceThemePage {
await this.customHelpLinkLabelInput.clear();
}
async toggleHideBranding() {
await this.hideBrandingToggle.scrollIntoViewIfNeeded();
await this.hideBrandingToggle.click();
}
/**
* Click "Apply Changes" and wait for both the PUT and the subsequent SWR
* revalidation GET. Both promises MUST be armed before the click — a
@@ -165,23 +156,10 @@ export class AppearanceThemePage {
await expect(link).toContainText(text);
}
/**
* Locator for the Logo's tagline, scoped exactly so it doesn't also match
* the toggle's helper text on the same page ("Remove 'powered by Onyx'
* and other Onyx branding..."). `getByText` is case-insensitive +
* substring by default; `exact: true` makes it strict equality on the
* element's full text content.
*/
private get poweredByOnyxTagline(): Locator {
return this.page.getByText("Powered by Onyx", { exact: true });
}
async expectPoweredByOnyxVisible() {
await expect(this.poweredByOnyxTagline).toBeVisible({ timeout: 5_000 });
}
async expectPoweredByOnyxAbsent() {
await expect(this.poweredByOnyxTagline).toHaveCount(0, { timeout: 5_000 });
await expect(
this.page.getByText("Powered by Onyx", { exact: true })
).toBeVisible({ timeout: 5_000 });
}
// ---------------------------------------------------------------------------
@@ -89,21 +89,6 @@ test.describe("Appearance Theme Settings @exclusive", () => {
await helpLinkLabelInput.clear();
}
// Disable hide-onyx-branding toggle if enabled
const hideBrandingToggle = page.locator(
'[data-label="hide-onyx-branding-toggle"]'
);
if (
await hideBrandingToggle.isVisible({ timeout: 1000 }).catch(() => false)
) {
const hideBrandingState =
await hideBrandingToggle.getAttribute("aria-checked");
if (hideBrandingState === "true") {
await hideBrandingToggle.click();
await page.waitForTimeout(300);
}
}
// Save reset. Arm the PUT waiter *before* clicking — a post-click
// waitForResponse can miss a fast response and then hang until the test
// timeout (the whole point of saveAndWaitForPut in AppearanceThemePage).
@@ -313,32 +298,25 @@ test.describe("Appearance Theme Settings @exclusive", () => {
await themePage.clearCustomHelpLinkLabel();
});
test("Hide Onyx Branding toggle removes the 'Powered by Onyx' tagline", async ({
test("custom application name keeps the 'Powered by Onyx' tagline", async ({
page,
}) => {
const settings = await (await page.request.get("/api/settings")).json();
test.skip(
settings.hide_onyx_branding === true,
"HIDE_ONYX_BRANDING hides the tagline on this deployment"
);
const themePage = new AppearanceThemePage(page);
// The sidebar's "Powered by Onyx" tagline only renders alongside an
// application name (the Logo's logo_and_name fall-through path), so
// first set a name and save a baseline that we can then assert against.
// With the default display style, the tagline renders only when an
// application name is set.
await themePage.setApplicationName(TEST_VALUES.applicationName);
const baselineResponse = await themePage.saveAndWaitForPut();
expect(baselineResponse.status()).toBe(200);
await themePage.expectSaveSuccessToast();
await themePage.reloadAndWaitForForm();
// Sanity: tagline now visible alongside the application name
await themePage.expectPoweredByOnyxVisible();
await themePage.toggleHideBranding();
const response = await themePage.saveAndWaitForPut();
expect(response.status()).toBe(200);
await themePage.expectSaveSuccessToast();
// Reload to read the persisted setting fresh — the sidebar then re-
// renders the Logo without the tagline.
await themePage.reloadAndWaitForForm();
await themePage.expectPoweredByOnyxAbsent();
await themePage.expectPoweredByOnyxVisible();
});
});