-
Notifications
You must be signed in to change notification settings - Fork 60
Introduce a Simplified Mode for Editing Prompts in the Expanded Editor #980
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
WalkthroughAdds PROMPT input mode and overhauls expanded editing: introduces ProseMirror rich-text and CodeMirror source editors, new toolbars and link dialog, a ProseMirror chip node/plugin, centralized helper-pane hooks/positioning, command utilities (undo/redo), and propagates helper-pane APIs into diagram integrations. (40 words) Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant ExpandedEditor
participant TemplateMode
participant SourceEditor as CodeMirror
participant RichEditor as ProseMirror
participant RawToolbar
participant RichToolbar
participant HelperPane
User->>ExpandedEditor: open (inputMode=Prompt/Template)
ExpandedEditor->>TemplateMode: render (passes inputMode, sanitized/raw, callbacks)
alt Source view (raw)
TemplateMode->>SourceEditor: mount CodeMirror (provide editorView)
TemplateMode->>RawToolbar: attach (editorView)
User->>RawToolbar: command (format/insert/undo)
RawToolbar->>SourceEditor: execute CodeMirror command
else Rich view (WYSIWYG)
TemplateMode->>RichEditor: mount ProseMirror (provide view)
TemplateMode->>RichToolbar: attach (editorView)
User->>RichToolbar: command (bold/heading/link)
RichToolbar->>RichEditor: execute ProseMirror command
RichEditor->>chipPlugin: token→chip transform (on token update)
end
User->>RichEditor: request helper pane (click/shortcut)
RichEditor->>HelperPane: compute position via useHelperPane -> calculateHelperPanePosition
HelperPane->>TemplateMode: notify onHelperPaneStateChange (isOpen, ref, toggle)
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes
Possibly related PRs
Suggested labels
Suggested reviewers
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
cbf6312 to
a020c3b
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 7
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/CodeUtils.ts (1)
716-763: Fix severity type cast to include "hint" from @codemirror/lint APIThe
buildLintingExtensionfunction castsdiagnostic.severity.toLowerCase()to"error" | "warning" | "info", but the @codemirror/lint API's Diagnostic type supports"hint" | "info" | "warning" | "error". The type union excludes"hint", creating a mismatch with the current API. Update line 746 to include"hint":severity: diagnostic.severity.toLowerCase() as "error" | "warning" | "info" | "hint",
🧹 Nitpick comments (6)
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RawTemplateMarkdownToolbar.tsx (1)
37-167: Rich and raw toolbars duplicate styling/layout logic
RawTemplateMarkdownToolbarlargely mirrorsRichTemplateMarkdownToolbar(container, button styles, split-button, dropdown). This is fine functionally, but it does increase the chance of visual/behavioral drift over time.Longer term, consider extracting shared toolbar primitives (container, button, split-button, dropdown components) into a common module that both toolbars reuse.
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/TemplateMode.tsx (2)
38-45: Avoid relying on hashed CodeMirror class names in CSSThe selectors
.ͼ1 .cm-scrollerand.ͼ1 .cm-lintRange-errordepend on an internal hashed class name that can change across CodeMirror versions/build setups. That makes the styling brittle.Prefer targeting stable selectors instead (for example,
.cm-editor .cm-scrollerand.cm-lintRange-error/ diagnostic-specific classes) so styles survive library upgrades.
94-127: Adjusted diagnostics are not propagated to child editors
computeDiagnostics/adjustedDiagnosticscorrectly rebase diagnostic ranges relative totargetLineRange, but the adjusted list is only used for theErrorBanner. NeitherChipExpressionEditorComponentnorRichTextTemplateEditorreceive these diagnostics via aformDiagnostics-style prop here.If the intent is to show inline lint markers in both Default (rich) and Raw modes for the template editor, consider passing
adjustedDiagnosticsdown to those components so the diagnostics used by the editors match what is shown in the banner:<ChipExpressionEditorComponent ... formDiagnostics={adjustedDiagnostics} ... /> <RichTextTemplateEditor ... formDiagnostics={adjustedDiagnostics} ... />workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/chipPlugin.ts (1)
46-110: Chip node + DOM mapping look solid; consider centralizing chip rendering logicThe
chipNodeSpec andtoDOM/parseDOMsetup are consistent and should work well with the serializer, but the visual construction is duplicated from the CodeMirror chip widget (diagnostics, colors, icon, underline). Extracting a shared helper (e.g., a pure “chip view model” or DOM factory) would reduce drift between the raw and rich editors when styles or diagnostic behavior change.workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/CodeUtils.ts (1)
58-167: ChipWidget equality ignores metadata/type; consider including them
ChipWidget.eqnow comparestext,start,end, anddiagnosticbut nottypeormetadata. If either of those change (e.g., a document chip’sdocumentTypeor variable/document classification changes without moving), the widget may not re-render, leaving stale icon/color. Includingthis.typeand, if relevant, a stable subset ofmetadatain the equality check would make updates more robust.workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx (1)
520-537: Helper-pane state exposure is useful; consider also wiring toolbar ref or drop it
onHelperPaneStateChangeexposesisOpen, the toggle function, andhelperPaneToggleButtonRef, which lets the parent own the toolbar button. However,toolbarRefinside this component is never attached to any JSX element, so the “click inside toolbar” exemption in the outside-click handler is effectively dead code. Either wiretoolbarRefinto the actual toolbar container or remove it to avoid confusion.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (2)
common/config/rush/pnpm-lock.yamlis excluded by!**/pnpm-lock.yamlworkspaces/common-libs/font-wso2-vscode/src/icons/bi-arrow-down.svgis excluded by!**/*.svg
📒 Files selected for processing (18)
workspaces/ballerina/ballerina-core/src/interfaces/bi.ts(1 hunks)workspaces/ballerina/ballerina-side-panel/package.json(1 hunks)workspaces/ballerina/ballerina-side-panel/src/components/Form/index.tsx(6 hunks)workspaces/ballerina/ballerina-side-panel/src/components/Form/utils.ts(2 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/ExpandedEditor.tsx(2 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RawTemplateMarkdownToolbar.tsx(1 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RichTemplateMarkdownToolbar.tsx(1 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/TemplateMarkdownToolbar.tsx(0 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/TemplateMode.tsx(5 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/utils/templateUtils.ts(3 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/CodeUtils.ts(9 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/chipStyles.ts(2 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/ChipExpressionEditor.tsx(9 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/HelperPaneToggleButton.tsx(3 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/types.ts(1 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx(1 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/chipPlugin.ts(1 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/markdownCommands.ts(1 hunks)
💤 Files with no reviewable changes (1)
- workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/TemplateMarkdownToolbar.tsx
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-11-24T14:51:49.207Z
Learnt from: KCSAbeywickrama
Repo: wso2/vscode-extensions PR: 998
File: workspaces/ballerina/data-mapper/src/components/DataMapper/Header/ExpressionBar.tsx:113-132
Timestamp: 2025-11-24T14:51:49.207Z
Learning: In workspaces/ballerina/data-mapper/src/components/DataMapper/Header/ExpressionBar.tsx, if `textFieldRef.current` is not undefined, `textFieldRef.current.inputElement` is guaranteed to exist. If `inputElement` doesn't exist when `current` exists, it's a fatal error that should reach the error boundary rather than being handled with defensive null checks.
Applied to files:
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/TemplateMode.tsx
🧬 Code graph analysis (7)
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RichTemplateMarkdownToolbar.tsx (4)
workspaces/common-libs/ui-toolkit/src/styles/Theme.ts (1)
ThemeColors(79-104)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/markdownCommands.ts (10)
toggleHeading(61-71)isNodeActive(113-123)isListActive(125-139)toggleBold(28-30)toggleItalic(32-34)toggleCode(36-38)toggleLink(40-59)toggleBlockquote(77-83)toggleBulletList(85-93)toggleOrderedList(95-103)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/HelperPaneToggleButton.tsx (1)
HelperPaneToggleButton(82-107)workspaces/common-libs/ui-toolkit/src/components/Swich/Swich.tsx (1)
Switch(146-176)
workspaces/ballerina/ballerina-side-panel/src/components/Form/index.tsx (1)
workspaces/ballerina/ballerina-side-panel/src/components/Form/utils.ts (2)
updateFormFieldWithImports(46-51)updateFormFieldWithDiagnostics(112-131)
workspaces/ballerina/ballerina-side-panel/src/components/Form/utils.ts (1)
workspaces/ballerina/ballerina-core/src/interfaces/bi.ts (3)
Diagnostic(160-163)DiagnosticMessage(165-174)FormDiagnostics(519-522)
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/HelperPaneToggleButton.tsx (1)
workspaces/common-libs/ui-toolkit/src/styles/Theme.ts (1)
ThemeColors(79-104)
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/CodeUtils.ts (2)
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/types.ts (2)
TokenMetadata(64-68)CompoundTokenSequence(90-98)workspaces/ballerina/ballerina-core/src/interfaces/bi.ts (2)
DiagnosticMessage(165-174)Diagnostic(160-163)
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/ChipExpressionEditor.tsx (3)
workspaces/ballerina/ballerina-core/src/interfaces/bi.ts (1)
DiagnosticMessage(165-174)workspaces/common-libs/ui-toolkit/src/components/ExpressionEditor/constants/form.ts (1)
HELPER_PANE_WIDTH(21-21)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/CodeUtils.ts (4)
buildHelperPaneKeymap(716-735)buildLintingExtension(737-763)diagnosticsField(250-262)diagnosticsChangeEffect(239-239)
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/utils/templateUtils.ts (1)
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/markdownCommands.ts (4)
undoCommand(141-143)redoCommand(145-147)canUndo(149-151)canRedo(153-155)
🔇 Additional comments (18)
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/types.ts (1)
41-42: LGTM!The
TokenType.ERRORaddition is consistent with the existing enum pattern and aligns with the error handling enhancements across the editor components.workspaces/ballerina/ballerina-core/src/interfaces/bi.ts (1)
168-173: LGTM!The extension of
DiagnosticMessagewith optionalrange,code, andsourcefields is backward-compatible and aligns well with VSCode's diagnostic structure. This enables more precise error localization in the UI.workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/ExpandedEditor.tsx (1)
189-189: LGTM!The comment updates clarify the preview behavior, and removing
isPreviewMode/onTogglePreviewfrom the template mode prop surface aligns with the internal state management refactoring inTemplateMode.tsx.Also applies to: 238-249
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/HelperPaneToggleButton.tsx (1)
29-29: LGTM!The optional
titleprop addition enhances accessibility by allowing tooltip text on the button. The explicit typing on Line 36 is a good practice for styled components.Also applies to: 36-36, 86-87, 101-101
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/chipStyles.ts (1)
67-75: LGTM!The updated
DOCUMENTtoken colors and newERRORtoken styling are consistent with the existing pattern. The icon class mapping follows the established convention.Also applies to: 95-95
workspaces/ballerina/ballerina-side-panel/src/components/Form/index.tsx (1)
58-58: LGTM!The diagnostics propagation through
updateFormFieldWithDiagnosticsis consistently applied across all field rendering paths (regular, advanced, and category fields). This ensures diagnostic information is properly attached to form fields throughout the UI.Also applies to: 805-806, 890-891, 918-918, 927-927, 944-944
workspaces/ballerina/ballerina-side-panel/src/components/Form/utils.ts (1)
112-131: LGTM!The
updateFormFieldWithDiagnosticsfunction correctly filters and attaches diagnostics to form fields. The early return logic is appropriate and the field spread maintains immutability.workspaces/ballerina/ballerina-side-panel/package.json (1)
20-61: Dependencies align with the new editor/markdown stackThe added CodeMirror, ProseMirror, markdown, and ui-toolkit dependencies look consistent with the new rich/raw template editors and toolbars; no issues from this manifest alone.
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/ChipExpressionEditor.tsx (1)
332-445: Diagnostics compartment wiring looks soundThe new linting Compartment and
formDiagnostics-drivenuseEffectcleanly separate diagnostics reconfiguration (lintCompartment.reconfigure) from other editor extensions, anddiagnosticsChangeEffectkeeps the diagnostics field in sync. This structure should scale well as more diagnostic-driven behavior is added.workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RawTemplateMarkdownToolbar.tsx (1)
250-399: Raw-mode toolbar behavior looks consistent with requirementsThe raw Markdown toolbar correctly wires undo/redo, formatting, headings, lists, helper pane toggle, and the Default/Raw switch against the CodeMirror
EditorView. Guarding all actions withdisabled={!editorView}avoids null-view issues.workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/TemplateMode.tsx (1)
133-196: Dual-mode wiring between rich/raw editors and toolbars looks coherentThe TemplateMode component cleanly switches between raw (CodeMirror) and rich (ProseMirror) views using
isSourceView, passing the correspondingEditorViewinstances intoRawTemplateMarkdownToolbarandRichTemplateMarkdownToolbarviaonEditorViewReady. Helper pane toggle state is shared across modes, and the consolidatedErrorBanneruses the adjusted diagnostics. Overall, the architecture matches the stated Default/Raw mode objectives.workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/utils/templateUtils.ts (2)
217-233: List toggle behavior change for blank lines makes senseRequiring
trimmed !== ""in theallListedcheck avoids treating empty lines as list items when deciding whether to strip list formatting. This should reduce surprising mass un-listing when selections include blank lines.
348-384: Code is correct — no changes neededCodeMirror 6 exports
undoandredoas StateCommand functions callable with an EditorView, andundoDepth/redoDepthas(state: EditorState) => number. The code correctly callsundo(view)andredo(view)from UI handlers and usesundoDepth(view.state)andredoDepth(view.state)to check availability. All API signatures match the implementation.workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/CodeUtils.ts (2)
407-475: Diagnostics-aware chip rendering in CodeMirror looks correct and efficientRecomputing decorations only when the doc, tokens, or diagnostics change, and using
findDiagnosticForRangewith simple overlap checks, is a good balance between accuracy and cost. Passing the resolved{ severity, message }intocreateChipgives you consistent visuals (background, border, icon, underline, tooltip) with the ProseMirror chips.
320-342: LSP-style range → CodeMirror position mapping verified as correctLSP ranges use 0-based line numbers, while CodeMirror 6's
doc.line(n)expects 1-based input. The code correctly converts by adding 1 when callingdoc.line(startLine + 1)/doc.line(endLine + 1), consistent with the standard LSP-to-CodeMirror 6 conversion pattern. Line clamping is also correct. No issues found.workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx (2)
235-274: Bug: cursor position forextractArgsFromFunctionis incorrect inside string templatesIn
onHelperItemSelect, whennewValuematches a${...}template,cursorPositionForExtractionis computed asprefix.length + functionDef.length - 1but then passed together withfunctionDefalone intoextractArgsFromFunction. For a value like${func()}, this yields an index beyond the end of"func()", which can break argument extraction.You likely want the cursor index relative to
functionDefonly. For example:- let cursorPositionForExtraction = prefix.length + functionDef.length - 1; + let cursorPositionForExtraction = functionDef.length - 1; if (functionDef.endsWith(')}')) { cursorPositionForExtraction -= 1; }This keeps the cursor inside the function definition string regardless of surrounding template prefix/suffix.
Likely an incorrect or invalid review comment.
404-499: Verify undo/redo and selection behavior with chip transformationsThe code correctly marks appended chip transactions with
addToHistory: falseand handles position mapping during text-to-chip replacement via reverse-order application. However, ProseMirror's history plugin attempts to account for mappings, but it's easy to run into edge cases when skipping history entries.Your implementation relies on implicit selection mapping after replacements apply. While the reverse-order replacement strategy helps preserve positions during the transformation, small differences in step order or appended transactions can produce subtle bugs (caret jumps or inability to undo).
Recommend testing:
- Undo/redo flows after chip insertion/modification
- Caret placement before, during, and after chip transformations
- Multi-step edits followed by undo to verify history consistency
- Edge cases like cursor positioned at chip boundaries
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/chipPlugin.ts (1)
245-423: Explicitly handle the case whereplainTextis not found inwrappedTextThe code at line 403-407 assumes that
plainTextis always a substring ofwrappedText(derived fromrawExpression(plainText)). WhenwrappedText.indexOf(plainText)returns-1, the conditionprefixLength > 0is false, so token position adjustment is silently skipped. This leaves tokens in wrapped-text coordinates, potentially misaligning chip placement.Since
rawExpressionis a custom transformation prop, it could theoretically produce output whereplainTextis not a substring. Add an explicit check for the-1case:const prefixLength = wrappedText.indexOf(plainText); if (prefixLength > 0) { parsedTokens = parsedTokens.map(token => ({...})); } else if (prefixLength === -1) { // Handle: plainText not found in wrappedText - validate, log, or fallback }Alternatively, validate that the prefix/suffix wrapper is still present before applying the adjustment, per ProseMirror offset-mapping patterns.
⛔ Skipped due to learnings
Learnt from: KCSAbeywickrama Repo: wso2/vscode-extensions PR: 998 File: workspaces/ballerina/data-mapper/src/components/DataMapper/Header/ExpressionBar.tsx:113-132 Timestamp: 2025-11-24T14:51:49.207Z Learning: In workspaces/ballerina/data-mapper/src/components/DataMapper/Header/ExpressionBar.tsx, if `textFieldRef.current` is not undefined, `textFieldRef.current.inputElement` is guaranteed to exist. If `inputElement` doesn't exist when `current` exists, it's a fatal error that should reach the error boundary rather than being handled with defensive null checks.
...na-side-panel/src/components/editors/ExpandedEditor/controls/RichTemplateMarkdownToolbar.tsx
Show resolved
Hide resolved
...ide-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/CodeUtils.ts
Outdated
Show resolved
Hide resolved
...s/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/ChipExpressionEditor.tsx
Outdated
Show resolved
Hide resolved
.../src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/markdownCommands.ts
Outdated
Show resolved
Hide resolved
...mponents/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx
Outdated
Show resolved
Hide resolved
...mponents/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx
Show resolved
Hide resolved
workspaces/ballerina/ballerina-side-panel/src/components/Form/utils.ts
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
♻️ Duplicate comments (4)
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/ChipExpressionEditor.tsx (1)
100-101: Helper pane Escape handling still depends on stale state from initial renderEven though the toggle behavior was refactored to use a functional
setHelperPaneState, the keymap still receivesgetIsHelperPaneOpen: () => helperPaneState.isOpenat editor initialization time. Because theEditorState(and thus the keymap) is created only once in theuseEffect([]), thegetIsHelperPaneOpenclosure will always see the initialhelperPaneStatevalue. As a result, the"Escape"binding insidebuildHelperPaneKeymapmay never callonClose()while the editor has focus, making Escape unreliable for closing the helper pane.You can keep the current keymap API but route
getIsHelperPaneOpenthrough a ref that is kept up to date wheneverhelperPaneState.isOpenchanges:- const savedSelectionRef = useRef<{ from: number; to: number } | null>(null); - const lintCompartment = useRef(new Compartment()); + const savedSelectionRef = useRef<{ from: number; to: number } | null>(null); + const lintCompartment = useRef(new Compartment()); + const helperPaneOpenRef = useRef(helperPaneState.isOpen); @@ - const helperPaneKeymap = buildHelperPaneKeymap( - () => helperPaneState.isOpen, + const helperPaneKeymap = buildHelperPaneKeymap( + () => helperPaneOpenRef.current, () => { setHelperPaneState(prev => ({ ...prev, isOpen: false })); }, handleHelperPaneKeyboardToggle ); @@ - // Expose helper pane state to parent component - useEffect(() => { - if (props.onHelperPaneStateChange) { + // Expose helper pane state to parent component + useEffect(() => { + helperPaneOpenRef.current = helperPaneState.isOpen; + if (props.onHelperPaneStateChange) { props.onHelperPaneStateChange({ isOpen: helperPaneState.isOpen, ref: helperPaneToggleButtonRef, toggle: handleHelperPaneManualToggle }); } }, [helperPaneState.isOpen]);This keeps the CodeMirror keymap using up‑to‑date open/closed state without needing to rebuild the editor, and ensures the
"Escape"handler works consistently.Also applies to: 167-199, 201-207, 305-313
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RawTemplateMarkdownToolbar.tsx (1)
190-207: Toolbar-triggered commands don’t force a toolbar state refresh
forceUpdateis only wired to DOM events oneditorView.dom(input,click,keyup). When users trigger changes via the toolbar (undo/redo, headings, lists, formatting), those events happen on the toolbar buttons, not the editor element, soisUndoAvailable/isRedoAvailable(and any future state you derive) may stay stale until the user next interacts inside the editor.You can mirror the rich toolbar pattern by forcing an update after successful commands, e.g.:
- const handleBold = () => insertMarkdownFormatting(editorView, '**'); + const handleBold = () => { + if (!editorView) return; + insertMarkdownFormatting(editorView, '**'); + forceUpdate(); + editorView.focus(); + };and similarly for italic, link, quote, lists, headings, undo/redo, etc.
Also applies to: 223-244, 266-383
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RichTemplateMarkdownToolbar.tsx (1)
233-240: Command execution helper now keeps toolbar state in sync
executeCommandcaptures the command’s boolean result and callsforceUpdate()on success before refocusing the editor. This resolves the stale active-state issue for bold/italic/headings/lists/undo-redo after toolbar-triggered changes.workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx (1)
563-568: Externalvaluechanges still don’t trigger token refresh due topendingTokenFetchRefguard
fetchAndUpdateTokensreturns early whenpendingTokenFetchRef.currentisfalse, but the[value]effect calls it without setting the flag. This means external updates tovalue(e.g., mode switches, resets) won’t re-tokenize the document, so chips can get out of sync with the displayed content.You can align this with the initialization/undo-redo path by setting the flag before calling:
- useEffect(() => { - if (viewRef.current) { - fetchAndUpdateTokens(viewRef.current); - } - }, [value]); + useEffect(() => { + if (viewRef.current) { + pendingTokenFetchRef.current = true; + fetchAndUpdateTokens(viewRef.current); + } + }, [value]);
🧹 Nitpick comments (5)
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/ChipExpressionEditor.tsx (1)
214-220: Comment and selection behavior are now out of syncThe comment still mentions “Use saved selection if available”, but
onHelperItemSelectnow always uses the current selection (view.state.selection.main), and thesavedSelectionRefis no longer consulted.Either restore the saved‑selection behavior (if it’s still desired UX) or update the comment and remove
savedSelectionRefto reflect the current, simpler semantics.workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RawTemplateMarkdownToolbar.tsx (1)
37-167: Shared toolbar styling is duplicated across Raw and Rich toolbarsThe styled components (
ToolbarContainer,ToolbarButton, split-button pieces, dropdown, etc.) appear identical in both RawTemplateMarkdownToolbar and RichTemplateMarkdownToolbar. Consider extracting them into a small shared module (e.g.,TemplateToolbar.styles.ts) to avoid drift and simplify future visual changes.workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RichTemplateMarkdownToolbar.tsx (1)
233-240: TightenexecuteCommandtyping to use ProseMirror’sCommandThe
commandparameter is currently typed withanyforstate,dispatch, andview. You can improve type safety and editor tooling by using theCommandtype fromprosemirror-state:-import { - toggleBold, - ... - canRedo -} from "../../MultiModeExpressionEditor/RichTextTemplateEditor/markdownCommands"; +import { + toggleBold, + ... + canRedo +} from "../../MultiModeExpressionEditor/RichTextTemplateEditor/markdownCommands"; +import { Command } from "prosemirror-state"; - const executeCommand = (command: (state: any, dispatch?: any, view?: any) => boolean) => { + const executeCommand = (command: Command) => { if (!editorView) return; const didChange = command(editorView.state, editorView.dispatch, editorView); if (didChange) { forceUpdate(); } editorView.focus(); };This keeps the helper aligned with ProseMirror’s API surface.
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx (2)
479-487: Escape key handler in keymap still closes over stalehelperPaneStateUnlike
handleHelperPaneKeyboardToggle, the"Escape"binding in the keymap plugin readshelperPaneState.isOpenfrom a closure created in the empty‑depsuseEffect. That value never updates, so the keymap may never actually see the pane as open, depending on how ProseMirror orders key handling versus the document‑level Escape listener.You can avoid the stale closure by relying solely on the state updater, similar to the Mod‑/ handler:
- "Escape": () => { - if (helperPaneState.isOpen) { - setHelperPaneState(prev => ({ ...prev, isOpen: false })); - return true; - } - return false; - } + "Escape": () => { + let handled = false; + setHelperPaneState(prev => { + if (!prev.isOpen) { + return prev; + } + handled = true; + return { ...prev, isOpen: false }; + }); + return handled; + }This keeps the plugin self‑contained and ensures it always acts on the latest open/closed state.
195-196:toolbarRefis never attached to a DOM element, making the toolbar “inside click” check ineffective
toolbarRefis created and used inhandleClickOutsideviatoolbarRef.current?.contains(target), but it is never passed to any JSX element in this component (and not exposed via props). As a result,isClickInsideToolbaris alwaysfalse, so clicks on the toolbar will be treated as “outside” and close the helper pane, regardless of the intent behind this check.Either wire
toolbarRefto the actual toolbar element (likely via a prop from the parent) or remove thetoolbarRef/isClickInsideToolbarbranch to avoid misleading logic:- const toolbarRef = useRef<HTMLDivElement>(null); + // Optional: inject a toolbar ref from the parent if toolbar clicks + // should not close the helper pane, or remove toolbarRef entirely + // if that behavior is no longer desired.and adjust
handleClickOutsideaccordingly.Also applies to: 570-591
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RawTemplateMarkdownToolbar.tsx(1 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RichTemplateMarkdownToolbar.tsx(1 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/ChipExpressionEditor.tsx(9 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx(1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-11-20T11:04:33.712Z
Learnt from: KCSAbeywickrama
Repo: wso2/vscode-extensions PR: 898
File: workspaces/ballerina/data-mapper/src/components/DataMapper/SidePanel/QueryClauses/ClausesPanel.tsx:38-38
Timestamp: 2025-11-20T11:04:33.712Z
Learning: In workspaces/ballerina/data-mapper/src/components/DataMapper/SidePanel/QueryClauses/ClausesPanel.tsx, the use of `useDMQueryClausesPanelStore.getState()` to access `clauseToAdd` and `setClauseToAdd` (instead of the hook subscription pattern) is intentional to prevent re-renders when these state values change.
Applied to files:
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx
🧬 Code graph analysis (3)
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/ChipExpressionEditor.tsx (2)
workspaces/ballerina/ballerina-core/src/interfaces/bi.ts (1)
DiagnosticMessage(165-174)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/CodeUtils.ts (4)
buildHelperPaneKeymap(716-735)buildLintingExtension(737-763)diagnosticsField(250-262)diagnosticsChangeEffect(239-239)
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx (5)
workspaces/common-libs/ui-toolkit/src/components/ExpressionEditor/constants/form.ts (1)
HELPER_PANE_WIDTH(21-21)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/chipPlugin.ts (3)
chipSchema(121-121)createChipSchema(112-119)updateChipTokens(455-458)workspaces/ballerina/ballerina-side-panel/src/context/form.tsx (1)
useFormContext(70-70)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/CodeUtils.ts (1)
chipPlugin(407-485)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/markdownCommands.ts (7)
toggleBold(28-30)toggleItalic(32-34)toggleLink(40-59)toggleHeading(61-71)toggleBlockquote(77-83)toggleBulletList(85-93)toggleOrderedList(95-103)
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RichTemplateMarkdownToolbar.tsx (1)
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/markdownCommands.ts (8)
toggleHeading(61-71)isMarkActive(105-111)isNodeActive(113-123)isListActive(125-139)canUndo(149-151)canRedo(153-155)undoCommand(141-143)redoCommand(145-147)
🔇 Additional comments (2)
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/ChipExpressionEditor.tsx (2)
38-42: Diagnostics prop + linting compartment wiring look correctThe introduction of
formDiagnostics, the dedicatedlintCompartment, and the combination ofbuildLintingExtensionwithdiagnosticsField/diagnosticsChangeEffectis a solid way to keep editor linting in sync with form-level diagnostics without recreating the whole editor state. The initial compartment configuration inEditorState.createand the follow‑upuseEffectthat reconfigures the compartment and updates the diagnostics field whenprops.formDiagnosticschanges both look consistent and side‑effect free.No changes needed from my side; just ensure upstream callers always pass fresh arrays (or new references) when diagnostics change so that the
useEffectreliably fires.If you want to double‑check CodeMirror API usage across versions, you can verify that
Compartment.reconfigurestill accepts either a singleExtensionor anExtension[], and thatlinterfrom@codemirror/lintis compatible with the currentEditorStateversion being used in this repo.Also applies to: 50-50, 97-98, 114-114, 333-336, 339-339, 433-445
485-493: Nice UX touch on helper toggle button titleAdding the
"Toggle Helper Panel (Ctrl+/ or Cmd+/)"title makes the keyboard shortcut discoverable and aligns with the new keymap behavior. No issues here.
...ina-side-panel/src/components/editors/ExpandedEditor/controls/RawTemplateMarkdownToolbar.tsx
Show resolved
Hide resolved
...na-side-panel/src/components/editors/ExpandedEditor/controls/RichTemplateMarkdownToolbar.tsx
Show resolved
Hide resolved
9a9799a to
f0a7d4b
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Nitpick comments (2)
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/CodeUtils.ts (1)
608-626: Helper pane keymap toggle wiring is correct; double‑check shortcut choiceThe optional
onTogglehandling and array spread pattern are sound and will only register the Cmd/Ctrl-/ binding when needed. One thing to double‑check is whether overriding Cmd/Ctrl-/ inside this editor is acceptable, since many users expect that key for “toggle line comment”. If that global behavior is important in this context, you might want to pick a less overloaded key or control the keymap ordering so this binding doesn’t unintentionally shadow comment toggling.workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/TemplateMode.tsx (1)
38-40: Fragile selector relying on CodeMirror internal class naming.The
.ͼ1class is an internal CodeMirror class that may change across versions. Consider using a more stable selector like.cm-editor .cm-scrolleror wrapping the editor in a custom class and targeting it from there.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/TemplateMode.tsx(5 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/CodeUtils.ts(3 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/chipStyles.ts(1 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/ChipExpressionEditor.tsx(6 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
- workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/ChipExpressionEditor.tsx
- workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/chipStyles.ts
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: dan-niles
Repo: wso2/vscode-extensions PR: 980
File: workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx:384-412
Timestamp: 2025-11-24T22:16:28.359Z
Learning: In the RichTextTemplateEditor component (workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx), token fetching on external `value` prop changes is intentionally disabled. Users cannot edit both the minimized and expanded editors simultaneously, so tokens only need to be generated based on user typing in the expanded editor view, not on external prop updates.
📚 Learning: 2025-11-24T22:16:28.359Z
Learnt from: dan-niles
Repo: wso2/vscode-extensions PR: 980
File: workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx:384-412
Timestamp: 2025-11-24T22:16:28.359Z
Learning: In the RichTextTemplateEditor component (workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx), token fetching on external `value` prop changes is intentionally disabled. Users cannot edit both the minimized and expanded editors simultaneously, so tokens only need to be generated based on user typing in the expanded editor view, not on external prop updates.
Applied to files:
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/CodeUtils.tsworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/TemplateMode.tsx
📚 Learning: 2025-11-24T14:51:49.207Z
Learnt from: KCSAbeywickrama
Repo: wso2/vscode-extensions PR: 998
File: workspaces/ballerina/data-mapper/src/components/DataMapper/Header/ExpressionBar.tsx:113-132
Timestamp: 2025-11-24T14:51:49.207Z
Learning: In workspaces/ballerina/data-mapper/src/components/DataMapper/Header/ExpressionBar.tsx, if `textFieldRef.current` is not undefined, `textFieldRef.current.inputElement` is guaranteed to exist. If `inputElement` doesn't exist when `current` exists, it's a fatal error that should reach the error boundary rather than being handled with defensive null checks.
Applied to files:
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/TemplateMode.tsx
🔇 Additional comments (2)
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/CodeUtils.ts (1)
22-27: Import additions look fineThe added imports for CodeMirror commands/types integrate cleanly with the existing module and don’t introduce any obvious issues. Nothing to change here.
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/TemplateMode.tsx (1)
89-154: LGTM!The conditional rendering logic for switching between source view (CodeMirror + RawTemplateMarkdownToolbar) and rich text view (ProseMirror + RichTemplateMarkdownToolbar) is well-structured. The editor view references and toolbar refs are correctly wired to their respective components.
.../ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/TemplateMode.tsx
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (5)
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/chipPlugin.ts (3)
184-212: Early exit infindDocPositionmay skip valid positions.The
docPos > 0check at line 194 causes premature exit when the target position happens to be at the start of a text node (pos = 0 is valid). This could cause incorrect position mapping for tokens starting at document position 0.Consider using a sentinel value or boolean flag instead:
function findDocPosition(doc: any, textOffset: number): number { // Clamp offset to valid range if (textOffset <= 0) return 0; if (textOffset >= doc.textContent.length) return doc.content.size; let charCount = 0; - let docPos = 0; + let docPos: number | null = null; doc.descendants((node: any, pos: number) => { // If we've found the position, stop traversing - if (docPos > 0) return false; + if (docPos !== null) return false; if (node.isText) { const textLength = node.text.length; if (charCount + textLength >= textOffset) { // This text node contains our target offset docPos = pos + (textOffset - charCount); return false; } charCount += textLength; } return true; }); - return docPos || 0; + return docPos ?? 0; }
214-220: Consider adding explicit types instead ofany.The
trparameter andnodein the replacements array useanytype. Using proper ProseMirror types would improve type safety and IDE support.+import { Transaction } from 'prosemirror-state'; +import { Node } from 'prosemirror-model'; function replaceTextWithChips( - tr: any, + tr: Transaction, schema: Schema, tokens: ParsedToken[], compounds: CompoundTokenSequence[], plainText: string -): any { +): Transaction { const docLength = plainText.length; - const replacements: Array<{ from: number; to: number; node: any }> = []; + const replacements: Array<{ from: number; to: number; node: Node }> = [];
424-427: Consider typing theviewparameter.The
updateChipTokensfunction usesanyfor the view parameter. UsingEditorViewfrom prosemirror-view would improve type safety.+import { EditorView } from 'prosemirror-view'; -export function updateChipTokens(view: any, tokenUpdate: TokenUpdate) { +export function updateChipTokens(view: EditorView, tokenUpdate: TokenUpdate) { const tr = view.state.tr.setMeta(chipPluginKey, tokenUpdate); view.dispatch(tr); }workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/TemplateMode.tsx (1)
146-151: Consider improving multi-error display readability.When multiple diagnostics exist, joining messages with a comma may reduce readability. Consider using line breaks or a more structured format.
formDiagnostics && formDiagnostics.length > 0 && - <ErrorBanner sx={{ maxHeight: "50px", overflowY: "auto" }} errorMsg={formDiagnostics.map(d => { - return d.message; - }).join(', ')} /> + <ErrorBanner + sx={{ maxHeight: "50px", overflowY: "auto" }} + errorMsg={formDiagnostics.map(d => d.message).join(' • ')} + /> }Alternatively, if more space is available, consider displaying each error on a separate line.
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RawTemplateMarkdownToolbar.tsx (1)
341-352: Heading dropdown keyboard navigation could be enhanced.The dropdown items have
focus-visiblestyles but lack arrow key navigation between options. Consider adding keyboard navigation for improved accessibility.For enhanced accessibility, consider adding arrow key navigation within the dropdown menu to allow users to navigate between heading levels using keyboard only. This is a nice-to-have improvement that could be addressed in a follow-up.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RawTemplateMarkdownToolbar.tsx(1 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RichTemplateMarkdownToolbar.tsx(1 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/TemplateMode.tsx(5 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/chipPlugin.ts(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RichTemplateMarkdownToolbar.tsx
🧰 Additional context used
🧠 Learnings (4)
📓 Common learnings
Learnt from: dan-niles
Repo: wso2/vscode-extensions PR: 980
File: workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx:384-412
Timestamp: 2025-11-24T22:16:28.359Z
Learning: In the RichTextTemplateEditor component (workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx), token fetching on external `value` prop changes is intentionally disabled. Users cannot edit both the minimized and expanded editors simultaneously, so tokens only need to be generated based on user typing in the expanded editor view, not on external prop updates.
📚 Learning: 2025-11-24T22:16:28.359Z
Learnt from: dan-niles
Repo: wso2/vscode-extensions PR: 980
File: workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx:384-412
Timestamp: 2025-11-24T22:16:28.359Z
Learning: In the RichTextTemplateEditor component (workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx), token fetching on external `value` prop changes is intentionally disabled. Users cannot edit both the minimized and expanded editors simultaneously, so tokens only need to be generated based on user typing in the expanded editor view, not on external prop updates.
Applied to files:
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/chipPlugin.tsworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/TemplateMode.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RawTemplateMarkdownToolbar.tsx
📚 Learning: 2025-11-20T11:04:33.712Z
Learnt from: KCSAbeywickrama
Repo: wso2/vscode-extensions PR: 898
File: workspaces/ballerina/data-mapper/src/components/DataMapper/SidePanel/QueryClauses/ClausesPanel.tsx:38-38
Timestamp: 2025-11-20T11:04:33.712Z
Learning: In workspaces/ballerina/data-mapper/src/components/DataMapper/SidePanel/QueryClauses/ClausesPanel.tsx, the use of `useDMQueryClausesPanelStore.getState()` to access `clauseToAdd` and `setClauseToAdd` (instead of the hook subscription pattern) is intentional to prevent re-renders when these state values change.
Applied to files:
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/TemplateMode.tsx
📚 Learning: 2025-11-24T14:51:49.207Z
Learnt from: KCSAbeywickrama
Repo: wso2/vscode-extensions PR: 998
File: workspaces/ballerina/data-mapper/src/components/DataMapper/Header/ExpressionBar.tsx:113-132
Timestamp: 2025-11-24T14:51:49.207Z
Learning: In workspaces/ballerina/data-mapper/src/components/DataMapper/Header/ExpressionBar.tsx, if `textFieldRef.current` is not undefined, `textFieldRef.current.inputElement` is guaranteed to exist. If `inputElement` doesn't exist when `current` exists, it's a fatal error that should reach the error boundary rather than being handled with defensive null checks.
Applied to files:
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/TemplateMode.tsx
🧬 Code graph analysis (2)
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/chipPlugin.ts (3)
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/types.ts (2)
TokenMetadata(63-67)CompoundTokenSequence(89-97)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/chipStyles.ts (5)
getChipDisplayContent(107-109)BASE_CHIP_STYLES(22-37)getTokenIconClass(92-97)BASE_ICON_STYLES(39-42)CHIP_TEXT_STYLES(44-48)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/utils.ts (3)
ParsedToken(104-109)getParsedExpressionTokens(111-137)detectTokenPatterns(277-331)
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/TemplateMode.tsx (3)
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RawTemplateMarkdownToolbar.tsx (1)
RawTemplateMarkdownToolbar(179-401)workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RichTemplateMarkdownToolbar.tsx (1)
RichTemplateMarkdownToolbar(184-430)workspaces/common-libs/ui-toolkit/src/components/Commons/ErrorBanner.tsx (1)
ErrorBanner(46-55)
🔇 Additional comments (10)
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/chipPlugin.ts (2)
336-350: Token comparison viaJSON.stringifymay be slow for large token arrays.For documents with many tokens, serializing the entire token array on every state change could impact performance. Consider using a hash or incremental comparison if performance becomes a concern.
The current implementation is functionally correct and should work well for typical use cases. Monitor performance with larger documents.
61-94: Well-structured chip DOM serialization.The
toDOMimplementation correctly handles chip rendering with icon and text children, and theparseDOMproperly extracts attributes from the DOM. The use of data attributes for storing chip metadata is a clean approach.workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/TemplateMode.tsx (3)
56-65: Clean dual-view state management.The separation of
codeMirrorViewandproseMirrorViewstates, along with dedicated toolbar refs for each mode, provides a clear architecture for the dual-view editing experience.
84-106: Toolbar view toggle wiring looks correct.The conditional toolbar rendering properly passes the corresponding editor view (
codeMirrorViewfor Raw,proseMirrorViewfor Rich) and maintains consistent props across both toolbars.
128-144: RichTextTemplateEditor integration is well-structured.The component properly passes all necessary props and correctly wires up the editor lifecycle callbacks (
onEditorViewReady,onHelperPaneStateChange) to update parent state.workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RawTemplateMarkdownToolbar.tsx (5)
190-207: Event listeners properly cleaned up.The effect correctly attaches and removes DOM event listeners when the editor view changes, preventing memory leaks.
209-221: Efficient dropdown close behavior.The click-outside handler only registers when the dropdown is open, avoiding unnecessary event listeners. The cleanup in the return function prevents memory leaks.
223-243: Focus preservation pattern correctly implemented.Using
e.preventDefault()inhandleMouseDownprevents toolbar buttons from stealing focus from the editor, which is essential for a good UX. The formatting handlers are cleanly implemented.
37-88: Well-organized styled components with consistent theming.The styled components use
ThemeColorsconsistently and include proper states (hover, active, disabled, focus-visible). The responsive flex-wrap ensures the toolbar adapts to different container widths.
403-403: Good practice: displayName set for debugging.Setting
displayNameon forwardRef components ensures the component name appears correctly in React DevTools, improving debugging experience.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (3)
workspaces/ballerina/ballerina-visualizer/src/views/BI/HelperPaneNew/utils/utils.ts (1)
21-24: PROMPT interpolation behavior matches TEMPLATE; update comment for clarityExtending
wrapInTemplateInterpolationto treatInputMode.PROMPTlikeTEMPLATEis consistent with the rest of the PR. The only nit is the comment still saying “template mode” only—consider updating it to mention PROMPT as well to avoid confusion later.workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/TemplateMode.tsx (1)
19-41: Rich/source view split and toolbar wiring look solid; consider functional toggleThe new
TemplateModesplit between:
- rich view:
RichTemplateMarkdownToolbar+RichTextTemplateEditor- source view:
RawTemplateMarkdownToolbar+ChipExpressionEditorComponentis wired cleanly: editor views are captured via
onEditorViewReady, passed back into the corresponding toolbar, and the helper-pane toggle flows throughhandleHelperPaneStateChange.One small robustness tweak:
handleToggleViewcurrently does:const handleToggleView = () => { setIsSourceView(!isSourceView); };Switching to a functional update avoids any chance of stale closures during rapid toggles:
const handleToggleView = () => { setIsSourceView(prev => !prev); };Also applies to: 56-66, 84-87, 90-107, 108-145
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionEditor.tsx (1)
823-833: Confirm whether TEMPLATE should still map to ExpandedEditor “template” modeHere:
mode={ inputModeRef.current === InputMode.EXP ? "expression" : inputModeRef.current === InputMode.PROMPT ? "template" : undefined }
InputMode.TEMPLATEnow results inmode === undefined, even though:
- PROMPT is explicitly mapped to
"template".sanitizedExpressionandrawExpressionare always passed toExpandedEditorregardless of mode.If TEMPLATE is still a reachable
InputModehere (e.g., viagetInputModeFromTypes), you might want:mode={ inputModeRef.current === InputMode.EXP ? "expression" : (inputModeRef.current === InputMode.PROMPT || inputModeRef.current === InputMode.TEMPLATE) ? "template" : undefined }If TEMPLATE is intentionally deprecated in this flow and PROMPT is the only “template-like” mode that should open the new editor, a brief comment would help make that intent clear.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/ExpressionMode.tsx(1 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/TemplateMode.tsx(5 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionEditor.tsx(9 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/types.ts(1 hunks)workspaces/ballerina/ballerina-visualizer/src/views/BI/HelperPaneNew/Views/DocumentConfig.tsx(2 hunks)workspaces/ballerina/ballerina-visualizer/src/views/BI/HelperPaneNew/utils/utils.ts(1 hunks)
🧰 Additional context used
🧠 Learnings (4)
📓 Common learnings
Learnt from: dan-niles
Repo: wso2/vscode-extensions PR: 980
File: workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx:384-412
Timestamp: 2025-11-24T22:16:28.359Z
Learning: In the RichTextTemplateEditor component (workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx), token fetching on external `value` prop changes is intentionally disabled. Users cannot edit both the minimized and expanded editors simultaneously, so tokens only need to be generated based on user typing in the expanded editor view, not on external prop updates.
📚 Learning: 2025-11-24T22:16:28.359Z
Learnt from: dan-niles
Repo: wso2/vscode-extensions PR: 980
File: workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx:384-412
Timestamp: 2025-11-24T22:16:28.359Z
Learning: In the RichTextTemplateEditor component (workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx), token fetching on external `value` prop changes is intentionally disabled. Users cannot edit both the minimized and expanded editors simultaneously, so tokens only need to be generated based on user typing in the expanded editor view, not on external prop updates.
Applied to files:
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/TemplateMode.tsxworkspaces/ballerina/ballerina-visualizer/src/views/BI/HelperPaneNew/Views/DocumentConfig.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionEditor.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/ExpressionMode.tsx
📚 Learning: 2025-11-20T11:04:33.712Z
Learnt from: KCSAbeywickrama
Repo: wso2/vscode-extensions PR: 898
File: workspaces/ballerina/data-mapper/src/components/DataMapper/SidePanel/QueryClauses/ClausesPanel.tsx:38-38
Timestamp: 2025-11-20T11:04:33.712Z
Learning: In workspaces/ballerina/data-mapper/src/components/DataMapper/SidePanel/QueryClauses/ClausesPanel.tsx, the use of `useDMQueryClausesPanelStore.getState()` to access `clauseToAdd` and `setClauseToAdd` (instead of the hook subscription pattern) is intentional to prevent re-renders when these state values change.
Applied to files:
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/TemplateMode.tsx
📚 Learning: 2025-11-24T14:51:49.207Z
Learnt from: KCSAbeywickrama
Repo: wso2/vscode-extensions PR: 998
File: workspaces/ballerina/data-mapper/src/components/DataMapper/Header/ExpressionBar.tsx:113-132
Timestamp: 2025-11-24T14:51:49.207Z
Learning: In workspaces/ballerina/data-mapper/src/components/DataMapper/Header/ExpressionBar.tsx, if `textFieldRef.current` is not undefined, `textFieldRef.current.inputElement` is guaranteed to exist. If `inputElement` doesn't exist when `current` exists, it's a fatal error that should reach the error boundary rather than being handled with defensive null checks.
Applied to files:
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/TemplateMode.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionEditor.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/ExpressionMode.tsx
🧬 Code graph analysis (5)
workspaces/ballerina/ballerina-visualizer/src/views/BI/HelperPaneNew/utils/utils.ts (1)
workspaces/ballerina/ballerina-side-panel/src/components/editors/index.ts (1)
InputMode(31-31)
workspaces/ballerina/ballerina-visualizer/src/views/BI/HelperPaneNew/Views/DocumentConfig.tsx (1)
workspaces/ballerina/ballerina-side-panel/src/components/editors/index.ts (1)
InputMode(31-31)
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionEditor.tsx (1)
workspaces/ballerina/ballerina-side-panel/src/components/editors/index.ts (1)
InputMode(31-31)
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/types.ts (1)
workspaces/ballerina/ballerina-side-panel/src/components/editors/index.ts (1)
InputMode(31-31)
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/ExpressionMode.tsx (1)
workspaces/common-libs/ui-toolkit/src/components/Commons/ErrorBanner.tsx (1)
ErrorBanner(46-55)
🔇 Additional comments (4)
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/types.ts (1)
19-30: PROMPT mode wiring into InputMode and INPUT_MODE_MAP looks correctAdding
InputMode.PROMPT = "Prompt"and mapping"ai:Prompt"to it fits the new prompt-editor semantics and keeps TEMPLATE available for other uses. No issues from a type or behavior perspective.workspaces/ballerina/ballerina-visualizer/src/views/BI/HelperPaneNew/Views/DocumentConfig.tsx (1)
147-179: Verify intentional difference between PROMPT vs TEMPLATE for hardcoded URLsIn
handleItemSelectyou treat template mode as:const isTemplateMode = inputMode === InputMode.PROMPT || inputMode === InputMode.TEMPLATE;but in
URLInputModal.handleCreateyou now have:const isTemplateMode = inputMode === InputMode.PROMPT;So:
- For variable selections, both PROMPT and TEMPLATE can yield
${...}-wrapped document expressions.- For “Insert Hardcoded URL”, only PROMPT gets interpolation; TEMPLATE now inserts a bare
<DocType>{content: "..."}.If TEMPLATE is still expected to behave like PROMPT here, this might be an accidental divergence; if not, a short comment explaining why URLs are PROMPT-only interpolated would help avoid future regressions.
Also applies to: 210-217
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/ExpressionMode.tsx (1)
71-75: Scrollable error banner is a good UX safeguardCapping the error area and enabling vertical scrolling on
ErrorBannerkeeps long messages from overwhelming the editor surface while still being accessible. The change is self-contained and looks correct.workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionEditor.tsx (1)
411-435: PROMPT handling is consistently aligned with TEMPLATE across editor flowsThe additions that treat PROMPT like TEMPLATE look coherent:
fieldValuenow usesrawExpressionwheninputModeRef.currentis PROMPT or TEMPLATE, so diagnostics and initial validation see the underlying expression rather than the sanitized view.- Initial diagnostics and subsequent
getExpressionEditorDiagnosticscalls now gate oninputMode/currentModebeingEXP | PROMPT | TEMPLATE, which keeps validation active in all three modes.- Mode initialization via
getInputModeFromTypesconsiders PROMPT/TEMPLATE together and only opts into them whensanitizedExpression/rawExpressionare available and actually change the initial value.- Mode-switch warnings from EXP → PROMPT/TEMPLATE reuse the existing TEMPLATE logic, including the sanitization equality check and warning popup.
- Both inline
ExpressionFieldandExpandedEditoronChange paths computerawValueusingrawExpression(updatedValue)in PROMPT/TEMPLATE modes, and run diagnostics + completions against that raw value.All of this lines up with the new prompt-editor model and keeps PROMPT behavior consistent with TEMPLATE without introducing obvious regressions.
Also applies to: 460-472, 567-583, 595-603, 624-627, 708-721, 788-791
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Nitpick comments (4)
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/LinkDialog.tsx (2)
23-58: Consider adding focus trap for accessibility.The modal lacks a focus trap, which means users can tab out of the dialog to elements behind the overlay. For accessibility compliance, modal dialogs should trap focus within themselves until closed.
Additionally, consider adding
role="dialog"andaria-modal="true"toPopupBoxfor screen reader support.-const PopupBox = styled.div` +const PopupBox = styled.div.attrs({ + role: 'dialog', + 'aria-modal': 'true', + 'aria-labelledby': 'link-dialog-title' +})` width: 400px;And update the header title:
<Typography id="link-dialog-title" variant="h3" sx={{ margin: 0 }}> Create a link </Typography>
143-150: Consider adding basic URL validation.The URL field only trims whitespace but doesn't validate the format. Users could submit invalid URLs (e.g., "abc" instead of "https://example.com"). Consider adding minimal validation or at least a protocol prefix suggestion.
const handleInsert = () => { - if (!url.trim()) return; - onInsert(url.trim(), title.trim() || undefined); + let trimmedUrl = url.trim(); + if (!trimmedUrl) return; + // Add protocol if missing + if (trimmedUrl && !/^https?:\/\//i.test(trimmedUrl)) { + trimmedUrl = 'https://' + trimmedUrl; + } + onInsert(trimmedUrl, title.trim() || undefined); handleClose(); };workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/markdownCommands.ts (1)
164-169:canUndo/canRedoimplementation differs from existing pattern in codebase.These functions call
undo(state)andredo(state)without a dispatch function, which works because ProseMirror commands returnfalseif they can't be applied. However, the existingtemplateUtils.tsusesundoDepth(state) > 0andredoDepth(state) > 0, which is more explicit and avoids the ambiguity of calling the actual command function.Consider aligning with the existing pattern for consistency:
+import { undoDepth, redoDepth } from "prosemirror-history"; -export const canUndo = (state: EditorState): boolean => { - return undo(state); -}; +export const canUndo = (state: EditorState): boolean => { + return undoDepth(state) > 0; +}; -export const canRedo = (state: EditorState): boolean => { - return redo(state); -}; +export const canRedo = (state: EditorState): boolean => { + return redoDepth(state) > 0; +};workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RichTemplateMarkdownToolbar.tsx (1)
392-403: Dropdown menu items should have keyboard navigation.The heading dropdown can be opened but lacks keyboard navigation (arrow keys to move between items, Enter to select). Users relying on keyboard navigation may find it difficult to use.
Consider adding
onKeyDownhandler to the dropdown for arrow key navigation and Enter to select:<DropdownMenu isOpen={isHeadingDropdownOpen} onKeyDown={(e) => { if (e.key === 'ArrowDown' || e.key === 'ArrowUp') { // Focus next/previous item } else if (e.key === 'Escape') { setIsHeadingDropdownOpen(false); } }} >
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/LinkDialog.tsx(1 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RichTemplateMarkdownToolbar.tsx(1 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx(1 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/markdownCommands.ts(1 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: dan-niles
Repo: wso2/vscode-extensions PR: 980
File: workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx:384-412
Timestamp: 2025-11-24T22:16:28.359Z
Learning: In the RichTextTemplateEditor component (workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx), token fetching on external `value` prop changes is intentionally disabled. Users cannot edit both the minimized and expanded editors simultaneously, so tokens only need to be generated based on user typing in the expanded editor view, not on external prop updates.
📚 Learning: 2025-11-24T22:16:28.359Z
Learnt from: dan-niles
Repo: wso2/vscode-extensions PR: 980
File: workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx:384-412
Timestamp: 2025-11-24T22:16:28.359Z
Learning: In the RichTextTemplateEditor component (workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx), token fetching on external `value` prop changes is intentionally disabled. Users cannot edit both the minimized and expanded editors simultaneously, so tokens only need to be generated based on user typing in the expanded editor view, not on external prop updates.
Applied to files:
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RichTemplateMarkdownToolbar.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/LinkDialog.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/markdownCommands.ts
🧬 Code graph analysis (3)
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RichTemplateMarkdownToolbar.tsx (6)
workspaces/common-libs/ui-toolkit/src/styles/Theme.ts (1)
ThemeColors(79-104)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/markdownCommands.ts (14)
toggleHeading(76-86)toggleLink(40-74)isMarkActive(120-126)isNodeActive(128-138)isListActive(140-154)canUndo(164-166)canRedo(168-170)undoCommand(156-158)redoCommand(160-162)toggleBold(28-30)toggleItalic(32-34)toggleBlockquote(92-98)toggleBulletList(100-108)toggleOrderedList(110-118)workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/utils/templateUtils.ts (4)
canUndo(373-376)canRedo(381-384)undoCommand(353-358)redoCommand(363-368)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/HelperPaneToggleButton.tsx (1)
HelperPaneToggleButton(82-107)workspaces/common-libs/ui-toolkit/src/components/Swich/Swich.tsx (1)
Switch(146-176)workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/LinkDialog.tsx (1)
LinkDialog(90-175)
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/LinkDialog.tsx (3)
workspaces/common-libs/ui-toolkit/src/styles/Theme.ts (1)
ThemeColors(79-104)workspaces/common-libs/ui-toolkit/src/components/Codicon/Codicon.tsx (1)
Codicon(44-56)workspaces/common-libs/ui-toolkit/src/components/Button/Button.tsx (1)
Button(54-65)
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/markdownCommands.ts (1)
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/utils/templateUtils.ts (4)
undoCommand(353-358)redoCommand(363-368)canUndo(373-376)canRedo(381-384)
🔇 Additional comments (12)
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/LinkDialog.tsx (1)
130-174: LGTM overall structure and UX flow.The dialog implementation correctly handles:
- State reset on open via useEffect
- Enter key to submit (with validation)
- Escape key and overlay click to cancel
- Auto-focus on URL input
- Disabled Insert button when URL is empty
The component integrates well with the toolbar's link insertion workflow.
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx (4)
322-354: Function argument extraction has complex string parsing that may fail on edge cases.The regex
^(.*\$\{)([^}]+)(\}.*)$assumes the closing brace}appears only once. Nested braces or escaped braces could cause incorrect parsing. TheHACKcomment suggests this needs refinement.Consider documenting known limitations or adding tests for edge cases like:
- Nested template expressions:
${foo(${bar})}- Multiple expressions:
${a} and ${b()}
562-567: Token fetch on external value changes intentionally skipped.This aligns with the documented learning that users cannot edit both minimized and expanded editors simultaneously, so tokens only need generation based on user typing. The current implementation is correct.
Based on retrieved learnings from the PR author.
554-560: Cleanup properly destroys ProseMirror view.The cleanup function correctly destroys the EditorView and nullifies the ref, preventing memory leaks.
596-612: Potential duplicate Escape key handling.The global
keydownevent listener ondocument(line 596-603) handles Escape to close the helper pane, but there's also an Escape handler in the ProseMirror keymap (lines 480-486). When the editor has focus, both handlers may fire. The keymap handler has the stale closure issue, so currently it likely doesn't interfere, but once fixed, you may want to coordinate them or consolidate into one handler.Verify that fixing the keymap Escape handler doesn't cause double-close attempts or event propagation issues.
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/markdownCommands.ts (3)
40-74: Link toggle now properly accepts href parameter.The
toggleLinkfunction now takes optionalhrefandtitleparameters, addressing the previous review concern about hardcoded URLs. The implementation correctly:
- Removes existing links when present
- Returns
falseif no href is provided for new links- Handles both selection-based wrapping and cursor insertion with new text
120-154: Helper functions for detecting active marks/nodes are well-implemented.The
isMarkActive,isNodeActive, andisListActivefunctions correctly traverse the document structure and handle edge cases like empty selections (checking stored marks) and attribute matching.
46-51: <!-- [scratchpad_start]
[task verify_as_any_cast_necessity_1/1]
[observations]
- node_modules not available in sandbox environment (cannot access type definitions)
- Web search confirms: addMark() and removeMark() ARE standard Transaction methods in ProseMirror API
- File shows two
as anycasts at lines 50 and 65- prosemirror-state v1.4.3 is installed (per package.json)
- prosemirror-state includes built-in TypeScript definitions (no @types package needed)
- tsconfig.json has noImplicitAny: false (permissive but strict: true overall)
[analysis]- Web search definitively shows these methods exist in the public API
- Cannot verify actual type definitions in v1.4.3 without node_modules access
- Presence in public API does not guarantee types are present in the specific installed version
- If types are available, casts are unnecessary and can be removed
- If types are unavailable, casts may be necessary (though bad practice)
[conclusion]- Cannot make definitive determination without accessing actual installed types
- Verification is inconclusive - need manual verification or testing
- Evidence is mixed: methods exist in API, but actual typing in v1.4.3 is unverifiable in sandbox
[done]- Web search confirms API methods exist
- Cannot access node_modules to verify type definitions
- Per instructions, this warrants tag
</scratchpad_end] -->Verify whether type definitions for
addMarkandremoveMarkexist inprosemirror-state@^1.4.3.The methods
tr.addMark(from, to, mark)andtr.removeMark(from, to, markOrType)are confirmed to exist in ProseMirror's Transaction API. However, whether the type definitions are available in your installed version ofprosemirror-state@^1.4.3cannot be verified in this environment.To resolve this:
- Check if TypeScript compilation succeeds without the
as anycasts by removing them temporarily- If compilation succeeds without errors, the casts are unnecessary and should be removed
- If TypeScript reports type errors, the version of
prosemirror-statemay lack type definitions for these methods and the casts may be neededThe suggested refactor in the review (removing the
as anycasts on lines 50 and 65) is appropriate if the type definitions are available.workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RichTemplateMarkdownToolbar.tsx (4)
235-242: Toolbar state synchronization fixed.The
executeCommandfunction now callsforceUpdate()when the command succeeds, ensuring toolbar active states update immediately after toolbar-triggered commands. This addresses the previously reported issue.
23-38: UnusedtoggleCodeimport has been removed.The import list no longer includes
toggleCode, which aligns with the commented-out inline code button. This resolves the previous review feedback about unused imports.
255-276: Link handling correctly integrates with LinkDialog.The implementation properly:
- Detects existing links and removes them immediately without opening the dialog
- Captures selected text to pre-fill the title field
- Delegates URL input to the dialog component
This provides good UX for both adding and removing links.
439-452: View toggle switch provides clear Default/Raw mode distinction.The Switch component with "Default" and "Raw" labels clearly communicates the editing mode options to users, aligning with the PR objectives of providing a simplified WYSIWYG experience while maintaining access to raw markdown.
...mponents/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (4)
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RichTemplateMarkdownToolbar.tsx (1)
299-310: Orphan divider whenhelperPaneToggleis not provided.The
ToolbarDividerat line 310 renders unconditionally, but theHelperPaneToggleButtononly renders whenhelperPaneToggleis provided. This results in a leading divider with nothing before it when the helper pane toggle is absent.{helperPaneToggle && ( - <HelperPaneToggleButton - ref={helperPaneToggle.ref} - disabled={!editorView} - isOpen={helperPaneToggle.isOpen} - onClick={helperPaneToggle.onClick} - sx={{ marginBottom: 0 }} - title="Toggle Helper Panel (Ctrl+/ or Cmd+/)" - /> + <> + <HelperPaneToggleButton + ref={helperPaneToggle.ref} + disabled={!editorView} + isOpen={helperPaneToggle.isOpen} + onClick={helperPaneToggle.onClick} + sx={{ marginBottom: 0 }} + title="Toggle Helper Panel (Ctrl+/ or Cmd+/)" + /> + <ToolbarDivider /> + </> )} - - <ToolbarDivider />workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/markdownCommands.ts (3)
40-74: Consider removingas anycasts for type safety.The
as anycasts on lines 48 and 67 bypass TypeScript's type checking. ProseMirror'sTransactionextendsTransform, which includesaddMarkandremoveMarkmethods. These casts may indicate outdated type definitions.if (from !== to && state.doc.rangeHasMark(from, to, linkMarkType)) { if (dispatch) { - dispatch((state.tr as any).removeMark(from, to, linkMarkType)); + dispatch(state.tr.removeMark(from, to, linkMarkType)); } return true; }} else { // Has selection: wrap selection with link - (tr as any).addMark(from, to, mark); + tr.addMark(from, to, mark); }If TypeScript still complains, verify
prosemirror-statetypes are up to date, or consider adding a targeted type assertion like(state.tr as Transaction & Transform).
100-114: Consider removingas anycast inconvertListType.Same concern as with link commands –
replaceWithis a method onTransform, so the cast shouldn't be necessary.if ($from.node(d).type === fromListType) { const pos = $from.before(d); const node = $from.node(d); - const tr = (state.tr as any).replaceWith(pos, pos + node.nodeSize, toListType.create(node.attrs, node.content)); + const tr = state.tr.replaceWith(pos, pos + node.nodeSize, toListType.create(node.attrs, node.content)); dispatch(tr.setSelection(state.selection.map(tr.doc, tr.mapping))); return true; }
188-194: PreferundoDepth/redoDepthfor efficiency.Calling
undo(state)andredo(state)without dispatch works but actually computes the undo/redo operation to determine availability. UsingundoDepth/redoDepthfromprosemirror-historyis more efficient, as shown intemplateUtils.ts.+import { undo, redo, undoDepth, redoDepth } from "prosemirror-history"; -import { undo, redo } from "prosemirror-history"; export const canUndo = (state: EditorState): boolean => { - return undo(state); + return undoDepth(state) > 0; }; export const canRedo = (state: EditorState): boolean => { - return redo(state); + return redoDepth(state) > 0; };
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RawTemplateMarkdownToolbar.tsx(1 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RichTemplateMarkdownToolbar.tsx(1 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/markdownCommands.ts(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RawTemplateMarkdownToolbar.tsx
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: dan-niles
Repo: wso2/vscode-extensions PR: 980
File: workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx:384-412
Timestamp: 2025-11-24T22:16:28.380Z
Learning: In the RichTextTemplateEditor component (workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx), token fetching on external `value` prop changes is intentionally disabled. Users cannot edit both the minimized and expanded editors simultaneously, so tokens only need to be generated based on user typing in the expanded editor view, not on external prop updates.
📚 Learning: 2025-11-24T22:16:28.380Z
Learnt from: dan-niles
Repo: wso2/vscode-extensions PR: 980
File: workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx:384-412
Timestamp: 2025-11-24T22:16:28.380Z
Learning: In the RichTextTemplateEditor component (workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx), token fetching on external `value` prop changes is intentionally disabled. Users cannot edit both the minimized and expanded editors simultaneously, so tokens only need to be generated based on user typing in the expanded editor view, not on external prop updates.
Applied to files:
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/markdownCommands.tsworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RichTemplateMarkdownToolbar.tsx
🧬 Code graph analysis (1)
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/markdownCommands.ts (1)
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/utils/templateUtils.ts (4)
undoCommand(353-358)redoCommand(363-368)canUndo(373-376)canRedo(381-384)
🔇 Additional comments (8)
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RichTemplateMarkdownToolbar.tsx (4)
184-214: LGTM – well-structured component setup.The component correctly uses
forwardRef, manages local state for heading level and dropdowns, and the DOM event listeners for toolbar state updates are properly cleaned up in the effect's return function.
235-251: LGTM – command execution and heading handler.
executeCommandcorrectly triggersforceUpdatewhen a command succeeds, keeping toolbar state in sync. ThehandleHeaderfunction properly toggles the heading level and manages dropdown state.
255-276: LGTM – link handling logic.The link button behavior correctly distinguishes between removing an existing link (immediate toggle) and inserting a new link (opens dialog). Pre-filling the title from selected text is a nice UX touch.
374-404: LGTM – split button dropdown implementation.The heading split button with dropdown menu is well implemented. Click-outside handling via
dropdownRefcorrectly closes the menu, andhandleMouseDownprevents focus loss from the editor.workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/markdownCommands.ts (4)
28-38: LGTM – mark toggle commands.Simple, correct wrappers around ProseMirror's
toggleMarkfor bold, italic, and code marks.
76-98: LGTM – heading, paragraph, and blockquote toggles.The
toggleHeadingcommand correctly toggles between heading and paragraph based on active state.toggleBlockquoteproperly usesliftto unwrap andwrapInto wrap.
116-142: LGTM – list toggle commands.The list commands correctly handle three cases: lifting when active, converting between list types, and wrapping in a new list. The logic is sound.
144-178: LGTM – active state query functions.
isMarkActivecorrectly handles both empty selections (storedMarks) and ranges.isNodeActiveandisListActiveproperly traverse the document depth to find matching nodes.
472afd8 to
4e82930
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/types.ts (1)
19-30: Use proper ProseMirror Node type instead ofanyforclickedChipNodeThe INPUT_MODE_MAP completeness concern is not an issue—TEMPLATE and RECORD modes are intentionally not constraint-driven and therefore correctly absent from the mapping. Only modes routed via
getInputModeFromTypes(based on fieldvalueTypeConstraint) need entries; PROMPT is the only constraint-mapped mode currently.However, at line 114 in types.ts,
clickedChipNode?: anyshould be typed asNodefromprosemirror-model. The property holds a ProseMirror node (created viaschema.nodes.chip.create()) and is accessed with.nodeSizeat RichTextTemplateEditor.tsx:245, so tightening the type would improve type safety.import { Node } from 'prosemirror-model'; export type HelperPaneState = { isOpen: boolean; top: number; left: number; clickedChipPos?: number; clickedChipNode?: Node; };
🧹 Nitpick comments (2)
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/utils.ts (1)
334-355: Helper pane positioning: consider clamping left to viewport edge
calculateHelperPanePositionhandles right-side overflow, but whenoverflow > 0andleftis already small,left -= overflowcan push the pane off-screen to the left. Clamping to zero keeps it visible while preserving your current behavior.- if (overflow > 0) { - left -= overflow; - } + if (overflow > 0) { + left = Math.max(left - overflow, 0); + }workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/ChipExpressionEditor.tsx (1)
107-116: Use functionalsetHelperPaneStateupdates to preserve extra state fieldsNow that
HelperPaneStateincludes optional fields likeclickedChipPos/clickedChipNode, the places where you callsetHelperPaneState({ ... })with a fresh object (e.g., in change/focus/selection listeners,onHelperItemSelect, and click‑outside/Escape handlers) will drop any existing extra fields on every update.To keep the new hook’s behavior consistent and future‑proof, it’s safer to always update via the previous state:
- const handleChangeListner = buildOnChangeListner((newValue, cursor) => { + const handleChangeListner = buildOnChangeListner((newValue, cursor) => { @@ - if (newValue === '' || isTrigger || isRangeSelection) { - setHelperPaneState({ isOpen: true, top: cursor.top, left: cursor.left }); - } else { - setHelperPaneState({ isOpen: false, top: 0, left: 0 }); - } + if (newValue === '' || isTrigger || isRangeSelection) { + setHelperPaneState(prev => ({ ...prev, isOpen: true, top: cursor.top, left: cursor.left })); + } else { + setHelperPaneState(prev => ({ ...prev, isOpen: false, top: 0, left: 0 })); + } }); @@ - const handleFocusListner = buildOnFocusListner((cursor: CursorInfo) => { - setHelperPaneState({ isOpen: true, top: cursor.top, left: cursor.left }); - }); + const handleFocusListner = buildOnFocusListner((cursor: CursorInfo) => { + setHelperPaneState(prev => ({ ...prev, isOpen: true, top: cursor.top, left: cursor.left })); + }); @@ - const handleSelectionChange = buildOnSelectionChange((cursor: CursorInfo) => { - setHelperPaneState({ isOpen: true, top: cursor.top, left: cursor.left }); - }); + const handleSelectionChange = buildOnSelectionChange((cursor: CursorInfo) => { + setHelperPaneState(prev => ({ ...prev, isOpen: true, top: cursor.top, left: cursor.left })); + }); @@ - if (options.closeHelperPane) { - setIsTokenUpdateScheduled(true); - } - setHelperPaneState(prev => ({ ...prev, isOpen: !options.closeHelperPane })); + if (options.closeHelperPane) { + setIsTokenUpdateScheduled(true); + } + setHelperPaneState(prev => ({ ...prev, isOpen: !options.closeHelperPane })); @@ - onClickOutside: () => { - setHelperPaneState(prev => ({ ...prev, isOpen: false })); - viewRef.current?.dom.blur(); - }, - onEscapeKey: () => { - setHelperPaneState(prev => ({ ...prev, isOpen: false })); - } + onClickOutside: () => { + setHelperPaneState(prev => ({ ...prev, isOpen: false })); + viewRef.current?.dom.blur(); + }, + onEscapeKey: () => { + setHelperPaneState(prev => ({ ...prev, isOpen: false })); + }(Some call sites already use the functional form; aligning all of them makes the behavior predictable if more fields get added to
HelperPaneStatelater.)Also applies to: 122-144, 174-207, 321-337
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/ChipExpressionEditor.tsx(8 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/constants.ts(1 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/hooks/useHelperPane.ts(1 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/types.ts(2 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/utils.ts(2 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
- workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/constants.ts
- workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx
🧰 Additional context used
🧠 Learnings (5)
📓 Common learnings
Learnt from: dan-niles
Repo: wso2/vscode-extensions PR: 980
File: workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx:384-412
Timestamp: 2025-11-24T22:16:28.380Z
Learning: In the RichTextTemplateEditor component (workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx), token fetching on external `value` prop changes is intentionally disabled. Users cannot edit both the minimized and expanded editors simultaneously, so tokens only need to be generated based on user typing in the expanded editor view, not on external prop updates.
📚 Learning: 2025-11-24T22:16:28.380Z
Learnt from: dan-niles
Repo: wso2/vscode-extensions PR: 980
File: workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx:384-412
Timestamp: 2025-11-24T22:16:28.380Z
Learning: In the RichTextTemplateEditor component (workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx), token fetching on external `value` prop changes is intentionally disabled. Users cannot edit both the minimized and expanded editors simultaneously, so tokens only need to be generated based on user typing in the expanded editor view, not on external prop updates.
Applied to files:
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/types.tsworkspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/ChipExpressionEditor.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/utils.ts
📚 Learning: 2025-11-25T06:34:10.812Z
Learnt from: CR
Repo: wso2/vscode-extensions PR: 0
File: workspaces/ballerina/component-diagram/AGENTS.md:0-0
Timestamp: 2025-11-25T06:34:10.812Z
Learning: Applies to workspaces/ballerina/component-diagram/src/components/**/*.tsx : Use React 18.2.0 features including concurrent rendering and automatic batching; avoid class components in favor of functional components with hooks
Applied to files:
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/ChipExpressionEditor.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/hooks/useHelperPane.ts
📚 Learning: 2025-11-20T11:04:33.712Z
Learnt from: KCSAbeywickrama
Repo: wso2/vscode-extensions PR: 898
File: workspaces/ballerina/data-mapper/src/components/DataMapper/SidePanel/QueryClauses/ClausesPanel.tsx:38-38
Timestamp: 2025-11-20T11:04:33.712Z
Learning: In workspaces/ballerina/data-mapper/src/components/DataMapper/SidePanel/QueryClauses/ClausesPanel.tsx, the use of `useDMQueryClausesPanelStore.getState()` to access `clauseToAdd` and `setClauseToAdd` (instead of the hook subscription pattern) is intentional to prevent re-renders when these state values change.
Applied to files:
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/ChipExpressionEditor.tsx
📚 Learning: 2025-11-25T06:34:10.812Z
Learnt from: CR
Repo: wso2/vscode-extensions PR: 0
File: workspaces/ballerina/component-diagram/AGENTS.md:0-0
Timestamp: 2025-11-25T06:34:10.812Z
Learning: Applies to workspaces/ballerina/component-diagram/src/components/nodes/EntryNode/components/**/*.tsx : Implement lazy expansion of functions: only render function items when they are visible to improve performance for large function lists
Applied to files:
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/utils.ts
🧬 Code graph analysis (3)
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/types.ts (1)
workspaces/ballerina/ballerina-side-panel/src/components/editors/index.ts (1)
InputMode(31-31)
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/ChipExpressionEditor.tsx (5)
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/hooks/useHelperPane.ts (2)
useHelperPane(96-164)useHelperPaneClickOutside(36-70)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/constants.ts (1)
HELPER_PANE_WIDTH(42-42)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/CodeUtils.ts (1)
buildHelperPaneKeymap(608-627)workspaces/ballerina/ballerina-side-panel/src/components/Form/types.ts (1)
HelperpaneOnChangeOptions(96-99)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/utils.ts (1)
processFunctionWithArguments(363-413)
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/hooks/useHelperPane.ts (2)
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/types.ts (1)
HelperPaneState(109-115)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/utils.ts (1)
calculateHelperPanePosition(335-355)
🔇 Additional comments (3)
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/ChipExpressionEditor.tsx (2)
321-337: Escape handling now intercepts CodeMirror’sEscape– verify this is desired
useHelperPaneClickOutsideinstalls a document‑levelkeydownhandler that, onEscape, callsevent.preventDefault()andevent.stopPropagation()before closing the helper pane. While the pane is open, this prevents CodeMirror’s ownEscapekeymap handlers (including the one frombuildHelperPaneKeymap, and any others such as closing the completion widget) from seeing the key event at all.If the intention is purely “close the helper pane” while still allowing CodeMirror to react to
Escape, consider only callingpreventDefault/stopPropagationwhen absolutely necessary, or letting the event bubble after you close the pane.You can manually verify behavior by:
- Opening the helper pane.
- Triggering a completion list or any other ESC‑driven UX inside the editor.
- Pressing
Escand observing whether only the helper pane closes, or whether CodeMirror behaviors still run as expected.
343-349: Toggle buttons correctly share the helper pane toggle behaviorBoth
HelperPaneToggleButton(expanded mode) and the floatingFloatingToggleButton(non‑expanded mode) now delegate tohandleManualTogglefromuseHelperPane, withhelperPaneToggleButtonRefpassed into the hook. Because only one of these buttons renders at a time, the ref always points at the active toggle, and positioning logic based on the button rect will be correct.Also applies to: 373-381
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/hooks/useHelperPane.ts (1)
19-164: Nice centralization of helper pane behavior in a reusable hook
useHelperPaneanduseHelperPaneClickOutsideencapsulate the helper pane’s positioning, toggling, and outside‑click/Escape behavior cleanly, and the use of functionalsetHelperPaneStateupdates avoids stale‑closure issues that existed in earlier inline implementations. The abstractions and types line up well with the ChipExpressionEditor usage.
...na-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/utils.ts
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
♻️ Duplicate comments (1)
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx (1)
325-471: Stale closure in Escape keymap handler.The Escape handler at line 391-397 reads
helperPaneState.isOpenfrom a stale closure. Since the keymap plugin is created in the initialuseEffect(line 325) with empty dependencies, the Escape handler always sees the initialisOpenvalue (false) and will never actually close the helper pane when pressed.Use the functional state updater pattern to check current state:
"Escape": () => { - if (helperPaneState.isOpen) { - setHelperPaneState(prev => ({ ...prev, isOpen: false })); - return true; - } - return false; + let wasOpen = false; + setHelperPaneState(prev => { + wasOpen = prev.isOpen; + if (prev.isOpen) { + return { ...prev, isOpen: false }; + } + return prev; + }); + return wasOpen; }This ensures the Escape key reads the current state instead of the stale closure value.
🧹 Nitpick comments (2)
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RichTemplateMarkdownToolbar.tsx (1)
23-38: Remove unusedtoggleCodeimport.The
toggleCodefunction is imported on line 26 but never used (the inline code button andisCodeActiveare commented out at lines 282 and 353-361). This will trigger unused import lint warnings.Apply this diff to remove the unused import:
import { toggleBold, toggleItalic, - toggleCode, toggleLink, toggleHeading,If you plan to re-enable inline code formatting later, you can add the import back when uncommenting the button.
workspaces/ballerina/ballerina-side-panel/package.json (1)
21-51: Standardize dependency versioning strategy for consistency and reproducibility.The dependencies use an inconsistent mix of tilde (
~) and caret (^) version ranges, which can lead to non-deterministic builds and environment-specific issues. Most pinning should follow a single strategy; recommend~for patch-level safety.- "@codemirror/autocomplete": "~6.19.1", - "@codemirror/commands": "~6.10.0", - "@codemirror/language-data": "^6.5.2", - "@codemirror/lint": "~6.8.1", - "@codemirror/state": "~6.5.2", - "@codemirror/view": "~6.38.8", + "@codemirror/autocomplete": "~6.19.1", + "@codemirror/commands": "~6.10.0", + "@codemirror/language-data": "~6.5.2", + "@codemirror/lint": "~6.8.1", + "@codemirror/state": "~6.5.2", + "@codemirror/view": "~6.38.8", ... - "markdown-it": "^14.1.0", + "markdown-it": "~14.1.0", ... - "@github/markdown-toolbar-element": "^2.2.3", + "@github/markdown-toolbar-element": "~2.2.3", ... - "remark-gfm": "^4.0.1" + "remark-gfm": "~4.0.1"
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
common/config/rush/pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (11)
workspaces/ballerina/ballerina-side-panel/package.json(1 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/ExpandedEditor.tsx(5 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RawTemplateMarkdownToolbar.tsx(1 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RichTemplateMarkdownToolbar.tsx(1 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/TemplateMode.tsx(5 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/types.ts(2 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionEditor.tsx(9 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/ChipExpressionEditor.tsx(9 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/HelperPaneToggleButton.tsx(3 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/hooks/useHelperPane.ts(1 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
- workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/ExpandedEditor.tsx
- workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/HelperPaneToggleButton.tsx
- workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/hooks/useHelperPane.ts
🧰 Additional context used
🧠 Learnings (11)
📓 Common learnings
Learnt from: dan-niles
Repo: wso2/vscode-extensions PR: 980
File: workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx:384-412
Timestamp: 2025-11-24T22:16:28.380Z
Learning: In the RichTextTemplateEditor component (workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx), token fetching on external `value` prop changes is intentionally disabled. Users cannot edit both the minimized and expanded editors simultaneously, so tokens only need to be generated based on user typing in the expanded editor view, not on external prop updates.
📚 Learning: 2025-11-24T22:16:28.380Z
Learnt from: dan-niles
Repo: wso2/vscode-extensions PR: 980
File: workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx:384-412
Timestamp: 2025-11-24T22:16:28.380Z
Learning: In the RichTextTemplateEditor component (workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx), token fetching on external `value` prop changes is intentionally disabled. Users cannot edit both the minimized and expanded editors simultaneously, so tokens only need to be generated based on user typing in the expanded editor view, not on external prop updates.
Applied to files:
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/TemplateMode.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/ChipExpressionEditor.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/types.tsworkspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionEditor.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RawTemplateMarkdownToolbar.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RichTemplateMarkdownToolbar.tsx
📚 Learning: 2025-11-25T06:34:10.812Z
Learnt from: CR
Repo: wso2/vscode-extensions PR: 0
File: workspaces/ballerina/component-diagram/AGENTS.md:0-0
Timestamp: 2025-11-25T06:34:10.812Z
Learning: Applies to workspaces/ballerina/component-diagram/src/components/**/*.tsx : Use React 18.2.0 features including concurrent rendering and automatic batching; avoid class components in favor of functional components with hooks
Applied to files:
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/TemplateMode.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/ChipExpressionEditor.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RawTemplateMarkdownToolbar.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RichTemplateMarkdownToolbar.tsxworkspaces/ballerina/ballerina-side-panel/package.json
📚 Learning: 2025-11-20T11:04:33.712Z
Learnt from: KCSAbeywickrama
Repo: wso2/vscode-extensions PR: 898
File: workspaces/ballerina/data-mapper/src/components/DataMapper/SidePanel/QueryClauses/ClausesPanel.tsx:38-38
Timestamp: 2025-11-20T11:04:33.712Z
Learning: In workspaces/ballerina/data-mapper/src/components/DataMapper/SidePanel/QueryClauses/ClausesPanel.tsx, the use of `useDMQueryClausesPanelStore.getState()` to access `clauseToAdd` and `setClauseToAdd` (instead of the hook subscription pattern) is intentional to prevent re-renders when these state values change.
Applied to files:
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/TemplateMode.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx
📚 Learning: 2025-11-25T06:34:10.812Z
Learnt from: CR
Repo: wso2/vscode-extensions PR: 0
File: workspaces/ballerina/component-diagram/AGENTS.md:0-0
Timestamp: 2025-11-25T06:34:10.812Z
Learning: Applies to workspaces/ballerina/component-diagram/src/components/nodes/EntryNode/components/**/*.tsx : Implement lazy expansion of functions: only render function items when they are visible to improve performance for large function lists
Applied to files:
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/TemplateMode.tsx
📚 Learning: 2025-11-25T06:34:10.812Z
Learnt from: CR
Repo: wso2/vscode-extensions PR: 0
File: workspaces/ballerina/component-diagram/AGENTS.md:0-0
Timestamp: 2025-11-25T06:34:10.812Z
Learning: Applies to workspaces/ballerina/component-diagram/src/components/**/*.tsx : Use Emotion for CSS-in-JS styling instead of inline styles or external CSS files
Applied to files:
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/TemplateMode.tsxworkspaces/ballerina/ballerina-side-panel/package.json
📚 Learning: 2025-11-24T14:51:49.267Z
Learnt from: KCSAbeywickrama
Repo: wso2/vscode-extensions PR: 998
File: workspaces/ballerina/data-mapper/src/components/DataMapper/Header/ExpressionBar.tsx:113-132
Timestamp: 2025-11-24T14:51:49.267Z
Learning: In workspaces/ballerina/data-mapper/src/components/DataMapper/Header/ExpressionBar.tsx, if `textFieldRef.current` is not undefined, `textFieldRef.current.inputElement` is guaranteed to exist. If `inputElement` doesn't exist when `current` exists, it's a fatal error that should reach the error boundary rather than being handled with defensive null checks.
Applied to files:
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/TemplateMode.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionEditor.tsx
📚 Learning: 2025-11-25T06:34:10.812Z
Learnt from: CR
Repo: wso2/vscode-extensions PR: 0
File: workspaces/ballerina/component-diagram/AGENTS.md:0-0
Timestamp: 2025-11-25T06:34:10.812Z
Learning: Applies to workspaces/ballerina/component-diagram/**/*.config.{js,ts} : Use minimatch-compatible glob patterns for file matching in build and test configuration files
Applied to files:
workspaces/ballerina/ballerina-side-panel/package.json
📚 Learning: 2025-11-25T06:34:10.812Z
Learnt from: CR
Repo: wso2/vscode-extensions PR: 0
File: workspaces/ballerina/component-diagram/AGENTS.md:0-0
Timestamp: 2025-11-25T06:34:10.812Z
Learning: Applies to workspaces/ballerina/component-diagram/src/**/*.{ts,tsx} : Define all constants (node types, sizing, spacing) in src/resources/constants.ts and import them where needed instead of hardcoding values
Applied to files:
workspaces/ballerina/ballerina-side-panel/package.json
📚 Learning: 2025-11-25T06:34:10.812Z
Learnt from: CR
Repo: wso2/vscode-extensions PR: 0
File: workspaces/ballerina/component-diagram/AGENTS.md:0-0
Timestamp: 2025-11-25T06:34:10.812Z
Learning: Applies to workspaces/ballerina/component-diagram/src/**/*.{ts,tsx} : Use TypeScript 5.8.3 with strict type checking enabled for all source files
Applied to files:
workspaces/ballerina/ballerina-side-panel/package.json
📚 Learning: 2025-11-25T06:34:10.812Z
Learnt from: CR
Repo: wso2/vscode-extensions PR: 0
File: workspaces/ballerina/component-diagram/AGENTS.md:0-0
Timestamp: 2025-11-25T06:34:10.812Z
Learning: Applies to workspaces/ballerina/component-diagram/src/resources/icons/**/*.tsx : Create separate SVG icon components in src/resources/icons/ for all diagram icons and import them as React components
Applied to files:
workspaces/ballerina/ballerina-side-panel/package.json
🧬 Code graph analysis (4)
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/TemplateMode.tsx (2)
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RawTemplateMarkdownToolbar.tsx (1)
RawTemplateMarkdownToolbar(179-402)workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RichTemplateMarkdownToolbar.tsx (1)
RichTemplateMarkdownToolbar(184-463)
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/ChipExpressionEditor.tsx (5)
workspaces/ballerina/ballerina-side-panel/src/components/editors/index.ts (1)
InputMode(31-31)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/hooks/useHelperPane.ts (2)
useHelperPane(97-170)useHelperPaneClickOutside(36-70)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/constants.ts (1)
HELPER_PANE_WIDTH(42-42)workspaces/ballerina/ballerina-side-panel/src/components/Form/types.ts (1)
HelperpaneOnChangeOptions(96-99)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/utils.ts (1)
processFunctionWithArguments(363-413)
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/types.ts (1)
workspaces/ballerina/ballerina-side-panel/src/components/editors/index.ts (1)
InputMode(31-31)
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionEditor.tsx (2)
workspaces/ballerina/ballerina-side-panel/src/components/editors/index.ts (1)
InputMode(31-31)workspaces/mcp-inspector/mcp-inspector-extension/src/utils/logger.ts (1)
error(24-26)
🔇 Additional comments (21)
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RawTemplateMarkdownToolbar.tsx (1)
179-402: LGTM! Well-structured toolbar component.The RawTemplateMarkdownToolbar is cleanly implemented with proper event listener management, accessibility features, and coordinated state updates. The forceUpdate pattern ensures the toolbar UI stays in sync with editor state changes.
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/types.ts (1)
82-83: LGTM! Clean API extension.Adding
inputModetoEditorModeExpressionPropsproperly extends the interface to support the new PROMPT/TEMPLATE mode distinction throughout the editor flow.workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/TemplateMode.tsx (2)
53-83: LGTM! Clean dual-mode implementation.The refactored state management with separate
codeMirrorViewandproseMirrorViewstates, along withisSourceViewtoggle, provides a clear separation between raw and rich editing modes. ThehandleToggleViewfunction properly coordinates the mode switch.
87-143: LGTM! Proper conditional rendering.The conditional rendering logic cleanly separates the two editing paths, rendering the appropriate toolbar (Raw/Rich) and editor (ChipExpressionEditorComponent/RichTextTemplateEditor) based on
isSourceView. The props are correctly wired through to both paths.workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/ChipExpressionEditor.tsx (3)
92-92: LGTM! Clean API extension.Adding the
inputModeprop enables mode-specific behavior, aligning with the broader PR changes to distinguish PROMPT from TEMPLATE modes.
109-126: LGTM! Excellent refactoring with centralized state management.The
useHelperPanehook integration eliminates stale closure issues and centralizes helper pane positioning logic. The custom toggle for PROMPT mode in expanded view provides appropriate fixed positioning.
331-347: LGTM! Proper outside-click handling.The
useHelperPaneClickOutsidehook centralizes outside-click and Escape key behavior, making the code more maintainable and avoiding duplicate logic across components.workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionEditor.tsx (5)
411-434: LGTM! Consistent PROMPT handling.Properly extends the
fieldValuecalculation and initial diagnostics fetch to includeInputMode.PROMPTalongsideInputMode.TEMPLATE, treating prompts as template-like content throughout the editor lifecycle.
460-472: LGTM! Proper mode initialization.The mode initialization logic correctly handles PROMPT alongside TEMPLATE, applying sanitized/raw expression transformations to both modes when appropriate.
569-604: LGTM! Consistent mode switching.The mode switching warnings and value transformations properly handle PROMPT as equivalent to TEMPLATE, ensuring users are warned when switching from EXP mode would hide expression parts.
707-747: LGTM! Proper value transformation.The
onChangehandler correctly computesrawValuefor both PROMPT and TEMPLATE modes and triggers diagnostics appropriately for all three expression modes (EXP, PROMPT, TEMPLATE).
823-833: LGTM! Correct mode mapping.The ExpandedEditor mode mapping properly translates
InputMode.PROMPTto"template"mode, aligning with the PR's goal of providing template-like editing for prompts.workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx (2)
171-220: LGTM! Clean helper pane integration.The
useHelperPanehook integration with custom toggle logic provides proper helper pane positioning for the rich text editor. The custom toggle for toolbar-based opening uses fixed positioning as intended.
294-322: LGTM! Token fetching logic is correct.Based on learnings, the token fetch on external
valuechanges is intentionally minimal since users cannot edit both minimized and expanded editors simultaneously. ThependingTokenFetchRefguard ensures tokens are only fetched when needed (on user input or undo/redo).workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RichTemplateMarkdownToolbar.tsx (2)
235-242: LGTM! Proper toolbar state synchronization.The
executeCommandwrapper correctly callsforceUpdatewhen commands succeed, ensuring toolbar active states (bold, italic, etc.) update immediately after toolbar actions.
255-276: LGTM! Smart link handling.The link button logic properly handles both removing existing links and opening the dialog for new links, with pre-filled selected text for a better UX.
workspaces/ballerina/ballerina-side-panel/package.json (5)
58-59: Remove concern about dependency order in package.json.The review comment incorrectly assumes that the order of dependencies in package.json (copyfiles before TypeScript on lines 58-59) affects build execution order. However, the actual execution order is explicitly defined by the build script:
tsc --pretty && npm run copy:assetsruns TypeScript first, then copyfiles. Both are devDependencies and will be available during the build regardless of their listing order. The current setup is correct.Likely an incorrect or invalid review comment.
21-26: No verification issues found—CodeMirror versions are compatible.The specified versions are both valid and current releases: @codemirror/state 6.5.2 is the latest version and @codemirror/view 6.38.8 is the latest version. CodeMirror is structured as a collection of separate modules, and minor version differences between state and view packages are normal and expected in this architecture. No peer dependency conflicts between these versions were identified, and both are declared as peerDependencies in similar CodeMirror-based projects. The mixed tilde and caret ranges follow standard npm versioning practices.
34-34: The original review comment's concerns are not valid.The verification shows the three markdown packages serve distinct, non-overlapping purposes and are all actively used:
- markdown-it + prosemirror-markdown (in RichTextTemplateEditor.tsx): Work together to enable markdown ↔ ProseMirror bidirectional conversion in the rich text editor. The
markdown-ittokenizer is directly passed to theMarkdownParserconstructor—it's not redundant but essential.- react-markdown + plugins (in TypeEditor, ExpressionEditor, ActionTypeEditor, MarkdownPreview, Form): Separate layer for rendering documentation markdown read-only display.
No conflicts exist: the ProseMirror editor and react-markdown components handle different content in different contexts. All three packages are genuinely required.
Likely an incorrect or invalid review comment.
46-47: Searching for dependency relationships to assess impact of React version divergence:Need to verify if the target package has dependencies on the React 19 packages:
Verify and address React version incompatibilities in the monorepo.
Verification found significant version divergence: while ballerina-side-panel and the requested packages (ui-toolkit, ballerina-core) correctly use React 18.2.0, multiple packages install conflicting versions of React in the monorepo. Specifically,
workspaces/mi/mi-rpc-clientuses React 19.1.0 andworkspaces/ballerina/statement-editoruses ^19.1.0.React 19's peer dependency conflicts have led to issues across the ecosystem, and monorepos mixing React versions have historically struggled with version resolution. Confirm whether:
- These React 19 packages are intentionally isolated (no shared dependencies with React 18 packages)
- The monorepo uses explicit resolution strategies (resolutions, overrides, pnpm extensions) to prevent type resolution conflicts
- Build and type-checking passes without peer dependency warnings
If packages are interdependent, standardize on a single React version across the monorepo.
35-45: Now let me search for more specific compatibility information about these versions:Verify ProseMirror package compatibility by testing the editor flow.
The PR introduces 10 ProseMirror packages with the following versions:
- prosemirror-model: ^1.19.4
- prosemirror-state: ^1.4.3
- prosemirror-view: ^1.33.0
- prosemirror-commands, prosemirror-gapcursor, prosemirror-history, prosemirror-inputrules, prosemirror-keymap, prosemirror-markdown, prosemirror-schema-basic, prosemirror-schema-list
ProseMirror packages must use matching versions from the same compatible series across model, state, view, transform, and commands. prosemirror-model is currently in the 1.25.x series, but this PR specifies ^1.19.4. Without a lock file or post-install verification, the actual resolved versions cannot be confirmed.
Ensure these packages resolve to compatible versions and test the editor flow (including markdown input, history, schema validation, and keymaps) to confirm no runtime conflicts occur.
9c905e9 to
842bc28
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionEditor.tsx (2)
452-472: Add type guard before callingsanitizedExpression/.trim()for PROMPT/TEMPLATEIn the new PROMPT/TEMPLATE branch,
initialFieldValue.currentis used without confirming it’s a string:const sanitized = sanitizedExpression(initialFieldValue.current as string); if (sanitized !== initialFieldValue.current || !initialFieldValue.current || initialFieldValue.current.trim() === '') { setInputMode(newInputMode); } else { setInputMode(InputMode.EXP); }If
initialFieldValue.currentisundefined,null, or a non‑string,sanitizedExpression(which expects a string) and especially.trim()can throw at runtime. The TEXT branch above already has atypeof initialFieldValue.current === 'string'guard; this block should mirror that.Consider:
- } else if (newInputMode === InputMode.PROMPT || newInputMode === InputMode.TEMPLATE) { - if (sanitizedExpression && rawExpression) { - const sanitized = sanitizedExpression(initialFieldValue.current as string); - if (sanitized !== initialFieldValue.current || !initialFieldValue.current || initialFieldValue.current.trim() === '') { - setInputMode(newInputMode); - } else { - setInputMode(InputMode.EXP); - } - } + } else if (newInputMode === InputMode.PROMPT || newInputMode === InputMode.TEMPLATE) { + if (sanitizedExpression && rawExpression && typeof initialFieldValue.current === 'string') { + const sanitized = sanitizedExpression(initialFieldValue.current); + if (sanitized !== initialFieldValue.current || initialFieldValue.current.trim() === '') { + setInputMode(newInputMode); + } else { + setInputMode(InputMode.EXP); + } + } else { + setInputMode(InputMode.EXP); + } }This keeps PROMPT/TEMPLATE detection robust even when the initial value is absent or not a string.
569-582: Sanitization warning condition appears inverted vs commentThe comment says:
// Warn when switching from EXP to TEMPLATE if sanitization would hide parts of the expressionbut the logic warns when
currentValue === sanitizedExpression(currentValue)(i.e., no change on sanitization), and silently switches modes when sanitization does change the string:if (currentValue === sanitizedExpression(currentValue)) { setShowModeSwitchWarning(true); } else { setInputMode(value); }For both
InputMode.PROMPTandInputMode.TEMPLATE, it seems more intuitive to warn when sanitization alters the value (potentially hiding parts), and auto‑switch when it’s a no‑op. If that’s the intent, the condition should likely be flipped, or the comment updated to match the actual behavior.Please double‑check whether the warning should trigger on
!==instead.
♻️ Duplicate comments (1)
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx (1)
391-397: Keymap Escape handler reads from stale closure.This handler captures
helperPaneState.isOpenfrom the closure when the keymap is created (in the empty-depsuseEffect). Since the state never updates in this closure,helperPaneState.isOpenwill always befalse(initial value), making this handler effectively a no-op.The
useHelperPaneClickOutsidehook at lines 481-495 handles Escape correctly using the functional updater pattern. Consider removing this redundant keymap entry or using a ref to track the current open state.// Helper pane "Mod-/": () => handleKeyboardToggle(), - "Escape": () => { - if (helperPaneState.isOpen) { - setHelperPaneState(prev => ({ ...prev, isOpen: false })); - return true; - } - return false; - } + // Escape key handling moved to useHelperPaneClickOutside hook
🧹 Nitpick comments (14)
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/utils.ts (1)
333-355: Consider adding vertical overflow correction.The function handles horizontal overflow well, but doesn't account for vertical overflow. If the target position is near the bottom of the viewport, the helper pane could extend below the visible area.
This is a minor edge case since the helper pane typically appears within a scrollable editor container.
if (overflow > 0) { left -= overflow; } + // Optional: Add vertical overflow correction + const viewportHeight = window.innerHeight; + const absoluteBottom = targetCoords.bottom; + const helperPaneHeight = 200; // Approximate height, could be parameterized + const verticalOverflow = absoluteBottom + helperPaneHeight - viewportHeight; + if (verticalOverflow > 0) { + // Position above the target instead of below + top = targetCoords.bottom - editorRect.top - helperPaneHeight + scrollTop; + } + return { top, left };workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/hooks/useHelperPane.ts (3)
54-60: Consider whetherstopPropagationis necessary for Escape.The Escape key handler calls both
preventDefault()andstopPropagation(). WhilepreventDefault()is fine,stopPropagation()prevents other components from handling the Escape key, which could interfere with parent dialogs or modals that also listen for Escape.If the helper pane is used inside a modal, users might expect Escape to close the modal after the helper pane is closed, but the propagation stop could prevent that.
const handleEscapeKey = (event: KeyboardEvent) => { if (event.key === 'Escape') { event.preventDefault(); - event.stopPropagation(); onEscapeKey(); } };
69-69: Dependency array includes stable refs unnecessarily.The refs (
refs.editor,refs.helperPane, etc.) areRefObjectinstances which are stable across renders. Including them in the dependency array doesn't cause bugs but is unnecessary. The callbacksonClickOutsideandonEscapeKeyare the meaningful dependencies.This is a minor optimization and the current code works correctly.
154-162: Missing dependencies in useEffect.The dependency array only includes
helperPaneState.isOpen, but the effect body referencesonStateChange,toggleButtonRef, andhandleManualToggle. This could cause issues if these values change.However, in practice:
onStateChangeis typically stable (passed from parent)toggleButtonRefis a stable ref objecthandleManualToggleis memoizedThe primary concern is that if
onStateChangeis replaced, the old callback continues to be called.useEffect(() => { if (onStateChange) { onStateChange({ isOpen: helperPaneState.isOpen, ref: toggleButtonRef, toggle: handleManualToggle }); } - }, [helperPaneState.isOpen]); + }, [helperPaneState.isOpen, onStateChange, toggleButtonRef, handleManualToggle]);workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/LinkDialog.tsx (2)
23-58: High z-index values may cause layering conflicts.The z-index values (29999, 30000, 30001) are extremely high. While this ensures the dialog appears above most content, it could conflict with other modals or overlays in the application.
Consider using CSS custom properties or a centralized z-index management system to maintain consistency across the codebase.
139-139: Add accessibility attributes to the close button.The close icon should have proper accessibility attributes for screen reader users and keyboard navigation.
- <Codicon name="close" onClick={handleClose} /> + <Codicon + name="close" + onClick={handleClose} + aria-label="Close dialog" + role="button" + tabIndex={0} + onKeyDown={(e) => e.key === 'Enter' && handleClose()} + />workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/chipPlugin.ts (3)
173-175: Remove unused variable assignment.The
textStylesvariable is assigned but the originalCHIP_TEXT_STYLESis already available and applied directly. This intermediate variable serves no purpose.- const textStyles: any = { ...CHIP_TEXT_STYLES }; - - Object.assign(textSpan.style, textStyles); + Object.assign(textSpan.style, CHIP_TEXT_STYLES);
184-212: Potential issue:findDocPositionreturns 0 for unfound positions.If the target text offset is within a non-text node or the traversal doesn't find it, the function returns
0(fromdocPos || 0). This could cause incorrect chip placement.Consider adding explicit handling or logging for cases where the position isn't found.
function findDocPosition(doc: any, textOffset: number): number { // Clamp offset to valid range if (textOffset <= 0) return 0; if (textOffset >= doc.textContent.length) return doc.content.size; let charCount = 0; let docPos = 0; + let found = false; doc.descendants((node: any, pos: number) => { // If we've found the position, stop traversing - if (docPos > 0) return false; + if (found) return false; if (node.isText) { const textLength = node.text.length; if (charCount + textLength >= textOffset) { // This text node contains our target offset docPos = pos + (textOffset - charCount); + found = true; return false; } charCount += textLength; } return true; }); - return docPos || 0; + return docPos; }
336-349: Consider optimizing token comparison for large documents.Using
JSON.stringifyto compare token updates could become expensive for documents with many tokens. For large documents, consider using a hash or incremental comparison.For now this is acceptable, but if performance issues arise with large documents, consider computing a hash of the tokens array instead of full serialization.
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/ExpandedEditor.tsx (1)
190-195: Comment is slightly inaccurate.The comment says "Only text mode and prompt mode don't support preview" but the condition only checks for
textmode. Based on the code, prompt mode does support preview (it hasisPreviewModeandonTogglePreviewprops).useEffect(() => { - // Only text mode and prompt mode don't support preview + // Text mode doesn't support preview if (mode === "text") { setShowPreview(false); } }, [mode]);workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RichTemplateMarkdownToolbar.tsx (1)
197-214: Consider using ProseMirror'supdateStateevent instead of DOM events.The toolbar subscribes to DOM events (
input,click,keyup) to detect state changes. ProseMirror provides a more reliable approach via pluginview.updateor by triggering updates when dispatching transactions. The current approach works but may miss some state changes triggered programmatically.workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/markdownCommands.ts (1)
48-48: Consider removingas anytype assertions.The
as anycasts on Transaction methods (removeMark,addMark,replaceWith) bypass TypeScript's type checking. ProseMirror'sTransactionclass does have these methods, but the types might not be fully recognized.You can improve type safety by ensuring proper type imports or using type augmentation:
// Option 1: Cast only the specific call if Transaction types are incomplete dispatch(state.tr.removeMark(from, to, linkMarkType)); // Option 2: If types don't match, consider extending the type definitions declare module "prosemirror-state" { interface Transaction { removeMark(from: number, to: number, mark?: MarkType): this; addMark(from: number, to: number, mark: Mark): this; } }Also applies to: 67-67, 108-108
workspaces/ballerina/ballerina-side-panel/package.json (1)
21-26: Standardize CodeMirror package version pinning strategy.The CodeMirror packages use inconsistent semver constraints: most use tilde (
~) for tight pinning (e.g.,~6.19.1), but@codemirror/language-datauses caret (^) for broader pinning. This inconsistency could lead to unexpected version drift and subtle incompatibilities.Decide on a consistent pinning strategy for all CodeMirror packages within this major version (6.x). Given the tight integration between CodeMirror modules, recommend tilde (
~) across the board to minimize drift risk."@codemirror/autocomplete": "~6.19.1", "@codemirror/commands": "~6.10.0", - "@codemirror/language-data": "^6.5.2", + "@codemirror/language-data": "~6.5.2", "@codemirror/lint": "~6.8.1", "@codemirror/state": "~6.5.2", "@codemirror/view": "~6.38.8",workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionEditor.tsx (1)
699-748: PROMPT/TEMPLATE raw value pipeline and conditional props look sound (small duplication note)The inline editor now:
- Only passes
sanitizedExpression/rawExpressiontoExpressionFieldwhen inPROMPT/TEMPLATEmodes.- Converts
updatedValueback to a raw value viarawExpressionfor PROMPT/TEMPLATE before storing and before diagnostics/completions.- Uses
inputModeRef.currentto avoid stale closures in the asynconChangepath.This keeps EXP/TEXT/RECORD unaffected while enabling the raw↔sanitized mapping for the new prompt mode.
The
onChangebody here is almost identical to the one inExpandedEditorbelow; if this logic keeps evolving (e.g., more PROMPT‑specific behavior), consider extracting a shared helper to reduce the risk of the two diverging.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (2)
common/config/rush/pnpm-lock.yamlis excluded by!**/pnpm-lock.yamlworkspaces/common-libs/font-wso2-vscode/src/icons/bi-arrow-down.svgis excluded by!**/*.svg
📒 Files selected for processing (24)
workspaces/ballerina/ballerina-side-panel/package.json(1 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/ExpandedEditor.tsx(5 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/LinkDialog.tsx(1 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RawTemplateMarkdownToolbar.tsx(1 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RichTemplateMarkdownToolbar.tsx(1 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/TemplateMarkdownToolbar.tsx(0 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/ExpressionMode.tsx(1 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/TemplateMode.tsx(5 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/types.ts(2 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/utils/templateUtils.ts(3 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionEditor.tsx(9 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/CodeUtils.ts(3 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/chipStyles.ts(1 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/ChipExpressionEditor.tsx(9 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/HelperPaneToggleButton.tsx(3 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/constants.ts(1 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/hooks/useHelperPane.ts(1 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/types.ts(2 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/utils.ts(2 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx(1 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/chipPlugin.ts(1 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/markdownCommands.ts(1 hunks)workspaces/ballerina/ballerina-visualizer/src/views/BI/HelperPaneNew/Views/DocumentConfig.tsx(2 hunks)workspaces/ballerina/ballerina-visualizer/src/views/BI/HelperPaneNew/utils/utils.ts(1 hunks)
💤 Files with no reviewable changes (1)
- workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/TemplateMarkdownToolbar.tsx
🚧 Files skipped from review as they are similar to previous changes (8)
- workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/ExpressionMode.tsx
- workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/CodeUtils.ts
- workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/HelperPaneToggleButton.tsx
- workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/types.ts
- workspaces/ballerina/ballerina-visualizer/src/views/BI/HelperPaneNew/utils/utils.ts
- workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/chipStyles.ts
- workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RawTemplateMarkdownToolbar.tsx
- workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/types.ts
🧰 Additional context used
🧠 Learnings (11)
📓 Common learnings
Learnt from: dan-niles
Repo: wso2/vscode-extensions PR: 980
File: workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx:384-412
Timestamp: 2025-11-24T22:16:28.380Z
Learning: In the RichTextTemplateEditor component (workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx), token fetching on external `value` prop changes is intentionally disabled. Users cannot edit both the minimized and expanded editors simultaneously, so tokens only need to be generated based on user typing in the expanded editor view, not on external prop updates.
📚 Learning: 2025-11-24T22:16:28.380Z
Learnt from: dan-niles
Repo: wso2/vscode-extensions PR: 980
File: workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx:384-412
Timestamp: 2025-11-24T22:16:28.380Z
Learning: In the RichTextTemplateEditor component (workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx), token fetching on external `value` prop changes is intentionally disabled. Users cannot edit both the minimized and expanded editors simultaneously, so tokens only need to be generated based on user typing in the expanded editor view, not on external prop updates.
Applied to files:
workspaces/ballerina/ballerina-visualizer/src/views/BI/HelperPaneNew/Views/DocumentConfig.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/ExpandedEditor.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/LinkDialog.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionEditor.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/utils.tsworkspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/markdownCommands.tsworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RichTemplateMarkdownToolbar.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/TemplateMode.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/ChipExpressionEditor.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/chipPlugin.tsworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/utils/templateUtils.ts
📚 Learning: 2025-11-25T06:34:10.812Z
Learnt from: CR
Repo: wso2/vscode-extensions PR: 0
File: workspaces/ballerina/component-diagram/AGENTS.md:0-0
Timestamp: 2025-11-25T06:34:10.812Z
Learning: Applies to workspaces/ballerina/component-diagram/src/components/**/*.tsx : Use React 18.2.0 features including concurrent rendering and automatic batching; avoid class components in favor of functional components with hooks
Applied to files:
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/LinkDialog.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/TemplateMode.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/ChipExpressionEditor.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/hooks/useHelperPane.tsworkspaces/ballerina/ballerina-side-panel/package.json
📚 Learning: 2025-11-24T14:51:49.267Z
Learnt from: KCSAbeywickrama
Repo: wso2/vscode-extensions PR: 998
File: workspaces/ballerina/data-mapper/src/components/DataMapper/Header/ExpressionBar.tsx:113-132
Timestamp: 2025-11-24T14:51:49.267Z
Learning: In workspaces/ballerina/data-mapper/src/components/DataMapper/Header/ExpressionBar.tsx, if `textFieldRef.current` is not undefined, `textFieldRef.current.inputElement` is guaranteed to exist. If `inputElement` doesn't exist when `current` exists, it's a fatal error that should reach the error boundary rather than being handled with defensive null checks.
Applied to files:
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionEditor.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/TemplateMode.tsx
📚 Learning: 2025-11-25T06:34:10.812Z
Learnt from: CR
Repo: wso2/vscode-extensions PR: 0
File: workspaces/ballerina/component-diagram/AGENTS.md:0-0
Timestamp: 2025-11-25T06:34:10.812Z
Learning: Applies to workspaces/ballerina/component-diagram/src/components/nodes/EntryNode/components/**/*.tsx : Implement lazy expansion of functions: only render function items when they are visible to improve performance for large function lists
Applied to files:
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/utils.tsworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/TemplateMode.tsx
📚 Learning: 2025-11-25T06:34:10.812Z
Learnt from: CR
Repo: wso2/vscode-extensions PR: 0
File: workspaces/ballerina/component-diagram/AGENTS.md:0-0
Timestamp: 2025-11-25T06:34:10.812Z
Learning: Applies to workspaces/ballerina/component-diagram/src/**/*.{ts,tsx} : Define all constants (node types, sizing, spacing) in src/resources/constants.ts and import them where needed instead of hardcoding values
Applied to files:
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/utils.tsworkspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/constants.tsworkspaces/ballerina/ballerina-side-panel/package.json
📚 Learning: 2025-11-20T11:04:33.712Z
Learnt from: KCSAbeywickrama
Repo: wso2/vscode-extensions PR: 898
File: workspaces/ballerina/data-mapper/src/components/DataMapper/SidePanel/QueryClauses/ClausesPanel.tsx:38-38
Timestamp: 2025-11-20T11:04:33.712Z
Learning: In workspaces/ballerina/data-mapper/src/components/DataMapper/SidePanel/QueryClauses/ClausesPanel.tsx, the use of `useDMQueryClausesPanelStore.getState()` to access `clauseToAdd` and `setClauseToAdd` (instead of the hook subscription pattern) is intentional to prevent re-renders when these state values change.
Applied to files:
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/TemplateMode.tsx
📚 Learning: 2025-11-25T06:34:10.812Z
Learnt from: CR
Repo: wso2/vscode-extensions PR: 0
File: workspaces/ballerina/component-diagram/AGENTS.md:0-0
Timestamp: 2025-11-25T06:34:10.812Z
Learning: Applies to workspaces/ballerina/component-diagram/src/components/**/*.tsx : Use Emotion for CSS-in-JS styling instead of inline styles or external CSS files
Applied to files:
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/TemplateMode.tsxworkspaces/ballerina/ballerina-side-panel/package.json
📚 Learning: 2025-11-25T06:34:10.812Z
Learnt from: CR
Repo: wso2/vscode-extensions PR: 0
File: workspaces/ballerina/component-diagram/AGENTS.md:0-0
Timestamp: 2025-11-25T06:34:10.812Z
Learning: Applies to workspaces/ballerina/component-diagram/**/*.config.{js,ts} : Use minimatch-compatible glob patterns for file matching in build and test configuration files
Applied to files:
workspaces/ballerina/ballerina-side-panel/package.json
📚 Learning: 2025-11-25T06:34:10.812Z
Learnt from: CR
Repo: wso2/vscode-extensions PR: 0
File: workspaces/ballerina/component-diagram/AGENTS.md:0-0
Timestamp: 2025-11-25T06:34:10.812Z
Learning: Applies to workspaces/ballerina/component-diagram/src/**/*.{ts,tsx} : Use TypeScript 5.8.3 with strict type checking enabled for all source files
Applied to files:
workspaces/ballerina/ballerina-side-panel/package.json
📚 Learning: 2025-11-25T06:34:10.812Z
Learnt from: CR
Repo: wso2/vscode-extensions PR: 0
File: workspaces/ballerina/component-diagram/AGENTS.md:0-0
Timestamp: 2025-11-25T06:34:10.812Z
Learning: Applies to workspaces/ballerina/component-diagram/src/resources/icons/**/*.tsx : Create separate SVG icon components in src/resources/icons/ for all diagram icons and import them as React components
Applied to files:
workspaces/ballerina/ballerina-side-panel/package.json
🧬 Code graph analysis (9)
workspaces/ballerina/ballerina-visualizer/src/views/BI/HelperPaneNew/Views/DocumentConfig.tsx (1)
workspaces/ballerina/ballerina-side-panel/src/components/editors/index.ts (1)
InputMode(31-31)
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/ExpandedEditor.tsx (1)
workspaces/ballerina/ballerina-side-panel/src/components/editors/index.ts (1)
InputMode(31-31)
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionEditor.tsx (1)
workspaces/ballerina/ballerina-side-panel/src/components/editors/index.ts (1)
InputMode(31-31)
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/markdownCommands.ts (1)
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/utils/templateUtils.ts (4)
undoCommand(353-358)redoCommand(363-368)canUndo(373-376)canRedo(381-384)
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RichTemplateMarkdownToolbar.tsx (6)
workspaces/common-libs/ui-toolkit/src/styles/Theme.ts (1)
ThemeColors(79-104)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/markdownCommands.ts (9)
toggleHeading(76-86)toggleLink(40-74)isMarkActive(144-150)isNodeActive(152-162)isListActive(164-178)canUndo(188-190)canRedo(192-194)undoCommand(180-182)redoCommand(184-186)workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/utils/templateUtils.ts (4)
canUndo(373-376)canRedo(381-384)undoCommand(353-358)redoCommand(363-368)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/HelperPaneToggleButton.tsx (1)
HelperPaneToggleButton(83-109)workspaces/common-libs/ui-toolkit/src/components/Swich/Swich.tsx (1)
Switch(146-176)workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/LinkDialog.tsx (1)
LinkDialog(90-175)
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/ChipExpressionEditor.tsx (5)
workspaces/ballerina/ballerina-side-panel/src/components/editors/index.ts (1)
InputMode(31-31)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/hooks/useHelperPane.ts (1)
useHelperPane(97-170)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/constants.ts (1)
HELPER_PANE_WIDTH(42-42)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/CodeUtils.ts (1)
buildHelperPaneKeymap(610-629)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/utils.ts (1)
processFunctionWithArguments(363-416)
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/chipPlugin.ts (3)
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/types.ts (2)
TokenMetadata(64-68)CompoundTokenSequence(90-98)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/chipStyles.ts (6)
getChipDisplayContent(107-109)getTokenTypeColor(99-101)BASE_CHIP_STYLES(22-37)getTokenIconClass(92-97)BASE_ICON_STYLES(39-42)CHIP_TEXT_STYLES(44-48)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/utils.ts (3)
ParsedToken(105-110)getParsedExpressionTokens(112-138)detectTokenPatterns(278-332)
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/hooks/useHelperPane.ts (2)
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/types.ts (1)
HelperPaneState(109-115)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/utils.ts (1)
calculateHelperPanePosition(335-355)
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/utils/templateUtils.ts (1)
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/markdownCommands.ts (4)
undoCommand(180-182)redoCommand(184-186)canUndo(188-190)canRedo(192-194)
🔇 Additional comments (39)
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/constants.ts (1)
40-42: LGTM!The constant is well-placed alongside existing markers and follows the project convention of centralizing constants. This aligns with the learning that constants should be defined in dedicated files and imported where needed.
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/utils.ts (1)
357-416: LGTM!The implementation correctly handles function argument extraction with proper error handling. The cursor positioning logic using
lastIndexOf(")")ensures accurate caret placement regardless of document position, addressing the issues from the previous review.workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/ChipExpressionEditor.tsx (6)
52-55: LGTM!Clean imports for the new helper pane utilities and hooks. The modular approach improves maintainability.
108-126: LGTM!The hook integration is well-structured with appropriate conditional logic for PROMPT mode. The custom manual toggle provides fixed positioning for the expanded editor view, which is a reasonable UX decision.
184-217: VerifycursorAdjustmentsemantics.On line 205,
cursorPosition = from + result.cursorAdjustmentassumescursorAdjustmentis an offset from the insertion point. However, looking atprocessFunctionWithArgumentsin utils.ts (line 403-405),cursorAdjustmentis set toclosingParenIndexwhich is an index withinfinalValue, not a relative offset.This means the cursor will be placed at
from + closingParenIndex, which is actually correct since you're insertingfinalValuestarting atfrom, and you want the cursor atclosingParenIndexwithin that inserted text.The naming is slightly misleading (
cursorAdjustmentsuggests a delta), but the logic is correct.
331-347: LGTM!The hook integration properly centralizes click-outside and escape key handling. The inclusion of
toolbarRefensures clicks on the toolbar don't close the helper pane, which is the expected behavior.
353-359: LGTM!Good UX improvement adding the keyboard shortcut hint to the title. The consistent use of
handleManualToggleacross toggle buttons ensures uniform behavior.
176-182: Stale closure confirmed, but practical impact mitigated.The review comment correctly identifies a stale closure issue:
helperPaneKeymapis created at render level with a closure capturinghelperPaneState.isOpen, but theuseEffect(line 219) that installs it has an empty dependency array[]. This means the keymap is created once and never reinstalled, so the Escape key handler uses a stale value ofhelperPaneState.isOpenfrom initial render.However, the review's assessment is accurate—the practical impact is minimal since
onClose()becomes a no-op when already closed. To prevent potential subtle bugs, consider either:
- Adding
helperPaneStateto the useEffect dependency array, or- Adding
helperPaneKeymapas a dependencyworkspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/hooks/useHelperPane.ts (2)
131-152: LGTM! Functional setState pattern correctly addresses stale closure.The
handleKeyboardToggleimplementation correctly uses functionalsetHelperPaneStateto avoid the stale closure issue identified in the past review. The callback computes the position at toggle time rather than capturing it in a closure.
96-107: Well-designed hook API.The hook provides a clean abstraction with clear separation between manual toggle (button click) and keyboard toggle (Ctrl+/). The
customManualToggleescape hatch allows flexibility for different positioning strategies per mode.workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/LinkDialog.tsx (1)
90-127: LGTM - Clean component implementation with proper state management.The component correctly:
- Resets state when dialog opens via
useEffect- Validates URL before insertion
- Handles keyboard shortcuts (Enter/Escape)
- Trims input values appropriately
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/utils/templateUtils.ts (2)
217-220: Good fix: Empty lines now correctly excluded from "all listed" check.The change ensures that when toggling lists, empty lines (
trimmed !== "") are not counted when determining if all lines are already formatted as a list. This prevents incorrect toggle behavior when the selection includes empty lines.
347-384: LGTM - Well-implemented undo/redo helpers for CodeMirror.The implementation correctly:
- Uses
undoDepth/redoDepthfor availability checks (more efficient than trying the operation)- Calls
view.focus()after operations to maintain editor focus- Handles null view gracefully
Note: These are distinct from the ProseMirror undo/redo in
markdownCommands.tssince they operate on different editor backends (CodeMirror vs ProseMirror).workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/chipPlugin.ts (2)
370-379: Handle edge case when plainText is not found in wrappedText.If
wrappedText.indexOf(plainText)returns-1(plainText not found), the conditionprefixLength > 0will be false, which is correct. However, ifplainTextis at position 0,prefixLengthwill be 0, and no adjustment occurs, which is also correct.The logic handles both edge cases appropriately.
320-422: Well-structured plugin implementation.The plugin correctly:
- Manages state with deduplication to avoid reprocessing
- Uses
appendTransactionfor automatic chip replacement- Marks transformations as non-undoable (
addToHistory: false)- Handles chip click events with position resolution
workspaces/ballerina/ballerina-visualizer/src/views/BI/HelperPaneNew/Views/DocumentConfig.tsx (2)
162-162: LGTM - Correct expansion of template mode check.The change correctly treats both
PROMPTandTEMPLATEinput modes as requiring string interpolation wrapping when selecting AI document type items.
214-214: InconsistentisTemplateModelogic between item selection and URL insertion.At line 162,
isTemplateModeisinputMode === InputMode.PROMPT || inputMode === InputMode.TEMPLATE, but here it only checksinputMode === InputMode.PROMPT. This inconsistency may cause different wrapping behavior for the same input mode.If this is intentional (e.g., URL insertion should only wrap in PROMPT mode), consider adding a comment explaining the difference. Otherwise, align the logic:
- const isTemplateMode = inputMode === InputMode.PROMPT; + const isTemplateMode = inputMode === InputMode.PROMPT || inputMode === InputMode.TEMPLATE;workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/ExpandedEditor.tsx (2)
64-64: LGTM - Clean addition of optional inputMode prop.The
inputModeprop is correctly typed as optional and follows the existing prop pattern in the interface.
240-252: LGTM - Proper propagation of inputMode to template mode.The
inputModeis correctly included in the template mode props, enabling theTemplateModecomponent to determine whether to use source view or rich text editing based on the input mode.workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/TemplateMode.tsx (3)
53-62: State management for dual editor views is well structured.The state setup cleanly manages both CodeMirror and ProseMirror editor instances with dedicated refs for their respective toolbars, enabling proper coordination between the two editing modes.
81-83: Toggle function is straightforward.Simple state toggle for view switching—no additional logic needed.
126-142: Dismiss this review comment - the architectural design is intentional.RichTextTemplateEditor doesn't need
inputModebecause it's a specialized template-view renderer, not a multi-mode editor. ChipExpressionEditorComponent accepts and usesinputModeto conditionally handle PROMPT-mode behavior, but RichTextTemplateEditor is only deployed for template rendering and has no input-mode-dependent logic. The fact that inputMode is passed to one but not the other reflects proper separation of concerns: ChipExpressionEditorComponent handles mode-aware logic; RichTextTemplateEditor handles template-specific formatting.Likely an incorrect or invalid review comment.
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RichTemplateMarkdownToolbar.tsx (3)
235-242: Good fix for toolbar state synchronization.The
executeCommandnow correctly callsforceUpdate()when the command succeeds, ensuring toolbar active states update immediately after toolbar-triggered commands.
255-276: Link toggle and dialog flow is well implemented.The logic correctly removes existing links when clicked again, extracts selected text for pre-filling the title field, and opens the dialog for new link insertion.
440-453: Switch component integration looks correct.The Switch correctly reflects the current view state and triggers the toggle callback. The styling props integrate well with the VS Code theme variables.
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx (4)
121-142: Markdown parsing and serialization setup is solid.The custom parser and serializer correctly integrate chip nodes with the standard markdown handling. The serializer properly converts chip nodes back to their original text representation.
194-219: Helper pane state management uses proper patterns.The
useHelperPanehook integration with custom manual toggle logic and cursor coordinate calculation provides clean separation of concerns.
473-478: Token fetching on external value changes is intentionally disabled.Per the established design, tokens are only generated based on user typing in the expanded editor view, not on external prop updates—this is correct since users cannot edit both minimized and expanded editors simultaneously. Based on learnings.
480-495: Click-outside and Escape handling via hook is well implemented.The
useHelperPaneClickOutsidehook properly uses functional state updaters, avoiding the stale closure issues that affect the keymap-based approach.workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/markdownCommands.ts (4)
26-26: Well-defined Command type for ProseMirror integration.The type signature correctly matches ProseMirror's command pattern with optional dispatch and view parameters.
40-74: Link toggle command handles all cases correctly.The implementation properly:
- Removes existing links when toggled on linked text
- Returns false when no href is provided (preventing invalid links)
- Inserts link text when no selection exists
- Wraps selection with link mark when text is selected
100-114: List type conversion helper is functional.The
convertListTypefunction correctly finds the parent list node and replaces it with the target list type while preserving content and selection.
188-194: Capability check functions follow ProseMirror conventions.Calling
undo(state)andredo(state)without a dispatch function correctly returns whether the operation can be applied—this is the standard ProseMirror pattern for capability queries.workspaces/ballerina/ballerina-side-panel/package.json (2)
29-29: No compatibility issues found—integration is correct and follows Web Component best practices.Verification confirms that
@github/markdown-toolbar-elementv2.2.3 integrates properly with React 18.2.0. The package is a vanilla Web Component with no peer dependencies, and the codebase follows proper React + Web Component interop patterns: lowercase tag names in JSX, correct TypeScript type declarations for custom elements (inMarkdownToolbar.tsxlines 26–30), and the import statement to register the component. No known compatibility issues exist between the package and React 18.2.0 or TypeScript 5.8.3.
35-45: Verify ProseMirror compatibility through code review and testing.npm install detected no peer dependency conflicts across the specified ProseMirror versions (state@^1.4.3, view@^1.33.0, commands@^1.5.2, etc.). However, ProseMirror has documented breaking changes across versions that require manual verification in your code:
- Widget decoration API: removed associative option (use side instead)
- EditorView handlers: handleDOMEvent → handleDOMEvents, dispatchTransaction this-binding changed
- Selection/ResolvedPos APIs: constructors and helpers renamed
- IME/composition and mark DOM structure changes
Review the codebase for these breaking changes and test the editor under realistic scenarios (IME input, composition, custom decorations, undo/redo) to ensure compatibility.
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionEditor.tsx (4)
411-418: PROMPT mode inclusion in diagnostics field value looks consistentExtending
fieldValueand the diagnostics guard to treatInputMode.PROMPTthe same way asTEMPLATEkeeps validation behavior aligned across expression, template, and prompt modes. This fits the new PROMPT flow without changing existing EXP/TEMPLATE semantics.
595-602: Confirm clearing existing value on EXP → PROMPT/TEMPLATE mode switch is desiredIn
handleModeSwitchWarningContinue, when continuing from EXP to PROMPT/TEMPLATE, the current field value is replaced withrawExpression(""):if ((targetInputMode === InputMode.PROMPT || targetInputMode === InputMode.TEMPLATE) && inputMode === InputMode.EXP && rawExpression) { setValue(key, rawExpression("")); }This discards any existing EXP content instead of attempting to migrate/sanitize it, which is now applied to PROMPT as well as TEMPLATE.
If the UX expectation is that accepting the warning starts with a blank prompt/template (rather than transforming the existing expression), this is fine; otherwise, you may want to base the new value on
currentValueinstead of an empty string.
622-625: Expanded mode gating correctly includes PROMPT and TEMPLATEAllowing
onOpenExpandedModewheninputModeisEXP,PROMPT, orTEMPLATE(in addition to the key whitelist) looks right and ensures PROMPT fields can use the new expanded rich editor:(["query", "instructions", "role"].includes(field.key) || inputMode === InputMode.EXP || inputMode === InputMode.PROMPT || inputMode === InputMode.TEMPLATE)This matches the PR objective of making the simplified editor available from the expanded view for prompt fields.
777-834: Expanded editor PROMPT wiring is consistent, but TEMPLATE handling andmodemapping should be double‑checkedThe expanded editor integration now:
- Mirrors the rawValue/diagnostics/completions logic from the inline editor for PROMPT/TEMPLATE.
- Always passes
sanitizedExpression,rawExpression, andinputMode={inputModeRef.current}.- Maps only PROMPT to
"template"mode:mode={inputModeRef.current === InputMode.EXP ? "expression" : inputModeRef.current === InputMode.PROMPT ? "template" : undefined}Given this, a couple of things to confirm:
TEMPLATE input mode in expanded editor
ForInputMode.TEMPLATE,modebecomesundefinednow. If TEMPLATE is still a supported mode, this changes its expanded‑mode behavior (likely falling back to whatever the default is inExpandedEditor). If TEMPLATE is effectively superseded by PROMPT for the new rich editing experience, this is fine; otherwise, you may still wantInputMode.TEMPLATEto map to"template".Consistency with RichTextTemplateEditor value semantics
Passingvalue={watch(key)}plussanitizedExpression/rawExpressionand usingrawExpression(updatedValue)on change aligns with the RichTextTemplateEditor behavior where token fetching is intentionally not driven by externalvaluechanges, but by user edits inside the expanded editor view. Based on learnings, this looks correct, but it’s worth sanity‑checking that PROMPT mode doesn’t accidentally re‑generate tokens on programmatic updates.If TEMPLATE is truly legacy here, maybe adding a brief comment in this block would help future readers understand why only PROMPT maps to
"template".
|
ChipExpressionEditor component looks LGTM |
7e29c2b to
1d4fa5d
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
♻️ Duplicate comments (1)
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx (1)
391-397: Escape handler still reads stalehelperPaneState.isOpenfrom closure.The Escape keymap is defined inside a
useEffectwith empty deps (line 325), so it captures the initialhelperPaneState({ isOpen: false, ... }). When the helper pane opens, the keymap closure never sees the update, sohelperPaneState.isOpenremainsfalse, and the handler always returnsfalse.This means ProseMirror's keymap never actually handles Escape—it only works because the event bubbles to the document-level listener in
useHelperPaneClickOutside. This is fragile and was flagged in previous reviews.Use the functional updater pattern like you did for
handleKeyboardToggle:"Escape": () => { - if (helperPaneState.isOpen) { - setHelperPaneState(prev => ({ ...prev, isOpen: false })); - return true; - } - return false; + let wasOpen = false; + setHelperPaneState(prev => { + wasOpen = prev.isOpen; + if (prev.isOpen) { + return { ...prev, isOpen: false }; + } + return prev; + }); + return wasOpen; }This ensures the keymap reads the current state and properly handles Escape without relying on fallback behavior.
🧹 Nitpick comments (15)
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/HelperPaneToggleButton.tsx (3)
24-31: Newtitle/displayTextprops are straightforward; consider naming consistencyAdding
title?: stringanddisplayText?: stringis a clean, backward‑compatible way to customize the button. For future clarity, you might consider a more semantically-aligned name likelabelinstead ofdisplayText, since it effectively serves as the visible label for the control.
33-40: Minor typing redundancy inOutlineButtonstyled definitionYou already parameterize
OutlineButtonasstyled.button<{ isOpen: boolean }>; the inline type on the interpolation(props: { isOpen: boolean }) => ...is redundant. Dropping the inline type will keep the source a bit cleaner while still fully typed via the generic:- background-color: ${(props: { isOpen: boolean }) => props.isOpen + background-color: ${(props) => props.isOpen ? ThemeColors.SURFACE : ThemeColors.SURFACE_BRIGHT};
83-107: Consider aligningaria-labelwith customizabledisplayText/ adding an overrideThe new
displayTextandtitlecustomizations are wired correctly and preserve the"Helper Panel"default. One small a11y concern:aria-labelremains hard-coded as"Toggle helper panel"even whendisplayTextchanges, which can cause screen reader text to drift from the visible label. Consider either:
- deriving the
aria-labelfromdisplayTextwhen provided, or- adding an optional
ariaLabelprop to explicitly control it.This keeps visual and assistive text in sync across different helper-pane usages.
workspaces/ballerina/ballerina-side-panel/package.json (2)
20-51: Document version pinning strategy or standardize.The dependency set mixes tilde (~) and caret (^) version specifiers—tilde for CodeMirror, ProseMirror, and some utilities; caret for markdown-it and GitHub components. This is acceptable, but consider documenting the rationale (e.g., "tilde for stable APIs, caret for rapid development") or standardizing the approach for maintainability.
20-51: Monitor bundle size impact.Adding CodeMirror, ProseMirror, markdown-it, and related packages significantly expands the dependency footprint. Ensure the bundle size remains acceptable and that both editors are always shipped together; lazy-loading or code-splitting may be worth investigating if bundle size becomes a concern during or after testing.
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/constants.ts (1)
41-42: Good centralization of helper pane width; consider reusing it in CodeUtils listeners.Defining
HELPER_PANE_WIDTHhere is the right direction. The helper-related listeners inCodeUtils.tsstill hardcode300; importing this constant there would keep all helper-pane positioning logic in sync if the width ever changes. Based on learnings, consolidating shared sizing constants improves maintainability.workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/CodeUtils.ts (1)
430-456: Reuse the shared HELPER_PANE_WIDTH constant instead of hardcoding300in listeners.
buildOnFocusListner,buildOnSelectionChange, andbuildOnChangeListnerall duplicateconst HELPER_PANE_WIDTH = 300;even thoughHELPER_PANE_WIDTHis now exported fromconstants.ts. Importing and using the shared constant will prevent subtle layout skew if the pane width changes in the future.You can refactor as follows:
@@ -import { StateEffect, StateField, RangeSet, Transaction, SelectionRange, Annotation } from "@codemirror/state"; +import { StateEffect, StateField, RangeSet, Transaction, SelectionRange, Annotation } from "@codemirror/state"; @@ -import { - CHIP_TEXT_STYLES, - BASE_CHIP_STYLES, - BASE_ICON_STYLES, - getTokenIconClass, - getTokenTypeColor, - getChipDisplayContent -} from "./chipStyles"; +import { + CHIP_TEXT_STYLES, + BASE_CHIP_STYLES, + BASE_ICON_STYLES, + getTokenIconClass, + getTokenTypeColor, + getChipDisplayContent +} from "./chipStyles"; +import { HELPER_PANE_WIDTH } from "./constants"; @@ - const HELPER_PANE_WIDTH = 300; const editorWidth = editorRect.width; @@ - const HELPER_PANE_WIDTH = 300; const editorWidth = editorRect.width; @@ - const HELPER_PANE_WIDTH = 300; const editorWidth = editorRect.width;Also applies to: 471-491, 552-560
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/markdownCommands.ts (1)
40-74: Consider removingas anycasts on transactions for better type safety.
toggleLinkandconvertListTypecurrently caststate.trtoanyto accessremoveMark,addMark, andreplaceWith. Those methods are part of ProseMirror’s transaction/transform API, so you may be able to rely on the typed surface and drop the casts:- if (dispatch) { - dispatch((state.tr as any).removeMark(from, to, linkMarkType)); - } + if (dispatch) { + dispatch(state.tr.removeMark(from, to, linkMarkType)); + } @@ - const tr = state.tr; + const tr = state.tr; @@ - // Has selection: wrap selection with link - (tr as any).addMark(from, to, mark); + // Has selection: wrap selection with link + tr.addMark(from, to, mark); @@ - const tr = (state.tr as any).replaceWith(pos, pos + node.nodeSize, toListType.create(node.attrs, node.content)); + const tr = state.tr.replaceWith(pos, pos + node.nodeSize, toListType.create(node.attrs, node.content));If your current
prosemirror-state/prosemirror-transformtypings don’t expose these methods cleanly, keeping the casts is acceptable, but it’d be good to revisit as the dependency versions evolve.Also applies to: 100-114
workspaces/ballerina/bi-diagram/src/components/Diagram.tsx (1)
331-336: Safe default expressionContext avoids undefined accessProviding a default
expressionContextobject here prevents consumers from dealing withundefinedand keeps diagrams without expression tooling safe; if you later require callbacks likeonCancelorgetExpressionTokens, consider adding no‑op defaults as well.workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/ExpandedEditor.tsx (1)
64-65: inputMode plumbing into TemplateMode looks good; preview comment is misleadingAdding
inputModetoExpandedPromptEditorPropsand passing it only to thetemplatemode props is consistent with howTemplateModeandNPPromptEditorconsume it.The comment
// Only text mode and prompt mode don't support previewdoesn’t match the code anymore—onlytextforcibly disables preview, whilepromptstill receivesisPreviewMode/onTogglePreview. Consider updating or removing the comment to reflect the current behavior.Also applies to: 156-175, 190-195, 240-252
workspaces/ballerina/bi-diagram/src/components/nodes/PromptNode/PromptNodeWidget.tsx (1)
231-235: Guard against missing NP_FUNCTION when passing node into NPPromptEditor
npFunctionNodeis resolved viaflow.nodes.find(… === "NP_FUNCTION")and then passed directly asnode={npFunctionNode}intoNPPromptEditor. From theNPPromptEditorimplementation,props.nodeis dereferenced (props.node.properties['prompt']) without a null check, so if a flow ever lacks anNP_FUNCTIONnode this will blow up at runtime.If the design guarantees that every prompt node is rendered only in a flow that always contains an
NP_FUNCTION, it’d still be safer to:
- Either assert that invariant (e.g., early return or fallback to
model.node), or- Skip rendering the editor and show a clear error/placeholder when
npFunctionNodeisundefined.The completion retrieval changes and the rest of the
NPPromptEditorwiring look fine once this invariant is ensured.Also applies to: 371-399, 457-475
workspaces/ballerina/ballerina-visualizer/src/views/BI/FocusFlowDiagram/utils.tsx (1)
33-57: createPromptHelperPane wrapper aligns with HelperPaneNew; minor cleanups possibleThe helper correctly:
- Constructs a
Property/FormFieldfor the prompt.- Routes
updateImportsthrough the BI diagram RPC client.- Forwards completions and
handleRetrieveCompletionsvia the debounced function.- Wraps everything in
FieldProviderwithTRIGGER_CHARACTERS.A couple of small follow‑ups you might consider:
exprRefis accepted inCreatePromptHelperPaneParamsbut never used; ifGetHelperPaneFunctiondoesn’t need it here, you can drop it from the params to reduce noise.valueTypeConstraintis typed asstring | string[]but passed asvalueTypeConstraint as string || "ai:Prompt". If an array were ever passed, it would still be an array at runtime. Tightening the type (tostring) or explicitly normalizing arrays would make this more robust.Also applies to: 81-137, 139-143
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionEditor.tsx (1)
411-411: Consider extracting repeated mode check to a helper.The condition
inputMode === InputMode.PROMPT || inputMode === InputMode.TEMPLATEis repeated ~10 times throughout this file. A small helper would reduce duplication and make future mode additions easier:const isTemplateOrPromptMode = (mode: InputMode) => mode === InputMode.PROMPT || mode === InputMode.TEMPLATE;This is a minor refactor suggestion; the current implementation is functionally correct.
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RichTemplateMarkdownToolbar.tsx (1)
299-311: Divider rendered unconditionally after optional helperPaneToggle.When
helperPaneToggleis not provided, the divider on line 311 will still render, creating a visual gap at the start of the toolbar.{helperPaneToggle && ( - <HelperPaneToggleButton + <> + <HelperPaneToggleButton ref={helperPaneToggle.ref} disabled={!editorView} isOpen={helperPaneToggle.isOpen} onClick={helperPaneToggle.onClick} sx={{ marginBottom: 0, width: '90px' }} title="Toggle Helper Panel (Ctrl+/ or Cmd+/)" displayText="Insert" - /> + /> + <ToolbarDivider /> + </> )} - - <ToolbarDivider />workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/ChipExpressionEditor.tsx (1)
183-185: Dependency array forcompletionSourcememo may be overly broad.The
useMemodepends onprops.completions, but the returnedbuildCompletionSource(waitForStateChange)doesn't usecompletionsdirectly — it usescompletionsRef.currentinsidewaitForStateChange. SincecompletionsRefis always kept in sync (lines 339-342), the memoization may cause unnecessary re-computation.Consider using an empty dependency array or removing this memo if
buildCompletionSourceandwaitForStateChangeare stable:const completionSource = useMemo(() => { return buildCompletionSource(waitForStateChange); - }, [props.completions]); + }, []);
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (2)
common/config/rush/pnpm-lock.yamlis excluded by!**/pnpm-lock.yamlworkspaces/common-libs/font-wso2-vscode/src/icons/bi-arrow-down.svgis excluded by!**/*.svg
📒 Files selected for processing (34)
workspaces/ballerina/ballerina-side-panel/package.json(1 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/ExpandedEditor.tsx(5 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/LinkDialog.tsx(1 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RawTemplateMarkdownToolbar.tsx(1 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RichTemplateMarkdownToolbar.tsx(1 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/TemplateMarkdownToolbar.tsx(0 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/ExpressionMode.tsx(1 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/TemplateMode.tsx(5 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/types.ts(2 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/utils/templateUtils.ts(3 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionEditor.tsx(9 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/CodeUtils.ts(3 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/chipStyles.ts(1 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/ChipExpressionEditor.tsx(11 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/HelperPaneToggleButton.tsx(3 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/constants.ts(1 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/hooks/useHelperPane.ts(1 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/types.ts(2 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/utils.ts(2 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx(1 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/chipPlugin.ts(1 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/markdownCommands.ts(1 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/index.ts(1 hunks)workspaces/ballerina/ballerina-visualizer/src/views/BI/FocusFlowDiagram/index.tsx(7 hunks)workspaces/ballerina/ballerina-visualizer/src/views/BI/FocusFlowDiagram/utils.tsx(1 hunks)workspaces/ballerina/ballerina-visualizer/src/views/BI/HelperPaneNew/Components/EmptyItemsPlaceHolder.tsx(1 hunks)workspaces/ballerina/ballerina-visualizer/src/views/BI/HelperPaneNew/Views/DocumentConfig.tsx(2 hunks)workspaces/ballerina/ballerina-visualizer/src/views/BI/HelperPaneNew/utils/utils.ts(1 hunks)workspaces/ballerina/bi-diagram/package.json(1 hunks)workspaces/ballerina/bi-diagram/src/components/Diagram.tsx(1 hunks)workspaces/ballerina/bi-diagram/src/components/DiagramContext.tsx(2 hunks)workspaces/ballerina/bi-diagram/src/components/editors/NPPromptEditor.tsx(1 hunks)workspaces/ballerina/bi-diagram/src/components/nodes/PromptNode/PromptNodeWidget.tsx(7 hunks)workspaces/ballerina/bi-diagram/src/index.tsx(1 hunks)
💤 Files with no reviewable changes (1)
- workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/TemplateMarkdownToolbar.tsx
🚧 Files skipped from review as they are similar to previous changes (7)
- workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/types.ts
- workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/utils.ts
- workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/types.ts
- workspaces/ballerina/ballerina-visualizer/src/views/BI/HelperPaneNew/utils/utils.ts
- workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/ExpressionMode.tsx
- workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/hooks/useHelperPane.ts
- workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/utils/templateUtils.ts
🧰 Additional context used
🧠 Learnings (31)
📓 Common learnings
Learnt from: dan-niles
Repo: wso2/vscode-extensions PR: 980
File: workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx:384-412
Timestamp: 2025-11-24T22:16:28.380Z
Learning: In the RichTextTemplateEditor component (workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx), token fetching on external `value` prop changes is intentionally disabled. Users cannot edit both the minimized and expanded editors simultaneously, so tokens only need to be generated based on user typing in the expanded editor view, not on external prop updates.
📚 Learning: 2025-11-25T06:34:10.812Z
Learnt from: CR
Repo: wso2/vscode-extensions PR: 0
File: workspaces/ballerina/component-diagram/AGENTS.md:0-0
Timestamp: 2025-11-25T06:34:10.812Z
Learning: Applies to workspaces/ballerina/component-diagram/src/index.ts : Export the main Diagram component as the default export from the package entry point (index.ts)
Applied to files:
workspaces/ballerina/bi-diagram/src/index.tsxworkspaces/ballerina/bi-diagram/src/components/Diagram.tsxworkspaces/ballerina/bi-diagram/src/components/DiagramContext.tsxworkspaces/ballerina/ballerina-visualizer/src/views/BI/FocusFlowDiagram/index.tsxworkspaces/ballerina/bi-diagram/package.json
📚 Learning: 2025-11-25T06:34:10.812Z
Learnt from: CR
Repo: wso2/vscode-extensions PR: 0
File: workspaces/ballerina/component-diagram/AGENTS.md:0-0
Timestamp: 2025-11-25T06:34:10.812Z
Learning: Applies to workspaces/ballerina/component-diagram/src/components/DiagramContext.tsx : Use DiagramContext (React Context API) for state management across the diagram component, including expandedNodes and graphQLGroupOpen state
Applied to files:
workspaces/ballerina/bi-diagram/src/index.tsxworkspaces/ballerina/bi-diagram/src/components/Diagram.tsxworkspaces/ballerina/bi-diagram/src/components/DiagramContext.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/ChipExpressionEditor.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/LinkDialog.tsxworkspaces/ballerina/ballerina-visualizer/src/views/BI/FocusFlowDiagram/index.tsxworkspaces/ballerina/bi-diagram/package.jsonworkspaces/ballerina/bi-diagram/src/components/nodes/PromptNode/PromptNodeWidget.tsx
📚 Learning: 2025-11-25T06:34:10.812Z
Learnt from: CR
Repo: wso2/vscode-extensions PR: 0
File: workspaces/ballerina/component-diagram/AGENTS.md:0-0
Timestamp: 2025-11-25T06:34:10.812Z
Learning: Applies to workspaces/ballerina/component-diagram/src/components/**/*.tsx : Use React 18.2.0 features including concurrent rendering and automatic batching; avoid class components in favor of functional components with hooks
Applied to files:
workspaces/ballerina/bi-diagram/src/index.tsxworkspaces/ballerina/bi-diagram/src/components/Diagram.tsxworkspaces/ballerina/bi-diagram/src/components/DiagramContext.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/ChipExpressionEditor.tsxworkspaces/ballerina/bi-diagram/src/components/editors/NPPromptEditor.tsxworkspaces/ballerina/ballerina-visualizer/src/views/BI/HelperPaneNew/Components/EmptyItemsPlaceHolder.tsxworkspaces/ballerina/ballerina-visualizer/src/views/BI/HelperPaneNew/Views/DocumentConfig.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RichTemplateMarkdownToolbar.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RawTemplateMarkdownToolbar.tsxworkspaces/ballerina/ballerina-side-panel/package.jsonworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/TemplateMode.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/LinkDialog.tsxworkspaces/ballerina/ballerina-visualizer/src/views/BI/FocusFlowDiagram/utils.tsxworkspaces/ballerina/ballerina-visualizer/src/views/BI/FocusFlowDiagram/index.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsxworkspaces/ballerina/bi-diagram/package.jsonworkspaces/ballerina/bi-diagram/src/components/nodes/PromptNode/PromptNodeWidget.tsx
📚 Learning: 2025-11-25T06:34:10.812Z
Learnt from: CR
Repo: wso2/vscode-extensions PR: 0
File: workspaces/ballerina/component-diagram/AGENTS.md:0-0
Timestamp: 2025-11-25T06:34:10.812Z
Learning: Applies to workspaces/ballerina/component-diagram/src/**/*.{ts,tsx} : Define all constants (node types, sizing, spacing) in src/resources/constants.ts and import them where needed instead of hardcoding values
Applied to files:
workspaces/ballerina/bi-diagram/src/index.tsxworkspaces/ballerina/bi-diagram/src/components/Diagram.tsxworkspaces/ballerina/bi-diagram/src/components/DiagramContext.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/constants.tsworkspaces/ballerina/ballerina-visualizer/src/views/BI/HelperPaneNew/Components/EmptyItemsPlaceHolder.tsxworkspaces/ballerina/ballerina-side-panel/package.jsonworkspaces/ballerina/ballerina-visualizer/src/views/BI/FocusFlowDiagram/index.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/chipStyles.tsworkspaces/ballerina/bi-diagram/package.jsonworkspaces/ballerina/bi-diagram/src/components/nodes/PromptNode/PromptNodeWidget.tsx
📚 Learning: 2025-11-25T06:34:10.812Z
Learnt from: CR
Repo: wso2/vscode-extensions PR: 0
File: workspaces/ballerina/component-diagram/AGENTS.md:0-0
Timestamp: 2025-11-25T06:34:10.812Z
Learning: Applies to workspaces/ballerina/component-diagram/src/resources/icons/**/*.tsx : Create separate SVG icon components in src/resources/icons/ for all diagram icons and import them as React components
Applied to files:
workspaces/ballerina/bi-diagram/src/index.tsxworkspaces/ballerina/bi-diagram/src/components/DiagramContext.tsxworkspaces/ballerina/ballerina-side-panel/package.jsonworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/LinkDialog.tsxworkspaces/ballerina/ballerina-visualizer/src/views/BI/FocusFlowDiagram/index.tsxworkspaces/ballerina/bi-diagram/package.json
📚 Learning: 2025-11-25T06:34:10.812Z
Learnt from: CR
Repo: wso2/vscode-extensions PR: 0
File: workspaces/ballerina/component-diagram/AGENTS.md:0-0
Timestamp: 2025-11-25T06:34:10.812Z
Learning: Applies to workspaces/ballerina/component-diagram/src/components/Diagram.tsx : Implement proper error boundaries around the Diagram component to gracefully handle rendering errors without crashing the parent application
Applied to files:
workspaces/ballerina/bi-diagram/src/index.tsxworkspaces/ballerina/bi-diagram/src/components/Diagram.tsxworkspaces/ballerina/bi-diagram/src/components/DiagramContext.tsxworkspaces/ballerina/ballerina-visualizer/src/views/BI/FocusFlowDiagram/index.tsxworkspaces/ballerina/bi-diagram/package.json
📚 Learning: 2025-11-25T06:34:10.812Z
Learnt from: CR
Repo: wso2/vscode-extensions PR: 0
File: workspaces/ballerina/component-diagram/AGENTS.md:0-0
Timestamp: 2025-11-25T06:34:10.812Z
Learning: Applies to workspaces/ballerina/component-diagram/src/utils/diagram.ts : Create function-level links instead of service-level links: each function should connect individually to its target connections, not the entire service
Applied to files:
workspaces/ballerina/bi-diagram/src/index.tsxworkspaces/ballerina/bi-diagram/src/components/Diagram.tsx
📚 Learning: 2025-11-25T06:34:10.812Z
Learnt from: CR
Repo: wso2/vscode-extensions PR: 0
File: workspaces/ballerina/component-diagram/AGENTS.md:0-0
Timestamp: 2025-11-25T06:34:10.812Z
Learning: Applies to workspaces/ballerina/component-diagram/src/components/nodes/EntryNode/components/**/*.tsx : Implement lazy expansion of functions: only render function items when they are visible to improve performance for large function lists
Applied to files:
workspaces/ballerina/bi-diagram/src/index.tsxworkspaces/ballerina/bi-diagram/src/components/DiagramContext.tsxworkspaces/ballerina/bi-diagram/src/components/editors/NPPromptEditor.tsxworkspaces/ballerina/ballerina-visualizer/src/views/BI/HelperPaneNew/Components/EmptyItemsPlaceHolder.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/TemplateMode.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/LinkDialog.tsxworkspaces/ballerina/ballerina-visualizer/src/views/BI/FocusFlowDiagram/index.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/index.tsworkspaces/ballerina/bi-diagram/src/components/nodes/PromptNode/PromptNodeWidget.tsx
📚 Learning: 2025-11-25T06:34:10.812Z
Learnt from: CR
Repo: wso2/vscode-extensions PR: 0
File: workspaces/ballerina/component-diagram/AGENTS.md:0-0
Timestamp: 2025-11-25T06:34:10.812Z
Learning: Applies to workspaces/ballerina/component-diagram/src/**/diagram.ts : Register custom factories with the diagram engine: NodePortFactory, NodeLinkFactory, ListenerNodeFactory, EntryNodeFactory, ConnectionNodeFactory, and OverlayLayerFactory
Applied to files:
workspaces/ballerina/bi-diagram/src/index.tsx
📚 Learning: 2025-11-25T06:34:10.812Z
Learnt from: CR
Repo: wso2/vscode-extensions PR: 0
File: workspaces/ballerina/component-diagram/AGENTS.md:0-0
Timestamp: 2025-11-25T06:34:10.812Z
Learning: Applies to workspaces/ballerina/component-diagram/src/utils/diagram.ts : Filter out autogenerated connections (symbol starting with '_') and connections with enableFlowModel=false before rendering
Applied to files:
workspaces/ballerina/bi-diagram/src/index.tsxworkspaces/ballerina/ballerina-visualizer/src/views/BI/FocusFlowDiagram/index.tsx
📚 Learning: 2025-11-25T06:34:10.812Z
Learnt from: CR
Repo: wso2/vscode-extensions PR: 0
File: workspaces/ballerina/component-diagram/AGENTS.md:0-0
Timestamp: 2025-11-25T06:34:10.812Z
Learning: Applies to workspaces/ballerina/component-diagram/src/**/*.{ts,tsx} : All async operations and promise handling in diagram utilities should use async/await syntax instead of .then() callbacks
Applied to files:
workspaces/ballerina/bi-diagram/src/index.tsxworkspaces/ballerina/ballerina-visualizer/src/views/BI/FocusFlowDiagram/index.tsxworkspaces/ballerina/bi-diagram/package.json
📚 Learning: 2025-11-25T06:34:10.812Z
Learnt from: CR
Repo: wso2/vscode-extensions PR: 0
File: workspaces/ballerina/component-diagram/AGENTS.md:0-0
Timestamp: 2025-11-25T06:34:10.812Z
Learning: Applies to workspaces/ballerina/component-diagram/src/utils/diagram.ts : Implement dynamic node height calculation based on visible function count: BASE_HEIGHT (72px) + (FUNCTION_HEIGHT (48px) per visible function) + VIEW_ALL_BUTTON_HEIGHT (40px if needed)
Applied to files:
workspaces/ballerina/bi-diagram/src/index.tsxworkspaces/ballerina/ballerina-visualizer/src/views/BI/FocusFlowDiagram/index.tsx
📚 Learning: 2025-11-25T06:34:10.812Z
Learnt from: CR
Repo: wso2/vscode-extensions PR: 0
File: workspaces/ballerina/component-diagram/AGENTS.md:0-0
Timestamp: 2025-11-25T06:34:10.812Z
Learning: Applies to workspaces/ballerina/component-diagram/src/components/nodes/**/!(*Widget|*Model).tsx : Implement the factory pattern for node instantiation: each node type (Listener, Entry, Connection) must have a corresponding Factory class that extends the appropriate factory interface
Applied to files:
workspaces/ballerina/bi-diagram/src/index.tsxworkspaces/ballerina/bi-diagram/src/components/nodes/PromptNode/PromptNodeWidget.tsx
📚 Learning: 2025-11-25T06:34:10.812Z
Learnt from: CR
Repo: wso2/vscode-extensions PR: 0
File: workspaces/ballerina/component-diagram/AGENTS.md:0-0
Timestamp: 2025-11-25T06:34:10.812Z
Learning: Applies to workspaces/ballerina/component-diagram/src/components/Diagram.tsx : Debounce diagram repaints to avoid excessive re-renders when state changes occur
Applied to files:
workspaces/ballerina/bi-diagram/src/components/Diagram.tsxworkspaces/ballerina/bi-diagram/src/components/DiagramContext.tsxworkspaces/ballerina/ballerina-visualizer/src/views/BI/FocusFlowDiagram/index.tsx
📚 Learning: 2025-11-25T06:34:10.812Z
Learnt from: CR
Repo: wso2/vscode-extensions PR: 0
File: workspaces/ballerina/component-diagram/AGENTS.md:0-0
Timestamp: 2025-11-25T06:34:10.812Z
Learning: Applies to workspaces/ballerina/component-diagram/src/components/Diagram.tsx : Implement input validation for CDModel structure: verify that all required properties (connections, listeners, services) are present and properly typed
Applied to files:
workspaces/ballerina/bi-diagram/src/components/Diagram.tsxworkspaces/ballerina/bi-diagram/src/components/DiagramContext.tsx
📚 Learning: 2025-11-25T06:34:10.812Z
Learnt from: CR
Repo: wso2/vscode-extensions PR: 0
File: workspaces/ballerina/component-diagram/AGENTS.md:0-0
Timestamp: 2025-11-25T06:34:10.812Z
Learning: Applies to workspaces/ballerina/component-diagram/src/components/(Diagram|DiagramCanvas|Controls)*.tsx : Store diagram zoom and offset positions in state; optionally cache them in localStorage for session persistence
Applied to files:
workspaces/ballerina/bi-diagram/src/components/Diagram.tsxworkspaces/ballerina/bi-diagram/src/components/DiagramContext.tsxworkspaces/ballerina/ballerina-visualizer/src/views/BI/FocusFlowDiagram/index.tsx
📚 Learning: 2025-11-27T07:59:33.534Z
Learnt from: KCSAbeywickrama
Repo: wso2/vscode-extensions PR: 897
File: workspaces/ballerina/data-mapper/src/components/DataMapper/SidePanel/QueryClauses/ClausesPanel.tsx:50-59
Timestamp: 2025-11-27T07:59:33.534Z
Learning: In workspaces/ballerina/data-mapper/src/components/DataMapper/SidePanel/QueryClauses/ClausesPanel.tsx, the `clause.properties.expression` property in the `fillDefaults` function does not require defensive null/undefined checks because it's a required property enforced by form validation in ClauseEditor.
Applied to files:
workspaces/ballerina/bi-diagram/src/components/Diagram.tsxworkspaces/ballerina/bi-diagram/src/components/DiagramContext.tsx
📚 Learning: 2025-11-24T14:51:49.267Z
Learnt from: KCSAbeywickrama
Repo: wso2/vscode-extensions PR: 998
File: workspaces/ballerina/data-mapper/src/components/DataMapper/Header/ExpressionBar.tsx:113-132
Timestamp: 2025-11-24T14:51:49.267Z
Learning: In workspaces/ballerina/data-mapper/src/components/DataMapper/Header/ExpressionBar.tsx, if `textFieldRef.current` is not undefined, `textFieldRef.current.inputElement` is guaranteed to exist. If `inputElement` doesn't exist when `current` exists, it's a fatal error that should reach the error boundary rather than being handled with defensive null checks.
Applied to files:
workspaces/ballerina/bi-diagram/src/components/DiagramContext.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/TemplateMode.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionEditor.tsxworkspaces/ballerina/bi-diagram/src/components/nodes/PromptNode/PromptNodeWidget.tsx
📚 Learning: 2025-11-24T22:16:28.380Z
Learnt from: dan-niles
Repo: wso2/vscode-extensions PR: 980
File: workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx:384-412
Timestamp: 2025-11-24T22:16:28.380Z
Learning: In the RichTextTemplateEditor component (workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx), token fetching on external `value` prop changes is intentionally disabled. Users cannot edit both the minimized and expanded editors simultaneously, so tokens only need to be generated based on user typing in the expanded editor view, not on external prop updates.
Applied to files:
workspaces/ballerina/bi-diagram/src/components/DiagramContext.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/ChipExpressionEditor.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/CodeUtils.tsworkspaces/ballerina/bi-diagram/src/components/editors/NPPromptEditor.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/HelperPaneToggleButton.tsxworkspaces/ballerina/ballerina-visualizer/src/views/BI/HelperPaneNew/Views/DocumentConfig.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RichTemplateMarkdownToolbar.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RawTemplateMarkdownToolbar.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/chipPlugin.tsworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/TemplateMode.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/LinkDialog.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionEditor.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/ExpandedEditor.tsxworkspaces/ballerina/ballerina-visualizer/src/views/BI/FocusFlowDiagram/index.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/index.tsworkspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/markdownCommands.tsworkspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/chipStyles.tsworkspaces/ballerina/bi-diagram/src/components/nodes/PromptNode/PromptNodeWidget.tsx
📚 Learning: 2025-11-25T06:34:10.812Z
Learnt from: CR
Repo: wso2/vscode-extensions PR: 0
File: workspaces/ballerina/component-diagram/AGENTS.md:0-0
Timestamp: 2025-11-25T06:34:10.812Z
Learning: Applies to workspaces/ballerina/component-diagram/src/components/**/*.tsx : Use Emotion for CSS-in-JS styling instead of inline styles or external CSS files
Applied to files:
workspaces/ballerina/ballerina-visualizer/src/views/BI/HelperPaneNew/Components/EmptyItemsPlaceHolder.tsxworkspaces/ballerina/ballerina-side-panel/package.jsonworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/TemplateMode.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/LinkDialog.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/chipStyles.tsworkspaces/ballerina/bi-diagram/package.json
📚 Learning: 2025-11-26T07:49:56.428Z
Learnt from: KCSAbeywickrama
Repo: wso2/vscode-extensions PR: 653
File: workspaces/bi/bi-extension/src/test/e2e-playwright-tests/data-mapper/DataMapperUtils.ts:136-141
Timestamp: 2025-11-26T07:49:56.428Z
Learning: In workspaces/bi/bi-extension/src/test/e2e-playwright-tests/data-mapper/DataMapperUtils.ts, the goPrevViewBackButton() method is only called when in a focused view, ensuring breadcrumbs are always present. No guard for empty breadcrumbs is needed.
Applied to files:
workspaces/ballerina/ballerina-visualizer/src/views/BI/HelperPaneNew/Components/EmptyItemsPlaceHolder.tsxworkspaces/ballerina/ballerina-visualizer/src/views/BI/HelperPaneNew/Views/DocumentConfig.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RawTemplateMarkdownToolbar.tsx
📚 Learning: 2025-11-26T06:34:09.752Z
Learnt from: KCSAbeywickrama
Repo: wso2/vscode-extensions PR: 653
File: workspaces/bi/bi-extension/src/test/e2e-playwright-tests/data-mapper/DataMapperUtils.ts:128-134
Timestamp: 2025-11-26T06:34:09.752Z
Learning: In workspaces/bi/bi-extension/src/test/e2e-playwright-tests/data-mapper/DataMapperUtils.ts, the goPrevViewBreadcrumb() method is only called when in a focused view, ensuring breadcrumbs are always present. No guard for empty breadcrumbs is needed.
Applied to files:
workspaces/ballerina/ballerina-visualizer/src/views/BI/HelperPaneNew/Components/EmptyItemsPlaceHolder.tsx
📚 Learning: 2025-11-26T06:35:19.217Z
Learnt from: KCSAbeywickrama
Repo: wso2/vscode-extensions PR: 653
File: workspaces/bi/bi-extension/src/test/e2e-playwright-tests/data-mapper/DataMapperUtils.ts:173-178
Timestamp: 2025-11-26T06:35:19.217Z
Learning: In workspaces/bi/bi-extension/src/test/e2e-playwright-tests/data-mapper/DataMapperUtils.ts, the commented-out debugging block in the verifyFileContent function (lines 172-177 containing console.log, page.pause, and updateDataFileSync) is intentionally kept as a developer utility for updating test data files when needed. It should not be removed.
Applied to files:
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RichTemplateMarkdownToolbar.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RawTemplateMarkdownToolbar.tsx
📚 Learning: 2025-11-25T06:34:10.812Z
Learnt from: CR
Repo: wso2/vscode-extensions PR: 0
File: workspaces/ballerina/component-diagram/AGENTS.md:0-0
Timestamp: 2025-11-25T06:34:10.812Z
Learning: Applies to workspaces/ballerina/component-diagram/**/*.config.{js,ts} : Use minimatch-compatible glob patterns for file matching in build and test configuration files
Applied to files:
workspaces/ballerina/ballerina-side-panel/package.jsonworkspaces/ballerina/bi-diagram/package.json
📚 Learning: 2025-11-25T06:34:10.812Z
Learnt from: CR
Repo: wso2/vscode-extensions PR: 0
File: workspaces/ballerina/component-diagram/AGENTS.md:0-0
Timestamp: 2025-11-25T06:34:10.812Z
Learning: Applies to workspaces/ballerina/component-diagram/src/**/*.{ts,tsx} : Use TypeScript 5.8.3 with strict type checking enabled for all source files
Applied to files:
workspaces/ballerina/ballerina-side-panel/package.jsonworkspaces/ballerina/bi-diagram/package.json
📚 Learning: 2025-11-20T11:04:33.712Z
Learnt from: KCSAbeywickrama
Repo: wso2/vscode-extensions PR: 898
File: workspaces/ballerina/data-mapper/src/components/DataMapper/SidePanel/QueryClauses/ClausesPanel.tsx:38-38
Timestamp: 2025-11-20T11:04:33.712Z
Learning: In workspaces/ballerina/data-mapper/src/components/DataMapper/SidePanel/QueryClauses/ClausesPanel.tsx, the use of `useDMQueryClausesPanelStore.getState()` to access `clauseToAdd` and `setClauseToAdd` (instead of the hook subscription pattern) is intentional to prevent re-renders when these state values change.
Applied to files:
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/TemplateMode.tsxworkspaces/ballerina/ballerina-visualizer/src/views/BI/FocusFlowDiagram/index.tsx
📚 Learning: 2025-11-10T15:04:50.474Z
Learnt from: madushajg
Repo: wso2/vscode-extensions PR: 868
File: workspaces/bi/bi-extension/src/utils.ts:153-169
Timestamp: 2025-11-10T15:04:50.474Z
Learning: The workspaces/bi/bi-extension and workspaces/ballerina/ballerina-extension are separate, independently deployable VSCode extensions in the wso2/vscode-extensions repository. Code duplication between these extensions is acceptable and often necessary to maintain their independence, rather than creating cross-extension dependencies.
Applied to files:
workspaces/ballerina/bi-diagram/package.json
📚 Learning: 2025-11-10T15:05:11.309Z
Learnt from: madushajg
Repo: wso2/vscode-extensions PR: 868
File: workspaces/bi/bi-extension/src/utils.ts:224-242
Timestamp: 2025-11-10T15:05:11.309Z
Learning: The workspaces/bi/bi-extension and workspaces/ballerina/ballerina-extension are separate VS Code extensions that are packaged and distributed independently, so they cannot share code via imports and must maintain their own implementations of common utilities.
Applied to files:
workspaces/ballerina/bi-diagram/package.json
📚 Learning: 2025-11-25T06:34:10.812Z
Learnt from: CR
Repo: wso2/vscode-extensions PR: 0
File: workspaces/ballerina/component-diagram/AGENTS.md:0-0
Timestamp: 2025-11-25T06:34:10.812Z
Learning: Applies to workspaces/ballerina/component-diagram/src/stories/**/*.json : Provide sample data files in JSON format for Storybook stories covering: empty project, automation only, simple service, multiple services, complex connections, AI services, GraphQL services, and multiple connections
Applied to files:
workspaces/ballerina/bi-diagram/package.json
📚 Learning: 2025-11-25T06:34:10.812Z
Learnt from: CR
Repo: wso2/vscode-extensions PR: 0
File: workspaces/ballerina/component-diagram/AGENTS.md:0-0
Timestamp: 2025-11-25T06:34:10.812Z
Learning: Applies to workspaces/ballerina/component-diagram/src/components/nodes/**/*.{ts,tsx} : Each node type must have a Model class extending NodeModel, a Factory class implementing the factory pattern, and a Widget React component for visual representation
Applied to files:
workspaces/ballerina/bi-diagram/src/components/nodes/PromptNode/PromptNodeWidget.tsx
🧬 Code graph analysis (13)
workspaces/ballerina/bi-diagram/src/components/DiagramContext.tsx (5)
workspaces/ballerina/bi-diagram/src/index.tsx (1)
GetHelperPaneFunction(29-29)workspaces/common-libs/ui-toolkit/src/components/ExpressionEditor/types/form.ts (1)
FormExpressionEditorRef(79-83)workspaces/ballerina/ballerina-side-panel/src/components/Form/types.ts (1)
HelperpaneOnChangeOptions(96-99)workspaces/ballerina/ballerina-core/src/interfaces/bi.ts (1)
RecordTypeField(154-158)workspaces/ballerina/ballerina-side-panel/src/components/editors/index.ts (1)
InputMode(31-31)
workspaces/ballerina/ballerina-visualizer/src/views/BI/HelperPaneNew/Views/DocumentConfig.tsx (1)
workspaces/ballerina/ballerina-side-panel/src/components/editors/index.ts (1)
InputMode(31-31)
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RichTemplateMarkdownToolbar.tsx (5)
workspaces/common-libs/ui-toolkit/src/styles/Theme.ts (1)
ThemeColors(79-104)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/markdownCommands.ts (14)
toggleHeading(76-86)toggleLink(40-74)isMarkActive(144-150)isNodeActive(152-162)isListActive(164-178)canUndo(188-190)canRedo(192-194)undoCommand(180-182)redoCommand(184-186)toggleBold(28-30)toggleItalic(32-34)toggleBlockquote(92-98)toggleBulletList(116-128)toggleOrderedList(130-142)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/HelperPaneToggleButton.tsx (1)
HelperPaneToggleButton(83-109)workspaces/common-libs/ui-toolkit/src/components/Swich/Swich.tsx (1)
Switch(146-176)workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/LinkDialog.tsx (1)
LinkDialog(90-175)
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RawTemplateMarkdownToolbar.tsx (3)
workspaces/common-libs/ui-toolkit/src/styles/Theme.ts (1)
ThemeColors(79-104)workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/utils/templateUtils.ts (10)
insertMarkdownFormatting(25-75)insertMarkdownLink(104-155)insertMarkdownBlockquote(160-193)insertMarkdownUnorderedList(252-258)insertMarkdownOrderedList(260-266)insertMarkdownHeader(80-99)canUndo(373-376)canRedo(381-384)undoCommand(353-358)redoCommand(363-368)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/HelperPaneToggleButton.tsx (1)
HelperPaneToggleButton(83-109)
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/chipPlugin.ts (4)
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/types.ts (2)
TokenMetadata(64-68)CompoundTokenSequence(90-98)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/chipStyles.ts (6)
getChipDisplayContent(107-109)getTokenTypeColor(99-101)BASE_CHIP_STYLES(22-37)getTokenIconClass(92-97)BASE_ICON_STYLES(39-42)CHIP_TEXT_STYLES(44-48)workspaces/ballerina/component-diagram/src/components/nodes/EntryNode/components/styles.ts (1)
colors(228-236)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/utils.ts (3)
ParsedToken(105-110)getParsedExpressionTokens(112-138)detectTokenPatterns(278-332)
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/TemplateMode.tsx (2)
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RawTemplateMarkdownToolbar.tsx (1)
RawTemplateMarkdownToolbar(179-402)workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RichTemplateMarkdownToolbar.tsx (1)
RichTemplateMarkdownToolbar(184-463)
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/LinkDialog.tsx (4)
workspaces/common-libs/ui-toolkit/src/styles/Theme.ts (1)
ThemeColors(79-104)workspaces/mcp-inspector/mcp-inspector-extension/src/client-wrapper.js (1)
url(57-57)workspaces/common-libs/ui-toolkit/src/components/Codicon/Codicon.tsx (1)
Codicon(44-56)workspaces/common-libs/ui-toolkit/src/components/Button/Button.tsx (1)
Button(54-65)
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionEditor.tsx (1)
workspaces/ballerina/ballerina-side-panel/src/components/editors/index.ts (1)
InputMode(31-31)
workspaces/ballerina/ballerina-visualizer/src/views/BI/FocusFlowDiagram/utils.tsx (3)
workspaces/common-libs/ui-toolkit/src/components/ExpressionEditor/types/form.ts (1)
FormExpressionEditorRef(79-83)workspaces/ballerina/ballerina-side-panel/src/components/editors/index.ts (1)
InputMode(31-31)workspaces/ballerina/ballerina-rpc-client/src/BallerinaRpcClient.ts (1)
BallerinaRpcClient(72-262)
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/ExpandedEditor.tsx (1)
workspaces/ballerina/ballerina-side-panel/src/components/editors/index.ts (1)
InputMode(31-31)
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx (3)
workspaces/common-libs/ui-toolkit/src/styles/Theme.ts (1)
ThemeColors(79-104)workspaces/ballerina/ballerina-side-panel/src/context/form.tsx (1)
useFormContext(70-70)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/markdownCommands.ts (6)
toggleBold(28-30)toggleItalic(32-34)toggleHeading(76-86)toggleBlockquote(92-98)toggleBulletList(116-128)toggleOrderedList(130-142)
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/markdownCommands.ts (1)
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/utils/templateUtils.ts (4)
undoCommand(353-358)redoCommand(363-368)canUndo(373-376)canRedo(381-384)
workspaces/ballerina/bi-diagram/src/components/nodes/PromptNode/PromptNodeWidget.tsx (2)
workspaces/ballerina/bi-diagram/src/components/editors/NPPromptEditor.tsx (1)
NPPromptEditor(110-413)workspaces/ballerina/ballerina-side-panel/src/components/editors/index.ts (1)
InputMode(31-31)
...ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/LinkDialog.tsx
Show resolved
Hide resolved
workspaces/ballerina/bi-diagram/src/components/editors/NPPromptEditor.tsx
Show resolved
Hide resolved
…and pnpm-lock.yaml
ff20805 to
766e30f
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
♻️ Duplicate comments (1)
workspaces/ballerina/bi-diagram/src/components/editors/NPPromptEditor.tsx (1)
173-203: Stale closure issue persists.The dependency array for
fetchDiagnosticsstill doesn't includeprops.node, whichcreatePropertyreferences. This was flagged in a previous review.
🧹 Nitpick comments (17)
workspaces/ballerina/bi-diagram/src/components/editors/NPPromptEditor.tsx (1)
313-340:formContextValuerecreated on every render.
expressionEditoris created inline (lines 288-311) without memoization, so including it in the dependency array meansformContextValuewill be recreated on every render, negating theuseMemobenefit.Consider memoizing
expressionEditorseparately or extracting stable dependencies.workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/types.ts (1)
107-115: Consider typingclickedChipNodemore specifically.Using
anyforclickedChipNodeworks but loses type safety. If this always holds a ProseMirrorNode, consider typing it asNode | undefined(fromprosemirror-model). However, if the type varies based on context,anyis acceptable for flexibility.workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/HelperPaneToggleButton.tsx (1)
106-106: Consider using nullish coalescing for the default value.The ternary works but nullish coalescing is more idiomatic for default values.
- <ButtonText>{displayText ? displayText : "Helper Panel"}</ButtonText> + <ButtonText>{displayText ?? "Helper Panel"}</ButtonText>workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/TemplateMode.tsx (1)
47-50: Consider removing the redundant wrapper function.The
handleChangefunction simply forwards both arguments without transformation. You can passonChangedirectly to avoid the extra function layer.- // Convert onChange signature from (value: string) => void to (value: string, cursorPosition: number) => void - const handleChange = (updatedValue: string, updatedCursorPosition: number) => { - onChange(updatedValue, updatedCursorPosition); - }; - return ( <> <ExpressionContainer> <ChipExpressionEditorComponent value={value} - onChange={handleChange} + onChange={onChange}workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionEditor.tsx (2)
411-411: Consider extracting the repeated mode check into a helper.The pattern
(inputMode === InputMode.PROMPT || inputMode === InputMode.TEMPLATE)is repeated across multiple locations (lines 411, 418, 460, 570, 599, 705, 706, 715, 718, 785, 788). Extract it to improve maintainability.// Add near other helpers or in utils.ts const isMarkdownMode = (mode: InputMode): boolean => mode === InputMode.PROMPT || mode === InputMode.TEMPLATE;Then replace occurrences like:
-const fieldValue = (inputModeRef.current === InputMode.PROMPT || inputModeRef.current === InputMode.TEMPLATE) && rawExpression ? rawExpression(watch(key)) : watch(key); +const fieldValue = isMarkdownMode(inputModeRef.current) && rawExpression ? rawExpression(watch(key)) : watch(key);
779-816: Significant code duplication between the two onChange handlers.The onChange handler passed to
ExpandedEditor(lines 779-816) is nearly identical to the one passed toExpressionField(lines 709-746). Consider extracting a shared handler function to reduce duplication and ensure consistent behavior.// Extract shared handler const createChangeHandler = (controllerOnChange: (value: string) => void) => async (updatedValue: string, updatedCursorPosition: number) => { setFormDiagnostics([]); const currentMode = inputModeRef.current; const rawValue = isMarkdownMode(currentMode) && rawExpression ? rawExpression(updatedValue) : updatedValue; controllerOnChange(rawValue); if (getExpressionEditorDiagnostics && (currentMode === InputMode.EXP || isMarkdownMode(currentMode))) { getExpressionEditorDiagnostics( (required ?? !field.optional) || rawValue !== '', rawValue, key, getPropertyFromFormField(field) ); } const triggerCharacter = updatedCursorPosition > 0 ? triggerCharacters.find((char) => rawValue[updatedCursorPosition - 1] === char) : undefined; await retrieveCompletions( rawValue, getPropertyFromFormField(field), updatedCursorPosition, triggerCharacter ); };workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/PromptMode.tsx (3)
39-39: Consider exporting or documenting SIMPLE_PROMPT_FIELDS.This constant determines behavior for specific field keys. If these fields are referenced elsewhere or the list might change, consider moving it to a shared constants file or adding a comment explaining the criteria.
62-66: Consider extracting the helper pane toggle state type.The inline type definition for
helperPaneTogglestate is repeated in concept. A named interface would improve readability and reusability.interface HelperPaneToggleState { ref: React.RefObject<HTMLButtonElement>; isOpen: boolean; onClick: () => void; } const [helperPaneToggle, setHelperPaneToggle] = useState<HelperPaneToggleState | null>(null);
70-73: Same redundant wrapper as noted in TemplateMode.The
handleChangefunction just passes arguments through. Consider passingonChangedirectly to the child components.workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RichTemplateMarkdownToolbar.tsx (1)
61-93: Consider using emotion's typed props pattern more idiomatically.The explicit type annotation
(props: { isActive?: boolean })in the template literal is redundant since the generic already defines the prop type. Emotion infers props from the generic.const ToolbarButton = styled.button<{ isActive?: boolean }>` display: flex; align-items: center; justify-content: center; width: 32px; height: 32px; padding: 0; - background-color: ${(props: { isActive?: boolean }) => props.isActive ? ThemeColors.SECONDARY_CONTAINER : 'transparent'}; + background-color: ${props => props.isActive ? ThemeColors.SECONDARY_CONTAINER : 'transparent'}; color: ${ThemeColors.ON_SURFACE}; - border: 1px solid ${(props: { isActive?: boolean }) => props.isActive ? ThemeColors.OUTLINE : 'transparent'}; + border: 1px solid ${props => props.isActive ? ThemeColors.OUTLINE : 'transparent'};workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx (1)
391-397: Escape keymap handler may read stalehelperPaneState.isOpen.This handler captures
helperPaneStatein the closure when the keymap plugin is created (empty-deps useEffect). The conditionhelperPaneState.isOpenmay not reflect current state.However, since
setHelperPaneStateuses a functional updater that returns unchanged state when not open, this is partially mitigated. The handler will still always callsetHelperPaneStatebut won't cause incorrect state.For consistency with the fixed
handleKeyboardToggle, consider using a ref or purely functional pattern:"Escape": () => { - if (helperPaneState.isOpen) { - setHelperPaneState(prev => ({ ...prev, isOpen: false })); - return true; - } - return false; + let wasOpen = false; + setHelperPaneState(prev => { + wasOpen = prev.isOpen; + return prev.isOpen ? { ...prev, isOpen: false } : prev; + }); + return wasOpen; }workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RawTemplateMarkdownToolbar.tsx (1)
37-166: Significant duplication with RichTemplateMarkdownToolbar styled components.The styled components (ToolbarContainer, ToolbarButton, ToolbarDivider, SplitButtonContainer, etc.) are nearly identical to those in RichTemplateMarkdownToolbar.tsx.
Consider extracting shared styled components to a common module:
// controls/ToolbarStyles.ts export const ToolbarContainer = styled.div`...`; export const ToolbarButton = styled.button<{ isActive?: boolean }>`...`; export const ToolbarDivider = styled.div`...`; // etc.Then import in both toolbars to reduce maintenance burden.
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/markdownCommands.ts (1)
40-74: Type assertions (as any) bypass type safety.Lines 48 and 67 use
(state.tr as any)to accessremoveMarkandaddMark. These methods exist on Transaction but TypeScript may not recognize them due to version mismatches or declaration issues.If the methods exist at runtime, consider adding a type assertion or extending the Transaction type:
// At top of file or in a types file declare module "prosemirror-state" { interface Transaction { addMark(from: number, to: number, mark: Mark): Transaction; removeMark(from: number, to: number, mark?: Mark | MarkType): Transaction; } }This would eliminate the
as anycasts while maintaining type safety.workspaces/ballerina/ballerina-visualizer/src/views/BI/FocusFlowDiagram/index.tsx (2)
604-642: Unused parameterisAssignIdentifierincreateHelperPane.The
isAssignIdentifierparameter is received but never passed tocreatePromptHelperPane. If this is intentional (e.g., not applicable for prompt helper panes), consider documenting it or removing it from the destructured parameters to avoid confusion.const createHelperPane = useCallback<GetHelperPaneFunction>(( fieldKey, exprRef, anchorRef, defaultValue, value, onChange, changeHelperPaneState, helperPaneHeight, recordTypeField, - isAssignIdentifier, + _isAssignIdentifier, // Not used for prompt helper panes valueTypeConstraint, inputMode ) => {
534-544: Consider memoizinghandleGetExpressionTokensto stabilize reference.
handleGetExpressionTokensis included in thememoizedDiagramPropsdependency array but isn't wrapped inuseCallback. This causes a new function reference on every render, potentially triggering unnecessary recalculations ofmemoizedDiagramProps.- const handleGetExpressionTokens = async ( + const handleGetExpressionTokens = useCallback(async ( expression: string, fileName: string, position: { line: number; offset: number } ): Promise<number[]> => { return rpcClient.getBIDiagramRpcClient().getExpressionTokens({ expression: expression, filePath: fileName, position: position }); - }; + }, [rpcClient]);workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/ChipExpressionEditor.tsx (1)
264-281: Height styling logic is complex but handles all cases.The nested ternary for height styling covers three scenarios: expanded/hideFxButton mode, custom height via props.sx, and default max-height. While functional, consider extracting this to a helper function for readability if more conditions are added in the future.
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/chipPlugin.ts (1)
338-341: JSON.stringify comparison may be expensive for large token arrays.Using
JSON.stringifyto compare token updates works but could be slow for expressions with many tokens. Consider a lighter comparison (e.g., comparing token array length + first/last elements, or using a hash) if performance becomes an issue.// Current approach - functional but potentially slow const tokensKey = JSON.stringify({ tokens: newTokenUpdate.tokens, plainText: newTokenUpdate.plainText });
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (2)
common/config/rush/pnpm-lock.yamlis excluded by!**/pnpm-lock.yamlworkspaces/common-libs/font-wso2-vscode/src/icons/bi-arrow-down.svgis excluded by!**/*.svg
📒 Files selected for processing (37)
workspaces/ballerina/ballerina-side-panel/package.json(1 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/ExpandedEditor.tsx(5 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/LinkDialog.tsx(1 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RawTemplateMarkdownToolbar.tsx(1 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RichTemplateMarkdownToolbar.tsx(1 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/TemplateMarkdownToolbar.tsx(0 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/ExpressionMode.tsx(1 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/PromptMode.tsx(1 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/TemplateMode.tsx(2 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/types.ts(2 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/utils/templateUtils.ts(3 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionEditor.tsx(11 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/CodeUtils.ts(3 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/chipStyles.ts(1 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/ChipExpressionEditor.tsx(11 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/HelperPaneToggleButton.tsx(3 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/constants.ts(1 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/hooks/useHelperPane.ts(1 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/types.ts(2 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/utils.ts(2 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx(1 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/chipPlugin.ts(1 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/markdownCommands.ts(1 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/TextAreaEditor.tsx(2 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/index.ts(1 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/utils.ts(2 hunks)workspaces/ballerina/ballerina-visualizer/src/views/BI/FocusFlowDiagram/index.tsx(7 hunks)workspaces/ballerina/ballerina-visualizer/src/views/BI/FocusFlowDiagram/utils.tsx(1 hunks)workspaces/ballerina/ballerina-visualizer/src/views/BI/HelperPaneNew/Components/EmptyItemsPlaceHolder.tsx(1 hunks)workspaces/ballerina/ballerina-visualizer/src/views/BI/HelperPaneNew/Views/DocumentConfig.tsx(2 hunks)workspaces/ballerina/ballerina-visualizer/src/views/BI/HelperPaneNew/utils/utils.ts(1 hunks)workspaces/ballerina/bi-diagram/package.json(1 hunks)workspaces/ballerina/bi-diagram/src/components/Diagram.tsx(1 hunks)workspaces/ballerina/bi-diagram/src/components/DiagramContext.tsx(2 hunks)workspaces/ballerina/bi-diagram/src/components/editors/NPPromptEditor.tsx(1 hunks)workspaces/ballerina/bi-diagram/src/components/nodes/PromptNode/PromptNodeWidget.tsx(7 hunks)workspaces/ballerina/bi-diagram/src/index.tsx(1 hunks)
💤 Files with no reviewable changes (1)
- workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/TemplateMarkdownToolbar.tsx
✅ Files skipped from review due to trivial changes (1)
- workspaces/ballerina/ballerina-side-panel/src/components/editors/TextAreaEditor.tsx
🚧 Files skipped from review as they are similar to previous changes (10)
- workspaces/ballerina/bi-diagram/package.json
- workspaces/ballerina/ballerina-visualizer/src/views/BI/HelperPaneNew/Components/EmptyItemsPlaceHolder.tsx
- workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/ExpressionMode.tsx
- workspaces/ballerina/bi-diagram/src/index.tsx
- workspaces/ballerina/ballerina-visualizer/src/views/BI/FocusFlowDiagram/utils.tsx
- workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/chipStyles.ts
- workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/utils.ts
- workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/LinkDialog.tsx
- workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/utils/templateUtils.ts
- workspaces/ballerina/ballerina-side-panel/src/components/editors/index.ts
🧰 Additional context used
🧠 Learnings (25)
📚 Learning: 2025-11-24T22:16:28.380Z
Learnt from: dan-niles
Repo: wso2/vscode-extensions PR: 980
File: workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx:384-412
Timestamp: 2025-11-24T22:16:28.380Z
Learning: In the RichTextTemplateEditor component (workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx), token fetching on external `value` prop changes is intentionally disabled. Users cannot edit both the minimized and expanded editors simultaneously, so tokens only need to be generated based on user typing in the expanded editor view, not on external prop updates.
Applied to files:
workspaces/ballerina/ballerina-side-panel/src/components/editors/utils.tsworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/types.tsworkspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/CodeUtils.tsworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/TemplateMode.tsxworkspaces/ballerina/ballerina-visualizer/src/views/BI/HelperPaneNew/Views/DocumentConfig.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/HelperPaneToggleButton.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/ChipExpressionEditor.tsxworkspaces/ballerina/ballerina-visualizer/src/views/BI/HelperPaneNew/utils/utils.tsworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionEditor.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/ExpandedEditor.tsxworkspaces/ballerina/bi-diagram/src/components/editors/NPPromptEditor.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RichTemplateMarkdownToolbar.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/PromptMode.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RawTemplateMarkdownToolbar.tsxworkspaces/ballerina/bi-diagram/src/components/nodes/PromptNode/PromptNodeWidget.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/markdownCommands.tsworkspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/chipPlugin.tsworkspaces/ballerina/bi-diagram/src/components/DiagramContext.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsxworkspaces/ballerina/ballerina-visualizer/src/views/BI/FocusFlowDiagram/index.tsx
📚 Learning: 2025-11-25T06:34:10.812Z
Learnt from: CR
Repo: wso2/vscode-extensions PR: 0
File: workspaces/ballerina/component-diagram/AGENTS.md:0-0
Timestamp: 2025-11-25T06:34:10.812Z
Learning: Applies to workspaces/ballerina/component-diagram/src/components/nodes/EntryNode/components/**/*.tsx : Implement lazy expansion of functions: only render function items when they are visible to improve performance for large function lists
Applied to files:
workspaces/ballerina/ballerina-side-panel/src/components/editors/utils.tsworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/TemplateMode.tsxworkspaces/ballerina/bi-diagram/src/components/editors/NPPromptEditor.tsxworkspaces/ballerina/bi-diagram/src/components/nodes/PromptNode/PromptNodeWidget.tsxworkspaces/ballerina/bi-diagram/src/components/DiagramContext.tsxworkspaces/ballerina/ballerina-visualizer/src/views/BI/FocusFlowDiagram/index.tsx
📚 Learning: 2025-11-25T06:34:10.812Z
Learnt from: CR
Repo: wso2/vscode-extensions PR: 0
File: workspaces/ballerina/component-diagram/AGENTS.md:0-0
Timestamp: 2025-11-25T06:34:10.812Z
Learning: Applies to workspaces/ballerina/component-diagram/src/**/*.{ts,tsx} : Define all constants (node types, sizing, spacing) in src/resources/constants.ts and import them where needed instead of hardcoding values
Applied to files:
workspaces/ballerina/ballerina-side-panel/src/components/editors/utils.tsworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/types.tsworkspaces/ballerina/ballerina-side-panel/package.jsonworkspaces/ballerina/bi-diagram/src/components/editors/NPPromptEditor.tsxworkspaces/ballerina/bi-diagram/src/components/Diagram.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/constants.tsworkspaces/ballerina/bi-diagram/src/components/nodes/PromptNode/PromptNodeWidget.tsxworkspaces/ballerina/bi-diagram/src/components/DiagramContext.tsxworkspaces/ballerina/ballerina-visualizer/src/views/BI/FocusFlowDiagram/index.tsx
📚 Learning: 2025-11-25T06:34:10.812Z
Learnt from: CR
Repo: wso2/vscode-extensions PR: 0
File: workspaces/ballerina/component-diagram/AGENTS.md:0-0
Timestamp: 2025-11-25T06:34:10.812Z
Learning: Applies to workspaces/ballerina/component-diagram/src/components/**/*.tsx : Use React 18.2.0 features including concurrent rendering and automatic batching; avoid class components in favor of functional components with hooks
Applied to files:
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/TemplateMode.tsxworkspaces/ballerina/ballerina-visualizer/src/views/BI/HelperPaneNew/Views/DocumentConfig.tsxworkspaces/ballerina/ballerina-side-panel/package.jsonworkspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/ChipExpressionEditor.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/ExpandedEditor.tsxworkspaces/ballerina/bi-diagram/src/components/editors/NPPromptEditor.tsxworkspaces/ballerina/bi-diagram/src/components/Diagram.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/PromptMode.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RawTemplateMarkdownToolbar.tsxworkspaces/ballerina/bi-diagram/src/components/nodes/PromptNode/PromptNodeWidget.tsxworkspaces/ballerina/bi-diagram/src/components/DiagramContext.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsxworkspaces/ballerina/ballerina-visualizer/src/views/BI/FocusFlowDiagram/index.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/hooks/useHelperPane.ts
📚 Learning: 2025-11-20T11:04:33.712Z
Learnt from: KCSAbeywickrama
Repo: wso2/vscode-extensions PR: 898
File: workspaces/ballerina/data-mapper/src/components/DataMapper/SidePanel/QueryClauses/ClausesPanel.tsx:38-38
Timestamp: 2025-11-20T11:04:33.712Z
Learning: In workspaces/ballerina/data-mapper/src/components/DataMapper/SidePanel/QueryClauses/ClausesPanel.tsx, the use of `useDMQueryClausesPanelStore.getState()` to access `clauseToAdd` and `setClauseToAdd` (instead of the hook subscription pattern) is intentional to prevent re-renders when these state values change.
Applied to files:
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/TemplateMode.tsxworkspaces/ballerina/ballerina-visualizer/src/views/BI/FocusFlowDiagram/index.tsx
📚 Learning: 2025-11-24T14:51:49.267Z
Learnt from: KCSAbeywickrama
Repo: wso2/vscode-extensions PR: 998
File: workspaces/ballerina/data-mapper/src/components/DataMapper/Header/ExpressionBar.tsx:113-132
Timestamp: 2025-11-24T14:51:49.267Z
Learning: In workspaces/ballerina/data-mapper/src/components/DataMapper/Header/ExpressionBar.tsx, if `textFieldRef.current` is not undefined, `textFieldRef.current.inputElement` is guaranteed to exist. If `inputElement` doesn't exist when `current` exists, it's a fatal error that should reach the error boundary rather than being handled with defensive null checks.
Applied to files:
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/TemplateMode.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/ChipExpressionEditor.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionEditor.tsxworkspaces/ballerina/bi-diagram/src/components/editors/NPPromptEditor.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/PromptMode.tsxworkspaces/ballerina/bi-diagram/src/components/nodes/PromptNode/PromptNodeWidget.tsxworkspaces/ballerina/bi-diagram/src/components/DiagramContext.tsx
📚 Learning: 2025-11-25T06:34:10.812Z
Learnt from: CR
Repo: wso2/vscode-extensions PR: 0
File: workspaces/ballerina/component-diagram/AGENTS.md:0-0
Timestamp: 2025-11-25T06:34:10.812Z
Learning: Applies to workspaces/ballerina/component-diagram/**/*.config.{js,ts} : Use minimatch-compatible glob patterns for file matching in build and test configuration files
Applied to files:
workspaces/ballerina/ballerina-side-panel/package.json
📚 Learning: 2025-11-25T06:34:10.812Z
Learnt from: CR
Repo: wso2/vscode-extensions PR: 0
File: workspaces/ballerina/component-diagram/AGENTS.md:0-0
Timestamp: 2025-11-25T06:34:10.812Z
Learning: Applies to workspaces/ballerina/component-diagram/src/**/*.{ts,tsx} : Use TypeScript 5.8.3 with strict type checking enabled for all source files
Applied to files:
workspaces/ballerina/ballerina-side-panel/package.json
📚 Learning: 2025-11-25T06:34:10.812Z
Learnt from: CR
Repo: wso2/vscode-extensions PR: 0
File: workspaces/ballerina/component-diagram/AGENTS.md:0-0
Timestamp: 2025-11-25T06:34:10.812Z
Learning: Applies to workspaces/ballerina/component-diagram/src/components/**/*.tsx : Use Emotion for CSS-in-JS styling instead of inline styles or external CSS files
Applied to files:
workspaces/ballerina/ballerina-side-panel/package.json
📚 Learning: 2025-11-25T06:34:10.812Z
Learnt from: CR
Repo: wso2/vscode-extensions PR: 0
File: workspaces/ballerina/component-diagram/AGENTS.md:0-0
Timestamp: 2025-11-25T06:34:10.812Z
Learning: Applies to workspaces/ballerina/component-diagram/src/resources/icons/**/*.tsx : Create separate SVG icon components in src/resources/icons/ for all diagram icons and import them as React components
Applied to files:
workspaces/ballerina/ballerina-side-panel/package.jsonworkspaces/ballerina/bi-diagram/src/components/editors/NPPromptEditor.tsxworkspaces/ballerina/bi-diagram/src/components/Diagram.tsxworkspaces/ballerina/bi-diagram/src/components/DiagramContext.tsxworkspaces/ballerina/ballerina-visualizer/src/views/BI/FocusFlowDiagram/index.tsx
📚 Learning: 2025-11-10T15:05:11.309Z
Learnt from: madushajg
Repo: wso2/vscode-extensions PR: 868
File: workspaces/bi/bi-extension/src/utils.ts:224-242
Timestamp: 2025-11-10T15:05:11.309Z
Learning: The workspaces/bi/bi-extension and workspaces/ballerina/ballerina-extension are separate VS Code extensions that are packaged and distributed independently, so they cannot share code via imports and must maintain their own implementations of common utilities.
Applied to files:
workspaces/ballerina/ballerina-side-panel/package.json
📚 Learning: 2025-11-25T06:34:10.812Z
Learnt from: CR
Repo: wso2/vscode-extensions PR: 0
File: workspaces/ballerina/component-diagram/AGENTS.md:0-0
Timestamp: 2025-11-25T06:34:10.812Z
Learning: Applies to workspaces/ballerina/component-diagram/src/components/DiagramContext.tsx : Use DiagramContext (React Context API) for state management across the diagram component, including expandedNodes and graphQLGroupOpen state
Applied to files:
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/ChipExpressionEditor.tsxworkspaces/ballerina/bi-diagram/src/components/Diagram.tsxworkspaces/ballerina/bi-diagram/src/components/nodes/PromptNode/PromptNodeWidget.tsxworkspaces/ballerina/bi-diagram/src/components/DiagramContext.tsxworkspaces/ballerina/ballerina-visualizer/src/views/BI/FocusFlowDiagram/index.tsx
📚 Learning: 2025-11-26T06:34:09.752Z
Learnt from: KCSAbeywickrama
Repo: wso2/vscode-extensions PR: 653
File: workspaces/bi/bi-extension/src/test/e2e-playwright-tests/data-mapper/DataMapperUtils.ts:128-134
Timestamp: 2025-11-26T06:34:09.752Z
Learning: In workspaces/bi/bi-extension/src/test/e2e-playwright-tests/data-mapper/DataMapperUtils.ts, the goPrevViewBreadcrumb() method is only called when in a focused view, ensuring breadcrumbs are always present. No guard for empty breadcrumbs is needed.
Applied to files:
workspaces/ballerina/ballerina-visualizer/src/views/BI/HelperPaneNew/utils/utils.ts
📚 Learning: 2025-11-26T07:49:56.428Z
Learnt from: KCSAbeywickrama
Repo: wso2/vscode-extensions PR: 653
File: workspaces/bi/bi-extension/src/test/e2e-playwright-tests/data-mapper/DataMapperUtils.ts:136-141
Timestamp: 2025-11-26T07:49:56.428Z
Learning: In workspaces/bi/bi-extension/src/test/e2e-playwright-tests/data-mapper/DataMapperUtils.ts, the goPrevViewBackButton() method is only called when in a focused view, ensuring breadcrumbs are always present. No guard for empty breadcrumbs is needed.
Applied to files:
workspaces/ballerina/ballerina-visualizer/src/views/BI/HelperPaneNew/utils/utils.tsworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RawTemplateMarkdownToolbar.tsx
📚 Learning: 2025-11-25T06:34:10.812Z
Learnt from: CR
Repo: wso2/vscode-extensions PR: 0
File: workspaces/ballerina/component-diagram/AGENTS.md:0-0
Timestamp: 2025-11-25T06:34:10.812Z
Learning: Applies to workspaces/ballerina/component-diagram/src/components/Diagram.tsx : Implement proper error boundaries around the Diagram component to gracefully handle rendering errors without crashing the parent application
Applied to files:
workspaces/ballerina/bi-diagram/src/components/editors/NPPromptEditor.tsxworkspaces/ballerina/bi-diagram/src/components/Diagram.tsxworkspaces/ballerina/bi-diagram/src/components/DiagramContext.tsxworkspaces/ballerina/ballerina-visualizer/src/views/BI/FocusFlowDiagram/index.tsx
📚 Learning: 2025-11-25T06:34:10.812Z
Learnt from: CR
Repo: wso2/vscode-extensions PR: 0
File: workspaces/ballerina/component-diagram/AGENTS.md:0-0
Timestamp: 2025-11-25T06:34:10.812Z
Learning: Applies to workspaces/ballerina/component-diagram/src/components/Diagram.tsx : Debounce diagram repaints to avoid excessive re-renders when state changes occur
Applied to files:
workspaces/ballerina/bi-diagram/src/components/editors/NPPromptEditor.tsxworkspaces/ballerina/bi-diagram/src/components/Diagram.tsxworkspaces/ballerina/bi-diagram/src/components/DiagramContext.tsxworkspaces/ballerina/ballerina-visualizer/src/views/BI/FocusFlowDiagram/index.tsx
📚 Learning: 2025-11-27T07:59:33.534Z
Learnt from: KCSAbeywickrama
Repo: wso2/vscode-extensions PR: 897
File: workspaces/ballerina/data-mapper/src/components/DataMapper/SidePanel/QueryClauses/ClausesPanel.tsx:50-59
Timestamp: 2025-11-27T07:59:33.534Z
Learning: In workspaces/ballerina/data-mapper/src/components/DataMapper/SidePanel/QueryClauses/ClausesPanel.tsx, the `clause.properties.expression` property in the `fillDefaults` function does not require defensive null/undefined checks because it's a required property enforced by form validation in ClauseEditor.
Applied to files:
workspaces/ballerina/bi-diagram/src/components/editors/NPPromptEditor.tsxworkspaces/ballerina/bi-diagram/src/components/Diagram.tsxworkspaces/ballerina/bi-diagram/src/components/DiagramContext.tsx
📚 Learning: 2025-11-25T06:34:10.812Z
Learnt from: CR
Repo: wso2/vscode-extensions PR: 0
File: workspaces/ballerina/component-diagram/AGENTS.md:0-0
Timestamp: 2025-11-25T06:34:10.812Z
Learning: Applies to workspaces/ballerina/component-diagram/src/index.ts : Export the main Diagram component as the default export from the package entry point (index.ts)
Applied to files:
workspaces/ballerina/bi-diagram/src/components/Diagram.tsxworkspaces/ballerina/bi-diagram/src/components/DiagramContext.tsxworkspaces/ballerina/ballerina-visualizer/src/views/BI/FocusFlowDiagram/index.tsx
📚 Learning: 2025-11-25T06:34:10.812Z
Learnt from: CR
Repo: wso2/vscode-extensions PR: 0
File: workspaces/ballerina/component-diagram/AGENTS.md:0-0
Timestamp: 2025-11-25T06:34:10.812Z
Learning: Applies to workspaces/ballerina/component-diagram/src/components/Diagram.tsx : Implement input validation for CDModel structure: verify that all required properties (connections, listeners, services) are present and properly typed
Applied to files:
workspaces/ballerina/bi-diagram/src/components/Diagram.tsxworkspaces/ballerina/bi-diagram/src/components/DiagramContext.tsxworkspaces/ballerina/ballerina-visualizer/src/views/BI/FocusFlowDiagram/index.tsx
📚 Learning: 2025-11-25T06:34:10.812Z
Learnt from: CR
Repo: wso2/vscode-extensions PR: 0
File: workspaces/ballerina/component-diagram/AGENTS.md:0-0
Timestamp: 2025-11-25T06:34:10.812Z
Learning: Applies to workspaces/ballerina/component-diagram/src/components/(Diagram|DiagramCanvas|Controls)*.tsx : Store diagram zoom and offset positions in state; optionally cache them in localStorage for session persistence
Applied to files:
workspaces/ballerina/bi-diagram/src/components/Diagram.tsxworkspaces/ballerina/bi-diagram/src/components/DiagramContext.tsxworkspaces/ballerina/ballerina-visualizer/src/views/BI/FocusFlowDiagram/index.tsx
📚 Learning: 2025-11-26T06:35:19.217Z
Learnt from: KCSAbeywickrama
Repo: wso2/vscode-extensions PR: 653
File: workspaces/bi/bi-extension/src/test/e2e-playwright-tests/data-mapper/DataMapperUtils.ts:173-178
Timestamp: 2025-11-26T06:35:19.217Z
Learning: In workspaces/bi/bi-extension/src/test/e2e-playwright-tests/data-mapper/DataMapperUtils.ts, the commented-out debugging block in the verifyFileContent function (lines 172-177 containing console.log, page.pause, and updateDataFileSync) is intentionally kept as a developer utility for updating test data files when needed. It should not be removed.
Applied to files:
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RichTemplateMarkdownToolbar.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RawTemplateMarkdownToolbar.tsx
📚 Learning: 2025-11-25T06:34:10.812Z
Learnt from: CR
Repo: wso2/vscode-extensions PR: 0
File: workspaces/ballerina/component-diagram/AGENTS.md:0-0
Timestamp: 2025-11-25T06:34:10.812Z
Learning: Applies to workspaces/ballerina/component-diagram/src/components/nodes/**/!(*Widget|*Model).tsx : Implement the factory pattern for node instantiation: each node type (Listener, Entry, Connection) must have a corresponding Factory class that extends the appropriate factory interface
Applied to files:
workspaces/ballerina/bi-diagram/src/components/nodes/PromptNode/PromptNodeWidget.tsx
📚 Learning: 2025-11-25T06:34:10.812Z
Learnt from: CR
Repo: wso2/vscode-extensions PR: 0
File: workspaces/ballerina/component-diagram/AGENTS.md:0-0
Timestamp: 2025-11-25T06:34:10.812Z
Learning: Applies to workspaces/ballerina/component-diagram/src/**/*.{ts,tsx} : All async operations and promise handling in diagram utilities should use async/await syntax instead of .then() callbacks
Applied to files:
workspaces/ballerina/ballerina-visualizer/src/views/BI/FocusFlowDiagram/index.tsx
📚 Learning: 2025-11-25T06:34:10.812Z
Learnt from: CR
Repo: wso2/vscode-extensions PR: 0
File: workspaces/ballerina/component-diagram/AGENTS.md:0-0
Timestamp: 2025-11-25T06:34:10.812Z
Learning: Applies to workspaces/ballerina/component-diagram/src/utils/diagram.ts : Implement dynamic node height calculation based on visible function count: BASE_HEIGHT (72px) + (FUNCTION_HEIGHT (48px) per visible function) + VIEW_ALL_BUTTON_HEIGHT (40px if needed)
Applied to files:
workspaces/ballerina/ballerina-visualizer/src/views/BI/FocusFlowDiagram/index.tsx
📚 Learning: 2025-11-25T06:34:10.812Z
Learnt from: CR
Repo: wso2/vscode-extensions PR: 0
File: workspaces/ballerina/component-diagram/AGENTS.md:0-0
Timestamp: 2025-11-25T06:34:10.812Z
Learning: Applies to workspaces/ballerina/component-diagram/src/utils/diagram.ts : Filter out autogenerated connections (symbol starting with '_') and connections with enableFlowModel=false before rendering
Applied to files:
workspaces/ballerina/ballerina-visualizer/src/views/BI/FocusFlowDiagram/index.tsx
🧬 Code graph analysis (13)
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/TemplateMode.tsx (1)
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/ChipExpressionEditor.tsx (1)
ChipExpressionEditorComponent(98-431)
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/HelperPaneToggleButton.tsx (2)
workspaces/common-libs/ui-toolkit/src/styles/Theme.ts (1)
ThemeColors(79-104)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/FloatingButtonIcons.tsx (2)
CloseHelperIcon(32-41)OpenHelperIcon(21-30)
workspaces/ballerina/ballerina-visualizer/src/views/BI/HelperPaneNew/utils/utils.ts (1)
workspaces/ballerina/ballerina-side-panel/src/components/editors/index.ts (1)
InputMode(31-31)
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionEditor.tsx (2)
workspaces/ballerina/ballerina-side-panel/src/components/editors/index.ts (1)
InputMode(31-31)workspaces/ballerina/ballerina-side-panel/src/components/editors/utils.ts (2)
isExpandableMode(112-114)toEditorMode(116-118)
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/ExpandedEditor.tsx (7)
workspaces/ballerina/ballerina-side-panel/src/components/editors/index.ts (1)
InputMode(31-31)workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/TextMode.tsx (1)
TextMode(47-56)workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/PromptMode.tsx (1)
PromptMode(41-159)workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/ExpressionMode.tsx (1)
ExpressionMode(36-78)workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/TemplateMode.tsx (1)
TemplateMode(33-77)workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/types.ts (1)
EditorMode(93-93)workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/index.ts (1)
EditorMode(20-20)
workspaces/ballerina/bi-diagram/src/components/editors/NPPromptEditor.tsx (8)
workspaces/ballerina/ballerina-core/src/interfaces/bi.ts (1)
NodeKind(393-466)workspaces/ballerina/ballerina-core/src/interfaces/extended-lang-client.ts (1)
ExpressionProperty(1090-1090)workspaces/ballerina/bi-diagram/src/components/DiagramContext.tsx (1)
GetHelperPaneFunction(40-53)workspaces/ballerina/bi-diagram/src/index.tsx (1)
GetHelperPaneFunction(29-29)workspaces/ballerina/ballerina-side-panel/src/components/editors/index.ts (2)
InputMode(31-31)ExpandedEditor(32-32)workspaces/common-libs/ui-toolkit/src/components/ExpressionEditor/types/form.ts (1)
FormExpressionEditorRef(79-83)workspaces/ballerina/ballerina-side-panel/src/components/Form/types.ts (1)
HelperpaneOnChangeOptions(96-99)workspaces/common-libs/ui-toolkit/src/components/Commons/ErrorBanner.tsx (1)
ErrorBanner(46-55)
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RichTemplateMarkdownToolbar.tsx (4)
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/markdownCommands.ts (14)
toggleHeading(76-86)toggleLink(40-74)isMarkActive(144-150)isNodeActive(152-162)isListActive(164-178)canUndo(188-190)canRedo(192-194)undoCommand(180-182)redoCommand(184-186)toggleBold(28-30)toggleItalic(32-34)toggleBlockquote(92-98)toggleBulletList(116-128)toggleOrderedList(130-142)workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/utils/templateUtils.ts (4)
canUndo(373-376)canRedo(381-384)undoCommand(353-358)redoCommand(363-368)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/HelperPaneToggleButton.tsx (1)
HelperPaneToggleButton(83-109)workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/LinkDialog.tsx (1)
LinkDialog(90-175)
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/PromptMode.tsx (4)
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/types.ts (1)
EditorModeExpressionProps(51-84)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/ChipExpressionEditor.tsx (1)
ChipExpressionEditorComponent(98-431)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx (1)
RichTextTemplateEditor(171-513)workspaces/common-libs/ui-toolkit/src/components/Commons/ErrorBanner.tsx (1)
ErrorBanner(46-55)
workspaces/ballerina/bi-diagram/src/components/nodes/PromptNode/PromptNodeWidget.tsx (2)
workspaces/ballerina/bi-diagram/src/components/editors/NPPromptEditor.tsx (1)
NPPromptEditor(110-413)workspaces/ballerina/ballerina-side-panel/src/components/editors/index.ts (1)
InputMode(31-31)
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/markdownCommands.ts (1)
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/utils/templateUtils.ts (4)
undoCommand(353-358)redoCommand(363-368)canUndo(373-376)canRedo(381-384)
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/chipPlugin.ts (3)
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/types.ts (2)
TokenMetadata(64-68)CompoundTokenSequence(90-98)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/chipStyles.ts (6)
getChipDisplayContent(107-109)getTokenTypeColor(99-101)BASE_CHIP_STYLES(22-37)getTokenIconClass(92-97)BASE_ICON_STYLES(39-42)CHIP_TEXT_STYLES(44-48)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/utils.ts (3)
ParsedToken(105-110)getParsedExpressionTokens(112-138)detectTokenPatterns(278-332)
workspaces/ballerina/bi-diagram/src/components/DiagramContext.tsx (5)
workspaces/ballerina/bi-diagram/src/index.tsx (1)
GetHelperPaneFunction(29-29)workspaces/common-libs/ui-toolkit/src/components/ExpressionEditor/types/form.ts (1)
FormExpressionEditorRef(79-83)workspaces/ballerina/ballerina-side-panel/src/components/Form/types.ts (1)
HelperpaneOnChangeOptions(96-99)workspaces/ballerina/ballerina-core/src/interfaces/bi.ts (1)
RecordTypeField(154-158)workspaces/ballerina/ballerina-side-panel/src/components/editors/index.ts (1)
InputMode(31-31)
workspaces/ballerina/ballerina-visualizer/src/views/BI/FocusFlowDiagram/index.tsx (3)
workspaces/ballerina/bi-diagram/src/components/DiagramContext.tsx (1)
GetHelperPaneFunction(40-53)workspaces/ballerina/bi-diagram/src/index.tsx (1)
GetHelperPaneFunction(29-29)workspaces/ballerina/ballerina-visualizer/src/views/BI/FocusFlowDiagram/utils.tsx (1)
createPromptHelperPane(59-144)
...src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/hooks/useHelperPane.ts
Show resolved
Hide resolved
workspaces/ballerina/ballerina-visualizer/src/views/BI/HelperPaneNew/Views/DocumentConfig.tsx
Show resolved
Hide resolved
workspaces/ballerina/bi-diagram/src/components/editors/NPPromptEditor.tsx
Show resolved
Hide resolved
766e30f to
867b995
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
♻️ Duplicate comments (2)
workspaces/ballerina/bi-diagram/src/components/editors/NPPromptEditor.tsx (2)
164-203: Includeprops.nodeinfetchDiagnosticsdependencies to avoid stale diagnostics.
createProperty(Line 165) readsprops.node.properties["prompt"], andfetchDiagnosticscloses overcreateProperty, but theuseCallbackdependency array omits anything related toprops.node. If the sameNPPromptEditorinstance is reused with a different node, diagnostics will continue to be computed against the old node’s prompt property.You can fix this by including the node (or
createProperty) in the dependency list so the debounced callback is recreated when the node changes:- }, 300), - [enableDiagnostics, getExpressionFormDiagnostics] + }, 300), + [enableDiagnostics, getExpressionFormDiagnostics, props.node] );Optionally, consider calling
fetchDiagnostics.cancel?.()in auseEffectcleanup to avoid pending debounced calls firing after unmount.
276-285: Fix staleprops.nodeclosure inchipExtractArgsFromFunction.
chipExtractArgsFromFunctionalso usescreateProperty(which readsprops.node) but itsuseMemoonly depends onextractArgsFromFunction. Ifprops.nodechanges while reusing this component instance, argument extraction will still use the old node’s prompt property.Update the dependencies to track the node as well:
- }, [extractArgsFromFunction]); + }, [extractArgsFromFunction, props.node]);This keeps the memoized function consistent with the current node.
🧹 Nitpick comments (6)
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionEditor.tsx (2)
411-411: Consider extracting repeated mode-check pattern.The condition
inputMode === InputMode.PROMPT || inputMode === InputMode.TEMPLATEappears multiple times in this file (lines 411, 460, 570, 599, 705-706, 715, 785, 788). Consider extracting this to a helper function for clarity and maintainability.Example helper in
utils.ts:export function isRichTextMode(mode: InputMode): boolean { return mode === InputMode.PROMPT || mode === InputMode.TEMPLATE; }Then usage becomes:
-const fieldValue = (inputModeRef.current === InputMode.PROMPT || inputModeRef.current === InputMode.TEMPLATE) && rawExpression ? rawExpression(watch(key)) : watch(key); +const fieldValue = isRichTextMode(inputModeRef.current) && rawExpression ? rawExpression(watch(key)) : watch(key);
779-816: Duplicated onChange handler logic.The
onChangehandler passed toExpandedEditor(lines 779-816) is nearly identical to the one inExpressionField(lines 709-746). This duplication creates a maintenance burden where changes must be applied in both places.Consider extracting a shared handler factory:
const createChangeHandler = (onChange: (value: string) => void) => async (updatedValue: string, updatedCursorPosition: number) => { setFormDiagnostics([]); const currentMode = inputModeRef.current; const rawValue = isRichTextMode(currentMode) && rawExpression ? rawExpression(updatedValue) : updatedValue; onChange(rawValue); if (getExpressionEditorDiagnostics && (currentMode === InputMode.EXP || isRichTextMode(currentMode))) { getExpressionEditorDiagnostics( (required ?? !field.optional) || rawValue !== '', rawValue, key, getPropertyFromFormField(field) ); } // ... trigger character handling };workspaces/ballerina/bi-diagram/src/components/editors/NPPromptEditor.tsx (4)
230-247: Align sanitized/raw expression usage for completions in expanded editor.In
handleChangeFromExpandedEditor, you sanitizeupdatedValueforonChange, but you pass the rawupdatedValue(with backticks) intoretrieveCompletions, while the inline editor path routes completions throughretrieveCompletions(getSanitizedExp(value), …).This mismatch can easily desynchronize text/offset expectations between the language server and
ExpressionProperty(which always uses the sanitized value), especially if offsets are computed on the sanitized form elsewhere.Consider passing the same sanitized expression and offset contract here that you use in the inline path, e.g., basing both
propertyand thevalueargument toretrieveCompletionsonsanitized, and adjusting the offset accordingly. Please verify against the expectedretrieveCompletionsAPI before changing this.
144-146: Verify thatexprRefis actually wired to the underlying editor.You create
exprRef(Line 144) and pass it intogetHelperPaneviawrappedGetHelperPane(Lines 260–263), but there’s no place whereexprRefis attached toChipExpressionEditorComponentorExpandedEditor. Unless those components internally populate this ref via context,exprRef.currentwill remainnull, and any helper-pane logic that relies on the editor ref (for positioning, scrolling, etc.) won’t work as intended.If
ChipExpressionEditorComponentis aforwardRef<FormExpressionEditorRef, …>, you likely want to pass it as:<ChipExpressionEditorComponent ref={exprRef} … />Otherwise, consider removing
exprReffrom thegetHelperPanecall to avoid a misleading, always-null ref.Also applies to: 252-274
121-132: UnusedonFocusprop — either plumb it through or drop it from the API.
NPPromptEditorPropsexposesonFocus(Lines 63, 121), but it’s never used or forwarded toChipExpressionEditorComponentorExpandedEditor. This makes the prop misleading for consumers expecting a focus callback.Either:
- Wire
onFocusinto the underlying editor(s) if they support it, or- Remove
onFocusfromNPPromptEditorPropsuntil it’s needed.Also applies to: 351-408
128-131: Confirm intended default forinputModevs. hard-codedPROMPTmode.The component defaults
inputMode = InputMode.EXP(Line 128) but usesmode={InputMode.PROMPT}when renderingExpandedEditor(Line 399) while also passinginputMode={inputMode}(Line 407). For a prompt-specific editor, it might be more intuitive to defaultinputModetoInputMode.PROMPT, or to rely consistently on a single prop ifExpandedEditordoesn’t need both.Please double-check the
ExpandedEditorAPI and confirm this split is intentional; if not, adjusting the default or consolidating on one prop would reduce confusion.Also applies to: 399-407
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/ExpandedEditor.tsx(5 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/types.ts(2 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionEditor.tsx(11 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/utils.ts(2 hunks)workspaces/ballerina/bi-diagram/src/components/editors/NPPromptEditor.tsx(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- workspaces/ballerina/ballerina-side-panel/src/components/editors/utils.ts
🧰 Additional context used
🧠 Learnings (10)
📚 Learning: 2025-11-24T22:16:28.380Z
Learnt from: dan-niles
Repo: wso2/vscode-extensions PR: 980
File: workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx:384-412
Timestamp: 2025-11-24T22:16:28.380Z
Learning: In the RichTextTemplateEditor component (workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx), token fetching on external `value` prop changes is intentionally disabled. Users cannot edit both the minimized and expanded editors simultaneously, so tokens only need to be generated based on user typing in the expanded editor view, not on external prop updates.
Applied to files:
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/types.tsworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/ExpandedEditor.tsxworkspaces/ballerina/bi-diagram/src/components/editors/NPPromptEditor.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionEditor.tsx
📚 Learning: 2025-11-25T06:34:10.812Z
Learnt from: CR
Repo: wso2/vscode-extensions PR: 0
File: workspaces/ballerina/component-diagram/AGENTS.md:0-0
Timestamp: 2025-11-25T06:34:10.812Z
Learning: Applies to workspaces/ballerina/component-diagram/src/**/*.{ts,tsx} : Define all constants (node types, sizing, spacing) in src/resources/constants.ts and import them where needed instead of hardcoding values
Applied to files:
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/types.tsworkspaces/ballerina/bi-diagram/src/components/editors/NPPromptEditor.tsx
📚 Learning: 2025-11-25T06:34:10.812Z
Learnt from: CR
Repo: wso2/vscode-extensions PR: 0
File: workspaces/ballerina/component-diagram/AGENTS.md:0-0
Timestamp: 2025-11-25T06:34:10.812Z
Learning: Applies to workspaces/ballerina/component-diagram/src/**/*.{ts,tsx} : Use TypeScript 5.8.3 with strict type checking enabled for all source files
Applied to files:
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/types.ts
📚 Learning: 2025-11-24T14:51:49.267Z
Learnt from: KCSAbeywickrama
Repo: wso2/vscode-extensions PR: 998
File: workspaces/ballerina/data-mapper/src/components/DataMapper/Header/ExpressionBar.tsx:113-132
Timestamp: 2025-11-24T14:51:49.267Z
Learning: In workspaces/ballerina/data-mapper/src/components/DataMapper/Header/ExpressionBar.tsx, if `textFieldRef.current` is not undefined, `textFieldRef.current.inputElement` is guaranteed to exist. If `inputElement` doesn't exist when `current` exists, it's a fatal error that should reach the error boundary rather than being handled with defensive null checks.
Applied to files:
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/ExpandedEditor.tsxworkspaces/ballerina/bi-diagram/src/components/editors/NPPromptEditor.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionEditor.tsx
📚 Learning: 2025-11-25T06:34:10.812Z
Learnt from: CR
Repo: wso2/vscode-extensions PR: 0
File: workspaces/ballerina/component-diagram/AGENTS.md:0-0
Timestamp: 2025-11-25T06:34:10.812Z
Learning: Applies to workspaces/ballerina/component-diagram/src/components/**/*.tsx : Use React 18.2.0 features including concurrent rendering and automatic batching; avoid class components in favor of functional components with hooks
Applied to files:
workspaces/ballerina/bi-diagram/src/components/editors/NPPromptEditor.tsx
📚 Learning: 2025-11-25T06:34:10.812Z
Learnt from: CR
Repo: wso2/vscode-extensions PR: 0
File: workspaces/ballerina/component-diagram/AGENTS.md:0-0
Timestamp: 2025-11-25T06:34:10.812Z
Learning: Applies to workspaces/ballerina/component-diagram/src/components/nodes/EntryNode/components/**/*.tsx : Implement lazy expansion of functions: only render function items when they are visible to improve performance for large function lists
Applied to files:
workspaces/ballerina/bi-diagram/src/components/editors/NPPromptEditor.tsx
📚 Learning: 2025-11-25T06:34:10.812Z
Learnt from: CR
Repo: wso2/vscode-extensions PR: 0
File: workspaces/ballerina/component-diagram/AGENTS.md:0-0
Timestamp: 2025-11-25T06:34:10.812Z
Learning: Applies to workspaces/ballerina/component-diagram/src/resources/icons/**/*.tsx : Create separate SVG icon components in src/resources/icons/ for all diagram icons and import them as React components
Applied to files:
workspaces/ballerina/bi-diagram/src/components/editors/NPPromptEditor.tsx
📚 Learning: 2025-11-25T06:34:10.812Z
Learnt from: CR
Repo: wso2/vscode-extensions PR: 0
File: workspaces/ballerina/component-diagram/AGENTS.md:0-0
Timestamp: 2025-11-25T06:34:10.812Z
Learning: Applies to workspaces/ballerina/component-diagram/src/components/Diagram.tsx : Implement proper error boundaries around the Diagram component to gracefully handle rendering errors without crashing the parent application
Applied to files:
workspaces/ballerina/bi-diagram/src/components/editors/NPPromptEditor.tsx
📚 Learning: 2025-11-25T06:34:10.812Z
Learnt from: CR
Repo: wso2/vscode-extensions PR: 0
File: workspaces/ballerina/component-diagram/AGENTS.md:0-0
Timestamp: 2025-11-25T06:34:10.812Z
Learning: Applies to workspaces/ballerina/component-diagram/src/components/Diagram.tsx : Debounce diagram repaints to avoid excessive re-renders when state changes occur
Applied to files:
workspaces/ballerina/bi-diagram/src/components/editors/NPPromptEditor.tsx
📚 Learning: 2025-11-27T07:59:33.534Z
Learnt from: KCSAbeywickrama
Repo: wso2/vscode-extensions PR: 897
File: workspaces/ballerina/data-mapper/src/components/DataMapper/SidePanel/QueryClauses/ClausesPanel.tsx:50-59
Timestamp: 2025-11-27T07:59:33.534Z
Learning: In workspaces/ballerina/data-mapper/src/components/DataMapper/SidePanel/QueryClauses/ClausesPanel.tsx, the `clause.properties.expression` property in the `fillDefaults` function does not require defensive null/undefined checks because it's a required property enforced by form validation in ClauseEditor.
Applied to files:
workspaces/ballerina/bi-diagram/src/components/editors/NPPromptEditor.tsx
🧬 Code graph analysis (1)
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionEditor.tsx (1)
workspaces/ballerina/ballerina-side-panel/src/components/editors/utils.ts (2)
isExpandableMode(112-114)toEditorMode(116-118)
🔇 Additional comments (6)
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/types.ts (1)
86-93: Well-structured type derivation from runtime constant.The
as constassertion onEXPANDABLE_MODEScombined with the indexed access typetypeof EXPANDABLE_MODES[number]is an idiomatic TypeScript pattern that ensuresEditorModestays in sync with the runtime array. This eliminates potential drift between the constant and the type.workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionEditor.tsx (2)
774-832: ExpandedEditor integration looks correct.The guard condition at line 774 ensures
toEditorMode(inputModeRef.current)is truthy before rendering, making the non-null assertion at line 821 safe. TheinputModeprop is correctly passed to enable mode-specific behavior in the expanded editor.
460-471: Mode initialization logic correctly extended for PROMPT.The initialization logic properly handles PROMPT alongside TEMPLATE, using sanitization to determine if the value is compatible with the mode before setting it. Falls back to EXP mode when sanitization would alter the value.
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/ExpandedEditor.tsx (3)
149-154: Good refactor: MODE_COMPONENTS now uses enum keys.Switching from string literal keys to computed
[InputMode.*]keys ensures type safety and consistency with theEditorModetype definition. This prevents typos and makes the mapping easier to maintain.
229-252: InconsistentinputModeprop distribution across modes.
inputModeis passed toPromptMode(line 226) andTemplateMode(line 251) but not toExpressionMode(lines 229-239). SinceEditorModeExpressionPropsintypes.tsincludesinputMode?: InputMode, this inconsistency may cause issues ifExpressionModeneeds mode awareness in the future.Please verify whether
ExpressionModerequires theinputModeprop. If it does (or may in the future), add it for consistency:...(mode === InputMode.EXP && { completions, fileName, targetLineRange, sanitizedExpression, rawExpression, extractArgsFromFunction, getHelperPane, error, - formDiagnostics + formDiagnostics, + inputMode }),
211-253: Props construction pattern is clear and maintainable.The conditional spread pattern for building
modePropsbased on the current mode is a clean approach that only passes relevant props to each mode component. This prevents passing unnecessary props and keeps each mode's dependencies explicit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
♻️ Duplicate comments (1)
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx (1)
364-414: Escape key handler in keymap still reads stalehelperPaneStatefrom closureInside the keymap plugin, the
"Escape"binding closes the helper pane only ifhelperPaneState.isOpenfrom the initial render is true:"Escape": () => { if (helperPaneState.isOpen) { setHelperPaneState(prev => ({ ...prev, isOpen: false })); return true; } return false; }Because the keymap is created in an empty-deps
useEffect, this closure never sees updated state, so the handler will almost always returnfalse. The globaluseHelperPaneClickOutsideEscape handler currently hides this, but the keymap’s behavior is still incorrect and brittle.You can mirror the already-fixed Mod-/ toggle pattern and rely solely on the functional updater:
- "Escape": () => { - if (helperPaneState.isOpen) { - setHelperPaneState(prev => ({ ...prev, isOpen: false })); - return true; - } - return false; - } + "Escape": () => { + let wasOpen = false; + setHelperPaneState(prev => { + wasOpen = prev.isOpen; + return prev.isOpen ? { ...prev, isOpen: false } : prev; + }); + return wasOpen; + }This makes the keymap self-contained and ensures it always uses the latest pane state.
🧹 Nitpick comments (6)
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/utils.ts (1)
43-68: Consider externalizing the field-key-to-mode mapping.The special-case check
if (key === "query") return InputMode.PROMPThardcodes the relationship between the field key and its input mode. This pattern repeats across EditorFactory (line 158) and ExpressionEditor (lines 182–184), creating coupling that requires code changes in multiple files when adding new PROMPT-mode fields.Consider one of these approaches:
Option 1: Accept a configuration map:
+const FIELD_KEY_MODE_MAP: Record<string, InputMode> = { + query: InputMode.PROMPT +}; + export const getInputModeFromTypes = (valueTypeConstraint: string | string[], key?: string): InputMode => { if (!valueTypeConstraint) return; - if (key === "query") return InputMode.PROMPT; + if (key && FIELD_KEY_MODE_MAP[key]) return FIELD_KEY_MODE_MAP[key];Option 2: Store mode metadata on the field itself (e.g.,
field.inputMode) and check that before falling back to type-based inference. This would centralize mode decisions in the field definitions rather than scattered across utilities.workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionEditor.tsx (1)
411-411: Consider extracting the templated-mode check into a helper.The pattern
inputMode === InputMode.PROMPT || inputMode === InputMode.TEMPLATEappears throughout this file (lines 411, 418, 460, 570, 599, 706, 707, 716, 786, 789). Extracting it would reduce duplication and make future mode additions easier.For example, in utils.ts:
export const isTemplatedMode = (mode: InputMode): boolean => mode === InputMode.PROMPT || mode === InputMode.TEMPLATE;Then replace occurrences:
-const fieldValue = (inputModeRef.current === InputMode.PROMPT || inputModeRef.current === InputMode.TEMPLATE) && rawExpression ? rawExpression(watch(key)) : watch(key); +const fieldValue = isTemplatedMode(inputModeRef.current) && rawExpression ? rawExpression(watch(key)) : watch(key);workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/xmlTagDecorationPlugin.ts (1)
24-71: Decoration logic looks solid; consider avoidinganycasts inapplyThe decoration scan and classification (opening/closing/selfClosing) look correct and efficient enough for prompt-sized docs. In
state.apply, you can drop the(tr as any)casts and use the typedTransactionAPI directly:- apply(tr: Transaction, oldDecorationSet: DecorationSet, _oldState, newState) { - if ((tr as any).docChanged) { - return getDecorations(newState.doc); - } - return oldDecorationSet.map((tr as any).mapping, (tr as any).doc); - } + apply(tr: Transaction, oldDecorationSet: DecorationSet, _oldState, newState) { + if (tr.docChanged) { + return getDecorations(newState.doc); + } + return oldDecorationSet.map(tr.mapping, tr.doc); + }This keeps the logic the same while improving type safety and readability.
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx (3)
229-300: Chip click + helper selection flow is coherent; consider clarifying chip-specific state shapeThe chip click → helper-pane → chip replacement flow is nicely handled, including the
processFunctionWithArgumentshook and cursor repositioning logic.One small improvement would be to make the chip-specific fields (
clickedChipPos,clickedChipNode) explicit in the helper-pane state type (or in a dedicated local state) rather than piggybacking them onto the generichelperPaneState. That will make it clearer which parts of state belong to shared helper behavior vs. chip-specific behavior and avoid type drift asHelperPaneStateevolves.- setHelperPaneState({ - isOpen: true, - ...position, - clickedChipPos: chipPos, - clickedChipNode: chipNode - }); + setHelperPaneState(prev => ({ + ...prev, + isOpen: true, + ...position, + })); + // Optionally keep chip selection in a dedicated local ref/state: + setClickedChip({ pos: chipPos, node: chipNode });If
HelperPaneStatehas already been extended to include these fields in the shared hook, then this is just a documentation/typing detail.
418-452: Undo/redo detection via'history$'meta is a bit brittleThe dispatch logic differentiates undo/redo vs. regular edits using:
const meta = (transaction as any).getMeta('history$'); if (meta) { pendingTokenFetchRef.current = true; fetchAndUpdateTokens(view); } else { // inspect steps for inserted text, etc. }Relying on the literal
'history$'key ties this code to an internal detail ofprosemirror-history. Prefer using the official key or API exposed by that module (e.g., the exported history plugin key, if available) so future library changes don’t silently break token refresh.If
prosemirror-historyin this repo exports ahistoryKey/plugin key, you can do:import { history, undo, redo, historyKey } from "prosemirror-history"; const meta = transaction.getMeta(historyKey);Please double-check the exact API for the library version you have in
package.json.
471-488:value-based token fetch effect is effectively a no-op under current gatingThe
useEffectwatching[value]callsfetchAndUpdateTokens(viewRef.current), butfetchAndUpdateTokensimmediately returns unlesspendingTokenFetchRef.currentistrue. Since you intentionally only set that flag on user-driven edits (not on externalvaluechanges), this effect doesn’t actually re-tokenize on prop changes.Given the design choice from earlier discussions that tokenization should only react to user typing in the expanded editor, you could either:
- Remove this effect entirely, or
- Add a short code comment explaining that it’s intentionally gated by
pendingTokenFetchRefso future readers don’t assume external value updates re-tokenize.Based on learnings, token fetching on external
valuechanges is intentionally disabled.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
common/config/rush/pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (13)
workspaces/ballerina/ballerina-side-panel/package.json(1 hunks)workspaces/ballerina/ballerina-side-panel/src/components/ModeSwitcher/index.tsx(1 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/EditorFactory.tsx(1 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/ExpandedEditor.tsx(5 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/ChipComponent.tsx(0 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/MarkdownPreview.tsx(0 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/MarkdownToolbar.tsx(0 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/styles/markdown-preview.css(0 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/utils/transformToMarkdown.ts(0 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionEditor.tsx(13 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/utils.ts(4 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx(1 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/xmlTagDecorationPlugin.ts(1 hunks)
💤 Files with no reviewable changes (5)
- workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/utils/transformToMarkdown.ts
- workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/ChipComponent.tsx
- workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/MarkdownPreview.tsx
- workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/styles/markdown-preview.css
- workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/MarkdownToolbar.tsx
🧰 Additional context used
🧠 Learnings (12)
📚 Learning: 2025-11-25T06:34:10.812Z
Learnt from: CR
Repo: wso2/vscode-extensions PR: 0
File: workspaces/ballerina/component-diagram/AGENTS.md:0-0
Timestamp: 2025-11-25T06:34:10.812Z
Learning: Applies to workspaces/ballerina/component-diagram/src/components/**/*.tsx : Use React 18.2.0 features including concurrent rendering and automatic batching; avoid class components in favor of functional components with hooks
Applied to files:
workspaces/ballerina/ballerina-side-panel/src/components/ModeSwitcher/index.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/EditorFactory.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionEditor.tsxworkspaces/ballerina/ballerina-side-panel/package.json
📚 Learning: 2025-11-24T22:16:28.380Z
Learnt from: dan-niles
Repo: wso2/vscode-extensions PR: 980
File: workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx:384-412
Timestamp: 2025-11-24T22:16:28.380Z
Learning: In the RichTextTemplateEditor component (workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx), token fetching on external `value` prop changes is intentionally disabled. Users cannot edit both the minimized and expanded editors simultaneously, so tokens only need to be generated based on user typing in the expanded editor view, not on external prop updates.
Applied to files:
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/ExpandedEditor.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/EditorFactory.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionEditor.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/utils.ts
📚 Learning: 2025-11-27T07:59:33.534Z
Learnt from: KCSAbeywickrama
Repo: wso2/vscode-extensions PR: 897
File: workspaces/ballerina/data-mapper/src/components/DataMapper/SidePanel/QueryClauses/ClausesPanel.tsx:50-59
Timestamp: 2025-11-27T07:59:33.534Z
Learning: In workspaces/ballerina/data-mapper/src/components/DataMapper/SidePanel/QueryClauses/ClausesPanel.tsx, the `clause.properties.expression` property in the `fillDefaults` function does not require defensive null/undefined checks because it's a required property enforced by form validation in ClauseEditor.
Applied to files:
workspaces/ballerina/ballerina-side-panel/src/components/editors/EditorFactory.tsx
📚 Learning: 2025-11-24T14:51:49.267Z
Learnt from: KCSAbeywickrama
Repo: wso2/vscode-extensions PR: 998
File: workspaces/ballerina/data-mapper/src/components/DataMapper/Header/ExpressionBar.tsx:113-132
Timestamp: 2025-11-24T14:51:49.267Z
Learning: In workspaces/ballerina/data-mapper/src/components/DataMapper/Header/ExpressionBar.tsx, if `textFieldRef.current` is not undefined, `textFieldRef.current.inputElement` is guaranteed to exist. If `inputElement` doesn't exist when `current` exists, it's a fatal error that should reach the error boundary rather than being handled with defensive null checks.
Applied to files:
workspaces/ballerina/ballerina-side-panel/src/components/editors/EditorFactory.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionEditor.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/utils.ts
📚 Learning: 2025-11-25T06:34:10.812Z
Learnt from: CR
Repo: wso2/vscode-extensions PR: 0
File: workspaces/ballerina/component-diagram/AGENTS.md:0-0
Timestamp: 2025-11-25T06:34:10.812Z
Learning: Applies to workspaces/ballerina/component-diagram/src/components/nodes/EntryNode/components/**/*.tsx : Implement lazy expansion of functions: only render function items when they are visible to improve performance for large function lists
Applied to files:
workspaces/ballerina/ballerina-side-panel/src/components/editors/EditorFactory.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionEditor.tsx
📚 Learning: 2025-11-25T06:34:10.812Z
Learnt from: CR
Repo: wso2/vscode-extensions PR: 0
File: workspaces/ballerina/component-diagram/AGENTS.md:0-0
Timestamp: 2025-11-25T06:34:10.812Z
Learning: Applies to workspaces/ballerina/component-diagram/src/**/*.{ts,tsx} : Define all constants (node types, sizing, spacing) in src/resources/constants.ts and import them where needed instead of hardcoding values
Applied to files:
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/utils.tsworkspaces/ballerina/ballerina-side-panel/package.json
📚 Learning: 2025-11-25T06:34:10.812Z
Learnt from: CR
Repo: wso2/vscode-extensions PR: 0
File: workspaces/ballerina/component-diagram/AGENTS.md:0-0
Timestamp: 2025-11-25T06:34:10.812Z
Learning: Applies to workspaces/ballerina/component-diagram/**/*.config.{js,ts} : Use minimatch-compatible glob patterns for file matching in build and test configuration files
Applied to files:
workspaces/ballerina/ballerina-side-panel/package.json
📚 Learning: 2025-11-25T06:34:10.812Z
Learnt from: CR
Repo: wso2/vscode-extensions PR: 0
File: workspaces/ballerina/component-diagram/AGENTS.md:0-0
Timestamp: 2025-11-25T06:34:10.812Z
Learning: Applies to workspaces/ballerina/component-diagram/src/**/*.{ts,tsx} : Use TypeScript 5.8.3 with strict type checking enabled for all source files
Applied to files:
workspaces/ballerina/ballerina-side-panel/package.json
📚 Learning: 2025-11-25T06:34:10.812Z
Learnt from: CR
Repo: wso2/vscode-extensions PR: 0
File: workspaces/ballerina/component-diagram/AGENTS.md:0-0
Timestamp: 2025-11-25T06:34:10.812Z
Learning: Applies to workspaces/ballerina/component-diagram/src/components/**/*.tsx : Use Emotion for CSS-in-JS styling instead of inline styles or external CSS files
Applied to files:
workspaces/ballerina/ballerina-side-panel/package.json
📚 Learning: 2025-11-25T06:34:10.812Z
Learnt from: CR
Repo: wso2/vscode-extensions PR: 0
File: workspaces/ballerina/component-diagram/AGENTS.md:0-0
Timestamp: 2025-11-25T06:34:10.812Z
Learning: Applies to workspaces/ballerina/component-diagram/src/resources/icons/**/*.tsx : Create separate SVG icon components in src/resources/icons/ for all diagram icons and import them as React components
Applied to files:
workspaces/ballerina/ballerina-side-panel/package.json
📚 Learning: 2025-11-10T15:05:11.309Z
Learnt from: madushajg
Repo: wso2/vscode-extensions PR: 868
File: workspaces/bi/bi-extension/src/utils.ts:224-242
Timestamp: 2025-11-10T15:05:11.309Z
Learning: The workspaces/bi/bi-extension and workspaces/ballerina/ballerina-extension are separate VS Code extensions that are packaged and distributed independently, so they cannot share code via imports and must maintain their own implementations of common utilities.
Applied to files:
workspaces/ballerina/ballerina-side-panel/package.json
📚 Learning: 2025-11-25T06:34:10.812Z
Learnt from: CR
Repo: wso2/vscode-extensions PR: 0
File: workspaces/ballerina/component-diagram/AGENTS.md:0-0
Timestamp: 2025-11-25T06:34:10.812Z
Learning: Applies to workspaces/ballerina/component-diagram/src/stories/**/*.json : Provide sample data files in JSON format for Storybook stories covering: empty project, automation only, simple service, multiple services, complex connections, AI services, GraphQL services, and multiple connections
Applied to files:
workspaces/ballerina/ballerina-side-panel/package.json
🧬 Code graph analysis (3)
workspaces/ballerina/ballerina-side-panel/src/components/ModeSwitcher/index.tsx (2)
workspaces/ballerina/ballerina-side-panel/src/components/editors/index.ts (1)
InputMode(31-31)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/utils.ts (1)
getDefaultExpressionMode(65-68)
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx (5)
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/hooks/useHelperPane.ts (2)
useHelperPane(97-170)useHelperPaneClickOutside(36-70)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/constants.ts (1)
HELPER_PANE_WIDTH(42-42)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/utils.ts (2)
calculateHelperPanePosition(336-356)processFunctionWithArguments(364-417)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/CodeUtils.ts (1)
chipPlugin(327-379)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/xmlTagDecorationPlugin.ts (1)
createXMLTagDecorationPlugin(58-80)
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionEditor.tsx (3)
workspaces/ballerina/ballerina-side-panel/src/components/editors/index.ts (1)
InputMode(31-31)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/utils.ts (1)
getInputModeFromTypes(43-63)workspaces/ballerina/ballerina-side-panel/src/components/editors/utils.ts (2)
isExpandableMode(112-114)toEditorMode(116-118)
🔇 Additional comments (18)
workspaces/ballerina/ballerina-side-panel/src/components/ModeSwitcher/index.tsx (1)
29-38: WiringfieldKeyinto default mode calculation looks correctThe new optional
fieldKeyprop is typed consistently, passed through togetDefaultExpressionMode, and correctly added to theuseMemodependency array. ExistingisRecordTypeFieldbehavior is preserved, and no new edge‑case or correctness issues are apparent.workspaces/ballerina/ballerina-side-panel/package.json (4)
21-26: CodeMirror package versions now consistent.The CodeMirror package specifiers have been aligned to use tilde (
~) ranges uniformly across all @codemirror/* packages. This resolves the previous mixed-operator concern and should prevent runtime conflicts from duplicate core class instances. After merging, verify a single copy is resolved with:npm ls @codemirror/state
45-46: Verify intentional exact pinning of React and React-DOM.React and React-DOM are pinned to exact versions (18.2.0) rather than using a semver range. This is stricter than the tilde (~) ranges used for other dependencies.
If exact pinning is intentional (e.g., to ensure consistent concurrent rendering behavior per learnings), this is acceptable. If accidental, consider using a compatible range (e.g., ~18.2.0) to allow patch-level updates.
21-26: Verify CodeMirror 6 + ProseMirror 1.x integration in implementation.The package.json includes both CodeMirror 6 (lines 21–26) and ProseMirror 1.x (lines 34–44). These libraries can coexist, but require careful synchronization of text, selection, focus, and history to avoid conflicts.
Ensure the implementation:
- Syncs CodeMirror↔ProseMirror text changes via ProseMirror transactions.
- Coordinates undo/redo across both editors (prefer ProseMirror history).
- Explicitly handles focus transitions and debounces NodeView re-creation.
Search the codebase for NodeView implementations and CM6/ProseMirror integration tests to confirm these patterns are in place.
33-33: Bothmarkdown-itandreact-markdownserve distinct architectural purposes—likely no redundancy.
markdown-it(line 33, ~14.1.0) is a standalone CommonMark parser that produces HTML strings and supports plugins for extending parsing rules—useful for server-side rendering, static generation, or feeding Markdown into non-React systems (e.g., ProseMirror schemas).
react-markdown(line 48, ~10.1.0) is a React component wrapper that renders Markdown directly as React elements with safe-by-default behavior—appropriate for displaying user or CMS-supplied Markdown within React components with component-level customization.If both are present in
package.json, confirm they serve different integration points in the codebase (e.g., one for schema generation or server-side use, the other for UI rendering). If only one code path actually uses them, consider removing the unused dependency.workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/utils.ts (1)
335-356: LGTM! Helper pane positioning logic is sound.The function correctly computes position relative to the editor container, accounts for scroll offset, and prevents viewport overflow by adjusting left when the pane would extend beyond the window width.
workspaces/ballerina/ballerina-side-panel/src/components/editors/EditorFactory.tsx (1)
158-169: Routes "query" fields to the raw expression editor.This change aligns with the PROMPT mode routing introduced in
getInputModeFromTypes(utils.ts line 45) and ensures consistent editor selection for query fields across the factory.Note: This is part of the hardcoded field-key pattern discussed in the utils.ts review. If the mapping approach is refactored, update this condition accordingly.
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/ExpandedEditor.tsx (2)
150-154: LGTM! Enum-based mode mapping improves type safety.Migrating from string literals (
"text","prompt", etc.) to theInputModeenum (InputMode.TEXT,InputMode.PROMPT, etc.) provides compile-time checks and better IDE support.
220-256: inputMode prop correctly threaded to mode components.The
inputModeprop is now passed to PromptMode and TemplateMode, enabling those components to adapt behavior based on the active input mode.workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionEditor.tsx (2)
443-471: PROMPT mode detection and switching logic integrated correctly.The changes properly extend mode detection and switching to support PROMPT mode alongside TEMPLATE. The sanitization check (lines 461–467) correctly prevents mode switching when it would hide parts of the expression.
775-833: ExpandedEditor integration is sound.The
inputModeprop is correctly threaded through to ExpandedEditor, and the conditional rendering ensurestoEditorModereturns a valid mode before rendering (line 775), making the non-null assertion on line 822 safe.workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx (7)
49-127: Editor container styling aligns well with ProseMirror usageThe
EditorContainerstyling (padding, VS Code font/colour integration, heading/list/blockquote/pre/code rules, and the.xml-tag*classes) is cohesive and matches typical ProseMirror theming patterns. No changes needed here.
129-150: Markdown parser/serializer wiring for chips looks correctUsing a shared
chipSchemawith a customMarkdownParserand extendingdefaultMarkdownSerializer.nodeswith achiphandler that emitsnode.attrs.textkeeps markdown round-tripping straightforward. This should serialize back to the original text cleanly as long as chip nodes always carry the raw source inattrs.text.
179-227: Helper pane integration viauseHelperPaneis consistent with ChipExpressionEditorThe way you plug
useHelperPaneinto the rich-text editor (fixed manual toggle behavior, keyboard toggle based on cursor coordinates, and forwardingonHelperPaneStateChange) cleanly reuses the shared helper-pane abstraction fromChipExpressionEditor. This keeps positioning logic centralized and reduces duplication. Looks good.
302-330: Token fetch gate viapendingTokenFetchRefis sound; logging is the only side effect on failureThe
fetchAndUpdateTokenshelper correctly short-circuits whenrpcManager/fileNameare missing or whenpendingTokenFetchRefis false, and it resets the flag immediately before making the async call. The use ofplainText+wrappedForAPIandupdateChipTokensmatches the chip plugin contract; the only side effect on failure is a console error, which is acceptable for this UI path.
333-414: One-time editor initialization is fine; just ensure externalvaluechanges aren’t expected to rehydrate the docThe
useEffectwith an empty dependency array creates the ProseMirror state/view once and never re-parsesvalueon subsequent prop updates. This is a valid pattern for a “locally controlled” editor where the parent doesn’t programmatically changevaluewhile the component is mounted (other than throughonChangecallbacks).If there are flows (e.g., prompt reset, mode switch) where the parent might push a new
valueinto an already-mountedRichTextTemplateEditor, you’ll need to either:
- Recreate the editor state when
value(orsanitizedExpression) changes, or- Unmount/remount the editor component on such transitions.
You may want to confirm that all current callers either unmount on mode changes or treat this as the single source of truth so you don’t get out-of-sync ProseMirror content.
490-505: Helper-pane click-outside + Escape handling looks robustWiring
useHelperPaneClickOutsidewith the editor, helper pane, toggle button, and toolbar refs plus a dedicatedonEscapeKeythat closes the pane provides a good UX safety net. Combined with the keyboard toggle and keymap, this should make the helper pane behave predictably. No changes needed.
507-522: Render structure cleanly isolates the editor and helper paneConditionally rendering
HelperPaneinsideEditorContainerwith top/left props and forwardingvalue/onChangekeeps the overlay logic simple and self-contained. This matches the rest of the helper infrastructure and should integrate cleanly with externalgetHelperPaneproviders.
595fe69 to
02131e3
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (1)
workspaces/ballerina/ballerina-side-panel/package.json (1)
27-28: Optional: Normalize Emotion package semver ranges for consistency.Emotion packages use
^(caret) while most other dependencies use~(tilde). Unlike CodeMirror, Emotion does not rely on runtime identity, so this is not a blocker. However, for consistency across the manifest, consider aligning them:- "@emotion/react": "^11.14.0", - "@emotion/styled": "^11.14.0", + "@emotion/react": "~11.14.0", + "@emotion/styled": "~11.14.0",
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
common/config/rush/pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (1)
workspaces/ballerina/ballerina-side-panel/package.json(1 hunks)
🧰 Additional context used
🧠 Learnings (7)
📚 Learning: 2025-11-25T06:34:10.812Z
Learnt from: CR
Repo: wso2/vscode-extensions PR: 0
File: workspaces/ballerina/component-diagram/AGENTS.md:0-0
Timestamp: 2025-11-25T06:34:10.812Z
Learning: Applies to workspaces/ballerina/component-diagram/src/components/**/*.tsx : Use React 18.2.0 features including concurrent rendering and automatic batching; avoid class components in favor of functional components with hooks
Applied to files:
workspaces/ballerina/ballerina-side-panel/package.json
📚 Learning: 2025-11-25T06:34:10.812Z
Learnt from: CR
Repo: wso2/vscode-extensions PR: 0
File: workspaces/ballerina/component-diagram/AGENTS.md:0-0
Timestamp: 2025-11-25T06:34:10.812Z
Learning: Applies to workspaces/ballerina/component-diagram/**/*.config.{js,ts} : Use minimatch-compatible glob patterns for file matching in build and test configuration files
Applied to files:
workspaces/ballerina/ballerina-side-panel/package.json
📚 Learning: 2025-11-25T06:34:10.812Z
Learnt from: CR
Repo: wso2/vscode-extensions PR: 0
File: workspaces/ballerina/component-diagram/AGENTS.md:0-0
Timestamp: 2025-11-25T06:34:10.812Z
Learning: Applies to workspaces/ballerina/component-diagram/src/**/*.{ts,tsx} : Use TypeScript 5.8.3 with strict type checking enabled for all source files
Applied to files:
workspaces/ballerina/ballerina-side-panel/package.json
📚 Learning: 2025-11-25T06:34:10.812Z
Learnt from: CR
Repo: wso2/vscode-extensions PR: 0
File: workspaces/ballerina/component-diagram/AGENTS.md:0-0
Timestamp: 2025-11-25T06:34:10.812Z
Learning: Applies to workspaces/ballerina/component-diagram/src/components/**/*.tsx : Use Emotion for CSS-in-JS styling instead of inline styles or external CSS files
Applied to files:
workspaces/ballerina/ballerina-side-panel/package.json
📚 Learning: 2025-11-25T06:34:10.812Z
Learnt from: CR
Repo: wso2/vscode-extensions PR: 0
File: workspaces/ballerina/component-diagram/AGENTS.md:0-0
Timestamp: 2025-11-25T06:34:10.812Z
Learning: Applies to workspaces/ballerina/component-diagram/src/**/*.{ts,tsx} : Define all constants (node types, sizing, spacing) in src/resources/constants.ts and import them where needed instead of hardcoding values
Applied to files:
workspaces/ballerina/ballerina-side-panel/package.json
📚 Learning: 2025-11-25T06:34:10.812Z
Learnt from: CR
Repo: wso2/vscode-extensions PR: 0
File: workspaces/ballerina/component-diagram/AGENTS.md:0-0
Timestamp: 2025-11-25T06:34:10.812Z
Learning: Applies to workspaces/ballerina/component-diagram/src/resources/icons/**/*.tsx : Create separate SVG icon components in src/resources/icons/ for all diagram icons and import them as React components
Applied to files:
workspaces/ballerina/ballerina-side-panel/package.json
📚 Learning: 2025-11-25T06:34:10.812Z
Learnt from: CR
Repo: wso2/vscode-extensions PR: 0
File: workspaces/ballerina/component-diagram/AGENTS.md:0-0
Timestamp: 2025-11-25T06:34:10.812Z
Learning: Applies to workspaces/ballerina/component-diagram/src/stories/**/*.json : Provide sample data files in JSON format for Storybook stories covering: empty project, automation only, simple service, multiple services, complex connections, AI services, GraphQL services, and multiple connections
Applied to files:
workspaces/ballerina/ballerina-side-panel/package.json
🔇 Additional comments (2)
workspaces/ballerina/ballerina-side-panel/package.json (2)
21-26: ✅ CodeMirror package versions now consistently aligned.The previous concern about mixed semver operators (tilde vs. caret) in CodeMirror dependencies has been resolved. All
@codemirror/*packages now use the~prefix, ensuring npm resolves them to the same minor/patch release and avoiding duplicate@codemirror/stateclass instances at runtime.
27-28: Verify CodeMirror 6 + ProseMirror 1.x integration is tested.This change introduces a substantial integration of CodeMirror 6 and ProseMirror 1.x together in the editor stack. Per prior discussion, this requires careful two-way synchronization (content, selection, focus, undo/redo). Before merge, ensure that:
- The NodeView mounting CodeMirror inside ProseMirror properly syncs text changes and selection state.
- History/undo-redo coordination does not create duplicate stacks or inconsistent state.
- Focus transitions between the two editors work reliably.
Consider running manual integration tests in the prompt editor to validate these edge cases.
Also applies to: 32-48
Purpose
Resolves wso2/product-ballerina-integrator#1962, wso2/product-ballerina-integrator#2008
This PR introduces a simplified, WYSIWYG-style editing mode for the prompt editor. The new editor hides all underlying markdown syntax and allows users to work entirely with formatted text, making prompt creation more intuitive for integration developers.
Screen.Recording.2025-11-25.at.5.56.59.PM.mov
Screen.Recording.2025-11-30.at.9.39.38.AM.mov
Changes Include:
Goals
This change addresses the usability issues described in the linked GitHub issue by:
Approach
The solution is implemented using a ProseMirror-powered rich text editor configured to:
UI Component Development
npm run storybookfrom the root directory to view current components.Manage Icons
User stories
This change supports the following user story:
"As an integration developer, I want a simplified prompt editor that hides unnecessary markdown syntax, so I can write prompts easily without learning markdown."
Release note
Introduces a new simplified WYSIWYG-style prompt editor with full formatting capabilities, replacing the old Edit/Preview modes with Rich Text/Raw modes. Includes support for helper pane integrations and variable chip rendering.
Summary by CodeRabbit
New Features
Improvements
✏️ Tip: You can customize this high-level summary in your review settings.