Skip to content

[CSM Portal] fix page clipping, dark-mode comment readability, and severity defaulting to S3 - #1422

Merged
Rashmika998 merged 4 commits into
wso2-open-operations:mainfrom
rksk:fix/comment-overflow-readability
Aug 11, 2026
Merged

Rashmika998 merged 4 commits into
wso2-open-operations:mainfrom
rksk:fix/comment-overflow-readability

Conversation

@rksk

@rksk rksk commented Aug 11, 2026 •

Copy link
Copy Markdown
Contributor

Purpose

Describe the problems, issues, or needs driving this feature/fix and include links to related issues in the following format: Resolves issue1, issue2, etc.

Three UX/correctness issues reported on the CSM portal's case-detail page and case views:

  1. Page content (comment bubbles, the case Overview info grid) silently clips at the right edge on any browser window narrower than roughly 1780px — most laptop screens. Root cause: @wso2/oxygen-ui's AppShell component never sets minWidth: 0 on the <main> flex item it renders, so <main> locks to its content's intrinsic width instead of shrinking to the viewport, and the surrounding flex row's overflow: hidden then clips the excess instead of scrolling or wrapping. This affects the whole page, not just comments.
  2. A ServiceNow-authored comment (e.g. a call-note callout box) with a light/pastel inline background is unreadable in dark mode, because the dark-mode style-stripping only neutralized near-white backgrounds, not light backgrounds generally.
  3. A case with no severity value (empty/unrecognized from the backend) was silently displayed and filtered as if it were severity S3 (Medium) — a false signal, since "severity unknown" and "severity is genuinely Medium" are different facts that were rendered identically. Reported separately from the two issues above.

Goals

Describe the solutions that this feature/fix will introduce to resolve the problems described above

  1. Stop relying on oxygen-ui's AppShell for the page shell; use a hand-built AppShellLayout that explicitly cascades minWidth: 0 through every flex ancestor down to <main>, so content sizes to the actual viewport instead of clipping.
  2. Broaden the dark-mode inline-style stripping so any sufficiently light background (measured via WCAG relative luminance, not just near-white) gets neutralized before a comment renders in dark mode.
  3. Stop the severity mapper from defaulting falsy/unrecognized severity to "S3". Represent "unset" as its own distinct value, rendered as a visually distinct "Unset" badge, and keep it excluded from all S1-S4 severity filters so it can never be mistaken for a real severity again.

Approach

Describe how you are implementing the solutions. Include an animated GIF or screenshot if the change affects the UI (email documentation@wso2.com to review all UI text). Include a link to a Markdown file or Google doc if the feature write-up is too long to paste here.

apps/csm-portal/webapp/src/layouts/AppShellLayout.tsx (new) ports the same pattern the customer portal already ships in production for the identical bug (apps/customer-portal/webapp/src/layouts/AppShellLayout.tsx), trimmed to what CSM's AppLayout actually needs (no footer slot, no overlay/mobile-drawer sidebar — CSM's sidebar only ever renders inline). AppLayout.tsx swaps its <AppShell>/<AppShell.Navbar>/<AppShell.Sidebar>/<AppShell.Main> usage for the new component; all surrounding behavior (banners, loading state, scroll-reset-on-route-change, useAppShell() state) is unchanged.

utils/sanitizeHtml.ts's stripLightModeInlineStyles (dark-mode only, called from CsmCaseCommentBubble.tsx) replaces its near-white-only RGB threshold with a WCAG relative-luminance calculation, catching light/pastel backgrounds generally while leaving dark/saturated backgrounds (code blocks, etc.) untouched.

For the severity issue: src/api/backend/mappers.ts's severity mapper (renamed severityFromPriority → severityFromBe, since it consumes the backend's severity field, not a "priority" field) now returns a new "unset" value instead of "S3" for falsy/unrecognized input. A new SeverityOrUnset = Severity | "unset" type is applied only to display-facing fields (case-list rows, case detail, quick-search hits, child-case rows); severity filter option arrays and the severity-change dialog's radio options stay Severity-only, which keeps "unset" out of the filter UI by construction rather than needing separate exclusion logic. SeverityChip renders "unset" as an outlined, non-bold "Unset" badge, visually distinct from every real severity's filled/bold chip. Investigation confirmed the backend (Go entity-service) already returns an empty value for unmapped severity and never defaults it to Medium — the defaulting was purely a frontend display bug.

User stories

Summary of user stories addressed by this change

As a CS engineer, I can see the full case-detail page (Overview fields, comment content) without content being cut off on my laptop screen, I can read ServiceNow-authored comments with light-colored callout boxes in dark mode, and I can tell at a glance whether a case genuinely has no severity set versus being a real S3 case.

Release note

Brief description of the new feature or bug fix as it will appear in the release notes

Fixed CSM portal page content being clipped on narrower browser windows, fixed low-contrast comment backgrounds in dark mode, and fixed cases with no severity set incorrectly displaying as S3.

Documentation

Link(s) to product documentation that addresses the changes of this PR. If no doc impact, enter "N/A" plus brief explanation of why there's no doc impact

N/A — internal layout/rendering/display fix, no user-facing documentation to update.

Training

N/A — not training content.

Certification

N/A — no certification exam impact.

Marketing

N/A — internal bug fix, not a marketed feature.

Automation tests

  • Unit tests

    Code coverage information

Added/updated sanitizeHtml.test.ts (16 tests passing, including 3 new cases: pastel background stripped, near-white regression check, dark background left untouched). Added/updated mappers.test.ts and new SeverityChip.test.tsx for the severity fix (61/61 passing across the 7 directly-affected test files: mapper, chip, severity-change dialog, log-time-card dialog, case-detail page, case search payload, filters URL).

  • Integration tests

    Details about the test cases and coverage

None added; layout and severity changes verified via typecheck + full existing suite (tsc -b --force exit 0, eslint . unchanged from baseline, vitest run 133/141 with the same 8 pre-existing unrelated failures confirmed present on main).

Security checks

Samples

N/A

Related PRs

A companion fix for the same dark-mode background-contrast issue in the customer portal is being opened separately (different app, kept as its own PR).

Migrations (if applicable)

N/A

Test environment

Verified with pnpm run build and pnpm run test (Vitest) locally against Node/pnpm versions pinned in this repo. Full local-stack browser verification (real viewport resize + dark-mode screenshot, and a live unset-severity case vs. a real S3 case) is recommended as a follow-up before merge.

Learning

Root-caused the clipping bug by reading @wso2/oxygen-ui's compiled source directly (a shallow-merge bug in its Layout.Content's sx prop handling drops minWidth/overflow defaults) and comparing against the customer portal's existing fix for the same issue. For the severity bug, confirmed the defaulting lived entirely in the frontend mapper by reading the Go entity-service's case-severity path first — it already exposes severity (not priority) and never defaults unmapped input to Medium.

Summary by CodeRabbit

  • New Features

    • Added support for cases with missing or unrecognized severity, displayed as “Unset.”
    • Prevented unset severities from being treated as S3 or selected accidentally.
    • Improved related-case, call-request, and time-entry behavior when severity is unset.
    • Added a refreshed application shell with improved content sizing, scrolling, and loading layout.
  • Bug Fixes

    • Improved inline background sanitization to remove low-contrast light colors while preserving appropriate dark or saturated colors.

@coderabbitai

coderabbitai Bot commented Aug 11, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 7f07873c-e792-4cad-893c-a747c6c83160

📥 Commits

Reviewing files that changed from the base of the PR and between 03f71f7 and 9d49f71.

📒 Files selected for processing (4)
  • apps/csm-portal/webapp/src/features/csm-cases/types/csmCases.ts
  • apps/csm-portal/webapp/src/features/csm-dashboard/types/abtDashboard.ts
  • apps/csm-portal/webapp/src/utils/sanitizeHtml.test.ts
  • apps/csm-portal/webapp/src/utils/sanitizeHtml.ts
🚧 Files skipped from review as they are similar to previous changes (4)
  • apps/csm-portal/webapp/src/features/csm-dashboard/types/abtDashboard.ts
  • apps/csm-portal/webapp/src/utils/sanitizeHtml.test.ts
  • apps/csm-portal/webapp/src/features/csm-cases/types/csmCases.ts
  • apps/csm-portal/webapp/src/utils/sanitizeHtml.ts

📝 Walkthrough

Walkthrough

The PR adds explicit unset severity handling across case APIs and UI components, replaces the application shell layout, and changes inline background sanitization to use relative luminance with expanded color parsing.

Changes

Unset severity handling

Layer / File(s) Summary
Severity contract and backend mapping
apps/csm-portal/webapp/src/features/csm-dashboard/types/abtDashboard.ts, apps/csm-portal/webapp/src/api/backend/mappers.ts, apps/csm-portal/webapp/src/api/backend/mappers.test.ts
Adds SeverityOrUnset. severityFromBe maps missing and unknown values to "unset" while preserving recognized mappings.
Case severity API propagation
apps/csm-portal/webapp/src/features/csm-cases/api/*, apps/csm-portal/webapp/src/features/csm-cases/types/csmCases.ts, apps/csm-portal/webapp/src/features/csm-cases/utils/caseSearchPayload.ts, apps/csm-portal/webapp/src/features/csm-dashboard/api/useGetMyAssignedOpenCases.ts
Case detail, search, dashboard, and row mappings use severityFromBe and expose SeverityOrUnset.
Case UI unset-state behavior
apps/csm-portal/webapp/src/components/SeverityChip.tsx, apps/csm-portal/webapp/src/components/SeverityChip.test.tsx, apps/csm-portal/webapp/src/features/csm-cases/components/*, apps/csm-portal/webapp/src/features/csm-cases/pages/CsmCaseDetailPage.tsx
Displays unset severity explicitly, excludes it from acknowledgement, guards severity changes, and leaves related-case severity blank when unset.
Call requests and time logging
apps/csm-portal/webapp/src/features/csm-cases/components/CreateCallRequestDialog.tsx, apps/csm-portal/webapp/src/features/csm-timecards/components/LogTimeCardDialog.tsx
Uses a 300-minute default lead time for unset severity and excludes unset severity from non-billable checks.

Application shell layout

Layer / File(s) Summary
Application shell integration
apps/csm-portal/webapp/src/layouts/AppShellLayout.tsx, apps/csm-portal/webapp/src/layouts/AppLayout.tsx
Adds a flex-based AppShellLayout and uses it for the header, conditional sidebar, loading indicator, suspense content, and consolidated scrolling.

Light-background sanitization

Layer / File(s) Summary
Luminance-based background filtering
apps/csm-portal/webapp/src/utils/sanitizeHtml.ts, apps/csm-portal/webapp/src/utils/sanitizeHtml.test.ts
Adds luminance-based filtering and parsing for RGB, hexadecimal, and selected named colors. Tests cover light and dark background handling.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Backend
  participant useGetCsmCaseDetail
  participant severityFromBe
  participant SeverityChip
  Backend->>useGetCsmCaseDetail: case severity value
  useGetCsmCaseDetail->>severityFromBe: map backend severity
  severityFromBe-->>useGetCsmCaseDetail: SeverityOrUnset
  useGetCsmCaseDetail->>SeverityChip: render severity
  SeverityChip-->>SeverityChip: display severity or "Unset"
Loading

Possibly related PRs

Suggested labels: Type/Improvement

Suggested reviewers: cloby99

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 70.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the three primary fixes: page clipping, dark-mode comment readability, and incorrect severity defaulting to S3.
Description check ✅ Passed The description follows the template and clearly documents the purpose, implementation, testing, security checks, and areas with no impact.
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.
✨ 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.

@rksk
rksk marked this pull request as ready for review August 11, 2026 02:42

@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: 2

🤖 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-dashboard/types/abtDashboard.ts`:
- Around line 19-25: Update the documentation for SeverityOrUnset in
apps/csm-portal/webapp/src/features/csm-dashboard/types/abtDashboard.ts:19-25
and CsmCaseRow.severity in
apps/csm-portal/webapp/src/features/csm-cases/types/csmCases.ts:60-64 to state
that "unset" also represents unrecognized backend severity values, in addition
to empty or missing values. No code behavior changes are needed.

In `@apps/csm-portal/webapp/src/utils/sanitizeHtml.ts`:
- Around line 118-122: Replace the hard-coded
LIGHT_BACKGROUND_LUMINANCE_THRESHOLD value with a threshold derived from the
dark-mode text color and the required 4.5:1 contrast ratio, using the existing
luminance/contrast utilities or conventions in sanitizeHtml.ts. Update the
sanitization logic so background-color: `#808080` is removed, and add a focused
test covering that behavior.
🪄 Autofix

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 Plus

Run ID: 6ae816bf-efa5-4573-8d44-afc2535d8e47

📥 Commits

Reviewing files that changed from the base of the PR and between 6056303 and 03f71f7.

📒 Files selected for processing (21)
  • apps/csm-portal/webapp/src/api/backend/mappers.test.ts
  • apps/csm-portal/webapp/src/api/backend/mappers.ts
  • apps/csm-portal/webapp/src/components/SeverityChip.test.tsx
  • apps/csm-portal/webapp/src/components/SeverityChip.tsx
  • apps/csm-portal/webapp/src/features/csm-cases/api/useGetCsmCaseDetail.ts
  • apps/csm-portal/webapp/src/features/csm-cases/api/useQuickCaseSearch.ts
  • apps/csm-portal/webapp/src/features/csm-cases/api/useSearchChildCases.ts
  • apps/csm-portal/webapp/src/features/csm-cases/components/CallRequestsWidget.tsx
  • apps/csm-portal/webapp/src/features/csm-cases/components/CaseActionBar.tsx
  • apps/csm-portal/webapp/src/features/csm-cases/components/ChangeSeverityDialog.tsx
  • apps/csm-portal/webapp/src/features/csm-cases/components/CreateCallRequestDialog.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-cases/utils/caseSearchPayload.ts
  • apps/csm-portal/webapp/src/features/csm-dashboard/api/useGetMyAssignedOpenCases.ts
  • apps/csm-portal/webapp/src/features/csm-dashboard/types/abtDashboard.ts
  • apps/csm-portal/webapp/src/features/csm-timecards/components/LogTimeCardDialog.tsx
  • apps/csm-portal/webapp/src/layouts/AppLayout.tsx
  • apps/csm-portal/webapp/src/layouts/AppShellLayout.tsx
  • apps/csm-portal/webapp/src/utils/sanitizeHtml.test.ts
  • apps/csm-portal/webapp/src/utils/sanitizeHtml.ts

Comment thread apps/csm-portal/webapp/src/utils/sanitizeHtml.ts Outdated
@rksk rksk changed the title [CSM Portal] fix page content clipping and dark-mode comment readability [CSM Portal] fix page clipping, dark-mode comment readability, and severity defaulting to S3 Aug 11, 2026
rksk added 2 commits August 11, 2026 08:25
Case-detail (and other) pages silently clipped content on the right edge
below roughly 1780px window width: oxygen-ui's AppShell never sets
minWidth: 0 on its <main> flex item, so it locks to its content's
intrinsic width instead of shrinking, and the surrounding row's
overflow:hidden then clips the excess instead of scrolling. Replace the
oxygen-ui AppShell wiring in AppLayout with a hand-built AppShellLayout
that cascades minWidth: 0 through every flex ancestor, mirroring the fix
already shipped in the customer portal.

Separately, dark-mode comment rendering only stripped near-white inline
backgrounds from ServiceNow-authored HTML, so a light/pastel background
(e.g. a call-note callout box) survived into dark mode with the app's
light default text on top, reading as low-contrast. Switch the check to
a WCAG relative-luminance threshold so any sufficiently light background
gets neutralized, not just near-white ones.
…ontrast

The fixed 0.55 luminance cutoff still preserved backgrounds like #808080
(luminance ~0.22, ~3.95:1 contrast against white text) that fall below
the 4.5:1 WCAG AA minimum for normal text. Derive the threshold from
the actual contrast formula instead of an eyeballed constant.
@rksk
rksk force-pushed the fix/comment-overflow-readability branch from 03f71f7 to e2a6f1a Compare August 11, 2026 02:59
rksk added 2 commits August 11, 2026 08:33
A case with no severity value (empty/missing from the source) was rendered
and filtered as if it were S3 (Medium) -- a false signal, since "we don't
know the severity" and "the severity really is Medium" are different facts.

severityFromBe (renamed from severityFromPriority, which no longer matched
what it consumes) now maps falsy/unrecognized input to a new "unset" state
instead of collapsing it into S3. SeverityChip renders "unset" as a distinct
outlined "Unset" badge, visually unlike any real S0-S4 chip. Filtering by a
specific severity is unaffected since the filter dropdown never offers
"unset" as an option and the backend query already excludes non-matching
cases, so unset-severity cases only ever show up in the unfiltered list.

Also fixes a related discrepancy in CreateCallRequestDialog's lead-time
table, which previously enforced 90 min (S3's lead time) for a null-severity
case instead of the backend's own 300 min fallback for null/unknown.
…real contract

Both doc comments described "unset" as only empty/missing severity, but
severityFromBe also falls back to "unset" for any unrecognized value.
@rksk

rksk commented Aug 11, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai resume

@coderabbitai

coderabbitai Bot commented Aug 11, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Reviews resumed.

@Rashmika998
Rashmika998 merged commit 25d467a into wso2-open-operations:main Aug 11, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants