diff --git a/emain/emain.ts b/emain/emain.ts index ff6cccd155..002176c33d 100644 --- a/emain/emain.ts +++ b/emain/emain.ts @@ -370,6 +370,7 @@ electron.ipcMain.on("quicklook", (event, filePath: string) => { electron.ipcMain.on("open-native-path", (event, filePath: string) => { console.log("open-native-path", filePath); + filePath = filePath.replace("~", electronApp.getPath("home")); fireAndForget(() => callWithOriginalXdgCurrentDesktopAsync(() => electron.shell.openPath(filePath).then((excuse) => { diff --git a/frontend/app/app-bg.tsx b/frontend/app/app-bg.tsx index 9ac70a550e..718e3b82af 100644 --- a/frontend/app/app-bg.tsx +++ b/frontend/app/app-bg.tsx @@ -1,12 +1,13 @@ // Copyright 2025, Command Line Inc. // SPDX-License-Identifier: Apache-2.0 +import { PLATFORM, PlatformMacOS } from "@/util/platformutil"; import { computeBgStyleFromMeta } from "@/util/waveutil"; import useResizeObserver from "@react-hook/resize-observer"; import { useAtomValue } from "jotai"; import { CSSProperties, useCallback, useLayoutEffect, useRef } from "react"; import { debounce } from "throttle-debounce"; -import { atoms, getApi, PLATFORM, WOS } from "./store/global"; +import { atoms, getApi, WOS } from "./store/global"; import { useWaveObjectValue } from "./store/wos"; export function AppBackground() { @@ -18,7 +19,7 @@ export function AppBackground() { debounce(30, () => { if ( bgRef.current && - PLATFORM !== "darwin" && + PLATFORM !== PlatformMacOS && bgRef.current && "windowControlsOverlay" in window.navigator ) { diff --git a/frontend/app/app.tsx b/frontend/app/app.tsx index 880a034d25..dfe5679fc0 100644 --- a/frontend/app/app.tsx +++ b/frontend/app/app.tsx @@ -3,18 +3,11 @@ import { Workspace } from "@/app/workspace/workspace"; import { ContextMenuModel } from "@/store/contextmenu"; -import { - atoms, - createBlock, - getSettingsPrefixAtom, - globalStore, - isDev, - PLATFORM, - removeFlashError, -} from "@/store/global"; +import { atoms, createBlock, getSettingsPrefixAtom, globalStore, isDev, removeFlashError } from "@/store/global"; import { appHandleKeyDown, keyboardMouseDownHandler } from "@/store/keymodel"; import { getElemAsStr } from "@/util/focusutil"; import * as keyutil from "@/util/keyutil"; +import { PLATFORM } from "@/util/platformutil"; import * as util from "@/util/util"; import clsx from "clsx"; import debug from "debug"; @@ -29,7 +22,7 @@ import { NotificationBubbles } from "./notification/notificationbubbles"; import "./app.scss"; -// this should come after app.scss (don't remove the newline above otherwise prettier will reorder these imports) +// tailwindsetup.css should come *after* app.scss (don't remove the newline above otherwise prettier will reorder these imports) import "../tailwindsetup.css"; const dlog = debug("wave:app"); diff --git a/frontend/app/element/quicktips.tsx b/frontend/app/element/quicktips.tsx index 99e51d8912..36243b8b00 100644 --- a/frontend/app/element/quicktips.tsx +++ b/frontend/app/element/quicktips.tsx @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 import { MagnifyIcon } from "@/app/element/magnify"; -import { PLATFORM } from "@/app/store/global"; +import { PLATFORM, PlatformMacOS } from "@/util/platformutil"; import "./quicktips.scss"; const KeyBinding = ({ keyDecl }: { keyDecl: string }) => { @@ -10,7 +10,7 @@ const KeyBinding = ({ keyDecl }: { keyDecl: string }) => { const elems: React.ReactNode[] = []; for (let part of parts) { if (part === "Cmd") { - if (PLATFORM === "darwin") { + if (PLATFORM === PlatformMacOS) { elems.push(
⌘ Cmd diff --git a/frontend/app/store/global.ts b/frontend/app/store/global.ts index 00a386f223..5db71d62a5 100644 --- a/frontend/app/store/global.ts +++ b/frontend/app/store/global.ts @@ -17,6 +17,7 @@ import { } from "@/layout/lib/types"; import { getWebServerEndpoint } from "@/util/endpoints"; import { fetch } from "@/util/fetchutil"; +import { setPlatform } from "@/util/platformutil"; import { deepCompareReturnPrev, getPrefixedSettings, isBlank } from "@/util/util"; import { atom, Atom, PrimitiveAtom, useAtomValue } from "jotai"; import { globalStore } from "./jotaiStore"; @@ -25,7 +26,6 @@ import { ClientService, ObjectService } from "./services"; import * as WOS from "./wos"; import { getFileSubject, waveEventSubscribe } from "./wps"; -let PLATFORM: NodeJS.Platform = "darwin"; let atoms: GlobalAtomsType; let globalEnvironment: "electron" | "renderer"; const blockComponentModelMap = new Map(); @@ -46,10 +46,6 @@ function initGlobal(initOpts: GlobalInitOptions) { initGlobalAtoms(initOpts); } -function setPlatform(platform: NodeJS.Platform) { - PLATFORM = platform; -} - function initGlobalAtoms(initOpts: GlobalInitOptions) { const windowIdAtom = atom(initOpts.windowId) as PrimitiveAtom; const clientIdAtom = atom(initOpts.clientId) as PrimitiveAtom; @@ -790,7 +786,6 @@ export { isDev, loadConnStatus, openLink, - PLATFORM, pushFlashError, pushNotification, recordTEvent, diff --git a/frontend/app/tab/tabbar.tsx b/frontend/app/tab/tabbar.tsx index 6fe2f622cb..47cc15e2e6 100644 --- a/frontend/app/tab/tabbar.tsx +++ b/frontend/app/tab/tabbar.tsx @@ -5,7 +5,8 @@ import { Button } from "@/app/element/button"; import { modalsModel } from "@/app/store/modalmodel"; import { WindowDrag } from "@/element/windowdrag"; import { deleteLayoutModelForTab } from "@/layout/index"; -import { atoms, createTab, getApi, globalStore, isDev, PLATFORM, setActiveTab } from "@/store/global"; +import { atoms, createTab, getApi, globalStore, isDev, setActiveTab } from "@/store/global"; +import { PLATFORM, PlatformMacOS } from "@/util/platformutil"; import { fireAndForget } from "@/util/util"; import { useAtomValue } from "jotai"; import { OverlayScrollbars } from "overlayscrollbars"; @@ -641,7 +642,7 @@ const TabBar = memo(({ workspace }: TabBarProps) => {
) : undefined; const appMenuButton = - PLATFORM !== "darwin" && !settings["window:showmenubar"] ? ( + PLATFORM !== PlatformMacOS && !settings["window:showmenubar"] ? (
diff --git a/frontend/app/view/preview/directorypreview.tsx b/frontend/app/view/preview/directorypreview.tsx index 6350a840a0..cccb413e13 100644 --- a/frontend/app/view/preview/directorypreview.tsx +++ b/frontend/app/view/preview/directorypreview.tsx @@ -6,12 +6,14 @@ import { CopyButton } from "@/app/element/copybutton"; import { Input } from "@/app/element/input"; import { useDimensionsWithCallbackRef } from "@/app/hook/useDimensions"; import { ContextMenuModel } from "@/app/store/contextmenu"; -import { PLATFORM, atoms, createBlock, getApi, globalStore } from "@/app/store/global"; +import { atoms, getApi, globalStore } from "@/app/store/global"; 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, makeNativeLabel } from "@/util/util"; +import { PLATFORM, PlatformMacOS } from "@/util/platformutil"; +import { addOpenMenuItems } from "@/util/previewutil"; +import { fireAndForget, isBlank } from "@/util/util"; import { formatRemoteUri } from "@/util/waveutil"; import { offset, useDismiss, useFloating, useInteractions } from "@floating-ui/react"; import { @@ -301,13 +303,21 @@ function DirectoryTable({ newPath = path.substring(0, lastInstance) + newName; console.log(`replacing ${fileName} with ${newName}: ${path}`); fireAndForget(async () => { - await RpcApi.FileMoveCommand(TabRpcClient, { - srcuri: await model.formatRemoteUri(path, globalStore.get), - desturi: await model.formatRemoteUri(newPath, globalStore.get), - opts: { - recursive: true, - }, - }); + try { + await RpcApi.FileMoveCommand(TabRpcClient, { + srcuri: await model.formatRemoteUri(path, globalStore.get), + desturi: await model.formatRemoteUri(newPath, globalStore.get), + opts: { + recursive: true, + }, + }); + } catch (e) { + const errorStatus: ErrorMsg = { + status: "Rename Failed", + text: `${e}`, + }; + globalStore.set(model.errorMsgAtom, errorStatus); + } model.refreshCallback(); }); } @@ -521,17 +531,6 @@ function TableBody({ } const normPath = finfo.path; const fileName = finfo.path.split("/").pop(); - let parentFileInfo: FileInfo; - try { - parentFileInfo = await RpcApi.FileInfoCommand(TabRpcClient, { - info: { - path: await model.formatRemoteUri(finfo.dir, globalStore.get), - }, - }); - } catch (e) { - console.log("could not get parent file info. using child file info as fallback"); - parentFileInfo = finfo; - } const menu: ContextMenuItem[] = [ { label: "New File", @@ -570,71 +569,8 @@ function TableBody({ label: "Copy Full File Name (Shell Quoted)", click: () => fireAndForget(() => navigator.clipboard.writeText(shellQuote([finfo.path]))), }, - { - type: "separator", - }, - { - label: "Download File", - click: () => { - const remoteUri = formatRemoteUri(finfo.path, conn); - getApi().downloadFile(remoteUri); - }, - }, - { - type: "separator", - }, - { - label: "Open Preview in New Block", - click: () => - fireAndForget(async () => { - const blockDef: BlockDef = { - 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.path); - }, - } - ); - } - if (finfo.mimetype == "directory") { - menu.push({ - label: "Open Terminal in New Block", - click: () => - fireAndForget(async () => { - const termBlockDef: BlockDef = { - meta: { - controller: "shell", - view: "term", - "cmd:cwd": await model.formatRemoteUri(finfo.path, globalStore.get), - connection: conn, - }, - }; - await createBlock(termBlockDef); - }), - }); - } + addOpenMenuItems(menu, conn, finfo); menu.push( { type: "separator", @@ -643,10 +579,18 @@ function TableBody({ label: "Delete", click: () => { fireAndForget(async () => { - await RpcApi.FileDeleteCommand(TabRpcClient, { - path: await model.formatRemoteUri(finfo.path, globalStore.get), - recursive: false, - }).catch((e) => console.log(e)); + try { + await RpcApi.FileDeleteCommand(TabRpcClient, { + path: await model.formatRemoteUri(finfo.path, globalStore.get), + recursive: false, + }); + } catch (e) { + const errorStatus: ErrorMsg = { + status: "Delete Failed", + text: `${e}`, + }; + globalStore.set(model.errorMsgAtom, errorStatus); + } setRefreshVersion((current) => current + 1); }); }, @@ -782,7 +726,8 @@ function DirectoryPreview({ model }: DirectoryPreviewProps) { const [refreshVersion, setRefreshVersion] = useAtom(model.refreshVersion); const conn = useAtomValue(model.connection); const blockData = useAtomValue(model.blockAtom); - const dirPath = useAtomValue(model.normFilePath); + const finfo = useAtomValue(model.statFile); + const dirPath = finfo?.path; const [copyStatus, setCopyStatus] = useState(null); useEffect(() => { @@ -796,16 +741,26 @@ function DirectoryPreview({ model }: DirectoryPreviewProps) { useEffect(() => { const getContent = async () => { - const file = await RpcApi.FileReadCommand( - TabRpcClient, - { - info: { - path: await model.formatRemoteUri(dirPath, globalStore.get), + let entries: FileInfo[]; + try { + const file = await RpcApi.FileReadCommand( + TabRpcClient, + { + info: { + path: await model.formatRemoteUri(dirPath, globalStore.get), + }, }, - }, - null - ); - setUnfilteredData(file.entries); + null + ); + entries = file.entries ?? []; + } catch (e) { + const errorStatus: ErrorMsg = { + status: "Cannot Read Directory", + text: `${e}`, + }; + globalStore.set(model.errorMsgAtom, errorStatus); + } + setUnfilteredData(entries); }; getContent(); }, [conn, dirPath, refreshVersion]); @@ -864,7 +819,7 @@ function DirectoryPreview({ model }: DirectoryPreviewProps) { if ( checkKeyPressed(waveEvent, "Space") && searchText == "" && - PLATFORM == "darwin" && + PLATFORM == PlatformMacOS && !blockData?.meta?.connection ) { getApi().onQuicklook(selectedPath); @@ -1023,29 +978,7 @@ function DirectoryPreview({ model }: DirectoryPreviewProps) { type: "separator", }, ]; - if (!conn) { - // TODO: resolve correct host path if connection is WSL - menu.push({ - label: makeNativeLabel(PLATFORM, true, true), - click: () => { - getApi().openNativePath(dirPath); - }, - }); - } - menu.push({ - label: "Open Terminal in New Block", - click: async () => { - const termBlockDef: BlockDef = { - meta: { - controller: "shell", - view: "term", - "cmd:cwd": dirPath, - connection: conn, - }, - }; - await createBlock(termBlockDef); - }, - }); + addOpenMenuItems(menu, conn, finfo); ContextMenuModel.showContextMenu(menu, e); }, diff --git a/frontend/app/view/preview/preview.tsx b/frontend/app/view/preview/preview.tsx index afdc8cbe22..27896ccce3 100644 --- a/frontend/app/view/preview/preview.tsx +++ b/frontend/app/view/preview/preview.tsx @@ -15,13 +15,10 @@ import { CodeEditor } from "@/app/view/codeeditor/codeeditor"; import { Markdown } from "@/element/markdown"; import { atoms, - createBlock, - getApi, getConnStatusAtom, getOverrideConfigAtom, getSettingsKeyAtom, globalStore, - PLATFORM, refocusNode, } from "@/store/global"; import * as services from "@/store/services"; @@ -29,15 +26,8 @@ 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, - makeNativeLabel, - stringToBase64, -} from "@/util/util"; +import { addOpenMenuItems } from "@/util/previewutil"; +import { base64ToString, fireAndForget, isBlank, jotaiLoadableValue, makeConnRoute, stringToBase64 } from "@/util/util"; import { formatRemoteUri } from "@/util/waveutil"; import { Monaco } from "@monaco-editor/react"; import clsx from "clsx"; @@ -434,13 +424,20 @@ export class PreviewModel implements ViewModel { if (fileName == null) { return null; } - console.log("full file path", path); - const file = await RpcApi.FileReadCommand(TabRpcClient, { - info: { - path, - }, - }); - console.log("full file", file); + let file: FileData; + try { + file = await RpcApi.FileReadCommand(TabRpcClient, { + info: { + path, + }, + }); + } catch (e) { + const errorStatus: ErrorMsg = { + status: "File Read Failed", + text: `${e}`, + }; + globalStore.set(this.errorMsgAtom, errorStatus); + } return file; }); @@ -593,7 +590,6 @@ export class PreviewModel implements ViewModel { path: await this.formatRemoteUri(fileInfo.dir, globalStore.get), }, }); - console.log("parent file info", parentFileInfo); return parentFileInfo; } catch { return undefined; @@ -680,8 +676,12 @@ export class PreviewModel implements ViewModel { globalStore.set(this.fileContent, newFileContent); globalStore.set(this.newFileContent, null); console.log("saved file", filePath); - } catch (error) { - console.error("Error saving file:", error); + } catch (e) { + const errorStatus: ErrorMsg = { + status: "Save Failed", + text: `${e}`, + }; + globalStore.set(this.errorMsgAtom, errorStatus); } } @@ -742,47 +742,8 @@ export class PreviewModel implements ViewModel { await navigator.clipboard.writeText(fileInfo.name); }), }); - const mimeType = jotaiLoadableValue(globalStore.get(this.fileMimeTypeLoadable), ""); - if (mimeType == "directory") { - menuItems.push({ - 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.path, - 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.path); - }, - }); - } - } 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.path); - }, - }); - } - } + const finfo = jotaiLoadableValue(globalStore.get(this.loadableFileInfo), null); + addOpenMenuItems(menuItems, globalStore.get(this.connectionImmediate), finfo); const loadableSV = globalStore.get(this.loadableSpecializedView); const wordWrapAtom = getOverrideConfigAtom(this.blockId, "editor:wordwrap"); const wordWrap = globalStore.get(wordWrapAtom) ?? false; diff --git a/frontend/app/view/term/termwrap.ts b/frontend/app/view/term/termwrap.ts index 46089c4aa7..370312b090 100644 --- a/frontend/app/view/term/termwrap.ts +++ b/frontend/app/view/term/termwrap.ts @@ -5,8 +5,9 @@ import { getFileSubject } from "@/app/store/wps"; import { sendWSCommand } from "@/app/store/ws"; import { RpcApi } from "@/app/store/wshclientapi"; import { TabRpcClient } from "@/app/store/wshrpcutil"; -import { PLATFORM, WOS, atoms, fetchWaveFile, getSettingsKeyAtom, globalStore, openLink } from "@/store/global"; +import { WOS, atoms, fetchWaveFile, getSettingsKeyAtom, globalStore, openLink } from "@/store/global"; import * as services from "@/store/services"; +import { PLATFORM, PlatformMacOS } from "@/util/platformutil"; import { base64ToArray, fireAndForget } from "@/util/util"; import { SearchAddon } from "@xterm/addon-search"; import { SerializeAddon } from "@xterm/addon-serialize"; @@ -166,7 +167,7 @@ export class TermWrap { this.hasResized = false; this.terminal = new Terminal(options); this.fitAddon = new FitAddon(); - this.fitAddon.noScrollbar = PLATFORM == "darwin"; + this.fitAddon.noScrollbar = PLATFORM === PlatformMacOS; this.serializeAddon = new SerializeAddon(); this.searchAddon = new SearchAddon(); this.terminal.loadAddon(this.searchAddon); @@ -176,7 +177,7 @@ export class TermWrap { new WebLinksAddon((e, uri) => { e.preventDefault(); switch (PLATFORM) { - case "darwin": + case PlatformMacOS: if (e.metaKey) { fireAndForget(() => openLink(uri)); } diff --git a/frontend/app/view/vdom/vdom-model.tsx b/frontend/app/view/vdom/vdom-model.tsx index 5c07799f30..745d808ee8 100644 --- a/frontend/app/view/vdom/vdom-model.tsx +++ b/frontend/app/view/vdom/vdom-model.tsx @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 import { BlockNodeModel } from "@/app/block/blocktypes"; -import { getBlockMetaKeyAtom, globalStore, PLATFORM, WOS } from "@/app/store/global"; +import { getBlockMetaKeyAtom, globalStore, WOS } from "@/app/store/global"; import { makeORef } from "@/app/store/wos"; import { waveEventSubscribe } from "@/app/store/wps"; import { RpcResponseHelper, WshClient } from "@/app/store/wshclient"; @@ -13,6 +13,7 @@ import { VDomView } from "@/app/view/vdom/vdom"; import { applyCanvasOp, mergeBackendUpdates, restoreVDomElems } from "@/app/view/vdom/vdom-utils"; import { getWebServerEndpoint } from "@/util/endpoints"; import { adaptFromReactOrNativeKeyEvent, checkKeyPressed } from "@/util/keyutil"; +import { PLATFORM, PlatformMacOS } from "@/util/platformutil"; import debug from "debug"; import * as jotai from "jotai"; @@ -73,7 +74,7 @@ function annotateEvent(event: VDomEvent, propName: string, reactEvent: React.Syn movementx: mouseEvent.movementX, movementy: mouseEvent.movementY, }; - if (PLATFORM == "darwin") { + if (PLATFORM == PlatformMacOS) { event.mousedata.cmd = event.mousedata.meta; event.mousedata.option = event.mousedata.alt; } else { diff --git a/frontend/util/platformutil.ts b/frontend/util/platformutil.ts new file mode 100644 index 0000000000..e2db630678 --- /dev/null +++ b/frontend/util/platformutil.ts @@ -0,0 +1,27 @@ +export const PlatformMacOS = "darwin"; +export let PLATFORM: NodeJS.Platform = PlatformMacOS; + +export function setPlatform(platform: NodeJS.Platform) { + PLATFORM = platform; +} + +export function makeNativeLabel(isDirectory: boolean) { + let managerName: string; + if (!isDirectory) { + managerName = "Default Application"; + } else if (PLATFORM === PlatformMacOS) { + managerName = "Finder"; + } else if (PLATFORM == "win32") { + managerName = "Explorer"; + } else { + managerName = "File Manager"; + } + + let fileAction: string; + if (isDirectory) { + fileAction = "Reveal"; + } else { + fileAction = "Open File"; + } + return `${fileAction} in ${managerName}`; +} diff --git a/frontend/util/previewutil.ts b/frontend/util/previewutil.ts new file mode 100644 index 0000000000..e730f588d6 --- /dev/null +++ b/frontend/util/previewutil.ts @@ -0,0 +1,77 @@ +import { createBlock, getApi } from "@/app/store/global"; +import { makeNativeLabel } from "./platformutil"; +import { fireAndForget } from "./util"; +import { formatRemoteUri } from "./waveutil"; + +export function addOpenMenuItems(menu: ContextMenuItem[], conn: string, finfo: FileInfo): ContextMenuItem[] { + if (!finfo) { + return menu; + } + menu.push({ + type: "separator", + }); + if (!conn) { + // TODO: resolve correct host path if connection is WSL + // if the entry is a directory, reveal it in the file manager, if the entry is a file, reveal its parent directory + menu.push({ + label: makeNativeLabel(true), + click: () => { + getApi().openNativePath(finfo.isdir ? finfo.path : finfo.dir); + }, + }); + // if the entry is a file, open it in the default application + if (!finfo.isdir) { + menu.push({ + label: makeNativeLabel(false), + click: () => { + getApi().openNativePath(finfo.path); + }, + }); + } + } else { + menu.push({ + label: "Download File", + click: () => { + const remoteUri = formatRemoteUri(finfo.path, conn); + getApi().downloadFile(remoteUri); + }, + }); + } + menu.push({ + type: "separator", + }); + if (!finfo.isdir) { + menu.push({ + label: "Open Preview in New Block", + click: () => + fireAndForget(async () => { + const blockDef: BlockDef = { + meta: { + view: "preview", + file: finfo.path, + connection: conn, + }, + }; + await createBlock(blockDef); + }), + }); + } + // TODO: improve behavior as we add more connection types + if (!conn?.startsWith("aws:")) { + menu.push({ + label: "Open Terminal in New Block", + click: () => { + const termBlockDef: BlockDef = { + meta: { + controller: "shell", + view: "term", + "cmd:cwd": finfo.isdir ? finfo.path : finfo.dir, + connection: conn, + }, + }; + fireAndForget(() => createBlock(termBlockDef)); + }, + }); + } + return menu; +} diff --git a/frontend/util/util.ts b/frontend/util/util.ts index 04b581521a..34391f979c 100644 --- a/frontend/util/util.ts +++ b/frontend/util/util.ts @@ -306,29 +306,6 @@ function sleep(ms: number): Promise { 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}`; -} - function mergeMeta(meta: MetaType, metaUpdate: MetaType, prefix?: string): MetaType { const rtn: MetaType = {}; @@ -419,7 +396,6 @@ export { makeConnRoute, makeExternLink, makeIconClass, - makeNativeLabel, mergeMeta, sleep, stringToBase64,