From 3f507f60d117361dbe1629da1cdf3d4a003965c6 Mon Sep 17 00:00:00 2001 From: Deepak-Gnanasekar Date: Tue, 31 Mar 2026 12:48:16 +0530 Subject: [PATCH 1/6] bug fixes --- .../application/config_parser/constants.py | 9 +++++ backend/formulasql/functions/text.py | 11 +++--- .../ide/chat-ai/PastConversationActions.jsx | 35 +++++++++++++------ .../no-code-configuration/configure-joins.jsx | 8 +++++ .../editor/no-code-toolbar/formula-editor.jsx | 8 +++++ .../ide/editor/no-code-ui/filter/filter.jsx | 15 +++++--- 6 files changed, 65 insertions(+), 21 deletions(-) diff --git a/backend/backend/application/config_parser/constants.py b/backend/backend/application/config_parser/constants.py index 94577501..181adadd 100644 --- a/backend/backend/application/config_parser/constants.py +++ b/backend/backend/application/config_parser/constants.py @@ -318,6 +318,15 @@ "description": "Tests whether a number is greater than a supplied threshold value ", "function_type": "Math", }, + "HASH": { + "key": "HASH", + "value": "HASH", + "description": ( + "Returns a hash of the concatenated values. Accepts one or more columns." + " \n Example: HASH(col1) or HASH(col1, col2, col3)" + ), + "function_type": "Text", + }, "HOUR": { "key": "HOUR", "value": "HOUR", diff --git a/backend/formulasql/functions/text.py b/backend/formulasql/functions/text.py index 86197d8b..e4e72fb5 100644 --- a/backend/formulasql/functions/text.py +++ b/backend/formulasql/functions/text.py @@ -318,13 +318,14 @@ def startswith(table, node, data_types, inter_exps): @staticmethod def hash(table, node, data_types, inter_exps): - if node['inputs'].__len__() == 2: + if node['inputs'].__len__() >= 1: e = FormulaSQLUtils.build_ibis_expression(table, data_types, inter_exps, node['inputs'][0]).cast('string') - e2 = FormulaSQLUtils.build_ibis_expression(table, data_types, inter_exps, node['inputs'][1]) - e = e.hash(e2) + for i in range(1, node['inputs'].__len__()): + e = e + FormulaSQLUtils.build_ibis_expression(table, data_types, inter_exps, node['inputs'][i]).cast('string') + e = e.hash() else: - raise Exception("HASH function requires 1 parameter") - data_types[node['outputs'][0]] = 'string' + raise Exception("HASH function requires at least 1 parameter") + data_types[node['outputs'][0]] = 'numeric' return e @staticmethod diff --git a/frontend/src/ide/chat-ai/PastConversationActions.jsx b/frontend/src/ide/chat-ai/PastConversationActions.jsx index f439ae46..8f04aa84 100644 --- a/frontend/src/ide/chat-ai/PastConversationActions.jsx +++ b/frontend/src/ide/chat-ai/PastConversationActions.jsx @@ -16,6 +16,7 @@ const PastConversationActions = memo(function PastConversationActions({ handleUpdate, }) { const [confirmDeleteId, setConfirmDeleteId] = useState(null); + const [isDeleting, setIsDeleting] = useState(false); const [editingId, setEditingId] = useState(null); const [editValue, setEditValue] = useState(""); const [isSaving, setIsSaving] = useState(false); @@ -82,17 +83,29 @@ const PastConversationActions = memo(function PastConversationActions({ if (confirmDeleteId) { return ( - { - e.stopPropagation(); - handleDelete(confirmDeleteId); - }} - className="cursor-pointer past-conversation-action-icon" - /> - + {isDeleting ? ( + + ) : ( + <> + { + e.stopPropagation(); + setIsDeleting(true); + try { + await handleDelete(confirmDeleteId); + } finally { + setIsDeleting(false); + setConfirmDeleteId(null); + } + }} + className="cursor-pointer past-conversation-action-icon" + /> + + + )} ); } diff --git a/frontend/src/ide/editor/no-code-configuration/configure-joins.jsx b/frontend/src/ide/editor/no-code-configuration/configure-joins.jsx index c1ba457e..e089d650 100644 --- a/frontend/src/ide/editor/no-code-configuration/configure-joins.jsx +++ b/frontend/src/ide/editor/no-code-configuration/configure-joins.jsx @@ -464,6 +464,13 @@ function ConfigureJoins({ rhsTable.table_name ); } + // For Full join, keep only the first criteria and reset operator to EQ + if (value === "Full" && draft[joinIndex].criteria.length > 0) { + draft[joinIndex].criteria = [draft[joinIndex].criteria[0]]; + if (draft[joinIndex].criteria[0].condition) { + draft[joinIndex].criteria[0].condition.operator = "EQ"; + } + } }); } else if (key === "alias_name") { // Update joined_table alias_name for self-join support @@ -707,6 +714,7 @@ function ConfigureJoins({ setFilterConditions={setJoinFilterConditions} columnDetails={transformedColumnDetails} type="join" + joinType={joinType} join={joins} setJoins={setJoins} joinIndex={joinIndex} diff --git a/frontend/src/ide/editor/no-code-toolbar/formula-editor.jsx b/frontend/src/ide/editor/no-code-toolbar/formula-editor.jsx index 2babcd05..70bdbe90 100644 --- a/frontend/src/ide/editor/no-code-toolbar/formula-editor.jsx +++ b/frontend/src/ide/editor/no-code-toolbar/formula-editor.jsx @@ -312,6 +312,14 @@ const FUNCTION_SIGNATURES = { description: "Adds interval to date", }, + // Hashing + HASH: { + min: 1, + max: Infinity, + params: ["value1", "[value2]", "..."], + description: "Returns a hash of the concatenated values", + }, + // No-arg functions RANDOM: { min: 0, diff --git a/frontend/src/ide/editor/no-code-ui/filter/filter.jsx b/frontend/src/ide/editor/no-code-ui/filter/filter.jsx index a7d59c03..f4a823b7 100644 --- a/frontend/src/ide/editor/no-code-ui/filter/filter.jsx +++ b/frontend/src/ide/editor/no-code-ui/filter/filter.jsx @@ -428,8 +428,8 @@ function Filter({ newFilterCondition.condition.lhs.column?.data_type?.toLowerCase() || ""; let sanitized = value.trimStart(); if (dataType === "number") { - setShowHint(/[^\d.-]/.test(sanitized)); - sanitized = sanitized.replace(/[^\d.-]/g, ""); + setShowHint(/[^\d]/.test(sanitized)); + sanitized = sanitized.replace(/\D/g, ""); } if (!Array.isArray(newFilterCondition.condition.rhs.value)) { newFilterCondition.condition.rhs.value = ["", ""]; @@ -872,7 +872,10 @@ function Filter({ type === "join" ? getOperators(type, lhs.column?.data_type).filter( (item) => { - if (joinType === "Cross" && item.value !== "EQ") { + if ( + ["Cross", "Full"].includes(joinType) && + item.value !== "EQ" + ) { return false; } @@ -1020,11 +1023,13 @@ function Filter({ icon={} type="text" disabled={ + // For Full joins, only one condition is allowed (no additional filters) + joinType === "Full" || // For joins, only check length limit; for model/source, also check if columns exist - isJoinType + (isJoinType ? filterConditions.length >= 5 : !columnDetails?.columns?.filter?.length || - filterConditions.length >= 5 + filterConditions.length >= 5) } > {filterConditions.length ? "Add another filter" : "Add a filter"} From 4c49103f7cd5454b22420774f809a3ba9cbc8455 Mon Sep 17 00:00:00 2001 From: Deepak-Gnanasekar Date: Tue, 31 Mar 2026 13:00:56 +0530 Subject: [PATCH 2/6] removed between from the joins filter --- frontend/src/ide/editor/no-code-ui/filter/filter.jsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/frontend/src/ide/editor/no-code-ui/filter/filter.jsx b/frontend/src/ide/editor/no-code-ui/filter/filter.jsx index f4a823b7..0f776b89 100644 --- a/frontend/src/ide/editor/no-code-ui/filter/filter.jsx +++ b/frontend/src/ide/editor/no-code-ui/filter/filter.jsx @@ -879,7 +879,9 @@ function Filter({ return false; } - return ["NULL", "NOTNULL"].includes(item.value) + return ["NULL", "NOTNULL", "BETWEEN"].includes( + item.value + ) ? false : true; } From 07e2b5aab72d550349a0f10bb76ee775dd24ecfe Mon Sep 17 00:00:00 2001 From: Deepak-Gnanasekar Date: Tue, 31 Mar 2026 15:09:39 +0530 Subject: [PATCH 3/6] float field vaule enabled --- frontend/src/ide/editor/no-code-ui/filter/filter.jsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/frontend/src/ide/editor/no-code-ui/filter/filter.jsx b/frontend/src/ide/editor/no-code-ui/filter/filter.jsx index 0f776b89..539b923f 100644 --- a/frontend/src/ide/editor/no-code-ui/filter/filter.jsx +++ b/frontend/src/ide/editor/no-code-ui/filter/filter.jsx @@ -367,8 +367,8 @@ function Filter({ if (dataType === "number") { inAndNotIn - ? setAndSanitizeValue(/[^\d,]/, /[^\d,]/g) - : setAndSanitizeValue(/[^\d]/, /\D/g); + ? setAndSanitizeValue(/[^\d,.-]/, /[^\d,.-]/g) + : setAndSanitizeValue(/[^\d.-]/, /[^\d.-]/g); } newFilterCondition["condition"][conditionKey][key] = [value]; newFilterCondition["condition"][conditionKey]["type"] = typed; @@ -428,8 +428,8 @@ function Filter({ newFilterCondition.condition.lhs.column?.data_type?.toLowerCase() || ""; let sanitized = value.trimStart(); if (dataType === "number") { - setShowHint(/[^\d]/.test(sanitized)); - sanitized = sanitized.replace(/\D/g, ""); + setShowHint(/[^\d.-]/.test(sanitized)); + sanitized = sanitized.replace(/[^\d.-]/g, ""); } if (!Array.isArray(newFilterCondition.condition.rhs.value)) { newFilterCondition.condition.rhs.value = ["", ""]; From a834646b39ded6cb3eaa475ce7d05638278d518f Mon Sep 17 00:00:00 2001 From: Deepak-Gnanasekar Date: Tue, 31 Mar 2026 18:48:07 +0530 Subject: [PATCH 4/6] addressing comments --- backend/formulasql/functions/text.py | 22 +++++++++++++------ .../no-code-configuration/configure-joins.jsx | 2 +- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/backend/formulasql/functions/text.py b/backend/formulasql/functions/text.py index e4e72fb5..07218c36 100644 --- a/backend/formulasql/functions/text.py +++ b/backend/formulasql/functions/text.py @@ -318,13 +318,21 @@ def startswith(table, node, data_types, inter_exps): @staticmethod def hash(table, node, data_types, inter_exps): - if node['inputs'].__len__() >= 1: - e = FormulaSQLUtils.build_ibis_expression(table, data_types, inter_exps, node['inputs'][0]).cast('string') - for i in range(1, node['inputs'].__len__()): - e = e + FormulaSQLUtils.build_ibis_expression(table, data_types, inter_exps, node['inputs'][i]).cast('string') - e = e.hash() - else: - raise Exception("HASH function requires at least 1 parameter") + inputs = node['inputs'] + + if not inputs: + raise ValueError("HASH function requires at least 1 parameter") + + e = FormulaSQLUtils.build_ibis_expression( + table, data_types, inter_exps, inputs[0] + ).cast('string') + + for input_node in inputs[1:]: + e = e + FormulaSQLUtils.build_ibis_expression( + table, data_types, inter_exps, input_node + ).cast('string') + + e = e.hash() data_types[node['outputs'][0]] = 'numeric' return e diff --git a/frontend/src/ide/editor/no-code-configuration/configure-joins.jsx b/frontend/src/ide/editor/no-code-configuration/configure-joins.jsx index e089d650..407404b8 100644 --- a/frontend/src/ide/editor/no-code-configuration/configure-joins.jsx +++ b/frontend/src/ide/editor/no-code-configuration/configure-joins.jsx @@ -467,7 +467,7 @@ function ConfigureJoins({ // For Full join, keep only the first criteria and reset operator to EQ if (value === "Full" && draft[joinIndex].criteria.length > 0) { draft[joinIndex].criteria = [draft[joinIndex].criteria[0]]; - if (draft[joinIndex].criteria[0].condition) { + if (draft[joinIndex]?.criteria?.[0]?.condition) { draft[joinIndex].criteria[0].condition.operator = "EQ"; } } From b8563e8ed182230aa73bda469f3193dfb9a01153 Mon Sep 17 00:00:00 2001 From: Deepak-Gnanasekar Date: Thu, 2 Apr 2026 10:18:01 +0530 Subject: [PATCH 5/6] fix for greptile comments --- frontend/src/ide/editor/no-code-ui/filter/filter.jsx | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/frontend/src/ide/editor/no-code-ui/filter/filter.jsx b/frontend/src/ide/editor/no-code-ui/filter/filter.jsx index 539b923f..d9be4f92 100644 --- a/frontend/src/ide/editor/no-code-ui/filter/filter.jsx +++ b/frontend/src/ide/editor/no-code-ui/filter/filter.jsx @@ -369,6 +369,17 @@ function Filter({ inAndNotIn ? setAndSanitizeValue(/[^\d,.-]/, /[^\d,.-]/g) : setAndSanitizeValue(/[^\d.-]/, /[^\d.-]/g); + // Sanitize each numeric segment to prevent malformed values + // like "3.1.4" (multiple dots) or "--3" (multiple minus signs) + const sanitizeNumericSegment = (s) => { + const sign = s.startsWith("-") ? "-" : ""; + const rest = (sign ? s.slice(1) : s).replace(/-/g, ""); + const parts = rest.split("."); + return sign + parts[0] + (parts.length > 1 ? "." + parts.slice(1).join("") : ""); + }; + value = inAndNotIn + ? value.split(",").map(sanitizeNumericSegment).join(",") + : sanitizeNumericSegment(value); } newFilterCondition["condition"][conditionKey][key] = [value]; newFilterCondition["condition"][conditionKey]["type"] = typed; From 0ee958501456a0e6559bf47be7533648e29de284 Mon Sep 17 00:00:00 2001 From: Deepak-Gnanasekar Date: Thu, 2 Apr 2026 10:19:47 +0530 Subject: [PATCH 6/6] lint fixes --- frontend/src/ide/editor/no-code-ui/filter/filter.jsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/frontend/src/ide/editor/no-code-ui/filter/filter.jsx b/frontend/src/ide/editor/no-code-ui/filter/filter.jsx index d9be4f92..c4979869 100644 --- a/frontend/src/ide/editor/no-code-ui/filter/filter.jsx +++ b/frontend/src/ide/editor/no-code-ui/filter/filter.jsx @@ -375,7 +375,11 @@ function Filter({ const sign = s.startsWith("-") ? "-" : ""; const rest = (sign ? s.slice(1) : s).replace(/-/g, ""); const parts = rest.split("."); - return sign + parts[0] + (parts.length > 1 ? "." + parts.slice(1).join("") : ""); + return ( + sign + + parts[0] + + (parts.length > 1 ? "." + parts.slice(1).join("") : "") + ); }; value = inAndNotIn ? value.split(",").map(sanitizeNumericSegment).join(",")