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
74 changes: 40 additions & 34 deletions frontend/app/view/preview/directorypreview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { RpcApi } from "@/app/store/wshclientapi";
import { TabRpcClient } from "@/app/store/wshrpcutil";
import type { PreviewModel } from "@/app/view/preview/preview";
import { checkKeyPressed, isCharacterKeyEvent } from "@/util/keyutil";
import { fireAndForget, isBlank } from "@/util/util";
import { fireAndForget, isBlank, makeConnRoute, makeNativeLabel } from "@/util/util";
import { offset, useDismiss, useFloating, useInteractions } from "@floating-ui/react";
import {
Column,
Expand Down Expand Up @@ -508,24 +508,22 @@ function TableBody({
}, [focusIndex]);

const handleFileContextMenu = useCallback(
(e: any, finfo: FileInfo) => {
async (e: any, finfo: FileInfo) => {
e.preventDefault();
e.stopPropagation();
if (finfo == null) {
return;
}
const normPath = getNormFilePath(finfo);
const fileName = finfo.path.split("/").pop();
let openNativeLabel = "Open File";
if (finfo.isdir) {
openNativeLabel = "Open Directory in File Manager";
if (PLATFORM == "darwin") {
openNativeLabel = "Open Directory in Finder";
} else if (PLATFORM == "win32") {
openNativeLabel = "Open Directory in Explorer";
}
} else {
openNativeLabel = "Open File in Default Application";
let parentFileInfo: FileInfo;
try {
parentFileInfo = await RpcApi.RemoteFileJoinCommand(TabRpcClient, [normPath, ".."], {
route: makeConnRoute(conn),
});
} catch (e) {
console.log("could not get parent file info. using child file info as fallback");
parentFileInfo = finfo;
Comment on lines +511 to +526
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Improve error handling and parent directory fallback logic.

The error handling for parent directory info could be improved:

  1. The error log message is too generic and doesn't include the actual error.
  2. Using the child file info as a fallback might lead to incorrect behavior.

Consider this improved implementation:

 try {
     parentFileInfo = await RpcApi.RemoteFileJoinCommand(TabRpcClient, [normPath, ".."], {
         route: makeConnRoute(conn),
     });
 } catch (e) {
-    console.log("could not get parent file info. using child file info as fallback");
-    parentFileInfo = finfo;
+    console.error(`Failed to get parent info for ${normPath}:`, e);
+    throw new Error(`Unable to access parent directory: ${e.message}`);
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
async (e: any, finfo: FileInfo) => {
e.preventDefault();
e.stopPropagation();
if (finfo == null) {
return;
}
const normPath = getNormFilePath(finfo);
const fileName = finfo.path.split("/").pop();
let openNativeLabel = "Open File";
if (finfo.isdir) {
openNativeLabel = "Open Directory in File Manager";
if (PLATFORM == "darwin") {
openNativeLabel = "Open Directory in Finder";
} else if (PLATFORM == "win32") {
openNativeLabel = "Open Directory in Explorer";
}
} else {
openNativeLabel = "Open File in Default Application";
let parentFileInfo: FileInfo;
try {
parentFileInfo = await RpcApi.RemoteFileJoinCommand(TabRpcClient, [normPath, ".."], {
route: makeConnRoute(conn),
});
} catch (e) {
console.log("could not get parent file info. using child file info as fallback");
parentFileInfo = finfo;
async (e: any, finfo: FileInfo) => {
e.preventDefault();
e.stopPropagation();
if (finfo == null) {
return;
}
const normPath = getNormFilePath(finfo);
const fileName = finfo.path.split("/").pop();
let parentFileInfo: FileInfo;
try {
parentFileInfo = await RpcApi.RemoteFileJoinCommand(TabRpcClient, [normPath, ".."], {
route: makeConnRoute(conn),
});
} catch (e) {
console.error(`Failed to get parent info for ${normPath}:`, e);
throw new Error(`Unable to access parent directory: ${e.message}`);
}

}
const menu: ContextMenuItem[] = [
{
Expand Down Expand Up @@ -577,16 +575,6 @@ function TableBody({
{
type: "separator",
},
// TODO: Only show this option for local files, resolve correct host path if connection is WSL
{
label: openNativeLabel,
click: () => {
getApi().openNativePath(normPath);
},
},
{
type: "separator",
},
{
label: "Open Preview in New Block",
click: () =>
Expand All @@ -595,12 +583,33 @@ function TableBody({
meta: {
view: "preview",
file: finfo.path,
connection: conn,
},
};
await createBlock(blockDef);
}),
},
];
if (!conn) {
menu.push(
{
type: "separator",
},
// TODO: resolve correct host path if connection is WSL
{
label: makeNativeLabel(PLATFORM, finfo.isdir, false),
click: () => {
getApi().openNativePath(normPath);
},
},
{
label: makeNativeLabel(PLATFORM, true, true),
click: () => {
getApi().openNativePath(parentFileInfo.dir);
},
}
);
}
if (finfo.mimetype == "directory") {
menu.push({
label: "Open Terminal in New Block",
Expand All @@ -611,6 +620,7 @@ function TableBody({
controller: "shell",
view: "term",
"cmd:cwd": await model.formatRemoteUri(finfo.path, globalStore.get),
connection: conn,
},
};
await createBlock(termBlockDef);
Expand Down Expand Up @@ -858,12 +868,6 @@ function DirectoryPreview({ model }: DirectoryPreviewProps) {
(e: any) => {
e.preventDefault();
e.stopPropagation();
let openNativeLabel = "Open Directory in File Manager";
if (PLATFORM == "darwin") {
openNativeLabel = "Open Directory in Finder";
} else if (PLATFORM == "win32") {
openNativeLabel = "Open Directory in Explorer";
}
const menu: ContextMenuItem[] = [
{
label: "New File",
Expand All @@ -880,15 +884,16 @@ function DirectoryPreview({ model }: DirectoryPreviewProps) {
{
type: "separator",
},
// TODO: Only show this option for local files, resolve correct host path if connection is WSL
{
label: openNativeLabel,
];
if (!conn) {
// TODO: resolve correct host path if connection is WSL
menu.push({
label: makeNativeLabel(PLATFORM, true, true),
click: () => {
console.log(`opening ${dirPath}`);
getApi().openNativePath(dirPath);
},
},
];
});
}
menu.push({
label: "Open Terminal in New Block",
click: async () => {
Expand All @@ -897,6 +902,7 @@ function DirectoryPreview({ model }: DirectoryPreviewProps) {
controller: "shell",
view: "term",
"cmd:cwd": dirPath,
connection: conn,
},
};
await createBlock(termBlockDef);
Expand Down
39 changes: 38 additions & 1 deletion frontend/app/view/preview/preview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,28 @@ import { Markdown } from "@/element/markdown";
import {
atoms,
createBlock,
getApi,
getConnStatusAtom,
getOverrideConfigAtom,
getSettingsKeyAtom,
globalStore,
PLATFORM,
refocusNode,
} from "@/store/global";
import * as services from "@/store/services";
import * as WOS from "@/store/wos";
import { getWebServerEndpoint } from "@/util/endpoints";
import { goHistory, goHistoryBack, goHistoryForward } from "@/util/historyutil";
import { adaptFromReactOrNativeKeyEvent, checkKeyPressed, keydownWrapper } from "@/util/keyutil";
import { base64ToString, fireAndForget, isBlank, jotaiLoadableValue, makeConnRoute, stringToBase64 } from "@/util/util";
import {
base64ToString,
fireAndForget,
isBlank,
jotaiLoadableValue,
makeConnRoute,
makeNativeLabel,
stringToBase64,
} from "@/util/util";
import { Monaco } from "@monaco-editor/react";
import clsx from "clsx";
import { Atom, atom, Getter, PrimitiveAtom, useAtomValue, useSetAtom, WritableAtom } from "jotai";
Expand Down Expand Up @@ -139,6 +149,7 @@ export class PreviewModel implements ViewModel {
loadableStatFilePath: Atom<Loadable<string>>;
loadableFileInfo: Atom<Loadable<FileInfo>>;
connection: Atom<Promise<string>>;
connectionImmediate: Atom<string>;
statFile: Atom<Promise<FileInfo>>;
fullFile: Atom<Promise<FileData>>;
fileMimeType: Atom<Promise<string>>;
Expand Down Expand Up @@ -364,6 +375,9 @@ export class PreviewModel implements ViewModel {
}
return connName;
});
this.connectionImmediate = atom<string>((get) => {
return get(this.blockAtom)?.meta?.connection;
});
this.statFile = atom<Promise<FileInfo>>(async (get) => {
const fileName = get(this.metaFilePath);
if (fileName == null) {
Expand Down Expand Up @@ -677,17 +691,40 @@ export class PreviewModel implements ViewModel {
label: "Open Terminal in New Block",
click: () =>
fireAndForget(async () => {
const conn = await globalStore.get(this.connection);
const fileInfo = await globalStore.get(this.statFile);
const termBlockDef: BlockDef = {
meta: {
view: "term",
controller: "shell",
"cmd:cwd": fileInfo.dir,
connection: conn,
},
};
await createBlock(termBlockDef);
}),
});
const conn = globalStore.get(this.connectionImmediate);
if (!conn) {
menuItems.push({
label: makeNativeLabel(PLATFORM, true, true),
click: async () => {
const fileInfo = await globalStore.get(this.statFile);
getApi().openNativePath(fileInfo.dir);
},
});
}
} else {
const conn = globalStore.get(this.connectionImmediate);
if (!conn) {
menuItems.push({
label: makeNativeLabel(PLATFORM, false, false),
click: async () => {
const fileInfo = await globalStore.get(this.statFile);
getApi().openNativePath(`${fileInfo.dir}/${fileInfo.name}`);
},
});
}
}
const loadableSV = globalStore.get(this.loadableSpecializedView);
const wordWrapAtom = getOverrideConfigAtom(this.blockId, "editor:wordwrap");
Expand Down
24 changes: 24 additions & 0 deletions frontend/util/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,29 @@ function sleep(ms: number): Promise<void> {
return new Promise((resolve) => setTimeout(resolve, ms));
}

function makeNativeLabel(platform: string, isDirectory: boolean, isParent: boolean) {
let managerName: string;
if (!isDirectory && !isParent) {
managerName = "Default Application";
} else if (platform == "darwin") {
managerName = "Finder";
} else if (platform == "win32") {
managerName = "Explorer";
} else {
managerName = "File Manager";
}

let fileAction: string;
if (isParent) {
fileAction = "Reveal";
} else if (isDirectory) {
fileAction = "Open Directory";
} else {
fileAction = "Open File";
}
return `${fileAction} in ${managerName}`;
}

export {
atomWithDebounce,
atomWithThrottle,
Expand All @@ -325,6 +348,7 @@ export {
makeConnRoute,
makeExternLink,
makeIconClass,
makeNativeLabel,
sleep,
stringToBase64,
useAtomValueSafe,
Expand Down
Loading