Skip to content

Commit

Permalink
feat(trashbin): Allow emptying trash
Browse files Browse the repository at this point in the history
Signed-off-by: Christopher Ng <[email protected]>
  • Loading branch information
Pytal authored and skjnldsv committed Dec 12, 2024
1 parent 90ea62e commit 7f7019e
Show file tree
Hide file tree
Showing 3 changed files with 125 additions and 1 deletion.
109 changes: 109 additions & 0 deletions apps/files_trashbin/src/fileListActions/emptyTrashAction.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
/**
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

import type { Node } from '@nextcloud/files'

import PQueue from 'p-queue'
import { FileListAction } from '@nextcloud/files'
import {
DialogSeverity,
getDialogBuilder,
showError,
showInfo,
showSuccess,
TOAST_PERMANENT_TIMEOUT,
} from '@nextcloud/dialogs'

import { deleteNode } from '../../../files/src/actions/deleteUtils.ts'
import { logger } from '../logger.ts'

type Toast = ReturnType<typeof showInfo>

const queue = new PQueue({ concurrency: 5 })

const showLoadingToast = (): null | Toast => {
const message = t('files_trashbin', 'Deleting files…')
let toast: null | Toast = null
toast = showInfo(
`<span class="icon icon-loading-small toast-loading-icon"></span> ${message}`,
{
isHTML: true,
timeout: TOAST_PERMANENT_TIMEOUT,
onRemove: () => {
toast?.hideToast()
toast = null
},
},
)
return toast
}

const emptyTrash = async (nodes: Node[]) => {
const promises = nodes.map((node) => {
const { promise, resolve, reject } = Promise.withResolvers<void>()
queue.add(async () => {
try {
await deleteNode(node)
resolve()
} catch (error) {
logger.error('Failed to delete node', { error, node })
reject(error)
}
})
return promise
})

const toast = showLoadingToast()
const results = await Promise.allSettled(promises)
if (results.some((result) => result.status === 'rejected')) {
toast?.hideToast()
showError(t('files_trashbin', 'Failed to delete all previously deleted files'))
return
}
toast?.hideToast()
showSuccess(t('files_trashbin', 'Permanently deleted all previously deleted files'))
}

export const emptyTrashAction = new FileListAction({
id: 'empty-trash',

displayName: () => t('files_trashbin', 'Empty deleted files'),
order: 0,

enabled: (view, nodes, { folder }) => {
if (view.id !== 'trashbin') {
return false
}
return nodes.length > 0 && folder.path === '/'
},

exec: async (view, nodes) => {
const dialog = getDialogBuilder(t('files_trashbin', 'Confirm permanent deletion'))
.setSeverity(DialogSeverity.Warning)
// TODO Add note for groupfolders
.setText(t('files_trashbin', 'Are you sure you want to permanently delete all previously deleted files? This cannot be undone.'))
.setButtons([
{
label: t('files_trashbin', 'Cancel'),
type: 'secondary',
callback: () => {},
},
{
label: t('files_trashbin', 'Empty deleted files'),
type: 'error',
callback: () => {
emptyTrash(nodes)
},
},
])
.build()

try {
await dialog.show()
} catch (error) {
// Allow throw on dialog close
}
},
})
6 changes: 5 additions & 1 deletion apps/files_trashbin/src/files-init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,16 @@
import './trashbin.scss'

import { translate as t } from '@nextcloud/l10n'
import { View, getNavigation, registerFileListAction } from '@nextcloud/files'
import DeleteSvg from '@mdi/svg/svg/delete.svg?raw'

import { getContents } from './services/trashbin'
import { columns } from './columns.ts'

// Register restore action
import './actions/restoreAction'
import { View, getNavigation } from '@nextcloud/files'

import { emptyTrashAction } from './fileListActions/emptyTrashAction.ts'

const Navigation = getNavigation()
Navigation.register(new View({
Expand All @@ -34,3 +36,5 @@ Navigation.register(new View({

getContents,
}))

registerFileListAction(emptyTrashAction)
11 changes: 11 additions & 0 deletions apps/files_trashbin/src/logger.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/**
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

import { getLoggerBuilder } from '@nextcloud/logger'

export const logger = getLoggerBuilder()
.setApp('files_trashbin')
.detectUser()
.build()

0 comments on commit 7f7019e

Please sign in to comment.