Skip to content

Conversation

@samithkavishke
Copy link
Contributor

@samithkavishke samithkavishke commented Nov 12, 2025

Purpose

wso2/product-ballerina-integrator#1684

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 [email protected] 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 [email protected] 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

  • New Features

    • FTP service support: file handler configuration panels, FTP-specific forms, and parameter management components (FTPForm, FTPConfigForm, Parameters, ParamEditor).
    • New payload context type enabling protocol/filter metadata.
  • UI/UX Improvements

    • Updated file integration and entry node icons for FTP/file.
    • File format-aware type editor (JSON, XML, CSV) and GraphQL context passed as payloadContext.
  • Bug Fixes

    • Minor syntax/formatting fixes.

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

@samithkavishke samithkavishke marked this pull request as draft November 12, 2025 08:50
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 12, 2025

Walkthrough

FTP file integration support added with a new GeneralPayloadContext interface enabling protocol-aware payload handling. Boolean GraphQL flags replaced by payloadContext objects, FTP-specific form components and type-filtering logic were introduced, plus UI and icon updates to surface FTP/file integrations.

Changes

Cohort / File(s) Summary
Core Context Types
workspaces/ballerina/ballerina-core/src/interfaces/service.ts
Introduced GeneralPayloadContext (protocol: string; filterType?: string) and extended PayloadContext union to include it.
GraphQL Context Migration
workspaces/ballerina/ballerina-visualizer/src/views/BI/Forms/FormGenerator/index.tsx, workspaces/ballerina/ballerina-visualizer/src/views/BI/Forms/FormGeneratorNew/index.tsx, workspaces/ballerina/ballerina-visualizer/src/views/GraphQLDiagram/index.tsx, workspaces/ballerina/ballerina-visualizer/src/views/BI/TypeEditor/index.tsx
Replaced isGraphql boolean prop with payloadContext object ({ protocol: "GRAPHQL" } / { protocol: "GRAPHQL", filterType: "INPUT" }); FormTypeEditor now derives GraphQL behavior from payloadContext.
Type System & Filtering
workspaces/ballerina/ballerina-visualizer/src/views/BI/TypeEditor/utils.tsx
getTypes signature extended to accept payloadContext; added FTP-specific filtering and injections (filter UDTs by description "Record"; inject JSON/XML/CSV types based on filterType).
FTP Form Components
workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/Forms/FTPForm/index.tsx, .../FTPConfigForm.tsx, .../Parameters/Parameters.tsx, .../Parameters/ParamEditor.tsx
Added FTPForm, FTPConfigForm, Parameters, and ParamEditor components with public props/interfaces to configure FTP file handlers, select formats, define content schemas, and edit parameters.
Service Designer FTP Integration
workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/index.tsx
Added FTP detection (isFtpService), handler selection state (selectedFTPHandler), new handlers (handleNewFTPFunction), and conditional UI to render FTP-specific panels and wire submission flows into existing save logic.
Dynamic Field Handling
workspaces/ballerina/ballerina-side-panel/src/components/editors/ChoiceForm.tsx
Split dynamic record-type fields into dynamicRecordTypeFields; updated convertConfig to return { formFields, recordTypeFieldsForChoice }; merged record type fields into EditorFactory and added debug logs.
UI Icon Updates
workspaces/ballerina/ballerina-visualizer/src/views/BI/ComponentListView/FileIntegrationPanel.tsx, workspaces/ballerina/component-diagram/src/components/nodes/EntryNode/components/GeneralWidget.tsx
Replaced Codicon inline usage with getFileIntegrationIcon / getCustomFileIntegrationIcon helpers mapping ftp and file to bi-icons; updated entry node widget to support same icons.
Minor Updates
workspaces/ballerina/ballerina-visualizer/src/components/EntryPointTypeCreator/index.tsx, workspaces/ballerina/ballerina-extension/src/rpc-managers/bi-diagram/rpc-manager.ts, workspaces/ballerina/ballerina-extension/package.json
Formatting cleanup (removed empty line), added a missing semicolon, and changed extension icon glyph character in package.json.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant ServiceDesigner
    participant FTPConfigForm
    participant FTPForm
    participant ParamEditor
    participant TypeEditor
    participant Project

    User->>ServiceDesigner: Click "Add File Handler"
    ServiceDesigner->>FTPConfigForm: Render list of non-enabled handlers
    User->>FTPConfigForm: Select event (onCreate/onDelete)
    FTPConfigForm->>ServiceDesigner: onSubmit(selectedHandler)
    ServiceDesigner->>FTPForm: Render FTPForm with selected handler

    rect rgb(220,240,220)
    Note over FTPForm,TypeEditor: FTP Form → Define Content Schema flow
    User->>FTPForm: Choose file format (JSON/XML/CSV)
    FTPForm->>TypeEditor: Open EntryPointTypeCreator / FormTypeEditor with payloadContext {protocol:"FTP", filterType:"..."}
    TypeEditor->>Project: Create/submit payload type
    FTPForm->>FTPForm: Attach created type to DATA_BINDING parameter
    end

    User->>FTPForm: Edit parameter
    FTPForm->>ParamEditor: Open ParamEditor
    ParamEditor->>TypeEditor: Render FormGeneratorNew with payloadContext
    User->>TypeEditor: Select filtered type
    ParamEditor->>FTPForm: Return updated parameter
    User->>FTPForm: Save
    FTPForm->>ServiceDesigner: handleFunctionSubmit
    ServiceDesigner->>Project: Persist configuration
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Poem

🐰 New FTP paths the rabbit hops,
Contexts flutter, payload pops,
Forms assemble, types align,
Filters pick JSON, XML, CSV fine,
Handlers saved — a happy sign!

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description follows the required template structure but is largely incomplete, with most sections containing only placeholder text and no substantive content provided for Goals, Approach, or other critical sections. Fill in Goals section with concrete solutions, Approach section with implementation details, and complete all critical sections including test coverage, security checks, and documentation links.
Docstring Coverage ⚠️ Warning Docstring coverage is 14.29% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Improve file integration funcitonality' contains a typo ('funcitonality' instead of 'functionality') and refers to file integration improvements, which aligns with changes adding FTP support and enhancing file integration UI components.
✨ 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.

@samithkavishke samithkavishke force-pushed the ftp branch 2 times, most recently from 7961bce to b5ebf99 Compare December 16, 2025 07:37
@samithkavishke samithkavishke marked this pull request as ready for review December 16, 2025 09: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: 13

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/ChoiceForm.tsx (1)

153-153: Remove debug console log.

This debug log should be removed before merging to production.

Apply this diff:

-                        console.log("Choice Form Index:", Number(e.target.value))
🧹 Nitpick comments (13)
workspaces/ballerina/ballerina-side-panel/src/components/editors/ChoiceForm.tsx (2)

118-135: RecordTypeField creation logic is correct.

The logic correctly creates RecordTypeField entries when typeMembers are present, and the structure matches the expected type definition.

Optionally, you could simplify the property construction by reusing expression properties:

                const recordTypeField: RecordTypeField = {
                    key: key,
                    property: {
-                       metadata: expression.metadata || { label: "", description: "" },
-                       valueType: expression.valueType || "EXPRESSION",
-                       value: expression.value || "",
-                       optional: expression.optional || false,
-                       editable: expression.editable !== undefined ? expression.editable : true,
-                       valueTypeConstraint: expression.valueTypeConstraint,
-                       typeMembers: expression.typeMembers
+                       ...expression,
+                       metadata: expression.metadata || { label: "", description: "" },
+                       valueType: expression.valueType || "EXPRESSION",
+                       value: expression.value || ""
                    },
                    recordTypeMembers: expression.typeMembers
                };

164-176: Move recordTypeFields merge outside the map function.

The merging of recordTypeFields with dynamicRecordTypeFields is currently performed on every iteration of the map, which is inefficient. Since the merged array is identical for all iterations, it should be computed once before the map.

Apply this diff to improve performance:

+            {(() => {
+                // Merge parent recordTypeFields with dynamically generated ones
+                const mergedRecordTypeFields = [
+                    ...(recordTypeFields || []),
+                    ...dynamicRecordTypeFields
+                ];
+
+                return dynamicFields.map((dfield, index) => {
-            <FormSection>
-                {dynamicFields.map((dfield, index) => {
-                    // Merge parent recordTypeFields with dynamically generated ones
-                    const mergedRecordTypeFields = [
-                        ...(recordTypeFields || []),
-                        ...dynamicRecordTypeFields
-                    ];
-
                     return (
                         <EditorFactory
                             key={dfield.key}
                             field={dfield}
                             autoFocus={index === 0 ? true : false}
                             recordTypeFields={mergedRecordTypeFields}
                         />
                     );
-                })}
+                });
+            })()}
             </FormSection>

Alternatively, use useMemo for a cleaner approach:

const mergedRecordTypeFields = React.useMemo(() => [
    ...(recordTypeFields || []),
    ...dynamicRecordTypeFields
], [recordTypeFields, dynamicRecordTypeFields]);

// Then in JSX:
<FormSection>
    {dynamicFields.map((dfield, index) => (
        <EditorFactory
            key={dfield.key}
            field={dfield}
            autoFocus={index === 0}
            recordTypeFields={mergedRecordTypeFields}
        />
    ))}
</FormSection>
workspaces/ballerina/type-editor/src/TypeEditor/ContextBasedTypeEditor/ContextTypeEditor.tsx (1)

141-143: Minor formatting inconsistency in conditional.

The FTP-specific initial tab logic is correct. However, there's a minor formatting inconsistency with the missing space after if.

-        if( payloadContext?.protocol === "FTP"){
+        if (payloadContext?.protocol === "FTP") {
             return "create-from-scratch";
         }
workspaces/ballerina/ballerina-visualizer/src/views/BI/Forms/FormGeneratorNew/index.tsx (1)

1023-1023: Inline object creation on every render.

The migration from isGraphql to payloadContext aligns with the PR's context-based approach. However, creating the object inline {{protocol: "GRAPHQL"}} will produce a new object reference on every render, which could cause unnecessary re-renders in child components that use reference equality checks.

Consider extracting to a constant if this causes performance issues:

const GRAPHQL_PAYLOAD_CONTEXT = { protocol: "GRAPHQL" } as const;
// Then use: payloadContext={GRAPHQL_PAYLOAD_CONTEXT}
workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/Forms/FTPForm/FTPConfigForm.tsx (1)

33-33: Minor formatting nit.

Missing space after comma in destructuring.

-    const { onBack, onSubmit,isSaving } = props;
+    const { onBack, onSubmit, isSaving } = props;
workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/Forms/FTPForm/Parameters/ParamEditor.tsx (2)

48-53: Missing dependency in useEffect causes stale closure.

The effect uses rpcClient but doesn't include it in the dependency array. Also, updateFormFields is called here and again via the effect on line 75-77, causing redundant initialization.

     useEffect(() => {
         rpcClient.getVisualizerRpcClient().joinProjectPath({ segments: ['main.bal'] }).then((response) => {
             setFilePath(response.filePath);
         });
-        updateFormFields();
-    }, []);
+    }, [rpcClient]);

The updateFormFields() call can be removed since the effect at lines 75-77 will handle it when param.type changes.


75-77: Missing param in dependency array.

The effect depends on param.type but only lists param.type which may not trigger re-runs correctly in all cases. Since updateFormFields reads from param, the full param object or a more stable reference should be considered.

     useEffect(() => {
         updateFormFields();
-    }, [param.type]);
+    }, [param]);
workspaces/ballerina/ballerina-visualizer/src/views/BI/TypeEditor/index.tsx (1)

182-184: Stale closure risk: Missing isGraphql in dependency array.

The debouncedSearchTypeHelper callback uses isGraphql (line 113) but the dependency array doesn't include it. Since isGraphql is derived from payloadContext, consider adding payloadContext or isGraphql to the dependencies.

         }, 150),
-        [basicTypes, filePath, targetLineRange, rpcClient]
+        [basicTypes, filePath, targetLineRange, rpcClient, isGraphql, payloadContext]
     );
workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/index.tsx (1)

1012-1022: Empty goToSource callback is a no-op.

Passing an empty function () => { } for goToSource means clicking to view source does nothing. If this functionality isn't supported for FTP handlers, consider either hiding the button in ResourceAccordion or implementing the navigation.

                                                     {enabledHandlers.map((functionModel, index) => (
                                                         <ResourceAccordion
                                                             key={`${index}-${functionModel.name.value}`}
                                                             method={functionModel.metadata.label}
                                                             functionModel={functionModel}
-                                                            goToSource={() => { }}
+                                                            goToSource={handleOpenDiagram}
                                                             onEditResource={handleFunctionEdit}
                                                             onDeleteResource={handleFunctionDelete}
                                                             onResourceImplement={handleOpenDiagram}
                                                         />
                                                     ))}
workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/Forms/FTPForm/Parameters/Parameters.tsx (1)

65-74: Duplicate HeaderLabel styled component.

HeaderLabel is already imported from ../../../styles (visible in relevant_code_snippets) but is redefined here with slightly different styling (margin instead of margin-top). This creates inconsistency. Consider either using the imported one or renaming this local variant.

-const HeaderLabel = styled.div<CSSObject>`
+const ParameterHeaderLabel = styled.div<CSSObject>`
     display: flex;
     background: var(--vscode-editor-background);
     border: 1px solid ${(props: { haveErrors: boolean; }) => props.haveErrors ? "red" : "var(--vscode-dropdown-border)"};
     margin: 8px 0;
-    display: flex;
     width: 100%;
     height: 32px;
     align-items: center;
 `;

Note: There's also a duplicate display: flex declaration that can be removed.

workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/Forms/FTPForm/index.tsx (3)

26-26: Unused import: has from lodash.

The has function is imported but never used in this file.

-import { has } from 'lodash';

86-95: Consider memoizing nonEnabledFunctions.

This filtering logic runs on every render. Since it depends on serviceModel.functions and selectedHandler, it should be memoized with useMemo.

+import { useMemo } from 'react';

-    // Filter non-enabled functions for dropdown options based on selected handler
-    const nonEnabledFunctions = serviceModel.functions?.filter(fn => {
+    const nonEnabledFunctions = useMemo(() => serviceModel.functions?.filter(fn => {
         if (!fn.enabled && selectedHandler && fn.metadata?.label === selectedHandler) {
             return true;
         }
-        // If no selectedHandler is provided, default to onCreate for backward compatibility
         if (!fn.enabled && !selectedHandler && fn.metadata?.label === "onCreate") {
             return true;
         }
         return false;
-    }) || [];
+    }) || [], [serviceModel.functions, selectedHandler]);

98-120: Stale closure and dependency issues in useEffect hooks.

The effects at lines 98-111 and 114-120 have dependency issues:

  1. Both depend on nonEnabledFunctions which is recalculated every render but not in the dependency array.
  2. isNew is used but not in the dependency array of the first effect.

Since the ESLint rule is disabled, these issues are hidden. After memoizing nonEnabledFunctions, add it to the dependency arrays.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 456c3bf and b5ebf99.

📒 Files selected for processing (15)
  • workspaces/ballerina/ballerina-core/src/interfaces/service.ts (1 hunks)
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/ChoiceForm.tsx (4 hunks)
  • workspaces/ballerina/ballerina-visualizer/src/components/EntryPointTypeCreator/index.tsx (0 hunks)
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/Forms/FormGenerator/index.tsx (2 hunks)
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/Forms/FormGeneratorNew/index.tsx (1 hunks)
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/Forms/FTPForm/FTPConfigForm.tsx (1 hunks)
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/Forms/FTPForm/Parameters/ParamEditor.tsx (1 hunks)
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/Forms/FTPForm/Parameters/Parameters.tsx (1 hunks)
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/Forms/FTPForm/index.tsx (1 hunks)
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/index.tsx (16 hunks)
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/TypeEditor/index.tsx (2 hunks)
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/TypeEditor/utils.tsx (5 hunks)
  • workspaces/ballerina/ballerina-visualizer/src/views/GraphQLDiagram/index.tsx (2 hunks)
  • workspaces/ballerina/type-editor/src/TypeEditor/ContextBasedTypeEditor/ContextTypeEditor.tsx (1 hunks)
  • workspaces/ballerina/type-editor/src/TypeEditor/ContextBasedTypeEditor/GenericImportTab.tsx (3 hunks)
💤 Files with no reviewable changes (1)
  • workspaces/ballerina/ballerina-visualizer/src/components/EntryPointTypeCreator/index.tsx
🧰 Additional context used
🧠 Learnings (15)
📚 Learning: 2025-11-25T06:34:10.812Z
Learnt from: CR
Repo: wso2/vscode-extensions PR: 0
File: workspaces/ballerina/component-diagram/AGENTS.md:0-0
Timestamp: 2025-11-25T06:34:10.812Z
Learning: Applies to workspaces/ballerina/component-diagram/src/components/**/*.tsx : Use React 18.2.0 features including concurrent rendering and automatic batching; avoid class components in favor of functional components with hooks

Applied to files:

  • workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/Forms/FTPForm/Parameters/ParamEditor.tsx
  • workspaces/ballerina/type-editor/src/TypeEditor/ContextBasedTypeEditor/GenericImportTab.tsx
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/Forms/FTPForm/Parameters/Parameters.tsx
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/TypeEditor/index.tsx
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/ChoiceForm.tsx
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/Forms/FTPForm/index.tsx
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/Forms/FormGenerator/index.tsx
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/Forms/FTPForm/FTPConfigForm.tsx
  • workspaces/ballerina/ballerina-visualizer/src/views/GraphQLDiagram/index.tsx
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/index.tsx
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/Forms/FormGeneratorNew/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/type-editor/src/TypeEditor/ContextBasedTypeEditor/GenericImportTab.tsx
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/Forms/FTPForm/Parameters/Parameters.tsx
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/TypeEditor/index.tsx
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/Forms/FTPForm/index.tsx
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/Forms/FormGenerator/index.tsx
  • workspaces/ballerina/ballerina-visualizer/src/views/GraphQLDiagram/index.tsx
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/Forms/FormGeneratorNew/index.tsx
📚 Learning: 2025-11-25T06:34:10.812Z
Learnt from: CR
Repo: wso2/vscode-extensions PR: 0
File: workspaces/ballerina/component-diagram/AGENTS.md:0-0
Timestamp: 2025-11-25T06:34:10.812Z
Learning: Applies to workspaces/ballerina/component-diagram/src/components/DiagramContext.tsx : Use DiagramContext (React Context API) for state management across the diagram component, including expandedNodes and graphQLGroupOpen state

Applied to files:

  • workspaces/ballerina/type-editor/src/TypeEditor/ContextBasedTypeEditor/GenericImportTab.tsx
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/TypeEditor/index.tsx
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/Forms/FormGenerator/index.tsx
  • workspaces/ballerina/ballerina-visualizer/src/views/GraphQLDiagram/index.tsx
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/Forms/FormGeneratorNew/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 Emotion for CSS-in-JS styling instead of inline styles or external CSS files

Applied to files:

  • workspaces/ballerina/type-editor/src/TypeEditor/ContextBasedTypeEditor/GenericImportTab.tsx
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/TypeEditor/index.tsx
  • workspaces/ballerina/ballerina-visualizer/src/views/GraphQLDiagram/index.tsx
📚 Learning: 2025-11-24T22:16:28.380Z
Learnt from: dan-niles
Repo: wso2/vscode-extensions PR: 980
File: workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx:384-412
Timestamp: 2025-11-24T22:16:28.380Z
Learning: In the RichTextTemplateEditor component (workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx), token fetching on external `value` prop changes is intentionally disabled. Users cannot edit both the minimized and expanded editors simultaneously, so tokens only need to be generated based on user typing in the expanded editor view, not on external prop updates.

Applied to files:

  • workspaces/ballerina/type-editor/src/TypeEditor/ContextBasedTypeEditor/GenericImportTab.tsx
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/TypeEditor/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/GraphQLServiceWidget.tsx : For GraphQL services, group functions by type (Query, Subscription, Mutation) and allow independent expand/collapse of each group. Default state: Query group open, Subscription/Mutation groups collapsed

Applied to files:

  • workspaces/ballerina/ballerina-visualizer/src/views/BI/TypeEditor/utils.tsx
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/TypeEditor/index.tsx
  • workspaces/ballerina/ballerina-visualizer/src/views/GraphQLDiagram/index.tsx
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/Forms/FormGeneratorNew/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} : Use TypeScript 5.8.3 with strict type checking enabled for all source files

Applied to files:

  • workspaces/ballerina/ballerina-visualizer/src/views/BI/TypeEditor/index.tsx
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/Forms/FormGenerator/index.tsx
  • workspaces/ballerina/ballerina-visualizer/src/views/GraphQLDiagram/index.tsx
📚 Learning: 2025-12-12T08:55:43.437Z
Learnt from: dan-niles
Repo: wso2/vscode-extensions PR: 1080
File: workspaces/ballerina/ballerina-visualizer/src/views/BI/AIChatAgent/AddMcpServer.tsx:269-281
Timestamp: 2025-12-12T08:55:43.437Z
Learning: In `FormGenerator` component used in AddMcpServer.tsx, the component automatically triggers `onChange` callbacks with saved field values during initialization when a `node` prop is provided, so manual state setter calls (e.g., setServerUrl, setAuth) are not needed in initialization logic like initializeEditMode.

Applied to files:

  • workspaces/ballerina/ballerina-visualizer/src/views/BI/TypeEditor/index.tsx
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/Forms/FormGenerator/index.tsx
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/Forms/FormGeneratorNew/index.tsx
📚 Learning: 2025-11-25T06:34:10.812Z
Learnt from: CR
Repo: wso2/vscode-extensions PR: 0
File: workspaces/ballerina/component-diagram/AGENTS.md:0-0
Timestamp: 2025-11-25T06:34:10.812Z
Learning: Applies to workspaces/ballerina/component-diagram/src/resources/icons/**/*.tsx : Create separate SVG icon components in src/resources/icons/ for all diagram icons and import them as React components

Applied to files:

  • workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/Forms/FTPForm/index.tsx
  • workspaces/ballerina/ballerina-visualizer/src/views/GraphQLDiagram/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/ballerina-visualizer/src/views/BI/Forms/FormGenerator/index.tsx
📚 Learning: 2025-11-25T06:34:10.812Z
Learnt from: CR
Repo: wso2/vscode-extensions PR: 0
File: workspaces/ballerina/component-diagram/AGENTS.md:0-0
Timestamp: 2025-11-25T06:34:10.812Z
Learning: Applies to workspaces/ballerina/component-diagram/src/components/Diagram.tsx : Implement proper error boundaries around the Diagram component to gracefully handle rendering errors without crashing the parent application

Applied to files:

  • workspaces/ballerina/ballerina-visualizer/src/views/GraphQLDiagram/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/ballerina-visualizer/src/views/GraphQLDiagram/index.tsx
📚 Learning: 2025-11-25T06:34:10.812Z
Learnt from: CR
Repo: wso2/vscode-extensions PR: 0
File: workspaces/ballerina/component-diagram/AGENTS.md:0-0
Timestamp: 2025-11-25T06:34:10.812Z
Learning: Applies to workspaces/ballerina/component-diagram/src/index.ts : Export the main Diagram component as the default export from the package entry point (index.ts)

Applied to files:

  • workspaces/ballerina/ballerina-visualizer/src/views/GraphQLDiagram/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-visualizer/src/views/BI/ServiceDesigner/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/GeneralWidget.tsx : For regular services with more than 3 functions, show only the first 2 functions with a 'View All' button; for services with 3 or fewer functions, show all functions

Applied to files:

  • workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/index.tsx
🧬 Code graph analysis (6)
workspaces/ballerina/type-editor/src/TypeEditor/ContextBasedTypeEditor/GenericImportTab.tsx (1)
workspaces/ballerina/ballerina-core/src/interfaces/service.ts (1)
  • GeneralPayloadContext (127-131)
workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/Forms/FTPForm/Parameters/Parameters.tsx (2)
workspaces/ballerina/ballerina-core/src/interfaces/service.ts (1)
  • ParameterModel (186-192)
workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/styles.tsx (6)
  • HeaderLabel (124-133)
  • disabledHeaderLabel (117-122)
  • headerLabelStyles (102-108)
  • ActionIconWrapper (135-141)
  • EditIconWrapper (62-69)
  • DeleteIconWrapper (71-79)
workspaces/ballerina/ballerina-visualizer/src/views/BI/TypeEditor/utils.tsx (3)
workspaces/ballerina/ballerina-core/src/interfaces/extended-lang-client.ts (1)
  • VisibleTypeItem (1165-1174)
workspaces/ballerina/ballerina-core/src/interfaces/service.ts (1)
  • GeneralPayloadContext (127-131)
workspaces/ballerina/type-editor/src/TypeHelper/index.tsx (1)
  • TypeHelperCategory (51-56)
workspaces/ballerina/ballerina-side-panel/src/components/editors/ChoiceForm.tsx (4)
workspaces/ballerina/ballerina-core/src/interfaces/bi.ts (1)
  • RecordTypeField (154-158)
workspaces/ballerina/ballerina-visualizer/src/utils/bi.tsx (1)
  • convertConfig (961-980)
workspaces/ballerina/ballerina-core/src/interfaces/service.ts (1)
  • PropertyModel (159-184)
workspaces/ballerina/ballerina-side-panel/src/components/editors/EditorFactory.tsx (1)
  • EditorFactory (70-239)
workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/Forms/FTPForm/FTPConfigForm.tsx (2)
workspaces/common-libs/rpc-generator/index.js (1)
  • handlerName (316-316)
workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/Forms/FTPForm/index.tsx (1)
  • EditorContentColumn (49-55)
workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/index.tsx (3)
workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/components/ResourceAccordion.tsx (1)
  • ResourceAccordion (138-234)
workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/utils.tsx (1)
  • canDataBind (76-78)
workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/Forms/FTPForm/index.tsx (1)
  • FTPForm (68-539)
🔇 Additional comments (12)
workspaces/ballerina/ballerina-side-panel/src/components/editors/ChoiceForm.tsx (3)

61-61: LGTM!

The new state variable appropriately tracks dynamic record type fields generated from choice selections.


67-69: LGTM!

The destructuring and state updates correctly handle the refactored convertConfig return value.


79-81: LGTM!

The refactored return type improves clarity by explicitly returning both form fields and record type fields as a structured object.

workspaces/ballerina/ballerina-core/src/interfaces/service.ts (1)

127-133: LGTM - New GeneralPayloadContext interface extends payload handling.

The addition of GeneralPayloadContext with a flexible protocol: string field provides a generic mechanism for FTP and other protocols without needing dedicated interfaces for each. The optional filterType and hideJsonTypeFallback fields support the FTP-specific type filtering behavior seen in downstream components.

Consider documenting the expected protocol values (e.g., "FTP", "GRAPHQL") to help consumers understand the contract.

workspaces/ballerina/type-editor/src/TypeEditor/ContextBasedTypeEditor/GenericImportTab.tsx (1)

552-559: Type assertion approach is acceptable but could be cleaner.

The conditional rendering based on hideJsonTypeFallback correctly hides the JSON fallback UI for FTP flows. The type assertion (payloadContext as GeneralPayloadContext)?.hideJsonTypeFallback is safe due to optional chaining, but repeated casting is verbose.

For future maintainability, consider adding a type guard helper:

const isGeneralPayloadContext = (ctx?: PayloadContext): ctx is GeneralPayloadContext =>
    ctx !== undefined && ctx.protocol !== "HTTP" && ctx.protocol !== "MESSAGE_BROKER";

Also applies to: 587-604

workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/Forms/FTPForm/FTPConfigForm.tsx (1)

31-67: Clean component implementation with minor observations.

The FunctionConfigForm component is well-structured. A few observations:

  1. The file is named FTPConfigForm.tsx but exports FunctionConfigForm - consider aligning the naming for discoverability.

  2. The events array is hardcoded inside the component. If these events are FTP-specific constants, consider extracting them:

const FTP_EVENTS = [
    { name: 'onCreate', description: 'Triggered when a new file is created' },
    { name: 'onDelete', description: 'Triggered when a file is deleted' }
] as const;
workspaces/ballerina/ballerina-visualizer/src/views/GraphQLDiagram/index.tsx (1)

478-478: Consistent migration to payloadContext pattern.

Both FormTypeEditor usages have been correctly updated from isGraphql={true} to payloadContext={{protocol: "GRAPHQL"}}, maintaining consistency with the broader PR changes.

Also applies to: 512-512

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

1578-1578: Consistent payloadContext usage in default form modal.

The default form's type editor modal correctly uses the GraphQL payload context without additional filtering.


1447-1452: filterType: "INPUT" is GraphQL-specific context for variable declarations.

The payloadContext for the VariableForm includes filterType: "INPUT", which is intentionally used for GraphQL variable type declarations. This value prevents the inclusion of JSON/XML/CSV-specific data type categories that are added for other protocols, keeping the type editor focused on GraphQL input types appropriate for variable declarations.

workspaces/ballerina/ballerina-visualizer/src/views/BI/TypeEditor/utils.tsx (1)

47-47: Function signature extended to support payload context.

The getTypes function now accepts an optional payloadContext parameter, enabling protocol-aware type filtering. This is a backward-compatible change.

workspaces/ballerina/ballerina-visualizer/src/views/BI/TypeEditor/index.tsx (1)

59-61: Good refactor: Deriving isGraphql from payloadContext.

This change correctly centralizes protocol detection logic, making the component more flexible for supporting different payload contexts (GraphQL, FTP, etc.) without requiring separate boolean props.

workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/index.tsx (1)

1355-1373: Panel title logic appears inverted.

The condition selectedFTPHandler !== "onDelete" shows "On Create Handler Configuration" when the handler is NOT "onDelete", but this seems backwards. When selectedFTPHandler is undefined or any value other than "onDelete", it shows "On Create", which may not be correct for all cases.

Please verify the title logic is correct. Consider using a more explicit condition:

                             <PanelContainer
-                                    title={selectedFTPHandler !=="onDelete" ? "On Create Handler Configuration" : "On Delete Handler Configuration"}
+                                    title={selectedFTPHandler === "onDelete" ? "On Delete Handler Configuration" : `${selectedFTPHandler || 'On Create'} Handler Configuration`}
                                     show={showForm}

Comment on lines 86 to 92
console.log(`>>> Processing property: ${key}`, {
valueType: expression.valueType,
valueTypeConstraint: expression.valueTypeConstraint,
hasTypeMembers: !!expression.typeMembers,
typeMembersLength: expression.typeMembers?.length || 0,
typeMembers: expression.typeMembers
});
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

Remove debug console logs.

These verbose console logs should be removed before merging to production. If logging is needed for troubleshooting, consider using a proper logging framework that can be controlled via environment variables.

Apply this diff to remove the debug logs:

-            console.log(`>>> Processing property: ${key}`, {
-                valueType: expression.valueType,
-                valueTypeConstraint: expression.valueTypeConstraint,
-                hasTypeMembers: !!expression.typeMembers,
-                typeMembersLength: expression.typeMembers?.length || 0,
-                typeMembers: expression.typeMembers
-            });
-
📝 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
console.log(`>>> Processing property: ${key}`, {
valueType: expression.valueType,
valueTypeConstraint: expression.valueTypeConstraint,
hasTypeMembers: !!expression.typeMembers,
typeMembersLength: expression.typeMembers?.length || 0,
typeMembers: expression.typeMembers
});
🤖 Prompt for AI Agents
In
workspaces/ballerina/ballerina-side-panel/src/components/editors/ChoiceForm.tsx
around lines 86 to 92, remove the debug console.log that prints expression
details; delete the entire console.log(...) call and related interim object, or
replace it with a controlled logger (e.g., use an existing logging utility or
wrap with if (process.env.NODE_ENV !== 'production' && debugEnabled)
logger.debug(...)) so no verbose console output reaches production.

Comment on lines +137 to +136
console.log(">>> Final Dynamic Form Fields:", formFields)
console.log(">>> Final Dynamic Record Type Fields:", recordTypeFieldsForChoice)
return { formFields, recordTypeFieldsForChoice };
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

Remove debug console logs.

These debug logs should also be removed before merging to production.

Apply this diff to remove the debug logs:

-        console.log(">>> Final Dynamic Form Fields:", formFields)
-        console.log(">>> Final Dynamic Record Type Fields:", recordTypeFieldsForChoice)
📝 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
console.log(">>> Final Dynamic Form Fields:", formFields)
console.log(">>> Final Dynamic Record Type Fields:", recordTypeFieldsForChoice)
return { formFields, recordTypeFieldsForChoice };
return { formFields, recordTypeFieldsForChoice };
🤖 Prompt for AI Agents
In
workspaces/ballerina/ballerina-side-panel/src/components/editors/ChoiceForm.tsx
around lines 137 to 139, remove the two debug console.log statements that print
">>> Final Dynamic Form Fields:" and ">>> Final Dynamic Record Type Fields:" so
the function returns only the computed values; simply delete those console.log
lines and keep the existing return { formFields, recordTypeFieldsForChoice }
unchanged.

@@ -0,0 +1,539 @@
/* eslint-disable react-hooks/exhaustive-deps */
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

Avoid blanket ESLint disable for hooks rules.

Disabling react-hooks/exhaustive-deps for the entire file hides legitimate dependency issues. Instead, fix the actual dependency problems or add targeted disable comments with explanations for specific cases.

Remove the blanket disable and address the underlying issues in the useEffect hooks.

🤖 Prompt for AI Agents
In
workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/Forms/FTPForm/index.tsx
around line 1, remove the top-line blanket ESLint disable for
react-hooks/exhaustive-deps and instead resolve each useEffect dependency issue:
review every useEffect, add missing dependencies (or memoize functions/values
with useCallback/useMemo), and if a dependency is intentionally omitted, add a
single-line eslint-disable-next-line comment immediately above that useEffect
with a brief justification comment; after changes, run the linter to confirm no
remaining hook dependency warnings.

Comment on lines 232 to 269
const handleTypeCreated = (type: Type | string) => {
// When a type is created, set it as the payload type for the DATA_BINDING parameter
const defaultParamIndex = functionModel.parameters.findIndex(param => param.kind === "REQUIRED" && param.name.value === "content");
const defaultParam = functionModel.parameters?.find(param => param.kind === "REQUIRED" && param.name.value === "content");
const payloadParam = functionModel.parameters?.find(param => param.kind === "DATA_BINDING");
if (payloadParam) {
const defaultParamModel = { ...defaultParam };
const updatedPayloadModel = { ...payloadParam };
updatedPayloadModel.name.value = "content";
const typeValue = typeof type === 'string' ? type : type.name;
updatedPayloadModel.type.value = selectType(typeValue, functionModel.properties.stream?.enabled);
updatedPayloadModel.enabled = true;

defaultParamModel.enabled = false; // Disable the default content parameter

// Find the index of the payload parameter
const index = functionModel.parameters.findIndex(param => param.kind === "DATA_BINDING");
if (index >= 0) {
const updatedParameters = [...functionModel.parameters];
updatedParameters[index] = updatedPayloadModel;

// Update canDataBind property to enabled
const updatedFunctionModel = {
...functionModel,
parameters: updatedParameters
};
setFunctionModel(updatedFunctionModel);
}

// Find the index of the payload parameter

if (defaultParamIndex >= 0) {
const updatedParameters = [...functionModel.parameters];
updatedParameters[defaultParamIndex] = updatedPayloadModel;

// Update canDataBind property to enabled
const updatedFunctionModel = {
...functionModel,
parameters: updatedParameters
};
setFunctionModel(updatedFunctionModel);
}
}
// Close the modal
setIsTypeEditorOpen(false);
};
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

Logic issue in handleTypeCreated: Confusing dual updates and mutations.

This function has several issues:

  1. Direct mutation of updatedPayloadModel.name.value (line 240) and defaultParamModel.enabled (line 245) instead of immutable updates.
  2. Overwriting state twice: Lines 249-258 update state, then lines 263-273 update it again, but the second update uses updatedPayloadModel instead of defaultParamModel, effectively ignoring the changes to defaultParamModel.
  3. Sequential setFunctionModel calls will be batched in React 18, so only the last one takes effect.

Consider consolidating the logic:

     const handleTypeCreated = (type: Type | string) => {
-        // When a type is created, set it as the payload type for the DATA_BINDING parameter
-        const defaultParamIndex = functionModel.parameters.findIndex(param => param.kind === "REQUIRED" && param.name.value === "content");
-        const defaultParam = functionModel.parameters?.find(param => param.kind === "REQUIRED" && param.name.value === "content");
         const payloadParam = functionModel.parameters?.find(param => param.kind === "DATA_BINDING");
+        
         if (payloadParam) {
-            const defaultParamModel = { ...defaultParam };
-            const updatedPayloadModel = { ...payloadParam };
-            updatedPayloadModel.name.value = "content";
             const typeValue = typeof type === 'string' ? type : type.name;
-            updatedPayloadModel.type.value = selectType(typeValue, functionModel.properties.stream?.enabled);
-            updatedPayloadModel.enabled = true;
-
-            defaultParamModel.enabled = false; // Disable the default content parameter
-
-            // Find the index of the payload parameter
-            const index = functionModel.parameters.findIndex(param => param.kind === "DATA_BINDING");
-            if (index >= 0) {
-                const updatedParameters = [...functionModel.parameters];
-                updatedParameters[index] = updatedPayloadModel;
-
-                // Update canDataBind property to enabled
-                const updatedFunctionModel = {
-                    ...functionModel,
-                    parameters: updatedParameters
-                };
-                setFunctionModel(updatedFunctionModel);
-            }
-
-            // Find the index of the payload parameter
-
-            if (defaultParamIndex >= 0) {
-                const updatedParameters = [...functionModel.parameters];
-                updatedParameters[defaultParamIndex] = updatedPayloadModel;
-
-                // Update canDataBind property to enabled
-                const updatedFunctionModel = {
-                    ...functionModel,
-                    parameters: updatedParameters
-                };
-                setFunctionModel(updatedFunctionModel);
-            }
+            const updatedParameters = functionModel.parameters.map(param => {
+                if (param.kind === "DATA_BINDING") {
+                    return {
+                        ...param,
+                        name: { ...param.name, value: "content" },
+                        type: { ...param.type, value: selectType(typeValue, functionModel.properties.stream?.enabled) },
+                        enabled: true
+                    };
+                }
+                return param;
+            });
+            
+            setFunctionModel({
+                ...functionModel,
+                parameters: updatedParameters
+            });
         }
-        // Close the modal
         setIsTypeEditorOpen(false);
     };

Comment on lines 440 to 468
const handleNewFTPFunction = (selectedHandler: string) => {
// rpcClient
// .getServiceDesignerRpcClient()
// .getFunctionModel({ type: "ftp", functionName: "remote" })
// .then((res) => {
// console.log("New Function Model: ", res.function);
// setFunctionModel(res.function);
// setIsNew(true);
// setShowForm(true);
// });
setShowForm(true);
// handleNewFunctionClose();
handleFunctionConfigClose();
setIsSaving(false);
};
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

Dead/commented code should be removed or implemented.

This function contains substantial commented-out code that appears to be placeholder implementation. The function currently just shows the form without fetching any model data, which may cause issues.

Either implement the RPC call or remove the commented code:

     const handleNewFTPFunction = (selectedHandler: string) => {
-        // rpcClient
-        //     .getServiceDesignerRpcClient()
-        //     .getFunctionModel({ type: "ftp", functionName: "remote" })
-        //     .then((res) => {
-        //         console.log("New Function Model: ", res.function);
-        //         setFunctionModel(res.function);
-        //         setIsNew(true);
-        //         setShowForm(true);
-        //     });
+        setSelectedFTPHandler(selectedHandler);
+        setIsNew(true);
         setShowForm(true);
-        // handleNewFunctionClose();
         handleFunctionConfigClose();
         setIsSaving(false);
     };
🤖 Prompt for AI Agents
In
workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/index.tsx
around lines 440-454, the function handleNewFTPFunction contains large
commented-out RPC code that is either dead or unfinished; remove the commented
block or fully implement the RPC call. If implementing: call
rpcClient.getServiceDesignerRpcClient().getFunctionModel({ type: "ftp",
functionName: "remote" }), await the result, setFunctionModel(res.function),
setIsNew(true), setShowForm(true), setIsSaving(false), close any config modals,
and add error handling and a loading state. If removing: delete the commented
code and keep the minimal logic (setShowForm, handleFunctionConfigClose,
setIsSaving(false)) or add a clear TODO comment indicating RPC implementation
required.

Comment on lines 550 to 568
const handleFunctionEdit = (value: FunctionModel) => {
setFunctionModel(value);
setSelectedFTPHandler(value.metadata.label);
setIsNew(false);
setShowForm(true);
};
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

Setting selectedFTPHandler on edit but not on new handler creation.

selectedFTPHandler is set in handleFunctionEdit but handleNewFTPFunction doesn't set it, even though it receives selectedHandler as a parameter. This may cause the FTP form panel title (line 1357) to display incorrectly.

The selectedHandler parameter in handleNewFTPFunction should be used to set state:

     const handleNewFTPFunction = (selectedHandler: string) => {
+        setSelectedFTPHandler(selectedHandler);
         setShowForm(true);
📝 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 handleFunctionEdit = (value: FunctionModel) => {
setFunctionModel(value);
setSelectedFTPHandler(value.metadata.label);
setIsNew(false);
setShowForm(true);
};
const handleNewFTPFunction = (selectedHandler: string) => {
setSelectedFTPHandler(selectedHandler);
setShowForm(true);
};
🤖 Prompt for AI Agents
In
workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/index.tsx
around lines 550-555, handleFunctionEdit sets selectedFTPHandler but
handleNewFTPFunction (which receives selectedHandler) does not—causing the FTP
form panel title to be wrong; update handleNewFTPFunction to
setSelectedFTPHandler(selectedHandler) (and ensure it still sets isNew true,
setFunctionModel appropriately, and setShowForm(true)) so the form title and
state are consistent for new handler creation.

Comment on lines 986 to 1001
<Button appearance="primary" tooltip="Add Handler" onClick={onSelectAddHandler}>
<Codicon name="add" sx={{ marginRight: 8 }} /> <ButtonText>Resource</ButtonText>
</Button>
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

Button text inconsistency: "Resource" should be "Handler" for FTP.

The button label says "Resource" but this is the FTP File Handlers section where "Handler" would be more appropriate and consistent with the section title.

                                                 {!haveServiceTypeName && enabledHandlers.length > 0 && (
                                                     <Button appearance="primary" tooltip="Add Handler" onClick={onSelectAddHandler}>
-                                                        <Codicon name="add" sx={{ marginRight: 8 }} /> <ButtonText>Resource</ButtonText>
+                                                        <Codicon name="add" sx={{ marginRight: 8 }} /> <ButtonText>Handler</ButtonText>
                                                     </Button>
                                                 )}
📝 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
<Button appearance="primary" tooltip="Add Handler" onClick={onSelectAddHandler}>
<Codicon name="add" sx={{ marginRight: 8 }} /> <ButtonText>Resource</ButtonText>
</Button>
<Button appearance="primary" tooltip="Add Handler" onClick={onSelectAddHandler}>
<Codicon name="add" sx={{ marginRight: 8 }} /> <ButtonText>Handler</ButtonText>
</Button>
🤖 Prompt for AI Agents
In
workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/index.tsx
around lines 986 to 988, the button label currently reads "Resource" but should
read "Handler" to match the FTP File Handlers section; update the ButtonText
content to "Handler" so the UI is consistent with the section title and other
handler-related controls.

Comment on lines +994 to +1024
{/* {enabledHandlers
.filter((resource) => {
const search = searchValue.toLowerCase();
const nameMatch = resource.name && resource.name.toLowerCase().includes(search);
const iconMatch = resource.icon && resource.icon.toLowerCase().includes(search);
return nameMatch || iconMatch;
})
.filter((resource) => resource.type === DIRECTORY_MAP.RESOURCE)
.map((resource, index) => (
<ResourceAccordionV2
key={`${index}-${resource.name}`}
resource={resource}
readOnly={serviceModel.properties.hasOwnProperty('serviceTypeName')}
onEditResource={handleFunctionEdit}
onDeleteResource={handleFunctionDelete}
onResourceImplement={handleOpenDiagram}
/>
))} */}
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

Remove commented-out code block.

This large commented-out code block adds noise and should be removed. If this represents planned functionality, consider tracking it in a separate issue instead.

🤖 Prompt for AI Agents
In
workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/index.tsx
around lines 994 to 1011, there is a large commented-out JSX block that should
be removed to reduce noise; delete the entire commented block (including the
surrounding {/* ... */} markers) and, if this represents planned functionality,
create or reference a tracker/issue instead of leaving commented code in the
file so the codebase stays clean.

Comment on lines +77 to +143
if (payloadContext?.protocol === "FTP") {

categories = categories
.filter((category) => category.category === "User-Defined")
.map((category) => ({
...category,
items: category.items.filter((item) => item.labelDetails?.description === "Record")
}))
.filter((category) => category.items.length > 0);

if (payloadContext?.filterType === "JSON") {
categories = [...categories,
{
category: "Data Types",
sortText: "2",
items: [
{
name: "json",
insertText: "json",
type: "type-parameter",
labelDetails: {
detail: "Data Types",
description: "Built-in JSON type"
}
}
]
}
];
} else if (payloadContext?.filterType === "XML") {
categories = [...categories,
{
category: "Data Types",
sortText: "2",
items: [
{
name: "xml",
insertText: "xml",
type: "type-parameter",
labelDetails: {
detail: "Data Types",
description: "Built-in XML type"
}
}
]
}
];
} else if (payloadContext?.filterType === "CSV") {
categories = [...categories,
{
category: "Structural Types",
sortText: "3",
items: [
{
name: "string[]",
insertText: "string[]",
type: "type-parameter",
labelDetails: {
detail: "Structural Types",
description: "Built-in string array type"
}
}
]
}
];

}
}
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

FTP-specific type filtering logic is functional but has potential issues.

The FTP handling logic correctly:

  1. Filters to User-Defined Records only
  2. Injects built-in types based on filterType

However, there are a few concerns:

  1. Potential runtime error on line 144: After FTP filtering, sortText could be undefined for categories, causing a.sortText.localeCompare(b.sortText) to throw. The injected categories have explicit sortText, but filtered categories use TYPE_CATEGORY_ORDER.find() which may return undefined.

  2. Code duplication: The category object structures for JSON, XML, and CSV are very similar.

Consider adding a null check in the sort comparator:

-    return categories.sort((a, b) => a.sortText.localeCompare(b.sortText));
+    return categories.sort((a, b) => (a.sortText ?? "z").localeCompare(b.sortText ?? "z"));

And optionally consolidate the built-in type injection:

const BUILTIN_FTP_TYPES: Record<string, { category: string; sortText: string; name: string; description: string }> = {
    JSON: { category: "Data Types", sortText: "2", name: "json", description: "Built-in JSON type" },
    XML: { category: "Data Types", sortText: "2", name: "xml", description: "Built-in XML type" },
    CSV: { category: "Structural Types", sortText: "3", name: "string[]", description: "Built-in string array type" }
};
🤖 Prompt for AI Agents
In workspaces/ballerina/ballerina-visualizer/src/views/BI/TypeEditor/utils.tsx
around lines 77-143, the FTP branch injects built-in categories but later
sorting can throw because some categories may have undefined sortText; also the
JSON/XML/CSV injection blocks are duplicated. Fix by (1) making the comparator
null-safe: coerce undefined sortText to a stable fallback (e.g., empty string or
a high/low sentinel) before calling localeCompare, and (2) replace the three
nearly-identical injection blocks with a single lookup map (keyed by
payloadContext.filterType) that provides category, sortText, item name and
description, then conditionally push the mapped category when present. Ensure
filtered categories also get an explicit sortText (from TYPE_CATEGORY_ORDER or
the fallback) so no undefined values remain.

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

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b5ebf99 and a8a22da.

⛔ Files ignored due to path filters (2)
  • workspaces/common-libs/font-wso2-vscode/src/icons/bi-file.svg is excluded by !**/*.svg
  • workspaces/common-libs/font-wso2-vscode/src/icons/bi-ftp.svg is excluded by !**/*.svg
📒 Files selected for processing (2)
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/ComponentListView/FileIntegrationPanel.tsx (3 hunks)
  • workspaces/ballerina/component-diagram/src/components/nodes/EntryNode/components/GeneralWidget.tsx (1 hunks)
🧰 Additional context used
📓 Path-based instructions (5)
workspaces/ballerina/component-diagram/src/components/nodes/**/*.{ts,tsx}

📄 CodeRabbit inference engine (workspaces/ballerina/component-diagram/AGENTS.md)

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

Files:

  • workspaces/ballerina/component-diagram/src/components/nodes/EntryNode/components/GeneralWidget.tsx
workspaces/ballerina/component-diagram/src/components/nodes/EntryNode/components/GeneralWidget.tsx

📄 CodeRabbit inference engine (workspaces/ballerina/component-diagram/AGENTS.md)

For regular services with more than 3 functions, show only the first 2 functions with a 'View All' button; for services with 3 or fewer functions, show all functions

Files:

  • workspaces/ballerina/component-diagram/src/components/nodes/EntryNode/components/GeneralWidget.tsx
workspaces/ballerina/component-diagram/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (workspaces/ballerina/component-diagram/AGENTS.md)

workspaces/ballerina/component-diagram/src/**/*.{ts,tsx}: Use TypeScript 5.8.3 with strict type checking enabled for all source files
Define all constants (node types, sizing, spacing) in src/resources/constants.ts and import them where needed instead of hardcoding values
All async operations and promise handling in diagram utilities should use async/await syntax instead of .then() callbacks

Files:

  • workspaces/ballerina/component-diagram/src/components/nodes/EntryNode/components/GeneralWidget.tsx
workspaces/ballerina/component-diagram/src/components/**/*.tsx

📄 CodeRabbit inference engine (workspaces/ballerina/component-diagram/AGENTS.md)

workspaces/ballerina/component-diagram/src/components/**/*.tsx: Use Emotion for CSS-in-JS styling instead of inline styles or external CSS files
Use React 18.2.0 features including concurrent rendering and automatic batching; avoid class components in favor of functional components with hooks

Files:

  • workspaces/ballerina/component-diagram/src/components/nodes/EntryNode/components/GeneralWidget.tsx
workspaces/ballerina/component-diagram/src/components/nodes/EntryNode/components/**/*.tsx

📄 CodeRabbit inference engine (workspaces/ballerina/component-diagram/AGENTS.md)

Implement lazy expansion of functions: only render function items when they are visible to improve performance for large function lists

Files:

  • workspaces/ballerina/component-diagram/src/components/nodes/EntryNode/components/GeneralWidget.tsx
🧠 Learnings (13)
📚 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/EntryNodeWidget.tsx : Route EntryNode rendering to specialized widgets based on service type: use AIServiceWidget for 'ai:Service', GraphQLServiceWidget for 'graphql:Service', and GeneralWidget for HTTP and other services

Applied to files:

  • workspaces/ballerina/component-diagram/src/components/nodes/EntryNode/components/GeneralWidget.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/component-diagram/src/components/nodes/EntryNode/components/GeneralWidget.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/component-diagram/src/components/nodes/EntryNode/components/GeneralWidget.tsx
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/ComponentListView/FileIntegrationPanel.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/GeneralWidget.tsx : For regular services with more than 3 functions, show only the first 2 functions with a 'View All' button; for services with 3 or fewer functions, show all functions

Applied to files:

  • workspaces/ballerina/component-diagram/src/components/nodes/EntryNode/components/GeneralWidget.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/component-diagram/src/components/nodes/EntryNode/components/GeneralWidget.tsx
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/ComponentListView/FileIntegrationPanel.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/**/*.{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/component-diagram/src/components/nodes/EntryNode/components/GeneralWidget.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/component-diagram/src/components/nodes/EntryNode/components/GeneralWidget.tsx
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/ComponentListView/FileIntegrationPanel.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/**/*.test.{ts,tsx} : Create snapshot tests for all node widgets and verify visual consistency across renders

Applied to files:

  • workspaces/ballerina/component-diagram/src/components/nodes/EntryNode/components/GeneralWidget.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-visualizer/src/views/BI/ComponentListView/FileIntegrationPanel.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/ComponentListView/FileIntegrationPanel.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-visualizer/src/views/BI/ComponentListView/FileIntegrationPanel.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-visualizer/src/views/BI/ComponentListView/FileIntegrationPanel.tsx
📚 Learning: 2025-11-25T06:34:10.812Z
Learnt from: CR
Repo: wso2/vscode-extensions PR: 0
File: workspaces/ballerina/component-diagram/AGENTS.md:0-0
Timestamp: 2025-11-25T06:34:10.812Z
Learning: Applies to workspaces/ballerina/component-diagram/src/components/DiagramContext.tsx : Use DiagramContext (React Context API) for state management across the diagram component, including expandedNodes and graphQLGroupOpen state

Applied to files:

  • workspaces/ballerina/ballerina-visualizer/src/views/BI/ComponentListView/FileIntegrationPanel.tsx
🔇 Additional comments (3)
workspaces/ballerina/component-diagram/src/components/nodes/EntryNode/components/GeneralWidget.tsx (1)

123-126: Pattern and icons confirmed.

The FTP and file icon cases correctly follow the established pattern in the switch statement and are consistent with existing protocol icon mappings. The icon names bi-ftp and bi-file are already validated through their use in other components (FileIntegrationPanel.tsx, project-artifacts.ts), confirming they exist in the ui-toolkit library.

workspaces/ballerina/ballerina-visualizer/src/views/BI/ComponentListView/FileIntegrationPanel.tsx (2)

19-19: LGTM: Standardized icon component usage.

Replacing Codicon with the Icon component from @wso2/ui-toolkit aligns with best practices for using centralized UI components.


63-70: Verify whether FTP triggers have the expected type field value.

The code filters items by type === "file" but distinguishes icon display by moduleName ("ftp" or "file"). This pattern suggests FTP triggers should have type="file" with moduleName="ftp". However, the actual type value assigned to FTP trigger items cannot be confirmed from the codebase. Verify with backend code or test data that FTP triggers are assigned type="file" to ensure they're properly included in the filtered list.

Comment on lines +84 to +100
// TODO: This should be removed once the new icons are added to the BE API.
export function getFileIntegrationIcon(item: ServiceModel) {
return getCustomFileIntegrationIcon(item.moduleName) || <img src={item.icon} alt={item.name} style={{ width: "38px" }} />;
}

// INFO: This is a temporary function to get the custom icon for the file integration triggers.
// TODO: This should be removed once the new icons are added to the BE API.
export function getCustomFileIntegrationIcon(type: string) {
switch (type) {
case "ftp":
return <Icon name="bi-ftp" />;
case "file":
return <Icon name="bi-file" />;
default:
return null;
}
}
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

🧩 Analysis chain

🏁 Script executed:

fd -type f -name "FileIntegrationPanel.tsx" -o -name "FileIntegrationPanel.ts"

Repository: wso2/vscode-extensions

Length of output: 236


🏁 Script executed:

fd "FileIntegrationPanel.tsx"

Repository: wso2/vscode-extensions

Length of output: 163


🏁 Script executed:

cat -n workspaces/ballerina/ballerina-visualizer/src/views/BI/ComponentListView/FileIntegrationPanel.tsx | sed -n '80,105p'

Repository: wso2/vscode-extensions

Length of output: 946


🏁 Script executed:

# Check where Icon component comes from and how it's imported
head -50 workspaces/ballerina/ballerina-visualizer/src/views/BI/ComponentListView/FileIntegrationPanel.tsx

Repository: wso2/vscode-extensions

Length of output: 2122


🏁 Script executed:

# Search for usages of getFileIntegrationIcon throughout the codebase
rg "getFileIntegrationIcon" -B 2 -A 2

Repository: wso2/vscode-extensions

Length of output: 1586


🏁 Script executed:

# Check ButtonCard component to see what it expects for the icon prop
rg "interface ButtonCardProps|type ButtonCardProps" -A 10

Repository: wso2/vscode-extensions

Length of output: 1204


🏁 Script executed:

# Check how ButtonCard renders the icon
cat -n workspaces/ballerina/ballerina-visualizer/src/components/ButtonCard/index.tsx | head -100

Repository: wso2/vscode-extensions

Length of output: 3855


🏁 Script executed:

cat -n workspaces/ballerina/ballerina-visualizer/src/components/ButtonCard/index.tsx | sed -n '100,150p'

Repository: wso2/vscode-extensions

Length of output: 1720


🏁 Script executed:

# Search for Icon component definition in @wso2/ui-toolkit
rg "Icon" node_modules/@wso2/ui-toolkit -l | head -5

Repository: wso2/vscode-extensions

Length of output: 135


🏁 Script executed:

# Check package.json to see ui-toolkit dependency
find . -name "package.json" -type f | xargs grep -l "@wso2/ui-toolkit" | head -3

Repository: wso2/vscode-extensions

Length of output: 242


🏁 Script executed:

# Check the ui-toolkit version
cat workspaces/ballerina/ballerina-visualizer/package.json | grep -A 2 -B 2 "@wso2/ui-toolkit"

Repository: wso2/vscode-extensions

Length of output: 274


🏁 Script executed:

# Find the ui-toolkit workspace package
find . -path "*/node_modules" -prune -o -name "ui-toolkit" -type d -print

Repository: wso2/vscode-extensions

Length of output: 101


🏁 Script executed:

# Check Icon component in ui-toolkit
find workspaces/common-libs/ui-toolkit -name "*.tsx" -o -name "*.ts" | xargs rg "export.*Icon" | head -20

Repository: wso2/vscode-extensions

Length of output: 2741


🏁 Script executed:

# Check the Icon component implementation
cat workspaces/common-libs/ui-toolkit/src/components/Icon/Icon.tsx

Repository: wso2/vscode-extensions

Length of output: 1683


🏁 Script executed:

# Check the font-wso2-vscode package
find . -path "*/node_modules" -prune -o -name "*font*wso2*" -type d -print | grep -v node_modules

Repository: wso2/vscode-extensions

Length of output: 107


🏁 Script executed:

# Check what icons are available in the font
ls -la workspaces/common-libs/font-wso2-vscode/dist/

Repository: wso2/vscode-extensions

Length of output: 158


Clarify parameter naming and verify icon availability.

The helper functions have issues that need attention:

  1. Parameter naming inconsistency: getCustomFileIntegrationIcon(type: string) uses parameter name type, but it's called with item.moduleName (line 86). Rename the parameter to moduleName for clarity.

  2. Icon name verification: The Icon component references "bi-ftp" and "bi-file". Verify these icon names exist in the font-wso2-vscode package or consider using SVG icon components from src/resources/icons/.

  3. Sizing inconsistency: The Icon component renders at 16×14px, but the fallback img uses hardcoded width: "38px" (line 86), causing visual inconsistency. Align the sizing.

Rename the parameter for clarity:

-export function getCustomFileIntegrationIcon(type: string) {
-    switch (type) {
+export function getCustomFileIntegrationIcon(moduleName: string) {
+    switch (moduleName) {

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-side-panel/src/components/editors/ChoiceForm.tsx (1)

150-150: Remove debug console log.

This console log should be removed before merging to production. If logging is needed for troubleshooting, consider using a proper logging framework that can be controlled via environment variables.

🔎 Proposed fix
-                        console.log("Choice Form Index:", Number(e.target.value))
workspaces/ballerina/ballerina-extension/package.json (1)

1164-1169: Confirm the intentional duplication of the icon glyph.

The distro-design-view icon now uses fontCharacter \f175, which is identical to distro-agent-view (line 1038). This appears to be a deliberate change from the previous value (\f16e to \f175).

The two icons are used in distinctly different contexts:

  • distro-agent-view: Used for visualization and viewing operations (Show Visualizer, View Type Diagram, View Configurations)
  • distro-design-view: Used for design and editing operations (Open Service Designer, Edit test suite, Edit test case)

Please confirm whether sharing the same glyph is intentional, as the different naming and usage patterns suggest they may have been intended to have distinct visual representations.

♻️ Duplicate comments (8)
workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/Forms/FTPForm/Parameters/Parameters.tsx (2)

93-107: Remove unused formatParameterLabel function.

This function is defined but never called (the only usage is commented out on lines 119-124). Either use it or remove it to reduce code complexity.

🔎 Proposed fix
-    const formatParameterLabel = (typeValue: string, hasStreamProperty: boolean, isStreamEnabled: boolean, hasDataBinding: boolean) => {
-        if (!hasStreamProperty || !hasDataBinding) {
-            return typeValue;
-        }
-
-        if (isStreamEnabled) {
-            const value = typeValue.endsWith("[]") ? typeValue.slice(0, -2) : typeValue;
-            const value2 = value.startsWith("stream<") && value.endsWith(", error>") ? value.slice(7, -8) : value;
-            return `stream<${value2}>`;
-        } else {
-            const value = typeValue.endsWith("[]") ? typeValue.slice(0, -2) : typeValue;
-            const value2 = value.startsWith("stream<") && value.endsWith(", error>") ? value.slice(7, -8) : value;
-            return `${value2}[]`;
-        }
-    };
-

139-146: Potential runtime error when onEditClick is undefined.

onEditClick is optional in the props interface but is called without a null check on lines 139 and 146. Use optional chaining to prevent runtime errors.

🔎 Proposed fix
                                     <div
                                         data-test-id={`${param.name.value}-param`}
                                         className={readonly ? disabledHeaderLabel : headerLabelStyles}
-                                        onClick={() => !readonly && onEditClick(param)}
+                                        onClick={() => !readonly && onEditClick?.(param)}
                                     >
                                         {label}
                                     </div>
                                     <ActionIconWrapper>
                                         {!readonly && (
                                             <EditIconWrapper>
-                                                <Codicon name="edit" onClick={() => onEditClick(param)} />
+                                                <Codicon name="edit" onClick={() => onEditClick?.(param)} />
                                             </EditIconWrapper>
                                         )}
workspaces/ballerina/ballerina-side-panel/src/components/editors/ChoiceForm.tsx (2)

86-92: Remove commented-out debug code.

This commented-out debug code was flagged in previous reviews and should be removed before merging.


134-135: Remove debug console logs.

These debug logs were flagged in previous reviews and should be removed before merging to production.

workspaces/ballerina/ballerina-visualizer/src/views/BI/ComponentListView/FileIntegrationPanel.tsx (1)

84-99: Icon helper naming and sizing could be tightened up.

getCustomFileIntegrationIcon is passed item.moduleName but the parameter is named type, and the fallback <img> uses a much larger width (38px) than the Icon component. Consider renaming the parameter to moduleName (or similar) and aligning the bitmap size with the vector icon for consistent visuals. Also double‑check that "bi-ftp" / "bi-file" exist in font-wso2-vscode.

Please verify icon names and sizing against @wso2/ui-toolkit / font-wso2-vscode docs or by checking the rendered UI.

workspaces/ballerina/ballerina-visualizer/src/views/BI/TypeEditor/utils.tsx (1)

47-145: Guard against undefined sortText and consider consolidating FTP injection logic.

sortText is looked up via TYPE_CATEGORY_ORDER.find(...)?.sortText and then used unconditionally in categories.sort((a, b) => a.sortText.localeCompare(b.sortText)). If the LS ever introduces a category label that’s not in TYPE_CATEGORY_ORDER, sortText will be undefined and localeCompare will throw.

You can make this robust by normalizing to a fallback string:

-    return categories.sort((a, b) => a.sortText.localeCompare(b.sortText));
+    return categories.sort((a, b) => (a.sortText ?? "z").localeCompare(b.sortText ?? "z"));

Optionally, the three FTP blocks that append JSON/XML/CSV categories can be collapsed into a small lookup map keyed by payloadContext.filterType to remove duplication and keep category metadata in one place.

Please re‑run the TypeEditor UI (HTTP/GraphQL/FTP flows) after changing the comparator to ensure categories still appear in the intended order.

workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/Forms/FTPForm/Parameters/ParamEditor.tsx (1)

28-46: Guard optional onCancel to avoid runtime errors.

onCancel is optional in ParamProps but handleOnCancel calls it unconditionally. If the parent omits this prop, clicking “Back” will throw.

Use optional chaining (or a default no‑op) when invoking it:

-    const handleOnCancel = () => {
-        onCancel(param);
-    };
+    const handleOnCancel = () => {
+        onCancel?.(param);
+    };

Please verify all current ParamEditor call sites either provide onCancel or that this guard is added before merging.

workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/Forms/FTPForm/index.tsx (1)

224-291: Avoid mutating parameter objects in handleTypeCreated / handleDeleteContentSchema.

handleTypeCreated and handleDeleteContentSchema both mutate nested state:

  • updatedPayloadModel.name.value = "content";
  • updatedPayloadModel.type.value = …;
  • defaultParamModel.enabled = false;
  • p.type.value = p.type.placeholder;

and then perform multiple setFunctionModel calls with partially updated arrays. This mixes mutation with immutable updates and makes the final parameter state harder to reason about (React may batch the set calls, and you also overwrite the same parameter twice in handleTypeCreated).

Refactor these to build new parameter objects and a single updated functionModel, e.g.:

-    const handleTypeCreated = (type: Type | string) => {
-        // When a type is created, set it as the payload type for the DATA_BINDING parameter
-        const defaultParamIndex = functionModel.parameters.findIndex(param => param.kind === "REQUIRED" && param.name.value === "content");
-        const defaultParam = functionModel.parameters?.find(param => param.kind === "REQUIRED" && param.name.value === "content");
-        const payloadParam = functionModel.parameters?.find(param => param.kind === "DATA_BINDING");
-        if (payloadParam) {
-            const defaultParamModel = { ...defaultParam };
-            const updatedPayloadModel = { ...payloadParam };
-            updatedPayloadModel.name.value = "content";
-            const typeValue = typeof type === 'string' ? type : type.name;
-            updatedPayloadModel.type.value = selectType(typeValue, functionModel.properties.stream?.enabled) ;
-            updatedPayloadModel.enabled = true;
-            
-            defaultParamModel.enabled = false; // Disable the default content parameter
-
-            // ... two separate updatedParameters/setFunctionModel blocks ...
-        }
-        setIsTypeEditorOpen(false);
-    };
+    const handleTypeCreated = (type: Type | string) => {
+        if (!functionModel) {
+            setIsTypeEditorOpen(false);
+            return;
+        }
+        const typeValue = typeof type === "string" ? type : type.name;
+        const updatedParameters = functionModel.parameters.map((param) => {
+            if (param.kind === "DATA_BINDING") {
+                return {
+                    ...param,
+                    name: { ...param.name, value: "content" },
+                    type: {
+                        ...param.type,
+                        value: selectType(typeValue, functionModel.properties?.stream?.enabled),
+                    },
+                    enabled: true,
+                };
+            }
+            if (param.kind === "REQUIRED" && param.name?.value === "content") {
+                return { ...param, enabled: false };
+            }
+            return param;
+        });
+
+        setFunctionModel({ ...functionModel, parameters: updatedParameters });
+        setIsTypeEditorOpen(false);
+    };

and for handleDeleteContentSchema:

-    const updatedParameters = functionModel.parameters.map((p) => {
-        if (p.kind === "DATA_BINDING") {
-            p.type.value = p.type.placeholder;
-            return { ...p, enabled: true };
-        }
-        return p;
-    });
+    const updatedParameters = functionModel.parameters.map((p) => {
+        if (p.kind === "DATA_BINDING") {
+            return {
+                ...p,
+                type: { ...p.type, value: p.type.placeholder },
+                enabled: true,
+            };
+        }
+        return p;
+    });

This keeps updates immutable and removes the duplicate setFunctionModel calls.

After refactoring, retest creating, editing, and deleting the Content Schema to confirm parameter lists and stream wrapping behave as before.

🧹 Nitpick comments (5)
workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/Forms/FTPForm/Parameters/Parameters.tsx (3)

65-74: Remove duplicate CSS property.

Line 70 duplicates the display: flex; declaration from line 66.

🔎 Proposed fix
 const HeaderLabel = styled.div<CSSObject>`
     display: flex;
     background: var(--vscode-editor-background);
     border: 1px solid ${(props: { haveErrors: boolean; }) => props.haveErrors ? "red" : "var(--vscode-dropdown-border)"};
     margin: 8px 0;
-    display: flex;
     width: 100%;
     height: 32px;
     align-items: center;
 `;

76-81: Remove unused ParamDefault styled component.

The ParamDefault component is defined but never used in the rendering logic.

🔎 Proposed fix
-const ParamDefault = styled.span`
-    font-size: 13px;
-    color: var(--vscode-editorHint-foreground, #b0b0b0);
-    margin-left: 8px;
-    font-style: italic;
-`;
-
 export function Parameters(props: ParametersProps) {

115-125: Remove unused variable calculations.

Variables hasStreamProperty, isStreamEnabled, and hasDataBinding are calculated but only used in the commented-out code. Remove them along with the commented-out code and the unused formatParameterLabel function.

🔎 Proposed fix
                     {parameters.map((param: ParameterModel, index) => {
                         const readonly = param.editable === false;
-                        const hasStreamProperty = streamEnabled !== undefined;
-                        const isStreamEnabled = streamEnabled === true;
-                        const hasDataBinding = param.kind === "DATA_BINDING";
 
-                        // const formattedTypeValue = formatParameterLabel(
-                        //     param.type.value,
-                        //     hasStreamProperty,
-                        //     isStreamEnabled,
-                        //     hasDataBinding
-                        // );
                         const formattedTypeValue = param.type.value;
workspaces/ballerina/ballerina-side-panel/src/components/editors/ChoiceForm.tsx (1)

162-166: Move merged array creation outside the map callback.

The mergedRecordTypeFields array is recreated on every iteration. Move it outside the map callback to avoid unnecessary re-creation.

🔎 Proposed refactor
+            // Merge parent recordTypeFields with dynamically generated ones
+            const mergedRecordTypeFields = [
+                ...(recordTypeFields || []),
+                ...dynamicRecordTypeFields
+            ];
+
             <FormSection>
                 {dynamicFields.map((dfield, index) => {
-                    // Merge parent recordTypeFields with dynamically generated ones
-                    const mergedRecordTypeFields = [
-                        ...(recordTypeFields || []),
-                        ...dynamicRecordTypeFields
-                    ];
-
                     return (
                         <EditorFactory
workspaces/ballerina/ballerina-core/src/interfaces/service.ts (1)

127-133: Be careful: GeneralPayloadContext may break PayloadContext discriminated union.

By adding GeneralPayloadContext with protocol: string into PayloadContext, the protocol field is no longer a pure string‑literal discriminant ("HTTP" | "MESSAGE_BROKER"). Any existing code that relies on switch (ctx.protocol) or if (ctx.protocol === "HTTP") for exhaustive narrowing over PayloadContext may now lose type‑safety and fall back to a generic union.

If the only new protocols are known (e.g. "GRAPHQL", "FTP"), consider tightening this to a union of literals instead of string, or keeping GeneralPayloadContext separate from PayloadContext where full generality is needed.

Please run a TypeScript type‑check focusing on usages of PayloadContext (e.g. rg "PayloadContext") to ensure no narrowed control‑flow was degraded.

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a8a22da and 93c3d03.

📒 Files selected for processing (15)
  • workspaces/ballerina/ballerina-core/src/interfaces/service.ts
  • workspaces/ballerina/ballerina-extension/package.json
  • workspaces/ballerina/ballerina-extension/src/rpc-managers/bi-diagram/rpc-manager.ts
  • workspaces/ballerina/ballerina-side-panel/src/components/editors/ChoiceForm.tsx
  • workspaces/ballerina/ballerina-visualizer/src/components/EntryPointTypeCreator/index.tsx
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/ComponentListView/FileIntegrationPanel.tsx
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/Forms/FormGenerator/index.tsx
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/Forms/FormGeneratorNew/index.tsx
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/Forms/FTPForm/FTPConfigForm.tsx
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/Forms/FTPForm/Parameters/ParamEditor.tsx
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/Forms/FTPForm/Parameters/Parameters.tsx
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/Forms/FTPForm/index.tsx
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/index.tsx
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/TypeEditor/index.tsx
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/TypeEditor/utils.tsx
💤 Files with no reviewable changes (1)
  • workspaces/ballerina/ballerina-visualizer/src/components/EntryPointTypeCreator/index.tsx
✅ Files skipped from review due to trivial changes (1)
  • workspaces/ballerina/ballerina-extension/src/rpc-managers/bi-diagram/rpc-manager.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/Forms/FormGeneratorNew/index.tsx
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/TypeEditor/index.tsx
🧰 Additional context used
🧠 Learnings (22)
📚 Learning: 2025-12-16T13:47:11.133Z
Learnt from: kanushka
Repo: wso2/vscode-extensions PR: 1117
File: workspaces/ballerina/ballerina-visualizer/src/views/BI/Forms/FormGenerator/index.tsx:1183-1184
Timestamp: 2025-12-16T13:47:11.133Z
Learning: In workspaces/ballerina/ballerina-visualizer/src/views/BI/Forms/FormGenerator/index.tsx, the findMatchedType function intentionally uses module?.split('.').pop() to handle simple cases where the last segment of the module name is used for matching. Wildcard imports should be used for collision cases (when different modules have the same last segment), but this is not currently implemented as the code only handles the simple case for now.

Applied to files:

  • workspaces/ballerina/ballerina-visualizer/src/views/BI/TypeEditor/utils.tsx
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/ComponentListView/FileIntegrationPanel.tsx
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/Forms/FormGenerator/index.tsx
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/Forms/FTPForm/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/GraphQLServiceWidget.tsx : For GraphQL services, group functions by type (Query, Subscription, Mutation) and allow independent expand/collapse of each group. Default state: Query group open, Subscription/Mutation groups collapsed

Applied to files:

  • workspaces/ballerina/ballerina-visualizer/src/views/BI/TypeEditor/utils.tsx
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/Forms/FormGenerator/index.tsx
📚 Learning: 2025-11-25T06:34:10.812Z
Learnt from: CR
Repo: wso2/vscode-extensions PR: 0
File: workspaces/ballerina/component-diagram/AGENTS.md:0-0
Timestamp: 2025-11-25T06:34:10.812Z
Learning: Applies to workspaces/ballerina/component-diagram/src/resources/icons/**/*.tsx : Create separate SVG icon components in src/resources/icons/ for all diagram icons and import them as React components

Applied to files:

  • workspaces/ballerina/ballerina-visualizer/src/views/BI/ComponentListView/FileIntegrationPanel.tsx
  • workspaces/ballerina/ballerina-extension/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 React 18.2.0 features including concurrent rendering and automatic batching; avoid class components in favor of functional components with hooks

Applied to files:

  • workspaces/ballerina/ballerina-visualizer/src/views/BI/ComponentListView/FileIntegrationPanel.tsx
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/Forms/FTPForm/Parameters/ParamEditor.tsx
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/index.tsx
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/Forms/FTPForm/Parameters/Parameters.tsx
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/Forms/FormGenerator/index.tsx
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/Forms/FTPForm/FTPConfigForm.tsx
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/Forms/FTPForm/index.tsx
📚 Learning: 2025-11-25T06:34:10.812Z
Learnt from: CR
Repo: wso2/vscode-extensions PR: 0
File: workspaces/ballerina/component-diagram/AGENTS.md:0-0
Timestamp: 2025-11-25T06:34:10.812Z
Learning: Applies to workspaces/ballerina/component-diagram/src/**/*.{ts,tsx} : Define all constants (node types, sizing, spacing) in src/resources/constants.ts and import them where needed instead of hardcoding values

Applied to files:

  • workspaces/ballerina/ballerina-visualizer/src/views/BI/ComponentListView/FileIntegrationPanel.tsx
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/Forms/FTPForm/Parameters/ParamEditor.tsx
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/Forms/FTPForm/Parameters/Parameters.tsx
  • workspaces/ballerina/ballerina-extension/package.json
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/Forms/FTPForm/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 Emotion for CSS-in-JS styling instead of inline styles or external CSS files

Applied to files:

  • workspaces/ballerina/ballerina-visualizer/src/views/BI/ComponentListView/FileIntegrationPanel.tsx
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/index.tsx
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/Forms/FTPForm/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/**/*.config.{js,ts} : Use minimatch-compatible glob patterns for file matching in build and test configuration files

Applied to files:

  • workspaces/ballerina/ballerina-visualizer/src/views/BI/ComponentListView/FileIntegrationPanel.tsx
  • workspaces/ballerina/ballerina-extension/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-visualizer/src/views/BI/ComponentListView/FileIntegrationPanel.tsx
  • workspaces/ballerina/ballerina-extension/package.json
📚 Learning: 2025-11-25T06:34:10.812Z
Learnt from: CR
Repo: wso2/vscode-extensions PR: 0
File: workspaces/ballerina/component-diagram/AGENTS.md:0-0
Timestamp: 2025-11-25T06:34:10.812Z
Learning: Applies to workspaces/ballerina/component-diagram/src/components/nodes/EntryNode/components/**/*.tsx : Implement lazy expansion of functions: only render function items when they are visible to improve performance for large function lists

Applied to files:

  • workspaces/ballerina/ballerina-visualizer/src/views/BI/ComponentListView/FileIntegrationPanel.tsx
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/index.tsx
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/Forms/FTPForm/index.tsx
📚 Learning: 2025-11-25T06:34:10.812Z
Learnt from: CR
Repo: wso2/vscode-extensions PR: 0
File: workspaces/ballerina/component-diagram/AGENTS.md:0-0
Timestamp: 2025-11-25T06:34:10.812Z
Learning: Applies to workspaces/ballerina/component-diagram/src/components/DiagramContext.tsx : Use DiagramContext (React Context API) for state management across the diagram component, including expandedNodes and graphQLGroupOpen state

Applied to files:

  • workspaces/ballerina/ballerina-visualizer/src/views/BI/ComponentListView/FileIntegrationPanel.tsx
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/Forms/FormGenerator/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/ChoiceForm.tsx
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/index.tsx
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/Forms/FTPForm/Parameters/Parameters.tsx
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/Forms/FTPForm/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/ballerina-side-panel/src/components/editors/ChoiceForm.tsx
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/Forms/FTPForm/Parameters/ParamEditor.tsx
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/Forms/FTPForm/Parameters/Parameters.tsx
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/Forms/FormGenerator/index.tsx
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/Forms/FTPForm/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/ChoiceForm.tsx
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/Forms/FTPForm/Parameters/ParamEditor.tsx
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/Forms/FTPForm/Parameters/Parameters.tsx
📚 Learning: 2025-12-12T08:55:43.437Z
Learnt from: dan-niles
Repo: wso2/vscode-extensions PR: 1080
File: workspaces/ballerina/ballerina-visualizer/src/views/BI/AIChatAgent/AddMcpServer.tsx:269-281
Timestamp: 2025-12-12T08:55:43.437Z
Learning: In `FormGenerator` component used in AddMcpServer.tsx, the component automatically triggers `onChange` callbacks with saved field values during initialization when a `node` prop is provided, so manual state setter calls (e.g., setServerUrl, setAuth) are not needed in initialization logic like initializeEditMode.

Applied to files:

  • workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/index.tsx
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/Forms/FTPForm/Parameters/Parameters.tsx
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/Forms/FormGenerator/index.tsx
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/Forms/FTPForm/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/GeneralWidget.tsx : For regular services with more than 3 functions, show only the first 2 functions with a 'View All' button; for services with 3 or fewer functions, show all functions

Applied to files:

  • workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/index.tsx
📚 Learning: 2025-12-13T14:58:12.691Z
Learnt from: KCSAbeywickrama
Repo: wso2/vscode-extensions PR: 1069
File: workspaces/ballerina/ballerina-visualizer/src/views/DataMapper/index.tsx:43-52
Timestamp: 2025-12-13T14:58:12.691Z
Learning: In workspaces/ballerina/ballerina-visualizer/src/views/DataMapper/index.tsx, the goToSource function does not need to guard against undefined lineRange. When lineRange is undefined, the RPC client will still open/show the file but won't select the relevant part.

Applied to files:

  • workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/Forms/FTPForm/Parameters/Parameters.tsx
📚 Learning: 2025-11-26T07:49:56.428Z
Learnt from: KCSAbeywickrama
Repo: wso2/vscode-extensions PR: 653
File: workspaces/bi/bi-extension/src/test/e2e-playwright-tests/data-mapper/DataMapperUtils.ts:136-141
Timestamp: 2025-11-26T07:49:56.428Z
Learning: In workspaces/bi/bi-extension/src/test/e2e-playwright-tests/data-mapper/DataMapperUtils.ts, the goPrevViewBackButton() method is only called when in a focused view, ensuring breadcrumbs are always present. No guard for empty breadcrumbs is needed.

Applied to files:

  • workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/Forms/FTPForm/Parameters/Parameters.tsx
📚 Learning: 2025-11-25T06:34:10.812Z
Learnt from: CR
Repo: wso2/vscode-extensions PR: 0
File: workspaces/ballerina/component-diagram/AGENTS.md:0-0
Timestamp: 2025-11-25T06:34:10.812Z
Learning: Applies to workspaces/ballerina/component-diagram/src/components/Diagram.tsx : Implement proper error boundaries around the Diagram component to gracefully handle rendering errors without crashing the parent application

Applied to files:

  • workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/Forms/FTPForm/Parameters/Parameters.tsx
📚 Learning: 2025-11-24T22:16:28.380Z
Learnt from: dan-niles
Repo: wso2/vscode-extensions PR: 980
File: workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx:384-412
Timestamp: 2025-11-24T22:16:28.380Z
Learning: In the RichTextTemplateEditor component (workspaces/ballerina/ballerina-side-panel/src/components/editors/MultiModeExpressionEditor/RichTextTemplateEditor/RichTextTemplateEditor.tsx), token fetching on external `value` prop changes is intentionally disabled. Users cannot edit both the minimized and expanded editors simultaneously, so tokens only need to be generated based on user typing in the expanded editor view, not on external prop updates.

Applied to files:

  • workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/Forms/FTPForm/Parameters/Parameters.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/ballerina-visualizer/src/views/BI/ServiceDesigner/Forms/FTPForm/Parameters/Parameters.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/ServiceDesigner/Forms/FTPForm/Parameters/Parameters.tsx
📚 Learning: 2025-11-20T11:04:33.712Z
Learnt from: KCSAbeywickrama
Repo: wso2/vscode-extensions PR: 898
File: workspaces/ballerina/data-mapper/src/components/DataMapper/SidePanel/QueryClauses/ClausesPanel.tsx:38-38
Timestamp: 2025-11-20T11:04:33.712Z
Learning: In workspaces/ballerina/data-mapper/src/components/DataMapper/SidePanel/QueryClauses/ClausesPanel.tsx, the use of `useDMQueryClausesPanelStore.getState()` to access `clauseToAdd` and `setClauseToAdd` (instead of the hook subscription pattern) is intentional to prevent re-renders when these state values change.

Applied to files:

  • workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/Forms/FTPForm/index.tsx
🧬 Code graph analysis (7)
workspaces/ballerina/ballerina-visualizer/src/views/BI/TypeEditor/utils.tsx (2)
workspaces/ballerina/ballerina-core/src/interfaces/extended-lang-client.ts (1)
  • VisibleTypeItem (1174-1183)
workspaces/ballerina/ballerina-core/src/interfaces/service.ts (1)
  • GeneralPayloadContext (127-130)
workspaces/ballerina/ballerina-visualizer/src/views/BI/ComponentListView/FileIntegrationPanel.tsx (1)
workspaces/ballerina/ballerina-core/src/interfaces/service.ts (1)
  • ServiceModel (39-54)
workspaces/ballerina/ballerina-side-panel/src/components/editors/ChoiceForm.tsx (4)
workspaces/ballerina/ballerina-core/src/interfaces/bi.ts (1)
  • RecordTypeField (203-207)
workspaces/ballerina/ballerina-side-panel/src/components/Form/types.ts (1)
  • FormField (38-73)
workspaces/ballerina/ballerina-core/src/utils/form-property-utils.ts (1)
  • getPrimaryInputType (21-24)
workspaces/ballerina/ballerina-side-panel/src/components/editors/EditorFactory.tsx (1)
  • EditorFactory (70-247)
workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/index.tsx (3)
workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/components/ResourceAccordion.tsx (1)
  • ResourceAccordion (138-234)
workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/utils.tsx (1)
  • canDataBind (76-78)
workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/Forms/FTPForm/index.tsx (1)
  • FTPForm (68-520)
workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/Forms/FTPForm/Parameters/Parameters.tsx (2)
workspaces/ballerina/ballerina-core/src/interfaces/service.ts (1)
  • ParameterModel (183-189)
workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/styles.tsx (6)
  • HeaderLabel (124-133)
  • disabledHeaderLabel (117-122)
  • headerLabelStyles (102-108)
  • ActionIconWrapper (135-141)
  • EditIconWrapper (62-69)
  • DeleteIconWrapper (71-79)
workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/Forms/FTPForm/FTPConfigForm.tsx (3)
workspaces/ballerina/ballerina-core/src/interfaces/service.ts (1)
  • ServiceModel (39-54)
workspaces/common-libs/rpc-generator/index.js (1)
  • handlerName (316-316)
workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/Forms/FTPForm/index.tsx (1)
  • EditorContentColumn (49-55)
workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/Forms/FTPForm/index.tsx (5)
workspaces/ballerina/ballerina-core/src/interfaces/service.ts (4)
  • FunctionModel (74-94)
  • ServiceModel (39-54)
  • GeneralPayloadContext (127-130)
  • ParameterModel (183-189)
workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceFunctionForm/utils.ts (1)
  • handleParamChange (171-188)
workspaces/wso2-platform/wso2-platform-webviews/src/components/FormElements/Dropdown/Dropdown.tsx (1)
  • Dropdown (37-78)
workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/Forms/FTPForm/Parameters/Parameters.tsx (1)
  • Parameters (83-161)
workspaces/ballerina/ballerina-visualizer/src/components/EntryPointTypeCreator/index.tsx (1)
  • EntryPointTypeCreator (52-323)
🔇 Additional comments (6)
workspaces/ballerina/ballerina-side-panel/src/components/editors/ChoiceForm.tsx (4)

61-61: LGTM!

The new state for tracking dynamic record type fields is well-typed and follows React conventions.


67-70: LGTM!

The destructuring and state updates correctly handle the new return structure from convertConfig.


79-81: LGTM!

The explicit return type and initialization of recordTypeFieldsForChoice improve code clarity and correctness.


117-132: LGTM!

The logic correctly creates RecordTypeField objects for properties with type members, properly filtering for record types.

workspaces/ballerina/ballerina-visualizer/src/views/BI/Forms/FormGenerator/index.tsx (1)

1454-1463: GraphQL payloadContext wiring looks consistent; just ensure FormTypeEditor matches.

Passing payloadContext={{ protocol: "GRAPHQL", filterType: "INPUT" }} in the variable declaration flow and payloadContext={{ protocol: "GRAPHQL" }} in the default flow aligns with the new context‑based API. As long as FormTypeEditor and its internal type‑fetching logic now rely solely on payloadContext (and no longer on isGraphql), this should behave as intended.

Please run the type checker and quickly exercise both GraphQL type‑editor entry points (variable form + default form) to confirm expected filtering/behavior.

Also applies to: 1585-1591

workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/Forms/FTPForm/FTPConfigForm.tsx (1)

33-80: FTP handler selection logic looks sound.

Filtering events to only those with at least one non‑enabled function (metadata.label match and !fn.enabled) is correct and protects against offering exhausted handlers. The onSubmit callback is safely guarded, and disabling via isSaving is appropriate. Any cleanup of the unused onBack prop or event constants can be deferred.

Comment on lines +68 to +79
export function FTPForm(props: FTPFormProps) {
const { model, isSaving, onSave, onClose, isNew, selectedHandler } = props;

const payloadContext = {
protocol: "FTP",
filterType: props.functionModel?.name.metadata.label || "JSON"
} as GeneralPayloadContext;

const [serviceModel, setserviceModel] = useState<ServiceModel>(model);
const [functionModel, setFunctionModel] = useState<FunctionModel | null>(props.functionModel || null);
const [selectedFileFormat, setSelectedFileFormat] = useState<string>('');

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 . -name "index.tsx" -path "*/FTPForm/*" 2>/dev/null | head -5

Repository: wso2/vscode-extensions

Length of output: 162


🏁 Script executed:

cat -n ./workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/Forms/FTPForm/index.tsx | head -200

Repository: wso2/vscode-extensions

Length of output: 8051


🏁 Script executed:

cat -n ./workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/Forms/FTPForm/index.tsx | sed -n '200,400p'

Repository: wso2/vscode-extensions

Length of output: 11257


🏁 Script executed:

cat -n ./workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/Forms/FTPForm/index.tsx | sed -n '400,500p'

Repository: wso2/vscode-extensions

Length of output: 6796


🏁 Script executed:

cat -n ./workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/Forms/FTPForm/index.tsx | sed -n '500,600p'

Repository: wso2/vscode-extensions

Length of output: 944


🏁 Script executed:

find ./workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/Forms -name "index.tsx" -type f

Repository: wso2/vscode-extensions

Length of output: 569


🏁 Script executed:

grep -n "payloadContext" ./workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/Forms/*/index.tsx

Repository: wso2/vscode-extensions

Length of output: 1884


🏁 Script executed:

# Check if there are similar issues in McpToolForm
grep -A 10 "payloadContext" ./workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/Forms/McpToolForm/index.tsx | head -20

Repository: wso2/vscode-extensions

Length of output: 48


🏁 Script executed:

# Let me check if there are similar payloadContext patterns in other files that might need the same fix
grep -B 5 -A 5 "payloadContext.*=.*{" ./workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/Forms/*/index.tsx

Repository: wso2/vscode-extensions

Length of output: 7902


🏁 Script executed:

# Verify that lines 152-160 don't contain payloadContext issues
sed -n '152,160p' ./workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/Forms/FTPForm/index.tsx

Repository: wso2/vscode-extensions

Length of output: 343


Fix payloadContext to avoid null access and keep it in sync with the selected file format.

payloadContext is currently computed as:

const payloadContext = {
    protocol: "FTP",
    filterType: props.functionModel?.name.metadata.label || "JSON"
} as GeneralPayloadContext;

Two problems:

  1. When creating a new handler, props.functionModel is undefined, so props.functionModel?.name evaluates to undefined and .metadata is then accessed on undefined → potential runtime error.
  2. payloadContext.filterType never updates when functionModel changes (e.g. user picks a different file format), so the EntryPointTypeCreator may get the wrong filterType (e.g. stuck on "JSON").

Compute payloadContext from the local functionModel state (with full optional chaining) and after the state is declared, e.g.:

-    const { model, isSaving, onSave, onClose, isNew, selectedHandler } = props;
-
-    const payloadContext = {
-        protocol: "FTP",
-        filterType: props.functionModel?.name.metadata.label || "JSON"
-    } as GeneralPayloadContext;
-
-    const [serviceModel, setserviceModel] = useState<ServiceModel>(model);
-    const [functionModel, setFunctionModel] = useState<FunctionModel | null>(props.functionModel || null);
+    const { model, isSaving, onSave, onClose, isNew, selectedHandler } = props;
+
+    const [serviceModel, setserviceModel] = useState<ServiceModel>(model);
+    const [functionModel, setFunctionModel] = useState<FunctionModel | null>(props.functionModel || null);
+
+    const payloadContext: GeneralPayloadContext = {
+        protocol: "FTP",
+        filterType: functionModel?.name?.metadata?.label || "JSON",
+    };

This removes the null‑access risk and keeps filterType aligned with the currently selected function/file format.

🤖 Prompt for AI Agents
In
workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/Forms/FTPForm/index.tsx
around lines 68 to 79, payloadContext is built using props.functionModel and is
defined before local state, causing null-access risk when creating new handlers
and making filterType stale when functionModel state changes; fix it by moving
payloadContext construction to after the useState declarations and derive it
from the local functionModel state (use optional chaining like
functionModel?.name?.metadata?.label and default to "JSON"), or wrap the
computation in a useMemo that depends on [functionModel], so filterType always
reflects the current selection and avoids runtime errors.

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

♻️ Duplicate comments (3)
workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/Forms/FTPForm/index.tsx (3)

1-1: Avoid blanket ESLint disable for hooks rules.

This issue has already been flagged in a previous review. The blanket disable for react-hooks/exhaustive-deps hides legitimate dependency issues throughout the file.


72-75: Fix payloadContext to avoid null access and keep it in sync with the selected file format.

This issue has already been flagged in a previous review. The payloadContext is computed from props.functionModel before state initialization, causing null-access risk and stale filterType when the function model changes.


225-270: Logic issue in handleTypeCreated: Confusing dual updates and mutations.

This issue has already been flagged in a previous review. The function has direct mutation problems and overwrites state twice with conflicting updates.

🧹 Nitpick comments (2)
workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/Forms/FTPForm/index.tsx (2)

26-27: Remove unused imports.

The imports has from lodash and Description from @headlessui/react are not used anywhere in this file.

🔎 Proposed fix
 import { FunctionModel, ParameterModel, GeneralPayloadContext, Type, ServiceModel } from '@wso2/ballerina-core';
 import { EntryPointTypeCreator } from '../../../../../components/EntryPointTypeCreator';
 import { Parameters } from './Parameters/Parameters';
-import { has } from 'lodash';
-import { Description } from '@headlessui/react';

163-223: Consider relocating helper functions for better code organization.

The selectType and withoutStreamType functions reference hasStreamProperty which is defined later at line 345. While this works due to function declaration hoisting, it can impact readability when hasStreamProperty isn't visible nearby.

Consider moving these helper functions after hasStreamProperty is defined, or moving the hasStreamProperty computation closer to the top of the component.

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 93c3d03 and 732a306.

📒 Files selected for processing (2)
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/Forms/FTPForm/Parameters/Parameters.tsx
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/Forms/FTPForm/index.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/Forms/FTPForm/Parameters/Parameters.tsx
🧰 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-visualizer/src/views/BI/ServiceDesigner/Forms/FTPForm/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 Emotion for CSS-in-JS styling instead of inline styles or external CSS files

Applied to files:

  • workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/Forms/FTPForm/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/ballerina-visualizer/src/views/BI/ServiceDesigner/Forms/FTPForm/index.tsx
📚 Learning: 2025-12-12T08:55:43.437Z
Learnt from: dan-niles
Repo: wso2/vscode-extensions PR: 1080
File: workspaces/ballerina/ballerina-visualizer/src/views/BI/AIChatAgent/AddMcpServer.tsx:269-281
Timestamp: 2025-12-12T08:55:43.437Z
Learning: In `FormGenerator` component used in AddMcpServer.tsx, the component automatically triggers `onChange` callbacks with saved field values during initialization when a `node` prop is provided, so manual state setter calls (e.g., setServerUrl, setAuth) are not needed in initialization logic like initializeEditMode.

Applied to files:

  • workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/Forms/FTPForm/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-visualizer/src/views/BI/ServiceDesigner/Forms/FTPForm/index.tsx
📚 Learning: 2025-11-20T11:04:33.712Z
Learnt from: KCSAbeywickrama
Repo: wso2/vscode-extensions PR: 898
File: workspaces/ballerina/data-mapper/src/components/DataMapper/SidePanel/QueryClauses/ClausesPanel.tsx:38-38
Timestamp: 2025-11-20T11:04:33.712Z
Learning: In workspaces/ballerina/data-mapper/src/components/DataMapper/SidePanel/QueryClauses/ClausesPanel.tsx, the use of `useDMQueryClausesPanelStore.getState()` to access `clauseToAdd` and `setClauseToAdd` (instead of the hook subscription pattern) is intentional to prevent re-renders when these state values change.

Applied to files:

  • workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/Forms/FTPForm/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-visualizer/src/views/BI/ServiceDesigner/Forms/FTPForm/index.tsx

Comment on lines +454 to +470
<CheckBoxGroup direction="vertical">
<CheckBox
label={parameterConfig.fileInfo.label}
checked={fileInfoParameter.enabled}
onChange={(checked) => {
const updatedParameters = functionModel.parameters.map((p) => {
if (p === fileInfoParameter) {
return { ...p, enabled: checked };
}
return p;
});
handleParamChange(updatedParameters);
}}
sx={{ marginTop: 0 , description: parameterConfig.fileInfo.description}}
/>
</CheckBoxGroup>
</>
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

Incorrect description prop usage in CheckBox components.

The description property is being passed inside the sx prop at lines 467 and 489, which is incorrect. The sx prop is for styling only and won't render the description text. This results in users not seeing helpful contextual information for the File Metadata and FTP Connection options.

Compare with the stream checkbox (lines 406-442) which correctly wraps the CheckBox in a Tooltip to display the description.

🔎 Proposed fix
     {/* File Metadata Section */}
     {fileInfoParameter && (
         <>
-
+            <Tooltip content={parameterConfig.fileInfo.description} position="right">
                 <CheckBoxGroup direction="vertical">
                     <CheckBox
                         label={parameterConfig.fileInfo.label}
                         checked={fileInfoParameter.enabled}
                         onChange={(checked) => {
                             const updatedParameters = functionModel.parameters.map((p) => {
                                 if (p === fileInfoParameter) {
                                     return { ...p, enabled: checked };
                                 }
                                 return p;
                             });
                             handleParamChange(updatedParameters);
                         }}
-                        sx={{ marginTop: 0 , description: parameterConfig.fileInfo.description}}
+                        sx={{ marginTop: 0 }}
                     />
                 </CheckBoxGroup>
+            </Tooltip>
         </>
     )}

     {/* FTP Connection Section */}
     {callerParameter && (
         <>
+            <Tooltip content={parameterConfig.caller.description} position="right">
                 <CheckBoxGroup direction="vertical">
                     <CheckBox
                         label={parameterConfig.caller.label}
                         checked={callerParameter.enabled}
                         onChange={(checked) => {
                             const updatedParameters = functionModel.parameters.map((p) => {
                                 if (p === callerParameter) {
                                     return { ...p, enabled: checked };
                                 }
                                 return p;
                             });
                             handleParamChange(updatedParameters);
                         }}
-                        sx={{ marginTop: 0, description: parameterConfig.caller.description }}
+                        sx={{ marginTop: 0 }}
                     />
                 </CheckBoxGroup>
+            </Tooltip>
         </>
     )}

Also applies to: 476-492

🤖 Prompt for AI Agents
In
workspaces/ballerina/ballerina-visualizer/src/views/BI/ServiceDesigner/Forms/FTPForm/index.tsx
around lines 454-470 (and similarly 476-492 / specific occurrences at ~467 and
~489), the CheckBox components incorrectly place description text inside the sx
prop; remove the description from sx and wrap each CheckBox with the same
Tooltip pattern used by the stream checkbox (pass
parameterConfig.xxx.description as the Tooltip content), so the description is
rendered to users instead of being treated as styling metadata.

@samithkavishke samithkavishke marked this pull request as draft December 23, 2025 13: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.

1 participant