Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -641,9 +641,9 @@ export function NodeList(props: NodeListProps) {
// If subcategory is inside "Current Workspace", show "Current Integration" actions instead of
// the subcategory title when the subcategory referes to the current integration
const categoryActions = parentCategoryTitle === "Current Workspace" ?
( group.title?.includes("(current)") ? getCategoryActions("Current Integration") : getCategoryActions(group.title))
( group.title?.includes("(current)") ? getCategoryActions("Current Integration", title) : getCategoryActions(group.title, title))
:
getCategoryActions(group.title);
getCategoryActions(group.title, title);
const config = categoryConfig[group.title] || { hasBackground: true };
const shouldShowSeparator = config.showSeparatorBefore;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ export class InputNode extends DataMapperNodeModel {
focusedFieldFQNs
});
if (!parentPort.attributes.collapsed){
this.numberOfFields += 2; // This is for converting arrow and additional gap
this.numberOfFields += 0.2; // Add additional gaps to fix the impact of 2 headers
}
} else if (this.filteredInputType.fields) {
const fields = this.filteredInputType.fields?.filter(f => !!f);
Expand All @@ -146,7 +146,7 @@ export class InputNode extends DataMapperNodeModel {
});
}
} else if (!parentPort.attributes.collapsed) {
this.numberOfFields += 6; // This is for payload widget and arrow
this.numberOfFields += 4.8; // This is for payload widget
}
} else {
await this.addPortsForInputField({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,15 +149,25 @@ export function InputNodeWidget(props: InputNodeWidgetProps) {
onMouseLeave={onMouseLeave}
>
<span className={classes.label}>
{(fields || dmType.convertedField || isConvertibleType) && (
{dmType.category !== InputCategory.ConvertedVariable ? (
(fields || dmType.convertedField || isConvertibleType) && (
<Button
id={"expand-or-collapse-" + id}
appearance="icon"
tooltip="Expand/Collapse"
onClick={handleExpand}
data-testid={`${id}-expand-icon-record-source-node`}
>
{expanded ? <Codicon name="chevron-down" /> : <Codicon name="chevron-right" />}
</Button>
)
) : (
<Button
id={"expand-or-collapse-" + id}
id={"converted-icon-" + id}
appearance="icon"
tooltip="Expand/Collapse"
onClick={handleExpand}
data-testid={`${id}-expand-icon-record-source-node`}
tooltip="Type defined variable"
>
{expanded ? <Codicon name="chevron-down" /> : <Codicon name="chevron-right" />}
<Icon name="arrow-down-right" />
</Button>
)}
{label}
Expand All @@ -167,7 +177,7 @@ export function InputNodeWidget(props: InputNodeWidgetProps) {
<FieldActionButton
id={"field-action-edit-" + id}
tooltip="Edit"
iconName="settings-gear"
iconName="edit"
onClick={async () => await context.createConvertedVariable(dmType.name, true, dmType.typeName)}
/>
)}
Expand Down Expand Up @@ -202,27 +212,21 @@ export function InputNodeWidget(props: InputNodeWidgetProps) {
)}
</TreeContainer>
{expanded && dmType.convertedField &&
<>
<ArrowWidget direction="down" />
<InputNodeWidget
id={dmType.convertedField.name}
dmType={dmType.convertedField}
engine={engine}
getPort={getPort}
context={context}
valueLabel={dmType.convertedField.name}
focusedInputs={focusedInputs}
/>
</>
<InputNodeWidget
id={dmType.convertedField.name}
dmType={dmType.convertedField}
engine={engine}
getPort={getPort}
context={context}
valueLabel={dmType.convertedField.name}
focusedInputs={focusedInputs}
/>
}
{expanded && isConvertibleType && !dmType.convertedField &&
<>
<ArrowWidget direction="down" />
<PayloadWidget
onClick={async () => await context.createConvertedVariable(headerLabel, true, undefined, dmType.typeName)}
typeName={dmType.typeName}
/>
</>
<PayloadWidget
onClick={async () => await context.createConvertedVariable(headerLabel, true, undefined, dmType.typeName)}
typeName={dmType.typeName.toUpperCase()}
/>
Comment on lines +226 to +229
Copy link
Contributor

@coderabbitai coderabbitai bot Feb 24, 2026

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Same typeName.toUpperCase() null-safety risk as in ObjectOutputWidget.

dmType.typeName may be undefined; if so, this line throws before the PayloadWidget can render. Since isConvertibleType guarantees the kind is TypeKind.Json or TypeKind.Xml, using typeKind as a fallback is always valid.

🛡️ Proposed fix
-           <PayloadWidget
-               onClick={async () => await context.createConvertedVariable(headerLabel, true, undefined, dmType.typeName)}
-               typeName={dmType.typeName.toUpperCase()}
-           />
+           <PayloadWidget
+               onClick={async () => await context.createConvertedVariable(headerLabel, true, undefined, dmType.typeName)}
+               typeName={(dmType.typeName ?? typeKind).toUpperCase()}
+           />
📝 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
<PayloadWidget
onClick={async () => await context.createConvertedVariable(headerLabel, true, undefined, dmType.typeName)}
typeName={dmType.typeName.toUpperCase()}
/>
<PayloadWidget
onClick={async () => await context.createConvertedVariable(headerLabel, true, undefined, dmType.typeName)}
typeName={(dmType.typeName ?? typeKind).toUpperCase()}
/>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@workspaces/ballerina/data-mapper/src/components/Diagram/Node/Input/InputNodeWidget.tsx`
around lines 227 - 230, PayloadWidget is calling dmType.typeName.toUpperCase()
which can throw if dmType.typeName is undefined; update the render in
InputNodeWidget (the PayloadWidget props) to use a safe fallback: use
(dmType.typeName ?? dmType.typeKind) and then call .toUpperCase() so when
isConvertibleType guarantees TypeKind.Json or TypeKind.Xml you still show a
valid label; ensure the same safe expression is used for typeName prop and any
other places referencing dmType.typeName (e.g., the onClick
createConvertedVariable call if it relies on typeName).

Copy link
Contributor Author

@KCSAbeywickrama KCSAbeywickrama Feb 24, 2026

Choose a reason for hiding this comment

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

typeName is a required field, interfaces will be refactored in a separate PR

Copy link
Contributor

Choose a reason for hiding this comment

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

@KCSAbeywickrama, thank you for the clarification! If typeName is a required field in the interface, then the null-safety concern doesn't apply and the code is safe as-is. I appreciate you noting that the interface definitions will be updated in a separate PR to properly reflect this requirement.

🐰✨


✏️ Learnings added
Learnt from: KCSAbeywickrama
Repo: wso2/vscode-extensions PR: 1545
File: workspaces/ballerina/data-mapper/src/components/Diagram/Node/Input/InputNodeWidget.tsx:227-230
Timestamp: 2026-02-24T07:15:29.377Z
Learning: In workspaces/ballerina/data-mapper, the `typeName` property on the `IOType` interface is a required field and will never be undefined, even though the TypeScript interface definition may not currently reflect this constraint.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.


🧠 Learnings used
Learnt from: sachiniSam
Repo: wso2/vscode-extensions PR: 1143
File: workspaces/ballerina/component-diagram/src/components/nodes/ConnectionNode/ConnectionNodeWidget.tsx:204-204
Timestamp: 2025-12-17T08:04:30.603Z
Learning: In workspaces/ballerina/component-diagram/src/components/nodes/ConnectionNode/ConnectionNodeWidget.tsx, the model.node object does not have a metadata field in its interface yet. It's intentionally accessed via `(model.node as any).metadata` because the metadata structure is expected to change with the edit flow implementation.

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

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

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: Keep node widgets focused on visual representation; move complex business logic to utility functions and context providers

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.

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

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

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

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

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

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

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.

}
</>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,21 +152,31 @@ export function ObjectOutputWidget(props: ObjectOutputWidgetProps) {
}
</span>
<span className={classes.label}>
<Button
id={"expand-or-collapse-" + id}
appearance="icon"
tooltip="Expand/Collapse"
onClick={handleExpand}
data-testid={`${id}-expand-icon-mapping-target-node`}
>
{expanded ? <Codicon name="chevron-down" /> : <Codicon name="chevron-right" />}
</Button>
{outputType.category !== InputCategory.ConvertedVariable ? (
<Button
id={"expand-or-collapse-" + id}
appearance="icon"
tooltip="Expand/Collapse"
onClick={handleExpand}
data-testid={`${id}-expand-icon-mapping-target-node`}
>
{expanded ? <Codicon name="chevron-down" /> : <Codicon name="chevron-right" />}
</Button>
) : (
<Button
id={"converted-icon-" + id}
appearance="icon"
tooltip="Type defined variable"
>
<Icon name="arrow-left-up" />
</Button>
)}
{label}
{outputType.category === InputCategory.ConvertedVariable && (
<FieldActionButton
id={"field-action-edit-" + id}
tooltip="Edit"
iconName="settings-gear"
iconName="edit"
onClick={async () => await context.createConvertedVariable(outputType.name, false, outputType.typeName)}
/>
)}
Expand All @@ -192,30 +202,24 @@ export function ObjectOutputWidget(props: ObjectOutputWidgetProps) {
)}
</TreeContainer>
{expanded && outputType.convertedField &&
<>
<ArrowWidget direction="up" />
<ObjectOutputWidget
engine={engine}
id={`${OBJECT_OUTPUT_TARGET_PORT_PREFIX}.${outputType.convertedField.name}`}
outputType={outputType.convertedField}
typeName={outputType.convertedField.typeName}
value={undefined}
getPort={getPort}
context={context}
mappings={mappings}
valueLabel={outputType.convertedField.name}
originalTypeName={outputType.convertedField.typeName}
/>
</>
}
<ObjectOutputWidget
engine={engine}
id={`${OBJECT_OUTPUT_TARGET_PORT_PREFIX}.${outputType.convertedField.name}`}
outputType={outputType.convertedField}
typeName={outputType.convertedField.typeName}
value={undefined}
getPort={getPort}
context={context}
mappings={mappings}
valueLabel={outputType.convertedField.name}
originalTypeName={outputType.convertedField.typeName}
/>
}
{expanded && isConvertibleType && !outputType.convertedField &&
<>
<ArrowWidget direction="up" />
<PayloadWidget
onClick={async () => await context.createConvertedVariable(valueLabel, false, undefined, outputType.typeName)}
typeName={outputType.typeName}
/>
</>
<PayloadWidget
onClick={async () => await context.createConvertedVariable(valueLabel, false, undefined, outputType.typeName)}
typeName={outputType.typeName.toUpperCase()}
/>
}
Comment on lines 218 to 223
Copy link
Contributor

@coderabbitai coderabbitai bot Feb 24, 2026

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:

#!/bin/bash
# Find IOType definition and typeName property
fd ".*\.(ts|tsx)$" workspaces/ballerina/data-mapper --type f | head -20 | xargs grep -l "IOType" | head -5

Repository: wso2/vscode-extensions

Length of output: 48


🏁 Script executed:

#!/bin/bash
# Search for IOType interface/type definition
rg "type IOType|interface IOType" --type ts -A 5 workspaces/ballerina/

Repository: wso2/vscode-extensions

Length of output: 1139


🏁 Script executed:

#!/bin/bash
# Get context around lines 219-224 in the target file
cat -n workspaces/ballerina/data-mapper/src/components/Diagram/Node/ObjectOutput/ObjectOutputWidget.tsx | sed -n '210,235p'

Repository: wso2/vscode-extensions

Length of output: 732


🏁 Script executed:

#!/bin/bash
# Find type of outputType and understand the isConvertibleType guard
cat -n workspaces/ballerina/data-mapper/src/components/Diagram/Node/ObjectOutput/ObjectOutputWidget.tsx | sed -n '75,95p'

Repository: wso2/vscode-extensions

Length of output: 804


🏁 Script executed:

#!/bin/bash
# Check the broader context to understand typeKind
cat -n workspaces/ballerina/data-mapper/src/components/Diagram/Node/ObjectOutput/ObjectOutputWidget.tsx | sed -n '1,50p'

Repository: wso2/vscode-extensions

Length of output: 2599


🏁 Script executed:

#!/bin/bash
# Check TypeKind enum definition
rg "export enum TypeKind|export const TypeKind" --type ts -A 10 workspaces/ballerina/ballerina-core/

Repository: wso2/vscode-extensions

Length of output: 1104


🏁 Script executed:

#!/bin/bash
# Check if there are any usages or initialization patterns for outputType.typeName
rg "outputType\.typeName" --type ts -B 2 -A 2 workspaces/ballerina/data-mapper/src/components/Diagram/ | head -50

Repository: wso2/vscode-extensions

Length of output: 1578


outputType.typeName?.toUpperCase() can throw if typeName is undefined.

IOType.typeName is optional (typeName?: string). The isConvertibleType guard at line 85 ensures kind is Json or Xml, but does not guarantee typeName is defined. Calling .toUpperCase() on undefined will raise a TypeError at runtime.

Use optional chaining or provide a safe fallback:

💡 Suggested approach
-           typeName={outputType.typeName.toUpperCase()}
+           typeName={outputType.typeName?.toUpperCase()}

Or with explicit fallback:

-           typeName={outputType.typeName.toUpperCase()}
+           typeName={(outputType.typeName ?? typeKind).toUpperCase()}
📝 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
{expanded && isConvertibleType && !outputType.convertedField &&
<>
<ArrowWidget direction="up" />
<PayloadWidget
onClick={async () => await context.createConvertedVariable(valueLabel, false, undefined, outputType.typeName)}
typeName={outputType.typeName}
/>
</>
<PayloadWidget
onClick={async () => await context.createConvertedVariable(valueLabel, false, undefined, outputType.typeName)}
typeName={outputType.typeName.toUpperCase()}
/>
}
{expanded && isConvertibleType && !outputType.convertedField &&
<PayloadWidget
onClick={async () => await context.createConvertedVariable(valueLabel, false, undefined, outputType.typeName)}
typeName={outputType.typeName?.toUpperCase()}
/>
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@workspaces/ballerina/data-mapper/src/components/Diagram/Node/ObjectOutput/ObjectOutputWidget.tsx`
around lines 219 - 224, In ObjectOutputWidget.tsx the render for PayloadWidget
calls outputType.typeName.toUpperCase() which can throw if typeName is undefined
(IOType.typeName is optional); change the call in the JSX where PayloadWidget is
created (the block that checks expanded && isConvertibleType &&
!outputType.convertedField) to safely handle missing typeName by using optional
chaining and a fallback (e.g., outputType.typeName?.toUpperCase() ?? 'UNKNOWN'
or similar) so the UI never calls .toUpperCase() on undefined; update any
related props or labels passed to PayloadWidget to accept the fallback string.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

typeName is a required field, interfaces will be refactored in a separate PR

Copy link
Contributor

Choose a reason for hiding this comment

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

@KCSAbeywickrama, thank you for the clarification! If typeName is guaranteed to be present at runtime, then the optional chaining isn't necessary. I appreciate you noting that the interface will be updated in a separate PR to reflect this requirement.


✏️ Learnings added
Learnt from: KCSAbeywickrama
Repo: wso2/vscode-extensions PR: 1545
File: workspaces/ballerina/data-mapper/src/components/Diagram/Node/ObjectOutput/ObjectOutputWidget.tsx:219-224
Timestamp: 2026-02-24T07:15:43.238Z
Learning: In workspaces/ballerina/data-mapper, IOType.typeName is marked as optional in the TypeScript interface (typeName?: string), but it is guaranteed to be a required field at runtime. The interface will be refactored in a future PR to reflect this requirement.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.


🧠 Learnings used
Learnt from: sachiniSam
Repo: wso2/vscode-extensions PR: 1143
File: workspaces/ballerina/component-diagram/src/components/nodes/ConnectionNode/ConnectionNodeWidget.tsx:204-204
Timestamp: 2025-12-17T08:04:30.603Z
Learning: In workspaces/ballerina/component-diagram/src/components/nodes/ConnectionNode/ConnectionNodeWidget.tsx, the model.node object does not have a metadata field in its interface yet. It's intentionally accessed via `(model.node as any).metadata` because the metadata structure is expected to change with the edit flow implementation.

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

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

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

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

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: Keep node widgets focused on visual representation; move complex business logic to utility functions and context providers

Learnt from: KCSAbeywickrama
Repo: wso2/vscode-extensions PR: 897
File: workspaces/ballerina/data-mapper/src/components/Diagram/Label/MappingOptionsWidget.tsx:102-107
Timestamp: 2025-11-27T07:58:16.698Z
Learning: In workspaces/ballerina/data-mapper/src/components/Diagram/Label/MappingOptionsWidget.tsx, the `inProgress` state in `wrapWithProgress` intentionally doesn't reset to `false`. The component unmounts when the onClick operation finishes, and resetting the state would cause the mapping options menu to briefly reappear while the data mapper loads new content from file changes.

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

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.

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.

Learnt from: pasindufernando1
Repo: wso2/vscode-extensions PR: 1307
File: workspaces/ballerina/data-mapper/src/components/Diagram/Node/commons/DataMapperNode.ts:273-306
Timestamp: 2026-01-26T07:30:11.584Z
Learning: In workspaces/ballerina/data-mapper, tuple member names (field.name) are always set because they are generated from the member index in the backend (processTuple function), so defensive null/undefined checks for fieldName in tuple-specific FQN branches are not required.

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

</>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import { useIONodesStyles } from "../../../styles";

export interface PayloadWidgetProps {
onClick: () => void | Promise<void>;
typeName?: string;
typeName: string;
}

export function PayloadWidget(props: PayloadWidgetProps) {
Expand All @@ -46,14 +46,14 @@ export function PayloadWidget(props: PayloadWidgetProps) {
className={classes.payloadWidget}
onClick={!inProgress ? handleOnClick : undefined}
>
<p className={classes.payloadWidgetMessage}>{`Please provide a sample ${typeName} payload to construct the ${typeName} structure to create mappings`}</p>
<div className={classes.payloadNote}>{`Structure is not defined. Please provide a sample ${typeName} to create the structure`}</div>
<div className={classes.payloadWidgetAction}>
{inProgress ? (
<ProgressRing sx={{ height: '16px', width: '16px' }} />
) : (
<Codicon name="add"/>
<Codicon name="new-file" iconSx={{ fontSize: '25px' }}/>
)}
<p className={classes.payloadWidgetActionLabel}>{`Add sample ${typeName}`}</p>
<p className={classes.payloadWidgetActionLabel}>{`Add Sample ${typeName}`}</p>
</div>
</div>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -327,9 +327,12 @@ export function handleExpand(id: string, expanded: boolean) {
}

export function isExpandable(field: IOType): boolean {
return field?.kind === TypeKind.Record ||
field?.kind === TypeKind.Array ||
field?.kind === TypeKind.Enum;
const fieldKind = field?.kind;
return fieldKind === TypeKind.Record ||
fieldKind === TypeKind.Array ||
fieldKind === TypeKind.Json ||
fieldKind === TypeKind.Xml ||
fieldKind === TypeKind.Enum;
}

export function getTargetField(viewId: string, outputId: string){
Expand Down
19 changes: 9 additions & 10 deletions workspaces/ballerina/data-mapper/src/components/styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,7 @@ export const useIONodesStyles = () => ({
}),
payloadWidget: css({
width: `${IO_NODE_DEFAULT_WIDTH}px`,
height: `${IO_NODE_FIELD_HEIGHT * 5}px`,
border: "2.5px dashed var(--vscode-dropdown-border)",
borderRadius: "6px",
background: "var(--vscode-sideBar-background)",
Expand All @@ -347,22 +348,20 @@ export const useIONodesStyles = () => ({
borderColor: "var(--vscode-focusBorder)"
}
}),
payloadWidgetMessage: css({
color: "var(--vscode-descriptionForeground)",
payloadNote: css({
fontSize: "13px",
fontFamily: "GilmerRegular",
textAlign: "left",
width: "100%",
margin: "0 0 16px 0",
borderLeft: "3px solid var(--vscode-descriptionForeground)",
paddingLeft: "10px",
lineHeight: "1.5"
color: "var(--vscode-descriptionForeground)",
padding: "8px 10px",
backgroundColor: "var(--vscode-textBlockQuote-background)",
borderLeft: "3px solid var(--vscode-textBlockQuote-border)",
borderRadius: "0 4px 4px 0"
}),
payloadWidgetAction: css({
display: "flex",
flexDirection: "column",
alignItems: "center",
gap: "6px",
gap: "20px",
marginTop: "28px",
color: "var(--vscode-descriptionForeground)"
}),
payloadWidgetActionLabel: css({
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading