mirror of
https://github.com/nextcloud/server.git
synced 2026-06-08 16:26:59 -04:00
Merge pull request #58108 from nextcloud/chore/update-files
chore(deps): update `@nextcloud/files` to v4.0.0-rc.1
This commit is contained in:
commit
9def7a8ba7
196 changed files with 970 additions and 1141 deletions
|
|
@ -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 { File, FileAction, Permission } from '@nextcloud/files'
|
||||
import { File, Permission } from '@nextcloud/files'
|
||||
import { describe, expect, test, vi } from 'vitest'
|
||||
import logger from '../logger.js'
|
||||
import { action } from './inlineUnreadCommentsAction.ts'
|
||||
|
|
@ -13,7 +13,7 @@ import { action } from './inlineUnreadCommentsAction.ts'
|
|||
const view = {
|
||||
id: 'files',
|
||||
name: 'Files',
|
||||
} as View
|
||||
} as IView
|
||||
|
||||
describe('Inline unread comments action display name tests', () => {
|
||||
test('Default values', () => {
|
||||
|
|
@ -29,36 +29,35 @@ describe('Inline unread comments action display name tests', () => {
|
|||
root: '/files/admin',
|
||||
})
|
||||
|
||||
expect(action).toBeInstanceOf(FileAction)
|
||||
expect(action.id).toBe('comments-unread')
|
||||
expect(action.displayName({
|
||||
nodes: [file],
|
||||
view,
|
||||
folder: {} as Folder,
|
||||
folder: {} as IFolder,
|
||||
contents: [],
|
||||
})).toBe('')
|
||||
expect(action.title!({
|
||||
nodes: [file],
|
||||
view,
|
||||
folder: {} as Folder,
|
||||
folder: {} as IFolder,
|
||||
contents: [],
|
||||
})).toBe('1 new comment')
|
||||
expect(action.iconSvgInline({
|
||||
nodes: [file],
|
||||
view,
|
||||
folder: {} as Folder,
|
||||
folder: {} as IFolder,
|
||||
contents: [],
|
||||
})).toMatch(/<svg.+<\/svg>/)
|
||||
expect(action.enabled!({
|
||||
nodes: [file],
|
||||
view,
|
||||
folder: {} as Folder,
|
||||
folder: {} as IFolder,
|
||||
contents: [],
|
||||
})).toBe(true)
|
||||
expect(action.inline!({
|
||||
nodes: [file],
|
||||
view,
|
||||
folder: {} as Folder,
|
||||
folder: {} as IFolder,
|
||||
contents: [],
|
||||
})).toBe(true)
|
||||
expect(action.default).toBeUndefined()
|
||||
|
|
@ -81,13 +80,13 @@ describe('Inline unread comments action display name tests', () => {
|
|||
expect(action.displayName({
|
||||
nodes: [file],
|
||||
view,
|
||||
folder: {} as Folder,
|
||||
folder: {} as IFolder,
|
||||
contents: [],
|
||||
})).toBe('')
|
||||
expect(action.title!({
|
||||
nodes: [file],
|
||||
view,
|
||||
folder: {} as Folder,
|
||||
folder: {} as IFolder,
|
||||
contents: [],
|
||||
})).toBe('2 new comments')
|
||||
})
|
||||
|
|
@ -108,7 +107,7 @@ describe('Inline unread comments action enabled tests', () => {
|
|||
expect(action.enabled!({
|
||||
nodes: [file],
|
||||
view,
|
||||
folder: {} as Folder,
|
||||
folder: {} as IFolder,
|
||||
contents: [],
|
||||
})).toBe(false)
|
||||
})
|
||||
|
|
@ -129,7 +128,7 @@ describe('Inline unread comments action enabled tests', () => {
|
|||
expect(action.enabled!({
|
||||
nodes: [file],
|
||||
view,
|
||||
folder: {} as Folder,
|
||||
folder: {} as IFolder,
|
||||
contents: [],
|
||||
})).toBe(false)
|
||||
})
|
||||
|
|
@ -150,7 +149,7 @@ describe('Inline unread comments action enabled tests', () => {
|
|||
expect(action.enabled!({
|
||||
nodes: [file],
|
||||
view,
|
||||
folder: {} as Folder,
|
||||
folder: {} as IFolder,
|
||||
contents: [],
|
||||
})).toBe(true)
|
||||
})
|
||||
|
|
@ -171,7 +170,7 @@ describe('Inline unread comments action enabled tests', () => {
|
|||
expect(action.enabled!({
|
||||
nodes: [file],
|
||||
view,
|
||||
folder: {} as Folder,
|
||||
folder: {} as IFolder,
|
||||
contents: [],
|
||||
})).toBe(true)
|
||||
})
|
||||
|
|
@ -204,7 +203,7 @@ describe('Inline unread comments action execute tests', () => {
|
|||
const result = await action.exec!({
|
||||
nodes: [file],
|
||||
view,
|
||||
folder: {} as Folder,
|
||||
folder: {} as IFolder,
|
||||
contents: [],
|
||||
})
|
||||
|
||||
|
|
@ -241,7 +240,7 @@ describe('Inline unread comments action execute tests', () => {
|
|||
const result = await action.exec!({
|
||||
nodes: [file],
|
||||
view,
|
||||
folder: {} as Folder,
|
||||
folder: {} as IFolder,
|
||||
contents: [],
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -3,12 +3,14 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import type { IFileAction } from '@nextcloud/files'
|
||||
|
||||
import CommentProcessingSvg from '@mdi/svg/svg/comment-processing.svg?raw'
|
||||
import { FileAction, getSidebar } from '@nextcloud/files'
|
||||
import { getSidebar } from '@nextcloud/files'
|
||||
import { n, t } from '@nextcloud/l10n'
|
||||
import logger from '../logger.js'
|
||||
|
||||
export const action = new FileAction({
|
||||
export const action: IFileAction = {
|
||||
id: 'comments-unread',
|
||||
|
||||
title({ nodes }) {
|
||||
|
|
@ -47,4 +49,4 @@ export const action = new FileAction({
|
|||
inline: () => true,
|
||||
|
||||
order: -140,
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,13 @@
|
|||
/**
|
||||
/*!
|
||||
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import type { IFileAction } from '@nextcloud/files'
|
||||
|
||||
import AutoRenewSvg from '@mdi/svg/svg/autorenew.svg?raw'
|
||||
import { getCapabilities } from '@nextcloud/capabilities'
|
||||
import { FileAction, registerFileAction } from '@nextcloud/files'
|
||||
import { registerFileAction } from '@nextcloud/files'
|
||||
import { t } from '@nextcloud/l10n'
|
||||
import { generateUrl } from '@nextcloud/router'
|
||||
import { convertFile, convertFiles } from './convertUtils.ts'
|
||||
|
|
@ -18,47 +21,45 @@ type ConversionsProvider = {
|
|||
export const ACTION_CONVERT = 'convert'
|
||||
|
||||
/**
|
||||
*
|
||||
* Registers the convert actions based on the capabilities provided by the server.
|
||||
*/
|
||||
export function registerConvertActions() {
|
||||
// Generate sub actions
|
||||
const convertProviders = getCapabilities()?.files?.file_conversions as ConversionsProvider[] ?? []
|
||||
const actions = convertProviders.map(({ to, from, displayName }) => {
|
||||
return new FileAction({
|
||||
id: `convert-${from}-${to}`,
|
||||
displayName: () => t('files', 'Save as {displayName}', { displayName }),
|
||||
iconSvgInline: () => generateIconSvg(to),
|
||||
enabled: ({ nodes }) => {
|
||||
// Check that all nodes have the same mime type
|
||||
return nodes.every((node) => from === node.mime)
|
||||
},
|
||||
const actions = convertProviders.map(({ to, from, displayName }) => ({
|
||||
id: `convert-${from}-${to}`,
|
||||
displayName: () => t('files', 'Save as {displayName}', { displayName }),
|
||||
iconSvgInline: () => generateIconSvg(to),
|
||||
enabled: ({ nodes }) => {
|
||||
// Check that all nodes have the same mime type
|
||||
return nodes.every((node) => from === node.mime)
|
||||
},
|
||||
|
||||
async exec({ nodes }) {
|
||||
if (!nodes[0]) {
|
||||
return false
|
||||
}
|
||||
async exec({ nodes }) {
|
||||
if (!nodes[0]) {
|
||||
return false
|
||||
}
|
||||
|
||||
// If we're here, we know that the node has a fileid
|
||||
convertFile(nodes[0].fileid as number, to)
|
||||
// If we're here, we know that the node has a fileid
|
||||
convertFile(nodes[0].fileid as number, to)
|
||||
|
||||
// Silently terminate, we'll handle the UI in the background
|
||||
return null
|
||||
},
|
||||
// Silently terminate, we'll handle the UI in the background
|
||||
return null
|
||||
},
|
||||
|
||||
async execBatch({ nodes }) {
|
||||
const fileIds = nodes.map((node) => node.fileid).filter(Boolean) as number[]
|
||||
convertFiles(fileIds, to)
|
||||
async execBatch({ nodes }) {
|
||||
const fileIds = nodes.map((node) => node.fileid).filter(Boolean) as number[]
|
||||
convertFiles(fileIds, to)
|
||||
|
||||
// Silently terminate, we'll handle the UI in the background
|
||||
return Array(nodes.length).fill(null)
|
||||
},
|
||||
// Silently terminate, we'll handle the UI in the background
|
||||
return Array(nodes.length).fill(null)
|
||||
},
|
||||
|
||||
parent: ACTION_CONVERT,
|
||||
})
|
||||
})
|
||||
parent: ACTION_CONVERT,
|
||||
} satisfies IFileAction))
|
||||
|
||||
// Register main action
|
||||
registerFileAction(new FileAction({
|
||||
registerFileAction({
|
||||
id: ACTION_CONVERT,
|
||||
displayName: () => t('files', 'Save as …'),
|
||||
iconSvgInline: () => AutoRenewSvg,
|
||||
|
|
@ -69,15 +70,16 @@ export function registerConvertActions() {
|
|||
return null
|
||||
},
|
||||
order: 25,
|
||||
}))
|
||||
} satisfies IFileAction)
|
||||
|
||||
// Register sub actions
|
||||
actions.forEach(registerFileAction)
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates an SVG icon for a given mime type by using the server's mime icon endpoint.
|
||||
*
|
||||
* @param mime
|
||||
* @param mime - The mime type to generate the icon for
|
||||
*/
|
||||
export function generateIconSvg(mime: string) {
|
||||
// Generate icon based on mime type
|
||||
|
|
|
|||
|
|
@ -1,13 +1,14 @@
|
|||
/**
|
||||
/*!
|
||||
* 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 capabilities from '@nextcloud/capabilities'
|
||||
import * as eventBus from '@nextcloud/event-bus'
|
||||
import { File, FileAction, Folder, Permission } from '@nextcloud/files'
|
||||
import { File, Folder, Permission } from '@nextcloud/files'
|
||||
import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest'
|
||||
import logger from '../logger.ts'
|
||||
import { action } from './deleteAction.ts'
|
||||
|
|
@ -20,12 +21,12 @@ vi.mock('@nextcloud/capabilities')
|
|||
const view = {
|
||||
id: 'files',
|
||||
name: 'Files',
|
||||
} as View
|
||||
} as IView
|
||||
|
||||
const trashbinView = {
|
||||
id: 'trashbin',
|
||||
name: 'Trashbin',
|
||||
} as View
|
||||
} as IView
|
||||
|
||||
describe('Delete action conditions tests', () => {
|
||||
beforeEach(() => {
|
||||
|
|
@ -90,7 +91,6 @@ describe('Delete action conditions tests', () => {
|
|||
})
|
||||
|
||||
test('Default values', () => {
|
||||
expect(action).toBeInstanceOf(FileAction)
|
||||
expect(action.id).toBe('delete')
|
||||
expect(action.displayName({
|
||||
nodes: [file],
|
||||
|
|
|
|||
|
|
@ -1,11 +1,14 @@
|
|||
/**
|
||||
/*!
|
||||
* 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 NetworkOffSvg from '@mdi/svg/svg/network-off.svg?raw'
|
||||
import TrashCanSvg from '@mdi/svg/svg/trash-can-outline.svg?raw'
|
||||
import { FileAction, Permission } from '@nextcloud/files'
|
||||
import { Permission } from '@nextcloud/files'
|
||||
import { loadState } from '@nextcloud/initial-state'
|
||||
import { t } from '@nextcloud/l10n'
|
||||
import PQueue from 'p-queue'
|
||||
|
|
@ -20,7 +23,7 @@ const queue = new PQueue({ concurrency: 5 })
|
|||
|
||||
export const ACTION_DELETE = 'delete'
|
||||
|
||||
export const action = new FileAction({
|
||||
export const action: IFileAction = {
|
||||
id: ACTION_DELETE,
|
||||
displayName,
|
||||
iconSvgInline: ({ nodes }) => {
|
||||
|
|
@ -117,4 +120,4 @@ export const action = new FileAction({
|
|||
description: t('files', 'Delete'),
|
||||
key: 'Delete',
|
||||
},
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
/**
|
||||
/*!
|
||||
* 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 dialogs from '@nextcloud/dialogs'
|
||||
import * as eventBus from '@nextcloud/event-bus'
|
||||
import { DefaultType, File, FileAction, Folder, Permission } from '@nextcloud/files'
|
||||
import { DefaultType, File, Folder, Permission } from '@nextcloud/files'
|
||||
import { beforeAll, beforeEach, describe, expect, test, vi } from 'vitest'
|
||||
import { action } from './downloadAction.ts'
|
||||
|
||||
|
|
@ -19,7 +19,7 @@ vi.mock('@nextcloud/event-bus')
|
|||
const view = {
|
||||
id: 'files',
|
||||
name: 'Files',
|
||||
} as View
|
||||
} as IView
|
||||
|
||||
// Mock webroot variable
|
||||
beforeAll(() => {
|
||||
|
|
@ -28,7 +28,6 @@ beforeAll(() => {
|
|||
|
||||
describe('Download action conditions tests', () => {
|
||||
test('Default values', () => {
|
||||
expect(action).toBeInstanceOf(FileAction)
|
||||
expect(action.id).toBe('download')
|
||||
expect(action.displayName({
|
||||
nodes: [],
|
||||
|
|
|
|||
|
|
@ -1,15 +1,15 @@
|
|||
/**
|
||||
/*!
|
||||
* SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import type { Node, View } from '@nextcloud/files'
|
||||
import type { IFileAction, INode, IView } from '@nextcloud/files'
|
||||
|
||||
import ArrowDownSvg from '@mdi/svg/svg/arrow-down.svg?raw'
|
||||
import axios from '@nextcloud/axios'
|
||||
import { showError } from '@nextcloud/dialogs'
|
||||
import { emit } from '@nextcloud/event-bus'
|
||||
import { DefaultType, FileAction, FileType } from '@nextcloud/files'
|
||||
import { DefaultType, FileType } from '@nextcloud/files'
|
||||
import { t } from '@nextcloud/l10n'
|
||||
import logger from '../logger.ts'
|
||||
import { useFilesStore } from '../store/files.ts'
|
||||
|
|
@ -17,112 +17,7 @@ import { getPinia } from '../store/index.ts'
|
|||
import { usePathsStore } from '../store/paths.ts'
|
||||
import { isDownloadable } from '../utils/permissions.ts'
|
||||
|
||||
/**
|
||||
* Trigger downloading a file.
|
||||
*
|
||||
* @param url The url of the asset to download
|
||||
* @param name Optionally the recommended name of the download (browsers might ignore it)
|
||||
*/
|
||||
async function triggerDownload(url: string, name?: string) {
|
||||
// try to see if the resource is still available
|
||||
await axios.head(url)
|
||||
|
||||
const hiddenElement = document.createElement('a')
|
||||
hiddenElement.download = name ?? ''
|
||||
hiddenElement.href = url
|
||||
hiddenElement.click()
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the longest common path prefix of both input paths
|
||||
*
|
||||
* @param first The first path
|
||||
* @param second The second path
|
||||
*/
|
||||
function longestCommonPath(first: string, second: string): string {
|
||||
const firstSegments = first.split('/').filter(Boolean)
|
||||
const secondSegments = second.split('/').filter(Boolean)
|
||||
let base = ''
|
||||
for (const [index, segment] of firstSegments.entries()) {
|
||||
if (index >= second.length) {
|
||||
break
|
||||
}
|
||||
if (segment !== secondSegments[index]) {
|
||||
break
|
||||
}
|
||||
const sep = base === '' ? '' : '/'
|
||||
base = `${base}${sep}${segment}`
|
||||
}
|
||||
return base
|
||||
}
|
||||
|
||||
/**
|
||||
* Download the given nodes.
|
||||
*
|
||||
* If only one node is given, it will be downloaded directly.
|
||||
* If multiple nodes are given, they will be zipped and downloaded.
|
||||
*
|
||||
* @param nodes The node(s) to download
|
||||
*/
|
||||
async function downloadNodes(nodes: Node[]) {
|
||||
let url: URL
|
||||
|
||||
if (!nodes[0]) {
|
||||
throw new Error('No nodes to download')
|
||||
}
|
||||
|
||||
if (nodes.length === 1) {
|
||||
if (nodes[0].type === FileType.File) {
|
||||
await triggerDownload(nodes[0].encodedSource, nodes[0].displayname)
|
||||
return
|
||||
} else {
|
||||
url = new URL(nodes[0].encodedSource)
|
||||
url.searchParams.append('accept', 'zip')
|
||||
}
|
||||
} else {
|
||||
url = new URL(nodes[0].encodedSource)
|
||||
let base = url.pathname
|
||||
for (const node of nodes.slice(1)) {
|
||||
base = longestCommonPath(base, (new URL(node.encodedSource).pathname))
|
||||
}
|
||||
url.pathname = base
|
||||
|
||||
// The URL contains the path encoded so we need to decode as the query.append will re-encode it
|
||||
const filenames = nodes.map((node) => decodeURIComponent(node.encodedSource.slice(url.href.length + 1)))
|
||||
url.searchParams.append('accept', 'zip')
|
||||
url.searchParams.append('files', JSON.stringify(filenames))
|
||||
}
|
||||
|
||||
if (url.pathname.at(-1) !== '/') {
|
||||
url.pathname = `${url.pathname}/`
|
||||
}
|
||||
|
||||
await triggerDownload(url.href)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current directory node for the given view and path.
|
||||
* TODO: ideally the folder would directly be passed as exec params
|
||||
*
|
||||
* @param view The current view
|
||||
* @param directory The directory path
|
||||
* @return The current directory node or null if not found
|
||||
*/
|
||||
function getCurrentDirectory(view: View, directory: string): Node | null {
|
||||
const filesStore = useFilesStore(getPinia())
|
||||
const pathsStore = usePathsStore(getPinia())
|
||||
if (!view?.id) {
|
||||
return null
|
||||
}
|
||||
|
||||
if (directory === '/') {
|
||||
return filesStore.getRoot(view.id) || null
|
||||
}
|
||||
const fileId = pathsStore.getPath(view.id, directory)!
|
||||
return filesStore.getNode(fileId) || null
|
||||
}
|
||||
|
||||
export const action = new FileAction({
|
||||
export const action: IFileAction = {
|
||||
id: 'download',
|
||||
default: DefaultType.DEFAULT,
|
||||
|
||||
|
|
@ -172,4 +67,109 @@ export const action = new FileAction({
|
|||
},
|
||||
|
||||
order: 30,
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Trigger downloading a file.
|
||||
*
|
||||
* @param url The url of the asset to download
|
||||
* @param name Optionally the recommended name of the download (browsers might ignore it)
|
||||
*/
|
||||
async function triggerDownload(url: string, name?: string) {
|
||||
// try to see if the resource is still available
|
||||
await axios.head(url)
|
||||
|
||||
const hiddenElement = document.createElement('a')
|
||||
hiddenElement.download = name ?? ''
|
||||
hiddenElement.href = url
|
||||
hiddenElement.click()
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the longest common path prefix of both input paths
|
||||
*
|
||||
* @param first The first path
|
||||
* @param second The second path
|
||||
*/
|
||||
function longestCommonPath(first: string, second: string): string {
|
||||
const firstSegments = first.split('/').filter(Boolean)
|
||||
const secondSegments = second.split('/').filter(Boolean)
|
||||
let base = ''
|
||||
for (const [index, segment] of firstSegments.entries()) {
|
||||
if (index >= second.length) {
|
||||
break
|
||||
}
|
||||
if (segment !== secondSegments[index]) {
|
||||
break
|
||||
}
|
||||
const sep = base === '' ? '' : '/'
|
||||
base = `${base}${sep}${segment}`
|
||||
}
|
||||
return base
|
||||
}
|
||||
|
||||
/**
|
||||
* Download the given nodes.
|
||||
*
|
||||
* If only one node is given, it will be downloaded directly.
|
||||
* If multiple nodes are given, they will be zipped and downloaded.
|
||||
*
|
||||
* @param nodes The node(s) to download
|
||||
*/
|
||||
async function downloadNodes(nodes: INode[]) {
|
||||
let url: URL
|
||||
|
||||
if (!nodes[0]) {
|
||||
throw new Error('No nodes to download')
|
||||
}
|
||||
|
||||
if (nodes.length === 1) {
|
||||
if (nodes[0].type === FileType.File) {
|
||||
await triggerDownload(nodes[0].encodedSource, nodes[0].displayname)
|
||||
return
|
||||
} else {
|
||||
url = new URL(nodes[0].encodedSource)
|
||||
url.searchParams.append('accept', 'zip')
|
||||
}
|
||||
} else {
|
||||
url = new URL(nodes[0].encodedSource)
|
||||
let base = url.pathname
|
||||
for (const node of nodes.slice(1)) {
|
||||
base = longestCommonPath(base, (new URL(node.encodedSource).pathname))
|
||||
}
|
||||
url.pathname = base
|
||||
|
||||
// The URL contains the path encoded so we need to decode as the query.append will re-encode it
|
||||
const filenames = nodes.map((node) => decodeURIComponent(node.encodedSource.slice(url.href.length + 1)))
|
||||
url.searchParams.append('accept', 'zip')
|
||||
url.searchParams.append('files', JSON.stringify(filenames))
|
||||
}
|
||||
|
||||
if (url.pathname.at(-1) !== '/') {
|
||||
url.pathname = `${url.pathname}/`
|
||||
}
|
||||
|
||||
await triggerDownload(url.href)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current directory node for the given view and path.
|
||||
* TODO: ideally the folder would directly be passed as exec params
|
||||
*
|
||||
* @param view The current view
|
||||
* @param directory The directory path
|
||||
* @return The current directory node or null if not found
|
||||
*/
|
||||
function getCurrentDirectory(view: IView, directory: string): INode | null {
|
||||
const filesStore = useFilesStore(getPinia())
|
||||
const pathsStore = usePathsStore(getPinia())
|
||||
if (!view?.id) {
|
||||
return null
|
||||
}
|
||||
|
||||
if (directory === '/') {
|
||||
return filesStore.getRoot(view.id) || null
|
||||
}
|
||||
const fileId = pathsStore.getPath(view.id, directory)!
|
||||
return filesStore.getNode(fileId) || null
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,13 +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 { beforeAll, beforeEach, describe, expect, test, vi } from 'vitest'
|
||||
import logger from '../logger.ts'
|
||||
import { action } from './favoriteAction.ts'
|
||||
|
|
@ -19,12 +19,12 @@ vi.mock('@nextcloud/axios')
|
|||
const view = {
|
||||
id: 'files',
|
||||
name: 'Files',
|
||||
} as View
|
||||
} as IView
|
||||
|
||||
const favoriteView = {
|
||||
id: 'favorites',
|
||||
name: 'Favorites',
|
||||
} as View
|
||||
} as IView
|
||||
|
||||
// Mock webroot variable
|
||||
beforeAll(() => {
|
||||
|
|
@ -46,18 +46,17 @@ describe('Favorite action conditions tests', () => {
|
|||
root: '/files/admin',
|
||||
})
|
||||
|
||||
expect(action).toBeInstanceOf(FileAction)
|
||||
expect(action.id).toBe('favorite')
|
||||
expect(action.displayName({
|
||||
nodes: [file],
|
||||
view,
|
||||
folder: {} as Folder,
|
||||
folder: {} as IFolder,
|
||||
contents: [],
|
||||
})).toBe('Add to favorites')
|
||||
expect(action.iconSvgInline({
|
||||
nodes: [],
|
||||
view,
|
||||
folder: {} as Folder,
|
||||
folder: {} as IFolder,
|
||||
contents: [],
|
||||
})).toMatch(/<svg.+<\/svg>/)
|
||||
expect(action.default).toBeUndefined()
|
||||
|
|
@ -79,7 +78,7 @@ describe('Favorite action conditions tests', () => {
|
|||
expect(action.displayName({
|
||||
nodes: [file],
|
||||
view,
|
||||
folder: {} as Folder,
|
||||
folder: {} as IFolder,
|
||||
contents: [],
|
||||
})).toBe('Remove from favorites')
|
||||
})
|
||||
|
|
@ -122,25 +121,25 @@ describe('Favorite action conditions tests', () => {
|
|||
expect(action.displayName({
|
||||
nodes: [file1, file2, file3],
|
||||
view,
|
||||
folder: {} as Folder,
|
||||
folder: {} as IFolder,
|
||||
contents: [],
|
||||
})).toBe('Add to favorites')
|
||||
expect(action.displayName({
|
||||
nodes: [file2, file3],
|
||||
view,
|
||||
folder: {} as Folder,
|
||||
folder: {} as IFolder,
|
||||
contents: [],
|
||||
})).toBe('Add to favorites')
|
||||
expect(action.displayName({
|
||||
nodes: [file2, file3],
|
||||
view,
|
||||
folder: {} as Folder,
|
||||
folder: {} as IFolder,
|
||||
contents: [],
|
||||
})).toBe('Add to favorites')
|
||||
expect(action.displayName({
|
||||
nodes: [file1, file3],
|
||||
view,
|
||||
folder: {} as Folder,
|
||||
folder: {} as IFolder,
|
||||
contents: [],
|
||||
})).toBe('Remove from favorites')
|
||||
})
|
||||
|
|
@ -161,7 +160,7 @@ describe('Favorite action enabled tests', () => {
|
|||
expect(action.enabled!({
|
||||
nodes: [file],
|
||||
view,
|
||||
folder: {} as Folder,
|
||||
folder: {} as IFolder,
|
||||
contents: [],
|
||||
})).toBe(true)
|
||||
})
|
||||
|
|
@ -179,7 +178,7 @@ describe('Favorite action enabled tests', () => {
|
|||
expect(action.enabled!({
|
||||
nodes: [file],
|
||||
view,
|
||||
folder: {} as Folder,
|
||||
folder: {} as IFolder,
|
||||
contents: [],
|
||||
})).toBe(false)
|
||||
})
|
||||
|
|
@ -205,7 +204,7 @@ describe('Favorite action execute tests', () => {
|
|||
const exec = await action.exec({
|
||||
nodes: [file],
|
||||
view,
|
||||
folder: {} as Folder,
|
||||
folder: {} as IFolder,
|
||||
contents: [],
|
||||
})
|
||||
|
||||
|
|
@ -239,7 +238,7 @@ describe('Favorite action execute tests', () => {
|
|||
const exec = await action.exec({
|
||||
nodes: [file],
|
||||
view,
|
||||
folder: {} as Folder,
|
||||
folder: {} as IFolder,
|
||||
contents: [],
|
||||
})
|
||||
|
||||
|
|
@ -273,7 +272,7 @@ describe('Favorite action execute tests', () => {
|
|||
const exec = await action.exec({
|
||||
nodes: [file],
|
||||
view: favoriteView,
|
||||
folder: {} as Folder,
|
||||
folder: {} as IFolder,
|
||||
contents: [],
|
||||
})
|
||||
|
||||
|
|
@ -308,7 +307,7 @@ describe('Favorite action execute tests', () => {
|
|||
const exec = await action.exec({
|
||||
nodes: [file],
|
||||
view: favoriteView,
|
||||
folder: {} as Folder,
|
||||
folder: {} as IFolder,
|
||||
contents: [],
|
||||
})
|
||||
|
||||
|
|
@ -345,7 +344,7 @@ describe('Favorite action execute tests', () => {
|
|||
const exec = await action.exec({
|
||||
nodes: [file],
|
||||
view,
|
||||
folder: {} as Folder,
|
||||
folder: {} as IFolder,
|
||||
contents: [],
|
||||
})
|
||||
|
||||
|
|
@ -383,7 +382,7 @@ describe('Favorite action execute tests', () => {
|
|||
const exec = await action.exec({
|
||||
nodes: [file],
|
||||
view,
|
||||
folder: {} as Folder,
|
||||
folder: {} as IFolder,
|
||||
contents: [],
|
||||
})
|
||||
|
||||
|
|
@ -437,7 +436,7 @@ describe('Favorite action batch execute tests', () => {
|
|||
const exec = await action.execBatch!({
|
||||
nodes: [file1, file2],
|
||||
view,
|
||||
folder: {} as Folder,
|
||||
folder: {} as IFolder,
|
||||
contents: [],
|
||||
})
|
||||
expect(exec).toStrictEqual([true, true])
|
||||
|
|
@ -479,7 +478,7 @@ describe('Favorite action batch execute tests', () => {
|
|||
const exec = await action.execBatch!({
|
||||
nodes: [file1, file2],
|
||||
view,
|
||||
folder: {} as Folder,
|
||||
folder: {} as IFolder,
|
||||
contents: [],
|
||||
})
|
||||
expect(exec).toStrictEqual([true, true])
|
||||
|
|
|
|||
|
|
@ -3,13 +3,13 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import type { INode, IView } from '@nextcloud/files'
|
||||
import type { IFileAction, INode, IView } from '@nextcloud/files'
|
||||
|
||||
import StarOutlineSvg from '@mdi/svg/svg/star-outline.svg?raw'
|
||||
import StarSvg from '@mdi/svg/svg/star.svg?raw'
|
||||
import axios from '@nextcloud/axios'
|
||||
import { emit } from '@nextcloud/event-bus'
|
||||
import { FileAction, Permission } from '@nextcloud/files'
|
||||
import { Permission } from '@nextcloud/files'
|
||||
import { t } from '@nextcloud/l10n'
|
||||
import { encodePath } from '@nextcloud/paths'
|
||||
import { generateUrl } from '@nextcloud/router'
|
||||
|
|
@ -18,63 +18,11 @@ import PQueue from 'p-queue'
|
|||
import Vue from 'vue'
|
||||
import logger from '../logger.ts'
|
||||
|
||||
export const ACTION_FAVORITE = 'favorite'
|
||||
|
||||
const queue = new PQueue({ concurrency: 5 })
|
||||
|
||||
/**
|
||||
* If any of the nodes is not favorited, we display the favorite action.
|
||||
*
|
||||
* @param nodes - The nodes to check
|
||||
*/
|
||||
function shouldFavorite(nodes: INode[]): boolean {
|
||||
return nodes.some((node) => node.attributes.favorite !== 1)
|
||||
}
|
||||
export const ACTION_FAVORITE = 'favorite'
|
||||
|
||||
/**
|
||||
* Favorite or unfavorite a node
|
||||
*
|
||||
* @param node - The node to favorite/unfavorite
|
||||
* @param view - The current view
|
||||
* @param willFavorite - Whether to favorite or unfavorite the node
|
||||
*/
|
||||
export async function favoriteNode(node: INode, view: IView, willFavorite: boolean): Promise<boolean> {
|
||||
try {
|
||||
// TODO: migrate to webdav tags plugin
|
||||
const url = generateUrl('/apps/files/api/v1/files') + encodePath(node.path)
|
||||
await axios.post(url, {
|
||||
tags: willFavorite
|
||||
? [window.OC.TAG_FAVORITE]
|
||||
: [],
|
||||
})
|
||||
|
||||
// Let's delete if we are in the favourites view
|
||||
// AND if it is removed from the user favorites
|
||||
// AND it's in the root of the favorites view
|
||||
if (view.id === 'favorites' && !willFavorite && node.dirname === '/') {
|
||||
emit('files:node:deleted', node)
|
||||
}
|
||||
|
||||
// Update the node webdav attribute
|
||||
Vue.set(node.attributes, 'favorite', willFavorite ? 1 : 0)
|
||||
emit('files:node:updated', node)
|
||||
|
||||
// Dispatch event to whoever is interested
|
||||
if (willFavorite) {
|
||||
emit('files:favorites:added', node)
|
||||
} else {
|
||||
emit('files:favorites:removed', node)
|
||||
}
|
||||
|
||||
return true
|
||||
} catch (error) {
|
||||
const action = willFavorite ? 'adding a file to favourites' : 'removing a file from favourites'
|
||||
logger.error('Error while ' + action, { error, source: node.source, node })
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
export const action = new FileAction({
|
||||
export const action: IFileAction = {
|
||||
id: ACTION_FAVORITE,
|
||||
displayName({ nodes }) {
|
||||
return shouldFavorite(nodes)
|
||||
|
|
@ -132,4 +80,56 @@ export const action = new FileAction({
|
|||
description: t('files', 'Add or remove favorite'),
|
||||
key: 'S',
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Favorite or unfavorite a node
|
||||
*
|
||||
* @param node - The node to favorite/unfavorite
|
||||
* @param view - The current view
|
||||
* @param willFavorite - Whether to favorite or unfavorite the node
|
||||
*/
|
||||
export async function favoriteNode(node: INode, view: IView, willFavorite: boolean): Promise<boolean> {
|
||||
try {
|
||||
// TODO: migrate to webdav tags plugin
|
||||
const url = generateUrl('/apps/files/api/v1/files') + encodePath(node.path)
|
||||
await axios.post(url, {
|
||||
tags: willFavorite
|
||||
? [window.OC.TAG_FAVORITE]
|
||||
: [],
|
||||
})
|
||||
|
||||
// Let's delete if we are in the favourites view
|
||||
// AND if it is removed from the user favorites
|
||||
// AND it's in the root of the favorites view
|
||||
if (view.id === 'favorites' && !willFavorite && node.dirname === '/') {
|
||||
emit('files:node:deleted', node)
|
||||
}
|
||||
|
||||
// Update the node webdav attribute
|
||||
Vue.set(node.attributes, 'favorite', willFavorite ? 1 : 0)
|
||||
emit('files:node:updated', node)
|
||||
|
||||
// Dispatch event to whoever is interested
|
||||
if (willFavorite) {
|
||||
emit('files:favorites:added', node)
|
||||
} else {
|
||||
emit('files:favorites:removed', node)
|
||||
}
|
||||
|
||||
return true
|
||||
} catch (error) {
|
||||
const action = willFavorite ? 'adding a file to favourites' : 'removing a file from favourites'
|
||||
logger.error('Error while ' + action, { error, source: node.source, node })
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If any of the nodes is not favored, we display the favorite action.
|
||||
*
|
||||
* @param nodes - The nodes to check
|
||||
*/
|
||||
function shouldFavorite(nodes: INode[]): boolean {
|
||||
return nodes.some((node) => node.attributes.favorite !== 1)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
*/
|
||||
|
||||
import type { IFilePickerButton } from '@nextcloud/dialogs'
|
||||
import type { IFolder, INode } from '@nextcloud/files'
|
||||
import type { IFileAction, IFolder, INode } from '@nextcloud/files'
|
||||
import type { FileStat, ResponseDataDetailed, WebDAVClientError } from 'webdav'
|
||||
import type { MoveCopyResult } from './moveOrCopyActionUtils.ts'
|
||||
|
||||
|
|
@ -13,7 +13,7 @@ import CopyIconSvg from '@mdi/svg/svg/folder-multiple-outline.svg?raw'
|
|||
import { isAxiosError } from '@nextcloud/axios'
|
||||
import { FilePickerClosed, getFilePickerBuilder, openConflictPicker, showError, showLoading } from '@nextcloud/dialogs'
|
||||
import { emit } from '@nextcloud/event-bus'
|
||||
import { FileAction, FileType, getUniqueName, NodeStatus, Permission } from '@nextcloud/files'
|
||||
import { FileType, getUniqueName, NodeStatus, Permission } from '@nextcloud/files'
|
||||
import { defaultRootPath, getClient, getDefaultPropfind, resultToNode } from '@nextcloud/files/dav'
|
||||
import { t } from '@nextcloud/l10n'
|
||||
import { getConflicts } from '@nextcloud/upload'
|
||||
|
|
@ -31,7 +31,7 @@ export class HintException extends Error {}
|
|||
|
||||
export const ACTION_COPY_MOVE = 'move-copy'
|
||||
|
||||
export const action = new FileAction({
|
||||
export const action: IFileAction = {
|
||||
id: ACTION_COPY_MOVE,
|
||||
order: 15,
|
||||
displayName({ nodes }) {
|
||||
|
|
@ -84,7 +84,7 @@ export const action = new FileAction({
|
|||
return nodes.map(() => false)
|
||||
}
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the copy/move of a node to a destination
|
||||
|
|
@ -248,11 +248,11 @@ function getActionForNodes(nodes: INode[]): MoveCopyAction {
|
|||
function createLoadingNotification(mode: MoveCopyAction, sources: string[], destination: string): () => void {
|
||||
const text = mode === MoveCopyAction.MOVE
|
||||
? (sources.length === 1
|
||||
? t('files', 'Moving "{source}" to "{destination}" …', { source: sources[0], destination })
|
||||
? t('files', 'Moving "{source}" to "{destination}" …', { source: sources[0]!, destination })
|
||||
: t('files', 'Moving {count} files to "{destination}" …', { count: sources.length, destination })
|
||||
)
|
||||
: (sources.length === 1
|
||||
? t('files', 'Copying "{source}" to "{destination}" …', { source: sources[0], destination })
|
||||
? t('files', 'Copying "{source}" to "{destination}" …', { source: sources[0]!, destination })
|
||||
: t('files', 'Copying {count} files to "{destination}" …', { count: sources.length, destination })
|
||||
)
|
||||
|
||||
|
|
@ -277,7 +277,7 @@ async function openFilePickerForAction(
|
|||
const fileIDs = nodes.map((node) => node.fileid).filter(Boolean)
|
||||
const filePicker = getFilePickerBuilder(t('files', 'Choose destination'))
|
||||
.allowDirectories(true)
|
||||
.setFilter((n: INode) => {
|
||||
.setFilter((n) => {
|
||||
// We don't want to show the current nodes in the file picker
|
||||
return !fileIDs.includes(n.fileid)
|
||||
})
|
||||
|
|
@ -288,7 +288,7 @@ async function openFilePickerForAction(
|
|||
.setMimeTypeFilter([])
|
||||
.setMultiSelect(false)
|
||||
.startAt(dir)
|
||||
.setButtonFactory((selection: INode[], path: string) => {
|
||||
.setButtonFactory((selection, path) => {
|
||||
const buttons: IFilePickerButton[] = []
|
||||
const target = basename(path)
|
||||
|
||||
|
|
@ -300,9 +300,9 @@ async function openFilePickerForAction(
|
|||
label: target ? t('files', 'Copy to {target}', { target }, { escape: false, sanitize: false }) : t('files', 'Copy'),
|
||||
variant: 'primary',
|
||||
icon: CopyIconSvg,
|
||||
async callback(destination: INode[]) {
|
||||
async callback(destination) {
|
||||
resolve({
|
||||
destination: destination[0] as IFolder,
|
||||
destination: destination[0] as unknown as IFolder,
|
||||
action: MoveCopyAction.COPY,
|
||||
} as MoveCopyResult)
|
||||
},
|
||||
|
|
@ -330,9 +330,9 @@ async function openFilePickerForAction(
|
|||
label: target ? t('files', 'Move to {target}', { target }, undefined, { escape: false, sanitize: false }) : t('files', 'Move'),
|
||||
variant: action === MoveCopyAction.MOVE ? 'primary' : 'secondary',
|
||||
icon: FolderMoveSvg,
|
||||
async callback(destination: INode[]) {
|
||||
async callback(destination) {
|
||||
resolve({
|
||||
destination: destination[0] as IFolder,
|
||||
destination: destination[0] as unknown as IFolder,
|
||||
action: MoveCopyAction.MOVE,
|
||||
} as MoveCopyResult)
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,18 +1,18 @@
|
|||
/**
|
||||
/*!
|
||||
* 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 { DefaultType, File, FileAction, Folder, Permission } from '@nextcloud/files'
|
||||
import { DefaultType, File, Folder, Permission } from '@nextcloud/files'
|
||||
import { describe, expect, test, vi } from 'vitest'
|
||||
import { action } from './openFolderAction.ts'
|
||||
|
||||
const view = {
|
||||
id: 'files',
|
||||
name: 'Files',
|
||||
} as View
|
||||
} as IView
|
||||
|
||||
describe('Open folder action conditions tests', () => {
|
||||
test('Default values', () => {
|
||||
|
|
@ -24,7 +24,6 @@ describe('Open folder action conditions tests', () => {
|
|||
root: '/files/admin',
|
||||
})
|
||||
|
||||
expect(action).toBeInstanceOf(FileAction)
|
||||
expect(action.id).toBe('open-folder')
|
||||
expect(action.displayName({
|
||||
nodes: [folder],
|
||||
|
|
|
|||
|
|
@ -1,12 +1,15 @@
|
|||
/**
|
||||
/*!
|
||||
* SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
import FolderSvg from '@mdi/svg/svg/folder.svg?raw'
|
||||
import { DefaultType, FileAction, FileType, Permission } from '@nextcloud/files'
|
||||
import { translate as t } from '@nextcloud/l10n'
|
||||
|
||||
export const action = new FileAction({
|
||||
import type { IFileAction } from '@nextcloud/files'
|
||||
|
||||
import FolderSvg from '@mdi/svg/svg/folder.svg?raw'
|
||||
import { DefaultType, FileType, Permission } from '@nextcloud/files'
|
||||
import { t } from '@nextcloud/l10n'
|
||||
|
||||
export const action: IFileAction = {
|
||||
id: 'open-folder',
|
||||
displayName({ nodes }) {
|
||||
if (nodes.length !== 1 || !nodes[0]) {
|
||||
|
|
@ -51,4 +54,4 @@ export const action = new FileAction({
|
|||
// Main action if enabled, meaning folders only
|
||||
default: DefaultType.HIDDEN,
|
||||
order: -100,
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,27 +1,26 @@
|
|||
/**
|
||||
/*!
|
||||
* 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 { DefaultType, File, FileAction, Folder, Permission } from '@nextcloud/files'
|
||||
import { DefaultType, File, Folder, Permission } from '@nextcloud/files'
|
||||
import { describe, expect, test, vi } from 'vitest'
|
||||
import { action } from './openInFilesAction.ts'
|
||||
|
||||
const view = {
|
||||
id: 'files',
|
||||
name: 'Files',
|
||||
} as View
|
||||
} as IView
|
||||
|
||||
const recentView = {
|
||||
id: 'recent',
|
||||
name: 'Recent',
|
||||
} as View
|
||||
} as IView
|
||||
|
||||
describe('Open in files action conditions tests', () => {
|
||||
test('Default values', () => {
|
||||
expect(action).toBeInstanceOf(FileAction)
|
||||
expect(action.id).toBe('open-in-files')
|
||||
expect(action.displayName({
|
||||
nodes: [],
|
||||
|
|
|
|||
|
|
@ -1,12 +1,15 @@
|
|||
/**
|
||||
/*!
|
||||
* SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
import { DefaultType, FileAction, FileType } from '@nextcloud/files'
|
||||
|
||||
import type { IFileAction } from '@nextcloud/files'
|
||||
|
||||
import { DefaultType, FileType } from '@nextcloud/files'
|
||||
import { t } from '@nextcloud/l10n'
|
||||
import { VIEW_ID as SEARCH_VIEW_ID } from '../views/search.ts'
|
||||
|
||||
export const action = new FileAction({
|
||||
export const action: IFileAction = {
|
||||
id: 'open-in-files',
|
||||
displayName: () => t('files', 'Open in Files'),
|
||||
iconSvgInline: () => '',
|
||||
|
|
@ -36,4 +39,4 @@ export const action = new FileAction({
|
|||
// Before openFolderAction
|
||||
order: -1000,
|
||||
default: DefaultType.HIDDEN,
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,13 +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 nextcloudDialogs from '@nextcloud/dialogs'
|
||||
import { File, FileAction, Permission } from '@nextcloud/files'
|
||||
import { File, Permission } from '@nextcloud/files'
|
||||
import { beforeAll, beforeEach, describe, expect, test, vi } from 'vitest'
|
||||
import { action } from './openLocallyAction.ts'
|
||||
|
||||
|
|
@ -17,7 +17,7 @@ vi.mock('@nextcloud/axios')
|
|||
const view = {
|
||||
id: 'files',
|
||||
name: 'Files',
|
||||
} as View
|
||||
} as IView
|
||||
|
||||
// Mock web root variable
|
||||
beforeAll(() => {
|
||||
|
|
@ -28,18 +28,17 @@ beforeAll(() => {
|
|||
|
||||
describe('Open locally action conditions tests', () => {
|
||||
test('Default values', () => {
|
||||
expect(action).toBeInstanceOf(FileAction)
|
||||
expect(action.id).toBe('edit-locally')
|
||||
expect(action.displayName({
|
||||
nodes: [],
|
||||
view,
|
||||
folder: {} as any,
|
||||
folder: {} as IFolder,
|
||||
contents: [],
|
||||
})).toBe('Open locally')
|
||||
expect(action.iconSvgInline({
|
||||
nodes: [],
|
||||
view,
|
||||
folder: {} as any,
|
||||
folder: {} as IFolder,
|
||||
contents: [],
|
||||
})).toMatch(/<svg.+<\/svg>/)
|
||||
expect(action.default).toBeUndefined()
|
||||
|
|
@ -62,7 +61,7 @@ describe('Open locally action enabled tests', () => {
|
|||
expect(action.enabled!({
|
||||
nodes: [file],
|
||||
view,
|
||||
folder: {} as any,
|
||||
folder: {} as IFolder,
|
||||
contents: [],
|
||||
})).toBe(true)
|
||||
})
|
||||
|
|
@ -80,7 +79,7 @@ describe('Open locally action enabled tests', () => {
|
|||
expect(action.enabled!({
|
||||
nodes: [file],
|
||||
view,
|
||||
folder: {} as any,
|
||||
folder: {} as IFolder,
|
||||
contents: [],
|
||||
})).toBe(false)
|
||||
})
|
||||
|
|
@ -107,7 +106,7 @@ describe('Open locally action enabled tests', () => {
|
|||
expect(action.enabled!({
|
||||
nodes: [file1, file2],
|
||||
view,
|
||||
folder: {} as any,
|
||||
folder: {} as IFolder,
|
||||
contents: [],
|
||||
})).toBe(false)
|
||||
})
|
||||
|
|
@ -125,7 +124,7 @@ describe('Open locally action enabled tests', () => {
|
|||
expect(action.enabled!({
|
||||
nodes: [file],
|
||||
view,
|
||||
folder: {} as any,
|
||||
folder: {} as IFolder,
|
||||
contents: [],
|
||||
})).toBe(false)
|
||||
})
|
||||
|
|
@ -144,7 +143,7 @@ describe('Open locally action enabled tests', () => {
|
|||
expect(action.enabled!({
|
||||
nodes: [file],
|
||||
view,
|
||||
folder: {} as any,
|
||||
folder: {} as IFolder,
|
||||
contents: [],
|
||||
})).toBe(false)
|
||||
})
|
||||
|
|
@ -177,7 +176,7 @@ describe('Open locally action execute tests', () => {
|
|||
const exec = await action.exec({
|
||||
nodes: [file],
|
||||
view,
|
||||
folder: {} as Folder,
|
||||
folder: {} as IFolder,
|
||||
contents: [],
|
||||
})
|
||||
|
||||
|
|
@ -207,7 +206,7 @@ describe('Open locally action execute tests', () => {
|
|||
const exec = await action.exec({
|
||||
nodes: [file],
|
||||
view,
|
||||
folder: {} as Folder,
|
||||
folder: {} as IFolder,
|
||||
contents: [],
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -1,13 +1,15 @@
|
|||
/**
|
||||
/*!
|
||||
* SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import type { IFileAction } from '@nextcloud/files'
|
||||
|
||||
import LaptopSvg from '@mdi/svg/svg/laptop.svg?raw'
|
||||
import IconWeb from '@mdi/svg/svg/web.svg?raw'
|
||||
import { getCurrentUser } from '@nextcloud/auth'
|
||||
import axios from '@nextcloud/axios'
|
||||
import { DialogBuilder, showError } from '@nextcloud/dialogs'
|
||||
import { FileAction } from '@nextcloud/files'
|
||||
import { translate as t } from '@nextcloud/l10n'
|
||||
import { encodePath } from '@nextcloud/paths'
|
||||
import { generateOcsUrl } from '@nextcloud/router'
|
||||
|
|
@ -15,7 +17,7 @@ import { isPublicShare } from '@nextcloud/sharing/public'
|
|||
import logger from '../logger.ts'
|
||||
import { isSyncable } from '../utils/permissions.ts'
|
||||
|
||||
export const action = new FileAction({
|
||||
export const action: IFileAction = {
|
||||
id: 'edit-locally',
|
||||
displayName: () => t('files', 'Open locally'),
|
||||
iconSvgInline: () => LaptopSvg,
|
||||
|
|
@ -32,7 +34,7 @@ export const action = new FileAction({
|
|||
return false
|
||||
}
|
||||
|
||||
return isSyncable(nodes[0])
|
||||
return isSyncable(nodes[0]!)
|
||||
},
|
||||
|
||||
async exec({ nodes }) {
|
||||
|
|
@ -41,7 +43,7 @@ export const action = new FileAction({
|
|||
},
|
||||
|
||||
order: 25,
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to open the path in the Nextcloud client.
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import type { View } from '@nextcloud/files'
|
||||
import type { IView } from '@nextcloud/files'
|
||||
|
||||
import * as eventBus from '@nextcloud/event-bus'
|
||||
import { File, FileAction, Folder, Permission } from '@nextcloud/files'
|
||||
import { File, Folder, Permission } from '@nextcloud/files'
|
||||
import { beforeEach, describe, expect, test, vi } from 'vitest'
|
||||
import { useFilesStore } from '../store/files.ts'
|
||||
import { getPinia } from '../store/index.ts'
|
||||
|
|
@ -15,7 +15,7 @@ import { action } from './renameAction.ts'
|
|||
const view = {
|
||||
id: 'files',
|
||||
name: 'Files',
|
||||
} as View
|
||||
} as IView
|
||||
|
||||
beforeEach(() => {
|
||||
const root = new Folder({
|
||||
|
|
@ -31,7 +31,6 @@ beforeEach(() => {
|
|||
|
||||
describe('Rename action conditions tests', () => {
|
||||
test('Default values', () => {
|
||||
expect(action).toBeInstanceOf(FileAction)
|
||||
expect(action.id).toBe('rename')
|
||||
expect(action.displayName({
|
||||
nodes: [],
|
||||
|
|
|
|||
|
|
@ -1,10 +1,13 @@
|
|||
/**
|
||||
/*!
|
||||
* SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import type { IFileAction } from '@nextcloud/files'
|
||||
|
||||
import PencilSvg from '@mdi/svg/svg/pencil-outline.svg?raw'
|
||||
import { emit } from '@nextcloud/event-bus'
|
||||
import { FileAction, Permission } from '@nextcloud/files'
|
||||
import { Permission } from '@nextcloud/files'
|
||||
import { translate as t } from '@nextcloud/l10n'
|
||||
import { dirname } from 'path'
|
||||
import { useFilesStore } from '../store/files.ts'
|
||||
|
|
@ -12,7 +15,7 @@ import { getPinia } from '../store/index.ts'
|
|||
|
||||
export const ACTION_RENAME = 'rename'
|
||||
|
||||
export const action = new FileAction({
|
||||
export const action: IFileAction = {
|
||||
id: ACTION_RENAME,
|
||||
displayName: () => t('files', 'Rename'),
|
||||
iconSvgInline: () => PencilSvg,
|
||||
|
|
@ -52,4 +55,4 @@ export const action = new FileAction({
|
|||
description: t('files', 'Rename'),
|
||||
key: 'F2',
|
||||
},
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
/**
|
||||
/*!
|
||||
* SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import type { IView } from '@nextcloud/files'
|
||||
|
||||
import { File, FileAction, Folder, Permission } from '@nextcloud/files'
|
||||
import { File, Folder, Permission } from '@nextcloud/files'
|
||||
import { beforeEach, describe, expect, test, vi } from 'vitest'
|
||||
import logger from '../logger.ts'
|
||||
import { action } from './sidebarAction.ts'
|
||||
|
|
@ -32,7 +32,6 @@ beforeEach(() => {
|
|||
|
||||
describe('Open sidebar action conditions tests', () => {
|
||||
test('Default values', () => {
|
||||
expect(action).toBeInstanceOf(FileAction)
|
||||
expect(action.id).toBe('details')
|
||||
expect(action.displayName({
|
||||
nodes: [],
|
||||
|
|
|
|||
|
|
@ -3,15 +3,17 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import type { IFileAction } from '@nextcloud/files'
|
||||
|
||||
import InformationSvg from '@mdi/svg/svg/information-outline.svg?raw'
|
||||
import { FileAction, getSidebar, Permission } from '@nextcloud/files'
|
||||
import { getSidebar, Permission } from '@nextcloud/files'
|
||||
import { t } from '@nextcloud/l10n'
|
||||
import { isPublicShare } from '@nextcloud/sharing/public'
|
||||
import logger from '../logger.ts'
|
||||
|
||||
export const ACTION_DETAILS = 'details'
|
||||
|
||||
export const action = new FileAction({
|
||||
export const action: IFileAction = {
|
||||
id: ACTION_DETAILS,
|
||||
displayName: () => t('files', 'Details'),
|
||||
iconSvgInline: () => InformationSvg,
|
||||
|
|
@ -59,4 +61,4 @@ export const action = new FileAction({
|
|||
key: 'D',
|
||||
description: t('files', 'Open the details sidebar'),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,26 +1,26 @@
|
|||
/**
|
||||
/*!
|
||||
* SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
import type { View } from '@nextcloud/files'
|
||||
|
||||
import { File, FileAction, Folder, Permission } from '@nextcloud/files'
|
||||
import type { IView } from '@nextcloud/files'
|
||||
|
||||
import { File, Folder, Permission } from '@nextcloud/files'
|
||||
import { describe, expect, test, vi } from 'vitest'
|
||||
import { action } from './viewInFolderAction.ts'
|
||||
|
||||
const view = {
|
||||
id: 'trashbin',
|
||||
name: 'Trashbin',
|
||||
} as View
|
||||
} as IView
|
||||
|
||||
const viewFiles = {
|
||||
id: 'files',
|
||||
name: 'Files',
|
||||
} as View
|
||||
} as IView
|
||||
|
||||
describe('View in folder action conditions tests', () => {
|
||||
test('Default values', () => {
|
||||
expect(action).toBeInstanceOf(FileAction)
|
||||
expect(action.id).toBe('view-in-folder')
|
||||
expect(action.displayName({
|
||||
nodes: [],
|
||||
|
|
|
|||
|
|
@ -1,13 +1,16 @@
|
|||
/**
|
||||
/*!
|
||||
* SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import type { IFileAction } from '@nextcloud/files'
|
||||
|
||||
import FolderMoveSvg from '@mdi/svg/svg/folder-move-outline.svg?raw'
|
||||
import { FileAction, FileType, Permission } from '@nextcloud/files'
|
||||
import { FileType, Permission } from '@nextcloud/files'
|
||||
import { t } from '@nextcloud/l10n'
|
||||
import { isPublicShare } from '@nextcloud/sharing/public'
|
||||
|
||||
export const action = new FileAction({
|
||||
export const action: IFileAction = {
|
||||
id: 'view-in-folder',
|
||||
displayName() {
|
||||
return t('files', 'View in folder')
|
||||
|
|
@ -61,4 +64,4 @@ export const action = new FileAction({
|
|||
},
|
||||
|
||||
order: 80,
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,10 +7,10 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import type { FileAction, Folder, Node, View } from '@nextcloud/files'
|
||||
import type { IFileAction, IFolder, INode, IView } from '@nextcloud/files'
|
||||
import type { PropType } from 'vue'
|
||||
|
||||
type RenderFunction = typeof FileAction.prototype.renderInline
|
||||
type RenderFunction = IFileAction['renderInline']
|
||||
|
||||
/**
|
||||
* This component is used to render custom
|
||||
|
|
@ -22,17 +22,17 @@ export default {
|
|||
name: 'CustomElementRender',
|
||||
props: {
|
||||
source: {
|
||||
type: Object as PropType<Node>,
|
||||
type: Object as PropType<INode>,
|
||||
required: true,
|
||||
},
|
||||
|
||||
activeView: {
|
||||
type: Object as PropType<View>,
|
||||
type: Object as PropType<IView>,
|
||||
required: true,
|
||||
},
|
||||
|
||||
activeFolder: {
|
||||
type: Object as PropType<Folder>,
|
||||
type: Object as PropType<IFolder>,
|
||||
required: true,
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -121,7 +121,7 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import type { ActionContextSingle, FileAction, Node } from '@nextcloud/files'
|
||||
import type { ActionContextSingle, IFileAction, Node } from '@nextcloud/files'
|
||||
import type { PropType } from 'vue'
|
||||
|
||||
import { DefaultType, NodeStatus } from '@nextcloud/files'
|
||||
|
|
@ -179,7 +179,7 @@ export default defineComponent({
|
|||
// The file list is guaranteed to be shown with active view - thus we can set the `loaded` flag
|
||||
const activeStore = useActiveStore()
|
||||
const { isNarrow } = useFileListWidth()
|
||||
const enabledFileActions = inject<FileAction[]>('enabledFileActions', [])
|
||||
const enabledFileActions = inject<IFileAction[]>('enabledFileActions', [])
|
||||
return {
|
||||
activeStore,
|
||||
enabledFileActions,
|
||||
|
|
@ -302,7 +302,7 @@ export default defineComponent({
|
|||
},
|
||||
|
||||
methods: {
|
||||
actionDisplayName(action: FileAction) {
|
||||
actionDisplayName(action: IFileAction) {
|
||||
try {
|
||||
if ((this.gridMode || (this.isNarrow && action.inline)) && typeof action.title === 'function') {
|
||||
// if an inline action is rendered in the menu for
|
||||
|
|
@ -320,7 +320,7 @@ export default defineComponent({
|
|||
}
|
||||
},
|
||||
|
||||
isLoadingAction(action: FileAction) {
|
||||
isLoadingAction(action: IFileAction) {
|
||||
if (!this.isActive) {
|
||||
return false
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import type { FileAction, Node, TFileType } from '@nextcloud/files'
|
||||
import type { IFileAction, Node, TFileType } from '@nextcloud/files'
|
||||
import type { PropType } from 'vue'
|
||||
|
||||
import { showError } from '@nextcloud/dialogs'
|
||||
|
|
@ -92,7 +92,7 @@ export default defineComponent({
|
|||
const userConfigStore = useUserConfigStore()
|
||||
const { activeFolder, activeView } = useActiveStore()
|
||||
|
||||
const defaultFileAction = inject<FileAction | undefined>('defaultFileAction')
|
||||
const defaultFileAction = inject<IFileAction | undefined>('defaultFileAction')
|
||||
|
||||
return {
|
||||
activeFolder,
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import type { FileAction } from '@nextcloud/files'
|
||||
import type { IFileAction } from '@nextcloud/files'
|
||||
import type { PropType } from 'vue'
|
||||
import type { FileSource } from '../types.ts'
|
||||
|
||||
|
|
@ -234,7 +234,7 @@ export default defineComponent({
|
|||
}
|
||||
|
||||
return actions
|
||||
.filter((action: FileAction) => {
|
||||
.filter((action: IFileAction) => {
|
||||
if (!action.enabled) {
|
||||
return true
|
||||
}
|
||||
|
|
@ -257,7 +257,7 @@ export default defineComponent({
|
|||
},
|
||||
|
||||
defaultFileAction() {
|
||||
return this.enabledFileActions.find((action: FileAction) => action.default !== undefined)
|
||||
return this.enabledFileActions.find((action: IFileAction) => action.default !== undefined)
|
||||
},
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import type { ActionContext, FileAction, Node, View } from '@nextcloud/files'
|
||||
import type { ActionContext, IFileAction, Node, View } from '@nextcloud/files'
|
||||
import type { PropType } from 'vue'
|
||||
import type { FileSource } from '../types.ts'
|
||||
|
||||
|
|
@ -158,7 +158,7 @@ export default defineComponent({
|
|||
},
|
||||
|
||||
computed: {
|
||||
enabledFileActions(): FileAction[] {
|
||||
enabledFileActions(): IFileAction[] {
|
||||
return actions
|
||||
// We don't handle renderInline actions in this component
|
||||
.filter((action) => !action.renderInline)
|
||||
|
|
@ -178,7 +178,7 @@ export default defineComponent({
|
|||
* This means that they are not within a menu, nor
|
||||
* being the parent of submenu actions.
|
||||
*/
|
||||
enabledInlineActions(): FileAction[] {
|
||||
enabledInlineActions(): IFileAction[] {
|
||||
return this.enabledFileActions
|
||||
// Remove all actions that are not top-level actions
|
||||
.filter((action) => action.parent === undefined)
|
||||
|
|
@ -194,7 +194,7 @@ export default defineComponent({
|
|||
* Return the rest of enabled actions that are not
|
||||
* rendered inlined.
|
||||
*/
|
||||
enabledMenuActions(): FileAction[] {
|
||||
enabledMenuActions(): IFileAction[] {
|
||||
// If we're in a submenu, only render the inline
|
||||
// actions before the filtered submenu
|
||||
if (this.openedSubmenu) {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import type { FileAction } from '@nextcloud/files'
|
||||
import type { IFileAction } from '@nextcloud/files'
|
||||
|
||||
import { defineComponent } from 'vue'
|
||||
|
||||
|
|
@ -11,23 +11,23 @@ export default defineComponent({
|
|||
|
||||
data() {
|
||||
return {
|
||||
openedSubmenu: null as FileAction | null,
|
||||
openedSubmenu: null as IFileAction | null,
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
enabledSubmenuActions(): Record<string, FileAction[]> {
|
||||
return (this.enabledFileActions as FileAction[])
|
||||
enabledSubmenuActions(): Record<string, IFileAction[]> {
|
||||
return (this.enabledFileActions as IFileAction[])
|
||||
.reduce((record, action) => {
|
||||
if (action.parent !== undefined) {
|
||||
if (!record[action.parent]) {
|
||||
record[action.parent] = []
|
||||
}
|
||||
|
||||
record[action.parent].push(action)
|
||||
record[action.parent]!.push(action)
|
||||
}
|
||||
return record
|
||||
}, {} as Record<string, FileAction[]>)
|
||||
}, {} as Record<string, IFileAction[]>)
|
||||
},
|
||||
},
|
||||
|
||||
|
|
@ -38,11 +38,11 @@ export default defineComponent({
|
|||
*
|
||||
* @param action The action to check
|
||||
*/
|
||||
isValidMenu(action: FileAction): boolean {
|
||||
isValidMenu(action: IFileAction): boolean {
|
||||
return this.enabledSubmenuActions[action.id]?.length > 0
|
||||
},
|
||||
|
||||
async onBackToMenuClick(action: FileAction | null) {
|
||||
async onBackToMenuClick(action: IFileAction | null) {
|
||||
if (!action) {
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,19 +3,19 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import type { FileAction, IFolder, INode, IView } from '@nextcloud/files'
|
||||
import type { IFileAction, IFolder, INode, IView } from '@nextcloud/files'
|
||||
|
||||
import { subscribe } from '@nextcloud/event-bus'
|
||||
import { getNavigation } from '@nextcloud/files'
|
||||
import { defineStore } from 'pinia'
|
||||
import { ref, watch } from 'vue'
|
||||
import { ref, shallowRef, watch } from 'vue'
|
||||
import logger from '../logger.ts'
|
||||
|
||||
export const useActiveStore = defineStore('active', () => {
|
||||
/**
|
||||
* The currently active action
|
||||
*/
|
||||
const activeAction = ref<FileAction>()
|
||||
const activeAction = shallowRef<IFileAction>()
|
||||
|
||||
/**
|
||||
* The currently active folder
|
||||
|
|
@ -30,7 +30,7 @@ export const useActiveStore = defineStore('active', () => {
|
|||
/**
|
||||
* The current active view
|
||||
*/
|
||||
const activeView = ref<IView>()
|
||||
const activeView = shallowRef<IView>()
|
||||
|
||||
// Set the active node on the router params
|
||||
watch(activeNode, () => {
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
/**
|
||||
/*!
|
||||
* SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
import type { FileAction, Folder, Node, View } from '@nextcloud/files'
|
||||
|
||||
import type { IFileAction, IFolder, INode, IView } from '@nextcloud/files'
|
||||
import type { Upload } from '@nextcloud/upload'
|
||||
|
||||
// Global definitions
|
||||
|
|
@ -12,11 +13,11 @@ export type ViewId = string
|
|||
|
||||
// Files store
|
||||
export type FilesStore = {
|
||||
[source: FileSource]: Node
|
||||
[source: FileSource]: INode
|
||||
}
|
||||
|
||||
export type RootsStore = {
|
||||
[service: Service]: Folder
|
||||
[service: Service]: IFolder
|
||||
}
|
||||
|
||||
export type FilesState = {
|
||||
|
|
@ -25,7 +26,7 @@ export type FilesState = {
|
|||
}
|
||||
|
||||
export interface RootOptions {
|
||||
root: Folder
|
||||
root: IFolder
|
||||
service: Service
|
||||
}
|
||||
|
||||
|
|
@ -95,7 +96,7 @@ export interface ViewConfigStore {
|
|||
|
||||
// Renaming store
|
||||
export interface RenamingStore {
|
||||
renamingNode?: Node
|
||||
renamingNode?: INode
|
||||
newName: string
|
||||
}
|
||||
|
||||
|
|
@ -111,10 +112,10 @@ export interface DragAndDropStore {
|
|||
|
||||
// Active node store
|
||||
export interface ActiveStore {
|
||||
activeAction: FileAction | null
|
||||
activeFolder: Folder | null
|
||||
activeNode: Node | null
|
||||
activeView: View | null
|
||||
activeAction: IFileAction | null
|
||||
activeFolder: IFolder | null
|
||||
activeNode: INode | null
|
||||
activeView: IView | null
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
import type { ActionContextSingle, FileAction } from '@nextcloud/files'
|
||||
import type { ActionContextSingle, IFileAction } from '@nextcloud/files'
|
||||
|
||||
import { showError, showSuccess } from '@nextcloud/dialogs'
|
||||
import { NodeStatus } from '@nextcloud/files'
|
||||
|
|
@ -16,7 +16,7 @@ import { useActiveStore } from '../store/active.ts'
|
|||
*
|
||||
* @param action The action to execute
|
||||
*/
|
||||
export async function executeAction(action: FileAction) {
|
||||
export async function executeAction(action: IFileAction) {
|
||||
const activeStore = useActiveStore()
|
||||
const currentFolder = activeStore.activeFolder
|
||||
const currentNode = activeStore.activeNode
|
||||
|
|
|
|||
|
|
@ -2,7 +2,8 @@
|
|||
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
import type { Node } from '@nextcloud/files'
|
||||
|
||||
import type { INode } from '@nextcloud/files'
|
||||
import type { ShareAttribute } from '../../../files_sharing/src/sharing.ts'
|
||||
|
||||
import { Permission } from '@nextcloud/files'
|
||||
|
|
@ -13,7 +14,7 @@ import { Permission } from '@nextcloud/files'
|
|||
* @param node The node to check
|
||||
* @return True if downloadable, false otherwise
|
||||
*/
|
||||
export function isDownloadable(node: Node): boolean {
|
||||
export function isDownloadable(node: INode): boolean {
|
||||
if ((node.permissions & Permission.READ) === 0) {
|
||||
return false
|
||||
}
|
||||
|
|
@ -43,7 +44,7 @@ export function isDownloadable(node: Node): boolean {
|
|||
* @param node The node to check
|
||||
* @return True if syncable, false otherwise
|
||||
*/
|
||||
export function isSyncable(node: Node): boolean {
|
||||
export function isSyncable(node: INode): boolean {
|
||||
if (!node.isDavResource) {
|
||||
return false
|
||||
}
|
||||
|
|
|
|||
|
|
@ -167,7 +167,6 @@ export default defineComponent({
|
|||
const viewsToLoad: View[] = (Object.entries(this.viewConfigStore.viewConfigs) as Array<[string, ViewConfig]>)
|
||||
.filter(([, config]) => config.expanded === true)
|
||||
.map(([viewId]) => this.views.find((view) => view.id === viewId))
|
||||
|
||||
.filter(Boolean as unknown as ((u: unknown) => u is View))
|
||||
.filter((view) => view.loadChildViews && !view.loaded)
|
||||
for (const view of viewsToLoad) {
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import type { View } from '@nextcloud/files'
|
||||
import type { IView } from '@nextcloud/files'
|
||||
import type { IStorage } from '../types.ts'
|
||||
|
||||
import { DefaultType, File, FileAction, Folder, Permission } from '@nextcloud/files'
|
||||
import { DefaultType, File, Folder, Permission } from '@nextcloud/files'
|
||||
import { describe, expect, test } from 'vitest'
|
||||
import { StorageStatus } from '../types.ts'
|
||||
import { action } from './enterCredentialsAction.ts'
|
||||
|
|
@ -14,12 +14,12 @@ import { action } from './enterCredentialsAction.ts'
|
|||
const view = {
|
||||
id: 'files',
|
||||
name: 'Files',
|
||||
} as View
|
||||
} as IView
|
||||
|
||||
const externalStorageView = {
|
||||
id: 'extstoragemounts',
|
||||
name: 'External storage',
|
||||
} as View
|
||||
} as IView
|
||||
|
||||
describe('Enter credentials action conditions tests', () => {
|
||||
test('Default values', () => {
|
||||
|
|
@ -36,7 +36,6 @@ describe('Enter credentials action conditions tests', () => {
|
|||
},
|
||||
})
|
||||
|
||||
expect(action).toBeInstanceOf(FileAction)
|
||||
expect(action.id).toBe('credentials-external-storage')
|
||||
expect(action.displayName({
|
||||
view: externalStorageView,
|
||||
|
|
|
|||
|
|
@ -4,14 +4,14 @@
|
|||
*/
|
||||
|
||||
import type { AxiosResponse } from '@nextcloud/axios'
|
||||
import type { INode } from '@nextcloud/files'
|
||||
import type { IFileAction, INode } from '@nextcloud/files'
|
||||
import type { IStorage } from '../types.ts'
|
||||
|
||||
import LoginSvg from '@mdi/svg/svg/login.svg?raw'
|
||||
import axios from '@nextcloud/axios'
|
||||
import { showError, showSuccess } from '@nextcloud/dialogs'
|
||||
import { emit } from '@nextcloud/event-bus'
|
||||
import { DefaultType, FileAction } from '@nextcloud/files'
|
||||
import { DefaultType } from '@nextcloud/files'
|
||||
import { t } from '@nextcloud/l10n'
|
||||
import { addPasswordConfirmationInterceptors, PwdConfirmationMode } from '@nextcloud/password-confirmation'
|
||||
import { generateUrl } from '@nextcloud/router'
|
||||
|
|
@ -60,7 +60,7 @@ async function setCredentials(node: INode, login: string, password: string): Pro
|
|||
|
||||
export const ACTION_CREDENTIALS_EXTERNAL_STORAGE = 'credentials-external-storage'
|
||||
|
||||
export const action = new FileAction({
|
||||
export const action: IFileAction = {
|
||||
id: ACTION_CREDENTIALS_EXTERNAL_STORAGE,
|
||||
displayName: () => t('files', 'Enter missing credentials'),
|
||||
iconSvgInline: () => LoginSvg,
|
||||
|
|
@ -104,4 +104,4 @@ export const action = new FileAction({
|
|||
order: -1000,
|
||||
default: DefaultType.DEFAULT,
|
||||
inline: () => true,
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,12 +4,12 @@
|
|||
*/
|
||||
|
||||
import type { AxiosError } from '@nextcloud/axios'
|
||||
import type { IFileAction } from '@nextcloud/files'
|
||||
import type { IStorage } from '../types.ts'
|
||||
|
||||
import AlertSvg from '@mdi/svg/svg/alert-circle.svg?raw'
|
||||
import { showWarning } from '@nextcloud/dialogs'
|
||||
import { emit } from '@nextcloud/event-bus'
|
||||
import { FileAction } from '@nextcloud/files'
|
||||
import { t } from '@nextcloud/l10n'
|
||||
import { getStatus } from '../services/externalStorage.ts'
|
||||
import { StorageStatus } from '../types.ts'
|
||||
|
|
@ -18,7 +18,7 @@ import { isNodeExternalStorage } from '../utils/externalStorageUtils.ts'
|
|||
|
||||
import '../css/fileEntryStatus.scss'
|
||||
|
||||
export const action = new FileAction({
|
||||
export const action: IFileAction = {
|
||||
id: 'check-external-storage',
|
||||
displayName: () => '',
|
||||
iconSvgInline: () => '',
|
||||
|
|
@ -88,4 +88,4 @@ export const action = new FileAction({
|
|||
},
|
||||
|
||||
order: 10,
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,11 +3,11 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import type { View } from '@nextcloud/files'
|
||||
import type { IView } from '@nextcloud/files'
|
||||
import type { IStorage } from '../types.ts'
|
||||
|
||||
import * as dialogs from '@nextcloud/dialogs'
|
||||
import { DefaultType, FileAction, Folder, Permission } from '@nextcloud/files'
|
||||
import { DefaultType, Folder, Permission } from '@nextcloud/files'
|
||||
import { describe, expect, test, vi } from 'vitest'
|
||||
import { StorageStatus } from '../types.ts'
|
||||
import { action } from './openInFilesAction.ts'
|
||||
|
|
@ -17,12 +17,12 @@ vi.mock('@nextcloud/dialogs', { spy: true })
|
|||
const view = {
|
||||
id: 'files',
|
||||
name: 'Files',
|
||||
} as View
|
||||
} as IView
|
||||
|
||||
const externalStorageView = {
|
||||
id: 'extstoragemounts',
|
||||
name: 'External storage',
|
||||
} as View
|
||||
} as IView
|
||||
|
||||
describe('Open in files action conditions tests', () => {
|
||||
test('Default values', () => {
|
||||
|
|
@ -39,7 +39,6 @@ describe('Open in files action conditions tests', () => {
|
|||
},
|
||||
})
|
||||
|
||||
expect(action).toBeInstanceOf(FileAction)
|
||||
expect(action.id).toBe('open-in-files-external-storage')
|
||||
expect(action.displayName({
|
||||
nodes: [storage],
|
||||
|
|
|
|||
|
|
@ -3,16 +3,17 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import type { IFileAction } from '@nextcloud/files'
|
||||
import type { IStorage } from '../types.ts'
|
||||
|
||||
import { getCurrentUser } from '@nextcloud/auth'
|
||||
import { showConfirmation } from '@nextcloud/dialogs'
|
||||
import { DefaultType, FileAction } from '@nextcloud/files'
|
||||
import { DefaultType } from '@nextcloud/files'
|
||||
import { t } from '@nextcloud/l10n'
|
||||
import { generateUrl } from '@nextcloud/router'
|
||||
import { StorageStatus } from '../types.ts'
|
||||
|
||||
export const action = new FileAction({
|
||||
export const action: IFileAction = {
|
||||
id: 'open-in-files-external-storage',
|
||||
displayName: ({ nodes }) => {
|
||||
const config = nodes?.[0]?.attributes?.config as IStorage || { status: StorageStatus.Indeterminate }
|
||||
|
|
@ -54,4 +55,4 @@ export const action = new FileAction({
|
|||
// Before openFolderAction
|
||||
order: -1000,
|
||||
default: DefaultType.HIDDEN,
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/**
|
||||
/*!
|
||||
* SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
|
@ -9,7 +9,7 @@ import { action as clearAction } from './files_actions/clearReminderAction.ts'
|
|||
import { action as statusAction } from './files_actions/reminderStatusAction.ts'
|
||||
import { action as customAction } from './files_actions/setReminderCustomAction.ts'
|
||||
import { action as menuAction } from './files_actions/setReminderMenuAction.ts'
|
||||
import { actions as suggestionActions } from './files_actions/setReminderSuggestionActions.ts'
|
||||
import { getSetReminderSuggestionActions } from './files_actions/setReminderSuggestionActions.ts'
|
||||
|
||||
registerDavProperty('nc:reminder-due-date', { nc: 'http://nextcloud.org/ns' })
|
||||
|
||||
|
|
@ -17,4 +17,5 @@ registerFileAction(statusAction)
|
|||
registerFileAction(clearAction)
|
||||
registerFileAction(menuAction)
|
||||
registerFileAction(customAction)
|
||||
suggestionActions.forEach((action) => registerFileAction(action))
|
||||
getSetReminderSuggestionActions()
|
||||
.forEach(registerFileAction)
|
||||
|
|
|
|||
|
|
@ -1,15 +1,15 @@
|
|||
/**
|
||||
/*!
|
||||
* SPDX-FileCopyrightText: 2025 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 { Folder } from '@nextcloud/files'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { action } from './clearReminderAction.ts'
|
||||
|
||||
const view = {} as unknown as View
|
||||
const view = {} as unknown as IView
|
||||
|
||||
const root = new Folder({
|
||||
owner: 'user',
|
||||
|
|
|
|||
|
|
@ -1,15 +1,17 @@
|
|||
/**
|
||||
/*!
|
||||
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import type { IFileAction } from '@nextcloud/files'
|
||||
|
||||
import AlarmOffSvg from '@mdi/svg/svg/alarm-off.svg?raw'
|
||||
import { emit } from '@nextcloud/event-bus'
|
||||
import { FileAction } from '@nextcloud/files'
|
||||
import { t } from '@nextcloud/l10n'
|
||||
import { clearReminder } from '../services/reminderService.ts'
|
||||
import { getVerboseDateString } from '../shared/utils.ts'
|
||||
|
||||
export const action = new FileAction({
|
||||
export const action: IFileAction = {
|
||||
id: 'clear-reminder',
|
||||
|
||||
displayName: () => t('files_reminders', 'Clear reminder'),
|
||||
|
|
@ -48,4 +50,4 @@ export const action = new FileAction({
|
|||
},
|
||||
|
||||
order: 19,
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,15 +1,15 @@
|
|||
/**
|
||||
/*!
|
||||
* SPDX-FileCopyrightText: 2025 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 { Folder } from '@nextcloud/files'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { action } from './reminderStatusAction.ts'
|
||||
|
||||
const view = {} as unknown as View
|
||||
const view = {} as unknown as IView
|
||||
|
||||
const root = new Folder({
|
||||
owner: 'user',
|
||||
|
|
|
|||
|
|
@ -1,14 +1,16 @@
|
|||
/**
|
||||
/*!
|
||||
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import type { IFileAction } from '@nextcloud/files'
|
||||
|
||||
import AlarmSvg from '@mdi/svg/svg/alarm.svg?raw'
|
||||
import { FileAction } from '@nextcloud/files'
|
||||
import { t } from '@nextcloud/l10n'
|
||||
import { pickCustomDate } from '../services/customPicker.ts'
|
||||
import { getVerboseDateString } from '../shared/utils.ts'
|
||||
|
||||
export const action = new FileAction({
|
||||
export const action: IFileAction = {
|
||||
id: 'reminder-status',
|
||||
|
||||
inline: () => true,
|
||||
|
|
@ -41,4 +43,4 @@ export const action = new FileAction({
|
|||
},
|
||||
|
||||
order: -15,
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,16 @@
|
|||
/**
|
||||
/*!
|
||||
* SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import type { IFileAction } from '@nextcloud/files'
|
||||
|
||||
import CalendarClockSvg from '@mdi/svg/svg/calendar-clock.svg?raw'
|
||||
import { FileAction } from '@nextcloud/files'
|
||||
import { t } from '@nextcloud/l10n'
|
||||
import { pickCustomDate } from '../services/customPicker.ts'
|
||||
import { SET_REMINDER_MENU_ID } from './setReminderMenuAction.ts'
|
||||
|
||||
export const action = new FileAction({
|
||||
export const action: IFileAction = {
|
||||
id: 'set-reminder-custom',
|
||||
displayName: () => t('files_reminders', 'Custom reminder'),
|
||||
title: () => t('files_reminders', 'Reminder at custom date & time'),
|
||||
|
|
@ -37,4 +39,4 @@ export const action = new FileAction({
|
|||
|
||||
// After presets
|
||||
order: 22,
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,16 @@
|
|||
/**
|
||||
/*!
|
||||
* SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import type { IFileAction } from '@nextcloud/files'
|
||||
|
||||
import AlarmSvg from '@mdi/svg/svg/alarm.svg?raw'
|
||||
import { FileAction } from '@nextcloud/files'
|
||||
import { translate as t } from '@nextcloud/l10n'
|
||||
|
||||
export const SET_REMINDER_MENU_ID = 'set-reminder-menu'
|
||||
|
||||
export const action = new FileAction({
|
||||
export const action: IFileAction = {
|
||||
id: SET_REMINDER_MENU_ID,
|
||||
displayName: () => t('files_reminders', 'Set reminder'),
|
||||
iconSvgInline: () => AlarmSvg,
|
||||
|
|
@ -31,4 +33,4 @@ export const action = new FileAction({
|
|||
},
|
||||
|
||||
order: 20,
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,12 @@
|
|||
/**
|
||||
/*!
|
||||
* SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import type { IFileAction } from '@nextcloud/files'
|
||||
|
||||
import { showError, showSuccess } from '@nextcloud/dialogs'
|
||||
import { emit } from '@nextcloud/event-bus'
|
||||
import { FileAction } from '@nextcloud/files'
|
||||
import { t } from '@nextcloud/l10n'
|
||||
import { setReminder } from '../services/reminderService.ts'
|
||||
import { logger } from '../shared/logger.ts'
|
||||
|
|
@ -54,14 +56,45 @@ const nextWeek: ReminderOption = {
|
|||
verboseDateString: '',
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all set reminder suggestion actions from presets
|
||||
*/
|
||||
export function getSetReminderSuggestionActions() {
|
||||
[laterToday, tomorrow, thisWeekend, nextWeek].forEach((option) => {
|
||||
// Generate the initial date string
|
||||
const dateTime = getDateTime(option.dateTimePreset)
|
||||
if (!dateTime) {
|
||||
return
|
||||
}
|
||||
option.dateString = getDateString(dateTime)
|
||||
option.verboseDateString = getVerboseDateString(dateTime)
|
||||
|
||||
// Update the date string every 30 minutes
|
||||
setInterval(() => {
|
||||
const dateTime = getDateTime(option.dateTimePreset)
|
||||
if (!dateTime) {
|
||||
return
|
||||
}
|
||||
|
||||
// update the submenu remind options strings
|
||||
option.dateString = getDateString(dateTime)
|
||||
option.verboseDateString = getVerboseDateString(dateTime)
|
||||
}, 1000 * 30 * 60)
|
||||
})
|
||||
|
||||
// Generate the default preset actions
|
||||
return [laterToday, tomorrow, thisWeekend, nextWeek]
|
||||
.map(generateFileAction)
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a file action for the given option
|
||||
*
|
||||
* @param option The option to generate the action for
|
||||
* @return The file action or null if the option should not be shown
|
||||
*/
|
||||
function generateFileAction(option: ReminderOption): FileAction | null {
|
||||
return new FileAction({
|
||||
function generateFileAction(option: ReminderOption): IFileAction {
|
||||
return {
|
||||
id: `set-reminder-${option.dateTimePreset}`,
|
||||
displayName: () => `${option.label} – ${option.dateString}`,
|
||||
title: () => `${option.ariaLabel} – ${option.verboseDateString}`,
|
||||
|
|
@ -109,31 +142,5 @@ function generateFileAction(option: ReminderOption): FileAction | null {
|
|||
},
|
||||
|
||||
order: 21,
|
||||
})
|
||||
}
|
||||
|
||||
[laterToday, tomorrow, thisWeekend, nextWeek].forEach((option) => {
|
||||
// Generate the initial date string
|
||||
const dateTime = getDateTime(option.dateTimePreset)
|
||||
if (!dateTime) {
|
||||
return
|
||||
}
|
||||
option.dateString = getDateString(dateTime)
|
||||
option.verboseDateString = getVerboseDateString(dateTime)
|
||||
|
||||
// Update the date string every 30 minutes
|
||||
setInterval(() => {
|
||||
const dateTime = getDateTime(option.dateTimePreset)
|
||||
if (!dateTime) {
|
||||
return
|
||||
}
|
||||
|
||||
// update the submenu remind options strings
|
||||
option.dateString = getDateString(dateTime)
|
||||
option.verboseDateString = getVerboseDateString(dateTime)
|
||||
}, 1000 * 30 * 60)
|
||||
})
|
||||
|
||||
// Generate the default preset actions
|
||||
export const actions = [laterToday, tomorrow, thisWeekend, nextWeek]
|
||||
.map(generateFileAction) as FileAction[]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,20 +0,0 @@
|
|||
/**
|
||||
* SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { registerFileAction } from '@nextcloud/files'
|
||||
import { registerDavProperty } from '@nextcloud/files/dav'
|
||||
import { action as clearAction } from './files_actions/clearReminderAction.ts'
|
||||
import { action as statusAction } from './files_actions/reminderStatusAction.ts'
|
||||
import { action as customAction } from './files_actions/setReminderCustomAction.ts'
|
||||
import { action as menuAction } from './files_actions/setReminderMenuAction.ts'
|
||||
import { actions as suggestionActions } from './files_actions/setReminderSuggestionActions.ts'
|
||||
|
||||
registerDavProperty('nc:reminder-due-date', { nc: 'http://nextcloud.org/ns' })
|
||||
|
||||
registerFileAction(statusAction)
|
||||
registerFileAction(clearAction)
|
||||
registerFileAction(menuAction)
|
||||
registerFileAction(customAction)
|
||||
suggestionActions.forEach((action) => registerFileAction(action))
|
||||
|
|
@ -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: [],
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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],
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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: [],
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -2,19 +2,22 @@
|
|||
* SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import type { IFileAction } from '@nextcloud/files'
|
||||
|
||||
import svgHistory from '@mdi/svg/svg/history.svg?raw'
|
||||
import { getCurrentUser } from '@nextcloud/auth'
|
||||
import axios, { isAxiosError } from '@nextcloud/axios'
|
||||
import { showError } from '@nextcloud/dialogs'
|
||||
import { emit } from '@nextcloud/event-bus'
|
||||
import { FileAction, Permission } from '@nextcloud/files'
|
||||
import { Permission } from '@nextcloud/files'
|
||||
import { t } from '@nextcloud/l10n'
|
||||
import { encodePath } from '@nextcloud/paths'
|
||||
import { generateRemoteUrl } from '@nextcloud/router'
|
||||
import { TRASHBIN_VIEW_ID } from '../files_views/trashbinView.ts'
|
||||
import { logger } from '../logger.ts'
|
||||
|
||||
export const restoreAction = new FileAction({
|
||||
export const restoreAction: IFileAction = {
|
||||
id: 'restore',
|
||||
|
||||
displayName() {
|
||||
|
|
@ -68,4 +71,4 @@ export const restoreAction = new FileAction({
|
|||
order: 1,
|
||||
|
||||
inline: () => true,
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import type { Node } from '@nextcloud/files'
|
||||
import type { IFolder, Node } from '@nextcloud/files'
|
||||
|
||||
import * as ncDialogs from '@nextcloud/dialogs'
|
||||
import * as ncEventBus from '@nextcloud/event-bus'
|
||||
|
|
@ -34,7 +34,7 @@ describe('files_trashbin: file list actions - empty trashbin', () => {
|
|||
})
|
||||
|
||||
it('has display name set', () => {
|
||||
expect(emptyTrashAction.displayName({ view: trashbinView })).toBe('Empty deleted files')
|
||||
expect(emptyTrashAction.displayName({ view: trashbinView, folder: {} as IFolder, contents: [] })).toBe('Empty deleted files')
|
||||
})
|
||||
|
||||
it('has order set', () => {
|
||||
|
|
|
|||
|
|
@ -1,10 +1,12 @@
|
|||
/**
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import type { IFileListAction } from '@nextcloud/files'
|
||||
|
||||
import { getDialogBuilder } from '@nextcloud/dialogs'
|
||||
import { emit } from '@nextcloud/event-bus'
|
||||
import { FileListAction } from '@nextcloud/files'
|
||||
import { loadState } from '@nextcloud/initial-state'
|
||||
import { t } from '@nextcloud/l10n'
|
||||
import { TRASHBIN_VIEW_ID } from '../files_views/trashbinView.ts'
|
||||
|
|
@ -14,7 +16,7 @@ export type FilesTrashbinConfigState = {
|
|||
allow_delete: boolean
|
||||
}
|
||||
|
||||
export const emptyTrashAction = new FileListAction({
|
||||
export const emptyTrashAction: IFileListAction = {
|
||||
id: 'empty-trash',
|
||||
|
||||
displayName: () => t('files_trashbin', 'Empty deleted files'),
|
||||
|
|
@ -67,4 +69,4 @@ export const emptyTrashAction = new FileListAction({
|
|||
|
||||
return null
|
||||
},
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,33 +1,32 @@
|
|||
/**
|
||||
/*!
|
||||
* SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import type { View } from '@nextcloud/files'
|
||||
import type { IFolder, IView } from '@nextcloud/files'
|
||||
|
||||
import { File, FileAction, Folder, Permission } from '@nextcloud/files'
|
||||
import { File, Folder, Permission } from '@nextcloud/files'
|
||||
import { describe, expect, test } from 'vitest'
|
||||
import { action } from './bulkSystemTagsAction.ts'
|
||||
|
||||
const view = {
|
||||
id: 'files',
|
||||
name: 'Files',
|
||||
} as View
|
||||
} as IView
|
||||
|
||||
describe('Manage tags action conditions tests', () => {
|
||||
test('Default values', () => {
|
||||
expect(action).toBeInstanceOf(FileAction)
|
||||
expect(action.id).toBe('systemtags:bulk')
|
||||
expect(action.displayName({
|
||||
nodes: [],
|
||||
view,
|
||||
folder: {} as Folder,
|
||||
folder: {} as IFolder,
|
||||
contents: [],
|
||||
})).toBe('Manage tags')
|
||||
expect(action.iconSvgInline({
|
||||
nodes: [],
|
||||
view,
|
||||
folder: {} as Folder,
|
||||
folder: {} as IFolder,
|
||||
contents: [],
|
||||
})).toMatch(/<svg.+<\/svg>/)
|
||||
expect(action.default).toBeUndefined()
|
||||
|
|
@ -60,19 +59,19 @@ describe('Manage tags action enabled tests', () => {
|
|||
expect(action.enabled!({
|
||||
nodes: [file1, file2],
|
||||
view,
|
||||
folder: {} as Folder,
|
||||
folder: {} as IFolder,
|
||||
contents: [],
|
||||
})).toBe(false)
|
||||
expect(action.enabled!({
|
||||
nodes: [file1],
|
||||
view,
|
||||
folder: {} as Folder,
|
||||
folder: {} as IFolder,
|
||||
contents: [],
|
||||
})).toBe(false)
|
||||
expect(action.enabled!({
|
||||
nodes: [file2],
|
||||
view,
|
||||
folder: {} as Folder,
|
||||
folder: {} as IFolder,
|
||||
contents: [],
|
||||
})).toBe(true)
|
||||
})
|
||||
|
|
@ -91,7 +90,7 @@ describe('Manage tags action enabled tests', () => {
|
|||
expect(action.enabled!({
|
||||
nodes: [file],
|
||||
view,
|
||||
folder: {} as Folder,
|
||||
folder: {} as IFolder,
|
||||
contents: [],
|
||||
})).toBe(false)
|
||||
})
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import type { ActionContext, ActionContextSingle } from '@nextcloud/files'
|
||||
import type { ActionContext, ActionContextSingle, IFileAction } from '@nextcloud/files'
|
||||
|
||||
import TagMultipleSvg from '@mdi/svg/svg/tag-multiple-outline.svg?raw'
|
||||
import { FileAction, Permission } from '@nextcloud/files'
|
||||
import { Permission } from '@nextcloud/files'
|
||||
import { t } from '@nextcloud/l10n'
|
||||
import { isPublicShare } from '@nextcloud/sharing/public'
|
||||
import { spawnDialog } from '@nextcloud/vue/functions/dialog'
|
||||
|
|
@ -29,7 +29,7 @@ async function execBatch({ nodes }: ActionContext | ActionContextSingle): Promis
|
|||
.fill(response)
|
||||
}
|
||||
|
||||
export const action = new FileAction({
|
||||
export const action: IFileAction = {
|
||||
id: 'systemtags:bulk',
|
||||
displayName: () => t('systemtags', 'Manage tags'),
|
||||
iconSvgInline: () => TagMultipleSvg,
|
||||
|
|
@ -64,4 +64,4 @@ export const action = new FileAction({
|
|||
description: t('systemtags', 'Manage tags'),
|
||||
key: 't',
|
||||
},
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import type { Folder, View } from '@nextcloud/files'
|
||||
import type { IFolder, IView } from '@nextcloud/files'
|
||||
|
||||
import { emit, subscribe } from '@nextcloud/event-bus'
|
||||
import { File, FileAction, Permission } from '@nextcloud/files'
|
||||
import { File, Permission } from '@nextcloud/files'
|
||||
import { beforeEach, describe, expect, test, vi } from 'vitest'
|
||||
import * as serviceTagApi from '../services/api.ts'
|
||||
import { setNodeSystemTags } from '../utils.ts'
|
||||
|
|
@ -15,7 +15,7 @@ import { action } from './inlineSystemTagsAction.ts'
|
|||
const view = {
|
||||
id: 'files',
|
||||
name: 'Files',
|
||||
} as View
|
||||
} as IView
|
||||
|
||||
describe('Inline system tags action conditions tests', () => {
|
||||
test('Default values', () => {
|
||||
|
|
@ -28,18 +28,17 @@ describe('Inline system tags action conditions tests', () => {
|
|||
root: '/files/admin',
|
||||
})
|
||||
|
||||
expect(action).toBeInstanceOf(FileAction)
|
||||
expect(action.id).toBe('system-tags')
|
||||
expect(action.displayName({
|
||||
nodes: [file],
|
||||
view,
|
||||
folder: {} as Folder,
|
||||
folder: {} as IFolder,
|
||||
contents: [],
|
||||
})).toBe('')
|
||||
expect(action.iconSvgInline({
|
||||
nodes: [file],
|
||||
view,
|
||||
folder: {} as Folder,
|
||||
folder: {} as IFolder,
|
||||
contents: [],
|
||||
})).toBe('')
|
||||
expect(action.default).toBeUndefined()
|
||||
|
|
@ -49,7 +48,7 @@ describe('Inline system tags action conditions tests', () => {
|
|||
expect(action.enabled!({
|
||||
nodes: [file],
|
||||
view,
|
||||
folder: {} as Folder,
|
||||
folder: {} as IFolder,
|
||||
contents: [],
|
||||
})).toBe(true)
|
||||
})
|
||||
|
|
@ -72,7 +71,7 @@ describe('Inline system tags action conditions tests', () => {
|
|||
expect(action.enabled!({
|
||||
nodes: [file],
|
||||
view,
|
||||
folder: {} as Folder,
|
||||
folder: {} as IFolder,
|
||||
contents: [],
|
||||
})).toBe(true)
|
||||
})
|
||||
|
|
@ -98,7 +97,7 @@ describe('Inline system tags action render tests', () => {
|
|||
const result = await action.renderInline!({
|
||||
nodes: [file],
|
||||
view,
|
||||
folder: {} as Folder,
|
||||
folder: {} as IFolder,
|
||||
contents: [],
|
||||
})
|
||||
expect(result).toBeInstanceOf(HTMLElement)
|
||||
|
|
@ -123,7 +122,7 @@ describe('Inline system tags action render tests', () => {
|
|||
const result = await action.renderInline!({
|
||||
nodes: [file],
|
||||
view,
|
||||
folder: {} as Folder,
|
||||
folder: {} as IFolder,
|
||||
contents: [],
|
||||
})
|
||||
expect(result).toBeInstanceOf(HTMLElement)
|
||||
|
|
@ -148,7 +147,7 @@ describe('Inline system tags action render tests', () => {
|
|||
const result = await action.renderInline!({
|
||||
nodes: [file],
|
||||
view,
|
||||
folder: {} as Folder,
|
||||
folder: {} as IFolder,
|
||||
contents: [],
|
||||
})
|
||||
expect(result).toBeInstanceOf(HTMLElement)
|
||||
|
|
@ -178,7 +177,7 @@ describe('Inline system tags action render tests', () => {
|
|||
const result = await action.renderInline!({
|
||||
nodes: [file],
|
||||
view,
|
||||
folder: {} as Folder,
|
||||
folder: {} as IFolder,
|
||||
contents: [],
|
||||
})
|
||||
expect(result).toBeInstanceOf(HTMLElement)
|
||||
|
|
@ -208,7 +207,7 @@ describe('Inline system tags action render tests', () => {
|
|||
const result = await action.renderInline!({
|
||||
nodes: [file],
|
||||
view,
|
||||
folder: {} as Folder,
|
||||
folder: {} as IFolder,
|
||||
contents: [],
|
||||
}) as HTMLElement
|
||||
document.body.appendChild(result)
|
||||
|
|
@ -270,7 +269,7 @@ describe('Inline system tags action colors', () => {
|
|||
const result = await action.renderInline!({
|
||||
nodes: [file],
|
||||
view,
|
||||
folder: {} as Folder,
|
||||
folder: {} as IFolder,
|
||||
contents: [],
|
||||
})
|
||||
expect(result).toBeInstanceOf(HTMLElement)
|
||||
|
|
@ -297,7 +296,7 @@ describe('Inline system tags action colors', () => {
|
|||
const result = await action.renderInline!({
|
||||
nodes: [file],
|
||||
view,
|
||||
folder: {} as Folder,
|
||||
folder: {} as IFolder,
|
||||
contents: [],
|
||||
})
|
||||
expect(result).toBeInstanceOf(HTMLElement)
|
||||
|
|
@ -324,7 +323,7 @@ describe('Inline system tags action colors', () => {
|
|||
const result = await action.renderInline!({
|
||||
nodes: [file],
|
||||
view,
|
||||
folder: {} as Folder,
|
||||
folder: {} as IFolder,
|
||||
contents: [],
|
||||
}) as HTMLElement
|
||||
document.body.appendChild(result)
|
||||
|
|
|
|||
|
|
@ -3,11 +3,10 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import type { INode } from '@nextcloud/files'
|
||||
import type { IFileAction, INode } from '@nextcloud/files'
|
||||
import type { TagWithId } from '../types.ts'
|
||||
|
||||
import { subscribe } from '@nextcloud/event-bus'
|
||||
import { FileAction } from '@nextcloud/files'
|
||||
import { t } from '@nextcloud/l10n'
|
||||
import logger from '../logger.ts'
|
||||
import { fetchTags } from '../services/api.ts'
|
||||
|
|
@ -19,7 +18,7 @@ import '../css/fileEntryInlineSystemTags.scss'
|
|||
// Init tag cache
|
||||
const cache: TagWithId[] = []
|
||||
|
||||
export const action = new FileAction({
|
||||
export const action: IFileAction = {
|
||||
id: 'system-tags',
|
||||
displayName: () => '',
|
||||
iconSvgInline: () => '',
|
||||
|
|
@ -44,7 +43,7 @@ export const action = new FileAction({
|
|||
},
|
||||
|
||||
order: 0,
|
||||
})
|
||||
}
|
||||
|
||||
// Subscribe to the events
|
||||
subscribe('systemtags:node:updated', updateSystemTagsHtml)
|
||||
|
|
@ -167,11 +166,11 @@ async function renderInline(node: INode): Promise<HTMLElement> {
|
|||
}
|
||||
}
|
||||
|
||||
systemTagsElement.append(renderTag(tags[0]))
|
||||
systemTagsElement.append(renderTag(tags[0]!))
|
||||
if (tags.length === 2) {
|
||||
// Special case only two tags:
|
||||
// the overflow fake tag would take the same space as this, so render it
|
||||
systemTagsElement.append(renderTag(tags[1]))
|
||||
systemTagsElement.append(renderTag(tags[1]!))
|
||||
} else if (tags.length > 1) {
|
||||
// More tags than the one we're showing
|
||||
// So we add a overflow element indicating there are more tags
|
||||
|
|
|
|||
|
|
@ -3,21 +3,21 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import type { View } from '@nextcloud/files'
|
||||
import type { IView } from '@nextcloud/files'
|
||||
|
||||
import { DefaultType, File, FileAction, Folder, Permission } from '@nextcloud/files'
|
||||
import { DefaultType, File, Folder, Permission } from '@nextcloud/files'
|
||||
import { describe, expect, test, vi } from 'vitest'
|
||||
import { action } from './openInFilesAction.ts'
|
||||
|
||||
const view = {
|
||||
id: 'files',
|
||||
name: 'Files',
|
||||
} as View
|
||||
} as IView
|
||||
|
||||
const systemTagsView = {
|
||||
id: 'tags',
|
||||
name: 'tags',
|
||||
} as View
|
||||
} as IView
|
||||
|
||||
const validNode = new Folder({
|
||||
id: 1,
|
||||
|
|
@ -43,7 +43,6 @@ const validTag = new Folder({
|
|||
|
||||
describe('Open in files action conditions tests', () => {
|
||||
test('Default values', () => {
|
||||
expect(action).toBeInstanceOf(FileAction)
|
||||
expect(action.id).toBe('systemtags:open-in-files')
|
||||
expect(action.displayName({
|
||||
nodes: [],
|
||||
|
|
|
|||
|
|
@ -1,13 +1,15 @@
|
|||
/**
|
||||
/*!
|
||||
* SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { DefaultType, FileAction, FileType } from '@nextcloud/files'
|
||||
import type { IFileAction } from '@nextcloud/files'
|
||||
|
||||
import { DefaultType, FileType } from '@nextcloud/files'
|
||||
import { t } from '@nextcloud/l10n'
|
||||
import { systemTagsViewId } from '../files_views/systemtagsView.ts'
|
||||
|
||||
export const action = new FileAction({
|
||||
export const action: IFileAction = {
|
||||
id: 'systemtags:open-in-files',
|
||||
displayName: () => t('systemtags', 'Open in Files'),
|
||||
iconSvgInline: () => '',
|
||||
|
|
@ -47,4 +49,4 @@ export const action = new FileAction({
|
|||
// Before openFolderAction
|
||||
order: -1000,
|
||||
default: DefaultType.HIDDEN,
|
||||
})
|
||||
}
|
||||
|
|
|
|||
353
build/frontend-legacy/package-lock.json
generated
353
build/frontend-legacy/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -35,7 +35,7 @@
|
|||
"@nextcloud/capabilities": "^1.2.1",
|
||||
"@nextcloud/dialogs": "^7.2.0",
|
||||
"@nextcloud/event-bus": "^3.3.3",
|
||||
"@nextcloud/files": "^4.0.0-rc.0",
|
||||
"@nextcloud/files": "^4.0.0-rc.1",
|
||||
"@nextcloud/initial-state": "^3.0.0",
|
||||
"@nextcloud/l10n": "^3.4.1",
|
||||
"@nextcloud/logger": "^3.0.3",
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@
|
|||
*/
|
||||
|
||||
import type { User } from '@nextcloud/e2e-test-server/cypress'
|
||||
import type { IFileAction } from '@nextcloud/files'
|
||||
|
||||
import { FileAction } from '@nextcloud/files'
|
||||
import { getActionButtonForFileId, getActionEntryForFileId, getRowForFile, getSelectionActionButton, getSelectionActionEntry, selectRowForFile } from './FilesUtils.ts'
|
||||
|
||||
const ACTION_DELETE = 'delete'
|
||||
|
|
@ -14,7 +14,7 @@ const ACTION_DETAILS = 'details'
|
|||
|
||||
declare global {
|
||||
interface Window {
|
||||
_nc_fileactions: FileAction[]
|
||||
_nc_fileactions: IFileAction[]
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -58,28 +58,28 @@ describe('Files: Actions', { testIsolation: true }, () => {
|
|||
})
|
||||
|
||||
it('Show some nested actions', () => {
|
||||
const parent = new FileAction({
|
||||
const parent: IFileAction = {
|
||||
id: 'nested-action',
|
||||
displayName: () => 'Nested Action',
|
||||
exec: cy.spy(),
|
||||
iconSvgInline: () => '<svg></svg>',
|
||||
})
|
||||
}
|
||||
|
||||
const child1 = new FileAction({
|
||||
const child1: IFileAction = {
|
||||
id: 'nested-child-1',
|
||||
displayName: () => 'Nested Child 1',
|
||||
exec: cy.spy(),
|
||||
iconSvgInline: () => '<svg></svg>',
|
||||
parent: 'nested-action',
|
||||
})
|
||||
}
|
||||
|
||||
const child2 = new FileAction({
|
||||
const child2: IFileAction = {
|
||||
id: 'nested-child-2',
|
||||
displayName: () => 'Nested Child 2',
|
||||
exec: cy.spy(),
|
||||
iconSvgInline: () => '<svg></svg>',
|
||||
parent: 'nested-action',
|
||||
})
|
||||
}
|
||||
|
||||
cy.visit('/apps/files', {
|
||||
// Cannot use registerFileAction here
|
||||
|
|
@ -147,30 +147,30 @@ describe('Files: Actions', { testIsolation: true }, () => {
|
|||
})
|
||||
|
||||
it('Show some nested actions for a selection', () => {
|
||||
const parent = new FileAction({
|
||||
const parent: IFileAction = {
|
||||
id: 'nested-action',
|
||||
displayName: () => 'Nested Action',
|
||||
exec: cy.spy(),
|
||||
iconSvgInline: () => '<svg></svg>',
|
||||
})
|
||||
}
|
||||
|
||||
const child1 = new FileAction({
|
||||
const child1: IFileAction = {
|
||||
id: 'nested-child-1',
|
||||
displayName: () => 'Nested Child 1',
|
||||
exec: cy.spy(),
|
||||
execBatch: cy.spy(),
|
||||
iconSvgInline: () => '<svg></svg>',
|
||||
parent: 'nested-action',
|
||||
})
|
||||
}
|
||||
|
||||
const child2 = new FileAction({
|
||||
const child2: IFileAction = {
|
||||
id: 'nested-child-2',
|
||||
displayName: () => 'Nested Child 2',
|
||||
exec: cy.spy(),
|
||||
execBatch: cy.spy(),
|
||||
iconSvgInline: () => '<svg></svg>',
|
||||
parent: 'nested-action',
|
||||
})
|
||||
}
|
||||
|
||||
cy.visit('/apps/files', {
|
||||
// Cannot use registerFileAction here
|
||||
|
|
@ -220,28 +220,28 @@ describe('Files: Actions', { testIsolation: true }, () => {
|
|||
})
|
||||
|
||||
it('Do not show parent if nested action has no batch support', () => {
|
||||
const parent = new FileAction({
|
||||
const parent: IFileAction = {
|
||||
id: 'nested-action',
|
||||
displayName: () => 'Nested Action',
|
||||
exec: cy.spy(),
|
||||
iconSvgInline: () => '<svg></svg>',
|
||||
})
|
||||
}
|
||||
|
||||
const child1 = new FileAction({
|
||||
const child1: IFileAction = {
|
||||
id: 'nested-child-1',
|
||||
displayName: () => 'Nested Child 1',
|
||||
exec: cy.spy(),
|
||||
iconSvgInline: () => '<svg></svg>',
|
||||
parent: 'nested-action',
|
||||
})
|
||||
}
|
||||
|
||||
const child2 = new FileAction({
|
||||
const child2: IFileAction = {
|
||||
id: 'nested-child-2',
|
||||
displayName: () => 'Nested Child 2',
|
||||
exec: cy.spy(),
|
||||
iconSvgInline: () => '<svg></svg>',
|
||||
parent: 'nested-action',
|
||||
})
|
||||
}
|
||||
|
||||
cy.visit('/apps/files', {
|
||||
// Cannot use registerFileAction here
|
||||
|
|
|
|||
2
dist/1035-1035.js.license
vendored
2
dist/1035-1035.js.license
vendored
|
|
@ -56,7 +56,7 @@ This file is generated from multiple sources. Included packages:
|
|||
- version: 3.3.3
|
||||
- license: GPL-3.0-or-later
|
||||
- @nextcloud/files
|
||||
- version: 4.0.0-rc.0
|
||||
- version: 4.0.0-rc.1
|
||||
- license: AGPL-3.0-or-later
|
||||
- @nextcloud/initial-state
|
||||
- version: 3.0.0
|
||||
|
|
|
|||
2
dist/1598-1598.js.license
vendored
2
dist/1598-1598.js.license
vendored
|
|
@ -91,7 +91,7 @@ This file is generated from multiple sources. Included packages:
|
|||
- version: 3.3.3
|
||||
- license: GPL-3.0-or-later
|
||||
- @nextcloud/files
|
||||
- version: 4.0.0-rc.0
|
||||
- version: 4.0.0-rc.1
|
||||
- license: AGPL-3.0-or-later
|
||||
- @nextcloud/initial-state
|
||||
- version: 3.0.0
|
||||
|
|
|
|||
2
dist/2915-2915.js.license
vendored
2
dist/2915-2915.js.license
vendored
|
|
@ -84,7 +84,7 @@ This file is generated from multiple sources. Included packages:
|
|||
- version: 3.3.3
|
||||
- license: GPL-3.0-or-later
|
||||
- @nextcloud/files
|
||||
- version: 4.0.0-rc.0
|
||||
- version: 4.0.0-rc.1
|
||||
- license: AGPL-3.0-or-later
|
||||
- @nextcloud/initial-state
|
||||
- version: 3.0.0
|
||||
|
|
|
|||
3
dist/4471-4471.js.license
vendored
3
dist/4471-4471.js.license
vendored
|
|
@ -43,9 +43,6 @@ This file is generated from multiple sources. Included packages:
|
|||
- @nextcloud/capabilities
|
||||
- version: 1.2.1
|
||||
- license: GPL-3.0-or-later
|
||||
- @nextcloud/paths
|
||||
- version: 3.0.0
|
||||
- license: GPL-3.0-or-later
|
||||
- @nextcloud/files
|
||||
- version: 3.12.2
|
||||
- license: AGPL-3.0-or-later
|
||||
|
|
|
|||
3
dist/7004-7004.js.license
vendored
3
dist/7004-7004.js.license
vendored
|
|
@ -51,9 +51,6 @@ This file is generated from multiple sources. Included packages:
|
|||
- @nextcloud/capabilities
|
||||
- version: 1.2.1
|
||||
- license: GPL-3.0-or-later
|
||||
- @nextcloud/paths
|
||||
- version: 3.0.0
|
||||
- license: GPL-3.0-or-later
|
||||
- @nextcloud/files
|
||||
- version: 3.12.2
|
||||
- license: AGPL-3.0-or-later
|
||||
|
|
|
|||
4
dist/7394-7394.js
vendored
4
dist/7394-7394.js
vendored
File diff suppressed because one or more lines are too long
3
dist/7394-7394.js.license
vendored
3
dist/7394-7394.js.license
vendored
|
|
@ -60,9 +60,6 @@ This file is generated from multiple sources. Included packages:
|
|||
- @nextcloud/capabilities
|
||||
- version: 1.2.1
|
||||
- license: GPL-3.0-or-later
|
||||
- @nextcloud/paths
|
||||
- version: 3.0.0
|
||||
- license: GPL-3.0-or-later
|
||||
- @nextcloud/files
|
||||
- version: 3.12.2
|
||||
- license: AGPL-3.0-or-later
|
||||
|
|
|
|||
2
dist/7394-7394.js.map
vendored
2
dist/7394-7394.js.map
vendored
File diff suppressed because one or more lines are too long
6
dist/8127-8127.js.license
vendored
6
dist/8127-8127.js.license
vendored
|
|
@ -36,9 +36,6 @@ This file is generated from multiple sources. Included packages:
|
|||
- @nextcloud/capabilities
|
||||
- version: 1.2.1
|
||||
- license: GPL-3.0-or-later
|
||||
- @nextcloud/paths
|
||||
- version: 3.0.0
|
||||
- license: GPL-3.0-or-later
|
||||
- @nextcloud/files
|
||||
- version: 3.12.2
|
||||
- license: AGPL-3.0-or-later
|
||||
|
|
@ -69,6 +66,9 @@ This file is generated from multiple sources. Included packages:
|
|||
- @nextcloud/logger
|
||||
- version: 3.0.3
|
||||
- license: GPL-3.0-or-later
|
||||
- @nextcloud/paths
|
||||
- version: 3.0.0
|
||||
- license: GPL-3.0-or-later
|
||||
- @nextcloud/router
|
||||
- version: 3.1.0
|
||||
- license: GPL-3.0-or-later
|
||||
|
|
|
|||
2
dist/8577-8577.js.license
vendored
2
dist/8577-8577.js.license
vendored
|
|
@ -108,7 +108,7 @@ This file is generated from multiple sources. Included packages:
|
|||
- version: 3.3.3
|
||||
- license: GPL-3.0-or-later
|
||||
- @nextcloud/files
|
||||
- version: 4.0.0-rc.0
|
||||
- version: 4.0.0-rc.1
|
||||
- license: AGPL-3.0-or-later
|
||||
- @nextcloud/initial-state
|
||||
- version: 3.0.0
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
4
dist/comments-comments-app.js
vendored
4
dist/comments-comments-app.js
vendored
File diff suppressed because one or more lines are too long
2
dist/comments-comments-app.js.map
vendored
2
dist/comments-comments-app.js.map
vendored
File diff suppressed because one or more lines are too long
4
dist/comments-comments-tab.js
vendored
4
dist/comments-comments-tab.js
vendored
File diff suppressed because one or more lines are too long
2
dist/comments-comments-tab.js.license
vendored
2
dist/comments-comments-tab.js.license
vendored
|
|
@ -73,7 +73,7 @@ This file is generated from multiple sources. Included packages:
|
|||
- version: 3.3.3
|
||||
- license: GPL-3.0-or-later
|
||||
- @nextcloud/files
|
||||
- version: 4.0.0-rc.0
|
||||
- version: 4.0.0-rc.1
|
||||
- license: AGPL-3.0-or-later
|
||||
- @nextcloud/initial-state
|
||||
- version: 3.0.0
|
||||
|
|
|
|||
2
dist/comments-comments-tab.js.map
vendored
2
dist/comments-comments-tab.js.map
vendored
File diff suppressed because one or more lines are too long
4
dist/comments-init.js
vendored
4
dist/comments-init.js
vendored
File diff suppressed because one or more lines are too long
2
dist/comments-init.js.license
vendored
2
dist/comments-init.js.license
vendored
|
|
@ -41,7 +41,7 @@ This file is generated from multiple sources. Included packages:
|
|||
- version: 3.3.3
|
||||
- license: GPL-3.0-or-later
|
||||
- @nextcloud/files
|
||||
- version: 4.0.0-rc.0
|
||||
- version: 4.0.0-rc.1
|
||||
- license: AGPL-3.0-or-later
|
||||
- @nextcloud/initial-state
|
||||
- version: 3.0.0
|
||||
|
|
|
|||
2
dist/comments-init.js.map
vendored
2
dist/comments-init.js.map
vendored
File diff suppressed because one or more lines are too long
4
dist/core-common.js
vendored
4
dist/core-common.js
vendored
File diff suppressed because one or more lines are too long
5
dist/core-common.js.license
vendored
5
dist/core-common.js.license
vendored
|
|
@ -123,9 +123,6 @@ This file is generated from multiple sources. Included packages:
|
|||
- @nextcloud/capabilities
|
||||
- version: 1.2.1
|
||||
- license: GPL-3.0-or-later
|
||||
- @nextcloud/paths
|
||||
- version: 3.0.0
|
||||
- license: GPL-3.0-or-later
|
||||
- @nextcloud/files
|
||||
- version: 3.12.2
|
||||
- license: AGPL-3.0-or-later
|
||||
|
|
@ -157,7 +154,7 @@ This file is generated from multiple sources. Included packages:
|
|||
- version: 3.3.3
|
||||
- license: GPL-3.0-or-later
|
||||
- @nextcloud/files
|
||||
- version: 4.0.0-rc.0
|
||||
- version: 4.0.0-rc.1
|
||||
- license: AGPL-3.0-or-later
|
||||
- @nextcloud/initial-state
|
||||
- version: 3.0.0
|
||||
|
|
|
|||
2
dist/core-common.js.map
vendored
2
dist/core-common.js.map
vendored
File diff suppressed because one or more lines are too long
4
dist/core-legacy-unified-search.js
vendored
4
dist/core-legacy-unified-search.js
vendored
File diff suppressed because one or more lines are too long
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue