diff options
author | John Molakvoæ <skjnldsv@protonmail.com> | 2023-08-18 10:59:14 +0200 |
---|---|---|
committer | John Molakvoæ <skjnldsv@protonmail.com> | 2023-08-23 14:03:50 +0200 |
commit | b4e71ad0fb282fbc9981924b9783ae6659a9e4fe (patch) | |
tree | ac0a921804b87d6c5707dc87c3041938aec505a6 | |
parent | c9a197e6dd699942b0cf36504ff1fa5f5ef26893 (diff) | |
download | nextcloud-server-b4e71ad0fb282fbc9981924b9783ae6659a9e4fe.tar.gz nextcloud-server-b4e71ad0fb282fbc9981924b9783ae6659a9e4fe.zip |
chore: use Navigation from `@nextcloud/files`
Signed-off-by: John Molakvoæ <skjnldsv@protonmail.com>
43 files changed, 158 insertions, 446 deletions
diff --git a/apps/files/src/actions/deleteAction.spec.ts b/apps/files/src/actions/deleteAction.spec.ts index 8d99b195c3d..d7b7cd5307d 100644 --- a/apps/files/src/actions/deleteAction.spec.ts +++ b/apps/files/src/actions/deleteAction.spec.ts @@ -21,22 +21,21 @@ */ import { action } from './deleteAction' import { expect } from '@jest/globals' -import { File, Folder, Permission } from '@nextcloud/files' +import { File, Folder, Permission, View } from '@nextcloud/files' import { FileAction } from '../services/FileAction' import * as eventBus from '@nextcloud/event-bus' import axios from '@nextcloud/axios' import logger from '../logger' -import type { Navigation } from '../services/Navigation' const view = { id: 'files', name: 'Files', -} as Navigation +} as View const trashbinView = { id: 'trashbin', name: 'Trashbin', -} as Navigation +} as View describe('Delete action conditions tests', () => { test('Default values', () => { diff --git a/apps/files/src/actions/deleteAction.ts b/apps/files/src/actions/deleteAction.ts index 52dd2f53491..6fd8fc467e3 100644 --- a/apps/files/src/actions/deleteAction.ts +++ b/apps/files/src/actions/deleteAction.ts @@ -20,18 +20,17 @@ * */ import { emit } from '@nextcloud/event-bus' -import { Permission, Node } from '@nextcloud/files' +import { Permission, Node, View } from '@nextcloud/files' import { translate as t } from '@nextcloud/l10n' import axios from '@nextcloud/axios' import TrashCanSvg from '@mdi/svg/svg/trash-can.svg?raw' import { registerFileAction, FileAction } from '../services/FileAction' import logger from '../logger.js' -import type { Navigation } from '../services/Navigation' export const action = new FileAction({ id: 'delete', - displayName(nodes: Node[], view: Navigation) { + displayName(nodes: Node[], view: View) { return view.id === 'trashbin' ? t('files_trashbin', 'Delete permanently') : t('files', 'Delete') @@ -58,7 +57,7 @@ export const action = new FileAction({ return false } }, - async execBatch(nodes: Node[], view: Navigation, dir: string) { + async execBatch(nodes: Node[], view: View, dir: string) { return Promise.all(nodes.map(node => this.exec(node, view, dir))) }, diff --git a/apps/files/src/actions/downloadAction.spec.ts b/apps/files/src/actions/downloadAction.spec.ts index abe099af3f8..35a4c0a277a 100644 --- a/apps/files/src/actions/downloadAction.spec.ts +++ b/apps/files/src/actions/downloadAction.spec.ts @@ -21,17 +21,13 @@ */ import { action } from './downloadAction' import { expect } from '@jest/globals' -import { File, Folder, Permission } from '@nextcloud/files' +import { File, Folder, Permission, View } from '@nextcloud/files' import { FileAction } from '../services/FileAction' -import * as eventBus from '@nextcloud/event-bus' -import axios from '@nextcloud/axios' -import type { Navigation } from '../services/Navigation' -import logger from '../logger' const view = { id: 'files', name: 'Files', -} as Navigation +} as View describe('Download action conditions tests', () => { test('Default values', () => { diff --git a/apps/files/src/actions/downloadAction.ts b/apps/files/src/actions/downloadAction.ts index 13fcde61063..bf4e05ec8b0 100644 --- a/apps/files/src/actions/downloadAction.ts +++ b/apps/files/src/actions/downloadAction.ts @@ -19,13 +19,12 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. * */ -import { Permission, Node, FileType } from '@nextcloud/files' +import { Permission, Node, FileType, View } from '@nextcloud/files' import { translate as t } from '@nextcloud/l10n' import ArrowDownSvg from '@mdi/svg/svg/arrow-down.svg?raw' -import { registerFileAction, FileAction, DefaultType } from '../services/FileAction' +import { registerFileAction, FileAction } from '../services/FileAction' import { generateUrl } from '@nextcloud/router' -import type { Navigation } from '../services/Navigation' const triggerDownload = function(url: string) { const hiddenElement = document.createElement('a') @@ -55,7 +54,7 @@ export const action = new FileAction({ .every(permission => (permission & Permission.READ) !== 0) }, - async exec(node: Node, view: Navigation, dir: string) { + async exec(node: Node, view: View, dir: string) { if (node.type === FileType.Folder) { downloadNodes(dir, [node]) return null @@ -65,7 +64,7 @@ export const action = new FileAction({ return null }, - async execBatch(nodes: Node[], view: Navigation, dir: string) { + async execBatch(nodes: Node[], view: View, dir: string) { if (nodes.length === 1) { this.exec(nodes[0], view, dir) return [null] diff --git a/apps/files/src/actions/editLocallyAction.spec.ts b/apps/files/src/actions/editLocallyAction.spec.ts index f40b3b558db..3d2c31c468e 100644 --- a/apps/files/src/actions/editLocallyAction.spec.ts +++ b/apps/files/src/actions/editLocallyAction.spec.ts @@ -21,16 +21,15 @@ */ import { action } from './editLocallyAction' import { expect } from '@jest/globals' -import { File, Permission } from '@nextcloud/files' -import { DefaultType, FileAction } from '../services/FileAction' +import { File, Permission, View } from '@nextcloud/files' +import { FileAction } from '../services/FileAction' import * as ncDialogs from '@nextcloud/dialogs' import axios from '@nextcloud/axios' -import type { Navigation } from '../services/Navigation' const view = { id: 'files', name: 'Files', -} as Navigation +} as View describe('Edit locally action conditions tests', () => { test('Default values', () => { diff --git a/apps/files/src/actions/favoriteAction.spec.ts b/apps/files/src/actions/favoriteAction.spec.ts index 57957e67a33..b24984dfdc2 100644 --- a/apps/files/src/actions/favoriteAction.spec.ts +++ b/apps/files/src/actions/favoriteAction.spec.ts @@ -19,25 +19,24 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. * */ -import * as favoriteAction from './favoriteAction' import { action } from './favoriteAction' import { expect } from '@jest/globals' -import { File, Permission } from '@nextcloud/files' +import { File, Permission, View } from '@nextcloud/files' import { FileAction } from '../services/FileAction' import * as eventBus from '@nextcloud/event-bus' +import * as favoriteAction from './favoriteAction' import axios from '@nextcloud/axios' -import type { Navigation } from '../services/Navigation' import logger from '../logger' const view = { id: 'files', name: 'Files', -} as Navigation +} as View const favoriteView = { id: 'favorites', name: 'Favorites', -} as Navigation +} as View global.window.OC = { TAG_FAVORITE: '_$!<Favorite>!$_', diff --git a/apps/files/src/actions/favoriteAction.ts b/apps/files/src/actions/favoriteAction.ts index a33aacf4947..7a067bb9407 100644 --- a/apps/files/src/actions/favoriteAction.ts +++ b/apps/files/src/actions/favoriteAction.ts @@ -21,7 +21,7 @@ */ import { emit } from '@nextcloud/event-bus' import { generateUrl } from '@nextcloud/router' -import { Permission, type Node } from '@nextcloud/files' +import { Permission, type Node, View } from '@nextcloud/files' import { translate as t } from '@nextcloud/l10n' import axios from '@nextcloud/axios' import Vue from 'vue' @@ -31,14 +31,13 @@ import StarSvg from '@mdi/svg/svg/star.svg?raw' import { registerFileAction, FileAction } from '../services/FileAction' import logger from '../logger.js' -import type { Navigation } from '../services/Navigation' // If any of the nodes is not favorited, we display the favorite action. const shouldFavorite = (nodes: Node[]): boolean => { return nodes.some(node => node.attributes.favorite !== 1) } -export const favoriteNode = async (node: Node, view: Navigation, willFavorite: boolean): Promise<boolean> => { +export const favoriteNode = async (node: Node, view: View, willFavorite: boolean): Promise<boolean> => { try { // TODO: migrate to webdav tags plugin const url = generateUrl('/apps/files/api/v1/files') + node.path @@ -92,11 +91,11 @@ export const action = new FileAction({ && nodes.every(node => node.permissions !== Permission.NONE) }, - async exec(node: Node, view: Navigation) { + async exec(node: Node, view: View) { const willFavorite = shouldFavorite([node]) return await favoriteNode(node, view, willFavorite) }, - async execBatch(nodes: Node[], view: Navigation) { + async execBatch(nodes: Node[], view: View) { const willFavorite = shouldFavorite(nodes) return Promise.all(nodes.map(async node => await favoriteNode(node, view, willFavorite))) }, diff --git a/apps/files/src/actions/openFolderAction.spec.ts b/apps/files/src/actions/openFolderAction.spec.ts index 49fc9a9a63a..ff72f10b4d7 100644 --- a/apps/files/src/actions/openFolderAction.spec.ts +++ b/apps/files/src/actions/openFolderAction.spec.ts @@ -19,10 +19,8 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. * */ -import type { Navigation } from '../services/Navigation' - import { expect } from '@jest/globals' -import { File, Folder, Node, Permission } from '@nextcloud/files' +import { File, Folder, Node, Permission, View } from '@nextcloud/files' import { action } from './openFolderAction' import { DefaultType, FileAction } from '../services/FileAction' @@ -30,7 +28,7 @@ import { DefaultType, FileAction } from '../services/FileAction' const view = { id: 'files', name: 'Files', -} as Navigation +} as View describe('Open folder action conditions tests', () => { test('Default values', () => { diff --git a/apps/files/src/actions/openFolderAction.ts b/apps/files/src/actions/openFolderAction.ts index c0e03b20af0..0d28792f15e 100644 --- a/apps/files/src/actions/openFolderAction.ts +++ b/apps/files/src/actions/openFolderAction.ts @@ -19,11 +19,10 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. * */ -import { Permission, Node, FileType } from '@nextcloud/files' +import { Permission, Node, FileType, View } from '@nextcloud/files' import { translate as t } from '@nextcloud/l10n' import FolderSvg from '@mdi/svg/svg/folder.svg?raw' -import type { Navigation } from '../services/Navigation' import { join } from 'path' import { registerFileAction, FileAction, DefaultType } from '../services/FileAction' @@ -52,7 +51,7 @@ export const action = new FileAction({ && (node.permissions & Permission.READ) !== 0 }, - async exec(node: Node, view: Navigation, dir: string) { + async exec(node: Node, view: View, dir: string) { if (!node || node.type !== FileType.Folder) { return false } diff --git a/apps/files/src/actions/openInFilesAction.spec.ts b/apps/files/src/actions/openInFilesAction.spec.ts index 4fc402c73a8..2097095c9ef 100644 --- a/apps/files/src/actions/openInFilesAction.spec.ts +++ b/apps/files/src/actions/openInFilesAction.spec.ts @@ -21,19 +21,18 @@ */ import { action } from './openInFilesAction' import { expect } from '@jest/globals' -import { File, Folder, Permission } from '@nextcloud/files' +import { File, Folder, Permission, View } from '@nextcloud/files' import { DefaultType, FileAction } from '../../../files/src/services/FileAction' -import type { Navigation } from '../../../files/src/services/Navigation' const view = { id: 'files', name: 'Files', -} as Navigation +} as View const recentView = { id: 'recent', name: 'Recent', -} as Navigation +} as View describe('Open in files action conditions tests', () => { test('Default values', () => { diff --git a/apps/files/src/actions/renameAction.spec.ts b/apps/files/src/actions/renameAction.spec.ts index c4d5d45cde9..8e76bea4b84 100644 --- a/apps/files/src/actions/renameAction.spec.ts +++ b/apps/files/src/actions/renameAction.spec.ts @@ -21,15 +21,14 @@ */ import { action } from './renameAction' import { expect } from '@jest/globals' -import { File, Permission } from '@nextcloud/files' +import { File, Permission, View } from '@nextcloud/files' import { FileAction } from '../services/FileAction' import * as eventBus from '@nextcloud/event-bus' -import type { Navigation } from '../services/Navigation' const view = { id: 'files', name: 'Files', -} as Navigation +} as View describe('Rename action conditions tests', () => { test('Default values', () => { diff --git a/apps/files/src/actions/sidebarAction.spec.ts b/apps/files/src/actions/sidebarAction.spec.ts index 6b33667d1dd..1fb31959944 100644 --- a/apps/files/src/actions/sidebarAction.spec.ts +++ b/apps/files/src/actions/sidebarAction.spec.ts @@ -19,10 +19,8 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. * */ -import type { Navigation } from '../services/Navigation' - import { expect } from '@jest/globals' -import { File, Permission } from '@nextcloud/files' +import { File, Permission, View } from '@nextcloud/files' import { action } from './sidebarAction' import { FileAction } from '../services/FileAction' @@ -31,7 +29,7 @@ import logger from '../logger' const view = { id: 'files', name: 'Files', -} as Navigation +} as View describe('Open sidebar action conditions tests', () => { test('Default values', () => { diff --git a/apps/files/src/actions/sidebarAction.ts b/apps/files/src/actions/sidebarAction.ts index 849cf78368d..52244d9912a 100644 --- a/apps/files/src/actions/sidebarAction.ts +++ b/apps/files/src/actions/sidebarAction.ts @@ -19,9 +19,7 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. * */ -import type { Navigation } from '../services/Navigation' - -import { Permission, type Node } from '@nextcloud/files' +import { Permission, type Node, View } from '@nextcloud/files' import { translate as t } from '@nextcloud/l10n' import InformationSvg from '@mdi/svg/svg/information-variant.svg?raw' @@ -54,7 +52,7 @@ export const action = new FileAction({ return (nodes[0].root?.startsWith('/files/') && nodes[0].permissions !== Permission.NONE) ?? false }, - async exec(node: Node, view: Navigation) { + async exec(node: Node, view: View) { try { // TODO: migrate Sidebar to use a Node instead await window.OCA.Files.Sidebar.open(node.path) diff --git a/apps/files/src/actions/viewInFolderAction.spec.ts b/apps/files/src/actions/viewInFolderAction.spec.ts index 7d61fa4298d..c26eb52e400 100644 --- a/apps/files/src/actions/viewInFolderAction.spec.ts +++ b/apps/files/src/actions/viewInFolderAction.spec.ts @@ -21,14 +21,13 @@ */ import { action } from './viewInFolderAction' import { expect } from '@jest/globals' -import { File, Folder, Node, Permission } from '@nextcloud/files' +import { File, Folder, Node, Permission, View } from '@nextcloud/files' import { FileAction } from '../services/FileAction' -import type { Navigation } from '../services/Navigation' const view = { id: 'files', name: 'Files', -} as Navigation +} as View describe('View in folder action conditions tests', () => { test('Default values', () => { diff --git a/apps/files/src/actions/viewInFolderAction.ts b/apps/files/src/actions/viewInFolderAction.ts index f0c5d2485a3..c8abcbb72f1 100644 --- a/apps/files/src/actions/viewInFolderAction.ts +++ b/apps/files/src/actions/viewInFolderAction.ts @@ -19,12 +19,10 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. * */ -import { Node, FileType, Permission } from '@nextcloud/files' +import { Node, FileType, Permission, View } from '@nextcloud/files' import { translate as t } from '@nextcloud/l10n' import FolderMoveSvg from '@mdi/svg/svg/folder-move.svg?raw' -import type { Navigation } from '../services/Navigation' -import { join } from 'path' import { registerFileAction, FileAction } from '../services/FileAction' export const action = new FileAction({ @@ -53,7 +51,7 @@ export const action = new FileAction({ return node.type === FileType.File }, - async exec(node: Node, view: Navigation, dir: string) { + async exec(node: Node, view: View, dir: string) { if (!node || node.type !== FileType.File) { return false } diff --git a/apps/files/src/components/FilesListHeader.vue b/apps/files/src/components/FilesListHeader.vue index 74dc224a39b..a1ad790da98 100644 --- a/apps/files/src/components/FilesListHeader.vue +++ b/apps/files/src/components/FilesListHeader.vue @@ -50,7 +50,6 @@ export default { }, computed: { enabled() { - console.debug('Enabled', this.header.id) return this.header.enabled(this.currentFolder, this.currentView) }, }, diff --git a/apps/files/src/main.ts b/apps/files/src/main.ts index d0fb3922229..3094656ecc0 100644 --- a/apps/files/src/main.ts +++ b/apps/files/src/main.ts @@ -10,12 +10,13 @@ import './actions/openInFilesAction.js' import './actions/renameAction' import './actions/sidebarAction' import './actions/viewInFolderAction' +import './newMenu/newFolder' import Vue from 'vue' import { createPinia, PiniaVuePlugin } from 'pinia' +import { getNavigation } from '@nextcloud/files' import FilesListView from './views/FilesList.vue' -import { NavigationService } from './services/Navigation' import NavigationView from './views/Navigation.vue' import registerFavoritesView from './views/favorites' import registerRecentView from './views/recent' @@ -47,8 +48,7 @@ Vue.use(PiniaVuePlugin) const pinia = createPinia() // Init Navigation Service -const Navigation = new NavigationService() -Object.assign(window.OCP.Files, { Navigation }) +const Navigation = getNavigation() Vue.prototype.$navigation = Navigation // Init Files App Settings Service diff --git a/apps/files/src/mixins/filesSorting.ts b/apps/files/src/mixins/filesSorting.ts index e766ea631f3..2ec3d94d67e 100644 --- a/apps/files/src/mixins/filesSorting.ts +++ b/apps/files/src/mixins/filesSorting.ts @@ -23,14 +23,14 @@ import Vue from 'vue' import { mapState } from 'pinia' import { useViewConfigStore } from '../store/viewConfig' -import type { NavigationService, Navigation } from '../services/Navigation' +import { Navigation, View } from '@nextcloud/files' export default Vue.extend({ computed: { ...mapState(useViewConfigStore, ['getConfig', 'setSortingBy', 'toggleSortingDirection']), - currentView(): Navigation { - return (this.$navigation as NavigationService).active as Navigation + currentView(): View { + return (this.$navigation as Navigation).active as View }, /** diff --git a/apps/files/src/services/Navigation.ts b/apps/files/src/services/Navigation.ts deleted file mode 100644 index 8f8212783ca..00000000000 --- a/apps/files/src/services/Navigation.ts +++ /dev/null @@ -1,241 +0,0 @@ -/** - * @copyright Copyright (c) 2022 John Molakvoæ <skjnldsv@protonmail.com> - * - * @author John Molakvoæ <skjnldsv@protonmail.com> - * - * @license AGPL-3.0-or-later - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - */ -/* eslint-disable no-use-before-define */ -import type { Folder, Node } from '@nextcloud/files' -import isSvg from 'is-svg' - -import logger from '../logger.js' - -export type ContentsWithRoot = { - folder: Folder, - contents: Node[] -} - -export interface Column { - /** Unique column ID */ - id: string - /** Translated column title */ - title: string - /** The content of the cell. The element will be appended within */ - render: (node: Node, view: Navigation) => HTMLElement - /** Function used to sort Nodes between them */ - sort?: (nodeA: Node, nodeB: Node) => number - /** - * Custom summary of the column to display at the end of the list. - * Will not be displayed if nothing is provided - */ - summary?: (node: Node[], view: Navigation) => string -} - -export interface Navigation { - /** Unique view ID */ - id: string - /** Translated view name */ - name: string - /** Translated accessible description of the view */ - caption?: string - - /** Translated title of the empty view */ - emptyTitle?: string - /** Translated description of the empty view */ - emptyCaption?: string - - /** - * Method return the content of the provided path - * This ideally should be a cancellable promise. - * promise.cancel(reason) will be called when the directory - * change and the promise is not resolved yet. - * You _must_ also return the current directory - * information alongside with its content. - */ - getContents: (path: string) => Promise<ContentsWithRoot> - /** The view icon as an inline svg */ - icon: string - /** The view order */ - order: number - - /** - * This view column(s). Name and actions are - * by default always included - */ - columns?: Column[] - /** The empty view element to render your empty content into */ - emptyView?: (div: HTMLDivElement) => void - /** The parent unique ID */ - parent?: string - /** This view is sticky (sent at the bottom) */ - sticky?: boolean - - /** - * This view has children and is expanded or not, - * will be overridden by user config. - */ - expanded?: boolean - - /** - * Will be used as default if the user - * haven't customized their sorting column - */ - defaultSortKey?: string -} - -export class NavigationService { - - private _views: Navigation[] = [] - private _currentView: Navigation | null = null - - constructor() { - logger.debug('Navigation service initialized') - } - - register(view: Navigation) { - try { - isValidNavigation(view) - isUniqueNavigation(view, this._views) - } catch (e) { - if (e instanceof Error) { - logger.error(e.message, { view }) - } - throw e - } - - this._views.push(view) - } - - remove(id: string) { - const index = this._views.findIndex(view => view.id === id) - if (index !== -1) { - this._views.splice(index, 1) - } - } - - get views(): Navigation[] { - return this._views - } - - setActive(view: Navigation | null) { - this._currentView = view - } - - get active(): Navigation | null { - return this._currentView - } - -} - -/** - * Make sure the given view is unique - * and not already registered. - */ -const isUniqueNavigation = function(view: Navigation, views: Navigation[]): boolean { - if (views.find(search => search.id === view.id)) { - throw new Error(`Navigation id ${view.id} is already registered`) - } - return true -} - -/** - * Typescript cannot validate an interface. - * Please keep in sync with the Navigation interface requirements. - */ -const isValidNavigation = function(view: Navigation): boolean { - if (!view.id || typeof view.id !== 'string') { - throw new Error('Navigation id is required and must be a string') - } - - if (!view.name || typeof view.name !== 'string') { - throw new Error('Navigation name is required and must be a string') - } - - if (view.columns && view.columns.length > 0 - && (!view.caption || typeof view.caption !== 'string')) { - throw new Error('Navigation caption is required for top-level views and must be a string') - } - - if (!view.getContents || typeof view.getContents !== 'function') { - throw new Error('Navigation getContents is required and must be a function') - } - - if (!view.icon || typeof view.icon !== 'string' || !isSvg(view.icon)) { - throw new Error('Navigation icon is required and must be a valid svg string') - } - - if (!('order' in view) || typeof view.order !== 'number') { - throw new Error('Navigation order is required and must be a number') - } - - // Optional properties - if (view.columns) { - view.columns.forEach(isValidColumn) - } - - if (view.emptyView && typeof view.emptyView !== 'function') { - throw new Error('Navigation emptyView must be a function') - } - - if (view.parent && typeof view.parent !== 'string') { - throw new Error('Navigation parent must be a string') - } - - if ('sticky' in view && typeof view.sticky !== 'boolean') { - throw new Error('Navigation sticky must be a boolean') - } - - if ('expanded' in view && typeof view.expanded !== 'boolean') { - throw new Error('Navigation expanded must be a boolean') - } - - if (view.defaultSortKey && typeof view.defaultSortKey !== 'string') { - throw new Error('Navigation defaultSortKey must be a string') - } - - return true -} - -/** - * Typescript cannot validate an interface. - * Please keep in sync with the Column interface requirements. - */ -const isValidColumn = function(column: Column): boolean { - if (!column.id || typeof column.id !== 'string') { - throw new Error('A column id is required') - } - - if (!column.title || typeof column.title !== 'string') { - throw new Error('A column title is required') - } - - if (!column.render || typeof column.render !== 'function') { - throw new Error('A render function is required') - } - - // Optional properties - if (column.sort && typeof column.sort !== 'function') { - throw new Error('Column sortFunction must be a function') - } - - if (column.summary && typeof column.summary !== 'function') { - throw new Error('Column summary must be a function') - } - - return true -} diff --git a/apps/files/src/views/FilesList.vue b/apps/files/src/views/FilesList.vue index eb38d09e290..8aa93dd41a5 100644 --- a/apps/files/src/views/FilesList.vue +++ b/apps/files/src/views/FilesList.vue @@ -64,10 +64,9 @@ <script lang="ts"> import type { Route } from 'vue-router' -import type { Navigation, ContentsWithRoot } from '../services/Navigation.ts' import type { UserConfig } from '../types.ts' -import { Folder, Node } from '@nextcloud/files' +import { Folder, Node, type View, type ContentsWithRoot } from '@nextcloud/files' import { join } from 'path' import { orderBy } from 'natural-orderby' import { translate } from '@nextcloud/l10n' @@ -132,9 +131,9 @@ export default Vue.extend({ return this.userConfigStore.userConfig }, - currentView(): Navigation { + currentView(): View { return (this.$navigation.active - || this.$navigation.views.find(view => view.id === 'files')) as Navigation + || this.$navigation.views.find(view => view.id === 'files')) as View }, /** diff --git a/apps/files/src/views/Navigation.cy.ts b/apps/files/src/views/Navigation.cy.ts index a65016da297..a84a4927bb2 100644 --- a/apps/files/src/views/Navigation.cy.ts +++ b/apps/files/src/views/Navigation.cy.ts @@ -2,13 +2,14 @@ import FolderSvg from '@mdi/svg/svg/folder.svg' import ShareSvg from '@mdi/svg/svg/share-variant.svg' import { createTestingPinia } from '@pinia/testing' -import { NavigationService } from '../services/Navigation' import NavigationView from './Navigation.vue' import router from '../router/router' import { useViewConfigStore } from '../store/viewConfig' +import { Folder, View, getNavigation } from '@nextcloud/files' describe('Navigation renders', () => { - const Navigation = new NavigationService() as NavigationService + delete window._nc_navigation + const Navigation = getNavigation() before(() => { cy.mockInitialState('files', 'storageStats', { @@ -38,16 +39,17 @@ describe('Navigation renders', () => { }) describe('Navigation API', () => { - const Navigation = new NavigationService() as NavigationService + delete window._nc_navigation + const Navigation = getNavigation() it('Check API entries rendering', () => { - Navigation.register({ + Navigation.register(new View({ id: 'files', name: 'Files', - getContents: () => Promise.resolve(), + getContents: async () => ({ folder: {} as Folder, contents: [] }), icon: FolderSvg, order: 1, - }) + })) cy.mount(NavigationView, { propsData: { @@ -68,13 +70,13 @@ describe('Navigation API', () => { }) it('Adds a new entry and render', () => { - Navigation.register({ + Navigation.register(new View({ id: 'sharing', name: 'Sharing', - getContents: () => Promise.resolve(), + getContents: async () => ({ folder: {} as Folder, contents: [] }), icon: ShareSvg, order: 2, - }) + })) cy.mount(NavigationView, { propsData: { @@ -95,14 +97,14 @@ describe('Navigation API', () => { }) it('Adds a new children, render and open menu', () => { - Navigation.register({ + Navigation.register(new View({ id: 'sharingin', name: 'Shared with me', - getContents: () => Promise.resolve(), + getContents: async () => ({ folder: {} as Folder, contents: [] }), parent: 'sharing', icon: ShareSvg, order: 1, - }) + })) cy.mount(NavigationView, { propsData: { @@ -142,19 +144,20 @@ describe('Navigation API', () => { it('Throws when adding a duplicate entry', () => { expect(() => { - Navigation.register({ + Navigation.register(new View({ id: 'files', name: 'Files', - getContents: () => Promise.resolve(), + getContents: async () => ({ folder: {} as Folder, contents: [] }), icon: FolderSvg, order: 1, - }) - }).to.throw('Navigation id files is already registered') + })) + }).to.throw('View id files is already registered') }) }) describe('Quota rendering', () => { - const Navigation = new NavigationService() + delete window._nc_navigation + const Navigation = getNavigation() afterEach(() => cy.unmockInitialState()) diff --git a/apps/files/src/views/Navigation.vue b/apps/files/src/views/Navigation.vue index 9b1df413ccc..7544c8991a0 100644 --- a/apps/files/src/views/Navigation.vue +++ b/apps/files/src/views/Navigation.vue @@ -83,7 +83,7 @@ import NcIconSvgWrapper from '@nextcloud/vue/dist/Components/NcIconSvgWrapper.js import { setPageHeading } from '../../../../core/src/OCP/accessibility.js' import { useViewConfigStore } from '../store/viewConfig.ts' import logger from '../logger.js' -import type { NavigationService, Navigation } from '../services/Navigation.ts' +import type { Navigation, View } from '@nextcloud/files' import NavigationQuota from '../components/NavigationQuota.vue' import SettingsModal from './Settings.vue' @@ -125,15 +125,15 @@ export default { return this.$route?.params?.view || 'files' }, - currentView(): Navigation { + currentView(): View { return this.views.find(view => view.id === this.currentViewId) }, - views(): Navigation[] { + views(): View[] { return this.Navigation.views }, - parentViews(): Navigation[] { + parentViews(): View[] { return this.views // filter child views .filter(view => !view.parent) @@ -143,7 +143,7 @@ export default { }) }, - childViews(): Navigation[] { + childViews(): View[] { return this.views // filter parent views .filter(view => !!view.parent) @@ -165,7 +165,7 @@ export default { this.Navigation.setActive(view) logger.debug('Navigation changed', { id: view.id, view }) - this.showView(view, oldView) + this.showView(view) } }, }, @@ -178,7 +178,7 @@ export default { }, methods: { - showView(view: Navigation) { + showView(view: View) { // Closing any opened sidebar window?.OCA?.Files?.Sidebar?.close?.() this.Navigation.setActive(view) @@ -190,7 +190,7 @@ export default { * Expand/collapse a a view with children and permanently * save this setting in the server. */ - onToggleExpand(view: Navigation) { + onToggleExpand(view: View) { // Invert state const isExpanded = this.isExpanded(view) // Update the view expanded state, might not be necessary @@ -202,7 +202,7 @@ export default { * Check if a view is expanded by user config * or fallback to the default value. */ - isExpanded(view: Navigation): boolean { + isExpanded(view: View): boolean { return typeof this.viewConfigStore.getConfig(view.id)?.expanded === 'boolean' ? this.viewConfigStore.getConfig(view.id).expanded === true : view.expanded === true @@ -211,7 +211,7 @@ export default { /** * Generate the route to a view */ - generateToNavigation(view: Navigation) { + generateToNavigation(view: View) { if (view.params) { const { dir, fileid } = view.params return { name: 'filelist', params: view.params, query: { dir, fileid } } diff --git a/apps/files/src/views/favorites.spec.ts b/apps/files/src/views/favorites.spec.ts index b1340187244..f9cf5031f5f 100644 --- a/apps/files/src/views/favorites.spec.ts +++ b/apps/files/src/views/favorites.spec.ts @@ -21,13 +21,12 @@ */ import { expect } from '@jest/globals' import * as initialState from '@nextcloud/initial-state' -import { Folder } from '@nextcloud/files' +import { Folder, getNavigation } from '@nextcloud/files' import { basename } from 'path' import * as eventBus from '@nextcloud/event-bus' import { action } from '../actions/favoriteAction' import * as favoritesService from '../services/Favorites' -import { NavigationService } from '../services/Navigation' import registerFavoritesView from './favorites' jest.mock('webdav/dist/node/request.js', () => ({ @@ -41,8 +40,7 @@ global.window.OC = { describe('Favorites view definition', () => { let Navigation beforeEach(() => { - Navigation = new NavigationService() - window.OCP = { Files: { Navigation } } + Navigation = getNavigation() }) afterAll(() => { @@ -114,8 +112,7 @@ describe('Favorites view definition', () => { describe('Dynamic update of favourite folders', () => { let Navigation beforeEach(() => { - Navigation = new NavigationService() - window.OCP = { Files: { Navigation } } + Navigation = getNavigation() }) afterAll(() => { diff --git a/apps/files/src/views/favorites.ts b/apps/files/src/views/favorites.ts index 7485340a2fe..738f9b19e6b 100644 --- a/apps/files/src/views/favorites.ts +++ b/apps/files/src/views/favorites.ts @@ -19,7 +19,6 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. * */ -import type { Navigation, NavigationService } from '../services/Navigation' import { getLanguage, translate as t } from '@nextcloud/l10n' import FolderSvg from '@mdi/svg/svg/folder.svg?raw' import StarSvg from '@mdi/svg/svg/star.svg?raw' @@ -28,12 +27,12 @@ import { basename } from 'path' import { getContents } from '../services/Favorites' import { hashCode } from '../utils/hashUtils' import { loadState } from '@nextcloud/initial-state' -import { Node, FileType } from '@nextcloud/files' +import { Node, FileType, View, getNavigation } from '@nextcloud/files' import { subscribe } from '@nextcloud/event-bus' import logger from '../logger' -export const generateFolderView = function(folder: string, index = 0): Navigation { - return { +export const generateFolderView = function(folder: string, index = 0): View { + return new View({ id: generateIdFromPath(folder), name: basename(folder), @@ -49,7 +48,7 @@ export const generateFolderView = function(folder: string, index = 0): Navigatio columns: [], getContents, - } as Navigation + }) } export const generateIdFromPath = function(path: string): string { @@ -59,10 +58,10 @@ export const generateIdFromPath = function(path: string): string { export default () => { // Load state in function for mock testing purposes const favoriteFolders = loadState<string[]>('files', 'favoriteFolders', []) - const favoriteFoldersViews = favoriteFolders.map((folder, index) => generateFolderView(folder, index)) + const favoriteFoldersViews = favoriteFolders.map((folder, index) => generateFolderView(folder, index)) as View[] - const Navigation = window.OCP.Files.Navigation as NavigationService - Navigation.register({ + const Navigation = getNavigation() + Navigation.register(new View({ id: 'favorites', name: t('files', 'Favorites'), caption: t('files', 'List of favorites files and folders.'), @@ -76,7 +75,7 @@ export default () => { columns: [], getContents, - } as Navigation) + })) favoriteFoldersViews.forEach(view => Navigation.register(view)) diff --git a/apps/files/src/views/files.ts b/apps/files/src/views/files.ts index baafc8572c2..a535481a061 100644 --- a/apps/files/src/views/files.ts +++ b/apps/files/src/views/files.ts @@ -19,16 +19,15 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. * */ -import type { NavigationService, Navigation } from '../services/Navigation' - import { translate as t } from '@nextcloud/l10n' import FolderSvg from '@mdi/svg/svg/folder.svg?raw' import { getContents } from '../services/Files' +import { View, getNavigation } from '@nextcloud/files' export default () => { - const Navigation = window.OCP.Files.Navigation as NavigationService - Navigation.register({ + const Navigation = getNavigation() + Navigation.register(new View({ id: 'files', name: t('files', 'All files'), caption: t('files', 'List of your files and folders.'), @@ -37,5 +36,5 @@ export default () => { order: 0, getContents, - } as Navigation) + })) } diff --git a/apps/files/src/views/recent.ts b/apps/files/src/views/recent.ts index 3e0c51184e4..08ae5db6f39 100644 --- a/apps/files/src/views/recent.ts +++ b/apps/files/src/views/recent.ts @@ -19,16 +19,15 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. * */ -import type { NavigationService, Navigation } from '../services/Navigation' - import { translate as t } from '@nextcloud/l10n' import HistorySvg from '@mdi/svg/svg/history.svg?raw' import { getContents } from '../services/Recent' +import { View, getNavigation } from '@nextcloud/files' export default () => { - const Navigation = window.OCP.Files.Navigation as NavigationService - Navigation.register({ + const Navigation = getNavigation() + Navigation.register(new View({ id: 'recent', name: t('files', 'Recent'), caption: t('files', 'List of recently modified files and folders.'), @@ -42,5 +41,5 @@ export default () => { defaultSortKey: 'mtime', getContents, - } as Navigation) + })) } diff --git a/apps/files_external/src/actions/enterCredentialsAction.spec.ts b/apps/files_external/src/actions/enterCredentialsAction.spec.ts index 29e1fe31f02..ef3a767365b 100644 --- a/apps/files_external/src/actions/enterCredentialsAction.spec.ts +++ b/apps/files_external/src/actions/enterCredentialsAction.spec.ts @@ -21,21 +21,20 @@ */ import { action } from './enterCredentialsAction' import { expect } from '@jest/globals' -import { File, Folder, Permission } from '@nextcloud/files' +import { File, Folder, Permission, View } from '@nextcloud/files' import { DefaultType, FileAction } from '../../../files/src/services/FileAction' -import type { Navigation } from '../../../files/src/services/Navigation' import type { StorageConfig } from '../services/externalStorage' import { STORAGE_STATUS } from '../utils/credentialsUtils' const view = { id: 'files', name: 'Files', -} as Navigation +} as View const externalStorageView = { id: 'extstoragemounts', name: 'External storage', -} as Navigation +} as View describe('Enter credentials action conditions tests', () => { test('Default values', () => { diff --git a/apps/files_external/src/actions/openInFilesAction.spec.ts b/apps/files_external/src/actions/openInFilesAction.spec.ts index 803bee8e096..4f25d2449b4 100644 --- a/apps/files_external/src/actions/openInFilesAction.spec.ts +++ b/apps/files_external/src/actions/openInFilesAction.spec.ts @@ -21,21 +21,20 @@ */ import { action } from './openInFilesAction' import { expect } from '@jest/globals' -import { File, Folder, Permission } from '@nextcloud/files' +import { Folder, Permission, View } from '@nextcloud/files' import { DefaultType, FileAction } from '../../../files/src/services/FileAction' -import type { Navigation } from '../../../files/src/services/Navigation' import type { StorageConfig } from '../services/externalStorage' import { STORAGE_STATUS } from '../utils/credentialsUtils' const view = { id: 'files', name: 'Files', -} as Navigation +} as View const externalStorageView = { id: 'extstoragemounts', name: 'External storage', -} as Navigation +} as View describe('Open in files action conditions tests', () => { test('Default values', () => { diff --git a/apps/files_external/src/main.ts b/apps/files_external/src/main.ts index 250ad51e38f..c85dd371f51 100644 --- a/apps/files_external/src/main.ts +++ b/apps/files_external/src/main.ts @@ -19,8 +19,6 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. * */ -import type { NavigationService, Navigation } from '../../files/src/services/Navigation' - import { translate as t } from '@nextcloud/l10n' import { loadState } from '@nextcloud/initial-state' import FolderNetworkSvg from '@mdi/svg/svg/folder-network.svg?raw' @@ -29,11 +27,12 @@ import './actions/enterCredentialsAction' import './actions/inlineStorageCheckAction' import './actions/openInFilesAction' import { getContents } from './services/externalStorage' +import { View, getNavigation, Column } from '@nextcloud/files' const allowUserMounting = loadState('files_external', 'allowUserMounting', false) -const Navigation = window.OCP.Files.Navigation as NavigationService -Navigation.register({ +const Navigation = getNavigation() +Navigation.register(new View({ id: 'extstoragemounts', name: t('files_external', 'External storage'), caption: t('files_external', 'List of external storage.'), @@ -47,7 +46,7 @@ Navigation.register({ order: 30, columns: [ - { + new Column({ id: 'storage-type', title: t('files_external', 'Storage type'), render(node) { @@ -56,8 +55,8 @@ Navigation.register({ span.textContent = backend return span }, - }, - { + }), + new Column({ id: 'scope', title: t('files_external', 'Scope'), render(node) { @@ -69,8 +68,8 @@ Navigation.register({ span.textContent = scope return span }, - }, + }), ], getContents, -} as Navigation) +})) diff --git a/apps/files_external/src/services/externalStorage.ts b/apps/files_external/src/services/externalStorage.ts index c84ad6bcc5b..95010c2b6a4 100644 --- a/apps/files_external/src/services/externalStorage.ts +++ b/apps/files_external/src/services/externalStorage.ts @@ -21,10 +21,9 @@ */ // eslint-disable-next-line n/no-extraneous-import import type { AxiosResponse } from 'axios' -import type { ContentsWithRoot } from '../../../files/src/services/Navigation' import type { OCSResponse } from '../../../files_sharing/src/services/SharingService' -import { Folder, Permission } from '@nextcloud/files' +import { Folder, Permission, type ContentsWithRoot } from '@nextcloud/files' import { generateOcsUrl, generateRemoteUrl, generateUrl } from '@nextcloud/router' import { getCurrentUser } from '@nextcloud/auth' import axios from '@nextcloud/axios' diff --git a/apps/files_sharing/src/actions/acceptShareAction.spec.ts b/apps/files_sharing/src/actions/acceptShareAction.spec.ts index acef697b1aa..7ad8a42a1a6 100644 --- a/apps/files_sharing/src/actions/acceptShareAction.spec.ts +++ b/apps/files_sharing/src/actions/acceptShareAction.spec.ts @@ -21,22 +21,21 @@ */ import { action } from './acceptShareAction' import { expect } from '@jest/globals' -import { File, Permission } from '@nextcloud/files' +import { File, Permission, View } from '@nextcloud/files' import { FileAction } from '../../../files/src/services/FileAction' import * as eventBus from '@nextcloud/event-bus' import axios from '@nextcloud/axios' -import type { Navigation } from '../../../files/src/services/Navigation' import '../main' const view = { id: 'files', name: 'Files', -} as Navigation +} as View const pendingShareView = { id: 'pendingshares', name: 'Pending shares', -} as Navigation +} as View describe('Accept share action conditions tests', () => { test('Default values', () => { diff --git a/apps/files_sharing/src/actions/acceptShareAction.ts b/apps/files_sharing/src/actions/acceptShareAction.ts index 4be69633122..8bd8d6a5533 100644 --- a/apps/files_sharing/src/actions/acceptShareAction.ts +++ b/apps/files_sharing/src/actions/acceptShareAction.ts @@ -19,8 +19,7 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. * */ -import type { Node } from '@nextcloud/files' -import type { Navigation } from '../../../files/src/services/Navigation' +import type { Node, View } from '@nextcloud/files' import { emit } from '@nextcloud/event-bus' import { generateOcsUrl } from '@nextcloud/router' @@ -55,7 +54,7 @@ export const action = new FileAction({ return false } }, - async execBatch(nodes: Node[], view: Navigation, dir: string) { + async execBatch(nodes: Node[], view: View, dir: string) { return Promise.all(nodes.map(node => this.exec(node, view, dir))) }, diff --git a/apps/files_sharing/src/actions/openInFilesAction.spec.ts b/apps/files_sharing/src/actions/openInFilesAction.spec.ts index 49d4e192d39..2d723770ee9 100644 --- a/apps/files_sharing/src/actions/openInFilesAction.spec.ts +++ b/apps/files_sharing/src/actions/openInFilesAction.spec.ts @@ -19,10 +19,8 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. * */ -import type { Navigation } from '../../../files/src/services/Navigation' - import { expect } from '@jest/globals' -import { File, Permission } from '@nextcloud/files' +import { File, Permission, View } from '@nextcloud/files' import '../main' import { action } from './openInFilesAction' @@ -32,19 +30,19 @@ import { deletedSharesViewId, pendingSharesViewId, sharedWithOthersViewId, share const view = { id: 'files', name: 'Files', -} as Navigation +} as View const validViews = [ sharesViewId, sharedWithYouViewId, sharedWithOthersViewId, sharingByLinksViewId, -].map(id => ({ id, name: id })) as Navigation[] +].map(id => ({ id, name: id })) as View[] const invalidViews = [ deletedSharesViewId, pendingSharesViewId, -].map(id => ({ id, name: id })) as Navigation[] +].map(id => ({ id, name: id })) as View[] describe('Open in files action conditions tests', () => { test('Default values', () => { diff --git a/apps/files_sharing/src/actions/rejectShareAction.spec.ts b/apps/files_sharing/src/actions/rejectShareAction.spec.ts index a075b45eedb..bc666b7c081 100644 --- a/apps/files_sharing/src/actions/rejectShareAction.spec.ts +++ b/apps/files_sharing/src/actions/rejectShareAction.spec.ts @@ -21,22 +21,21 @@ */ import { action } from './rejectShareAction' import { expect } from '@jest/globals' -import { File, Folder, Permission } from '@nextcloud/files' +import { File, Folder, Permission, View } from '@nextcloud/files' import { FileAction } from '../../../files/src/services/FileAction' import * as eventBus from '@nextcloud/event-bus' import axios from '@nextcloud/axios' -import type { Navigation } from '../../../files/src/services/Navigation' import '../main' const view = { id: 'files', name: 'Files', -} as Navigation +} as View const pendingShareView = { id: 'pendingshares', name: 'Pending shares', -} as Navigation +} as View describe('Reject share action conditions tests', () => { test('Default values', () => { diff --git a/apps/files_sharing/src/actions/rejectShareAction.ts b/apps/files_sharing/src/actions/rejectShareAction.ts index 44dd36abe55..7fb04d36227 100644 --- a/apps/files_sharing/src/actions/rejectShareAction.ts +++ b/apps/files_sharing/src/actions/rejectShareAction.ts @@ -19,8 +19,7 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. * */ -import type { Node } from '@nextcloud/files' -import type { Navigation } from '../../../files/src/services/Navigation' +import type { Node, View } from '@nextcloud/files' import { emit } from '@nextcloud/event-bus' import { generateOcsUrl } from '@nextcloud/router' @@ -72,7 +71,7 @@ export const action = new FileAction({ return false } }, - async execBatch(nodes: Node[], view: Navigation, dir: string) { + async execBatch(nodes: Node[], view: View, dir: string) { return Promise.all(nodes.map(node => this.exec(node, view, dir))) }, diff --git a/apps/files_sharing/src/actions/restoreShareAction.spec.ts b/apps/files_sharing/src/actions/restoreShareAction.spec.ts index 6b87d0549cf..2c37dd83857 100644 --- a/apps/files_sharing/src/actions/restoreShareAction.spec.ts +++ b/apps/files_sharing/src/actions/restoreShareAction.spec.ts @@ -21,22 +21,21 @@ */ import { action } from './restoreShareAction' import { expect } from '@jest/globals' -import { File, Permission } from '@nextcloud/files' +import { File, Permission, View } from '@nextcloud/files' import { FileAction } from '../../../files/src/services/FileAction' import * as eventBus from '@nextcloud/event-bus' import axios from '@nextcloud/axios' -import type { Navigation } from '../../../files/src/services/Navigation' import '../main' const view = { id: 'files', name: 'Files', -} as Navigation +} as View const deletedShareView = { id: 'deletedshares', name: 'Deleted shares', -} as Navigation +} as View describe('Restore share action conditions tests', () => { test('Default values', () => { diff --git a/apps/files_sharing/src/actions/restoreShareAction.ts b/apps/files_sharing/src/actions/restoreShareAction.ts index 6c43b0cfb37..d1b67f10b08 100644 --- a/apps/files_sharing/src/actions/restoreShareAction.ts +++ b/apps/files_sharing/src/actions/restoreShareAction.ts @@ -19,8 +19,7 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. * */ -import type { Node } from '@nextcloud/files' -import type { Navigation } from '../../../files/src/services/Navigation' +import type { Node, View } from '@nextcloud/files' import { emit } from '@nextcloud/event-bus' import { generateOcsUrl } from '@nextcloud/router' @@ -54,7 +53,7 @@ export const action = new FileAction({ return false } }, - async execBatch(nodes: Node[], view: Navigation, dir: string) { + async execBatch(nodes: Node[], view: View, dir: string) { return Promise.all(nodes.map(node => this.exec(node, view, dir))) }, diff --git a/apps/files_sharing/src/services/SharingService.ts b/apps/files_sharing/src/services/SharingService.ts index 5f288ce7fc5..2b5e2e0d329 100644 --- a/apps/files_sharing/src/services/SharingService.ts +++ b/apps/files_sharing/src/services/SharingService.ts @@ -21,9 +21,8 @@ */ /* eslint-disable camelcase, n/no-extraneous-import */ import type { AxiosPromise } from 'axios' -import type { ContentsWithRoot } from '../../../files/src/services/Navigation' -import { Folder, File } from '@nextcloud/files' +import { Folder, File, type ContentsWithRoot } from '@nextcloud/files' import { generateOcsUrl, generateRemoteUrl, generateUrl } from '@nextcloud/router' import { getCurrentUser } from '@nextcloud/auth' import axios from '@nextcloud/axios' diff --git a/apps/files_sharing/src/views/shares.spec.ts b/apps/files_sharing/src/views/shares.spec.ts index 424d3680411..4107c3154ba 100644 --- a/apps/files_sharing/src/views/shares.spec.ts +++ b/apps/files_sharing/src/views/shares.spec.ts @@ -23,19 +23,16 @@ import { expect } from '@jest/globals' import axios from '@nextcloud/axios' -import { type Navigation } from '../../../files/src/services/Navigation' import { type OCSResponse } from '../services/SharingService' -import { NavigationService } from '../../../files/src/services/Navigation' import registerSharingViews from './shares' import '../main' -import { Folder } from '@nextcloud/files' +import { Folder, getNavigation } from '@nextcloud/files' describe('Sharing views definition', () => { let Navigation beforeEach(() => { - Navigation = new NavigationService() - window.OCP = { Files: { Navigation } } + Navigation = getNavigation() }) afterAll(() => { diff --git a/apps/files_sharing/src/views/shares.ts b/apps/files_sharing/src/views/shares.ts index 74be9e7a503..e5e8df8fdb9 100644 --- a/apps/files_sharing/src/views/shares.ts +++ b/apps/files_sharing/src/views/shares.ts @@ -19,8 +19,6 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. * */ -import type { NavigationService, Navigation } from '../../../files/src/services/Navigation' - import { translate as t } from '@nextcloud/l10n' import AccountClockSvg from '@mdi/svg/svg/account-clock.svg?raw' import AccountGroupSvg from '@mdi/svg/svg/account-group.svg?raw' @@ -30,6 +28,7 @@ import LinkSvg from '@mdi/svg/svg/link.svg?raw' import AccountPlusSvg from '@mdi/svg/svg/account-plus.svg?raw' import { getContents } from '../services/SharingService' +import { View, getNavigation } from '@nextcloud/files' export const sharesViewId = 'shareoverview' export const sharedWithYouViewId = 'sharingin' @@ -39,8 +38,8 @@ export const deletedSharesViewId = 'deletedshares' export const pendingSharesViewId = 'pendingshares' export default () => { - const Navigation = window.OCP.Files.Navigation as NavigationService - Navigation.register({ + const Navigation = getNavigation() + Navigation.register(new View({ id: sharesViewId, name: t('files_sharing', 'Shares'), caption: t('files_sharing', 'Overview of shared files.'), @@ -54,9 +53,9 @@ export default () => { columns: [], getContents: () => getContents(), - } as Navigation) + })) - Navigation.register({ + Navigation.register(new View({ id: sharedWithYouViewId, name: t('files_sharing', 'Shared with you'), caption: t('files_sharing', 'List of files that are shared with you.'), @@ -71,9 +70,9 @@ export default () => { columns: [], getContents: () => getContents(true, false, false, false), - } as Navigation) + })) - Navigation.register({ + Navigation.register(new View({ id: sharedWithOthersViewId, name: t('files_sharing', 'Shared with others'), caption: t('files_sharing', 'List of files that you shared with others.'), @@ -88,9 +87,9 @@ export default () => { columns: [], getContents: () => getContents(false, true, false, false), - } as Navigation) + })) - Navigation.register({ + Navigation.register(new View({ id: sharingByLinksViewId, name: t('files_sharing', 'Shared by link'), caption: t('files_sharing', 'List of files that are shared by link.'), @@ -105,9 +104,9 @@ export default () => { columns: [], getContents: () => getContents(false, true, false, false, [window.OC.Share.SHARE_TYPE_LINK]), - } as Navigation) + })) - Navigation.register({ + Navigation.register(new View({ id: deletedSharesViewId, name: t('files_sharing', 'Deleted shares'), caption: t('files_sharing', 'List of shares you left.'), @@ -122,9 +121,9 @@ export default () => { columns: [], getContents: () => getContents(false, false, false, true), - } as Navigation) + })) - Navigation.register({ + Navigation.register(new View({ id: pendingSharesViewId, name: t('files_sharing', 'Pending shares'), caption: t('files_sharing', 'List of unapproved shares.'), @@ -139,5 +138,5 @@ export default () => { columns: [], getContents: () => getContents(false, false, true, false), - } as Navigation) + })) } diff --git a/apps/files_trashbin/src/actions/restoreAction.ts b/apps/files_trashbin/src/actions/restoreAction.ts index 1b14efd545d..ce8b4077195 100644 --- a/apps/files_trashbin/src/actions/restoreAction.ts +++ b/apps/files_trashbin/src/actions/restoreAction.ts @@ -22,14 +22,13 @@ import { emit } from '@nextcloud/event-bus' import { generateRemoteUrl } from '@nextcloud/router' import { getCurrentUser } from '@nextcloud/auth' -import { Permission, Node } from '@nextcloud/files' +import { Permission, Node, View } from '@nextcloud/files' import { translate as t } from '@nextcloud/l10n' import axios from '@nextcloud/axios' import History from '@mdi/svg/svg/history.svg?raw' import { registerFileAction, FileAction } from '../../../files/src/services/FileAction' import logger from '../../../files/src/logger.js' -import type { Navigation } from '../../../files/src/services/Navigation' registerFileAction(new FileAction({ id: 'restore', @@ -70,7 +69,7 @@ registerFileAction(new FileAction({ return false } }, - async execBatch(nodes: Node[], view: Navigation, dir: string) { + async execBatch(nodes: Node[], view: View, dir: string) { return Promise.all(nodes.map(node => this.exec(node, view, dir))) }, diff --git a/apps/files_trashbin/src/main.ts b/apps/files_trashbin/src/main.ts index cf5a95bb1d8..5c625e7bf4f 100644 --- a/apps/files_trashbin/src/main.ts +++ b/apps/files_trashbin/src/main.ts @@ -19,8 +19,6 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. * */ -import type { NavigationService, Navigation } from '../../files/src/services/Navigation' - import { translate as t, translate } from '@nextcloud/l10n' import DeleteSvg from '@mdi/svg/svg/delete.svg?raw' import moment from '@nextcloud/moment' @@ -29,9 +27,10 @@ import { getContents } from './services/trashbin' // Register restore action import './actions/restoreAction' +import { Column, View, getNavigation } from '@nextcloud/files' -const Navigation = window.OCP.Files.Navigation as NavigationService -Navigation.register({ +const Navigation = getNavigation() +Navigation.register(new View({ id: 'trashbin', name: t('files_trashbin', 'Deleted files'), caption: t('files_trashbin', 'List of files that have been deleted.'), @@ -46,7 +45,7 @@ Navigation.register({ defaultSortKey: 'deleted', columns: [ - { + new Column({ id: 'deleted', title: t('files_trashbin', 'Deleted'), render(node) { @@ -67,8 +66,8 @@ Navigation.register({ const deletionTimeB = nodeB.attributes?.['trashbin-deletion-time'] || nodeB?.mtime || 0 return deletionTimeB - deletionTimeA }, - }, + }), ], getContents, -} as Navigation) +})) diff --git a/apps/files_trashbin/src/services/trashbin.ts b/apps/files_trashbin/src/services/trashbin.ts index bc52100a492..2c4aa373a3f 100644 --- a/apps/files_trashbin/src/services/trashbin.ts +++ b/apps/files_trashbin/src/services/trashbin.ts @@ -21,12 +21,11 @@ */ /* eslint-disable */ import { getCurrentUser } from '@nextcloud/auth' -import { File, Folder, davParsePermissions } from '@nextcloud/files' +import { File, Folder, davParsePermissions, type ContentsWithRoot } from '@nextcloud/files' import { generateRemoteUrl, generateUrl } from '@nextcloud/router' import type { FileStat, ResponseDataDetailed } from 'webdav' import { getDavNameSpaces, getDavProperties } from '../../../files/src/services/DavProperties' -import type { ContentsWithRoot } from '../../../files/src/services/Navigation.ts' import client, { rootPath } from './client' |