This is an automated email from the ASF dual-hosted git repository.

lizhimins pushed a commit to branch rocketmq-studio
in repository https://gitbox.apache.org/repos/asf/rocketmq-dashboard.git


The following commit(s) were added to refs/heads/rocketmq-studio by this push:
     new 505f0ed0b fix(settings): reflect active appearance preferences in 
controls (#7219)
505f0ed0b is described below

commit 505f0ed0b680e91d1aef7515940e88fea5756226
Author: coder999o <[email protected]>
AuthorDate: Mon Oct 26 20:08:37 2026 +0800

    fix(settings): reflect active appearance preferences in controls (#7219)
    
    * fix(settings): reflect active appearance preferences in controls
---
 web/src/pages/settings/GeneralSettingsTab.tsx      |  9 ++---
 .../settings/__tests__/GeneralSettingsTab.test.tsx | 43 ++++++++++++++++++++++
 2 files changed, 46 insertions(+), 6 deletions(-)

diff --git a/web/src/pages/settings/GeneralSettingsTab.tsx 
b/web/src/pages/settings/GeneralSettingsTab.tsx
index a654b6073..66cac55ff 100644
--- a/web/src/pages/settings/GeneralSettingsTab.tsx
+++ b/web/src/pages/settings/GeneralSettingsTab.tsx
@@ -39,9 +39,6 @@ import useAuthStore from '../../stores/authStore';
 
 const { Text } = Typography;
 
-const toThemeMode = (value?: string): ThemeMode =>
-  value === 'light' || value === 'dark' ? value : 'system';
-
 const buildPayload = (settings: GeneralSettings): GeneralSettingsUpdate => ({
   preserveLlmConfig: true,
   theme: settings.theme,
@@ -65,7 +62,7 @@ const buildPayload = (settings: GeneralSettings): 
GeneralSettingsUpdate => ({
 export const GeneralSettingsTab = () => {
   const { t } = useLang();
   const { message } = App.useApp();
-  const { setThemeMode, setCompact } = useTheme();
+  const { themeMode, compact, setThemeMode, setCompact } = useTheme();
   const [settings, setSettings] = useState<GeneralSettings | null>(null);
   const [loading, setLoading] = useState(true);
   const [savingPreference, setSavingPreference] = useState(false);
@@ -265,7 +262,7 @@ export const GeneralSettingsTab = () => {
               </Text>
             </div>
             <Segmented
-              value={toThemeMode(settings?.theme)}
+              value={themeMode}
               options={[
                 { value: 'light', label: t('settings.lightTheme') },
                 { value: 'dark', label: t('settings.darkTheme') },
@@ -287,7 +284,7 @@ export const GeneralSettingsTab = () => {
               </Text>
             </div>
             <Switch
-              checked={Boolean(settings?.compact)}
+              checked={compact}
               disabled={savingPreference}
               onChange={(checked) => {
                 setCompact(checked);
diff --git a/web/src/pages/settings/__tests__/GeneralSettingsTab.test.tsx 
b/web/src/pages/settings/__tests__/GeneralSettingsTab.test.tsx
index 9fd25504a..2cf1f3e76 100644
--- a/web/src/pages/settings/__tests__/GeneralSettingsTab.test.tsx
+++ b/web/src/pages/settings/__tests__/GeneralSettingsTab.test.tsx
@@ -21,6 +21,8 @@ import userEvent from '@testing-library/user-event';
 import { App } from 'antd';
 import { getGeneralSettings, saveGeneralSettings } from 
'../../../api/settings';
 import { ThemeProvider } from '../../../theme/ThemeProvider';
+import { useTheme } from '../../../theme/useTheme';
+import { COMPACT_STORAGE_KEY, THEME_STORAGE_KEY } from 
'../../../theme/themePreference';
 import { LangProvider } from '../../../i18n/LangContext';
 import { LANGUAGE_STORAGE_KEY } from '../../../i18n/languagePreference';
 import { GeneralSettingsTab } from '../GeneralSettingsTab';
@@ -51,11 +53,17 @@ vi.mock('../../../api/settings', () => ({
   updateDataSource: vi.fn(),
 }));
 
+const ThemeShortcut = () => {
+  const { toggleTheme } = useTheme();
+  return <button onClick={toggleTheme}>Toggle theme</button>;
+};
+
 const renderTab = () =>
   render(
     <App>
       <LangProvider>
         <ThemeProvider>
+          <ThemeShortcut />
           <GeneralSettingsTab />
         </ThemeProvider>
       </LangProvider>
@@ -209,6 +217,41 @@ describe('GeneralSettingsTab', () => {
     );
   });
 
+  it('displays restored local appearance preferences instead of server 
defaultsTest', async () => {
+    localStorage.setItem(THEME_STORAGE_KEY, 'dark');
+    localStorage.setItem(COMPACT_STORAGE_KEY, 'true');
+    renderTab();
+
+    await screen.findByDisplayValue('30');
+
+    expect(screen.getByRole('radio', { name: '深色' })).toBeChecked();
+    expect(screen.getByRole('switch')).toBeChecked();
+    expect(saveGeneralSettings).not.toHaveBeenCalled();
+  });
+
+  it('follows global theme changes and allows returning to system modeTest', 
async () => {
+    vi.mocked(saveGeneralSettings).mockResolvedValue();
+    const user = userEvent.setup();
+    renderTab();
+    await screen.findByDisplayValue('30');
+
+    await user.click(screen.getByRole('button', { name: 'Toggle theme' }));
+
+    expect(localStorage.getItem(THEME_STORAGE_KEY)).toBe('dark');
+    expect(screen.getByRole('radio', { name: '深色' })).toBeChecked();
+    expect(saveGeneralSettings).not.toHaveBeenCalled();
+
+    await user.click(screen.getByText('跟随系统'));
+
+    await waitFor(() =>
+      expect(saveGeneralSettings).toHaveBeenCalledWith(
+        expect.objectContaining({ theme: 'system' }),
+      ),
+    );
+    expect(localStorage.getItem(THEME_STORAGE_KEY)).toBe('system');
+    expect(screen.getByRole('radio', { name: '跟随系统' })).toBeChecked();
+  });
+
   it('saves llm fields from a fresh read instead of the mount-time snapshot', 
async () => {
     const baseSettings = {
       theme: 'system',

Reply via email to