FN-9199: Replace chat text back marker with arrow icon

Use a consistent icon-and-label back affordance across direct and room chat threads.

- Render the lucide ArrowLeft icon with localized Back text and preserved accessible naming.
- Cover mobile direct and room thread back buttons with icon, text, and accessibility assertions.
- Add a patch changeset for the published Fusion package.

Files changed:
 .changeset/fix-chat-back-arrow.md                          |  6 ++++++
 packages/dashboard/app/components/ChatView.css             |  2 +-
 packages/dashboard/app/components/ChatView.tsx             | 14 ++++++++++++--
 .../app/components/__tests__/ChatView.mobile.test.tsx      |  4 +++-
 .../app/components/__tests__/ChatView.rooms.test.tsx       |  7 ++++++-
 5 files changed, 28 insertions(+), 5 deletions(-)

Fusion-Task-Id: FN-9199

Fusion-Task-Lineage: aab2a300-cc2a-4768-b60b-81d7477b8fab

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
This commit is contained in:
gsxdsm
2026-08-23 09:13:23 -07:00
parent bd93723d44
commit 46b329fed9
5 changed files with 28 additions and 5 deletions

View File

@@ -0,0 +1,6 @@
---
"@runfusion/fusion": patch
---
summary: Chat's back button now shows a real back arrow icon instead of a text character.
category: fix

View File

@@ -2181,7 +2181,7 @@ Thinking-section text uses the defined muted text token across all themes. The m
visible, the thread is hidden; when the sidebar is hidden (a session is
open), the sidebar is collapsed via .chat-sidebar--hidden and the
thread takes the full viewport. The thread already renders a back
button (ChevronLeft) on mobile to flip back to the session list. */
button (ArrowLeft) on mobile to flip back to the session list. */
@media (max-width: 768px) {
html[data-viewport-mode="tablet"] .chat-view--docked-list .chat-view__body {
flex-direction: row;

View File

@@ -7,6 +7,7 @@ import {
Search,
Trash2,
Archive,
ArrowLeft,
Pencil,
Bot,
Paperclip,
@@ -3911,6 +3912,13 @@ export function ChatView({ projectId, addToast, floating = false, compactLayout
{rooms.activeRoom ? (
<>
<div className="chat-room-thread-header">
{/*
FNXC:ChatNavigation 2026-08-23-15:54:
FN-9199 requires the chat detail Back affordance to render a real lucide ArrowLeft
glyph, never a literal less-than text character. Both Rooms and Direct thread
headers use this same icon-and-translated-label pattern on every chat host and
breakpoint, while aria-label retains the fuller accessible name.
*/}
{!dockedSidebarVisible ? <button
type="button"
className="btn btn-sm chat-thread-header-back chat-back-btn"
@@ -3918,7 +3926,8 @@ export function ChatView({ projectId, addToast, floating = false, compactLayout
data-testid="chat-back-btn"
aria-label={t("chat.backToConversations", "Back to conversations")}
>
{"< BACK"}
<ArrowLeft size={14} aria-hidden="true" />
<span>{t("chat.back", "Back")}</span>
</button> : null}
<span className="chat-thread-header-title">#{rooms.activeRoom.name}</span>
<div className="chat-room-thread-members">
@@ -4131,7 +4140,8 @@ export function ChatView({ projectId, addToast, floating = false, compactLayout
data-testid="chat-back-btn"
aria-label={t("chat.backToConversations", "Back to conversations")}
>
{"< BACK"}
<ArrowLeft size={14} aria-hidden="true" />
<span>{t("chat.back", "Back")}</span>
</button> : null}
<div className="chat-thread-header-identity" data-testid="chat-thread-header-identity">
{activeModelProvider ? <ProviderIcon provider={activeModelProvider} size="md" /> : <Bot size={16} />}

View File

@@ -54,7 +54,9 @@ describe("ChatView mobile list/detail navigation", () => {
expect(sidebar).toHaveClass("chat-sidebar--hidden");
const back = screen.getByTestId("chat-back-btn");
expect(back).toHaveAccessibleName("Back to conversations");
expect(back).toHaveTextContent("< BACK");
expect(back.textContent ?? "").not.toContain("<");
expect(back.querySelector("svg")).toBeInTheDocument();
expect(back).toHaveTextContent("Back");
expect(back.closest(".chat-thread-header")).toBeInTheDocument();
expect(back.closest(".view-header")).toBeNull();
expect(screen.getAllByTestId("chat-back-btn")).toHaveLength(1);

View File

@@ -777,7 +777,12 @@ describe("ChatView — rooms (FN-3805..FN-3811 contract)", () => {
await renderRoomDetailWithAct(<ChatView projectId="proj-123" addToast={vi.fn()} experimentalFeatures={{ chatRooms: true }} />);
await userEvent.click(screen.getByTestId("chat-room-item-room-a"));
expect(screen.getByTestId("chat-back-btn")).toBeInTheDocument();
const back = screen.getByTestId("chat-back-btn");
expect(back).toBeInTheDocument();
expect(back).toHaveAccessibleName("Back to conversations");
expect(back.textContent ?? "").not.toContain("<");
expect(back.querySelector("svg")).toBeInTheDocument();
expect(back).toHaveTextContent("Back");
mediaSpy.mockRestore();
});