diff --git a/backend/ee/onyx/server/enterprise_settings/api.py b/backend/ee/onyx/server/enterprise_settings/api.py index a067aed84a..a2938ae7f4 100644 --- a/backend/ee/onyx/server/enterprise_settings/api.py +++ b/backend/ee/onyx/server/enterprise_settings/api.py @@ -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) diff --git a/backend/ee/onyx/server/enterprise_settings/models.py b/backend/ee/onyx/server/enterprise_settings/models.py index 68c4d0d0c4..8b739e7519 100644 --- a/backend/ee/onyx/server/enterprise_settings/models.py +++ b/backend/ee/onyx/server/enterprise_settings/models.py @@ -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: diff --git a/backend/onyx/configs/app_configs.py b/backend/onyx/configs/app_configs.py index e484d49c6c..9001b46e2c 100644 --- a/backend/onyx/configs/app_configs.py +++ b/backend/onyx/configs/app_configs.py @@ -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, diff --git a/backend/onyx/server/settings/api.py b/backend/onyx/server/settings/api.py index 5065e026d6..32875293bc 100644 --- a/backend/onyx/server/settings/api.py +++ b/backend/onyx/server/settings/api.py @@ -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, diff --git a/backend/onyx/server/settings/models.py b/backend/onyx/server/settings/models.py index c597aefd5a..a11a69704e 100644 --- a/backend/onyx/server/settings/models.py +++ b/backend/onyx/server/settings/models.py @@ -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. diff --git a/backend/tests/unit/ee/onyx/server/enterprise_settings/test_enterprise_settings_store.py b/backend/tests/unit/ee/onyx/server/enterprise_settings/test_enterprise_settings_store.py new file mode 100644 index 0000000000..694e78c875 --- /dev/null +++ b/backend/tests/unit/ee/onyx/server/enterprise_settings/test_enterprise_settings_store.py @@ -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" diff --git a/cli/internal/deploy/deployfiles/embedded/docker_compose/docker-compose.prod.yml b/cli/internal/deploy/deployfiles/embedded/docker_compose/docker-compose.prod.yml index b603991f9a..baaad0de8d 100644 --- a/cli/internal/deploy/deployfiles/embedded/docker_compose/docker-compose.prod.yml +++ b/cli/internal/deploy/deployfiles/embedded/docker_compose/docker-compose.prod.yml @@ -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 diff --git a/cli/internal/deploy/deployfiles/embedded/docker_compose/docker-compose.yml b/cli/internal/deploy/deployfiles/embedded/docker_compose/docker-compose.yml index 87b608bbf4..756f76a657 100644 --- a/cli/internal/deploy/deployfiles/embedded/docker_compose/docker-compose.yml +++ b/cli/internal/deploy/deployfiles/embedded/docker_compose/docker-compose.yml @@ -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 diff --git a/cli/internal/deploy/deployfiles/embedded/docker_compose/env.template b/cli/internal/deploy/deployfiles/embedded/docker_compose/env.template index cc21d40a66..f785a819a6 100644 --- a/cli/internal/deploy/deployfiles/embedded/docker_compose/env.template +++ b/cli/internal/deploy/deployfiles/embedded/docker_compose/env.template @@ -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 diff --git a/deployment/docker_compose/docker-compose.prod-no-letsencrypt.yml b/deployment/docker_compose/docker-compose.prod-no-letsencrypt.yml index bebc4eb3b6..e35b833f52 100644 --- a/deployment/docker_compose/docker-compose.prod-no-letsencrypt.yml +++ b/deployment/docker_compose/docker-compose.prod-no-letsencrypt.yml @@ -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 diff --git a/deployment/docker_compose/docker-compose.prod.yml b/deployment/docker_compose/docker-compose.prod.yml index b603991f9a..baaad0de8d 100644 --- a/deployment/docker_compose/docker-compose.prod.yml +++ b/deployment/docker_compose/docker-compose.prod.yml @@ -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 diff --git a/deployment/docker_compose/docker-compose.search-testing.yml b/deployment/docker_compose/docker-compose.search-testing.yml index cd30149e53..8fedc460e5 100644 --- a/deployment/docker_compose/docker-compose.search-testing.yml +++ b/deployment/docker_compose/docker-compose.search-testing.yml @@ -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 diff --git a/deployment/docker_compose/docker-compose.template.yml b/deployment/docker_compose/docker-compose.template.yml index 21aa5407e1..0ac8ded49b 100644 --- a/deployment/docker_compose/docker-compose.template.yml +++ b/deployment/docker_compose/docker-compose.template.yml @@ -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 diff --git a/deployment/docker_compose/docker-compose.yml b/deployment/docker_compose/docker-compose.yml index 87b608bbf4..756f76a657 100644 --- a/deployment/docker_compose/docker-compose.yml +++ b/deployment/docker_compose/docker-compose.yml @@ -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 diff --git a/deployment/docker_compose/env.template b/deployment/docker_compose/env.template index cc21d40a66..f785a819a6 100644 --- a/deployment/docker_compose/env.template +++ b/deployment/docker_compose/env.template @@ -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 diff --git a/web/Dockerfile b/web/Dockerfile index f403ec4666..c031d3f504 100644 --- a/web/Dockerfile +++ b/web/Dockerfile @@ -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} diff --git a/web/src/app/ee/admin/theme/AppearanceThemeSettings.tsx b/web/src/app/ee/admin/theme/AppearanceThemeSettings.tsx index e680749a50..42ebd90df6 100644 --- a/web/src/app/ee/admin/theme/AppearanceThemeSettings.tsx +++ b/web/src/app/ee/admin/theme/AppearanceThemeSettings.tsx @@ -581,36 +581,6 @@ export const AppearanceThemeSettings = forwardRef< - - -
- - {t("branding.label")} - {!enterpriseTier && ( - - )} - - - - setFieldValue("hide_onyx_branding", checked) - } - disabled={!enterpriseTier} - /> - -
- - {t("branding.description")} - -
-
-
diff --git a/web/src/app/ee/admin/theme/page.tsx b/web/src/app/ee/admin/theme/page.tsx index 6d8e809da9..d0ed44eef3 100644 --- a/web/src/app/ee/admin/theme/page.tsx +++ b/web/src/app/ee/admin/theme/page.tsx @@ -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 diff --git a/web/src/i18n/messages/ar.json b/web/src/i18n/messages/ar.json index cd6cfa2ee2..54de0d0950 100644 --- a/web/src/i18n/messages/ar.json +++ b/web/src/i18n/messages/ar.json @@ -7511,11 +7511,6 @@ "description": "سيظهر هذا الاسم في جميع أنحاء التطبيق وسيحل محل \"Onyx\" في الواجهة.", "label": "اسم عرض التطبيق" }, - "branding": { - "description": "أزل عبارة \"powered by Onyx\" وغيرها من عناصر علامة Onyx التجارية في التطبيق.", - "enterpriseTooltip": "إخفاء علامة Onyx التجارية هو ميزة في خطة Enterprise.", - "label": "إخفاء علامة Onyx التجارية" - }, "chatFooter": { "description": "أضف محتوى ماركداون لإخلاء المسؤولية أو معلومات إضافية.", "label": "نص تذييل الدردشة" diff --git a/web/src/i18n/messages/de.json b/web/src/i18n/messages/de.json index 71d758ff19..c8e6d89ae8 100644 --- a/web/src/i18n/messages/de.json +++ b/web/src/i18n/messages/de.json @@ -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" diff --git a/web/src/i18n/messages/en.json b/web/src/i18n/messages/en.json index 36daf7146b..eee4a74a7c 100644 --- a/web/src/i18n/messages/en.json +++ b/web/src/i18n/messages/en.json @@ -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" diff --git a/web/src/i18n/messages/es.json b/web/src/i18n/messages/es.json index c4fc064cea..173865b1d3 100644 --- a/web/src/i18n/messages/es.json +++ b/web/src/i18n/messages/es.json @@ -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" diff --git a/web/src/i18n/messages/fr.json b/web/src/i18n/messages/fr.json index 9e9ed18896..98aa29ef88 100644 --- a/web/src/i18n/messages/fr.json +++ b/web/src/i18n/messages/fr.json @@ -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" diff --git a/web/src/i18n/messages/ja.json b/web/src/i18n/messages/ja.json index 4cd4c1a86a..b0d60f72f5 100644 --- a/web/src/i18n/messages/ja.json +++ b/web/src/i18n/messages/ja.json @@ -7511,11 +7511,6 @@ "description": "この名前はアプリ全体に表示され、UI内の「Onyx」を置き換えます。", "label": "アプリケーションの表示名" }, - "branding": { - "description": "アプリ内の「powered by Onyx」やその他のOnyxブランディングを削除します。", - "enterpriseTooltip": "Onyxブランディングの非表示はEnterpriseプランの機能です。", - "label": "Onyxブランディングを非表示" - }, "chatFooter": { "description": "免責事項や追加情報のためのマークダウンコンテンツを追加します。", "label": "チャットフッターのテキスト" diff --git a/web/src/i18n/messages/ko.json b/web/src/i18n/messages/ko.json index a0188b5153..48df1055eb 100644 --- a/web/src/i18n/messages/ko.json +++ b/web/src/i18n/messages/ko.json @@ -7511,11 +7511,6 @@ "description": "이 이름은 앱 전체에 표시되며 UI에서 \"Onyx\"를 대체합니다.", "label": "애플리케이션 표시 이름" }, - "branding": { - "description": "앱에서 \"powered by Onyx\" 및 기타 Onyx 브랜딩을 제거합니다.", - "enterpriseTooltip": "Onyx 브랜딩 숨기기는 Enterprise 플랜 기능입니다.", - "label": "Onyx 브랜딩 숨기기" - }, "chatFooter": { "description": "면책 조항이나 추가 정보를 위한 마크다운 콘텐츠를 추가하세요.", "label": "채팅 푸터 텍스트" diff --git a/web/src/i18n/messages/pt.json b/web/src/i18n/messages/pt.json index e330480719..76e86a0afd 100644 --- a/web/src/i18n/messages/pt.json +++ b/web/src/i18n/messages/pt.json @@ -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" diff --git a/web/src/i18n/messages/zh.json b/web/src/i18n/messages/zh.json index 74940557c9..3dc85b56a1 100644 --- a/web/src/i18n/messages/zh.json +++ b/web/src/i18n/messages/zh.json @@ -7511,11 +7511,6 @@ "description": "此名称将在整个应用中显示,并替换界面中的\"Onyx\"。", "label": "应用显示名称" }, - "branding": { - "description": "移除应用中的\"powered by Onyx\"及其他 Onyx 品牌标识。", - "enterpriseTooltip": "隐藏 Onyx 品牌标识是企业版套餐的功能。", - "label": "隐藏 Onyx 品牌标识" - }, "chatFooter": { "description": "添加用于免责声明或附加信息的 markdown 内容。", "label": "聊天页脚文本" diff --git a/web/src/lib/app/components.tsx b/web/src/lib/app/components.tsx index 37b1735368..bae48d5ca9 100644 --- a/web/src/lib/app/components.tsx +++ b/web/src/lib/app/components.tsx @@ -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 && ( {applicationName} )} - {!NEXT_PUBLIC_DO_NOT_USE_TOGGLE_OFF_DANSWER_POWERED && - !enterprise?.hide_onyx_branding && ( - - {t("logo.poweredBy.label")} - - )} + {/* Wait for settings so a hidden tagline never flashes. */} + {!isLoading && !hide_onyx_branding && ( + + {t("logo.poweredBy.label")} + + )}
)} diff --git a/web/src/lib/constants.ts b/web/src/lib/constants.ts index 8802c516e1..6d5ee51adc 100644 --- a/web/src/lib/constants.ts +++ b/web/src/lib/constants.ts @@ -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. diff --git a/web/src/lib/settings/types.ts b/web/src/lib/settings/types.ts index 9cb85f07e5..da31896d82 100644 --- a/web/src/lib/settings/types.ts +++ b/web/src/lib/settings/types.ts @@ -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; } /** diff --git a/web/tests/e2e/admin/theme/AppearanceThemePage.ts b/web/tests/e2e/admin/theme/AppearanceThemePage.ts index b0ac2dc8e1..a19066b66d 100644 --- a/web/tests/e2e/admin/theme/AppearanceThemePage.ts +++ b/web/tests/e2e/admin/theme/AppearanceThemePage.ts @@ -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 }); } // --------------------------------------------------------------------------- diff --git a/web/tests/e2e/admin/theme/appearance_theme_settings.spec.ts b/web/tests/e2e/admin/theme/appearance_theme_settings.spec.ts index bd22b889a9..6c7ef00d10 100644 --- a/web/tests/e2e/admin/theme/appearance_theme_settings.spec.ts +++ b/web/tests/e2e/admin/theme/appearance_theme_settings.spec.ts @@ -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(); }); });