From 96d42ee3e1e14d2f56854b4f60528ed567c34b9a Mon Sep 17 00:00:00 2001 From: Ivan087 Date: Wed, 13 May 2026 15:51:55 +0800 Subject: [PATCH] fix: scale replicas in response, YAML lineWidth, delta values, modified keys - Scale API now returns actual replicas in instance response - ModifyModal: fix YAML stringify line breaking (lineWidth: 0) - ModifyModal: show modified keys summary above YAML editor - ModifyModal: only send delta (user-modified) values to server - Add diffObjects helper for deep object comparison --- .../input/http/rest/instance_handler.go | 5 +- .../instances/components/ModifyModal.tsx | 82 +++++++++++++++++-- 2 files changed, 81 insertions(+), 6 deletions(-) diff --git a/backend/internal/adapter/input/http/rest/instance_handler.go b/backend/internal/adapter/input/http/rest/instance_handler.go index de4c5fc..22b55fb 100644 --- a/backend/internal/adapter/input/http/rest/instance_handler.go +++ b/backend/internal/adapter/input/http/rest/instance_handler.go @@ -393,8 +393,11 @@ func (h *InstanceHandler) ScaleInstance(w http.ResponseWriter, r *http.Request) return } + instResp := convertInstanceResponse(result, true) + instResp.Replicas = req.Replicas + respondJSON(w, http.StatusOK, dto.ScaleInstanceResponse{ - Instance: convertInstanceResponse(result, true), + Instance: instResp, Replicas: req.Replicas, Message: fmt.Sprintf("Scaled to %d replicas", req.Replicas), }) diff --git a/frontend/src/features/artifact/instances/components/ModifyModal.tsx b/frontend/src/features/artifact/instances/components/ModifyModal.tsx index 8fc3a57..f64cf2c 100644 --- a/frontend/src/features/artifact/instances/components/ModifyModal.tsx +++ b/frontend/src/features/artifact/instances/components/ModifyModal.tsx @@ -35,6 +35,8 @@ export const ModifyModal: React.FC = ({ const [valuesYaml, setValuesYaml] = useState(""); const [loading, setLoading] = useState(false); const [error, setError] = useState(null); + const [originalValuesYaml, setOriginalValuesYaml] = useState(""); + const [modifiedKeys, setModifiedKeys] = useState([]); // Values Diff support const [showDiff, setShowDiff] = useState(false); @@ -56,9 +58,10 @@ export const ModifyModal: React.FC = ({ const detail = await getInstance( { clusterId: instance.clusterId, instanceId: instance.id }, ); - // Parse and display existing values as YAML if (detail.values && Object.keys(detail.values).length > 0) { - setValuesYaml(stringifyYaml(detail.values)); + const currentYaml = stringifyYaml(detail.values, { lineWidth: 0 }); + setValuesYaml(currentYaml); + setOriginalValuesYaml(currentYaml); } } catch (err) { console.error('[ModifyModal] Failed to fetch instance detail:', err); @@ -70,6 +73,31 @@ export const ModifyModal: React.FC = ({ loadFullInstance(); }, [instance]); + // Recompute modified keys when valuesYaml or diffData changes + useEffect(() => { + if (!diffData?.defaults || !valuesYaml) return; + try { + const current = parseYaml(valuesYaml); + const defaults = diffData.defaults; + const changed: string[] = []; + const walkKeys = (curr: any, def: any, prefix: string) => { + if (curr === null || curr === undefined) return; + if (typeof curr !== 'object') return; + for (const key of Object.keys(curr)) { + const fullKey = prefix ? `${prefix}.${key}` : key; + if (JSON.stringify(curr[key]) !== JSON.stringify(def?.[key])) { + changed.push(fullKey); + } + if (typeof curr[key] === 'object' && curr[key] !== null && !Array.isArray(curr[key])) { + walkKeys(curr[key], def?.[key] ?? {}, fullKey); + } + } + }; + walkKeys(current, defaults, ''); + setModifiedKeys(changed); + } catch { /* ignore parse errors */ } + }, [valuesYaml, diffData]); + const loadValuesDiff = async () => { if (!instance.clusterId || !instance.id) return; @@ -91,7 +119,7 @@ export const ModifyModal: React.FC = ({ const applyDefaults = () => { if (!diffData?.defaults) return; - setValuesYaml(stringifyYaml(diffData.defaults)); + setValuesYaml(stringifyYaml(diffData.defaults, { lineWidth: 0 })); }; /** @@ -123,16 +151,29 @@ export const ModifyModal: React.FC = ({ }); }; + const computeDeltaValues = (): Record | undefined => { + if (!valuesYaml.trim()) return undefined; + try { + const current = parseYaml(valuesYaml); + if (!originalValuesYaml) return current; // no original to compare against + const original = parseYaml(originalValuesYaml); + return diffObjects(current, original); + } catch { + return parseValuesYaml(valuesYaml); + } + }; + const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); setLoading(true); setError(null); try { + const deltaValues = computeDeltaValues(); const payload: UpdateInstanceRequest = { version: tag && tag !== instance.version ? tag : undefined, description: description.trim() || undefined, - values: valuesYaml.trim() ? parseValuesYaml(valuesYaml) : undefined, + values: deltaValues, valuesYaml: valuesYaml.trim() || undefined, }; @@ -235,8 +276,18 @@ export const ModifyModal: React.FC = ({ Configuration Values

- Editing current deployed values. Changes are merged with existing release values (--reuse-values). + Editing current deployed values. Only modified keys are sent to the server.

+ {modifiedKeys.length > 0 && ( +
+ Modified: + {modifiedKeys.map((k) => ( + + {k} + + ))} +
+ )}