[CSM Portal Microapp] Support page: case list, case detail, and app shell - #1092
Conversation
Wires up the support case list and detail views with routing, layout, and auth/API client updates needed to bootstrap the app.
Case timestamps come from the ServiceNow-backed backend as zone-less
strings ("2026-06-08 10:15:00" or "...T10:15:00", no offset/Z), but
the code parsed them with a bare `new Date(str)`, which treats an
unzoned date-time string as local time rather than UTC. Depending on
the viewer's timezone this silently shifts every timestamp by the
local UTC offset, and on stricter runtimes fails to parse at all —
dayjs renders that failure as "a month ago" instead of erroring,
which is what showed up on every case/service-request card.
Add parseBackendTimestamp()/parseOptionalBackendTimestamp(), which
normalize the zone-less string to explicit UTC before parsing, and
use them wherever case/comment timestamps are mapped from the DTO.
The previous fix only normalized "YYYY-MM-DD HH:mm:ss" and "YYYY-MM-DDTHH:mm:ss" (no zone). The sibling csm-portal webapp's proven normalizer (src/utils/dateTime.ts there) also handles a "MM/DD/YYYY HH:mm:ss" variant and is lenient about non-zero-padded components — some ServiceNow APIs return timestamps in that shape. Port the same three patterns here so the microapp covers what the webapp already covers, since this is what showed up as "Updated —" (the invalid-date fallback) on real case cards.
Checked the sibling csm-portal webapp's mapping (useGetCsmCases.ts: `updatedAt: c.updatedOn ?? c.createdOn ?? ""`) and its hand-maintained backend types (api/backend/types.ts), which mark both createdOn and updatedOn optional — unlike this repo's OpenAPI doc, which declares them required. In practice the search/detail views don't always populate updatedOn (e.g. a case untouched since creation), which is what produced "Updated —" for real cases like CS0440563 even after normalizing the timestamp format. Mark createdOn/updatedOn optional on CaseSearchViewDto/CaseViewDto to match the real contract, and fall back updatedOn to createdOn during mapping, same as the webapp. Also guard formatDate() the same way fromNow() already is, so an unparseable date renders "—" instead of "Invalid Date" on the case detail page.
|
Warning Review limit reached
Next review available in: 52 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the 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 configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughThis PR adds the CSM Portal microapp shell, native bridge, auth and API layers, case data types and services, support/case detail screens, shared UI components, theming, and global styling updates. ChangesCSM Portal Microapp Implementation
Estimated code review effort: 4 (Complex) | ~60 minutes Possibly related PRs
Suggested labels: Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 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 |
There was a problem hiding this comment.
Actionable comments posted: 13
🧹 Nitpick comments (9)
apps/csm-portal/microapp/src/components/microapp-bridge/index.ts (1)
24-34: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winConsolidate
TOPICandTopicinto a single source of truth.
TOPICduplicates several values already in the exportedTopicconstant fromtypes.ts(e.g.,TOKEN,SAVE_LOCAL_DATA,GET_LOCAL_DATA,OPEN_URL,MICRO_APP_VERSION) but is not type-checked againstTopicType. Addingalert,confirm_alert, andtotptoTopicand removingTOPICwould eliminate drift risk and give all topics compile-time safety.🤖 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/microapp/src/components/microapp-bridge/index.ts` around lines 24 - 34, Consolidate the duplicated topic definitions by removing the local TOPIC object in microapp-bridge and using the exported Topic constant from types.ts as the single source of truth. Update TopicType to include the missing alert, confirm_alert, and totp values, then replace all TOPIC references in the microapp bridge with Topic so the topic names stay compile-time checked and cannot drift.apps/csm-portal/microapp/src/components/layout/MainLayout.tsx (1)
21-30: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winConsider using
--tab-bar-heightCSS variable instead of hardcodedpb={15}.
TabBardynamically measures its height and sets--tab-bar-heightviaResizeObserver, butMainLayoutuses a fixedpb={15}(120px with 8px spacing). If the TabBar's actual height diverges from this value—due to font scaling, orientation changes, or safe-area insets—content could overlap the TabBar or leave excess space. Using the CSS variable keeps the layout in sync with the measured height.♻️ Proposed refactor
export default function MainLayout() { return ( <> - <Box component="main" p={2} pb={15}> + <Box component="main" p={2} sx={{ pb: "calc(var(--tab-bar-height, 120px) + 16px)" }}> <Outlet /> </Box> <TabBar /> </> ); }🤖 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/microapp/src/components/layout/MainLayout.tsx` around lines 21 - 30, The MainLayout padding-bottom is hardcoded with pb={15}, which can drift from the TabBar’s measured height. Update MainLayout to use the --tab-bar-height CSS variable instead, referencing the existing TabBar measurement behavior so the main content stays aligned as the bar size changes. Keep the change localized in MainLayout and preserve the Outlet/TabBar structure.apps/csm-portal/microapp/src/services/apiClient.ts (2)
33-35: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick winNo request timeout configured — requests can hang indefinitely.
Without a
timeouton the Axios instance, a non-responsive backend will leave requests pending forever, degrading the UX of the microapp.♻️ Proposed fix
const apiClient = axios.create({ baseURL: BACKEND_URL, + timeout: 30000, });🤖 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/microapp/src/services/apiClient.ts` around lines 33 - 35, The Axios instance in apiClient is missing a request timeout, so requests can hang indefinitely if the backend is unresponsive. Update the axios.create configuration for apiClient to include a reasonable timeout value alongside BACKEND_URL, and keep the change scoped to the shared client so all requests made through this instance inherit the timeout automatically.
155-162: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value
console.errorbypasses theLoggerand native DevTools pipeline.Line 158 uses
console.errordirectly while the rest of the file usesLogger.error. This error won't be forwarded to the native bridge.♻️ Proposed fix
- console.error("Token refresh failed:", refreshError); + Logger.error("Token refresh failed:", refreshError);🤖 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/microapp/src/services/apiClient.ts` around lines 155 - 162, The refresh-failure path in apiClient’s token handling is logging through console.error instead of the shared Logger, so the native bridge won’t receive it. Update the catch block around the token refresh flow to use Logger.error consistently with the existing "Token refresh failed" message and refreshError, and remove the direct console.error call so all errors go through the same logging pipeline.apps/csm-portal/microapp/src/config/config.ts (1)
39-43: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value
serviceUrlshas a redundant nested key.The exported object nests a
serviceUrlskey insideserviceUrls, producingserviceUrls.serviceUrls. This is likely a copy-paste mistake.♻️ Proposed fix
export const serviceUrls = { - serviceUrls: { - // TODO: Add service URLs here as needed for future implementation. - }, + // TODO: Add service URLs here as needed for future implementation. };🤖 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/microapp/src/config/config.ts` around lines 39 - 43, The exported serviceUrls object currently has an unnecessary nested serviceUrls key, resulting in serviceUrls.serviceUrls instead of a flat shape. Update the serviceUrls export in config.ts to remove the inner wrapper and keep only the actual URL entries at the top level of the exported object. Use the serviceUrls symbol as the location to adjust the structure so consumers access URLs directly from serviceUrls.apps/csm-portal/microapp/src/services/auth.ts (1)
44-51: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueReject promises with
Errorobjects, not strings.Rejecting with strings (
"ID Token failed") produces non-Errorrejection values. Downstream handlers usinginstanceof Erroror accessing.message/.stackwill behave unexpectedly.♻️ Proposed fix
- getToken((token) => (token ? resolve(token) : reject("ID Token failed"))); + getToken((token) => (token ? resolve(token) : reject(new Error("ID Token failed"))));- getAccessTokenFromBridge((token) => (token ? resolve(token) : reject("Access Token failed"))); + getAccessTokenFromBridge((token) => (token ? resolve(token) : reject(new Error("Access Token failed"))));🤖 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/microapp/src/services/auth.ts` around lines 44 - 51, Update refreshToken so the promise rejections use Error objects instead of string literals. In the idTokenPromise and accessTokenPromise callbacks, reject with a new Error containing the same failure message, and keep the logic in refreshToken unchanged otherwise so downstream handlers can reliably inspect .message and .stack.apps/csm-portal/microapp/src/pages/CaseDetailPage.tsx (1)
52-54: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick winUse
useSuspenseQueriesfor parallel fetching of case detail and comments.The two
useSuspenseQuerycalls are sequential — the comments query doesn't start until the case detail query resolves. Switching touseSuspenseQueriesallows both to fetch in parallel, cutting perceived load time when both requests take similar durations.♻️ Proposed refactor
-import { useSuspenseQuery } from "`@tanstack/react-query`"; +import { useSuspenseQueries } from "`@tanstack/react-query`"; function CaseDetailContent({ id }: { id: string }) { - const { data: caseDetail } = useSuspenseQuery(cases.get(id)); - const { data: comments } = useSuspenseQuery(cases.comments(id)); + const [{ data: caseDetail }, { data: comments }] = useSuspenseQueries({ + queries: [cases.get(id), cases.comments(id)], + });🤖 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/microapp/src/pages/CaseDetailPage.tsx` around lines 52 - 54, The two data fetches in CaseDetailContent are happening sequentially because separate useSuspenseQuery calls are used for cases.get(id) and cases.comments(id). Refactor this component to use useSuspenseQueries with both query configs so case detail and comments start in parallel, and update the destructuring in CaseDetailContent to read both results from the combined hook.apps/csm-portal/microapp/src/types/case.model.ts (2)
107-108: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueInvalid Date when both
createdOnandupdatedOnare absent.When both fields are
undefined,parseBackendTimestamp("")producesnew Date("")— an Invalid Date. The model types declarecreatedOn: DateandupdatedOn: Date(non-nullable), so consumers expect a validDate. TheformatDate/fromNowutilities guard withNumber.isNaN(date.getTime())and render "—", so the UI is safe. However, the type contract is misleading. Consider typing these asDate | nullin the model and returningnullwhen the source is absent, so the type system reflects reality.Also applies to: 135-136
🤖 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/microapp/src/types/case.model.ts` around lines 107 - 108, The Case model timestamps are typed as non-nullable Date even though parseBackendTimestamp("") can return an Invalid Date when createdOn and updatedOn are missing. Update the relevant model/DTO mapping in case.model.ts, including the constructors or mappers around createdOn and updatedOn, so absent backend values return null instead of an invalid Date. Adjust the associated Case type definitions to Date | null and make sure any consumers rely on the same symbols (parseBackendTimestamp, createdOn, updatedOn) reflect the nullable contract consistently.
104-104: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueUnsafe
as CaseTypecasts ondto.type.
CaseSearchViewDto.typeisstringandCaseViewDto.typeisstring | null, but both are cast toCaseType/CaseType | nullwithout runtime validation. If the backend returns an unexpected type string, the model will carry an invalidCaseType. The UI mitigates this withTYPE_CONFIG[item.type] ?? TYPE_CONFIG.caseinCaseCard.tsx:27, so this is not a runtime defect, but the type assertion masks the gap. Consider narrowing the DTOtypetoCaseTypedirectly (if the backend contract guarantees it), or adding a runtime guard.Also applies to: 131-131
🤖 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/microapp/src/types/case.model.ts` at line 104, The `CaseModel` mapping is unsafely asserting `dto.type` to `CaseType` (and the nullable variant), which can hide invalid backend values. Update the conversion logic in `CaseModel` to either use a runtime guard/validator before assigning `type`, or tighten the DTO definitions for `CaseSearchViewDto`/`CaseViewDto` so `type` is already `CaseType`-typed if the backend contract guarantees it. Make the same fix in both mapping sites that currently use the `as CaseType` cast.
🤖 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/microapp/package.json`:
- Around line 22-24: The package.json versions for `@wso2/oxygen-ui`,
`@wso2/oxygen-ui-charts-react`, and `@wso2/oxygen-ui-icons-react` have been bumped,
but the lockfile still pins older resolved versions. Update the
package-lock.json entries for these three packages so they resolve to 0.6.1
consistently, and make sure the lockfile matches the dependency declarations in
package.json for the microapp package.
In `@apps/csm-portal/microapp/src/components/microapp-bridge/index.ts`:
- Around line 156-158: The error branches in saveLocalData, getLocalData, and
getVersion only log ErrorMessages.NATIVE_BRIDGE_NOT_AVAILABLE and leave the
caller hanging; update each native-bridge fallback path in
microapp-bridge/index.ts to invoke the provided callback with an error/failed
result after logging. Use the existing callback parameters in saveLocalData,
getLocalData, and getVersion so every code path completes even when the native
bridge is unavailable.
- Line 143: Normalize the key string in the microapp bridge helper by replacing
every space, not just the first one. Update the key normalization logic where
key.toString().replace(" ", "-").toLowerCase() is used so it handles all
whitespace occurrences (for example with replaceAll or a global regex), and
apply the same change to the duplicate normalization site noted in the review.
- Line 144: The current bridge serialization in microapp-bridge uses btoa/atob
on JSON.stringify(value), which breaks for UTF-8 payloads like emoji or CJK
characters. Update the paired encode/decode logic in the relevant
microapp-bridge helpers around the existing encodedValue handling to use a
UTF-8-safe approach such as TextEncoder/TextDecoder (or an equivalent safe
base64 wrapper) so both serialization and deserialization can handle non-Latin1
data reliably.
In `@apps/csm-portal/microapp/src/index.css`:
- Line 19: Fix the stylelint violations in index.css by changing the Google
Fonts import in the stylesheet to use plain `@import` string notation instead of
url(), and rename the keyframe definitions gentlePulse and stepIn to kebab-case
names gentle-pulse and step-in. Update any animation references in the same
stylesheet or related styles that use the old keyframe names so they match the
renamed identifiers.
In `@apps/csm-portal/microapp/src/main.tsx`:
- Around line 29-35: The retry guard in the query client setup is treating every
4xx response as non-retryable, which blocks 429 Too Many Requests from backing
off and retrying. Update the retry logic in the main bootstrap configuration to
special-case status 429 as retryable while keeping other 4xx responses excluded,
and keep the existing failureCount-based retry limit intact in the retry
callback.
In `@apps/csm-portal/microapp/src/pages/SupportPage.tsx`:
- Around line 29-43: The SupportPage tab state is being initialized from the URL
only once, so it can drift from the current search param during browser
back/forward navigation. Update SupportPage to derive the active tab directly
from searchParams.tab instead of storing it in local useState, and keep
handleTabChange only responsible for updating the URL via setSearchParams. Use
the existing symbols SupportPage, tabFromParams, tab, and handleTabChange to
make the change.
In `@apps/csm-portal/microapp/src/services/apiClient.ts`:
- Around line 43-49: The apiClient interceptors are logging sensitive data
through Logger and sendNativeLog. Update the request logging in apiClient to
avoid emitting config.headers (especially Authorization) and the full
URL/details that may expose tokens, and change the response logging path to stop
spreading response.data into logs. Use apiClient’s request/response interceptor
code to redact or omit sensitive fields before calling Logger.info and
sendNativeLog, keeping only minimal non-sensitive metadata.
- Around line 52-60: The token refresh flow in apiClient currently reuses
refreshTokenPromise only while a request is in flight, but refreshToken() still
always calls the native bridge and re-initializes the user on every request once
the promise settles. Update the logic around apiClient’s token retrieval path
and refreshToken() so it first checks the current token’s expiry or near-expiry
state, and only invokes the bridge refresh when the token is close to expiring
or already expired. Keep the existing refreshTokenPromise deduping in place, but
make the refresh decision conditional on expiry rather than unconditional.
- Around line 124-126: The Axios response interceptor in apiClient.ts assumes
error.config is always present, but some Axios errors can omit it and cause a
crash before the 401 retry logic runs. Update the interceptor around the
originalRequest/_retry check to first guard for a missing config and exit early
when it is absent. Also extend the request config type used by the interceptor
so it explicitly includes the _retry flag, ensuring the retry marker is
type-safe when accessed in the retry path.
In `@apps/csm-portal/microapp/src/services/auth.ts`:
- Around line 79-92: Wrap the jwtDecode call in checkUserGroups with try-catch
so a malformed ID token doesn’t throw an unhandled exception; on decode failure,
log a clear error with Logger.error and return false. Keep the existing
token-missing early return, and mirror the error-handling pattern used by
decodeTokenAndStoreUser so callers of checkUserGroups can safely rely on a
boolean result.
- Around line 99-123: The success path in decodeTokenAndStoreUser builds a User
but never saves it to the Zustand store, so the current user stays null. Update
decodeTokenAndStoreUser to call useUserStore.getState().setUser(user) after
decoding the token and before returning, while keeping the existing clearUser
calls on the null-token and catch paths. Also ensure initializeUserFromToken
relies on the store update rather than discarding the returned User.
In `@apps/csm-portal/microapp/src/services/cases.ts`:
- Around line 52-57: The getCaseComments helper currently hardcodes a 50-item
page and drops CaseCommentSearchResponseDto pagination metadata, so update it to
either return the full response details (such as total/hasMore) or otherwise
expose enough info for the UI to know more comments exist. Then adjust
CaseCommentsSection to use that metadata for a “Load more” flow or, at minimum,
show a “Showing first 50 comments” hint when the limit is reached, using
getCaseComments and toComment as the key symbols to update.
---
Nitpick comments:
In `@apps/csm-portal/microapp/src/components/layout/MainLayout.tsx`:
- Around line 21-30: The MainLayout padding-bottom is hardcoded with pb={15},
which can drift from the TabBar’s measured height. Update MainLayout to use the
--tab-bar-height CSS variable instead, referencing the existing TabBar
measurement behavior so the main content stays aligned as the bar size changes.
Keep the change localized in MainLayout and preserve the Outlet/TabBar
structure.
In `@apps/csm-portal/microapp/src/components/microapp-bridge/index.ts`:
- Around line 24-34: Consolidate the duplicated topic definitions by removing
the local TOPIC object in microapp-bridge and using the exported Topic constant
from types.ts as the single source of truth. Update TopicType to include the
missing alert, confirm_alert, and totp values, then replace all TOPIC references
in the microapp bridge with Topic so the topic names stay compile-time checked
and cannot drift.
In `@apps/csm-portal/microapp/src/config/config.ts`:
- Around line 39-43: The exported serviceUrls object currently has an
unnecessary nested serviceUrls key, resulting in serviceUrls.serviceUrls instead
of a flat shape. Update the serviceUrls export in config.ts to remove the inner
wrapper and keep only the actual URL entries at the top level of the exported
object. Use the serviceUrls symbol as the location to adjust the structure so
consumers access URLs directly from serviceUrls.
In `@apps/csm-portal/microapp/src/pages/CaseDetailPage.tsx`:
- Around line 52-54: The two data fetches in CaseDetailContent are happening
sequentially because separate useSuspenseQuery calls are used for cases.get(id)
and cases.comments(id). Refactor this component to use useSuspenseQueries with
both query configs so case detail and comments start in parallel, and update the
destructuring in CaseDetailContent to read both results from the combined hook.
In `@apps/csm-portal/microapp/src/services/apiClient.ts`:
- Around line 33-35: The Axios instance in apiClient is missing a request
timeout, so requests can hang indefinitely if the backend is unresponsive.
Update the axios.create configuration for apiClient to include a reasonable
timeout value alongside BACKEND_URL, and keep the change scoped to the shared
client so all requests made through this instance inherit the timeout
automatically.
- Around line 155-162: The refresh-failure path in apiClient’s token handling is
logging through console.error instead of the shared Logger, so the native bridge
won’t receive it. Update the catch block around the token refresh flow to use
Logger.error consistently with the existing "Token refresh failed" message and
refreshError, and remove the direct console.error call so all errors go through
the same logging pipeline.
In `@apps/csm-portal/microapp/src/services/auth.ts`:
- Around line 44-51: Update refreshToken so the promise rejections use Error
objects instead of string literals. In the idTokenPromise and accessTokenPromise
callbacks, reject with a new Error containing the same failure message, and keep
the logic in refreshToken unchanged otherwise so downstream handlers can
reliably inspect .message and .stack.
In `@apps/csm-portal/microapp/src/types/case.model.ts`:
- Around line 107-108: The Case model timestamps are typed as non-nullable Date
even though parseBackendTimestamp("") can return an Invalid Date when createdOn
and updatedOn are missing. Update the relevant model/DTO mapping in
case.model.ts, including the constructors or mappers around createdOn and
updatedOn, so absent backend values return null instead of an invalid Date.
Adjust the associated Case type definitions to Date | null and make sure any
consumers rely on the same symbols (parseBackendTimestamp, createdOn, updatedOn)
reflect the nullable contract consistently.
- Line 104: The `CaseModel` mapping is unsafely asserting `dto.type` to
`CaseType` (and the nullable variant), which can hide invalid backend values.
Update the conversion logic in `CaseModel` to either use a runtime
guard/validator before assigning `type`, or tighten the DTO definitions for
`CaseSearchViewDto`/`CaseViewDto` so `type` is already `CaseType`-typed if the
backend contract guarantees it. Make the same fix in both mapping sites that
currently use the `as CaseType` cast.
🪄 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: cb0878d2-ccd6-4bc7-b67e-8d1b59124148
📒 Files selected for processing (31)
apps/csm-portal/microapp/package.jsonapps/csm-portal/microapp/src/App.tsxapps/csm-portal/microapp/src/components/common/ErrorBoundary.tsxapps/csm-portal/microapp/src/components/layout/MainLayout.tsxapps/csm-portal/microapp/src/components/layout/TabBar.tsxapps/csm-portal/microapp/src/components/microapp-bridge/index.tsapps/csm-portal/microapp/src/components/microapp-bridge/types.tsapps/csm-portal/microapp/src/components/support/CaseCard.tsxapps/csm-portal/microapp/src/components/support/Chips.tsxapps/csm-portal/microapp/src/components/support/EmptyState.tsxapps/csm-portal/microapp/src/components/support/ErrorState.tsxapps/csm-portal/microapp/src/components/support/config.tsxapps/csm-portal/microapp/src/config/config.tsapps/csm-portal/microapp/src/config/endpoints.tsapps/csm-portal/microapp/src/index.cssapps/csm-portal/microapp/src/main.tsxapps/csm-portal/microapp/src/pages/CaseDetailPage.tsxapps/csm-portal/microapp/src/pages/SupportPage.tsxapps/csm-portal/microapp/src/services/apiClient.tsapps/csm-portal/microapp/src/services/auth.tsapps/csm-portal/microapp/src/services/cases.tsapps/csm-portal/microapp/src/store/user.tsapps/csm-portal/microapp/src/theme/index.tsapps/csm-portal/microapp/src/theme/typography.tsapps/csm-portal/microapp/src/types/case.dto.tsapps/csm-portal/microapp/src/types/case.model.tsapps/csm-portal/microapp/src/types/index.tsapps/csm-portal/microapp/src/utils/ApiError.tsapps/csm-portal/microapp/src/utils/constants.tsapps/csm-portal/microapp/src/utils/dateTime.tsapps/csm-portal/microapp/src/utils/logger.ts
…te, token/logging hygiene - microapp-bridge: saveLocalData/getLocalData/getVersion now invoke their callback with a failure result when the native bridge is unavailable, instead of leaving the caller hanging forever. - SupportPage: derive the active tab directly from the ?tab= search param every render instead of a useState that only reads it once, so browser back/forward navigation is reflected instead of showing a stale tab. - apiClient: stop logging config.headers on outgoing requests (a retried request already carries the prior Authorization/x-user-id-token at that point) and stop spreading response.data into the response log (response bodies carry user PII and case content) — both logs forward to the native bridge. Guard against error.config being undefined in the response interceptor, and type the _retry marker instead of relying on implicit any. - auth: refreshToken() now skips the native-bridge round trip (and the user re-init that comes with it) when the current ID token still has useful life left, only refreshing when it's missing or near expiry. checkUserGroups no longer throws on a malformed token. decodeTokenAndStoreUser now actually calls setUser() on success, instead of decoding a user and discarding it. Two other review findings were checked against the sibling webapp and skipped as intentional, not oversights: main.tsx's retry policy and cases.ts's getCaseComments page-size/pagination both match the webapp's documented, deliberate behavior (webapp only retries 502/503 by design, and caps comments at the same 50-item single page with the same "switch to an explicit pagination wrapper" caveat).
Co-authored-by: Anuradha Basnayake <anuradhabsnk@gmail.com>
Co-authored-by: Anuradha Basnayake <anuradhabsnk@gmail.com>
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
apps/csm-portal/microapp/src/index.css (1)
1-16: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick winFix the remaining stylelint violations in
apps/csm-portal/microapp/src/index.css
- Replace
@import url(...)with plain@import "..."at line 19.- Rename
@keyframes gentlePulseand@keyframes stepInto kebab-case at lines 43 and 48.🤖 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/microapp/src/index.css` around lines 1 - 16, Fix the remaining stylelint issues in index.css by updating the stylesheet imports and animation names in the same file: replace the URL-based `@import` with the plain string form, and rename the `@keyframes` blocks gentlePulse and stepIn to kebab-case so they match the project’s naming rules. Update any matching animation references in the CSS to use the new keyframe names consistently.
🤖 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/microapp/src/services/auth.ts`:
- Around line 63-67: The 401 retry path can reuse a stale bearer token because
refreshToken() short-circuits on the ID token alone while the request
interceptor and retry logic still read getAccessToken(). Update the auth flow so
a 401 forces an access-token refresh, or make refreshToken()’s fast path depend
on both the ID token and access token being valid. Use the existing refreshToken
and getAccessToken helpers in auth.ts so the interceptor and retry always pick
up a fresh bearer token.
---
Outside diff comments:
In `@apps/csm-portal/microapp/src/index.css`:
- Around line 1-16: Fix the remaining stylelint issues in index.css by updating
the stylesheet imports and animation names in the same file: replace the
URL-based `@import` with the plain string form, and rename the `@keyframes` blocks
gentlePulse and stepIn to kebab-case so they match the project’s naming rules.
Update any matching animation references in the CSS to use the new keyframe
names consistently.
🪄 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: 985c7bfb-d3ec-4181-a394-9f6d4a04e157
📒 Files selected for processing (22)
apps/csm-portal/microapp/src/App.tsxapps/csm-portal/microapp/src/components/common/ErrorBoundary.tsxapps/csm-portal/microapp/src/components/layout/MainLayout.tsxapps/csm-portal/microapp/src/components/layout/TabBar.tsxapps/csm-portal/microapp/src/components/microapp-bridge/index.tsapps/csm-portal/microapp/src/components/support/CaseCard.tsxapps/csm-portal/microapp/src/components/support/Chips.tsxapps/csm-portal/microapp/src/components/support/EmptyState.tsxapps/csm-portal/microapp/src/components/support/ErrorState.tsxapps/csm-portal/microapp/src/components/support/config.tsxapps/csm-portal/microapp/src/config/endpoints.tsapps/csm-portal/microapp/src/index.cssapps/csm-portal/microapp/src/main.tsxapps/csm-portal/microapp/src/pages/CaseDetailPage.tsxapps/csm-portal/microapp/src/pages/SupportPage.tsxapps/csm-portal/microapp/src/services/apiClient.tsapps/csm-portal/microapp/src/services/auth.tsapps/csm-portal/microapp/src/services/cases.tsapps/csm-portal/microapp/src/types/case.dto.tsapps/csm-portal/microapp/src/types/case.model.tsapps/csm-portal/microapp/src/types/index.tsapps/csm-portal/microapp/src/utils/dateTime.ts
✅ Files skipped from review due to trivial changes (2)
- apps/csm-portal/microapp/src/components/support/ErrorState.tsx
- apps/csm-portal/microapp/src/types/index.ts
🚧 Files skipped from review as they are similar to previous changes (17)
- apps/csm-portal/microapp/src/components/common/ErrorBoundary.tsx
- apps/csm-portal/microapp/src/components/support/EmptyState.tsx
- apps/csm-portal/microapp/src/config/endpoints.ts
- apps/csm-portal/microapp/src/components/support/Chips.tsx
- apps/csm-portal/microapp/src/main.tsx
- apps/csm-portal/microapp/src/components/support/CaseCard.tsx
- apps/csm-portal/microapp/src/components/layout/TabBar.tsx
- apps/csm-portal/microapp/src/components/layout/MainLayout.tsx
- apps/csm-portal/microapp/src/components/support/config.tsx
- apps/csm-portal/microapp/src/pages/SupportPage.tsx
- apps/csm-portal/microapp/src/types/case.dto.ts
- apps/csm-portal/microapp/src/pages/CaseDetailPage.tsx
- apps/csm-portal/microapp/src/types/case.model.ts
- apps/csm-portal/microapp/src/services/cases.ts
- apps/csm-portal/microapp/src/components/microapp-bridge/index.ts
- apps/csm-portal/microapp/src/services/apiClient.ts
- apps/csm-portal/microapp/src/App.tsx
a1ccc62
into
wso2-open-operations:dev-app-csm-portal
Summary
updatedOnentirely; timestamps are now normalized to UTC with acreatedOnfallback.Test plan
npm run lint/tsc --noEmitcleanupdatedOnfallback case)Summary by CodeRabbit