mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-12 12:28:42 +00:00
fix(core): title could not be changed when creating a new doc (#8203)
Before change, the title could not be modified from outside the editor without refreshing: https://github.com/user-attachments/assets/536acba1-4e31-418a-bc1a-8578e3128bba after: https://github.com/user-attachments/assets/30a4b270-b8b1-4787-acef-0ab2a72a8f74
This commit is contained in:
@@ -9,7 +9,7 @@ import { apis } from '@affine/electron-api';
|
||||
import { WorkspaceFlavour } from '@affine/env/workspace';
|
||||
import { useI18n } from '@affine/i18n';
|
||||
import {
|
||||
initEmptyPage,
|
||||
DocsService,
|
||||
useLiveData,
|
||||
useService,
|
||||
WorkspacesService,
|
||||
@@ -179,6 +179,7 @@ export const CreateWorkspaceModal = ({
|
||||
const [step, setStep] = useState<CreateWorkspaceStep>();
|
||||
const t = useI18n();
|
||||
const workspacesService = useService(WorkspacesService);
|
||||
const docsService = useService(DocsService);
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
// TODO(@Peng): maybe refactor using xstate?
|
||||
@@ -242,9 +243,8 @@ export const CreateWorkspaceModal = ({
|
||||
async workspace => {
|
||||
workspace.meta.initialize();
|
||||
workspace.meta.setName(name);
|
||||
const page = workspace.createDoc();
|
||||
const page = docsService.createDoc();
|
||||
defaultDocId = page.id;
|
||||
initEmptyPage(page);
|
||||
}
|
||||
);
|
||||
onCreate(id, defaultDocId);
|
||||
@@ -252,7 +252,7 @@ export const CreateWorkspaceModal = ({
|
||||
|
||||
setLoading(false);
|
||||
},
|
||||
[loading, onCreate, workspacesService]
|
||||
[docsService, loading, onCreate, workspacesService]
|
||||
);
|
||||
|
||||
const onOpenChange = useCallback(
|
||||
|
||||
@@ -39,7 +39,6 @@ export const EmptyDocs = ({
|
||||
undefined,
|
||||
isNewTabTrigger(e) ? 'new-tab' : true
|
||||
);
|
||||
doc.load();
|
||||
|
||||
if (tag) tag.tag(doc.id);
|
||||
},
|
||||
|
||||
@@ -239,7 +239,7 @@ export const useRestorePage = (
|
||||
const { trigger: recover, isMutating } = useMutation({
|
||||
mutation: recoverDocMutation,
|
||||
});
|
||||
const { getDocMeta, setDocTitle } = useDocMetaHelper(docCollection);
|
||||
const { getDocMeta, setDocTitle } = useDocMetaHelper();
|
||||
|
||||
const onRestore = useMemo(() => {
|
||||
return async (version: string, update: Uint8Array) => {
|
||||
|
||||
@@ -95,7 +95,7 @@ export function AffinePageReference({
|
||||
mode?: DocMode;
|
||||
params?: URLSearchParams;
|
||||
}) {
|
||||
const pageMetaHelper = useDocMetaHelper(docCollection);
|
||||
const pageMetaHelper = useDocMetaHelper();
|
||||
const journalHelper = useJournalHelper(docCollection);
|
||||
const t = useI18n();
|
||||
|
||||
|
||||
@@ -120,7 +120,7 @@ export const AppearanceSettings = () => {
|
||||
) : null}
|
||||
{runtimeConfig.enableThemeEditor ? <ThemeEditorSetting /> : null}
|
||||
</SettingWrapper>
|
||||
{/* //TODO(@JimmFly): remove Page component when stable release */}
|
||||
{/* // TODO(@JimmFly): remove Page component when stable release */}
|
||||
<Page />
|
||||
{runtimeConfig.enableNewSettingUnstableApi ? (
|
||||
<SettingWrapper title={t['com.affine.appearanceSettings.date.title']()}>
|
||||
|
||||
@@ -459,7 +459,7 @@ export const General = () => {
|
||||
<FontFamilySettings />
|
||||
<CustomFontFamilySettings />
|
||||
<NewDocDefaultModeSettings />
|
||||
{/* //TODO(@akumatus): implement these settings
|
||||
{/* // TODO(@akumatus): implement these settings
|
||||
<DeFaultCodeBlockSettings />
|
||||
<SpellCheckSettings /> */}
|
||||
</SettingWrapper>
|
||||
|
||||
@@ -81,12 +81,12 @@ export const PageHeaderMenuButton = ({
|
||||
|
||||
const { favorite, toggleFavorite } = useFavorite(pageId);
|
||||
|
||||
const { duplicate } = useBlockSuiteMetaHelper(docCollection);
|
||||
const { duplicate } = useBlockSuiteMetaHelper();
|
||||
const { importFile } = usePageHelper(docCollection);
|
||||
const { setTrashModal } = useTrashModalHelper(docCollection);
|
||||
const { setTrashModal } = useTrashModalHelper();
|
||||
|
||||
const [isEditing, setEditing] = useState(!page.readonly);
|
||||
const { setDocReadonly } = useDocMetaHelper(docCollection);
|
||||
const { setDocReadonly } = useDocMetaHelper();
|
||||
|
||||
const view = useService(ViewService).view;
|
||||
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import { toast } from '@affine/component';
|
||||
import { useDocCollectionHelper } from '@affine/core/hooks/use-block-suite-workspace-helper';
|
||||
import { WorkbenchService } from '@affine/core/modules/workbench';
|
||||
import type { DocMode } from '@blocksuite/blocks';
|
||||
import { DocsService, initEmptyPage, useServices } from '@toeverything/infra';
|
||||
import { DocsService, useServices } from '@toeverything/infra';
|
||||
import { useCallback, useMemo } from 'react';
|
||||
|
||||
import type { DocCollection } from '../../../shared';
|
||||
@@ -13,13 +12,11 @@ export const usePageHelper = (docCollection: DocCollection) => {
|
||||
WorkbenchService,
|
||||
});
|
||||
const workbench = workbenchService.workbench;
|
||||
const { createDoc } = useDocCollectionHelper(docCollection);
|
||||
const docRecordList = docsService.list;
|
||||
|
||||
const createPageAndOpen = useCallback(
|
||||
(mode?: DocMode, open?: boolean | 'new-tab') => {
|
||||
const page = createDoc();
|
||||
initEmptyPage(page);
|
||||
const page = docsService.createDoc();
|
||||
if (mode) {
|
||||
docRecordList.doc$(page.id).value?.setPrimaryMode(mode);
|
||||
}
|
||||
@@ -30,7 +27,7 @@ export const usePageHelper = (docCollection: DocCollection) => {
|
||||
});
|
||||
return page;
|
||||
},
|
||||
[createDoc, docRecordList, workbench]
|
||||
[docRecordList, docsService, workbench]
|
||||
);
|
||||
|
||||
const createEdgelessAndOpen = useCallback(
|
||||
|
||||
@@ -19,7 +19,7 @@ import {
|
||||
SearchIcon,
|
||||
ViewLayersIcon,
|
||||
} from '@blocksuite/icons/rc';
|
||||
import type { Doc as BlockSuiteDoc } from '@blocksuite/store';
|
||||
import type { DocRecord } from '@toeverything/infra';
|
||||
import {
|
||||
useLiveData,
|
||||
useService,
|
||||
@@ -122,7 +122,7 @@ export const CollectionPageListHeader = ({
|
||||
const { openConfirmModal } = useConfirmModal();
|
||||
|
||||
const createAndAddDocument = useCallback(
|
||||
(createDocumentFn: () => BlockSuiteDoc) => {
|
||||
(createDocumentFn: () => DocRecord) => {
|
||||
const newDoc = createDocumentFn();
|
||||
collectionService.addPageToCollection(collection.id, newDoc.id);
|
||||
},
|
||||
@@ -130,7 +130,7 @@ export const CollectionPageListHeader = ({
|
||||
);
|
||||
|
||||
const onConfirmAddDocument = useCallback(
|
||||
(createDocumentFn: () => BlockSuiteDoc) => {
|
||||
(createDocumentFn: () => DocRecord) => {
|
||||
openConfirmModal({
|
||||
title: t['com.affine.collection.add-doc.confirm.title'](),
|
||||
description: t['com.affine.collection.add-doc.confirm.description'](),
|
||||
|
||||
@@ -122,7 +122,7 @@ export const VirtualizedPageList = ({
|
||||
return <PageListHeader />;
|
||||
}, [collection, currentWorkspace.id, tag]);
|
||||
|
||||
const { setTrashModal } = useTrashModalHelper(currentWorkspace.docCollection);
|
||||
const { setTrashModal } = useTrashModalHelper();
|
||||
|
||||
const handleMultiDelete = useCallback(() => {
|
||||
if (filteredSelectedPageIds.length === 0) {
|
||||
|
||||
@@ -80,10 +80,10 @@ export const PageOperationCell = ({
|
||||
featureFlagService.flags.enable_multi_view.$
|
||||
);
|
||||
const currentWorkspace = workspaceService.workspace;
|
||||
const { setTrashModal } = useTrashModalHelper(currentWorkspace.docCollection);
|
||||
const { setTrashModal } = useTrashModalHelper();
|
||||
const favourite = useLiveData(favAdapter.isFavorite$(page.id, 'doc'));
|
||||
const workbench = workbenchService.workbench;
|
||||
const { duplicate } = useBlockSuiteMetaHelper(currentWorkspace.docCollection);
|
||||
const { duplicate } = useBlockSuiteMetaHelper();
|
||||
const blocksuiteDoc = currentWorkspace.docCollection.getDoc(page.id);
|
||||
|
||||
const [openInfoModal, setOpenInfoModal] = useState(false);
|
||||
@@ -93,7 +93,7 @@ export const PageOperationCell = ({
|
||||
}, []);
|
||||
|
||||
const onDisablePublicSharing = useCallback(() => {
|
||||
//TODO(@EYHN): implement disable public sharing
|
||||
// TODO(@EYHN): implement disable public sharing
|
||||
toast('Successfully disabled', {
|
||||
portal: document.body,
|
||||
});
|
||||
|
||||
@@ -23,7 +23,7 @@ const TagListTitleCell = ({
|
||||
>
|
||||
{title || t['Untitled']()}
|
||||
</div>
|
||||
{/* //TODO(@EYHN): when indexer is ready, add this back
|
||||
{/* // TODO(@EYHN): when indexer is ready, add this back
|
||||
<div
|
||||
data-testid="page-list-item-preview-text"
|
||||
className={styles.titleCellPreview}
|
||||
|
||||
@@ -18,8 +18,7 @@ import { VirtualizedList } from './virtualized-list';
|
||||
export const VirtualizedTrashList = () => {
|
||||
const currentWorkspace = useService(WorkspaceService).workspace;
|
||||
const docCollection = currentWorkspace.docCollection;
|
||||
const { restoreFromTrash, permanentlyDeletePage } =
|
||||
useBlockSuiteMetaHelper(docCollection);
|
||||
const { restoreFromTrash, permanentlyDeletePage } = useBlockSuiteMetaHelper();
|
||||
const pageMetas = useBlockSuiteDocMeta(docCollection);
|
||||
const filteredPageMetas = useFilteredPageMetas(pageMetas, {
|
||||
trash: true,
|
||||
|
||||
@@ -19,7 +19,7 @@ export const TrashPageFooter = () => {
|
||||
const t = useI18n();
|
||||
const { appSettings } = useAppSettingHelper();
|
||||
const { jumpToSubPath } = useNavigateHelper();
|
||||
const { restoreFromTrash } = useBlockSuiteMetaHelper(docCollection);
|
||||
const { restoreFromTrash } = useBlockSuiteMetaHelper();
|
||||
const [open, setOpen] = useState(false);
|
||||
const hintText = t['com.affine.cmdk.affine.editor.trash-footer-hint']();
|
||||
|
||||
|
||||
@@ -99,11 +99,7 @@ export const RootAppSidebar = (): ReactElement => {
|
||||
|
||||
const onClickNewPage = useAsyncCallback(
|
||||
async (e?: MouseEvent) => {
|
||||
const page = pageHelper.createPage(
|
||||
undefined,
|
||||
isNewTabTrigger(e) ? 'new-tab' : true
|
||||
);
|
||||
page.load();
|
||||
pageHelper.createPage(undefined, isNewTabTrigger(e) ? 'new-tab' : true);
|
||||
track.$.navigationPanel.$.createDoc();
|
||||
},
|
||||
[pageHelper]
|
||||
|
||||
@@ -1,86 +1,59 @@
|
||||
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
|
||||
import { useDocMetaHelper } from '@affine/core/hooks/use-block-suite-page-meta';
|
||||
import { useDocCollectionHelper } from '@affine/core/hooks/use-block-suite-workspace-helper';
|
||||
import { CollectionService } from '@affine/core/modules/collection';
|
||||
import type { DocMode } from '@blocksuite/blocks';
|
||||
import { DocsService, useService } from '@toeverything/infra';
|
||||
import { DocsService, useService, WorkspaceService } from '@toeverything/infra';
|
||||
import { useCallback } from 'react';
|
||||
import { applyUpdate, encodeStateAsUpdate } from 'yjs';
|
||||
|
||||
import type { DocCollection } from '../../shared';
|
||||
import { useNavigateHelper } from '../use-navigate-helper';
|
||||
|
||||
export function useBlockSuiteMetaHelper(docCollection: DocCollection) {
|
||||
const { setDocMeta, getDocMeta, setDocReadonly, setDocTitle } =
|
||||
useDocMetaHelper(docCollection);
|
||||
const { createDoc } = useDocCollectionHelper(docCollection);
|
||||
export function useBlockSuiteMetaHelper() {
|
||||
const workspace = useService(WorkspaceService).workspace;
|
||||
const { setDocMeta, getDocMeta, setDocTitle, setDocReadonly } =
|
||||
useDocMetaHelper();
|
||||
const { createDoc } = useDocCollectionHelper(workspace.docCollection);
|
||||
const { openPage } = useNavigateHelper();
|
||||
const collectionService = useService(CollectionService);
|
||||
const pageRecordList = useService(DocsService).list;
|
||||
const docRecordList = useService(DocsService).list;
|
||||
|
||||
// TODO-Doma
|
||||
// "Remove" may cause ambiguity here. Consider renaming as "moveToTrash".
|
||||
const removeToTrash = useCallback(
|
||||
(pageId: string) => {
|
||||
setDocMeta(pageId, {
|
||||
trash: true,
|
||||
trashDate: Date.now(),
|
||||
});
|
||||
setDocReadonly(pageId, true);
|
||||
collectionService.deletePagesFromCollections([pageId]);
|
||||
(docId: string) => {
|
||||
const docRecord = docRecordList.doc$(docId).value;
|
||||
if (docRecord) {
|
||||
docRecord.moveToTrash();
|
||||
setDocReadonly(docId, true);
|
||||
}
|
||||
},
|
||||
[collectionService, setDocMeta, setDocReadonly]
|
||||
[docRecordList, setDocReadonly]
|
||||
);
|
||||
|
||||
const restoreFromTrash = useCallback(
|
||||
(pageId: string) => {
|
||||
setDocMeta(pageId, {
|
||||
trash: false,
|
||||
trashDate: undefined,
|
||||
});
|
||||
setDocReadonly(pageId, false);
|
||||
(docId: string) => {
|
||||
const docRecord = docRecordList.doc$(docId).value;
|
||||
if (docRecord) {
|
||||
docRecord.restoreFromTrash();
|
||||
setDocReadonly(docId, false);
|
||||
}
|
||||
},
|
||||
[setDocMeta, setDocReadonly]
|
||||
[docRecordList, setDocReadonly]
|
||||
);
|
||||
|
||||
const permanentlyDeletePage = useCallback(
|
||||
(pageId: string) => {
|
||||
docCollection.removeDoc(pageId);
|
||||
workspace.docCollection.removeDoc(pageId);
|
||||
},
|
||||
[docCollection]
|
||||
);
|
||||
|
||||
/**
|
||||
* see {@link useBlockSuiteWorkspacePageIsPublic}
|
||||
*/
|
||||
const publicPage = useCallback(
|
||||
(pageId: string) => {
|
||||
setDocMeta(pageId, {
|
||||
isPublic: true,
|
||||
});
|
||||
},
|
||||
[setDocMeta]
|
||||
);
|
||||
|
||||
/**
|
||||
* see {@link useBlockSuiteWorkspacePageIsPublic}
|
||||
*/
|
||||
const cancelPublicPage = useCallback(
|
||||
(pageId: string) => {
|
||||
setDocMeta(pageId, {
|
||||
isPublic: false,
|
||||
});
|
||||
},
|
||||
[setDocMeta]
|
||||
[workspace]
|
||||
);
|
||||
|
||||
const duplicate = useAsyncCallback(
|
||||
async (pageId: string, openPageAfterDuplication: boolean = true) => {
|
||||
const currentPagePrimaryMode =
|
||||
pageRecordList.doc$(pageId).value?.primaryMode$.value;
|
||||
docRecordList.doc$(pageId).value?.primaryMode$.value;
|
||||
const currentPageMeta = getDocMeta(pageId);
|
||||
const newPage = createDoc();
|
||||
const currentPage = docCollection.getDoc(pageId);
|
||||
const currentPage = workspace.docCollection.getDoc(pageId);
|
||||
|
||||
newPage.load();
|
||||
if (!currentPageMeta || !currentPage) {
|
||||
@@ -95,33 +68,31 @@ export function useBlockSuiteMetaHelper(docCollection: DocCollection) {
|
||||
});
|
||||
|
||||
const lastDigitRegex = /\((\d+)\)$/;
|
||||
const match = currentPageMeta.title.match(lastDigitRegex);
|
||||
const match = currentPageMeta?.title?.match(lastDigitRegex);
|
||||
const newNumber = match ? parseInt(match[1], 10) + 1 : 1;
|
||||
|
||||
const newPageTitle =
|
||||
currentPageMeta.title.replace(lastDigitRegex, '') + `(${newNumber})`;
|
||||
currentPageMeta?.title?.replace(lastDigitRegex, '') + `(${newNumber})`;
|
||||
|
||||
pageRecordList
|
||||
docRecordList
|
||||
.doc$(newPage.id)
|
||||
.value?.setPrimaryMode(currentPagePrimaryMode || ('page' as DocMode));
|
||||
setDocTitle(newPage.id, newPageTitle);
|
||||
openPageAfterDuplication && openPage(docCollection.id, newPage.id);
|
||||
openPageAfterDuplication &&
|
||||
openPage(workspace.docCollection.id, newPage.id);
|
||||
},
|
||||
[
|
||||
docCollection,
|
||||
createDoc,
|
||||
docRecordList,
|
||||
getDocMeta,
|
||||
openPage,
|
||||
pageRecordList,
|
||||
createDoc,
|
||||
workspace.docCollection,
|
||||
setDocMeta,
|
||||
setDocTitle,
|
||||
openPage,
|
||||
]
|
||||
);
|
||||
|
||||
return {
|
||||
publicPage,
|
||||
cancelPublicPage,
|
||||
|
||||
removeToTrash,
|
||||
restoreFromTrash,
|
||||
permanentlyDeletePage,
|
||||
|
||||
@@ -30,7 +30,6 @@ export function useRegisterBlocksuiteEditorCommands(editor: Editor) {
|
||||
const mode = useLiveData(editor.mode$);
|
||||
const t = useI18n();
|
||||
const workspace = useService(WorkspaceService).workspace;
|
||||
const docCollection = workspace.docCollection;
|
||||
|
||||
const favAdapter = useService(CompatibleFavoriteItemsAdapter);
|
||||
const favorite = useLiveData(favAdapter.isFavorite$(docId, 'doc'));
|
||||
@@ -50,9 +49,9 @@ export function useRegisterBlocksuiteEditorCommands(editor: Editor) {
|
||||
setInfoModalState(true);
|
||||
}, [setInfoModalState]);
|
||||
|
||||
const { duplicate } = useBlockSuiteMetaHelper(docCollection);
|
||||
const { duplicate } = useBlockSuiteMetaHelper();
|
||||
const exportHandler = useExportPage();
|
||||
const { setTrashModal } = useTrashModalHelper(docCollection);
|
||||
const { setTrashModal } = useTrashModalHelper();
|
||||
const onClickDelete = useCallback(
|
||||
(title: string) => {
|
||||
setTrashModal({
|
||||
|
||||
@@ -1,18 +1,16 @@
|
||||
import { toast } from '@affine/component';
|
||||
import { useI18n } from '@affine/i18n';
|
||||
import type { DocCollection } from '@blocksuite/store';
|
||||
import { useAtom } from 'jotai';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
import { trashModalAtom } from '../../atoms/trash-modal';
|
||||
import { useBlockSuiteMetaHelper } from './use-block-suite-meta-helper';
|
||||
|
||||
export function useTrashModalHelper(docCollection: DocCollection) {
|
||||
export function useTrashModalHelper() {
|
||||
const t = useI18n();
|
||||
const [trashModal, setTrashModal] = useAtom(trashModalAtom);
|
||||
const { pageIds } = trashModal;
|
||||
const { removeToTrash } = useBlockSuiteMetaHelper(docCollection);
|
||||
|
||||
const { removeToTrash } = useBlockSuiteMetaHelper();
|
||||
const handleOnConfirm = useCallback(() => {
|
||||
pageIds.forEach(pageId => {
|
||||
removeToTrash(pageId);
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import type { RootBlockModel } from '@blocksuite/blocks';
|
||||
import { assertExists } from '@blocksuite/global/utils';
|
||||
import type { DocCollection, DocMeta } from '@blocksuite/store';
|
||||
import { useMemo } from 'react';
|
||||
import { DocsService, useService, WorkspaceService } from '@toeverything/infra';
|
||||
import { useCallback, useMemo } from 'react';
|
||||
|
||||
import { useAsyncCallback } from './affine-async-hooks';
|
||||
import { useAllBlockSuiteDocMeta } from './use-all-block-suite-page-meta';
|
||||
import { useJournalHelper } from './use-journal';
|
||||
|
||||
@@ -23,34 +23,54 @@ export function useBlockSuiteDocMeta(docCollection: DocCollection) {
|
||||
);
|
||||
}
|
||||
|
||||
export function useDocMetaHelper(docCollection: DocCollection) {
|
||||
export function useDocMetaHelper() {
|
||||
const workspaceService = useService(WorkspaceService);
|
||||
const docsService = useService(DocsService);
|
||||
|
||||
const setDocTitle = useAsyncCallback(
|
||||
async (docId: string, newTitle: string) => {
|
||||
await docsService.changeDocTitle(docId, newTitle);
|
||||
},
|
||||
[docsService]
|
||||
);
|
||||
|
||||
const setDocMeta = useCallback(
|
||||
(docId: string, docMeta: Partial<DocMeta>) => {
|
||||
const doc = docsService.list.doc$(docId).value;
|
||||
if (doc) {
|
||||
doc.setMeta(docMeta);
|
||||
}
|
||||
},
|
||||
[docsService]
|
||||
);
|
||||
|
||||
const getDocMeta = useCallback(
|
||||
(docId: string) => {
|
||||
const doc = docsService.list.doc$(docId).value;
|
||||
return doc?.meta$.value;
|
||||
},
|
||||
[docsService]
|
||||
);
|
||||
const setDocReadonly = useCallback(
|
||||
(docId: string, readonly: boolean) => {
|
||||
const doc = workspaceService.workspace.docCollection.getDoc(docId);
|
||||
if (doc?.blockCollection) {
|
||||
workspaceService.workspace.docCollection.awarenessStore.setReadonly(
|
||||
doc.blockCollection,
|
||||
readonly
|
||||
);
|
||||
}
|
||||
},
|
||||
[workspaceService]
|
||||
);
|
||||
|
||||
return useMemo(
|
||||
() => ({
|
||||
setDocTitle: (docId: string, newTitle: string) => {
|
||||
const page = docCollection.getDoc(docId);
|
||||
assertExists(page);
|
||||
const pageBlock = page
|
||||
.getBlockByFlavour('affine:page')
|
||||
.at(0) as RootBlockModel;
|
||||
assertExists(pageBlock);
|
||||
page.transact(() => {
|
||||
pageBlock.title.delete(0, pageBlock.title.length);
|
||||
pageBlock.title.insert(newTitle, 0);
|
||||
});
|
||||
docCollection.meta.setDocMeta(docId, { title: newTitle });
|
||||
},
|
||||
setDocReadonly: (docId: string, readonly: boolean) => {
|
||||
const page = docCollection.getDoc(docId);
|
||||
assertExists(page);
|
||||
page.awarenessStore.setReadonly(page.blockCollection, readonly);
|
||||
},
|
||||
setDocMeta: (docId: string, docMeta: Partial<DocMeta>) => {
|
||||
docCollection.meta.setDocMeta(docId, docMeta);
|
||||
},
|
||||
getDocMeta: (docId: string) => {
|
||||
return docCollection.meta.getDocMeta(docId);
|
||||
},
|
||||
setDocTitle,
|
||||
setDocMeta,
|
||||
getDocMeta,
|
||||
setDocReadonly,
|
||||
}),
|
||||
[docCollection]
|
||||
[getDocMeta, setDocMeta, setDocReadonly, setDocTitle]
|
||||
);
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
} from '@affine/component';
|
||||
import { usePageHelper } from '@affine/core/components/blocksuite/block-suite-page-list/utils';
|
||||
import { IsFavoriteIcon } from '@affine/core/components/pure/icons';
|
||||
import { useBlockSuiteMetaHelper } from '@affine/core/hooks/affine/use-block-suite-meta-helper';
|
||||
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
|
||||
import { track } from '@affine/core/mixpanel';
|
||||
import { CompatibleFavoriteItemsAdapter } from '@affine/core/modules/properties';
|
||||
@@ -14,6 +15,7 @@ import { WorkbenchService } from '@affine/core/modules/workbench';
|
||||
import { useI18n } from '@affine/i18n';
|
||||
import {
|
||||
DeleteIcon,
|
||||
DuplicateIcon,
|
||||
InformationIcon,
|
||||
LinkedPageIcon,
|
||||
OpenInNewIcon,
|
||||
@@ -69,6 +71,11 @@ export const useExplorerDocNodeOperations = (
|
||||
}, [docId, compatibleFavoriteItemsAdapter])
|
||||
);
|
||||
|
||||
const { duplicate } = useBlockSuiteMetaHelper();
|
||||
const handleDuplicate = useCallback(() => {
|
||||
duplicate(docId, true);
|
||||
track.$.navigationPanel.docs.createDoc();
|
||||
}, [docId, duplicate]);
|
||||
const handleOpenInfoModal = useCallback(() => {
|
||||
track.$.docInfoPanel.$.open();
|
||||
options.openInfoModal();
|
||||
@@ -173,6 +180,14 @@ export const useExplorerDocNodeOperations = (
|
||||
</MenuItem>
|
||||
),
|
||||
},
|
||||
{
|
||||
index: 99,
|
||||
view: (
|
||||
<MenuItem prefixIcon={<DuplicateIcon />} onClick={handleDuplicate}>
|
||||
{t['com.affine.header.option.duplicate']()}
|
||||
</MenuItem>
|
||||
),
|
||||
},
|
||||
{
|
||||
index: 99,
|
||||
view: (
|
||||
@@ -230,6 +245,7 @@ export const useExplorerDocNodeOperations = (
|
||||
enableMultiView,
|
||||
favorite,
|
||||
handleAddLinkedPage,
|
||||
handleDuplicate,
|
||||
handleMoveToTrash,
|
||||
handleOpenInNewTab,
|
||||
handleOpenInSplitView,
|
||||
|
||||
@@ -89,7 +89,7 @@ const DetailPageImpl = memo(function DetailPageImpl() {
|
||||
const isSideBarOpen = useLiveData(workbench.sidebarOpen$);
|
||||
const { appSettings } = useAppSettingHelper();
|
||||
const chatPanelRef = useRef<ChatPanel | null>(null);
|
||||
const { setDocReadonly } = useDocMetaHelper(workspace.docCollection);
|
||||
const { setDocReadonly } = useDocMetaHelper();
|
||||
|
||||
const isActiveView = useIsActiveView();
|
||||
// TODO(@eyhn): remove jotai here
|
||||
|
||||
@@ -301,9 +301,8 @@ const ConflictList = ({
|
||||
className,
|
||||
...attrs
|
||||
}: ConflictListProps) => {
|
||||
const workspace = useService(WorkspaceService).workspace;
|
||||
const currentDoc = useService(DocService).doc;
|
||||
const { setTrashModal } = useTrashModalHelper(workspace.docCollection);
|
||||
const { setTrashModal } = useTrashModalHelper();
|
||||
|
||||
const handleOpenTrashModal = useCallback(
|
||||
(docRecord: DocRecord) => {
|
||||
|
||||
@@ -91,9 +91,7 @@ export const Setting = () => {
|
||||
export function CurrentWorkspaceModals() {
|
||||
const currentWorkspace = useService(WorkspaceService).workspace;
|
||||
|
||||
const { trashModal, setTrashModal, handleOnConfirm } = useTrashModalHelper(
|
||||
currentWorkspace.docCollection
|
||||
);
|
||||
const { trashModal, setTrashModal, handleOnConfirm } = useTrashModalHelper();
|
||||
const deletePageTitles = trashModal.pageTitles;
|
||||
const trashConfirmOpen = trashModal.open;
|
||||
const onTrashConfirmOpenChange = useCallback(
|
||||
|
||||
Reference in New Issue
Block a user