Skip to content

[Customer Portal][FE][Web] Improve Settings State Persistence, Success Banner Handling, and Dashboard Cleanup - #599

Merged
chanukaranaba merged 10 commits into
wso2-open-operations:mainfrom
dileepapeiris:feat-bug-fix-v14
Apr 25, 2026
Merged

chanukaranaba merged 10 commits into
wso2-open-operations:mainfrom
dileepapeiris:feat-bug-fix-v14

Conversation

@dileepapeiris

@dileepapeiris dileepapeiris commented Apr 25, 2026 •

Copy link
Copy Markdown
Contributor

Description

This pull request introduces several improvements to user experience and state management in the customer portal, particularly around the Settings and Dashboard pages. The most significant changes include implementing cross-page success banner and tab state persistence using session storage, enhancing loading skeletons for better UI feedback, and refining the display logic for dashboard sections.

State Persistence and Success Banner Improvements:

  • Added utility functions in settingsStorage.ts to store and retrieve pending success messages and active settings tab across page reloads, enabling smoother UX when actions require a reload.
  • Updated the SuccessBannerContext to consume and display any pending success message after a reload.
  • Modified SettingsAiAssistant.tsx to use the new session storage utilities for success messages and tab selection, removing the need for direct banner calls and project list refetching [1] [2] [3].
  • Updated SettingsPage.tsx to restore the active tab from session storage after reloads, ensuring users return to the correct tab.

UI/UX Enhancements:

  • Improved the appearance and structure of loading skeletons in ChangeRequestsListSkeleton.tsx for more accurate visual feedback [1] [2].
  • Refined the AI Assistant settings card styling to use blue color accents, aligning with the rest of the UI.

Dashboard and Operations Page Logic:

  • Removed the "Resolved Items" section and its logic from the dashboard, simplifying the page and reducing clutter [1] [2].
  • Fixed the mapping of internalId in change requests to prefer the case's internalId if available.

Miscellaneous:

  • Simplified and clarified error messages for ServiceNow redirects.
  • Added missing imports and minor code cleanups to support the above changes [1] [2] [3] [4].

These updates collectively enhance the user experience by making settings changes more intuitive, improving feedback during loading states, and decluttering key pages.

Summary by CodeRabbit

  • New Features

    • Persistent success notifications now carry across page reloads
    • Enhanced thinking steps in chat with markdown formatting support
  • Improvements

    • Loading states and skeleton layouts refined for better accuracy
    • Comment author names now display full names when available
    • Settings tab selection persists after reload
  • UI Updates

    • Refined color palette for solution-proposed case status
    • Improved spacing and button styling for visual consistency
    • Removed resolved items display from outstanding interactions view

Reformat JSX and style objects for readability and consistency in ChatMessageBubble.tsx (multi-line imports, useMemo, sx props, and ReactMarkdown props). Replace the previous Typography rendering for message.thinkingSteps with a Box + MarkdownContent so thinking steps are rendered as markdown (styled p/li) for correct wrapping and styling. Overall small tidy-up to improve markdown handling and code clarity.
Use createdByFullName in case comment data and prefer it when rendering author names (fall back to createdBy or "Unknown"). Simplify name handling by removing manual first/last concatenation. Update Settings UI: import alpha and switch SettingsAiAssistant visuals from grey to blue accents with alpha transparency, adjust avatar/icon colors and remove avatar border. Also increase vertical spacing on SettingsPage (gap 1 -> 3) for improved layout.
Remove the derived visibleResolvedSections and the entire rendering block for resolved items shown in outstanding mode. The resolvedSections variable is retained with a void statement to avoid unused-variable linting. This cleans up the dashboard by removing the resolved-items accordion, counts, lists, navigation buttons, and the "No resolved items found" fallback.
Change the color for CaseStatus.SOLUTION_PROPOSED from colors.purple[900] to colors.purple[300]. This makes the status display a lighter purple to improve visibility and better align with the UI design.
Replace the previous CardHeader-based skeleton with a simpler, stacked layout using Stack and Box. Added Stack to imports, removed the CardHeader and various individual Skeleton nodes, and reorganized the skeleton into explicit Header (internalId/number/status), Content (title + description) and Footer (assigned engineer + relative time) sections with adjusted skeleton sizes. Also removed the explicit minHeight to let the new layout size naturally.
Introduce two new sessionStorage keys and helper functions to persist small UI state across a page reload: PENDING_SETTINGS_TAB_KEY and PENDING_SUCCESS_MESSAGE_KEY. Adds setPendingSettingsTab / consumePendingSettingsTab and setPendingSuccessMessage / consumePendingSuccessMessage to store, read and clear a pending settings tab id and a pending success message respectively. All operations use try/catch to safely handle storage errors and remove items when consumed.
Read any pending settings tab stored in settingsStorage when SettingsPage mounts and apply it to the active tab. Adds useEffect and imports consumePendingSettingsTab, preserving the existing default (USERS) when no pending value is present.
Replace in-place refetch flow with a pending-state + full reload approach for AI assistant toggles. Removed infinite projects refetch and SuccessBanner usage; notifyPatchSuccess now stores pending settings tab and success message via settingsStorage (setPendingSettingsTab, setPendingSuccessMessage) and calls window.location.reload() to let the app pick up updated project state. Updated imports accordingly and simplified notifyPatchSuccess usage.
Prefer cr.case.internalId when mapping changeRequests so the internalId reflects the associated case if present (falling back to cr.internalId). Also simplify SERVICENOW_REDIRECT_RESOLVE_ERROR text to a more generic "Something went wrong" message.
GetHelpDropdown: add Stack import and return a compact skeleton row (buttons + divider) when projects list is busy to improve loading UX.

SuccessBannerContext: import and call consumePendingSuccessMessage on mount; if a pending message exists, show it and bump the key so persisted success banners are displayed after navigation.

ChangeRequestsListSkeleton: refine skeleton layout to better mirror the final row (add state dot + label, pipes and spacing tweaks, and adjust several skeleton widths) for a more accurate placeholder representation.
@dileepapeiris dileepapeiris self-assigned this Apr 25, 2026
@coderabbitai

coderabbitai Bot commented Apr 25, 2026 •

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

This pull request introduces a reload-based state persistence pattern for settings changes, refactors skeleton layouts across support and operations UI components, updates comment author display logic, removes resolved items rendering from dashboard view, and enhances chat message markdown support. Changes span state management, UI components, and utility functions.

Changes

Cohort / File(s) Summary
Skeleton Layout Refactoring
apps/customer-portal/webapp/src/features/operations/components/change-requests/ChangeRequestsListSkeleton.tsx, apps/customer-portal/webapp/src/features/support/components/support-overview-cards/OutstandingCasesSkeleton.tsx
Restructured skeleton placeholders to better match inline layouts with circular state dots, text separators, and improved spacing/sizing.
Settings & State Persistence
apps/customer-portal/webapp/src/features/settings/utils/settingsStorage.ts, apps/customer-portal/webapp/src/features/settings/components/SettingsAiAssistant.tsx, apps/customer-portal/webapp/src/features/settings/pages/SettingsPage.tsx
Introduced sessionStorage-based utility functions for persisting UI state (pending tabs, success messages) across page reloads. Settings AI assistant patch flow now triggers reload instead of refetch. SettingsPage consumes pending tab state on mount to restore UI position.
Success Banner Integration
apps/customer-portal/webapp/src/context/success-banner/SuccessBannerContext.tsx
Provider now initializes banner state from externally persisted pending success messages on mount, enabling message display after page reload.
Comment Author & Display
apps/customer-portal/webapp/src/features/support/api/useGetCaseComments.ts, apps/customer-portal/webapp/src/features/support/components/case-details/activity-tab/CommentBubble.tsx, apps/customer-portal/webapp/src/features/support/types/cases.ts
Extended CaseComment type with optional createdByFullName field. Updated CommentBubble to prefer full name over composed first/last name for author display.
Dashboard & Operations Pages
apps/customer-portal/webapp/src/features/dashboard/pages/DashboardItemsPage.tsx, apps/customer-portal/webapp/src/features/operations/pages/OperationsPage.tsx
Removed resolved items UI and "no resolved items" messaging from dashboard outstanding-interactions mode. Updated change request mapping to source internalId from nested case field with fallback.
Chat Message Rendering
apps/customer-portal/webapp/src/features/support/components/novera-ai-assistant/novera-chat-page/ChatMessageBubble.tsx
Refactored markdown rendering; thinking steps now rendered via markdown-capable MarkdownContent with secondary text styling instead of plain typography captions.
Header & Dropdown Components
apps/customer-portal/webapp/src/components/header/GetHelpDropdown.tsx
Added busy-state short-circuit to replace dropdown trigger UI with horizontal skeleton layout when projects list is loading.
Constants & Minor Updates
apps/customer-portal/webapp/src/features/project-hub/constants/projectHubConstants.ts, apps/customer-portal/webapp/src/features/support/utils/support.ts, apps/customer-portal/webapp/src/features/support/pages/DescribeIssuePage.tsx
Updated ServiceNow redirect error message to generic text. Changed SOLUTION_PROPOSED case status color from purple-900 to purple-300. Added vertical padding to submit button.

Sequence Diagram(s)

sequenceDiagram
    actor User
    participant SettingsUI as Settings AI Assistant<br/>Component
    participant Storage as sessionStorage
    participant Reload as Page Reload
    participant SettingsPage as Settings Page
    participant SuccessBanner as Success Banner<br/>Context

    User->>SettingsUI: Click patch/save settings
    SettingsUI->>Storage: setPendingSettingsTab("ai")
    SettingsUI->>Storage: setPendingSuccessMessage(message)
    SettingsUI->>Reload: window.location.reload()
    
    Reload->>SettingsPage: Page initialization
    SettingsPage->>Storage: consumePendingSettingsTab()
    Storage-->>SettingsPage: "ai" (clears storage)
    SettingsPage->>SettingsPage: Override activeTab state
    
    Reload->>SuccessBanner: Banner provider mounts
    SuccessBanner->>Storage: consumePendingSuccessMessage()
    Storage-->>SuccessBanner: message (clears storage)
    SuccessBanner->>SuccessBanner: Set banner message & trigger display
    
    SettingsPage-->>User: Displays "AI" tab active
    SuccessBanner-->>User: Shows success notification
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

Suggested labels

Type/Improvement, Type/Task, Type/UX, App/Customer Portal, Area/Frontend, Platform/Web

Suggested reviewers

  • Rashmika998
  • cloby99
  • v15a1

Poem

🐰 With pending states and reloads bright,
Settings dance through storage's light,
Skeletons shimmer, comments glow,
Success banners steal the show!
A rabbit's work, now fresh and keen,
The finest changes ever seen! ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the three primary change areas: Settings State Persistence, Success Banner Handling, and Dashboard Cleanup, all of which are major themes present throughout the changeset.
Description check ✅ Passed The description provides comprehensive context for all major changes including state persistence, UI enhancements, dashboard logic updates, and miscellaneous improvements, with relevant code references and links.
Docstring Coverage ✅ Passed Docstring coverage is 89.47% which is sufficient. The required threshold is 80.00%.
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.

@dileepapeiris dileepapeiris added Type/New Feature Represents a request or task for a new feature Type/Improvement Marks enhancements or improvements to existing features Type/Task General task that does not fit into other categories Type/UX Refers to user experience-related tasks or issues App/Customer Portal labels Apr 25, 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: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/customer-portal/webapp/src/features/dashboard/pages/DashboardItemsPage.tsx (1)

264-367: 🛠️ Refactor suggestion | 🟠 Major

Remove dead resolved-items code or actually render it.

The Resolved Items UI was removed, but five useGetProjectCasesPage/useGetChangeRequests queries (lines 264-367), all resolved* derived values (lines 402-444), and the resolvedSections array (lines 625-701) remain. They still fire network requests in outstanding-interactions mode (each enabled gate still evaluates isOutstandingMode && hasResolvedStatusIds && permissions.*), and resolvedSections is then discarded with void resolvedSections; on line 713. This wastes bandwidth and React Query cache, and leaves expandedSections initialized with "resolved-*" keys (lines 455-459) that nothing toggles.

If the intent is to keep the UI hidden for now, gate the resolved queries (and section state) on a render flag rather than always-on, or drop them entirely until the UI is reintroduced.

Also applies to: 625-713

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@apps/customer-portal/webapp/src/features/dashboard/pages/DashboardItemsPage.tsx`
around lines 264 - 367, The resolved-items queries and state are dead: remove or
gate them so they don't run when the UI is hidden. Either (A) fully remove the
resolved queries (the useGetProjectCasesPage and useGetChangeRequests calls that
populate resolvedCasesData / resolvedSrData / resolvedSraData / resolvedEngData
/ resolvedCrData and their isLoading/isError vars), delete the resolvedSections
array and the useState initialization that seeds expandedSections with
"resolved-*" keys, and remove the stray void resolvedSections; line, or (B)
introduce a single render flag (e.g., renderResolved) and use it in the queries'
options.enabled and when initializing/including "resolved-*" keys in
expandedSections so the queries never run and the sections are not part of state
while the UI is hidden (update references to resolvedSections, resolved*
variables, and expandedSections accordingly).
🧹 Nitpick comments (2)
apps/customer-portal/webapp/src/components/header/GetHelpDropdown.tsx (1)

224-229: Dead loading branch inside Menu.

With the early return at lines 162-174, GetHelpDropdownContent never reaches this <Menu> while isProjectsListBusy is true (the trigger Button is not rendered, so anchorEl cannot be set and the Menu cannot be open). The isProjectsListBusy ? <Skeleton …/> : menuItems.map(...) branch on lines 224-229 is now unreachable and can be simplified to just menuItems.map(...).

♻️ Proposed simplification
-        {isProjectsListBusy ? (
-          <Box sx={{ px: 2, py: 1.5, width: 224 }}>
-            <Skeleton variant="rounded" height={48} sx={{ mb: 1 }} />
-            <Skeleton variant="rounded" height={48} sx={{ mb: 1 }} />
-            <Skeleton variant="rounded" height={48} />
-          </Box>
-        ) : (
-          menuItems.map((item, index) => (
+        {menuItems.map((item, index) => (
           <Box key={item.id}>
             {index > 0 && (
               <Divider
                 variant="middle"
                 component="li"
                 sx={{ listStyle: "none" }}
               />
             )}
             <MenuItem onClick={item.onClick}>
               …
             </MenuItem>
           </Box>
-          ))
-        )}
+        ))}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/customer-portal/webapp/src/components/header/GetHelpDropdown.tsx` around
lines 224 - 229, The conditional rendering inside the Menu that checks
isProjectsListBusy is dead code because GetHelpDropdownContent returns early
when the projects list is busy; remove the ternary (isProjectsListBusy ?
<Skeleton...> : menuItems.map(...)) and simplify the Menu body to always render
menuItems.map(...) (use the existing menuItems array/map logic). Also remove any
now-unused references to isProjectsListBusy within GetHelpDropdownContent/Menu
to keep the component tidy.
apps/customer-portal/webapp/src/features/settings/utils/settingsStorage.ts (1)

112-118: Consider tightening tabId to the SettingsPageTabId enum.

setPendingSettingsTab(tabId: string) accepts any string and is then read back in SettingsPage.tsx as the activeTab value. Although safeActiveTab/displayTab use resolveSettingsPageTabId(...) to recover from unknown values, accepting a typed enum here would prevent typos at the call site (e.g. SettingsAiAssistant.tsx currently passes the literal "ai"). Optional refinement, no behavioural impact.

♻️ Suggested refinement
-export function setPendingSettingsTab(tabId: string): void {
+import type { SettingsPageTabId } from "@features/settings/types/settings";
+
+export function setPendingSettingsTab(tabId: SettingsPageTabId | string): void {
   try {
     sessionStorage.setItem(PENDING_SETTINGS_TAB_KEY, tabId);
   } catch {
     return;
   }
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/customer-portal/webapp/src/features/settings/utils/settingsStorage.ts`
around lines 112 - 118, Change setPendingSettingsTab to accept the typed enum
SettingsPageTabId instead of a plain string: update the function signature
setPendingSettingsTab(tabId: SettingsPageTabId): void, keep storing tabId as a
string to sessionStorage using PENDING_SETTINGS_TAB_KEY, and update all callers
(e.g. the literal "ai" in SettingsAiAssistant.tsx) to pass a SettingsPageTabId
value. You can still read/resolve it in SettingsPage.tsx with
resolveSettingsPageTabId as before; this change just prevents typos at call
sites.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@apps/customer-portal/webapp/src/features/project-hub/constants/projectHubConstants.ts`:
- Around line 87-88: Replace the generic SERVICENOW_REDIRECT_RESOLVE_ERROR
string with the original, actionable message to restore user clarity: change the
value of SERVICENOW_REDIRECT_RESOLVE_ERROR to "Unable to resolve the case.
Please try again." so the constant used by redirect error handling provides a
specific problem statement and next step.

In
`@apps/customer-portal/webapp/src/features/settings/components/SettingsAiAssistant.tsx`:
- Around line 84-91: The notifyPatchSuccess function currently calls
window.location.reload() which force-reloads the app; remove that reload and
instead call showSuccess(getAiAssistantPatchSuccessMessage(kind)) directly,
relying on usePatchProject's onSuccess invalidations of [PROJECT_DETAILS,
projectId] and [PROJECTS] plus useGetProjectDetails (staleTime: 0) to refresh
projectHasAgent; also remove or stop using the pending-state helpers
setPendingSettingsTab and setPendingSuccessMessage (and related
settingsStorage/consumePending plumbing) for this flow since they become
unnecessary. Ensure notifyPatchSuccess still sets any immediate UI state only if
needed, but do not trigger a full-page reload.

In `@apps/customer-portal/webapp/src/features/settings/pages/SettingsPage.tsx`:
- Around line 44-50: Init activeTab using a lazy initializer that calls
consumePendingSettingsTab so the initial render uses the pending tab (instead of
starting at SettingsPageTabId.USERS and switching after paint), and add a useRef
guard to avoid consuming-and-deleting the pending key twice under StrictMode;
replace the current useState call (activeTab, setActiveTab) with useState(() =>
consumePendingSettingsTab() ?? SettingsPageTabId.USERS) and create a ref (e.g.,
consumedRef) to ensure consumePendingSettingsTab is only invoked once (or move
the consume into the lazy initializer and still use a ref to prevent
double-consume), then remove the now-unnecessary useEffect import and effect
that previously called consumePendingSettingsTab.

---

Outside diff comments:
In
`@apps/customer-portal/webapp/src/features/dashboard/pages/DashboardItemsPage.tsx`:
- Around line 264-367: The resolved-items queries and state are dead: remove or
gate them so they don't run when the UI is hidden. Either (A) fully remove the
resolved queries (the useGetProjectCasesPage and useGetChangeRequests calls that
populate resolvedCasesData / resolvedSrData / resolvedSraData / resolvedEngData
/ resolvedCrData and their isLoading/isError vars), delete the resolvedSections
array and the useState initialization that seeds expandedSections with
"resolved-*" keys, and remove the stray void resolvedSections; line, or (B)
introduce a single render flag (e.g., renderResolved) and use it in the queries'
options.enabled and when initializing/including "resolved-*" keys in
expandedSections so the queries never run and the sections are not part of state
while the UI is hidden (update references to resolvedSections, resolved*
variables, and expandedSections accordingly).

---

Nitpick comments:
In `@apps/customer-portal/webapp/src/components/header/GetHelpDropdown.tsx`:
- Around line 224-229: The conditional rendering inside the Menu that checks
isProjectsListBusy is dead code because GetHelpDropdownContent returns early
when the projects list is busy; remove the ternary (isProjectsListBusy ?
<Skeleton...> : menuItems.map(...)) and simplify the Menu body to always render
menuItems.map(...) (use the existing menuItems array/map logic). Also remove any
now-unused references to isProjectsListBusy within GetHelpDropdownContent/Menu
to keep the component tidy.

In `@apps/customer-portal/webapp/src/features/settings/utils/settingsStorage.ts`:
- Around line 112-118: Change setPendingSettingsTab to accept the typed enum
SettingsPageTabId instead of a plain string: update the function signature
setPendingSettingsTab(tabId: SettingsPageTabId): void, keep storing tabId as a
string to sessionStorage using PENDING_SETTINGS_TAB_KEY, and update all callers
(e.g. the literal "ai" in SettingsAiAssistant.tsx) to pass a SettingsPageTabId
value. You can still read/resolve it in SettingsPage.tsx with
resolveSettingsPageTabId as before; this change just prevents typos at call
sites.
🪄 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: e73d4c6e-7ea3-4b04-9163-8f3a7666b128

📥 Commits

Reviewing files that changed from the base of the PR and between 91591c7 and 5fd39c1.

📒 Files selected for processing (16)
  • apps/customer-portal/webapp/src/components/header/GetHelpDropdown.tsx
  • apps/customer-portal/webapp/src/context/success-banner/SuccessBannerContext.tsx
  • apps/customer-portal/webapp/src/features/dashboard/pages/DashboardItemsPage.tsx
  • apps/customer-portal/webapp/src/features/operations/components/change-requests/ChangeRequestsListSkeleton.tsx
  • apps/customer-portal/webapp/src/features/operations/pages/OperationsPage.tsx
  • apps/customer-portal/webapp/src/features/project-hub/constants/projectHubConstants.ts
  • apps/customer-portal/webapp/src/features/settings/components/SettingsAiAssistant.tsx
  • apps/customer-portal/webapp/src/features/settings/pages/SettingsPage.tsx
  • apps/customer-portal/webapp/src/features/settings/utils/settingsStorage.ts
  • apps/customer-portal/webapp/src/features/support/api/useGetCaseComments.ts
  • apps/customer-portal/webapp/src/features/support/components/case-details/activity-tab/CommentBubble.tsx
  • apps/customer-portal/webapp/src/features/support/components/novera-ai-assistant/novera-chat-page/ChatMessageBubble.tsx
  • apps/customer-portal/webapp/src/features/support/components/support-overview-cards/OutstandingCasesSkeleton.tsx
  • apps/customer-portal/webapp/src/features/support/pages/DescribeIssuePage.tsx
  • apps/customer-portal/webapp/src/features/support/types/cases.ts
  • apps/customer-portal/webapp/src/features/support/utils/support.ts

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

Labels

App/Customer Portal Type/Improvement Marks enhancements or improvements to existing features Type/New Feature Represents a request or task for a new feature Type/Task General task that does not fit into other categories Type/UX Refers to user experience-related tasks or issues

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants