Skip to content

Resolve the listeners not showing issue#1554

Merged
samithkavishke merged 4 commits intowso2:release/bi-1.8.xfrom
samithkavishke:issue-2568
Feb 25, 2026
Merged

Resolve the listeners not showing issue#1554
samithkavishke merged 4 commits intowso2:release/bi-1.8.xfrom
samithkavishke:issue-2568

Conversation

@samithkavishke
Copy link
Contributor

@samithkavishke samithkavishke commented Feb 25, 2026

Purpose

Fix: wso2/product-ballerina-integrator#2568, wso2/product-ballerina-integrator#2533

Goals

Describe the solutions that this feature/fix will introduce to resolve the problems described above

Approach

Describe how you are implementing the solutions. Include an animated GIF or screenshot if the change affects the UI (email documentation@wso2.com to review all UI text). Include a link to a Markdown file or Google doc if the feature write-up is too long to paste here.

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

Summary of user stories addressed by this change>

Release note

Brief description of the new feature or bug fix as it will appear in the release notes

Documentation

Link(s) to product documentation that addresses the changes of this PR. If no doc impact, enter “N/A” plus brief explanation of why there’s no doc impact

Training

Link to the PR for changes to the training content in https://github.com/wso2/WSO2-Training, if applicable

Certification

Type “Sent” when you have provided new/updated certification questions, plus four answers for each question (correct answer highlighted in bold), based on this change. Certification questions/answers should be sent to certification@wso2.com and NOT pasted in this PR. If there is no impact on certification exams, type “N/A” and explain why.

Marketing

Link to drafts of marketing content that will describe and promote this feature, including product page changes, technical articles, blog posts, videos, etc., if applicable

Automation tests

  • Unit tests

    Code coverage information

  • Integration tests

    Details about the test cases and coverage

Security checks

Samples

Provide high-level details about the samples related to this feature

Related PRs

List any other related PRs

Migrations (if applicable)

Describe migration steps and platforms on which migration has been tested

Test environment

List all JDK versions, operating systems, databases, and browser/versions on which this feature/fix was tested

Learning

Describe the research phase and any blog posts, patterns, libraries, or add-ons you used to solve the problem.

Summary by CodeRabbit

  • Bug Fixes

    • Improved position tracking and state management in the Service Designer so listener and service updates maintain correct positions and refetch reliably.
    • Fixed listener update behavior to ensure updates apply consistently without unintended metadata side effects.
  • Refactor

    • Simplified listener configuration UI to always show the full config form when a listener exists, removing legacy minimal-config branches.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 25, 2026

📝 Walkthrough

Walkthrough

The changes introduce local position state and refactor ServiceConfigureView rendering to always use the listener config form; they also remove the explicit DIRECTORY_MAP.LISTENER artifactType when calling updateSourceCode in the RPC manager.

Changes

Cohort / File(s) Summary
RPC Manager Listener Update
workspaces/ballerina/ballerina-extension/src/rpc-managers/service-designer/rpc-manager.ts
updateListenerSourceCode no longer passes artifactData with artifactType: DIRECTORY_MAP.LISTENER to updateSourceCode; call now provides only textEdits and a description.
Service Configure View State & Rendering
workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/ServiceConfigureView.tsx
Added local position state (initialized from props) and wired it into fetchService/update flows; set currentIdentifier from service name where available; propagate updated artifact positions after detach/save operations; removed legacy minimal-config branch and always render ListenerConfigForm when a listenerModel exists.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Poem

🐇 I hopped through code and found the trace,
Positions kept, no listeners misplaced.
RPC trims a tag, clean and small,
Service views align and stand tall.
Hooray — the configs answered the call! 🎉

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description only fills in the 'Purpose' section with linked issue references but leaves all other required sections (Goals, Approach, UI Component Development, etc.) as unfilled template placeholders with no concrete implementation details. Complete the description by filling in Goals, Approach, and other relevant sections with specific details about how the listeners issue is being fixed.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Resolve the listeners not showing issue' directly relates to the main problem described in the linked issues (#2568, #2533) about listeners not displaying in the service configuration view.
Linked Issues check ✅ Passed The code changes address the core issues: removing explicit LISTENER artifact type association in updateListenerSourceCode and refactoring position/identifier state management in ServiceConfigureView to prevent listener data loss during configuration updates.
Out of Scope Changes check ✅ Passed All changes are focused on fixing the listeners issue: RPC manager changes for artifact handling and view logic updates for state management and listener configuration display.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 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.

@samithkavishke samithkavishke changed the base branch from main to release/bi-1.8.x February 25, 2026 04:42
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 (2)
workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/ServiceConfigureView.tsx (2)

699-731: ⚠️ Potential issue | 🟡 Minor

Double fetchService calls in the service-save and detach paths.

When saving service changes (lines 725–726), setPosition(...) triggers the useEffect at line 299 which calls fetchService(position), but fetchService is also called directly on line 726. Same pattern in handleOnDetachListener (lines 664–666). This results in two identical network round-trips.

The listener-save loop (lines 706–714) does it correctly — it only calls setPosition and lets the effect handle the fetch.

Pick one pattern consistently. The simplest fix is to remove the direct fetchService calls where setPosition already triggers it:

Suggested fix
         // Update service changes
         for (const change of serviceChanges) {
             const res = await rpcClient.getServiceDesignerRpcClient().updateServiceSourceCode({ filePath: change.filePath, service: change.data as ServiceModel });
             const updatedArtifact = res.artifacts.at(0);
             if (!updatedArtifact) {
                 console.error("No artifact returned after saving service changes");
                 continue;
             }
             setCurrentIdentifier(updatedArtifact.name);
             setPosition(updatedArtifact.position);
-            await fetchService(updatedArtifact.position);
         }

And similarly in handleOnDetachListener:

         setPosition(updatedArtifact.position);
         setCurrentIdentifier(updatedArtifact.name);
-        await fetchService(updatedArtifact.position);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/ServiceConfigureView.tsx`
around lines 699 - 731, handleSave currently calls fetchService(...) directly
after setPosition(...) for service changes, causing duplicate network calls
because the useEffect watching position already invokes fetchService; likewise
handleOnDetachListener has the same double-call pattern. Remove the direct calls
to fetchService(...) in these places (specifically the await
fetchService(updatedArtifact.position) in handleSave and the analogous
fetchService call in handleOnDetachListener) and rely on setPosition(...) + the
existing useEffect to perform the fetch; keep the listener-save loop unchanged
since it already uses setPosition only.

888-896: ⚠️ Potential issue | 🟠 Major

ServiceEditView still receives props.position instead of the local position state.

After a listener update shifts the service's position, ServiceEditView (line 891) will still hold the original props.position. This means the change-map key generated via handleFormDirtyChange will reference the stale position, potentially causing mismatches when looking up dirty/change state.

Consider passing the local position state:

 <ServiceEditView
     filePath={props.filePath}
-    position={props.position}
+    position={position}
     onChange={handleServiceChange}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/ServiceConfigureView.tsx`
around lines 888 - 896, ServiceEditView is being given props.position (the
original prop) instead of the component's local position state, so after
position updates the child still renders with stale position causing
handleFormDirtyChange and change-map keys to mismatch; update the JSX to pass
the local position state (the variable named position) into ServiceEditView
instead of props.position and ensure any callbacks like
onDirtyChange/onValidityChange continue to use that local position when invoking
handleFormDirtyChange/handleFormValidityChange so keys reflect the current
position.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/ServiceConfigureView.tsx`:
- Around line 706-714: In the loop over listenerChanges, fix the typo variable
name listnerResponse to listenerResponse to keep naming consistent: replace all
uses of listnerResponse (assigned from
rpcClient.getServiceDesignerRpcClient().updateListenerSourceCode(...)) with
listenerResponse and ensure updatedServiceArtifact is obtained from
listenerResponse.artifacts before calling
setPosition(updatedServiceArtifact.position).
- Line 217: The local state position in ServiceConfigureView is initialized from
props.position but never updated when the prop changes; add a useEffect in
ServiceConfigureView that watches props.position (or props.position.x/y) and
calls setPosition(props.position) when they differ so the internal position
state stays in sync and ServiceEditView (which reads the original
props.position) receives up-to-date coordinates; reference the
position/setPosition state pair and props.position in the effect to detect
changes and update accordingly.

---

Outside diff comments:
In
`@workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/ServiceConfigureView.tsx`:
- Around line 699-731: handleSave currently calls fetchService(...) directly
after setPosition(...) for service changes, causing duplicate network calls
because the useEffect watching position already invokes fetchService; likewise
handleOnDetachListener has the same double-call pattern. Remove the direct calls
to fetchService(...) in these places (specifically the await
fetchService(updatedArtifact.position) in handleSave and the analogous
fetchService call in handleOnDetachListener) and rely on setPosition(...) + the
existing useEffect to perform the fetch; keep the listener-save loop unchanged
since it already uses setPosition only.
- Around line 888-896: ServiceEditView is being given props.position (the
original prop) instead of the component's local position state, so after
position updates the child still renders with stale position causing
handleFormDirtyChange and change-map keys to mismatch; update the JSX to pass
the local position state (the variable named position) into ServiceEditView
instead of props.position and ensure any callbacks like
onDirtyChange/onValidityChange continue to use that local position when invoking
handleFormDirtyChange/handleFormValidityChange so keys reflect the current
position.

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a3a33f4 and 2686afe.

📒 Files selected for processing (2)
  • workspaces/ballerina/ballerina-extension/src/rpc-managers/service-designer/rpc-manager.ts
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/ServiceConfigureView.tsx

const [currentIdentifier, setCurrentIdentifier] = useState<string | null>(null);

const [isSaving, setIsSaving] = useState<boolean>(false);
const [position, setPosition] = useState<NodePosition>(props.position);
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 | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# Find where ServiceConfigureView is instantiated/rendered
rg -n "ServiceConfigureView" --type=tsx --type=ts -B3 -A3 | head -100

Repository: wso2/vscode-extensions

Length of output: 93


🏁 Script executed:

# Check the component file structure to understand line numbers better
wc -l workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/ServiceConfigureView.tsx

Repository: wso2/vscode-extensions

Length of output: 166


🏁 Script executed:

# Look at the listener/service save logic around lines 706-727
sed -n '700,730p' workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/ServiceConfigureView.tsx

Repository: wso2/vscode-extensions

Length of output: 1678


🏁 Script executed:

# Check ServiceEditView and how it uses position
rg -n "ServiceEditView" --type=tsx --type=ts -B2 -A2 | grep -A5 -B5 "position"

Repository: wso2/vscode-extensions

Length of output: 93


🏁 Script executed:

# Examine the parent component passing position to ServiceConfigureView
rg -n "ServiceConfigureView" --type=tsx --type=ts | head -20

Repository: wso2/vscode-extensions

Length of output: 93


🏁 Script executed:

# Use generic file search without specifying tsx
rg "ServiceConfigureView" -B3 -A3 --type=js | head -100

Repository: wso2/vscode-extensions

Length of output: 48


🏁 Script executed:

# Look for ServiceEditView usage and position prop around line 891
sed -n '880,920p' workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/ServiceConfigureView.tsx

Repository: wso2/vscode-extensions

Length of output: 4313


🏁 Script executed:

# Find all imports and exports to understand component relationship
sed -n '1,50p' workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/ServiceConfigureView.tsx

Repository: wso2/vscode-extensions

Length of output: 2103


🏁 Script executed:

# Search for where ServiceConfigureView is used in the project
find workspaces/ballerina/ballerina-visualizer/src -type f \( -name "*.ts" -o -name "*.tsx" -o -name "*.js" -o -name "*.jsx" \) -exec grep -l "ServiceConfigureView" {} \;

Repository: wso2/vscode-extensions

Length of output: 221


🏁 Script executed:

# Find how ServiceConfigureView is instantiated in MainPanel.tsx
sed -n '1,100p' workspaces/ballerina/ballerina-visualizer/src/MainPanel.tsx | grep -A10 "ServiceConfigureView"

Repository: wso2/vscode-extensions

Length of output: 649


🏁 Script executed:

# Full context of ServiceConfigureView instantiation in MainPanel.tsx
rg "ServiceConfigureView" workspaces/ballerina/ballerina-visualizer/src/MainPanel.tsx -B5 -A5

Repository: wso2/vscode-extensions

Length of output: 1304


🏁 Script executed:

# Check if ServiceEditView uses the position prop it receives
sed -n '1,100p' workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/ServiceEditView.tsx | head -80

Repository: wso2/vscode-extensions

Length of output: 2352


🏁 Script executed:

# Look at the fetchService function to understand if double-fetch matters
sed -n '200,300p' workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/ServiceConfigureView.tsx | grep -A20 "fetchService"

Repository: wso2/vscode-extensions

Length of output: 97


🏁 Script executed:

# Examine ServiceEditView to see how it uses the position prop
sed -n '1,150p' workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/ServiceEditView.tsx

Repository: wso2/vscode-extensions

Length of output: 5107


🏁 Script executed:

# Check if position prop is used beyond initial state
rg "props\.position" workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/ServiceEditView.tsx -B2 -A2

Repository: wso2/vscode-extensions

Length of output: 215


🏁 Script executed:

# Look at the full context around line 217 in ServiceConfigureView
sed -n '210,230p' workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/ServiceConfigureView.tsx

Repository: wso2/vscode-extensions

Length of output: 1278


Sync local position state with props.position changes.

The local position state is initialized from props.position but never updated when the prop changes. Since ServiceEditView receives the original props.position (line 891) and depends on it in its effect hook to fetch service data, any internal position updates from setPosition won't propagate to ServiceEditView, causing it to work with stale position data.

Add a sync effect:

Suggested sync effect
 const [position, setPosition] = useState<NodePosition>(props.position);
+
+ useEffect(() => {
+     setPosition(props.position);
+ }, [props.position]);
📝 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 [position, setPosition] = useState<NodePosition>(props.position);
const [position, setPosition] = useState<NodePosition>(props.position);
useEffect(() => {
setPosition(props.position);
}, [props.position]);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/ServiceConfigureView.tsx`
at line 217, The local state position in ServiceConfigureView is initialized
from props.position but never updated when the prop changes; add a useEffect in
ServiceConfigureView that watches props.position (or props.position.x/y) and
calls setPosition(props.position) when they differ so the internal position
state stays in sync and ServiceEditView (which reads the original
props.position) receives up-to-date coordinates; reference the
position/setPosition state pair and props.position in the effect to detect
changes and update accordingly.

Comment on lines 706 to 714
for (const change of listenerChanges) {
await rpcClient.getServiceDesignerRpcClient().updateListenerSourceCode({ filePath: change.filePath, listener: change.data as ListenerModel });
const listnerResponse = await rpcClient.getServiceDesignerRpcClient().updateListenerSourceCode({ filePath: change.filePath, listener: change.data as ListenerModel });
const updatedServiceArtifact = listnerResponse.artifacts.filter(artifact => artifact.name ===currentIdentifier).at(0);
if (!updatedServiceArtifact) {
console.error("No service artifact returned after updating listener");
continue;
}
setPosition(updatedServiceArtifact.position);
}
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

Typo in variable name: listnerResponselistenerResponse.

Minor naming inconsistency.

Suggested fix
-            const listnerResponse = await rpcClient.getServiceDesignerRpcClient().updateListenerSourceCode({ filePath: change.filePath, listener: change.data as ListenerModel });
-            const updatedServiceArtifact = listnerResponse.artifacts.filter(artifact => artifact.name ===currentIdentifier).at(0);
+            const listenerResponse = await rpcClient.getServiceDesignerRpcClient().updateListenerSourceCode({ filePath: change.filePath, listener: change.data as ListenerModel });
+            const updatedServiceArtifact = listenerResponse.artifacts.filter(artifact => artifact.name === currentIdentifier).at(0);
📝 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
for (const change of listenerChanges) {
await rpcClient.getServiceDesignerRpcClient().updateListenerSourceCode({ filePath: change.filePath, listener: change.data as ListenerModel });
const listnerResponse = await rpcClient.getServiceDesignerRpcClient().updateListenerSourceCode({ filePath: change.filePath, listener: change.data as ListenerModel });
const updatedServiceArtifact = listnerResponse.artifacts.filter(artifact => artifact.name ===currentIdentifier).at(0);
if (!updatedServiceArtifact) {
console.error("No service artifact returned after updating listener");
continue;
}
setPosition(updatedServiceArtifact.position);
}
for (const change of listenerChanges) {
const listenerResponse = await rpcClient.getServiceDesignerRpcClient().updateListenerSourceCode({ filePath: change.filePath, listener: change.data as ListenerModel });
const updatedServiceArtifact = listenerResponse.artifacts.filter(artifact => artifact.name === currentIdentifier).at(0);
if (!updatedServiceArtifact) {
console.error("No service artifact returned after updating listener");
continue;
}
setPosition(updatedServiceArtifact.position);
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/ServiceConfigureView.tsx`
around lines 706 - 714, In the loop over listenerChanges, fix the typo variable
name listnerResponse to listenerResponse to keep naming consistent: replace all
uses of listnerResponse (assigned from
rpcClient.getServiceDesignerRpcClient().updateListenerSourceCode(...)) with
listenerResponse and ensure updatedServiceArtifact is obtained from
listenerResponse.artifacts before calling
setPosition(updatedServiceArtifact.position).

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 (2)
workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/ServiceConfigureView.tsx (2)

619-625: ⚠️ Potential issue | 🟠 Major

handleOnAttachListener never calls setPosition, leaving local position state stale after attach.

handleOnDetachListener and handleSave both call setPosition(updatedArtifact.position) after a mutation, but handleOnAttachListener only calls setCurrentIdentifier and fetchService directly (line 624), never setPosition. After an attach, the local position state still holds the pre-attach value. Any subsequent operation that reads position (e.g., the useEffect re-triggering, or the stale position being passed to ServiceEditView via the sync effect once it is added) would use the wrong coordinates.

🐛 Proposed fix
     setCurrentIdentifier(updatedArtifact.name);
+    setPosition(updatedArtifact.position);
     await fetchService(updatedArtifact.position);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/ServiceConfigureView.tsx`
around lines 619 - 625, handleOnAttachListener currently updates current
identifier and refetches the service but never updates the local position state,
leaving position stale; after verifying updatedArtifact is present, call
setPosition(updatedArtifact.position) (in the same place where
setCurrentIdentifier and fetchService are invoked) so the local position state
is updated before calling fetchService and
closeModal(POPUP_IDS.ATTACH_LISTENER).

573-578: ⚠️ Potential issue | 🟡 Minor

Fallback position in setServiceListeners still uses props.position instead of local position state.

The fallback branch for inline listeners (when there is no codedata.lineRange) constructs a ProjectStructureArtifactResponse using the original props.position coordinates. After any mutation that updates the local position state, this fallback will produce a stale position for those listeners.

🐛 Proposed fix
                     listenersToSet.push({
                         id: listenerName,
                         name: listenerName,
                         path: props.filePath,
                         type: DIRECTORY_MAP.LISTENER,
                         position: {
-                            startLine: props.position.startLine,
-                            startColumn: props.position.startColumn,
-                            endLine: props.position.endLine,
-                            endColumn: props.position.endColumn,
+                            startLine: position.startLine,
+                            startColumn: position.startColumn,
+                            endLine: position.endLine,
+                            endColumn: position.endColumn,
                         },
                     });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/ServiceConfigureView.tsx`
around lines 573 - 578, In setServiceListeners, the fallback branch that builds
the ProjectStructureArtifactResponse still uses props.position
(startLine/startColumn/endLine/endColumn) which can be stale after local
position state updates; change that construction to use the component's local
position state (the position variable/state referenced in this file) instead of
props.position so inline listeners get the current coordinates; update any
occurrences in ServiceConfigureView (where position: { startLine:
props.position.startLine, ... } is created) to reference
position.startLine/position.startColumn/position.endLine/position.endColumn.
♻️ Duplicate comments (2)
workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/ServiceConfigureView.tsx (2)

217-217: Local position state is not synced when props.position changes.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/ServiceConfigureView.tsx`
at line 217, The local state variable position initialized via
useState(props.position) in ServiceConfigureView is not updated when
props.position changes; add an effect that watches props.position and calls
setPosition(props.position) to sync local state (useEffect(() =>
setPosition(props.position), [props.position])) so the component reflect
external updates to props.position while keeping local edits via setPosition.

707-714: Typo listnerResponselistenerResponse.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/ServiceConfigureView.tsx`
around lines 707 - 714, The local variable name listnerResponse is misspelled;
rename it to listenerResponse wherever declared and used in this block (the
await call to rpcClient.getServiceDesignerRpcClient().updateListenerSourceCode
and the subsequent access to .artifacts), so the assignment from
updateListenerSourceCode({ filePath: change.filePath, listener: change.data as
ListenerModel }) is stored in listenerResponse and you then use
listenerResponse.artifacts.filter(...).at(0) to find updatedServiceArtifact
before calling setPosition(updatedServiceArtifact.position).
🧹 Nitpick comments (1)
workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/ServiceConfigureView.tsx (1)

1075-1086: AttachedListenerMinimalConfig is dead code after the rendering simplification.

The component is defined at lines 1075-1086 but is never instantiated anywhere in the file following the removal of the showMinimalConfig branch. It can be deleted.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/ServiceConfigureView.tsx`
around lines 1075 - 1086, Remove the unused component
AttachedListenerMinimalConfig and any related unused references (e.g., the
now-obsolete showMinimalConfig branch) from ServiceConfigureView.tsx;
specifically delete the AttachedListenerMinimalConfig function declaration and
ensure no imports or variables remain that only served that component so there
are no unused-symbol warnings.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/ServiceConfigureView.tsx`:
- Around line 299-301: The duplicate RPC happens because setPosition(...)
triggers the useEffect([position]) which calls fetchService, while code also
calls await fetchService(updatedArtifact.position) immediately after; remove the
immediate/direct fetchService calls (the awaits following setPosition in
handleSave and the other places that call
fetchService(updatedArtifact.position)) and rely on the existing useEffect that
watches position to perform the fetchService call after setPosition; keep
setPosition as-is so the effect runs, and delete the redundant fetchService
calls (and their awaits) adjacent to setPosition to eliminate the double fetch.

---

Outside diff comments:
In
`@workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/ServiceConfigureView.tsx`:
- Around line 619-625: handleOnAttachListener currently updates current
identifier and refetches the service but never updates the local position state,
leaving position stale; after verifying updatedArtifact is present, call
setPosition(updatedArtifact.position) (in the same place where
setCurrentIdentifier and fetchService are invoked) so the local position state
is updated before calling fetchService and
closeModal(POPUP_IDS.ATTACH_LISTENER).
- Around line 573-578: In setServiceListeners, the fallback branch that builds
the ProjectStructureArtifactResponse still uses props.position
(startLine/startColumn/endLine/endColumn) which can be stale after local
position state updates; change that construction to use the component's local
position state (the position variable/state referenced in this file) instead of
props.position so inline listeners get the current coordinates; update any
occurrences in ServiceConfigureView (where position: { startLine:
props.position.startLine, ... } is created) to reference
position.startLine/position.startColumn/position.endLine/position.endColumn.

---

Duplicate comments:
In
`@workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/ServiceConfigureView.tsx`:
- Line 217: The local state variable position initialized via
useState(props.position) in ServiceConfigureView is not updated when
props.position changes; add an effect that watches props.position and calls
setPosition(props.position) to sync local state (useEffect(() =>
setPosition(props.position), [props.position])) so the component reflect
external updates to props.position while keeping local edits via setPosition.
- Around line 707-714: The local variable name listnerResponse is misspelled;
rename it to listenerResponse wherever declared and used in this block (the
await call to rpcClient.getServiceDesignerRpcClient().updateListenerSourceCode
and the subsequent access to .artifacts), so the assignment from
updateListenerSourceCode({ filePath: change.filePath, listener: change.data as
ListenerModel }) is stored in listenerResponse and you then use
listenerResponse.artifacts.filter(...).at(0) to find updatedServiceArtifact
before calling setPosition(updatedServiceArtifact.position).

---

Nitpick comments:
In
`@workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/ServiceConfigureView.tsx`:
- Around line 1075-1086: Remove the unused component
AttachedListenerMinimalConfig and any related unused references (e.g., the
now-obsolete showMinimalConfig branch) from ServiceConfigureView.tsx;
specifically delete the AttachedListenerMinimalConfig function declaration and
ensure no imports or variables remain that only served that component so there
are no unused-symbol warnings.

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2686afe and c631cfb.

📒 Files selected for processing (1)
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/ServiceConfigureView.tsx

Comment on lines 299 to +301
useEffect(() => {
fetchService(props.position);
}, [props.position]);
fetchService(position);
}, [position]);
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 | 🔴 Critical

setPosition + direct fetchService call causes a double fetch on every mutation.

After each setPosition(...) call (lines 664, 713, 737), the useEffect at lines 299-301 will fire — because position changed — and invoke fetchService a second time for the same position. The immediately-following await fetchService(updatedArtifact.position) call then becomes a duplicate RPC round-trip. Over multiple listener changes in handleSave's loop this multiplies further.

There are two clean options:

Option A — drop the direct fetchService calls and rely solely on the effect:

🐛 Option A: let the effect drive fetching
 // handleOnDetachListener
     setPosition(updatedArtifact.position);
     setCurrentIdentifier(updatedArtifact.name);
-    await fetchService(updatedArtifact.position);
     setChangeMap({});
     setDirtyFormMap({});

 // handleSave – listener loop
     setPosition(updatedServiceArtifact.position);
+    // useEffect will re-fetch once position changes

 // handleSave – service loop
     setCurrentIdentifier(updatedArtifact.name);
     setPosition(updatedArtifact.position);
-    await fetchService(updatedArtifact.position);

Option B — keep direct fetchService calls, remove position from the effect dependency:

🐛 Option B: effect only for initial mount
 useEffect(() => {
     fetchService(position);
-}, [position]);
+}, []); // run once on mount; mutations call fetchService directly

Also applies to: 664-666, 713-713, 737-738

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/ServiceConfigureView.tsx`
around lines 299 - 301, The duplicate RPC happens because setPosition(...)
triggers the useEffect([position]) which calls fetchService, while code also
calls await fetchService(updatedArtifact.position) immediately after; remove the
immediate/direct fetchService calls (the awaits following setPosition in
handleSave and the other places that call
fetchService(updatedArtifact.position)) and rely on the existing useEffect that
watches position to perform the fetchService call after setPosition; keep
setPosition as-is so the effect runs, and delete the redundant fetchService
calls (and their awaits) adjacent to setPosition to eliminate the double fetch.

@samithkavishke samithkavishke merged commit 04d9bd4 into wso2:release/bi-1.8.x Feb 25, 2026
10 of 12 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.

Issues of having multiple configurations in the service configuration view

2 participants