From 509175e5ebc1d2b57f14162509b024272d2e3ec8 Mon Sep 17 00:00:00 2001 From: maranix Date: Sat, 19 Oct 2024 12:06:18 +0530 Subject: [PATCH 1/3] ProviderForm: fix Database Schema Table Row description overflow --- .../ProviderForm/ProviderForm.jsx | 586 +++++++++--------- 1 file changed, 294 insertions(+), 292 deletions(-) diff --git a/ui/src/pages/Configuration/ProviderForm/ProviderForm.jsx b/ui/src/pages/Configuration/ProviderForm/ProviderForm.jsx index 920ffd6a..4f4834cb 100644 --- a/ui/src/pages/Configuration/ProviderForm/ProviderForm.jsx +++ b/ui/src/pages/Configuration/ProviderForm/ProviderForm.jsx @@ -11,12 +11,12 @@ import { FaArrowLeft, FaPen } from "react-icons/fa6"; import { RiPlugLine } from "react-icons/ri"; import { FaRegArrowAltCircleRight } from "react-icons/fa"; -import { FiTable} from "react-icons/fi" +import { FiTable } from "react-icons/fi" -import { useEffect, useState, useRef} from "react" +import { useEffect, useState, useRef } from "react" import { useParams, useNavigate, useSearchParams } from "react-router-dom" -import { getConnector, healthCheck, saveConnector, updateSchema, updateDocument} from "src/services/Connectors" +import { getConnector, healthCheck, saveConnector, updateSchema, updateDocument } from "src/services/Connectors" import { toast } from "react-toastify" import "./DatabaseTable.css" @@ -27,7 +27,7 @@ import { API_URL } from "src/config/const" import UploadFile from "src/utils/http/UploadFile" -const ProviderForm = ()=>{ +const ProviderForm = () => { const [providerDetails, setProviderDetails] = useState({}) const [providerConfig, setProviderConfig] = useState([]) @@ -40,140 +40,142 @@ const ProviderForm = ()=>{ const [progressPrecentage, setProgressPrecentage] = useState(0); const [progressTime, setProgressTime] = useState(''); const pdfUploadRef = useRef(null); - - + + const [disableConnectorSave, setDisableConnectorSave] = useState(true); - - let [documentationError, setDocumentationError] = useState({hasError: false, errorMessage: ""}) + + let [documentationError, setDocumentationError] = useState({ hasError: false, errorMessage: "" }) let configDocRef = useRef(null) let [searchParams] = useSearchParams(); - - const { register, getValues, handleSubmit, trigger, setValue , formState } = useForm({mode : "all"}) + + const { register, getValues, handleSubmit, trigger, setValue, formState } = useForm({ mode: "all" }) const { errors } = formState - const {providerId, connectorId} = useParams() + const { providerId, connectorId } = useParams() const navigate = useNavigate() const maxFileSizeMB = 10; - const maxFiles = 5; + const maxFiles = 5; let tableColumns = [ - + { name: 'Name', - selector: row =>
{row.table_name}
, + selector: row =>
{row.table_name}
, // sortable: true, width: "200px" }, { name: 'Description', - grow:1, + style: { + width: '200px', + }, selector: row => { - return( -
-
-
- - {row.description} -
-
- -
+ return ( +
+
+
+ + {row.description} +
+
+
+
) } // sortable: true, } - -] + ] - const updateTableDetails = (elem)=>{ - let tempTableDetails = JSON.parse(window.localStorage.getItem("dbschema")) - if(elem){ - if(elem.dataset.type == "table"){ - tempTableDetails[elem.dataset.tableId].description = elem.value + const updateTableDetails = (elem) => { + let tempTableDetails = JSON.parse(window.localStorage.getItem("dbschema")) - }else{ + if (elem) { + if (elem.dataset.type == "table") { + tempTableDetails[elem.dataset.tableId].description = elem.value + + } else { tempTableDetails[elem.dataset.tableId].columns[elem.dataset.columnId].description = elem.value - + } } - + window.localStorage.setItem("dbschema", JSON.stringify(tempTableDetails)) - + } - - - - const rowExpandComponent = (row)=>{ - let tempTableDetails = JSON.parse(window.localStorage.getItem("dbschema")) - return(<> -
- {row?.data?.columns?.map((column, index)=>{ - return( -
-
{column.column_name}
-
-
-
-
- - { tempTableDetails[row.data.table_id].columns[column.column_id].description != "" ? tempTableDetails[row.data.table_id].columns[column.column_id].description : column.description} -
-
- -
+ + + + const rowExpandComponent = (row) => { + let tempTableDetails = JSON.parse(window.localStorage.getItem("dbschema")) + return (<> +
+ {row?.data?.columns?.map((column, index) => { + return ( +
+
{column.column_name}
+
+
+
+
+ + {tempTableDetails[row.data.table_id].columns[column.column_id].description != "" ? tempTableDetails[row.data.table_id].columns[column.column_id].description : column.description} +
+
+
- -
-
+
+ +
- - ) - })} -
+
+ + ) + })} +
) } - const onRowExpand = (expandState)=>{ - - if(expandState == true){ - setTimeout(()=>{ + const onRowExpand = (expandState) => { + + if (expandState == true) { + setTimeout(() => { let elem = document.querySelectorAll(".field-edit"); - + for (let index = 0; index < elem.length; index++) { - + let targetElem = elem[index].parentElement.parentElement - targetElem.addEventListener("click",()=>{ + targetElem.addEventListener("click", () => { targetElem.querySelector(".textarea").addEventListener("focusout", (event) => { targetElem.querySelector(".textarea").style.display = "none" targetElem.querySelector(".span").style.display = "block" targetElem.querySelector(".span").innerText = targetElem.querySelector(".textarea").value - + let txtElem = targetElem.querySelector(".textarea") - let tempTableDetails = JSON.parse(window.localStorage.getItem("dbschema")) + let tempTableDetails = JSON.parse(window.localStorage.getItem("dbschema")) tempTableDetails[txtElem.dataset.tableId].columns[txtElem.dataset.columnId].description = txtElem.value - + window.localStorage.setItem("dbschema", JSON.stringify(tempTableDetails)) - - }); - if(targetElem.querySelector(".textarea").style.display == "none"){ + }); + + if (targetElem.querySelector(".textarea").style.display == "none") { targetElem.querySelector(".textarea").style.display = "block" targetElem.querySelector(".textarea").focus() targetElem.querySelector(".span").style.display = "none" - }else{ + } else { targetElem.querySelector(".textarea").style.display = "none" targetElem.querySelector(".span").style.display = "block" } @@ -181,42 +183,42 @@ const ProviderForm = ()=>{ }) } - },1000) - + }, 1000) + } } - const getProviderDetails = ()=>{ + const getProviderDetails = () => { - getProviderInfo(providerId).then(response=>{ + getProviderInfo(providerId).then(response => { let data = response.data.data; setProviderDetails({ name: data.provider.name, - description: data.provider.description, + description: data.provider.description, icon: data.provider.icon, category_id: data.provider.category_id, enable: data.provider.enable }) setProviderConfig(data.provider.configs) - if(connectorId){ + if (connectorId) { getConnectDetails(); } - + }) } - - const getConnectDetails = ()=>{ - getConnector(connectorId).then(response=>{ + + const getConnectDetails = () => { + getConnector(connectorId).then(response => { let connectorData = response.data.data.connector; let connectorConfig = response.data.data.connector.connector_config - - setValue("pluginName", connectorData.connector_name ) - setValue("pluginDescription", connectorData.connector_description ) - for( let key in connectorConfig){ + setValue("pluginName", connectorData.connector_name) + setValue("pluginDescription", connectorData.connector_description) + + for (let key in connectorConfig) { setValue(key, connectorConfig[key]) } @@ -226,79 +228,79 @@ const ProviderForm = ()=>{ const fetchedFiles = connectorConfig.document_files?.map(file => ({ file_path: file.file_path, file_name: file.file_name, - file_size: parseFloat(file.file_size) * 1024, + file_size: parseFloat(file.file_size) * 1024, file_id: file.file_id })) || []; setFiles(prevFiles => [...prevFiles, ...fetchedFiles]); - setDisableConnectorSave(false); + setDisableConnectorSave(false); let tempSaveTableDetails = {} - connectorData.schema_config?.map(item=>{ - if(!tempSaveTableDetails[item.table_id]){ - tempSaveTableDetails[item.table_id] = { table_id: item.table_id, table_name: item.table_name, description: item.description, columns: {}} + connectorData.schema_config?.map(item => { + if (!tempSaveTableDetails[item.table_id]) { + tempSaveTableDetails[item.table_id] = { table_id: item.table_id, table_name: item.table_name, description: item.description, columns: {} } } - - item?.columns?.map(col=>{ - if(!tempSaveTableDetails[item.table_id].columns[col.column_id]){ - tempSaveTableDetails[item.table_id].columns[col.column_id] = { column_id: col.column_id, column_name: col.column_name, description :col.description } + + item?.columns?.map(col => { + if (!tempSaveTableDetails[item.table_id].columns[col.column_id]) { + tempSaveTableDetails[item.table_id].columns[col.column_id] = { column_id: col.column_id, column_name: col.column_name, description: col.description } } - + }) - + }) window.localStorage.setItem("dbschema", JSON.stringify(tempSaveTableDetails)) - + }) } - + const onSaveFiles = (file) => { const uploadUrl = API_URL + `/connector/upload/datasource`; const formData = new FormData(); formData.append('file', file); setShowProgressBar(true); - + return UploadFile(uploadUrl, formData, (percentage, estimatedTime) => { setProgressPrecentage(percentage); setProgressTime(estimatedTime); }) - .then(response => { - const fileData = response.data.data.file; - const fileDetails = { - file_path: fileData.file_path, - file_name: fileData.file_name, - file_size: fileData.file_size, - file_id: fileData.file_id - }; - - setFilePaths(prevPaths => [...prevPaths, fileDetails]); - - setFiles(prevFiles => [ - ...prevFiles, - { - file_name: file.name, - file_size: (file.size / (1024 * 1024)).toFixed(2), // Convert size to MB - file_path: fileDetails.file_path, - file_id: fileDetails.file_id, - } - ]); - - setDisableConnectorSave(false); - setShowProgressBar(false); - }) - .catch(error => { - toast.error('File upload failed', error); - setShowProgressBar(false); - }) - .finally(() => { - setProgressPrecentage(0); - setProgressTime(""); - }); + .then(response => { + const fileData = response.data.data.file; + const fileDetails = { + file_path: fileData.file_path, + file_name: fileData.file_name, + file_size: fileData.file_size, + file_id: fileData.file_id + }; + + setFilePaths(prevPaths => [...prevPaths, fileDetails]); + + setFiles(prevFiles => [ + ...prevFiles, + { + file_name: file.name, + file_size: (file.size / (1024 * 1024)).toFixed(2), // Convert size to MB + file_path: fileDetails.file_path, + file_id: fileDetails.file_id, + } + ]); + + setDisableConnectorSave(false); + setShowProgressBar(false); + }) + .catch(error => { + toast.error('File upload failed', error); + setShowProgressBar(false); + }) + .finally(() => { + setProgressPrecentage(0); + setProgressTime(""); + }); }; - + @@ -306,89 +308,89 @@ const ProviderForm = ()=>{ const onFileChange = (event) => { const selectedFile = event.target.files[0]; if (!selectedFile) return; - - const fileSizeMB = selectedFile.size / (1024 * 1024); - + + const fileSizeMB = selectedFile.size / (1024 * 1024); + if (files.length >= maxFiles) { toast.error(`You can only upload up to ${maxFiles} files.`) return; } - + if (fileSizeMB > maxFileSizeMB) { toast.error(`File size should not exceed ${maxFileSizeMB} MB. The selected file is ${fileSizeMB.toFixed(2)} MB.`) return; } - + onSaveFiles(selectedFile) }; - + const onAddFileOnDrag = (event) => { event.preventDefault(); const draggedFile = event.dataTransfer.files[0]; - + if (!draggedFile) return; - - const fileSizeMB = draggedFile.size / (1024 * 1024); - + + const fileSizeMB = draggedFile.size / (1024 * 1024); + if (files.length >= maxFiles) { toast.error(`You can only upload up to ${maxFiles} files.`) return; } - + if (fileSizeMB > maxFileSizeMB) { toast.error(`File size should not exceed ${maxFileSizeMB} MB. The selected file is ${fileSizeMB.toFixed(2)} MB.`) return; } - + onSaveFiles(draggedFile) }; -const onRemoveFile = (fileId) => { - const updatedFiles = files.filter(file => file.file_id !== fileId); - setFiles(updatedFiles); + const onRemoveFile = (fileId) => { + const updatedFiles = files.filter(file => file.file_id !== fileId); + setFiles(updatedFiles); - const updatedFilePaths = filePaths.filter(filePath => filePath.file_id !== fileId); - setFilePaths(updatedFilePaths); -}; + const updatedFilePaths = filePaths.filter(filePath => filePath.file_id !== fileId); + setFilePaths(updatedFilePaths); + }; - const getConfigFormData = async ()=>{ - let slugs = await providerConfig.map(item=>item.slug) + const getConfigFormData = async () => { + let slugs = await providerConfig.map(item => item.slug) let formValues = {}; let formFilled = true - slugs.forEach((input)=>{ + slugs.forEach((input) => { formValues[input] = getValues(input) - if(formValues[input] == ""){ + if (formValues[input] == "") { trigger(input) formFilled = false } }); - return {formValues, formFilled} + return { formValues, formFilled } } - - const generateConfig = ()=>{ - providerConfig.sort((firstItem, secondItem)=>{ + const generateConfig = () => { + + providerConfig.sort((firstItem, secondItem) => { return firstItem.order > secondItem.order ? -1 : 1 }) - return( + return ( <> - {providerConfig.map((item, index)=>{ - - switch(item.config_type){ - case 1: return - case 2: return - case 3: return - case 4: return {item.name} (Include http or https in the url) } required={item.required} placeholder="https://www.raggenie.com" hasError={errors[item.slug]?.message ? true : false} errorMessage={errors[item.slug]?.message} {...register(item.slug, {required: item.required ? "This is required": false})} onChange={onChangesOption}/> - case 5: return + {providerConfig.map((item, index) => { + + switch (item.config_type) { + case 1: return + case 2: return + case 3: return + case 4: return {item.name} (Include http or https in the url) } required={item.required} placeholder="https://www.raggenie.com" hasError={errors[item.slug]?.message ? true : false} errorMessage={errors[item.slug]?.message} {...register(item.slug, { required: item.required ? "This is required" : false })} onChange={onChangesOption} /> + case 5: return case 6: return (
- onChangesOption(e)}> {item.value?.map((val, valIndex) => { return (
) - case 7: return - {tempTableDetails[row.data.table_id].columns[column.column_id].description != "" ? tempTableDetails[row.data.table_id].columns[column.column_id].description : column.description} -
+ + + {tempTableDetails[row.data.table_id].columns[column.column_id].description != "" ? tempTableDetails[row.data.table_id].columns[column.column_id].description : column.description} +
From 6d198172f259cf21ba28ef84487909e300c7edae Mon Sep 17 00:00:00 2001 From: maranix Date: Mon, 21 Oct 2024 23:18:52 +0530 Subject: [PATCH 3/3] ProviderForm: add title property to row divs for full description tooltip --- .../Configuration/ProviderForm/ProviderForm.jsx | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/ui/src/pages/Configuration/ProviderForm/ProviderForm.jsx b/ui/src/pages/Configuration/ProviderForm/ProviderForm.jsx index b5c80954..1c6784ae 100644 --- a/ui/src/pages/Configuration/ProviderForm/ProviderForm.jsx +++ b/ui/src/pages/Configuration/ProviderForm/ProviderForm.jsx @@ -81,7 +81,7 @@ const ProviderForm = () => { return (
-
+
{row.description}
@@ -116,9 +116,18 @@ const ProviderForm = () => { } - const rowExpandComponent = (row) => { let tempTableDetails = JSON.parse(window.localStorage.getItem("dbschema")) + + const getRowExpandComponentDescription = (column) => { + const description = tempTableDetails[row.data.table_id].columns[column.column_id].description; + if (description === "") { + return column.description + } + + return tempTableDetails[row.data.table_id].columns[column.column_id].description + } + return (<>
{row?.data?.columns?.map((column, index) => { @@ -127,10 +136,10 @@ const ProviderForm = () => {
{column.column_name}
-
+
- {tempTableDetails[row.data.table_id].columns[column.column_id].description != "" ? tempTableDetails[row.data.table_id].columns[column.column_id].description : column.description} + {getRowExpandComponentDescription(column)}