feat: add brand customization settings#2153
Merged
Merged
Conversation
There was a problem hiding this comment.
Pull request overview
This PR introduces a full “brand customization” capability (assets + text + loading visuals), including new backend APIs/storage, runtime injection via runtime.js, and new admin UI under System → Appearance/Theme for configuring and previewing branding.
Changes:
- Add backend
/api/v1/brand/*endpoints and domain service for persisting brand config, listing/uploading/deleting assets, and serving a runtime JS payload. - Add platform admin UI for brand customization (asset upload/select/URL add, loading animation/icon, preview panel) and wire it into System → Appearance settings.
- Update frontend runtime loading (index.html + Vite html injection) and refactor multiple places to consume brand-configured assets/icons.
Reviewed changes
Copilot reviewed 41 out of 49 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| src/frontend/platform/src/utils/brand.ts | New helper utilities to resolve brand asset URLs against base URL/runtime config. |
| src/frontend/platform/src/types/global.d.ts | Extends window.BRAND_CONFIG typing for new brand fields/assets/loading config. |
| src/frontend/platform/src/pages/SystemPage/theme/index.tsx | Adds tabs to split theme colors vs brand customization settings. |
| src/frontend/platform/src/pages/SystemPage/theme/brandTypes.ts | Defines shared brand config types/defaults for the admin UI. |
| src/frontend/platform/src/pages/SystemPage/theme/BrandPreviewPanel.tsx | Adds a preview panel to visualize brand changes across surfaces. |
| src/frontend/platform/src/pages/SystemPage/theme/BrandCustomization.tsx | Implements the admin brand customization page with load/save/reset flows. |
| src/frontend/platform/src/pages/SystemPage/theme/BrandAssetUpload.tsx | Reusable asset picker/uploader with delete and “paste URL” support. |
| src/frontend/platform/src/pages/SystemPage/index.tsx | Renames the System tab label to “Appearance” (i18n key change). |
| src/frontend/platform/src/pages/LoginPage/resetPwd.tsx | Uses brand-configured header logo on reset password page. |
| src/frontend/platform/src/pages/LoginPage/login.tsx | Uses brand-configured login hero and header logos on login page. |
| src/frontend/platform/src/layout/MainLayout.tsx | Uses brand-configured header logos in the platform layout header. |
| src/frontend/platform/src/i18n.js | Adjusts defaultVariables and removes reliance on removed full-name fields. |
| src/frontend/platform/src/controllers/API/index.ts | Adds brand config + brand asset API client types and functions. |
| src/frontend/platform/src/components/bs-icons/loading/index.tsx | Loads custom loading icon via new helper instead of direct global access. |
| src/frontend/platform/public/locales/zh-Hans/bs.json | Adds brand customization UI strings and “appearanceSettings” label. |
| src/frontend/platform/public/locales/ja/bs.json | Adds brand customization UI strings and “appearanceSettings” label. |
| src/frontend/platform/public/locales/en-US/bs.json | Adds brand customization UI strings and “appearanceSettings” label. |
| src/frontend/platform/public/assets/bisheng/config.js | Updates default BRAND_CONFIG schema (removes full-name fields, adds URLLoadingIcon). |
| src/frontend/platform/index.html | Loads /api/v1/brand/runtime.js and updates initial title selection logic. |
| src/frontend/client/vite.config.ts | Injects baseUrl into client HTML template. |
| src/frontend/client/src/vite-env.d.ts | Extends window.BRAND_CONFIG typing for new brand fields/assets/loading config. |
| src/frontend/client/src/pages/Subscription/Sidebar/ChannelSidebar.tsx | Adjusts mobile sidebar header logo URL handling. |
| src/frontend/client/src/pages/knowledge/sidebar/KnowledgeSpaceSidebar.tsx | Adjusts mobile sidebar header logo URL handling. |
| src/frontend/client/src/locales/i18n.ts | Adjusts defaultVariables and removes reliance on removed full-name fields. |
| src/frontend/client/src/layouts/MainLayout.tsx | Merges workstation config from query hook into existing config state. |
| src/frontend/client/src/hooks/queries/endpoints/queries.ts | Adds URL normalization helper and updates favicon URL handling + refetch behavior. |
| src/frontend/client/src/components/Nav/NewChat.tsx | Adjusts mobile header logo URL handling. |
| src/frontend/client/public/assets/bisheng/config.js | Updates default BRAND_CONFIG schema (removes full-name fields, adds URLLoadingIcon). |
| src/frontend/client/index.html | Loads brand config + runtime JS using injected baseUrl, updates initial title logic. |
| src/backend/bisheng/brand/domain/services/brand_service.py | Implements brand config persistence, MinIO asset management, and runtime JS generation. |
| src/backend/bisheng/brand/domain/services/init.py | Brand services package marker. |
| src/backend/bisheng/brand/domain/schemas/brand_schema.py | Pydantic schemas for brand config/assets/loading and update payloads. |
| src/backend/bisheng/brand/domain/schemas/init.py | Brand schemas package marker. |
| src/backend/bisheng/brand/domain/repositories/brand_config_repository.py | Repository adapter for storing brand config in ConfigDao. |
| src/backend/bisheng/brand/domain/repositories/init.py | Brand repositories package marker. |
| src/backend/bisheng/brand/domain/init.py | Brand domain package marker. |
| src/backend/bisheng/brand/api/router.py | Aggregates brand endpoints under /brand. |
| src/backend/bisheng/brand/api/endpoints/brand.py | Adds brand config CRUD, asset options/upload/delete, and public runtime JS endpoint. |
| src/backend/bisheng/brand/api/endpoints/init.py | Brand endpoints package marker. |
| src/backend/bisheng/brand/api/init.py | Brand API package marker. |
| src/backend/bisheng/brand/init.py | Brand module package marker. |
| src/backend/bisheng/api/router.py | Registers the brand router into the main API router. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+8
to
+16
| const ABSOLUTE_URL_PATTERN = /^(https?:|data:|blob:)/i; | ||
|
|
||
| export function withBrandBaseUrl(url = "") { | ||
| if (!url) return ""; | ||
| if (ABSOLUTE_URL_PATTERN.test(url)) return url; | ||
| const baseUrl = (__APP_ENV__.BASE_URL || "").replace(/\/$/, ""); | ||
| const normalizedUrl = url.startsWith("/") ? url : `/${url}`; | ||
| return `${baseUrl}${normalizedUrl}`; | ||
| } |
Comment on lines
+35
to
+37
| const getLocalizedText = (text?: { zh?: string; en?: string }) => ( | ||
| text?.zh || text?.en || "" | ||
| ); |
Comment on lines
160
to
162
| <MobileSidebarHeaderTabs | ||
| logoSrc={bsConfig?.sidebarIcon?.image} | ||
| logoSrc={bsConfig?.sidebarIcon?.image ? __APP_ENV__.BASE_URL + bsConfig.sidebarIcon.image : undefined} | ||
| onClose={onDrawerClose} |
Comment on lines
210
to
214
| {mobileDrawerMode ? ( | ||
| <MobileSidebarHeaderTabs | ||
| logoSrc={bsConfig?.sidebarIcon?.image} | ||
| logoSrc={bsConfig?.sidebarIcon?.image ? __APP_ENV__.BASE_URL + bsConfig.sidebarIcon.image : undefined} | ||
| onClose={onDrawerClose} | ||
| onLinkClick={(link) => { |
Comment on lines
110
to
113
| {isSmallScreen ? ( | ||
| <MobileSidebarHeaderTabs | ||
| logoSrc={bsConfig?.sidebarIcon?.image} | ||
| logoSrc={bsConfig?.sidebarIcon?.image ? __APP_ENV__.BASE_URL + bsConfig.sidebarIcon.image : undefined} | ||
| onClose={toggleNav} |
Comment on lines
+17
to
+34
| @router.get('/config') | ||
| async def get_brand_config( | ||
| admin_user: UserPayload = Depends(UserPayload.get_admin_user), | ||
| service: BrandService = Depends(get_brand_service), | ||
| ): | ||
| config = await service.get_config() | ||
| return resp_200(config.model_dump(mode='json')) | ||
|
|
||
|
|
||
| @router.put('/config') | ||
| async def update_brand_config( | ||
| data: BrandConfigUpdate, | ||
| admin_user: UserPayload = Depends(UserPayload.get_admin_user), | ||
| service: BrandService = Depends(get_brand_service), | ||
| ): | ||
| config = await service.save_config(data) | ||
| return resp_200(config.model_dump(mode='json')) | ||
|
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.