mirror of
https://github.com/getpaseo/paseo.git
synced 2026-07-29 12:01:31 +00:00
Open project and workspace folders from the sidebar (#2491)
* feat(app): open project folder from project context menu (#2487) * refactor(app): give file manager action a home --------- Co-authored-by: Mohamed Boudra <boudra.moha@gmail.com>
This commit is contained in:
@@ -131,6 +131,7 @@ import {
|
|||||||
getIsElectron,
|
getIsElectron,
|
||||||
} from "@/constants/platform";
|
} from "@/constants/platform";
|
||||||
import { getDesktopHost } from "@/desktop/host";
|
import { getDesktopHost } from "@/desktop/host";
|
||||||
|
import { OpenInFileManagerMenuItem } from "@/workspace/open-in-file-manager/menu-item";
|
||||||
|
|
||||||
const workspaceKeyExtractor = (workspace: SidebarWorkspacePlacement) => workspace.workspaceKey;
|
const workspaceKeyExtractor = (workspace: SidebarWorkspacePlacement) => workspace.workspaceKey;
|
||||||
|
|
||||||
@@ -609,6 +610,10 @@ function ProjectKebabMenu({
|
|||||||
{t("sidebar.project.actions.openNewWindow")}
|
{t("sidebar.project.actions.openNewWindow")}
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
) : null}
|
) : null}
|
||||||
|
<OpenInFileManagerMenuItem
|
||||||
|
path={projectPath}
|
||||||
|
testID={`sidebar-project-menu-open-folder-${projectKey}`}
|
||||||
|
/>
|
||||||
<DropdownMenuItem
|
<DropdownMenuItem
|
||||||
testID={`sidebar-project-menu-remove-${projectKey}`}
|
testID={`sidebar-project-menu-remove-${projectKey}`}
|
||||||
leading={trash2LeadingIcon}
|
leading={trash2LeadingIcon}
|
||||||
@@ -660,6 +665,7 @@ function WorkspaceRowRightGroup({
|
|||||||
isPinned?: boolean;
|
isPinned?: boolean;
|
||||||
onTogglePin?: () => void;
|
onTogglePin?: () => void;
|
||||||
}) {
|
}) {
|
||||||
|
const workspacePath = workspace.workspaceDirectory ?? workspace.projectRootPath;
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const showShortcut = showShortcutBadge && shortcutNumber !== null;
|
const showShortcut = showShortcutBadge && shortcutNumber !== null;
|
||||||
const showKebab = Boolean(onArchive && (isHovered || isTouchPlatform));
|
const showKebab = Boolean(onArchive && (isHovered || isTouchPlatform));
|
||||||
@@ -698,6 +704,7 @@ function WorkspaceRowRightGroup({
|
|||||||
archiveShortcutKeys={archiveShortcutKeys}
|
archiveShortcutKeys={archiveShortcutKeys}
|
||||||
isPinned={isPinned}
|
isPinned={isPinned}
|
||||||
onTogglePin={onTogglePin}
|
onTogglePin={onTogglePin}
|
||||||
|
openInFileManagerPath={workspacePath}
|
||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
</SidebarWorkspaceTrailingActionOverlay>
|
</SidebarWorkspaceTrailingActionOverlay>
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import {
|
|||||||
DropdownMenuTrigger,
|
DropdownMenuTrigger,
|
||||||
} from "@/components/ui/dropdown-menu";
|
} from "@/components/ui/dropdown-menu";
|
||||||
import { Shortcut } from "@/components/ui/shortcut";
|
import { Shortcut } from "@/components/ui/shortcut";
|
||||||
|
import { OpenInFileManagerMenuItem } from "@/workspace/open-in-file-manager/menu-item";
|
||||||
|
|
||||||
const foregroundColorMapping = (theme: Theme) => ({ color: theme.colors.foreground });
|
const foregroundColorMapping = (theme: Theme) => ({ color: theme.colors.foreground });
|
||||||
const foregroundMutedColorMapping = (theme: Theme) => ({
|
const foregroundMutedColorMapping = (theme: Theme) => ({
|
||||||
@@ -58,6 +59,7 @@ interface SidebarWorkspaceMenuProps {
|
|||||||
archiveShortcutKeys?: ShortcutKey[][] | null;
|
archiveShortcutKeys?: ShortcutKey[][] | null;
|
||||||
isPinned?: boolean;
|
isPinned?: boolean;
|
||||||
onTogglePin?: () => void;
|
onTogglePin?: () => void;
|
||||||
|
openInFileManagerPath?: string | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function SidebarWorkspaceMenu({
|
export function SidebarWorkspaceMenu({
|
||||||
@@ -73,6 +75,7 @@ export function SidebarWorkspaceMenu({
|
|||||||
archiveShortcutKeys,
|
archiveShortcutKeys,
|
||||||
isPinned,
|
isPinned,
|
||||||
onTogglePin,
|
onTogglePin,
|
||||||
|
openInFileManagerPath,
|
||||||
}: SidebarWorkspaceMenuProps) {
|
}: SidebarWorkspaceMenuProps) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const archiveTrailing = useMemo(
|
const archiveTrailing = useMemo(
|
||||||
@@ -137,6 +140,10 @@ export function SidebarWorkspaceMenu({
|
|||||||
{isPinned ? t("sidebar.workspace.actions.unpin") : t("sidebar.workspace.actions.pin")}
|
{isPinned ? t("sidebar.workspace.actions.unpin") : t("sidebar.workspace.actions.pin")}
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
) : null}
|
) : null}
|
||||||
|
<OpenInFileManagerMenuItem
|
||||||
|
path={openInFileManagerPath}
|
||||||
|
testID={`sidebar-workspace-menu-open-folder-${workspaceKey}`}
|
||||||
|
/>
|
||||||
<DropdownMenuItem
|
<DropdownMenuItem
|
||||||
testID={`sidebar-workspace-menu-archive-${workspaceKey}`}
|
testID={`sidebar-workspace-menu-archive-${workspaceKey}`}
|
||||||
leading={archiveLeadingIcon}
|
leading={archiveLeadingIcon}
|
||||||
|
|||||||
@@ -908,6 +908,8 @@ export const ar: TranslationResources = {
|
|||||||
openSettings: "افتح إعدادات المشروع",
|
openSettings: "افتح إعدادات المشروع",
|
||||||
openNewWindow: "Open in new window",
|
openNewWindow: "Open in new window",
|
||||||
openNewWindowFailed: "Couldn't open a new window",
|
openNewWindowFailed: "Couldn't open a new window",
|
||||||
|
openFolder: "Open in file manager",
|
||||||
|
openFolderFailed: "Couldn't open folder",
|
||||||
remove: "إزالة المشروع",
|
remove: "إزالة المشروع",
|
||||||
removing: "جارٍ الإزالة...",
|
removing: "جارٍ الإزالة...",
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -918,6 +918,8 @@ export const en = {
|
|||||||
openSettings: "Open project settings",
|
openSettings: "Open project settings",
|
||||||
openNewWindow: "Open in new window",
|
openNewWindow: "Open in new window",
|
||||||
openNewWindowFailed: "Couldn't open a new window",
|
openNewWindowFailed: "Couldn't open a new window",
|
||||||
|
openFolder: "Open in file manager",
|
||||||
|
openFolderFailed: "Couldn't open folder",
|
||||||
remove: "Remove project",
|
remove: "Remove project",
|
||||||
removing: "Removing...",
|
removing: "Removing...",
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -939,6 +939,8 @@ export const es: TranslationResources = {
|
|||||||
openSettings: "Abrir la configuración del proyecto",
|
openSettings: "Abrir la configuración del proyecto",
|
||||||
openNewWindow: "Open in new window",
|
openNewWindow: "Open in new window",
|
||||||
openNewWindowFailed: "Couldn't open a new window",
|
openNewWindowFailed: "Couldn't open a new window",
|
||||||
|
openFolder: "Open in file manager",
|
||||||
|
openFolderFailed: "Couldn't open folder",
|
||||||
remove: "Eliminar proyecto",
|
remove: "Eliminar proyecto",
|
||||||
removing: "Eliminando...",
|
removing: "Eliminando...",
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -938,6 +938,8 @@ export const fr: TranslationResources = {
|
|||||||
openSettings: "Ouvrir les paramètres du projet",
|
openSettings: "Ouvrir les paramètres du projet",
|
||||||
openNewWindow: "Open in new window",
|
openNewWindow: "Open in new window",
|
||||||
openNewWindowFailed: "Couldn't open a new window",
|
openNewWindowFailed: "Couldn't open a new window",
|
||||||
|
openFolder: "Open in file manager",
|
||||||
|
openFolderFailed: "Couldn't open folder",
|
||||||
remove: "Supprimer le projet",
|
remove: "Supprimer le projet",
|
||||||
removing: "Suppression...",
|
removing: "Suppression...",
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -919,6 +919,8 @@ export const ja: TranslationResources = {
|
|||||||
openSettings: "プロジェクト設定を開く",
|
openSettings: "プロジェクト設定を開く",
|
||||||
openNewWindow: "新しいウィンドウで開く",
|
openNewWindow: "新しいウィンドウで開く",
|
||||||
openNewWindowFailed: "新しいウィンドウを開けませんでした",
|
openNewWindowFailed: "新しいウィンドウを開けませんでした",
|
||||||
|
openFolder: "Open in file manager",
|
||||||
|
openFolderFailed: "Couldn't open folder",
|
||||||
remove: "プロジェクトを削除",
|
remove: "プロジェクトを削除",
|
||||||
removing: "削除中...",
|
removing: "削除中...",
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -930,6 +930,8 @@ export const ptBR: TranslationResources = {
|
|||||||
openSettings: "Abrir configurações do projeto",
|
openSettings: "Abrir configurações do projeto",
|
||||||
openNewWindow: "Abrir em nova janela",
|
openNewWindow: "Abrir em nova janela",
|
||||||
openNewWindowFailed: "Não foi possível abrir uma nova janela",
|
openNewWindowFailed: "Não foi possível abrir uma nova janela",
|
||||||
|
openFolder: "Open in file manager",
|
||||||
|
openFolderFailed: "Couldn't open folder",
|
||||||
remove: "Remover projeto",
|
remove: "Remover projeto",
|
||||||
removing: "Removendo...",
|
removing: "Removendo...",
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -930,6 +930,8 @@ export const ru: TranslationResources = {
|
|||||||
openSettings: "Открыть настройки проекта",
|
openSettings: "Открыть настройки проекта",
|
||||||
openNewWindow: "Open in new window",
|
openNewWindow: "Open in new window",
|
||||||
openNewWindowFailed: "Couldn't open a new window",
|
openNewWindowFailed: "Couldn't open a new window",
|
||||||
|
openFolder: "Open in file manager",
|
||||||
|
openFolderFailed: "Couldn't open folder",
|
||||||
remove: "Удалить проект",
|
remove: "Удалить проект",
|
||||||
removing: "Удаление...",
|
removing: "Удаление...",
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -899,6 +899,8 @@ export const zhCN: TranslationResources = {
|
|||||||
openSettings: "打开 project 设置",
|
openSettings: "打开 project 设置",
|
||||||
openNewWindow: "在新窗口中打开",
|
openNewWindow: "在新窗口中打开",
|
||||||
openNewWindowFailed: "无法打开新窗口",
|
openNewWindowFailed: "无法打开新窗口",
|
||||||
|
openFolder: "Open in file manager",
|
||||||
|
openFolderFailed: "Couldn't open folder",
|
||||||
remove: "移除 project",
|
remove: "移除 project",
|
||||||
removing: "正在移除...",
|
removing: "正在移除...",
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -0,0 +1,54 @@
|
|||||||
|
import { useCallback } from "react";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { FolderOpen } from "lucide-react-native";
|
||||||
|
import { withUnistyles } from "react-native-unistyles";
|
||||||
|
import { DropdownMenuItem } from "@/components/ui/dropdown-menu";
|
||||||
|
import { getIsElectron } from "@/constants/platform";
|
||||||
|
import { useToast } from "@/contexts/toast-context";
|
||||||
|
import type { Theme } from "@/styles/theme";
|
||||||
|
import { openDesktopTarget, useDesktopOpenTargets } from "@/workspace/desktop-open-targets";
|
||||||
|
|
||||||
|
interface OpenInFileManagerMenuItemProps {
|
||||||
|
path?: string | null;
|
||||||
|
testID: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ThemedFolderOpen = withUnistyles(FolderOpen);
|
||||||
|
|
||||||
|
const foregroundMutedColorMapping = (theme: Theme) => ({
|
||||||
|
color: theme.colors.foregroundMuted,
|
||||||
|
});
|
||||||
|
|
||||||
|
const leadingIcon = <ThemedFolderOpen size={14} uniProps={foregroundMutedColorMapping} />;
|
||||||
|
|
||||||
|
export function OpenInFileManagerMenuItem({ path, testID }: OpenInFileManagerMenuItemProps) {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const toast = useToast();
|
||||||
|
const isElectron = getIsElectron();
|
||||||
|
const workspacePath = path?.trim() ?? "";
|
||||||
|
const { targets } = useDesktopOpenTargets({
|
||||||
|
isLocalExecution: isElectron && workspacePath.length > 0,
|
||||||
|
});
|
||||||
|
const fileManagerTarget = targets.find((target) => target.kind === "file-manager");
|
||||||
|
|
||||||
|
const openInFileManager = useCallback(() => {
|
||||||
|
if (!fileManagerTarget || workspacePath.length === 0) return;
|
||||||
|
void openDesktopTarget({
|
||||||
|
editorId: fileManagerTarget.id,
|
||||||
|
workspacePath,
|
||||||
|
}).catch((error) => {
|
||||||
|
console.warn("[open-in-file-manager] open failed", error);
|
||||||
|
toast.error(t("sidebar.project.actions.openFolderFailed"));
|
||||||
|
});
|
||||||
|
}, [fileManagerTarget, t, toast, workspacePath]);
|
||||||
|
|
||||||
|
if (!isElectron || !fileManagerTarget || workspacePath.length === 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<DropdownMenuItem testID={testID} leading={leadingIcon} onSelect={openInFileManager}>
|
||||||
|
{t("sidebar.project.actions.openFolder")}
|
||||||
|
</DropdownMenuItem>
|
||||||
|
);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user