Skip to content

[CSM Portal] Drive case action bar from backend nextStates; unify reopened spelling - #848

Merged
Rashmika998 merged 2 commits into
wso2-open-operations:v2from
rksk:fix/csm-case-state-machine-fe
Jun 12, 2026
Merged

[CSM Portal] Drive case action bar from backend nextStates; unify reopened spelling#848
Rashmika998 merged 2 commits into
wso2-open-operations:v2from
rksk:fix/csm-case-state-machine-fe

Conversation

@rksk

@rksk rksk commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

What

The case state machine was duplicated in the webapp and the FE used a different spelling for one state than the backend/entity service. This aligns the FE to the backend as the single source of truth.

  • CaseActionBar now renders lifecycle buttons solely from the case's backend-supplied nextStates. Removed FALLBACK_TARGETS (the duplicated client-side transition graph): an absent or empty nextStates now yields no lifecycle buttons rather than guessing from a second copy of the graph. EDGE_OVERRIDES-style presentational labels remain driven by the target state's name.
  • Mock fixtures now carry nextStates (computed from a small graph that stands in for the backend, mirroring backend/internal/handler/state.go) so mock mode keeps showing the correct buttons.
  • Spelling alignment: the CaseState vocabulary now uses the backend spelling reopened (was reopen) across types, labels, colours, filters and mocks. uiStateFromBe / beStateFromUi are now identity at the type level; uiStateFromBe keeps a runtime guard that defaults unknown/undefined to open.

Why

The transition graph should live in exactly one place per tier. Previously the FE kept its own copy and could drift from the backend (and did, on the reopen/reopened spelling). Buttons are now whatever the backend permits, nothing more.

Note

The case-filter URL token for that state changes reopenreopened; any pre-existing bookmarked filter URL using the old token will drop that one state silently. Acceptable pre-launch.

Testing

  • pnpm build (tsc + vite) — passes
  • pnpm lint — clean
  • pnpm test — 47 tests pass (incl. CaseActionBar and mapper suites; the obsolete fallback test was rewritten to assert no buttons when nextStates is absent)

Summary by CodeRabbit

  • Bug Fixes

    • Corrected case state terminology to "reopened" across case filters, dashboards, queue displays, and case details for consistency.
    • Fixed queue categorization and dashboard metrics to properly reflect reopened cases in action-required counts.
  • Refactor

    • Streamlined backend-frontend state handling logic.

…pened spelling

The case state machine was duplicated client-side and the FE used a different
spelling for one state than the backend/entity service.

- CaseActionBar now renders lifecycle buttons solely from the case's
  backend-supplied nextStates. Removed FALLBACK_TARGETS (the duplicated
  client-side transition graph): an absent or empty nextStates yields no
  lifecycle buttons rather than guessing from a second copy of the graph.
- Mock case-detail fixtures now carry nextStates (computed from a mock that
  stands in for the backend) so mock mode keeps showing the right buttons.
- Aligned the CaseState vocabulary to the backend spelling 'reopened' (was
  'reopen') across types, labels, colours, filters and mocks. uiStateFromBe /
  beStateFromUi are now identity at the type level; uiStateFromBe keeps a
  runtime guard defaulting unknown/undefined to 'open'.

Build, lint and the webapp test suite (47 tests) pass.
@coderabbitai

coderabbitai Bot commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@rksk, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 41 minutes and 51 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more credits in the billing tab to continue.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 5a37abea-bfde-4fd7-bc2a-cbf97ffb5d4c

📥 Commits

Reviewing files that changed from the base of the PR and between 7ff245e and fedf542.

📒 Files selected for processing (10)
  • apps/csm-portal/webapp/src/api/backend/mappers.test.ts
  • apps/csm-portal/webapp/src/api/backend/mappers.ts
  • apps/csm-portal/webapp/src/features/csm-cases/components/CaseActionBar.test.tsx
  • apps/csm-portal/webapp/src/features/csm-cases/components/CaseActionBar.tsx
  • apps/csm-portal/webapp/src/features/csm-cases/components/CasesList.tsx
  • apps/csm-portal/webapp/src/features/csm-cases/pages/CsmCaseDetailPage.tsx
  • apps/csm-portal/webapp/src/features/csm-cases/types/csmCases.ts
  • apps/csm-portal/webapp/src/features/csm-dashboard/components/MyQueueSection.tsx
  • apps/csm-portal/webapp/src/features/csm-dashboard/components/SlaAtRiskSection.tsx
  • apps/csm-portal/webapp/src/features/csm-dashboard/utils/abtDashboard.ts
📝 Walkthrough

Walkthrough

This PR unifies the case state vocabulary by replacing "reopen" with "reopened" across the CSM portal webapp and integrates backend-driven nextStates field into lifecycle transition rendering. The backend mappers now treat both vocabularies as identical. Mock data and consuming layers (filters, dashboard) are updated throughout to use the new state value consistently.

Changes

Case State Unification and NextStates Integration

Layer / File(s) Summary
Backend-to-UI state mapping alignment
src/api/backend/mappers.ts, src/api/backend/mappers.test.ts
Introduce KNOWN_STATES allowlist and simplify mappers to use identity mapping. uiStateFromBe validates against known states and defaults to "open"; beStateFromUi returns the state directly. Tests confirm "reopened" passes through unchanged in both directions.
Case state type and display mappings
src/features/csm-dashboard/types/abtDashboard.ts, src/features/csm-dashboard/utils/abtDashboard.ts
Update CaseState type to include "reopened" instead of "reopen". Update exported STATE_LABEL and STATE_COLOR constants to key the reopened state under "reopened" with the same label and warning color. Update documentation comment to reference the new state name.
Mock CSM case data and nextStates integration
src/features/csm-cases/api/mocks/casesMocks.ts
Seed test cases with "reopened" state. Correct tag and audit derivation logic to check for the new state value. Introduce MOCK_NEXT_STATES mapping that mirrors the backend transition graph. Extend getMockCsmCaseDetailById to populate nextStates from the mock mapping with empty array fallback.
CaseActionBar lifecycle button refactoring
src/features/csm-cases/components/CaseActionBar.tsx, src/features/csm-cases/components/CaseActionBar.test.tsx
Render lifecycle targets strictly from caseDetail.nextStates ?? [], removing client-side fallback graph. Update TARGET_CONFIG, DISPLAY_ORDER, and REOPEN_BUTTON to target "reopened" state. Remove FALLBACK_TARGETS mapping. Test confirms no lifecycle buttons render when nextStates is undefined.
Filter and dashboard state references
src/features/csm-cases/components/CasesFilterBar.tsx, src/features/csm-cases/utils/casesFiltersUrl.ts, src/features/csm-dashboard/api/useCaseCountsMatrix.ts, src/features/csm-dashboard/api/mocks/dashboardMocks.ts, src/features/csm-dashboard/components/MyQueueSection.tsx
Update PRIMARY_STATES filter enum, VALID_STATES URL whitelist, and MATRIX_STATES dashboard matrix to use "reopened". Correct queue bucketing and "Action required" stat pill to check/use the new state value.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • wso2-open-operations/cs-tools#812: Backend addition of next_states field to GET /cases/{id} response, which this PR's frontend changes consume and render through caseDetail.nextStates.
  • wso2-open-operations/cs-tools#820: Backend rename from next_states to nextStates in the GET /cases/{id} response, aligning with this PR's frontend integration of the nextStates field.
  • wso2-open-operations/cs-tools#839: Refactoring of lifecycle button rendering in CaseActionBar to be driven by backend nextStates and updated state labels, overlapping with the same components modified in this PR.

Suggested labels

Type/Improvement, Type/Task, App/CSM Portal, Area/Frontend, Platform/Web

Suggested reviewers

  • cloby99
  • Rashmika998
  • v15a1

Poem

🐰 A state by any other name rings clear,
From "reopen" to "reopened"—no more fear!
The backend whispers nextStates down the line,
No fallbacks needed, just backend-truth divine.
Buttons dance, filters flow, dashboards align—
What unified harmony, what a design! ✨

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ❓ Inconclusive The description provides clear 'What', 'Why', 'Note', and 'Testing' sections explaining the changes, but does not follow the repository's required template structure with Purpose, Goals, Approach, User Stories, Release Notes, Documentation, etc. Consider restructuring the description to follow the repository template, or clarify which sections are applicable to this PR and why others are omitted.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the two main changes: driving CaseActionBar from backend nextStates and unifying the 'reopened' spelling across the codebase.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@rksk rksk added Type/Bug Identifies a bug in the project Area/Frontend App/CSM Portal labels Jun 12, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 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.

Inline comments:
In `@apps/csm-portal/webapp/src/features/csm-cases/components/CaseActionBar.tsx`:
- Around line 257-264: The code currently trusts caseDetail.nextStates and maps
it through orderRank and buttonFor, which can create invalid buttons; update
CaseActionBar to first validate/filter caseDetail.nextStates against the
canonical set (e.g., TARGET_CONFIG or the states returned by uiStateFromBe/state
enum) before sorting/mapping so only known states are used. Specifically,
replace direct use of targets = caseDetail.nextStates ?? [] with a filtered list
(filter unknown/typo values by membership in TARGET_CONFIG or
uiStateFromBe(state) keys), then perform the dedupe/sort/map steps; ensure
runPrimary and buttonFor will never receive undefined/badState by only
generating actions for validated states.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: edaada25-4709-4bda-bfbd-15fa537f9835

📥 Commits

Reviewing files that changed from the base of the PR and between ce58b33 and 7ff245e.

📒 Files selected for processing (12)
  • apps/csm-portal/webapp/src/api/backend/mappers.test.ts
  • apps/csm-portal/webapp/src/api/backend/mappers.ts
  • apps/csm-portal/webapp/src/features/csm-cases/api/mocks/casesMocks.ts
  • apps/csm-portal/webapp/src/features/csm-cases/components/CaseActionBar.test.tsx
  • apps/csm-portal/webapp/src/features/csm-cases/components/CaseActionBar.tsx
  • apps/csm-portal/webapp/src/features/csm-cases/components/CasesFilterBar.tsx
  • apps/csm-portal/webapp/src/features/csm-cases/utils/casesFiltersUrl.ts
  • apps/csm-portal/webapp/src/features/csm-dashboard/api/mocks/dashboardMocks.ts
  • apps/csm-portal/webapp/src/features/csm-dashboard/api/useCaseCountsMatrix.ts
  • apps/csm-portal/webapp/src/features/csm-dashboard/components/MyQueueSection.tsx
  • apps/csm-portal/webapp/src/features/csm-dashboard/types/abtDashboard.ts
  • apps/csm-portal/webapp/src/features/csm-dashboard/utils/abtDashboard.ts

A new case state or transition introduced on the backend should not require a
frontend change to appear and work. Previously an unrecognized state would build
a broken action-bar button (undefined label, dispatching an undefined action)
and render an empty status chip.

- uiStateFromBe now passes an unknown backend state through unchanged instead of
  collapsing it to 'open' (only a genuinely absent value defaults to 'open'), so
  the value reaches the UI.
- Added stateLabel()/stateColor()/humanizeState() helpers that fall back to a
  title-cased key and neutral colour for any state without a curated entry.
  Status chips (cases list, dashboard queue/SLA sections, related cases) use
  them.
- CaseActionBar renders a usable button for an unknown state via a neutral
  DEFAULT_TARGET_CONFIG and a generic 'transition' lifecycle action. The PATCH
  target still comes from the backend nextStates value, so the transition works;
  the action only drives the post-transition toast.

This keeps the action bar driven solely by backend nextStates while making the
no-FE-change-for-new-states property hold instead of silently filtering unknown
states out (which would have required an FE update for every new state).

Build, lint and the webapp test suite (49 tests) pass.
@Rashmika998
Rashmika998 merged commit 14ff8d0 into wso2-open-operations:v2 Jun 12, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

App/CSM Portal Area/Frontend Type/Bug Identifies a bug in the project

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants