aboutsummaryrefslogtreecommitdiffstats
path: root/apps/files/src/services
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 /apps/files/src/services
parent014a57e54174ce9a8f2c55beafad2dd8d1c6a9d0 (diff)
downloadnextcloud-server-bdbe4773370aa9f29e4514fb9be73a9f2a033244.tar.gz
nextcloud-server-bdbe4773370aa9f29e4514fb9be73a9f2a033244.zip
feat(files): add FileAction service
Signed-off-by: John Molakvoæ <skjnldsv@protonmail.com>
Diffstat (limited to 'apps/files/src/services')
-rw-r--r--apps/files/src/services/FileAction.ts184
1 files changed, 184 insertions, 0 deletions
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 || []
+}