feat(desktop): open workspace files with system app

This commit is contained in:
m4
2026-09-27 17:32:11 +08:00
parent 3272102fe9
commit 226350cd04
2 changed files with 59 additions and 0 deletions
@@ -0,0 +1,50 @@
import { cleanup, fireEvent, render, screen } from '@testing-library/react'
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import { I18nProvider } from '@/i18n'
const { openFileWithSystemApp } = vi.hoisted(() => ({ openFileWithSystemApp: vi.fn() }))
vi.mock('@/lib/desktop-fs', () => ({ isDesktopFsRemoteMode: () => false }))
vi.mock('@/lib/office-files', () => ({ openFileWithSystemApp }))
import { FileEntryContextMenu } from './file-actions'
function renderMenu(isDirectory = false) {
return render(
<I18nProvider configClient={null} initialLocale="zh">
<FileEntryContextMenu
isDirectory={isDirectory}
name={isDirectory ? 'src' : 'notes.md'}
path={`/w/${isDirectory ? 'src' : 'notes.md'}`}
>
<button type="button">Row</button>
</FileEntryContextMenu>
</I18nProvider>
)
}
beforeEach(() => {
openFileWithSystemApp.mockReset().mockResolvedValue(true)
})
afterEach(cleanup)
describe('FileEntryContextMenu system open action', () => {
it('opens files with the system app', async () => {
renderMenu()
fireEvent.contextMenu(screen.getByRole('button', { name: 'Row' }))
fireEvent.click(await screen.findByRole('menuitem', { name: '用系统应用打开' }))
expect(openFileWithSystemApp).toHaveBeenCalledWith('/w/notes.md')
})
it('does not offer system open for directories', () => {
renderMenu(true)
fireEvent.contextMenu(screen.getByRole('button', { name: 'Row' }))
expect(screen.queryByRole('menuitem', { name: '用系统应用打开' })).toBeNull()
})
})
@@ -13,6 +13,7 @@ import { translateNow, useI18n } from '@/i18n'
import { isDesktopFsRemoteMode } from '@/lib/desktop-fs' import { isDesktopFsRemoteMode } from '@/lib/desktop-fs'
import { isSubmitEnter } from '@/lib/ime' import { isSubmitEnter } from '@/lib/ime'
import { IS_MAC } from '@/lib/keybinds/combo' import { IS_MAC } from '@/lib/keybinds/combo'
import { openFileWithSystemApp } from '@/lib/office-files'
import { cn } from '@/lib/utils' import { cn } from '@/lib/utils'
import { import {
$fileActionDialog, $fileActionDialog,
@@ -73,6 +74,14 @@ export function FileEntryContextMenu({ children, isDirectory, name, path, relati
{/* Don't restore focus to the row on close: "Rename" mounts an autofocused {/* Don't restore focus to the row on close: "Rename" mounts an autofocused
inline input, and the default focus-return would blur it immediately. */} inline input, and the default focus-return would blur it immediately. */}
<ContextMenuContent onCloseAutoFocus={event => event.preventDefault()}> <ContextMenuContent onCloseAutoFocus={event => event.preventDefault()}>
{!isDirectory && (
<>
<ContextMenuItem onSelect={() => void openFileWithSystemApp(path)}>
{t.preview.openWithSystemApp}
</ContextMenuItem>
<ContextMenuSeparator />
</>
)}
{localFs && ( {localFs && (
<> <>
<ContextMenuItem onSelect={() => void revealFile(path)}>{revealLabel}</ContextMenuItem> <ContextMenuItem onSelect={() => void revealFile(path)}>{revealLabel}</ContextMenuItem>