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 <patrick@perlbach24.de>
This commit is contained in:
@@ -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"""
|
||||
|
||||
@@ -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<any[]>([])
|
||||
const [nfsShares, setNfsShares] = useState<any[]>([])
|
||||
const [sambaConfig, setSambaConfig] = useState<any[]>([])
|
||||
const [loading, setLoading] = useState(true)
|
||||
const [error, setError] = useState<string | null>(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
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setActiveTab("config")}
|
||||
className={`px-4 py-2 font-medium transition-colors ${
|
||||
activeTab === "config"
|
||||
? "border-b-2 border-primary text-primary"
|
||||
: "text-muted-foreground hover:text-foreground"
|
||||
}`}
|
||||
>
|
||||
Samba Config
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -254,6 +267,41 @@ export default function SharesPage() {
|
||||
</CardContent>
|
||||
</Card>
|
||||
)}
|
||||
|
||||
{/* SAMBA CONFIG TAB */}
|
||||
{activeTab === "config" && (
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Samba Global Configuration</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
{sambaConfig.length === 0 ? (
|
||||
<p className="text-muted-foreground text-center py-12">
|
||||
No global configuration parameters found.
|
||||
</p>
|
||||
) : (
|
||||
<div className="overflow-x-auto">
|
||||
<table className="w-full text-sm">
|
||||
<thead className="border-b border-border bg-muted/30">
|
||||
<tr>
|
||||
<th className="text-left py-3 px-4 font-medium w-40">Parameter</th>
|
||||
<th className="text-left py-3 px-4 font-medium">Value</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{sambaConfig.map((param, idx) => (
|
||||
<tr key={idx} className="border-b border-border/50 hover:bg-muted/30">
|
||||
<td className="py-3 px-4 font-mono text-xs font-medium text-blue-600">{param.key}</td>
|
||||
<td className="py-3 px-4 text-xs font-mono break-all">{param.value}</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
)}
|
||||
</main>
|
||||
|
||||
{/* Dialogs */}
|
||||
|
||||
@@ -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<NfsShare[]> {
|
||||
const response = await this.client.get("/api/shares/nfs")
|
||||
|
||||
Reference in New Issue
Block a user