refactor(thread-comment): scope resources by host package (#7595)

This commit is contained in:
wpxp123456
2026-08-26 17:01:06 +08:00
committed by GitHub
parent 3fbd045d25
commit 79a5b5609c
12 changed files with 231 additions and 401 deletions
@@ -21,7 +21,7 @@ import { createIdentifier } from '../../common/di';
export type IResources = Array<{ id?: string; name: string; data: string }>;
type IBusinessName = 'SHEET' | 'DOC' | 'SLIDE' | 'BASE' | 'UNIVER';
type IBusinessName = 'SHEET' | 'DOC' | 'SLIDE' | 'BOARD' | 'BASE' | 'UNIVER';
export type IResourceName = `${IBusinessName}_${string}_PLUGIN`;
export interface IResourceHook<T = any> {
pluginName: IResourceName;
@@ -0,0 +1,41 @@
/**
* Copyright 2023-present DreamNum Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { Disposable, Inject, IResourceManagerService, UniverInstanceType } from '@univerjs/core';
import {
createThreadCommentResourceHook,
IThreadCommentDataSourceService,
TC_PLUGIN_NAME,
ThreadCommentModel,
} from '@univerjs/thread-comment';
export const DOC_UNIVER_THREAD_COMMENT_PLUGIN = `DOC_${TC_PLUGIN_NAME}`;
export class DocsThreadCommentResourceController extends Disposable {
constructor(
@IResourceManagerService private readonly _resourceManagerService: IResourceManagerService,
@Inject(ThreadCommentModel) private readonly _threadCommentModel: ThreadCommentModel,
@IThreadCommentDataSourceService private readonly _threadCommentDataSourceService: IThreadCommentDataSourceService
) {
super();
this.disposeWithMe(this._resourceManagerService.registerPluginResource(createThreadCommentResourceHook(
this._threadCommentModel,
this._threadCommentDataSourceService,
DOC_UNIVER_THREAD_COMMENT_PLUGIN,
[UniverInstanceType.UNIVER_DOC]
)));
}
}
@@ -34,6 +34,7 @@ import {
} from './commands/commands/create-doc-text-range-comment.command';
import { DOCS_THREAD_COMMENT_PLUGIN_NAME } from './common/const';
import { defaultPluginConfig, DOCS_THREAD_COMMENT_PLUGIN_CONFIG_KEY } from './config/config';
import { DocsThreadCommentResourceController } from './controllers/docs-thread-comment-resource.controller';
@DependentOn(UniverDocsPlugin, UniverThreadCommentPlugin)
export class UniverDocsThreadCommentPlugin extends Plugin {
@@ -59,6 +60,8 @@ export class UniverDocsThreadCommentPlugin extends Plugin {
}
override onStarting(): void {
this._injector.add([DocsThreadCommentResourceController]);
this._injector.get(DocsThreadCommentResourceController);
this.disposeWithMe(this._commandService.registerCommand(CreateDocTextRangeCommentCommand));
this.disposeWithMe(this._commandService.registerCommand(AddDocCommentDecorationMutation));
}
@@ -14,9 +14,14 @@
* limitations under the License.
*/
import { UniverInstanceType } from '@univerjs/core';
import { CopySheetCommand, RemoveSheetCommand } from '@univerjs/sheets';
import { AddCommentMutation, DeleteCommentMutation } from '@univerjs/thread-comment';
import {
AddCommentMutation,
DeleteCommentMutation,
} from '@univerjs/thread-comment';
import { describe, expect, it, vi } from 'vitest';
import { SHEET_UNIVER_THREAD_COMMENT_PLUGIN } from '../../types/const';
import { SheetsThreadCommentResourceController } from '../sheets-thread-comment-resource.controller';
function createRootComment() {
@@ -40,6 +45,9 @@ describe('SheetsThreadCommentResourceController', () => {
const rootComment = createRootComment();
const controller = new SheetsThreadCommentResourceController(
{
registerPluginResource: () => ({ dispose: vi.fn() }),
} as any,
{
getCurrentUnitOfType: () => ({
getUnitId: () => 'unit-1',
@@ -94,6 +102,9 @@ describe('SheetsThreadCommentResourceController', () => {
const rootComment = createRootComment();
const controller = new SheetsThreadCommentResourceController(
{
registerPluginResource: () => ({ dispose: vi.fn() }),
} as any,
{} as any,
{
interceptCommand: (config: any) => {
@@ -149,4 +160,24 @@ describe('SheetsThreadCommentResourceController', () => {
controller.dispose();
});
it('registers sheet thread comment snapshot resources for sheet units', () => {
let hook: any;
const controller = new SheetsThreadCommentResourceController(
{
registerPluginResource: (nextHook: any) => {
hook = nextHook;
return { dispose: vi.fn() };
},
} as any,
{} as any,
{ interceptCommand: () => ({ dispose: vi.fn() }) } as any,
{ getUnit: () => [] } as any,
{ saveToSnapshot: (value: unknown) => value } as any
);
expect(hook.pluginName).toBe(SHEET_UNIVER_THREAD_COMMENT_PLUGIN);
expect(hook.businesses).toEqual([UniverInstanceType.UNIVER_SHEET]);
controller.dispose();
});
});
@@ -16,21 +16,46 @@
import type { IMutationInfo, Workbook } from '@univerjs/core';
import type { ICopySheetCommandParams, IRemoveSheetCommandParams } from '@univerjs/sheets';
import { Disposable, generateRandomId, Inject, IUniverInstanceService, UniverInstanceType } from '@univerjs/core';
import {
Disposable,
generateRandomId,
Inject,
IResourceManagerService,
IUniverInstanceService,
UniverInstanceType,
} from '@univerjs/core';
import { CopySheetCommand, RemoveSheetCommand, SheetInterceptorService } from '@univerjs/sheets';
import { AddCommentMutation, DeleteCommentMutation, IThreadCommentDataSourceService, ThreadCommentModel } from '@univerjs/thread-comment';
import {
AddCommentMutation,
createThreadCommentResourceHook,
DeleteCommentMutation,
IThreadCommentDataSourceService,
ThreadCommentModel,
} from '@univerjs/thread-comment';
import { SHEET_UNIVER_THREAD_COMMENT_PLUGIN } from '../types/const';
export class SheetsThreadCommentResourceController extends Disposable {
constructor(
@IResourceManagerService private readonly _resourceManagerService: IResourceManagerService,
@IUniverInstanceService private readonly _univerInstanceService: IUniverInstanceService,
@Inject(SheetInterceptorService) private _sheetInterceptorService: SheetInterceptorService,
@Inject(ThreadCommentModel) private _threadCommentModel: ThreadCommentModel,
@IThreadCommentDataSourceService private _threadCommentDataSourceService: IThreadCommentDataSourceService
@Inject(SheetInterceptorService) private readonly _sheetInterceptorService: SheetInterceptorService,
@Inject(ThreadCommentModel) private readonly _threadCommentModel: ThreadCommentModel,
@IThreadCommentDataSourceService private readonly _threadCommentDataSourceService: IThreadCommentDataSourceService
) {
super();
this._initSnapshot();
this._initSheetChange();
}
private _initSnapshot() {
this.disposeWithMe(this._resourceManagerService.registerPluginResource(createThreadCommentResourceHook(
this._threadCommentModel,
this._threadCommentDataSourceService,
SHEET_UNIVER_THREAD_COMMENT_PLUGIN,
[UniverInstanceType.UNIVER_SHEET]
)));
}
// eslint-disable-next-line max-lines-per-function
private _initSheetChange() {
this.disposeWithMe(
@@ -16,6 +16,8 @@
export type { IUniverSheetsThreadCommentConfig } from './config/config';
export { SheetsThreadCommentRefRangeController } from './controllers/sheets-thread-comment-ref-range.controller';
export { SheetsThreadCommentResourceController } from './controllers/sheets-thread-comment-resource.controller';
export { SheetsThreadCommentModel } from './models/sheets-thread-comment.model';
export { UniverSheetsThreadCommentPlugin } from './plugin';
export { SHEET_UNIVER_THREAD_COMMENT_PLUGIN } from './types/const';
export type { ISheetThreadComment } from './types/interfaces/i-sheet-thread-comment';
@@ -14,4 +14,7 @@
* limitations under the License.
*/
import { TC_PLUGIN_NAME } from '@univerjs/thread-comment';
export const SHEET_THREAD_COMMENT_BASE = 'SHEET_THREAD_COMMENT_BASE_PLUGIN';
export const SHEET_UNIVER_THREAD_COMMENT_PLUGIN = `SHEET_${TC_PLUGIN_NAME}`;
@@ -0,0 +1,116 @@
/**
* Copyright 2023-present DreamNum Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import type { IResourceHook, UniverInstanceType } from '@univerjs/core';
import type { ThreadCommentModel } from '../models/thread-comment.model';
import type { IThreadCommentDataSourceService } from '../services/tc-datasource.service';
import type { IThreadComment } from '../types/interfaces/i-thread-comment';
import { isThreadCommentDocumentBody } from '../services/thread-comment-api.service';
export type UnitThreadCommentJSON = Record<string, IThreadComment[]>;
function isStringArray(value: unknown): value is string[] {
return Array.isArray(value) && value.every((item) => typeof item === 'string');
}
function isSnapshotComment(value: unknown, allowChildren = true): value is IThreadComment {
if (!value || typeof value !== 'object') {
return false;
}
const comment = value as Record<string, unknown>;
return typeof comment.id === 'string'
&& comment.id.length > 0
&& typeof comment.threadId === 'string'
&& comment.threadId.length > 0
&& typeof comment.ref === 'string'
&& (comment.text === undefined || isThreadCommentDocumentBody(comment.text))
&& (comment.attachments === undefined || isStringArray(comment.attachments))
&& (comment.mentions === undefined || isStringArray(comment.mentions))
&& (!allowChildren || comment.children === undefined || (
Array.isArray(comment.children)
&& comment.children.every((child) => isSnapshotComment(child, false))
));
}
export function createThreadCommentResourceHook(
threadCommentModel: ThreadCommentModel,
threadCommentDataSourceService: IThreadCommentDataSourceService,
pluginName: IResourceHook['pluginName'],
businesses: UniverInstanceType[]
): IResourceHook<UnitThreadCommentJSON> {
return {
pluginName,
businesses,
toJson: (unitID) => {
const map = threadCommentModel.getUnit(unitID);
const resultMap: UnitThreadCommentJSON = {};
map.forEach((info) => {
const subUnitComments = resultMap[info.subUnitId] ?? [];
subUnitComments.push({
...info.root,
children: info.children,
});
resultMap[info.subUnitId] = subUnitComments;
});
return JSON.stringify(threadCommentDataSourceService.saveToSnapshot(resultMap, unitID));
},
parseJson: (json) => {
if (!json) {
return {};
}
try {
const value: unknown = JSON.parse(json);
if (!value || typeof value !== 'object' || Array.isArray(value)) {
return {};
}
return Object.fromEntries(Object.entries(value).flatMap(([subUnitId, comments]) => (
Array.isArray(comments)
? [[subUnitId, comments.filter((comment) => isSnapshotComment(comment))]]
: []
)));
} catch {
return {};
}
},
onUnLoad: (unitID) => {
threadCommentModel.deleteUnit(unitID);
},
onLoad: (unitID, value) => {
Object.keys(value).forEach((subunitId) => {
const commentList = value[subunitId];
commentList.forEach((comment: IThreadComment) => {
const seenIds = new Set([comment.id]);
const children = comment.children?.filter((child) => {
if (child.threadId !== comment.threadId || seenIds.has(child.id)) {
return false;
}
seenIds.add(child.id);
return true;
}).map((child) => ({ ...child, unitId: unitID, subUnitId: subunitId }));
threadCommentModel.addComment(unitID, subunitId, {
...comment,
unitId: unitID,
subUnitId: subunitId,
children,
});
});
threadCommentModel.syncThreadComments(unitID, subunitId, commentList.map((i) => i.threadId));
});
},
};
}
@@ -1,247 +0,0 @@
/**
* Copyright 2023-present DreamNum Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import type { IDocumentBody, Injector, IWorkbookData } from '@univerjs/core';
import type { IThreadComment } from '../../types/interfaces/i-thread-comment';
import {
IResourceManagerService,
IUniverInstanceService,
LifecycleService,
LifecycleStages,
LocaleType,
Univer,
UniverInstanceType,
} from '@univerjs/core';
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
import { ThreadCommentModel } from '../../models/thread-comment.model';
import { UniverThreadCommentPlugin } from '../../plugin';
import { serializeThreadCommentAnchor, ThreadCommentAnchorKind } from '../../types/comment-anchor';
import { SHEET_UNIVER_THREAD_COMMENT_PLUGIN } from '../tc-resource.controller';
function createWorkbookData(): IWorkbookData {
return {
id: 'unit-1',
appVersion: '3.0.0-alpha',
locale: LocaleType.EN_US,
name: '',
sheetOrder: ['sheet-1'],
styles: {},
sheets: {
'sheet-1': {
id: 'sheet-1',
name: 'Sheet1',
cellData: {},
},
},
};
}
function createBody(text: string): IDocumentBody {
return {
dataStream: `${text}\r\n`,
};
}
function createComment(overrides: Partial<IThreadComment> = {}): IThreadComment {
const id = overrides.id ?? 'comment-1';
return {
id,
threadId: overrides.threadId ?? overrides.parentId ?? id,
ref: overrides.ref ?? 'A1',
dT: overrides.dT ?? '2024-01-01T00:00:00.000Z',
personId: overrides.personId ?? 'user-1',
text: overrides.text ?? createBody(id),
unitId: overrides.unitId ?? 'unit-1',
subUnitId: overrides.subUnitId ?? 'sheet-1',
attachments: overrides.attachments,
children: overrides.children,
mentions: overrides.mentions,
parentId: overrides.parentId,
resolved: overrides.resolved,
updateT: overrides.updateT,
updated: overrides.updated,
};
}
describe('ThreadCommentResourceController', () => {
let univer: Univer;
let get: Injector['get'];
let resourceManagerService: IResourceManagerService;
let threadCommentModel: ThreadCommentModel;
beforeEach(() => {
univer = new Univer();
univer.registerPlugin(UniverThreadCommentPlugin);
univer.createUnit(UniverInstanceType.UNIVER_SHEET, createWorkbookData());
const injector = univer.__getInjector();
get = injector.get.bind(injector);
get(IUniverInstanceService).focusUnit('unit-1');
get(LifecycleService).stage = LifecycleStages.Rendered;
resourceManagerService = get(IResourceManagerService);
threadCommentModel = get(ThreadCommentModel);
});
afterEach(() => {
univer.dispose();
});
it('serializes thread comments by sub unit with children preserved', () => {
const root = createComment({ id: 'root-1', ref: 'A1' });
const reply = createComment({ id: 'reply-1', parentId: root.id, threadId: root.id, ref: '' });
const sideThread = createComment({ id: 'root-2', subUnitId: 'sheet-2', ref: 'B2' });
threadCommentModel.addComment('unit-1', 'sheet-1', root);
threadCommentModel.addComment('unit-1', 'sheet-1', reply);
threadCommentModel.addComment('unit-1', 'sheet-2', sideThread);
const resource = resourceManagerService.getResourcesByType('unit-1', UniverInstanceType.UNIVER_SHEET)
.find((item) => item.name === SHEET_UNIVER_THREAD_COMMENT_PLUGIN);
expect(resource).toBeDefined();
expect(JSON.parse(resource!.data)).toEqual({
'sheet-1': [
{
...root,
children: [reply],
},
],
'sheet-2': [
{
...sideThread,
children: [],
},
],
});
});
it.each([
UniverInstanceType.UNIVER_SLIDE,
UniverInstanceType.UNIVER_BOARD,
UniverInstanceType.UNIVER_BASE,
])('serializes thread comments for business type %s', (businessType) => {
const root = createComment({ id: 'root-business', ref: 'element-1', subUnitId: 'page-1' });
threadCommentModel.addComment('unit-1', 'page-1', root);
const resource = resourceManagerService.getResourcesByType('unit-1', businessType)
.find((item) => item.name === SHEET_UNIVER_THREAD_COMMENT_PLUGIN);
expect(resource).toBeDefined();
if (resource === undefined) {
return;
}
expect(JSON.parse(resource.data)).toEqual({
'page-1': [{
...root,
children: [],
}],
});
});
it('loads serialized comments and clears them on unload', async () => {
const root = createComment({
id: 'root-3',
ref: serializeThreadCommentAnchor({ kind: ThreadCommentAnchorKind.SHEET_DRAWING, elementId: 'drawing-1' }),
attachments: ['root.png'],
mentions: ['user-2'],
resolved: true,
updated: true,
updateT: '2024-01-02T00:00:00.000Z',
});
const reply = createComment({
id: 'reply-3',
parentId: root.id,
threadId: root.id,
ref: '',
attachments: ['reply.png'],
});
resourceManagerService.loadResources('unit-1', [{
name: SHEET_UNIVER_THREAD_COMMENT_PLUGIN,
data: JSON.stringify({
'sheet-1': [
{
...root,
children: [reply],
},
],
}),
}]);
await Promise.resolve();
expect(threadCommentModel.getThread('unit-1', 'sheet-1', root.id)).toEqual({
unitId: 'unit-1',
subUnitId: 'sheet-1',
threadId: root.id,
root,
children: [reply],
relativeUsers: new Set(['user-1']),
});
resourceManagerService.unloadResources('unit-1', UniverInstanceType.UNIVER_SHEET);
expect(threadCommentModel.getUnit('unit-1')).toEqual([]);
});
it('ignores invalid snapshot payloads', async () => {
resourceManagerService.loadResources('unit-1', [{
name: SHEET_UNIVER_THREAD_COMMENT_PLUGIN,
data: '{invalid-json',
}]);
await Promise.resolve();
expect(threadCommentModel.getUnit('unit-1')).toEqual([]);
});
it('filters malformed snapshot entries and keeps loaded comments inside their resource unit', async () => {
const root = createComment({
id: 'safe-root',
unitId: 'spoofed-unit',
subUnitId: 'spoofed-sheet',
children: [
createComment({ id: 'safe-root', threadId: 'safe-root', parentId: 'safe-root' }),
createComment({ id: 'wrong-thread', threadId: 'other-thread', parentId: 'safe-root' }),
createComment({ id: 'safe-reply', threadId: 'safe-root', parentId: 'safe-root' }),
],
});
resourceManagerService.loadResources('unit-1', [{
name: SHEET_UNIVER_THREAD_COMMENT_PLUGIN,
data: JSON.stringify({
'not-an-array': {},
'sheet-1': [
null,
{ id: '', threadId: 'bad', ref: 'A1' },
{ id: 'bad-body', threadId: 'bad-body', ref: 'A1', text: { dataStream: 1 } },
root,
],
}),
}]);
await Promise.resolve();
expect(threadCommentModel.getUnit('spoofed-unit')).toEqual([]);
expect(threadCommentModel.getThread('unit-1', 'sheet-1', root.threadId)).toMatchObject({
root: { id: root.id, unitId: 'unit-1', subUnitId: 'sheet-1' },
children: [{ id: 'safe-reply', unitId: 'unit-1', subUnitId: 'sheet-1' }],
});
expect(threadCommentModel.getComment('unit-1', 'sheet-1', 'wrong-thread')).toBeUndefined();
});
});
@@ -1,139 +0,0 @@
/**
* Copyright 2023-present DreamNum Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import type { IThreadComment } from '../types/interfaces/i-thread-comment';
import { Disposable, Inject, IResourceManagerService, UniverInstanceType } from '@univerjs/core';
import { ThreadCommentModel } from '../models/thread-comment.model';
import { IThreadCommentDataSourceService } from '../services/tc-datasource.service';
import { isThreadCommentDocumentBody } from '../services/thread-comment-api.service';
import { TC_PLUGIN_NAME } from '../types/const';
export type UnitThreadCommentJSON = Record<string, IThreadComment[]>;
export const SHEET_UNIVER_THREAD_COMMENT_PLUGIN = `SHEET_${TC_PLUGIN_NAME}`;
function isStringArray(value: unknown): value is string[] {
return Array.isArray(value) && value.every((item) => typeof item === 'string');
}
function isSnapshotComment(value: unknown, allowChildren = true): value is IThreadComment {
if (!value || typeof value !== 'object') {
return false;
}
const comment = value as Record<string, unknown>;
return typeof comment.id === 'string'
&& comment.id.length > 0
&& typeof comment.threadId === 'string'
&& comment.threadId.length > 0
&& typeof comment.ref === 'string'
&& (comment.text === undefined || isThreadCommentDocumentBody(comment.text))
&& (comment.attachments === undefined || isStringArray(comment.attachments))
&& (comment.mentions === undefined || isStringArray(comment.mentions))
&& (!allowChildren || comment.children === undefined || (
Array.isArray(comment.children)
&& comment.children.every((child) => isSnapshotComment(child, false))
));
}
export class ThreadCommentResourceController extends Disposable {
constructor(
@IResourceManagerService private readonly _resourceManagerService: IResourceManagerService,
@Inject(ThreadCommentModel) private readonly _threadCommentModel: ThreadCommentModel,
@IThreadCommentDataSourceService private readonly _threadCommentDataSourceService: IThreadCommentDataSourceService
) {
super();
this._initSnapshot();
}
private _initSnapshot() {
const toJson = (unitID: string) => {
const map = this._threadCommentModel.getUnit(unitID);
const resultMap: UnitThreadCommentJSON = {};
if (map) {
map.forEach((info) => {
const subUnitComments = resultMap[info.subUnitId] ?? [];
subUnitComments.push({
...info.root,
children: info.children,
});
resultMap[info.subUnitId] = subUnitComments;
});
return JSON.stringify(this._threadCommentDataSourceService.saveToSnapshot(resultMap, unitID));
}
return '';
};
const parseJson = (json: string): UnitThreadCommentJSON => {
if (!json) {
return {};
}
try {
const value: unknown = JSON.parse(json);
if (!value || typeof value !== 'object' || Array.isArray(value)) {
return {};
}
return Object.fromEntries(Object.entries(value).flatMap(([subUnitId, comments]) => (
Array.isArray(comments)
? [[subUnitId, comments.filter((comment) => isSnapshotComment(comment))]]
: []
)));
} catch {
return {};
}
};
this.disposeWithMe(
this._resourceManagerService.registerPluginResource({
pluginName: SHEET_UNIVER_THREAD_COMMENT_PLUGIN,
businesses: [
UniverInstanceType.UNIVER_SHEET,
UniverInstanceType.UNIVER_DOC,
UniverInstanceType.UNIVER_SLIDE,
UniverInstanceType.UNIVER_BOARD,
UniverInstanceType.UNIVER_BASE,
],
toJson: (unitID) => toJson(unitID),
parseJson: (json) => parseJson(json),
onUnLoad: (unitID) => {
this._threadCommentModel.deleteUnit(unitID);
},
onLoad: async (unitID, value) => {
Object.keys(value).forEach((subunitId) => {
const commentList = value[subunitId];
commentList.forEach((comment: IThreadComment) => {
const seenIds = new Set([comment.id]);
const children = comment.children?.filter((child) => {
if (child.threadId !== comment.threadId || seenIds.has(child.id)) {
return false;
}
seenIds.add(child.id);
return true;
}).map((child) => ({ ...child, unitId: unitID, subUnitId: subunitId }));
this._threadCommentModel.addComment(unitID, subunitId, {
...comment,
unitId: unitID,
subUnitId: subunitId,
children,
});
});
this._threadCommentModel.syncThreadComments(unitID, subunitId, commentList.map((i) => i.threadId));
});
},
})
);
}
}
+3 -4
View File
@@ -43,12 +43,11 @@ export type {
IUpdateCommentPayload,
IUpdateCommentRefMutationParams,
} from './commands/mutations/comment.mutation';
export {
createThreadCommentResourceHook,
} from './common/tc-resource';
export { getDT } from './common/utils';
export type { IUniverThreadCommentConfig } from './config/config';
export {
SHEET_UNIVER_THREAD_COMMENT_PLUGIN,
ThreadCommentResourceController,
} from './controllers/tc-resource.controller';
export { ThreadCommentModel } from './models/thread-comment.model';
export type { CommentUpdate, IThreadCommentQuery, IThreadInfo } from './models/thread-comment.model';
export { UniverThreadCommentPlugin } from './plugin';
-4
View File
@@ -42,7 +42,6 @@ import {
UpdateCommentRefMutation,
} from './commands/mutations/comment.mutation';
import { defaultPluginConfig, THREAD_COMMENT_PLUGIN_CONFIG_KEY } from './config/config';
import { ThreadCommentResourceController } from './controllers/tc-resource.controller';
import { ThreadCommentModel } from './models/thread-comment.model';
import { IThreadCommentDataSourceService, ThreadCommentDataSourceService } from './services/tc-datasource.service';
import { ThreadCommentFacadeService } from './services/thread-comment-api.service';
@@ -76,7 +75,6 @@ export class UniverThreadCommentPlugin extends Plugin {
[IThreadCommentDataSourceService, { useClass: ThreadCommentDataSourceService }],
[ThreadCommentModel],
[ThreadCommentFacadeService],
[ThreadCommentResourceController],
], this._config?.overrides) as Dependency[]).forEach(
(d) => {
this._injector.add(d);
@@ -97,7 +95,5 @@ export class UniverThreadCommentPlugin extends Plugin {
].forEach((command) => {
this._commandService.registerCommand(command);
});
this._injector.get(ThreadCommentResourceController);
}
}