+
+
+
+
+
+
+
+
+
+
+
diff --git a/apps/files/src/main.js b/apps/files/src/main.js
index 3099a4c619c..3d1c88755f0 100644
--- a/apps/files/src/main.js
+++ b/apps/files/src/main.js
@@ -4,12 +4,15 @@ import processLegacyFilesViews from './legacy/navigationMapper.js'
import Vue from 'vue'
import NavigationService from './services/Navigation.ts'
+
import NavigationView from './views/Navigation.vue'
+import FilesListView from './views/FilesList.vue'
import SettingsService from './services/Settings.js'
import SettingsModel from './models/Setting.js'
import router from './router/router.js'
+import store from './store/index.ts'
// Init private and public Files namespace
window.OCA.Files = window.OCA.Files ?? {}
@@ -35,5 +38,17 @@ const FilesNavigationRoot = new View({
})
FilesNavigationRoot.$mount('#app-navigation-files')
+// Init content list view
+const ListView = Vue.extend(FilesListView)
+const FilesList = new ListView({
+ name: 'FilesListRoot',
+ propsData: {
+ Navigation,
+ },
+ router,
+ store,
+})
+FilesList.$mount('#app-content-vue')
+
// Init legacy files views
processLegacyFilesViews()
diff --git a/apps/files/src/mixins/fileslist-row.scss b/apps/files/src/mixins/fileslist-row.scss
new file mode 100644
index 00000000000..9b0c3197b76
--- /dev/null
+++ b/apps/files/src/mixins/fileslist-row.scss
@@ -0,0 +1,63 @@
+/**
+ * @copyright Copyright (c) 2023 John Molakvoæ
+ *
+ * @author John Molakvoæ
+ *
+ * @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 .
+ *
+ */
+td, th {
+ height: var(--row-height);
+ vertical-align: middle;
+ padding: 0px;
+ border: none;
+}
+
+.files-list__row-checkbox {
+ width: var(--row-height);
+ &::v-deep .checkbox-radio-switch {
+ --icon-size: var(--checkbox-size);
+
+ display: flex;
+ justify-content: center;
+
+ label.checkbox-radio-switch__label {
+ margin: 0;
+ height: var(--clickable-area);
+ width: var(--clickable-area);
+ padding: calc((var(--clickable-area) - var(--checkbox-size)) / 2)
+ }
+
+ .checkbox-radio-switch__icon {
+ margin: 0 !important;
+ }
+ }
+}
+
+.files-list__row-icon {
+ // Remove left padding to look nicer with the checkbox
+ // => ico preview size + one checkbox td padding
+ width: calc(var(--icon-preview-size) + var(--checkbox-padding));
+ padding-right: var(--checkbox-padding);
+ color: var(--color-primary-element);
+ & > span {
+ justify-content: flex-start;
+ }
+ &::v-deep svg {
+ width: var(--icon-preview-size);
+ height: var(--icon-preview-size);
+ }
+}
diff --git a/apps/files/src/services/Navigation.ts b/apps/files/src/services/Navigation.ts
index 9efed538825..01b6e701c72 100644
--- a/apps/files/src/services/Navigation.ts
+++ b/apps/files/src/services/Navigation.ts
@@ -19,19 +19,27 @@
* along with this program. If not, see .
*
*/
-import type Node from '@nextcloud/files/dist/files/node'
+/* eslint-disable */
+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
- /** Property key from Node main or additional attributes.
- Will be used if no custom sort function is provided.
- Sorting will be done by localCompare */
+ /**
+ * Property key from Node main or additional attributes.
+ * Will be used if no custom sort function is provided.
+ * Sorting will be done by localCompare
+ */
property: string
/** Special function used to sort Nodes between them */
sortFunction?: (nodeA: Node, nodeB: Node) => number;
@@ -45,8 +53,15 @@ export interface Navigation {
id: string
/** Translated view name */
name: string
- /** Method return the content of the provided path */
- getFiles: (path: string) => Node[]
+ /**
+ * 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
/** The view icon as an inline svg */
icon: string
/** The view order */
@@ -150,8 +165,8 @@ const isValidNavigation = function(view: Navigation): boolean {
* TODO: remove when support for legacy views is removed
*/
if (!view.legacy) {
- if (!view.getFiles || typeof view.getFiles !== 'function') {
- throw new Error('Navigation getFiles is required and must be a function')
+ 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)) {
diff --git a/apps/files/src/store/files.ts b/apps/files/src/store/files.ts
new file mode 100644
index 00000000000..e9760e2bc85
--- /dev/null
+++ b/apps/files/src/store/files.ts
@@ -0,0 +1,97 @@
+/**
+ * @copyright Copyright (c) 2023 John Molakvoæ
+ *
+ * @author John Molakvoæ
+ *
+ * @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 .
+ *
+ */
+/* eslint-disable */
+import type { Folder, Node } from '@nextcloud/files'
+import Vue from 'vue'
+import type { FileStore, RootStore, RootOptions, Service } from '../types'
+
+const state = {
+ files: {} as FileStore,
+ roots: {} as RootStore,
+}
+
+const getters = {
+ /**
+ * Get a file or folder by id
+ */
+ getNode: (state) => (id: number): Node|undefined => state.files[id],
+
+ /**
+ * Get a list of files or folders by their IDs
+ * Does not return undefined values
+ */
+ getNodes: (state) => (ids: number[]): Node[] => ids
+ .map(id => state.files[id])
+ .filter(Boolean),
+ /**
+ * Get a file or folder by id
+ */
+ getRoot: (state) => (service: Service): Folder|undefined => state.roots[service],
+}
+
+const mutations = {
+ updateNodes: (state, nodes: Node[]) => {
+ nodes.forEach(node => {
+ if (!node.attributes.fileid) {
+ return
+ }
+ Vue.set(state.files, node.attributes.fileid, node)
+ // state.files = {
+ // ...state.files,
+ // [node.attributes.fileid]: node,
+ // }
+ })
+ },
+
+ setRoot: (state, { service, root }: RootOptions) => {
+ state.roots = {
+ ...state.roots,
+ [service]: root,
+ }
+ }
+}
+
+const actions = {
+ /**
+ * Insert valid nodes into the store.
+ * Roots (that does _not_ have a fileid) should
+ * be defined in the roots store
+ */
+ addNodes: (context, nodes: Node[]) => {
+ context.commit('updateNodes', nodes)
+ },
+
+ /**
+ * Set the root of a service
+ */
+ setRoot(context, { service, root }: RootOptions) {
+ context.commit('setRoot', { service, root })
+ }
+}
+
+export default {
+ namespaced: true,
+ state,
+ getters,
+ mutations,
+ actions,
+}
diff --git a/apps/files/src/store/index.ts b/apps/files/src/store/index.ts
new file mode 100644
index 00000000000..52007fef892
--- /dev/null
+++ b/apps/files/src/store/index.ts
@@ -0,0 +1,16 @@
+import Vue from 'vue'
+import Vuex, { Store } from 'vuex'
+
+import files from './files'
+import paths from './paths'
+import selection from './selection'
+
+Vue.use(Vuex)
+
+export default new Store({
+ modules: {
+ files,
+ paths,
+ selection,
+ },
+})
diff --git a/apps/files/src/store/paths.ts b/apps/files/src/store/paths.ts
new file mode 100644
index 00000000000..d6b23578da7
--- /dev/null
+++ b/apps/files/src/store/paths.ts
@@ -0,0 +1,71 @@
+/**
+ * @copyright Copyright (c) 2023 John Molakvoæ
+ *
+ * @author John Molakvoæ
+ *
+ * @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 .
+ *
+ */
+/* eslint-disable */
+import type { Folder } from '@nextcloud/files'
+import Vue from 'vue'
+import type { PathOptions, ServicePaths, ServiceStore } from '../types'
+
+const module = {
+ state: {
+ services: {
+ files: {} as ServicePaths,
+ } as ServiceStore,
+ },
+
+ getters: {
+ getPath(state: { services: ServiceStore }) {
+ return (service: string, path: string): number|undefined => {
+ if (!state.services[service]) {
+ return undefined
+ }
+ return state.services[service][path]
+ }
+ },
+ },
+
+ mutations: {
+ addPath: (state, opts: PathOptions) => {
+ // If it doesn't exists, init the service state
+ if (!state.services[opts.service]) {
+ // TODO: investigate why Vue.set is not working
+ state.services = {
+ [opts.service]: {} as ServicePaths,
+ ...state.services
+ }
+ }
+
+ // Now we can set the path
+ Vue.set(state.services[opts.service], opts.path, opts.fileid)
+ }
+ },
+
+ actions: {
+ addPath: (context, opts: PathOptions) => {
+ context.commit('addPath', opts)
+ },
+ }
+}
+
+export default {
+ namespaced: true,
+ ...module,
+}
diff --git a/apps/files/src/store/selection.ts b/apps/files/src/store/selection.ts
new file mode 100644
index 00000000000..3ec61848c98
--- /dev/null
+++ b/apps/files/src/store/selection.ts
@@ -0,0 +1,51 @@
+/**
+ * @copyright Copyright (c) 2023 John Molakvoæ
+ *
+ * @author John Molakvoæ
+ *
+ * @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 .
+ *
+ */
+/* eslint-disable */
+import type { Folder } from '@nextcloud/files'
+import Vue from 'vue'
+import type { PathOptions, ServicePaths, ServiceStore } from '../types'
+
+const module = {
+ state: {
+ selected: [] as number[]
+ },
+
+ mutations: {
+ set: (state, selection: number[]) => {
+ Vue.set(state, 'selected', selection)
+ }
+ },
+
+ actions: {
+ set: (context, selection = [] as number[]) => {
+ context.commit('set', selection)
+ },
+ reset(context) {
+ context.commit('set', [])
+ }
+ }
+}
+
+export default {
+ namespaced: true,
+ ...module,
+}
diff --git a/apps/files/src/types.ts b/apps/files/src/types.ts
new file mode 100644
index 00000000000..1c7068985d8
--- /dev/null
+++ b/apps/files/src/types.ts
@@ -0,0 +1,56 @@
+/**
+ * @copyright Copyright (c) 2023 John Molakvoæ
+ *
+ * @author John Molakvoæ
+ *
+ * @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 .
+ *
+ */
+/* eslint-disable */
+import type { Folder } from '@nextcloud/files'
+import type { Node } from '@nextcloud/files'
+
+// Global definitions
+export type Service = string
+
+// Files store
+export type FileStore = {
+ [id: number]: Node
+}
+
+export type RootStore = {
+ [service: Service]: Folder
+}
+
+export interface RootOptions {
+ root: Folder
+ service: Service
+}
+
+// Paths store
+export type ServicePaths = {
+ [path: string]: number
+}
+
+export type ServiceStore = {
+ [service: Service]: ServicePaths
+}
+
+export interface PathOptions {
+ service: Service
+ path: string
+ fileid: number
+}
diff --git a/apps/files/src/views/FilesList.vue b/apps/files/src/views/FilesList.vue
new file mode 100644
index 00000000000..adc8a3bcb0f
--- /dev/null
+++ b/apps/files/src/views/FilesList.vue
@@ -0,0 +1,318 @@
+
+
+
+
-
-
diff --git a/apps/files_trashbin/composer/composer/autoload_classmap.php b/apps/files_trashbin/composer/composer/autoload_classmap.php
index 760044d4f87..01f602448d4 100644
--- a/apps/files_trashbin/composer/composer/autoload_classmap.php
+++ b/apps/files_trashbin/composer/composer/autoload_classmap.php
@@ -21,6 +21,7 @@ return array(
'OCA\\Files_Trashbin\\Expiration' => $baseDir . '/../lib/Expiration.php',
'OCA\\Files_Trashbin\\Helper' => $baseDir . '/../lib/Helper.php',
'OCA\\Files_Trashbin\\Hooks' => $baseDir . '/../lib/Hooks.php',
+ 'OCA\\Files_Trashbin\\Listeners\\LoadAdditionalScripts' => $baseDir . '/../lib/Listeners/LoadAdditionalScripts.php',
'OCA\\Files_Trashbin\\Migration\\Version1010Date20200630192639' => $baseDir . '/../lib/Migration/Version1010Date20200630192639.php',
'OCA\\Files_Trashbin\\Sabre\\AbstractTrash' => $baseDir . '/../lib/Sabre/AbstractTrash.php',
'OCA\\Files_Trashbin\\Sabre\\AbstractTrashFile' => $baseDir . '/../lib/Sabre/AbstractTrashFile.php',
diff --git a/apps/files_trashbin/composer/composer/autoload_static.php b/apps/files_trashbin/composer/composer/autoload_static.php
index ef52ac0e1e7..40f3310c663 100644
--- a/apps/files_trashbin/composer/composer/autoload_static.php
+++ b/apps/files_trashbin/composer/composer/autoload_static.php
@@ -36,6 +36,7 @@ class ComposerStaticInitFiles_Trashbin
'OCA\\Files_Trashbin\\Expiration' => __DIR__ . '/..' . '/../lib/Expiration.php',
'OCA\\Files_Trashbin\\Helper' => __DIR__ . '/..' . '/../lib/Helper.php',
'OCA\\Files_Trashbin\\Hooks' => __DIR__ . '/..' . '/../lib/Hooks.php',
+ 'OCA\\Files_Trashbin\\Listeners\\LoadAdditionalScripts' => __DIR__ . '/..' . '/../lib/Listeners/LoadAdditionalScripts.php',
'OCA\\Files_Trashbin\\Migration\\Version1010Date20200630192639' => __DIR__ . '/..' . '/../lib/Migration/Version1010Date20200630192639.php',
'OCA\\Files_Trashbin\\Sabre\\AbstractTrash' => __DIR__ . '/..' . '/../lib/Sabre/AbstractTrash.php',
'OCA\\Files_Trashbin\\Sabre\\AbstractTrashFile' => __DIR__ . '/..' . '/../lib/Sabre/AbstractTrashFile.php',
diff --git a/apps/files_trashbin/lib/AppInfo/Application.php b/apps/files_trashbin/lib/AppInfo/Application.php
index 41466a865ac..461eade6802 100644
--- a/apps/files_trashbin/lib/AppInfo/Application.php
+++ b/apps/files_trashbin/lib/AppInfo/Application.php
@@ -26,8 +26,10 @@
namespace OCA\Files_Trashbin\AppInfo;
use OCA\DAV\Connector\Sabre\Principal;
+use OCA\Files\Event\LoadAdditionalScriptsEvent;
use OCA\Files_Trashbin\Capabilities;
use OCA\Files_Trashbin\Expiration;
+use OCA\Files_Trashbin\Listeners\LoadAdditionalScripts;
use OCA\Files_Trashbin\Trash\ITrashManager;
use OCA\Files_Trashbin\Trash\TrashManager;
use OCA\Files_Trashbin\UserMigration\TrashbinMigrator;
@@ -55,6 +57,11 @@ class Application extends App implements IBootstrap {
$context->registerServiceAlias('principalBackend', Principal::class);
$context->registerUserMigrator(TrashbinMigrator::class);
+
+ $context->registerEventListener(
+ LoadAdditionalScriptsEvent::class,
+ LoadAdditionalScripts::class
+ );
}
public function boot(IBootContext $context): void {
@@ -68,18 +75,6 @@ class Application extends App implements IBootstrap {
\OCP\Util::connectHook('OC_Filesystem', 'post_write', 'OCA\Files_Trashbin\Hooks', 'post_write_hook');
// pre and post-rename, disable trash logic for the copy+unlink case
\OCP\Util::connectHook('OC_Filesystem', 'delete', 'OCA\Files_Trashbin\Trashbin', 'ensureFileScannedHook');
-
- \OCA\Files\App::getNavigationManager()->add(function () {
- $l = \OC::$server->getL10N(self::APP_ID);
- return [
- 'id' => 'trashbin',
- 'appname' => self::APP_ID,
- 'script' => 'list.php',
- 'order' => 50,
- 'name' => $l->t('Deleted files'),
- 'classes' => 'pinned',
- ];
- });
}
public function registerTrashBackends(IServerContainer $serverContainer, ILogger $logger, IAppManager $appManager, ITrashManager $trashManager) {
diff --git a/apps/files_trashbin/lib/Listeners/LoadAdditionalScripts.php b/apps/files_trashbin/lib/Listeners/LoadAdditionalScripts.php
new file mode 100644
index 00000000000..33b1b2de1cc
--- /dev/null
+++ b/apps/files_trashbin/lib/Listeners/LoadAdditionalScripts.php
@@ -0,0 +1,41 @@
+
+ *
+ * @author John Molakvoæ
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * 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 .
+ *
+ */
+namespace OCA\Files_Trashbin\Listeners;
+
+use OCA\Files_Trashbin\AppInfo\Application;
+use OCA\Files\Event\LoadAdditionalScriptsEvent;
+use OCP\EventDispatcher\Event;
+use OCP\EventDispatcher\IEventListener;
+use OCP\Util;
+
+class LoadAdditionalScripts implements IEventListener {
+ public function handle(Event $event): void {
+ if (!($event instanceof LoadAdditionalScriptsEvent)) {
+ return;
+ }
+
+ Util::addScript(Application::APP_ID, 'main');
+ }
+}
diff --git a/apps/files_trashbin/src/main.ts b/apps/files_trashbin/src/main.ts
new file mode 100644
index 00000000000..626b9ef813d
--- /dev/null
+++ b/apps/files_trashbin/src/main.ts
@@ -0,0 +1,39 @@
+/**
+ * @copyright Copyright (c) 2023 John Molakvoæ
+ *
+ * @author John Molakvoæ
+ *
+ * @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 .
+ *
+ */
+import type NavigationService from '../../files/src/services/Navigation'
+
+import { translate as t } from '@nextcloud/l10n'
+import DeleteSvg from '@mdi/svg/svg/delete.svg?raw'
+
+import getContents from './services/trashbin'
+
+const Navigation = window.OCP.Files.Navigation as NavigationService
+Navigation.register({
+ id: 'trashbin',
+ name: t('files_trashbin', 'Deleted files'),
+
+ icon: DeleteSvg,
+ order: 50,
+ sticky: true,
+
+ getContents,
+})
diff --git a/apps/files_trashbin/src/services/client.ts b/apps/files_trashbin/src/services/client.ts
new file mode 100644
index 00000000000..9fb3361839a
--- /dev/null
+++ b/apps/files_trashbin/src/services/client.ts
@@ -0,0 +1,33 @@
+/**
+ * @copyright Copyright (c) 2023 John Molakvoæ
+ *
+ * @author John Molakvoæ
+ *
+ * @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 .
+ *
+ */
+import { createClient } from 'webdav'
+import { generateRemoteUrl } from '@nextcloud/router'
+import { getCurrentUser, getRequestToken } from '@nextcloud/auth'
+
+export const rootPath = `/trashbin/${getCurrentUser()?.uid}/trash`
+export const rootUrl = generateRemoteUrl('dav' + rootPath)
+const client = createClient(rootUrl, {
+ headers: {
+ requesttoken: getRequestToken(),
+ },
+})
+export default client
diff --git a/apps/files_trashbin/src/services/trashbin.ts b/apps/files_trashbin/src/services/trashbin.ts
new file mode 100644
index 00000000000..2070cfc92b0
--- /dev/null
+++ b/apps/files_trashbin/src/services/trashbin.ts
@@ -0,0 +1,95 @@
+/**
+ * @copyright Copyright (c) 2023 John Molakvoæ
+ *
+ * @author John Molakvoæ
+ *
+ * @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 .
+ *
+ */
+/* eslint-disable */
+import { getCurrentUser } from '@nextcloud/auth'
+import { File, Folder, parseWebdavPermissions } from '@nextcloud/files'
+import { generateRemoteUrl } from '@nextcloud/router'
+
+import type { FileStat, ResponseDataDetailed } from 'webdav'
+import type { ContentsWithRoot } from '../../../files/src/services/Navigation'
+
+import client, { rootPath } from './client'
+
+const data = `
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`
+
+const resultToNode = function(node: FileStat): File | Folder {
+ const permissions = parseWebdavPermissions(node.props?.permissions)
+ const owner = getCurrentUser()?.uid as string
+
+ const nodeData = {
+ id: node.props?.fileid as number || 0,
+ source: generateRemoteUrl('dav' + rootPath + node.filename),
+ mtime: new Date(node.lastmod),
+ mime: node.mime as string,
+ size: node.props?.size as number || 0,
+ permissions,
+ owner,
+ root: rootPath,
+ attributes: {
+ ...node,
+ ...node.props,
+ // Override displayed name on the list
+ displayName: node.props?.['trashbin-filename'],
+ },
+ }
+
+ return node.type === 'file'
+ ? new File(nodeData)
+ : new Folder(nodeData)
+}
+
+export default async (path: string = '/'): Promise => {
+ // TODO: use only one request when webdav-client supports it
+ // @see https://github.com/perry-mitchell/webdav-client/pull/334
+ const rootResponse = await client.stat(path, {
+ details: true,
+ data,
+ }) as ResponseDataDetailed
+
+ const contentsResponse = await client.getDirectoryContents(path, {
+ details: true,
+ data,
+ }) as ResponseDataDetailed
+
+ return {
+ folder: resultToNode(rootResponse.data) as Folder,
+ contents: contentsResponse.data.map(resultToNode),
+ }
+}
diff --git a/apps/files_trashbin/src/trash.scss b/apps/files_trashbin/src/trash.scss
deleted file mode 100644
index 633107c9d6d..00000000000
--- a/apps/files_trashbin/src/trash.scss
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright (c) 2014
- *
- * This file is licensed under the Affero General Public License version 3
- * or later.
- *
- * See the COPYING-README file.
- *
- */
-#app-content-trashbin tbody tr[data-type="file"] td a.name,
-#app-content-trashbin tbody tr[data-type="file"] td a.name span.nametext,
-#app-content-trashbin tbody tr[data-type="file"] td a.name span.nametext span {
- cursor: default;
-}
-
-#app-content-trashbin .summary :last-child {
- padding: 0;
-}
-#app-content-trashbin .files-filestable .summary .filesize {
- display: none;
-}
-
diff --git a/apps/files_trashbin/tests/js/appSpec.js b/apps/files_trashbin/tests/js/appSpec.js
deleted file mode 100644
index 281e7bbc2ba..00000000000
--- a/apps/files_trashbin/tests/js/appSpec.js
+++ /dev/null
@@ -1,70 +0,0 @@
-/**
-* @copyright 2014 Vincent Petry
- *
- * @author Vincent Petry
- *
- * @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 .
- *
- */
-
-describe('OCA.Trashbin.App tests', function() {
- var App = OCA.Trashbin.App;
-
- beforeEach(function() {
- $('#testArea').append(
- '
'
- );
- App.initialize($('#app-content-trashbin'));
- });
- afterEach(function() {
- App._initialized = false;
- App.fileList = null;
- });
-
- describe('initialization', function() {
- it('creates a custom filelist instance', function() {
- App.initialize();
- expect(App.fileList).toBeDefined();
- expect(App.fileList.$el.is('#app-content-trashbin')).toEqual(true);
- });
-
- it('registers custom file actions', function() {
- var fileActions;
- App.initialize();
-
- fileActions = App.fileList.fileActions;
-
- expect(fileActions.actions.all).toBeDefined();
- expect(fileActions.actions.all.Restore).toBeDefined();
- expect(fileActions.actions.all.Delete).toBeDefined();
-
- expect(fileActions.actions.all.Rename).not.toBeDefined();
- expect(fileActions.actions.all.Download).not.toBeDefined();
-
- expect(fileActions.defaults.dir).toEqual('Open');
- });
- });
-});
diff --git a/apps/files_trashbin/tests/js/filelistSpec.js b/apps/files_trashbin/tests/js/filelistSpec.js
deleted file mode 100644
index 9e27188efb8..00000000000
--- a/apps/files_trashbin/tests/js/filelistSpec.js
+++ /dev/null
@@ -1,397 +0,0 @@
-/**
- * @copyright 2014 Vincent Petry
- *
- * @author Abijeet
- * @author Christoph Wurst
- * @author Jan C. Borchardt
- * @author Jan-Christoph Borchardt
- * @author John Molakvoæ
- * @author Robin Appelman
- * @author Vincent Petry
- *
- * @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 .
- *
- */
-
-describe('OCA.Trashbin.FileList tests', function () {
- var testFiles, alertStub, notificationStub, fileList, client;
-
- beforeEach(function () {
- alertStub = sinon.stub(OC.dialogs, 'alert');
- notificationStub = sinon.stub(OC.Notification, 'show');
-
- client = new OC.Files.Client({
- host: 'localhost',
- port: 80,
- root: '/remote.php/dav/trashbin/user',
- useHTTPS: OC.getProtocol() === 'https'
- });
-
- // init parameters and test table elements
- $('#testArea').append(
- '
' +
- // set this but it shouldn't be used (could be the one from the
- // files app)
- '' +
- // dummy controls
- '
' +
- ' ' +
- ' ' +
- '
' +
- // dummy table
- // TODO: at some point this will be rendered by the fileList class itself!
- '