From 52b9c02264c61fd4973a58f94fa190221ff784b7 Mon Sep 17 00:00:00 2001 From: Patrick Date: Wed, 22 Apr 2026 01:01:40 +0200 Subject: [PATCH] Improve Samba Global Configuration display in WebUI Backend: - Parse global config into structured key-value pairs - Return parameters array instead of raw text - Better handling of comments and empty lines Frontend: - Add 'Samba Config' tab to shares page - Display config parameters in readable table format - Color-code parameter names for clarity - Add getSambaConfig() method to API client Co-Authored-By: Patrick --- backend/services/shares.py | 21 ++++++++++----- frontend/app/shares/page.tsx | 52 ++++++++++++++++++++++++++++++++++-- frontend/lib/api.ts | 5 ++++ 3 files changed, 69 insertions(+), 9 deletions(-) diff --git a/backend/services/shares.py b/backend/services/shares.py index f996623..e62ea8b 100644 --- a/backend/services/shares.py +++ b/backend/services/shares.py @@ -180,16 +180,15 @@ class SharesManager: return False def get_samba_global_config(self) -> Dict[str, Any]: - """Read Samba global configuration section""" + """Read Samba global configuration section as structured key-value pairs""" if not SAMBA_CONFIG.exists(): - return {"raw": ""} + return {"parameters": []} try: with open(SAMBA_CONFIG, 'r') as f: content = f.read() - # Extract global section - global_section = "" + parameters = [] lines = content.split('\n') in_global = False for line in lines: @@ -199,12 +198,20 @@ class SharesManager: if in_global: if line.strip().startswith('['): break - global_section += line + '\n' + line = line.strip() + if not line or line.startswith(';') or line.startswith('#'): + continue + if '=' in line: + key, value = line.split('=', 1) + parameters.append({ + "key": key.strip(), + "value": value.strip() + }) - return {"raw": global_section.strip()} + return {"parameters": parameters} except Exception as e: logger.error(f"Error reading Samba global config: {e}") - return {"raw": ""} + return {"parameters": []} def set_samba_global_config(self, config_text: str) -> bool: """Write Samba global configuration section""" diff --git a/frontend/app/shares/page.tsx b/frontend/app/shares/page.tsx index 1ffc9c3..88661fc 100644 --- a/frontend/app/shares/page.tsx +++ b/frontend/app/shares/page.tsx @@ -13,9 +13,10 @@ import DeleteConfirmDialog from "@/components/shares/DeleteConfirmDialog" export default function SharesPage() { const router = useRouter() - const [activeTab, setActiveTab] = useState<"samba" | "nfs">("samba") + const [activeTab, setActiveTab] = useState<"samba" | "nfs" | "config">("samba") const [sambaShares, setSambaShares] = useState([]) const [nfsShares, setNfsShares] = useState([]) + const [sambaConfig, setSambaConfig] = useState([]) const [loading, setLoading] = useState(true) const [error, setError] = useState(null) const [showSambaDialog, setShowSambaDialog] = useState(false) @@ -37,13 +38,15 @@ export default function SharesPage() { setLoading(true) setError(null) - const [samba, nfs] = await Promise.all([ + const [samba, nfs, config] = await Promise.all([ api.getSambaShares().catch(() => []), api.getNfsShares().catch(() => []), + api.getSambaConfig().catch(() => ({ parameters: [] })), ]) setSambaShares(samba) setNfsShares(nfs) + setSambaConfig(config.parameters || []) } catch (err) { setError(err instanceof Error ? err.message : "Failed to load shares") } finally { @@ -138,6 +141,16 @@ export default function SharesPage() { > NFS + @@ -254,6 +267,41 @@ export default function SharesPage() { )} + + {/* SAMBA CONFIG TAB */} + {activeTab === "config" && ( + + + Samba Global Configuration + + + {sambaConfig.length === 0 ? ( +

+ No global configuration parameters found. +

+ ) : ( +
+ + + + + + + + + {sambaConfig.map((param, idx) => ( + + + + + ))} + +
ParameterValue
{param.key}{param.value}
+
+ )} +
+
+ )} {/* Dialogs */} diff --git a/frontend/lib/api.ts b/frontend/lib/api.ts index ecc6028..8cb6411 100644 --- a/frontend/lib/api.ts +++ b/frontend/lib/api.ts @@ -282,6 +282,11 @@ export class ZFSManagerAPI { return response.data } + async getSambaConfig(): Promise<{ parameters: Array<{ key: string; value: string }> }> { + const response = await this.client.get("/api/shares/samba/config") + return response.data + } + // Shares — NFS async getNfsShares(): Promise { const response = await this.client.get("/api/shares/nfs")