fix(ui): keep resource scaling form values while user is editing
Skip syncing form state from the 5s resources poll when the form is dirty, and reset dirty only after apply or workload tab change. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -70,6 +70,7 @@ export default function AppDetailPage() {
|
||||
replicas: 1,
|
||||
});
|
||||
const [scaleWorkload, setScaleWorkload] = useState<'app' | 'database' | 'redis' | 'rabbitmq'>('app');
|
||||
const [resourceFormDirty, setResourceFormDirty] = useState(false);
|
||||
const [showDbDiskExpand, setShowDbDiskExpand] = useState(false);
|
||||
const [dbStorageSize, setDbStorageSize] = useState('1');
|
||||
const [dbStorageLoading, setDbStorageLoading] = useState(false);
|
||||
@@ -467,8 +468,19 @@ export default function AppDetailPage() {
|
||||
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
||||
};
|
||||
|
||||
// Sync form when resource data loads (selected workload)
|
||||
const patchResourceForm = (patch: Partial<typeof resourceForm>) => {
|
||||
setResourceFormDirty(true);
|
||||
setResourceForm((f) => ({ ...f, ...patch }));
|
||||
};
|
||||
|
||||
// Sync form when workload changes or when live metrics refresh — but not while user is editing.
|
||||
useEffect(() => {
|
||||
setResourceFormDirty(false);
|
||||
}, [scaleWorkload]);
|
||||
|
||||
useEffect(() => {
|
||||
if (resourceFormDirty) return;
|
||||
|
||||
const workloads = resourceUsage?.workloads;
|
||||
const w =
|
||||
workloads?.find((x) => x.key === scaleWorkload) ||
|
||||
@@ -487,7 +499,7 @@ export default function AppDetailPage() {
|
||||
replicas: w.configured.replicas ?? 1,
|
||||
});
|
||||
}
|
||||
}, [resourceUsage, scaleWorkload]);
|
||||
}, [resourceUsage, scaleWorkload, resourceFormDirty]);
|
||||
|
||||
// Auto-scroll logs to bottom
|
||||
useEffect(() => {
|
||||
@@ -560,6 +572,7 @@ export default function AppDetailPage() {
|
||||
mutationFn: (data: { cpuRequest?: string; cpuLimit?: string; memoryRequest?: string; memoryLimit?: string; replicas?: number }) =>
|
||||
api.post(`/billing/applications/${appId}/upgrade`, data),
|
||||
onSuccess: (res) => {
|
||||
setResourceFormDirty(false);
|
||||
invalidateAll();
|
||||
queryClient.invalidateQueries({ queryKey: ['resources', appId] });
|
||||
queryClient.invalidateQueries({ queryKey: ['wallet'] });
|
||||
@@ -585,6 +598,7 @@ export default function AppDetailPage() {
|
||||
memoryLimit?: string;
|
||||
}) => api.patch(`/applications/${appId}/resources`, data),
|
||||
onSuccess: () => {
|
||||
setResourceFormDirty(false);
|
||||
invalidateAll();
|
||||
queryClient.invalidateQueries({ queryKey: ['resources', appId] });
|
||||
toast.success('Resources updated');
|
||||
@@ -2107,7 +2121,7 @@ export default function AppDetailPage() {
|
||||
<input
|
||||
type="text"
|
||||
value={resourceForm.cpuRequest}
|
||||
onChange={(e) => setResourceForm((f) => ({ ...f, cpuRequest: e.target.value }))}
|
||||
onChange={(e) => patchResourceForm({ cpuRequest: e.target.value })}
|
||||
className="input-field text-sm"
|
||||
placeholder="100m"
|
||||
/>
|
||||
@@ -2117,7 +2131,7 @@ export default function AppDetailPage() {
|
||||
<input
|
||||
type="text"
|
||||
value={resourceForm.cpuLimit}
|
||||
onChange={(e) => setResourceForm((f) => ({ ...f, cpuLimit: e.target.value }))}
|
||||
onChange={(e) => patchResourceForm({ cpuLimit: e.target.value })}
|
||||
className="input-field text-sm"
|
||||
placeholder="500m"
|
||||
/>
|
||||
@@ -2127,7 +2141,7 @@ export default function AppDetailPage() {
|
||||
<input
|
||||
type="text"
|
||||
value={resourceForm.memoryRequest}
|
||||
onChange={(e) => setResourceForm((f) => ({ ...f, memoryRequest: e.target.value }))}
|
||||
onChange={(e) => patchResourceForm({ memoryRequest: e.target.value })}
|
||||
className="input-field text-sm"
|
||||
placeholder="128Mi"
|
||||
/>
|
||||
@@ -2137,7 +2151,7 @@ export default function AppDetailPage() {
|
||||
<input
|
||||
type="text"
|
||||
value={resourceForm.memoryLimit}
|
||||
onChange={(e) => setResourceForm((f) => ({ ...f, memoryLimit: e.target.value }))}
|
||||
onChange={(e) => patchResourceForm({ memoryLimit: e.target.value })}
|
||||
className="input-field text-sm"
|
||||
placeholder="512Mi"
|
||||
/>
|
||||
@@ -2148,7 +2162,7 @@ export default function AppDetailPage() {
|
||||
<div className="flex items-center gap-2">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setResourceForm((f) => ({ ...f, replicas: Math.max(1, f.replicas - 1) }))}
|
||||
onClick={() => patchResourceForm({ replicas: Math.max(1, resourceForm.replicas - 1) })}
|
||||
className="btn-icon w-9 h-9"
|
||||
>
|
||||
−
|
||||
@@ -2156,7 +2170,7 @@ export default function AppDetailPage() {
|
||||
<span className="text-lg font-bold text-gray-800 w-8 text-center">{resourceForm.replicas}</span>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setResourceForm((f) => ({ ...f, replicas: Math.min(10, f.replicas + 1) }))}
|
||||
onClick={() => patchResourceForm({ replicas: Math.min(10, resourceForm.replicas + 1) })}
|
||||
className="btn-icon w-9 h-9"
|
||||
>
|
||||
+
|
||||
|
||||
Reference in New Issue
Block a user