فهرست منبع

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 3 ماه پیش
والد
کامیت
778d1966af

+ 1 - 0
CHANGELOG.md

@@ -10,6 +10,7 @@ All notable changes to Bambuddy will be documented in this file.
 
 ### 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.
+- **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
 

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

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

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

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

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

@@ -1063,12 +1063,12 @@ export default {
       smartPlugs: 'スマートプラグ',
       notifications: '通知',
       apiKeys: 'APIキー',
-      users: 'ユーザー',
+      users: '認証',
       backup: 'バックアップ',
       filament: 'フィラメント',
       network: 'ネットワーク',
       virtualPrinter: '仮想プリンター',
-      globalEmail: 'グローバルメール',
+      emailAuth: 'メール認証',
     },
     appearance: '外観',
     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 { 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 UsersSubTab = 'users' | 'email';
 
 export function SettingsPage() {
   const queryClient = useQueryClient();
@@ -57,14 +58,19 @@ export function SettingsPage() {
   const [showLogViewer, setShowLogViewer] = useState(false);
   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 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 [usersSubTab, setUsersSubTab] = useState<UsersSubTab>(isLegacyEmailTab ? 'email' : 'users');
 
   // Update URL when tab changes
   const handleTabChange = (tab: TabType) => {
     setActiveTab(tab);
+    if (tab === 'users') {
+      setUsersSubTab('users');
+    }
     if (tab === 'general') {
       searchParams.delete('tab');
     } else {
@@ -987,20 +993,6 @@ export function SettingsPage() {
             </span>
           )}
         </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
           onClick={() => handleTabChange('notifications')}
           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 */}
       {activeTab === 'users' && (
         <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 */}
           <Card>
             <CardContent className="py-4">
@@ -3784,6 +3808,15 @@ export function SettingsPage() {
               </CardContent>
             </Card>
           )}
+          </>
+          )}
+
+          {/* Email Auth Sub-tab */}
+          {usersSubTab === 'email' && (
+            <div className="max-w-2xl">
+              <EmailSettings />
+            </div>
+          )}
         </div>
       )}
 
@@ -4405,13 +4438,6 @@ export function SettingsPage() {
         />
       )}
 
-      {/* Email Tab */}
-      {activeTab === 'email' && (
-        <div className="max-w-2xl">
-          <EmailSettings />
-        </div>
-      )}
-
       {/* Backup Tab */}
       {activeTab === 'backup' && (
         <GitHubBackupSettings />

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 0
static/assets/index-8p-dzNdz.js


+ 1 - 1
static/index.html

@@ -23,7 +23,7 @@
 
     <!-- Splash screens for iOS -->
     <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">
   </head>
   <body>

برخی فایل ها در این مقایسه diff نمایش داده نمی شوند زیرا تعداد فایل ها بسیار زیاد است