mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-12 12:28:42 +00:00
refactor(editor): replace-id middlware (#12250)
<!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **Refactor** - Improved the internal structure and clarity of ID handling during import processes, leading to more maintainable and modular code. No changes to user-facing functionality. - **Chores** - Enhanced type definitions for import events to improve code readability and maintainability. No impact on end-user experience. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
import type {
|
import {
|
||||||
DatabaseBlockModel,
|
DatabaseBlockModel,
|
||||||
EmbedLinkedDocModel,
|
EmbedLinkedDocModel,
|
||||||
EmbedSyncedDocModel,
|
EmbedSyncedDocModel,
|
||||||
@@ -7,32 +7,50 @@ import type {
|
|||||||
SurfaceRefBlockModel,
|
SurfaceRefBlockModel,
|
||||||
} from '@blocksuite/affine-model';
|
} from '@blocksuite/affine-model';
|
||||||
import { BlockSuiteError } from '@blocksuite/global/exceptions';
|
import { BlockSuiteError } from '@blocksuite/global/exceptions';
|
||||||
import type { DeltaOperation, TransformerMiddleware } from '@blocksuite/store';
|
import type {
|
||||||
|
AfterImportBlockPayload,
|
||||||
|
BeforeImportBlockPayload,
|
||||||
|
DeltaOperation,
|
||||||
|
TransformerMiddleware,
|
||||||
|
} from '@blocksuite/store';
|
||||||
|
import { filter, map } from 'rxjs';
|
||||||
|
|
||||||
|
import { matchModels } from '../../utils';
|
||||||
|
|
||||||
export const replaceIdMiddleware =
|
export const replaceIdMiddleware =
|
||||||
(idGenerator: () => string): TransformerMiddleware =>
|
(idGenerator: () => string): TransformerMiddleware =>
|
||||||
({ slots, docCRUD }) => {
|
({ slots, docCRUD }) => {
|
||||||
const idMap = new Map<string, string>();
|
const idMap = new Map<string, string>();
|
||||||
slots.afterImport.subscribe(payload => {
|
|
||||||
if (
|
// After Import
|
||||||
payload.type === 'block' &&
|
|
||||||
payload.snapshot.flavour === 'affine:database'
|
const afterImportBlock$ = slots.afterImport.pipe(
|
||||||
) {
|
filter(
|
||||||
const model = payload.model as DatabaseBlockModel;
|
(payload): payload is AfterImportBlockPayload =>
|
||||||
|
payload.type === 'block'
|
||||||
|
),
|
||||||
|
map(({ model }) => model)
|
||||||
|
);
|
||||||
|
|
||||||
|
afterImportBlock$
|
||||||
|
.pipe(filter(model => matchModels(model, [DatabaseBlockModel])))
|
||||||
|
.subscribe(model => {
|
||||||
Object.keys(model.props.cells).forEach(cellId => {
|
Object.keys(model.props.cells).forEach(cellId => {
|
||||||
if (idMap.has(cellId)) {
|
if (idMap.has(cellId)) {
|
||||||
model.props.cells[idMap.get(cellId)!] = model.props.cells[cellId];
|
model.props.cells[idMap.get(cellId)!] = model.props.cells[cellId];
|
||||||
delete model.props.cells[cellId];
|
delete model.props.cells[cellId];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
});
|
||||||
|
|
||||||
// replace LinkedPage pageId with new id in paragraph blocks
|
// replace LinkedPage pageId with new id in paragraph blocks
|
||||||
if (
|
afterImportBlock$
|
||||||
payload.type === 'block' &&
|
.pipe(
|
||||||
['affine:list', 'affine:paragraph'].includes(payload.snapshot.flavour)
|
filter(model =>
|
||||||
) {
|
matchModels(model, [ParagraphBlockModel, ListBlockModel])
|
||||||
const model = payload.model as ParagraphBlockModel | ListBlockModel;
|
)
|
||||||
|
)
|
||||||
|
.subscribe(model => {
|
||||||
let prev = 0;
|
let prev = 0;
|
||||||
const delta: DeltaOperation[] = [];
|
const delta: DeltaOperation[] = [];
|
||||||
for (const d of model.props.text.toDelta()) {
|
for (const d of model.props.text.toDelta()) {
|
||||||
@@ -64,13 +82,11 @@ export const replaceIdMiddleware =
|
|||||||
if (delta.length > 0) {
|
if (delta.length > 0) {
|
||||||
model.props.text.applyDelta(delta);
|
model.props.text.applyDelta(delta);
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
|
||||||
if (
|
afterImportBlock$
|
||||||
payload.type === 'block' &&
|
.pipe(filter(model => matchModels(model, [SurfaceRefBlockModel])))
|
||||||
payload.snapshot.flavour === 'affine:surface-ref'
|
.subscribe(model => {
|
||||||
) {
|
|
||||||
const model = payload.model as SurfaceRefBlockModel;
|
|
||||||
const original = model.props.reference;
|
const original = model.props.reference;
|
||||||
// If there exists a replacement, replace the reference with the new id.
|
// If there exists a replacement, replace the reference with the new id.
|
||||||
// Otherwise,
|
// Otherwise,
|
||||||
@@ -86,18 +102,16 @@ export const replaceIdMiddleware =
|
|||||||
idMap.set(original, newId);
|
idMap.set(original, newId);
|
||||||
model.props.reference = newId;
|
model.props.reference = newId;
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
|
||||||
// TODO(@fundon): process linked block/element
|
// TODO(@fundon): process linked block/element
|
||||||
if (
|
afterImportBlock$
|
||||||
payload.type === 'block' &&
|
.pipe(
|
||||||
['affine:embed-linked-doc', 'affine:embed-synced-doc'].includes(
|
filter(model =>
|
||||||
payload.snapshot.flavour
|
matchModels(model, [EmbedLinkedDocModel, EmbedSyncedDocModel])
|
||||||
)
|
)
|
||||||
) {
|
)
|
||||||
const model = payload.model as
|
.subscribe(model => {
|
||||||
| EmbedLinkedDocModel
|
|
||||||
| EmbedSyncedDocModel;
|
|
||||||
const original = model.props.pageId;
|
const original = model.props.pageId;
|
||||||
// If the pageId is not in the doc, generate a new id.
|
// If the pageId is not in the doc, generate a new id.
|
||||||
// If we already have a replacement, use it.
|
// If we already have a replacement, use it.
|
||||||
@@ -110,10 +124,13 @@ export const replaceIdMiddleware =
|
|||||||
model.props.pageId = newId;
|
model.props.pageId = newId;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
});
|
|
||||||
slots.beforeImport.subscribe(payload => {
|
// Before Import
|
||||||
if (payload.type === 'page') {
|
|
||||||
|
slots.beforeImport
|
||||||
|
.pipe(filter(payload => payload.type === 'page'))
|
||||||
|
.subscribe(payload => {
|
||||||
if (idMap.has(payload.snapshot.meta.id)) {
|
if (idMap.has(payload.snapshot.meta.id)) {
|
||||||
payload.snapshot.meta.id = idMap.get(payload.snapshot.meta.id)!;
|
payload.snapshot.meta.id = idMap.get(payload.snapshot.meta.id)!;
|
||||||
return;
|
return;
|
||||||
@@ -121,10 +138,16 @@ export const replaceIdMiddleware =
|
|||||||
const newId = idGenerator();
|
const newId = idGenerator();
|
||||||
idMap.set(payload.snapshot.meta.id, newId);
|
idMap.set(payload.snapshot.meta.id, newId);
|
||||||
payload.snapshot.meta.id = newId;
|
payload.snapshot.meta.id = newId;
|
||||||
return;
|
});
|
||||||
}
|
|
||||||
|
|
||||||
if (payload.type === 'block') {
|
slots.beforeImport
|
||||||
|
.pipe(
|
||||||
|
filter(
|
||||||
|
(payload): payload is BeforeImportBlockPayload =>
|
||||||
|
payload.type === 'block'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.subscribe(payload => {
|
||||||
const { snapshot } = payload;
|
const { snapshot } = payload;
|
||||||
if (snapshot.flavour === 'affine:page') {
|
if (snapshot.flavour === 'affine:page') {
|
||||||
const index = snapshot.children.findIndex(
|
const index = snapshot.children.findIndex(
|
||||||
@@ -210,6 +233,5 @@ export const replaceIdMiddleware =
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -11,13 +11,15 @@ import type {
|
|||||||
SliceSnapshot,
|
SliceSnapshot,
|
||||||
} from './type.js';
|
} from './type.js';
|
||||||
|
|
||||||
|
export type BeforeImportBlockPayload = {
|
||||||
|
snapshot: BlockSnapshot;
|
||||||
|
type: 'block';
|
||||||
|
parent?: string;
|
||||||
|
index?: number;
|
||||||
|
};
|
||||||
|
|
||||||
export type BeforeImportPayload =
|
export type BeforeImportPayload =
|
||||||
| {
|
| BeforeImportBlockPayload
|
||||||
snapshot: BlockSnapshot;
|
|
||||||
type: 'block';
|
|
||||||
parent?: string;
|
|
||||||
index?: number;
|
|
||||||
}
|
|
||||||
| {
|
| {
|
||||||
snapshot: SliceSnapshot;
|
snapshot: SliceSnapshot;
|
||||||
type: 'slice';
|
type: 'slice';
|
||||||
@@ -71,14 +73,16 @@ export type AfterExportPayload =
|
|||||||
type: 'info';
|
type: 'info';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type AfterImportBlockPayload = {
|
||||||
|
snapshot: BlockSnapshot;
|
||||||
|
type: 'block';
|
||||||
|
model: BlockModel;
|
||||||
|
parent?: string;
|
||||||
|
index?: number;
|
||||||
|
};
|
||||||
|
|
||||||
export type AfterImportPayload =
|
export type AfterImportPayload =
|
||||||
| {
|
| AfterImportBlockPayload
|
||||||
snapshot: BlockSnapshot;
|
|
||||||
type: 'block';
|
|
||||||
model: BlockModel;
|
|
||||||
parent?: string;
|
|
||||||
index?: number;
|
|
||||||
}
|
|
||||||
| {
|
| {
|
||||||
snapshot: DocSnapshot;
|
snapshot: DocSnapshot;
|
||||||
type: 'page';
|
type: 'page';
|
||||||
|
|||||||
Reference in New Issue
Block a user