Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions crates/agent-gateway/web/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2236,6 +2236,38 @@ export default function App() {
[activateWorkspaceProject, checkWorkspaceProjectDirectory],
);

const handleBrowseWorkspaceProjectInFileTree = useCallback(
async (project: WorkspaceProject) => {
if (!(await checkWorkspaceProjectDirectory(project))) {
return;
}
const pathKey = workspaceProjectPathKey(project.path);
if (!pathKey) {
return;
}

if (isMobileSidebarLayout()) {
setSidebarOpen(false);
}
setActiveView("chat");
setProjectToolsPanelOpen(true);
activateWorkspaceProject(project);
setSettings((prev) =>
updateProjectToolsFileTreeOpen(
updateCustomSettings(prev, {
projectToolsPanel: {
...prev.customSettings.projectToolsPanel,
activeTab: "fileTree",
},
}),
pathKey,
true,
),
);
},
[activateWorkspaceProject, checkWorkspaceProjectDirectory, setSettings],
);

const handleOpenCreateWorkspaceProject = useCallback(() => {
setProjectPickerOpen(true);
}, []);
Expand Down Expand Up @@ -5891,6 +5923,7 @@ export default function App() {
onCreateProject={handleOpenCreateWorkspaceProject}
onSelectProject={handleSelectWorkspaceProject}
onNewConversationForProject={handleNewConversationForProject}
onBrowseProjectInFileTree={handleBrowseWorkspaceProjectInFileTree}
onStartRenamingProject={handleStartRenamingWorkspaceProject}
onProjectRenameDraftChange={setProjectRenameDraft}
onCommitProjectRename={handleCommitWorkspaceProjectRename}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
ChevronRight,
Edit3,
Folder,
FolderTree,
Link2,
MessageSquareText,
MoreHorizontal,
Expand Down Expand Up @@ -75,6 +76,7 @@ type ChatHistorySidebarProps = {
onCreateProject?: () => void;
onSelectProject?: (project: WorkspaceProject) => void;
onNewConversationForProject?: (project: WorkspaceProject) => void;
onBrowseProjectInFileTree?: (project: WorkspaceProject) => void;
onStartRenamingProject?: (project: WorkspaceProject) => void;
onProjectRenameDraftChange?: (value: string) => void;
onCommitProjectRename?: () => void;
Expand Down Expand Up @@ -642,6 +644,7 @@ const ProjectRow = memo(function ProjectRow(props: {
renameDraft: string;
onSelectProject: (project: WorkspaceProject) => void;
onNewConversationForProject: (project: WorkspaceProject) => void;
onBrowseProjectInFileTree?: (project: WorkspaceProject) => void;
onStartRenamingProject: (project: WorkspaceProject) => void;
onProjectRenameDraftChange: (value: string) => void;
onCommitProjectRename: () => void;
Expand All @@ -660,6 +663,7 @@ const ProjectRow = memo(function ProjectRow(props: {
renameDraft,
onSelectProject,
onNewConversationForProject,
onBrowseProjectInFileTree,
onStartRenamingProject,
onProjectRenameDraftChange,
onCommitProjectRename,
Expand Down Expand Up @@ -698,6 +702,10 @@ const ProjectRow = memo(function ProjectRow(props: {
onSetProjectPinned(project, !isPinned);
}, [isPinned, onSetProjectPinned, project]);

const handleBrowseInFileTree = useCallback(() => {
onBrowseProjectInFileTree?.(project);
}, [onBrowseProjectInFileTree, project]);

if (isPendingRemove) {
return (
<div className="rounded-lg border border-destructive/25 bg-destructive/5 px-3 py-2.5 text-sm text-destructive shadow-xs shadow-black/5">
Expand Down Expand Up @@ -936,6 +944,12 @@ const ProjectRow = memo(function ProjectRow(props: {
</DropdownMenuItem>
</>
) : null}
{onBrowseProjectInFileTree ? (
<DropdownMenuItem onSelect={handleBrowseInFileTree} className="gap-2">
<FolderTree className="h-3.5 w-3.5" />
{t("chat.workspaceBrowseInFileTree")}
</DropdownMenuItem>
) : null}
</DropdownMenuContent>
</DropdownMenu>
</>
Expand Down Expand Up @@ -1034,6 +1048,7 @@ export const ChatHistorySidebar = memo(function ChatHistorySidebar(props: ChatHi
onCreateProject,
onSelectProject,
onNewConversationForProject,
onBrowseProjectInFileTree,
onStartRenamingProject,
onProjectRenameDraftChange,
onCommitProjectRename,
Expand Down Expand Up @@ -1088,6 +1103,9 @@ export const ChatHistorySidebar = memo(function ChatHistorySidebar(props: ChatHi
const handleNewConversationForProject = useStableEvent((project: WorkspaceProject) => {
onNewConversationForProject?.(project);
});
const handleBrowseProjectInFileTree = useStableEvent((project: WorkspaceProject) => {
onBrowseProjectInFileTree?.(project);
});
const handleStartRenamingProject = useStableEvent((project: WorkspaceProject) => {
onStartRenamingProject?.(project);
});
Expand Down Expand Up @@ -1631,6 +1649,9 @@ export const ChatHistorySidebar = memo(function ChatHistorySidebar(props: ChatHi
renameDraft={projectRenameDraft}
onSelectProject={handleSelectProject}
onNewConversationForProject={handleNewConversationForProject}
onBrowseProjectInFileTree={
onBrowseProjectInFileTree ? handleBrowseProjectInFileTree : undefined
}
onStartRenamingProject={handleStartRenamingProject}
onProjectRenameDraftChange={handleProjectRenameDraftChange}
onCommitProjectRename={handleCommitProjectRename}
Expand Down
2 changes: 2 additions & 0 deletions crates/agent-gateway/web/src/i18n/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export const translations: Record<Locale, Record<string, string>> = {
"chat.workspaceUnpin": "取消置顶",
"chat.workspaceRename": "修改标题",
"chat.workspaceRemove": "移除工作空间",
"chat.workspaceBrowseInFileTree": "在文件树浏览",
"chat.workspaceRemoveConfirm": "移除「{name}」?",
"chat.workspaceRemoveRunning": "后台任务运行中,暂时不能移除。",
"chat.workspaceRemoveDescription": "会删除此工作空间下的历史对话,不会删除文件夹。",
Expand Down Expand Up @@ -1121,6 +1122,7 @@ export const translations: Record<Locale, Record<string, string>> = {
"chat.workspaceUnpin": "Unpin",
"chat.workspaceRename": "Rename",
"chat.workspaceRemove": "Remove workspace",
"chat.workspaceBrowseInFileTree": "Browse in File Tree",
"chat.workspaceRemoveConfirm": "Remove \"{name}\"?",
"chat.workspaceRemoveRunning": "A background task is running, so this workspace cannot be removed yet.",
"chat.workspaceRemoveDescription":
Expand Down
47 changes: 47 additions & 0 deletions crates/agent-gui/src/components/chat/ChatHistorySidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import {
ChevronRight,
Edit3,
Folder,
FolderOpen,
FolderTree,
Link2,
MessageSquareText,
MoreHorizontal,
Expand Down Expand Up @@ -66,6 +68,8 @@ type ChatHistorySidebarProps = {
onCreateProject?: () => void;
onSelectProject?: (project: WorkspaceProject) => void;
onNewConversationForProject?: (project: WorkspaceProject) => void;
onBrowseProjectInFileTree?: (project: WorkspaceProject) => void;
onBrowseProjectInSystemFileManager?: (project: WorkspaceProject) => void;
onStartRenamingProject?: (project: WorkspaceProject) => void;
onProjectRenameDraftChange?: (value: string) => void;
onCommitProjectRename?: () => void;
Expand Down Expand Up @@ -407,6 +411,8 @@ const ProjectRow = memo(function ProjectRow(props: {
renameDraft: string;
onSelectProject: (project: WorkspaceProject) => void;
onNewConversationForProject: (project: WorkspaceProject) => void;
onBrowseProjectInFileTree?: (project: WorkspaceProject) => void;
onBrowseProjectInSystemFileManager?: (project: WorkspaceProject) => void;
onStartRenamingProject: (project: WorkspaceProject) => void;
onProjectRenameDraftChange: (value: string) => void;
onCommitProjectRename: () => void;
Expand All @@ -425,6 +431,8 @@ const ProjectRow = memo(function ProjectRow(props: {
renameDraft,
onSelectProject,
onNewConversationForProject,
onBrowseProjectInFileTree,
onBrowseProjectInSystemFileManager,
onStartRenamingProject,
onProjectRenameDraftChange,
onCommitProjectRename,
Expand Down Expand Up @@ -463,6 +471,14 @@ const ProjectRow = memo(function ProjectRow(props: {
onSetProjectPinned(project, !isPinned);
}, [isPinned, onSetProjectPinned, project]);

const handleBrowseInFileTree = useCallback(() => {
onBrowseProjectInFileTree?.(project);
}, [onBrowseProjectInFileTree, project]);

const handleBrowseInSystemFileManager = useCallback(() => {
onBrowseProjectInSystemFileManager?.(project);
}, [onBrowseProjectInSystemFileManager, project]);

if (isPendingRemove) {
return (
<div className="rounded-lg border border-destructive/25 bg-destructive/5 px-3 py-2.5 text-sm text-destructive shadow-xs shadow-black/5">
Expand Down Expand Up @@ -703,6 +719,21 @@ const ProjectRow = memo(function ProjectRow(props: {
</DropdownMenuItem>
</>
) : null}
{onBrowseProjectInFileTree ? (
<DropdownMenuItem onSelect={handleBrowseInFileTree} className="gap-2">
<FolderTree className="h-3.5 w-3.5" />
{t("chat.workspaceBrowseInFileTree")}
</DropdownMenuItem>
) : null}
{onBrowseProjectInSystemFileManager ? (
<DropdownMenuItem
onSelect={handleBrowseInSystemFileManager}
className="gap-2"
>
<FolderOpen className="h-3.5 w-3.5" />
{t("chat.workspaceBrowseInSystemFileManager")}
</DropdownMenuItem>
) : null}
</DropdownMenuContent>
</DropdownMenu>
</>
Expand Down Expand Up @@ -801,6 +832,8 @@ export const ChatHistorySidebar = memo(function ChatHistorySidebar(props: ChatHi
onCreateProject,
onSelectProject,
onNewConversationForProject,
onBrowseProjectInFileTree,
onBrowseProjectInSystemFileManager,
onStartRenamingProject,
onProjectRenameDraftChange,
onCommitProjectRename,
Expand Down Expand Up @@ -853,6 +886,12 @@ export const ChatHistorySidebar = memo(function ChatHistorySidebar(props: ChatHi
const handleNewConversationForProject = useStableEvent((project: WorkspaceProject) => {
onNewConversationForProject?.(project);
});
const handleBrowseProjectInFileTree = useStableEvent((project: WorkspaceProject) => {
onBrowseProjectInFileTree?.(project);
});
const handleBrowseProjectInSystemFileManager = useStableEvent((project: WorkspaceProject) => {
onBrowseProjectInSystemFileManager?.(project);
});
const handleStartRenamingProject = useStableEvent((project: WorkspaceProject) => {
onStartRenamingProject?.(project);
});
Expand Down Expand Up @@ -1355,6 +1394,14 @@ export const ChatHistorySidebar = memo(function ChatHistorySidebar(props: ChatHi
renameDraft={projectRenameDraft}
onSelectProject={handleSelectProject}
onNewConversationForProject={handleNewConversationForProject}
onBrowseProjectInFileTree={
onBrowseProjectInFileTree ? handleBrowseProjectInFileTree : undefined
}
onBrowseProjectInSystemFileManager={
onBrowseProjectInSystemFileManager
? handleBrowseProjectInSystemFileManager
: undefined
}
onStartRenamingProject={handleStartRenamingProject}
onProjectRenameDraftChange={handleProjectRenameDraftChange}
onCommitProjectRename={handleCommitProjectRename}
Expand Down
6 changes: 6 additions & 0 deletions crates/agent-gui/src/i18n/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,12 @@ export const translations: Record<Locale, Record<string, string>> = {
"chat.workspaceUnpin": "取消置顶",
"chat.workspaceRename": "修改标题",
"chat.workspaceRemove": "移除工作空间",
"chat.workspaceBrowseInFileTree": "在文件树浏览",
"chat.workspaceBrowseInSystemFileManager": "在资源管理器浏览",
"chat.workspaceRemoveConfirm": "移除「{name}」?",
"chat.workspaceRemoveRunning": "后台任务运行中,暂时不能移除。",
"chat.workspaceRemoveDescription": "会删除此工作空间下的历史对话,不会删除文件夹。",
"chat.workspaceOpenSystemFileManagerFailed": "打开资源管理器失败",
"chat.exitConfirmTitle": "退出 LiveAgent?",
"chat.exitConfirmSubtitle": "当前仍有终端任务在运行。",
"chat.exitConfirmRunningLabel": "正在运行的 Terminal",
Expand Down Expand Up @@ -1186,10 +1189,13 @@ export const translations: Record<Locale, Record<string, string>> = {
"chat.workspaceUnpin": "Unpin",
"chat.workspaceRename": "Rename",
"chat.workspaceRemove": "Remove workspace",
"chat.workspaceBrowseInFileTree": "Browse in File Tree",
"chat.workspaceBrowseInSystemFileManager": "Browse in System File Manager",
"chat.workspaceRemoveConfirm": "Remove \"{name}\"?",
"chat.workspaceRemoveRunning": "A background task is running, so this workspace cannot be removed yet.",
"chat.workspaceRemoveDescription":
"This deletes conversations under the workspace, but it does not delete the folder.",
"chat.workspaceOpenSystemFileManagerFailed": "Failed to open the file manager",
"chat.exitConfirmTitle": "Exit LiveAgent?",
"chat.exitConfirmSubtitle": "Terminal tasks are still running.",
"chat.exitConfirmRunningLabel": "Running Terminal sessions",
Expand Down
49 changes: 49 additions & 0 deletions crates/agent-gui/src/pages/ChatPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import type { Context, UserMessage } from "@earendil-works/pi-ai";
import { invoke } from "@tauri-apps/api/core";
import { listen } from "@tauri-apps/api/event";
import { getCurrentWebview } from "@tauri-apps/api/webview";
import { revealItemInDir } from "@tauri-apps/plugin-opener";
import { type SetStateAction, useCallback, useEffect, useMemo, useRef, useState } from "react";
import { MacOsTitleBarSpacer, MacOsTitleBarToggle } from "../components/MacOsTitleBarSpacer";
import { ChatHistorySidebar } from "../components/chat/ChatHistorySidebar";
Expand Down Expand Up @@ -1009,6 +1010,52 @@ export function ChatPage(props: ChatPageProps) {
[activateWorkspaceProject, checkWorkspaceProjectDirectory],
);

const handleBrowseWorkspaceProjectInFileTree = useCallback(
async (project: WorkspaceProject) => {
if (!(await checkWorkspaceProjectDirectory(project))) {
return;
}
const pathKey = workspaceProjectPathKey(project.path);
if (!pathKey) {
return;
}

setActiveView("chat");
setProjectToolsPanelOpen(true);
activateWorkspaceProject(project);
setSettings((prev) =>
updateProjectToolsFileTreeOpen(
updateCustomSettings(prev, {
projectToolsPanel: {
...prev.customSettings.projectToolsPanel,
activeTab: "fileTree",
},
}),
pathKey,
true,
),
);
},
[activateWorkspaceProject, checkWorkspaceProjectDirectory, setSettings],
);

const handleBrowseWorkspaceProjectInSystemFileManager = useCallback(
async (project: WorkspaceProject) => {
if (!(await checkWorkspaceProjectDirectory(project))) {
return;
}

try {
await revealItemInDir(project.path.trim());
} catch (error) {
const message = asErrorMessage(error, t("chat.workspaceOpenSystemFileManagerFailed"));
setHistoryError(message);
setErrorMessage(message);
}
},
[checkWorkspaceProjectDirectory, setErrorMessage, setHistoryError, t],
);

const handleOpenCreateWorkspaceProject = useCallback(async () => {
try {
const picked = await invoke<string | null>("system_pick_folder", {
Expand Down Expand Up @@ -4094,6 +4141,8 @@ export function ChatPage(props: ChatPageProps) {
onCreateProject={handleOpenCreateWorkspaceProject}
onSelectProject={handleSelectWorkspaceProject}
onNewConversationForProject={handleNewConversationForProject}
onBrowseProjectInFileTree={handleBrowseWorkspaceProjectInFileTree}
onBrowseProjectInSystemFileManager={handleBrowseWorkspaceProjectInSystemFileManager}
onStartRenamingProject={handleStartRenamingWorkspaceProject}
onProjectRenameDraftChange={setProjectRenameDraft}
onCommitProjectRename={handleCommitWorkspaceProjectRename}
Expand Down
Loading