feat: enhance condition handling with input type support and value coercion

This commit is contained in:
Nawaz Dhandala
2026-03-25 20:25:19 +00:00
parent 178fa45dd8
commit 923e020e6e
4 changed files with 124 additions and 26 deletions

View File

@@ -9,6 +9,7 @@ import ComponentMetadata, {
import ComponentID from "../../../../../Types/Workflow/ComponentID";
import Components, {
ConditionOperator,
ConditionValueType,
} from "../../../../../Types/Workflow/Components/Condition";
import CaptureSpan from "../../../../Utils/Telemetry/CaptureSpan";
@@ -61,30 +62,69 @@ export default class IfElse extends ComponentCode {
* Inject dependencies
*/
for (const key in args) {
if (key === "operator") {
continue;
// Get explicit types from dropdowns, default to text
let input1Type: ConditionValueType =
(args["input-1-type"] as ConditionValueType) ||
ConditionValueType.Text;
let input2Type: ConditionValueType =
(args["input-2-type"] as ConditionValueType) ||
ConditionValueType.Text;
// When types differ, coerce both to the more specific type
// so comparisons like text "true" == boolean true work correctly.
// Priority: Null/Undefined keep as-is, Boolean > Number > Text.
if (input1Type !== input2Type) {
const isNullish = (t: ConditionValueType): boolean =>
t === ConditionValueType.Null ||
t === ConditionValueType.Undefined;
if (!isNullish(input1Type) && !isNullish(input2Type)) {
const typePriority: Record<string, number> = {
[ConditionValueType.Boolean]: 2,
[ConditionValueType.Number]: 1,
[ConditionValueType.Text]: 0,
};
const p1: number = typePriority[input1Type] ?? 0;
const p2: number = typePriority[input2Type] ?? 0;
const commonType: ConditionValueType =
p1 >= p2 ? input1Type : input2Type;
input1Type = commonType;
input2Type = commonType;
}
const value: JSONValue = args[key];
let shouldHaveQuotes: boolean = false;
if (
typeof value === "string" &&
value !== "null" &&
value !== "undefined"
) {
shouldHaveQuotes = true;
}
if (typeof value === "object") {
args[key] = JSON.stringify(args[key]);
}
args[key] = shouldHaveQuotes ? `"${args[key]}"` : args[key];
}
type FormatValueFunction = (
value: JSONValue,
valueType: ConditionValueType,
) => string;
const formatValue: FormatValueFunction = (
value: JSONValue,
valueType: ConditionValueType,
): string => {
const strValue: string = typeof value === "object"
? JSON.stringify(value)
: String(value ?? "");
switch (valueType) {
case ConditionValueType.Boolean:
return strValue === "true" ? "true" : "false";
case ConditionValueType.Number:
return isNaN(Number(strValue)) ? "0" : String(Number(strValue));
case ConditionValueType.Null:
return "null";
case ConditionValueType.Undefined:
return "undefined";
case ConditionValueType.Text:
default:
return `"${strValue}"`;
}
};
args["input-1"] = formatValue(args["input-1"], input1Type);
args["input-2"] = formatValue(args["input-2"], input2Type);
type SerializeFunction = (arg: string) => string;
const serialize: SerializeFunction = (arg: string): string => {
@@ -107,13 +147,13 @@ export default class IfElse extends ComponentCode {
`;
if (args["operator"] === ConditionOperator.Contains) {
code += `return input1.includes(input2);`;
code += `return String(input1).includes(String(input2));`;
} else if (args["operator"] === ConditionOperator.DoesNotContain) {
code += `return !input1.includes(input2);`;
code += `return !String(input1).includes(String(input2));`;
} else if (args["operator"] === ConditionOperator.StartsWith) {
code += `return input1.startsWith(input2);`;
code += `return String(input1).startsWith(String(input2));`;
} else if (args["operator"] === ConditionOperator.EndsWith) {
code += `return input1.endsWith(input2);`;
code += `return String(input1).endsWith(String(input2));`;
} else {
code += `return input1 ${(args["operator"] as string) || "=="} input2;`;
}

View File

@@ -26,6 +26,7 @@ export enum ComponentInputType {
HTML = "HTML",
Operator = "Operator",
Markdown = "Markdown",
ValueType = "Value Type",
}
export enum ComponentType {

View File

@@ -5,6 +5,14 @@ import ComponentMetadata, {
ComponentType,
} from "./../Component";
export enum ConditionValueType {
Text = "text",
Boolean = "boolean",
Number = "number",
Null = "null",
Undefined = "undefined",
}
export enum ConditionOperator {
EqualTo = "==",
NotEqualTo = "!=",
@@ -27,6 +35,15 @@ const components: Array<ComponentMetadata> = [
iconProp: IconProp.Condition,
componentType: ComponentType.Component,
arguments: [
{
type: ComponentInputType.ValueType,
name: "Input 1 Type",
description:
"Type of Input 1. Defaults to Text if not selected.",
placeholder: "Text",
required: false,
id: "input-1-type",
},
{
type: ComponentInputType.Text,
name: "Input 1",
@@ -43,6 +60,15 @@ const components: Array<ComponentMetadata> = [
required: true,
id: "operator",
},
{
type: ComponentInputType.ValueType,
name: "Input 2 Type",
description:
"Type of Input 2. Defaults to Text if not selected.",
placeholder: "Text",
required: false,
id: "input-2-type",
},
{
type: ComponentInputType.Text,
name: "Input 2",

View File

@@ -8,7 +8,10 @@ import ComponentMetadata, {
import Components, { Categories } from "../../../Types/Workflow/Components";
import BaseModelComponentFactory from "../../../Types/Workflow/Components/BaseModel";
import Entities from "../../../Models/DatabaseModels/Index";
import { ConditionOperator } from "../../../Types/Workflow/Components/Condition";
import {
ConditionOperator,
ConditionValueType,
} from "../../../Types/Workflow/Components/Condition";
type LoadComponentsAndCategoriesFunction = () => {
components: Array<ComponentMetadata>;
@@ -230,6 +233,34 @@ export const componentInputTypeToFormFieldType: ComponentInputTypeToFormFieldTyp
};
}
if (componentInputType === ComponentInputType.ValueType) {
return {
fieldType: FormFieldSchemaType.Dropdown,
dropdownOptions: [
{
label: "Text",
value: ConditionValueType.Text,
},
{
label: "Boolean",
value: ConditionValueType.Boolean,
},
{
label: "Number",
value: ConditionValueType.Number,
},
{
label: "Null",
value: ConditionValueType.Null,
},
{
label: "Undefined",
value: ConditionValueType.Undefined,
},
],
};
}
if (componentInputType === ComponentInputType.Date) {
return {
fieldType: FormFieldSchemaType.Date,