mirror of
https://github.com/nextcloud/server.git
synced 2026-06-07 07:43:18 -04:00
Merge pull request #46909 from nextcloud/backport/46452/stable28
[stable28] feat(editLocallyAction): Handle possible no local client scenario
This commit is contained in:
commit
656828a8bb
14 changed files with 110 additions and 30 deletions
|
|
@ -22,14 +22,35 @@
|
|||
import { action } from './editLocallyAction'
|
||||
import { expect } from '@jest/globals'
|
||||
import { File, Permission, View, FileAction } from '@nextcloud/files'
|
||||
import * as ncDialogs from '@nextcloud/dialogs'
|
||||
import { DialogBuilder, showError } from '@nextcloud/dialogs'
|
||||
import axios from '@nextcloud/axios'
|
||||
|
||||
const dialogBuilder = {
|
||||
setName: jest.fn().mockReturnThis(),
|
||||
setText: jest.fn().mockReturnThis(),
|
||||
setButtons: jest.fn().mockReturnThis(),
|
||||
build: jest.fn().mockReturnValue({
|
||||
show: jest.fn().mockResolvedValue(true),
|
||||
}),
|
||||
} as unknown as DialogBuilder
|
||||
|
||||
jest.mock('@nextcloud/dialogs', () => ({
|
||||
DialogBuilder: jest.fn(() => dialogBuilder),
|
||||
showError: jest.fn(),
|
||||
}))
|
||||
|
||||
const view = {
|
||||
id: 'files',
|
||||
name: 'Files',
|
||||
} as View
|
||||
|
||||
// Mock webroot variable
|
||||
beforeAll(() => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
(window as any)._oc_webroot = '';
|
||||
(window as any).OCA = { Viewer: { open: jest.fn() } }
|
||||
})
|
||||
|
||||
describe('Edit locally action conditions tests', () => {
|
||||
test('Default values', () => {
|
||||
expect(action).toBeInstanceOf(FileAction)
|
||||
|
|
@ -55,7 +76,7 @@ describe('Edit locally action enabled tests', () => {
|
|||
expect(action.enabled!([file], view)).toBe(true)
|
||||
})
|
||||
|
||||
test('Disabled for non-dav ressources', () => {
|
||||
test('Disabled for non-dav resources', () => {
|
||||
const file = new File({
|
||||
id: 1,
|
||||
source: 'https://domain.com/data/foobar.txt',
|
||||
|
|
@ -115,8 +136,11 @@ describe('Edit locally action enabled tests', () => {
|
|||
|
||||
describe('Edit locally action execute tests', () => {
|
||||
test('Edit locally opens proper URL', async () => {
|
||||
jest.spyOn(axios, 'post').mockImplementation(async () => ({ data: { ocs: { data: { token: 'foobar' } } } }))
|
||||
jest.spyOn(ncDialogs, 'showError')
|
||||
jest.spyOn(axios, 'post').mockImplementation(async () => ({
|
||||
data: { ocs: { data: { token: 'foobar' } } }
|
||||
}))
|
||||
const mockedShowError = jest.mocked(showError)
|
||||
const spyDialogBuilder = jest.spyOn(dialogBuilder, 'build')
|
||||
|
||||
const file = new File({
|
||||
id: 1,
|
||||
|
|
@ -128,17 +152,20 @@ describe('Edit locally action execute tests', () => {
|
|||
|
||||
const exec = await action.exec(file, view, '/')
|
||||
|
||||
expect(spyDialogBuilder).toBeCalled()
|
||||
|
||||
// Silent action
|
||||
expect(exec).toBe(null)
|
||||
expect(axios.post).toBeCalledTimes(1)
|
||||
expect(axios.post).toBeCalledWith('http://localhost/ocs/v2.php/apps/files/api/v1/openlocaleditor?format=json', { path: '/foobar.txt' })
|
||||
expect(ncDialogs.showError).toBeCalledTimes(0)
|
||||
expect(mockedShowError).toBeCalledTimes(0)
|
||||
expect(window.location.href).toBe('nc://open/test@localhost/foobar.txt?token=foobar')
|
||||
})
|
||||
|
||||
test('Edit locally fails and show error', async () => {
|
||||
test('Edit locally fails and shows error', async () => {
|
||||
jest.spyOn(axios, 'post').mockImplementation(async () => ({}))
|
||||
jest.spyOn(ncDialogs, 'showError')
|
||||
const mockedShowError = jest.mocked(showError)
|
||||
const spyDialogBuilder = jest.spyOn(dialogBuilder, 'build')
|
||||
|
||||
const file = new File({
|
||||
id: 1,
|
||||
|
|
@ -150,12 +177,14 @@ describe('Edit locally action execute tests', () => {
|
|||
|
||||
const exec = await action.exec(file, view, '/')
|
||||
|
||||
expect(spyDialogBuilder).toBeCalled()
|
||||
|
||||
// Silent action
|
||||
expect(exec).toBe(null)
|
||||
expect(axios.post).toBeCalledTimes(1)
|
||||
expect(axios.post).toBeCalledWith('http://localhost/ocs/v2.php/apps/files/api/v1/openlocaleditor?format=json', { path: '/foobar.txt' })
|
||||
expect(ncDialogs.showError).toBeCalledTimes(1)
|
||||
expect(ncDialogs.showError).toBeCalledWith('Failed to redirect to client')
|
||||
expect(mockedShowError).toBeCalledTimes(1)
|
||||
expect(mockedShowError).toBeCalledWith('Failed to redirect to client')
|
||||
expect(window.location.href).toBe('http://localhost/')
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -23,11 +23,62 @@ import { encodePath } from '@nextcloud/paths'
|
|||
import { generateOcsUrl } from '@nextcloud/router'
|
||||
import { getCurrentUser } from '@nextcloud/auth'
|
||||
import { FileAction, Permission, type Node } from '@nextcloud/files'
|
||||
import { showError } from '@nextcloud/dialogs'
|
||||
import { showError, DialogBuilder } from '@nextcloud/dialogs'
|
||||
import { translate as t } from '@nextcloud/l10n'
|
||||
import axios from '@nextcloud/axios'
|
||||
|
||||
import LaptopSvg from '@mdi/svg/svg/laptop.svg?raw'
|
||||
import IconCancel from '@mdi/svg/svg/cancel.svg?raw'
|
||||
import IconCheck from '@mdi/svg/svg/check.svg?raw'
|
||||
|
||||
const confirmLocalEditDialog = (
|
||||
localEditCallback: (openingLocally: boolean) => void = () => {},
|
||||
) => {
|
||||
let callbackCalled = false
|
||||
|
||||
return (new DialogBuilder())
|
||||
.setName(t('files', 'Edit file locally'))
|
||||
.setText(t('files', 'The file should now open locally. If you don\'t see this happening, make sure that the desktop client is installed on your system.'))
|
||||
.setButtons([
|
||||
{
|
||||
label: t('files', 'Retry local edit'),
|
||||
icon: IconCancel,
|
||||
callback: () => {
|
||||
callbackCalled = true
|
||||
localEditCallback(false)
|
||||
},
|
||||
},
|
||||
{
|
||||
label: t('files', 'Edit online'),
|
||||
icon: IconCheck,
|
||||
type: 'primary',
|
||||
callback: () => {
|
||||
callbackCalled = true
|
||||
localEditCallback(true)
|
||||
},
|
||||
},
|
||||
])
|
||||
.build()
|
||||
.show()
|
||||
.then(() => {
|
||||
// Ensure the callback is called even if the dialog is dismissed in other ways
|
||||
if (!callbackCalled) {
|
||||
localEditCallback(false)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const attemptOpenLocalClient = async (path: string) => {
|
||||
openLocalClient(path)
|
||||
confirmLocalEditDialog(
|
||||
(openLocally: boolean) => {
|
||||
if (!openLocally) {
|
||||
window.OCA.Viewer.open({ path })
|
||||
return
|
||||
}
|
||||
openLocalClient(path)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
const openLocalClient = async function(path: string) {
|
||||
const link = generateOcsUrl('apps/files/api/v1') + '/openlocaleditor?format=json'
|
||||
|
|
@ -60,7 +111,7 @@ export const action = new FileAction({
|
|||
},
|
||||
|
||||
async exec(node: Node) {
|
||||
openLocalClient(node.path)
|
||||
attemptOpenLocalClient(node.path)
|
||||
return null
|
||||
},
|
||||
|
||||
|
|
|
|||
4
dist/core-common.js
vendored
4
dist/core-common.js
vendored
File diff suppressed because one or more lines are too long
2
dist/core-common.js.map
vendored
2
dist/core-common.js.map
vendored
File diff suppressed because one or more lines are too long
4
dist/files-init.js
vendored
4
dist/files-init.js
vendored
File diff suppressed because one or more lines are too long
2
dist/files-init.js.map
vendored
2
dist/files-init.js.map
vendored
File diff suppressed because one or more lines are too long
4
dist/files_sharing-init.js
vendored
4
dist/files_sharing-init.js
vendored
File diff suppressed because one or more lines are too long
2
dist/files_sharing-init.js.map
vendored
2
dist/files_sharing-init.js.map
vendored
File diff suppressed because one or more lines are too long
4
dist/settings-apps-view-4529.js
vendored
4
dist/settings-apps-view-4529.js
vendored
File diff suppressed because one or more lines are too long
2
dist/settings-apps-view-4529.js.map
vendored
2
dist/settings-apps-view-4529.js.map
vendored
File diff suppressed because one or more lines are too long
4
dist/settings-users-3239.js
vendored
4
dist/settings-users-3239.js
vendored
File diff suppressed because one or more lines are too long
2
dist/settings-users-3239.js.map
vendored
2
dist/settings-users-3239.js.map
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Loading…
Reference in a new issue