refactor(core): implement doc created/updated by service (#12150)

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

- **New Features**
  - Documents now automatically track and display "created by" and "updated by" user information.
  - Document creation and update timestamps are now managed and shown more accurately.
  - Workspace and document metadata (name, avatar) updates are more responsive and reliable.
  - Document creation supports middleware for customizing properties and behavior.

- **Improvements**
  - Simplified and unified event handling for document list updates, reducing redundant event subscriptions.
  - Enhanced integration of editor and theme settings into the document creation process.
  - Explicit Yjs document initialization for improved workspace stability and reliability.
  - Consolidated journal-related metadata display in document icons and titles for clarity.

- **Bug Fixes**
  - Fixed inconsistencies in how workspace and document names are set and updated.
  - Improved accuracy of "last updated" indicators by handling timestamps automatically.

- **Refactor**
  - Removed deprecated event subjects and direct metadata manipulation in favor of more robust, reactive patterns.
  - Streamlined document creation logic across various features (quick search, journal, recording, etc.).
  - Simplified user avatar display components and removed cloud metadata dependencies.
  - Removed legacy editor setting and theme service dependencies from multiple modules.

- **Chores**
  - Updated internal APIs and interfaces to support new metadata and event handling mechanisms.
  - Cleaned up unused code and dependencies related to editor settings and theme services.
  - Skipped flaky end-to-end test to improve test suite stability.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
EYHN
2025-05-08 07:53:33 +00:00
parent 93d74ff220
commit 2d1600fa00
56 changed files with 496 additions and 458 deletions
@@ -6,6 +6,7 @@ import type { Store } from '@blocksuite/affine/store';
import { css, html, LitElement, nothing } from 'lit';
import { property, query } from 'lit/decorators.js';
import { createRef, type Ref, ref } from 'lit/directives/ref.js';
import { Doc as YDoc } from 'yjs';
import { PPTBuilder } from '../slides/index';
import { getAIPanelWidget } from '../utils/ai-widgets';
@@ -223,6 +224,7 @@ export class AISlidesRenderer extends WithDisposable(LitElement) {
const collection = new WorkspaceImpl({
id: 'SLIDES_PREVIEW',
rootDoc: new YDoc({ guid: 'SLIDES_PREVIEW' }),
});
collection.meta.initialize();
const doc = collection.createDoc().getStore();
@@ -20,6 +20,7 @@ import { property, query } from 'lit/decorators.js';
import { repeat } from 'lit/directives/repeat.js';
import { styleMap } from 'lit/directives/style-map.js';
import type { Root } from 'mdast';
import { Doc as YDoc } from 'yjs';
import { MiniMindmapSchema, MiniMindmapSpecs } from './spec.js';
@@ -101,6 +102,7 @@ export class MiniMindmapPreview extends WithDisposable(LitElement) {
const collection = new WorkspaceImpl({
id: 'MINI_MINDMAP_TEMPORARY',
rootDoc: new YDoc({ guid: 'MINI_MINDMAP_TEMPORARY' }),
});
collection.meta.initialize();
const doc = collection.createDoc('doc:home').getStore();
@@ -174,18 +174,6 @@ const BlockSuiteEditorImpl = ({
std.command.exec(appendParagraphCommand);
}, [affineEditorContainerProxy.host?.std, page, readonly, shared]);
useEffect(() => {
const disposable = page.slots.blockUpdated.subscribe(() => {
disposable.unsubscribe();
page.workspace.meta.setDocMeta(page.id, {
updatedDate: Date.now(),
});
});
return () => {
disposable.unsubscribe();
};
}, [page]);
useEffect(() => {
const editorContainer = rootRef.current;
if (editorContainer) {
@@ -1,15 +1,9 @@
import { toast } from '@affine/component';
import type { DocProps } from '@affine/core/blocksuite/initialization';
import { AppSidebarService } from '@affine/core/modules/app-sidebar';
import { DocsService } from '@affine/core/modules/doc';
import { EditorSettingService } from '@affine/core/modules/editor-setting';
import { WorkbenchService } from '@affine/core/modules/workbench';
import { getAFFiNEWorkspaceSchema } from '@affine/core/modules/workspace';
import {
DEFAULT_PAGE_BLOCK_HEIGHT,
DEFAULT_PAGE_BLOCK_WIDTH,
type DocMode,
} from '@blocksuite/affine/model';
import { type DocMode } from '@blocksuite/affine/model';
import type { Workspace } from '@blocksuite/affine/store';
import { useServices } from '@toeverything/infra';
import { useCallback, useMemo } from 'react';
@@ -17,15 +11,9 @@ import { useCallback, useMemo } from 'react';
import { getStoreManager } from '../manager/migrating-store';
export const usePageHelper = (docCollection: Workspace) => {
const {
docsService,
workbenchService,
editorSettingService,
appSidebarService,
} = useServices({
const { docsService, workbenchService, appSidebarService } = useServices({
DocsService,
WorkbenchService,
EditorSettingService,
AppSidebarService,
});
const workbench = workbenchService.workbench;
@@ -44,13 +32,7 @@ export const usePageHelper = (docCollection: Workspace) => {
}
) => {
appSidebar.setHovering(false);
const docProps: DocProps = {
note: {
...editorSettingService.editorSetting.get('affine:note'),
xywh: `[0, 0, ${DEFAULT_PAGE_BLOCK_WIDTH}, ${DEFAULT_PAGE_BLOCK_HEIGHT}]`,
},
};
const page = docsService.createDoc({ docProps });
const page = docsService.createDoc();
if (mode) {
docRecordList.doc$(page.id).value?.setPrimaryMode(mode);
@@ -64,13 +46,7 @@ export const usePageHelper = (docCollection: Workspace) => {
}
return page;
},
[
appSidebar,
docRecordList,
docsService,
editorSettingService.editorSetting,
workbench,
]
[appSidebar, docRecordList, docsService, workbench]
);
const createEdgelessAndOpen = useCallback(
@@ -1,5 +1,4 @@
import { DocsService } from '@affine/core/modules/doc';
import { EditorSettingService } from '@affine/core/modules/editor-setting';
import {
CreationQuickSearchSession,
DocsQuickSearchSession,
@@ -20,7 +19,7 @@ import {
QuickSearchExtension,
type QuickSearchResult,
} from '@blocksuite/affine/shared/services';
import { type ExtensionType, Text } from '@blocksuite/affine/store';
import { type ExtensionType } from '@blocksuite/affine/store';
import type {
SlashMenuConfig,
SlashMenuItem,
@@ -28,8 +27,6 @@ import type {
import type { FrameworkProvider } from '@toeverything/infra';
import { pick } from 'lodash-es';
import type { DocProps } from '../initialization';
export function patchQuickSearchService(framework: FrameworkProvider) {
const QuickSearch = QuickSearchExtension({
async openQuickSearch() {
@@ -96,16 +93,11 @@ export function patchQuickSearchService(framework: FrameworkProvider) {
if (result.source === 'creation') {
const docsService = framework.get(DocsService);
const editorSettingService = framework.get(EditorSettingService);
const mode =
result.id === 'creation:create-edgeless' ? 'edgeless' : 'page';
const docProps: DocProps = {
page: { title: new Text(result.payload.title) },
note: editorSettingService.editorSetting.get('affine:note'),
};
const newDoc = docsService.createDoc({
primaryMode: mode,
docProps,
title: result.payload.title,
});
resolve({ docId: newDoc.id });
@@ -1,3 +1,4 @@
import type { DocCreateOptions } from '@affine/core/modules/doc/types';
import {
NoteDisplayMode,
type NoteProps,
@@ -22,11 +23,15 @@ export interface DocProps {
) => void;
}
export function initDocFromProps(doc: Store, props?: DocProps) {
export function initDocFromProps(
doc: Store,
props?: DocProps,
options: DocCreateOptions = {}
) {
doc.load(() => {
const pageBlockId = doc.addBlock(
'affine:page',
props?.page || { title: new Text('') }
props?.page || { title: new Text(options.title || '') }
);
const surfaceId = doc.addBlock(
'affine:surface' as never,
@@ -25,7 +25,7 @@ import type {
TransformerMiddleware,
} from '@blocksuite/affine/store';
import { toDraftModel, Transformer } from '@blocksuite/affine/store';
import { Doc as YDoc } from 'yjs';
const updateSnapshotText = (
point: TextRangePoint,
snapshot: BlockSnapshot,
@@ -164,7 +164,9 @@ export async function markDownToDoc(
middlewares?: TransformerMiddleware[]
) {
// Should not create a new doc in the original collection
const collection = new WorkspaceImpl();
const collection = new WorkspaceImpl({
rootDoc: new YDoc({ guid: 'markdownToDoc' }),
});
collection.meta.initialize();
const transformer = new Transformer({
schema,