2024-06-15 14:27:06 +05:30
|
|
|
import React, { useState, useEffect } from "react";
|
|
|
|
|
import {
|
|
|
|
|
DesktopOutlined,
|
|
|
|
|
FileOutlined,
|
|
|
|
|
PieChartOutlined,
|
|
|
|
|
TeamOutlined,
|
|
|
|
|
UserOutlined,
|
|
|
|
|
} from "@ant-design/icons";
|
|
|
|
|
import { Breadcrumb, Layout, Menu, Typography, theme } from "antd";
|
|
|
|
|
import { ToastContainer, toast } from "react-toastify";
|
|
|
|
|
import { Box, Button } from "@mui/material";
|
|
|
|
|
import TextField from "@mui/material/TextField";
|
|
|
|
|
import EditButton from "./EditButton";
|
|
|
|
|
import { width } from "@mui/system";
|
|
|
|
|
import "react-toastify/dist/ReactToastify.css";
|
|
|
|
|
import { useSearchParams } from "react-router-dom";
|
|
|
|
|
import LoadingContainer from "./LoadingContainer";
|
|
|
|
|
import HomeIcon from "@mui/icons-material/Home";
|
|
|
|
|
import ArrowBackIcon from "@mui/icons-material/ArrowBack";
|
|
|
|
|
import { useNavigate } from "react-router-dom";
|
|
|
|
|
import QueryStatsIcon from "@mui/icons-material/QueryStats";
|
|
|
|
|
import RotateLeftIcon from "@mui/icons-material/RotateLeft";
|
|
|
|
|
import RotateRightIcon from "@mui/icons-material/RotateRight";
|
|
|
|
|
import { useSelector, useDispatch } from "react-redux";
|
|
|
|
|
import {
|
|
|
|
|
updatePartAanomolyData,
|
|
|
|
|
updateSystemNo,
|
|
|
|
|
} from "../redux/actions/actions";
|
|
|
|
|
import SimpleDialog from "./SimpleDialog";
|
|
|
|
|
import SystemNumberDialog from "./SystemNumberDialog";
|
|
|
|
|
import ValidationContainer from "./ValidationContainer";
|
|
|
|
|
|
|
|
|
|
const { Header, Content, Footer, Sider } = Layout;
|
|
|
|
|
const QueryExecutor = () => {
|
|
|
|
|
const [responseData, setResponseData] = useState([]);
|
|
|
|
|
const [totalData, setTotalData] = useState([]);
|
|
|
|
|
const [currentPage, setCurrentPage] = useState(1);
|
|
|
|
|
const [totalPages, setTotalPages] = useState(0);
|
|
|
|
|
const [imageColumn, setImageColumn] = useState(null);
|
|
|
|
|
const [query, setQuery] = useState("");
|
|
|
|
|
const [isLoading, setIsLoading] = useState(false);
|
|
|
|
|
const [limit, setLimit] = useState("");
|
|
|
|
|
const recordsPerPage = 5;
|
|
|
|
|
|
|
|
|
|
const {
|
|
|
|
|
token: { colorBgContainer, borderRadiusLG },
|
|
|
|
|
} = theme.useToken();
|
|
|
|
|
|
|
|
|
|
const fetchQueryValue = async () => {
|
|
|
|
|
if (query.includes("limit")) {
|
|
|
|
|
alert("Please specify the limit in the input field.");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (query.includes(";")) {
|
|
|
|
|
alert("Please remove the special character from the query ';'");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (!limit) {
|
|
|
|
|
alert("Limit cannot be empty !!");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
setIsLoading(true);
|
|
|
|
|
const payload = {
|
|
|
|
|
query: query,
|
|
|
|
|
limit: limit,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
const response = await fetch(
|
|
|
|
|
`${import.meta.env.VITE_REACT_APP_BACKEND_URL}/fetchQueryValue`,
|
|
|
|
|
{
|
|
|
|
|
method: "POST",
|
|
|
|
|
headers: {
|
|
|
|
|
"Content-Type": "application/json",
|
|
|
|
|
},
|
|
|
|
|
body: JSON.stringify(payload),
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
const data = await response.json();
|
|
|
|
|
setIsLoading(false);
|
|
|
|
|
if (data.status === "success") {
|
|
|
|
|
setTotalData(data.results);
|
|
|
|
|
const totalPageCount = Math.ceil(data.results.length / recordsPerPage);
|
|
|
|
|
setTotalPages(totalPageCount);
|
|
|
|
|
setCurrentPage(1);
|
|
|
|
|
setResponseData(data.results.slice(0, recordsPerPage));
|
|
|
|
|
} else {
|
|
|
|
|
toast.error(data.message);
|
|
|
|
|
}
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error("Error:", error);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
if (totalData.length > 0) {
|
|
|
|
|
const startIndex = (currentPage - 1) * recordsPerPage;
|
|
|
|
|
const endIndex = startIndex + recordsPerPage;
|
|
|
|
|
setResponseData(totalData.slice(startIndex, endIndex));
|
|
|
|
|
}
|
|
|
|
|
}, [currentPage, totalData]);
|
|
|
|
|
|
|
|
|
|
const getTableData = () => {
|
|
|
|
|
if (responseData.length === 0) return null;
|
|
|
|
|
const keys = Object.keys(totalData[0]);
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<div className="w-100">
|
|
|
|
|
<div className="text-left d-flex justify-content-between align-items-center">
|
|
|
|
|
<h5>
|
|
|
|
|
<strong>Total Results </strong> : {totalData.length}
|
|
|
|
|
</h5>
|
|
|
|
|
{totalData.length > 0 && (
|
|
|
|
|
<div id="footer-container">
|
|
|
|
|
<div
|
|
|
|
|
id="footer-main"
|
|
|
|
|
className="d-flex justify-content-center p-3 align-items-center"
|
|
|
|
|
>
|
|
|
|
|
<div className="d-flex justify-content-center align-items-center p-1">
|
|
|
|
|
<strong>{currentPage}</strong>/<strong>{totalPages}</strong>
|
|
|
|
|
</div>
|
|
|
|
|
<div className="d-flex gap-3">
|
|
|
|
|
<button
|
|
|
|
|
className="btn text-light bg-primary rounded p-2 mx-3"
|
|
|
|
|
onClick={() =>
|
|
|
|
|
setCurrentPage((prev) => Math.max(prev - 1, 1))
|
|
|
|
|
}
|
|
|
|
|
>
|
|
|
|
|
Previous
|
|
|
|
|
</button>
|
|
|
|
|
<button
|
|
|
|
|
className="btn text-light bg-primary rounded p-2"
|
|
|
|
|
onClick={() =>
|
|
|
|
|
setCurrentPage((prev) => Math.min(prev + 1, totalPages))
|
|
|
|
|
}
|
|
|
|
|
>
|
|
|
|
|
Next
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
<div className="my-2 overflow-auto">
|
|
|
|
|
<table>
|
|
|
|
|
<thead>
|
|
|
|
|
<tr>
|
|
|
|
|
<th>sno</th>
|
|
|
|
|
<th>Record Info</th>
|
|
|
|
|
<th>Image</th>
|
|
|
|
|
</tr>
|
|
|
|
|
</thead>
|
|
|
|
|
<tbody>
|
|
|
|
|
{responseData.map((value, index) => {
|
|
|
|
|
const sno = totalData.indexOf(value) + 1;
|
|
|
|
|
let recordInfo = "";
|
|
|
|
|
let imageInfo = "";
|
|
|
|
|
|
|
|
|
|
keys.forEach((header) => {
|
|
|
|
|
if (header !== imageColumn) {
|
|
|
|
|
recordInfo += `<p><strong>${header}</strong>: ${value[header]}</p>`;
|
|
|
|
|
} else {
|
|
|
|
|
imageInfo = (
|
|
|
|
|
<td key={header}>
|
|
|
|
|
<img
|
|
|
|
|
src={`https://docs.exampaper.vidh.ai/${value[header]}`}
|
|
|
|
|
width="900px"
|
|
|
|
|
height="auto"
|
|
|
|
|
alt={header}
|
|
|
|
|
/>
|
|
|
|
|
</td>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<tr key={index}>
|
|
|
|
|
<td>{sno}</td>
|
|
|
|
|
<td>
|
|
|
|
|
<div
|
|
|
|
|
className="d-flex flex-column p-2"
|
|
|
|
|
dangerouslySetInnerHTML={{ __html: recordInfo }}
|
|
|
|
|
></div>
|
|
|
|
|
</td>
|
|
|
|
|
{imageInfo}
|
|
|
|
|
</tr>
|
|
|
|
|
);
|
|
|
|
|
})}
|
|
|
|
|
</tbody>
|
|
|
|
|
</table>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<Layout
|
|
|
|
|
style={{
|
|
|
|
|
minHeight: "100vh",
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
<ToastContainer />
|
|
|
|
|
<Layout>
|
|
|
|
|
<Header
|
|
|
|
|
style={{
|
|
|
|
|
padding: 0,
|
|
|
|
|
background: colorBgContainer,
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
<Box className="d-flex justify-content-between h-100 py-1 px-2">
|
|
|
|
|
<Button
|
|
|
|
|
className="bg-primary p-1 text-light"
|
|
|
|
|
onClick={() => {
|
|
|
|
|
navigate(-1);
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
<ArrowBackIcon />
|
|
|
|
|
</Button>
|
|
|
|
|
<Box className="d-flex justify-content-between gap-2">
|
|
|
|
|
{/* <Button
|
|
|
|
|
className="bg-primary p-1 text-light"
|
|
|
|
|
onClick={() => {
|
|
|
|
|
navigate("/anomoly/reassigned/stats");
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
<QueryStatsIcon />
|
|
|
|
|
</Button> */}
|
|
|
|
|
<Box className="d-flex justify-content-between gap-md-4 gap-1 align-items-center">
|
|
|
|
|
<Button
|
|
|
|
|
className="bg-primary p-1 text-light rounded h-100"
|
|
|
|
|
onClick={() => {
|
|
|
|
|
navigate("/");
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
<HomeIcon />
|
|
|
|
|
</Button>
|
|
|
|
|
</Box>
|
|
|
|
|
</Box>
|
|
|
|
|
</Box>
|
|
|
|
|
</Header>
|
|
|
|
|
<Content
|
|
|
|
|
style={{
|
|
|
|
|
margin: "16px 16px",
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
<div className="mx-3">
|
|
|
|
|
<div className="my-3 d-flex flex-md-row flex-column">
|
|
|
|
|
<div className="w-100 w-md-75">
|
|
|
|
|
<textarea
|
|
|
|
|
className="w-100 p-3 h5"
|
|
|
|
|
id="text-area-input"
|
|
|
|
|
placeholder="Enter your query ...."
|
2024-06-15 16:53:45 +05:30
|
|
|
rows="7"
|
2024-06-15 14:27:06 +05:30
|
|
|
value={query}
|
|
|
|
|
onChange={(e) => setQuery(e.target.value)}
|
|
|
|
|
></textarea>
|
|
|
|
|
</div>
|
|
|
|
|
<div className="d-none d-md-block w-25">
|
|
|
|
|
<div className="w-100 d-flex flex-column gap-2 mx-2">
|
2024-06-15 16:53:45 +05:30
|
|
|
<TextField
|
2024-06-15 14:27:06 +05:30
|
|
|
className="rounded p-2 h6"
|
|
|
|
|
type="text"
|
|
|
|
|
placeholder="Limit"
|
|
|
|
|
id="limit-input"
|
|
|
|
|
autoComplete="off"
|
|
|
|
|
value={limit}
|
|
|
|
|
onChange={(e) => setLimit(e.target.value)}
|
|
|
|
|
/>
|
2024-06-15 16:53:45 +05:30
|
|
|
<TextField
|
2024-06-15 14:27:06 +05:30
|
|
|
className="input rounded p-2 h6"
|
|
|
|
|
type="text"
|
|
|
|
|
placeholder="Image column name"
|
|
|
|
|
id="image-column-input"
|
|
|
|
|
autoComplete="off"
|
|
|
|
|
value={imageColumn}
|
|
|
|
|
onChange={(e) => setImageColumn(e.target.value)}
|
|
|
|
|
/>
|
|
|
|
|
<button
|
|
|
|
|
className="btn bg-primary text-light"
|
|
|
|
|
id="submit-btn"
|
|
|
|
|
onClick={fetchQueryValue}
|
|
|
|
|
>
|
|
|
|
|
Submit
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div className="d-block d-md-none w-100">
|
2024-06-15 16:53:45 +05:30
|
|
|
<div className="w-100 d-flex flex-column gap-2">
|
|
|
|
|
<TextField
|
2024-06-15 14:27:06 +05:30
|
|
|
className="rounded p-2 h6"
|
|
|
|
|
type="text"
|
|
|
|
|
placeholder="Limit"
|
|
|
|
|
id="limit-input"
|
|
|
|
|
autoComplete="off"
|
|
|
|
|
value={limit}
|
|
|
|
|
onChange={(e) => setLimit(e.target.value)}
|
|
|
|
|
/>
|
2024-06-15 16:53:45 +05:30
|
|
|
<TextField
|
2024-06-15 14:27:06 +05:30
|
|
|
className="input rounded p-2 h6"
|
|
|
|
|
type="text"
|
|
|
|
|
placeholder="Image column name"
|
|
|
|
|
id="image-column-input"
|
|
|
|
|
autoComplete="off"
|
|
|
|
|
value={imageColumn}
|
|
|
|
|
onChange={(e) => setImageColumn(e.target.value)}
|
|
|
|
|
/>
|
|
|
|
|
<button
|
|
|
|
|
className="btn bg-primary text-light"
|
|
|
|
|
id="submit-btn"
|
|
|
|
|
onClick={fetchQueryValue}
|
|
|
|
|
>
|
|
|
|
|
Submit
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div
|
|
|
|
|
id="results-container"
|
|
|
|
|
className="d-flex w-100 justify-content-center"
|
|
|
|
|
>
|
|
|
|
|
{getTableData()}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</Content>
|
|
|
|
|
<Footer
|
|
|
|
|
style={{
|
|
|
|
|
textAlign: "center",
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
exampaper.vidh.ai ©{new Date().getFullYear()}
|
|
|
|
|
</Footer>
|
|
|
|
|
</Layout>
|
|
|
|
|
{isLoading && <LoadingContainer loadingText={"Loading"} />}
|
|
|
|
|
</Layout>
|
|
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export default QueryExecutor;
|