diff --git a/frontend/src/navigation/MobileTopBar.test.tsx b/frontend/src/navigation/MobileTopBar.test.tsx index 37733702..5b241e2c 100644 --- a/frontend/src/navigation/MobileTopBar.test.tsx +++ b/frontend/src/navigation/MobileTopBar.test.tsx @@ -179,4 +179,54 @@ describe('MobileTopBar', () => { expect(menuItem('navigation.editAgent')).toBeDefined(); expect(menuItem('convTile.share')).toBeUndefined(); }); + + it('keeps the menu on a chat or owned agent with an empty name', () => { + render({ + title: '', + conversationId: 'c1', + editAgentPath: '/agents/edit/a1', + onRename: () => {}, + onDelete: () => {}, + }); + + const title = container.querySelector('[data-testid="mobile-title"]')!; + expect(title.tagName).toBe('BUTTON'); + expect(title.textContent).toContain('newChat'); + openMenu(title); + expect(menuItem('navigation.editAgent')).toBeDefined(); + expect(menuItem('convTile.rename')).toBeDefined(); + }); + + it('drops a rename in progress when the conversation changes', () => { + const onRename = vi.fn(); + const props = { title: 'Router drops', onRename, onDelete: () => {} }; + render({ ...props, conversationId: 'c1' }); + + openMenu(container.querySelector('[data-testid="mobile-title"]')!); + act(() => menuItem('convTile.rename')!.click()); + expect(container.querySelector('input')).not.toBeNull(); + + render({ ...props, title: 'Other chat', conversationId: 'c2' }); + expect(container.querySelector('input')).toBeNull(); + expect(button('convTile.save')).toBeNull(); + expect(onRename).not.toHaveBeenCalled(); + }); + + it('closes an open share when the conversation changes', () => { + const props = { + title: 'Router drops', + onRename: () => {}, + onDelete: () => {}, + }; + render({ ...props, conversationId: 'c1' }); + + openMenu(container.querySelector('[data-testid="mobile-title"]')!); + act(() => menuItem('convTile.share')!.click()); + expect( + document.querySelector('[data-testid="share-modal"]'), + ).not.toBeNull(); + + render({ ...props, conversationId: 'c2' }); + expect(document.querySelector('[data-testid="share-modal"]')).toBeNull(); + }); }); diff --git a/frontend/src/navigation/MobileTopBar.tsx b/frontend/src/navigation/MobileTopBar.tsx index 6018d302..297f3378 100644 --- a/frontend/src/navigation/MobileTopBar.tsx +++ b/frontend/src/navigation/MobileTopBar.tsx @@ -87,6 +87,15 @@ export default function MobileTopBar({ const [isShareOpen, setIsShareOpen] = useState(false); const [deleteModalState, setDeleteModalState] = useState('INACTIVE'); + // A rename, share or delete belongs to the chat it started on. The bar + // stays mounted across chats, so drop any that is open when the chat changes. + const [actionsFor, setActionsFor] = useState(conversationId); + if (actionsFor !== conversationId) { + setActionsFor(conversationId); + setIsEditing(false); + setIsShareOpen(false); + setDeleteModalState('INACTIVE'); + } const actions: TitleAction[] = []; if (editAgentPath) { @@ -176,8 +185,8 @@ export default function MobileTopBar({ ); } - if (!title) return null; if (actions.length === 0) { + if (!title) return null; return ( {agentMark} - - {title} + + {title || t('newChat')}