Browse Source

Move email settings under Authentication tab in settings

Rename the "Users" settings tab to "Authentication" and move the
standalone "Global Email" tab into it as an "Email Authentication"
sub-tab. This groups email/SMTP configuration with user management
where it logically belongs.

- Remove top-level email tab from settings tab bar
- Add sub-tab navigation (Users / Email Authentication) inside the
  Authentication tab
- Handle legacy ?tab=email URLs by mapping to users tab + email sub-tab
- Update i18n keys in en/de/ja locales
maziggy 6 tháng trước cách đây
mục cha
commit
778d1966af

+ 1 - 0
CHANGELOG.md

@@ -10,6 +10,7 @@ All notable changes to Bambuddy will be documented in this file.
 
 
 ### Improved
 ### Improved
 - **Additional Currency Options** ([#329](https://github.com/maziggy/bambuddy/issues/329)) — Added 16 additional currencies to the cost tracking dropdown: HKD, INR, KRW, SEK, NOK, DKK, PLN, BRL, TWD, SGD, NZD, MXN, CZK, THB, ZAR.
 - **Additional Currency Options** ([#329](https://github.com/maziggy/bambuddy/issues/329)) — Added 16 additional currencies to the cost tracking dropdown: HKD, INR, KRW, SEK, NOK, DKK, PLN, BRL, TWD, SGD, NZD, MXN, CZK, THB, ZAR.
+- **Move Email Settings Under Authentication Tab** — Renamed the settings "Users" tab to "Authentication" and moved the standalone "Global Email" tab into it as an "Email Authentication" sub-tab. Groups email/SMTP configuration with user management where it logically belongs. Legacy `?tab=email` URLs are handled automatically.
 
 
 ## [0.1.9] - 2026-02-10
 ## [0.1.9] - 2026-02-10
 
 

+ 2 - 2
frontend/src/i18n/locales/de.ts

@@ -1019,9 +1019,9 @@ export default {
       network: 'Netzwerk',
       network: 'Netzwerk',
       apiKeys: 'API-Schlüssel',
       apiKeys: 'API-Schlüssel',
       virtualPrinter: 'Virtueller Drucker',
       virtualPrinter: 'Virtueller Drucker',
-      users: 'Benutzer',
+      users: 'Authentifizierung',
       backup: 'Sicherung',
       backup: 'Sicherung',
-      globalEmail: 'Globale E-Mail',
+      emailAuth: 'E-Mail-Authentifizierung',
     },
     },
     // Email settings
     // Email settings
     email: {
     email: {

+ 2 - 2
frontend/src/i18n/locales/en.ts

@@ -1019,9 +1019,9 @@ export default {
       network: 'Network',
       network: 'Network',
       apiKeys: 'API Keys',
       apiKeys: 'API Keys',
       virtualPrinter: 'Virtual Printer',
       virtualPrinter: 'Virtual Printer',
-      users: 'Users',
+      users: 'Authentication',
       backup: 'Backup',
       backup: 'Backup',
-      globalEmail: 'Global Email',
+      emailAuth: 'Email Authentication',
     },
     },
     // Email settings
     // Email settings
     email: {
     email: {

+ 2 - 2
frontend/src/i18n/locales/ja.ts

@@ -1063,12 +1063,12 @@ export default {
       smartPlugs: 'スマートプラグ',
       smartPlugs: 'スマートプラグ',
       notifications: '通知',
       notifications: '通知',
       apiKeys: 'APIキー',
       apiKeys: 'APIキー',
-      users: 'ユーザー',
+      users: '認証',
       backup: 'バックアップ',
       backup: 'バックアップ',
       filament: 'フィラメント',
       filament: 'フィラメント',
       network: 'ネットワーク',
       network: 'ネットワーク',
       virtualPrinter: '仮想プリンター',
       virtualPrinter: '仮想プリンター',
-      globalEmail: 'グローバルメール',
+      emailAuth: 'メール認証',
     },
     },
     appearance: '外観',
     appearance: '外観',
     notifications: '通知',
     notifications: '通知',

+ 50 - 24
frontend/src/pages/SettingsPage.tsx

@@ -31,8 +31,9 @@ import { useTheme, type ThemeStyle, type DarkBackground, type LightBackground, t
 import { useState, useEffect, useRef, useCallback } from 'react';
 import { useState, useEffect, useRef, useCallback } from 'react';
 import { Palette } from 'lucide-react';
 import { Palette } from 'lucide-react';
 
 
-const validTabs = ['general', 'network', 'plugs', 'email', 'notifications', 'filament', 'apikeys', 'virtual-printer', 'users', 'backup'] as const;
+const validTabs = ['general', 'network', 'plugs', 'notifications', 'filament', 'apikeys', 'virtual-printer', 'users', 'backup'] as const;
 type TabType = typeof validTabs[number];
 type TabType = typeof validTabs[number];
+type UsersSubTab = 'users' | 'email';
 
 
 export function SettingsPage() {
 export function SettingsPage() {
   const queryClient = useQueryClient();
   const queryClient = useQueryClient();
@@ -57,14 +58,19 @@ export function SettingsPage() {
   const [showLogViewer, setShowLogViewer] = useState(false);
   const [showLogViewer, setShowLogViewer] = useState(false);
   const [defaultView, setDefaultViewState] = useState<string>(getDefaultView());
   const [defaultView, setDefaultViewState] = useState<string>(getDefaultView());
 
 
-  // Initialize tab from URL params
+  // Initialize tab from URL params (handle legacy ?tab=email → users tab + email sub-tab)
   const tabParam = searchParams.get('tab');
   const tabParam = searchParams.get('tab');
-  const initialTab = tabParam && validTabs.includes(tabParam as TabType) ? tabParam as TabType : 'general';
+  const isLegacyEmailTab = tabParam === 'email';
+  const initialTab = isLegacyEmailTab ? 'users' : (tabParam && validTabs.includes(tabParam as TabType) ? tabParam as TabType : 'general');
   const [activeTab, setActiveTab] = useState<TabType>(initialTab);
   const [activeTab, setActiveTab] = useState<TabType>(initialTab);
+  const [usersSubTab, setUsersSubTab] = useState<UsersSubTab>(isLegacyEmailTab ? 'email' : 'users');
 
 
   // Update URL when tab changes
   // Update URL when tab changes
   const handleTabChange = (tab: TabType) => {
   const handleTabChange = (tab: TabType) => {
     setActiveTab(tab);
     setActiveTab(tab);
+    if (tab === 'users') {
+      setUsersSubTab('users');
+    }
     if (tab === 'general') {
     if (tab === 'general') {
       searchParams.delete('tab');
       searchParams.delete('tab');
     } else {
     } else {
@@ -987,20 +993,6 @@ export function SettingsPage() {
             </span>
             </span>
           )}
           )}
         </button>
         </button>
-        <button
-          onClick={() => handleTabChange('email')}
-          className={`px-4 py-2 text-sm font-medium transition-colors border-b-2 -mb-px flex items-center gap-2 ${
-            activeTab === 'email'
-              ? 'text-bambu-green border-bambu-green'
-              : 'text-bambu-gray hover:text-gray-900 dark:hover:text-white border-transparent'
-          }`}
-        >
-          <Mail className="w-4 h-4" />
-          {t('settings.tabs.globalEmail') || 'Global Email'}
-          {advancedAuthStatus?.advanced_auth_enabled && (
-            <span className="w-2 h-2 rounded-full bg-green-400" />
-          )}
-        </button>
         <button
         <button
           onClick={() => handleTabChange('notifications')}
           onClick={() => handleTabChange('notifications')}
           className={`px-4 py-2 text-sm font-medium transition-colors border-b-2 -mb-px flex items-center gap-2 ${
           className={`px-4 py-2 text-sm font-medium transition-colors border-b-2 -mb-px flex items-center gap-2 ${
@@ -3482,6 +3474,38 @@ export function SettingsPage() {
       {/* Users Tab */}
       {/* Users Tab */}
       {activeTab === 'users' && (
       {activeTab === 'users' && (
         <div className="space-y-6">
         <div className="space-y-6">
+          {/* Sub-tab Navigation */}
+          <div className="flex gap-1 border-b border-bambu-dark-tertiary">
+            <button
+              onClick={() => setUsersSubTab('users')}
+              className={`px-4 py-2 text-sm font-medium transition-colors border-b-2 -mb-px flex items-center gap-2 ${
+                usersSubTab === 'users'
+                  ? 'text-bambu-green border-bambu-green'
+                  : 'text-bambu-gray hover:text-gray-900 dark:hover:text-white border-transparent'
+              }`}
+            >
+              <Users className="w-4 h-4" />
+              {t('settings.tabs.users')}
+            </button>
+            <button
+              onClick={() => setUsersSubTab('email')}
+              className={`px-4 py-2 text-sm font-medium transition-colors border-b-2 -mb-px flex items-center gap-2 ${
+                usersSubTab === 'email'
+                  ? 'text-bambu-green border-bambu-green'
+                  : 'text-bambu-gray hover:text-gray-900 dark:hover:text-white border-transparent'
+              }`}
+            >
+              <Mail className="w-4 h-4" />
+              {t('settings.tabs.emailAuth') || 'Email Authentication'}
+              {advancedAuthStatus?.advanced_auth_enabled && (
+                <span className="w-2 h-2 rounded-full bg-green-400" />
+              )}
+            </button>
+          </div>
+
+          {/* Users Sub-tab */}
+          {usersSubTab === 'users' && (
+          <>
           {/* Auth Toggle Header */}
           {/* Auth Toggle Header */}
           <Card>
           <Card>
             <CardContent className="py-4">
             <CardContent className="py-4">
@@ -3784,6 +3808,15 @@ export function SettingsPage() {
               </CardContent>
               </CardContent>
             </Card>
             </Card>
           )}
           )}
+          </>
+          )}
+
+          {/* Email Auth Sub-tab */}
+          {usersSubTab === 'email' && (
+            <div className="max-w-2xl">
+              <EmailSettings />
+            </div>
+          )}
         </div>
         </div>
       )}
       )}
 
 
@@ -4405,13 +4438,6 @@ export function SettingsPage() {
         />
         />
       )}
       )}
 
 
-      {/* Email Tab */}
-      {activeTab === 'email' && (
-        <div className="max-w-2xl">
-          <EmailSettings />
-        </div>
-      )}
-
       {/* Backup Tab */}
       {/* Backup Tab */}
       {activeTab === 'backup' && (
       {activeTab === 'backup' && (
         <GitHubBackupSettings />
         <GitHubBackupSettings />

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 0 - 0
static/assets/index-8p-dzNdz.js


+ 1 - 1
static/index.html

@@ -23,7 +23,7 @@
 
 
     <!-- Splash screens for iOS -->
     <!-- Splash screens for iOS -->
     <link rel="apple-touch-startup-image" href="/img/android-chrome-512x512.png" />
     <link rel="apple-touch-startup-image" href="/img/android-chrome-512x512.png" />
-    <script type="module" crossorigin src="/assets/index-Co9UeRtt.js"></script>
+    <script type="module" crossorigin src="/assets/index-8p-dzNdz.js"></script>
     <link rel="stylesheet" crossorigin href="/assets/index-DLgJjh2G.css">
     <link rel="stylesheet" crossorigin href="/assets/index-DLgJjh2G.css">
   </head>
   </head>
   <body>
   <body>

Một số tệp đã không được hiển thị bởi vì quá nhiều tập tin thay đổi trong này khác