[CSM Portal] collect Post Resolution Activity when closing or proposing a solution - #1094
Conversation
…ng a solution PRs wso2-open-operations#1074/wso2-open-operations#1077 added resolutionCode, cause, and closeNotes to PATCH /cases/{id} at the API contract level (entity-service + BFF openapi.yaml passthrough), but no UI was ever built to collect them — Close and Propose Solution just fired a plain state PATCH. Adds a ResolutionDialog (resolution code + cause selects, required; free-text close notes, optional) that opens for both transitions instead of the old plain yes/no confirm — it doubles as the confirmation step, so CaseActionBar's now-unused confirm mechanism is removed. Submitting PATCHes state + resolutionCode + cause + closeNotes in one call, per the existing contract.
📝 WalkthroughWalkthroughThis PR replaces the in-component confirmation dialog in CaseActionBar with a new ResolutionDialog component that collects resolution code, cause, and close notes before closing a case or proposing a solution. Backend types are extended, and CsmCaseDetailPage is updated to orchestrate the new dialog flow. ChangesCase resolution dialog workflow
Estimated code review effort: 3 (Moderate) | ~25 minutes Sequence Diagram(s)sequenceDiagram
participant User
participant CaseActionBar
participant CsmCaseDetailPage
participant ResolutionDialog
participant BackendAPI
User->>CaseActionBar: Click "Close" or "Propose Solution"
CaseActionBar->>CsmCaseDetailPage: onAction(action, targetState)
CsmCaseDetailPage->>CsmCaseDetailPage: setResolutionDialog(action, targetState)
CsmCaseDetailPage->>ResolutionDialog: render with kind/isSubmitting
User->>ResolutionDialog: select resolutionCode, cause, enter closeNotes
User->>ResolutionDialog: click confirm
ResolutionDialog->>CsmCaseDetailPage: onSubmit({resolutionCode, cause, closeNotes})
CsmCaseDetailPage->>BackendAPI: PATCH case {state, resolutionCode, cause, closeNotes}
BackendAPI-->>CsmCaseDetailPage: success/error
CsmCaseDetailPage->>CsmCaseDetailPage: close dialog, show feedback/error
Possibly related PRs
Suggested labels: Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
…ialog # Conflicts: # apps/csm-portal/webapp/src/features/csm-cases/pages/CsmCaseDetailPage.tsx
…ialog # Conflicts: # apps/csm-portal/webapp/src/features/csm-cases/pages/CsmCaseDetailPage.tsx
|
@coderabbitai resume |
✅ Action performedReviews resumed. |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
apps/csm-portal/webapp/src/api/backend/types.ts (1)
415-425: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick winConsider splitting the state branch to enforce the resolution-field constraint at the type level.
The comment on line 421 documents that
resolutionCode,cause, andcloseNotesare only accepted by the backend alongsidestate: "closed"or"solution_proposed", but the type allows them with anyBeCaseState. This means TypeScript won't catch a payload like{ state: "open", resolutionCode: "SOLVED_BY_CUSTOMER" }that the backend would reject. Splitting the branch — consistent with the?: neverpattern already used forseverity,workState, etc. — would enforce the contract at compile time.♻️ Proposed type refinement
export type BeCaseUpdatePayload = | { - state: BeCaseState; + state: "closed" | "solution_proposed"; severity?: never; workState?: never; assigneeEmail?: never; watchList?: never; /** Post Resolution Activity — only meaningful (and only accepted by the backend) alongside `state: "closed"` or `"solution_proposed"`. */ resolutionCode?: BeCaseResolutionCode; cause?: BeCaseCause; closeNotes?: string; } + | { + state: Exclude<BeCaseState, "closed" | "solution_proposed">; + severity?: never; + workState?: never; + assigneeEmail?: never; + watchList?: never; + resolutionCode?: never; + cause?: never; + closeNotes?: never; + } | { state?: never; severity: BeCaseSeverity; workState?: never; assigneeEmail?: never; watchList?: never }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/csm-portal/webapp/src/api/backend/types.ts` around lines 415 - 425, The `BeCase` payload union in `types.ts` currently allows `resolutionCode`, `cause`, and `closeNotes` for any `BeCaseState`, even though they should only be valid with `state: "closed"` or `"solution_proposed"`. Update the `state` branch in the relevant type definition to split those cases at the type level, following the existing `?: never` pattern used for `severity`, `workState`, and `assigneeEmail`. Make sure the `resolutionCode`/`cause`/`closeNotes` fields are only present in the allowed states so TypeScript rejects invalid combinations like an open case with resolution fields.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@apps/csm-portal/webapp/src/api/backend/types.ts`:
- Around line 415-425: The `BeCase` payload union in `types.ts` currently allows
`resolutionCode`, `cause`, and `closeNotes` for any `BeCaseState`, even though
they should only be valid with `state: "closed"` or `"solution_proposed"`.
Update the `state` branch in the relevant type definition to split those cases
at the type level, following the existing `?: never` pattern used for
`severity`, `workState`, and `assigneeEmail`. Make sure the
`resolutionCode`/`cause`/`closeNotes` fields are only present in the allowed
states so TypeScript rejects invalid combinations like an open case with
resolution fields.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: aa7a6dfd-260c-4ea0-a534-10632334036e
📒 Files selected for processing (7)
apps/csm-portal/webapp/src/api/backend/types.tsapps/csm-portal/webapp/src/features/csm-cases/components/CaseActionBar.test.tsxapps/csm-portal/webapp/src/features/csm-cases/components/CaseActionBar.tsxapps/csm-portal/webapp/src/features/csm-cases/components/ResolutionDialog.test.tsxapps/csm-portal/webapp/src/features/csm-cases/components/ResolutionDialog.tsxapps/csm-portal/webapp/src/features/csm-cases/pages/CsmCaseDetailPage.tsxapps/csm-portal/webapp/src/features/csm-cases/utils/caseResolution.ts
Purpose
resolutionCode,cause, andcloseNoteswere added to thePATCH /cases/{id}contract at the API layer only — the entity-service and this repo's ownopenapi.yamlaccept them, and the BFF handler passes them through as-is. But no UI was ever built to collect these from the user: closing a case or proposing a solution just fired a plain state-transition PATCH with none of the Post Resolution Activity (PRA) fields the product requirement (case resolution management) calls for.Goals
Collect resolution code, root cause, and optional close notes from the CS engineer before a case is closed or a solution is proposed, and send them in the same
PATCH /cases/{id}call as the state transition.Approach
ResolutionDialogcomponent: a resolution-code select and a cause select (both required, populated from the full backend enums), plus a free-text close-notes field (optional). Opens for both the "Close" and "Propose solution" actions.CsmCaseDetailPage's action handler now interceptsclose/propose_solutionbefore the generic state-PATCH branch and opens this dialog instead of PATCHing immediately; submitting sends{ state, resolutionCode, cause, closeNotes }in one call.CaseActionBar's old plain yes/no confirm for these two targets, so that now-unused confirm mechanism (ActionConfirmtype,pendingConfirmstate, itsDialog) is removed fromCaseActionBarrather than left dead.caseResolution.tsutil holds the two enum value lists plus ahumanizeResolutionEnumhelper (mirrors the existinghumanizeStateconvention) so dropdown labels stay readable without a hand-maintained label map.BeCaseUpdatePayload'sstatevariant with the three optional fields; no other request shapes change.No API contract change — this only starts sending fields the backend has accepted since PR #1077.
User stories
As a CS engineer, when I close a case or propose a solution, I record the resolution code, root cause, and any closing notes as part of that action, instead of the case closing with no resolution record at all.
Release note
Added: closing a case or proposing a solution now collects the Post Resolution Activity (resolution code, cause, close notes) before submitting.
Documentation
N/A — internal case-detail UI behavior, not separately documented.
Automation tests
New
ResolutionDialog.test.tsxcovers: submit disabled until both required fields are chosen, correct payload shape on submit, and cancel behavior. UpdatedCaseActionBar.test.tsxfor the removed confirm-dialog behavior on Close (confirmation now happens via the resolution dialog upstream, not insideCaseActionBar).pnpm build,pnpm test, andpnpm lintall pass (two pre-existing, unrelated test failures onorigin/mainpersist unchanged).N/A — no integration test suite for this component.
Security checks
eslintruns clean)Samples
N/A
Related PRs
None
Migrations (if applicable)
N/A — no schema or data migration involved.
Test environment
Local:
pnpm build+pnpm test+pnpm lint, on macOS.Learning
N/A
Summary by CodeRabbit