From 2b726fa2dd1597b53159fbdf14936ee4cfbf4999 Mon Sep 17 00:00:00 2001
From: John Molakvoæ <skjnldsv@protonmail.com>
Date: Fri, 21 Apr 2023 15:33:08 +0200
Subject: fix(files): always force menu
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: John Molakvoæ <skjnldsv@protonmail.com>
---
 apps/files/src/components/FileEntry.vue | 1 +
 1 file changed, 1 insertion(+)

(limited to 'apps/files/src/components/FileEntry.vue')

diff --git a/apps/files/src/components/FileEntry.vue b/apps/files/src/components/FileEntry.vue
index 00ff8a3d533..c42327e8821 100644
--- a/apps/files/src/components/FileEntry.vue
+++ b/apps/files/src/components/FileEntry.vue
@@ -75,6 +75,7 @@
 				:container="boundariesElement"
 				:disabled="source._loading"
 				:force-title="true"
+				:force-menu="true"
 				:inline="enabledInlineActions.length"
 				:open.sync="openedMenu">
 				<NcActionButton v-for="action in enabledMenuActions"
-- 
cgit v1.2.3


From 6e29560475f328f3f2cfe908895287f9c095eadd Mon Sep 17 00:00:00 2001
From: John Molakvoæ <skjnldsv@protonmail.com>
Date: Fri, 21 Apr 2023 15:39:31 +0200
Subject: feat(files): add sidebar action
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: John Molakvoæ <skjnldsv@protonmail.com>
---
 apps/files/src/actions/sidebarAction.ts | 54 +++++++++++++++++++++++++++++++++
 apps/files/src/components/FileEntry.vue | 14 +++++++--
 apps/files/src/main.ts                  |  3 +-
 3 files changed, 68 insertions(+), 3 deletions(-)
 create mode 100644 apps/files/src/actions/sidebarAction.ts

(limited to 'apps/files/src/components/FileEntry.vue')

diff --git a/apps/files/src/actions/sidebarAction.ts b/apps/files/src/actions/sidebarAction.ts
new file mode 100644
index 00000000000..f56d3a9475f
--- /dev/null
+++ b/apps/files/src/actions/sidebarAction.ts
@@ -0,0 +1,54 @@
+/**
+ * @copyright Copyright (c) 2023 John Molakvoæ <skjnldsv@protonmail.com>
+ *
+ * @author John Molakvoæ <skjnldsv@protonmail.com>
+ *
+ * @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 <http://www.gnu.org/licenses/>.
+ *
+ */
+import { translate as t } from '@nextcloud/l10n'
+import InformationSvg from '@mdi/svg/svg/information-variant.svg?raw'
+import type { Node } from '@nextcloud/files'
+
+import { registerFileAction, FileAction } from '../services/FileAction.ts'
+import logger from '../logger.js'
+
+export const ACTION_DETAILS = 'details'
+
+registerFileAction(new FileAction({
+	id: ACTION_DETAILS,
+	displayName: () => t('files', 'Details'),
+	iconSvgInline: () => InformationSvg,
+
+	// Sidebar currently supports user folder only, /files/USER
+	enabled: (files: Node[]) => !!window?.OCA?.Files?.Sidebar
+		&& files.some(node => node.root?.startsWith('/files/')),
+
+	async exec(node: Node) {
+		try {
+			// TODO: migrate Sidebar to use a Node instead
+			window?.OCA?.Files?.Sidebar?.open?.(node.path)
+
+			return null
+		} catch (error) {
+			logger.error('Error while opening sidebar', { error })
+			return false
+		}
+	},
+
+	default: true,
+	order: -50,
+}))
diff --git a/apps/files/src/components/FileEntry.vue b/apps/files/src/components/FileEntry.vue
index c42327e8821..215a8fdbbc7 100644
--- a/apps/files/src/components/FileEntry.vue
+++ b/apps/files/src/components/FileEntry.vue
@@ -95,7 +95,7 @@
 		<td v-if="isSizeAvailable"
 			:style="{ opacity: sizeOpacity }"
 			class="files-list__row-size"
-			@click="execDefaultAction">
+			@click="openDetailsIfAvailable">
 			<span>{{ size }}</span>
 		</td>
 
@@ -104,7 +104,7 @@
 			:key="column.id"
 			:class="`files-list__row-${currentView?.id}-${column.id}`"
 			class="files-list__row-column-custom"
-			@click="execDefaultAction">
+			@click="openDetailsIfAvailable">
 			<CustomElementRender v-if="active"
 				:current-view="currentView"
 				:render="column.render"
@@ -130,6 +130,7 @@ import NcLoadingIcon from '@nextcloud/vue/dist/Components/NcLoadingIcon.js'
 import StarIcon from 'vue-material-design-icons/Star.vue'
 import Vue from 'vue'
 
+import { ACTION_DETAILS } from '../actions/sidebarAction.ts'
 import { getFileActions } from '../services/FileAction.ts'
 import { hashCode } from '../utils/hashUtils.ts'
 import { isCachedPreview } from '../services/PreviewService.ts'
@@ -532,6 +533,15 @@ export default Vue.extend({
 			}
 		},
 
+		openDetailsIfAvailable(event) {
+			const detailsAction = this.enabledDefaultActions.find(action => action.id === ACTION_DETAILS)
+			if (detailsAction) {
+				event.preventDefault()
+				event.stopPropagation()
+				detailsAction.exec(this.source, this.currentView)
+			}
+		},
+
 		onSelectionChange(selection) {
 			const newSelectedIndex = this.index
 			const lastSelectedIndex = this.selectionStore.lastSelectedIndex
diff --git a/apps/files/src/main.ts b/apps/files/src/main.ts
index 976714a8f1f..195357d0e0a 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/sidebarAction'
 
 import Vue from 'vue'
 import { createPinia, PiniaVuePlugin } from 'pinia'
@@ -11,9 +12,9 @@ import NavigationView from './views/Navigation.vue'
 import processLegacyFilesViews from './legacy/navigationMapper.js'
 import registerPreviewServiceWorker from './services/ServiceWorker.js'
 import router from './router/router.js'
+import RouterService from './services/RouterService'
 import SettingsModel from './models/Setting.js'
 import SettingsService from './services/Settings.js'
-import RouterService from './services/RouterService'
 
 declare global {
 	interface Window {
-- 
cgit v1.2.3


From 1de3666e16af8362789d7a000c93b9aea1229c12 Mon Sep 17 00:00:00 2001
From: John Molakvoæ <skjnldsv@protonmail.com>
Date: Fri, 21 Apr 2023 15:40:27 +0200
Subject: feat(files): add dir file action parameter
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: John Molakvoæ <skjnldsv@protonmail.com>
---
 apps/files/src/actions/deleteAction.ts               | 7 ++++---
 apps/files/src/components/FileEntry.vue              | 4 ++--
 apps/files/src/components/FilesListHeaderActions.vue | 6 +++++-
 apps/files/src/services/FileAction.ts                | 5 +++--
 4 files changed, 14 insertions(+), 8 deletions(-)

(limited to 'apps/files/src/components/FileEntry.vue')

diff --git a/apps/files/src/actions/deleteAction.ts b/apps/files/src/actions/deleteAction.ts
index 087884b3362..a633e477b1f 100644
--- a/apps/files/src/actions/deleteAction.ts
+++ b/apps/files/src/actions/deleteAction.ts
@@ -27,10 +27,11 @@ import TrashCan from '@mdi/svg/svg/trash-can.svg?raw'
 
 import { registerFileAction, FileAction } from '../services/FileAction.ts'
 import logger from '../logger.js'
+import type { Navigation } from '../services/Navigation.ts'
 
 registerFileAction(new FileAction({
 	id: 'delete',
-	displayName(nodes: Node[], view) {
+	displayName(nodes: Node[], view: Navigation) {
 		return view.id === 'trashbin'
 			? t('files_trashbin', 'Delete permanently')
 			: t('files', 'Delete')
@@ -57,8 +58,8 @@ registerFileAction(new FileAction({
 			return false
 		}
 	},
-	async execBatch(nodes: Node[], view) {
-		return Promise.all(nodes.map(node => this.exec(node, view)))
+	async execBatch(nodes: Node[], view: Navigation, dir: string) {
+		return Promise.all(nodes.map(node => this.exec(node, view, dir)))
 	},
 
 	order: 100,
diff --git a/apps/files/src/components/FileEntry.vue b/apps/files/src/components/FileEntry.vue
index 215a8fdbbc7..d4258f29861 100644
--- a/apps/files/src/components/FileEntry.vue
+++ b/apps/files/src/components/FileEntry.vue
@@ -503,7 +503,7 @@ export default Vue.extend({
 				this.loading = action.id
 				Vue.set(this.source, '_loading', true)
 
-				const success = await action.exec(this.source, this.currentView)
+				const success = await action.exec(this.source, this.currentView, this.dir)
 
 				// If the action returns null, we stay silent
 				if (success === null) {
@@ -529,7 +529,7 @@ export default Vue.extend({
 				event.preventDefault()
 				event.stopPropagation()
 				// Execute the first default action if any
-				this.enabledDefaultActions[0].exec(this.source, this.currentView)
+				this.enabledDefaultActions[0].exec(this.source, this.currentView, this.dir)
 			}
 		},
 
diff --git a/apps/files/src/components/FilesListHeaderActions.vue b/apps/files/src/components/FilesListHeaderActions.vue
index a53a1d041bf..f8c60a5cd1b 100644
--- a/apps/files/src/components/FilesListHeaderActions.vue
+++ b/apps/files/src/components/FilesListHeaderActions.vue
@@ -103,6 +103,10 @@ export default Vue.extend({
 	},
 
 	computed: {
+		dir() {
+			// Remove any trailing slash but leave root slash
+			return (this.$route?.query?.dir || '/').replace(/^(.+)\/$/, '$1')
+		},
 		enabledActions() {
 			return actions
 				.filter(action => action.execBatch)
@@ -165,7 +169,7 @@ export default Vue.extend({
 				})
 
 				// Dispatch action execution
-				const results = await action.execBatch(this.nodes, this.currentView)
+				const results = await action.execBatch(this.nodes, this.currentView, this.dir)
 
 				// Check if all actions returned null
 				if (!results.some(result => result !== null)) {
diff --git a/apps/files/src/services/FileAction.ts b/apps/files/src/services/FileAction.ts
index 94fc7e8ce5f..70d6405c804 100644
--- a/apps/files/src/services/FileAction.ts
+++ b/apps/files/src/services/FileAction.ts
@@ -22,6 +22,7 @@
 
 import type { Node } from '@nextcloud/files'
 import logger from '../logger'
+import type { Navigation } from './Navigation'
 
 declare global {
 	interface Window {
@@ -48,14 +49,14 @@ interface FileActionData {
 	 * @returns true if the action was executed, false otherwise
 	 * @throws Error if the action failed
 	 */
-	exec: (file: Node, view) => Promise<boolean|null>,
+	exec: (file: Node, view: Navigation, dir: string) => Promise<boolean|null>,
 	/**
 	 * Function executed on multiple files action
 	 * @returns true if the action was executed successfully,
 	 * false otherwise and null if the action is silent/undefined.
 	 * @throws Error if the action failed
 	 */
-	execBatch?: (files: Node[], view) => Promise<(boolean|null)[]>
+	execBatch?: (files: Node[], view: Navigation, dir: string) => Promise<(boolean|null)[]>
 	/** This action order in the list */
 	order?: number,
 	/** Make this action the default */
-- 
cgit v1.2.3


From 51f2f56b4bc9bd9883857563b9ada57bdb79ba2f Mon Sep 17 00:00:00 2001
From: John Molakvoæ <skjnldsv@protonmail.com>
Date: Fri, 21 Apr 2023 15:58:40 +0200
Subject: fix(files): do not execute the default action on folders
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: John Molakvoæ <skjnldsv@protonmail.com>
---
 apps/files/src/components/FileEntry.vue | 22 ++++++++++++++--------
 1 file changed, 14 insertions(+), 8 deletions(-)

(limited to 'apps/files/src/components/FileEntry.vue')

diff --git a/apps/files/src/components/FileEntry.vue b/apps/files/src/components/FileEntry.vue
index d4258f29861..8dc067a407d 100644
--- a/apps/files/src/components/FileEntry.vue
+++ b/apps/files/src/components/FileEntry.vue
@@ -262,6 +262,15 @@ export default Vue.extend({
 		},
 
 		linkTo() {
+			if (this.source.type === 'folder') {
+				const to = { ...this.$route, query: { dir: join(this.dir, this.source.basename) } }
+				return {
+					is: 'router-link',
+					title: this.t('files', 'Open folder {name}', { name: this.displayName }),
+					to,
+				}
+			}
+
 			if (this.enabledDefaultActions.length > 0) {
 				const action = this.enabledDefaultActions[0]
 				const displayName = action.displayName([this.source], this.currentView)
@@ -271,14 +280,6 @@ export default Vue.extend({
 				}
 			}
 
-			if (this.source.type === 'folder') {
-				const to = { ...this.$route, query: { dir: join(this.dir, this.source.basename) } }
-				return {
-					is: 'router-link',
-					title: this.t('files', 'Open folder {name}', { name: this.displayName }),
-					to,
-				}
-			}
 			return {
 				href: this.source.source,
 				// TODO: Use first action title ?
@@ -525,6 +526,11 @@ 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()
-- 
cgit v1.2.3

