Skip to content

Conversation

@dan-niles
Copy link
Contributor

@dan-niles dan-niles commented Nov 20, 2025

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:

  • Introduces a new rich text editor that renders markdown as styled text and supports direct in-place editing.
  • Replaces the existing Edit / Preview modes with:
    • Rich Text Mode – the new WYSIWYG-like editor
    • Raw Mode – displays the underlying markdown syntax
  • Adds helper pane support and variable chip rendering within the new editor.

Goals

This change addresses the usability issues described in the linked GitHub issue by:

  • Eliminating the need for users to work with raw markdown.
  • Providing a more approachable editing experience similar to modern document editors.
  • Ensuring that advanced features such as variable chips and helper pane interactions work seamlessly in the new simplified mode.

Approach

The solution is implemented using a ProseMirror-powered rich text editor configured to:

  • Render markdown as styled content
  • Keep markdown generation/persistence behind the scenes
  • Support custom node types for Ballerina variable chips
  • Provide toolbar-driven formatting and keyboard shortcuts (e.g., Cmd+B, Cmd+I, etc.)
  • The UI now displays two modes (Rich Text and Raw), to allow users to switch between simplified editing and full markdown visibility when needed.

UI Component Development

Specify the reason if following are not followed.

  • Added reusable UI components to the ui-toolkit. Follow the intructions when adding the componenent.
  • Use ui-toolkit components wherever possible. Run npm run storybook from the root directory to view current components.
  • Matches with the native VSCode look and feel.

Manage Icons

Specify the reason if following are not followed.

  • Added Icons to the font-wso2-vscode. Follow the instructions.

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

    • Rich-text template editor with formatting toolbar, source/raw view toggle, and link insertion dialog
    • New "Prompt" input mode and enhanced helper pane with chip-aware suggestions
  • Improvements

    • Undo/redo, heading and list controls added to markdown toolbars
    • Better editor layout, error/diagnostic display, and keyboard interactions for helper pane and editor switching

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 20, 2025

Walkthrough

Adds PROMPT input mode and overhauls expanded editing: introduces ProseMirror rich-text and CodeMirror source editors, new toolbars and link dialog, a ProseMirror chip node/plugin, centralized helper-pane hooks/positioning, command utilities (undo/redo), and propagates helper-pane APIs into diagram integrations. (40 words)

Changes

Cohort / File(s) Summary
Dependencies
workspaces/ballerina/ballerina-side-panel/package.json
Replaces/expands editor deps with modular @codemirror/*, prosemirror-*, markdown-it, reinstates explicit react/react-dom versions, and adds @wso2/ui-toolkit; devDeps adjusted.
ExpandedEditor API & Types
**/ExpandedEditor/ExpandedEditor.tsx, **/modes/types.ts, **/index.ts, **/utils.ts
Add inputMode?: InputMode; switch mode keys to typed EditorMode via EXPANDABLE_MODES; export helpers isExpandableMode/toEditorMode; export ExpandedEditor.
Prompt / Template Modes & Editor Routing
**/modes/PromptMode.tsx, **/modes/TemplateMode.tsx, ExpressionEditor.tsx, EditorFactory.tsx, ExpressionMode.tsx, ModeSwitcher/index.tsx
Replace preview flow with source/rich split (no preview props), remove preview tooling, pass inputMode and raw/sanitized expressions, update diagnostics/sanitization to include PROMPT, route query fields to raw source when applicable.
New Toolbars & Link Dialog
**/controls/RawTemplateMarkdownToolbar.tsx, **/controls/RichTemplateMarkdownToolbar.tsx, **/controls/LinkDialog.tsx
Add CodeMirror and ProseMirror toolbars (formatting, headings, lists, link dialog, undo/redo, helper-pane toggle, optional view switch).
Removed Legacy Toolbar & Preview
**/controls/TemplateMarkdownToolbar.tsx, **/controls/MarkdownToolbar.tsx, **/controls/MarkdownPreview.tsx, **/styles/markdown-preview.css, **/utils/transformToMarkdown.ts
Remove old markdown toolbar/preview components, their CSS and markdown transform utilities.
ProseMirror Rich Editor & Chip System
**/RichTextTemplateEditor.tsx, **/chipPlugin.ts, **/markdownCommands.ts, **/xmlTagDecorationPlugin.ts
Add RichTextTemplateEditor, chip inline node/schema and plugin (token→chip transform, update API), ProseMirror markdown commands, and XML tag decoration plugin.
ChipExpression Editor Enhancements
**/MultiModeExpressionEditor/ChipExpressionEditor/*, **/chipStyles.ts, **/constants.ts, **/types.ts
Add inputMode prop, centralized helper-pane state via useHelperPane, HELPER_PANE_WIDTH, processFunctionWithArguments, adjusted token colors and FX/helper-button wiring.
Helper Pane Hook & Utilities
**/hooks/useHelperPane.ts, **/utils.ts (chip editor)
New useHelperPane and useHelperPaneClickOutside; add calculateHelperPanePosition, GetCursorCoords type, helper-pane state APIs and outside-click/Escape handling.
CodeMirror Utilities
**/utils/templateUtils.ts, **/CodeUtils.ts
Add undo/redo wrappers and canUndo/canRedo; extend helper-pane keymap to accept optional onToggle; import indentWithTab.
Diagram / Visualizer Integration & New Editors
workspaces/ballerina/bi-diagram/**, workspaces/ballerina/ballerina-visualizer/**, workspaces/ballerina/bi-diagram/src/components/editors/NPPromptEditor.tsx, workspaces/ballerina/bi-diagram/src/index.tsx
Expose GetHelperPaneFunction and getExpressionTokens in diagram context; add createPromptHelperPane, add NPPromptEditor, wire helper-pane and token APIs into visualizer/diagram flows.
Minor UI tweaks & removals
**/EmptyItemsPlaceHolder.tsx, **/TextAreaEditor.tsx, **/ChipExpressionEditor/components/HelperPaneToggleButton.tsx, **/controls/ChipComponent.tsx (removed)
Small styling/prop tweaks (placeholder margin, expand button position, toggle button title/displayText); remove legacy ChipComponent.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant ExpandedEditor
    participant TemplateMode
    participant SourceEditor as CodeMirror
    participant RichEditor as ProseMirror
    participant RawToolbar
    participant RichToolbar
    participant HelperPane
    User->>ExpandedEditor: open (inputMode=Prompt/Template)
    ExpandedEditor->>TemplateMode: render (passes inputMode, sanitized/raw, callbacks)
    alt Source view (raw)
        TemplateMode->>SourceEditor: mount CodeMirror (provide editorView)
        TemplateMode->>RawToolbar: attach (editorView)
        User->>RawToolbar: command (format/insert/undo)
        RawToolbar->>SourceEditor: execute CodeMirror command
    else Rich view (WYSIWYG)
        TemplateMode->>RichEditor: mount ProseMirror (provide view)
        TemplateMode->>RichToolbar: attach (editorView)
        User->>RichToolbar: command (bold/heading/link)
        RichToolbar->>RichEditor: execute ProseMirror command
        RichEditor->>chipPlugin: token→chip transform (on token update)
    end
    User->>RichEditor: request helper pane (click/shortcut)
    RichEditor->>HelperPane: compute position via useHelperPane -> calculateHelperPanePosition
    HelperPane->>TemplateMode: notify onHelperPaneStateChange (isOpen, ref, toggle)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

  • Focus areas:
    • RichTextTemplateEditor.tsx — ProseMirror schema/serializer, lifecycle, token fetch/update pipeline.
    • chipPlugin.ts — token→chip replacements, position mapping, transaction/undo behaviour.
    • useHelperPane & calculateHelperPanePosition — placement math, scroll/window edge cases, outside-click/Escape handling.
    • PromptMode/TemplateMode/ExpandedEditor — source ↔ rich editor wiring and onChange(value, cursorPosition) consistency.
    • Diagram/Visualizer integrations — new GetHelperPaneFunction/getExpressionTokens types and usages.

Possibly related PRs

Suggested labels

Checks/Enable UI Tests

Suggested reviewers

  • hevayo
  • gigara

Poem

🐰 I nibble keys and hop through code tonight,

Rich and raw, the editors shine bright,
Chips like tiny carrots tucked just right,
The helper pane pops — a soft guiding light,
A rabbit claps: the editor feels light.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The PR title 'Introduce a Simplified Mode for Editing Prompts in the Expanded Editor' directly and clearly describes the main feature being introduced: a simplified editing mode for prompts. It is specific, concise, and accurately reflects the primary change in the changeset.
Description check ✅ Passed The PR description includes Purpose (with linked issues), Goals, Approach, and UI Component Development checklist items. It covers the main objectives, implementation details, and includes video/visual references. However, it lacks details in several template sections like Automation tests, Security checks, Test environment, and Learning sections, though these are not always mandatory for all PRs.
Linked Issues check ✅ Passed The PR addresses the core objectives from issue #1962: introducing a WYSIWYG-style simplified editing mode, replacing Edit/Preview with Rich Text/Raw modes, adding toolbar controls and keyboard shortcuts, and implementing helper pane support. The changes deliver all stated coding requirements from the linked issues.
Out of Scope Changes check ✅ Passed The PR introduces extensive new tooling (CodeMirror, ProseMirror, markdown-it packages), new editor components (RichTextTemplateEditor, RawTemplateMarkdownToolbar, RichTemplateMarkdownToolbar), helper pane hooks, and removes legacy preview components. While comprehensive, all changes directly support the core objective of implementing a simplified WYSIWYG editor with dual modes and helper pane support as described in the linked issues.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@dan-niles dan-niles force-pushed the prompt-editor-simplified-mode branch from cbf6312 to a020c3b Compare November 24, 2025 05:40
@dan-niles dan-niles marked this pull request as ready for review November 24, 2025 21:40
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/CodeUtils.ts (1)

716-763: Fix severity type cast to include "hint" from @codemirror/lint API

The buildLintingExtension function casts diagnostic.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

RawTemplateMarkdownToolbar largely mirrors RichTemplateMarkdownToolbar (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 CSS

The selectors .ͼ1 .cm-scroller and .ͼ1 .cm-lintRange-error depend 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-scroller and .cm-lintRange-error / diagnostic-specific classes) so styles survive library upgrades.


94-127: Adjusted diagnostics are not propagated to child editors

computeDiagnostics/adjustedDiagnostics correctly rebase diagnostic ranges relative to targetLineRange, but the adjusted list is only used for the ErrorBanner. Neither ChipExpressionEditorComponent nor RichTextTemplateEditor receive these diagnostics via a formDiagnostics-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 adjustedDiagnostics down 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 logic

The chip NodeSpec and toDOM/parseDOM setup 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.eq now compares text, start, end, and diagnostic but not type or metadata. If either of those change (e.g., a document chip’s documentType or variable/document classification changes without moving), the widget may not re-render, leaving stale icon/color. Including this.type and, if relevant, a stable subset of metadata in 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

onHelperPaneStateChange exposes isOpen, the toggle function, and helperPaneToggleButtonRef, which lets the parent own the toolbar button. However, toolbarRef inside 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 wire toolbarRef into the actual toolbar container or remove it to avoid confusion.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 816940a and 764ee7b.

⛔ Files ignored due to path filters (2)
  • common/config/rush/pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
  • workspaces/common-libs/font-wso2-vscode/src/icons/bi-arrow-down.svg is 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.ERROR addition 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 DiagnosticMessage with optional range, code, and source fields 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/onTogglePreview from the template mode prop surface aligns with the internal state management refactoring in TemplateMode.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 title prop 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 DOCUMENT token colors and new ERROR token 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 updateFormFieldWithDiagnostics is 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 updateFormFieldWithDiagnostics function 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 stack

The 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 sound

The new linting Compartment and formDiagnostics-driven useEffect cleanly separate diagnostics reconfiguration (lintCompartment.reconfigure) from other editor extensions, and diagnosticsChangeEffect keeps 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 requirements

The 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 with disabled={!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 coherent

The TemplateMode component cleanly switches between raw (CodeMirror) and rich (ProseMirror) views using isSourceView, passing the corresponding EditorView instances into RawTemplateMarkdownToolbar and RichTemplateMarkdownToolbar via onEditorViewReady. Helper pane toggle state is shared across modes, and the consolidated ErrorBanner uses 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 sense

Requiring trimmed !== "" in the allListed check 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 needed

CodeMirror 6 exports undo and redo as StateCommand functions callable with an EditorView, and undoDepth/redoDepth as (state: EditorState) => number. The code correctly calls undo(view) and redo(view) from UI handlers and uses undoDepth(view.state) and redoDepth(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 efficient

Recomputing decorations only when the doc, tokens, or diagnostics change, and using findDiagnosticForRange with simple overlap checks, is a good balance between accuracy and cost. Passing the resolved { severity, message } into createChip gives you consistent visuals (background, border, icon, underline, tooltip) with the ProseMirror chips.


320-342: LSP-style range → CodeMirror position mapping verified as correct

LSP 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 calling doc.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 for extractArgsFromFunction is incorrect inside string templates

In onHelperItemSelect, when newValue matches a ${...} template, cursorPositionForExtraction is computed as prefix.length + functionDef.length - 1 but then passed together with functionDef alone into extractArgsFromFunction. 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 functionDef only. 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 transformations

The code correctly marks appended chip transactions with addToHistory: false and 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 where plainText is not found in wrappedText

The code at line 403-407 assumes that plainText is always a substring of wrappedText (derived from rawExpression(plainText)). When wrappedText.indexOf(plainText) returns -1, the condition prefixLength > 0 is false, so token position adjustment is silently skipped. This leaves tokens in wrapped-text coordinates, potentially misaligning chip placement.

Since rawExpression is a custom transformation prop, it could theoretically produce output where plainText is not a substring. Add an explicit check for the -1 case:

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.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

♻️ Duplicate comments (4)
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/ChipExpressionEditor.tsx (1)

100-101: Helper pane Escape handling still depends on stale state from initial render

Even though the toggle behavior was refactored to use a functional setHelperPaneState, the keymap still receives getIsHelperPaneOpen: () => helperPaneState.isOpen at editor initialization time. Because the EditorState (and thus the keymap) is created only once in the useEffect([]), the getIsHelperPaneOpen closure will always see the initial helperPaneState value. As a result, the "Escape" binding inside buildHelperPaneKeymap may never call onClose() while the editor has focus, making Escape unreliable for closing the helper pane.

You can keep the current keymap API but route getIsHelperPaneOpen through a ref that is kept up to date whenever helperPaneState.isOpen changes:

-    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

forceUpdate is only wired to DOM events on editorView.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, so isUndoAvailable / 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

executeCommand captures the command’s boolean result and calls forceUpdate() 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: External value changes still don’t trigger token refresh due to pendingTokenFetchRef guard

fetchAndUpdateTokens returns early when pendingTokenFetchRef.current is false, but the [value] effect calls it without setting the flag. This means external updates to value (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 sync

The comment still mentions “Use saved selection if available”, but onHelperItemSelect now always uses the current selection (view.state.selection.main), and the savedSelectionRef is no longer consulted.

Either restore the saved‑selection behavior (if it’s still desired UX) or update the comment and remove savedSelectionRef to 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 toolbars

The 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: Tighten executeCommand typing to use ProseMirror’s Command

The command parameter is currently typed with any for state, dispatch, and view. You can improve type safety and editor tooling by using the Command type from prosemirror-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 stale helperPaneState

Unlike handleHelperPaneKeyboardToggle, the "Escape" binding in the keymap plugin reads helperPaneState.isOpen from a closure created in the empty‑deps useEffect. 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: toolbarRef is never attached to a DOM element, making the toolbar “inside click” check ineffective

toolbarRef is created and used in handleClickOutside via toolbarRef.current?.contains(target), but it is never passed to any JSX element in this component (and not exposed via props). As a result, isClickInsideToolbar is always false, so clicks on the toolbar will be treated as “outside” and close the helper pane, regardless of the intent behind this check.

Either wire toolbarRef to the actual toolbar element (likely via a prop from the parent) or remove the toolbarRef/isClickInsideToolbar branch 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 handleClickOutside accordingly.

Also applies to: 570-591

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 764ee7b and 250227d.

📒 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 correct

The introduction of formDiagnostics, the dedicated lintCompartment, and the combination of buildLintingExtension with diagnosticsField / diagnosticsChangeEffect is a solid way to keep editor linting in sync with form-level diagnostics without recreating the whole editor state. The initial compartment configuration in EditorState.create and the follow‑up useEffect that reconfigures the compartment and updates the diagnostics field when props.formDiagnostics changes 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 useEffect reliably fires.

If you want to double‑check CodeMirror API usage across versions, you can verify that Compartment.reconfigure still accepts either a single Extension or an Extension[], and that linter from @codemirror/lint is compatible with the current EditorState version 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 title

Adding the "Toggle Helper Panel (Ctrl+/ or Cmd+/)" title makes the keyboard shortcut discoverable and aligns with the new keymap behavior. No issues here.

@dan-niles dan-niles force-pushed the prompt-editor-simplified-mode branch from 9a9799a to f0a7d4b Compare November 24, 2025 22:27
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/CodeUtils.ts (1)

608-626: Helper pane keymap toggle wiring is correct; double‑check shortcut choice

The optional onToggle handling 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 .ͼ1 class is an internal CodeMirror class that may change across versions. Consider using a more stable selector like .cm-editor .cm-scroller or wrapping the editor in a custom class and targeting it from there.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 250227d and f0a7d4b.

📒 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.ts
  • 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
🔇 Additional comments (2)
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/CodeUtils.ts (1)

22-27: Import additions look fine

The 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.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (5)
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/chipPlugin.ts (3)

184-212: Early exit in findDocPosition may skip valid positions.

The docPos > 0 check 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 of any.

The tr parameter and node in the replacements array use any type. 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 the view parameter.

The updateChipTokens function uses any for the view parameter. Using EditorView from 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-visible styles 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

📥 Commits

Reviewing files that changed from the base of the PR and between f0a7d4b and 048c508.

📒 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.ts
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/TemplateMode.tsx
  • workspaces/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 via JSON.stringify may 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 toDOM implementation correctly handles chip rendering with icon and text children, and the parseDOM properly 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 codeMirrorView and proseMirrorView states, 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 (codeMirrorView for Raw, proseMirrorView for 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() in handleMouseDown prevents 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 ThemeColors consistently 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 displayName on forwardRef components ensures the component name appears correctly in React DevTools, improving debugging experience.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (3)
workspaces/ballerina/ballerina-visualizer/src/views/BI/HelperPaneNew/utils/utils.ts (1)

21-24: PROMPT interpolation behavior matches TEMPLATE; update comment for clarity

Extending wrapInTemplateInterpolation to treat InputMode.PROMPT like TEMPLATE is 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 toggle

The new TemplateMode split between:

  • rich view: RichTemplateMarkdownToolbar + RichTextTemplateEditor
  • source view: RawTemplateMarkdownToolbar + ChipExpressionEditorComponent

is wired cleanly: editor views are captured via onEditorViewReady, passed back into the corresponding toolbar, and the helper-pane toggle flows through handleHelperPaneStateChange.

One small robustness tweak: handleToggleView currently 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” mode

Here:

mode={
  inputModeRef.current === InputMode.EXP
    ? "expression"
    : inputModeRef.current === InputMode.PROMPT
      ? "template"
      : undefined
}

InputMode.TEMPLATE now results in mode === undefined, even though:

  • PROMPT is explicitly mapped to "template".
  • sanitizedExpression and rawExpression are always passed to ExpandedEditor regardless of mode.

If TEMPLATE is still a reachable InputMode here (e.g., via getInputModeFromTypes), 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

📥 Commits

Reviewing files that changed from the base of the PR and between 048c508 and 6a10daf.

📒 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.tsx
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/HelperPaneNew/Views/DocumentConfig.tsx
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionEditor.tsx
  • workspaces/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.tsx
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionEditor.tsx
  • workspaces/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 correct

Adding 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 URLs

In handleItemSelect you treat template mode as:

const isTemplateMode = inputMode === InputMode.PROMPT || inputMode === InputMode.TEMPLATE;

but in URLInputModal.handleCreate you 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 safeguard

Capping the error area and enabling vertical scrolling on ErrorBanner keeps 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 flows

The additions that treat PROMPT like TEMPLATE look coherent:

  • fieldValue now uses rawExpression when inputModeRef.current is PROMPT or TEMPLATE, so diagnostics and initial validation see the underlying expression rather than the sanitized view.
  • Initial diagnostics and subsequent getExpressionEditorDiagnostics calls now gate on inputMode / currentMode being EXP | PROMPT | TEMPLATE, which keeps validation active in all three modes.
  • Mode initialization via getInputModeFromTypes considers PROMPT/TEMPLATE together and only opts into them when sanitizedExpression/rawExpression are 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 ExpressionField and ExpandedEditor onChange paths compute rawValue using rawExpression(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

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (4)
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/LinkDialog.tsx (2)

23-58: Consider adding focus trap for accessibility.

The modal lacks a focus trap, which means users can tab out of the dialog to elements behind the overlay. For accessibility compliance, modal dialogs should trap focus within themselves until closed.

Additionally, consider adding role="dialog" and aria-modal="true" to PopupBox for 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 / canRedo implementation differs from existing pattern in codebase.

These functions call undo(state) and redo(state) without a dispatch function, which works because ProseMirror commands return false if they can't be applied. However, the existing templateUtils.ts uses undoDepth(state) > 0 and redoDepth(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 onKeyDown handler 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

📥 Commits

Reviewing files that changed from the base of the PR and between 6a10daf and c8fca16.

📒 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.tsx
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/LinkDialog.tsx
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx
  • workspaces/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. The HACK comment 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 keydown event listener on document (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 toggleLink function now takes optional href and title parameters, addressing the previous review concern about hardcoded URLs. The implementation correctly:

  • Removes existing links when present
  • Returns false if 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, and isListActive functions 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 any casts 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 addMark and removeMark exist in prosemirror-state@^1.4.3.

The methods tr.addMark(from, to, mark) and tr.removeMark(from, to, markOrType) are confirmed to exist in ProseMirror's Transaction API. However, whether the type definitions are available in your installed version of prosemirror-state@^1.4.3 cannot be verified in this environment.

To resolve this:

  1. Check if TypeScript compilation succeeds without the as any casts by removing them temporarily
  2. If compilation succeeds without errors, the casts are unnecessary and should be removed
  3. If TypeScript reports type errors, the version of prosemirror-state may lack type definitions for these methods and the casts may be needed

The suggested refactor in the review (removing the as any casts 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 executeCommand function now calls forceUpdate() when the command succeeds, ensuring toolbar active states update immediately after toolbar-triggered commands. This addresses the previously reported issue.


23-38: Unused toggleCode import 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.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (4)
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RichTemplateMarkdownToolbar.tsx (1)

299-310: Orphan divider when helperPaneToggle is not provided.

The ToolbarDivider at line 310 renders unconditionally, but the HelperPaneToggleButton only renders when helperPaneToggle is 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 removing as any casts for type safety.

The as any casts on lines 48 and 67 bypass TypeScript's type checking. ProseMirror's Transaction extends Transform, which includes addMark and removeMark methods. 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-state types are up to date, or consider adding a targeted type assertion like (state.tr as Transaction & Transform).


100-114: Consider removing as any cast in convertListType.

Same concern as with link commands – replaceWith is a method on Transform, 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: Prefer undoDepth/redoDepth for efficiency.

Calling undo(state) and redo(state) without dispatch works but actually computes the undo/redo operation to determine availability. Using undoDepth/redoDepth from prosemirror-history is more efficient, as shown in templateUtils.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

📥 Commits

Reviewing files that changed from the base of the PR and between c8fca16 and 7c2d492.

📒 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.ts
  • workspaces/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.

executeCommand correctly triggers forceUpdate when a command succeeds, keeping toolbar state in sync. The handleHeader function 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 dropdownRef correctly closes the menu, and handleMouseDown prevents 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 toggleMark for bold, italic, and code marks.


76-98: LGTM – heading, paragraph, and blockquote toggles.

The toggleHeading command correctly toggles between heading and paragraph based on active state. toggleBlockquote properly uses lift to unwrap and wrapIn to 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.

isMarkActive correctly handles both empty selections (storedMarks) and ranges. isNodeActive and isListActive properly traverse the document depth to find matching nodes.

@dan-niles dan-niles force-pushed the prompt-editor-simplified-mode branch from 472afd8 to 4e82930 Compare November 25, 2025 07:54
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/types.ts (1)

19-30: Use proper ProseMirror Node type instead of any for clickedChipNode

The 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 field valueTypeConstraint) need entries; PROMPT is the only constraint-mapped mode currently.

However, at line 114 in types.ts, clickedChipNode?: any should be typed as Node from prosemirror-model. The property holds a ProseMirror node (created via schema.nodes.chip.create()) and is accessed with .nodeSize at 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

calculateHelperPanePosition handles right-side overflow, but when overflow > 0 and left is already small, left -= overflow can 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 functional setHelperPaneState updates to preserve extra state fields

Now that HelperPaneState includes optional fields like clickedChipPos / clickedChipNode, the places where you call setHelperPaneState({ ... }) 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 HelperPaneState later.)

Also applies to: 122-144, 174-207, 321-337

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7c2d492 and 4e82930.

📒 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.ts
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/ChipExpressionEditor.tsx
  • workspaces/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.tsx
  • workspaces/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’s Escape – verify this is desired

useHelperPaneClickOutside installs a document‑level keydown handler that, on Escape, calls event.preventDefault() and event.stopPropagation() before closing the helper pane. While the pane is open, this prevents CodeMirror’s own Escape keymap handlers (including the one from buildHelperPaneKeymap, 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 calling preventDefault/stopPropagation when 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 Esc and 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 behavior

Both HelperPaneToggleButton (expanded mode) and the floating FloatingToggleButton (non‑expanded mode) now delegate to handleManualToggle from useHelperPane, with helperPaneToggleButtonRef passed 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

useHelperPane and useHelperPaneClickOutside encapsulate the helper pane’s positioning, toggling, and outside‑click/Escape behavior cleanly, and the use of functional setHelperPaneState updates avoids stale‑closure issues that existed in earlier inline implementations. The abstractions and types line up well with the ChipExpressionEditor usage.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx (1)

325-471: Stale closure in Escape keymap handler.

The Escape handler at line 391-397 reads helperPaneState.isOpen from a stale closure. Since the keymap plugin is created in the initial useEffect (line 325) with empty dependencies, the Escape handler always sees the initial isOpen value (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 unused toggleCode import.

The toggleCode function is imported on line 26 but never used (the inline code button and isCodeActive are 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

📥 Commits

Reviewing files that changed from the base of the PR and between 4e82930 and c30e069.

⛔ Files ignored due to path filters (1)
  • common/config/rush/pnpm-lock.yaml is 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.tsx
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/ChipExpressionEditor.tsx
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/types.ts
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionEditor.tsx
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RawTemplateMarkdownToolbar.tsx
  • 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/**/*.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.tsx
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/ChipExpressionEditor.tsx
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RawTemplateMarkdownToolbar.tsx
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RichTemplateMarkdownToolbar.tsx
  • workspaces/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
  • workspaces/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.tsx
  • workspaces/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.tsx
  • workspaces/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 inputMode to EditorModeExpressionProps properly 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 codeMirrorView and proseMirrorView states, along with isSourceView toggle, provides a clear separation between raw and rich editing modes. The handleToggleView function 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 inputMode prop 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 useHelperPane hook 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 useHelperPaneClickOutside hook 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 fieldValue calculation and initial diagnostics fetch to include InputMode.PROMPT alongside InputMode.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 onChange handler correctly computes rawValue for 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.PROMPT to "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 useHelperPane hook 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 value changes is intentionally minimal since users cannot edit both minimized and expanded editors simultaneously. The pendingTokenFetchRef guard 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 executeCommand wrapper correctly calls forceUpdate when 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:assets runs 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-it tokenizer is directly passed to the MarkdownParser constructor—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-client uses React 19.1.0 and workspaces/ballerina/statement-editor uses ^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:

  1. These React 19 packages are intentionally isolated (no shared dependencies with React 18 packages)
  2. The monorepo uses explicit resolution strategies (resolutions, overrides, pnpm extensions) to prevent type resolution conflicts
  3. 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.

@dan-niles dan-niles force-pushed the prompt-editor-simplified-mode branch from 9c905e9 to 842bc28 Compare November 25, 2025 12:40
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionEditor.tsx (2)

452-472: Add type guard before calling sanitizedExpression / .trim() for PROMPT/TEMPLATE

In the new PROMPT/TEMPLATE branch, initialFieldValue.current is 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.current is undefined, null, or a non‑string, sanitizedExpression (which expects a string) and especially .trim() can throw at runtime. The TEXT branch above already has a typeof 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 comment

The comment says:

// Warn when switching from EXP to TEMPLATE if sanitization would hide parts of the expression

but 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.PROMPT and InputMode.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.isOpen from the closure when the keymap is created (in the empty-deps useEffect). Since the state never updates in this closure, helperPaneState.isOpen will always be false (initial value), making this handler effectively a no-op.

The useHelperPaneClickOutside hook 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 whether stopPropagation is necessary for Escape.

The Escape key handler calls both preventDefault() and stopPropagation(). While preventDefault() 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.) are RefObject instances which are stable across renders. Including them in the dependency array doesn't cause bugs but is unnecessary. The callbacks onClickOutside and onEscapeKey are 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 references onStateChange, toggleButtonRef, and handleManualToggle. This could cause issues if these values change.

However, in practice:

  • onStateChange is typically stable (passed from parent)
  • toggleButtonRef is a stable ref object
  • handleManualToggle is memoized

The primary concern is that if onStateChange is 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 textStyles variable is assigned but the original CHIP_TEXT_STYLES is 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: findDocPosition returns 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 (from docPos || 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.stringify to 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 text mode. Based on the code, prompt mode does support preview (it has isPreviewMode and onTogglePreview props).

     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's updateState event instead of DOM events.

The toolbar subscribes to DOM events (input, click, keyup) to detect state changes. ProseMirror provides a more reliable approach via plugin view.update or 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 removing as any type assertions.

The as any casts on Transaction methods (removeMark, addMark, replaceWith) bypass TypeScript's type checking. ProseMirror's Transaction class 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-data uses 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/rawExpression to ExpressionField when in PROMPT/TEMPLATE modes.
  • Converts updatedValue back to a raw value via rawExpression for PROMPT/TEMPLATE before storing and before diagnostics/completions.
  • Uses inputModeRef.current to avoid stale closures in the async onChange path.

This keeps EXP/TEXT/RECORD unaffected while enabling the raw↔sanitized mapping for the new prompt mode.

The onChange body here is almost identical to the one in ExpandedEditor below; 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

📥 Commits

Reviewing files that changed from the base of the PR and between c30e069 and 842bc28.

⛔ Files ignored due to path filters (2)
  • common/config/rush/pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
  • workspaces/common-libs/font-wso2-vscode/src/icons/bi-arrow-down.svg is 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.tsx
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/ExpandedEditor.tsx
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/LinkDialog.tsx
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionEditor.tsx
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/utils.ts
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/markdownCommands.ts
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RichTemplateMarkdownToolbar.tsx
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/TemplateMode.tsx
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/ChipExpressionEditor.tsx
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/chipPlugin.ts
  • workspaces/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.tsx
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/TemplateMode.tsx
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/ChipExpressionEditor.tsx
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/hooks/useHelperPane.ts
  • workspaces/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.tsx
  • 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/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
  • 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/**/*.{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.ts
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/constants.ts
  • workspaces/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.tsx
  • 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/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: Verify cursorAdjustment semantics.

On line 205, cursorPosition = from + result.cursorAdjustment assumes cursorAdjustment is an offset from the insertion point. However, looking at processFunctionWithArguments in utils.ts (line 403-405), cursorAdjustment is set to closingParenIndex which is an index within finalValue, not a relative offset.

This means the cursor will be placed at from + closingParenIndex, which is actually correct since you're inserting finalValue starting at from, and you want the cursor at closingParenIndex within that inserted text.

The naming is slightly misleading (cursorAdjustment suggests a delta), but the logic is correct.


331-347: LGTM!

The hook integration properly centralizes click-outside and escape key handling. The inclusion of toolbarRef ensures 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 handleManualToggle across toggle buttons ensures uniform behavior.


176-182: Stale closure confirmed, but practical impact mitigated.

The review comment correctly identifies a stale closure issue: helperPaneKeymap is created at render level with a closure capturing helperPaneState.isOpen, but the useEffect (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 of helperPaneState.isOpen from 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 helperPaneState to the useEffect dependency array, or
  • Adding helperPaneKeymap as a dependency
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/hooks/useHelperPane.ts (2)

131-152: LGTM! Functional setState pattern correctly addresses stale closure.

The handleKeyboardToggle implementation correctly uses functional setHelperPaneState to 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 customManualToggle escape 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/redoDepth for 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.ts since 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 condition prefixLength > 0 will be false, which is correct. However, if plainText is at position 0, prefixLength will 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 appendTransaction for 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 PROMPT and TEMPLATE input modes as requiring string interpolation wrapping when selecting AI document type items.


214-214: Inconsistent isTemplateMode logic between item selection and URL insertion.

At line 162, isTemplateMode is inputMode === InputMode.PROMPT || inputMode === InputMode.TEMPLATE, but here it only checks inputMode === 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 inputMode prop 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 inputMode is correctly included in the template mode props, enabling the TemplateMode component 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 inputMode because it's a specialized template-view renderer, not a multi-mode editor. ChipExpressionEditorComponent accepts and uses inputMode to 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 executeCommand now correctly calls forceUpdate() 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 useHelperPane hook 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 useHelperPaneClickOutside hook 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 convertListType function 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) and redo(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-element v2.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 (in MarkdownToolbar.tsx lines 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 consistent

Extending fieldValue and the diagnostics guard to treat InputMode.PROMPT the same way as TEMPLATE keeps 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 desired

In handleModeSwitchWarningContinue, when continuing from EXP to PROMPT/TEMPLATE, the current field value is replaced with rawExpression(""):

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 currentValue instead of an empty string.


622-625: Expanded mode gating correctly includes PROMPT and TEMPLATE

Allowing onOpenExpandedMode when inputMode is EXP, PROMPT, or TEMPLATE (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 and mode mapping should be double‑checked

The expanded editor integration now:

  • Mirrors the rawValue/diagnostics/completions logic from the inline editor for PROMPT/TEMPLATE.
  • Always passes sanitizedExpression, rawExpression, and inputMode={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:

  1. TEMPLATE input mode in expanded editor
    For InputMode.TEMPLATE, mode becomes undefined now. If TEMPLATE is still a supported mode, this changes its expanded‑mode behavior (likely falling back to whatever the default is in ExpandedEditor). If TEMPLATE is effectively superseded by PROMPT for the new rich editing experience, this is fine; otherwise, you may still want InputMode.TEMPLATE to map to "template".

  2. Consistency with RichTextTemplateEditor value semantics
    Passing value={watch(key)} plus sanitizedExpression/rawExpression and using rawExpression(updatedValue) on change aligns with the RichTextTemplateEditor behavior where token fetching is intentionally not driven by external value changes, 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".

@senithkay
Copy link
Contributor

ChipExpressionEditor component looks LGTM

@dan-niles dan-niles force-pushed the prompt-editor-simplified-mode branch from 7e29c2b to 1d4fa5d Compare November 29, 2025 13:29
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

♻️ Duplicate comments (1)
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx (1)

391-397: Escape handler still reads stale helperPaneState.isOpen from closure.

The Escape keymap is defined inside a useEffect with empty deps (line 325), so it captures the initial helperPaneState ({ isOpen: false, ... }). When the helper pane opens, the keymap closure never sees the update, so helperPaneState.isOpen remains false, and the handler always returns false.

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: New title / displayText props are straightforward; consider naming consistency

Adding title?: string and displayText?: string is a clean, backward‑compatible way to customize the button. For future clarity, you might consider a more semantically-aligned name like label instead of displayText, since it effectively serves as the visible label for the control.


33-40: Minor typing redundancy in OutlineButton styled definition

You already parameterize OutlineButton as styled.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 aligning aria-label with customizable displayText / adding an override

The new displayText and title customizations are wired correctly and preserve the "Helper Panel" default. One small a11y concern: aria-label remains hard-coded as "Toggle helper panel" even when displayText changes, which can cause screen reader text to drift from the visible label. Consider either:

  • deriving the aria-label from displayText when provided, or
  • adding an optional ariaLabel prop 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_WIDTH here is the right direction. The helper-related listeners in CodeUtils.ts still hardcode 300; 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 hardcoding 300 in listeners.

buildOnFocusListner, buildOnSelectionChange, and buildOnChangeListner all duplicate const HELPER_PANE_WIDTH = 300; even though HELPER_PANE_WIDTH is now exported from constants.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 removing as any casts on transactions for better type safety.

toggleLink and convertListType currently cast state.tr to any to access removeMark, addMark, and replaceWith. 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-transform typings 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 access

Providing a default expressionContext object here prevents consumers from dealing with undefined and keeps diagrams without expression tooling safe; if you later require callbacks like onCancel or getExpressionTokens, 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 misleading

Adding inputMode to ExpandedPromptEditorProps and passing it only to the template mode props is consistent with how TemplateMode and NPPromptEditor consume it.

The comment // Only text mode and prompt mode don't support preview doesn’t match the code anymore—only text forcibly disables preview, while prompt still receives isPreviewMode/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

npFunctionNode is resolved via flow.nodes.find(… === "NP_FUNCTION") and then passed directly as node={npFunctionNode} into NPPromptEditor. From the NPPromptEditor implementation, props.node is dereferenced (props.node.properties['prompt']) without a null check, so if a flow ever lacks an NP_FUNCTION node 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 npFunctionNode is undefined.

The completion retrieval changes and the rest of the NPPromptEditor wiring 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 possible

The helper correctly:

  • Constructs a Property/FormField for the prompt.
  • Routes updateImports through the BI diagram RPC client.
  • Forwards completions and handleRetrieveCompletions via the debounced function.
  • Wraps everything in FieldProvider with TRIGGER_CHARACTERS.

A couple of small follow‑ups you might consider:

  • exprRef is accepted in CreatePromptHelperPaneParams but never used; if GetHelperPaneFunction doesn’t need it here, you can drop it from the params to reduce noise.
  • valueTypeConstraint is typed as string | string[] but passed as valueTypeConstraint as string || "ai:Prompt". If an array were ever passed, it would still be an array at runtime. Tightening the type (to string) 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.TEMPLATE is 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 helperPaneToggle is 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 for completionSource memo may be overly broad.

The useMemo depends on props.completions, but the returned buildCompletionSource(waitForStateChange) doesn't use completions directly — it uses completionsRef.current inside waitForStateChange. Since completionsRef is 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 buildCompletionSource and waitForStateChange are stable:

     const completionSource = useMemo(() => {
         return buildCompletionSource(waitForStateChange);
-    }, [props.completions]);
+    }, []);
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 842bc28 and 1d4fa5d.

⛔ Files ignored due to path filters (2)
  • common/config/rush/pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
  • workspaces/common-libs/font-wso2-vscode/src/icons/bi-arrow-down.svg is 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.tsx
  • workspaces/ballerina/bi-diagram/src/components/Diagram.tsx
  • workspaces/ballerina/bi-diagram/src/components/DiagramContext.tsx
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/FocusFlowDiagram/index.tsx
  • 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/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.tsx
  • workspaces/ballerina/bi-diagram/src/components/Diagram.tsx
  • workspaces/ballerina/bi-diagram/src/components/DiagramContext.tsx
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/ChipExpressionEditor.tsx
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/LinkDialog.tsx
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/FocusFlowDiagram/index.tsx
  • workspaces/ballerina/bi-diagram/package.json
  • 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/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.tsx
  • workspaces/ballerina/bi-diagram/src/components/Diagram.tsx
  • workspaces/ballerina/bi-diagram/src/components/DiagramContext.tsx
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/ChipExpressionEditor.tsx
  • workspaces/ballerina/bi-diagram/src/components/editors/NPPromptEditor.tsx
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/HelperPaneNew/Components/EmptyItemsPlaceHolder.tsx
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/HelperPaneNew/Views/DocumentConfig.tsx
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RichTemplateMarkdownToolbar.tsx
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RawTemplateMarkdownToolbar.tsx
  • workspaces/ballerina/ballerina-side-panel/package.json
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/TemplateMode.tsx
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/LinkDialog.tsx
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/FocusFlowDiagram/utils.tsx
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/FocusFlowDiagram/index.tsx
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx
  • workspaces/ballerina/bi-diagram/package.json
  • 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} : 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.tsx
  • workspaces/ballerina/bi-diagram/src/components/Diagram.tsx
  • workspaces/ballerina/bi-diagram/src/components/DiagramContext.tsx
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/constants.ts
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/HelperPaneNew/Components/EmptyItemsPlaceHolder.tsx
  • workspaces/ballerina/ballerina-side-panel/package.json
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/FocusFlowDiagram/index.tsx
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/chipStyles.ts
  • workspaces/ballerina/bi-diagram/package.json
  • 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/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.tsx
  • workspaces/ballerina/bi-diagram/src/components/DiagramContext.tsx
  • workspaces/ballerina/ballerina-side-panel/package.json
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/LinkDialog.tsx
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/FocusFlowDiagram/index.tsx
  • 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/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.tsx
  • workspaces/ballerina/bi-diagram/src/components/Diagram.tsx
  • workspaces/ballerina/bi-diagram/src/components/DiagramContext.tsx
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/FocusFlowDiagram/index.tsx
  • 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/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.tsx
  • workspaces/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.tsx
  • workspaces/ballerina/bi-diagram/src/components/DiagramContext.tsx
  • workspaces/ballerina/bi-diagram/src/components/editors/NPPromptEditor.tsx
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/HelperPaneNew/Components/EmptyItemsPlaceHolder.tsx
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/TemplateMode.tsx
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/LinkDialog.tsx
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/FocusFlowDiagram/index.tsx
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/index.ts
  • 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/**/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.tsx
  • 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/bi-diagram/src/index.tsx
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/FocusFlowDiagram/index.tsx
  • 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/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.tsx
  • 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/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.tsx
  • 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/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.tsx
  • workspaces/ballerina/bi-diagram/src/components/DiagramContext.tsx
  • 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 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.tsx
  • workspaces/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.tsx
  • workspaces/ballerina/bi-diagram/src/components/DiagramContext.tsx
  • workspaces/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.tsx
  • workspaces/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.tsx
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/TemplateMode.tsx
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionEditor.tsx
  • workspaces/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.tsx
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/ChipExpressionEditor.tsx
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/CodeUtils.ts
  • workspaces/ballerina/bi-diagram/src/components/editors/NPPromptEditor.tsx
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/HelperPaneToggleButton.tsx
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/HelperPaneNew/Views/DocumentConfig.tsx
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RichTemplateMarkdownToolbar.tsx
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RawTemplateMarkdownToolbar.tsx
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/chipPlugin.ts
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/TemplateMode.tsx
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/LinkDialog.tsx
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionEditor.tsx
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/ExpandedEditor.tsx
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/FocusFlowDiagram/index.tsx
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/index.ts
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/markdownCommands.ts
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/chipStyles.ts
  • 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/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.tsx
  • workspaces/ballerina/ballerina-side-panel/package.json
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/TemplateMode.tsx
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/LinkDialog.tsx
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/chipStyles.ts
  • workspaces/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.tsx
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/HelperPaneNew/Views/DocumentConfig.tsx
  • workspaces/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.tsx
  • 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/package.json
  • 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/**/*.{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
  • workspaces/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.tsx
  • workspaces/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)

@dan-niles dan-niles force-pushed the prompt-editor-simplified-mode branch from ff20805 to 766e30f Compare November 30, 2025 03:56
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

♻️ Duplicate comments (1)
workspaces/ballerina/bi-diagram/src/components/editors/NPPromptEditor.tsx (1)

173-203: Stale closure issue persists.

The dependency array for fetchDiagnostics still doesn't include props.node, which createProperty references. This was flagged in a previous review.

🧹 Nitpick comments (17)
workspaces/ballerina/bi-diagram/src/components/editors/NPPromptEditor.tsx (1)

313-340: formContextValue recreated on every render.

expressionEditor is created inline (lines 288-311) without memoization, so including it in the dependency array means formContextValue will be recreated on every render, negating the useMemo benefit.

Consider memoizing expressionEditor separately or extracting stable dependencies.

workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/types.ts (1)

107-115: Consider typing clickedChipNode more specifically.

Using any for clickedChipNode works but loses type safety. If this always holds a ProseMirror Node, consider typing it as Node | undefined (from prosemirror-model). However, if the type varies based on context, any is 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 handleChange function simply forwards both arguments without transformation. You can pass onChange directly 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 to ExpressionField (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 helperPaneToggle state 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 handleChange function just passes arguments through. Consider passing onChange directly 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 stale helperPaneState.isOpen.

This handler captures helperPaneState in the closure when the keymap plugin is created (empty-deps useEffect). The condition helperPaneState.isOpen may not reflect current state.

However, since setHelperPaneState uses a functional updater that returns unchanged state when not open, this is partially mitigated. The handler will still always call setHelperPaneState but 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 access removeMark and addMark. 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 any casts while maintaining type safety.

workspaces/ballerina/ballerina-visualizer/src/views/BI/FocusFlowDiagram/index.tsx (2)

604-642: Unused parameter isAssignIdentifier in createHelperPane.

The isAssignIdentifier parameter is received but never passed to createPromptHelperPane. 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 memoizing handleGetExpressionTokens to stabilize reference.

handleGetExpressionTokens is included in the memoizedDiagramProps dependency array but isn't wrapped in useCallback. This causes a new function reference on every render, potentially triggering unnecessary recalculations of memoizedDiagramProps.

-    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.stringify to 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

📥 Commits

Reviewing files that changed from the base of the PR and between 1d4fa5d and 766e30f.

⛔ Files ignored due to path filters (2)
  • common/config/rush/pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
  • workspaces/common-libs/font-wso2-vscode/src/icons/bi-arrow-down.svg is 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.ts
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/types.ts
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/CodeUtils.ts
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/TemplateMode.tsx
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/HelperPaneNew/Views/DocumentConfig.tsx
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/HelperPaneToggleButton.tsx
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/ChipExpressionEditor.tsx
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/HelperPaneNew/utils/utils.ts
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionEditor.tsx
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/ExpandedEditor.tsx
  • workspaces/ballerina/bi-diagram/src/components/editors/NPPromptEditor.tsx
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RichTemplateMarkdownToolbar.tsx
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/PromptMode.tsx
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RawTemplateMarkdownToolbar.tsx
  • workspaces/ballerina/bi-diagram/src/components/nodes/PromptNode/PromptNodeWidget.tsx
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/markdownCommands.ts
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/chipPlugin.ts
  • workspaces/ballerina/bi-diagram/src/components/DiagramContext.tsx
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx
  • 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/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.ts
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/TemplateMode.tsx
  • workspaces/ballerina/bi-diagram/src/components/editors/NPPromptEditor.tsx
  • workspaces/ballerina/bi-diagram/src/components/nodes/PromptNode/PromptNodeWidget.tsx
  • workspaces/ballerina/bi-diagram/src/components/DiagramContext.tsx
  • 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} : 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.ts
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/types.ts
  • workspaces/ballerina/ballerina-side-panel/package.json
  • workspaces/ballerina/bi-diagram/src/components/editors/NPPromptEditor.tsx
  • workspaces/ballerina/bi-diagram/src/components/Diagram.tsx
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/constants.ts
  • workspaces/ballerina/bi-diagram/src/components/nodes/PromptNode/PromptNodeWidget.tsx
  • workspaces/ballerina/bi-diagram/src/components/DiagramContext.tsx
  • 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/**/*.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.tsx
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/HelperPaneNew/Views/DocumentConfig.tsx
  • workspaces/ballerina/ballerina-side-panel/package.json
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/ChipExpressionEditor.tsx
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/ExpandedEditor.tsx
  • workspaces/ballerina/bi-diagram/src/components/editors/NPPromptEditor.tsx
  • workspaces/ballerina/bi-diagram/src/components/Diagram.tsx
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/PromptMode.tsx
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/controls/RawTemplateMarkdownToolbar.tsx
  • workspaces/ballerina/bi-diagram/src/components/nodes/PromptNode/PromptNodeWidget.tsx
  • workspaces/ballerina/bi-diagram/src/components/DiagramContext.tsx
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/FocusFlowDiagram/index.tsx
  • workspaces/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.tsx
  • workspaces/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.tsx
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/ChipExpressionEditor/components/ChipExpressionEditor.tsx
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionEditor.tsx
  • workspaces/ballerina/bi-diagram/src/components/editors/NPPromptEditor.tsx
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/modes/PromptMode.tsx
  • workspaces/ballerina/bi-diagram/src/components/nodes/PromptNode/PromptNodeWidget.tsx
  • workspaces/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.json
  • workspaces/ballerina/bi-diagram/src/components/editors/NPPromptEditor.tsx
  • workspaces/ballerina/bi-diagram/src/components/Diagram.tsx
  • workspaces/ballerina/bi-diagram/src/components/DiagramContext.tsx
  • workspaces/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.tsx
  • workspaces/ballerina/bi-diagram/src/components/Diagram.tsx
  • workspaces/ballerina/bi-diagram/src/components/nodes/PromptNode/PromptNodeWidget.tsx
  • workspaces/ballerina/bi-diagram/src/components/DiagramContext.tsx
  • workspaces/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.ts
  • 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/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
  • workspaces/ballerina/bi-diagram/src/components/Diagram.tsx
  • workspaces/ballerina/bi-diagram/src/components/DiagramContext.tsx
  • 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 : Debounce diagram repaints to avoid excessive re-renders when state changes occur

Applied to files:

  • workspaces/ballerina/bi-diagram/src/components/editors/NPPromptEditor.tsx
  • workspaces/ballerina/bi-diagram/src/components/Diagram.tsx
  • workspaces/ballerina/bi-diagram/src/components/DiagramContext.tsx
  • workspaces/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.tsx
  • workspaces/ballerina/bi-diagram/src/components/Diagram.tsx
  • workspaces/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.tsx
  • workspaces/ballerina/bi-diagram/src/components/DiagramContext.tsx
  • 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 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.tsx
  • workspaces/ballerina/bi-diagram/src/components/DiagramContext.tsx
  • 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/bi-diagram/src/components/Diagram.tsx
  • workspaces/ballerina/bi-diagram/src/components/DiagramContext.tsx
  • workspaces/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.tsx
  • 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/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)

@dan-niles dan-niles force-pushed the prompt-editor-simplified-mode branch from 766e30f to 867b995 Compare November 30, 2025 04:08
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (2)
workspaces/ballerina/bi-diagram/src/components/editors/NPPromptEditor.tsx (2)

164-203: Include props.node in fetchDiagnostics dependencies to avoid stale diagnostics.

createProperty (Line 165) reads props.node.properties["prompt"], and fetchDiagnostics closes over createProperty, but the useCallback dependency array omits anything related to props.node. If the same NPPromptEditor instance 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 a useEffect cleanup to avoid pending debounced calls firing after unmount.


276-285: Fix stale props.node closure in chipExtractArgsFromFunction.

chipExtractArgsFromFunction also uses createProperty (which reads props.node) but its useMemo only depends on extractArgsFromFunction. If props.node changes 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.TEMPLATE appears 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 onChange handler passed to ExpandedEditor (lines 779-816) is nearly identical to the one in ExpressionField (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 sanitize updatedValue for onChange, but you pass the raw updatedValue (with backticks) into retrieveCompletions, while the inline editor path routes completions through retrieveCompletions(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 property and the value argument to retrieveCompletions on sanitized, and adjusting the offset accordingly. Please verify against the expected retrieveCompletions API before changing this.


144-146: Verify that exprRef is actually wired to the underlying editor.

You create exprRef (Line 144) and pass it into getHelperPane via wrappedGetHelperPane (Lines 260–263), but there’s no place where exprRef is attached to ChipExpressionEditorComponent or ExpandedEditor. Unless those components internally populate this ref via context, exprRef.current will remain null, and any helper-pane logic that relies on the editor ref (for positioning, scrolling, etc.) won’t work as intended.

If ChipExpressionEditorComponent is a forwardRef<FormExpressionEditorRef, …>, you likely want to pass it as:

<ChipExpressionEditorComponent
    ref={exprRef}
    
/>

Otherwise, consider removing exprRef from the getHelperPane call to avoid a misleading, always-null ref.

Also applies to: 252-274


121-132: Unused onFocus prop — either plumb it through or drop it from the API.

NPPromptEditorProps exposes onFocus (Lines 63, 121), but it’s never used or forwarded to ChipExpressionEditorComponent or ExpandedEditor. This makes the prop misleading for consumers expecting a focus callback.

Either:

  • Wire onFocus into the underlying editor(s) if they support it, or
  • Remove onFocus from NPPromptEditorProps until it’s needed.

Also applies to: 351-408


128-131: Confirm intended default for inputMode vs. hard-coded PROMPT mode.

The component defaults inputMode = InputMode.EXP (Line 128) but uses mode={InputMode.PROMPT} when rendering ExpandedEditor (Line 399) while also passing inputMode={inputMode} (Line 407). For a prompt-specific editor, it might be more intuitive to default inputMode to InputMode.PROMPT, or to rely consistently on a single prop if ExpandedEditor doesn’t need both.

Please double-check the ExpandedEditor API 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

📥 Commits

Reviewing files that changed from the base of the PR and between 766e30f and 867b995.

📒 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.ts
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/ExpandedEditor.tsx
  • workspaces/ballerina/bi-diagram/src/components/editors/NPPromptEditor.tsx
  • workspaces/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.ts
  • 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/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.tsx
  • workspaces/ballerina/bi-diagram/src/components/editors/NPPromptEditor.tsx
  • workspaces/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 const assertion on EXPANDABLE_MODES combined with the indexed access type typeof EXPANDABLE_MODES[number] is an idiomatic TypeScript pattern that ensures EditorMode stays 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. The inputMode prop 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 the EditorMode type definition. This prevents typos and makes the mapping easier to maintain.


229-252: Inconsistent inputMode prop distribution across modes.

inputMode is passed to PromptMode (line 226) and TemplateMode (line 251) but not to ExpressionMode (lines 229-239). Since EditorModeExpressionProps in types.ts includes inputMode?: InputMode, this inconsistency may cause issues if ExpressionMode needs mode awareness in the future.

Please verify whether ExpressionMode requires the inputMode prop. 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 modeProps based 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.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx (1)

364-414: Escape key handler in keymap still reads stale helperPaneState from closure

Inside the keymap plugin, the "Escape" binding closes the helper pane only if helperPaneState.isOpen from 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 return false. The global useHelperPaneClickOutside Escape 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.PROMPT hardcodes 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.TEMPLATE appears 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 avoiding any casts in apply

The 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 typed Transaction API 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 shape

The chip click → helper-pane → chip replacement flow is nicely handled, including the processFunctionWithArguments hook 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 generic helperPaneState. That will make it clearer which parts of state belong to shared helper behavior vs. chip-specific behavior and avoid type drift as HelperPaneState evolves.

-        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 HelperPaneState has 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 brittle

The 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 of prosemirror-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-history in this repo exports a historyKey/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 gating

The useEffect watching [value] calls fetchAndUpdateTokens(viewRef.current), but fetchAndUpdateTokens immediately returns unless pendingTokenFetchRef.current is true. Since you intentionally only set that flag on user-driven edits (not on external value changes), 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 pendingTokenFetchRef so future readers don’t assume external value updates re-tokenize.

Based on learnings, token fetching on external value changes is intentionally disabled.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 867b995 and 668dde1.

⛔ Files ignored due to path filters (1)
  • common/config/rush/pnpm-lock.yaml is 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.tsx
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/EditorFactory.tsx
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionEditor.tsx
  • workspaces/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.tsx
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpandedEditor/ExpandedEditor.tsx
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/EditorFactory.tsx
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionEditor.tsx
  • workspaces/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.tsx
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionEditor.tsx
  • workspaces/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.tsx
  • workspaces/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.ts
  • 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/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: Wiring fieldKey into default mode calculation looks correct

The new optional fieldKey prop is typed consistently, passed through to getDefaultExpressionMode, and correctly added to the useMemo dependency array. Existing isRecordTypeField behavior 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: Both markdown-it and react-markdown serve 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 the InputMode enum (InputMode.TEXT, InputMode.PROMPT, etc.) provides compile-time checks and better IDE support.


220-256: inputMode prop correctly threaded to mode components.

The inputMode prop 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 inputMode prop is correctly threaded through to ExpandedEditor, and the conditional rendering ensures toEditorMode returns 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 usage

The EditorContainer styling (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 correct

Using a shared chipSchema with a custom MarkdownParser and extending defaultMarkdownSerializer.nodes with a chip handler that emits node.attrs.text keeps markdown round-tripping straightforward. This should serialize back to the original text cleanly as long as chip nodes always carry the raw source in attrs.text.


179-227: Helper pane integration via useHelperPane is consistent with ChipExpressionEditor

The way you plug useHelperPane into the rich-text editor (fixed manual toggle behavior, keyboard toggle based on cursor coordinates, and forwarding onHelperPaneStateChange) cleanly reuses the shared helper-pane abstraction from ChipExpressionEditor. This keeps positioning logic centralized and reduces duplication. Looks good.


302-330: Token fetch gate via pendingTokenFetchRef is sound; logging is the only side effect on failure

The fetchAndUpdateTokens helper correctly short-circuits when rpcManager/fileName are missing or when pendingTokenFetchRef is false, and it resets the flag immediately before making the async call. The use of plainText + wrappedForAPI and updateChipTokens matches 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 external value changes aren’t expected to rehydrate the doc

The useEffect with an empty dependency array creates the ProseMirror state/view once and never re-parses value on subsequent prop updates. This is a valid pattern for a “locally controlled” editor where the parent doesn’t programmatically change value while the component is mounted (other than through onChange callbacks).

If there are flows (e.g., prompt reset, mode switch) where the parent might push a new value into an already-mounted RichTextTemplateEditor, you’ll need to either:

  • Recreate the editor state when value (or sanitizedExpression) 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 robust

Wiring useHelperPaneClickOutside with the editor, helper pane, toggle button, and toolbar refs plus a dedicated onEscapeKey that 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 pane

Conditionally rendering HelperPane inside EditorContainer with top/left props and forwarding value/onChange keeps the overlay logic simple and self-contained. This matches the rest of the helper infrastructure and should integrate cleanly with external getHelperPane providers.

@dan-niles dan-niles force-pushed the prompt-editor-simplified-mode branch from 595fe69 to 02131e3 Compare December 1, 2025 05:35
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
workspaces/ballerina/ballerina-side-panel/package.json (1)

27-28: Optional: Normalize Emotion package semver ranges for consistency.

Emotion packages use ^ (caret) while most other dependencies use ~ (tilde). Unlike CodeMirror, Emotion does not rely on runtime identity, so this is not a blocker. However, for consistency across the manifest, consider aligning them:

-        "@emotion/react": "^11.14.0",
-        "@emotion/styled": "^11.14.0",
+        "@emotion/react": "~11.14.0",
+        "@emotion/styled": "~11.14.0",
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 668dde1 and 02131e3.

⛔ Files ignored due to path filters (1)
  • common/config/rush/pnpm-lock.yaml is 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/state class 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:

  1. The NodeView mounting CodeMirror inside ProseMirror properly syncs text changes and selection state.
  2. History/undo-redo coordination does not create duplicate stacks or inconsistent state.
  3. 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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Introduce a Simplified Mode for Editing Prompts in the Expanded Editor

2 participants