Skip to content

Commit 2c53393

Browse files
authored
Make WaveAI context menu consistent with kebab menu (#2517)
1 parent a5fb38e commit 2c53393

File tree

5 files changed

+58
-54
lines changed

5 files changed

+58
-54
lines changed

frontend/app/aipanel/aipanel-contextmenu.ts

Lines changed: 33 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,26 @@
33

44
import { waveAIHasSelection } from "@/app/aipanel/waveai-focus-utils";
55
import { ContextMenuModel } from "@/app/store/contextmenu";
6+
import { isDev } from "@/app/store/global";
67
import { RpcApi } from "@/app/store/wshclientapi";
78
import { TabRpcClient } from "@/app/store/wshrpcutil";
89
import { WaveAIModel } from "./waveai-model";
910

10-
export async function handleWaveAIContextMenu(e: React.MouseEvent, onClose?: () => void): Promise<void> {
11+
export async function handleWaveAIContextMenu(e: React.MouseEvent, showCopy: boolean): Promise<void> {
1112
e.preventDefault();
1213
e.stopPropagation();
1314

1415
const model = WaveAIModel.getInstance();
1516
const menu: ContextMenuItem[] = [];
1617

17-
const hasSelection = waveAIHasSelection();
18-
if (hasSelection) {
19-
menu.push({
20-
role: "copy",
21-
});
22-
menu.push({ type: "separator" });
18+
if (showCopy) {
19+
const hasSelection = waveAIHasSelection();
20+
if (hasSelection) {
21+
menu.push({
22+
role: "copy",
23+
});
24+
menu.push({ type: "separator" });
25+
}
2326
}
2427

2528
menu.push({
@@ -103,6 +106,19 @@ export async function handleWaveAIContextMenu(e: React.MouseEvent, onClose?: ()
103106
}
104107
);
105108
} else {
109+
if (isDev()) {
110+
maxTokensSubmenu.push({
111+
label: "1k (Dev Testing)",
112+
type: "checkbox",
113+
checked: currentMaxTokens === 1024,
114+
click: () => {
115+
RpcApi.SetRTInfoCommand(TabRpcClient, {
116+
oref: model.orefContext,
117+
data: { "waveai:maxoutputtokens": 1024 },
118+
});
119+
},
120+
});
121+
}
106122
maxTokensSubmenu.push(
107123
{
108124
label: "4k",
@@ -150,14 +166,16 @@ export async function handleWaveAIContextMenu(e: React.MouseEvent, onClose?: ()
150166
submenu: maxTokensSubmenu,
151167
});
152168

153-
menu.push({ type: "separator" });
169+
if (model.canCloseWaveAIPanel()) {
170+
menu.push({ type: "separator" });
154171

155-
menu.push({
156-
label: "Hide Wave AI",
157-
click: () => {
158-
onClose?.();
159-
},
160-
});
172+
menu.push({
173+
label: "Hide Wave AI",
174+
click: () => {
175+
model.closeWaveAIPanel();
176+
},
177+
});
178+
}
161179

162180
ContextMenuModel.showContextMenu(menu, e);
163-
}
181+
}

frontend/app/aipanel/aipanel.tsx

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -203,11 +203,7 @@ const AIErrorMessage = memo(({ errorMessage, onClear }: AIErrorMessageProps) =>
203203

204204
AIErrorMessage.displayName = "AIErrorMessage";
205205

206-
interface AIPanelProps {
207-
onClose?: () => void;
208-
}
209-
210-
const AIPanelComponentInner = memo(({ onClose }: AIPanelProps) => {
206+
const AIPanelComponentInner = memo(() => {
211207
const [isDragOver, setIsDragOver] = useState(false);
212208
const [isReactDndDragOver, setIsReactDndDragOver] = useState(false);
213209
const [initialLoadDone, setInitialLoadDone] = useState(false);
@@ -256,10 +252,6 @@ const AIPanelComponentInner = memo(({ onClose }: AIPanelProps) => {
256252

257253
// console.log("AICHAT messages", messages);
258254

259-
const handleClearChat = useCallback(() => {
260-
model.clearChat();
261-
}, [model]);
262-
263255
const handleKeyDown = (waveEvent: WaveKeyboardEvent): boolean => {
264256
if (checkKeyPressed(waveEvent, "Cmd:k")) {
265257
model.clearChat();
@@ -493,7 +485,7 @@ const AIPanelComponentInner = memo(({ onClose }: AIPanelProps) => {
493485
>
494486
{(isDragOver || isReactDndDragOver) && <AIDragOverlay />}
495487
{showBlockMask && <AIBlockMask />}
496-
<AIPanelHeader onClose={onClose} model={model} onClearChat={handleClearChat} />
488+
<AIPanelHeader />
497489
<AIRateLimitStrip />
498490

499491
<div key="main-content" className="flex-1 flex flex-col min-h-0">
@@ -504,15 +496,15 @@ const AIPanelComponentInner = memo(({ onClose }: AIPanelProps) => {
504496
{messages.length === 0 && initialLoadDone ? (
505497
<div
506498
className="flex-1 overflow-y-auto p-2"
507-
onContextMenu={(e) => handleWaveAIContextMenu(e, onClose)}
499+
onContextMenu={(e) => handleWaveAIContextMenu(e, true)}
508500
>
509501
{model.inBuilder ? <AIBuilderWelcomeMessage /> : <AIWelcomeMessage />}
510502
</div>
511503
) : (
512504
<AIPanelMessages
513505
messages={messages}
514506
status={status}
515-
onContextMenu={(e) => handleWaveAIContextMenu(e, onClose)}
507+
onContextMenu={(e) => handleWaveAIContextMenu(e, true)}
516508
/>
517509
)}
518510
{errorMessage && (
@@ -529,10 +521,10 @@ const AIPanelComponentInner = memo(({ onClose }: AIPanelProps) => {
529521

530522
AIPanelComponentInner.displayName = "AIPanelInner";
531523

532-
const AIPanelComponent = ({ onClose }: AIPanelProps) => {
524+
const AIPanelComponent = () => {
533525
return (
534526
<ErrorBoundary>
535-
<AIPanelComponentInner onClose={onClose} />
527+
<AIPanelComponentInner />
536528
</ErrorBoundary>
537529
);
538530
};

frontend/app/aipanel/aipanelheader.tsx

Lines changed: 4 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,18 @@
11
// Copyright 2025, Command Line Inc.
22
// SPDX-License-Identifier: Apache-2.0
33

4-
import { ContextMenuModel } from "@/app/store/contextmenu";
4+
import { handleWaveAIContextMenu } from "@/app/aipanel/aipanel-contextmenu";
55
import { useAtomValue } from "jotai";
66
import { memo } from "react";
77
import { WaveAIModel } from "./waveai-model";
88

9-
interface AIPanelHeaderProps {
10-
onClose?: () => void;
11-
model: WaveAIModel;
12-
onClearChat?: () => void;
13-
}
14-
15-
export const AIPanelHeader = memo(({ onClose, model, onClearChat }: AIPanelHeaderProps) => {
9+
export const AIPanelHeader = memo(() => {
10+
const model = WaveAIModel.getInstance();
1611
const widgetAccess = useAtomValue(model.widgetAccessAtom);
1712
const inBuilder = model.inBuilder;
1813

1914
const handleKebabClick = (e: React.MouseEvent) => {
20-
const menu: ContextMenuItem[] = [
21-
{
22-
label: "New Chat",
23-
click: () => {
24-
onClearChat?.();
25-
},
26-
},
27-
{ type: "separator" },
28-
{
29-
label: "Hide Wave AI",
30-
click: () => {
31-
onClose?.();
32-
},
33-
},
34-
];
35-
ContextMenuModel.showContextMenu(menu, e);
15+
handleWaveAIContextMenu(e, false);
3616
};
3717

3818
return (

frontend/app/aipanel/waveai-model.tsx

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -542,4 +542,18 @@ export class WaveAIModel {
542542
globalStore.set(this.restoreBackupStatus, "error");
543543
}
544544
}
545+
546+
canCloseWaveAIPanel(): boolean {
547+
if (this.inBuilder) {
548+
return false;
549+
}
550+
return true;
551+
}
552+
553+
closeWaveAIPanel() {
554+
if (this.inBuilder) {
555+
return;
556+
}
557+
WorkspaceLayoutModel.getInstance().setAIPanelVisible(false);
558+
}
545559
}

frontend/app/workspace/workspace.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ const WorkspaceElem = memo(() => {
5858
>
5959
<Panel ref={aiPanelRef} collapsible defaultSize={initialAiPanelPercentage} order={1} className="overflow-hidden">
6060
<div ref={aiPanelWrapperRef} className="w-full h-full">
61-
<AIPanel onClose={() => workspaceLayoutModel.setAIPanelVisible(false)} />
61+
<AIPanel />
6262
</div>
6363
</Panel>
6464
<PanelResizeHandle className="w-0.5 bg-transparent hover:bg-gray-500/20 transition-colors" />

0 commit comments

Comments
 (0)