fix(core): optimize performance when editing doc title (#7328)
This commit is contained in:
@@ -17,6 +17,7 @@ export class Doc extends Entity {
|
|||||||
readonly meta$ = this.record.meta$;
|
readonly meta$ = this.record.meta$;
|
||||||
readonly mode$ = this.record.mode$;
|
readonly mode$ = this.record.mode$;
|
||||||
readonly title$ = this.record.title$;
|
readonly title$ = this.record.title$;
|
||||||
|
readonly trash$ = this.record.trash$;
|
||||||
|
|
||||||
setMode(mode: DocMode) {
|
setMode(mode: DocMode) {
|
||||||
return this.record.setMode(mode);
|
return this.record.setMode(mode);
|
||||||
@@ -33,4 +34,12 @@ export class Doc extends Entity {
|
|||||||
observeMode() {
|
observeMode() {
|
||||||
return this.record.observeMode();
|
return this.record.observeMode();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
moveToTrash() {
|
||||||
|
return this.record.moveToTrash();
|
||||||
|
}
|
||||||
|
|
||||||
|
restoreFromTrash() {
|
||||||
|
return this.record.restoreFromTrash();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,5 +50,14 @@ export class DocRecord extends Entity<{ id: string }> {
|
|||||||
return this.docsStore.watchDocModeSetting(this.id);
|
return this.docsStore.watchDocModeSetting(this.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
moveToTrash() {
|
||||||
|
return this.setMeta({ trash: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
restoreFromTrash() {
|
||||||
|
return this.setMeta({ trash: false });
|
||||||
|
}
|
||||||
|
|
||||||
title$ = this.meta$.map(meta => meta.title ?? '');
|
title$ = this.meta$.map(meta => meta.title ?? '');
|
||||||
|
trash$ = this.meta$.map(meta => meta.trash ?? false);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,17 +12,14 @@ import { CollectionOperationCell } from '../operation-cell';
|
|||||||
import { CollectionListItemRenderer } from '../page-group';
|
import { CollectionListItemRenderer } from '../page-group';
|
||||||
import { ListTableHeader } from '../page-header';
|
import { ListTableHeader } from '../page-header';
|
||||||
import type { CollectionMeta, ItemListHandle, ListItem } from '../types';
|
import type { CollectionMeta, ItemListHandle, ListItem } from '../types';
|
||||||
import type { AllPageListConfig } from '../view';
|
|
||||||
import { VirtualizedList } from '../virtualized-list';
|
import { VirtualizedList } from '../virtualized-list';
|
||||||
import { CollectionListHeader } from './collection-list-header';
|
import { CollectionListHeader } from './collection-list-header';
|
||||||
|
|
||||||
const useCollectionOperationsRenderer = ({
|
const useCollectionOperationsRenderer = ({
|
||||||
info,
|
info,
|
||||||
service,
|
service,
|
||||||
config,
|
|
||||||
}: {
|
}: {
|
||||||
info: DeleteCollectionInfo;
|
info: DeleteCollectionInfo;
|
||||||
config: AllPageListConfig;
|
|
||||||
service: CollectionService;
|
service: CollectionService;
|
||||||
}) => {
|
}) => {
|
||||||
const collectionOperationsRenderer = useCallback(
|
const collectionOperationsRenderer = useCallback(
|
||||||
@@ -32,11 +29,10 @@ const useCollectionOperationsRenderer = ({
|
|||||||
info={info}
|
info={info}
|
||||||
collection={collection}
|
collection={collection}
|
||||||
service={service}
|
service={service}
|
||||||
config={config}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
[config, info, service]
|
[info, service]
|
||||||
);
|
);
|
||||||
|
|
||||||
return collectionOperationsRenderer;
|
return collectionOperationsRenderer;
|
||||||
@@ -48,11 +44,9 @@ export const VirtualizedCollectionList = ({
|
|||||||
setHideHeaderCreateNewCollection,
|
setHideHeaderCreateNewCollection,
|
||||||
node,
|
node,
|
||||||
handleCreateCollection,
|
handleCreateCollection,
|
||||||
config,
|
|
||||||
}: {
|
}: {
|
||||||
collections: Collection[];
|
collections: Collection[];
|
||||||
collectionMetas: CollectionMeta[];
|
collectionMetas: CollectionMeta[];
|
||||||
config: AllPageListConfig;
|
|
||||||
node: ReactElement | null;
|
node: ReactElement | null;
|
||||||
handleCreateCollection: () => void;
|
handleCreateCollection: () => void;
|
||||||
setHideHeaderCreateNewCollection: (hide: boolean) => void;
|
setHideHeaderCreateNewCollection: (hide: boolean) => void;
|
||||||
@@ -69,7 +63,6 @@ export const VirtualizedCollectionList = ({
|
|||||||
const collectionOperations = useCollectionOperationsRenderer({
|
const collectionOperations = useCollectionOperationsRenderer({
|
||||||
info,
|
info,
|
||||||
service: collectionService,
|
service: collectionService,
|
||||||
config,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const filteredSelectedCollectionIds = useMemo(() => {
|
const filteredSelectedCollectionIds = useMemo(() => {
|
||||||
|
|||||||
@@ -28,7 +28,6 @@ import { CollectionService } from '../../../modules/collection';
|
|||||||
import { usePageHelper } from '../../blocksuite/block-suite-page-list/utils';
|
import { usePageHelper } from '../../blocksuite/block-suite-page-list/utils';
|
||||||
import { createTagFilter } from '../filter/utils';
|
import { createTagFilter } from '../filter/utils';
|
||||||
import { createEmptyCollection } from '../use-collection-manager';
|
import { createEmptyCollection } from '../use-collection-manager';
|
||||||
import type { AllPageListConfig } from '../view/edit-collection/edit-collection';
|
|
||||||
import {
|
import {
|
||||||
useEditCollection,
|
useEditCollection,
|
||||||
useEditCollectionName,
|
useEditCollectionName,
|
||||||
@@ -87,9 +86,7 @@ export const PageListHeader = () => {
|
|||||||
export const CollectionPageListHeader = ({
|
export const CollectionPageListHeader = ({
|
||||||
collection,
|
collection,
|
||||||
workspaceId,
|
workspaceId,
|
||||||
config,
|
|
||||||
}: {
|
}: {
|
||||||
config: AllPageListConfig;
|
|
||||||
collection: Collection;
|
collection: Collection;
|
||||||
workspaceId: string;
|
workspaceId: string;
|
||||||
}) => {
|
}) => {
|
||||||
@@ -101,7 +98,7 @@ export const CollectionPageListHeader = ({
|
|||||||
}, [jumpToCollections, workspaceId]);
|
}, [jumpToCollections, workspaceId]);
|
||||||
|
|
||||||
const collectionService = useService(CollectionService);
|
const collectionService = useService(CollectionService);
|
||||||
const { node, open } = useEditCollection(config);
|
const { node, open } = useEditCollection();
|
||||||
|
|
||||||
const handleEdit = useAsyncCallback(async () => {
|
const handleEdit = useAsyncCallback(async () => {
|
||||||
const ret = await open({ ...collection }, 'page');
|
const ret = await open({ ...collection }, 'page');
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ import { PageListItemRenderer } from '../page-group';
|
|||||||
import { ListTableHeader } from '../page-header';
|
import { ListTableHeader } from '../page-header';
|
||||||
import type { ItemListHandle, ListItem } from '../types';
|
import type { ItemListHandle, ListItem } from '../types';
|
||||||
import { useFilteredPageMetas } from '../use-filtered-page-metas';
|
import { useFilteredPageMetas } from '../use-filtered-page-metas';
|
||||||
import type { AllPageListConfig } from '../view/edit-collection/edit-collection';
|
|
||||||
import { VirtualizedList } from '../virtualized-list';
|
import { VirtualizedList } from '../virtualized-list';
|
||||||
import {
|
import {
|
||||||
CollectionPageListHeader,
|
CollectionPageListHeader,
|
||||||
@@ -55,14 +54,12 @@ export const VirtualizedPageList = ({
|
|||||||
tag,
|
tag,
|
||||||
collection,
|
collection,
|
||||||
filters,
|
filters,
|
||||||
config,
|
|
||||||
listItem,
|
listItem,
|
||||||
setHideHeaderCreateNewPage,
|
setHideHeaderCreateNewPage,
|
||||||
}: {
|
}: {
|
||||||
tag?: Tag;
|
tag?: Tag;
|
||||||
collection?: Collection;
|
collection?: Collection;
|
||||||
filters?: Filter[];
|
filters?: Filter[];
|
||||||
config?: AllPageListConfig;
|
|
||||||
listItem?: DocMeta[];
|
listItem?: DocMeta[];
|
||||||
setHideHeaderCreateNewPage?: (hide: boolean) => void;
|
setHideHeaderCreateNewPage?: (hide: boolean) => void;
|
||||||
}) => {
|
}) => {
|
||||||
@@ -116,17 +113,16 @@ export const VirtualizedPageList = ({
|
|||||||
if (tag) {
|
if (tag) {
|
||||||
return <TagPageListHeader workspaceId={currentWorkspace.id} tag={tag} />;
|
return <TagPageListHeader workspaceId={currentWorkspace.id} tag={tag} />;
|
||||||
}
|
}
|
||||||
if (collection && config) {
|
if (collection) {
|
||||||
return (
|
return (
|
||||||
<CollectionPageListHeader
|
<CollectionPageListHeader
|
||||||
workspaceId={currentWorkspace.id}
|
workspaceId={currentWorkspace.id}
|
||||||
collection={collection}
|
collection={collection}
|
||||||
config={config}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return <PageListHeader />;
|
return <PageListHeader />;
|
||||||
}, [collection, config, currentWorkspace.id, tag]);
|
}, [collection, currentWorkspace.id, tag]);
|
||||||
|
|
||||||
const { setTrashModal } = useTrashModalHelper(currentWorkspace.docCollection);
|
const { setTrashModal } = useTrashModalHelper(currentWorkspace.docCollection);
|
||||||
|
|
||||||
|
|||||||
@@ -43,7 +43,6 @@ import { DisablePublicSharing, MoveToTrash } from './operation-menu-items';
|
|||||||
import { CreateOrEditTag } from './tags/create-tag';
|
import { CreateOrEditTag } from './tags/create-tag';
|
||||||
import type { TagMeta } from './types';
|
import type { TagMeta } from './types';
|
||||||
import { ColWrapper, stopPropagationWithoutPrevent } from './utils';
|
import { ColWrapper, stopPropagationWithoutPrevent } from './utils';
|
||||||
import type { AllPageListConfig } from './view';
|
|
||||||
import { useEditCollection, useEditCollectionName } from './view';
|
import { useEditCollection, useEditCollectionName } from './view';
|
||||||
|
|
||||||
export interface PageOperationCellProps {
|
export interface PageOperationCellProps {
|
||||||
@@ -282,27 +281,26 @@ export const TrashOperationCell = ({
|
|||||||
export interface CollectionOperationCellProps {
|
export interface CollectionOperationCellProps {
|
||||||
collection: Collection;
|
collection: Collection;
|
||||||
info: DeleteCollectionInfo;
|
info: DeleteCollectionInfo;
|
||||||
config: AllPageListConfig;
|
|
||||||
service: CollectionService;
|
service: CollectionService;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const CollectionOperationCell = ({
|
export const CollectionOperationCell = ({
|
||||||
collection,
|
collection,
|
||||||
config,
|
|
||||||
service,
|
service,
|
||||||
info,
|
info,
|
||||||
}: CollectionOperationCellProps) => {
|
}: CollectionOperationCellProps) => {
|
||||||
const t = useI18n();
|
const t = useI18n();
|
||||||
|
|
||||||
const favAdapter = useService(FavoriteItemsAdapter);
|
const favAdapter = useService(FavoriteItemsAdapter);
|
||||||
const { createPage } = usePageHelper(config.docCollection);
|
const docCollection = useService(WorkspaceService).workspace.docCollection;
|
||||||
|
const { createPage } = usePageHelper(docCollection);
|
||||||
const { openConfirmModal } = useConfirmModal();
|
const { openConfirmModal } = useConfirmModal();
|
||||||
const favourite = useLiveData(
|
const favourite = useLiveData(
|
||||||
favAdapter.isFavorite$(collection.id, 'collection')
|
favAdapter.isFavorite$(collection.id, 'collection')
|
||||||
);
|
);
|
||||||
|
|
||||||
const { open: openEditCollectionModal, node: editModal } =
|
const { open: openEditCollectionModal, node: editModal } =
|
||||||
useEditCollection(config);
|
useEditCollection();
|
||||||
|
|
||||||
const { open: openEditCollectionNameModal, node: editNameModal } =
|
const { open: openEditCollectionNameModal, node: editNameModal } =
|
||||||
useEditCollectionName({
|
useEditCollectionName({
|
||||||
|
|||||||
@@ -1,36 +1,10 @@
|
|||||||
import { Button, FlexWrapper, Menu } from '@affine/component';
|
import { Button, FlexWrapper, Menu } from '@affine/component';
|
||||||
import type { Collection, Filter, PropertiesMeta } from '@affine/env/filter';
|
import type { Filter, PropertiesMeta } from '@affine/env/filter';
|
||||||
import { useI18n } from '@affine/i18n';
|
import { useI18n } from '@affine/i18n';
|
||||||
import { FilterIcon } from '@blocksuite/icons/rc';
|
import { FilterIcon } from '@blocksuite/icons/rc';
|
||||||
|
|
||||||
import { CreateFilterMenu } from '../filter/vars';
|
import { CreateFilterMenu } from '../filter/vars';
|
||||||
import * as styles from './collection-list.css';
|
import * as styles from './collection-list.css';
|
||||||
import { CollectionOperations } from './collection-operations';
|
|
||||||
import type { AllPageListConfig } from './edit-collection/edit-collection';
|
|
||||||
|
|
||||||
export const CollectionPageListOperationsMenu = ({
|
|
||||||
collection,
|
|
||||||
allPageListConfig,
|
|
||||||
}: {
|
|
||||||
collection: Collection;
|
|
||||||
allPageListConfig: AllPageListConfig;
|
|
||||||
}) => {
|
|
||||||
const t = useI18n();
|
|
||||||
return (
|
|
||||||
<FlexWrapper alignItems="center">
|
|
||||||
<CollectionOperations collection={collection} config={allPageListConfig}>
|
|
||||||
<Button
|
|
||||||
className={styles.filterMenuTrigger}
|
|
||||||
type="default"
|
|
||||||
icon={<FilterIcon />}
|
|
||||||
data-testid="create-first-filter"
|
|
||||||
>
|
|
||||||
{t['com.affine.filter']()}
|
|
||||||
</Button>
|
|
||||||
</CollectionOperations>
|
|
||||||
</FlexWrapper>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const AllPageListOperationsMenu = ({
|
export const AllPageListOperationsMenu = ({
|
||||||
propertiesMeta,
|
propertiesMeta,
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ import { useCallback, useMemo } from 'react';
|
|||||||
|
|
||||||
import { CollectionService } from '../../../modules/collection';
|
import { CollectionService } from '../../../modules/collection';
|
||||||
import * as styles from './collection-operations.css';
|
import * as styles from './collection-operations.css';
|
||||||
import type { AllPageListConfig } from './index';
|
|
||||||
import {
|
import {
|
||||||
useEditCollection,
|
useEditCollection,
|
||||||
useEditCollectionName,
|
useEditCollectionName,
|
||||||
@@ -29,13 +28,11 @@ import {
|
|||||||
|
|
||||||
export const CollectionOperations = ({
|
export const CollectionOperations = ({
|
||||||
collection,
|
collection,
|
||||||
config,
|
|
||||||
openRenameModal,
|
openRenameModal,
|
||||||
onAddDocToCollection,
|
onAddDocToCollection,
|
||||||
children,
|
children,
|
||||||
}: PropsWithChildren<{
|
}: PropsWithChildren<{
|
||||||
collection: Collection;
|
collection: Collection;
|
||||||
config: AllPageListConfig;
|
|
||||||
openRenameModal?: () => void;
|
openRenameModal?: () => void;
|
||||||
onAddDocToCollection?: () => void;
|
onAddDocToCollection?: () => void;
|
||||||
}>) => {
|
}>) => {
|
||||||
@@ -44,7 +41,7 @@ export const CollectionOperations = ({
|
|||||||
const service = useService(CollectionService);
|
const service = useService(CollectionService);
|
||||||
const workbench = useService(WorkbenchService).workbench;
|
const workbench = useService(WorkbenchService).workbench;
|
||||||
const { open: openEditCollectionModal, node: editModal } =
|
const { open: openEditCollectionModal, node: editModal } =
|
||||||
useEditCollection(config);
|
useEditCollection();
|
||||||
const t = useI18n();
|
const t = useI18n();
|
||||||
const { open: openEditCollectionNameModal, node: editNameModal } =
|
const { open: openEditCollectionNameModal, node: editNameModal } =
|
||||||
useEditCollectionName({
|
useEditCollectionName({
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import {
|
|||||||
RadioButton,
|
RadioButton,
|
||||||
RadioButtonGroup,
|
RadioButtonGroup,
|
||||||
} from '@affine/component';
|
} from '@affine/component';
|
||||||
|
import { useAllPageListConfig } from '@affine/core/hooks/affine/use-all-page-list-config';
|
||||||
import type { Collection } from '@affine/env/filter';
|
import type { Collection } from '@affine/env/filter';
|
||||||
import { useI18n } from '@affine/i18n';
|
import { useI18n } from '@affine/i18n';
|
||||||
import type { DocCollection, DocMeta } from '@blocksuite/store';
|
import type { DocCollection, DocMeta } from '@blocksuite/store';
|
||||||
@@ -24,7 +25,6 @@ export interface EditCollectionModalProps {
|
|||||||
mode?: EditCollectionMode;
|
mode?: EditCollectionMode;
|
||||||
onOpenChange: (open: boolean) => void;
|
onOpenChange: (open: boolean) => void;
|
||||||
onConfirm: (view: Collection) => void;
|
onConfirm: (view: Collection) => void;
|
||||||
allPageListConfig: AllPageListConfig;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const contentOptions: DialogContentProps = {
|
const contentOptions: DialogContentProps = {
|
||||||
@@ -44,7 +44,6 @@ export const EditCollectionModal = ({
|
|||||||
onOpenChange,
|
onOpenChange,
|
||||||
title,
|
title,
|
||||||
mode,
|
mode,
|
||||||
allPageListConfig,
|
|
||||||
}: EditCollectionModalProps) => {
|
}: EditCollectionModalProps) => {
|
||||||
const t = useI18n();
|
const t = useI18n();
|
||||||
const onConfirmOnCollection = useCallback(
|
const onConfirmOnCollection = useCallback(
|
||||||
@@ -67,7 +66,7 @@ export const EditCollectionModal = ({
|
|||||||
height="80%"
|
height="80%"
|
||||||
contentOptions={contentOptions}
|
contentOptions={contentOptions}
|
||||||
>
|
>
|
||||||
{init ? (
|
{open && init ? (
|
||||||
<EditCollection
|
<EditCollection
|
||||||
title={title}
|
title={title}
|
||||||
onConfirmText={t['com.affine.editCollection.save']()}
|
onConfirmText={t['com.affine.editCollection.save']()}
|
||||||
@@ -75,7 +74,6 @@ export const EditCollectionModal = ({
|
|||||||
mode={mode}
|
mode={mode}
|
||||||
onCancel={onCancel}
|
onCancel={onCancel}
|
||||||
onConfirm={onConfirmOnCollection}
|
onConfirm={onConfirmOnCollection}
|
||||||
allPageListConfig={allPageListConfig}
|
|
||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
</Modal>
|
</Modal>
|
||||||
@@ -89,7 +87,6 @@ export interface EditCollectionProps {
|
|||||||
mode?: EditCollectionMode;
|
mode?: EditCollectionMode;
|
||||||
onCancel: () => void;
|
onCancel: () => void;
|
||||||
onConfirm: (collection: Collection) => void;
|
onConfirm: (collection: Collection) => void;
|
||||||
allPageListConfig: AllPageListConfig;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const EditCollection = ({
|
export const EditCollection = ({
|
||||||
@@ -98,9 +95,9 @@ export const EditCollection = ({
|
|||||||
onCancel,
|
onCancel,
|
||||||
onConfirmText,
|
onConfirmText,
|
||||||
mode: initMode,
|
mode: initMode,
|
||||||
allPageListConfig,
|
|
||||||
}: EditCollectionProps) => {
|
}: EditCollectionProps) => {
|
||||||
const t = useI18n();
|
const t = useI18n();
|
||||||
|
const config = useAllPageListConfig();
|
||||||
const [value, onChange] = useState<Collection>(init);
|
const [value, onChange] = useState<Collection>(init);
|
||||||
const [mode, setMode] = useState<'page' | 'rule'>(
|
const [mode, setMode] = useState<'page' | 'rule'>(
|
||||||
initMode ?? (init.filterList.length === 0 ? 'page' : 'rule')
|
initMode ?? (init.filterList.length === 0 ? 'page' : 'rule')
|
||||||
@@ -182,11 +179,11 @@ export const EditCollection = ({
|
|||||||
updateCollection={onChange}
|
updateCollection={onChange}
|
||||||
switchMode={switchMode}
|
switchMode={switchMode}
|
||||||
buttons={buttons}
|
buttons={buttons}
|
||||||
allPageListConfig={allPageListConfig}
|
allPageListConfig={config}
|
||||||
></PagesMode>
|
></PagesMode>
|
||||||
) : (
|
) : (
|
||||||
<RulesMode
|
<RulesMode
|
||||||
allPageListConfig={allPageListConfig}
|
allPageListConfig={config}
|
||||||
collection={value}
|
collection={value}
|
||||||
switchMode={switchMode}
|
switchMode={switchMode}
|
||||||
reset={reset}
|
reset={reset}
|
||||||
|
|||||||
@@ -2,13 +2,10 @@ import type { Collection } from '@affine/env/filter';
|
|||||||
import { useCallback, useState } from 'react';
|
import { useCallback, useState } from 'react';
|
||||||
|
|
||||||
import { CreateCollectionModal } from './create-collection';
|
import { CreateCollectionModal } from './create-collection';
|
||||||
import type {
|
import type { EditCollectionMode } from './edit-collection/edit-collection';
|
||||||
AllPageListConfig,
|
|
||||||
EditCollectionMode,
|
|
||||||
} from './edit-collection/edit-collection';
|
|
||||||
import { EditCollectionModal } from './edit-collection/edit-collection';
|
import { EditCollectionModal } from './edit-collection/edit-collection';
|
||||||
|
|
||||||
export const useEditCollection = (config: AllPageListConfig) => {
|
export const useEditCollection = () => {
|
||||||
const [data, setData] = useState<{
|
const [data, setData] = useState<{
|
||||||
collection: Collection;
|
collection: Collection;
|
||||||
mode?: 'page' | 'rule';
|
mode?: 'page' | 'rule';
|
||||||
@@ -19,7 +16,6 @@ export const useEditCollection = (config: AllPageListConfig) => {
|
|||||||
return {
|
return {
|
||||||
node: data ? (
|
node: data ? (
|
||||||
<EditCollectionModal
|
<EditCollectionModal
|
||||||
allPageListConfig={config}
|
|
||||||
init={data.collection}
|
init={data.collection}
|
||||||
open={!!data}
|
open={!!data}
|
||||||
mode={data.mode}
|
mode={data.mode}
|
||||||
|
|||||||
@@ -60,25 +60,13 @@ export const CollectionSidebarNavItem = ({
|
|||||||
dndId: DNDIdentifier;
|
dndId: DNDIdentifier;
|
||||||
className?: string;
|
className?: string;
|
||||||
}) => {
|
}) => {
|
||||||
const pages = useBlockSuiteDocMeta(docCollection);
|
|
||||||
const [collapsed, setCollapsed] = useState(true);
|
const [collapsed, setCollapsed] = useState(true);
|
||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
const collectionService = useService(CollectionService);
|
const collectionService = useService(CollectionService);
|
||||||
const favAdapter = useService(FavoriteItemsAdapter);
|
|
||||||
const { createPage } = usePageHelper(docCollection);
|
const { createPage } = usePageHelper(docCollection);
|
||||||
const { openConfirmModal } = useConfirmModal();
|
const { openConfirmModal } = useConfirmModal();
|
||||||
const t = useI18n();
|
const t = useI18n();
|
||||||
|
|
||||||
const favourites = useLiveData(favAdapter.favorites$);
|
|
||||||
|
|
||||||
const removeFromAllowList = useCallback(
|
|
||||||
(id: string) => {
|
|
||||||
collectionService.deletePageFromCollection(collection.id, id);
|
|
||||||
toast(t['com.affine.collection.removePage.success']());
|
|
||||||
},
|
|
||||||
[collection, collectionService, t]
|
|
||||||
);
|
|
||||||
|
|
||||||
const overlayPreview = useMemo(() => {
|
const overlayPreview = useMemo(() => {
|
||||||
return (
|
return (
|
||||||
<DragMenuItemOverlay icon={<ViewLayersIcon />} title={collection.name} />
|
<DragMenuItemOverlay icon={<ViewLayersIcon />} title={collection.name} />
|
||||||
@@ -112,25 +100,6 @@ export const CollectionSidebarNavItem = ({
|
|||||||
|
|
||||||
const isOver = over?.id === dndId && dragOverIntent === 'collection:add';
|
const isOver = over?.id === dndId && dragOverIntent === 'collection:add';
|
||||||
|
|
||||||
const config = useAllPageListConfig();
|
|
||||||
const allPagesMeta = useMemo(
|
|
||||||
() => Object.fromEntries(pages.map(v => [v.id, v])),
|
|
||||||
[pages]
|
|
||||||
);
|
|
||||||
const allowList = useMemo(
|
|
||||||
() => new Set(collection.allowList),
|
|
||||||
[collection.allowList]
|
|
||||||
);
|
|
||||||
|
|
||||||
const pagesToRender = pages.filter(meta => {
|
|
||||||
if (meta.trash) return false;
|
|
||||||
const pageData = {
|
|
||||||
meta,
|
|
||||||
publicMode: config.getPublicMode(meta.id),
|
|
||||||
favorite: favourites.some(fav => fav.id === meta.id),
|
|
||||||
};
|
|
||||||
return filterPage(collection, pageData);
|
|
||||||
});
|
|
||||||
const currentPath = useLiveData(
|
const currentPath = useLiveData(
|
||||||
useService(WorkbenchService).workbench.location$.map(
|
useService(WorkbenchService).workbench.location$.map(
|
||||||
location => location.pathname
|
location => location.pathname
|
||||||
@@ -205,7 +174,6 @@ export const CollectionSidebarNavItem = ({
|
|||||||
</IconButton>
|
</IconButton>
|
||||||
<CollectionOperations
|
<CollectionOperations
|
||||||
collection={collection}
|
collection={collection}
|
||||||
config={config}
|
|
||||||
openRenameModal={handleOpen}
|
openRenameModal={handleOpen}
|
||||||
onAddDocToCollection={onConfirmAddDocToCollection}
|
onAddDocToCollection={onConfirmAddDocToCollection}
|
||||||
>
|
>
|
||||||
@@ -226,30 +194,90 @@ export const CollectionSidebarNavItem = ({
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
collapsed={pagesToRender.length > 0 ? collapsed : undefined}
|
collapsed={collapsed}
|
||||||
>
|
>
|
||||||
<span>{collection.name}</span>
|
<span>{collection.name}</span>
|
||||||
</SidebarMenuLinkItem>
|
</SidebarMenuLinkItem>
|
||||||
<Collapsible.Content className={styles.collapsibleContent}>
|
<Collapsible.Content className={styles.collapsibleContent}>
|
||||||
<div className={styles.docsListContainer}>
|
{!collapsed && (
|
||||||
{pagesToRender.map(page => {
|
<CollectionSidebarNavItemContent
|
||||||
return (
|
collection={collection}
|
||||||
<Doc
|
docCollection={docCollection}
|
||||||
parentId={dndId}
|
dndId={dndId}
|
||||||
inAllowList={allowList.has(page.id)}
|
/>
|
||||||
removeFromAllowList={removeFromAllowList}
|
)}
|
||||||
allPageMeta={allPagesMeta}
|
|
||||||
doc={page}
|
|
||||||
key={page.id}
|
|
||||||
docCollection={docCollection}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
</Collapsible.Content>
|
</Collapsible.Content>
|
||||||
</Collapsible.Root>
|
</Collapsible.Root>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const CollectionSidebarNavItemContent = ({
|
||||||
|
collection,
|
||||||
|
docCollection,
|
||||||
|
dndId,
|
||||||
|
}: {
|
||||||
|
collection: Collection;
|
||||||
|
docCollection: DocCollection;
|
||||||
|
dndId: DNDIdentifier;
|
||||||
|
}) => {
|
||||||
|
const t = useI18n();
|
||||||
|
const pages = useBlockSuiteDocMeta(docCollection);
|
||||||
|
const favAdapter = useService(FavoriteItemsAdapter);
|
||||||
|
const collectionService = useService(CollectionService);
|
||||||
|
|
||||||
|
const config = useAllPageListConfig();
|
||||||
|
const favourites = useLiveData(favAdapter.favorites$);
|
||||||
|
const allowList = useMemo(
|
||||||
|
() => new Set(collection.allowList),
|
||||||
|
[collection.allowList]
|
||||||
|
);
|
||||||
|
const allPagesMeta = useMemo(
|
||||||
|
() => Object.fromEntries(pages.map(v => [v.id, v])),
|
||||||
|
[pages]
|
||||||
|
);
|
||||||
|
const removeFromAllowList = useCallback(
|
||||||
|
(id: string) => {
|
||||||
|
collectionService.deletePageFromCollection(collection.id, id);
|
||||||
|
toast(t['com.affine.collection.removePage.success']());
|
||||||
|
},
|
||||||
|
[collection, collectionService, t]
|
||||||
|
);
|
||||||
|
|
||||||
|
const filtered = pages.filter(meta => {
|
||||||
|
if (meta.trash) return false;
|
||||||
|
const pageData = {
|
||||||
|
meta,
|
||||||
|
publicMode: config.getPublicMode(meta.id),
|
||||||
|
favorite: favourites.some(fav => fav.id === meta.id),
|
||||||
|
};
|
||||||
|
return filterPage(collection, pageData);
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={styles.docsListContainer}>
|
||||||
|
{filtered.length > 0 ? (
|
||||||
|
filtered.map(page => {
|
||||||
|
return (
|
||||||
|
<Doc
|
||||||
|
parentId={dndId}
|
||||||
|
inAllowList={allowList.has(page.id)}
|
||||||
|
removeFromAllowList={removeFromAllowList}
|
||||||
|
allPageMeta={allPagesMeta}
|
||||||
|
doc={page}
|
||||||
|
key={page.id}
|
||||||
|
docCollection={docCollection}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})
|
||||||
|
) : (
|
||||||
|
<div className={styles.emptyCollection}>
|
||||||
|
{t['com.affine.collection.emptyCollection']()}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
export const CollectionsList = ({
|
export const CollectionsList = ({
|
||||||
docCollection: workspace,
|
docCollection: workspace,
|
||||||
onCreate,
|
onCreate,
|
||||||
|
|||||||
@@ -156,3 +156,10 @@ export const docsListContainer = style({
|
|||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
gap: 4,
|
gap: 4,
|
||||||
});
|
});
|
||||||
|
export const emptyCollection = style({
|
||||||
|
fontSize: cssVar('fontSm'),
|
||||||
|
textAlign: 'left',
|
||||||
|
paddingLeft: '32px',
|
||||||
|
color: cssVar('black30'),
|
||||||
|
userSelect: 'none',
|
||||||
|
});
|
||||||
|
|||||||
@@ -12,6 +12,9 @@ import { useCallback, useEffect, useMemo } from 'react';
|
|||||||
|
|
||||||
import { usePageHelper } from '../../components/blocksuite/block-suite-page-list/utils';
|
import { usePageHelper } from '../../components/blocksuite/block-suite-page-list/utils';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated very poor performance
|
||||||
|
*/
|
||||||
export const useAllPageListConfig = () => {
|
export const useAllPageListConfig = () => {
|
||||||
const currentWorkspace = useService(WorkspaceService).workspace;
|
const currentWorkspace = useService(WorkspaceService).workspace;
|
||||||
const shareDocService = useService(ShareDocsService);
|
const shareDocService = useService(ShareDocsService);
|
||||||
|
|||||||
@@ -3,12 +3,10 @@ import {
|
|||||||
PreconditionStrategy,
|
PreconditionStrategy,
|
||||||
registerAffineCommand,
|
registerAffineCommand,
|
||||||
} from '@affine/core/commands';
|
} from '@affine/core/commands';
|
||||||
import { useDocMetaHelper } from '@affine/core/hooks/use-block-suite-page-meta';
|
|
||||||
import { FavoriteItemsAdapter } from '@affine/core/modules/properties';
|
import { FavoriteItemsAdapter } from '@affine/core/modules/properties';
|
||||||
import { mixpanel } from '@affine/core/utils';
|
import { mixpanel } from '@affine/core/utils';
|
||||||
import { WorkspaceFlavour } from '@affine/env/workspace';
|
import { WorkspaceFlavour } from '@affine/env/workspace';
|
||||||
import { useI18n } from '@affine/i18n';
|
import { useI18n } from '@affine/i18n';
|
||||||
import { assertExists } from '@blocksuite/global/utils';
|
|
||||||
import { EdgelessIcon, HistoryIcon, PageIcon } from '@blocksuite/icons/rc';
|
import { EdgelessIcon, HistoryIcon, PageIcon } from '@blocksuite/icons/rc';
|
||||||
import {
|
import {
|
||||||
DocService,
|
DocService,
|
||||||
@@ -31,15 +29,10 @@ export function useRegisterBlocksuiteEditorCommands() {
|
|||||||
const t = useI18n();
|
const t = useI18n();
|
||||||
const workspace = useService(WorkspaceService).workspace;
|
const workspace = useService(WorkspaceService).workspace;
|
||||||
const docCollection = workspace.docCollection;
|
const docCollection = workspace.docCollection;
|
||||||
const { getDocMeta } = useDocMetaHelper(docCollection);
|
|
||||||
const currentPage = docCollection.getDoc(docId);
|
|
||||||
assertExists(currentPage);
|
|
||||||
const pageMeta = getDocMeta(docId);
|
|
||||||
assertExists(pageMeta);
|
|
||||||
|
|
||||||
const favAdapter = useService(FavoriteItemsAdapter);
|
const favAdapter = useService(FavoriteItemsAdapter);
|
||||||
const favorite = useLiveData(favAdapter.isFavorite$(docId, 'doc'));
|
const favorite = useLiveData(favAdapter.isFavorite$(docId, 'doc'));
|
||||||
const trash = pageMeta.trash ?? false;
|
const trash = useLiveData(doc.trash$);
|
||||||
|
|
||||||
const setPageHistoryModalState = useSetAtom(pageHistoryModalAtom);
|
const setPageHistoryModalState = useSetAtom(pageHistoryModalAtom);
|
||||||
|
|
||||||
@@ -52,15 +45,18 @@ export function useRegisterBlocksuiteEditorCommands() {
|
|||||||
|
|
||||||
const { restoreFromTrash, duplicate } =
|
const { restoreFromTrash, duplicate } =
|
||||||
useBlockSuiteMetaHelper(docCollection);
|
useBlockSuiteMetaHelper(docCollection);
|
||||||
const exportHandler = useExportPage(currentPage);
|
const exportHandler = useExportPage(doc.blockSuiteDoc);
|
||||||
const { setTrashModal } = useTrashModalHelper(docCollection);
|
const { setTrashModal } = useTrashModalHelper(docCollection);
|
||||||
const onClickDelete = useCallback(() => {
|
const onClickDelete = useCallback(
|
||||||
setTrashModal({
|
(title: string) => {
|
||||||
open: true,
|
setTrashModal({
|
||||||
pageIds: [docId],
|
open: true,
|
||||||
pageTitles: [pageMeta.title],
|
pageIds: [docId],
|
||||||
});
|
pageTitles: [title],
|
||||||
}, [docId, pageMeta.title, setTrashModal]);
|
});
|
||||||
|
},
|
||||||
|
[docId, setTrashModal]
|
||||||
|
);
|
||||||
|
|
||||||
const isCloudWorkspace = workspace.flavour === WorkspaceFlavour.AFFINE_CLOUD;
|
const isCloudWorkspace = workspace.flavour === WorkspaceFlavour.AFFINE_CLOUD;
|
||||||
|
|
||||||
@@ -213,7 +209,7 @@ export function useRegisterBlocksuiteEditorCommands() {
|
|||||||
icon: mode === 'page' ? <PageIcon /> : <EdgelessIcon />,
|
icon: mode === 'page' ? <PageIcon /> : <EdgelessIcon />,
|
||||||
label: t['com.affine.moveToTrash.title'](),
|
label: t['com.affine.moveToTrash.title'](),
|
||||||
run() {
|
run() {
|
||||||
onClickDelete();
|
onClickDelete(doc.title$.value);
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
@@ -227,7 +223,7 @@ export function useRegisterBlocksuiteEditorCommands() {
|
|||||||
icon: mode === 'page' ? <PageIcon /> : <EdgelessIcon />,
|
icon: mode === 'page' ? <PageIcon /> : <EdgelessIcon />,
|
||||||
label: t['com.affine.cmdk.affine.editor.restore-from-trash'](),
|
label: t['com.affine.cmdk.affine.editor.restore-from-trash'](),
|
||||||
run() {
|
run() {
|
||||||
restoreFromTrash(docId);
|
doc.restoreFromTrash();
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import {
|
|||||||
useEditCollectionName,
|
useEditCollectionName,
|
||||||
VirtualizedCollectionList,
|
VirtualizedCollectionList,
|
||||||
} from '@affine/core/components/page-list';
|
} from '@affine/core/components/page-list';
|
||||||
import { useAllPageListConfig } from '@affine/core/hooks/affine/use-all-page-list-config';
|
|
||||||
import { useNavigateHelper } from '@affine/core/hooks/use-navigate-helper';
|
import { useNavigateHelper } from '@affine/core/hooks/use-navigate-helper';
|
||||||
import { useI18n } from '@affine/i18n';
|
import { useI18n } from '@affine/i18n';
|
||||||
import { useLiveData, useService, WorkspaceService } from '@toeverything/infra';
|
import { useLiveData, useService, WorkspaceService } from '@toeverything/infra';
|
||||||
@@ -25,7 +24,6 @@ export const AllCollection = () => {
|
|||||||
|
|
||||||
const collectionService = useService(CollectionService);
|
const collectionService = useService(CollectionService);
|
||||||
const collections = useLiveData(collectionService.collections$);
|
const collections = useLiveData(collectionService.collections$);
|
||||||
const config = useAllPageListConfig();
|
|
||||||
|
|
||||||
const collectionMetas = useMemo(() => {
|
const collectionMetas = useMemo(() => {
|
||||||
const collectionsList: CollectionMeta[] = collections.map(collection => {
|
const collectionsList: CollectionMeta[] = collections.map(collection => {
|
||||||
@@ -71,7 +69,6 @@ export const AllCollection = () => {
|
|||||||
collectionMetas={collectionMetas}
|
collectionMetas={collectionMetas}
|
||||||
setHideHeaderCreateNewCollection={setHideHeaderCreateNew}
|
setHideHeaderCreateNewCollection={setHideHeaderCreateNew}
|
||||||
node={node}
|
node={node}
|
||||||
config={config}
|
|
||||||
handleCreateCollection={handleCreateCollection}
|
handleCreateCollection={handleCreateCollection}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import {
|
|||||||
useEditCollection,
|
useEditCollection,
|
||||||
VirtualizedPageList,
|
VirtualizedPageList,
|
||||||
} from '@affine/core/components/page-list';
|
} from '@affine/core/components/page-list';
|
||||||
import { useAllPageListConfig } from '@affine/core/hooks/affine/use-all-page-list-config';
|
|
||||||
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
|
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
|
||||||
import { CollectionService } from '@affine/core/modules/collection';
|
import { CollectionService } from '@affine/core/modules/collection';
|
||||||
import type { Collection } from '@affine/env/filter';
|
import type { Collection } from '@affine/env/filter';
|
||||||
@@ -30,8 +29,7 @@ export const CollectionDetail = ({
|
|||||||
}: {
|
}: {
|
||||||
collection: Collection;
|
collection: Collection;
|
||||||
}) => {
|
}) => {
|
||||||
const config = useAllPageListConfig();
|
const { node, open } = useEditCollection();
|
||||||
const { node, open } = useEditCollection(useAllPageListConfig());
|
|
||||||
const collectionService = useService(CollectionService);
|
const collectionService = useService(CollectionService);
|
||||||
const [hideHeaderCreateNew, setHideHeaderCreateNew] = useState(true);
|
const [hideHeaderCreateNew, setHideHeaderCreateNew] = useState(true);
|
||||||
|
|
||||||
@@ -51,7 +49,6 @@ export const CollectionDetail = ({
|
|||||||
<ViewBodyIsland>
|
<ViewBodyIsland>
|
||||||
<VirtualizedPageList
|
<VirtualizedPageList
|
||||||
collection={collection}
|
collection={collection}
|
||||||
config={config}
|
|
||||||
setHideHeaderCreateNewPage={setHideHeaderCreateNew}
|
setHideHeaderCreateNewPage={setHideHeaderCreateNew}
|
||||||
/>
|
/>
|
||||||
</ViewBodyIsland>
|
</ViewBodyIsland>
|
||||||
@@ -104,7 +101,7 @@ export const Component = function CollectionPage() {
|
|||||||
const Placeholder = ({ collection }: { collection: Collection }) => {
|
const Placeholder = ({ collection }: { collection: Collection }) => {
|
||||||
const workspace = useService(WorkspaceService).workspace;
|
const workspace = useService(WorkspaceService).workspace;
|
||||||
const collectionService = useService(CollectionService);
|
const collectionService = useService(CollectionService);
|
||||||
const { node, open } = useEditCollection(useAllPageListConfig());
|
const { node, open } = useEditCollection();
|
||||||
const { jumpToCollections } = useNavigateHelper();
|
const { jumpToCollections } = useNavigateHelper();
|
||||||
const openPageEdit = useAsyncCallback(async () => {
|
const openPageEdit = useAsyncCallback(async () => {
|
||||||
const ret = await open({ ...collection }, 'page');
|
const ret = await open({ ...collection }, 'page');
|
||||||
|
|||||||
Reference in New Issue
Block a user