aboutsummaryrefslogtreecommitdiffstats
path: root/apps/files/src/actions/editLocallyAction.ts
blob: 2471eaf40a55c70bf436ebc9689df4e4717690a9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
/**
 * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
 * SPDX-License-Identifier: AGPL-3.0-or-later
 */
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, 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'
import { isPublicShare } from '@nextcloud/sharing/public'

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'

	try {
		const result = await axios.post(link, { path })
		const uid = getCurrentUser()?.uid
		let url = `nc://open/${uid}@` + window.location.host + encodePath(path)
		url += '?token=' + result.data.ocs.data.token

		window.location.href = url
	} catch (error) {
		showError(t('files', 'Failed to redirect to client'))
	}
}

export const action = new FileAction({
	id: 'edit-locally',
	displayName: () => t('files', 'Edit locally'),
	iconSvgInline: () => LaptopSvg,

	// Only works on single files
	enabled(nodes: Node[]) {
		// Only works on single node
		if (nodes.length !== 1) {
			return false
		}

		// does not work with shares
		if (isPublicShare()) {
			return false
		}

		return (nodes[0].permissions & Permission.UPDATE) !== 0
	},

	async exec(node: Node) {
		attemptOpenLocalClient(node.path)
		return null
	},

	order: 25,
})