Skip to content

Comments

[BI Data Mapper] Improve completion support - frontend changes for clause editor form#956

Merged
madushajg merged 7 commits intowso2:mainfrom
KCSAbeywickrama:bi-dm-completion-impr-clause
Nov 21, 2025
Merged

[BI Data Mapper] Improve completion support - frontend changes for clause editor form#956
madushajg merged 7 commits intowso2:mainfrom
KCSAbeywickrama:bi-dm-completion-impr-clause

Conversation

@KCSAbeywickrama
Copy link
Contributor

@KCSAbeywickrama KCSAbeywickrama commented Nov 18, 2025

Purpose

Resolve wso2/product-ballerina-integrator#1793

Summary by CodeRabbit

Release Notes

  • New Features
    • Enhanced clause editing with dynamic positional tracking and loading indicators while fetching position data.
    • Added specialized editor component for join clause expressions with improved expression context handling.
    • Improved field property retrieval with streamlined field-based requests.
    • Dynamic line range calculation for better alignment with source code during editing operations.

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

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR improves completion support for the Data Mapper's clause editor form, introducing support for join clauses and enhancing the frontend architecture for query expression handling.

  • Adds support for JOIN clause type in query expressions with dedicated form fields (lhsExpression, rhsExpression, isOuter)
  • Introduces ClauseConnectorNode component for visualizing clause connections in the diagram
  • Refactors View interface to support multiple source fields (sourceFields array) instead of single sourceField
  • Adds new RPC methods getFieldProperty and getClausePosition for improved clause positioning and property retrieval

Reviewed Changes

Copilot reviewed 53 out of 53 changed files in this pull request and generated 11 comments.

Show a summary per file
File Description
workspaces/ballerina/data-mapper/src/visitors/IntermediateNodeInitVisitor.ts Adds ClauseConnectorNode initialization in visitor pattern
workspaces/ballerina/data-mapper/src/visitors/BaseVisitor.ts Extends visitor interface with query visit methods
workspaces/ballerina/data-mapper/src/utils/model-utils.ts Implements query traversal logic in model utilities
workspaces/ballerina/data-mapper/src/utils/DataMapperContext/DataMapperContext.ts Reorders constructor parameters for better organization
workspaces/ballerina/data-mapper/src/store/store.ts Adds clauseToAdd state for managing join clause creation
workspaces/ballerina/data-mapper/src/index.tsx Adds getClausePosition prop to DataMapperEditorProps
workspaces/ballerina/data-mapper/src/components/Diagram/utils/port-utils.ts Extends getInputPort to support SubMappingNode
workspaces/ballerina/data-mapper/src/components/Diagram/utils/node-utils.ts Refactors findInputNode to use focusInputRootMap for better input resolution
workspaces/ballerina/data-mapper/src/components/Diagram/utils/modification-utils.ts Adds mapWithJoin function and updates expandArrayFn calls
workspaces/ballerina/data-mapper/src/components/Diagram/utils/focus-positioning-utils.ts Adds ClauseConnectorNode type to focus positioning logic
workspaces/ballerina/data-mapper/src/components/Diagram/utils/common-utils.ts Refactors expandArrayFn to accept multiple input IDs and adds ArrayJoin mapping type
workspaces/ballerina/data-mapper/src/components/Diagram/hooks/useDiagramModel.ts Adds query inputs/outputs to dependency array for model regeneration
workspaces/ballerina/data-mapper/src/components/Diagram/Port/model/InputOutputPortModel.ts Adds ArrayJoin mapping type handling in link creation
workspaces/ballerina/data-mapper/src/components/Diagram/Node/index.ts Exports ClauseConnector components
workspaces/ballerina/data-mapper/src/components/Diagram/Node/commons/DataMapperNode.ts Simplifies array member field resolution
workspaces/ballerina/data-mapper/src/components/Diagram/Node/QueryOutput/QueryOutputNode.ts Removes unused query input/output link creation code
workspaces/ballerina/data-mapper/src/components/Diagram/Node/QueryExprConnector/QueryExprConnectorNodeWidget.tsx Updates expandArrayFn call with array parameter
workspaces/ballerina/data-mapper/src/components/Diagram/Node/Input/InputNode.ts Changes to use sourceFields array and removes focusedMemberId logic
workspaces/ballerina/data-mapper/src/components/Diagram/Node/ClauseConnector/index.ts New file exporting ClauseConnector components
workspaces/ballerina/data-mapper/src/components/Diagram/Node/ClauseConnector/ClauseConnectorNodeWidget.tsx New component for rendering clause connector nodes in diagram
workspaces/ballerina/data-mapper/src/components/Diagram/Node/ClauseConnector/ClauseConnectorNodeFactory.tsx Factory for creating ClauseConnectorNode instances
workspaces/ballerina/data-mapper/src/components/Diagram/Node/ClauseConnector/ClauseConnectorNode.ts Core logic for clause connector nodes with port and link management
workspaces/ballerina/data-mapper/src/components/Diagram/LinkState/CreateLinkState.ts Updates link state to support ClauseConnectorNode
workspaces/ballerina/data-mapper/src/components/Diagram/Link/DataMapperLink/DataMapperLink.ts Adds ArrayJoin mapping type enum
workspaces/ballerina/data-mapper/src/components/Diagram/Label/QueryExprLabelWidget.tsx Removed file - query expression label widget deleted
workspaces/ballerina/data-mapper/src/components/Diagram/Label/ExpressionLabelModel.ts Removes unused isQuery property
workspaces/ballerina/data-mapper/src/components/Diagram/Label/ExpressionLabelFactory.tsx Updates label widget generation to handle ArrayJoin
workspaces/ballerina/data-mapper/src/components/Diagram/Diagram.tsx Registers ClauseConnectorNodeFactory and updates node positioning
workspaces/ballerina/data-mapper/src/components/Diagram/Actions/utils.ts Adds ClauseConnectorNode to intermediate nodes list
workspaces/ballerina/data-mapper/src/components/Diagram/Actions/IONodesScrollCanvasAction.ts Includes ClauseConnectorNode in scroll action logic
workspaces/ballerina/data-mapper/src/components/DataMapper/Views/DataMapperView.ts Changes sourceField to sourceFields array
workspaces/ballerina/data-mapper/src/components/DataMapper/SidePanel/QueryClauses/ClausesPanel.tsx Adds getClausePosition prop and clauseToAdd state management
workspaces/ballerina/data-mapper/src/components/DataMapper/SidePanel/QueryClauses/ClauseItem.tsx Passes getClausePosition to ClauseEditor components
workspaces/ballerina/data-mapper/src/components/DataMapper/SidePanel/QueryClauses/ClauseEditor.tsx Implements JOIN clause support with new form fields and position fetching
workspaces/ballerina/data-mapper/src/components/DataMapper/DataMapperEditor.tsx Passes getClausePosition to ClausesPanel
workspaces/ballerina/ballerina-visualizer/src/views/DataMapper/DataMapperView.tsx Implements getClausePosition and updates completion API calls
workspaces/ballerina/ballerina-visualizer/src/views/BI/Forms/FormGeneratorNew/index.tsx Adds isDataMapperEditor flag to route completions correctly
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionEditor.tsx Adds DataMapperJoinClauseRhsEditor for join condition completions
workspaces/ballerina/ballerina-side-panel/src/components/editors/EditorFactory.tsx Registers DM_JOIN_CLAUSE_RHS_EXPRESSION field type
workspaces/ballerina/ballerina-rpc-client/src/rpc-clients/data-mapper/rpc-client.ts Adds getFieldProperty and getClausePosition RPC methods
workspaces/ballerina/ballerina-rpc-client/src/rpc-clients/bi-diagram/rpc-client.ts Adds getDataMapperCompletions RPC method
workspaces/ballerina/ballerina-extension/src/rpc-managers/data-mapper/utils.ts Implements focusInputRootMap tracking for input field resolution
workspaces/ballerina/ballerina-extension/src/rpc-managers/data-mapper/rpc-manager.ts Implements getFieldProperty and getClausePosition handlers
workspaces/ballerina/ballerina-extension/src/rpc-managers/data-mapper/rpc-handler.ts Registers new RPC handlers
workspaces/ballerina/ballerina-extension/src/rpc-managers/bi-diagram/rpc-manager.ts Implements getDataMapperCompletions method
workspaces/ballerina/ballerina-extension/src/rpc-managers/bi-diagram/rpc-handler.ts Registers getDataMapperCompletions handler
workspaces/ballerina/ballerina-extension/src/core/extended-language-client.ts Adds language server API methods for clause position and field properties
workspaces/ballerina/ballerina-core/src/rpc-types/data-mapper/rpc-type.ts Defines RPC request types for new methods
workspaces/ballerina/ballerina-core/src/rpc-types/data-mapper/index.ts Exports new API interfaces
workspaces/ballerina/ballerina-core/src/rpc-types/bi-diagram/rpc-type.ts Defines getDataMapperCompletions RPC type
workspaces/ballerina/ballerina-core/src/rpc-types/bi-diagram/index.ts Exports getDataMapperCompletions in API interface
workspaces/ballerina/ballerina-core/src/interfaces/extended-lang-client.ts Adds PropertyRequest, FieldPropertyRequest, ClausePositionRequest/Response interfaces
workspaces/ballerina/ballerina-core/src/interfaces/data-mapper.ts Adds JOIN clause type and new properties for join clauses

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 21, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

The PR introduces improved completion support for clause editors by adding RPC endpoints to fetch field properties and clause positions dynamically. New request/response types (FieldPropertyRequest, ClausePositionRequest, ClausePositionResponse) replace static configurations, enabling context-aware completion suggestions through a new DataMapperJoinClauseRhsEditor component.

Changes

Cohort / File(s) Change Summary
Core Interface Definitions
workspaces/ballerina/ballerina-core/src/interfaces/extended-lang-client.ts
Removed propertyKey field from PropertyRequest. Added FieldPropertyRequest extending PropertyRequest with fieldId. Introduced ClausePositionRequest and ClausePositionResponse for fetching clause line positions.
RPC Type Layer
workspaces/ballerina/ballerina-core/src/rpc-types/data-mapper/index.ts, workspaces/ballerina/ballerina-core/src/rpc-types/data-mapper/rpc-type.ts
Added two new RPC methods: getFieldProperty(FieldPropertyRequest) and getClausePosition(ClausePositionRequest) with corresponding response types. Updated imports to include new request/response types.
Extension Client Layer
workspaces/ballerina/ballerina-extension/src/core/extended-language-client.ts
Extended ExtendedLangClient with public methods getFieldProperty() and getClausePosition(). Added enum keys DATA_MAPPER_FIELD_PROPERTY and DATA_MAPPER_CLAUSE_POSITION to EXTENDED_APIS. Updated public exports for new request/response types.
RPC Manager/Handler Layer
workspaces/ballerina/ballerina-extension/src/rpc-managers/data-mapper/rpc-handler.ts, workspaces/ballerina/ballerina-extension/src/rpc-managers/data-mapper/rpc-manager.ts
Registered new RPC endpoints in handler and wired them in manager. Added async methods getFieldProperty() and getClausePosition() delegating to language client. Updated imports for new request/response types.
RPC Client
workspaces/ballerina/ballerina-rpc-client/src/rpc-clients/data-mapper/rpc-client.ts
Added getFieldProperty() and getClausePosition() methods. Removed AllDataMapperSourceRequest and added new request/response imports.
Expression Editor Components
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionEditor.tsx, workspaces/ballerina/ballerina-side-panel/src/components/editors/EditorFactory.tsx
Created DataMapperJoinClauseRhsEditor component wrapping ExpressionEditor with custom completion handling context. Updated EditorFactory to render new editor for DM_JOIN_CLAUSE_RHS_EXPRESSION field type.
Data Mapper Visualizer
workspaces/ballerina/ballerina-visualizer/src/views/DataMapper/DataMapperView.tsx
Added getClausePosition() helper to fetch line positions via RPC. Replaced getProperty() calls with getFieldProperty() and removed propertyKey parameter. Threaded getClausePosition and isDataMapperEditor props through component hierarchy.
Clause Editor Components
workspaces/ballerina/data-mapper/src/components/DataMapper/DataMapperEditor.tsx, workspaces/ballerina/data-mapper/src/components/DataMapper/SidePanel/QueryClauses/ClauseEditor.tsx, workspaces/ballerina/data-mapper/src/components/DataMapper/SidePanel/QueryClauses/ClauseItem.tsx, workspaces/ballerina/data-mapper/src/components/DataMapper/SidePanel/QueryClauses/ClausesPanel.tsx
Introduced getClausePosition prop throughout clause component hierarchy. ClauseEditor now fetches dynamic line positions via React Query and displays loading state. Updated RHS expression field type to DM_JOIN_CLAUSE_RHS_EXPRESSION. Added targetField and index props for position lookup.
Data Mapper Index/Props
workspaces/ballerina/data-mapper/src/index.tsx
Added getClausePosition prop to DataMapperEditorProps. Updated imports to include Property and LinePosition types.

Sequence Diagram

sequenceDiagram
    participant UI as Clause Editor UI
    participant React as React/Query
    participant RPC as RPC Manager
    participant Lang as Language Client
    
    UI->>React: Query getClausePosition(targetField, index)
    Note over UI: Show ProgressRing
    React->>RPC: getClausePosition(ClausePositionRequest)
    RPC->>Lang: getClausePosition(params)
    Lang-->>RPC: ClausePositionResponse {position: LinePosition}
    RPC-->>React: LinePosition
    React-->>UI: Cache result
    Note over UI: Render form with startLine/endLine<br/>Update ExpressionEditor context
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • ClauseEditor.tsx: Async position fetching logic with React Query and conditional ProgressRing rendering requires verification of query key uniqueness and loading state handling.
  • Property access pattern change: Shift from getProperty(propertyKey) to getFieldProperty(fieldId) across multiple call sites needs validation that all usages are correct.
  • Prop threading: Complex prop drilling of getClausePosition through five component levels—verify all intermediate components pass props correctly.
  • RPC layer consistency: Ensure new RPC endpoints follow existing patterns for error handling and type safety across all layers (handlers, managers, client).

Possibly related PRs

  • PR #969: Overlapping clause feature modifications including ClauseEditor, ClausesPanel, and data-mapper RPC wiring; likely addressing related clause position/completion concerns.
  • PR #906: Expression editor refactoring (CodeMirror/expression handling) that may interact with the new DataMapperJoinClauseRhsEditor implementation.
  • PR #898: Related data-mapper completion flow extensions and ExtendedLangClient RPC wiring for visualizer hooks.

Suggested reviewers

  • hevayo
  • gigara
  • kanushka

Poem

🐰 With whiskers twitching, I hop with glee,
Clause positions fetched, completions run free!
Dynamic line ranges, no static bounds—
Context-aware suggestions make perfect sounds! 🎉

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings, 1 inconclusive)
Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description is incomplete. It only includes the 'Purpose' section citing the linked issue, but is missing required sections like Goals, Approach, UI Component Development, Release notes, and others outlined in the template. Complete the PR description by filling in all required sections from the template, especially Goals, Approach, Release notes, and Documentation sections.
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.
Out of Scope Changes check ❓ Inconclusive One change appears out of scope: the removal of AllDataMapperSourceRequest from rpc-client imports is unexplained and not directly related to improving completion support for the clause editor form. Clarify whether the removal of AllDataMapperSourceRequest from ballerina-rpc-client is intentional or if it should be retained for backward compatibility.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The PR title accurately describes the main change: frontend modifications for clause editor form to improve completion support in the BI Data Mapper.
Linked Issues check ✅ Passed The PR implements all required changes to address issue #1793: added getClausePosition RPC endpoints, updated Expression Editor for clause context, integrated ClauseEditor with position fetching, and wired the capability through the component hierarchy.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 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.

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

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-extension/src/rpc-managers/data-mapper/rpc-manager.ts (1)

20-52: Avoid async Promise executors in new RPC helpers (Biome noAsyncPromiseExecutor)

Both new methods wrap an async executor inside new Promise, which Biome flags and which is unnecessary given langClient() already returns Promises:

async getFieldProperty(params: FieldPropertyRequest): Promise<PropertyResponse> {
    return new Promise(async (resolve) => {
        const property = await StateMachine
            .langClient()
            .getFieldProperty(params) as PropertyResponse;

        resolve(property);
    });
}

async getClausePosition(params: ClausePositionRequest): Promise<ClausePositionResponse> {
    return new Promise(async (resolve) => {
        const position: any = await StateMachine
            .langClient()
            .getClausePosition(params);

        resolve(position);
    });
}

You can simplify and satisfy the lint by returning the underlying Promise directly:

-    async getFieldProperty(params: FieldPropertyRequest): Promise<PropertyResponse> {
-        return new Promise(async (resolve) => {
-            const property = await StateMachine
-                .langClient()
-                .getFieldProperty(params) as PropertyResponse;
-
-            resolve(property);
-        });
-    }
-
-    async getClausePosition(params: ClausePositionRequest): Promise<ClausePositionResponse> {
-        return new Promise(async (resolve) => {
-            const position: any = await StateMachine
-                .langClient()
-                .getClausePosition(params);
-
-            resolve(position);
-        });
-    }
+    async getFieldProperty(params: FieldPropertyRequest): Promise<PropertyResponse> {
+        return StateMachine
+            .langClient()
+            .getFieldProperty(params) as Promise<PropertyResponse>;
+    }
+
+    async getClausePosition(params: ClausePositionRequest): Promise<ClausePositionResponse> {
+        return StateMachine
+            .langClient()
+            .getClausePosition(params) as Promise<ClausePositionResponse>;
+    }

This removes the lint error and keeps behavior unchanged.

Also applies to: 239-257

♻️ Duplicate comments (1)
workspaces/ballerina/data-mapper/src/index.tsx (1)

27-27: Verify whether Property import is needed.

A past review flagged Property as an unused import. Although LinePosition is now actively used in the new getClausePosition prop signature (line 71), Property does not appear to be referenced anywhere in this file. Consider removing it if it's not required for type exports or re-exports.

🧹 Nitpick comments (1)
workspaces/ballerina/data-mapper/src/components/DataMapper/SidePanel/QueryClauses/ClauseItem.tsx (1)

40-55: Index semantics for getClausePosition vs onAdd when inserting after a clause

For edits you pass index consistently to both ClauseEditor and onEdit, but for inserts-after you pass index + 1 to ClauseEditor (for getClausePosition) while onAdd receives the original index. This assumes the clause-position service interprets the index used for position lookup as the insertion index, not the source clause index.

If that’s the intended contract with getClausePosition, this wiring is fine; otherwise, you may want to align the index you use for position lookup with the index you pass into addClauses for new clauses.

Also applies to: 107-129

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c7443cd and 7650aa7.

📒 Files selected for processing (15)
  • workspaces/ballerina/ballerina-core/src/interfaces/extended-lang-client.ts (1 hunks)
  • workspaces/ballerina/ballerina-core/src/rpc-types/data-mapper/index.ts (2 hunks)
  • workspaces/ballerina/ballerina-core/src/rpc-types/data-mapper/rpc-type.ts (2 hunks)
  • workspaces/ballerina/ballerina-extension/src/core/extended-language-client.ts (3 hunks)
  • workspaces/ballerina/ballerina-extension/src/rpc-managers/data-mapper/rpc-handler.ts (4 hunks)
  • workspaces/ballerina/ballerina-extension/src/rpc-managers/data-mapper/rpc-manager.ts (4 hunks)
  • workspaces/ballerina/ballerina-rpc-client/src/rpc-clients/data-mapper/rpc-client.ts (4 hunks)
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/EditorFactory.tsx (2 hunks)
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionEditor.tsx (2 hunks)
  • workspaces/ballerina/ballerina-visualizer/src/views/DataMapper/DataMapperView.tsx (5 hunks)
  • workspaces/ballerina/data-mapper/src/components/DataMapper/DataMapperEditor.tsx (2 hunks)
  • workspaces/ballerina/data-mapper/src/components/DataMapper/SidePanel/QueryClauses/ClauseEditor.tsx (4 hunks)
  • workspaces/ballerina/data-mapper/src/components/DataMapper/SidePanel/QueryClauses/ClauseItem.tsx (3 hunks)
  • workspaces/ballerina/data-mapper/src/components/DataMapper/SidePanel/QueryClauses/ClausesPanel.tsx (4 hunks)
  • workspaces/ballerina/data-mapper/src/index.tsx (2 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/data-mapper/src/index.tsx
  • workspaces/ballerina/data-mapper/src/components/DataMapper/SidePanel/QueryClauses/ClausesPanel.tsx
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionEditor.tsx
  • workspaces/ballerina/data-mapper/src/components/DataMapper/SidePanel/QueryClauses/ClauseEditor.tsx
  • workspaces/ballerina/ballerina-visualizer/src/views/DataMapper/DataMapperView.tsx
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/EditorFactory.tsx
  • workspaces/ballerina/data-mapper/src/components/DataMapper/SidePanel/QueryClauses/ClauseItem.tsx
  • workspaces/ballerina/data-mapper/src/components/DataMapper/DataMapperEditor.tsx
🧬 Code graph analysis (14)
workspaces/ballerina/ballerina-core/src/rpc-types/data-mapper/index.ts (1)
workspaces/ballerina/ballerina-core/src/interfaces/extended-lang-client.ts (4)
  • FieldPropertyRequest (480-482)
  • PropertyResponse (484-486)
  • ClausePositionRequest (488-493)
  • ClausePositionResponse (495-497)
workspaces/ballerina/data-mapper/src/components/DataMapper/SidePanel/QueryClauses/ClausesPanel.tsx (3)
workspaces/ballerina/ballerina-core/src/interfaces/data-mapper.ts (2)
  • IntermediateClause (216-219)
  • DMFormProps (249-258)
workspaces/ballerina/ballerina-extension/src/core/extended-language-client.ts (1)
  • getClausePosition (857-859)
workspaces/ballerina/ballerina-extension/src/rpc-managers/data-mapper/rpc-manager.ts (1)
  • getClausePosition (249-257)
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionEditor.tsx (2)
workspaces/ballerina/ballerina-side-panel/src/context/form.tsx (1)
  • useFormContext (70-70)
workspaces/ballerina/ballerina-core/src/interfaces/extended-lang-client.ts (1)
  • ExpressionProperty (1090-1090)
workspaces/ballerina/data-mapper/src/components/DataMapper/SidePanel/QueryClauses/ClauseEditor.tsx (3)
workspaces/ballerina/ballerina-core/src/interfaces/data-mapper.ts (2)
  • IntermediateClause (216-219)
  • DMFormProps (249-258)
workspaces/ballerina/ballerina-extension/src/core/extended-language-client.ts (1)
  • getClausePosition (857-859)
workspaces/ballerina/ballerina-extension/src/rpc-managers/data-mapper/rpc-manager.ts (1)
  • getClausePosition (249-257)
workspaces/ballerina/ballerina-core/src/interfaces/extended-lang-client.ts (1)
workspaces/ballerina/ballerina-core/src/interfaces/bi.ts (2)
  • Property (124-144)
  • CodeData (170-190)
workspaces/ballerina/ballerina-extension/src/core/extended-language-client.ts (1)
workspaces/ballerina/ballerina-core/src/interfaces/extended-lang-client.ts (4)
  • FieldPropertyRequest (480-482)
  • PropertyResponse (484-486)
  • ClausePositionRequest (488-493)
  • ClausePositionResponse (495-497)
workspaces/ballerina/ballerina-visualizer/src/views/DataMapper/DataMapperView.tsx (2)
workspaces/ballerina/ballerina-extension/src/core/extended-language-client.ts (1)
  • getClausePosition (857-859)
workspaces/ballerina/ballerina-extension/src/rpc-managers/data-mapper/rpc-manager.ts (1)
  • getClausePosition (249-257)
workspaces/ballerina/ballerina-side-panel/src/components/editors/EditorFactory.tsx (1)
workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionEditor.tsx (1)
  • DataMapperJoinClauseRhsEditor (307-331)
workspaces/ballerina/ballerina-extension/src/rpc-managers/data-mapper/rpc-handler.ts (4)
workspaces/ballerina/ballerina-extension/src/rpc-managers/data-mapper/rpc-manager.ts (2)
  • getFieldProperty (239-247)
  • getClausePosition (249-257)
workspaces/ballerina/ballerina-core/src/rpc-types/data-mapper/rpc-type.ts (2)
  • getFieldProperty (71-71)
  • getClausePosition (72-72)
workspaces/ballerina/ballerina-rpc-client/src/rpc-clients/data-mapper/rpc-client.ts (2)
  • getFieldProperty (147-149)
  • getClausePosition (151-153)
workspaces/ballerina/ballerina-core/src/interfaces/extended-lang-client.ts (2)
  • FieldPropertyRequest (480-482)
  • ClausePositionRequest (488-493)
workspaces/ballerina/ballerina-core/src/rpc-types/data-mapper/rpc-type.ts (3)
workspaces/ballerina/ballerina-extension/src/rpc-managers/data-mapper/rpc-manager.ts (2)
  • getFieldProperty (239-247)
  • getClausePosition (249-257)
workspaces/ballerina/ballerina-rpc-client/src/rpc-clients/data-mapper/rpc-client.ts (2)
  • getFieldProperty (147-149)
  • getClausePosition (151-153)
workspaces/ballerina/ballerina-core/src/interfaces/extended-lang-client.ts (4)
  • FieldPropertyRequest (480-482)
  • PropertyResponse (484-486)
  • ClausePositionRequest (488-493)
  • ClausePositionResponse (495-497)
workspaces/ballerina/ballerina-rpc-client/src/rpc-clients/data-mapper/rpc-client.ts (3)
workspaces/ballerina/ballerina-core/src/interfaces/extended-lang-client.ts (4)
  • FieldPropertyRequest (480-482)
  • PropertyResponse (484-486)
  • ClausePositionRequest (488-493)
  • ClausePositionResponse (495-497)
workspaces/ballerina/ballerina-extension/src/rpc-managers/data-mapper/rpc-manager.ts (2)
  • getFieldProperty (239-247)
  • getClausePosition (249-257)
workspaces/ballerina/ballerina-core/src/rpc-types/data-mapper/rpc-type.ts (2)
  • getFieldProperty (71-71)
  • getClausePosition (72-72)
workspaces/ballerina/data-mapper/src/components/DataMapper/SidePanel/QueryClauses/ClauseItem.tsx (4)
workspaces/ballerina/ballerina-core/src/interfaces/data-mapper.ts (1)
  • DMFormProps (249-258)
workspaces/ballerina/ballerina-extension/src/core/extended-language-client.ts (1)
  • getClausePosition (857-859)
workspaces/ballerina/ballerina-extension/src/rpc-managers/data-mapper/rpc-manager.ts (1)
  • getClausePosition (249-257)
workspaces/ballerina/data-mapper/src/components/DataMapper/SidePanel/QueryClauses/ClauseEditor.tsx (1)
  • ClauseEditor (38-204)
workspaces/ballerina/data-mapper/src/components/DataMapper/DataMapperEditor.tsx (2)
workspaces/ballerina/ballerina-extension/src/core/extended-language-client.ts (1)
  • getClausePosition (857-859)
workspaces/ballerina/ballerina-extension/src/rpc-managers/data-mapper/rpc-manager.ts (1)
  • getClausePosition (249-257)
workspaces/ballerina/ballerina-extension/src/rpc-managers/data-mapper/rpc-manager.ts (1)
workspaces/ballerina/ballerina-core/src/interfaces/extended-lang-client.ts (4)
  • FieldPropertyRequest (480-482)
  • PropertyResponse (484-486)
  • ClausePositionRequest (488-493)
  • ClausePositionResponse (495-497)
🪛 Biome (2.1.2)
workspaces/ballerina/ballerina-extension/src/rpc-managers/data-mapper/rpc-manager.ts

[error] 240-246: Promise executor functions should not be async.

(lint/suspicious/noAsyncPromiseExecutor)


[error] 250-256: Promise executor functions should not be async.

(lint/suspicious/noAsyncPromiseExecutor)

🔇 Additional comments (15)
workspaces/ballerina/ballerina-side-panel/src/components/editors/EditorFactory.tsx (1)

27-27: LGTM! Clean integration of the new editor type.

The DataMapperJoinClauseRhsEditor is properly imported and integrated into the factory pattern, following the same prop-forwarding convention as other expression editors.

Also applies to: 221-233

workspaces/ballerina/data-mapper/src/index.tsx (1)

71-71: LGTM! Clear and well-typed API extension.

The new getClausePosition prop signature is concise and correctly typed with LinePosition as the return value.

workspaces/ballerina/data-mapper/src/components/DataMapper/DataMapperEditor.tsx (1)

142-142: LGTM! Proper prop threading.

The getClausePosition prop is correctly destructured from props and forwarded to ClausesPanel, consistent with the existing pattern for addClauses and deleteClause.

Also applies to: 365-365

workspaces/ballerina/ballerina-side-panel/src/components/editors/ExpressionEditor.tsx (1)

307-331: LGTM! Well-structured completion context wrapper.

The DataMapperJoinClauseRhsEditor correctly wraps ExpressionEditor and provides contextual completions by prepending a join clause prefix (from var ${varName} in ${expression} select). The offset adjustment accounts for the prefix length, ensuring accurate cursor positioning for completion requests.

The implementation assumes varName and expression from the form are valid; ensure upstream validation handles malformed or empty values to prevent invalid syntax from being sent to the completion provider.

workspaces/ballerina/ballerina-extension/src/rpc-managers/data-mapper/rpc-handler.ts (1)

27-27: LGTM! Correct RPC handler registration.

The new getFieldProperty and getClausePosition RPC endpoints are properly wired into the messenger, following the existing pattern. Imports and handler delegation to rpcManger are consistent with other endpoints.

Also applies to: 40-42, 83-84

workspaces/ballerina/ballerina-core/src/rpc-types/data-mapper/index.ts (1)

45-48: LGTM! Consistent API extension.

The DataMapperAPI interface is correctly extended with getFieldProperty and getClausePosition methods, using the appropriate request/response types. The signatures are consistent with other API methods.

Also applies to: 68-69

workspaces/ballerina/ballerina-core/src/rpc-types/data-mapper/rpc-type.ts (1)

47-50: LGTM! Well-defined RPC types.

The new RPC endpoints getFieldProperty and getClausePosition are properly defined with correct method paths and request/response type mappings, consistent with the existing RPC type definitions.

Also applies to: 71-72

workspaces/ballerina/ballerina-core/src/interfaces/extended-lang-client.ts (1)

480-497: LGTM! Clear interface definitions for clause positioning.

The new interfaces are well-structured:

  • FieldPropertyRequest extends PropertyRequest with a fieldId field for field-specific property retrieval.
  • ClausePositionRequest captures the necessary context (filePath, codedata, targetField, index) to locate a specific clause.
  • ClausePositionResponse returns a LinePosition for position-aware editing.

These interfaces enable the completion support improvements described in the PR objectives.

workspaces/ballerina/ballerina-rpc-client/src/rpc-clients/data-mapper/rpc-client.ts (1)

20-72: New DataMapper RPC client methods look consistent

getFieldProperty and getClausePosition are wired identically to the existing client methods: they use the correct request types from @wso2/ballerina-core and delegate via sendRequest to HOST_EXTENSION. This keeps the client in sync with the extended DataMapperAPI.

Also applies to: 147-153

workspaces/ballerina/data-mapper/src/components/DataMapper/SidePanel/QueryClauses/ClausesPanel.tsx (1)

26-35: Propagation of getClausePosition through ClausesPanel is coherent

Extending ClausesPanelProps with getClausePosition and threading it (along with targetField and index) into both the top-level ClauseEditor and each ClauseItem cleanly exposes clause-position lookup to all clause editors without changing the existing side-panel state management. The data flow looks consistent with the new RPC API.

Also applies to: 40-41, 106-115, 121-137

workspaces/ballerina/ballerina-visualizer/src/views/DataMapper/DataMapperView.tsx (3)

287-287: LGTM! Context flag added for DataMapper editor.

The isDataMapperEditor flag properly marks this form as a DataMapper editor, enabling context-aware completion behavior downstream.


509-514: LGTM! Successfully migrated to the new field-property API.

The migration from getProperty to getFieldProperty correctly adds the fieldId parameter and enables field-specific property retrieval for navigation.


703-703: LGTM! Clause position capability properly wired to DataMapper.

The getClausePosition function is correctly passed to the DataMapper component, enabling dynamic clause positioning for context-aware completions.

workspaces/ballerina/ballerina-extension/src/core/extended-language-client.ts (2)

377-378: LGTM! API endpoint constants properly defined.

The new DATA_MAPPER_FIELD_PROPERTY and DATA_MAPPER_CLAUSE_POSITION constants follow the established naming convention and namespace pattern for data-mapper endpoints.


853-859: LGTM! RPC methods properly implemented.

Both getFieldProperty and getClausePosition follow the established RPC wrapper pattern and correctly use the new API endpoint constants. The return type difference (NOT_SUPPORTED_TYPE union for getFieldProperty but not for getClausePosition) is consistent with similar data-mapper methods.

Comment on lines +363 to +375
const getClausePosition = async (targetField: string, index: number) => {
try {
const { position } = await rpcClient.getDataMapperRpcClient().getClausePosition({
filePath,
codedata: viewState.codedata,
targetField: targetField,
index: index
});
return position;
} catch (error) {
console.error(error);
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Improve error handling and add explicit return type.

The function silently swallows errors and returns undefined implicitly, making it difficult for callers to distinguish between "position not found" and "error occurred" scenarios.

Apply this diff:

-    const getClausePosition = async (targetField: string, index: number) => {
+    const getClausePosition = async (targetField: string, index: number): Promise<NodePosition | undefined> => {
         try {
             const { position } = await rpcClient.getDataMapperRpcClient().getClausePosition({
                 filePath,
                 codedata: viewState.codedata,
-                targetField: targetField,
-                index: index
+                targetField,
+                index
             });
             return position;
         } catch (error) {
             console.error(error);
+            return undefined;
         }
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const getClausePosition = async (targetField: string, index: number) => {
try {
const { position } = await rpcClient.getDataMapperRpcClient().getClausePosition({
filePath,
codedata: viewState.codedata,
targetField: targetField,
index: index
});
return position;
} catch (error) {
console.error(error);
}
}
const getClausePosition = async (targetField: string, index: number): Promise<NodePosition | undefined> => {
try {
const { position } = await rpcClient.getDataMapperRpcClient().getClausePosition({
filePath,
codedata: viewState.codedata,
targetField,
index
});
return position;
} catch (error) {
console.error(error);
return undefined;
}
}
🤖 Prompt for AI Agents
In
workspaces/ballerina/ballerina-visualizer/src/views/DataMapper/DataMapperView.tsx
around lines 363-375, the async getClausePosition swallows errors and returns
undefined implicitly; change its signature to an explicit return type (e.g.,
Promise<number | null>), and in the catch block log the error and re-throw it
(or reject) instead of returning/ignoring, so callers can distinguish a real
error from a "not found" null/number result; update any callers to handle the
thrown error or the explicit null return as needed.

Comment on lines +20 to 36
import { EditorContainer, ProgressRingWrapper } from "./styles";
import { Divider, Dropdown, OptionProps, ProgressRing, Typography } from "@wso2/ui-toolkit";
import { DMFormProps, DMFormField, DMFormFieldValues, IntermediateClauseType, IntermediateClause, IntermediateClauseProps, LinePosition } from "@wso2/ballerina-core";
import { useDMQueryClausesPanelStore } from "../../../../store/store";
import { useQuery } from "@tanstack/react-query";

export interface ClauseEditorProps {
index: number;
targetField: string;
clause?: IntermediateClause;
onSubmitText?: string;
isSaving: boolean;
onSubmit: (clause: IntermediateClause) => void;
onCancel: () => void;
getClausePosition: (targetField: string, index: number) => Promise<LinePosition>;
generateForm: (formProps: DMFormProps) => JSX.Element;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Guard against missing clausePosition when building targetLineRange

The new useQuery integration and ProgressRing gating align well with the clause-position RPC and should help anchor completions to the right place. One minor corner case: if getClausePosition fails or returns undefined, isFetchingTargetLineRange will eventually be false but clausePosition will still be undefined, and you’ll pass that through as both startLine and endLine:

const formProps: DMFormProps = {
    targetLineRange: { startLine: clausePosition, endLine: clausePosition },
    ...
};
...
{isFetchingTargetLineRange ?
    <ProgressRingWrapper> ... </ProgressRingWrapper> :
    generateForm(formProps)
}

To make this more robust, consider also checking clausePosition before rendering the form:

-    const formProps: DMFormProps = {
-        targetLineRange: { startLine: clausePosition, endLine: clausePosition },
-        ...
-    }
+    const formProps: DMFormProps | undefined = clausePosition && {
+        targetLineRange: { startLine: clausePosition, endLine: clausePosition },
+        ...
+    };
...
-            {isFetchingTargetLineRange ?
+            {isFetchingTargetLineRange || !formProps ?
                 <ProgressRingWrapper>
                     <ProgressRing sx={{ height: "20px", width: "20px" }} />
                 </ProgressRingWrapper> :
-                generateForm(formProps)
+                generateForm(formProps)
             }

This keeps the UI safe even if the position lookup fails, while preserving the intended loading behavior. The new "DM_JOIN_CLAUSE_RHS_EXPRESSION" field type for the RHS join expression also looks appropriate for distinguishing that field in the form.

Also applies to: 38-40, 114-124, 159-200

@madushajg madushajg merged commit 303bb75 into wso2:main Nov 21, 2025
6 checks passed
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.

[Data Mapper] Improve completion support - frontend changes for clause editor form

2 participants