mirror of
https://github.com/BradGroux/veritas-kanban.git
synced 2026-10-06 19:57:50 +00:00
fix: toggle active header chat panels (#1317)
This commit is contained in:
parent
8706b2b765
commit
9529d7e59a
2 changed files with 106 additions and 14 deletions
|
|
@ -1,10 +1,11 @@
|
|||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
import { cleanup, screen, waitFor } from '@testing-library/react';
|
||||
import { cleanup, screen, waitFor, within } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
|
||||
import { ViewProvider } from '@/contexts/ViewContext';
|
||||
import { KeyboardProvider } from '@/hooks/useKeyboard';
|
||||
import { Header } from '@/components/layout/Header';
|
||||
import { DesktopBottomPanel } from '@/components/layout/DesktopBottomPanel';
|
||||
import { DesktopShellProvider } from '@/components/layout/DesktopShellContext';
|
||||
import { UserMenu } from '@/components/layout/UserMenu';
|
||||
import { WorkspaceSwitcher } from '@/components/layout/WorkspaceSwitcher';
|
||||
|
|
@ -137,7 +138,7 @@ function renderHeaderChrome() {
|
|||
);
|
||||
}
|
||||
|
||||
function renderDesktopHeaderChrome() {
|
||||
function renderDesktopHeaderChrome(options: { withBottomPanel?: boolean } = {}) {
|
||||
Object.defineProperty(window, 'veritasDesktop', {
|
||||
configurable: true,
|
||||
value: {
|
||||
|
|
@ -151,6 +152,7 @@ function renderDesktopHeaderChrome() {
|
|||
<ViewProvider>
|
||||
<DesktopShellProvider>
|
||||
<Header />
|
||||
{options.withBottomPanel && <DesktopBottomPanel />}
|
||||
</DesktopShellProvider>
|
||||
</ViewProvider>
|
||||
</KeyboardProvider>
|
||||
|
|
@ -159,7 +161,22 @@ function renderDesktopHeaderChrome() {
|
|||
|
||||
describe('layout chrome Mantine migration', () => {
|
||||
beforeEach(() => {
|
||||
const storage = new Map<string, string>();
|
||||
Object.defineProperty(window, 'localStorage', {
|
||||
configurable: true,
|
||||
value: {
|
||||
get length() {
|
||||
return storage.size;
|
||||
},
|
||||
clear: () => storage.clear(),
|
||||
getItem: (key: string) => storage.get(key) ?? null,
|
||||
key: (index: number) => Array.from(storage.keys())[index] ?? null,
|
||||
removeItem: (key: string) => storage.delete(key),
|
||||
setItem: (key: string, value: string) => storage.set(key, value),
|
||||
} satisfies Storage,
|
||||
});
|
||||
vi.clearAllMocks();
|
||||
window.localStorage.clear();
|
||||
window.history.replaceState({}, '', '/');
|
||||
window.HTMLElement.prototype.scrollIntoView = vi.fn();
|
||||
});
|
||||
|
|
@ -257,12 +274,52 @@ describe('layout chrome Mantine migration', () => {
|
|||
expect(screen.getByRole('button', { name: 'Collapse left sidebar' })).toBeDefined();
|
||||
expect(screen.getByRole('button', { name: 'Expand right sidebar' })).toBeDefined();
|
||||
expect(screen.getByRole('button', { name: 'Open chat dock' })).toBeDefined();
|
||||
expect(screen.getByRole('button', { name: 'Board Chat' })).toBeDefined();
|
||||
expect(screen.getByRole('button', { name: 'Squad Chat' })).toBeDefined();
|
||||
expect(screen.getByRole('button', { name: 'Open Board Chat' })).toBeDefined();
|
||||
expect(screen.getByRole('button', { name: 'Open Squad Chat' })).toBeDefined();
|
||||
|
||||
const brandIcon = screen
|
||||
.getByRole('button', { name: 'Refresh page' })
|
||||
.querySelector('img[src="/icons/pwa-icon-192.png"]');
|
||||
expect(brandIcon).toBeDefined();
|
||||
});
|
||||
|
||||
it.each(['right', 'bottom'] as const)(
|
||||
'toggles and switches the header chat controls with the %s dock',
|
||||
async (dockPosition) => {
|
||||
window.localStorage.setItem('veritas.workbench.dockPosition', dockPosition);
|
||||
const user = userEvent.setup();
|
||||
renderDesktopHeaderChrome({ withBottomPanel: true });
|
||||
|
||||
const openBoard = screen.getByRole('button', { name: 'Open Board Chat' });
|
||||
const openSquad = screen.getByRole('button', { name: 'Open Squad Chat' });
|
||||
expect(openBoard.getAttribute('aria-pressed')).toBe('false');
|
||||
expect(openSquad.getAttribute('aria-pressed')).toBe('false');
|
||||
|
||||
await user.click(openBoard);
|
||||
const closeBoard = screen.getByRole('button', { name: 'Close Board Chat' });
|
||||
expect(closeBoard.getAttribute('aria-pressed')).toBe('true');
|
||||
expect(screen.getByRole('button', { name: 'Switch to Squad Chat' })).toBeDefined();
|
||||
|
||||
await user.click(closeBoard);
|
||||
expect(screen.getByRole('button', { name: 'Open Board Chat' })).toBeDefined();
|
||||
|
||||
await user.click(screen.getByRole('button', { name: 'Open Board Chat' }));
|
||||
await user.click(screen.getByRole('button', { name: 'Switch to Squad Chat' }));
|
||||
const closeSquad = screen.getByRole('button', { name: 'Close Squad Chat' });
|
||||
expect(closeSquad.getAttribute('aria-pressed')).toBe('true');
|
||||
expect(screen.getByRole('button', { name: 'Switch to Board Chat' })).toBeDefined();
|
||||
|
||||
await user.click(closeSquad);
|
||||
await waitFor(() => {
|
||||
const board = screen.getByRole('button', { name: 'Open Board Chat' });
|
||||
const squad = screen.getByRole('button', { name: 'Open Squad Chat' });
|
||||
expect([board, squad]).toContain(document.activeElement);
|
||||
});
|
||||
|
||||
await user.click(screen.getByRole('button', { name: 'Open Board Chat' }));
|
||||
const dock = screen.getByRole('region', { name: `Workbench ${dockPosition} dock` });
|
||||
await user.click(within(dock).getByRole('button', { name: `Close ${dockPosition} dock` }));
|
||||
expect(screen.getByRole('button', { name: 'Open Board Chat' })).toBeDefined();
|
||||
}
|
||||
);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -166,6 +166,23 @@ export function Header() {
|
|||
openBottomPanel,
|
||||
toggleBottomPanel,
|
||||
} = useDesktopShell();
|
||||
const usesWorkbenchChat = isDesktopClient || supportsWorkbenchPanel;
|
||||
const boardChatActive = usesWorkbenchChat && bottomPanel === 'board-chat';
|
||||
const squadChatActive = usesWorkbenchChat && bottomPanel === 'squad-chat';
|
||||
const boardChatAction = !usesWorkbenchChat
|
||||
? 'Open Board Chat'
|
||||
: boardChatActive
|
||||
? 'Close Board Chat'
|
||||
: bottomPanel
|
||||
? 'Switch to Board Chat'
|
||||
: 'Open Board Chat';
|
||||
const squadChatAction = !usesWorkbenchChat
|
||||
? 'Open Squad Chat'
|
||||
: squadChatActive
|
||||
? 'Close Squad Chat'
|
||||
: bottomPanel
|
||||
? 'Switch to Squad Chat'
|
||||
: 'Open Squad Chat';
|
||||
|
||||
const toggleView = useCallback(
|
||||
(nextView: NavigationItem['view']) => setView(view === nextView ? 'board' : nextView),
|
||||
|
|
@ -196,6 +213,14 @@ export function Header() {
|
|||
setChatOpen(true);
|
||||
}, [isDesktopClient, markPanelLoaded, openBottomPanel, supportsWorkbenchPanel]);
|
||||
|
||||
const toggleChatPanel = useCallback(() => {
|
||||
if (usesWorkbenchChat) {
|
||||
toggleBottomPanel('board-chat');
|
||||
return;
|
||||
}
|
||||
openChatPanel();
|
||||
}, [openChatPanel, toggleBottomPanel, usesWorkbenchChat]);
|
||||
|
||||
const openSearchDialog = useCallback(
|
||||
(preset?: SearchPreset) => {
|
||||
markPanelLoaded('search');
|
||||
|
|
@ -214,6 +239,14 @@ export function Header() {
|
|||
setSquadChatOpen(true);
|
||||
}, [isDesktopClient, markPanelLoaded, openBottomPanel, supportsWorkbenchPanel]);
|
||||
|
||||
const toggleSquadChatPanel = useCallback(() => {
|
||||
if (usesWorkbenchChat) {
|
||||
toggleBottomPanel('squad-chat');
|
||||
return;
|
||||
}
|
||||
openSquadChatPanel();
|
||||
}, [openSquadChatPanel, toggleBottomPanel, usesWorkbenchChat]);
|
||||
|
||||
const openSettingsDialog = useCallback(
|
||||
(section?: string) => {
|
||||
markPanelLoaded('settings');
|
||||
|
|
@ -504,22 +537,24 @@ export function Header() {
|
|||
{!isCompactHeader && (
|
||||
<>
|
||||
<ActionIcon
|
||||
variant="subtle"
|
||||
color="gray"
|
||||
variant={boardChatActive ? 'light' : 'subtle'}
|
||||
color={boardChatActive ? 'veritas' : 'gray'}
|
||||
size={32}
|
||||
onClick={openChatPanel}
|
||||
aria-label="Board Chat"
|
||||
title="Board Chat"
|
||||
onClick={toggleChatPanel}
|
||||
aria-label={boardChatAction}
|
||||
aria-pressed={boardChatActive}
|
||||
title={boardChatAction}
|
||||
>
|
||||
<MessageSquare className="h-4 w-4" aria-hidden="true" />
|
||||
</ActionIcon>
|
||||
<ActionIcon
|
||||
variant="subtle"
|
||||
color="gray"
|
||||
variant={squadChatActive ? 'light' : 'subtle'}
|
||||
color={squadChatActive ? 'veritas' : 'gray'}
|
||||
size={32}
|
||||
onClick={openSquadChatPanel}
|
||||
aria-label="Squad Chat"
|
||||
title="Squad Chat — Agent communication"
|
||||
onClick={toggleSquadChatPanel}
|
||||
aria-label={squadChatAction}
|
||||
aria-pressed={squadChatActive}
|
||||
title={squadChatAction}
|
||||
>
|
||||
<Users className="h-4 w-4" aria-hidden="true" />
|
||||
</ActionIcon>
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue