Repository navigation
[Customer Portal] Fix chat card navigation, cache KB recommendations, and cap chat history payload - #789
Conversation
…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>
📝 WalkthroughWalkthroughThis 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. ChangesSupport/Recommendations Message Processing
Dashboard Test Setup
Estimated code review effort🎯 2 (Simple) | ⏱️ ~12 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ 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: 1
🧹 Nitpick comments (3)
apps/customer-portal/webapp/src/features/support/utils/caseCreation.ts (1)
374-385: ⚡ Quick winExtract 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 valueDocument the new
conversationIdparameter in JSDoc.The JSDoc lists only
payloadandenabled; add a@paramentry for the new optionalconversationId.📝 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 winUse 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 foruseGetProjectCasesPage/useGetProjectFilterswhen you need to covershowAll, 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
beforeEachwithmockReturnValue(...).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
📒 Files selected for processing (7)
apps/customer-portal/webapp/src/features/dashboard/components/cases-table/__tests__/CasesTable.test.tsxapps/customer-portal/webapp/src/features/support/api/useConversationRecommendationsSearch.tsapps/customer-portal/webapp/src/features/support/components/support-overview-cards/ChatHistoryCard.tsxapps/customer-portal/webapp/src/features/support/utils/__tests__/caseCreation.test.tsapps/customer-portal/webapp/src/features/support/utils/__tests__/recommendations.test.tsapps/customer-portal/webapp/src/features/support/utils/caseCreation.tsapps/customer-portal/webapp/src/features/support/utils/recommendations.ts
Description:
Summary
Changes
ChatHistoryCard.tsx— card-level click now usesgetChatStatusAction(item.status)instead of hardcodedChatAction.VIEWuseConversationRecommendationsSearch.ts— query key usesconversationId, staleTime bumped from 10min → 45mincaseCreation.ts—formatChatHistoryForClassificationtruncates each message to last 150 charsrecommendations.ts—buildRecommendationRequestFromConversationMessagestruncates each message to last 150 charsSummary by CodeRabbit
Bug Fixes
Improvements
Tests