2025-12-07 00:10:35 +01:00
|
|
|
import SwiftUI
|
|
|
|
|
|
|
|
|
|
@MainActor
|
|
|
|
|
struct ConfigSettings: View {
|
2025-12-09 18:04:11 +01:00
|
|
|
private let isPreview = ProcessInfo.processInfo.isPreview
|
2025-12-20 21:32:06 +01:00
|
|
|
private let isNixMode = ProcessInfo.processInfo.isNixMode
|
2026-01-16 14:13:30 -06:00
|
|
|
@Bindable var store: ChannelsStore
|
2025-12-07 00:10:35 +01:00
|
|
|
@State private var hasLoaded = false
|
|
|
|
|
|
2026-01-16 14:13:30 -06:00
|
|
|
init(store: ChannelsStore = .shared) {
|
|
|
|
|
self.store = store
|
2026-01-02 12:25:47 -06:00
|
|
|
}
|
|
|
|
|
|
2025-12-07 00:10:35 +01:00
|
|
|
var body: some View {
|
2026-01-16 14:13:30 -06:00
|
|
|
ScrollView {
|
|
|
|
|
self.content
|
|
|
|
|
}
|
|
|
|
|
.task {
|
|
|
|
|
guard !self.hasLoaded else { return }
|
|
|
|
|
guard !self.isPreview else { return }
|
|
|
|
|
self.hasLoaded = true
|
|
|
|
|
await self.store.loadConfigSchema()
|
|
|
|
|
await self.store.loadConfig()
|
|
|
|
|
}
|
2025-12-17 19:14:54 +00:00
|
|
|
}
|
2026-01-12 05:42:06 +00:00
|
|
|
}
|
2025-12-13 15:55:31 +00:00
|
|
|
|
2026-01-12 05:42:06 +00:00
|
|
|
extension ConfigSettings {
|
2025-12-17 19:14:54 +00:00
|
|
|
private var content: some View {
|
2026-01-16 14:13:30 -06:00
|
|
|
VStack(alignment: .leading, spacing: 16) {
|
2025-12-17 19:14:54 +00:00
|
|
|
self.header
|
2026-01-16 14:13:30 -06:00
|
|
|
if let status = self.store.configStatus {
|
|
|
|
|
Text(status)
|
|
|
|
|
.font(.callout)
|
|
|
|
|
.foregroundStyle(.secondary)
|
|
|
|
|
}
|
|
|
|
|
self.actionRow
|
|
|
|
|
Group {
|
|
|
|
|
if self.store.configSchemaLoading {
|
|
|
|
|
ProgressView().controlSize(.small)
|
|
|
|
|
} else if let schema = self.store.configSchema {
|
|
|
|
|
ConfigSchemaForm(store: self.store, schema: schema, path: [])
|
|
|
|
|
.disabled(self.isNixMode)
|
|
|
|
|
} else {
|
|
|
|
|
Text("Schema unavailable.")
|
|
|
|
|
.font(.caption)
|
|
|
|
|
.foregroundStyle(.secondary)
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-01-17 17:22:30 +00:00
|
|
|
if self.store.configDirty, !self.isNixMode {
|
2026-01-16 14:13:30 -06:00
|
|
|
Text("Unsaved changes")
|
|
|
|
|
.font(.caption)
|
|
|
|
|
.foregroundStyle(.secondary)
|
|
|
|
|
}
|
2025-12-17 19:14:54 +00:00
|
|
|
Spacer(minLength: 0)
|
|
|
|
|
}
|
|
|
|
|
.frame(maxWidth: .infinity, alignment: .leading)
|
|
|
|
|
.padding(.horizontal, 24)
|
|
|
|
|
.padding(.vertical, 18)
|
|
|
|
|
.groupBoxStyle(PlainSettingsGroupBoxStyle())
|
|
|
|
|
}
|
2025-12-13 15:55:31 +00:00
|
|
|
|
2025-12-17 19:14:54 +00:00
|
|
|
@ViewBuilder
|
|
|
|
|
private var header: some View {
|
2026-01-16 14:13:30 -06:00
|
|
|
Text("Config")
|
2025-12-17 19:14:54 +00:00
|
|
|
.font(.title3.weight(.semibold))
|
2025-12-20 21:32:06 +01:00
|
|
|
Text(self.isNixMode
|
2026-01-15 14:40:57 +00:00
|
|
|
? "This tab is read-only in Nix mode. Edit config via Nix and rebuild."
|
2026-01-16 14:13:30 -06:00
|
|
|
: "Edit ~/.clawdbot/clawdbot.json using the schema-driven form.")
|
2025-12-17 19:14:54 +00:00
|
|
|
.font(.callout)
|
|
|
|
|
.foregroundStyle(.secondary)
|
|
|
|
|
}
|
2025-12-13 15:55:31 +00:00
|
|
|
|
2026-01-16 14:13:30 -06:00
|
|
|
private var actionRow: some View {
|
|
|
|
|
HStack(spacing: 10) {
|
|
|
|
|
Button("Reload") {
|
|
|
|
|
Task { await self.store.reloadConfigDraft() }
|
2025-12-17 19:14:54 +00:00
|
|
|
}
|
2026-01-16 14:13:30 -06:00
|
|
|
.disabled(!self.store.configLoaded)
|
2025-12-17 19:14:54 +00:00
|
|
|
|
2026-01-16 14:13:30 -06:00
|
|
|
Button(self.store.isSavingConfig ? "Saving…" : "Save") {
|
|
|
|
|
Task { await self.store.saveConfigDraft() }
|
2025-12-13 18:06:32 +00:00
|
|
|
}
|
2026-01-16 14:13:30 -06:00
|
|
|
.disabled(self.isNixMode || self.store.isSavingConfig || !self.store.configDirty)
|
2025-12-13 18:06:32 +00:00
|
|
|
}
|
2026-01-16 14:13:30 -06:00
|
|
|
.buttonStyle(.bordered)
|
2025-12-13 18:06:32 +00:00
|
|
|
}
|
2025-12-07 00:10:35 +01:00
|
|
|
}
|
2025-12-09 18:04:11 +01:00
|
|
|
|
|
|
|
|
struct ConfigSettings_Previews: PreviewProvider {
|
|
|
|
|
static var previews: some View {
|
|
|
|
|
ConfigSettings()
|
|
|
|
|
}
|
|
|
|
|
}
|