Fixed auto-update toggle to refresh upon save

This commit is contained in:
Muhammad Ibrahim
2025-09-26 01:05:49 +01:00
parent 641272dfb8
commit 527b0ccc3c
3 changed files with 127 additions and 10 deletions

View File

@@ -1073,7 +1073,7 @@ router.patch(
});
res.json({
message: `Host auto-update ${autoUpdate ? "enabled" : "disabled"} successfully`,
message: `Host auto-update ${auto_update ? "enabled" : "disabled"} successfully`,
host: {
id: host.id,
friendlyName: host.friendly_name,

View File

@@ -0,0 +1,106 @@
import { Check, Edit2, X } from "lucide-react";
import { useEffect, useState } from "react";
const InlineToggle = ({
value,
onSave,
onCancel,
className = "",
disabled = false,
trueLabel = "Yes",
falseLabel = "No",
}) => {
const [isEditing, setIsEditing] = useState(false);
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState("");
useEffect(() => {
// Auto-save when value changes during editing
if (isEditing && !isLoading) {
handleSave(!value);
}
}, [isEditing]);
const handleEdit = () => {
if (disabled) return;
setIsEditing(true);
setError("");
};
const handleCancel = () => {
setIsEditing(false);
setError("");
if (onCancel) onCancel();
};
const handleSave = async (newValue) => {
if (disabled || isLoading) return;
// Check if value actually changed
if (newValue === value) {
setIsEditing(false);
return;
}
setIsLoading(true);
setError("");
try {
await onSave(newValue);
setIsEditing(false);
} catch (err) {
setError(err.message || "Failed to save");
} finally {
setIsLoading(false);
}
};
const handleToggle = () => {
if (disabled || isLoading) return;
handleSave(!value);
};
const displayValue = (
<span
className={`text-sm font-medium ${
value
? "text-green-600 dark:text-green-400"
: "text-red-600 dark:text-red-400"
}`}
>
{value ? trueLabel : falseLabel}
</span>
);
return (
<div className={`flex items-center gap-2 group ${className}`}>
{displayValue}
{!disabled && (
<button
type="button"
onClick={handleToggle}
disabled={isLoading}
className={`relative inline-flex h-5 w-9 items-center rounded-full transition-colors focus:outline-none focus:ring-2 focus:ring-primary-500 focus:ring-offset-2 disabled:opacity-50 disabled:cursor-not-allowed ${
value
? "bg-primary-600 dark:bg-primary-500"
: "bg-secondary-200 dark:bg-secondary-600"
}`}
title={`Toggle ${value ? "off" : "on"}`}
>
<span
className={`inline-block h-3 w-3 transform rounded-full bg-white transition-transform ${
value ? "translate-x-5" : "translate-x-1"
}`}
/>
</button>
)}
{error && (
<span className="text-xs text-red-600 dark:text-red-400">
{error}
</span>
)}
</div>
);
};
export default InlineToggle;

View File

@@ -27,6 +27,7 @@ import { useEffect, useId, useMemo, useState } from "react";
import { Link, useNavigate, useSearchParams } from "react-router-dom";
import InlineEdit from "../components/InlineEdit";
import InlineGroupEdit from "../components/InlineGroupEdit";
import InlineToggle from "../components/InlineToggle";
import {
adminHostsAPI,
dashboardAPI,
@@ -471,6 +472,14 @@ const Hosts = () => {
},
});
const toggleAutoUpdateMutation = useMutation({
mutationFn: ({ hostId, autoUpdate }) =>
adminHostsAPI.toggleAutoUpdate(hostId, autoUpdate).then((res) => res.data),
onSuccess: () => {
queryClient.invalidateQueries(["hosts"]);
},
});
const bulkDeleteMutation = useMutation({
mutationFn: (hostIds) => adminHostsAPI.deleteBulk(hostIds),
onSuccess: (data) => {
@@ -818,15 +827,17 @@ const Hosts = () => {
);
case "auto_update":
return (
<span
className={`text-sm font-medium ${
host.auto_update
? "text-green-600 dark:text-green-400"
: "text-red-600 dark:text-red-400"
}`}
>
{host.auto_update ? "Yes" : "No"}
</span>
<InlineToggle
value={host.auto_update}
onSave={(autoUpdate) =>
toggleAutoUpdateMutation.mutate({
hostId: host.id,
autoUpdate: autoUpdate,
})
}
trueLabel="Yes"
falseLabel="No"
/>
);
case "status":
return (