diff options
Diffstat (limited to 'apps/files/src')
-rw-r--r-- | apps/files/src/actions/downloadAction.ts | 3 | ||||
-rw-r--r-- | apps/files/src/actions/favoriteAction.spec.ts | 3 | ||||
-rw-r--r-- | apps/files/src/actions/favoriteAction.ts | 13 | ||||
-rw-r--r-- | apps/files/src/actions/sidebarAction.spec.ts | 19 | ||||
-rw-r--r-- | apps/files/src/actions/sidebarAction.ts | 6 | ||||
-rw-r--r-- | apps/files/src/actions/viewInFolderAction.spec.ts | 20 | ||||
-rw-r--r-- | apps/files/src/actions/viewInFolderAction.ts | 6 | ||||
-rw-r--r-- | apps/files/src/components/FileEntry.vue | 29 | ||||
-rw-r--r-- | apps/files/src/components/FilesListVirtual.vue | 1 | ||||
-rw-r--r-- | apps/files/src/store/files.ts | 2 | ||||
-rw-r--r-- | apps/files/src/views/favorites.ts | 17 |
11 files changed, 94 insertions, 25 deletions
diff --git a/apps/files/src/actions/downloadAction.ts b/apps/files/src/actions/downloadAction.ts index 44e9fa4b379..13fcde61063 100644 --- a/apps/files/src/actions/downloadAction.ts +++ b/apps/files/src/actions/downloadAction.ts @@ -19,12 +19,11 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. * */ -import { emit } from '@nextcloud/event-bus' import { Permission, Node, FileType } from '@nextcloud/files' import { translate as t } from '@nextcloud/l10n' import ArrowDownSvg from '@mdi/svg/svg/arrow-down.svg?raw' -import { registerFileAction, FileAction } from '../services/FileAction' +import { registerFileAction, FileAction, DefaultType } from '../services/FileAction' import { generateUrl } from '@nextcloud/router' import type { Navigation } from '../services/Navigation' diff --git a/apps/files/src/actions/favoriteAction.spec.ts b/apps/files/src/actions/favoriteAction.spec.ts index 48a00094a0d..57957e67a33 100644 --- a/apps/files/src/actions/favoriteAction.spec.ts +++ b/apps/files/src/actions/favoriteAction.spec.ts @@ -22,7 +22,7 @@ import * as favoriteAction from './favoriteAction' import { action } from './favoriteAction' import { expect } from '@jest/globals' -import { File, Folder, Permission } from '@nextcloud/files' +import { File, Permission } from '@nextcloud/files' import { FileAction } from '../services/FileAction' import * as eventBus from '@nextcloud/event-bus' import axios from '@nextcloud/axios' @@ -120,6 +120,7 @@ describe('Favorite action enabled tests', () => { source: 'https://cloud.domain.com/remote.php/dav/files/admin/foobar.txt', owner: 'admin', mime: 'text/plain', + permissions: Permission.ALL, }) expect(action.enabled).toBeDefined() diff --git a/apps/files/src/actions/favoriteAction.ts b/apps/files/src/actions/favoriteAction.ts index 1ae77b6fb21..a33aacf4947 100644 --- a/apps/files/src/actions/favoriteAction.ts +++ b/apps/files/src/actions/favoriteAction.ts @@ -20,13 +20,15 @@ * */ import { emit } from '@nextcloud/event-bus' +import { generateUrl } from '@nextcloud/router' +import { Permission, type Node } from '@nextcloud/files' import { translate as t } from '@nextcloud/l10n' import axios from '@nextcloud/axios' -import StarSvg from '@mdi/svg/svg/star.svg?raw' +import Vue from 'vue' + import StarOutlineSvg from '@mdi/svg/svg/star-outline.svg?raw' -import type { Node } from '@nextcloud/files' +import StarSvg from '@mdi/svg/svg/star.svg?raw' -import { generateUrl } from '@nextcloud/router' import { registerFileAction, FileAction } from '../services/FileAction' import logger from '../logger.js' import type { Navigation } from '../services/Navigation' @@ -54,7 +56,7 @@ export const favoriteNode = async (node: Node, view: Navigation, willFavorite: b } // Update the node webdav attribute - node.attributes.favorite = willFavorite ? 1 : 0 + Vue.set(node.attributes, 'favorite', willFavorite ? 1 : 0) // Dispatch event to whoever is interested if (willFavorite) { @@ -85,8 +87,9 @@ export const action = new FileAction({ }, enabled(nodes: Node[]) { - // We can only favorite nodes within files + // We can only favorite nodes within files and with permissions return !nodes.some(node => !node.root?.startsWith?.('/files')) + && nodes.every(node => node.permissions !== Permission.NONE) }, async exec(node: Node, view: Navigation) { diff --git a/apps/files/src/actions/sidebarAction.spec.ts b/apps/files/src/actions/sidebarAction.spec.ts index c4750092ebc..69eabe4be79 100644 --- a/apps/files/src/actions/sidebarAction.spec.ts +++ b/apps/files/src/actions/sidebarAction.spec.ts @@ -21,7 +21,7 @@ */ import { action } from './sidebarAction' import { expect } from '@jest/globals' -import { File } from '@nextcloud/files' +import { File, Permission } from '@nextcloud/files' import { FileAction } from '../services/FileAction' import type { Navigation } from '../services/Navigation' import logger from '../logger' @@ -51,12 +51,29 @@ describe('Open sidebar action enabled tests', () => { source: 'https://cloud.domain.com/remote.php/dav/files/admin/foobar.txt', owner: 'admin', mime: 'text/plain', + permissions: Permission.ALL, }) expect(action.enabled).toBeDefined() expect(action.enabled!([file], view)).toBe(true) }) + test('Disabled without permissions', () => { + window.OCA = { Files: { Sidebar: {} } } + + const file = new File({ + id: 1, + source: 'https://cloud.domain.com/remote.php/dav/files/admin/foobar.txt', + owner: 'admin', + mime: 'text/plain', + permissions: Permission.NONE, + }) + + expect(action.enabled).toBeDefined() + expect(action.enabled!([file], view)).toBe(false) + + }) + test('Disabled if more than one node', () => { window.OCA = { Files: { Sidebar: {} } } diff --git a/apps/files/src/actions/sidebarAction.ts b/apps/files/src/actions/sidebarAction.ts index 141cd75ff19..6c553d97902 100644 --- a/apps/files/src/actions/sidebarAction.ts +++ b/apps/files/src/actions/sidebarAction.ts @@ -21,9 +21,9 @@ */ import { translate as t } from '@nextcloud/l10n' import InformationSvg from '@mdi/svg/svg/information-variant.svg?raw' -import type { Node } from '@nextcloud/files' +import { Permission, type Node } from '@nextcloud/files' -import { registerFileAction, FileAction, DefaultType } from '../services/FileAction' +import { registerFileAction, FileAction } from '../services/FileAction' import logger from '../logger.js' export const ACTION_DETAILS = 'details' @@ -45,7 +45,7 @@ export const action = new FileAction({ return false } - return nodes[0].root?.startsWith('/files/') ?? false + return (nodes[0].root?.startsWith('/files/') && nodes[0].permissions !== Permission.NONE) ?? false }, async exec(node: Node) { diff --git a/apps/files/src/actions/viewInFolderAction.spec.ts b/apps/files/src/actions/viewInFolderAction.spec.ts index b16f2663f33..887ed5d47c6 100644 --- a/apps/files/src/actions/viewInFolderAction.spec.ts +++ b/apps/files/src/actions/viewInFolderAction.spec.ts @@ -48,12 +48,26 @@ describe('View in folder action enabled tests', () => { source: 'https://cloud.domain.com/remote.php/dav/files/admin/foobar.txt', owner: 'admin', mime: 'text/plain', + permissions: Permission.ALL, }) expect(action.enabled).toBeDefined() expect(action.enabled!([file], view)).toBe(true) }) + test('Disabled without permissions', () => { + const file = new File({ + id: 1, + source: 'https://cloud.domain.com/remote.php/dav/files/admin/foobar.txt', + owner: 'admin', + mime: 'text/plain', + permissions: Permission.NONE, + }) + + expect(action.enabled).toBeDefined() + expect(action.enabled!([file], view)).toBe(false) + }) + test('Disabled for non-dav ressources', () => { const file = new File({ id: 1, @@ -107,13 +121,14 @@ describe('View in folder action execute tests', () => { source: 'https://cloud.domain.com/remote.php/dav/files/admin/foobar.txt', owner: 'admin', mime: 'text/plain', + permissions: Permission.READ, }) const exec = await action.exec(file, view, '/') // Silent action expect(exec).toBe(null) expect(goToRouteMock).toBeCalledTimes(1) - expect(goToRouteMock).toBeCalledWith(null, { view: 'files' }, { dir: '/' }) + expect(goToRouteMock).toBeCalledWith(null, { fileid: 1, view: 'files' }, { fileid: 1, dir: '/' }) }) test('View in (sub) folder', async () => { @@ -126,13 +141,14 @@ describe('View in folder action execute tests', () => { root: '/files/admin', owner: 'admin', mime: 'text/plain', + permissions: Permission.READ, }) const exec = await action.exec(file, view, '/') // Silent action expect(exec).toBe(null) expect(goToRouteMock).toBeCalledTimes(1) - expect(goToRouteMock).toBeCalledWith(null, { view: 'files' }, { dir: '/Foo/Bar' }) + expect(goToRouteMock).toBeCalledWith(null, { fileid: 1, view: 'files' }, { fileid: 1, dir: '/Foo/Bar' }) }) test('View in folder fails without node', async () => { diff --git a/apps/files/src/actions/viewInFolderAction.ts b/apps/files/src/actions/viewInFolderAction.ts index 67e276112dc..2f603e6cf3a 100644 --- a/apps/files/src/actions/viewInFolderAction.ts +++ b/apps/files/src/actions/viewInFolderAction.ts @@ -19,7 +19,7 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. * */ -import { Node, FileType } from '@nextcloud/files' +import { Node, FileType, Permission } from '@nextcloud/files' import { translate as t } from '@nextcloud/l10n' import FolderMoveSvg from '@mdi/svg/svg/folder-move.svg?raw' @@ -46,6 +46,10 @@ export const action = new FileAction({ return false } + if (node.permissions === Permission.NONE) { + return false + } + return node.type === FileType.File }, diff --git a/apps/files/src/components/FileEntry.vue b/apps/files/src/components/FileEntry.vue index 58b914041b2..672d7a0de33 100644 --- a/apps/files/src/components/FileEntry.vue +++ b/apps/files/src/components/FileEntry.vue @@ -150,7 +150,7 @@ <script lang='ts'> import { debounce } from 'debounce' import { emit } from '@nextcloud/event-bus' -import { formatFileSize } from '@nextcloud/files' +import { formatFileSize, Permission } from '@nextcloud/files' import { Fragment } from 'vue-frag' import { showError, showSuccess } from '@nextcloud/dialogs' import { translate } from '@nextcloud/l10n' @@ -166,6 +166,7 @@ import NcLoadingIcon from '@nextcloud/vue/dist/Components/NcLoadingIcon.js' import NcTextField from '@nextcloud/vue/dist/Components/NcTextField.js' import StarIcon from 'vue-material-design-icons/Star.vue' import Vue from 'vue' +import type moment from 'moment' import { ACTION_DETAILS } from '../actions/sidebarAction.ts' import { getFileActions, DefaultType } from '../services/FileAction.ts' @@ -173,7 +174,6 @@ import { hashCode } from '../utils/hashUtils.ts' import { isCachedPreview } from '../services/PreviewService.ts' import { useActionsMenuStore } from '../store/actionsmenu.ts' import { useFilesStore } from '../store/files.ts' -import type moment from 'moment' import { useKeyboardStore } from '../store/keyboard.ts' import { useSelectionStore } from '../store/selection.ts' import { useUserConfigStore } from '../store/userconfig.ts' @@ -336,11 +336,16 @@ export default Vue.extend({ } } + if (this.source?.permissions & Permission.READ) { + return { + download: this.source.basename, + href: this.source.source, + title: this.t('files', 'Download file {name}', { name: this.displayName }), + } + } + return { - download: this.source.basename, - href: this.source.source, - // TODO: Use first action title ? - title: this.t('files', 'Download file {name}', { name: this.displayName }), + is: 'span', } }, @@ -398,7 +403,15 @@ export default Vue.extend({ // Actions shown in the menu enabledMenuActions() { - return this.enabledActions.filter(action => action.default !== DefaultType.HIDDEN) + return [ + // Showing inline first for the NcActions inline prop + ...this.enabledInlineActions, + // Then the rest + ...this.enabledActions.filter(action => action.default !== DefaultType.HIDDEN), + ].filter((value, index, self) => { + // Then we filter duplicates to prevent inline actions to be shown twice + return index === self.findIndex(action => action.id === value.id) + }) }, openedMenu: { get() { @@ -602,7 +615,7 @@ export default Vue.extend({ }, openDetailsIfAvailable(event) { - const detailsAction = this.enabledDefaultActions.find(action => action.id === ACTION_DETAILS) + const detailsAction = this.enabledActions.find(action => action.id === ACTION_DETAILS) if (detailsAction) { event.preventDefault() event.stopPropagation() diff --git a/apps/files/src/components/FilesListVirtual.vue b/apps/files/src/components/FilesListVirtual.vue index c1d5c041992..e215714882c 100644 --- a/apps/files/src/components/FilesListVirtual.vue +++ b/apps/files/src/components/FilesListVirtual.vue @@ -322,6 +322,7 @@ export default Vue.extend({ } .files-list__row-name-text { + color: var(--color-main-text); // Make some space for the outline padding: 5px 10px; margin-left: -10px; diff --git a/apps/files/src/store/files.ts b/apps/files/src/store/files.ts index ac62512988b..c36ebcfecc2 100644 --- a/apps/files/src/store/files.ts +++ b/apps/files/src/store/files.ts @@ -58,7 +58,7 @@ export const useFilesStore = function(...args) { // Update the store all at once const files = nodes.reduce((acc, node) => { if (!node.fileid) { - logger.warn('Trying to update/set a node without fileid', node) + logger.error('Trying to update/set a node without fileid', node) return acc } acc[node.fileid] = node diff --git a/apps/files/src/views/favorites.ts b/apps/files/src/views/favorites.ts index 73293668664..571db4faab3 100644 --- a/apps/files/src/views/favorites.ts +++ b/apps/files/src/views/favorites.ts @@ -129,9 +129,16 @@ export default () => { // Add a folder to the favorites paths array and update the views const addPathToFavorites = function(path: string) { const view = generateFolderView(path) + + // Skip if already exists + if (favoriteFolders.find(folder => folder === path)) { + return + } + // Update arrays favoriteFolders.push(path) favoriteFoldersViews.push(view) + // Update and sort views updateAndSortViews() Navigation.register(view) @@ -140,10 +147,18 @@ export default () => { // Remove a folder from the favorites paths array and update the views const removePathFromFavorites = function(path: string) { const id = generateIdFromPath(path) - const index = favoriteFolders.findIndex(f => f === path) + const index = favoriteFolders.findIndex(folder => folder === path) + + // Skip if not exists + if (index === -1) { + return + } + // Update arrays favoriteFolders.splice(index, 1) favoriteFoldersViews.splice(index, 1) + + // Update and sort views Navigation.remove(id) updateAndSortViews() } |