fix: improve widget deletion UX and add debug logs for persistence

This commit is contained in:
ZacharyZcR
2025-10-09 09:06:50 +08:00
parent a671ad79a1
commit 8623ab896d

View File

@@ -67,7 +67,11 @@ export function Server({
const [hasUnsavedChanges, setHasUnsavedChanges] = React.useState(false); const [hasUnsavedChanges, setHasUnsavedChanges] = React.useState(false);
const statsConfig = React.useMemo((): StatsConfig => { const statsConfig = React.useMemo((): StatsConfig => {
console.log("[Load] Current host config:", currentHostConfig);
console.log("[Load] statsConfig field:", currentHostConfig?.statsConfig);
if (!currentHostConfig?.statsConfig) { if (!currentHostConfig?.statsConfig) {
console.log("[Load] No statsConfig found, using default");
return DEFAULT_STATS_CONFIG; return DEFAULT_STATS_CONFIG;
} }
try { try {
@@ -75,8 +79,10 @@ export function Server({
typeof currentHostConfig.statsConfig === "string" typeof currentHostConfig.statsConfig === "string"
? JSON.parse(currentHostConfig.statsConfig) ? JSON.parse(currentHostConfig.statsConfig)
: currentHostConfig.statsConfig; : currentHostConfig.statsConfig;
console.log("[Load] Parsed statsConfig:", parsed);
return parsed?.widgets ? parsed : DEFAULT_STATS_CONFIG; return parsed?.widgets ? parsed : DEFAULT_STATS_CONFIG;
} catch { } catch (error) {
console.error("[Load] Failed to parse statsConfig:", error);
return DEFAULT_STATS_CONFIG; return DEFAULT_STATS_CONFIG;
} }
}, [currentHostConfig?.statsConfig]); }, [currentHostConfig?.statsConfig]);
@@ -128,17 +134,20 @@ export function Server({
try { try {
const newConfig: StatsConfig = { widgets }; const newConfig: StatsConfig = { widgets };
console.log("[Save] Saving layout:", newConfig);
const { updateSSHHost } = await import("@/ui/main-axios.ts"); const { updateSSHHost } = await import("@/ui/main-axios.ts");
await updateSSHHost(currentHostConfig.id, { const result = await updateSSHHost(currentHostConfig.id, {
...currentHostConfig, ...currentHostConfig,
statsConfig: JSON.stringify(newConfig), statsConfig: JSON.stringify(newConfig),
} as any); } as any);
console.log("[Save] Server response:", result);
setHasUnsavedChanges(false); setHasUnsavedChanges(false);
toast.success(t("serverStats.layoutSaved")); toast.success(t("serverStats.layoutSaved"));
window.dispatchEvent(new Event("ssh-hosts:changed")); window.dispatchEvent(new Event("ssh-hosts:changed"));
} catch (error) { } catch (error) {
console.error("[Save] Failed to save layout:", error);
toast.error(t("serverStats.failedToSaveLayout")); toast.error(t("serverStats.failedToSaveLayout"));
} }
}; };
@@ -153,13 +162,17 @@ export function Server({
{isEditMode && ( {isEditMode && (
<button <button
onClick={(e) => handleDeleteWidget(widget.id, e)} onClick={(e) => handleDeleteWidget(widget.id, e)}
className="absolute top-2 right-2 z-[9999] w-6 h-6 bg-red-500/80 hover:bg-red-500 text-white rounded-full flex items-center justify-center cursor-pointer" onPointerDown={(e) => e.stopPropagation()}
onMouseDown={(e) => e.stopPropagation()}
className="absolute top-2 right-2 z-[9999] w-7 h-7 bg-red-500/90 hover:bg-red-600 text-white rounded-full flex items-center justify-center cursor-pointer shadow-lg"
type="button" type="button"
> >
<X className="h-4 w-4" /> <X className="h-4 w-4" />
</button> </button>
)} )}
<div className="flex items-center gap-2 mb-3"> <div
className={`flex items-center gap-2 mb-3 ${isEditMode ? "drag-handle cursor-move" : ""}`}
>
<Cpu className="h-5 w-5 text-blue-400" /> <Cpu className="h-5 w-5 text-blue-400" />
<h3 className="font-semibold text-lg text-white"> <h3 className="font-semibold text-lg text-white">
{config.label} {config.label}
@@ -205,13 +218,17 @@ export function Server({
{isEditMode && ( {isEditMode && (
<button <button
onClick={(e) => handleDeleteWidget(widget.id, e)} onClick={(e) => handleDeleteWidget(widget.id, e)}
className="absolute top-2 right-2 z-[9999] w-6 h-6 bg-red-500/80 hover:bg-red-500 text-white rounded-full flex items-center justify-center cursor-pointer" onPointerDown={(e) => e.stopPropagation()}
onMouseDown={(e) => e.stopPropagation()}
className="absolute top-2 right-2 z-[9999] w-7 h-7 bg-red-500/90 hover:bg-red-600 text-white rounded-full flex items-center justify-center cursor-pointer shadow-lg"
type="button" type="button"
> >
<X className="h-4 w-4" /> <X className="h-4 w-4" />
</button> </button>
)} )}
<div className="flex items-center gap-2 mb-3"> <div
className={`flex items-center gap-2 mb-3 ${isEditMode ? "drag-handle cursor-move" : ""}`}
>
<MemoryStick className="h-5 w-5 text-green-400" /> <MemoryStick className="h-5 w-5 text-green-400" />
<h3 className="font-semibold text-lg text-white"> <h3 className="font-semibold text-lg text-white">
{config.label} {config.label}
@@ -268,13 +285,17 @@ export function Server({
{isEditMode && ( {isEditMode && (
<button <button
onClick={(e) => handleDeleteWidget(widget.id, e)} onClick={(e) => handleDeleteWidget(widget.id, e)}
className="absolute top-2 right-2 z-[9999] w-6 h-6 bg-red-500/80 hover:bg-red-500 text-white rounded-full flex items-center justify-center cursor-pointer" onPointerDown={(e) => e.stopPropagation()}
onMouseDown={(e) => e.stopPropagation()}
className="absolute top-2 right-2 z-[9999] w-7 h-7 bg-red-500/90 hover:bg-red-600 text-white rounded-full flex items-center justify-center cursor-pointer shadow-lg"
type="button" type="button"
> >
<X className="h-4 w-4" /> <X className="h-4 w-4" />
</button> </button>
)} )}
<div className="flex items-center gap-2 mb-3"> <div
className={`flex items-center gap-2 mb-3 ${isEditMode ? "drag-handle cursor-move" : ""}`}
>
<HardDrive className="h-5 w-5 text-orange-400" /> <HardDrive className="h-5 w-5 text-orange-400" />
<h3 className="font-semibold text-lg text-white"> <h3 className="font-semibold text-lg text-white">
{config.label} {config.label}
@@ -663,7 +684,7 @@ export function Server({
isDraggable={isEditMode} isDraggable={isEditMode}
isResizable={isEditMode} isResizable={isEditMode}
onLayoutChange={handleLayoutChange} onLayoutChange={handleLayoutChange}
draggableHandle={isEditMode ? undefined : ".no-drag"} draggableHandle={isEditMode ? ".drag-handle" : ".no-drag"}
> >
{widgets.map((widget) => ( {widgets.map((widget) => (
<div key={widget.id} className="relative"> <div key={widget.id} className="relative">