From b87f367583cab06c5c1be418b3db9a0eafe6952c Mon Sep 17 00:00:00 2001 From: Andy Lee Date: Fri, 31 Jul 2026 16:55:25 +0800 Subject: [PATCH] fix: prevent VM detail page hang when static IP assigned (#1072) Make syncStaticIpAnnotations idempotent so it no longer mutates VM annotations when already in sync, breaking a reactive update loop that froze the browser on the VM detail page. Also stack multiple IP addresses vertically in the IP Address column. Signed-off-by: Andy Lee --- .../formatters/HarvesterIpAddress.vue | 18 ++++++++-- pkg/harvester/mixins/harvester-vm/index.js | 35 +++++++++++++++---- 2 files changed, 44 insertions(+), 9 deletions(-) diff --git a/pkg/harvester/formatters/HarvesterIpAddress.vue b/pkg/harvester/formatters/HarvesterIpAddress.vue index 04eff11d..468de23d 100644 --- a/pkg/harvester/formatters/HarvesterIpAddress.vue +++ b/pkg/harvester/formatters/HarvesterIpAddress.vue @@ -132,16 +132,28 @@ export default { + + diff --git a/pkg/harvester/mixins/harvester-vm/index.js b/pkg/harvester/mixins/harvester-vm/index.js index 5c227a1e..1243fd2f 100644 --- a/pkg/harvester/mixins/harvester-vm/index.js +++ b/pkg/harvester/mixins/harvester-vm/index.js @@ -791,18 +791,41 @@ export default { } const staticIpPrefix = `${ HCI_ANNOTATIONS.STATIC_IP }/`; + const annotations = vm.metadata.annotations; - Object.keys(vm.metadata.annotations).forEach((key) => { - if (key.startsWith(staticIpPrefix)) { - delete vm.metadata.annotations[key]; - } - }); + const desired = {}; this.networkRows.forEach((row) => { if (row.name && row.staticIp) { - vm.metadata.annotations[`${ staticIpPrefix }${ row.name }`] = row.staticIp; + desired[`${ staticIpPrefix }${ row.name }`] = row.staticIp; } }); + + const current = {}; + + Object.keys(annotations).forEach((key) => { + if (key.startsWith(staticIpPrefix)) { + current[key] = annotations[key]; + } + }); + + // Skip mutation when already in sync to avoid triggering a reactive update loop. + const desiredKeys = Object.keys(desired); + const currentKeys = Object.keys(current); + const isSame = desiredKeys.length === currentKeys.length && + desiredKeys.every((key) => current[key] === desired[key]); + + if (isSame) { + return; + } + + currentKeys.forEach((key) => { + delete annotations[key]; + }); + + Object.entries(desired).forEach(([key, value]) => { + annotations[key] = value; + }); }, setCPUAndMemory() {