From 4343d6a8c692251bf4a6089ce65f4c1caf4309a2 Mon Sep 17 00:00:00 2001 From: Deepak-Gnanasekar Date: Wed, 1 Apr 2026 15:40:14 +0530 Subject: [PATCH 1/8] table cell data hover copy added --- .../editor/no-code-model/no-code-model.jsx | 45 ++++--- .../widgets/copyable-cell/copyable-cell.css | 30 +++++ frontend/src/widgets/copyable-cell/index.js | 117 ++++++++++++++++++ 3 files changed, 176 insertions(+), 16 deletions(-) create mode 100644 frontend/src/widgets/copyable-cell/copyable-cell.css create mode 100644 frontend/src/widgets/copyable-cell/index.js diff --git a/frontend/src/ide/editor/no-code-model/no-code-model.jsx b/frontend/src/ide/editor/no-code-model/no-code-model.jsx index f988ced..ff79bd4 100644 --- a/frontend/src/ide/editor/no-code-model/no-code-model.jsx +++ b/frontend/src/ide/editor/no-code-model/no-code-model.jsx @@ -91,6 +91,7 @@ import { OpenTab, } from "../../../base/icons/index.js"; import { SpinnerLoader } from "../../../widgets/spinner_loader/index.js"; +import { CopyableCell } from "../../../widgets/copyable-cell/index.js"; import "./no-code-model.css"; import "reactflow/dist/style.css"; import { useNotificationService } from "../../../service/notification-service.js"; @@ -736,7 +737,9 @@ function NoCodeModel({ nodeData }) { setConfigApply(true); handleModalClose("ok"); }) - .catch(() => { + .catch((error) => { + notify({ error }); + setIsLoading(false); handleModalClose(); }); }; @@ -1353,23 +1356,33 @@ function NoCodeModel({ nodeData }) { ? JSON.stringify(text) : text; + const formattedValue = + displayValue === null || displayValue === undefined + ? "" + : ["Boolean", "boolean"].includes(dataType) + ? String(displayValue) + : dataType === "Number" + ? formatNumber(displayValue) + : displayValue; + + const alignClass = + dataType === "Number" + ? "flex-justify-right" + : ["Boolean", "boolean"].includes(dataType) + ? "flex-justify-center" + : ""; + return ( - - {["Boolean", "boolean"].includes(dataType) - ? String(displayValue) - : dataType === "Number" - ? formatNumber(displayValue) - : displayValue} - + {formattedValue} + ); }, }; diff --git a/frontend/src/widgets/copyable-cell/copyable-cell.css b/frontend/src/widgets/copyable-cell/copyable-cell.css new file mode 100644 index 0000000..1bf543c --- /dev/null +++ b/frontend/src/widgets/copyable-cell/copyable-cell.css @@ -0,0 +1,30 @@ +/* Copyable Cell - hover tooltip with copy for table cells */ + +.copyable-cell { + display: flex; + align-items: center; + width: 100%; + min-height: 20px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + cursor: default; +} + +/* Tooltip content layout */ +.copyable-cell-tooltip { + display: flex; + align-items: flex-start; + gap: 8px; + font-family: var(--font-family); +} + +.copyable-cell-tooltip-text { + flex: 1; + min-width: 0; + word-break: break-word; + white-space: pre-wrap; + user-select: text; + font-size: 12px; + line-height: 1.5; +} diff --git a/frontend/src/widgets/copyable-cell/index.js b/frontend/src/widgets/copyable-cell/index.js new file mode 100644 index 0000000..5a4f9d2 --- /dev/null +++ b/frontend/src/widgets/copyable-cell/index.js @@ -0,0 +1,117 @@ +import { useState, useCallback, useRef, useEffect, useMemo } from "react"; +import PropTypes from "prop-types"; +import { Tooltip, theme } from "antd"; +import { CopyOutlined, CheckOutlined } from "@ant-design/icons"; + +import "./copyable-cell.css"; + +const { useToken } = theme; +const MAX_TOOLTIP_LENGTH = 500; + +function CopyableCell({ children, value, className = "" }) { + const [copied, setCopied] = useState(false); + const timeoutRef = useRef(null); + const { token } = useToken(); + + const textValue = value !== undefined && value !== null ? String(value) : ""; + + // Cleanup timeout on unmount + useEffect(() => { + return () => { + if (timeoutRef.current) clearTimeout(timeoutRef.current); + }; + }, []); + + const doCopy = useCallback( + async (e) => { + e.stopPropagation(); + if (!textValue) return; + try { + await navigator?.clipboard?.writeText(textValue); + setCopied(true); + if (timeoutRef.current) clearTimeout(timeoutRef.current); + timeoutRef.current = setTimeout(() => setCopied(false), 2000); + } catch { + // silently fail – clipboard may not be available + } + }, + [textValue] + ); + + const overlayStyle = useMemo( + () => ({ + border: `1px solid ${token.colorBorder}`, + borderRadius: "8px", + }), + [token.colorBorder] + ); + + const copiedIconStyle = useMemo( + () => ({ color: token.colorSuccess, fontSize: 14, padding: 2 }), + [token.colorSuccess] + ); + + const copyIconStyle = useMemo( + () => ({ + cursor: "pointer", + color: token.colorTextSecondary, + fontSize: 14, + padding: 2, + }), + [token.colorTextSecondary] + ); + + if (!textValue) { + return
{children}
; + } + + const truncatedValue = + textValue.length > MAX_TOOLTIP_LENGTH + ? textValue.slice(0, MAX_TOOLTIP_LENGTH) + "..." + : textValue; + + const tooltipContent = ( +
+ + {truncatedValue} + + {copied ? ( + + ) : ( + + + + )} +
+ ); + + return ( + +
+ {children} +
+
+ ); +} + +CopyableCell.propTypes = { + children: PropTypes.node, + value: PropTypes.oneOfType([ + PropTypes.string, + PropTypes.number, + PropTypes.bool, + ]), + className: PropTypes.string, +}; + +export { CopyableCell }; From 22cdfd671bef5cce9a25cd7dc266d9448bfed0a8 Mon Sep 17 00:00:00 2001 From: Deepak-Gnanasekar Date: Wed, 1 Apr 2026 17:26:26 +0530 Subject: [PATCH 2/8] seed failure fix in duckdb --- backend/visitran/adapters/duckdb/seed.py | 17 ++++++++++++++++- frontend/src/service/notification-service.js | 2 +- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/backend/visitran/adapters/duckdb/seed.py b/backend/visitran/adapters/duckdb/seed.py index d68bcf9..7ae0fde 100644 --- a/backend/visitran/adapters/duckdb/seed.py +++ b/backend/visitran/adapters/duckdb/seed.py @@ -2,6 +2,7 @@ from visitran.adapters.duckdb.connection import DuckDbConnection from visitran.adapters.seed import BaseSeed +from visitran.errors import SeedFailureException class DuckDbSeed(BaseSeed): @@ -21,6 +22,20 @@ def execute(self) -> None: Overiding the base execute method to use the duckdb inbuild method """ + if self.db_connection is None: + raise SeedFailureException( + seed_file_name=self.csv_file_name, + error_message="Database connection is not available. Please check your connection settings.", + ) + # The drop SQL query will drop the table if it is only exists ! # Constructing SQL statement for CSV schema in target adapters - self.db_connection.insert_csv_records(abs_path=self.abs_path, table_name=self.destination_table_name) + try: + self.db_connection.insert_csv_records(abs_path=self.abs_path, table_name=self.destination_table_name) + except SeedFailureException: + raise + except Exception as err: + raise SeedFailureException( + seed_file_name=self.csv_file_name, + error_message=f'Failed to seed table "{self.destination_table_name}": {err}', + ) diff --git a/frontend/src/service/notification-service.js b/frontend/src/service/notification-service.js index 8194965..c1d1f8e 100644 --- a/frontend/src/service/notification-service.js +++ b/frontend/src/service/notification-service.js @@ -59,7 +59,7 @@ function NotificationProvider({ children }) { if (errorData && typeof errorData.error_message === "string") { const text = errorData.error_message; if (errorData.is_markdown) { - finalMessage = ""; + finalMessage = "Failed"; const formatted = text.replace(/\n/g, " \n"); finalDescription = formatted; type = errorData?.severity?.toLowerCase() || "error"; From 8decef2f1429f727ce2f07d81643081a55fab8e9 Mon Sep 17 00:00:00 2001 From: Deepak-Gnanasekar Date: Thu, 2 Apr 2026 16:42:33 +0530 Subject: [PATCH 3/8] removed custom data from env --- .../base/components/environment/NewEnv.jsx | 74 ++----------------- 1 file changed, 6 insertions(+), 68 deletions(-) diff --git a/frontend/src/base/components/environment/NewEnv.jsx b/frontend/src/base/components/environment/NewEnv.jsx index a82e9f8..d1b084f 100644 --- a/frontend/src/base/components/environment/NewEnv.jsx +++ b/frontend/src/base/components/environment/NewEnv.jsx @@ -1,4 +1,4 @@ -import { useState, useEffect, useCallback, useMemo } from "react"; +import { useState, useEffect, useCallback } from "react"; import Cookies from "js-cookie"; import { Button, Divider, Modal, Space } from "antd"; import PropTypes from "prop-types"; @@ -6,10 +6,8 @@ import isEqual from "lodash/isEqual.js"; import { useAxiosPrivate } from "../../../service/axios-service"; import { orgStore } from "../../../store/org-store"; -import { generateKey } from "../../../common/helpers"; import { fetchAllConnections, - fetchProjectByConnection, fetchSingleEnvironment, updateEnvironmentApi, createEnvironmentApi, @@ -23,7 +21,6 @@ import encryptionService from "../../../service/encryption-service"; import "./environment.css"; import EnvGeneralSection from "./EnvGeneralSection"; -import EnvCustomDataSection from "./EnvCustomDataSection"; import { CreateConnection } from "./CreateConnection"; import { useNotificationService } from "../../../service/notification-service"; @@ -41,7 +38,6 @@ const NewEnv = ({ const [isModalOpen, setIsModalOpen] = useState(false); const [connectionList, setConnectionList] = useState([]); - const [customData, setCustomData] = useState([]); const [connection, setConnection] = useState({ id: "" }); const [connectionDataSource, setConnectionDataSource] = useState(null); const [connectionSchema, setConnectionSchema] = useState({}); @@ -53,13 +49,11 @@ const NewEnv = ({ const [connType, setConnType] = useState("url"); const [connectionDetailsUpdated, setConnectionDetailsUpdated] = useState(false); - const [projListDep, setProjListDep] = useState([]); const [connectDetailBackup, setConnectDetailBackup] = useState({}); const [initialPrefillData, setInitialPrefillData] = useState({ name: "", description: "", deployment_type: "", - custom_data: [], }); const [activeUpdateBtn, setActiveUpdateBtn] = useState(false); const [isEncryptionLoading, setIsEncryptionLoading] = useState(true); @@ -109,7 +103,6 @@ const NewEnv = ({ description: "", deployment_type: "", }); - setCustomData([]); setInputFields({}); setConnection({ id: "" }); setConnectionDataSource(null); @@ -121,7 +114,6 @@ const NewEnv = ({ name: "", description: "", deployment_type: "", - custom_data: [], }); setConnectDetailBackup({}); setIsCredentialsRevealed(false); @@ -135,7 +127,6 @@ const NewEnv = ({ description: "", deployment_type: "", }); - setCustomData([]); setInputFields({}); setConnection({ id: "" }); setConnectionDataSource(null); @@ -147,7 +138,6 @@ const NewEnv = ({ name: "", description: "", deployment_type: "", - custom_data: [], }); setConnectDetailBackup({}); setIsCredentialsRevealed(false); @@ -262,16 +252,6 @@ const NewEnv = ({ } }, [selectedOrgId]); - const getProjectDependency = useCallback(async () => { - try { - const data = await fetchProjectByConnection(axiosRef, selectedOrgId, id); - setProjListDep(data); - } catch (error) { - console.error(error); - notify({ error }); - } - }, [id, selectedOrgId]); - useEffect(() => { getAllConnections(); }, [getAllConnections]); @@ -279,8 +259,7 @@ const NewEnv = ({ const getSingleEnvironmentDetails = useCallback(async () => { try { const data = await fetchSingleEnvironment(axiosRef, selectedOrgId, id); - const { connection, name, description, custom_data, deployment_type } = - data; + const { connection, name, description, deployment_type } = data; const connDetail = data.connection_details; setEnvNameDescInfo({ name, description, deployment_type }); @@ -288,14 +267,12 @@ const NewEnv = ({ name, description, deployment_type, - custom_data, }); setConnectDetailBackup({ connection_details: connDetail }); setConnType( connDetail?.connection_type ? connDetail?.connection_type : "host" ); setConnection({ id: connection.id }); - setCustomData(Array.isArray(custom_data) ? custom_data : []); // Process connection details to handle JSON objects for textarea fields const processedConnDetail = { ...connDetail }; @@ -322,14 +299,13 @@ const NewEnv = ({ useEffect(() => { if (id) { getSingleEnvironmentDetails(); - getProjectDependency(); } else { setConnection({ id: "" }); setEnvNameDescInfo({ name: "", description: "", deployment_type: "" }); setConnectionDataSource(null); setConnectionSchema({}); } - }, [id, getSingleEnvironmentDetails, getProjectDependency]); + }, [id, getSingleEnvironmentDetails]); const handleEnvNameDesChange = (value, name) => { setEnvNameDescInfo((prev) => ({ ...prev, [name]: value })); @@ -437,29 +413,6 @@ const NewEnv = ({ connectionDataSource, ]); - const AddnewEntry = () => { - const singleData = { source_schema: "", destination_schema: "" }; - setCustomData((prev) => [...prev, { id: generateKey(), ...singleData }]); - }; - - const handleCustomFieldChange = (value, name, rowId) => { - setCustomData((prev) => - prev.map((item) => - item.id === rowId ? { ...item, [name]: value } : item - ) - ); - }; - - const disabledAddCustomBtn = useMemo(() => { - return customData.some( - (item) => !item.source_schema || !item.destination_schema - ); - }, [customData]); - - const handleDelete = (rowId) => { - setCustomData((prev) => prev.filter((el) => el.id !== rowId)); - }; - const updateEnvironment = async () => { try { // Prepare environment data @@ -472,7 +425,7 @@ const NewEnv = ({ connection_type: connType, }), }, - custom_data: customData, + }; // Encrypt sensitive fields if encryption service is available @@ -526,7 +479,7 @@ const NewEnv = ({ connection_type: connType, }), }, - custom_data: customData, + }; // Encrypt sensitive fields if encryption service is available @@ -561,7 +514,6 @@ const NewEnv = ({ message: "Environment Created Successfully", }); setEnvNameDescInfo({ name: "", description: "", deployment_type: "" }); - setCustomData([]); setConnection({ id: "" }); } } catch (error) { @@ -581,10 +533,9 @@ const NewEnv = ({ name: envNameDescInfo.name, description: envNameDescInfo.description, deployment_type: envNameDescInfo.deployment_type, - custom_data: customData, }); setActiveUpdateBtn(!res); - }, [envNameDescInfo, customData, initialPrefillData]); + }, [envNameDescInfo, initialPrefillData]); useEffect(() => { const res = isEqual(connectDetailBackup, { @@ -625,19 +576,6 @@ const NewEnv = ({ - - - -
From e52692b4beccc0c82f07ba2452c9b871848af9fe Mon Sep 17 00:00:00 2001 From: Deepak-Gnanasekar Date: Thu, 2 Apr 2026 16:55:32 +0530 Subject: [PATCH 4/8] lint and cell copy fix --- .../widgets/copyable-cell/copyable-cell.css | 6 +---- frontend/src/widgets/copyable-cell/index.js | 27 ++++++++++--------- 2 files changed, 15 insertions(+), 18 deletions(-) diff --git a/frontend/src/widgets/copyable-cell/copyable-cell.css b/frontend/src/widgets/copyable-cell/copyable-cell.css index 1bf543c..2175468 100644 --- a/frontend/src/widgets/copyable-cell/copyable-cell.css +++ b/frontend/src/widgets/copyable-cell/copyable-cell.css @@ -1,10 +1,6 @@ /* Copyable Cell - hover tooltip with copy for table cells */ -.copyable-cell { - display: flex; - align-items: center; - width: 100%; - min-height: 20px; +.copyable-cell-text { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; diff --git a/frontend/src/widgets/copyable-cell/index.js b/frontend/src/widgets/copyable-cell/index.js index 5a4f9d2..3a17490 100644 --- a/frontend/src/widgets/copyable-cell/index.js +++ b/frontend/src/widgets/copyable-cell/index.js @@ -62,7 +62,7 @@ function CopyableCell({ children, value, className = "" }) { ); if (!textValue) { - return
{children}
; + return {children}; } const truncatedValue = @@ -89,18 +89,19 @@ function CopyableCell({ children, value, className = "" }) { ); return ( - -
- {children} -
-
+ + + + {children} + + + ); } From cbc4241bef1a1d42f5c47b96eb3c857ac41cda57 Mon Sep 17 00:00:00 2001 From: Deepak-Gnanasekar Date: Thu, 2 Apr 2026 17:06:42 +0530 Subject: [PATCH 5/8] lint fix --- frontend/src/base/components/environment/NewEnv.jsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/frontend/src/base/components/environment/NewEnv.jsx b/frontend/src/base/components/environment/NewEnv.jsx index 1bdbe97..9f83e08 100644 --- a/frontend/src/base/components/environment/NewEnv.jsx +++ b/frontend/src/base/components/environment/NewEnv.jsx @@ -441,7 +441,6 @@ const NewEnv = ({ connection_type: connType, }), }, - }; // Encrypt sensitive fields if encryption service is available @@ -495,7 +494,6 @@ const NewEnv = ({ connection_type: connType, }), }, - }; // Encrypt sensitive fields if encryption service is available From 740955144f321bcf616f7ef445397a88dcfd5681 Mon Sep 17 00:00:00 2001 From: Deepak-Gnanasekar Date: Thu, 2 Apr 2026 17:21:58 +0530 Subject: [PATCH 6/8] addressing greptile cmt --- frontend/src/ide/editor/no-code-model/no-code-model.jsx | 2 +- frontend/src/widgets/copyable-cell/index.js | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/frontend/src/ide/editor/no-code-model/no-code-model.jsx b/frontend/src/ide/editor/no-code-model/no-code-model.jsx index 72f4cb5..8f3fa3f 100644 --- a/frontend/src/ide/editor/no-code-model/no-code-model.jsx +++ b/frontend/src/ide/editor/no-code-model/no-code-model.jsx @@ -1382,7 +1382,7 @@ function NoCodeModel({ nodeData }) { return ( ) : ( - - - + )}
); From df930a0c20aa0c98dbc1e6fbd70907700926475a Mon Sep 17 00:00:00 2001 From: Deepak-Gnanasekar Date: Tue, 7 Apr 2026 16:47:32 +0530 Subject: [PATCH 7/8] tweaks on copy cell rendering --- frontend/src/widgets/copyable-cell/index.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/frontend/src/widgets/copyable-cell/index.js b/frontend/src/widgets/copyable-cell/index.js index b33b6b5..3060edc 100644 --- a/frontend/src/widgets/copyable-cell/index.js +++ b/frontend/src/widgets/copyable-cell/index.js @@ -1,4 +1,4 @@ -import { useState, useCallback, useRef, useEffect, useMemo } from "react"; +import { memo, useState, useCallback, useRef, useEffect, useMemo } from "react"; import PropTypes from "prop-types"; import { Tooltip, theme } from "antd"; import { CopyOutlined, CheckOutlined } from "@ant-design/icons"; @@ -8,7 +8,7 @@ import "./copyable-cell.css"; const { useToken } = theme; const MAX_TOOLTIP_LENGTH = 500; -function CopyableCell({ children, value, className = "" }) { +const CopyableCell = memo(function CopyableCell({ children, value, className = "" }) { const [copied, setCopied] = useState(false); const timeoutRef = useRef(null); const { token } = useToken(); @@ -101,7 +101,7 @@ function CopyableCell({ children, value, className = "" }) { ); -} +}); CopyableCell.propTypes = { children: PropTypes.node, From cdbdd90aeb4c1e7785580a3c246e9811f82e4442 Mon Sep 17 00:00:00 2001 From: Deepak-Gnanasekar Date: Tue, 7 Apr 2026 16:55:05 +0530 Subject: [PATCH 8/8] lint fix --- frontend/src/widgets/copyable-cell/index.js | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/frontend/src/widgets/copyable-cell/index.js b/frontend/src/widgets/copyable-cell/index.js index 3060edc..9f1bfaf 100644 --- a/frontend/src/widgets/copyable-cell/index.js +++ b/frontend/src/widgets/copyable-cell/index.js @@ -8,7 +8,11 @@ import "./copyable-cell.css"; const { useToken } = theme; const MAX_TOOLTIP_LENGTH = 500; -const CopyableCell = memo(function CopyableCell({ children, value, className = "" }) { +const CopyableCell = memo(function CopyableCell({ + children, + value, + className = "", +}) { const [copied, setCopied] = useState(false); const timeoutRef = useRef(null); const { token } = useToken(); @@ -81,7 +85,11 @@ const CopyableCell = memo(function CopyableCell({ children, value, className = " {copied ? ( ) : ( - + )} );