Skip to content

[CSM][Web] QuickNav follow-ups: sanitize stored text, header layout fixes - #1179

Merged
cloby99 merged 2 commits into
wso2-open-operations:mainfrom
Rashmika998:feature/csm-quicknav-followups
Jul 20, 2026
Merged

cloby99 merged 2 commits into
wso2-open-operations:mainfrom
Rashmika998:feature/csm-quicknav-followups

Conversation

@Rashmika998

@Rashmika998 Rashmika998 commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Summary

Follow-up to #1174 / #1175 (both merged) — the QuickNav search palette rework and its recent-views storage fix.

  • Sanitize before storing: title/subtitle/case-hit text recorded into the recent-views localStorage cache come from backend/customer free text (case subject, account/project name, assignee name). Every current render site uses plain JSX text interpolation, which React already escapes safely — but added stripHtmlTags (src/utils/sanitizeHtml.ts) and apply it in useRecordRecentView as defense-in-depth, so stored text can't do anything if a future change ever renders it less safely (e.g. dangerouslySetInnerHTML).
  • Search trigger shrinks when something's pinned: the QuickNav trigger button now uses a narrower width once the user has pinned at least one item, freeing horizontal space for PinnedTabs (which shares the header's flexible middle slot) to actually show the pinned chips instead of getting squeezed.
  • Fix "CSM Portal" wrapping to two lines: with several pinned tabs plus the search bar, the header row could run out of width and the flex layout would shrink/wrap the brand text instead of the (already horizontally-scrollable) PinnedTabs row. Header.Brand now has flexShrink: 0 and Header.BrandTitle has whiteSpace: "nowrap", so the brand never wraps.

Test plan

  • tsc -b --noEmit passes
  • eslint passes on all touched files
  • vitest run passes, including a new regression test asserting HTML tags are stripped from title/subtitle/case-hit text before storage
  • vite build succeeds

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes

    • Prevented the CSM Portal brand title from wrapping and preserved its layout.
    • Improved Quick Nav sizing when pinned items are present.
    • Removed HTML tags from recent-view details before saving them.
    • Improved detection of empty HTML content.
  • Tests

    • Added coverage verifying HTML sanitization in recent-view history.

…ixes

- Strip HTML tags from recent-view title/subtitle/case-hit text before
  persisting to localStorage (new stripHtmlTags in sanitizeHtml.ts,
  applied in useRecordRecentView). Not exploitable today — every render
  site uses plain JSX text interpolation, which React already escapes —
  but this closes the gap against a future change that renders it less
  safely (e.g. dangerouslySetInnerHTML).
- Shrink the QuickNav search trigger's width once something is pinned,
  so PinnedTabs (sharing the header's flexible middle slot) has room to
  show pinned chips instead of getting squeezed.
- Prevent "CSM Portal" from wrapping onto a second line when several
  pinned tabs plus the search bar leave little room in the header row —
  Header.Brand now has flexShrink: 0 and Header.BrandTitle has
  whiteSpace: nowrap, so PinnedTabs' own horizontal scroll absorbs the
  squeeze instead.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@Rashmika998, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 44 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

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.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 7e518627-f56c-4ce5-a6ff-1244bed7c855

📥 Commits

Reviewing files that changed from the base of the PR and between 0c34a71 and 30579e6.

📒 Files selected for processing (2)
  • apps/csm-portal/webapp/src/features/csm-recent/hooks/useRecentViews.test.ts
  • apps/csm-portal/webapp/src/utils/sanitizeHtml.ts
📝 Walkthrough

Walkthrough

The changes preserve portal header branding, resize the quick-navigation trigger when pinned items exist, and strip HTML tags from recent-view text before persistence. Blank HTML detection now reuses the shared tag-stripping helper, with tests covering sanitized recent-view fields.

Changes

Portal layout updates

Layer / File(s) Summary
Header branding layout
apps/csm-portal/webapp/src/components/header/Brand.tsx
Prevents the brand area and “CSM Portal” title from shrinking or wrapping while retaining conditional cursor behavior.
Pinned quick-navigation sizing
apps/csm-portal/webapp/src/features/csm-recent/components/QuickNav.tsx
Uses wider responsive trigger widths when recent views contain pinned items.

Recent-view text sanitization

Layer / File(s) Summary
HTML tag stripping utility
apps/csm-portal/webapp/src/utils/sanitizeHtml.ts
Adds stripHtmlTags and uses it when determining whether HTML content is blank.
Sanitized recent-view persistence
apps/csm-portal/webapp/src/features/csm-recent/hooks/useRecentViews.ts, apps/csm-portal/webapp/src/features/csm-recent/hooks/useRecentViews.test.ts
Strips tags from recorded recent-view fields, including case details, and verifies the persisted values in tests.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Suggested reviewers: rksk

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description covers summary and tests, but it omits most required template sections like Purpose, Goals, Approach, and documentation details. Expand it to complete the repository template sections, including Purpose, Goals, Approach, User stories, Release note, Documentation, and the remaining required fields.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and accurately reflects the main changes: recent-view sanitization and header/QuickNav layout fixes.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.

@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/utils/sanitizeHtml.ts`:
- Around line 48-50: Replace the regex in stripHtmlTags with
DOMPurify.sanitize(text, { ALLOWED_TAGS: [] }) to remove HTML safely while
preserving legitimate bracketed text. In
apps/csm-portal/webapp/src/features/csm-recent/hooks/useRecentViews.test.ts
lines 89-94, update the stored title assertion to expect "Case 1 " to reflect
script-content removal.
🪄 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: 3d02a55c-9b09-4742-ae63-f73035a947fc

📥 Commits

Reviewing files that changed from the base of the PR and between b82aa62 and 0c34a71.

📒 Files selected for processing (5)
  • apps/csm-portal/webapp/src/components/header/Brand.tsx
  • apps/csm-portal/webapp/src/features/csm-recent/components/QuickNav.tsx
  • apps/csm-portal/webapp/src/features/csm-recent/hooks/useRecentViews.test.ts
  • apps/csm-portal/webapp/src/features/csm-recent/hooks/useRecentViews.ts
  • apps/csm-portal/webapp/src/utils/sanitizeHtml.ts

Comment thread apps/csm-portal/webapp/src/utils/sanitizeHtml.ts
The <[^>]*> regex treated any <...> run as a tag, so plain text with
comparison operators (e.g. "x < y > z") would lose everything between
the brackets. Switch stripHtmlTags to DOMPurify.sanitize(text, {
ALLOWED_TAGS: [] }) for real HTML parsing instead.

DOMPurify's output alone isn't quite sufficient for plain-text use,
though: it HTML-entity-encodes a stray "<"/">" that isn't part of a real
tag (its output is meant for HTML re-insertion), which would otherwise
render as the literal text "&lt;" through plain JSX interpolation.
Round-trip through a detached element's innerHTML -> textContent to
decode those entities back to plain characters — safe here specifically
because the input to that second innerHTML assignment has already been
fully tag-stripped by DOMPurify.

Adds a regression test for the angle-bracket case, and updates the
existing sanitization test's expectation (DOMPurify drops a <script>
element's text content along with its tags, not just the tag markup).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@cloby99
cloby99 merged commit e7cdbf9 into wso2-open-operations:main Jul 20, 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