diff --git a/.changeset/fn-7441-chat-conversation-rename.md b/.changeset/fn-7441-chat-conversation-rename.md new file mode 100644 index 0000000000..1a80f2ccbd --- /dev/null +++ b/.changeset/fn-7441-chat-conversation-rename.md @@ -0,0 +1,7 @@ +--- +"@runfusion/fusion": patch +--- + +summary: Add sidebar rename buttons to direct Chat conversations. +category: feature +dev: Reuses ChatView's existing rename dialog and useChat renameSession path. diff --git a/docs/dashboard-guide.md b/docs/dashboard-guide.md index 92051a2ff0..847a659883 100644 --- a/docs/dashboard-guide.md +++ b/docs/dashboard-guide.md @@ -408,7 +408,7 @@ Chat view provides project-scoped conversations with agents. - Chat message lists now track near-bottom scroll state: while you are reading older messages, live streaming/new replies do not force-scroll; a **Latest** jump control appears until you return to the tail. - On mobile direct-chat threads, entering a thread and restoring Chat after tab/page visibility returns re-anchors to the newest message (`scrollTop = scrollHeight`) so the view always opens at the live tail. - On mobile direct-chat threads, tapping the active title/identity in the thread header opens a lightweight conversation dropdown so you can switch to another direct session or start a New Chat without backing out to the sidebar list first; long conversation titles now stay readable in the dropdown via wrapped option text and taller touch-friendly rows. -- Direct chat sessions can be renamed from the desktop conversation context menu and from the mobile session switcher; blank rename submissions clear the custom title so the default session label is shown again. +- Direct chat sessions can be renamed from the sidebar row edit button, the desktop conversation context menu, and the mobile session switcher; blank rename submissions clear the custom title so the default session label is shown again. - Task-detail planner Chat conversations stay available from each task's **Chat** tab, including after the task is `done`. They are hidden from the common Direct/common Chat feed by default; enable **Settings → Project General → Show task chats in common Chat feed** to include populated task chats again. Empty task chat sessions stay hidden either way. Planner Chat can answer token-count, estimated-cost, runtime, timing-event, workflow-step duration, and per-model usage questions for the current task through a read-only task-scoped metrics tool; unknown/stale pricing is reported as uncertain instead of `$0`. On completed tasks, clear follow-up implementation or improvement requests can create a normal refinement task from the completed source task. diff --git a/packages/dashboard/app/components/ChatView.css b/packages/dashboard/app/components/ChatView.css index 0f10beaab4..104f6af6ef 100644 --- a/packages/dashboard/app/components/ChatView.css +++ b/packages/dashboard/app/components/ChatView.css @@ -344,7 +344,7 @@ When the movable chat popup is resized narrow, collapse Direct/Rooms labels to i white-space: nowrap; overflow: hidden; text-overflow: ellipsis; - padding-right: calc(var(--space-md) * 3); + padding-right: calc((var(--space-md) * 4) + (var(--space-xs) * 2)); } .chat-session-preview { @@ -353,7 +353,7 @@ When the movable chat popup is resized narrow, collapse Direct/Rooms labels to i white-space: nowrap; overflow: hidden; text-overflow: ellipsis; - padding-right: calc(var(--space-md) * 3); + padding-right: calc((var(--space-md) * 4) + (var(--space-xs) * 2)); } .chat-session-meta { @@ -378,39 +378,37 @@ When the movable chat popup is resized narrow, collapse Direct/Rooms labels to i flex-shrink: 0; } -/* === Chat Session Delete Button === */ -.chat-session-delete-btn { +/* +FNXC:ChatSidebar 2026-07-02-00:00: +Direct conversation rows expose edit and delete as a compact action pair. Keep the pair outside the row text flow so title/preview truncation stays stable across desktop, mobile, and compact right-dock layouts. +*/ +.chat-session-actions { position: absolute; top: var(--space-sm); right: var(--space-sm); - display: flex; + display: inline-flex; align-items: center; - justify-content: center; + gap: var(--space-xs); +} + +.chat-session-action-btn { width: calc(var(--space-md) * 2); + min-width: calc(var(--space-md) * 2); height: calc(var(--space-md) * 2); - padding: 0; - background: transparent; - border: none; + min-height: calc(var(--space-md) * 2); + flex: 0 0 auto; border-radius: var(--radius-sm); color: var(--text-muted); - cursor: pointer; - opacity: 0; - transition: opacity var(--transition-fast), color var(--transition-fast); } -.chat-session-item:hover .chat-session-delete-btn { - opacity: 1; +.chat-session-action-btn:hover, +.chat-session-action-btn:focus-visible { + color: var(--text); } -.chat-session-delete-btn:hover { +.chat-session-delete-btn:hover, +.chat-session-delete-btn:focus-visible { color: var(--color-error); - opacity: 1; -} - -.chat-session-delete-btn:focus { - opacity: 1; - outline: none; - box-shadow: var(--focus-ring-strong); } /* Context menu for session items */ @@ -2200,15 +2198,10 @@ Queued-message banners stack above the composer input with a capped scroll area, min-height: calc(var(--space-lg) * 2.25); } - /* FN-4352: secondary control inside tappable session row; keep compact size (inflated by FN-3628). */ - .chat-session-delete-btn { - opacity: 1; - } - - /* FN-4352/FN-4385: keep row text clearance aligned to compact secondary delete control (matches base compact clearance). */ + /* FN-4352/FN-4385/FN-7441: direct session row action pair stays visible and text keeps clearance for both edit and delete touch targets. */ .chat-session-title, .chat-session-preview { - padding-right: calc(var(--space-md) * 3); + padding-right: calc((var(--space-md) * 4) + (var(--space-xs) * 2)); } .chat-message--assistant .chat-message-render-toggle { diff --git a/packages/dashboard/app/components/ChatView.tsx b/packages/dashboard/app/components/ChatView.tsx index d2c1019f5f..0436c64fd2 100644 --- a/packages/dashboard/app/components/ChatView.tsx +++ b/packages/dashboard/app/components/ChatView.tsx @@ -2716,6 +2716,7 @@ export function ChatView({ projectId, addToast, floating = false, compactLayout defaultModel, ); const sessionModelTag = formatModelTag(sessionResolvedModel?.provider, sessionResolvedModel?.modelId) ?? "Fusion"; + const sessionTitle = session.title || t("chat.untitledSession", "Untitled"); return (
{t("chat.renameConversationBody", "Choose a new name for this conversation. Leave it blank to show Untitled.")}
diff --git a/packages/dashboard/app/components/__tests__/ChatView.core-interactions.test.tsx b/packages/dashboard/app/components/__tests__/ChatView.core-interactions.test.tsx index 17b912aad9..b365721e82 100644 --- a/packages/dashboard/app/components/__tests__/ChatView.core-interactions.test.tsx +++ b/packages/dashboard/app/components/__tests__/ChatView.core-interactions.test.tsx @@ -1288,4 +1288,126 @@ describe("ChatView core interactions", () => { const messageBubble = screen.getByTestId("chat-message-msg-001"); expect(messageBubble.querySelector(".chat-message-avatar")).toBeNull(); }); + + describe("conversation rename affordances", () => { + it("renames the clicked sidebar session without selecting it", async () => { + const selectSession = vi.fn(); + const renameSession = vi.fn().mockResolvedValue(undefined); + const sessions: ChatSessionInfo[] = [ + { + id: "session-001", + agentId: "agent-001", + status: "active", + title: "Alpha Chat", + lastMessagePreview: "Alpha preview", + createdAt: "2026-04-08T00:00:00.000Z", + updatedAt: "2026-04-08T00:00:00.000Z", + }, + { + id: "session-002", + agentId: "agent-002", + status: "active", + title: "Beta Chat", + lastMessagePreview: "Beta preview", + createdAt: "2026-04-07T00:00:00.000Z", + updatedAt: "2026-04-07T00:00:00.000Z", + }, + ]; + + setupMockChat({ + sessions, + filteredSessions: sessions, + activeSession: sessions[0], + selectSession, + renameSession, + }); + await renderWithAct(