refactor(files_sharing): adjust for files library interfaces and remove sideeffects

Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
This commit is contained in:
Ferdinand Thiessen 2026-02-05 15:14:15 +01:00
parent 752ff74170
commit 7a60e43dd5
No known key found for this signature in database
GPG key ID: 7E849AE05218500F
11 changed files with 99 additions and 95 deletions

View file

@ -1,13 +1,14 @@
import type { Folder, View } from '@nextcloud/files'
import axios from '@nextcloud/axios'
import * as eventBus from '@nextcloud/event-bus'
import { File, FileAction, Permission } from '@nextcloud/files'
import { ShareType } from '@nextcloud/sharing'
/**
/*
* SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
import type { IFolder, IView } from '@nextcloud/files'
import axios from '@nextcloud/axios'
import * as eventBus from '@nextcloud/event-bus'
import { File, Permission } from '@nextcloud/files'
import { ShareType } from '@nextcloud/sharing'
import { beforeAll, beforeEach, describe, expect, test, vi } from 'vitest'
import { action } from './acceptShareAction.ts'
@ -18,12 +19,12 @@ vi.mock('@nextcloud/axios')
const view = {
id: 'files',
name: 'Files',
} as View
} as IView
const pendingShareView = {
id: 'pendingshares',
name: 'Pending shares',
} as View
} as IView
// Mock webroot variable
beforeAll(() => {
@ -41,18 +42,17 @@ describe('Accept share action conditions tests', () => {
root: '/files/admin',
})
expect(action).toBeInstanceOf(FileAction)
expect(action.id).toBe('accept-share')
expect(action.displayName({
nodes: [file],
view: pendingShareView,
folder: {} as Folder,
folder: {} as IFolder,
contents: [],
})).toBe('Accept share')
expect(action.iconSvgInline({
nodes: [file],
view: pendingShareView,
folder: {} as Folder,
folder: {} as IFolder,
contents: [],
})).toMatch(/<svg.+<\/svg>/)
expect(action.default).toBeUndefined()
@ -61,7 +61,7 @@ describe('Accept share action conditions tests', () => {
expect(action.inline!({
nodes: [file],
view: pendingShareView,
folder: {} as Folder,
folder: {} as IFolder,
contents: [],
})).toBe(true)
})
@ -87,7 +87,7 @@ describe('Accept share action conditions tests', () => {
expect(action.displayName({
nodes: [file1, file2],
view: pendingShareView,
folder: {} as Folder,
folder: {} as IFolder,
contents: [],
})).toBe('Accept shares')
})
@ -108,7 +108,7 @@ describe('Accept share action enabled tests', () => {
expect(action.enabled!({
nodes: [file],
view: pendingShareView,
folder: {} as Folder,
folder: {} as IFolder,
contents: [],
})).toBe(true)
})
@ -118,7 +118,7 @@ describe('Accept share action enabled tests', () => {
expect(action.enabled!({
nodes: [],
view,
folder: {} as Folder,
folder: {} as IFolder,
contents: [],
})).toBe(false)
})
@ -128,7 +128,7 @@ describe('Accept share action enabled tests', () => {
expect(action.enabled!({
nodes: [],
view: pendingShareView,
folder: {} as Folder,
folder: {} as IFolder,
contents: [],
})).toBe(false)
})
@ -159,7 +159,7 @@ describe('Accept share action execute tests', () => {
const exec = await action.exec({
nodes: [file],
view: pendingShareView,
folder: {} as Folder,
folder: {} as IFolder,
contents: [],
})
@ -192,7 +192,7 @@ describe('Accept share action execute tests', () => {
const exec = await action.exec({
nodes: [file],
view: pendingShareView,
folder: {} as Folder,
folder: {} as IFolder,
contents: [],
})
@ -237,7 +237,7 @@ describe('Accept share action execute tests', () => {
const exec = await action.execBatch!({
nodes: [file1, file2],
view: pendingShareView,
folder: {} as Folder,
folder: {} as IFolder,
contents: [],
})
@ -272,7 +272,7 @@ describe('Accept share action execute tests', () => {
const exec = await action.exec({
nodes: [file],
view: pendingShareView,
folder: {} as Folder,
folder: {} as IFolder,
contents: [],
})

View file

@ -1,16 +1,18 @@
/**
/*!
* SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
import type { IFileAction } from '@nextcloud/files'
import CheckSvg from '@mdi/svg/svg/check.svg?raw'
import axios from '@nextcloud/axios'
import { emit } from '@nextcloud/event-bus'
import { FileAction, registerFileAction } from '@nextcloud/files'
import { translatePlural as n } from '@nextcloud/l10n'
import { generateOcsUrl } from '@nextcloud/router'
import { pendingSharesViewId } from '../files_views/shares.ts'
export const action = new FileAction({
export const action: IFileAction = {
id: 'accept-share',
displayName: ({ nodes }) => n('files_sharing', 'Accept share', 'Accept shares', nodes.length),
iconSvgInline: () => CheckSvg,
@ -46,6 +48,4 @@ export const action = new FileAction({
order: 1,
inline: () => true,
})
registerFileAction(action)
}

View file

@ -1,11 +1,11 @@
/**
/*!
* SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
import type { Folder, View } from '@nextcloud/files'
import type { IFolder, IView } from '@nextcloud/files'
import { DefaultType, File, FileAction, Permission } from '@nextcloud/files'
import { DefaultType, File, Permission } from '@nextcloud/files'
import { describe, expect, test, vi } from 'vitest'
import { deletedSharesViewId, pendingSharesViewId, sharedWithOthersViewId, sharedWithYouViewId, sharesViewId, sharingByLinksViewId } from '../files_views/shares.ts'
import { action } from './openInFilesAction.ts'
@ -15,34 +15,33 @@ import '../main.ts'
const view = {
id: 'files',
name: 'Files',
} as View
} as IView
const validViews = [
sharesViewId,
sharedWithYouViewId,
sharedWithOthersViewId,
sharingByLinksViewId,
].map((id) => ({ id, name: id })) as View[]
].map((id) => ({ id, name: id })) as IView[]
const invalidViews = [
deletedSharesViewId,
pendingSharesViewId,
].map((id) => ({ id, name: id })) as View[]
].map((id) => ({ id, name: id })) as IView[]
describe('Open in files action conditions tests', () => {
test('Default values', () => {
expect(action).toBeInstanceOf(FileAction)
expect(action.id).toBe('files_sharing:open-in-files')
expect(action.displayName({
nodes: [],
view: validViews[0]!,
folder: {} as Folder,
folder: {} as IFolder,
contents: [],
})).toBe('Open in Files')
expect(action.iconSvgInline({
nodes: [],
view: validViews[0]!,
folder: {} as Folder,
folder: {} as IFolder,
contents: [],
})).toBe('')
expect(action.default).toBe(DefaultType.HIDDEN)
@ -58,7 +57,7 @@ describe('Open in files action enabled tests', () => {
expect(action.enabled!({
nodes: [],
view,
folder: {} as Folder,
folder: {} as IFolder,
contents: [],
})).toBe(true)
})
@ -70,7 +69,7 @@ describe('Open in files action enabled tests', () => {
expect(action.enabled!({
nodes: [],
view,
folder: {} as Folder,
folder: {} as IFolder,
contents: [],
})).toBe(false)
})
@ -80,6 +79,7 @@ describe('Open in files action enabled tests', () => {
describe('Open in files action execute tests', () => {
test('Open in files', async () => {
const goToRouteMock = vi.fn()
// @ts-expect-error -- mocking for tests
window.OCP = { Files: { Router: { goToRoute: goToRouteMock } } }
const file = new File({
@ -94,7 +94,7 @@ describe('Open in files action execute tests', () => {
const exec = await action.exec({
nodes: [file],
view,
folder: {} as Folder,
folder: {} as IFolder,
contents: [],
})
// Silent action

View file

@ -1,12 +1,15 @@
/**
/*!
* SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
import { DefaultType, FileAction, FileType, registerFileAction } from '@nextcloud/files'
import type { IFileAction } from '@nextcloud/files'
import { DefaultType, FileType } from '@nextcloud/files'
import { translate as t } from '@nextcloud/l10n'
import { sharedWithOthersViewId, sharedWithYouViewId, sharesViewId, sharingByLinksViewId } from '../files_views/shares.ts'
export const action = new FileAction({
export const action: IFileAction = {
id: 'files_sharing:open-in-files',
displayName: () => t('files_sharing', 'Open in Files'),
iconSvgInline: () => '',
@ -42,6 +45,4 @@ export const action = new FileAction({
// Before openFolderAction
order: -1000,
default: DefaultType.HIDDEN,
})
registerFileAction(action)
}

View file

@ -1,13 +1,13 @@
/**
/*
* SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
import type { View } from '@nextcloud/files'
import type { IView } from '@nextcloud/files'
import axios from '@nextcloud/axios'
import * as eventBus from '@nextcloud/event-bus'
import { File, FileAction, Folder, Permission } from '@nextcloud/files'
import { File, Folder, Permission } from '@nextcloud/files'
import { ShareType } from '@nextcloud/sharing'
import { beforeAll, beforeEach, describe, expect, test, vi } from 'vitest'
import { action } from './rejectShareAction.ts'
@ -19,12 +19,12 @@ vi.mock('@nextcloud/axios')
const view = {
id: 'files',
name: 'Files',
} as View
} as IView
const pendingShareView = {
id: 'pendingshares',
name: 'Pending shares',
} as View
} as IView
// Mock webroot variable
beforeAll(() => {
@ -42,7 +42,6 @@ describe('Reject share action conditions tests', () => {
root: '/files/admin',
})
expect(action).toBeInstanceOf(FileAction)
expect(action.id).toBe('reject-share')
expect(action.displayName({
nodes: [file],

View file

@ -1,17 +1,19 @@
/**
/*!
* SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
import type { IFileAction } from '@nextcloud/files'
import CloseSvg from '@mdi/svg/svg/close.svg?raw'
import axios from '@nextcloud/axios'
import { emit } from '@nextcloud/event-bus'
import { FileAction, registerFileAction } from '@nextcloud/files'
import { translatePlural as n } from '@nextcloud/l10n'
import { generateOcsUrl } from '@nextcloud/router'
import { ShareType } from '@nextcloud/sharing'
import { pendingSharesViewId } from '../files_views/shares.ts'
export const action = new FileAction({
export const action: IFileAction = {
id: 'reject-share',
displayName: ({ nodes }) => n('files_sharing', 'Reject share', 'Reject shares', nodes.length),
iconSvgInline: () => CloseSvg,
@ -69,6 +71,4 @@ export const action = new FileAction({
order: 2,
inline: () => true,
})
registerFileAction(action)
}

View file

@ -1,12 +1,13 @@
/**
/*!
* SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
import type { Folder, View } from '@nextcloud/files'
import type { IFolder, IView } from '@nextcloud/files'
import axios from '@nextcloud/axios'
import * as eventBus from '@nextcloud/event-bus'
import { File, FileAction, Permission } from '@nextcloud/files'
import { File, Permission } from '@nextcloud/files'
import { ShareType } from '@nextcloud/sharing'
import { beforeAll, beforeEach, describe, expect, test, vi } from 'vitest'
import { action } from './restoreShareAction.ts'
@ -19,12 +20,12 @@ vi.mock('@nextcloud/axios')
const view = {
id: 'files',
name: 'Files',
} as View
} as IView
const deletedShareView = {
id: 'deletedshares',
name: 'Deleted shares',
} as View
} as IView
// Mock webroot variable
beforeAll(() => {
@ -42,18 +43,17 @@ describe('Restore share action conditions tests', () => {
root: '/files/admin',
})
expect(action).toBeInstanceOf(FileAction)
expect(action.id).toBe('restore-share')
expect(action.displayName({
view: deletedShareView,
nodes: [file],
folder: {} as Folder,
folder: {} as IFolder,
contents: [],
})).toBe('Restore share')
expect(action.iconSvgInline({
view: deletedShareView,
nodes: [file],
folder: {} as Folder,
folder: {} as IFolder,
contents: [],
})).toMatch(/<svg.+<\/svg>/)
expect(action.default).toBeUndefined()
@ -62,7 +62,7 @@ describe('Restore share action conditions tests', () => {
expect(action.inline!({
view: deletedShareView,
nodes: [file],
folder: {} as Folder,
folder: {} as IFolder,
contents: [],
})).toBe(true)
})
@ -88,7 +88,7 @@ describe('Restore share action conditions tests', () => {
expect(action.displayName({
view: deletedShareView,
nodes: [file1, file2],
folder: {} as Folder,
folder: {} as IFolder,
contents: [],
})).toBe('Restore shares')
})
@ -109,7 +109,7 @@ describe('Restore share action enabled tests', () => {
expect(action.enabled!({
nodes: [file],
view: deletedShareView,
folder: {} as Folder,
folder: {} as IFolder,
contents: [],
})).toBe(true)
})
@ -119,7 +119,7 @@ describe('Restore share action enabled tests', () => {
expect(action.enabled!({
nodes: [],
view,
folder: {} as Folder,
folder: {} as IFolder,
contents: [],
})).toBe(false)
})
@ -129,7 +129,7 @@ describe('Restore share action enabled tests', () => {
expect(action.enabled!({
nodes: [],
view: deletedShareView,
folder: {} as Folder,
folder: {} as IFolder,
contents: [],
})).toBe(false)
})
@ -160,7 +160,7 @@ describe('Restore share action execute tests', () => {
const exec = await action.exec({
nodes: [file],
view: deletedShareView,
folder: {} as Folder,
folder: {} as IFolder,
contents: [],
})
@ -205,7 +205,7 @@ describe('Restore share action execute tests', () => {
const exec = await action.execBatch!({
nodes: [file1, file2],
view: deletedShareView,
folder: {} as Folder,
folder: {} as IFolder,
contents: [],
})
@ -239,7 +239,7 @@ describe('Restore share action execute tests', () => {
const exec = await action.exec({
nodes: [file],
view: deletedShareView,
folder: {} as Folder,
folder: {} as IFolder,
contents: [],
})

View file

@ -1,16 +1,18 @@
/**
/*!
* SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
import type { IFileAction } from '@nextcloud/files'
import ArrowULeftTopSvg from '@mdi/svg/svg/arrow-u-left-top.svg?raw'
import axios from '@nextcloud/axios'
import { emit } from '@nextcloud/event-bus'
import { FileAction, registerFileAction } from '@nextcloud/files'
import { translatePlural as n } from '@nextcloud/l10n'
import { generateOcsUrl } from '@nextcloud/router'
import { deletedSharesViewId } from '../files_views/shares.ts'
export const action = new FileAction({
export const action: IFileAction = {
id: 'restore-share',
displayName: ({ nodes }) => n('files_sharing', 'Restore share', 'Restore shares', nodes.length),
@ -40,6 +42,4 @@ export const action = new FileAction({
order: 1,
inline: () => true,
})
registerFileAction(action)
}

View file

@ -1,7 +1,8 @@
/**
/*
* SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
// Only when rendered inline, when not enough space, this is put in the menu
.action-items > .files-list__row-action-sharing-status {
// align icons with text-less inline actions

View file

@ -1,16 +1,16 @@
/**
/*!
* SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
import type { INode } from '@nextcloud/files'
import type { IFileAction, INode } from '@nextcloud/files'
import AccountGroupSvg from '@mdi/svg/svg/account-group-outline.svg?raw'
import AccountPlusSvg from '@mdi/svg/svg/account-plus-outline.svg?raw'
import LinkSvg from '@mdi/svg/svg/link.svg?raw'
import { getCurrentUser } from '@nextcloud/auth'
import { showError } from '@nextcloud/dialogs'
import { FileAction, getSidebar, Permission, registerFileAction } from '@nextcloud/files'
import { getSidebar, Permission } from '@nextcloud/files'
import { translate as t } from '@nextcloud/l10n'
import { ShareType } from '@nextcloud/sharing'
import { isPublicShare } from '@nextcloud/sharing/public'
@ -29,7 +29,7 @@ function isExternal(node: INode) {
}
export const ACTION_SHARING_STATUS = 'sharing-status'
export const action = new FileAction({
export const action: IFileAction = {
id: ACTION_SHARING_STATUS,
displayName({ nodes }) {
const node = nodes[0]!
@ -153,6 +153,4 @@ export const action = new FileAction({
inline: () => true,
})
registerFileAction(action)
}

View file

@ -1,21 +1,20 @@
/**
/*!
* SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
import { addNewFileMenuEntry } from '@nextcloud/files'
import { addNewFileMenuEntry, registerFileAction } from '@nextcloud/files'
import { registerDavProperty } from '@nextcloud/files/dav'
import { action as acceptShareAction } from './files_actions/acceptShareAction.ts'
import { action as openInFilesAction } from './files_actions/openInFilesAction.ts'
import { action as rejectShareAction } from './files_actions/rejectShareAction.ts'
import { action as restoreShareAction } from './files_actions/restoreShareAction.ts'
import { action as sharingStatusAction } from './files_actions/sharingStatusAction.ts'
import { registerAccountFilter } from './files_filters/AccountFilter.ts'
import registerNoteToRecipient from './files_headers/noteToRecipient.ts'
import { entry as newFileRequest } from './files_newMenu/newFileRequest.ts'
import registerSharingViews from './files_views/shares.ts'
import './files_actions/acceptShareAction.ts'
import './files_actions/openInFilesAction.ts'
import './files_actions/rejectShareAction.ts'
import './files_actions/restoreShareAction.ts'
import './files_actions/sharingStatusAction.ts'
registerSharingViews()
addNewFileMenuEntry(newFileRequest)
@ -27,6 +26,12 @@ registerDavProperty('nc:share-attributes', { nc: 'http://nextcloud.org/ns' })
registerDavProperty('oc:share-types', { oc: 'http://owncloud.org/ns' })
registerDavProperty('ocs:share-permissions', { ocs: 'http://open-collaboration-services.org/ns' })
registerFileAction(acceptShareAction)
registerFileAction(openInFilesAction)
registerFileAction(rejectShareAction)
registerFileAction(restoreShareAction)
registerFileAction(sharingStatusAction)
registerAccountFilter()
// Add "note to recipient" message