Skip to content

[Customer Portal] Fix chat card navigation, cache KB recommendations, and cap chat history payload - #789

Merged
cloby99 merged 1 commit into
wso2-open-operations:mainfrom
SasmithaDilshan:customer-portal
Jun 3, 2026
Merged

cloby99 merged 1 commit into
wso2-open-operations:mainfrom
SasmithaDilshan:customer-portal

Conversation

@SasmithaDilshan

@SasmithaDilshan SasmithaDilshan commented Jun 2, 2026 •

Copy link
Copy Markdown
Contributor

Description:

Summary

  • Fix chat card click on active/open/abandoned chats to navigate to the live chat page (same as the Resume button), enabling the "Create Case" button
  • Cache KB article recommendation API calls once per conversation instead of re-firing on every new message; increase staleTime to 45 minutes
  • Cap each message's text to the last 150 characters when building the chat history payload for both the classification and recommendation endpoints

Changes

  • ChatHistoryCard.tsx — card-level click now uses getChatStatusAction(item.status) instead of hardcoded ChatAction.VIEW
  • useConversationRecommendationsSearch.ts — query key uses conversationId, staleTime bumped from 10min → 45min
  • caseCreation.ts — formatChatHistoryForClassification truncates each message to last 150 chars
  • recommendations.ts — buildRecommendationRequestFromConversationMessages truncates each message to last 150 chars

Summary by CodeRabbit

  • Bug Fixes

    • Fixed chat history card button action to respond correctly based on conversation status.
  • Improvements

    • Optimized message text handling with character truncation for improved performance.
    • Increased cache duration for conversation recommendations from 10 to 45 minutes.
  • Tests

    • Added test coverage for message formatting and recommendation request building.

…ory payload

- Fix ChatHistoryCard card click to use status-aware action so active/open/abandoned chats navigate to the live chat page and Create Case works
- Key KB recommendation query by conversationId to fire once per conversation; increase staleTime to 45 minutes
- Cap message text to last 150 chars in classification and recommendation payloads

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

coderabbitai Bot commented Jun 2, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

This PR refines message handling for AI-powered recommendations and case classification: chat messages are truncated to 150 characters when building recommendation and classification payloads, recommendation search caching is optimized with conversationId-based query keys and longer staleTime, chat history card interactions are aligned with status-based action computation, and dashboard test infrastructure is expanded with new hook mocks.

Changes

Support/Recommendations Message Processing

Layer / File(s) Summary
Message truncation in classification and recommendations
apps/customer-portal/webapp/src/features/support/utils/caseCreation.ts, apps/customer-portal/webapp/src/features/support/utils/recommendations.ts
Both formatChatHistoryForClassification and buildRecommendationRequestFromConversationMessages now truncate trimmed message content/text to the last 150 characters before including it in their payloads.
Message truncation test coverage
apps/customer-portal/webapp/src/features/support/utils/__tests__/caseCreation.test.ts, apps/customer-portal/webapp/src/features/support/utils/__tests__/recommendations.test.ts
New test suites verify correct truncation of long messages to 150 characters, preservation of short messages, and proper User:/Assistant: prefix handling in classification output.
Recommendation search hook optimization
apps/customer-portal/webapp/src/features/support/api/useConversationRecommendationsSearch.ts
Hook accepts optional conversationId parameter for improved React Query cache keying (replacing payload fields), and staleTime increases from 10 to 45 minutes.
Chat history card action alignment
apps/customer-portal/webapp/src/features/support/components/support-overview-cards/ChatHistoryCard.tsx
Button click now passes computed status-based action to onItemAction instead of hardcoded ChatAction.VIEW.

Dashboard Test Setup

Layer / File(s) Summary
Dashboard test module mocks
apps/customer-portal/webapp/src/features/dashboard/components/cases-table/__tests__/CasesTable.test.tsx
Vitest mocks added for useGetProjectCases, usePostProjectDeploymentsSearchInfinite, and useGetProjectContacts with pagination, loading/error states, and fetchNextPage.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly related PRs

  • wso2-open-operations/cs-tools#489: Frontend buildRecommendationRequestFromConversationMessages message truncation aligns with backend /recommendations endpoint that consumes the request payload.
  • wso2-open-operations/cs-tools#292: Recommendation search hook and chat history card action handling changes align with conversation-based KB recommendations UI rendering.

Suggested labels

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

Suggested reviewers

  • Rashmika998

Poem

🐰 A rabbit hops through message streams,
Trimming words to 150 beams—
Recommendations flow with cleaner cache,
Chat cards now click with matching stash. ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description provides a clear summary of changes and specific file modifications, but lacks required template sections like Purpose/Goals, Approach, User stories, Release notes, Documentation, and other standard sections. Fill out the complete PR description template with Purpose, Goals, Approach, User stories, Release notes, Documentation, Training, Certification, Marketing, Automation tests, Security checks, and other required sections.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically summarizes all three main changes: chat card navigation fix, KB recommendations caching, and chat history payload capping.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% 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.

@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

🧹 Nitpick comments (3)
apps/customer-portal/webapp/src/features/support/utils/caseCreation.ts (1)

374-385: ⚡ Quick win

Extract the 150-character tail cap into a shared helper/constant.

This trim-and-tail rule now exists here and in recommendations.ts; keeping the policy duplicated makes the classification and recommendation payload builders easy to drift apart again. Centralizing the cap and truncation behavior will keep both endpoints and their tests aligned.

♻️ Possible direction
+export const CHAT_HISTORY_TAIL_CHAR_LIMIT = 150;
+
+export function getTrimmedMessageTail(text?: string | null): string {
+  return (text ?? "").trim().slice(-CHAT_HISTORY_TAIL_CHAR_LIMIT);
+}
-      const text = (m.text || "").trim().slice(-150);
+      const text = getTrimmedMessageTail(m.text);
-    const content = (m.content?.trim() ?? "").slice(-150);
+    const content = getTrimmedMessageTail(m.content);
🤖 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/customer-portal/webapp/src/features/support/utils/caseCreation.ts`
around lines 374 - 385, Extract the 150-character tail cap into a shared
constant/helper and use it in formatChatHistoryForClassification to perform
truncation via the shared utility; specifically, create (or reuse) a helper like
truncateTail(text: string, maxChars: number) and a MAX_TAIL_CHARS constant (set
to 150), replace the inline .trim().slice(-150) in
formatChatHistoryForClassification with a call to truncateTail(text,
MAX_TAIL_CHARS), and update the other location (recommendations.ts) to consume
the same constant/helper so both builders use identical truncation logic.
apps/customer-portal/webapp/src/features/support/api/useConversationRecommendationsSearch.ts (1)

27-37: 💤 Low value

Document the new conversationId parameter in JSDoc.

The JSDoc lists only payload and enabled; add a @param entry for the new optional conversationId.

📝 Proposed JSDoc update
  * `@param` {RecommendationSearchRequest | null} payload - Request body, or null to skip.
  * `@param` {boolean} enabled - When false, the query does not run.
+ * `@param` {string} [conversationId] - Stable conversation identifier used as the cache key to dedupe recommendation calls per conversation.
  * `@returns` {UseQueryResult<RecommendationSearchResponse, Error>} Query result.

Based on learnings: ensure JSDoc is complete and attached to the correct signature in apps/customer-portal/webapp.

🤖 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/customer-portal/webapp/src/features/support/api/useConversationRecommendationsSearch.ts`
around lines 27 - 37, The JSDoc for useConversationRecommendationsSearch is
missing documentation for the newly added optional conversationId parameter;
update the comment block above the function to add a `@param` {string | undefined}
conversationId - Optional conversation ID to scope the recommendation search (or
similar wording matching types). Make sure the `@param` entry is included with the
existing `@param` lines and appears directly above the
useConversationRecommendationsSearch function signature.
apps/customer-portal/webapp/src/features/dashboard/components/cases-table/__tests__/CasesTable.test.tsx (1)

34-67: ⚡ Quick win

Use one configurable mock per hook module.

These new mocks are hard-coded factory functions, and two of the module paths are declared twice. In Vitest's hoisted mock model that makes it unclear which factory is actually in play, and it also prevents this file from using the same vi.mocked(...).mockReturnValue(...) pattern already used for useGetProjectCasesPage / useGetProjectFilters when you need to cover showAll, deployment pages, or contacts loading branches.

♻️ Suggested pattern
+const mockUseGetProjectCases = vi.fn();
+const mockUsePostProjectDeploymentsSearchInfinite = vi.fn();
+const mockUseGetProjectContacts = vi.fn();
+
 vi.mock("`@api/useGetProjectCases`", () => ({
-  default: () => ({
-    data: undefined,
-    isLoading: false,
-    isError: false,
-    hasNextPage: false,
-    isFetchingNextPage: false,
-    fetchNextPage: vi.fn(),
-  }),
+  default: mockUseGetProjectCases,
 }));
+
 vi.mock("`@api/usePostProjectDeploymentsSearch`", () => ({
-  usePostProjectDeploymentsSearchInfinite: () => ({
-    data: undefined,
-    isLoading: false,
-    hasNextPage: false,
-    isFetchingNextPage: false,
-    fetchNextPage: vi.fn(),
-  }),
+  usePostProjectDeploymentsSearchInfinite:
+    mockUsePostProjectDeploymentsSearchInfinite,
 }));
+
 vi.mock("`@features/settings/api/useGetProjectContacts`", () => ({
-  default: () => ({ data: [], isLoading: false }),
+  default: mockUseGetProjectContacts,
 }));
-vi.mock("`@api/usePostProjectDeploymentsSearch`", () => ({
-  usePostProjectDeploymentsSearchInfinite: () => ({
-    data: undefined,
-    isLoading: false,
-    hasNextPage: false,
-    isFetchingNextPage: false,
-    fetchNextPage: vi.fn(),
-  }),
-}));
-vi.mock("`@features/settings/api/useGetProjectContacts`", () => ({
-  default: () => ({ data: [], isLoading: false }),
-}));

Then set defaults in beforeEach with mockReturnValue(...).

Based on learnings: In Vitest, don’t rely on hoisted top-level vi.mock(...) definitions as fixed behavior; use a single top-level mock and configure its return value within each test.

🤖 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/customer-portal/webapp/src/features/dashboard/components/cases-table/__tests__/CasesTable.test.tsx`
around lines 34 - 67, Replace the multiple hard-coded top-level vi.mock calls
with a single vi.mock per module (for the hooks useGetProjectCases,
usePostProjectDeploymentsSearch (exporting
usePostProjectDeploymentsSearchInfinite) and useGetProjectContacts) and remove
duplicate declarations; then in your test file configure their return values
inside beforeEach using vi.mocked(<hook>).mockReturnValue(...) (or
mockReturnValueOnce where needed) so tests can toggle branches like showAll,
deployment pages, and contacts loading by setting different mock returns per
test instead of relying on hoisted factories.
🤖 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/customer-portal/webapp/src/features/support/api/useConversationRecommendationsSearch.ts`:
- Around line 44-47: The query key in useConversationRecommendationsSearch is
colliding because conversationId is optional/unused and the key falls back to
payload?.chatHistory[0]?.timestamp ?? "" (which can be empty), so update the
hook to use a reliable unique identifier: either require and use conversationId
in the queryKey (e.g., include conversationId as the second element) or derive a
guaranteed-unique id from payload (e.g., payload.conversationId) instead of
earliest timestamp; also fix the payload builder to avoid mapping missing
createdOn to "" (use null/undefined or a real id) and add JSDoc for the
conversationId parameter (or remove the unused param) so callers and cache keys
are consistent with staleTime handling.

---

Nitpick comments:
In
`@apps/customer-portal/webapp/src/features/dashboard/components/cases-table/__tests__/CasesTable.test.tsx`:
- Around line 34-67: Replace the multiple hard-coded top-level vi.mock calls
with a single vi.mock per module (for the hooks useGetProjectCases,
usePostProjectDeploymentsSearch (exporting
usePostProjectDeploymentsSearchInfinite) and useGetProjectContacts) and remove
duplicate declarations; then in your test file configure their return values
inside beforeEach using vi.mocked(<hook>).mockReturnValue(...) (or
mockReturnValueOnce where needed) so tests can toggle branches like showAll,
deployment pages, and contacts loading by setting different mock returns per
test instead of relying on hoisted factories.

In
`@apps/customer-portal/webapp/src/features/support/api/useConversationRecommendationsSearch.ts`:
- Around line 27-37: The JSDoc for useConversationRecommendationsSearch is
missing documentation for the newly added optional conversationId parameter;
update the comment block above the function to add a `@param` {string | undefined}
conversationId - Optional conversation ID to scope the recommendation search (or
similar wording matching types). Make sure the `@param` entry is included with the
existing `@param` lines and appears directly above the
useConversationRecommendationsSearch function signature.

In `@apps/customer-portal/webapp/src/features/support/utils/caseCreation.ts`:
- Around line 374-385: Extract the 150-character tail cap into a shared
constant/helper and use it in formatChatHistoryForClassification to perform
truncation via the shared utility; specifically, create (or reuse) a helper like
truncateTail(text: string, maxChars: number) and a MAX_TAIL_CHARS constant (set
to 150), replace the inline .trim().slice(-150) in
formatChatHistoryForClassification with a call to truncateTail(text,
MAX_TAIL_CHARS), and update the other location (recommendations.ts) to consume
the same constant/helper so both builders use identical truncation logic.
🪄 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: bc740c41-0807-4f26-b0a6-6bcb793dbccf

📥 Commits

Reviewing files that changed from the base of the PR and between 6d627ae and 8ac2a26.

📒 Files selected for processing (7)
  • apps/customer-portal/webapp/src/features/dashboard/components/cases-table/__tests__/CasesTable.test.tsx
  • apps/customer-portal/webapp/src/features/support/api/useConversationRecommendationsSearch.ts
  • apps/customer-portal/webapp/src/features/support/components/support-overview-cards/ChatHistoryCard.tsx
  • apps/customer-portal/webapp/src/features/support/utils/__tests__/caseCreation.test.ts
  • apps/customer-portal/webapp/src/features/support/utils/__tests__/recommendations.test.ts
  • apps/customer-portal/webapp/src/features/support/utils/caseCreation.ts
  • apps/customer-portal/webapp/src/features/support/utils/recommendations.ts

@cloby99
cloby99 merged commit 758deed into wso2-open-operations:main Jun 3, 2026
1 check passed
@SasmithaDilshan SasmithaDilshan self-assigned this Jul 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants