Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,7 @@ export function ServiceConfigureView(props: ServiceConfigureProps) {
const [currentIdentifier, setCurrentIdentifier] = useState<string | null>(null);

const [isSaving, setIsSaving] = useState<boolean>(false);
const [position, setPosition] = useState<NodePosition>(props.position);
const [existingListenerType, setExistingListenerType] = useState<string>(""); // Example: "Listener", "CdcListener"

const [selectedListener, setSelectedListener] = useState<string | null>(null);
Expand Down Expand Up @@ -296,8 +297,8 @@ export function ServiceConfigureView(props: ServiceConfigureProps) {
}, []);

useEffect(() => {
fetchService(props.position);
}, [props.position]);
fetchService(position);
}, [position]);

useEffect(() => {
if (props.listenerName) {
Expand Down Expand Up @@ -475,6 +476,10 @@ export function ServiceConfigureView(props: ServiceConfigureProps) {
// Set the service model
setServiceModel(res.service);
setConfigTitle(`${getDisplayServiceName(res.service)} Configuration`);
// Set the current identifier from the service name
if (res.service.name && !currentIdentifier) {
setCurrentIdentifier(res.service.name);
}
// Set the service listeners
setServiceListeners(res.service);
// Find the listener type
Expand Down Expand Up @@ -656,6 +661,7 @@ export function ServiceConfigureView(props: ServiceConfigureProps) {
console.error("No artifact returned after detaching listener");
return;
}
setPosition(updatedArtifact.position);
setCurrentIdentifier(updatedArtifact.name);
await fetchService(updatedArtifact.position);
setChangeMap({});
Expand Down Expand Up @@ -691,6 +697,31 @@ export function ServiceConfigureView(props: ServiceConfigureProps) {
setIsSaving(false);
}

const refreshServicePosition = async () => {
if (!currentIdentifier) {
console.error("No current identifier available for refreshing service position");
return;
}

try {
const projectStructureResponse = await rpcClient.getBIDiagramRpcClient().getProjectStructure();
const project = projectStructureResponse.projects.find(p => p.projectPath === props.projectPath);

if (!project) {
console.error("Project not found in structure response");
return;
}

const entryPoint = project
.directoryMap[DIRECTORY_MAP.SERVICE]
.find((service: ProjectStructureArtifactResponse) => service.name === currentIdentifier);

setPosition(entryPoint.position);
} catch (error) {
console.error('Error refreshing service position:', error);
}
};
Comment on lines +700 to +723
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

Guard against missing service entry/position in refreshServicePosition

ProjectStructureArtifactResponse.position is optional, and .find(...) can return undefined. As written, setPosition(entryPoint.position) can throw or set undefined, which will break fetchService.

🛡️ Suggested fix
-        const entryPoint = project
-            .directoryMap[DIRECTORY_MAP.SERVICE]
-            .find((service: ProjectStructureArtifactResponse) => service.name === currentIdentifier);
-        
-        setPosition(entryPoint.position);
+        const services = project.directoryMap?.[DIRECTORY_MAP.SERVICE] ?? [];
+        const entryPoint = services.find(
+            (service: ProjectStructureArtifactResponse) => service.name === currentIdentifier
+        );
+
+        if (!entryPoint?.position) {
+            console.error("Service position not found for", currentIdentifier);
+            return;
+        }
+        setPosition(entryPoint.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 refreshServicePosition = async () => {
if (!currentIdentifier) {
console.error("No current identifier available for refreshing service position");
return;
}
try {
const projectStructureResponse = await rpcClient.getBIDiagramRpcClient().getProjectStructure();
const project = projectStructureResponse.projects.find(p => p.projectPath === props.projectPath);
if (!project) {
console.error("Project not found in structure response");
return;
}
const entryPoint = project
.directoryMap[DIRECTORY_MAP.SERVICE]
.find((service: ProjectStructureArtifactResponse) => service.name === currentIdentifier);
setPosition(entryPoint.position);
} catch (error) {
console.error('Error refreshing service position:', error);
}
};
const refreshServicePosition = async () => {
if (!currentIdentifier) {
console.error("No current identifier available for refreshing service position");
return;
}
try {
const projectStructureResponse = await rpcClient.getBIDiagramRpcClient().getProjectStructure();
const project = projectStructureResponse.projects.find(p => p.projectPath === props.projectPath);
if (!project) {
console.error("Project not found in structure response");
return;
}
const services = project.directoryMap?.[DIRECTORY_MAP.SERVICE] ?? [];
const entryPoint = services.find(
(service: ProjectStructureArtifactResponse) => service.name === currentIdentifier
);
if (!entryPoint?.position) {
console.error("Service position not found for", currentIdentifier);
return;
}
setPosition(entryPoint.position);
} catch (error) {
console.error('Error refreshing service position:', error);
}
};
🤖 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 700 - 723, In refreshServicePosition, guard against entryPoint
being undefined and against a missing optional position before calling
setPosition to avoid breaking fetchService: after locating entryPoint with
.find(...) check if entryPoint exists and if entryPoint.position is defined,
otherwise log a clear error (or return early) and do not call setPosition;
update the function around the entryPoint lookup (symbols:
refreshServicePosition, entryPoint, setPosition,
ProjectStructureArtifactResponse.position, fetchService) to handle both cases
safely.


const handleSave = async () => {
setIsSaving(true);
const changes = Object.values(changeMap);
Expand All @@ -700,6 +731,13 @@ export function ServiceConfigureView(props: ServiceConfigureProps) {
for (const change of listenerChanges) {
await rpcClient.getServiceDesignerRpcClient().updateListenerSourceCode({ filePath: change.filePath, listener: change.data as ListenerModel });
}

// Re-fetch service position after listener changes
if (listenerChanges.length > 0 && serviceChanges.length === 0) {
await refreshServicePosition();
}

// 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);
Expand All @@ -708,6 +746,7 @@ export function ServiceConfigureView(props: ServiceConfigureProps) {
continue;
}
setCurrentIdentifier(updatedArtifact.name);
setPosition(updatedArtifact.position);
await fetchService(updatedArtifact.position);
}
setChangeMap({});
Expand Down
Loading