Explorar o código

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 hai 6 meses
pai
achega
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 />

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 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>

Algúns arquivos non se mostraron porque demasiados arquivos cambiaron neste cambio