mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-24 18:02:47 +08:00
feat(core): new doc list for trash page (#12429)
<!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Added "Delete permanently" and "Restore" quick actions for documents in the Trash, enabling users to restore or permanently delete trashed documents directly from the UI. - Introduced multi-restore support, allowing batch restoration of selected trashed documents. - **Improvements** - Quick action tooltips are now localized for better international user experience. - Trash page now uses an updated explorer interface for a more consistent and reactive document management experience. - Enhanced quick actions with optional click handlers for better extensibility. - **Documentation** - Added new translation keys for "Delete permanently" and "Restore" actions. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
@@ -1,14 +1,18 @@
|
||||
import { useBlockSuiteDocMeta } from '@affine/core/components/hooks/use-block-suite-page-meta';
|
||||
import { VirtualizedTrashList } from '@affine/core/components/page-list';
|
||||
import { toast } from '@affine/component';
|
||||
import {
|
||||
createDocExplorerContext,
|
||||
DocExplorerContext,
|
||||
} from '@affine/core/components/explorer/context';
|
||||
import { DocsExplorer } from '@affine/core/components/explorer/docs-view/docs-list';
|
||||
import { useBlockSuiteMetaHelper } from '@affine/core/components/hooks/affine/use-block-suite-meta-helper';
|
||||
import { Header } from '@affine/core/components/pure/header';
|
||||
import { DocsService } from '@affine/core/modules/doc';
|
||||
import { CollectionRulesService } from '@affine/core/modules/collection-rules';
|
||||
import { GlobalContextService } from '@affine/core/modules/global-context';
|
||||
import { WorkspacePermissionService } from '@affine/core/modules/permissions';
|
||||
import { WorkspaceService } from '@affine/core/modules/workspace';
|
||||
import { useI18n } from '@affine/i18n';
|
||||
import { DeleteIcon } from '@blocksuite/icons/rc';
|
||||
import { LiveData, useLiveData, useService } from '@toeverything/infra';
|
||||
import { useEffect, useMemo } from 'react';
|
||||
import { useLiveData, useService } from '@toeverything/infra';
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
|
||||
import {
|
||||
useIsActiveView,
|
||||
@@ -35,23 +39,76 @@ const TrashHeader = () => {
|
||||
};
|
||||
|
||||
export const TrashPage = () => {
|
||||
const t = useI18n();
|
||||
const collectionRulesService = useService(CollectionRulesService);
|
||||
const globalContextService = useService(GlobalContextService);
|
||||
const currentWorkspace = useService(WorkspaceService).workspace;
|
||||
const permissionService = useService(WorkspacePermissionService);
|
||||
const isAdmin = useLiveData(permissionService.permission.isAdmin$);
|
||||
const isOwner = useLiveData(permissionService.permission.isOwner$);
|
||||
const docCollection = currentWorkspace.docCollection;
|
||||
const docsService = useService(DocsService);
|
||||
const allTrashPageIds = useLiveData(
|
||||
LiveData.from(docsService.allTrashDocIds$(), [])
|
||||
|
||||
const { restoreFromTrash } = useBlockSuiteMetaHelper();
|
||||
const isActiveView = useIsActiveView();
|
||||
|
||||
const [explorerContextValue] = useState(() =>
|
||||
createDocExplorerContext({
|
||||
displayProperties: [
|
||||
'system:createdAt',
|
||||
'system:updatedAt',
|
||||
'system:tags',
|
||||
],
|
||||
showMoreOperation: false,
|
||||
showDragHandle: true,
|
||||
showDocPreview: false,
|
||||
quickFavorite: false,
|
||||
quickDeletePermanently: true,
|
||||
quickRestore: true,
|
||||
})
|
||||
);
|
||||
|
||||
const pageMetas = useBlockSuiteDocMeta(docCollection);
|
||||
const filteredPageMetas = useMemo(() => {
|
||||
return pageMetas.filter(page => allTrashPageIds.includes(page.id));
|
||||
}, [pageMetas, allTrashPageIds]);
|
||||
const isAdmin = useLiveData(permissionService.permission.isAdmin$);
|
||||
const isOwner = useLiveData(permissionService.permission.isOwner$);
|
||||
const groups = useLiveData(explorerContextValue.groups$);
|
||||
const isEmpty =
|
||||
groups.length === 0 ||
|
||||
(groups.length > 0 && groups.every(group => !group.items?.length));
|
||||
|
||||
const isActiveView = useIsActiveView();
|
||||
const handleMultiRestore = useCallback(
|
||||
(ids: string[]) => {
|
||||
ids.forEach(id => {
|
||||
restoreFromTrash(id);
|
||||
});
|
||||
toast(
|
||||
t['com.affine.toastMessage.restored']({
|
||||
title: ids.length > 1 ? 'docs' : 'doc',
|
||||
})
|
||||
);
|
||||
},
|
||||
[restoreFromTrash, t]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const subscription = collectionRulesService
|
||||
.watch({
|
||||
filters: [
|
||||
{
|
||||
type: 'system',
|
||||
key: 'trash',
|
||||
method: 'is',
|
||||
value: 'true',
|
||||
},
|
||||
],
|
||||
orderBy: {
|
||||
type: 'system',
|
||||
key: 'updatedAt',
|
||||
desc: true,
|
||||
},
|
||||
})
|
||||
.subscribe(result => {
|
||||
explorerContextValue.groups$.next(result.groups);
|
||||
});
|
||||
|
||||
return () => {
|
||||
subscription.unsubscribe();
|
||||
};
|
||||
}, [collectionRulesService, explorerContextValue.groups$]);
|
||||
|
||||
useEffect(() => {
|
||||
if (isActiveView) {
|
||||
@@ -64,9 +121,8 @@ export const TrashPage = () => {
|
||||
return;
|
||||
}, [globalContextService.globalContext.isTrash, isActiveView]);
|
||||
|
||||
const t = useI18n();
|
||||
return (
|
||||
<>
|
||||
<DocExplorerContext.Provider value={explorerContextValue}>
|
||||
<ViewTitle title={t['Trash']()} />
|
||||
<ViewIcon icon={'trash'} />
|
||||
<ViewHeader>
|
||||
@@ -74,17 +130,17 @@ export const TrashPage = () => {
|
||||
</ViewHeader>
|
||||
<ViewBody>
|
||||
<div className={styles.body}>
|
||||
{filteredPageMetas.length > 0 ? (
|
||||
<VirtualizedTrashList
|
||||
disableMultiDelete={!isAdmin && !isOwner}
|
||||
disableMultiRestore={!isAdmin && !isOwner}
|
||||
/>
|
||||
) : (
|
||||
{isEmpty ? (
|
||||
<EmptyPageList type="trash" />
|
||||
) : (
|
||||
<DocsExplorer
|
||||
disableMultiDelete={!isAdmin && !isOwner}
|
||||
onRestore={isAdmin || isOwner ? handleMultiRestore : undefined}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</ViewBody>
|
||||
</>
|
||||
</DocExplorerContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user