Преглед изворни кода

Fix auto-connect settings and SelectLabel error

- Use explicit string values for preferred_port (__auto__, __none__)
- Backend stores values directly instead of converting to null
- Fix SelectLabel must be within SelectGroup error
- Connection manager handles both __auto__ and null for backwards compat

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
tuanchris пре 2 недеља
родитељ
комит
1ecf22cd6c
3 измењених фајлова са 36 додато и 44 уклоњено
  1. 32 36
      frontend/src/pages/SettingsPage.tsx
  2. 2 6
      main.py
  3. 2 2
      modules/connection/connection_manager.py

+ 32 - 36
frontend/src/pages/SettingsPage.tsx

@@ -18,9 +18,9 @@ import {
 import {
   Select,
   SelectContent,
+  SelectGroup,
   SelectItem,
   SelectLabel,
-  SelectSeparator,
   SelectTrigger,
   SelectValue,
 } from '@/components/ui/select'
@@ -454,7 +454,8 @@ export function SettingsPage() {
   const handleSavePreferredPort = async () => {
     setIsLoading('preferredPort')
     try {
-      const portValue = settings.preferred_port === '__none__' ? '__none__' : (settings.preferred_port || null)
+      // Send the actual value: __auto__, __none__, or specific port
+      const portValue = settings.preferred_port || '__auto__'
       await apiClient.patch('/api/settings', {
         connection: { preferred_port: portValue },
       })
@@ -826,29 +827,9 @@ export function SettingsPage() {
               <div className="flex gap-3">
                 <Select
                   value={settings.preferred_port || '__auto__'}
-                  onValueChange={async (value) => {
-                    const newPort = value === '__auto__' ? undefined : value
-                    setSettings({ ...settings, preferred_port: newPort })
-                    // Auto-save on change
-                    setIsLoading('preferredPort')
-                    try {
-                      const portValue = value === '__none__' ? '__none__' : (value === '__auto__' ? null : value)
-                      await apiClient.patch('/api/settings', {
-                        connection: { preferred_port: portValue },
-                      })
-                      if (value === '__auto__') {
-                        toast.success('Auto-connect: Auto (first available port)')
-                      } else if (value === '__none__') {
-                        toast.success('Auto-connect: Disabled')
-                      } else {
-                        toast.success(`Auto-connect: ${value}`)
-                      }
-                    } catch {
-                      toast.error('Failed to save auto-connect setting')
-                    } finally {
-                      setIsLoading(null)
-                    }
-                  }}
+                  onValueChange={(value) =>
+                    setSettings({ ...settings, preferred_port: value === '__auto__' ? undefined : value })
+                  }
                 >
                   <SelectTrigger className="flex-1">
                     <SelectValue placeholder="Select auto-connect option..." />
@@ -868,6 +849,18 @@ export function SettingsPage() {
                     )}
                   </SelectContent>
                 </Select>
+                <Button
+                  onClick={handleSavePreferredPort}
+                  disabled={isLoading === 'preferredPort'}
+                  className="gap-2"
+                >
+                  {isLoading === 'preferredPort' ? (
+                    <span className="material-icons-outlined animate-spin">sync</span>
+                  ) : (
+                    <span className="material-icons-outlined">save</span>
+                  )}
+                  Save
+                </Button>
               </div>
               <p className="text-xs text-muted-foreground">
                 Choose how the system connects on startup: Auto picks the first available port, Disabled requires manual connection, or select a specific port.
@@ -1452,17 +1445,20 @@ export function SettingsPage() {
                       <SelectValue />
                     </SelectTrigger>
                     <SelectContent>
-                      <SelectLabel>RGB Strips (3-channel)</SelectLabel>
-                      <SelectItem value="RGB">RGB - WS2815/WS2811</SelectItem>
-                      <SelectItem value="GRB">GRB - WS2812/WS2812B (common)</SelectItem>
-                      <SelectItem value="BGR">BGR - Some WS2811 variants</SelectItem>
-                      <SelectItem value="RBG">RBG - Rare variant</SelectItem>
-                      <SelectItem value="GBR">GBR - Rare variant</SelectItem>
-                      <SelectItem value="BRG">BRG - Rare variant</SelectItem>
-                      <SelectSeparator />
-                      <SelectLabel>RGBW Strips (4-channel)</SelectLabel>
-                      <SelectItem value="GRBW">GRBW - SK6812 RGBW (common)</SelectItem>
-                      <SelectItem value="RGBW">RGBW - SK6812 variant</SelectItem>
+                      <SelectGroup>
+                        <SelectLabel>RGB Strips (3-channel)</SelectLabel>
+                        <SelectItem value="RGB">RGB - WS2815/WS2811</SelectItem>
+                        <SelectItem value="GRB">GRB - WS2812/WS2812B (common)</SelectItem>
+                        <SelectItem value="BGR">BGR - Some WS2811 variants</SelectItem>
+                        <SelectItem value="RBG">RBG - Rare variant</SelectItem>
+                        <SelectItem value="GBR">GBR - Rare variant</SelectItem>
+                        <SelectItem value="BRG">BRG - Rare variant</SelectItem>
+                      </SelectGroup>
+                      <SelectGroup>
+                        <SelectLabel>RGBW Strips (4-channel)</SelectLabel>
+                        <SelectItem value="GRBW">GRBW - SK6812 RGBW (common)</SelectItem>
+                        <SelectItem value="RGBW">RGBW - SK6812 variant</SelectItem>
+                      </SelectGroup>
                     </SelectContent>
                   </Select>
                 </div>

+ 2 - 6
main.py

@@ -748,12 +748,8 @@ async def update_settings(settings_update: SettingsUpdate):
     # Connection settings
     if settings_update.connection:
         if settings_update.connection.preferred_port is not None:
-            port = settings_update.connection.preferred_port
-            # "" or "none" = auto mode (None), "__none__" = disabled, else specific port
-            if port in ("", "none"):
-                state.preferred_port = None  # Auto mode
-            else:
-                state.preferred_port = port  # "__none__" for disabled, or specific port
+            # Store exactly what frontend sends: "__auto__", "__none__", or specific port
+            state.preferred_port = settings_update.connection.preferred_port
         updated_categories.append("connection")
 
     # Pattern settings

+ 2 - 2
modules/connection/connection_manager.py

@@ -259,7 +259,7 @@ def connect_device(homing=True):
 
     ports = list_serial_ports()
 
-    # Check if auto-connect is disabled
+    # Check auto-connect mode: "__auto__" or None = auto, "__none__" = disabled, else specific port
     if state.preferred_port == "__none__":
         logger.info("Auto-connect disabled by user preference")
         # Skip all auto-connect logic, no connection will be established
@@ -267,7 +267,7 @@ def connect_device(homing=True):
     # 1. Preferred port (user's explicit choice) if available
     # 2. Last used port if available
     # 3. First available port as fallback
-    elif state.preferred_port and state.preferred_port in ports:
+    elif state.preferred_port and state.preferred_port not in ("__auto__", None) and state.preferred_port in ports:
         logger.info(f"Connecting to preferred port: {state.preferred_port}")
         state.conn = SerialConnection(state.preferred_port)
     elif state.port and state.port in ports: