-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathSettingsDialog.tsx
More file actions
129 lines (118 loc) · 4.47 KB
/
SettingsDialog.tsx
File metadata and controls
129 lines (118 loc) · 4.47 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
import { Dialog } from "@base-ui/react";
import { socketService } from "@workspace/core";
import { Badge, Button } from "@workspace/ui";
import { AlertTriangle, CheckCircle2, Loader2, X } from "@workspace/ui/icons";
import { useEffect, useState, useTransition } from "react";
import { config } from "../../../config";
import { DEFAULT_CONFIG } from "../../constants/defaultConfig";
import { useBranches } from "../../hooks/useBranches";
import { useStore } from "../../store/store";
import type { ConfigData } from "../../types/common/config";
import { SettingsForm } from "./SettingsForm";
export const SettingsDialog = () => {
const isSettingsOpen = useStore((s) => s.isSettingsOpen);
const setSettingsOpen = useStore((s) => s.setSettingsOpen);
const setRestarting = useStore((s) => s.setRestarting);
const setConfig = useStore((s) => s.setConfig);
const [localConfig, setLocalConfig] = useState<ConfigData | null>(null);
const [isSynced, setIsSynced] = useState(false);
const [isSaving, startSaving] = useTransition();
const branchesFetch = useBranches(isSettingsOpen);
const loadConfig = async () => {
if (window.electronAPI) {
try {
const config = await window.electronAPI.getConfig();
setLocalConfig(config);
setConfig(config);
setIsSynced(true);
} catch (error) {
console.error("Error loading config:", error);
setLocalConfig(DEFAULT_CONFIG);
setIsSynced(false);
}
} else {
console.log("Electron API not available. Using default config.");
setLocalConfig(DEFAULT_CONFIG);
setIsSynced(false);
}
};
useEffect(() => {
if (isSettingsOpen) {
loadConfig();
}
}, [isSettingsOpen]);
const handleSave = async () => {
startSaving(async () => {
if (window.electronAPI) {
await window.electronAPI.saveConfig(localConfig);
} else {
console.log("Electron API not available. Using default config.");
}
setRestarting(true);
setTimeout(() => {
socketService.connect();
setSettingsOpen(false);
setRestarting(false);
}, config.SETTINGS_RESPONSE_TIMEOUT);
});
};
return (
<Dialog.Root open={isSettingsOpen} onOpenChange={setSettingsOpen}>
<Dialog.Portal>
<Dialog.Backdrop className="fixed inset-0 z-50 bg-black/50" />
<Dialog.Popup className="bg-background fixed left-1/2 top-1/2 z-50 flex max-h-[85vh] min-w-[800px] max-w-2xl -translate-x-1/2 -translate-y-1/2 flex-col gap-4 rounded-lg border p-6 shadow-lg">
{/* Header */}
<div className="flex flex-col gap-2 pr-5">
<div className="flex items-center justify-between">
<Dialog.Title className="text-lg font-semibold leading-none">
System Configuration
</Dialog.Title>
<Badge className="gap-1 px-2 py-1">
{isSynced ? (
<>
<CheckCircle2 className="h-3 w-3" /> Synced with backend
</>
) : (
<>
<AlertTriangle className="h-3 w-3" /> Not synced with real
configuration
</>
)}
</Badge>
</div>
</div>
{/* Body */}
<div className="flex-1 overflow-y-auto px-1">
{localConfig && (
<SettingsForm
config={localConfig}
onChange={setLocalConfig}
branchesFetch={branchesFetch}
/>
)}
</div>
{/* Footer */}
<div className="flex flex-col-reverse gap-2 border-t pt-4 sm:flex-row sm:justify-end">
<Button variant="ghost" onClick={() => setSettingsOpen(false)}>
Cancel
</Button>
<Button onClick={handleSave} disabled={isSaving}>
{isSaving ? (
<>
<Loader2 className="h-4 w-4 animate-spin" /> Saving...
</>
) : (
"Save Changes"
)}
</Button>
</div>
{/* Close button */}
<Dialog.Close className="rounded-xs absolute right-4 top-4 opacity-70 transition-opacity hover:opacity-100 disabled:pointer-events-none [&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none">
<X />
<span className="sr-only">Close</span>
</Dialog.Close>
</Dialog.Popup>
</Dialog.Portal>
</Dialog.Root>
);
};