summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohn Molakvoæ <skjnldsv@protonmail.com>2023-04-04 11:42:41 +0200
committerJohn Molakvoæ <skjnldsv@protonmail.com>2023-04-06 14:49:32 +0200
commitbdbe4773370aa9f29e4514fb9be73a9f2a033244 (patch)
tree84d00c776e5cfe0ae2d13c61de8a6c909ae18cf8
parent014a57e54174ce9a8f2c55beafad2dd8d1c6a9d0 (diff)
downloadnextcloud-server-bdbe4773370aa9f29e4514fb9be73a9f2a033244.tar.gz
nextcloud-server-bdbe4773370aa9f29e4514fb9be73a9f2a033244.zip
feat(files): add FileAction service
Signed-off-by: John Molakvoæ <skjnldsv@protonmail.com>
-rw-r--r--apps/files/src/actions/deleteAction.ts3
-rw-r--r--apps/files/src/components/FileEntry.vue1
-rw-r--r--apps/files/src/services/FileAction.ts184
-rw-r--r--apps/files_trashbin/src/actions/restoreAction.ts4
-rw-r--r--package.json1
5 files changed, 191 insertions, 2 deletions
diff --git a/apps/files/src/actions/deleteAction.ts b/apps/files/src/actions/deleteAction.ts
index 88ec345fcf2..f8b7fdb1ac6 100644
--- a/apps/files/src/actions/deleteAction.ts
+++ b/apps/files/src/actions/deleteAction.ts
@@ -20,11 +20,12 @@
*
*/
import { emit } from '@nextcloud/event-bus'
-import { registerFileAction, Permission, FileAction, Node } from '@nextcloud/files'
+import { Permission, Node } from '@nextcloud/files'
import { translate as t } from '@nextcloud/l10n'
import axios from '@nextcloud/axios'
import TrashCan from '@mdi/svg/svg/trash-can.svg?raw'
+import { registerFileAction, FileAction } from '../services/FileAction'
import logger from '../logger'
registerFileAction(new FileAction({
diff --git a/apps/files/src/components/FileEntry.vue b/apps/files/src/components/FileEntry.vue
index a4b373a7d9d..33e8438156b 100644
--- a/apps/files/src/components/FileEntry.vue
+++ b/apps/files/src/components/FileEntry.vue
@@ -105,6 +105,7 @@ import { Fragment } from 'vue-fragment'
import { join } from 'path'
import { showError } from '@nextcloud/dialogs'
import { translate } from '@nextcloud/l10n'
+import CancelablePromise from 'cancelable-promise'
import FileIcon from 'vue-material-design-icons/File.vue'
import FolderIcon from 'vue-material-design-icons/Folder.vue'
import NcActionButton from '@nextcloud/vue/dist/Components/NcActionButton.js'
diff --git a/apps/files/src/services/FileAction.ts b/apps/files/src/services/FileAction.ts
new file mode 100644
index 00000000000..8c1d325e645
--- /dev/null
+++ b/apps/files/src/services/FileAction.ts
@@ -0,0 +1,184 @@
+/**
+ * @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 { Node } from '@nextcloud/files'
+import logger from '../logger'
+
+declare global {
+ interface Window {
+ OC: any;
+ _nc_fileactions: FileAction[] | undefined;
+ }
+}
+
+/**
+ * TODO: remove and move to @nextcloud/files
+ * @see https://github.com/nextcloud/nextcloud-files/pull/608
+ */
+interface FileActionData {
+ /** Unique ID */
+ id: string
+ /** Translatable string displayed in the menu */
+ displayName: (files: Node[], view) => string
+ /** Svg as inline string. <svg><path fill="..." /></svg> */
+ iconSvgInline: (files: Node[], view) => string
+ /** Condition wether this action is shown or not */
+ enabled?: (files: Node[], view) => boolean
+ /**
+ * Function executed on single file action
+ * @returns true if the action was executed, false otherwise
+ * @throws Error if the action failed
+ */
+ exec: (file: Node, view) => Promise<boolean>,
+ /**
+ * Function executed on multiple files action
+ * @returns true if the action was executed, false otherwise
+ * @throws Error if the action failed
+ */
+ execBatch?: (files: Node[], view) => Promise<boolean[]>
+ /** This action order in the list */
+ order?: number,
+ /** Make this action the default */
+ default?: boolean,
+ /**
+ * If true, the renderInline function will be called
+ */
+ inline?: (file: Node, view) => boolean,
+ /**
+ * If defined, the returned html element will be
+ * appended before the actions menu.
+ */
+ renderInline?: (file: Node, view) => HTMLElement,
+}
+
+export class FileAction {
+
+ private _action: FileActionData
+
+ constructor(action: FileActionData) {
+ this.validateAction(action)
+ this._action = action
+ }
+
+ get id() {
+ return this._action.id
+ }
+
+ get displayName() {
+ return this._action.displayName
+ }
+
+ get iconSvgInline() {
+ return this._action.iconSvgInline
+ }
+
+ get enabled() {
+ return this._action.enabled
+ }
+
+ get exec() {
+ return this._action.exec
+ }
+
+ get execBatch() {
+ return this._action.execBatch
+ }
+
+ get order() {
+ return this._action.order
+ }
+
+ get default() {
+ return this._action.default
+ }
+
+ get inline() {
+ return this._action.inline
+ }
+
+ get renderInline() {
+ return this._action.renderInline
+ }
+
+ private validateAction(action: FileActionData) {
+ if (!action.id || typeof action.id !== 'string') {
+ throw new Error('Invalid id')
+ }
+
+ if (!action.displayName || typeof action.displayName !== 'function') {
+ throw new Error('Invalid displayName function')
+ }
+
+ if (!action.iconSvgInline || typeof action.iconSvgInline !== 'function') {
+ throw new Error('Invalid iconSvgInline function')
+ }
+
+ if (!action.exec || typeof action.exec !== 'function') {
+ throw new Error('Invalid exec function')
+ }
+
+ // Optional properties --------------------------------------------
+ if ('enabled' in action && typeof action.enabled !== 'function') {
+ throw new Error('Invalid enabled function')
+ }
+
+ if ('execBatch' in action && typeof action.execBatch !== 'function') {
+ throw new Error('Invalid execBatch function')
+ }
+
+ if ('order' in action && typeof action.order !== 'number') {
+ throw new Error('Invalid order')
+ }
+
+ if ('default' in action && typeof action.default !== 'boolean') {
+ throw new Error('Invalid default')
+ }
+
+ if ('inline' in action && typeof action.inline !== 'function') {
+ throw new Error('Invalid inline function')
+ }
+
+ if ('renderInline' in action && typeof action.renderInline !== 'function') {
+ throw new Error('Invalid renderInline function')
+ }
+ }
+
+}
+
+export const registerFileAction = function(action: FileAction): void {
+ if (typeof window._nc_fileactions === 'undefined') {
+ window._nc_fileactions = []
+ logger.debug('FileActions initialized')
+ }
+
+ // Check duplicates
+ if (window._nc_fileactions.find(search => search.id === action.id)) {
+ logger.error(`FileAction ${action.id} already registered`, { action })
+ return
+ }
+
+ window._nc_fileactions.push(action)
+}
+
+export const getFileActions = function(): FileAction[] {
+ return window._nc_fileactions || []
+}
diff --git a/apps/files_trashbin/src/actions/restoreAction.ts b/apps/files_trashbin/src/actions/restoreAction.ts
index fe896f6b618..0d309a3f3c6 100644
--- a/apps/files_trashbin/src/actions/restoreAction.ts
+++ b/apps/files_trashbin/src/actions/restoreAction.ts
@@ -22,11 +22,13 @@
import { emit } from '@nextcloud/event-bus'
import { generateRemoteUrl } from '@nextcloud/router'
import { getCurrentUser } from '@nextcloud/auth'
-import { registerFileAction, Permission, FileAction, Node } from '@nextcloud/files'
+import { Permission, Node } from '@nextcloud/files'
import { translate as t } from '@nextcloud/l10n'
import axios from '@nextcloud/axios'
import History from '@mdi/svg/svg/history.svg?raw'
+import { registerFileAction, FileAction } from '../../../files/src/services/FileAction'
+
registerFileAction(new FileAction({
id: 'restore',
displayName() {
diff --git a/package.json b/package.json
index 2c2bbf28eaa..2feb218a387 100644
--- a/package.json
+++ b/package.json
@@ -61,6 +61,7 @@
"blueimp-md5": "^2.19.0",
"browserslist-useragent-regexp": "^3.0.2",
"camelcase": "^6.3.0",
+ "cancelable-promise": "^4.3.1",
"clipboard": "^2.0.11",
"colord": "^2.9.3",
"core-js": "^3.24.0",