feat(core): new template doc property (#9538)
close AF-2045, AF-2047, AF-2065
This commit is contained in:
@@ -5,7 +5,7 @@ import type { DocCustomPropertyInfo } from '../db';
|
||||
*
|
||||
* 'id' and 'type' is request, 'index' is a manually maintained incremental key.
|
||||
*/
|
||||
export const BUILT_IN_CUSTOM_PROPERTY_TYPE = [
|
||||
export const BUILT_IN_CUSTOM_PROPERTY_TYPE: DocCustomPropertyInfo[] = [
|
||||
{
|
||||
id: 'tags',
|
||||
type: 'tags',
|
||||
@@ -23,6 +23,12 @@ export const BUILT_IN_CUSTOM_PROPERTY_TYPE = [
|
||||
show: 'always-hide',
|
||||
index: 'a0000003',
|
||||
},
|
||||
{
|
||||
id: 'template',
|
||||
type: 'template',
|
||||
index: 'a00000031',
|
||||
show: 'always-hide',
|
||||
},
|
||||
{
|
||||
id: 'createdAt',
|
||||
type: 'createdAt',
|
||||
@@ -51,4 +57,4 @@ export const BUILT_IN_CUSTOM_PROPERTY_TYPE = [
|
||||
show: 'always-hide',
|
||||
index: 'a0000008',
|
||||
},
|
||||
] as DocCustomPropertyInfo[];
|
||||
];
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import type { DocMode, RootBlockModel } from '@blocksuite/affine/blocks';
|
||||
import { Entity } from '@toeverything/infra';
|
||||
|
||||
import type { DocProperties } from '../../db';
|
||||
import type { WorkspaceService } from '../../workspace';
|
||||
import type { DocScope } from '../scopes/doc';
|
||||
import type { DocsStore } from '../stores/docs';
|
||||
@@ -38,6 +39,18 @@ export class Doc extends Entity {
|
||||
return this.record.customProperty$(propertyId);
|
||||
}
|
||||
|
||||
setProperty(propertyId: string, value: string) {
|
||||
return this.record.setProperty(propertyId, value);
|
||||
}
|
||||
|
||||
updateProperties(properties: Partial<DocProperties>) {
|
||||
return this.record.updateProperties(properties);
|
||||
}
|
||||
|
||||
getProperties() {
|
||||
return this.record.getProperties();
|
||||
}
|
||||
|
||||
setCustomProperty(propertyId: string, value: string) {
|
||||
return this.record.setCustomProperty(propertyId, value);
|
||||
}
|
||||
|
||||
@@ -42,7 +42,18 @@ export class DocRecord extends Entity<{ id: string }> {
|
||||
});
|
||||
}
|
||||
|
||||
setProperty(propertyId: string, value: string) {
|
||||
getProperties() {
|
||||
return this.docPropertiesStore.getDocProperties(this.id);
|
||||
}
|
||||
|
||||
updateProperties(properties: Partial<DocProperties>) {
|
||||
this.docPropertiesStore.updateDocProperties(this.id, properties);
|
||||
}
|
||||
|
||||
setProperty<Key extends keyof DocProperties>(
|
||||
propertyId: Key,
|
||||
value: DocProperties[Key]
|
||||
) {
|
||||
this.docPropertiesStore.updateDocProperties(this.id, {
|
||||
[propertyId]: value,
|
||||
});
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { DebugLogger } from '@affine/debug';
|
||||
import { Unreachable } from '@affine/env/constant';
|
||||
import type { DocMode } from '@blocksuite/affine/blocks';
|
||||
import { type DocMode, replaceIdMiddleware } from '@blocksuite/affine/blocks';
|
||||
import type { DeltaInsert } from '@blocksuite/affine/inline';
|
||||
import { Text } from '@blocksuite/affine/store';
|
||||
import { Slice, Text, Transformer } from '@blocksuite/affine/store';
|
||||
import type { AffineTextAttributes } from '@blocksuite/affine-shared/types';
|
||||
import { LiveData, ObjectPool, Service } from '@toeverything/infra';
|
||||
import { omitBy } from 'lodash-es';
|
||||
@@ -150,4 +150,83 @@ export class DocsService extends Service {
|
||||
doc.changeDocTitle(newTitle);
|
||||
release();
|
||||
}
|
||||
|
||||
/**
|
||||
* Duplicate a doc from template
|
||||
* @param sourceDocId - the id of the source doc to be duplicated
|
||||
* @param _targetDocId - the id of the target doc to be duplicated, if not provided, a new doc will be created
|
||||
* @returns the id of the new doc
|
||||
*/
|
||||
async duplicateFromTemplate(sourceDocId: string, _targetDocId?: string) {
|
||||
const targetDocId = _targetDocId ?? this.createDoc().id;
|
||||
|
||||
// check if source doc is removed
|
||||
if (this.list.doc$(sourceDocId).value?.trash$.value) {
|
||||
console.warn(
|
||||
`Template doc(id: ${sourceDocId}) is removed, skip duplicate`
|
||||
);
|
||||
return targetDocId;
|
||||
}
|
||||
|
||||
const { release: sourceRelease, doc: sourceDoc } = this.open(sourceDocId);
|
||||
const { release: targetRelease, doc: targetDoc } = this.open(targetDocId);
|
||||
await sourceDoc.waitForSyncReady();
|
||||
|
||||
// duplicate doc content
|
||||
try {
|
||||
const sourceBsDoc = this.store.getBlockSuiteDoc(sourceDocId);
|
||||
const targetBsDoc = this.store.getBlockSuiteDoc(targetDocId);
|
||||
if (!sourceBsDoc) throw new Error('Source doc not found');
|
||||
if (!targetBsDoc) throw new Error('Target doc not found');
|
||||
|
||||
// clear the target doc (both surface and note)
|
||||
targetBsDoc.root?.children.forEach(child =>
|
||||
targetBsDoc.deleteBlock(child)
|
||||
);
|
||||
|
||||
const collection = this.store.getBlocksuiteCollection();
|
||||
const transformer = new Transformer({
|
||||
schema: collection.schema,
|
||||
blobCRUD: collection.blobSync,
|
||||
docCRUD: {
|
||||
create: (id: string) => collection.createDoc({ id }),
|
||||
get: (id: string) => collection.getDoc(id),
|
||||
delete: (id: string) => collection.removeDoc(id),
|
||||
},
|
||||
middlewares: [replaceIdMiddleware(collection.idGenerator)],
|
||||
});
|
||||
const slice = Slice.fromModels(sourceBsDoc, [
|
||||
...(sourceBsDoc.root?.children ?? []),
|
||||
]);
|
||||
const snapshot = transformer.sliceToSnapshot(slice);
|
||||
if (!snapshot) {
|
||||
throw new Error('Failed to create snapshot');
|
||||
}
|
||||
await transformer.snapshotToSlice(
|
||||
snapshot,
|
||||
targetBsDoc,
|
||||
targetBsDoc.root?.id
|
||||
);
|
||||
} catch (e) {
|
||||
logger.error('Failed to duplicate doc', {
|
||||
sourceDocId,
|
||||
targetDocId,
|
||||
originalTargetDocId: _targetDocId,
|
||||
error: e,
|
||||
});
|
||||
} finally {
|
||||
sourceRelease();
|
||||
targetRelease();
|
||||
}
|
||||
|
||||
// duplicate doc properties
|
||||
const properties = sourceDoc.getProperties();
|
||||
const removedProperties = ['id', 'isTemplate', 'journal'];
|
||||
removedProperties.forEach(key => {
|
||||
delete properties[key];
|
||||
});
|
||||
targetDoc.updateProperties(properties);
|
||||
|
||||
return targetDocId;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,10 @@ export class DocsStore extends Store {
|
||||
return this.workspaceService.workspace.docCollection.getDoc(id);
|
||||
}
|
||||
|
||||
getBlocksuiteCollection() {
|
||||
return this.workspaceService.workspace.docCollection;
|
||||
}
|
||||
|
||||
createBlockSuiteDoc() {
|
||||
return this.workspaceService.workspace.docCollection.createDoc();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user