Skip to content

Commit fae3dee

Browse files
wellyshenWelly Shenclaude
authored
Agents Manager: Adopt the chat UI design polish and expand the header menu (#113276)
* Agents Manager: Adopt the agenttic-ui 0.1.82 design polish Chat header: Minimize moves first (custom bottom-bar icon in the shared icons file), 32px buttons with 24px icons, 4px radius, 2px gap, muted hover/focus background, keyboard-only focus rings, and the more-options menu grouped so the "Switch to floating/sidebar" option (renamed from "Pop out sidebar"/"Move to sidebar", now last) sits behind a full-width divider with 2px item gaps. Message actions: 28px icons in the existing 32px buttons, 4px radius, muted hover with foreground icons, pressed feedback stays foreground while the ghost style dims the disabled vote. Companions for the new --color-input-border tokens: map them in the dark color scheme's agenttic overrides, and keep image-studio's composer borderless in its focused state. Grouped empty view title matches the package's 14px suggestion labels; the AM-side empty view icon now uses the package default. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Agents Manager: Size the chat header actions row to its 32px buttons Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Agents Manager: Drop the hover/focus background on chat header buttons Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Agents Manager: Out-specify wp's small icon button sizing in the chat header wp's `.components-button.is-small.has-icon:not(.has-text)` ties our selector at (0,4,0) and wins by load order, shrinking the buttons to 24px wide with no padding. Adding `.has-icon` makes the header sizing win regardless of stylesheet order. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Agents Manager: Size the chat header buttons at 24x24 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Agents Manager: Drop redundant padding and radius on chat header buttons Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Agents Manager: Tighten a chat header comment Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Agents Manager: Inset the chat header menu groups 16px/6px Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Agents Manager: Pad the chat header menu items 16px/6px Targets the real `.components-dropdown-menu__menu-item` class — the previous hover rule aimed at `.components-menu-item__button`, which the controls-based DropdownMenu never renders — and out-specifies wp's item padding. Menu groups return to their uniform 8px. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Agents Manager: 8px vertical padding for the chat header menu groups Vertical-only group padding: the menu opens and closes with an 8px inset, hover chips span the full popover width, and the item padding alone provides the 16px text inset. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Agents Manager: Rebalance chat header menu padding (groups 8px, items 6px 8px) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Agents Manager: Style the chat header menu against its real DOM The controls-based DropdownMenu renders a flat item list — control sets add `has-separator` to an item instead of MenuGroup wrappers — so the group-based popover rules never matched anything. Rebuild on the real structure: 8px menu padding, 2px item gaps, 6px/8px item padding, and wp's separator line stretched across the menu padding with 8px clearance on both sides. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Agents Manager: Round the chat header menu items 4px Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Agents Manager: Keep the menu label color steady on hover Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Agents Manager: Use the background as the menu items' focus indicator Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Agents Manager: No focus effect on disabled chat header menu items Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Agents Manager: Custom icons for the mode-switch menu options Replaces wp's `login`/`drawerRight` with the AI-1096 Figma glyphs for "Switch to floating" and "Switch to sidebar". The floating glyph's rect keeps an explicit fill="none" so wp's `svg { fill: currentColor }` doesn't flood the stroke-drawn square. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Agents Manager: Move View history from the chat header into the menu Pure relocation after "New chat" in the More Options menu: same `! isReaderChat` gate (reader frontends have no user-accessible session history), same `chat_history_open` tracking event, same `/history` navigation, label, and `backup` icon. The gating tests move to the agent-dock suite with the item. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Agents Manager: Tune the menu separator spacing to 11px Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Agents Manager: Menu separator spacing at 12px Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Agents Manager: Tighten menu comments Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Agents Manager: Add Knowledge and memory + AI Agent settings menu items Both sit after Split screen in the first control set, ahead of the switch divider. The gear is wp's `cog`; the bookmark glyph has no @wordpress/icons counterpart, so it joins the shared icons file. Destinations follow AI-1096: the wp-admin guidelines page and the site's WordPress.com AI tools settings, opened in a new tab. The ticket's visibility rules (Dotcom-hosted only for settings, admin role for both, omnibar-site resolution outside wp-admin) are not yet implemented. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Agents Manager: Use wp's heading glyph for Knowledge and memory Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Agents Manager: Drop a menu icon comment Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Agents Manager: Point AI Agent settings at the dashboard host per AI-1096 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Agents Manager: Show guidelines/settings menu items in wp-admin only Their destinations (a relative wp-admin URL and the current host's WordPress.com settings) can't resolve from Calypso-hosted chats. Gate on the wp-admin body class — section names vary across wp-admin screens, so they can't discriminate reliably. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Agents Manager: Document the wp-admin detection choice Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Agents Manager: Extract isWpAdmin into utils Follows the is-editor-page pattern (body-class detection with the SSR guard) for reuse by the upcoming visibility rules. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Agents Manager: Show AI Agent settings on Dotcom-hosted sites only The linked WordPress.com settings page only exists for Simple/WoA sites, and the wp-admin chat also ships to self-hosted Jetpack sites. Gate on a new `agentsManagerData.isDotcomSite` flag injected server-side via Jetpack's `Host::is_wpcom_platform_site()` (client-side heuristics can't tell: `canAccessWpcomApis()` is false on Atomic). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Agents Manager: Hostname fallback for the Dotcom settings gate The vendored jetpack-status doesn't ship is_wpcom_platform_site(), so the server-side isDotcomSite flag needs a Jetpack-package change before it can exist. Until then, the wordpress.com hostname covers Simple sites; WoA (custom domains) picks up when the flag ships. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Agents Manager: Use the server-provided site domain for the settings URL `site.domain` is the site's canonical slug; the wp-admin hostname only coincides with it when the site serves on its primary domain. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Agents Manager: Gate the settings item on the server-provided site domain Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Agents Manager: Name the Dotcom gate for readability Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Agents Manager: Rename the wp-admin gate for symmetry Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Agents Manager: Fix import order in the chat header Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Agents Manager: Address review feedback - Clear both focus-ring mechanisms (outline and box-shadow) on pointer focus — wp draws the ring differently across runtime versions - Replace filter(Boolean)-plus-assertion with a narrowing type guard in the chat header options builder Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Agents Manager: Format the menu option guard Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Agents Manager: Gate AI Agent settings on the server flag alone This PR deploys together with the Jetpack-side isDotcomSite injection, so the interim site-domain fallback goes: server truth or hidden. Sites on older Jetpack packages simply don't see the item until they update. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Agents Manager: Space the menu options preamble for readability Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Agents Manager: Drop the isDotcomSite gate from AI Agent settings The Jetpack-side flag PR was closed; the item now shows for any wp-admin chat, with a TODO to revisit the WP.com-host check. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Agents Manager: Note the wp-admin gate is about site-based links Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Agents Manager: Fix import order and prettier formatting Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Agents Manager: Address code review follow-ups - Make the copy button's keyboard-only focus ring load-order-proof (the compound replaces the dropped !important) - Hoist isMenuOption to module scope - Sync the test icon mocks with the components' real imports and assert the View history menu position its test title promises Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Agents Manager: Filter menu options with an inline predicate TS 6 infers the type guard from the truthiness arrow, so the named helper is unnecessary. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Agents Manager: Cover the menu actions and switch options Adds click tests for View history, Knowledge and memory, and AI Agent settings, plus visibility and divider-grouping tests for the renamed switch options. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Note E2E follow-ups for the themed composer borders Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Agents Manager: Use base-styles variables for the polish spacing Grid units and radii swap in for the raw px values with exact token matches; the compiled CSS is byte-identical. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Agents Manager: Keep the menu item padding literal The 6px half has no base-styles token; a half-tokenized shorthand reads worse than the plain values. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Agents Manager: Keep the polish spacing as literal px values Reverts the base-styles variable conversion — the polish is specced in exact pixels, and literals can't drift with upstream token changes. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Agents Manager: Correct the switch-option comment, drop a restating one Docking isn't wp-admin-only (the Calypso dashboard docks too) and the dock isn't a block-editor slot; the gate is about reader-chat frontends lacking a sidebar layout. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Agents Manager: Gate the site links on the injected site domain Only the Jetpack package's wp-admin enqueue injects site, so its domain replaces the body-class sniff and the hostname fallback — no domain, no item, and never a malformed settings URL. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Agents Manager: Simplify the site-gate comments Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Agents Manager: Gate the settings item on isWpcomPlatform and unify the menu tracks Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Agents Manager: Widen the chat-header actions gap to 4px Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Image Studio: Drop the dead composer border-token overrides Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Agents Manager: Drop the settled dark-scheme composer border TODO Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Agents Manager: Hide View history while the history view is open Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Agents Manager: Cover the dual-fired menu tracks with a test Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Agents Manager: Correct the popover comments, tighten the dual-fire note Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Agents Manager: Align the menu links on noopener,noreferrer Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Agents Manager: Drop the inert space-between override in the chat header Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Agents Manager: Fold the unified menu event into a local helper Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Agents Manager: Match the AM menu event name to its Big Sky analog Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Agents Manager: Use copySmall for the copy message action Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Update agenttic packages to 0.1.84 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Welly Shen <welly.shen@automattic.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
1 parent e39614f commit fae3dee

21 files changed

Lines changed: 526 additions & 171 deletions

File tree

client/lib/color-scheme/dark-theme.scss

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -821,6 +821,12 @@ This mixin generates alias variables for a color palette. For example, the
821821
--color-primary-foreground: var( --wp-components-color-accent-inverted );
822822
--color-muted: var( --dashboard-surface__border-color );
823823
--color-muted-foreground: var( --dashboard__text-muted-color );
824+
--color-input-border: var( --dashboard-surface__border-color );
825+
--color-input-border-focused: color-mix(
826+
in srgb,
827+
var( --dashboard-surface__border-color ) 85%,
828+
var( --dashboard__text-muted-color )
829+
);
824830
--color-ring: var( --wp-admin-theme-color );
825831
--color-link: var( --wp-admin-theme-color-darker-20 );
826832
}

client/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
"dependencies": {
1515
"@automattic/accessible-focus": "workspace:^",
1616
"@automattic/agents-manager": "workspace:^",
17-
"@automattic/agenttic-ui": "^0.1.83",
17+
"@automattic/agenttic-ui": "^0.1.84",
1818
"@automattic/api-core": "workspace:^",
1919
"@automattic/api-queries": "workspace:^",
2020
"@automattic/block-renderer": "workspace:^",

packages/agents-manager/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,8 @@
4141
"watch": "tsc --build ./tsconfig.json --watch"
4242
},
4343
"dependencies": {
44-
"@automattic/agenttic-client": "^0.1.83",
45-
"@automattic/agenttic-ui": "^0.1.83",
44+
"@automattic/agenttic-client": "^0.1.84",
45+
"@automattic/agenttic-ui": "^0.1.84",
4646
"@automattic/calypso-analytics": "workspace:^",
4747
"@automattic/components": "workspace:^",
4848
"@automattic/data-stores": "workspace:^",

packages/agents-manager/src/components/__tests__/agent-dock.test.tsx

Lines changed: 217 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
* @jest-environment jsdom
33
*/
44
/* eslint-disable import/order -- jest.mock calls must precede imports */
5-
import { act, fireEvent, render, screen } from '@testing-library/react';
5+
import { act, fireEvent, render, screen, within } from '@testing-library/react';
66
import { MemoryRouter, useLocation } from 'react-router-dom';
77
import type { AgentsManagerContextType } from '../../contexts';
88

@@ -15,6 +15,9 @@ const mockUseAgentLayoutManager = jest.fn();
1515
const mockResumeActiveChat = jest.fn();
1616
const mockCloseSidebar = jest.fn();
1717
let mockLayoutIsDocked = false;
18+
// Overrides the layout mock's `canDock` (which otherwise follows
19+
// `mockLayoutIsDocked`) so floating-but-dockable states are testable.
20+
let mockCanDock: boolean | null = null;
1821
let mockContext: Partial< AgentsManagerContextType > = {};
1922
let mockAgentsManagerState: {
2023
isOpen?: boolean;
@@ -46,11 +49,11 @@ jest.mock( '@wordpress/data', () => ( {
4649
} ) );
4750
jest.mock( '@wordpress/i18n', () => ( { __: ( text: string ) => text } ) );
4851
jest.mock( '@wordpress/icons', () => ( {
52+
backup: 'backup',
53+
cog: 'cog',
4954
columns: 'columns',
5055
comment: 'comment',
51-
drawerRight: 'drawerRight',
52-
lineSolid: 'lineSolid',
53-
login: 'login',
56+
heading: 'heading',
5457
} ) );
5558
jest.mock( '../../contexts', () => ( {
5659
useAgentsManagerContext: () => mockContext,
@@ -68,7 +71,7 @@ jest.mock( '../../hooks/use-agent-layout-manager', () => ( options: unknown ) =>
6871
return {
6972
isDocked: mockLayoutIsDocked,
7073
isSidebarOpen: mockLayoutIsDocked && mockAgentsManagerState.isOpen !== false,
71-
canDock: mockLayoutIsDocked,
74+
canDock: mockCanDock ?? mockLayoutIsDocked,
7275
dock: jest.fn(),
7376
undock: jest.fn(),
7477
openSidebar: jest.fn(),
@@ -103,22 +106,25 @@ jest.mock( '../orchestrator-chat', () => ( {
103106
onExpand,
104107
onClose,
105108
}: {
106-
chatHeaderOptions: { title: string; onClick?: () => void; isDisabled?: boolean }[];
109+
chatHeaderOptions: { title: string; onClick?: () => void; isDisabled?: boolean }[][];
107110
isOpen: boolean;
108111
onExpand: () => void;
109112
onClose: () => void;
110113
} ) => (
111114
<div data-testid="orchestrator-chat" data-chat-open={ String( isOpen ) }>
112-
{ chatHeaderOptions.map( ( option ) => (
113-
<button
114-
key={ option.title }
115-
type="button"
116-
onClick={ option.onClick }
117-
disabled={ option.isDisabled }
118-
>
119-
{ option.title }
120-
</button>
121-
) ) }
115+
{ chatHeaderOptions.map( ( group, groupIndex ) =>
116+
group.map( ( option ) => (
117+
<button
118+
key={ option.title }
119+
type="button"
120+
data-group={ groupIndex }
121+
onClick={ option.onClick }
122+
disabled={ option.isDisabled }
123+
>
124+
{ option.title }
125+
</button>
126+
) )
127+
) }
122128
<button onClick={ onExpand }>Expand chat</button>
123129
<button onClick={ onClose }>Close chat</button>
124130
</div>
@@ -138,9 +144,20 @@ jest.mock( '../zendesk-chat', () => ( {
138144
} ) );
139145
jest.mock( '../agent-history', () => ( {
140146
__esModule: true,
141-
default: ( { onExpand }: { onExpand: () => void } ) => (
147+
default: ( {
148+
onExpand,
149+
chatHeaderOptions,
150+
}: {
151+
onExpand: () => void;
152+
chatHeaderOptions: { title: string; onClick?: () => void; isDisabled?: boolean }[][];
153+
} ) => (
142154
<div data-testid="agent-history">
143155
History
156+
{ chatHeaderOptions.flat().map( ( option ) => (
157+
<button key={ option.title } onClick={ option.onClick } disabled={ option.isDisabled }>
158+
{ option.title }
159+
</button>
160+
) ) }
144161
<button onClick={ onExpand }>Expand history</button>
145162
</div>
146163
),
@@ -160,8 +177,9 @@ jest.mock( '../support-guides', () => ( {
160177
} ) );
161178

162179
import AgentDock from '../agent-dock';
163-
import { recordBigSkyTracksEvent } from '../../utils/tracks';
180+
import { recordAgentsManagerTracksEvent, recordBigSkyTracksEvent } from '../../utils/tracks';
164181

182+
const mockRecordAgentsManagerTracksEvent = recordAgentsManagerTracksEvent as jest.Mock;
165183
const mockRecordBigSkyTracksEvent = recordBigSkyTracksEvent as jest.Mock;
166184

167185
function LocationProbe() {
@@ -201,6 +219,8 @@ describe( 'AgentDock', () => {
201219
mockHasAdminBar = false;
202220
mockShouldUseUnifiedAgent = false;
203221
mockLayoutIsDocked = false;
222+
mockCanDock = null;
223+
delete ( globalThis as { agentsManagerData?: unknown } ).agentsManagerData;
204224
mockAgentsManagerState = { isOpen: true, isDocked: false };
205225
mockContext = {
206226
siteKey: 'site-1',
@@ -420,6 +440,179 @@ describe( 'AgentDock', () => {
420440
expect( mockSetIsOpen ).toHaveBeenCalledWith( true, true );
421441
} );
422442

443+
it( 'offers View history in More Options after New chat', () => {
444+
useWpAdminAgent();
445+
446+
renderAgentDock();
447+
448+
const options = within( screen.getByTestId( 'orchestrator-chat' ) ).getAllByRole( 'button' );
449+
450+
expect( options[ 0 ] ).toHaveTextContent( 'New chat' );
451+
expect( options[ 1 ] ).toHaveTextContent( 'View history' );
452+
} );
453+
454+
it( 'omits View history from More Options on reader chat', () => {
455+
renderAgentDock();
456+
457+
expect( screen.queryByText( 'View history' ) ).toBeNull();
458+
} );
459+
460+
it( 'omits View history from More Options while on the history view', () => {
461+
useWpAdminAgent();
462+
463+
renderAgentDock( '/history' );
464+
465+
expect( screen.getByText( 'New chat' ) ).toBeInTheDocument();
466+
expect( screen.queryByText( 'View history' ) ).toBeNull();
467+
} );
468+
469+
it( 'dual-fires the unified and Big Sky events for New chat', () => {
470+
useWpAdminAgent();
471+
472+
renderAgentDock( '/history' );
473+
fireEvent.click( screen.getByText( 'New chat' ) );
474+
475+
expect( mockRecordAgentsManagerTracksEvent ).toHaveBeenCalledWith(
476+
'ai_chat_more_options_click',
477+
{
478+
type: 'reset_chat',
479+
}
480+
);
481+
expect( mockRecordBigSkyTracksEvent ).toHaveBeenCalledWith( 'ai_chat_more_options_click', {
482+
type: 'reset_chat',
483+
} );
484+
} );
485+
486+
it( 'offers the guidelines and settings items when wp-admin injects the site', () => {
487+
useWpAdminAgent();
488+
( globalThis as { agentsManagerData?: unknown } ).agentsManagerData = {
489+
site: { domain: 'example.com' },
490+
isWpcomPlatform: true,
491+
};
492+
493+
renderAgentDock();
494+
495+
expect( screen.getByText( 'Knowledge and memory' ) ).toBeInTheDocument();
496+
expect( screen.getByText( 'AI Agent settings' ) ).toBeInTheDocument();
497+
} );
498+
499+
it( 'omits the settings item on non-WordPress.com-hosted sites', () => {
500+
useWpAdminAgent();
501+
( globalThis as { agentsManagerData?: unknown } ).agentsManagerData = {
502+
site: { domain: 'example.com' },
503+
};
504+
505+
renderAgentDock();
506+
507+
expect( screen.getByText( 'Knowledge and memory' ) ).toBeInTheDocument();
508+
expect( screen.queryByText( 'AI Agent settings' ) ).toBeNull();
509+
} );
510+
511+
it( 'omits the guidelines and settings items without the injected site', () => {
512+
useWpAdminAgent();
513+
514+
renderAgentDock();
515+
516+
expect( screen.queryByText( 'Knowledge and memory' ) ).toBeNull();
517+
expect( screen.queryByText( 'AI Agent settings' ) ).toBeNull();
518+
} );
519+
520+
it( 'navigates to history from More Options', () => {
521+
useWpAdminAgent();
522+
523+
renderAgentDock();
524+
fireEvent.click( screen.getByText( 'View history' ) );
525+
526+
expect( mockRecordAgentsManagerTracksEvent ).toHaveBeenCalledWith(
527+
'ai_chat_more_options_click',
528+
{
529+
type: 'view_history',
530+
}
531+
);
532+
expect( screen.getByTestId( 'location' ) ).toHaveTextContent( '/history' );
533+
} );
534+
535+
it( 'opens the guidelines page from More Options', () => {
536+
useWpAdminAgent();
537+
( globalThis as { agentsManagerData?: unknown } ).agentsManagerData = {
538+
site: { domain: 'example.com' },
539+
};
540+
const openSpy = jest.spyOn( window, 'open' ).mockImplementation( () => null );
541+
542+
renderAgentDock();
543+
fireEvent.click( screen.getByText( 'Knowledge and memory' ) );
544+
545+
expect( mockRecordAgentsManagerTracksEvent ).toHaveBeenCalledWith(
546+
'ai_chat_more_options_click',
547+
{
548+
type: 'knowledge_memory',
549+
}
550+
);
551+
expect( openSpy ).toHaveBeenCalledWith(
552+
'/wp-admin/options-general.php?page=guidelines-wp-admin',
553+
'_blank',
554+
'noopener,noreferrer'
555+
);
556+
557+
openSpy.mockRestore();
558+
} );
559+
560+
it( 'opens the AI Agent settings for the injected site', () => {
561+
useWpAdminAgent();
562+
( globalThis as { agentsManagerData?: unknown } ).agentsManagerData = {
563+
site: { domain: 'example.com' },
564+
isWpcomPlatform: true,
565+
};
566+
const openSpy = jest.spyOn( window, 'open' ).mockImplementation( () => null );
567+
568+
renderAgentDock();
569+
fireEvent.click( screen.getByText( 'AI Agent settings' ) );
570+
571+
expect( mockRecordAgentsManagerTracksEvent ).toHaveBeenCalledWith(
572+
'ai_chat_more_options_click',
573+
{
574+
type: 'ai_agent_settings',
575+
}
576+
);
577+
expect( openSpy ).toHaveBeenCalledWith(
578+
'https://my.wordpress.com/sites/example.com/settings/ai-tools',
579+
'_blank',
580+
'noopener,noreferrer'
581+
);
582+
583+
openSpy.mockRestore();
584+
} );
585+
586+
it( 'offers Switch to floating behind the divider while docked', () => {
587+
useWpAdminAgent();
588+
mockLayoutIsDocked = true;
589+
590+
renderAgentDock();
591+
592+
expect( screen.getByText( 'New chat' ) ).toHaveAttribute( 'data-group', '0' );
593+
expect( screen.getByText( 'Switch to floating' ) ).toHaveAttribute( 'data-group', '1' );
594+
expect( screen.queryByText( 'Switch to sidebar' ) ).toBeNull();
595+
} );
596+
597+
it( 'offers Switch to sidebar while floating and docking is available', () => {
598+
useWpAdminAgent();
599+
mockCanDock = true;
600+
601+
renderAgentDock();
602+
603+
expect( screen.getByText( 'Switch to sidebar' ) ).toBeInTheDocument();
604+
expect( screen.queryByText( 'Switch to floating' ) ).toBeNull();
605+
} );
606+
607+
it( 'omits the switch options on reader chat', () => {
608+
mockLayoutIsDocked = true;
609+
610+
renderAgentDock();
611+
612+
expect( screen.queryByText( 'Switch to floating' ) ).toBeNull();
613+
expect( screen.queryByText( 'Switch to sidebar' ) ).toBeNull();
614+
} );
615+
423616
it.each( [
424617
{
425618
isSplitScreen: false,
@@ -447,9 +640,12 @@ describe( 'AgentDock', () => {
447640
renderAgentDock( '/chat', { capabilities: { supportsSplitScreen: true } } );
448641
fireEvent.click( screen.getByRole( 'button', { name: label } ) );
449642

450-
expect( mockRecordBigSkyTracksEvent ).toHaveBeenCalledWith( 'ai_chat_more_options_click', {
451-
type,
452-
} );
643+
expect( mockRecordAgentsManagerTracksEvent ).toHaveBeenCalledWith(
644+
'ai_chat_more_options_click',
645+
{
646+
type,
647+
}
648+
);
453649
expect( mockSetIsSplitScreen ).toHaveBeenCalledWith( nextState );
454650
}
455651
);

packages/agents-manager/src/components/__tests__/chat-header.test.tsx

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,9 @@ jest.mock( '@wordpress/components', () => ( {
2828
} ) );
2929
jest.mock( '@wordpress/i18n', () => ( { __: ( text: string ) => text } ) );
3030
jest.mock( '@wordpress/icons', () => ( {
31-
backup: 'backup',
3231
chevronLeft: 'chevronLeft',
3332
close: 'close',
3433
Icon: () => null,
35-
lineSolid: 'lineSolid',
3634
moreVertical: 'moreVertical',
3735
} ) );
3836
jest.mock( '@wordpress/data', () => ( {
@@ -59,13 +57,6 @@ function installAdminBarTrigger() {
5957
document.body.appendChild( el );
6058
}
6159

62-
// `isReaderChatHost()` reads the agent ID from this global.
63-
function installReaderChatHost() {
64-
( globalThis as { agentsManagerData?: { agentId?: string } } ).agentsManagerData = {
65-
agentId: 'reader-chat',
66-
};
67-
}
68-
6960
function installMasterbarTrigger() {
7061
const el = document.createElement( 'div' );
7162
el.className = 'masterbar__item-agents-manager-ai-chat';
@@ -101,20 +92,6 @@ describe( 'ChatHeader', () => {
10192
expect( container.querySelector( '.agents-manager-chat-header__title' ) ).toBeNull();
10293
} );
10394

104-
it( 'shows the history button by default', () => {
105-
renderChatHeader();
106-
107-
expect( screen.getByText( 'View history' ) ).toBeInTheDocument();
108-
} );
109-
110-
it( 'hides the history button on reader-chat hosts', () => {
111-
installReaderChatHost();
112-
113-
renderChatHeader();
114-
115-
expect( screen.queryByText( 'View history' ) ).toBeNull();
116-
} );
117-
11895
it( 'minimizes the chat when the Minimize button is clicked', () => {
11996
installAdminBarTrigger();
12097

0 commit comments

Comments
 (0)