From 5b40d44f8472bbdbe9f694ac639d7cec056f1555 Mon Sep 17 00:00:00 2001 From: Juan Alcantara Date: Fri, 4 Sep 2026 11:33:51 +0200 Subject: [PATCH 1/2] =?UTF-8?q?=F0=9F=90=9B=20Append=20saved=20comment=20t?= =?UTF-8?q?o=20local=20state=20after=20postFlawComment?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After a public/private comment was posted, the resolved comment object was passed directly to afterSaveSuccess() as its queue argument. afterSaveSuccess() expected an array of callbacks and called .map() on it, causing a silent TypeError. More critically, flaw.value.comments was never updated, so the new comment was invisible until a full page reload. Fix: use the comment object already returned by postFlawComment to append it to flaw.value.comments, then call afterSaveSuccess() with no arguments matching its () => void signature. Test: 'should append the saved comment to flaw.value.comments' --- .../__tests__/useFlawCommentsModel.spec.ts | 15 +++++++++++++++ src/composables/useFlawCommentsModel.ts | 5 ++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/composables/__tests__/useFlawCommentsModel.spec.ts b/src/composables/__tests__/useFlawCommentsModel.spec.ts index 5da2cb2c5..5efc6fe1a 100644 --- a/src/composables/__tests__/useFlawCommentsModel.spec.ts +++ b/src/composables/__tests__/useFlawCommentsModel.spec.ts @@ -115,6 +115,21 @@ describe('useFlawCommentsModel', () => { expect(isSaving.value).toBe(false); }); + it('should append the saved comment to flaw.value.comments', async () => { + flaw.value.comments = []; + const savedComment = { + uuid: 'c1', text: 'new note', is_private: false, creator: 'creator', created_dt: '2026-01-01T00:00:00Z', + }; + vi.mocked(postFlawComment).mockResolvedValue(savedComment as any); + const { addFlawComment } = useFlawCommentsModel(flaw, isSaving, afterSaveSuccess); + + addFlawComment('new note', 'creator', 'Public'); + await flushPromises(); + + expect(flaw.value.comments).toHaveLength(1); + expect(flaw.value.comments[0]).toMatchObject({ text: 'new note', is_private: false }); + }); + it('should add an internal comment', async () => { vi.mocked(postJiraComment).mockResolvedValue({}); const { addFlawComment } = useFlawCommentsModel(flaw, isSaving, afterSaveSuccess); diff --git a/src/composables/useFlawCommentsModel.ts b/src/composables/useFlawCommentsModel.ts index fbecb444b..0c0fde7fc 100644 --- a/src/composables/useFlawCommentsModel.ts +++ b/src/composables/useFlawCommentsModel.ts @@ -94,7 +94,10 @@ export function useFlawCommentsModel(flaw: Ref, isSaving: Ref { + flaw.value.comments.push(newComment); + afterSaveSuccess(); + }) .finally(() => isSaving.value = false); } From 269f6228794854444fd486419cf3ee437ac017ad Mon Sep 17 00:00:00 2001 From: Juan Alcantara Date: Fri, 4 Sep 2026 11:37:59 +0200 Subject: [PATCH 2/2] =?UTF-8?q?=E2=9C=A8=20Expandable=20milestone=20rows?= =?UTF-8?q?=20showing=20notes=20and=20request=20details?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit manual_completion_notes was saved to the backend but never rendered. Add per-milestone expand/collapse rows (chevron toggle) that reveal: - Request Source - Request Received date - Request Text - Notes (manual_completion_notes) Clicking anywhere on the milestone row toggles the detail panel. Action buttons use @click.stop to avoid triggering the toggle. Keyboard accessible via Enter/Space. Tests: hidden by default, expands with content on click, collapses on second click. --- src/components/CRA/SRPReportDetails.vue | 164 +++++++++++++----- .../CRA/__tests__/SRPReportDetails.spec.ts | 75 +++++++- 2 files changed, 191 insertions(+), 48 deletions(-) diff --git a/src/components/CRA/SRPReportDetails.vue b/src/components/CRA/SRPReportDetails.vue index c35d64c73..11510c067 100644 --- a/src/components/CRA/SRPReportDetails.vue +++ b/src/components/CRA/SRPReportDetails.vue @@ -1,4 +1,6 @@