[Customer Portal][Web] Improve Novera Chat UX with Conversation History & Article Recommendations - #292
Conversation
Introduce a Recommendation interface (title, articleId, score) and add an optional recommendations field to the Message type. Wire conversationResponse.recommendations?.recommendations into newly created Message objects so recommendation data from the backend is preserved in the chat message model for rendering in the UI.
Introduce a new RecommendationsCard React component to display knowledge base article recommendations from the Novera AI agent. The component (apps/customer-portal/webapp/src/components/support/novera-ai-assistant/novera-chat-page/RecommendationsCard.tsx) accepts a recommendations array, renders up to four clickable cards, and opens the corresponding KB article in a new tab via KB_BASE_URL. Uses WSO2 Oxygen UI components and icons, applies themed styling and hover effects, and returns an empty fragment when no recommendations are provided.
Import RecommendationsCard and conditionally render it for non-user messages that include recommendations. Adds a block that displays message.recommendations via RecommendationsCard (when length > 0), so suggested recommendations appear below the message content.
📝 WalkthroughWalkthroughAdds UI and data flow for knowledge-base article recommendations in the Novera AI chat: new RecommendationsCard component, rendering of recommendations in ChatMessageBubble, propagation of a Recommendation type and recommendations[] on Message in NoveraChatPage, plus related routing, skeleton, and chat-status helper changes. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant Frontend as NoveraChatPage
participant Backend as ConversationAPI
participant KB as KnowledgeBase
User->>Frontend: Send message / resume conversation
Frontend->>Backend: fetch conversation messages / send user message
Backend-->>Frontend: bot message with recommendations[]
Frontend->>Frontend: map API response -> Message(recommendations)
Frontend->>Frontend: render ChatMessageBubble for bot
Frontend->>Frontend: render RecommendationsCard (cards with links)
User->>KB: click recommendation (opens new tab to KB article)
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 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 (1)
apps/customer-portal/webapp/src/components/support/novera-ai-assistant/novera-chat-page/RecommendationsCard.tsx (1)
49-51: Encode thearticleIdto prevent URL issues with special characters.If
articleIdcontains characters like spaces,&,?, or#, the URL could break or behave unexpectedly. UseencodeURIComponentfor safety.🛡️ Proposed fix
const handleArticleClick = (articleId: string) => { - window.open(`${KB_BASE_URL}${articleId}`, "_blank", "noopener,noreferrer"); + window.open(`${KB_BASE_URL}${encodeURIComponent(articleId)}`, "_blank", "noopener,noreferrer"); };🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/customer-portal/webapp/src/components/support/novera-ai-assistant/novera-chat-page/RecommendationsCard.tsx` around lines 49 - 51, The handleArticleClick function should URL-encode the articleId before concatenating with KB_BASE_URL to avoid broken URLs from special characters; update handleArticleClick to call encodeURIComponent(articleId) (keeping window.open with target "_blank" and "noopener,noreferrer") so the final URL is `${KB_BASE_URL}${encodeURIComponent(articleId)}`.
🤖 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/components/support/novera-ai-assistant/novera-chat-page/RecommendationsCard.tsx`:
- Around line 80-95: The Card elements rendered in RecommendationsCard are
clickable via onClick but missing keyboard accessibility; update the Card (the
Card element that uses key={rec.articleId || index} and onClick={() =>
handleArticleClick(rec.articleId)}) to either use an accessible Link or add
role="button", tabIndex={0}, and an onKeyDown handler that calls
handleArticleClick(rec.articleId) when Enter or Space is pressed; ensure the
same visual focus styles are preserved and do not remove the existing onClick
handler so both mouse and keyboard activate the same action.
---
Nitpick comments:
In
`@apps/customer-portal/webapp/src/components/support/novera-ai-assistant/novera-chat-page/RecommendationsCard.tsx`:
- Around line 49-51: The handleArticleClick function should URL-encode the
articleId before concatenating with KB_BASE_URL to avoid broken URLs from
special characters; update handleArticleClick to call
encodeURIComponent(articleId) (keeping window.open with target "_blank" and
"noopener,noreferrer") so the final URL is
`${KB_BASE_URL}${encodeURIComponent(articleId)}`.
ℹ️ Review info
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
apps/customer-portal/webapp/src/components/support/novera-ai-assistant/novera-chat-page/ChatMessageBubble.tsxapps/customer-portal/webapp/src/components/support/novera-ai-assistant/novera-chat-page/RecommendationsCard.tsxapps/customer-portal/webapp/src/pages/NoveraChatPage.tsx
Load and resume conversations from URL in NoveraChatPage, show skeleton while history loads, and persist conversationId to the URL. Changes include importing useGetConversationMessages and ChatSkeleton, initializing messages empty when resuming, converting loaded history into Message items, and guarding send/input while history is loading. SupportPage onItemAction now accepts an action and routes to the chat resume path for resume actions (otherwise routes to conversation details). utils/support.ts: adjust chat action logic/colors and add getConversationStatusColor and getConversationStatusIcon helpers (with new icon imports) to map ConversationStatus to palette colors and icons.
Introduce a new ChatSkeleton component to show loading placeholders for the chat UI. Add a dynamic route (":conversationId") that renders NoveraChatPage so individual conversation URLs open correctly. Update ChatHistoryList to always trigger ChatAction.VIEW on item click (ensuring consistent behavior) and apply a small chip label spacing tweak (marginTop: -1px) for visual alignment.
There was a problem hiding this comment.
🧹 Nitpick comments (2)
apps/customer-portal/webapp/src/pages/SupportPage.tsx (1)
198-207: UseChatAction.RESUMEconstant instead of string literal.The comparison uses the string literal
"resume"while the codebase definesChatAction.RESUMEconstant insupportConstants.ts. Using the constant improves type safety and consistency.♻️ Suggested refactor
+import { ChatAction } from "@constants/supportConstants";Then update the comparison:
- if (action === "resume") { + if (action === ChatAction.RESUME) {🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/customer-portal/webapp/src/pages/SupportPage.tsx` around lines 198 - 207, Replace the string literal "resume" used in the action comparison with the ChatAction.RESUME constant from supportConstants.ts: update the conditional that checks action (the one that chooses between navigate(`/${projectId}/support/chat/${chatId}`) and navigate(`/${projectId}/support/conversations/${chatId}`, { state: { conversationSummary: summary } })) to compare against ChatAction.RESUME instead of "resume" to ensure type safety and consistency.apps/customer-portal/webapp/src/pages/NoveraChatPage.tsx (1)
49-53: Consider co-locating or sharing theRecommendationtype.The
Recommendationinterface is exported here but appears to originate from API responses. Consider moving it to a shared types/models location (e.g.,@models/responses) for better discoverability and reuse across components.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/customer-portal/webapp/src/pages/NoveraChatPage.tsx` around lines 49 - 53, The Recommendation interface should be moved out of NoveraChatPage and into a shared model so it can be reused: create or add to a shared types module (e.g., `@models/responses`) an exported Recommendation type (matching the current fields title, articleId, score), replace the local export in NoveraChatPage.tsx with an import from that shared module, and update any other files that currently import or declare Recommendation to import it from the new shared location; ensure named export/imports remain consistent and run the build/type-check to catch any import path fixes.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@apps/customer-portal/webapp/src/pages/NoveraChatPage.tsx`:
- Around line 49-53: The Recommendation interface should be moved out of
NoveraChatPage and into a shared model so it can be reused: create or add to a
shared types module (e.g., `@models/responses`) an exported Recommendation type
(matching the current fields title, articleId, score), replace the local export
in NoveraChatPage.tsx with an import from that shared module, and update any
other files that currently import or declare Recommendation to import it from
the new shared location; ensure named export/imports remain consistent and run
the build/type-check to catch any import path fixes.
In `@apps/customer-portal/webapp/src/pages/SupportPage.tsx`:
- Around line 198-207: Replace the string literal "resume" used in the action
comparison with the ChatAction.RESUME constant from supportConstants.ts: update
the conditional that checks action (the one that chooses between
navigate(`/${projectId}/support/chat/${chatId}`) and
navigate(`/${projectId}/support/conversations/${chatId}`, { state: {
conversationSummary: summary } })) to compare against ChatAction.RESUME instead
of "resume" to ensure type safety and consistency.
ℹ️ Review info
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
apps/customer-portal/webapp/src/App.tsxapps/customer-portal/webapp/src/components/support/novera-ai-assistant/novera-chat-page/ChatSkeleton.tsxapps/customer-portal/webapp/src/components/support/support-overview-cards/ChatHistoryList.tsxapps/customer-portal/webapp/src/pages/NoveraChatPage.tsxapps/customer-portal/webapp/src/pages/SupportPage.tsxapps/customer-portal/webapp/src/utils/support.ts
b2f9cbc
into
wso2-open-operations:customer-portal-milestone-1
Description
This pull request introduces several enhancements to the Novera AI chat experience in the customer portal, focusing on improved conversation history handling, article recommendations, and user interface improvements. The main changes include support for resuming chat conversations via URL, displaying knowledge base article recommendations in chat, and adding a loading skeleton for chat messages.
Conversation history and navigation improvements:
:conversationId), enabling users to revisit or share specific chat sessions. The chat page now loads and displays previous messages for the given conversation. (apps/customer-portal/webapp/src/App.tsx[1]apps/customer-portal/webapp/src/pages/NoveraChatPage.tsx[2] [3] [4] [5] [6] [7]apps/customer-portal/webapp/src/pages/SupportPage.tsx[1] [2]apps/customer-portal/webapp/src/components/support/support-overview-cards/ChatHistoryList.tsx[3]Chat UI and user experience enhancements:
ChatSkeletoncomponent to display loading skeletons while chat history is being fetched, providing a smoother user experience during data loads. (apps/customer-portal/webapp/src/components/support/novera-ai-assistant/novera-chat-page/ChatSkeleton.tsx[1]apps/customer-portal/webapp/src/pages/NoveraChatPage.tsx[2] [3]apps/customer-portal/webapp/src/components/support/support-overview-cards/ChatHistoryList.tsxapps/customer-portal/webapp/src/components/support/support-overview-cards/ChatHistoryList.tsxR171)Knowledge base recommendations:
RecommendationsCardcomponent that displays knowledge base article recommendations under bot messages when available, enhancing the value of AI responses. (apps/customer-portal/webapp/src/components/support/novera-ai-assistant/novera-chat-page/RecommendationsCard.tsx[1]apps/customer-portal/webapp/src/components/support/novera-ai-assistant/novera-chat-page/ChatMessageBubble.tsx[2] [3]apps/customer-portal/webapp/src/pages/NoveraChatPage.tsx[4] [5] [6]API and type updates:
useGetConversationMessageshook to fetch conversation history and updated theMessageandRecommendationtypes to support new features. (apps/customer-portal/webapp/src/pages/NoveraChatPage.tsx[1] [2] [3]Other:
apps/customer-portal/webapp/src/utils/support.tsapps/customer-portal/webapp/src/utils/support.tsR18-R34)Summary by CodeRabbit
New Features
UX Improvements