File size: 2,868 Bytes
3d700dd | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 | import ConversationService from "#/api/conversation-service/conversation-service.api";
import {
ConversationTab,
useConversationStore,
} from "#/stores/conversation-store";
import { useFilesTabStore } from "#/stores/files-tab-store";
import type { CanvasUIAction } from "#/types/agent-server/core";
import { toFilesTabPath } from "#/utils/path-utils";
const VALID_TABS: ReadonlySet<ConversationTab> = new Set<ConversationTab>([
"files",
"browser",
"terminal",
"planner",
"tasklist",
]);
// Mirrors src/hooks/use-select-conversation-tab.ts so a non-React caller (the
// WebSocket dispatch) gets the same "reveal the right panel if collapsed"
// behavior as in-app tab switches.
function navigateToTab(tab: ConversationTab) {
const store = useConversationStore.getState();
store.setSelectedTab(tab);
if (!store.isRightPanelShown) {
store.setHasRightPanelToggled(true);
store.setIsRightPanelShown(true);
}
}
function isValidTab(value: string): value is ConversationTab {
return VALID_TABS.has(value as ConversationTab);
}
/**
* Chat path click → same as agent `navigate_to_file`.
* Optional `conversationId` tags the selection so FilesTab accepts it.
*/
export function openWorkspaceFile(
path: string,
conversationId?: string | null,
): void {
const conversation = ConversationService.getCurrentConversation();
handleCanvasUIAction(
{
kind: "CanvasUIAction",
command: "navigate_to_file",
path,
} as CanvasUIAction,
conversationId ?? conversation?.id ?? null,
);
}
export function handleCanvasUIAction(
action: CanvasUIAction,
conversationId: string | null = null,
): void {
switch (action.command) {
case "navigate_to_file":
case "show_preview": {
navigateToTab("files");
if (!action.path) return;
const workingDir =
ConversationService.getCurrentConversation()?.workspace?.working_dir;
const path = toFilesTabPath(action.path, workingDir);
if (!path) return;
useFilesTabStore.getState().setSelectedPath(path, conversationId);
return;
}
case "open_tab":
if (action.tab === "vscode") {
// The in-app VS Code tab was removed — on cloud backends VS Code
// now opens in a new browser window via the link in the drawer tab
// row. Route agent requests to Files so the drawer still opens.
navigateToTab("files");
} else if (action.tab && isValidTab(action.tab)) {
navigateToTab(action.tab);
} else if (action.tab) {
// Surface unknown tab names so they're diagnosable from the browser
// console rather than failing silently. Valid tabs are listed in
// VALID_TABS above and mirror ConversationTab.
console.warn(
`[canvas_ui] Ignoring open_tab with unknown tab: ${action.tab}`,
);
}
return;
}
}
|