Skip to content

Fix/footer layout theme sync ux - #2956

Closed
chasebank2017 wants to merge 10 commits into
QuantumNous:mainfrom
chasebank2017:fix/footer-layout-theme-sync-ux
Closed

Fix/footer layout theme sync ux#2956
chasebank2017 wants to merge 10 commits into
QuantumNous:mainfrom
chasebank2017:fix/footer-layout-theme-sync-ux

Conversation

@chasebank2017

@chasebank2017 chasebank2017 commented Feb 16, 2026

Copy link
Copy Markdown

Summary by CodeRabbit

  • New Features

    • Rebranded system to OpenClaw API with updated logo and visual identity
    • Added comprehensive deployment guides and documentation
  • Improvements

    • Enhanced header design with fixed positioning and improved navigation
    • Simplified menu structure with streamlined navigation links
    • Updated footer with consistent branding and relevant links
    • Refined color scheme and theme consistency across light and dark modes
    • Improved overall visual design and layout responsiveness

Chase and others added 10 commits February 8, 2026 13:07
- 统一语言状态: 修复 PageLayout 遗留 i18nextLng 引用为 locale
- 统一图标库: UserArea 使用 Lucide React 替换 Semi UI 图标
- 全局页脚: 移除 shouldHideFooter 逻辑,所有页面显示统一页脚
- Sync language and dark/light theme between openclawapi.ai and api.openclawapi.ai via shared cookies
- Align backend footer/header behavior and copy with frontend, removing visible "console" wording in favor of api.openclawapi.ai

Co-authored-by: Cursor <cursoragent@cursor.com>
- 移除所有console.log/console.error/console.warn语句(214行,63个文件)
- 确认语言和主题已通过cookie(oc_locale/oc_theme)在前后端同步
- 确认footer样式正确:h4标题使用白色,li子项使用红色/brand颜色
- footer定位已正确实现(滚动到底部才显示)
fix: 清理后端console语句,确认语言/主题同步和footer样式
- Footer: remove broken IntersectionObserver; show compact copyright bar
  on console pages, full multi-column footer on non-console pages
- PageLayout: move footer outside Content for proper sticky-bottom;
  add mobile sidebar backdrop overlay (click to close)
- LanguageSelector: show target language name (match frontend behavior)
- UserArea: replace hardcoded dark: Tailwind classes with Semi UI CSS
  variables for correct dark/light mode rendering
- User context: set/clear oc_logged_in cookie on login/logout so the
  frontend (openclawapi.ai) can detect auth state cross-domain
@coderabbitai

coderabbitai Bot commented Feb 16, 2026

Copy link
Copy Markdown
Contributor

Walkthrough

The pull request implements a comprehensive rebranding from "New API" to "OpenClaw API," introducing deployment automation via GitHub Actions, updating branding assets and color constants, refactoring frontend layout and styling with simplified empty-state placeholders and semantic color tokens, expanding i18n with footer content, adding cookie-based persistence for theme and locale, and systematically removing console logging statements throughout the frontend for cleaner production behavior.

Changes

Cohort / File(s) Summary
Deployment Automation
.github/workflows/deploy.yml, makefile, scripts/deploy-remote.sh, docker-compose.yml
Introduces GitHub Actions workflow for building and pushing Docker images to Docker Hub, adds Makefile targets (deploy, push-only, update-remote) with remote deployment variables, and implements SSH-based remote deployment script for pulling images and restarting services.
Branding & Constants
common/constants.go, web/index.html, Dockerfile, web/src/helpers/utils.jsx
Updates system name from "New API" to "OpenClaw API", replaces favicon/theme colors, adds NODE_OPTIONS memory limit for builds, updates default logo from PNG to SVG, and adjusts branding-related utility defaults.
Documentation
docs/BACKEND-FRONTEND-ALIGNMENT.md, docs/DEPLOY-VIA-DOCKERHUB.md, docs/OPENCLAW_DEPLOY.md
Adds comprehensive guides for frontend-backend alignment, Docker Hub deployment procedures, and OpenClaw API customization deployment with branding and styling instructions.
Layout & Navigation
web/src/App.jsx, web/src/components/layout/PageLayout.jsx, web/src/components/layout/SiderBar.jsx, router/web-router.go
Restructures routing with redirect from root to console, removes home/about routes, updates sidebar navigation to reflect new content structure, and adds explicit root path handling in web router.
Header & Footer Components
web/src/components/layout/Footer.jsx, web/src/components/layout/headerbar/index.jsx, web/src/components/layout/headerbar/HeaderLogo.jsx, web/src/components/layout/headerbar/ActionButtons.jsx
Redesigns footer with branding-consistent sections, restructures header with fixed positioning and centered container, updates logo linking and styling, and replaces license headers with module descriptions.
Navigation Controls
web/src/components/layout/headerbar/LanguageSelector.jsx, web/src/components/layout/headerbar/ThemeToggle.jsx, web/src/components/layout/headerbar/UserArea.jsx
Simplifies language selector to single-button toggle between zh/en, converts theme toggle from dropdown to dark/light button, and updates user area icons from semi-icons to lucide-react equivalents.
Theme & Storage Management
web/src/context/Theme/index.jsx, web/src/context/User/index.jsx, web/src/helpers/cookie.js
Removes auto/system theme option in favor of dark/light toggle, adds cookie-based theme persistence, implements login state cookie synchronization, and introduces new cookie helper utilities for domain-shared cookies.
i18n Localization
web/src/i18n/i18n.js, web/src/i18n/locales/en.json, web/src/i18n/locales/zh.json, web/src/i18n/locales/fr.json, web/src/i18n/locales/ja.json, web/src/i18n/locales/ru.json, web/src/i18n/locales/vi.json
Restricts supported languages to zh/en in i18n config, updates all locale files with OpenClaw branding, replaces "模型广场" with "模型商店", adds footer translation structure, and updates documentation URLs to openclawapi.ai domain.
Global Styling & Theming
web/src/index.css, web/src/index.jsx
Introduces comprehensive brand theming with CSS variables for colors/tokens, updates typography/layout defaults, adds brand-specific styling for cards/buttons/tables/navigation, implements dark/light mode adjustments, and updates welcome console log message.
UI Component Updates
web/src/components/layout/CrabLogo.jsx, web/src/components/common/DocumentRenderer/index.jsx, web/src/components/dashboard/DashboardHeader.jsx, web/src/components/topup/RechargeCard.jsx, web/src/components/topup/InvitationCard.jsx
Adds new CrabLogo SVG component, replaces illustration-based empty states with Empty.PRESENTED_IMAGE_SIMPLE across 40+ components, updates color styling to use CSS variables (primary, accent), removes gradient backgrounds in favor of solid colors with borders.
Empty State Standardization
web/src/components/dashboard/AnnouncementsPanel.jsx, web/src/components/dashboard/FaqPanel.jsx, web/src/components/dashboard/UptimePanel.jsx, web/src/components/table/channels/ChannelsTable.jsx, web/src/components/table/models/ModelsTable.jsx, web/src/components/table/tokens/TokensTable.jsx, web/src/components/table/*.../
Removes imports of IllustrationConstruction, IllustrationNoResult, IllustrationNoContent, and dark-mode variants from semi-illustrations; replaces all with Empty.PRESENTED_IMAGE_SIMPLE across ~35 table and panel components.
Authentication & Forms
web/src/components/auth/LoginForm.jsx, web/src/components/auth/RegisterForm.jsx, web/src/components/auth/PasswordResetForm.jsx, web/src/components/auth/PasswordResetConfirm.jsx
Updates link styling from blue text colors to semi-color-primary with hover opacity effects across login, register, and password reset flows.
Settings & Admin Pages
web/src/pages/Setting/Operation/SettingsGeneral.jsx, web/src/pages/Setting/Operation/SettingsHeaderNavModules.jsx, web/src/pages/Setting/Dashboard/*.jsx, web/src/pages/Setting/Model/*.jsx, web/src/pages/Setting/Ratio/*.jsx
Removes docs_link and home/about module configurations, simplifies header nav modules to console/pricing only, replaces console logging in error handlers with silent failures, and removes illustration-based empty states in settings tables.
Public Pages
web/src/pages/Home/index.jsx, web/src/pages/About/index.jsx, web/src/pages/Docs/index.jsx, web/src/pages/NotFound/index.jsx, web/src/pages/Forbidden/index.jsx
Adds new Docs page with documentation links, updates About page with OpenClaw branding and removes New API references, simplifies error page layouts from full-screen to min-height, replaces illustrated empty states with standard placeholders.
API & Playground Components
web/src/components/playground/CodeViewer.jsx, web/src/components/playground/CustomInputRender.jsx, web/src/components/playground/SSEViewer.jsx, web/src/components/playground/configStorage.js, web/src/pages/Playground/index.jsx
Removes console logging from SSE/API error handlers, clipboard operations, and config storage functions; maintains error handling via Toast notifications.
Hooks & Utilities
web/src/hooks/common/useHeaderBar.js, web/src/hooks/common/useNavigation.js, web/src/hooks/common/useUserPermissions.js, web/src/helpers/api.js, web/src/helpers/log.js, web/src/helpers/token.js, web/src/helpers/render.jsx
Updates useHeaderBar to persist locale via cookie, refactors useNavigation to remove home/about/docs links and simplify to internal/external links with memoization, removes console logging across utility functions and hooks, suppresses OAuth error logs.
Console Logging Cleanup
web/src/components/common/markdown/MarkdownRenderer.jsx, web/src/components/common/ui/ChannelKeyDisplay.jsx, web/src/components/common/ui/JSONEditor.jsx, web/src/components/table/tokens/index.jsx, web/src/contexts/PlaygroundContext.jsx, web/src/services/secureVerification.js
Systematically removes console.error, console.log, and console.warn statements from error handlers, parsing paths, event handlers, and debug code across 60+ files without altering control flow or error handling behavior.
Build Configuration
web/vite.config.js
Disables sourcemap generation in Vite build output for production deployments.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

Suggested reviewers

  • Calcium-Ion
  • seefs001
  • creamlike1024

Poem

🐰 A rabbit hops through rebranded land,
From blue to claws, a fresh new brand!
Old logs are silent, colors bright,
The API gleams in day and night.
No illustration tales remain,
Just clean, bold lines—a brand refined! 🦀

🚥 Pre-merge checks | ✅ 2 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Merge Conflict Detection ⚠️ Warning ❌ Merge conflicts detected (184 files):

⚔️ Dockerfile (content)
⚔️ README.fr.md (content)
⚔️ README.ja.md (content)
⚔️ README.md (content)
⚔️ common/body_storage.go (content)
⚔️ common/constants.go (content)
⚔️ common/endpoint_type.go (content)
⚔️ common/gin.go (content)
⚔️ controller/channel-test.go (content)
⚔️ controller/model_sync.go (content)
⚔️ controller/pricing.go (content)
⚔️ controller/ratio_sync.go (content)
⚔️ controller/relay.go (content)
⚔️ docker-compose.yml (content)
⚔️ dto/ratio_sync.go (content)
⚔️ i18n/i18n.go (content)
⚔️ i18n/keys.go (content)
⚔️ i18n/locales/en.yaml (content)
⚔️ makefile (content)
⚔️ middleware/auth.go (content)
⚔️ middleware/cache.go (content)
⚔️ middleware/distributor.go (content)
⚔️ model/model_meta.go (content)
⚔️ model/pricing.go (content)
⚔️ model/task.go (content)
⚔️ model/token.go (content)
⚔️ relay/channel/api_request.go (content)
⚔️ relay/channel/aws/relay-aws.go (content)
⚔️ relay/channel/gemini/relay-gemini.go (content)
⚔️ relay/channel/task/sora/adaptor.go (content)
⚔️ relay/channel/xai/adaptor.go (content)
⚔️ relay/channel/xai/constants.go (content)
⚔️ relay/channel/xai/text.go (content)
⚔️ relay/claude_handler.go (content)
⚔️ relay/common/relay_info.go (content)
⚔️ relay/compatible_handler.go (content)
⚔️ relay/gemini_handler.go (content)
⚔️ relay/image_handler.go (content)
⚔️ relay/rerank_handler.go (content)
⚔️ relay/responses_handler.go (content)
⚔️ router/web-router.go (content)
⚔️ service/channel_affinity.go (content)
⚔️ service/error.go (content)
⚔️ web/bun.lock (content)
⚔️ web/index.html (content)
⚔️ web/package.json (content)
⚔️ web/src/App.jsx (content)
⚔️ web/src/components/auth/LoginForm.jsx (content)
⚔️ web/src/components/auth/PasswordResetConfirm.jsx (content)
⚔️ web/src/components/auth/PasswordResetForm.jsx (content)
⚔️ web/src/components/auth/RegisterForm.jsx (content)
⚔️ web/src/components/common/DocumentRenderer/index.jsx (content)
⚔️ web/src/components/common/markdown/MarkdownRenderer.jsx (content)
⚔️ web/src/components/common/ui/ChannelKeyDisplay.jsx (content)
⚔️ web/src/components/common/ui/JSONEditor.jsx (content)
⚔️ web/src/components/dashboard/AnnouncementsPanel.jsx (content)
⚔️ web/src/components/dashboard/ApiInfoPanel.jsx (content)
⚔️ web/src/components/dashboard/DashboardHeader.jsx (content)
⚔️ web/src/components/dashboard/FaqPanel.jsx (content)
⚔️ web/src/components/dashboard/UptimePanel.jsx (content)
⚔️ web/src/components/layout/Footer.jsx (content)
⚔️ web/src/components/layout/NoticeModal.jsx (content)
⚔️ web/src/components/layout/PageLayout.jsx (content)
⚔️ web/src/components/layout/SiderBar.jsx (content)
⚔️ web/src/components/layout/headerbar/ActionButtons.jsx (content)
⚔️ web/src/components/layout/headerbar/HeaderLogo.jsx (content)
⚔️ web/src/components/layout/headerbar/LanguageSelector.jsx (content)
⚔️ web/src/components/layout/headerbar/ThemeToggle.jsx (content)
⚔️ web/src/components/layout/headerbar/UserArea.jsx (content)
⚔️ web/src/components/layout/headerbar/index.jsx (content)
⚔️ web/src/components/playground/CodeViewer.jsx (content)
⚔️ web/src/components/playground/CustomInputRender.jsx (content)
⚔️ web/src/components/playground/SSEViewer.jsx (content)
⚔️ web/src/components/playground/configStorage.js (content)
⚔️ web/src/components/settings/ChannelSelectorModal.jsx (content)
⚔️ web/src/components/settings/DashboardSetting.jsx (content)
⚔️ web/src/components/settings/ModelDeploymentSetting.jsx (content)
⚔️ web/src/components/settings/ModelSetting.jsx (content)
⚔️ web/src/components/settings/OtherSetting.jsx (content)
⚔️ web/src/components/settings/PaymentSetting.jsx (content)
⚔️ web/src/components/settings/PersonalSetting.jsx (content)
⚔️ web/src/components/settings/SystemSetting.jsx (content)
⚔️ web/src/components/settings/personal/cards/CheckinCalendar.jsx (content)
⚔️ web/src/components/settings/personal/cards/NotificationSettings.jsx (content)
⚔️ web/src/components/settings/personal/cards/PreferencesSettings.jsx (content)
⚔️ web/src/components/settings/personal/components/UserInfoHeader.jsx (content)
⚔️ web/src/components/setup/SetupWizard.jsx (content)
⚔️ web/src/components/table/channels/ChannelsActions.jsx (content)
⚔️ web/src/components/table/channels/ChannelsTable.jsx (content)
⚔️ web/src/components/table/channels/modals/CodexOAuthModal.jsx (content)
⚔️ web/src/components/table/channels/modals/EditChannelModal.jsx (content)
⚔️ web/src/components/table/channels/modals/ModelSelectModal.jsx (content)
⚔️ web/src/components/table/channels/modals/MultiKeyManageModal.jsx (content)
⚔️ web/src/components/table/channels/modals/OllamaModelModal.jsx (content)
⚔️ web/src/components/table/channels/modals/SingleModelSelectModal.jsx (content)
⚔️ web/src/components/table/mj-logs/MjLogsTable.jsx (content)
⚔️ web/src/components/table/model-deployments/DeploymentsTable.jsx (content)
⚔️ web/src/components/table/model-deployments/modals/CreateDeploymentModal.jsx (content)
⚔️ web/src/components/table/model-deployments/modals/EditDeploymentModal.jsx (content)
⚔️ web/src/components/table/model-pricing/layout/header/PricingVendorIntro.jsx (content)
⚔️ web/src/components/table/model-pricing/layout/header/PricingVendorIntroSkeleton.jsx (content)
⚔️ web/src/components/table/model-pricing/modal/components/ModelPricingTable.jsx (content)
⚔️ web/src/components/table/model-pricing/view/card/PricingCardView.jsx (content)
⚔️ web/src/components/table/model-pricing/view/table/PricingTable.jsx (content)
⚔️ web/src/components/table/models/ModelsTable.jsx (content)
⚔️ web/src/components/table/models/modals/EditModelModal.jsx (content)
⚔️ web/src/components/table/models/modals/MissingModelsModal.jsx (content)
⚔️ web/src/components/table/models/modals/PrefillGroupManagement.jsx (content)
⚔️ web/src/components/table/models/modals/SyncWizardModal.jsx (content)
⚔️ web/src/components/table/redemptions/RedemptionsTable.jsx (content)
⚔️ web/src/components/table/subscriptions/SubscriptionsTable.jsx (content)
⚔️ web/src/components/table/task-logs/TaskLogsColumnDefs.jsx (content)
⚔️ web/src/components/table/task-logs/TaskLogsTable.jsx (content)
⚔️ web/src/components/table/task-logs/index.jsx (content)
⚔️ web/src/components/table/tokens/TokensFilters.jsx (content)
⚔️ web/src/components/table/tokens/TokensTable.jsx (content)
⚔️ web/src/components/table/tokens/index.jsx (content)
⚔️ web/src/components/table/usage-logs/UsageLogsColumnDefs.jsx (content)
⚔️ web/src/components/table/usage-logs/UsageLogsTable.jsx (content)
⚔️ web/src/components/table/users/UsersTable.jsx (content)
⚔️ web/src/components/table/users/modals/EditUserModal.jsx (content)
⚔️ web/src/components/table/users/modals/UserSubscriptionsModal.jsx (content)
⚔️ web/src/components/topup/InvitationCard.jsx (content)
⚔️ web/src/components/topup/RechargeCard.jsx (content)
⚔️ web/src/components/topup/SubscriptionPlansCard.jsx (content)
⚔️ web/src/components/topup/index.jsx (content)
⚔️ web/src/components/topup/modals/SubscriptionPurchaseModal.jsx (content)
⚔️ web/src/components/topup/modals/TopupHistoryModal.jsx (content)
⚔️ web/src/context/Theme/index.jsx (content)
⚔️ web/src/context/User/index.jsx (content)
⚔️ web/src/contexts/PlaygroundContext.jsx (content)
⚔️ web/src/helpers/api.js (content)
⚔️ web/src/helpers/dashboard.jsx (content)
⚔️ web/src/helpers/index.js (content)
⚔️ web/src/helpers/log.js (content)
⚔️ web/src/helpers/render.jsx (content)
⚔️ web/src/helpers/token.js (content)
⚔️ web/src/helpers/utils.jsx (content)
⚔️ web/src/hooks/channels/useChannelsData.jsx (content)
⚔️ web/src/hooks/common/useHeaderBar.js (content)
⚔️ web/src/hooks/common/useNavigation.js (content)
⚔️ web/src/hooks/common/useUserPermissions.js (content)
⚔️ web/src/hooks/dashboard/useDashboardData.js (content)
⚔️ web/src/hooks/mj-logs/useMjLogsData.js (content)
⚔️ web/src/hooks/model-deployments/useDeploymentsData.jsx (content)
⚔️ web/src/hooks/model-deployments/useModelDeploymentSettings.js (content)
⚔️ web/src/hooks/models/useModelsData.jsx (content)
⚔️ web/src/hooks/playground/useApiRequest.jsx (content)
⚔️ web/src/hooks/playground/useMessageActions.jsx (content)
⚔️ web/src/hooks/playground/useSyncMessageAndCustomBody.js (content)
⚔️ web/src/hooks/task-logs/useTaskLogsData.js (content)
⚔️ web/src/hooks/tokens/useTokensData.jsx (content)
⚔️ web/src/hooks/usage-logs/useUsageLogsData.jsx (content)
⚔️ web/src/i18n/i18n.js (content)
⚔️ web/src/i18n/locales/en.json (content)
⚔️ web/src/i18n/locales/fr.json (content)
⚔️ web/src/i18n/locales/ja.json (content)
⚔️ web/src/i18n/locales/ru.json (content)
⚔️ web/src/i18n/locales/vi.json (content)
⚔️ web/src/index.css (content)
⚔️ web/src/index.jsx (content)
⚔️ web/src/pages/About/index.jsx (content)
⚔️ web/src/pages/Forbidden/index.jsx (content)
⚔️ web/src/pages/Home/index.jsx (content)
⚔️ web/src/pages/NotFound/index.jsx (content)
⚔️ web/src/pages/Playground/index.jsx (content)
⚔️ web/src/pages/Setting/Chat/SettingsChats.jsx (content)
⚔️ web/src/pages/Setting/Dashboard/SettingsAPIInfo.jsx (content)
⚔️ web/src/pages/Setting/Dashboard/SettingsAnnouncements.jsx (content)
⚔️ web/src/pages/Setting/Dashboard/SettingsFAQ.jsx (content)
⚔️ web/src/pages/Setting/Dashboard/SettingsUptimeKuma.jsx (content)
⚔️ web/src/pages/Setting/Model/SettingGeminiModel.jsx (content)
⚔️ web/src/pages/Setting/Model/SettingGrokModel.jsx (content)
⚔️ web/src/pages/Setting/Model/SettingModelDeployment.jsx (content)
⚔️ web/src/pages/Setting/Operation/SettingsGeneral.jsx (content)
⚔️ web/src/pages/Setting/Operation/SettingsHeaderNavModules.jsx (content)
⚔️ web/src/pages/Setting/Performance/SettingsPerformance.jsx (content)
⚔️ web/src/pages/Setting/Ratio/GroupRatioSettings.jsx (content)
⚔️ web/src/pages/Setting/Ratio/ModelRatioSettings.jsx (content)
⚔️ web/src/pages/Setting/Ratio/ModelRationNotSetEditor.jsx (content)
⚔️ web/src/pages/Setting/Ratio/ModelSettingsVisualEditor.jsx (content)
⚔️ web/src/pages/Setting/Ratio/UpstreamRatioSync.jsx (content)
⚔️ web/src/services/secureVerification.js (content)
⚔️ web/vite.config.js (content)

These conflicts must be resolved before merging into main.
Resolve conflicts locally and push changes to this branch.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Fix/footer layout theme sync ux' is a broad summary that relates to multiple significant changes in the PR, including footer restructuring, theme synchronization, and UX improvements across layout components.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
⚔️ Resolve merge conflicts (beta)
  • Auto-commit resolved conflicts to branch fix/footer-layout-theme-sync-ux
  • Post resolved changes as copyable diffs in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

Note

Due to the large number of review comments, Critical severity comments were prioritized as inline comments.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (13)
web/src/components/topup/InvitationCard.jsx (1)

64-168: ⚠️ Potential issue | 🟠 Major

White text on a light background — stats section will be unreadable in light mode.

The cover background was changed from a (presumably dark) gradient to var(--semi-color-bg-1), which is a light color in light theme. However, the three stat values (lines 98, 123, 148) still use style={{ color: 'white' }} and their labels (lines 107, 110, 130, 134, 153, 158) use rgba(255,255,255,0.8). This makes the "待使用收益", "总收益", "邀请人数" figures and labels invisible against the new light background.

Update these to use semantic tokens (e.g., var(--semi-color-text-0) for values and var(--semi-color-text-2) for labels) to match the header text treatment on line 73.

Proposed fix (representative — apply same pattern to all three stat blocks)
                    <div
                      className='text-base sm:text-2xl font-bold mb-2'
-                     style={{ color: 'white' }}
+                     style={{ color: 'var(--semi-color-text-0)' }}
                    >
-                       style={{ color: 'rgba(255,255,255,0.8)' }}
+                       style={{ color: 'var(--semi-color-text-2)' }}
web/src/pages/Setting/Performance/SettingsPerformance.jsx (1)

125-126: ⚠️ Potential issue | 🟡 Minor

Silent error swallowing in fetchStats.

Removing console.error leaves a completely empty catch block — network or server errors when fetching performance stats will be invisible to both users and developers debugging in the browser. Consider at minimum keeping a lightweight log or calling showError.

🛠️ Suggested minimal fix
     } catch (error) {
+      // stats fetch is non-critical; log for debugging
+      console.warn('Failed to fetch performance stats', error);
     } finally {
web/src/components/settings/OtherSetting.jsx (1)

494-494: ⚠️ Potential issue | 🟠 Major

XSS risk with dangerouslySetInnerHTML on external content.

marked.parse(body) on the GitHub API response is rendered unsanitized. While this is an admin-only update check, a compromised or spoofed response could inject scripts. Consider sanitizing with a library like DOMPurify before rendering.

Proposed fix
+import DOMPurify from 'dompurify';

Then at Line 259:

-          content: marked.parse(body),
+          content: DOMPurify.sanitize(marked.parse(body)),
web/src/components/table/model-pricing/layout/header/PricingVendorIntroSkeleton.jsx (1)

134-142: ⚠️ Potential issue | 🟡 Minor

Hardcoded rgba(255, 255, 255, 0.15) may be invisible on light backgrounds.

The second description skeleton (desc2) overrides backgroundColor with rgba(255, 255, 255, 0.15). Previously this worked against a colored/dark cover, but the cover now uses var(--semi-color-bg-1), which is typically a light color in light mode. A nearly-white skeleton on a white background would be invisible.

Consider using a CSS variable consistent with the other skeleton elements:

Proposed fix
                  {createSkeletonRect(
                    {
                      ...SKELETON_STYLES.description,
-                     backgroundColor: 'rgba(255, 255, 255, 0.15)',
+                     backgroundColor: 'var(--semi-color-fill-0)',
                      width: '75%',
                      height: SIZES.description.height,
                    },
                    'desc2',
                  )}
web/src/helpers/utils.jsx (3)

18-30: ⚠️ Potential issue | 🟠 Major

JSON.parse without try/catch will crash on corrupted localStorage.

Both isAdmin() and isRoot() call JSON.parse(user) without a try/catch. If the user key in localStorage contains malformed JSON (e.g., from a different version or manual tampering), these functions will throw an unhandled exception, potentially breaking any component that calls them.

Proposed fix
 export function isAdmin() {
   let user = localStorage.getItem('user');
   if (!user) return false;
-  user = JSON.parse(user);
-  return user.role >= 10;
+  try {
+    user = JSON.parse(user);
+    return user.role >= 10;
+  } catch {
+    return false;
+  }
 }
 
 export function isRoot() {
   let user = localStorage.getItem('user');
   if (!user) return false;
-  user = JSON.parse(user);
-  return user.role >= 100;
+  try {
+    user = JSON.parse(user);
+    return user.role >= 100;
+  } catch {
+    return false;
+  }
 }

44-49: ⚠️ Potential issue | 🟠 Major

Same JSON.parse crash risk in getUserIdFromLocalStorage.

Same issue as isAdmin/isRoot — wrap in try/catch and return the fallback -1 on parse failure.


14-16: ⚠️ Potential issue | 🟠 Major

dangerouslySetInnerHTML in toast content — XSS vector.

HTMLToastContent renders arbitrary HTML. If the htmlContent originates from an untrusted or insufficiently sanitized source, this is a stored XSS risk. Consider sanitizing with a library like DOMPurify before rendering.

web/src/index.jsx (1)

38-43: ⚠️ Potential issue | 🔴 Critical

Syntax error: missing console.log( — this will crash on load.

The console.log( call appears to have been removed when the string argument was modified. The current code is a bare string expression followed by );, which is a syntax error.

Proposed fix
 if (typeof window !== 'undefined') {
+  console.log(
     '%cOpenClaw API%c https://openclawapi.ai',
     'color: `#10b981`; font-weight: bold; font-size: 24px;',
     'color: inherit; font-size: 14px;',
   );
 }
web/src/pages/Home/index.jsx (1)

226-239: ⚠️ Potential issue | 🟡 Minor

IconGithubLogo used for a non-GitHub docs link — misleading.

The button now navigates to https://openclawapi.ai/docs but still uses IconGithubLogo as its icon. Users will expect a GitHub icon to lead to a GitHub page. Consider using IconFile or another docs-appropriate icon instead.

web/src/components/settings/personal/cards/PreferencesSettings.jsx (1)

101-111: ⚠️ Potential issue | 🟡 Minor

Cookie and localStorage are not reverted on backend save failure.

When the backend save fails (lines 101–111), currentLanguage and i18n are reverted to previousLang, but the localStorage('locale') and setCookie('oc_locale', lang) writes from lines 72–73 are not undone. On next page load, the stale cookie/localStorage value may override the user's actual preference.

Proposed fix
       } else {
         showError(res.data.message || t('保存失败'));
         // Revert on error
         setCurrentLanguage(previousLang);
         i18n.changeLanguage(previousLang);
+        try {
+          localStorage.setItem('locale', previousLang);
+          setCookie('oc_locale', previousLang);
+        } catch (e) {
+          // ignore
+        }
       }
     } catch (error) {
       showError(t('保存失败,请重试'));
       // Revert on error
       setCurrentLanguage(previousLang);
       i18n.changeLanguage(previousLang);
+      try {
+        localStorage.setItem('locale', previousLang);
+        setCookie('oc_locale', previousLang);
+      } catch (e) {
+        // ignore
+      }
     } finally {
web/src/i18n/locales/fr.json (1)

1-2724: ⚠️ Potential issue | 🟡 Minor

This file is now unused — i18n.js only loads zh and en resources.

The updated web/src/i18n/i18n.js restricts supportedLngs to ['zh', 'en'] and only imports en.json and zh.json. French translations in this file will never be loaded at runtime. Either remove fr.json (and other dropped locale files) to avoid maintenance burden, or re-add French to the i18n configuration if it should remain supported.

web/src/i18n/locales/en.json (1)

2763-2802: ⚠️ Potential issue | 🟠 Major

Remove duplicated disk-cache/perf-monitor keys to avoid overrides.
Biome reports this block as duplicate keys; JSON keeps only the last occurrence, so earlier translations are ignored and lint fails. Please dedupe and keep a single block.

web/src/i18n/locales/zh.json (1)

2775-2784: ⚠️ Potential issue | 🟠 Major

Remove duplicate translation keys (“自动检测”, “确认解绑”).
Biome flags these as duplicates; the last entry wins, and earlier values are ignored. Please keep a single definition for each key.

🤖 Fix all issues with AI agents
In `@docs/BACKEND-FRONTEND-ALIGNMENT.md`:
- Around line 45-48: The documentation currently instructs replacing the
QuantumNous/AGPL copyright header with a short "OpenClaw API" note (the line
containing "将 QuantumNous/AGPL 版权头替换为简短「OpenClaw API」说明"), which violates the
project's rule to preserve all 'new-api' and 'QuantumNous' attributions; revert
or remove that sentence and update the section "注释与品牌" to explicitly state that
license headers and copyright notices for 'new-api' and 'QuantumNous' must be
retained unchanged, referencing the project's rules in .cursor/rules/project.mdc
and CLAUDE.md for wording consistency.

In `@scripts/deploy-remote.sh`:
- Around line 6-8: The current defaults hardcode a production server IP and
Docker image; replace these silent fallbacks by requiring the env vars and
failing fast: change the assignments for SERVER, COMPOSE_DIR and IMAGE to
enforce that DEPLOY_SERVER, DEPLOY_COMPOSE_DIR and DEPLOY_IMAGE must be set (use
shell parameter-expansion or explicit checks) and print a clear error and exit
non-zero if any are missing so the script cannot accidentally target a real
server.

In `@web/src/components/table/model-pricing/layout/header/PricingVendorIntro.jsx`:
- Around line 262-268: The title and description styles
(COMPONENT_STYLES.titleText and descriptionText) use hardcoded white, causing
white-on-white in light mode after createCoverStyle() switched to
var(--semi-color-bg-1); change those hardcoded colors to semantic CSS tokens
(e.g., var(--semi-color-text-0) for primary title and a slightly muted token
like var(--semi-color-text-2) or rgba token derived from semantic tokens for
description) so text contrasts with the new background, and update the same
hardcoded white usages later in the file (the other title/description blocks
around the 329-351 region) to the same semantic tokens.

In `@web/src/index.jsx`:
- Around line 36-42: The welcome message string was altered to "OpenClaw API"
contrary to the project's branding rules; revert the altered console/message
content in web/src/index.jsx back to the original NEWAPI / QuantumNous
attribution and URL, keeping the surrounding protective comment ("欢迎信息... Do not
remove...") intact; locate the conditional block that checks typeof window !==
'undefined' (the welcome message statements on lines near the current snippet)
and replace the changed literal/branding tokens with the original
NEWAPI/QuantumNous text so the exact required attribution and URL are restored.

In `@web/src/pages/Setting/Dashboard/SettingsAPIInfo.jsx`:
- Around line 419-423: The Empty component usage uses the non-existent static
Empty.PRESENTED_IMAGE_SIMPLE (AntD API); update the Empty in SettingsAPIInfo.jsx
to use Semi UI-compatible images by replacing
image={Empty.PRESENTED_IMAGE_SIMPLE} with either image={null} for a simple state
or import and pass a Semi illustration (from `@douyinfe/semi-illustrations`) as
image={MyIllustration}; ensure the change targets the Empty element and its
image prop so it renders correctly in Semi v2.69.1.
🟠 Major comments (17)
web/src/pages/Setting/Operation/SettingsGeneral.jsx-182-182 (1)

182-182: ⚠️ Potential issue | 🟠 Major

Complete the docs_link deprecation or restore the UI field.

The backend still actively supports docs_link—it's defined in GeneralSetting struct and returned via the API (controller/misc.go). The frontend still uses it in multiple places (header bar in useHeaderBar.js, home page in Home/index.jsx, and stored in localStorage). Removing only the UI form field from SettingsGeneral.jsx while leaving the backend and other frontend consumers intact creates an inconsistency.

Either: (1) complete the deprecation by removing DocsLink from the backend struct and API response, then remove all frontend usage, or (2) restore the UI field so admins can update the value. The hardcoded URL fallback in the comment is a good UX safeguard, but it doesn't resolve the underlying architectural mismatch.

web/src/components/common/DocumentRenderer/index.jsx-24-26 (1)

24-26: 🛠️ Refactor suggestion | 🟠 Major

Non-standard statement interleaved between imports.

const { Title } = Typography; (line 25) is sandwiched between import statements (lines 22–23 and 26). While bundlers hoist imports so this technically works at runtime, it violates the conventional (and spec-intended) ordering where all import declarations appear before other statements, making the code confusing to read.

♻️ Suggested fix
 import { Empty, Card, Spin, Typography } from '@douyinfe/semi-ui';
 import { useTranslation } from 'react-i18next';
-
-const { Title } = Typography;
 import MarkdownRenderer from '../markdown/MarkdownRenderer';
+
+const { Title } = Typography;
.github/workflows/deploy.yml-32-32 (1)

32-32: ⚠️ Potential issue | 🟠 Major

Hardcoded Docker Hub image tag — use a repository variable or secret.

chasebank2023/new-api:latest is hardcoded both here and in scripts/deploy-remote.sh. Extract to a workflow-level env variable or GitHub repository variable to avoid drift and make it configurable.

docs/DEPLOY-VIA-DOCKERHUB.md-42-44 (1)

42-44: ⚠️ Potential issue | 🟠 Major

Default credentials exposed in documentation.

The default MySQL password (openclawapi2024) and session secret (openclawapi-session-secret-change-me) are shown inline. While they use ${VAR:-default} syntax, readers often copy-paste verbatim. Add a prominent warning to change these values, or omit the defaults from the doc and reference a .env.example file instead.

.github/workflows/deploy.yml-8-45 (1)

8-45: ⚠️ Potential issue | 🟠 Major

No concurrency control — overlapping deploys possible.

Multiple pushes to main in quick succession can trigger parallel workflow runs, leading to race conditions during deployment. Add a concurrency group to cancel or queue.

Proposed fix: add concurrency at job or workflow level
 on:
   push:
     branches: [ main ]
   workflow_dispatch:
 
+concurrency:
+  group: deploy-production
+  cancel-in-progress: false
+
 jobs:
   build-and-deploy:
.github/workflows/deploy.yml-37-38 (1)

37-38: ⚠️ Potential issue | 🟠 Major

Hardcoded production IP and root SSH access.

The host IP (101.36.104.77) is hardcoded and SSH access runs as root. Store the host in a GitHub secret (e.g., secrets.DEPLOY_HOST) and use a non-root deploy user with minimal privileges.

Proposed fix
       - name: SSH Remote Deploy
         uses: appleboy/ssh-action@v1.0.3
         with:
-          host: 101.36.104.77
-          username: root
+          host: ${{ secrets.DEPLOY_HOST }}
+          username: ${{ secrets.DEPLOY_USER }}
           key: ${{ secrets.SSH_PRIVATE_KEY }}
makefile-1-4 (1)

1-4: ⚠️ Potential issue | 🟠 Major

Hardcoded production server IP and credentials in source control.

The Makefile contains a hardcoded public IP address (101.36.104.77), deployment path, and Docker image name. Committing infrastructure details to a public repository exposes the server to targeted attacks and makes the Makefile non-portable for other contributors.

Use environment variables with sensible defaults or a .env file (gitignored) instead:

Proposed fix
-REMOTE_IP = 101.36.104.77
-REMOTE_DIR = /opt/openclawapi.ai
-DOCKER_IMAGE = chasebank2023/new-api:latest
+REMOTE_IP ?= $(error REMOTE_IP is not set)
+REMOTE_DIR ?= /opt/openclawapi.ai
+DOCKER_IMAGE ?= chasebank2023/new-api:latest
web/src/index.css-1020-1028 (1)

1020-1028: ⚠️ Potential issue | 🟠 Major

Overly broad tag selector overrides all semantic colors.

The [class*='semi-tag']:not(.channel-affinity-tag) selector will force brand-red on every Semi tag variant (green, blue, amber, etc.), breaking semantic color coding (e.g., success/warning/error indicators, the green discount tag on line 454 of RechargeCard.jsx).

Consider scoping this to only the tags you actually want branded, or remove the catch-all [class*='semi-tag'] rule.

web/src/helpers/utils.jsx-1-1 (1)

1-1: ⚠️ Potential issue | 🟠 Major

License/attribution header was replaced with a one-line comment.

The original AGPL/QuantumNous license header was removed and replaced with /** OpenClaw API - Shared utils ... */. Based on learnings, references and attributions related to 'new-api' and 'QuantumNous' must not be modified or removed — this includes license headers and copyright notices.

docs/OPENCLAW_DEPLOY.md-9-14 (1)

9-14: ⚠️ Potential issue | 🟠 Major

Deployment doc describes source-level branding changes that conflict with project policy.

The modifications table lists changes to common/constants.go (SystemName, Footer) and web/src/helpers/utils.jsx (default system name). Per project rules, references and attributions related to 'new-api' and 'QuantumNous' must not be modified in source. Method 1 (environment variables) is the correct approach for customization without source modifications. Consider clarifying that the table describes runtime configuration overrides rather than source code edits, or note that these source changes are for a fork. Based on learnings from .cursor/rules/project.mdc and CLAUDE.md.

web/index.html-10-13 (1)

10-13: ⚠️ Potential issue | 🟠 Major

Branding policy violation: new-api / QuantumNous references must not be replaced.

The project rules explicitly state that all references, mentions, branding, metadata, or attributions related to new-api and QuantumNous — including HTML titles, meta tags, and descriptions — must not be modified, deleted, replaced, or removed. This change replaces the title, <meta name="generator">, and <meta name="description"> with "OpenClaw API" branding, which violates that policy.

Please revert the title, generator, and description meta tags to their original new-api / QuantumNous values, or get explicit approval from the maintainers before proceeding.

Based on learnings: "Project information including all references, mentions, branding, metadata, or attributions related to 'new-api' (project name) and 'QuantumNous' (organization/author) MUST NOT be modified, deleted, replaced, or removed under any circumstances. This includes README files, license headers, copyright notices, package metadata, HTML titles, meta tags, Go module paths, Docker image names, CI/CD references, comments, and documentation."

web/src/helpers/cookie.js-6-7 (1)

6-7: ⚠️ Potential issue | 🟠 Major

Hardcoded cookie domain breaks self-hosted and development environments.

COOKIE_DOMAIN is hardcoded to '.openclawapi.ai'. Since this is an open-source project intended for self-hosting, cookies set with this domain will silently fail on any other domain (localhost, custom domains, etc.). Consider deriving the domain from window.location.hostname or making it configurable (e.g., via an environment variable or a config constant).

web/src/context/User/index.jsx-48-61 (1)

48-61: 🛠️ Refactor suggestion | 🟠 Major

Inconsistent cookie clearing: use the setCookie helper instead of raw document.cookie.

Setting the cookie uses setCookie(...) but clearing hardcodes document.cookie with a literal domain. This duplicates the domain string and diverges from the helper's behavior. Use setCookie with maxAge: 0 for both consistency and maintainability.

♻️ Proposed fix
       if (state.user) {
         setCookie('oc_logged_in', '1');
       } else {
-        // Clear the cookie on logout by setting max-age=0
-        document.cookie = 'oc_logged_in=; path=/; max-age=0; domain=.openclawapi.ai';
-        document.cookie = 'oc_logged_in=; path=/; max-age=0';
+        setCookie('oc_logged_in', '', { maxAge: 0 });
+        setCookie('oc_logged_in', '', { maxAge: 0, domain: '' });
       }
web/src/components/layout/headerbar/HeaderLogo.jsx-58-60 (1)

58-60: ⚠️ Potential issue | 🟠 Major

Logo click navigates away from the SPA to a hardcoded external URL.

frontendHome is hardcoded to https://openclawapi.ai and the anchor uses target='_self', so clicking the header logo will navigate the user away from the current application in the same tab. This is a breaking UX change for any deployment not hosted at that exact domain — the user loses their current app state. Also, rel='noopener noreferrer' has no effect with target='_self'.

If the intent is to link to the project homepage externally, use target='_blank'. If the intent is SPA navigation to /, restore the <Link to="/"> from react-router-dom.

Proposed fix if external link is intended
-  const frontendHome = 'https://openclawapi.ai';
+  const frontendHome = 'https://openclawapi.ai';
   return (
-    <a href={frontendHome} className='group flex items-center gap-2' target='_self' rel='noopener noreferrer'>
+    <a href={frontendHome} className='group flex items-center gap-2' target='_blank' rel='noopener noreferrer'>
Proposed fix if SPA home navigation is intended

Restore the Link import and use it:

+import { Link } from 'react-router-dom';
 ...
-  const frontendHome = 'https://openclawapi.ai';
   return (
-    <a href={frontendHome} className='group flex items-center gap-2' target='_self' rel='noopener noreferrer'>
+    <Link to='/' className='group flex items-center gap-2'>
     ...
-    </a>
+    </Link>
web/src/components/layout/Footer.jsx-49-81 (1)

49-81: ⚠️ Potential issue | 🟠 Major

Use Chinese source keys for footer translations.
t('footer.*') relies on nested English keys; the project i18n convention expects Chinese source-string keys. Please switch these calls to Chinese keys and align locale files to the flat format.
As per coding guidelines: “web/src/**/*.{ts,tsx,json}: Frontend internationalization (i18n) uses i18next + react-i18next + i18next-browser-languagedetector. Translation files are flat JSON at web/src/i18n/locales/{lang}.json with Chinese source strings as keys. Use useTranslation() hook and call t('中文key') in components.”

web/src/i18n/locales/zh.json-2797-2815 (1)

2797-2815: ⚠️ Potential issue | 🟠 Major

Flatten footer translations and keep Chinese source keys.
The nested footer object introduces English keys, but locale files are expected to be flat with Chinese source-string keys. Please flatten these entries and update consumers to use Chinese keys.
As per coding guidelines: “web/src/i18n/**: Frontend i18n uses i18next + react-i18next + i18next-browser-languagedetector with translation files at web/src/i18n/locales/{lang}.json using flat JSON format with Chinese source strings as keys”.

web/src/i18n/locales/en.json-2852-2870 (1)

2852-2870: ⚠️ Potential issue | 🟠 Major

Flatten the new footer translations and use Chinese source-string keys.
The nested footer object introduces English keys, but the i18n files are expected to be flat with Chinese source strings as keys. Please flatten these entries (e.g., “页脚产品”: “Product”) and adjust consumers accordingly.
As per coding guidelines: “web/src/i18n/**: Frontend i18n uses i18next + react-i18next + i18next-browser-languagedetector with translation files at web/src/i18n/locales/{lang}.json using flat JSON format with Chinese source strings as keys”.

🟡 Minor comments (8)
Dockerfile-9-11 (1)

9-11: ⚠️ Potential issue | 🟡 Minor

NODE_OPTIONS=--max-old-space-size=2048 is a V8 flag and has no effect under Bun.

Bun uses JavaScriptCore, not V8, so --max-old-space-size is not recognized. This ENV line will be ignored. If you need to constrain memory during the build, use Docker's --memory flag or --memory-reservation instead.

docker-compose.yml-19-22 (1)

19-22: ⚠️ Potential issue | 🟡 Minor

Switching to local build changes the deployment experience for existing users.

Previously, docker-compose up -d pulled a pre-built image (calciumion/new-api:latest), making it a quick start. Now it triggers a full local build, which is significantly slower and requires the complete source tree. This could surprise users following the "Quick Start" guide on line 4.

Consider either:

  1. Keeping the remote image reference as the default for end-user deployment (perhaps pointing to the new chasebank2023/new-api:latest image from the CI pipeline), and providing this local-build compose file separately (e.g., docker-compose.dev.yml).
  2. Or at minimum, updating the Quick Start comment to note the build requirement and expected build time.
docs/DEPLOY-VIA-DOCKERHUB.md-8-8 (1)

8-8: ⚠️ Potential issue | 🟡 Minor

Hardcoded personal machine path in documentation.

/Users/chasebank2017/Downloads/new-api is a developer-specific path. Replace with a generic placeholder like /path/to/new-api so the guide is usable by anyone.

scripts/deploy-remote.sh-11-15 (1)

11-15: ⚠️ Potential issue | 🟡 Minor

Unquoted variables in SSH command may break with special characters.

$COMPOSE_DIR and $IMAGE are interpolated unquoted inside the SSH command string. If they ever contain spaces or shell metacharacters, the command will break or behave unexpectedly. Quote them properly.

Proposed fix
-ssh "$SERVER" "cd $COMPOSE_DIR && \
-  sed -i 's|image:.*new-api.*|image: $IMAGE|g' docker-compose.yml && \
+ssh "$SERVER" "cd '$COMPOSE_DIR' && \
+  sed -i 's|image:.*new-api.*|image: $IMAGE|g' docker-compose.yml && \
makefile-7-11 (1)

7-11: ⚠️ Potential issue | 🟡 Minor

SSH as root and fragile sed replacement.

Two concerns with DEPLOY_CMD:

  1. SSH as root — Consider using a non-root deploy user with limited sudo permissions for security.
  2. Fragile sed patternsed -i 's|image:.*new-api.*|...|g' will match any line containing both image: and new-api, which could unintentionally modify comments or other services. A more targeted pattern would be safer.
web/src/components/layout/headerbar/LanguageSelector.jsx-9-12 (1)

9-12: ⚠️ Potential issue | 🟡 Minor

Header toggle only supports zh/en but settings offers 6 languages.

If a user selects French, Russian, Japanese, or Vietnamese via PreferencesSettings, this toggle will cycle them to zh (since currentLang !== 'zh'nextLang = 'zh'), with no way to return to their chosen language from the header. Consider either:

  • Cycling through all supported languages, or
  • Hiding this toggle when the active language isn't zh/en, or
  • Limiting PreferencesSettings to the same two languages.
web/src/pages/Docs/index.jsx-32-34 (1)

32-34: ⚠️ Potential issue | 🟡 Minor

Possibly wrong i18n key for the docs page description.

t('页脚品牌描述(与官网一致)') looks like a footer branding description key, not a docs page subtitle. This would render footer copy as the docs page description. Was a dedicated key intended here?

web/src/helpers/cookie.js-18-24 (1)

18-24: ⚠️ Potential issue | 🟡 Minor

Missing Secure and SameSite attributes on cross-subdomain cookies.

For cookies shared across subdomains (as described in the file comment), you should set SameSite=None; Secure (or at minimum SameSite=Lax). Without these, modern browsers may silently drop or restrict the cookies in cross-site/cross-subdomain contexts.

🔒 Proposed fix
 export function setCookie(name, value, options = {}) {
   if (typeof document === 'undefined') return;
-  const { domain = COOKIE_DOMAIN, maxAge = MAX_AGE_YEAR, path = '/' } = options;
+  const { domain = COOKIE_DOMAIN, maxAge = MAX_AGE_YEAR, path = '/', secure = true, sameSite = 'Lax' } = options;
   const encoded = encodeURIComponent(value);
   const parts = [`${name}=${encoded}`, `path=${path}`, `max-age=${maxAge}`];
   if (domain) parts.push(`domain=${domain}`);
+  if (secure) parts.push('Secure');
+  if (sameSite) parts.push(`SameSite=${sameSite}`);
   document.cookie = parts.join('; ');
 }
🧹 Nitpick comments (22)
web/src/components/settings/SystemSetting.jsx (1)

522-527: Silenced OIDC fetch error may hinder debugging.

Removing console.error(err) means the actual error details (network failure, malformed response, CORS issue, etc.) are lost. The user-facing message is generic. Consider keeping a minimal log or structured error report for operators diagnosing OIDC configuration issues.

💡 Suggested improvement
       } catch (err) {
+        console.warn('[OIDC] Failed to fetch well-known config:', err.message || err);
         showError(
           t('获取 OIDC 配置失败,请检查网络状况和 Well-Known URL 是否正确'),
         );
         return;
       }
web/src/pages/Setting/Operation/SettingsHeaderNavModules.jsx (2)

229-232: Redundant ternary — the module.key === 'pricing' guard makes the else-branch dead code.

Line 229 already restricts this block to module.key === 'pricing', so the ternary on line 230 will always evaluate the truthy branch. The : headerNavModules[module.key] path is unreachable. Simplify to just check headerNavModules.pricing?.enabled.

♻️ Suggested simplification
-                {module.key === 'pricing' &&
-                  (module.key === 'pricing'
-                    ? headerNavModules[module.key]?.enabled
-                    : headerNavModules[module.key]) && (
+                {module.key === 'pricing' &&
+                  headerNavModules.pricing?.enabled && (

122-146: Old config keys (home, docs, about) are silently carried into state.

When a previously stored HeaderNavModules JSON is parsed at line 136, any legacy keys (home, docs, about) are loaded into headerNavModules state as-is. They won't cause a runtime error since there's no UI for them, but they'll be persisted back on the next save, creating unnecessary clutter. Consider stripping unknown keys during initialization.

♻️ Optional: normalize parsed config
         // 处理向后兼容性:如果pricing是boolean,转换为对象格式
         if (typeof modules.pricing === 'boolean') {
           modules.pricing = {
             enabled: modules.pricing,
             requireAuth: false,
           };
         }

-        setHeaderNavModules(modules);
+        // Only keep known module keys
+        setHeaderNavModules({
+          console: modules.console ?? true,
+          pricing: modules.pricing ?? { enabled: true, requireAuth: false },
+        });
web/src/hooks/common/useNavigation.js (1)

22-22: Remove unused docsLink parameter from function signature.

The docsLink parameter is accepted in the function signature but never referenced in the function body—the docs link is hardcoded to /docs. Callers still pass this parameter (found one call site in web/src/components/layout/headerbar/index.jsx line 48), making it dead code in the signature.

Remove the parameter and update the call site.

♻️ Suggested changes

In web/src/hooks/common/useNavigation.js line 22:

-export const useNavigation = (t, docsLink, headerNavModules) => {
+export const useNavigation = (t, headerNavModules) => {

In web/src/components/layout/headerbar/index.jsx line 48:

-  const { mainNavLinks } = useNavigation(t, docsLink, headerNavModules);
+  const { mainNavLinks } = useNavigation(t, headerNavModules);
router/web-router.go (1)

20-24: Avoid hardcoding a specific domain in code comments.

The comment on line 20 references api.openclawapi.ai, which will become stale if the domain changes. Use a generic description instead.

Suggested comment
-	// 显式处理根路径,确保 api.openclawapi.ai/ 可访问
+	// 显式处理根路径,确保首页可正常访问并禁用缓存
web/src/pages/Setting/Dashboard/SettingsAnnouncements.jsx (1)

459-462: Consider removing empty callback stubs.

onSelect and onSelectAll are now no-ops. They can be removed from the rowSelection object entirely since Semi UI doesn't require them.

♻️ Suggested cleanup
   const rowSelection = {
     selectedRowKeys,
     onChange: (selectedRowKeys, selectedRows) => {
       setSelectedRowKeys(selectedRowKeys);
     },
-    onSelect: (record, selected, selectedRows) => {
-    },
-    onSelectAll: (selected, selectedRows) => {
-    },
     getCheckboxProps: (record) => ({
       disabled: false,
       name: record.id,
     }),
   };
web/src/pages/Setting/Dashboard/SettingsFAQ.jsx (1)

372-375: Same as SettingsAnnouncements: empty callback stubs can be removed.

These no-op onSelect/onSelectAll handlers are unnecessary.

web/src/components/settings/OtherSetting.jsx (2)

181-197: Dead code: submitOption is no longer reachable.

The HomePageContent UI that invoked submitOption was removed (Line 438 comment), but the handler and related state (HomePageContent in inputs at Line 50 and loadingInput at Line 81) remain. Consider removing them to avoid confusion.


173-175: Inconsistent i18n: hardcoded Chinese strings in showSuccess/showError.

submitLogo, submitOption, submitAbout, and submitFooter (Lines 173–175, 188–190, 204–205, 215–217) use hardcoded Chinese strings, while submitNotice, submitSystemName, etc. wrap messages in t(). Wrap all user-facing strings in t() for consistency.

web/src/components/table/model-pricing/layout/header/PricingVendorIntro.jsx (1)

318-318: Unused primaryDarkerChannel parameter.

renderHeaderCard still accepts primaryDarkerChannel in its destructured props (Line 318), but it's no longer used since createCoverStyle takes no arguments. Remove it to avoid confusion — callers at Lines 379 and 402 also pass it unnecessarily.

web/src/i18n/locales/ru.json (1)

134-135: Orphaned translation key at line 134.

The key "New API项目仓库地址:" (line 134) appears to still be present, but per the AI summary, the corresponding UI text was removed from the About page. This key may now be unused. Consider removing it to keep locale files clean, or verify it's still referenced elsewhere.

#!/bin/bash
# Check if the old key is still referenced anywhere in the codebase
rg -n "New API项目仓库地址" --type-add 'jsx:*.jsx' --type-add 'tsx:*.tsx' --type=jsx --type=tsx --type=ts --type=js
web/src/components/dashboard/DashboardHeader.jsx (1)

55-55: Redundant hover:!bg-[var(--oc-accent)] — same value as the base background.

The hover background color is identical to the base background. Since the hover effect is achieved via hover:!opacity-90, the hover:!bg-[var(--oc-accent)] class is unnecessary.

Simplify
-          className={`!bg-[var(--oc-accent)] hover:!bg-[var(--oc-accent)] hover:!opacity-90 ${ICON_BUTTON_CLASS}`}
+          className={`!bg-[var(--oc-accent)] hover:!opacity-90 ${ICON_BUTTON_CLASS}`}
web/src/index.css (3)

1062-1070: Attribute-substring selectors on style are fragile.

Selectors like .semi-tag[style*="background"][style*="red"] match inline style strings, which are sensitive to whitespace, property order, and value formatting. A minor change in how React serializes the style prop (or a library update) will silently break these rules.

Prefer assigning explicit CSS classes instead of matching against inline style substrings.


4-5: Stylelint: use @import string notation instead of url().

Per Stylelint import-notation rule, the @import url(...) should be @import '...'.

Proposed fix
-@import url('https://api.fontshare.com/v2/css?f[]=satoshi@400,500,700&display=swap');
+@import 'https://api.fontshare.com/v2/css?f[]=satoshi@400,500,700&display=swap';

80-86: Stylelint: minor value-casing and quote issues.

Static analysis flags: optimizeLegibility should be lowercase (optimizelegibility), and 'Satoshi' should be unquoted per font-family-name-quotes. These are low-priority but will fail linting.

Proposed fix
 html {
   font-size: 16px;
-  text-rendering: optimizeLegibility;
+  text-rendering: optimizelegibility;
 }
 
 body {
-  font-family: 'Satoshi', system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI',
-    'Microsoft YaHei', sans-serif;
+  font-family: Satoshi, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI',
+    'Microsoft YaHei', sans-serif;
web/src/pages/Home/index.jsx (1)

131-132: Empty catch block silently swallows errors.

The console.error was removed but no alternative error handling was added. Consider at minimum logging to a monitoring service, or adding a comment explaining why the error is intentionally ignored.

web/src/components/dashboard/UptimePanel.jsx (1)

42-42: ILLUSTRATION_SIZE prop is now unused.

This prop is still destructured but no longer referenced after removing the custom illustrations. Consider removing it from the props to keep the interface clean.

web/src/components/dashboard/ApiInfoPanel.jsx (1)

31-31: ILLUSTRATION_SIZE prop is now unused.

Same as in UptimePanel.jsx — this destructured prop is no longer referenced after removing custom illustrations.

web/src/App.jsx (1)

52-52: DocsPage is eagerly imported but wrapped in Suspense — inconsistent with other routes.

DocsPage is directly imported (not lazy()), so the Suspense wrapper on lines 191-193 serves no purpose. Either lazy-load it to match other routes' pattern, or remove the Suspense wrapper for clarity.

♻️ Option A: Make it lazy (consistent with other routes)
-import DocsPage from './pages/Docs';
+const DocsPage = lazy(() => import('./pages/Docs'));

Also applies to: 188-195

web/src/i18n/i18n.js (1)

22-22: Dropping support for fr/ja/ru/vi is a significant scope reduction.

If users have previously selected one of these languages (stored as locale in localStorage), supportedLngs will reject it and fall back to zh. This is correct behavior given the fallbackLng setting, but existing users on those locales will see an abrupt language switch with no explanation. Consider whether a migration note or UI toast is warranted.

web/src/context/Theme/index.jsx (2)

27-37: Users migrating from "auto" theme will silently switch to dark.

Previously stored "auto" values in localStorage will be ignored and default to "dark". This is likely intentional but worth noting — users who preferred system-following behavior will see a one-time theme change without explanation.


58-68: Duplicate persistence: setTheme writes to storage, then useEffect writes again.

The useEffect on [theme] (lines 50–55) already persists to localStorage and cookie whenever theme changes. The manual writes in setTheme (lines 63–64) are redundant since _setTheme(value) triggers the effect.

♻️ Remove duplicate writes from setTheme
   const setTheme = useCallback((newTheme) => {
     const value =
       newTheme === 'light' || newTheme === 'dark' ? newTheme : theme === 'dark' ? 'light' : 'dark';
     _setTheme(value);
-    try {
-      localStorage.setItem(STORAGE_KEY, value);
-      setCookie('oc_theme', value);
-    } catch (e) {
-      // ignore
-    }
   }, [theme]);

Comment on lines +45 to +48
### 5. 注释与品牌

- 已修改的模块中,将 QuantumNous/AGPL 版权头替换为简短「OpenClaw API」说明,避免露出上游项目信息。

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Documentation endorses removing required license attributions.

Line 47 states: "将 QuantumNous/AGPL 版权头替换为简短「OpenClaw API」说明,避免露出上游项目信息." This directly contradicts the project rule that all references, mentions, and attributions related to 'new-api' and 'QuantumNous' — including license headers and copyright notices — must not be modified, deleted, or removed. This guidance should be revised or removed. Based on learnings from .cursor/rules/project.mdc and CLAUDE.md.

🤖 Prompt for AI Agents
In `@docs/BACKEND-FRONTEND-ALIGNMENT.md` around lines 45 - 48, The documentation
currently instructs replacing the QuantumNous/AGPL copyright header with a short
"OpenClaw API" note (the line containing "将 QuantumNous/AGPL 版权头替换为简短「OpenClaw
API」说明"), which violates the project's rule to preserve all 'new-api' and
'QuantumNous' attributions; revert or remove that sentence and update the
section "注释与品牌" to explicitly state that license headers and copyright notices
for 'new-api' and 'QuantumNous' must be retained unchanged, referencing the
project's rules in .cursor/rules/project.mdc and CLAUDE.md for wording
consistency.

Comment thread scripts/deploy-remote.sh
Comment on lines +6 to +8
SERVER="${DEPLOY_SERVER:-root@101.36.104.77}"
COMPOSE_DIR="${DEPLOY_COMPOSE_DIR:-/opt/openclawapi.ai}"
IMAGE="${DEPLOY_IMAGE:-chasebank2023/new-api:latest}"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Hardcoded production IP and Docker Hub username in defaults.

The script defaults to a specific server IP (101.36.104.77) and image (chasebank2023/new-api:latest). These should not have production values as fallbacks — a missing env var should fail explicitly rather than silently targeting a real server.

Proposed fix: fail fast if env vars are unset
-SERVER="${DEPLOY_SERVER:-root@101.36.104.77}"
-COMPOSE_DIR="${DEPLOY_COMPOSE_DIR:-/opt/openclawapi.ai}"
-IMAGE="${DEPLOY_IMAGE:-chasebank2023/new-api:latest}"
+SERVER="${DEPLOY_SERVER:?DEPLOY_SERVER is required}"
+COMPOSE_DIR="${DEPLOY_COMPOSE_DIR:?DEPLOY_COMPOSE_DIR is required}"
+IMAGE="${DEPLOY_IMAGE:?DEPLOY_IMAGE is required}"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
SERVER="${DEPLOY_SERVER:-root@101.36.104.77}"
COMPOSE_DIR="${DEPLOY_COMPOSE_DIR:-/opt/openclawapi.ai}"
IMAGE="${DEPLOY_IMAGE:-chasebank2023/new-api:latest}"
SERVER="${DEPLOY_SERVER:?DEPLOY_SERVER is required}"
COMPOSE_DIR="${DEPLOY_COMPOSE_DIR:?DEPLOY_COMPOSE_DIR is required}"
IMAGE="${DEPLOY_IMAGE:?DEPLOY_IMAGE is required}"
🤖 Prompt for AI Agents
In `@scripts/deploy-remote.sh` around lines 6 - 8, The current defaults hardcode a
production server IP and Docker image; replace these silent fallbacks by
requiring the env vars and failing fast: change the assignments for SERVER,
COMPOSE_DIR and IMAGE to enforce that DEPLOY_SERVER, DEPLOY_COMPOSE_DIR and
DEPLOY_IMAGE must be set (use shell parameter-expansion or explicit checks) and
print a clear error and exit non-zero if any are missing so the script cannot
accidentally target a real server.

Comment on lines 262 to 268
const createCoverStyle = useCallback(
(primaryColor) => ({
'--palette-primary-darkerChannel': primaryColor,
backgroundImage: `linear-gradient(0deg, rgba(var(--palette-primary-darkerChannel) / 80%), rgba(var(--palette-primary-darkerChannel) / 80%)), url('/cover-4.webp')`,
backgroundSize: 'cover',
backgroundPosition: 'center',
backgroundRepeat: 'no-repeat',
() => ({
backgroundColor: 'var(--semi-color-bg-1)',
borderBottom: '1px solid var(--semi-color-border)',
}),
[],
);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

White text on theme background — unreadable in light mode.

createCoverStyle() now uses var(--semi-color-bg-1) (a light/neutral background), but the title and description still use hardcoded white text (COMPONENT_STYLES.titleText = { color: 'white' } and descriptionText = { color: 'rgba(255,255,255,0.9)' }). In light mode this will be white-on-white — invisible.

Update the text styles to use semantic color tokens consistent with the new background:

Proposed fix
 const COMPONENT_STYLES = {
   tag: {
-    backgroundColor: 'rgba(255,255,255,0.95)',
-    color: '#1f2937',
-    border: '1px solid rgba(255,255,255,0.8)',
+    backgroundColor: 'var(--semi-color-bg-2)',
+    color: 'var(--semi-color-text-0)',
+    border: '1px solid var(--semi-color-border)',
     fontWeight: '500',
   },
   avatarContainer:
     'w-16 h-16 rounded-2xl bg-white/90 shadow-md backdrop-blur-sm flex items-center justify-center',
-  titleText: { color: 'white' },
-  descriptionText: { color: 'rgba(255,255,255,0.9)' },
+  titleText: { color: 'var(--semi-color-text-0)' },
+  descriptionText: { color: 'var(--semi-color-text-2)' },
 };

Also applies to: 329-351

🤖 Prompt for AI Agents
In `@web/src/components/table/model-pricing/layout/header/PricingVendorIntro.jsx`
around lines 262 - 268, The title and description styles
(COMPONENT_STYLES.titleText and descriptionText) use hardcoded white, causing
white-on-white in light mode after createCoverStyle() switched to
var(--semi-color-bg-1); change those hardcoded colors to semantic CSS tokens
(e.g., var(--semi-color-text-0) for primary title and a slightly muted token
like var(--semi-color-text-2) or rgba token derived from semantic tokens for
description) so text contrasts with the new background, and update the same
hardcoded white usages later in the file (the other title/description blocks
around the 329-351 region) to the same semantic tokens.

Comment thread web/src/index.jsx
Comment on lines 36 to 42
// 欢迎信息(二次开发者未经允许不准将此移除)
// Welcome message (Do not remove this without permission from the original developer)
if (typeof window !== 'undefined') {
console.log(
'%cWE ❤ NEWAPI%c Github: https://github.com/QuantumNous/new-api',
'%cOpenClaw API%c https://openclawapi.ai',
'color: #10b981; font-weight: bold; font-size: 24px;',
'color: inherit; font-size: 14px;',
);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Welcome message branding changed despite explicit prohibition.

Lines 36–37 state: "二次开发者未经允许不准将此移除 / Do not remove this without permission from the original developer." The message content was changed from the original NEWAPI/QuantumNous branding to OpenClaw. Per project rules, attributions related to 'new-api' and 'QuantumNous' must not be modified or removed. Based on learnings from .cursor/rules/project.mdc and CLAUDE.md.

🤖 Prompt for AI Agents
In `@web/src/index.jsx` around lines 36 - 42, The welcome message string was
altered to "OpenClaw API" contrary to the project's branding rules; revert the
altered console/message content in web/src/index.jsx back to the original NEWAPI
/ QuantumNous attribution and URL, keeping the surrounding protective comment
("欢迎信息... Do not remove...") intact; locate the conditional block that checks
typeof window !== 'undefined' (the welcome message statements on lines near the
current snippet) and replace the changed literal/branding tokens with the
original NEWAPI/QuantumNous text so the exact required attribution and URL are
restored.

Comment on lines 419 to 423
<Empty
image={
<IllustrationNoResult style={{ width: 150, height: 150 }} />
}
darkModeImage={
<IllustrationNoResultDark style={{ width: 150, height: 150 }} />
}
image={Empty.PRESENTED_IMAGE_SIMPLE}
description={t('暂无API信息')}
style={{ padding: 30 }}
/>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

# Find package.json to check Semi UI version
find . -name "package.json" -type f | head -5

Repository: QuantumNous/new-api

Length of output: 105


🏁 Script executed:

# Check the web directory package.json for Semi UI version
cat web/package.json | grep -A 2 -B 2 "semi-ui"

Repository: QuantumNous/new-api

Length of output: 229


🏁 Script executed:

# Read the file to understand context
cat -n web/src/pages/Setting/Dashboard/SettingsAPIInfo.jsx | sed -n '1,50p'

Repository: QuantumNous/new-api

Length of output: 2092


🏁 Script executed:

# Check imports in the file
cat -n web/src/pages/Setting/Dashboard/SettingsAPIInfo.jsx | grep -i "import\|from" | head -20

Repository: QuantumNous/new-api

Length of output: 372


🏁 Script executed:

# Check if there's a node_modules or type definitions for semi-ui
find . -path "*node_modules/@douyinfe/semi-ui*" -name "*.d.ts" -type f 2>/dev/null | grep -i empty | head -10

Repository: QuantumNous/new-api

Length of output: 45


🏁 Script executed:

# Search for usage of Empty component in the codebase to see other examples
rg "Empty\." web/src --type jsx --type js -A 2 -B 2 | head -50

Repository: QuantumNous/new-api

Length of output: 90


🏁 Script executed:

# Check the specific lines 419-423 in context
cat -n web/src/pages/Setting/Dashboard/SettingsAPIInfo.jsx | sed -n '415,425p'

Repository: QuantumNous/new-api

Length of output: 436


🌐 Web query:

@douyinfe/semi-ui Empty component PRESENTED_IMAGE_SIMPLE v2.69.1

💡 Result:

In @douyinfe/semi-ui v2.69.1, the Empty component does not provide AntD-style static presets like Empty.PRESENTED_IMAGE_SIMPLE. Semi’s Empty only lets you control the illustration via the image prop (and darkModeImage for dark mode), typically by importing an illustration from @douyinfe/semi-illustrations, or by passing your own custom ReactNode (or by not using an image at all). [1]

If you want a “simple” empty style in Semi, you generally do one of these:

import { Empty } from '@douyinfe/semi-ui';
// option A: no image (simple)
<Empty image={null} title="No data" />

// option B: pick an illustration yourself
import { IllustrationIdle } from '@douyinfe/semi-illustrations';
<Empty image={<IllustrationIdle />} title="No data" />

Semi’s v2.69.1 changelog entry also doesn’t mention adding any PRESENTED_IMAGE_* preset API for Empty. [2]

Sources
[1] Semi Design docs – Empty component API/usage: https://semi.design/en-US/show/empty
[2] Semi Design changelog – v2.69.1 entry: https://semi.design/zh-CN/ecosystem/changelog


Empty.PRESENTED_IMAGE_SIMPLE does not exist in Semi UI v2.69.1 and will render as undefined.

Empty.PRESENTED_IMAGE_SIMPLE is an Ant Design API. Semi UI's Empty component does not provide this static property. To display a simple empty state, use image={null} or import an illustration from @douyinfe/semi-illustrations.

🤖 Prompt for AI Agents
In `@web/src/pages/Setting/Dashboard/SettingsAPIInfo.jsx` around lines 419 - 423,
The Empty component usage uses the non-existent static
Empty.PRESENTED_IMAGE_SIMPLE (AntD API); update the Empty in SettingsAPIInfo.jsx
to use Semi UI-compatible images by replacing
image={Empty.PRESENTED_IMAGE_SIMPLE} with either image={null} for a simple state
or import and pass a Semi illustration (from `@douyinfe/semi-illustrations`) as
image={MyIllustration}; ensure the change targets the Empty element and its
image prop so it renders correctly in Semi v2.69.1.

@seefs001 seefs001 closed this Feb 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants