Skip to content
Draft
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 @@ -124,7 +124,12 @@ export interface MessageQueuePayloadContext {
messageDocumentation?: string;
}

export type PayloadContext = HttpPayloadContext | MessageQueuePayloadContext;
export interface GeneralPayloadContext {
protocol: string;
filterType?: string;
}

export type PayloadContext = HttpPayloadContext | MessageQueuePayloadContext | GeneralPayloadContext;

export interface ParamDetails {
name: string;
Expand Down
2 changes: 1 addition & 1 deletion workspaces/ballerina/ballerina-extension/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -1165,7 +1165,7 @@
"description": "design-view",
"default": {
"fontPath": "./resources/font-wso2-vscode/dist/wso2-vscode.woff",
"fontCharacter": "\\f16e"
"fontCharacter": "\\f175"
}
}
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1565,7 +1565,7 @@ export class BiDiagramRpcManager implements BIDiagramAPI {
if (!filePath && StateMachine.context()?.projectPath){
const projectPath = StateMachine.context().projectPath;
const ballerinaFiles = await getBallerinaFiles(Uri.file(projectPath).fsPath);
filePath = ballerinaFiles.at(0)
filePath = ballerinaFiles.at(0);
}

if (!filePath) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,15 +58,16 @@ export function ChoiceForm(props: ChoiceFormProps) {
const [selectedOption, setSelectedOption] = useState<number>(1);

const [dynamicFields, setDynamicFields] = useState<FormField[]>([]);

const [dynamicRecordTypeFields, setDynamicRecordTypeFields] = useState<RecordTypeField[]>([]);

// Add useEffect to set initial values
useEffect(() => {
const realValue = selectedOption - 1;
const property = field.choices[realValue];
const choiceProperty = convertConfig(property);
setDynamicFields(choiceProperty);
if (choiceProperty.length > 0) {
const { formFields, recordTypeFieldsForChoice } = convertConfig(property);
setDynamicFields(formFields);
setDynamicRecordTypeFields(recordTypeFieldsForChoice);
if (formFields.length > 0) {
Object.entries(property.properties).forEach(([propKey, propValue]) => {
if (propValue.value !== undefined) {
setValue(propKey, propValue.value);
Expand All @@ -75,10 +76,21 @@ export function ChoiceForm(props: ChoiceFormProps) {
}
}, [selectedOption]);

const convertConfig = (model: PropertyModel): FormField[] => {
const convertConfig = (model: PropertyModel): { formFields: FormField[], recordTypeFieldsForChoice: RecordTypeField[] } => {
const formFields: FormField[] = [];
const recordTypeFieldsForChoice: RecordTypeField[] = [];

for (const key in model.properties) {
const expression = model.properties[key];

// console.log(`>>> Processing property: ${key}`, {
// valueType: expression.valueType,
// valueTypeConstraint: expression.valueTypeConstraint,
// hasTypeMembers: !!expression.typeMembers,
// typeMembersLength: expression.typeMembers?.length || 0,
// typeMembers: expression.typeMembers
// });

let items = undefined;
if (getPrimaryInputType(expression.types)?.fieldType === "MULTIPLE_SELECT" || getPrimaryInputType(expression.types)?.fieldType === "SINGLE_SELECT") {
items = expression.items;
Expand All @@ -101,9 +113,27 @@ export function ChoiceForm(props: ChoiceFormProps) {
defaultValue: expression.defaultValue as string
}
formFields.push(formField);

// If this property has typeMembers, create a RecordTypeField for it
const primaryType = getPrimaryInputType(expression.types);
if (primaryType?.typeMembers && primaryType.typeMembers.length > 0) {
const recordTypeField: RecordTypeField = {
key: key,
property: {
metadata: expression.metadata || { label: "", description: "" },
value: expression.value || "",
optional: expression.optional || false,
editable: expression.editable !== undefined ? expression.editable : true,
types: expression.types
},
recordTypeMembers: primaryType.typeMembers.filter(member => member.kind === "RECORD_TYPE")
};
recordTypeFieldsForChoice.push(recordTypeField);
}
}
console.log("Dynamic Form Fields:", formFields)
return formFields;
console.log(">>> Final Dynamic Form Fields:", formFields)
console.log(">>> Final Dynamic Record Type Fields:", recordTypeFieldsForChoice)
return { formFields, recordTypeFieldsForChoice };
Comment on lines +134 to +136
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.

}

return (
Expand All @@ -129,12 +159,18 @@ export function ChoiceForm(props: ChoiceFormProps) {

<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={recordTypeFields}
recordTypeFields={mergedRecordTypeFields}
/>
);
})}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ interface EntryPointTypeCreatorProps {
modalWidth?: number;
modalHeight?: number;
payloadContext?: PayloadContext;

}

interface TypeEditorState {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
* under the License.
*/
import React, { useEffect, useState } from 'react';
import { Codicon } from '@wso2/ui-toolkit';
import { Icon } from '@wso2/ui-toolkit';
import { useRpcContext } from '@wso2/ballerina-rpc-client';
import { EVENT_TYPE, MACHINE_VIEW, SCOPE, ServiceModel, TriggerModelsResponse } from '@wso2/ballerina-core';

Expand Down Expand Up @@ -67,17 +67,7 @@ export function FileIntegrationPanel(props: FileIntegrationPanelProps) {
id={`trigger-${item.moduleName}`}
key={item.id}
title={item.name}
icon={
item.icon ? (
<img
src={item.icon}
alt={item.name}
style={{ width: "40px" }}
/>
) : (
<Codicon name="mail" />
)
}
icon={getFileIntegrationIcon(item)}
onClick={() => {
handleOnSelect(item);
}}
Expand All @@ -90,3 +80,21 @@ export function FileIntegrationPanel(props: FileIntegrationPanelProps) {
</PanelViewMore>
);
};

// 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;
}
}
Comment on lines +84 to +100
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) {

Original file line number Diff line number Diff line change
Expand Up @@ -1455,7 +1455,12 @@ export const FormGenerator = forwardRef<FormExpressionEditorRef, FormProps>(func
type={peekTypeStack()?.type}
newType={peekTypeStack() ? peekTypeStack().isDirty : false}
newTypeValue={typeEditorState.newTypeValue}
isGraphql={isGraphql}
payloadContext={
{
protocol: "GRAPHQL",
filterType: "INPUT"
}
}
onTypeChange={onTypeChange}
onSaveType={onSaveType}
onTypeCreate={() => { }}
Expand Down Expand Up @@ -1582,7 +1587,7 @@ export const FormGenerator = forwardRef<FormExpressionEditorRef, FormProps>(func
newType={peekTypeStack() ? peekTypeStack().isDirty : false}
newTypeValue={typeEditorState.newTypeValue}
isPopupTypeForm={true}
isGraphql={isGraphql}
payloadContext={{protocol: "GRAPHQL"}}
onTypeChange={onTypeChange}
onSaveType={onSaveType}
onTypeCreate={() => { }}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1021,7 +1021,7 @@ export function FormGeneratorNew(props: FormProps) {
newType={peekTypeStack() ? peekTypeStack().isDirty : false}
newTypeValue={typeEditorState.newTypeValue}
isPopupTypeForm={true}
isGraphql={isGraphqlEditor}
payloadContext={{protocol: "GRAPHQL"}}
onTypeChange={handleTypeChange}
onSaveType={onSaveType}
onTypeCreate={() => { }}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/**
* Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com) All Rights Reserved.
*
* WSO2 LLC. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

import React from "react";
import { SidePanelBody } from "@wso2/ui-toolkit";
import ButtonCard from "../../../../../components/ButtonCard";
import { ServiceModel } from "@wso2/ballerina-core";

import { EditorContentColumn } from "../../styles";

interface FunctionConfigFormProps {
onBack?: () => void;
isSaving: boolean;
onSubmit?: (selectedHandler: string) => void;
serviceModel: ServiceModel;
}

export function FunctionConfigForm(props: FunctionConfigFormProps) {

const { onBack, onSubmit, isSaving, serviceModel } = props;

const events = [
{ name: 'onCreate', description: 'Triggered when a new file is created' },
{ name: 'onDelete', description: 'Triggered when a file is deleted' }
];

// Check if all functions with a specific metadata.label are enabled
const hasAvailableFunctions = (handlerType: string) => {
const functionsWithHandler = serviceModel.functions?.filter(fn => fn.metadata?.label === handlerType) || [];
if (functionsWithHandler.length === 0) return false;

// Return true if there's at least one non-enabled function
return functionsWithHandler.some(fn => !fn.enabled);
};

const handleEventClick = (handlerName: string) => {
// if (onBack) {
// onBack();
// }

onSubmit && onSubmit(handlerName);
};

// Filter events to only show those with available functions
const availableEvents = events.filter(event => hasAvailableFunctions(event.name));

return (
<SidePanelBody>
<EditorContentColumn>
{availableEvents.map((event, index) => {
const handleClick = () => handleEventClick(event.name);
return (
<ButtonCard
key={event.name}
id={`event-card-${index}`}
title={event.name}
tooltip={event.description}
onClick={handleClick}
disabled={isSaving}
/>
);
})}
</EditorContentColumn>
</SidePanelBody>
);
}

export default FunctionConfigForm;

Loading
Loading