From c3d1c7febfb2207327dd82a15e7815a718649cf9 Mon Sep 17 00:00:00 2001 From: mateaix <7333791@qq.com> Date: Mon, 14 Sep 2026 01:50:04 +0800 Subject: [PATCH] Invalidate stale artifact diagnostics on detail refresh --- .../execution/ExecutionEvidenceList.vue | 23 ++++++--- .../__tests__/ExecutionEvidenceList.test.ts | 48 +++++++++++++++++++ 2 files changed, 65 insertions(+), 6 deletions(-) diff --git a/mateclaw-ui/src/components/execution/ExecutionEvidenceList.vue b/mateclaw-ui/src/components/execution/ExecutionEvidenceList.vue index af30911a..4d91e0c8 100644 --- a/mateclaw-ui/src/components/execution/ExecutionEvidenceList.vue +++ b/mateclaw-ui/src/components/execution/ExecutionEvidenceList.vue @@ -17,7 +17,15 @@ const checkFields = ref>({}) const checkLoading = ref>({}) const checkErrors = ref>({}) const checkResults = ref>({}) +let checkGeneration: Record = {} +function invalidateCheck(id: string) { + checkGeneration[id] = (checkGeneration[id] ?? 0) + 1 + delete checkLoading.value[id] + delete checkErrors.value[id] + delete checkResults.value[id] +} function clearChecks() { + checkGeneration = {} checkFields.value = {} checkLoading.value = {} checkErrors.value = {} @@ -66,6 +74,7 @@ async function loadDetail(id: string, event: Event) { if (!(event.target as HTMLDetailsElement).open || detailLoading.value[id]) return const request = generation detailLoading.value[id] = true + invalidateCheck(id) delete detailErrors.value[id] try { const { data } = await executionEvidenceApi.get(id) @@ -86,7 +95,7 @@ async function loadDetail(id: string, event: Event) { } } async function checkJson(id: string) { - if (checkLoading.value[id]) return + if (loading.value || detailLoading.value[id] || checkLoading.value[id]) return const fields = (checkFields.value[id] ?? '').split(/\r?\n/).filter(field => field.length > 0) delete checkResults.value[id] delete checkErrors.value[id] @@ -96,17 +105,19 @@ async function checkJson(id: string) { return } const request = generation + const checkRequest = checkGeneration[id] ?? 0 + const isCurrent = () => request === generation && checkRequest === (checkGeneration[id] ?? 0) checkLoading.value[id] = true try { const { data } = await executionEvidenceApi.checkJson(id, fields) - if (request !== generation || !items.value.some(item => item.id === id)) return + if (!isCurrent() || !items.value.some(item => item.id === id)) return checkResults.value[id] = data if (data.status === 'UNAVAILABLE') { items.value = items.value.map(item => item.id === id ? { ...item, artifactRef: null, artifactDigest: null, summary: null, validity: 'UNAVAILABLE' } : item) } } catch (error) { - if (request !== generation) return + if (!isCurrent()) return const failure = error as { code?: number; response?: { status?: number } } const code = failure.response?.status ?? failure.code if (code === 401 || code === 403 || code === 404) { @@ -117,7 +128,7 @@ async function checkJson(id: string) { checkErrors.value[id] = code === 400 ? 'executionEvidence.jsonCheck.inputError' : 'executionEvidence.loadError' } } finally { - if (request === generation) delete checkLoading.value[id] + if (isCurrent()) delete checkLoading.value[id] } } function toggle() { @@ -178,10 +189,10 @@ onBeforeUnmount(() => { generation++ })