66import type { PropType } from 'vue'
77import type { FileSource } from '../types.ts'
88
9- import { FileType , Folder , getFileActions , File as NcFile , Node , NodeStatus , Permission } from '@nextcloud/files'
9+ import { openConflictPicker } from '@nextcloud/dialogs'
10+ import { FileType , Folder , getFileActions , File as NcFile , Node , NodeStatus , Permission , type View } from '@nextcloud/files'
1011import { t } from '@nextcloud/l10n'
1112import { extname } from '@nextcloud/paths'
1213import { isPublicShare } from '@nextcloud/sharing/public'
1314import { generateUrl } from '@nextcloud/router'
1415import { vOnClickOutside } from '@vueuse/components'
16+ import { dataTransferToFileTree , onDropExternalFiles , onDropInternalFiles } from '../services/DropService.ts'
17+ import { relative } from 'path'
18+ import { storeToRefs } from 'pinia'
1519import Vue , { computed , defineComponent } from 'vue'
16-
1720import { action as sidebarAction } from '../actions/sidebarAction.ts'
18- import { dataTransferToFileTree , onDropExternalFiles , onDropInternalFiles } from '../services/DropService.ts'
21+ import { onDropInternalFiles } from '../services/DropService.ts'
22+ import { useActiveStore } from '../store/active.ts'
1923import { getDragAndDropPreview } from '../utils/dragUtils.ts'
2024import { hashCode } from '../utils/hashUtils.ts'
2125import { isDownloadable } from '../utils/permissions.ts'
@@ -56,6 +60,14 @@ export default defineComponent({
5660 }
5761 } ,
5862
63+ setup ( ) {
64+ const { activeView } = storeToRefs ( useActiveStore ( ) )
65+
66+ return {
67+ activeView,
68+ }
69+ } ,
70+
5971 data ( ) {
6072 return {
6173 dragover : false ,
@@ -125,6 +137,12 @@ export default defineComponent({
125137 return String ( this . fileid ) === String ( this . currentFileId )
126138 } ,
127139
140+ isSourceFolder ( ) : boolean {
141+ return this . source . type === FileType . Folder
142+ || this . source . type === 'folder'
143+ || this . source . mime === 'httpd/unix-directory'
144+ } ,
145+
128146 /**
129147 * Check if the source is in a failed state after an API request
130148 */
@@ -226,6 +244,10 @@ export default defineComponent({
226244 }
227245 } ,
228246
247+ fileActionView ( ) : View {
248+ return this . activeView ?? this . currentView
249+ } ,
250+
229251 /**
230252 * Sorted actions that are enabled for this node
231253 */
@@ -243,7 +265,7 @@ export default defineComponent({
243265 // In case something goes wrong, since we don't want to break
244266 // the entire list, we filter out actions that throw an error.
245267 try {
246- return action . enabled ( [ this . source ] , this . currentView )
268+ return action . enabled ( [ this . source ] , this . fileActionView )
247269 } catch ( error ) {
248270 logger . error ( 'Error while checking action' , { action, error } )
249271 return false
@@ -253,7 +275,14 @@ export default defineComponent({
253275 } ,
254276
255277 defaultFileAction ( ) {
256- return this . enabledFileActions . find ( ( action ) => action . default !== undefined )
278+ const defaultAction = this . enabledFileActions . find ( ( action ) => action . default !== undefined )
279+
280+ // Folders must open, not download
281+ if ( this . isSourceFolder && defaultAction ?. id === 'download' ) {
282+ return this . enabledFileActions . find ( ( action ) => action . id === 'open-folder' ) ?? defaultAction
283+ }
284+
285+ return defaultAction
257286 } ,
258287 } ,
259288
@@ -298,6 +327,21 @@ export default defineComponent({
298327 this . openedMenu = false
299328 } ,
300329
330+ openFolderNode ( ) : boolean {
331+ const view = this . fileActionView
332+ if ( ! view ?. id || ! this . source . fileid ) {
333+ logger . warn ( 'Cannot open folder, missing view or fileid' , { view, source : this . source } )
334+ return false
335+ }
336+
337+ window . OCP . Files . Router . goToRoute (
338+ null ,
339+ { view : view . id , fileid : String ( this . source . fileid ) } ,
340+ { dir : this . source . path } ,
341+ )
342+ return true
343+ } ,
344+
301345 // Open the actions menu on right click
302346 onRightClick ( event ) {
303347 // If already opened, fallback to default browser
@@ -356,6 +400,15 @@ export default defineComponent({
356400 // if ctrl+click / cmd+click (MacOS uses the meta key) or middle mouse button (button & 4), open in new tab
357401 // also if there is no default action use this as a fallback
358402 const metaKeyPressed = event . ctrlKey || event . metaKey || event . button === 1
403+
404+ // Folders must navigate in the files app, never download
405+ if ( ! metaKeyPressed && this . isSourceFolder ) {
406+ event . preventDefault ( )
407+ event . stopPropagation ( )
408+ this . openFolderNode ( )
409+ return
410+ }
411+
359412 if ( metaKeyPressed || ! this . defaultFileAction ) {
360413 // If no download permission, then we can not allow to download (direct link) the files
361414 if ( ! isDownloadable ( this . source ) ) {
@@ -377,14 +430,14 @@ export default defineComponent({
377430 event . preventDefault ( )
378431 event . stopPropagation ( )
379432 // Execute the first default action if any
380- this . defaultFileAction . exec ( this . source , this . currentView , this . currentDir )
433+ this . defaultFileAction . exec ( this . source , this . fileActionView , this . currentDir )
381434 } ,
382435
383436 openDetailsIfAvailable ( event ) {
384437 event . preventDefault ( )
385438 event . stopPropagation ( )
386- if ( sidebarAction ?. enabled ?.( [ this . source ] , this . currentView ) ) {
387- sidebarAction . exec ( this . source , this . currentView , this . currentDir )
439+ if ( sidebarAction ?. enabled ?.( [ this . source ] , this . fileActionView ) ) {
440+ sidebarAction . exec ( this . source , this . fileActionView , this . currentDir )
388441 }
389442 } ,
390443
0 commit comments