From d9f9a7280e94064ded03bbfc7cb9331380c9b185 Mon Sep 17 00:00:00 2001 From: John Molakvoæ Date: Wed, 24 May 2023 17:20:35 +0200 Subject: fix(files): make open folder a default action MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: John Molakvoæ --- apps/files/src/actions/openFolderAction.ts | 69 ++++++++++++++++++++++++++++++ apps/files/src/components/FileEntry.vue | 33 +++++++------- apps/files/src/main.ts | 1 + 3 files changed, 87 insertions(+), 16 deletions(-) create mode 100644 apps/files/src/actions/openFolderAction.ts (limited to 'apps/files') diff --git a/apps/files/src/actions/openFolderAction.ts b/apps/files/src/actions/openFolderAction.ts new file mode 100644 index 00000000000..cc2c0825bd4 --- /dev/null +++ b/apps/files/src/actions/openFolderAction.ts @@ -0,0 +1,69 @@ +/** + * @copyright Copyright (c) 2023 John Molakvoæ + * + * @author John Molakvoæ + * + * @license AGPL-3.0-or-later + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ +import { Permission, Node, FileType } from '@nextcloud/files' +import { translate as t } from '@nextcloud/l10n' +import Folder from '@mdi/svg/svg/folder.svg?raw' + +import type { Navigation } from '../services/Navigation' +import { join } from 'path' +import { registerFileAction, FileAction } from '../services/FileAction' + +registerFileAction(new FileAction({ + id: 'open-folder', + displayName(files: Node[]) { + // Only works on single node + const displayName = files[0].attributes.displayName || files[0].basename + return t('files', 'Open folder {displayName}', { displayName }) + }, + iconSvgInline: () => Folder, + + enabled(nodes: Node[]) { + // Only works on single node + if (nodes.length !== 1) { + return false + } + + const node = nodes[0] + return node.type === FileType.Folder + && (node.permissions & Permission.READ) !== 0 + }, + + async exec(node: Node, view: Navigation, dir: string) { + if (!node || node.type !== FileType.Folder) { + return false + } + + window.OCP.Files.Router.goToRoute( + null, + null, + { dir: join(dir, node.basename) }, + ) + return null + }, + async execBatch(nodes: Node[], view: Navigation, dir: string) { + return Promise.all(nodes.map(node => this.exec(node, view, dir))) + }, + + // Main action if enabled, meaning folders only + order: -100, + default: true, +})) diff --git a/apps/files/src/components/FileEntry.vue b/apps/files/src/components/FileEntry.vue index 8dc067a407d..fd61f5e3623 100644 --- a/apps/files/src/components/FileEntry.vue +++ b/apps/files/src/components/FileEntry.vue @@ -33,7 +33,7 @@ - + @@ -261,7 +261,22 @@ export default Vue.extend({ return minOpacity + (1 - minOpacity) * Math.pow((this.source.size / maxOpacitySize), 2) }, - linkTo() { + linkAttrs() { + if (this.enabledDefaultActions.length > 0) { + const action = this.enabledDefaultActions[0] + const displayName = action.displayName([this.source], this.currentView) + return { + class: ['files-list__row-default-action', 'files-list__row-action-' + action.id], + role: 'button', + title: displayName, + } + } + + /** + * A folder would never reach this point + * as it has open-folder as default action. + * Just to be safe, let's handle it. + */ if (this.source.type === 'folder') { const to = { ...this.$route, query: { dir: join(this.dir, this.source.basename) } } return { @@ -271,15 +286,6 @@ export default Vue.extend({ } } - if (this.enabledDefaultActions.length > 0) { - const action = this.enabledDefaultActions[0] - const displayName = action.displayName([this.source], this.currentView) - return { - title: displayName, - role: 'button', - } - } - return { href: this.source.source, // TODO: Use first action title ? @@ -526,11 +532,6 @@ export default Vue.extend({ } }, execDefaultAction(event) { - // Do not execute the default action on the folder, navigate instead - if (this.source.type === 'folder') { - return - } - if (this.enabledDefaultActions.length > 0) { event.preventDefault() event.stopPropagation() diff --git a/apps/files/src/main.ts b/apps/files/src/main.ts index 195357d0e0a..1d96c2f6eaa 100644 --- a/apps/files/src/main.ts +++ b/apps/files/src/main.ts @@ -1,6 +1,7 @@ import './templates.js' import './legacy/filelistSearch.js' import './actions/deleteAction' +import './actions/openFolderAction' import './actions/sidebarAction' import Vue from 'vue' -- cgit v1.2.3