44 */
55import type { Node , View } from '@nextcloud/files'
66import { FileAction , FileType , DefaultType } from '@nextcloud/files'
7+ import { showError } from '@nextcloud/dialogs'
78import { t } from '@nextcloud/l10n'
8- import { isDownloadable } from '../utils/permissions '
9+ import axios from '@nextcloud/axios '
910
1011import ArrowDownSvg from '@mdi/svg/svg/arrow-down.svg?raw'
1112
13+ import { isDownloadable } from '../utils/permissions'
14+ import { usePathsStore } from '../store/paths'
15+ import { getPinia } from '../store'
16+ import { useFilesStore } from '../store/files'
17+ import { emit } from '@nextcloud/event-bus'
18+
1219/**
1320 * Trigger downloading a file.
1421 *
1522 * @param url The url of the asset to download
1623 * @param name Optionally the recommended name of the download (browsers might ignore it)
1724 */
18- function triggerDownload ( url : string , name ?: string ) {
25+ async function triggerDownload ( url : string , name ?: string ) {
26+ // try to see if the resource is still available
27+ await axios . head ( url )
28+
1929 const hiddenElement = document . createElement ( 'a' )
2030 hiddenElement . download = name ?? ''
2131 hiddenElement . href = url
@@ -44,12 +54,22 @@ function longestCommonPath(first: string, second: string): string {
4454 return base
4555}
4656
47- const downloadNodes = function ( nodes : Node [ ] ) {
57+
58+ /**
59+ * Download the given nodes.
60+ *
61+ * If only one node is given, it will be downloaded directly.
62+ * If multiple nodes are given, they will be zipped and downloaded.
63+ *
64+ * @param nodes The node(s) to download
65+ */
66+ async function downloadNodes ( nodes : Node [ ] ) {
4867 let url : URL
4968
5069 if ( nodes . length === 1 ) {
5170 if ( nodes [ 0 ] . type === FileType . File ) {
52- return triggerDownload ( nodes [ 0 ] . encodedSource , nodes [ 0 ] . displayname )
71+ await triggerDownload ( nodes [ 0 ] . encodedSource , nodes [ 0 ] . displayname )
72+ return
5373 } else {
5474 url = new URL ( nodes [ 0 ] . encodedSource )
5575 url . searchParams . append ( 'accept' , 'zip' )
@@ -72,7 +92,21 @@ const downloadNodes = function(nodes: Node[]) {
7292 url . pathname = `${ url . pathname } /`
7393 }
7494
75- return triggerDownload ( url . href )
95+ await triggerDownload ( url . href )
96+ }
97+
98+ function getCurrentDirectory ( view : View , directory : string ) : ?Node {
99+ const filesStore = useFilesStore ( getPinia ( ) )
100+ const pathsStore = usePathsStore ( getPinia ( ) )
101+ if ( ! view ?. id ) {
102+ return null
103+ }
104+
105+ if ( directory === '/' ) {
106+ return filesStore . getRoot ( view . id ) || null
107+ }
108+ const fileId = pathsStore . getPath ( view . id , directory ) !
109+ return filesStore . getNode ( fileId ) || null
76110}
77111
78112export const action = new FileAction ( {
@@ -100,13 +134,27 @@ export const action = new FileAction({
100134 return nodes . every ( isDownloadable )
101135 } ,
102136
103- async exec ( node : Node ) {
104- downloadNodes ( [ node ] )
137+ async exec ( node : Node , view : View , dir : string ) {
138+ try {
139+ await downloadNodes ( [ node ] )
140+ } catch ( e ) {
141+ showError ( t ( 'files' , 'The requested file is not available.' ) )
142+ // Try to reload the current directory to update the view
143+ const directory = getCurrentDirectory ( view , dir ) !
144+ emit ( 'files:node:updated' , directory )
145+ }
105146 return null
106147 } ,
107148
108- async execBatch ( nodes : Node [ ] ) {
109- downloadNodes ( nodes )
149+ async execBatch ( nodes : Node [ ] , view : View , dir : string ) {
150+ try {
151+ await downloadNodes ( nodes )
152+ } catch ( e ) {
153+ showError ( t ( 'files' , 'The requested files are not available.' ) )
154+ // Try to reload the current directory to update the view
155+ const directory = getCurrentDirectory ( view , dir ) !
156+ emit ( 'files:node:updated' , directory )
157+ }
110158 return new Array ( nodes . length ) . fill ( null )
111159 } ,
112160
0 commit comments