fix(sheets-thread-comment): preserve cell thread selection (#7571)

This commit is contained in:
wpxp123456
2026-08-21 16:50:54 +08:00
committed by GitHub
parent f37937c4e2
commit fd88260ce6
4 changed files with 89 additions and 3 deletions
@@ -27,11 +27,25 @@ export const SheetsThreadCommentCell = () => {
const sheetsThreadCommentPopupService = useDependency(SheetsThreadCommentPopupService);
const activePopup = useObservable(sheetsThreadCommentPopupService.activePopup$);
const sheetThreadCommentModel = useDependency(SheetsThreadCommentModel);
const getRootId = () => {
if (!activePopup) {
return undefined;
}
const { unitId, subUnitId, row, col, commentId } = activePopup;
const activeComment = commentId
? sheetThreadCommentModel.getAllByLocation(unitId, subUnitId, row, col).find((comment) => comment.id === commentId)
: undefined;
return activeComment && !activeComment.resolved
? activeComment.id
: sheetThreadCommentModel.getByLocation(unitId, subUnitId, row, col);
};
const rootId = useObservable(
activePopup
? () => sheetThreadCommentModel.commentUpdate$.pipe(
map(() => sheetThreadCommentModel.getByLocation(activePopup.unitId, activePopup.subUnitId, activePopup.row, activePopup.col)),
startWith(sheetThreadCommentModel.getByLocation(activePopup.unitId, activePopup.subUnitId, activePopup.row, activePopup.col))
map(() => getRootId()),
startWith(getRootId())
)
: null,
undefined,
@@ -1047,6 +1047,42 @@ describe('SheetsThreadCommentPanel', () => {
}));
});
it('switches the cell thread when the active popup selects another thread at the same location', () => {
const testBed = createTestBed();
univer = testBed.univer;
testBed.threadCommentModel.addComment(unitId, sheet1, createComment('first-thread', sheet1, 'B2', 'First B2 thread'));
testBed.threadCommentModel.addComment(unitId, sheet1, createComment('second-thread', sheet1, 'B2', 'Second B2 thread'));
testBed.popupService.showPopup({
unitId,
subUnitId: sheet1,
row: 1,
col: 1,
commentId: 'first-thread',
});
const rendered = renderCell(testBed.injector);
root = rendered.root;
container = rendered.container;
expect(container.querySelector(`#CELL-${unitId}-${sheet1}-first-thread`)).toBeInstanceOf(HTMLElement);
expect(container.textContent).toContain('First B2 thread');
expect(container.textContent).not.toContain('Second B2 thread');
act(() => {
testBed.popupService.showPopup({
unitId,
subUnitId: sheet1,
row: 1,
col: 1,
commentId: 'second-thread',
});
});
expect(container.querySelector(`#CELL-${unitId}-${sheet1}-second-thread`)).toBeInstanceOf(HTMLElement);
expect(container.textContent).toContain('Second B2 thread');
expect(container.textContent).not.toContain('First B2 thread');
});
it('updates an open cell popup when a thread is added at that cell location', () => {
const testBed = createTestBed();
univer = testBed.univer;
@@ -36,6 +36,42 @@ function createComment(overrides: Record<string, unknown> = {}) {
}
describe('SheetsThreadCommentModel', () => {
it('keeps the newer unresolved thread as the default when an older thread is reopened', () => {
const olderComment = createComment({ id: 'older-comment', threadId: 'older-thread', resolved: true });
const newerComment = createComment({ id: 'newer-comment', threadId: 'newer-thread' });
const comments = new Map([
[olderComment.id, olderComment],
[newerComment.id, newerComment],
]);
const updates$ = new Subject<unknown>();
const threadCommentModel = {
getAll: () => [{ threads: [
{ unitId: 'unit-1', subUnitId: 'sheet-1', root: olderComment },
{ unitId: 'unit-1', subUnitId: 'sheet-1', root: newerComment },
] }],
commentUpdate$: updates$,
getComment: (_unitId: string, _subUnitId: string, commentId: string) => comments.get(commentId),
};
const univerInstanceService = {
getUnitType: () => UniverInstanceType.UNIVER_SHEET,
};
const model = new SheetsThreadCommentModel(threadCommentModel as never, univerInstanceService as never);
expect(model.getByLocation('unit-1', 'sheet-1', 0, 0)).toBe(newerComment.id);
olderComment.resolved = false;
updates$.next({
type: 'resolve',
unitId: 'unit-1',
subUnitId: 'sheet-1',
payload: { commentId: olderComment.id, resolved: false },
});
expect(model.getByLocation('unit-1', 'sheet-1', 0, 0)).toBe(newerComment.id);
model.dispose();
});
it('should build location indexes from existing root comments and expose thread data', () => {
const root = createComment();
const reply = createComment({ id: 'reply-1', parentId: root.id, ref: '', resolved: false });
@@ -230,7 +230,7 @@ export class SheetsThreadCommentModel extends Disposable {
getByLocation(unitId: string, subUnitId: string, row: number, column: number): string | undefined {
const comments = this.getAllByLocation(unitId, subUnitId, row, column);
const activeComments = comments.filter((comment) => !comment.resolved);
return activeComments[0]?.id;
return activeComments[activeComments.length - 1]?.id;
}
getAllByLocation(unitId: string, subUnitId: string, row: number, column: number): IThreadComment[] {