mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-08-12 14:40:22 +08:00
feat(editor): resolve unassociated comments on init (#13008)
#### PR Dependency Tree * **PR #13008** 👈 This tree was auto-generated by [Charcoal](https://github.com/danerwilliams/charcoal) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Improved synchronization between comment states in the editor and the comment provider to ensure consistency of inline and block comments. * **Refactor** * Separated and modularized utility functions for finding commented texts and blocks, enhancing maintainability and reusability. * **Style** * Updated styles to remove background color and border from inline comments within embedded note content. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
@@ -1,8 +1,10 @@
|
||||
import { getInlineEditorByModel } from '@blocksuite/affine-rich-text';
|
||||
import { getSelectedBlocksCommand } from '@blocksuite/affine-shared/commands';
|
||||
import {
|
||||
BlockCommentManager,
|
||||
type CommentId,
|
||||
CommentProviderIdentifier,
|
||||
findAllCommentedBlocks,
|
||||
} from '@blocksuite/affine-shared/services';
|
||||
import type { AffineInlineEditor } from '@blocksuite/affine-shared/types';
|
||||
import { DisposableGroup } from '@blocksuite/global/disposable';
|
||||
@@ -13,8 +15,13 @@ import {
|
||||
} from '@blocksuite/std';
|
||||
import type { BaseSelection, BlockModel } from '@blocksuite/store';
|
||||
import { signal } from '@preact/signals-core';
|
||||
import difference from 'lodash-es/difference';
|
||||
|
||||
import { extractCommentIdFromDelta, findCommentedTexts } from './utils';
|
||||
import {
|
||||
extractCommentIdFromDelta,
|
||||
findAllCommentedTexts,
|
||||
findCommentedTexts,
|
||||
} from './utils';
|
||||
|
||||
export class InlineCommentManager extends LifeCycleWatcher {
|
||||
static override key = 'inline-comment-manager';
|
||||
@@ -31,6 +38,8 @@ export class InlineCommentManager extends LifeCycleWatcher {
|
||||
const provider = this._provider;
|
||||
if (!provider) return;
|
||||
|
||||
this._init();
|
||||
|
||||
this._disposables.add(provider.onCommentAdded(this._handleAddComment));
|
||||
this._disposables.add(
|
||||
provider.onCommentDeleted(this._handleDeleteAndResolve)
|
||||
@@ -50,6 +59,43 @@ export class InlineCommentManager extends LifeCycleWatcher {
|
||||
this._disposables.dispose();
|
||||
}
|
||||
|
||||
private _init() {
|
||||
const provider = this._provider;
|
||||
if (!provider) return;
|
||||
|
||||
const commentsInProvider = provider.getComments();
|
||||
const inlineComments = findAllCommentedTexts(this.std).flatMap(
|
||||
([selection, inlineEditor]) => {
|
||||
const deltas = inlineEditor.getDeltasByInlineRange({
|
||||
index: selection.from.index,
|
||||
length: selection.from.length,
|
||||
});
|
||||
return deltas.flatMap(([delta]) => extractCommentIdFromDelta(delta));
|
||||
}
|
||||
);
|
||||
|
||||
const blockComments = findAllCommentedBlocks(this.std.store).flatMap(
|
||||
block => Object.keys(block.props.comments)
|
||||
);
|
||||
|
||||
const commentsInEditor = [
|
||||
...new Set([...inlineComments, ...blockComments]),
|
||||
];
|
||||
|
||||
// resolve comments that are in provider but not in editor
|
||||
// which means the commented content may be deleted
|
||||
difference(commentsInProvider, commentsInEditor).forEach(comment => {
|
||||
provider.resolveComment(comment);
|
||||
});
|
||||
|
||||
// remove comments that are in editor but not in provider
|
||||
// which means the comment may be removed or resolved in provider side
|
||||
difference(commentsInEditor, commentsInProvider).forEach(comment => {
|
||||
this._handleDeleteAndResolve(comment);
|
||||
this.std.get(BlockCommentManager).handleDeleteAndResolve(comment);
|
||||
});
|
||||
}
|
||||
|
||||
private readonly _handleAddComment = (
|
||||
id: CommentId,
|
||||
selections: BaseSelection[]
|
||||
|
||||
@@ -5,8 +5,8 @@ import { type BlockStdScope, TextSelection } from '@blocksuite/std';
|
||||
import type { InlineEditor } from '@blocksuite/std/inline';
|
||||
import type { DeltaInsert } from '@blocksuite/store';
|
||||
|
||||
export function findCommentedTexts(std: BlockStdScope, commentId: CommentId) {
|
||||
const selections: [TextSelection, InlineEditor][] = [];
|
||||
export function findAllCommentedTexts(std: BlockStdScope) {
|
||||
const selections: [TextSelection, InlineEditor<AffineTextAttributes>][] = [];
|
||||
std.store.getAllModels().forEach(model => {
|
||||
const inlineEditor = getInlineEditorByModel(std, model);
|
||||
if (!inlineEditor) return;
|
||||
@@ -19,9 +19,7 @@ export function findCommentedTexts(std: BlockStdScope, commentId: CommentId) {
|
||||
(delta, rangeIndex) => {
|
||||
if (
|
||||
delta.attributes &&
|
||||
Object.keys(delta.attributes).some(
|
||||
key => key === `comment-${commentId}`
|
||||
)
|
||||
Object.keys(delta.attributes).some(key => key.startsWith('comment-'))
|
||||
) {
|
||||
selections.push([
|
||||
new TextSelection({
|
||||
@@ -42,6 +40,18 @@ export function findCommentedTexts(std: BlockStdScope, commentId: CommentId) {
|
||||
return selections;
|
||||
}
|
||||
|
||||
export function findCommentedTexts(std: BlockStdScope, commentId: CommentId) {
|
||||
return findAllCommentedTexts(std).filter(([selection, inlineEditor]) => {
|
||||
const deltas = inlineEditor.getDeltasByInlineRange({
|
||||
index: selection.from.index,
|
||||
length: selection.from.length,
|
||||
});
|
||||
return deltas
|
||||
.flatMap(([delta]) => extractCommentIdFromDelta(delta))
|
||||
.includes(commentId);
|
||||
});
|
||||
}
|
||||
|
||||
export function extractCommentIdFromDelta(
|
||||
delta: DeltaInsert<AffineTextAttributes>
|
||||
) {
|
||||
|
||||
Reference in New Issue
Block a user