Introduce a Simplified Mode for Editing Prompts in the Expanded Editor#980
Introduce a Simplified Mode for Editing Prompts in the Expanded Editor#980
Conversation
|
Note Other AI code review bot(s) detectedCodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review. WalkthroughAdds a WYSIWYG-capable prompt editor with a new InputMode.PROMPT, dual-source (CodeMirror) and rich (ProseMirror) editing views, toolbars and link dialog, helper‑pane hooks/utilities, ProseMirror plugins/editors, extensive token/chip handling, diagram integration, and dependency updates for CodeMirror/ProseMirror tooling. (50 words) Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant PromptMode as PromptMode
participant ViewToggle as View Toggle
participant CodeMirror as CodeMirror (source)
participant ProseMirror as ProseMirror (rich)
participant RawToolbar as RawTemplateMarkdownToolbar
participant RichToolbar as RichTemplateMarkdownToolbar
participant HelperPane as Helper Pane
participant Diagram as Diagram / RPC
User->>PromptMode: Open expanded editor
PromptMode->>PromptMode: Determine default view (simple vs rich) using InputMode.PROMPT
alt Source view (CodeMirror)
PromptMode->>CodeMirror: Mount source editor and attach RawToolbar
User->>RawToolbar: Click formatting
RawToolbar->>CodeMirror: Execute command (format/undo/redo)
else Rich view (ProseMirror)
PromptMode->>ProseMirror: Mount rich editor and attach RichToolbar
User->>RichToolbar: Click formatting or open link dialog
RichToolbar->>ProseMirror: Execute ProseMirror command
end
User->>ViewToggle: Toggle view
ViewToggle->>PromptMode: set isSourceView
PromptMode->>CodeMirror: Serialize/sync content
PromptMode->>ProseMirror: Initialize/sync rich view
User->>RichToolbar: Open helper pane
RichToolbar->>HelperPane: Request position (cursor coords)
HelperPane->>PromptMode: useHelperPane computes position (calculateHelperPanePosition)
HelperPane->>Diagram: Optionally fetch tokens/completions via RPC
Diagram->>HelperPane: Return completion/tokens
HelperPane->>User: Display anchored suggestions
Estimated code review effort🎯 4 (Complex) | ⏱️ ~75 minutes Areas needing extra attention:
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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
ff20805 to
766e30f
Compare
There was a problem hiding this comment.
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.
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.
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.
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
4772ca1 to
ad9c937
Compare
16a2c32 to
73d1253
Compare
There was a problem hiding this comment.
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/components/ChipExpressionEditor.tsx (1)
307-310: Unused variable:selectionis read but never used.The selection is retrieved but nothing is done with it.
// Save current cursor position before toggling - if (viewRef.current) { - const selection = viewRef.current.state.selection.main; - }
♻️ Duplicate comments (6)
workspaces/ballerina/bi-diagram/src/components/editors/NPPromptEditor.tsx (3)
277-286: Addprops.node(orcreateProperty) tochipExtractArgsFromFunctiondependencies
chipExtractArgsFromFunctionis memoized only onextractArgsFromFunction, but it also usescreateProperty(sanitizedValue)which depends onprops.node. If the node changes, the memoized function will keep using the old node’spromptproperty.Minimal fix:
- }, [extractArgsFromFunction]); + }, [extractArgsFromFunction, props.node]);This ensures argument extraction runs against the up‑to‑date node.
288-341: MemoizeexpressionEditorto makeFormContextvalue stable
expressionEditoris recreated on every render and then included in theformContextValuedependency list. This defeatsuseMemoonformContextValueand can cause unnecessary re-renders of all consumers of the context.You can memoize
expressionEditorand keepformContextValuestable when inputs don’t change:- const expressionEditor: FormExpressionEditorProps = { + const expressionEditor = useMemo<FormExpressionEditorProps>(() => ({ completions: completions, triggerCharacters: triggerCharacters, retrieveCompletions: async (value: string, property: ExpressionProperty, offset: number, triggerCharacter?: string) => { await retrieveCompletions(getSanitizedExp(value), property, offset, triggerCharacter); }, extractArgsFromFunction: extractArgsFromFunction, ...(getHelperPane ? { getHelperPane: getHelperPane, helperPaneOrigin: "vertical" as const, helperPaneHeight: "default" as const, } : {}), @@ onBlur: onBlur, onCancel: onCancel, getExpressionFormDiagnostics: getExpressionFormDiagnostics, rpcManager: { getExpressionTokens: getExpressionTokens || (async () => []) } - } as FormExpressionEditorProps; + }), [ + completions, + triggerCharacters, + retrieveCompletions, + extractArgsFromFunction, + getHelperPane, + onCompletionItemSelect, + onBlur, + onCancel, + getExpressionFormDiagnostics, + getExpressionTokens, + ]);
formContextValuecan then safely depend onexpressionEditorwithout constantly changing.
174-204: Debounced diagnostics still lack cleanup and may capture stale node stateThe debounced
fetchDiagnostics:
- Has no cleanup on unmount, so pending timeouts can still fire and call
setFormDiagnosticsafter the component is gone.- Only depends on
enableDiagnosticsandgetExpressionFormDiagnostics, but the callback also closes overprops.nodeviacreateProperty. If the node changes, diagnostics may be computed against stale node data.Consider:
- const fetchDiagnostics = useCallback( - debounce(async (expression: string) => { + const fetchDiagnostics = useCallback( + debounce(async (expression: string) => { if (!enableDiagnostics || !getExpressionFormDiagnostics) { return; } @@ - }, 300), - [enableDiagnostics, getExpressionFormDiagnostics] - ); + }, 300), + [enableDiagnostics, getExpressionFormDiagnostics, props.node] + ); + + // Cancel debounced diagnostics on unmount to avoid setState on unmounted component + React.useEffect(() => { + return () => { + fetchDiagnostics.cancel(); + }; + }, [fetchDiagnostics]);This keeps diagnostics aligned with the current node and prevents leaks / setState-after-unmount problems.
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/utils.ts (1)
342-343: Unused variable:linesis declared but never used.The
serializedValue.split('\n')result is stored but not referenced anywhere in the function. Either remove it or use it if intended for multi-line handling.- // Reconstruct the raw expression to properly handle multi-line cases - const lines = serializedValue.split('\n'); - for (const chunk of chunks) {workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionEditor.tsx (1)
443-443: Inconsistent usage ofgetInputModeFromTypes: missingfield.keyparameter.This call omits the
keyparameter while other calls in this file (lines 567, 642, 699) includefield.key. This may cause incorrect mode detection for query fields.- let newInputMode = getInputModeFromTypes(field.valueTypeConstraint); + let newInputMode = getInputModeFromTypes(field.valueTypeConstraint, field.key);workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx (1)
364-414: Escape key handler still suffers from a stalehelperPaneStateclosureThe keymap plugin is created in a
useEffectwith empty deps, so the"Escape"handler closes over the initialhelperPaneState. The condition:if (helperPaneState.isOpen) { setHelperPaneState(prev => ({ ...prev, isOpen: false })); return true; } return false;will always see the initial
isOpen(typicallyfalse), so Escape pressed inside the editor won’t reliably close the helper pane.Use the functional updater only and derive the return value from it, similar to how
handleKeyboardTogglewas fixed:- "Escape": () => { - if (helperPaneState.isOpen) { - setHelperPaneState(prev => ({ ...prev, isOpen: false })); - return true; - } - return false; - } + "Escape": () => { + let wasOpen = false; + setHelperPaneState(prev => { + wasOpen = prev.isOpen; + if (prev.isOpen) { + return { ...prev, isOpen: false }; + } + return prev; + }); + return wasOpen; + }This keeps the handler correct regardless of render cycles and avoids relying on closed-over state.
Also applies to: 398-406
🧹 Nitpick comments (8)
workspaces/ballerina/ballerina-visualizer/src/utils/bi.tsx (1)
700-737: Defensive guard is good; consider reflecting it in the type signatureThe new
if (!signatureHelp) { return undefined; }avoids a potential runtime error whensignatureHelpis null/undefined and is consistent with otherundefinedreturns in this helper.To tighten typings and make this contract clearer to callers, you could optionally update the function signature to accept/return
undefinedexplicitly, e.g.:export async function convertToFnSignature( signatureHelp?: SignatureHelpResponse ): Promise<ReturnType<typeof convertToFnSignature> | undefined> { /* … */ }or at least
signatureHelp: SignatureHelpResponse | undefined.Not strictly required for behavior, but it will surface misuse earlier via TS.
workspaces/ballerina/bi-diagram/src/components/editors/NPPromptEditor.tsx (2)
334-336: Avoid hard-codingnodeInfo.kind
nodeInfo.kindis currently hard-coded to"NP_FUNCTION":nodeInfo: { kind: "NP_FUNCTION" as NodeKind }If
NPPromptEditoris ever used with non-function nodes (or if the actualFlowNodekind differs), this will be wrong and may affect downstream behavior (e.g., helper panes, diagnostics).Consider deriving this from the actual node instead:
nodeInfo: { // Adjust field name if FlowNode exposes kind differently kind: (props.node as any).kind as NodeKind, }or pass the appropriate kind in via props if that’s more accurate.
372-373: InstantiateRawTemplateEditorConfigonce instead of per renderYou create a new
RawTemplateEditorConfiginstance on every render:configuration={new RawTemplateEditorConfig()} ... value={getRawExp(value)}If
RawTemplateEditorConfigis heavy or compared by reference inside the editor, this can add avoidable work.A small optimization:
const rawTemplateEditorConfig = React.useMemo( () => new RawTemplateEditorConfig(), [] );and then:
configuration={rawTemplateEditorConfig}This keeps the config stable across renders.
Also applies to: 395-395
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/PromptMode.tsx (2)
40-40: Consider extracting constant to a shared configuration file.
SIMPLE_PROMPT_FIELDSis hardcoded. If this list needs to be reused or extended elsewhere, consider moving it to a constants file.
71-74: Consider removing the pass-through adapter.
handleChangeis a direct pass-through toonChange. Unless additional logic is planned, you could passonChangedirectly to the child components.- const handleChange = (updatedValue: string, updatedCursorPosition: number) => { - onChange(updatedValue, updatedCursorPosition); - };Then use
onChangedirectly in place ofhandleChangeon lines 117 and 140.workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx (2)
154-190:completionsprop is currently unused in the rich editor
RichTextTemplateEditorPropsexposes acompletions?: CompletionItem[], but the component doesn’t destructure or pass it into any plugins. This can confuse consumers of the API.Either:
- Wire
completionsinto the chip/plugin layer if it’s meant to be supported here, or- Drop it from the props for now to keep the public surface aligned with behavior.
302-330: Token fetch gating matches the “no externalvalue-driven tokens” design, but is non-obvious
fetchAndUpdateTokensis guarded bypendingTokenFetchRef.current, and the[value]effect calls it without setting the flag, so externalvalueupdates effectively do not trigger token refresh. This aligns with the earlier design decision that tokens should only be regenerated from user typing in the expanded editor, not from external prop changes.If you want to make this clearer for future maintainers, consider:
- Either removing the
[value]effect entirely, or- Adding a brief comment there explaining that the early return is intentional and tied to the expanded-vs-minimized editor constraint.
Based on learnings, token fetching on external
valuechanges is intentionally disabled.Also applies to: 483-488
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/plugins/markdownCommands.ts (1)
100-142: TightenconvertListTypebehavior whendispatchis undefined
convertListTypecurrently short-circuits withif (!dispatch) return true;. That means capability checks that call commands withdispatch = undefined(e.g., toolbar enable/disable logic) will report that list conversion is always possible, even when the selection isn’t insidefromListType.You can make this more accurate by still walking the selection tree when
dispatchis undefined, but skipping the actual transaction dispatch:-const convertListType = (state: EditorState, dispatch: ((tr: Transaction) => void) | undefined, fromListType: NodeType, toListType: NodeType): boolean => { - if (!dispatch) return true; - +const convertListType = ( + state: EditorState, + dispatch: ((tr: Transaction) => void) | undefined, + fromListType: NodeType, + toListType: NodeType +): boolean => { const { $from } = state.selection; for (let d = $from.depth; d >= 0; d--) { 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)); - dispatch(tr.setSelection(state.selection.map(tr.doc, tr.mapping))); - return true; + if (dispatch) { + const tr = (state.tr as any).replaceWith( + pos, + pos + node.nodeSize, + toListType.create(node.attrs, node.content) + ); + dispatch(tr.setSelection(state.selection.map(tr.doc, tr.mapping))); + } + return true; } } return false; };This keeps runtime behavior the same while making
toggleBulletList/toggleOrderedListanswer more truthfully in “can execute?” contexts.
📜 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 (17)
workspaces/ballerina/ballerina-side-panel/src/components/editors/EditorFactory.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/PromptMode.tsx(1 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionEditor.tsx(14 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionField.tsx(1 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/CodeUtils.ts(8 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/ChipExpressionEditor.tsx(10 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/plugins/chipPlugin.ts(1 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/plugins/markdownCommands.ts(1 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/plugins/xmlTagDecorationPlugin.ts(1 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/index.ts(1 hunks)workspaces/ballerina/ballerina-visualizer/src/utils/bi.tsx(1 hunks)workspaces/ballerina/ballerina-visualizer/src/views/BI/HelperPaneNew/Views/DocumentConfig.tsx(5 hunks)workspaces/ballerina/ballerina-visualizer/src/views/BI/HelperPaneNew/utils/utils.ts(1 hunks)workspaces/ballerina/bi-diagram/src/components/editors/NPPromptEditor.tsx(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
- workspaces/ballerina/ballerina-side-panel/src/components/editors/EditorFactory.tsx
- workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/plugins/xmlTagDecorationPlugin.ts
- workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RichTemplateMarkdownToolbar.tsx
- workspaces/ballerina/ballerina-visualizer/src/views/BI/HelperPaneNew/Views/DocumentConfig.tsx
🧰 Additional context used
🧠 Learnings (13)
📚 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/utils/utils.tsworkspaces/ballerina/ballerina-side-panel/src/components/editors/index.tsworkspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/CodeUtils.tsworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/PromptMode.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/ChipExpressionEditor.tsxworkspaces/ballerina/bi-diagram/src/components/editors/NPPromptEditor.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionField.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/plugins/markdownCommands.tsworkspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/utils.tsworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionEditor.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/plugins/chipPlugin.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/**/*.{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/index.tsworkspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/utils.tsworkspaces/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/index.ts : Export the main Diagram component as the default export from the package entry point (index.ts)
Applied to files:
workspaces/ballerina/ballerina-side-panel/src/components/editors/index.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/**/*.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/src/components/editors/index.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/modes/PromptMode.tsxworkspaces/ballerina/bi-diagram/src/components/editors/NPPromptEditor.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionEditor.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/PromptMode.tsxworkspaces/ballerina/bi-diagram/src/components/editors/NPPromptEditor.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionField.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/utils.tsworkspaces/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/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.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.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/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.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 Emotion for CSS-in-JS styling instead of inline styles or external CSS files
Applied to files:
workspaces/ballerina/bi-diagram/src/components/editors/NPPromptEditor.tsx
🧬 Code graph analysis (7)
workspaces/ballerina/ballerina-visualizer/src/views/BI/HelperPaneNew/utils/utils.ts (1)
workspaces/ballerina/ballerina-side-panel/src/components/editors/index.ts (1)
InputMode(32-32)
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/CodeUtils.ts (1)
workspaces/common-libs/ui-toolkit/src/styles/Theme.ts (1)
ThemeColors(79-104)
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/ChipExpressionEditor.tsx (8)
workspaces/ballerina/ballerina-side-panel/src/components/editors/index.ts (1)
InputMode(32-32)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(21-21)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/CodeUtils.ts (1)
buildHelperPaneKeymap(606-625)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/utils.ts (1)
correctTokenStreamPositions(320-389)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/styles.tsx (3)
ChipEditorContainer(45-52)FloatingButtonContainer(273-280)FloatingToggleButton(282-309)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/FloatingToggleButton.tsx (1)
FloatingToggleButton(30-45)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/FloatingButtonIcons.tsx (4)
CloseHelperIcon(32-41)OpenHelperIcon(21-30)MinimizeIcon(54-63)ExpandIcon(43-52)
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionField.tsx (3)
workspaces/ballerina/ballerina-side-panel/src/components/editors/index.ts (1)
InputMode(32-32)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/TextExpressionEditor/TextModeEditor.tsx (1)
TextModeEditor(40-69)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/Configurations.tsx (2)
RawTemplateEditorConfig(96-126)StringTemplateEditorConfig(64-94)
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/plugins/markdownCommands.ts (1)
workspaces/mi/syntax-tree/src/syntax-tree-interfaces.ts (1)
Transaction(1588-1591)
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionEditor.tsx (2)
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)
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/plugins/chipPlugin.ts (4)
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/types.ts (2)
TokenMetadata(70-74)CompoundTokenSequence(96-104)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(106-111)getParsedExpressionTokens(113-139)detectTokenPatterns(236-290)
🔇 Additional comments (29)
workspaces/ballerina/ballerina-visualizer/src/views/BI/HelperPaneNew/utils/utils.ts (1)
22-24: Verify all call sites pass the requiredinputModeparameter.The improved signature (making
inputModerequired) clarifies the parameter is actively used. The logic correctly wraps values in template interpolation syntax for both PROMPT and TEMPLATE modes, aligning with the PROMPT mode template support.Ensure all call sites of
wrapInTemplateInterpolation()have been updated to provide the now-requiredinputModeparameter, as this is a breaking change to the function signature.workspaces/ballerina/bi-diagram/src/components/editors/NPPromptEditor.tsx (1)
231-251: Repository access unavailable for verificationThe repository
wso2/vscode-extensionscannot be accessed to verify the review comment aboutNPPromptEditor.tsx(lines 231-251). Without access to the actual codebase, I cannot confirm:
- Whether the code snippet matches the actual implementation
- What
retrieveCompletionsexpects for expression text and offset arguments- How the inline editor path handles sanitization
- Whether using raw
updatedValuevs sanitized value creates actual inconsistency- Whether the
cursorPosition + 1offset is correctThe review comment raises a valid concern pattern (sanitization consistency), but verification of the specific implementation details is impossible.
workspaces/ballerina/ballerina-side-panel/src/components/editors/index.ts (1)
30-33: LGTM!The new exports for
Configurations,InputMode, andExpandedEditorare properly organized and follow the existing barrel export pattern.workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/CodeUtils.ts (2)
336-355: LGTM - Sensible safeguard for multi-line content.Skipping chip rendering when content contains newlines prevents visual issues with multi-line tokens/compounds in the editor.
606-624: LGTM - Clean keyboard toggle integration.The optional
onTogglecallback extends the keymap to supportCtrl-//Cmd-/for toggling the helper pane, with backward-compatible behavior whenonToggleis not provided.workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/utils.ts (3)
43-67: LGTM - Clean key-based mode detection.The addition of the optional
keyparameter enables special handling for query fields (key === "query"→InputMode.PROMPT), with proper fallthrough to existing type-based detection.
292-313: LGTM - Well-structured helper pane positioning.The function properly handles viewport overflow correction and accounts for scroll position.
391-445: LGTM - Function argument processing with cursor placement.The cursor adjustment logic using
lastIndexOf(")")correctly positions the caret before the closing parenthesis, and the error handling with fallback is appropriate.workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionField.tsx (1)
212-231: LGTM - PROMPT mode integration follows established patterns.The new PROMPT mode branch correctly mirrors the existing TEXT and TEMPLATE implementations, with appropriate configuration selection based on
valueTypeConstraint.workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/PromptMode.tsx (1)
92-158: LGTM - Well-structured dual-editor implementation.The source/rich view toggle with appropriate toolbar and editor component switching is cleanly implemented. The error banner rendering for diagnostics provides good user feedback.
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionEditor.tsx (4)
411-418: LGTM - Consistent PROMPT mode handling.The
fieldValuecomputation and initial diagnostics fetch correctly includeInputMode.PROMPTalongside existing modes.
552-558: LGTM - Robust template safety check.The
isExpToTemplateSafefunction correctly validates both backtick-wrapped strings andstringtagged template literals using a regex pattern.
576-588: LGTM - Clean PROMPT/TEMPLATE mode switching logic.The mode switching correctly handles empty values, validates template safety, and provides appropriate fallback behavior.
775-833: LGTM - ExpandedEditor integration with PROMPT support.The ExpandedEditor invocation correctly passes
inputMode, usestoEditorMode()for mode mapping, and providessanitizedExpression/rawExpressionfor PROMPT and TEMPLATE modes.workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/plugins/chipPlugin.ts (5)
46-110: LGTM - Well-defined chip node specification.The node spec correctly defines an inline, atomic, draggable chip with proper DOM serialization and parsing. The attribute set covers all necessary token metadata.
184-212: LGTM - Robust position mapping.The
findDocPositionfunction correctly handles edge cases by clamping to valid bounds and properly traverses text nodes to map plain text offsets to document positions.
372-379: Potential edge case whenplainTextis not found inwrappedText.If
wrappedText.indexOf(plainText)returns -1 (substring not found),prefixLengthbecomes -1 and the conditionprefixLength > 0correctly skips adjustment. However, this also skips the case whenprefixLength === 0(exact match at start), which might be intentional but should be verified.Consider if the condition should be
>= 0to handle exact matches:- if (prefixLength > 0) { + if (prefixLength >= 0) {This would apply position adjustments even when the plain text starts at position 0, which is likely the correct behavior for most cases.
309-318: LGTM - Correct reverse-order replacement strategy.Sorting replacements in reverse order (end to start) before applying ensures earlier positions remain valid after modifications.
356-395: LGTM - Well-structured plugin with deduplication.The plugin correctly:
- Debounces token updates via
lastProcessedTokenscomparison- Marks chip transformations as non-undoable (
addToHistory: false)- Only processes when tokens actually change
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/ChipExpressionEditor.tsx (6)
100-103: LGTM - Well-designed prop additions.The new optional props (
inputMode,hideFxButton,disabled,placeholder) extend the component's flexibility without breaking existing usage.
153-179: LGTM - Clean helper pane state management.The
useHelperPanehook integration with conditional custom toggle for PROMPT mode in expanded view is well-structured. ThegetCursorCoordscallback is properly memoized.
362-393: LGTM - Proper dynamic configuration with Compartment.Using
CompartmentforEditorView.editableenables runtime toggling of the disabled state. The conditional placeholder extension and theme adjustments based on props are well-implemented.
433-440: LGTM - Token stream position correction.Proper use of
correctTokenStreamPositionswith serialization prefix/suffix lengths to adjust token positions after wrapping/unwrapping.
473-497: LGTM - Clean abstractions for editable state and click handling.The dynamic editable state update via compartment reconfiguration and the
useHelperPaneClickOutsidehook for closing the helper pane are well-implemented patterns.
537-553: LGTM - Conditional UI rendering respects disabled state.The floating buttons are correctly hidden when
disabledis true, preventing user interaction in readonly mode.workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx (3)
131-152: Chip-aware Markdown parser/serializer setup looks solidUsing
defaultMarkdownParser.tokenswith a custom schema and overriding only thechipnode inMarkdownSerializeris a clean way to keep default behavior while serializing chips vianode.attrs.text. No issues spotted here.
253-300: Helper-pane chip replacement flow is well-structuredThe logic to replace a clicked chip with helper-pane text (including the function-argument expansion via
processFunctionWithArguments) and then serialize back to markdown before callingonChangeis coherent and preserves the cursor position correctly. No changes needed from my side.
490-523: Helper pane outside-click / Escape handling is consistent
useHelperPaneClickOutsideis correctly wired with all relevant refs (editor, helper pane, toggle button, toolbar) and uses functional state updates to close the pane on outside clicks or Escape. This complements the keyboard keymap behavior nicely.workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/plugins/markdownCommands.ts (1)
26-99: Command definitions and active-state helpers look idiomaticThe
Commandtype alias, basic mark toggles, block toggles (headings, paragraphs, blockquotes), list toggles, and theisMarkActive/isNodeActive/isListActivehelpers follow common ProseMirror patterns and should integrate cleanly with both keymaps and toolbars. No functional issues stand out here.Also applies to: 144-194
workspaces/ballerina/bi-diagram/src/components/editors/NPPromptEditor.tsx
Show resolved
Hide resolved
There was a problem hiding this comment.
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/ExpressionEditor.tsx (1)
710-725: Diagnostics for PROMPT/TEMPLATE should userawValue(notupdatedValue) for consistency.In the inline
ExpressionFieldchange handler, you correctly computerawValuefor PROMPT/TEMPLATE (usingrawExpression), but still invokegetExpressionEditorDiagnosticswithupdatedValue. The expanded editor path already usesrawValue, and the initial diagnostics effect also uses the raw expression, so this is inconsistent and may validate the wrong text for PROMPT/TEMPLATE.You can fix this by always using
rawValuefor diagnostics and emptiness:- const rawValue = (currentMode === InputMode.PROMPT || currentMode === InputMode.TEMPLATE) && rawExpression ? rawExpression(updatedValue) : updatedValue; + const rawValue = + (currentMode === InputMode.PROMPT || currentMode === InputMode.TEMPLATE) && rawExpression + ? rawExpression(updatedValue) + : updatedValue; ... - onChange(rawValue); - if (getExpressionEditorDiagnostics && (currentMode === InputMode.EXP || currentMode === InputMode.PROMPT || currentMode === InputMode.TEMPLATE)) { - getExpressionEditorDiagnostics( - (required ?? !field.optional) || updatedValue !== '', - updatedValue, - key, - getPropertyFromFormField(field) - ); - } + onChange(rawValue); + if ( + getExpressionEditorDiagnostics && + (currentMode === InputMode.EXP || currentMode === InputMode.PROMPT || currentMode === InputMode.TEMPLATE) + ) { + getExpressionEditorDiagnostics( + (required ?? !field.optional) || rawValue !== '', + rawValue, + key, + getPropertyFromFormField(field) + ); + }This keeps EXP behavior unchanged (since
rawValue === updatedValuethere) while ensuring PROMPT/TEMPLATE diagnostics run against the underlying Ballerina expression.
♻️ Duplicate comments (11)
workspaces/ballerina/ballerina-visualizer/src/views/BI/HelperPaneNew/Views/DocumentConfig.tsx (1)
218-219: Inconsistent template mode detection for URL insertion.Line 166 treats both
InputMode.PROMPTandInputMode.TEMPLATEas template modes, but line 218 only checks forInputMode.PROMPT. This means URL insertion inTEMPLATEmode won't apply string interpolation wrapping, while item selection at line 166 will.Apply this diff if the behavior should be consistent:
- const isTemplateMode = inputMode === InputMode.PROMPT; + const isTemplateMode = inputMode === InputMode.PROMPT || inputMode === InputMode.TEMPLATE;Otherwise, add a comment explaining why URL insertion should behave differently in
TEMPLATEmode.workspaces/ballerina/bi-diagram/src/components/editors/NPPromptEditor.tsx (4)
278-286: Stale closure risk inchipExtractArgsFromFunction.
createPropertycapturesprops.node, but onlyextractArgsFromFunctionis in the dependency array. Ifprops.nodechanges, this memoized function will use stale node data.
174-204: Add cleanup for debounced function.The debounced
fetchDiagnosticsfunction lacks cleanup on unmount, which can cause memory leaks and setState calls on unmounted components. Additionally, the stale closure issue withprops.noderemains unresolved.
288-312: MemoizeexpressionEditorto prevent unnecessary re-renders.The
expressionEditorobject is created inline without memoization but is included as a dependency in theformContextValueuseMemo (line 339). This causesformContextValueto be recreated on every render.
64-65:onFocusprop is defined but never used.
onFocusis exposed viaNPPromptEditorPropsbut not wired intoChipExpressionEditorComponentorExpandedEditor. Callers passingonFocuswill see no effect.workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/utils.ts (2)
391-445: Consider removing unusedbasePositionparameter.Per a previous review, the
basePositionparameter is not used withinprocessFunctionWithArguments. The cursor adjustment is computed entirely fromfinalValue. Removing it would simplify the API.export const processFunctionWithArguments = async ( value: string, - basePosition: number, extractArgsFromFunction: (value: string, cursorPosition: number) => Promise<{Callers would need to be updated accordingly.
342-343: Unused variablelinesis still present.The
linesvariable fromserializedValue.split('\n')is declared but never used. This was flagged in a previous review but appears to remain unaddressed.- // Reconstruct the raw expression to properly handle multi-line cases - const lines = serializedValue.split('\n'); - for (const chunk of chunks) {workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/LinkDialog.tsx (1)
143-157: Fix TextField handlers: use onTextChange instead of onChangePer the existing review comment, the UI toolkit
TextFieldusesonTextChangerather than DOMonChange. The current approach withonChangeande.target.valuemay leaveurl/titlestuck at their initial values.workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionEditor.tsx (1)
443-467: PROMPT mode detection still omitsfield.keywhen inferringnewInputMode.This call still passes only
field.valueTypeConstraint, sogetInputModeFromTypescannot use the"query"key heuristic to selectInputMode.PROMPThere, unlike other call sites that pass the key. That can lead to inconsistent default modes for query fields between this editor andChipExpressionEditor.Recommend aligning this call with the others:
- let newInputMode = getInputModeFromTypes(field.valueTypeConstraint); + let newInputMode = getInputModeFromTypes(field.valueTypeConstraint, field.key);workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/hooks/useHelperPane.ts (1)
154-162: Effect that callsonStateChangestill omits key dependencies.The
useEffectthat invokesonStateChangeonly depends onhelperPaneState.isOpen, so if the parent passes a newonStateChangecallback or ifhandleManualTogglechanges, the effect won’t re-run with the updated values:useEffect(() => { if (onStateChange) { onStateChange({ isOpen: helperPaneState.isOpen, ref: toggleButtonRef, toggle: handleManualToggle }); } }, [helperPaneState.isOpen]);To avoid stale closures in consumers, expand the dependency array:
- }, [helperPaneState.isOpen]); + }, [helperPaneState.isOpen, onStateChange, toggleButtonRef, handleManualToggle]);This keeps the callback in sync if the parent or toggle handler changes, while preserving the current behavior.
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx (1)
398-406: Escape key handler still relies on a stalehelperPaneStateclosure.The ProseMirror keymap is created once in the mount effect, so this handler:
"Escape": () => { if (helperPaneState.isOpen) { setHelperPaneState(prev => ({ ...prev, isOpen: false })); return true; } return false; }captures the initial
helperPaneState.isOpenand never sees updates. In practice, the globaluseHelperPaneClickOutsidehook will close the pane on Escape, but this command itself won’t reliably report/drive the close.You can make it robust by using only the functional updater, similar to the previous fix:
- "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 keeps the keymap in sync with actual state while still delegating layout and click-outside behavior to
useHelperPaneClickOutside.
🧹 Nitpick comments (15)
workspaces/ballerina/ballerina-visualizer/src/views/BI/FocusFlowDiagram/index.tsx (1)
534-544: Add error handling for RPC token retrieval.The
handleGetExpressionTokensfunction lacks error handling. If the RPC call fails, the error will propagate uncaught to the caller.Consider wrapping the RPC call with try-catch:
const handleGetExpressionTokens = async ( expression: string, fileName: string, position: { line: number; offset: number } ): Promise<number[]> => { + try { return rpcClient.getBIDiagramRpcClient().getExpressionTokens({ expression: expression, filePath: fileName, position: position }); + } catch (error) { + console.error("Failed to retrieve expression tokens:", error); + return []; + } };workspaces/ballerina/bi-diagram/src/components/editors/NPPromptEditor.tsx (2)
372-372: Avoid creating new configuration instance on every render.
new RawTemplateEditorConfig()creates a new object on every render. Consider memoizing or defining it outside the component.+const rawTemplateConfig = useMemo(() => new RawTemplateEditorConfig(), []); + // ... in JSX: -configuration={new RawTemplateEditorConfig()} +configuration={rawTemplateConfig}
383-394: Consider memoizing thefieldobject.The
fieldobject is created inline and will be recreated whenever the modal opens. While not critical, memoizing it would avoid unnecessary object creation.+const expandedEditorField = useMemo(() => ({ + key: "expression", + label: "Prompt", + type: undefined, + optional: false, + editable: true, + documentation: "", + value: value, + valueTypeConstraint: undefined, + enabled: true, + placeholder: placeholder +}), [value, placeholder]); + // ... in JSX: -field={{ - key: "expression", - label: "Prompt", - // ... rest of properties -}} +field={expandedEditorField}workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/TemplateMode.tsx (2)
24-24: Unused import:RawTemplateEditorConfigThe
RawTemplateEditorConfigis imported but never used in this component. TheChipExpressionEditorComponentis rendered without aconfigurationprop, so it will use its default configuration.-import { RawTemplateEditorConfig } from "../../MultiModeExpressionEditor/Configurations";
48-51: Redundant wrapper function.The
handleChangefunction simply forwards parameters toonChangewithout transformation. Consider passingonChangedirectly to simplify the code.- // 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/MultiModeExpressionEditor/ChipExpressionEditor/components/HelperPaneToggleButton.tsx (1)
106-106: Consider using nullish coalescing for consistency.Using
??instead of ternary would be slightly more concise and idiomatic for default value handling.- <ButtonText>{displayText ? displayText : "Helper Panel"}</ButtonText> + <ButtonText>{displayText ?? "Helper Panel"}</ButtonText>workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/utils.ts (1)
43-45: Magic string "query" for InputMode.PROMPT detection.Consider extracting the
"query"string to a constant for maintainability. If more keys need to map toPROMPTin the future, this approach may not scale well.+const PROMPT_MODE_KEYS = ['query'] as const; + export const getInputModeFromTypes = (valueTypeConstraint: string | string[], key?: string): InputMode => { if (!valueTypeConstraint) return; - if (key === "query") return InputMode.PROMPT; + if (key && PROMPT_MODE_KEYS.includes(key as typeof PROMPT_MODE_KEYS[number])) return InputMode.PROMPT;workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/LinkDialog.tsx (1)
99-104: State reset may cause unnecessary re-renders wheninitialTitlechanges.The
useEffectresets bothurlandtitlewheneverisOpenorinitialTitlechanges. IfinitialTitleis derived from a parent's selection text and frequently updates while the dialog is closed, this could trigger unnecessary state updates.Consider guarding the effect to only run when the dialog opens:
useEffect(() => { - if (isOpen) { + if (isOpen) { setUrl(""); setTitle(initialTitle); } - }, [isOpen, initialTitle]); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [isOpen]);Alternatively, capture
initialTitleonly on open using a ref pattern if you need it to reflect the value at open time.workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RichTemplateMarkdownToolbar.tsx (1)
199-216: Consider throttling toolbar state updates.The effect attaches listeners for
input,click, andkeyupevents, each callingforceUpdate(). On rapid typing, this could cause frequent re-renders. While likely acceptable for toolbar UI, consider debouncing if performance issues arise with complex documents.workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/ExpandedEditor.tsx (1)
175-184: Consider extractingpromptFieldsto a shared constant.The
promptFieldsarray is defined inline and used for mode detection. If this list grows or is needed elsewhere, extracting it to a shared constant (similar toSIMPLE_PROMPT_FIELDSinPromptMode.tsx) would improve maintainability.workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/PromptMode.tsx (2)
57-58: Clarify theisSimpleModecondition.The condition
SIMPLE_PROMPT_FIELDS.includes(field.key) && !getHelperPanemeans "simple" fields with a helper pane still get full features. This might be intentional, but the naming suggests fields inSIMPLE_PROMPT_FIELDSwould always be simple.Consider renaming to clarify intent, e.g.,
hasAdvancedFeaturesor adding a comment:// Simple mode: no completions, helper pane, or advanced features const isSimpleMode = SIMPLE_PROMPT_FIELDS.includes(field.key) && !getHelperPane;
71-74: ThehandleChangewrapper is a no-op passthrough.Consider using
onChangedirectly in the child components instead of this wrapper, unless you anticipate adding transformation logic later.workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/plugins/chipPlugin.ts (1)
336-341:JSON.stringifyfor deduplication may be expensive with large token arrays.Using
JSON.stringifyto create a unique key works but could become a performance concern with many tokens. Consider a hash or checksum if this becomes a bottleneck.workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RawTemplateMarkdownToolbar.tsx (1)
37-166: Consider extracting shared styled components.
ToolbarContainer,ToolbarButton,ToolbarDivider,SplitButtonContainer,DropdownMenu, andDropdownItemare duplicated betweenRawTemplateMarkdownToolbarandRichTemplateMarkdownToolbar. Extracting these to a sharedToolbarStyles.tswould reduce duplication.workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/ChipExpressionEditor.tsx (1)
161-179: Avoid callingonHelperPaneStateChangefrom two different sources with different toggles.
useHelperPanealready exposes state via itsonStateChangecallback, but this component also has its ownuseEffectthat callsprops.onHelperPaneStateChangewith a separatehandleHelperPaneManualToggle. That means the parent can see two differenttogglefunctions for the same pane state, which is unnecessarily confusing and could lead to bugs if it stores/calls the wrong one.You can simplify by relying solely on
useHelperPane:
- Remove
handleHelperPaneManualToggleand the “Expose helper pane state to parent” effect.- Keep passing
onStateChange: props.onHelperPaneStateChangeintouseHelperPane, so the parent always gets a single, consistenttogglefunction (handleManualToggle).This keeps the behavior but clarifies the contract around helper-pane state.
Also applies to: 301-343
📜 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 (46)
workspaces/ballerina/ballerina-side-panel/package.json(2 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/LinkDialog.tsx(1 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/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/styles/markdown-preview.css(0 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/utils/templateUtils.ts(3 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(14 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionField.tsx(1 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/CodeUtils.ts(8 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(10 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/ChipExpressionEditor/types.ts(2 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/plugins/chipPlugin.ts(1 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/plugins/markdownCommands.ts(1 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/plugins/xmlTagDecorationPlugin.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/utils/bi.tsx(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(5 hunks)workspaces/ballerina/ballerina-visualizer/src/views/BI/HelperPaneNew/utils/utils.ts(1 hunks)workspaces/ballerina/bi-diagram/package.json(2 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 (6)
- workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/MarkdownToolbar.tsx
- workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/ChipComponent.tsx
- workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/utils/transformToMarkdown.ts
- 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/TemplateMarkdownToolbar.tsx
🚧 Files skipped from review as they are similar to previous changes (15)
- workspaces/ballerina/ballerina-side-panel/src/components/ModeSwitcher/index.tsx
- workspaces/ballerina/ballerina-visualizer/src/views/BI/HelperPaneNew/Components/EmptyItemsPlaceHolder.tsx
- workspaces/ballerina/bi-diagram/src/index.tsx
- workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/types.ts
- workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/types.ts
- workspaces/ballerina/ballerina-visualizer/src/views/BI/FocusFlowDiagram/utils.tsx
- workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/ExpressionMode.tsx
- workspaces/ballerina/bi-diagram/src/components/Diagram.tsx
- workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/plugins/xmlTagDecorationPlugin.ts
- workspaces/ballerina/ballerina-side-panel/src/components/editors/TextAreaEditor.tsx
- workspaces/ballerina/ballerina-visualizer/src/utils/bi.tsx
- workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionField.tsx
- workspaces/ballerina/bi-diagram/src/components/DiagramContext.tsx
- workspaces/ballerina/bi-diagram/package.json
- workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/CodeUtils.ts
🧰 Additional context used
🧠 Learnings (25)
📓 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/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-visualizer/src/views/BI/HelperPaneNew/Views/DocumentConfig.tsxworkspaces/ballerina/bi-diagram/src/components/editors/NPPromptEditor.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RichTemplateMarkdownToolbar.tsxworkspaces/ballerina/ballerina-visualizer/src/views/BI/FocusFlowDiagram/index.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/PromptMode.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionEditor.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/LinkDialog.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/ChipExpressionEditor.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/TemplateMode.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RawTemplateMarkdownToolbar.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsxworkspaces/ballerina/bi-diagram/src/components/nodes/PromptNode/PromptNodeWidget.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/EditorFactory.tsxworkspaces/ballerina/ballerina-side-panel/package.jsonworkspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/hooks/useHelperPane.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/**/*.{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-visualizer/src/views/BI/HelperPaneNew/Views/DocumentConfig.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/chipStyles.tsworkspaces/ballerina/ballerina-side-panel/src/components/editors/utils.tsworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionEditor.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/index.tsworkspaces/ballerina/bi-diagram/src/components/nodes/PromptNode/PromptNodeWidget.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/utils.tsworkspaces/ballerina/ballerina-side-panel/src/components/editors/EditorFactory.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-visualizer/src/views/BI/HelperPaneNew/Views/DocumentConfig.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/chipStyles.tsworkspaces/ballerina/ballerina-side-panel/src/components/editors/utils.tsworkspaces/ballerina/ballerina-visualizer/src/views/BI/HelperPaneNew/utils/utils.tsworkspaces/ballerina/bi-diagram/src/components/editors/NPPromptEditor.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RichTemplateMarkdownToolbar.tsxworkspaces/ballerina/ballerina-visualizer/src/views/BI/FocusFlowDiagram/index.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/PromptMode.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionEditor.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/ExpandedEditor.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/plugins/chipPlugin.tsworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/utils/templateUtils.tsworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/LinkDialog.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/ChipExpressionEditor.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/HelperPaneToggleButton.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/TemplateMode.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RawTemplateMarkdownToolbar.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/plugins/markdownCommands.tsworkspaces/ballerina/ballerina-side-panel/src/components/editors/index.tsworkspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsxworkspaces/ballerina/bi-diagram/src/components/nodes/PromptNode/PromptNodeWidget.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/utils.tsworkspaces/ballerina/ballerina-side-panel/src/components/editors/EditorFactory.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/hooks/useHelperPane.ts
📚 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/ballerina-visualizer/src/views/BI/HelperPaneNew/Views/DocumentConfig.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/MultiModeExpressionEditor/ChipExpressionEditor/chipStyles.tsworkspaces/ballerina/bi-diagram/src/components/editors/NPPromptEditor.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/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/bi-diagram/src/components/editors/NPPromptEditor.tsxworkspaces/ballerina/ballerina-visualizer/src/views/BI/FocusFlowDiagram/index.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionEditor.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/LinkDialog.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/TemplateMode.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/**/*.{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/utils.tsworkspaces/ballerina/ballerina-side-panel/src/components/editors/EditorFactory.tsxworkspaces/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/src/components/editors/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/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/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/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.tsxworkspaces/ballerina/ballerina-visualizer/src/views/BI/FocusFlowDiagram/index.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/LinkDialog.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/index.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/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/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/bi-diagram/src/components/editors/NPPromptEditor.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/PromptMode.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionEditor.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/ExpandedEditor/modes/TemplateMode.tsxworkspaces/ballerina/bi-diagram/src/components/nodes/PromptNode/PromptNodeWidget.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/bi-diagram/src/components/editors/NPPromptEditor.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionEditor.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/EditorFactory.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/hooks/useHelperPane.ts
📚 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/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-visualizer/src/views/BI/FocusFlowDiagram/index.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/ChipExpressionEditor.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/**/*.{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/index.ts : Export the main Diagram component as the default export from the package entry point (index.ts)
Applied to files:
workspaces/ballerina/ballerina-visualizer/src/views/BI/FocusFlowDiagram/index.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/index.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/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
📚 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-visualizer/src/views/BI/FocusFlowDiagram/index.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/TemplateMode.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/hooks/useHelperPane.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/(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/ballerina-visualizer/src/views/BI/FocusFlowDiagram/index.tsx
📚 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-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/src/components/editors/index.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/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.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/EditorFactory.tsx
🧬 Code graph analysis (13)
workspaces/ballerina/ballerina-side-panel/src/components/editors/utils.ts (2)
workspaces/ballerina/ballerina-side-panel/src/components/editors/index.ts (1)
InputMode(32-32)workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/types.ts (2)
EditorMode(93-93)EXPANDABLE_MODES(86-91)
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/plugins/markdownCommands.ts (13)
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)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/ExpandedEditor/controls/LinkDialog.tsx (1)
LinkDialog(90-175)
workspaces/ballerina/ballerina-visualizer/src/views/BI/FocusFlowDiagram/index.tsx (2)
workspaces/ballerina/bi-diagram/src/components/DiagramContext.tsx (1)
GetHelperPaneFunction(40-53)workspaces/ballerina/ballerina-visualizer/src/views/BI/FocusFlowDiagram/utils.tsx (1)
createPromptHelperPane(59-144)
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionEditor.tsx (3)
workspaces/ballerina/ballerina-side-panel/src/components/editors/index.ts (1)
InputMode(32-32)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)
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/plugins/chipPlugin.ts (3)
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/types.ts (2)
TokenMetadata(70-74)CompoundTokenSequence(96-104)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(106-111)getParsedExpressionTokens(113-139)detectTokenPatterns(236-290)
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/ChipExpressionEditor/components/ChipExpressionEditor.tsx (6)
workspaces/ballerina/ballerina-side-panel/src/components/editors/index.ts (1)
InputMode(32-32)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(21-21)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/CodeUtils.ts (3)
buildHelperPaneKeymap(606-625)chipPlugin(314-375)tokenField(206-249)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/utils.ts (1)
correctTokenStreamPositions(320-389)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/FloatingToggleButton.tsx (1)
FloatingToggleButton(30-45)
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-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(106-559)
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/plugins/markdownCommands.ts (1)
workspaces/mi/syntax-tree/src/syntax-tree-interfaces.ts (1)
Transaction(1588-1591)
workspaces/ballerina/bi-diagram/src/components/nodes/PromptNode/PromptNodeWidget.tsx (2)
workspaces/ballerina/bi-diagram/src/components/editors/NPPromptEditor.tsx (1)
NPPromptEditor(111-411)workspaces/ballerina/ballerina-side-panel/src/components/editors/index.ts (1)
InputMode(32-32)
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(115-121)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/utils.ts (1)
calculateHelperPanePosition(293-313)
🪛 Biome (2.1.2)
workspaces/ballerina/ballerina-side-panel/package.json
[error] 21-21: The key @codemirror/autocomplete was already declared.
This where a duplicated key was declared again.
If a key is defined multiple times, only the last definition takes effect. Previous definitions are ignored.
(lint/suspicious/noDuplicateObjectKeys)
[error] 22-22: The key @codemirror/commands was already declared.
This where a duplicated key was declared again.
If a key is defined multiple times, only the last definition takes effect. Previous definitions are ignored.
(lint/suspicious/noDuplicateObjectKeys)
[error] 25-25: The key @codemirror/state was already declared.
This where a duplicated key was declared again.
If a key is defined multiple times, only the last definition takes effect. Previous definitions are ignored.
(lint/suspicious/noDuplicateObjectKeys)
[error] 26-26: The key @codemirror/view was already declared.
This where a duplicated key was declared again.
If a key is defined multiple times, only the last definition takes effect. Previous definitions are ignored.
(lint/suspicious/noDuplicateObjectKeys)
workspaces/ballerina/bi-diagram/src/components/editors/NPPromptEditor.tsx
Outdated
Show resolved
Hide resolved
73d1253 to
7da9f50
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (9)
workspaces/ballerina/bi-diagram/src/components/editors/NPPromptEditor.tsx (5)
64-64:onFocusprop remains unused.This issue was flagged in a previous review. The
onFocusprop is destructured but never forwarded toChipExpressionEditorComponentorExpandedEditor, so callers passing it will see no effect.
166-172:createPropertyshould be memoized to prevent stale closures.This issue was flagged in a previous review. The
createPropertyfunction capturesprops.nodebut is not memoized, causing stale closure issues infetchDiagnostics,handleChangeFromExpandedEditor, andchipExtractArgsFromFunction.
174-204: Debounced function lacks cleanup and has stale closure risk.This issue was flagged in a previous review. The debounced
fetchDiagnosticsfunction:
- Lacks cleanup on unmount, causing memory leaks and potential setState-after-unmount warnings
- Calls
createPropertywhich capturesprops.node, but neither is in the dependency array
278-286: Stale closure risk inchipExtractArgsFromFunction.This issue was flagged in a previous review. The memoized function calls
createPropertywhich capturesprops.node, but onlyextractArgsFromFunctionis in the dependency array.
288-341:expressionEditorshould be memoized to prevent unnecessary re-renders.This issue was flagged in a previous review. The
expressionEditorobject is created inline without memoization but included in theformContextValuedependency array, causingformContextValueto be recreated on every render.workspaces/ballerina/ballerina-visualizer/src/views/BI/HelperPaneNew/Views/DocumentConfig.tsx (1)
218-218: Inconsistent template mode check causes different behavior for URL insertion.This is the same issue previously flagged: line 218 only checks for
InputMode.PROMPT, while line 166 (item selection) checks for bothInputMode.PROMPT || InputMode.TEMPLATE. This means:
- In TEMPLATE mode, selecting a variable: wraps with
${}✅- In TEMPLATE mode, inserting a URL: does NOT wrap with
${}❌The
wrapInTemplateInterpolationutility (from../utils/utils.ts) checks for both modes, and line 166 treats both modes consistently. Line 218 should do the same.Apply this diff to align with line 166:
- const isTemplateMode = inputMode === InputMode.PROMPT; + const isTemplateMode = inputMode === InputMode.PROMPT || inputMode === InputMode.TEMPLATE;Based on learnings: Past discussion confirmed this inconsistency exists between the two code paths, but it wasn't resolved.
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/plugins/chipPlugin.ts (1)
366-379: Potential issue withindexOfreturning -1 still present.The condition
prefixLength > 0correctly skips adjustment whenindexOfreturns -1 (plainText not found in wrappedText) or 0 (plainText starts at position 0). However, the comment in the past review raised a concern about this edge case. The current implementation is actually correct because:
- If
indexOfreturns -1,prefixLength > 0is false, so positions aren't adjusted- If
indexOfreturns 0, no adjustment is needed anywayConsider adding a comment clarifying this intentional behavior:
const prefixLength = wrappedText.indexOf(plainText); + // Only adjust positions if plainText is found and has a prefix (prefixLength > 0) + // When indexOf returns -1 (not found) or 0 (no prefix), skip adjustment if (prefixLength > 0) {workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/utils.ts (1)
315-318: TightenprocessFunctionWithArgumentsAPI and caret semanticsThe core flow (strip
${…}wrapper, callextractArgsFromFunction, inject$1..$nplaceholders, rebuildfinalValue) looks good, but the API surface is a bit inconsistent now:
- The
basePositionparameter is no longer used insideprocessFunctionWithArguments.- You return a
cursorAdjustmentbut the current caller (RichTextTemplateEditor’sonHelperItemSelect) ignores it, always placing the caret at the end of the inserted snippet.To avoid confusion and make caret placement predictable, consider either:
- Removing
basePositionandcursorAdjustmententirely and documenting that the caller should position the caret atinsertFrom + finalValue.length, or- Keeping
cursorAdjustmentbut having callers actually use it (e.g.,const cursorPos = from + result.cursorAdjustment) so the caret lands just before the closing)as intended.This will also make the
FunctionExtractionResultcomment (“adjust cursor position from base position”) match real usage.Also applies to: 391-445
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx (1)
368-407: Avoid stalehelperPaneStatein Escape key handlerThe keymap is created once in a
useEffectwith empty deps, so theEscapehandler closes over the initialhelperPaneState(withisOpen === false). As a result,helperPaneState.isOpeninside this handler never updates and the Escape keypath here will never actually triggersetHelperPaneState.You already use functional updates elsewhere; applying the same pattern here avoids stale state:
"Escape": () => { let wasOpen = false; setHelperPaneState(prev => { wasOpen = prev.isOpen; return prev.isOpen ? { ...prev, isOpen: false } : prev; }); return wasOpen; }Note that
useHelperPaneClickOutside’s global Escape handler still works, but fixing this keeps the ProseMirror keymap self‑contained and future‑proof.
🧹 Nitpick comments (7)
workspaces/ballerina/bi-diagram/src/components/editors/NPPromptEditor.tsx (1)
372-372: Consider memoizing the configuration object.Creating a new
RawTemplateEditorConfig()instance on every render may cause unnecessary re-renders ofChipExpressionEditorComponentif it uses shallow prop comparison.Apply this diff to memoize the configuration:
+const editorConfig = useMemo(() => new RawTemplateEditorConfig(), []); + // ... in render: - configuration={new RawTemplateEditorConfig()} + configuration={editorConfig}workspaces/ballerina/ballerina-visualizer/src/views/BI/HelperPaneNew/Views/DocumentConfig.tsx (1)
48-54: Redundant hardcodedInputMode.TEMPLATEin template wrapping.On line 51, you're passing a hardcoded
InputMode.TEMPLATEtowrapInTemplateInterpolation, but you've already determined that wrapping is needed via theisTemplateModeboolean. This creates unnecessary indirection.Option 1: If you need to preserve the actual input mode for other reasons, pass the real
inputModeinstead:-const wrapInDocumentType = (documentType: AIDocumentType, content: string, isTemplateMode: boolean): string => { +const wrapInDocumentType = (documentType: AIDocumentType, content: string, inputMode: InputMode): string => { const wrappedContent = `<${documentType}>{content: ${content}}`; - if (isTemplateMode) { - return wrapInTemplateInterpolation(wrappedContent, InputMode.TEMPLATE); + if (inputMode === InputMode.PROMPT || inputMode === InputMode.TEMPLATE) { + return wrapInTemplateInterpolation(wrappedContent, inputMode); } return wrappedContent; };Option 2: Since you already know whether to wrap via
isTemplateMode, directly apply the template syntax:const wrapInDocumentType = (documentType: AIDocumentType, content: string, isTemplateMode: boolean): string => { const wrappedContent = `<${documentType}>{content: ${content}}`; if (isTemplateMode) { - return wrapInTemplateInterpolation(wrappedContent, InputMode.TEMPLATE); + return `\${${wrappedContent}}`; } return wrappedContent; };workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/plugins/chipPlugin.ts (1)
338-353: Consider performance:JSON.stringifyfor deduplication.Using
JSON.stringifyto create a deduplication key works correctly but may be expensive for large token arrays. For typical prompt editing with moderate token counts, this should be acceptable. If performance becomes an issue, consider a cheaper comparison (e.g., array length + first/last token + plainText hash).workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/ChipExpressionEditor.tsx (2)
162-179: Unify helper-pane toggle behavior between internal and parent-controlled toggles
useHelperPanealready exposeshandleManualToggle(which respectscustomManualTogglefor PROMPT + expanded mode), but the parent-facingtoggleyou expose viaonHelperPaneStateChangeuses a separatehandleHelperPaneManualTogglewith its own positioning logic.This means in PROMPT expanded mode the helper pane position can differ depending on whether it was opened via the internal button (
handleManualToggle+customManualToggle) or via the parent-providedtogglecallback.Consider delegating the parent
toggletohandleManualToggleinstead of duplicating the positioning logic, so all entry points go throughuseHelperPane’s centralized behavior.Also applies to: 334-343, 503-509, 537-553
412-445: Token-stream prefix correction is logically correct; suffix parameter currently unusedFeeding RPC tokens through
correctTokenStreamPositionswithconfiguration.getSerializationPrefix().lengthcleanly shifts first-line token char offsets out of the serialization prefix before storing them intokenField. For the current${…}-style wrapping this should keep chip decorations aligned with the visible expression.Note that
suffixLengthandserializedValuearen’t used insidecorrectTokenStreamPositionsyet. That’s fine functionally today, but if you don’t plan suffix-based adjustments you could either drop the parameter or add a brief comment explaining it’s reserved for future multi-line/suffix handling, to avoid confusion for future readers.Also applies to: 46-47
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/utils.ts (1)
43-68: PROMPT input mode mapping forkey === "query"is clear but slightly under-documentedThe early
if (key === "query") return InputMode.PROMPT;override makes sense for routingqueryfields directly into prompt mode regardless of their value-type constraints, which matches the new simplified prompt editor behavior.It might be worth adding a short comment here (or to the callers) explaining that “query” keys are intentionally hard-wired to PROMPT mode so future changes to
INPUT_MODE_MAPdon’t accidentally regress this behavior.workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx (1)
253-300: UsecursorAdjustmentfromprocessFunctionWithArgumentsfor better caret placementWhen inserting a function template from the helper pane, you call
processFunctionWithArgumentsbut only useresult.finalValue, then set:cursorPosition = chipPos + finalValue.length;This always leaves the caret at the end of the snippet rather than just before the closing
), even thoughprocessFunctionWithArgumentscomputes acursorAdjustmentprecisely for that purpose.To align the UX with the chip editor and make argument tabbing smoother, consider:
const result = await processFunctionWithArguments(newValue, chipPos, extractArgsFromFunction); finalValue = result.finalValue; cursorPosition = chipPos + result.cursorAdjustment;(or equivalent), and if you do that you can simplify the util’s API as noted in the utils.ts comment.
📜 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 (17)
workspaces/ballerina/ballerina-side-panel/src/components/editors/EditorFactory.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/PromptMode.tsx(1 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionEditor.tsx(14 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionField.tsx(1 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/CodeUtils.ts(8 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/ChipExpressionEditor.tsx(10 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/plugins/chipPlugin.ts(1 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/plugins/markdownCommands.ts(1 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/plugins/xmlTagDecorationPlugin.ts(1 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/index.ts(1 hunks)workspaces/ballerina/ballerina-visualizer/src/utils/bi.tsx(1 hunks)workspaces/ballerina/ballerina-visualizer/src/views/BI/HelperPaneNew/Views/DocumentConfig.tsx(5 hunks)workspaces/ballerina/ballerina-visualizer/src/views/BI/HelperPaneNew/utils/utils.ts(1 hunks)workspaces/ballerina/bi-diagram/src/components/editors/NPPromptEditor.tsx(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (6)
- workspaces/ballerina/ballerina-visualizer/src/utils/bi.tsx
- workspaces/ballerina/ballerina-side-panel/src/components/editors/EditorFactory.tsx
- workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/plugins/xmlTagDecorationPlugin.ts
- workspaces/ballerina/ballerina-side-panel/src/components/editors/index.ts
- workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RichTemplateMarkdownToolbar.tsx
- workspaces/ballerina/ballerina-visualizer/src/views/BI/HelperPaneNew/utils/utils.ts
🧰 Additional context used
🧠 Learnings (13)
📚 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/PromptMode.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/plugins/chipPlugin.tsworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionField.tsxworkspaces/ballerina/bi-diagram/src/components/editors/NPPromptEditor.tsxworkspaces/ballerina/ballerina-visualizer/src/views/BI/HelperPaneNew/Views/DocumentConfig.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/MultiModeExpressionEditor/ChipExpressionEditor/CodeUtils.tsworkspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/utils.tsworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionEditor.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/plugins/markdownCommands.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/modes/PromptMode.tsxworkspaces/ballerina/bi-diagram/src/components/editors/NPPromptEditor.tsxworkspaces/ballerina/ballerina-visualizer/src/views/BI/HelperPaneNew/Views/DocumentConfig.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/ExpressionEditor.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/PromptMode.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionField.tsxworkspaces/ballerina/bi-diagram/src/components/editors/NPPromptEditor.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/utils.tsworkspaces/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/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.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/CodeUtils.tsworkspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/utils.tsworkspaces/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/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/**/*.{ts,tsx} : Use TypeScript 5.8.3 with strict type checking enabled for all source files
Applied to files:
workspaces/ballerina/bi-diagram/src/components/editors/NPPromptEditor.tsxworkspaces/ballerina/ballerina-visualizer/src/views/BI/HelperPaneNew/Views/DocumentConfig.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/components/editors/NPPromptEditor.tsxworkspaces/ballerina/ballerina-visualizer/src/views/BI/HelperPaneNew/Views/DocumentConfig.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/utils.tsworkspaces/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/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/**/*.tsx : Use Emotion for CSS-in-JS styling instead of inline styles or external CSS files
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.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionEditor.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/ballerina-visualizer/src/views/BI/HelperPaneNew/Views/DocumentConfig.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/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.tsx
🧬 Code graph analysis (8)
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/PromptMode.tsx (3)
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/types.ts (1)
EditorModeExpressionProps(51-84)workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RawTemplateMarkdownToolbar.tsx (1)
RawTemplateMarkdownToolbar(180-405)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/Configurations.tsx (2)
StringTemplateEditorConfig(64-94)RawTemplateEditorConfig(96-126)
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/plugins/chipPlugin.ts (4)
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/types.ts (2)
TokenMetadata(70-74)CompoundTokenSequence(96-104)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(106-111)getParsedExpressionTokens(113-139)detectTokenPatterns(236-290)
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionField.tsx (3)
workspaces/ballerina/ballerina-side-panel/src/components/editors/index.ts (1)
InputMode(32-32)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/TextExpressionEditor/TextModeEditor.tsx (1)
TextModeEditor(40-69)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/Configurations.tsx (2)
RawTemplateEditorConfig(96-126)StringTemplateEditorConfig(64-94)
workspaces/ballerina/ballerina-visualizer/src/views/BI/HelperPaneNew/Views/DocumentConfig.tsx (1)
workspaces/ballerina/ballerina-visualizer/src/views/BI/HelperPaneNew/utils/utils.ts (1)
wrapInTemplateInterpolation(22-24)
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/ChipExpressionEditor.tsx (9)
workspaces/ballerina/ballerina-side-panel/src/components/editors/index.ts (1)
InputMode(32-32)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(21-21)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/CodeUtils.ts (3)
buildHelperPaneKeymap(606-625)chipPlugin(314-375)tokenField(206-249)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)
correctTokenStreamPositions(320-389)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/styles.tsx (2)
FloatingButtonContainer(273-280)FloatingToggleButton(282-309)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/FloatingToggleButton.tsx (1)
FloatingToggleButton(30-45)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/FloatingButtonIcons.tsx (4)
CloseHelperIcon(32-41)OpenHelperIcon(21-30)MinimizeIcon(54-63)ExpandIcon(43-52)
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/utils.ts (1)
workspaces/ballerina/ballerina-side-panel/src/components/editors/index.ts (1)
InputMode(32-32)
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionEditor.tsx (2)
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)
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/plugins/markdownCommands.ts (1)
workspaces/mi/syntax-tree/src/syntax-tree-interfaces.ts (1)
Transaction(1588-1591)
🔇 Additional comments (26)
workspaces/ballerina/bi-diagram/src/components/editors/NPPromptEditor.tsx (5)
99-109: LGTM!The styled component properly handles disabled state with appropriate visual feedback.
217-251: LGTM with dependency on createProperty fix.The expanded mode handlers are correctly implemented. Once
createPropertyis memoized as suggested in earlier comments,handleChangeFromExpandedEditorwill capture the current node data.
254-275: LGTM!The
wrappedGetHelperPaneadapter is properly memoized with correct dependencies.
344-350: LGTM!Event handlers are properly memoized to prevent scroll/mouse event propagation to parent diagrams.
352-410: LGTM!The render logic correctly wires up the ChipExpressionEditorComponent and ExpandedEditor with appropriate props and conditional rendering.
workspaces/ballerina/ballerina-visualizer/src/views/BI/HelperPaneNew/Views/DocumentConfig.tsx (1)
151-183: LGTM: Item selection logic correctly handles both template modes.The template mode check at line 166 correctly includes both
InputMode.PROMPTandInputMode.TEMPLATE, ensuring consistent behavior when selecting variables from the list.workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/CodeUtils.ts (2)
336-356: LGTM! Sensible handling of multiline content.Skipping chip creation for tokens/compounds containing newlines prevents visual artifacts where chips would span multiple lines. The early returns are clean and efficient.
606-624: LGTM! Clean optional toggle keybinding implementation.The spread operator pattern for conditionally adding the toggle keybinding is idiomatic and correctly handles the case when
onToggleis not provided.workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionField.tsx (1)
212-232: LGTM! Consistent PROMPT mode handling.The new
InputMode.PROMPTbranch follows the same pattern as the existingTEXTandTEMPLATEbranches. The configuration selection based onfield.valueTypeConstraint === "ai:Prompt"is clear and appropriate for the dual-config approach.workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionEditor.tsx (5)
443-443: Good fix: Now consistent with othergetInputModeFromTypescalls.This addresses the previous review feedback about missing the
field.keyparameter.
576-588: LGTM! Correct handling of PROMPT/TEMPLATE mode transitions.The logic correctly:
- Checks if the current value is template-safe before allowing the switch
- If template-safe, switches to the primary input mode directly
- Otherwise, shows a warning and requires explicit user confirmation
594-600: Good: Clears the value when switching from EXP to PROMPT/TEMPLATE with incompatible content.When the user confirms the mode switch warning, clearing the value for PROMPT/TEMPLATE modes ensures no malformed content persists. The null check on
targetInputModeRef.currentis appropriate.
620-622: LGTM! Clean abstraction usingisExpandableMode.Using the utility function instead of inline mode checks improves maintainability and keeps the expandable modes list centralized.
775-833: LGTM! Proper ExpandedEditor integration with PROMPT mode.The ExpandedEditor correctly receives:
inputModeprop for mode-aware renderingsanitizedExpressionandrawExpressionfor PROMPT/TEMPLATE modesmodeviatoEditorMode(inputModeRef.current)for editor configurationThe guard
toEditorMode(inputModeRef.current)ensures the ExpandedEditor only renders for valid expandable modes.workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/plugins/chipPlugin.ts (3)
46-110: LGTM! Well-structured chip node specification.The chip node spec is correctly defined as:
inline: trueandgroup: "inline"for inline renderingatom: truefor atomic selection behaviordraggable: truefor drag-and-drop support- Proper
toDOMserialization with data attributesparseDOMfor hydration from HTMLThe attribute defaults are sensible, and the DOM output structure correctly preserves icon and text elements.
184-212: Edge case:findDocPositionreturns 0 when position not found.The function returns
docPos || 0at line 211. IfdocPosremains 0 after the loop (no text nodes found), this is correct. However, if the document has no text content but has nodes, all offsets would map to 0. This is acceptable for the current use case but worth noting.
397-421: LGTM! Clean click handler implementation.The chip click handler correctly:
- Checks for
onChipClickcallback before processing- Uses
closest('.pm-chip')for reliable chip element detection- Uses
posAtDOMto get the ProseMirror position- Returns
trueto indicate the event was handledworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/PromptMode.tsx (5)
40-40: LGTM! Clear simple mode detection constant.
SIMPLE_PROMPT_FIELDSprovides a maintainable way to identify fields that should use simplified editing without advanced features.
57-58: VerifyisSimpleModelogic intent.The condition
SIMPLE_PROMPT_FIELDS.includes(field.key) && !getHelperPanemeans simple mode is only active when both conditions are met. IfgetHelperPaneis provided for a simple field, it won't be treated as simple. Is this the intended behavior?If the intent is "simple fields should always be simple regardless of helper pane," consider:
- const isSimpleMode = SIMPLE_PROMPT_FIELDS.includes(field.key) && !getHelperPane; + const isSimpleMode = SIMPLE_PROMPT_FIELDS.includes(field.key);
88-90: Consider preserving editor content on view toggle.
handleToggleViewsimply togglesisSourceView. When switching views, ensure both editors are synchronized. If they maintain separate internal state, content changes in one view might not reflect in the other until the nextvalueprop update.Based on the retrieved learnings, token fetching in the RichTextTemplateEditor is intentionally limited to user typing. Verify that view switching correctly propagates the current value.
153-157: LGTM! Consistent error display.The ErrorBanner rendering follows the same pattern as other editor modes, with appropriate max-height constraint for overflow content.
136-150: No action needed: RichTextTemplateEditor intentionally does not process external prop updates.
RichTextTemplateEditoris designed to only respond to direct user typing in the expanded editor view, not to external state prop changes. UnlikeChipExpressionEditorComponentwhich accepts external props likesanitizedExpressionandrawExpression,RichTextTemplateEditorintentionally disables token fetching and state updates from external props because users cannot edit both the minimized and expanded editors simultaneously. Adding these props would conflict with this documented architectural design.Likely an incorrect or invalid review comment.
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/ChipExpressionEditor.tsx (1)
347-395: CM6 editable Compartment, placeholder, and height handling look solidThe new use of an
editableCompartmentto driveEditorView.editable.of(!props.disabled)plus theuseEffectreconfigure ondisabledupdates is idiomatic CM6. Likewise, wiringplaceholder(props.placeholder)once at state creation and deriving the height theme fromisInExpandedMode | hideFxButton | sx.heightaligns the DOM styling with the surrounding container’s layout.No changes needed here from a correctness or UX perspective.
Also applies to: 473-479, 512-521
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/utils.ts (1)
292-313: Good extraction of helper-pane positioning math
calculateHelperPanePositioncleanly centralizes thebottom/left → editor-relativetranslation and the viewport overflow correction. This removes duplicated DOMRect math from the rich/editor components and makes future tweaks (e.g., RTL, dynamic widths) much easier.No issues from a correctness standpoint.
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx (1)
302-330: Token fetching strategy matches the “expanded-only” design
fetchAndUpdateTokensis correctly gated bypendingTokenFetchRef, and the[value]effect calls it without setting the pending flag, effectively making externalvaluechanges a no-op for token fetching. Combined with the initialization and transaction paths (which do set the flag), this means tokens are only refreshed for edits made inside this rich editor, not for external prop updates.Given the documented design that minimized/expanded editors are mutually exclusive and tokens only need to follow user typing in the expanded view, this looks intentional and consistent.
Also applies to: 471-488
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/plugins/markdownCommands.ts (1)
19-194: Markdown-style command helpers are idiomatic ProseMirrorThe command wrappers for marks, headings, blockquotes, lists, and undo/redo all follow standard ProseMirror patterns.
toggleLink’s behavior (remove existing link on selection, or insert text+link when collapsed) is reasonable for a toolbar/shortcut integration, andcanUndo/canRedousingundo(state)/redo(state)as capability checks is the typical approach.Looks good as a reusable command layer for the rich-text prompt editor.
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionEditor.tsx
Show resolved
Hide resolved
7da9f50 to
eca5f4f
Compare
There was a problem hiding this comment.
Actionable comments posted: 0
♻️ Duplicate comments (7)
workspaces/ballerina/ballerina-visualizer/src/views/BI/HelperPaneNew/Views/DocumentConfig.tsx (1)
218-219: Inconsistent template mode check between variable selection and URL insertion.Line 166 treats both
InputMode.PROMPTandInputMode.TEMPLATEas template mode for variable selection, but line 218 only checks forInputMode.PROMPTwhen inserting URLs. This means URL insertion inTEMPLATEmode won't apply template interpolation wrapping, creating inconsistent behavior.Apply this diff to align the logic:
- const isTemplateMode = inputMode === InputMode.PROMPT; + const isTemplateMode = inputMode === InputMode.PROMPT || inputMode === InputMode.TEMPLATE;workspaces/ballerina/bi-diagram/src/components/editors/NPPromptEditor.tsx (3)
288-341: MemoizeexpressionEditorto keepformContextValuestable
expressionEditoris created as a new object on every render but is also listed as a dependency offormContextValue’suseMemo. This meansformContextValueis effectively recomputed on every render, which can cause unnecessary re-renders of consumers relying on the context.Wrap
expressionEditoritself in auseMemoso it only changes when its real inputs change:- const expressionEditor: FormExpressionEditorProps = { - completions: completions, - triggerCharacters: triggerCharacters, - retrieveCompletions: async (value: string, property: ExpressionProperty, offset: number, triggerCharacter?: string) => { - await retrieveCompletions(getSanitizedExp(value), property, offset, triggerCharacter); - }, - extractArgsFromFunction: extractArgsFromFunction, - ...(getHelperPane ? { - getHelperPane: getHelperPane, - helperPaneOrigin: "vertical" as const, - helperPaneHeight: "default" as const, - } : {}), - onCompletionItemSelect: async (value: string, fieldKey: string, additionalTextEdits?: TextEdit[]) => { - if (onCompletionItemSelect) { - await onCompletionItemSelect(getSanitizedExp(value), additionalTextEdits); - } - }, - onBlur: onBlur, - onCancel: onCancel, - getExpressionFormDiagnostics: getExpressionFormDiagnostics, - rpcManager: { - getExpressionTokens: getExpressionTokens || (async () => []) - } - } as FormExpressionEditorProps; + const expressionEditor = useMemo<FormExpressionEditorProps>(() => ({ + completions, + triggerCharacters, + retrieveCompletions: async ( + value: string, + property: ExpressionProperty, + offset: number, + triggerCharacter?: string + ) => { + await retrieveCompletions(getSanitizedExp(value), property, offset, triggerCharacter); + }, + extractArgsFromFunction, + ...(getHelperPane + ? { + getHelperPane, + helperPaneOrigin: "vertical" as const, + helperPaneHeight: "default" as const + } + : {}), + onCompletionItemSelect: async ( + value: string, + fieldKey: string, + additionalTextEdits?: TextEdit[] + ) => { + if (onCompletionItemSelect) { + await onCompletionItemSelect(getSanitizedExp(value), additionalTextEdits); + } + }, + onBlur, + onCancel, + getExpressionFormDiagnostics, + rpcManager: { + getExpressionTokens: getExpressionTokens || (async () => []) + } + }), [ + completions, + triggerCharacters, + retrieveCompletions, + extractArgsFromFunction, + getHelperPane, + onCompletionItemSelect, + onBlur, + onCancel, + getExpressionFormDiagnostics, + getExpressionTokens + ]);
formContextValuecan keepexpressionEditorin its dependency list as-is; with this change, it will only update when something meaningful changes.
48-67:onFocusprop is still unused in the implementation
onFocusis exposed inNPPromptEditorPropsand destructured (Line 122) but never wired intoChipExpressionEditorComponent,ExpandedEditor, or theexpressionEditorcontext. Callers passingonFocussee no effect.Either forward it to the underlying editor(s) where focus is meaningful, or remove it from the public API until you need it.
148-172: Fix stale closures aroundprops.nodeand add cleanup for debounced diagnostics
createPropertycloses overprops.nodeand is used inside both the debouncedfetchDiagnosticsandchipExtractArgsFromFunction, but:
createPropertyis not memoized.fetchDiagnostics’s andchipExtractArgsFromFunction’s dependency arrays don’t includecreateProperty.If
props.nodechanges while the component stays mounted, these callbacks will keep using stale node data. Additionally, the debouncedfetchDiagnosticsis never cancelled on unmount, which can lead to setState-after-unmount.You can address both issues like this:
- // Helper to create ExpressionProperty - const createProperty = (expressionValue: string): ExpressionProperty => { - const promptProperty = props.node.properties['prompt']; - return { - ...promptProperty, - value: getSanitizedExp(expressionValue), - } - }; + // Helper to create ExpressionProperty + const createProperty = useCallback((expressionValue: string): ExpressionProperty => { + const promptProperty = props.node.properties["prompt"]; + return { + ...promptProperty, + value: getSanitizedExp(expressionValue), + }; + }, [props.node]);- const fetchDiagnostics = useCallback( + const fetchDiagnostics = useCallback( debounce(async (expression: string) => { @@ - }, 300), - [enableDiagnostics, getExpressionFormDiagnostics] - ); + }, 300), + [enableDiagnostics, getExpressionFormDiagnostics, createProperty] + ); + + // Cancel debounced diagnostics on unmount + React.useEffect(() => { + return () => { + fetchDiagnostics.cancel(); + }; + }, [fetchDiagnostics]);- const chipExtractArgsFromFunction = useMemo(() => { + const chipExtractArgsFromFunction = useMemo(() => { if (!extractArgsFromFunction) return undefined; @@ - const sanitizedValue = getSanitizedExp(value); - const property = createProperty(sanitizedValue); - return await extractArgsFromFunction(sanitizedValue, property, cursorPosition); + const sanitizedValue = getSanitizedExp(value); + const property = createProperty(sanitizedValue); + return await extractArgsFromFunction(sanitizedValue, property, cursorPosition); }; - }, [extractArgsFromFunction]); + }, [extractArgsFromFunction, createProperty]);Also applies to: 174-205, 278-286
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionEditor.tsx (1)
558-564: Regex still doesn't handle escaped backticks in template strings.The regex
/^string\s*.$/suses greedy matching and cannot distinguish escaped backticks from unescaped ones. A template containing\`` will incorrectly match. Consider using a pattern that accounts for escape sequences, e.g.,/^string\s(?:\\.|[^])*$/s.workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/utils.ts (1)
342-343: Unused variable:linesis declared but never used.The
serializedValue.split('\n')result is stored but not referenced anywhere in the function. Either remove it or use it if intended for multi-line handling.- // Reconstruct the raw expression to properly handle multi-line cases - const lines = serializedValue.split('\n'); - for (const chunk of chunks) {workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx (1)
332-414: Escape key handler still readshelperPaneState.isOpenfrom a stale closureInside the keymap in the initialization
useEffect([]), the"Escape"handler closes the helper pane only ifhelperPaneState.isOpenfrom the initial render istrue. Because this closure never sees updated state, pressing Escape inside the editor can fail to close an already-open helper pane.You already use a functional updater pattern elsewhere; applying the same approach here will make Escape reliable:
- "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 keeps the logic inside the keymap independent of the closed‑over
helperPaneStatewhile still returning the correct boolean to ProseMirror.Also applies to: 399-406
🧹 Nitpick comments (6)
workspaces/ballerina/bi-diagram/src/components/editors/NPPromptEditor.tsx (2)
145-147: VerifyexprRefwiring for helper pane integrationsYou create
exprRefasRefObject<FormExpressionEditorRef>and pass it into theGetHelperPaneFunctionadapter, butexprRefis never attached to any editor component here (e.g., not passed asreftoChipExpressionEditorComponentorExpandedEditor).If helper-pane implementations rely on
exprRef.current(e.g., for cursor positioning or focus), it will remainnulland those features may break.Either:
- Attach
exprRefto the underlying editor instance that matches the expectedFormExpressionEditorRef, or- If the helper pane for prompts does not need editor access, consider passing
nullor omittingexprReffrom the adapter to make that explicit.Also applies to: 253-275, 381-406
139-140: Consider typing diagnostics instead ofany[]
formDiagnosticsis declared asany[]and later assumed to have a.messagefield. If there is a shared diagnostics type in the core or UI libraries, using it here would catch mismatches at compile time and make the ErrorBanner usage safer.Not critical, but a small win for strict typing.
Also applies to: 374-376
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/ChipExpressionEditor.tsx (2)
301-343: Two different manual toggle paths for the helper pane can diverge in behaviorYou now have:
handleManualTogglefromuseHelperPane(which may usecustomManualTogglein PROMPT/expanded mode), andhandleHelperPaneManualToggledefined locally and exposed viaonHelperPaneStateChange.These can compute different positions (fixed top/left via hook vs. buttonRect-based here) and different open/close semantics depending on
inputMode/isInExpandedMode. This makes the behavior oftoggle()from the parent potentially inconsistent with the in-editor toggle buttons usinghandleManualToggle.If possible, consider exposing
handleManualToggledirectly throughonHelperPaneStateChange(or delegatinghandleHelperPaneManualToggleto it) so all manual toggles share the same logic and positioning calculations.
481-497: Click‑outside/Escape behavior and disabled-state UI are mostly consistent, with one UX nuance
useHelperPaneClickOutsidecorrectly considers the editor, helper pane, toggle button, and external toolbar (viaprops.toolbarRef) as “inside” click regions, and always closes the pane on Escape via a functionalsetHelperPaneStateupdater. The bottomFloatingButtonContaineris suppressed whendisabled, which aligns with read‑only expectations.One nuance: the top
HelperPaneToggleButtonis still rendered whendisabled, so users can open/close the helper pane even though they cannot edit the underlying expression. If you want disabled to mean “fully non-interactive”, you may want to hide/disable this toggle as well.Also applies to: 499-553
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx (2)
201-227: Helper pane positioning/click‑outside wiring is generally good, but toolbar integration is incomplete
useHelperPanewith agetCursorCoordscallback andcalculateHelperPanePositionfor chip-clicks gives consistent positioning and handles scroll/viewport overflow correctly.useHelperPaneClickOutsidecloses the pane when clicking outside editor/helper/toggle, and handles Escape at the document level.However, this component defines a local
toolbarRefand passes it intouseHelperPaneClickOutside, but never attaches that ref to any DOM element. If the actual toolbar lives outside this component (which is likely), clicks on toolbar controls will currently be treated as “outside” and close the helper pane.If your intent is to treat the rich-text toolbar as part of the interactive area (so using bold/italic, etc. doesn’t dismiss the helper), consider passing a real toolbar ref from the parent (similar to
ChipExpressionEditor’stoolbarRefprop) instead of a local, unused ref.Also applies to: 229-251, 490-505
302-330: Token fetching logic matches the “only on user edits” design, but the[value]effect is misleading
fetchAndUpdateTokensis gated bypendingTokenFetchRef.current, which you set:
- on initial mount (before the first fetch), and
- inside
dispatchTransactionwhen doc changes (including undo/redo and specific trigger characters).The
useEffectwatching[value]callsfetchAndUpdateTokens(viewRef.current)without settingpendingTokenFetchRef.current = true, so in practice this effect is a no-op. This is consistent with your earlier design decision (tokens are only needed for user edits in the expanded editor, not for externalvaluechanges), but the presence of the effect suggests re-tokenization on prop changes that never actually happens. Based on learnings, this is intentional.To avoid confusion for future maintainers, you may want to either:
- remove the
[value]effect altogether, or- add a brief comment there stating that token fetching on external
valuechanges is intentionally disabled and relies on the pending flag.Based on learnings, token fetching on external
valuechanges is intentionally disabled.Also applies to: 471-488
📜 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 (17)
workspaces/ballerina/ballerina-side-panel/src/components/editors/EditorFactory.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/PromptMode.tsx(1 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionEditor.tsx(14 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionField.tsx(1 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/CodeUtils.ts(8 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/ChipExpressionEditor.tsx(10 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/plugins/chipPlugin.ts(1 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/plugins/markdownCommands.ts(1 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/plugins/xmlTagDecorationPlugin.ts(1 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/index.ts(1 hunks)workspaces/ballerina/ballerina-visualizer/src/utils/bi.tsx(1 hunks)workspaces/ballerina/ballerina-visualizer/src/views/BI/HelperPaneNew/Views/DocumentConfig.tsx(5 hunks)workspaces/ballerina/ballerina-visualizer/src/views/BI/HelperPaneNew/utils/utils.ts(1 hunks)workspaces/ballerina/bi-diagram/src/components/editors/NPPromptEditor.tsx(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (5)
- workspaces/ballerina/ballerina-side-panel/src/components/editors/index.ts
- workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RichTemplateMarkdownToolbar.tsx
- workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/plugins/xmlTagDecorationPlugin.ts
- workspaces/ballerina/ballerina-side-panel/src/components/editors/EditorFactory.tsx
- workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/plugins/chipPlugin.ts
🧰 Additional context used
🧠 Learnings (14)
📚 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/CodeUtils.tsworkspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/ChipExpressionEditor.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionField.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/PromptMode.tsxworkspaces/ballerina/ballerina-visualizer/src/views/BI/HelperPaneNew/utils/utils.tsworkspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/utils.tsworkspaces/ballerina/bi-diagram/src/components/editors/NPPromptEditor.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionEditor.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/plugins/markdownCommands.tsworkspaces/ballerina/ballerina-visualizer/src/views/BI/HelperPaneNew/Views/DocumentConfig.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/CodeUtils.tsworkspaces/ballerina/bi-diagram/src/components/editors/NPPromptEditor.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionEditor.tsx
📚 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-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/CodeUtils.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/ExpandedEditor/modes/PromptMode.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsxworkspaces/ballerina/bi-diagram/src/components/editors/NPPromptEditor.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionEditor.tsxworkspaces/ballerina/ballerina-visualizer/src/views/BI/HelperPaneNew/Views/DocumentConfig.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/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.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/ExpressionField.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/PromptMode.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/utils.tsworkspaces/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/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/**/*.{ts,tsx} : Use TypeScript 5.8.3 with strict type checking enabled for all source files
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/**/*.{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/components/editors/NPPromptEditor.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionEditor.tsxworkspaces/ballerina/ballerina-visualizer/src/views/BI/HelperPaneNew/Views/DocumentConfig.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.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 Emotion for CSS-in-JS styling instead of inline styles or external CSS files
Applied to files:
workspaces/ballerina/bi-diagram/src/components/editors/NPPromptEditor.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/ballerina-visualizer/src/views/BI/HelperPaneNew/Views/DocumentConfig.tsx
🧬 Code graph analysis (7)
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/CodeUtils.ts (1)
workspaces/common-libs/ui-toolkit/src/styles/Theme.ts (1)
ThemeColors(79-104)
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/ExpandedEditor/controls/RawTemplateMarkdownToolbar.tsx (1)
RawTemplateMarkdownToolbar(180-405)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/ChipExpressionEditor.tsx (1)
ChipExpressionEditorComponent(106-559)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/Configurations.tsx (2)
StringTemplateEditorConfig(64-94)RawTemplateEditorConfig(96-126)
workspaces/ballerina/ballerina-visualizer/src/views/BI/HelperPaneNew/utils/utils.ts (1)
workspaces/ballerina/ballerina-side-panel/src/components/editors/index.ts (1)
InputMode(32-32)
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx (9)
workspaces/common-libs/ui-toolkit/src/styles/Theme.ts (1)
ThemeColors(79-104)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/plugins/chipPlugin.ts (4)
chipSchema(121-121)createChipSchema(112-119)updateChipTokens(424-427)createChipPlugin(320-422)workspaces/ballerina/ballerina-side-panel/src/context/form.tsx (1)
useFormContext(70-70)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(21-21)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/utils.ts (1)
calculateHelperPanePosition(293-313)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/plugins/xmlTagDecorationPlugin.ts (1)
createXMLTagDecorationPlugin(58-80)workspaces/ballerina/ballerina-extension/src/stateMachine.ts (1)
history(71-71)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/plugins/markdownCommands.ts (6)
toggleBold(28-30)toggleItalic(32-34)toggleHeading(76-86)toggleBlockquote(92-98)toggleBulletList(116-128)toggleOrderedList(130-142)
workspaces/ballerina/bi-diagram/src/components/editors/NPPromptEditor.tsx (11)
workspaces/ballerina/ballerina-core/src/interfaces/bi.ts (2)
FlowNode(46-59)NodeKind(393-466)workspaces/ballerina/ballerina-core/src/interfaces/extended-lang-client.ts (1)
ExpressionProperty(1091-1091)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(32-32)ExpandedEditor(33-33)workspaces/common-libs/ui-toolkit/src/components/ExpressionEditor/types/form.ts (1)
FormExpressionEditorRef(79-83)workspaces/mcp-inspector/mcp-inspector-extension/src/utils/logger.ts (1)
error(24-26)workspaces/ballerina/ballerina-side-panel/src/components/Form/types.ts (1)
HelperpaneOnChangeOptions(96-99)workspaces/ballerina/ballerina-side-panel/src/context/form.tsx (1)
FormContext(35-59)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/Configurations.tsx (1)
RawTemplateEditorConfig(96-126)workspaces/common-libs/ui-toolkit/src/components/Commons/ErrorBanner.tsx (1)
ErrorBanner(46-55)
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionEditor.tsx (3)
workspaces/ballerina/ballerina-side-panel/src/components/editors/index.ts (1)
InputMode(32-32)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)
workspaces/ballerina/ballerina-visualizer/src/views/BI/HelperPaneNew/Views/DocumentConfig.tsx (2)
workspaces/ballerina/ballerina-visualizer/src/views/BI/HelperPaneNew/utils/utils.ts (1)
wrapInTemplateInterpolation(22-24)workspaces/ballerina/ballerina-side-panel/src/components/editors/index.ts (1)
InputMode(32-32)
🔇 Additional comments (29)
workspaces/ballerina/ballerina-visualizer/src/utils/bi.tsx (1)
701-703: LGTM!The early guard prevents potential null-pointer exceptions when accessing
signatureHelp.signatureson line 704.workspaces/ballerina/ballerina-visualizer/src/views/BI/HelperPaneNew/utils/utils.ts (1)
22-23: LGTM!Making
inputModea required parameter is clearer than the previous optional approach. The explicit check for bothPROMPTandTEMPLATEmodes aligns with the PR's dual-mode design.workspaces/ballerina/ballerina-visualizer/src/views/BI/HelperPaneNew/Views/DocumentConfig.tsx (2)
48-54: LGTM!The updated
wrapInDocumentTypefunction properly delegates template-wrapping logic towrapInTemplateInterpolationwhen in template mode, keeping the implementation clean and consistent.
166-177: LGTM!The item selection flow correctly treats both
PROMPTandTEMPLATEinput modes as template mode, ensuring variables are properly wrapped with template interpolation.workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/CodeUtils.ts (5)
21-27: Import cleanup and utility usage look consistentThe updated utils import set (
filterCompletionsByPrefixAndType,getParsedExpressionTokens,detectTokenPatterns,ParsedToken) matches the usages in this file, with no stray or missing imports detected.
331-366: Skips multi‑line chips to avoid rendering issues; behavior seems safeThe additional guards to skip compound/tokens whose text includes
'\n'prevent multi‑line chips from being rendered, falling back to plain text in those cases. This avoids potentially awkward chip layout across lines without impacting correctness of the underlying document or deletion logic.
606-624: Helper pane keymap extension is sound; verify Ctrl-/ override is intentionalThe extended
buildHelperPaneKeymapAPI and implementation look correct: Escape cleanly closes the pane only when open, and the optionalonTogglewiring forCtrl-//Cmd-/is straightforward.One thing to double‑check is whether reusing
Ctrl-//Cmd-/(commonly bound to toggle comment) for helper pane toggling is desired for this editor, given it may override existing behavior depending on keymap ordering.
659-700: Inline markdown parsing remains bounded and predictable
parseMarkdownToDOMstill uses a simple, linear scan with small regexes for bold and code spans, and falls back to emitting plain text for anything else. There are no new correctness or performance concerns introduced by the structural tweaks here; behavior stays constrained to the limited markdown subset used in tooltips.
776-814: Arguments documentation now consistently rendered via markdown helperRouting
documentation.argsthroughextractTextContentandparseMarkdownToDOM, with a dedicated “Arguments” label block, aligns its behavior withdocumentation.fnand gives a richer, styled tooltip without changing fallbacks when text is missing.workspaces/ballerina/bi-diagram/src/components/editors/NPPromptEditor.tsx (1)
129-133: Confirm the intended default forinputModevsmode
inputModedefaults toInputMode.EXP(Line 129), butExpandedEditoris always invoked withmode={InputMode.PROMPT}(Line 399) while also receivinginputMode={inputMode}(Line 405). For a prompt-specific editor, this default may be surprising and could lead to inconsistent behavior between inline and expanded modes or helper pane logic.If this editor is only ever used for prompts, consider defaulting
inputModetoInputMode.PROMPT(or inliningInputMode.PROMPTwhere you passinputMode). If expressions are also supported, documenting the distinction betweenmodeandinputModein this component's props would help avoid confusion.workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionField.tsx (1)
212-232: LGTM! Clean integration of PROMPT mode.The new
InputMode.PROMPTbranch follows the established pattern of the other mode handlers. The dynamic configuration selection based onfield.valueTypeConstraint === "ai:Prompt"correctly distinguishes between raw template and string template editing modes.workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionEditor.tsx (4)
566-575: LGTM! Well-implemented TEXT mode validation.The
isExpToTextSafefunction correctly validates double-quoted strings using the negative lookbehind pattern to detect unescaped quotes, and also handles string tagged templates.
577-615: Mode switching logic correctly extended for PROMPT and TEXT modes.The implementation properly:
- Validates expressions before switching to TEXT mode using
isExpToTextSafe- Shares
isExpToTemplateSafevalidation between PROMPT and TEMPLATE modes- Shows warning when sanitization would alter the value, otherwise switches directly
617-628: LGTM! Mode switch continuation logic properly clears invalid values.The logic correctly clears the field value when switching from EXP mode to PROMPT/TEMPLATE/TEXT modes, ensuring users start fresh rather than retaining incompatible expressions.
801-859: ExpandedEditor integration correctly wires PROMPT mode.The guard at line 801 ensures
toEditorMode(inputModeRef.current)is truthy before rendering, making the non-null assertion at line 848 safe. TheinputModeprop propagation enables downstream components to handle mode-specific behavior.workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/plugins/markdownCommands.ts (3)
40-74: LGTM! Robust link toggle implementation.The
toggleLinkcommand correctly handles all three cases:
- Removing existing links when selection has link marks
- Inserting new link text at cursor position when no selection
- Wrapping existing selection with link mark
The early return when
!hrefprevents invalid link creation.
100-142: LGTM! List toggle commands with proper type conversion.The
convertListTypehelper cleanly handles bullet-to-ordered and ordered-to-bullet conversions. BothtoggleBulletListandtoggleOrderedListfollow the expected three-way logic: lift if active, convert if other list type, wrap otherwise.
180-194: LGTM! Undo/redo commands follow standard ProseMirror patterns.The
canUndoandcanRedohelpers correctly leverage ProseMirror's command convention: calling without adispatchfunction returns whether the command is applicable without executing it.workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/PromptMode.tsx (3)
40-58: LGTM! Clean simple mode detection.The
SIMPLE_PROMPT_FIELDSconstant provides a clear whitelist for fields that don't need advanced features. TheisSimpleModecheck correctly requires both the field key match AND absence ofgetHelperPaneto trigger simplified behavior.
153-157: LGTM! Error banner rendering consistent with ExpressionEditor.The scrollable
ErrorBannerwith max height constraint appropriately handles long error messages, and the conditional rendering between validation errors and form diagnostics matches the parent component's pattern.
133-133: Verify configuration selection logic in PromptMode and ExpressionField components.Before applying the suggested change, confirm whether the difference between
field.valueTypeConstraint === "ai:Prompt"(ExpressionField.tsx:228) andfield.valueTypeConstraint === "string"(PromptMode.tsx:133, 148) represents an intentional design distinction for different editor contexts or an actual inconsistency requiring alignment.workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/utils.ts (4)
43-45: LGTM! PROMPT mode detection via field key.The
key === "query"check correctly enables PROMPT mode for query fields as specified in the PR objectives. This aligns with theisExpandableModeusage inExpressionEditor.tsx.
292-313: LGTM! Helper pane positioning with viewport overflow correction.The function correctly calculates position relative to the editor container, compensates for scroll offset, and prevents right-edge overflow. The approach is appropriate for downward-opening helper panes.
320-389: LGTM! Token stream position correction for serialization wrappers.The function correctly adjusts semantic token positions to account for prefix/suffix added during serialization. The algorithm properly handles:
- Early return when no adjustment needed
- First-line-only prefix adjustment
- Delta recalculation for relative positioning
391-445: LGTM! Function argument processing with corrected cursor positioning.The implementation correctly:
- Extracts function definitions from string templates
- Generates numbered placeholder arguments ($1, $2, etc.)
- Calculates cursor position relative to the inserted snippet using
lastIndexOf(")")- Handles extraction failures gracefully with fallback
Previous cursor positioning issues have been addressed.
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/ChipExpressionEditor.tsx (3)
153-179: Helper pane hook integration looks solid and fixes previous keyboard-toggle issuesThe move to
useHelperPane/handleKeyboardTogglewith a cursor-coords callback andHELPER_PANE_WIDTHcentralizes helper-pane behavior nicely and avoids the stale-closure problems from earlier keymap-based toggles. WiringhandleKeyboardTogglethroughbuildHelperPaneKeymapgives you a single, state-safe toggle path forMod-/.Also applies to: 229-235
345-395: Editable Compartment + disabled prop wiring is correct and extensibleUsing a
Compartmentto hostEditorView.editable.of(!props.disabled)and reconfiguring it in auseEffecttied toprops.disabledis the right pattern for toggling editability without recreating the entire editor state. The initial extension list and the follow-upeditableCompartment.reconfigure(...)dispatch are coherent and should play well with the rest of the extensions.Also applies to: 473-480
412-445: Token offset correction viacorrectTokenStreamPositionsimproves maintainabilityReplacing ad-hoc prefix-handling with
correctTokenStreamPositions(tokenStream, sanitizedValue, prefixLen, suffixLen)centralizes the mapping from backend token offsets to the current doc text. This should reduce off‑by‑one bugs when serialization prefix/suffix or sanitization rules change, and the guardedeffectsconstruction keeps the dispatch clean.workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx (1)
364-413: Overall ProseMirror setup and chip/token plumbing look correctThe ProseMirror
EditorStatesetup (chip schema, markdown parser/serializer, history, keymaps, gapCursor, chip/XML-tag plugins, andcursorMovePlugin) is coherent, anddispatchTransactioncorrectly:
- updates state,
- debounces token fetches via
pendingTokenFetchRef+fetchAndUpdateTokens, and- serializes back to markdown/plain text before calling
onChangewith an updated cursor position.The use of
processFunctionWithArgumentsinsideonHelperItemSelectto expand function templates before replacing chips is also a nice consolidation of the earlier ad-hoc argument extraction logic.Also applies to: 416-453
eca5f4f to
15c3d07
Compare
There was a problem hiding this comment.
Actionable comments posted: 0
♻️ Duplicate comments (3)
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx (1)
399-405: Stale closure in Escape keymap handler.The
helperPaneState.isOpenis read from a closure captured when the keymap is created (in the empty-depsuseEffect). This closure will never see updated state.However, this is mitigated by
useHelperPaneClickOutside(lines 489-504) which handles Escape with fresh state. To eliminate the dead code path, consider using a 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/RichTemplateMarkdownToolbar.tsx (1)
357-365: Commented-out inline code button is intentional.The inline code button is disabled with a clear comment. As noted in past reviews, the unused
toggleCodeimport should be removed if not planned for near-term use.workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionEditor.tsx (1)
558-575: Regex validation for templates has known limitations.The regex
/^string\s*.*$/s(lines 562-563, 573-574) uses greedy matching that cannot properly handle escaped backticks within template strings. A string likestring`foo\`bar`would incorrectly match at the first backtick.This was flagged in a previous review. Consider using a more robust pattern that accounts for escape sequences:
- const stringTaggedTemplateRegex = /^string\s*`.*`$/s; + const stringTaggedTemplateRegex = /^string\s*`(?:[^`\\]|\\.)*`$/s;This pattern matches either non-backtick/non-backslash characters or escape sequences (backslash followed by any character).
🧹 Nitpick comments (4)
workspaces/ballerina/ballerina-side-panel/src/components/editors/index.ts (1)
32-33: Re-exports look good; considerexport typeforInputModeif it’s type-only
InputModeandExpandedEditorbeing exposed via this barrel is a sensible public API choice and keeps consumers’ imports centralized. IfInputModeis purely a TypeScript type/alias (no runtime value), consider:-export { InputMode } from "./MultiModeExpressionEditor/ChipExpressionEditor/types"; +export type { InputMode } from "./MultiModeExpressionEditor/ChipExpressionEditor/types";to avoid emitting an unnecessary runtime re-export and to make intent explicit. If
InputModeis an enum or other runtime value, the current form is correct.workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RichTemplateMarkdownToolbar.tsx (1)
199-216: Event listener subscription is correct but consider memoizing the callback.The effect correctly attaches and removes event listeners when
editorViewchanges. However,updateListeneris recreated on every render. While this is mitigated by the[editorView]dependency array (effect only re-runs wheneditorViewchanges), consider extractingforceUpdatecall directly or usinguseCallbackfor cleaner semantics.This is a minor optimization and the current implementation is functionally correct.
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/PromptMode.tsx (2)
40-40: Consider making SIMPLE_PROMPT_FIELDS configurable or documenting its purpose.The constant
SIMPLE_PROMPT_FIELDSdetermines which fields use the simplified mode without helper panes. Consider adding a brief comment explaining the criteria for inclusion, or exporting this constant if other components need to reference it for consistency.
71-74:handleChangewrapper appears redundant.The
handleChangefunction simply forwards parameters toonChangewithout any transformation. Consider usingonChangedirectly to reduce indirection, unless future extensibility is planned.- // Convert onChange signature from (value: string) => void to (value: string, cursorPosition: number) => void - const handleChange = (updatedValue: string, updatedCursorPosition: number) => { - onChange(updatedValue, updatedCursorPosition); - };Then replace
handleChangewithonChangein the child components.
📜 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 (18)
workspaces/ballerina/ballerina-side-panel/src/components/editors/EditorFactory.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/PromptMode.tsx(1 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionEditor.tsx(14 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionField.tsx(1 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/CodeUtils.ts(8 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/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/plugins/chipPlugin.ts(1 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/plugins/markdownCommands.ts(1 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/plugins/xmlTagDecorationPlugin.ts(1 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/TextExpressionEditor/TextModeEditor.tsx(0 hunks)workspaces/ballerina/ballerina-side-panel/src/components/editors/index.ts(1 hunks)workspaces/ballerina/ballerina-visualizer/src/utils/bi.tsx(1 hunks)workspaces/ballerina/ballerina-visualizer/src/views/BI/HelperPaneNew/Views/DocumentConfig.tsx(5 hunks)workspaces/ballerina/ballerina-visualizer/src/views/BI/HelperPaneNew/utils/utils.ts(1 hunks)workspaces/ballerina/bi-diagram/src/components/editors/NPPromptEditor.tsx(1 hunks)
💤 Files with no reviewable changes (1)
- workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/TextExpressionEditor/TextModeEditor.tsx
🚧 Files skipped from review as they are similar to previous changes (7)
- workspaces/ballerina/ballerina-visualizer/src/utils/bi.tsx
- workspaces/ballerina/ballerina-visualizer/src/views/BI/HelperPaneNew/Views/DocumentConfig.tsx
- workspaces/ballerina/bi-diagram/src/components/editors/NPPromptEditor.tsx
- workspaces/ballerina/ballerina-side-panel/src/components/editors/EditorFactory.tsx
- workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/CodeUtils.ts
- workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/plugins/xmlTagDecorationPlugin.ts
- workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/utils.ts
🧰 Additional context used
🧠 Learnings (13)
📚 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/ExpressionField.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/PromptMode.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/plugins/chipPlugin.tsworkspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/plugins/markdownCommands.tsworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RichTemplateMarkdownToolbar.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/ChipExpressionEditor.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/index.tsworkspaces/ballerina/ballerina-visualizer/src/views/BI/HelperPaneNew/utils/utils.tsworkspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionEditor.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/ExpressionField.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/PromptMode.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/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/PromptMode.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RichTemplateMarkdownToolbar.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/ChipExpressionEditor.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/index.tsworkspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsxworkspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionEditor.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.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/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.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/index.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/**/*.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/src/components/editors/index.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/index.ts : Export the main Diagram component as the default export from the package entry point (index.ts)
Applied to files:
workspaces/ballerina/ballerina-side-panel/src/components/editors/index.ts
📚 Learning: 2025-11-05T10:31:47.583Z
Learnt from: madushajg
Repo: wso2/vscode-extensions PR: 830
File: workspaces/ballerina/ballerina-extension/test/ai/post_proccess/post.test.ts:0-0
Timestamp: 2025-11-05T10:31:47.583Z
Learning: In the workspaces/ballerina/ballerina-extension project, the tsconfig.json uses "rootDirs": ["src", "test"], which allows test files to import from src using shorter relative paths. For example, from test/ai/post_proccess/, the import '../../stateMachine' correctly resolves to src/stateMachine.ts due to this configuration.
Applied to files:
workspaces/ballerina/ballerina-side-panel/src/components/editors/index.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/index.tsworkspaces/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/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/src/components/editors/index.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/**/*.{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/index.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/ExpressionEditor.tsx
🧬 Code graph analysis (7)
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionField.tsx (3)
workspaces/ballerina/ballerina-side-panel/src/components/editors/index.ts (1)
InputMode(32-32)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/TextExpressionEditor/TextModeEditor.tsx (1)
TextModeEditor(40-62)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/Configurations.tsx (2)
RawTemplateEditorConfig(96-126)StringTemplateEditorConfig(64-94)
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/plugins/chipPlugin.ts (4)
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/types.ts (2)
TokenMetadata(70-74)CompoundTokenSequence(96-104)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/chipStyles.ts (5)
getChipDisplayContent(107-109)getTokenTypeColor(99-101)BASE_CHIP_STYLES(22-37)getTokenIconClass(92-97)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(106-111)getParsedExpressionTokens(113-139)detectTokenPatterns(236-290)
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/plugins/markdownCommands.ts (1)
workspaces/mi/syntax-tree/src/syntax-tree-interfaces.ts (1)
Transaction(1588-1591)
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RichTemplateMarkdownToolbar.tsx (3)
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/plugins/markdownCommands.ts (10)
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)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/ExpandedEditor/controls/LinkDialog.tsx (1)
LinkDialog(90-175)
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/ChipExpressionEditor.tsx (4)
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(21-21)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/utils.ts (2)
processFunctionWithArguments(389-441)correctTokenStreamPositions(320-386)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(32-32)
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionEditor.tsx (3)
workspaces/ballerina/ballerina-side-panel/src/components/editors/index.ts (1)
InputMode(32-32)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 (54)
workspaces/ballerina/ballerina-side-panel/src/components/editors/index.ts (1)
30-30: Configurations barrel export is consistent with existing API surfaceAdding
export * from "./MultiModeExpressionEditor/Configurations";matches the existing barrel pattern and cleanly exposes the new configuration utilities through the editors index. No issues from an API-structure standpoint.workspaces/ballerina/ballerina-visualizer/src/views/BI/HelperPaneNew/utils/utils.ts (2)
19-19: LGTM!The import is correctly added to support the updated function signature.
22-23: Verify all callers updated and InputMode enum values exist.The logic is correct and template interpolation wrapping is properly escaped. Since the
inputModeparameter changed from optional to required (breaking change), ensure all call sites have been updated to pass this parameter, and confirm InputMode.PROMPT and InputMode.TEMPLATE are defined in the enum.workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/plugins/chipPlugin.ts (8)
46-110: Chip node specification looks well-designed.The node spec correctly defines an atomic, inline, draggable node with appropriate attributes. The
toDOMserialization properly converts child nodes toDOMOutputSpecformat, and theparseDOMhandler gracefully handles re-parsing from HTML.
112-121: Schema creation is correct.The schema extends the markdown schema properly by adding the chip node at the end.
134-182: Chip element creation is well-implemented.The function correctly applies base chip styles, handles icon rendering conditionally, and uses the shared style utilities from
chipStyles.ts.
184-212: Document position mapping handles edge cases correctly.The function properly clamps offsets and uses
doc.descendantsfor traversal. The early return fortextOffset <= 0and the fallbackdocPos || 0ensure valid positions are always returned.
214-318: Text-to-chip replacement logic is correct.The reverse-order application of replacements correctly maintains document positions. The compound detection and individual token handling are properly separated.
366-379: Token position adjustment handles edge cases correctly.The
if (prefixLength > 0)guard ensures no adjustment occurs whenindexOfreturns-1(plainText not found) or0(no prefix). TheMath.max(0, prefixLength)inside the block is now redundant sinceprefixLength > 0is already guaranteed, but it doesn't cause issues.
397-420: Chip click handling is well-implemented.The event delegation pattern using
closest('.pm-chip')correctly identifies chip elements, and the position resolution viaview.posAtDOMproperly maps DOM to document positions.
424-427: Token update utility is concise and correct.The function properly dispatches the token update via ProseMirror's meta mechanism.
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/ChipExpressionEditor.tsx (9)
100-104: New props extend component flexibility appropriately.The
inputMode,hideFxButton,disabled, andplaceholderprops enable the component to handle the new PROMPT mode and support disabled states for read-only scenarios.
153-159: Memoization of compartment and cursor coordinate getter is correct.The
Compartmentis properly created once viauseMemo, andgetCursorCoordsis memoized to avoid unnecessary re-renders of dependent hooks.
161-179: Helper pane hook integration handles PROMPT mode correctly.The conditional
customManualToggleprovides fixed positioning for PROMPT mode while using default cursor-based positioning for other modes.
256-264: Function argument processing correctly refactored to use shared utility.The extraction of function arguments is now handled by
processFunctionWithArguments, improving code reuse across editors.
338-369: Editor extensions and theming logic is correctly implemented.The placeholder extension is conditionally added, and the editable compartment properly controls the disabled state. The theme logic handles expanded mode, hidden FX button, and custom height scenarios appropriately.
409-416: Token position correction now uses a dedicated utility.The refactoring to
correctTokenStreamPositionscentralizes the position adjustment logic and properly handles prefix/suffix lengths from the configuration.
449-455: Dynamic disabled state handling is correctly implemented.The effect properly reconfigures the
editableCompartmentwhen thedisabledprop changes, enabling runtime toggling of the editor's editable state.
513-529: Floating controls correctly hidden when editor is disabled.The conditional rendering of
FloatingButtonContainerbased on!props.disabledprevents interaction controls from appearing in read-only mode.
229-235: Potential stale closure in Escape keymap handler requires verification.The
getIsHelperPaneOpenclosure captureshelperPaneState.isOpenwhen the keymap is built and installed in editor state. Since editor state initialization uses empty dependencies, this closure may read stale state when the Escape key is pressed.The review claims this is mitigated by
useHelperPaneClickOutside(lines 458-473) which handles Escape with fresh state, and thathandleKeyboardToggleuses functional state updates. However, this mitigation should be confirmed to ensure the stale closure in the Escape handler doesn't cause unexpected behavior.workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/plugins/markdownCommands.ts (5)
19-26: Command type and imports are standard ProseMirror patterns.The
Commandtype correctly matches ProseMirror's command signature with optionaldispatchandviewparameters.
40-74: Link toggle command handles all scenarios correctly.The command properly handles link removal (when already linked), link insertion (when no selection), and link wrapping (when text is selected). The
as anycasts are pragmatic workarounds for TypeScript definition gaps in prosemirror-state.
116-142: List toggle commands handle type conversion correctly.The implementation properly handles three scenarios: lifting from current list type, converting between bullet and ordered lists, and wrapping new content in a list.
144-178: Active state detection functions are well-implemented.The functions correctly handle:
- Mark detection for both empty selections (using
storedMarks) and range selections- Node detection by traversing ancestor nodes
- List detection by checking the parent of
list_itemnodes
180-194: Undo/redo commands and availability checks follow ProseMirror conventions.The pattern of calling commands without a dispatch function to check availability is the standard ProseMirror approach.
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx (10)
50-128: Styled editor container provides comprehensive ProseMirror styling.The CSS covers typography, headings, lists, blockquotes, code blocks, and XML tag highlighting, ensuring a consistent editing experience.
130-151: Custom markdown parser and serializer correctly integrate chip nodes.The parser uses the chip schema, and the serializer properly converts chip nodes back to their original text representation, enabling round-trip editing.
200-226: Helper pane hook integration with fixed positioning is appropriate.The
customManualToggleprovides consistent left-aligned positioning for the helper pane in this rich text context.
228-250: Chip click handler correctly positions helper pane and stores chip reference.The handler properly calculates scroll-adjusted positioning and stores the clicked chip's position and node for potential replacement.
252-299: Helper item selection correctly handles both chip replacement and cursor insertion.The function properly distinguishes between replacing an existing chip and inserting new content, with appropriate serialization via
customMarkdownSerializer.
301-329: Token fetching with guard pattern prevents duplicate API calls.The
pendingTokenFetchRefguard ensures tokens are only fetched when needed, and theupdateChipTokenscall properly integrates with the chip plugin.
417-451: Transaction handling correctly optimizes token fetching.Token fetches are triggered on meaningful characters (space,
}) and undo/redo operations, reducing unnecessary API calls while ensuring chips stay synchronized.
453-461: Cmd+B propagation prevention is a good UX fix.Stopping propagation of
Cmd+Bprevents VSCode from toggling its sidebar when the user intends to bold text in the editor.
482-487: Token fetch on value change is intentionally guarded.Per the retrieved learnings, token fetching on external
valueprop 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.
506-521: Render structure is clean and correctly positioned.The component renders the editor container with a conditionally displayed, positioned helper pane.
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionField.tsx (1)
212-232: PROMPT mode handling follows established patterns.The new
InputMode.PROMPTcase correctly mirrors the TEXT and TEMPLATE handling, with dynamic configuration selection based onfield.valueTypeConstraint. When the type is"ai:Prompt",RawTemplateEditorConfigis used; otherwise,StringTemplateEditorConfigprovides default behavior.workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RichTemplateMarkdownToolbar.tsx (7)
1-40: LGTM on imports and setup.The imports are well-organized, and the component correctly imports all necessary ProseMirror commands and utilities from the local
markdownCommandsmodule.
42-171: Well-structured styled components with good accessibility support.The styled components include proper
:focus-visibleoutlines for keyboard navigation and appropriate disabled states. The responsiveflex-wraphandling is good for toolbar overflow scenarios.
173-183: Props interface is well-defined.Clean separation of concerns with optional props for view toggling and helper pane integration.
237-278: Command execution and link handling are well-implemented.The
executeCommandproperly callsforceUpdate()when the command succeeds (addressing the earlier review comment). The link button logic correctly distinguishes between removing an existing link and opening the dialog for new link insertion, with selected text pre-filled as the title.
280-296: Active state computations are correctly guarded.All state checks properly handle the nullable
editorViewandschema, preventing runtime errors when the editor is not yet initialized.
444-457: Switch component for view toggle is well-integrated.The conditional rendering of the view toggle Switch with proper styling integration looks good. The
enableTransition={false}prevents jarring animations during mode switches.
459-465: LinkDialog integration is correct.The dialog properly receives
initialTitlefrom the selected text and handles insert/close callbacks appropriately.workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/PromptMode.tsx (5)
19-30: Imports are well-organized.The imports correctly alias both CodeMirror and ProseMirror
EditorViewtypes to avoid naming conflicts. All necessary components and configurations are imported.
57-58:isSimpleModelogic is clear but consider edge cases.The condition
SIMPLE_PROMPT_FIELDS.includes(field.key) && !getHelperPanemeans a field will only be "simple" if both conditions are met. This is correct behavior - if a helper pane is available, the user should be able to access it regardless of field type.
113-151: Dual-editor approach is well-structured.The conditional rendering between
ChipExpressionEditorComponent(source view) andRichTextTemplateEditor(rich view) is clean. Both editors receive appropriate configurations based onfield.valueTypeConstraint.
153-157: Error banner rendering is correct.The conditional rendering properly prioritizes
erroroverformDiagnosticsand joins multiple diagnostic messages with commas.
125-126: Clarify the distinction betweenisInExpandedModeandisExpandedVersionprops.Both props are set to
trueforChipExpressionEditorComponent. Consider adding a comment or verifying if both are necessary, as the naming suggests they might be redundant.workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionEditor.tsx (6)
31-31: New utility imports are correctly used.The
isExpandableModeandtoEditorModeutilities fromutils.tsare properly imported and used throughout the component for mode gating.
600-612: PROMPT/TEMPLATE mode switching logic handles edge cases well.The logic correctly differentiates between:
- Non-empty values that aren't template-safe → show warning
- Template-safe values → switch to primary mode directly
- Empty values → implicit fall-through to switch mode
This ensures users don't lose data unexpectedly while still allowing valid transitions.
617-628: Value clearing on mode switch prevents invalid state.Clearing the value when switching from EXP to PROMPT/TEMPLATE/TEXT modes is the correct approach, as expression syntax would be invalid in those modes.
801-801: Guard condition ensures safe non-null assertion.The
toEditorMode(inputModeRef.current)check on line 801 ensures that the non-null assertion on line 848 is safe. ThetoEditorModefunction returnsundefinedfor non-expandable modes, preventing the ExpandedEditor from rendering in those cases.
852-853:sanitizedExpressionandrawExpressionare now unconditionally passed.Previously these were conditional on TEMPLATE mode. Now they're always passed to
ExpandedEditor. This is correct sinceExpandedEditorhandles PROMPT mode as well, and downstream code should gracefully handleundefinedvalues when these props aren't applicable.
411-411: PROMPT mode consistently integrated alongside TEMPLATE.The changes correctly extend all TEMPLATE-specific logic to include PROMPT mode, maintaining consistent behavior for both expandable template-based modes.
There was a problem hiding this comment.
Pull request overview
This PR introduces a simplified WYSIWYG-style prompt editor powered by ProseMirror, replacing the previous Edit/Preview modes with Rich Text/Raw modes. The implementation adds comprehensive markdown editing capabilities with toolbar controls, helper pane integration, and variable chip rendering within prompts. The changes enable integration developers to edit prompts without needing to understand markdown syntax, while still preserving the underlying markdown structure.
Key Changes:
- New ProseMirror-based rich text editor with markdown serialization/deserialization
- Dual-mode editing: Rich Text (WYSIWYG) and Raw (markdown source)
- Enhanced toolbars with formatting controls, undo/redo, and helper pane integration
- Variable chip rendering within both editors with token stream parsing
Reviewed changes
Copilot reviewed 47 out of 49 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx |
Core ProseMirror editor implementation with markdown parsing and chip rendering |
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/plugins/chipPlugin.ts |
ProseMirror plugin for rendering variable/document chips |
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/PromptMode.tsx |
Updated prompt mode with rich/raw view toggling |
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RichTemplateMarkdownToolbar.tsx |
Rich text toolbar with formatting buttons and mode switching |
workspaces/ballerina/bi-diagram/src/components/editors/NPPromptEditor.tsx |
New prompt editor wrapper for diagram nodes |
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/utils.ts |
Enhanced utilities for token processing and helper pane positioning |
workspaces/ballerina/ballerina-side-panel/package.json |
Added ProseMirror dependencies and markdown-it |
Files not reviewed (1)
- common/config/rush/pnpm-lock.yaml: Language not supported
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
...mponents/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx
Outdated
Show resolved
Hide resolved
workspaces/ballerina/ballerina-visualizer/src/views/BI/FocusFlowDiagram/utils.tsx
Outdated
Show resolved
Hide resolved
workspaces/ballerina/ballerina-visualizer/src/views/BI/FocusFlowDiagram/index.tsx
Outdated
Show resolved
Hide resolved
...mponents/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (1)
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx (1)
392-405: Escape key keymap still closes over stalehelperPaneStateand is redundant with global Escape handlingThe
"Escape"key handler in the ProseMirrorkeymapreadshelperPaneState.isOpenfrom a closure created in the empty‑depsuseEffect. That value never changes for this handler, so its behavior can diverge from actual helper‑pane state. Separately,useHelperPaneClickOutsidealready installs a document‑level Escape handler that reliably closes the pane.To reduce confusion and avoid stale‑closure pitfalls, consider either:
- Removing this
"Escape"key binding and relying solely onuseHelperPaneClickOutside, or- Rewriting it to use a functional state updater (or a ref) that always observes the latest
isOpen, similar to how the helper‑pane keyboard toggle was fixed.
🧹 Nitpick comments (3)
workspaces/ballerina/ballerina-visualizer/src/views/BI/FocusFlowDiagram/utils.tsx (1)
33-78: Consider prefixing unused parameter with underscore.The
exprRefparameter (line 37) is destructured (line 64) but never used in the function body. While this is acceptable since the function signature must matchGetHelperPaneFunctionfrom@wso2/bi-diagram, consider prefixing it with an underscore (_exprRef) to explicitly indicate it's intentionally unused.Apply this diff:
interface CreatePromptHelperPaneParams { selectedNode: FunctionNode; model: Flow; fieldKey: string; - exprRef: RefObject<FormExpressionEditorRef>; + _exprRef: RefObject<FormExpressionEditorRef>; anchorRef: RefObject<HTMLDivElement>;And update the destructuring:
export function createPromptHelperPane(params: CreatePromptHelperPaneParams): JSX.Element { const { selectedNode, model, fieldKey, anchorRef, defaultValue,workspaces/ballerina/ballerina-visualizer/src/views/BI/FocusFlowDiagram/index.tsx (1)
534-544: WraphandleGetExpressionTokensinuseCallbackfor proper memoization.This function is included in the memoization dependencies (line 670) but is not wrapped in
useCallback. As a result, it's recreated on every render, causingmemoizedDiagramPropsto change unnecessarily. For consistency with other handlers in this file (e.g.,handleRetrieveCompletionsat line 506) and to ensure effective memoization, wrap this function inuseCallback.Apply this diff:
- const handleGetExpressionTokens = async ( + const handleGetExpressionTokens = useCallback(async ( expression: string, fileName: string, position: { line: number; offset: number } - ): Promise<number[]> => { + ): Promise<number[]> => { return rpcClient.getBIDiagramRpcClient().getExpressionTokens({ expression: expression, filePath: fileName, position: position }); - }; + }, [rpcClient]);workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx (1)
253-299: Helper‑pane selection path callsonChangetwice; centralize cursor updates via the transaction
onHelperItemSelectdispatches a ProseMirror transaction and then manually serializes the doc and callsonChange(line 295–299), whiledispatchTransactionalready serializes and callsonChangeon everydocChangedtransaction (line 446–451). For helper‑pane insert/replace actions this results in two back‑to‑backonChangecalls for the same content, with potentially different cursor positions.To simplify behavior and avoid redundant work, consider:
- Encoding the desired cursor position into the transaction (e.g., by setting the selection before dispatch or via a custom transaction meta), and
- Letting
dispatchTransactionremain the single place that serializes and callsonChange.This keeps cursor handling and parent notifications in one path and avoids duplicate notifications.
Also applies to: 417-451
📜 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 (3)
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx(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)
🧰 Additional context used
🧠 Learnings (14)
📚 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-visualizer/src/views/BI/FocusFlowDiagram/utils.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/**/*.{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-visualizer/src/views/BI/FocusFlowDiagram/utils.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-visualizer/src/views/BI/FocusFlowDiagram/utils.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/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-visualizer/src/views/BI/FocusFlowDiagram/utils.tsxworkspaces/ballerina/ballerina-visualizer/src/views/BI/FocusFlowDiagram/index.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/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/Diagram.tsx : Debounce diagram repaints to avoid excessive re-renders when state changes occur
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/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-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/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/index.ts : Export the main Diagram component as the default export from the package entry point (index.ts)
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/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/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
📚 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-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/ballerina-visualizer/src/views/BI/FocusFlowDiagram/index.tsx
🧬 Code graph analysis (2)
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx (8)
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/plugins/chipPlugin.ts (4)
chipSchema(121-121)createChipSchema(112-119)updateChipTokens(424-427)createChipPlugin(320-422)workspaces/ballerina/ballerina-side-panel/src/context/form.tsx (1)
useFormContext(70-70)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(21-21)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/utils.ts (2)
calculateHelperPanePosition(293-313)processFunctionWithArguments(389-441)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/CodeUtils.ts (1)
chipPlugin(314-375)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/plugins/xmlTagDecorationPlugin.ts (1)
createXMLTagDecorationPlugin(58-80)workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/plugins/markdownCommands.ts (6)
toggleBold(28-30)toggleItalic(32-34)toggleHeading(76-86)toggleBlockquote(92-98)toggleBulletList(116-128)toggleOrderedList(130-142)
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-143)
🔇 Additional comments (4)
workspaces/ballerina/ballerina-visualizer/src/views/BI/FocusFlowDiagram/utils.tsx (1)
108-142: LGTM!The helper pane configuration and JSX structure are well-constructed. The empty
handleValueTypeConstChangehandler (line 134) appears to be an intentional no-op placeholder where the callback is required but no action is needed.workspaces/ballerina/ballerina-visualizer/src/views/BI/FocusFlowDiagram/index.tsx (3)
22-24: LGTM!Import additions properly support the new helper pane integration, bringing in
GetHelperPaneFunctionfor type safety andcreatePromptHelperPanefor the prompt helper pane implementation.Also applies to: 62-62
604-642: LGTM!The
createHelperPanecallback is properly implemented withuseCallback, includes appropriate guard checks (line 618), and has correct dependencies (line 642). The integration withcreatePromptHelperPanecleanly passes through all necessary context.
644-671: Memoization structure is correct.The
useMemoconfiguration properly includes the new helper pane and expression token functions in both theexpressionContextobject (lines 662-664) and the dependencies array (line 670). OncehandleGetExpressionTokensis wrapped inuseCallback(as noted in the previous comment), this memoization will work optimally.
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
Bug Fixes
Refactor
✏️ Tip: You can customize this high-level summary in your review settings.