Open
Conversation
Reviewer's GuideImplements full web support for AI meeting blocks, including tabbed summary/notes/transcript sections, speaker sub-blocks, inline references, and enforces read-only behavior for AI-generated meeting content, along with associated editor integration and UI tweaks. Sequence diagram for clicking an inline AI meeting referencesequenceDiagram
actor User
participant InlineReferenceComponent
participant SlateEditor
participant YjsEditor
participant DOM
User->>InlineReferenceComponent: click referenceBadge
InlineReferenceComponent->>InlineReferenceComponent: determine meetingNode and sourceType
InlineReferenceComponent->>YjsEditor: setBlockData(meetingBlockId, selected_tab_index)
Note over InlineReferenceComponent,YjsEditor: Switch to notes or transcript tab if needed
InlineReferenceComponent->>YjsEditor: findSlateEntryByBlockId(targetBlockId)
YjsEditor-->>InlineReferenceComponent: slateEntry
InlineReferenceComponent->>SlateEditor: ReactEditor.toDOMNode(targetNode)
SlateEditor-->>InlineReferenceComponent: domNode
InlineReferenceComponent->>DOM: smoothScrollIntoViewIfNeeded(domNode)
DOM-->>InlineReferenceComponent: scroll complete
InlineReferenceComponent->>DOM: add highlight-block class
Note over DOM: Highlight referenced content for a few seconds
Sequence diagram for read-only enforcement on AI meeting contentsequenceDiagram
participant SlateEditor
participant WithElementPlugin
participant SelectionToolbarHook
participant AIMeetingBlockComponent
participant Notify
participant User
SlateEditor->>WithElementPlugin: shouldTreatPathReadOnly(path)
WithElementPlugin->>WithElementPlugin: Editor.above(... aiMeetingReadOnlyTypes)
WithElementPlugin-->>SlateEditor: true when inside summary/notes/transcription
SlateEditor->>AIMeetingBlockComponent: render(node)
AIMeetingBlockComponent->>SlateEditor: editor.isElementReadOnly(element)
SlateEditor-->>AIMeetingBlockComponent: readOnly flag
AIMeetingBlockComponent-->>SlateEditor: render tabs/title with inputs disabled when readOnly
SlateEditor->>SelectionToolbarHook: selectionchange event
SelectionToolbarHook->>SelectionToolbarHook: isSelectionInReadOnly using Editor.above
SelectionToolbarHook-->>SelectionToolbarHook: visible false when in read-only AI meeting
User->>AIMeetingBlockComponent: click inside readOnly section
AIMeetingBlockComponent->>Notify: notify.info(readOnlyHint)
Notify-->>User: show read-only hint toast
Class diagram for AI meeting block types and inline reference dataclassDiagram
direction LR
class BlockData {
}
class AIMeetingBlockData {
+string title
+string date
+string audio_file_path
+string recording_state
+string summary_template
+string summary_detail
+string summary_language
+string transcript_id
+string transcription_type
+string created_at
+string last_modified
+number selected_tab_index
+number pending_billing_duration
+boolean show_notes_directly
+boolean auto_start_recording
+string speaker_info_map
}
class AIMeetingSpeakerBlockData {
+string speaker_id
+number timestamp
+number end_timestamp
}
class BlockNode {
+string id
+string blockId
+BlockType type
+BlockData data
}
class AIMeetingNode {
+AIMeetingBlockData data
}
class AIMeetingSummaryNode {
+BlockType type~AIMeetingSummaryBlock~
}
class AIMeetingNotesNode {
+BlockType type~AIMeetingNotesBlock~
}
class AIMeetingTranscriptionNode {
+BlockType type~AIMeetingTranscriptionBlock~
}
class AIMeetingSpeakerNode {
+AIMeetingSpeakerBlockData data
+BlockType type~AIMeetingSpeakerBlock~
}
class InlineReferenceData {
+string[] blockIds
+number number
}
class AIMeetingBlockComponent {
+string titleState
+number activeIndexState
+boolean readOnly
+handleTabChange(index number)
+commitTitle()
}
class AIMeetingSectionComponent {
+renderSummary()
+renderNotes()
+renderTranscription()
}
class AIMeetingSpeakerBlockComponent {
+resolveSpeakerInfo()
+formatTimestamp(value number)
}
class InlineReferenceComponent {
+InlineReferenceData reference
+buildStatuses(meetingNode Element)
+scrollToTarget(blockId string)
}
BlockData <|-- AIMeetingBlockData
BlockData <|-- AIMeetingSpeakerBlockData
BlockNode <|-- AIMeetingNode
BlockNode <|-- AIMeetingSummaryNode
BlockNode <|-- AIMeetingNotesNode
BlockNode <|-- AIMeetingTranscriptionNode
BlockNode <|-- AIMeetingSpeakerNode
AIMeetingNode --> AIMeetingBlockData
AIMeetingSpeakerNode --> AIMeetingSpeakerBlockData
AIMeetingBlockComponent --> AIMeetingNode
AIMeetingBlockComponent --> AIMeetingSectionComponent
AIMeetingSectionComponent --> AIMeetingSummaryNode
AIMeetingSectionComponent --> AIMeetingNotesNode
AIMeetingSectionComponent --> AIMeetingTranscriptionNode
AIMeetingSpeakerBlockComponent --> AIMeetingSpeakerNode
InlineReferenceComponent --> InlineReferenceData
InlineReferenceComponent --> AIMeetingNode
InlineReferenceComponent --> AIMeetingSpeakerNode
Flow diagram for selection toolbar visibility with AI meeting read-only logicflowchart TD
A[Selection change event] --> B{Editor has focus?}
B -- No --> Z[Hide selection toolbar]
B -- Yes --> C{Selection collapsed?}
C -- Yes --> Z
C -- No --> D{assistantTypeRef defined?}
D -- Yes --> Z
D -- No --> E{isSelectionInReadOnly?}
E -- Yes --> Z
E -- No --> F{selectedText nonempty and isExpanded and not isDragging}
F -- No --> Z
F -- Yes --> Y[Show selection toolbar]
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
🥷 Ninja i18n – 🛎️ Translations need to be updatedProject
|
| lint rule | new reports | level | link |
|---|---|---|---|
| Missing translation | 459 | warning | contribute (via Fink 🐦) |
There was a problem hiding this comment.
Hey - I've found 1 issue, and left some high level feedback:
- In
InlineReference,editor.isElementReadOnly(text as unknown as Element)is being called on aTextnode and could throw ifisElementReadOnlyassumes anElement; consider deriving read-only from the surrounding element (e.g., viaEditor.above) or justuseReadOnly()instead of casting. - The
formatTimestamphelper is duplicated in bothAIMeetingSpeakerBlockandInlineReference; extracting a shared utility would reduce repetition and keep timestamp formatting consistent.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- In `InlineReference`, `editor.isElementReadOnly(text as unknown as Element)` is being called on a `Text` node and could throw if `isElementReadOnly` assumes an `Element`; consider deriving read-only from the surrounding element (e.g., via `Editor.above`) or just `useReadOnly()` instead of casting.
- The `formatTimestamp` helper is duplicated in both `AIMeetingSpeakerBlock` and `InlineReference`; extracting a shared utility would reduce repetition and keep timestamp formatting consistent.
## Individual Comments
### Comment 1
<location> `src/components/editor/components/toolbar/selection-toolbar/SelectionToolbar.hooks.ts:14-18` </location>
<code_context>
import { Decorate, useEditorContext } from '@/components/editor/EditorContext';
import { createHotkey, HOT_KEY_NAME } from '@/utils/hotkeys';
+const AI_MEETING_READONLY_TYPES = new Set<BlockType>([
+ BlockType.AIMeetingSummaryBlock,
+ BlockType.AIMeetingNotesBlock,
+ BlockType.AIMeetingTranscriptionBlock,
+ BlockType.AIMeetingSpeakerBlock,
+]);
+
</code_context>
<issue_to_address>
**issue (bug_risk):** Speaker blocks are treated as read-only for the toolbar but not for `isElementReadOnly`, which may lead to inconsistent behavior.
`AI_MEETING_READONLY_TYPES` includes `AIMeetingSpeakerBlock`, so the selection toolbar is hidden inside speaker blocks. But in `withElement.ts`, `aiMeetingReadOnlyTypes` only covers summary/notes/transcription, so `editor.isElementReadOnly` may still return `false` for speaker blocks. This can leave speaker content editable (including via shortcuts) but without a toolbar. Please either:
- Add `AIMeetingSpeakerBlock` to `aiMeetingReadOnlyTypes` in `withElement.ts`, or
- Remove it from `AI_MEETING_READONLY_TYPES` if speaker content should remain editable.
Keeping these checks consistent will avoid this mismatch in behavior.
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
src/components/editor/components/toolbar/selection-toolbar/SelectionToolbar.hooks.ts
Show resolved
Hide resolved
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Checklist
General
Testing
Feature-Specific
Summary by Sourcery
Add full web rendering support for AI meeting blocks, including tabbed views, speaker sections, and inline references, while enforcing read-only behavior for AI-generated meeting content.
New Features:
Enhancements: