UNPKG

leumas-universal-crud-react

Version:

Leumas Universal CRUD to a dynamic Endpoint, Setup your own Dynamic Endpoint and Use Leumas API to send to your MONGO clusters

337 lines (285 loc) 11.8 kB
import { useState , useEffect } from 'react'; import {LeumasBaseStyle} from "../../styles/baseStyles" import useAuthUser from 'react-auth-kit/hooks/useAuthUser'; import {getItemsByOwner} from "../UniversalCrud/UniversalCrudHelpers" import SaveButton from "../UniversalCrud/SaveButton" import EditItem from "../UniversalCrud/EditItem" import DeleteItem from "../UniversalCrud/DeleteItem" import axios from "axios" import {AtomSpinner} from "react-epic-spinners" import { runBlocks } from './Helpers/runBlocks'; import CustomDropdown from '../UniversalCrud/CustomDropdown'; import {useParams} from 'react-router-dom' import { useTheme } from "../../Theme/ThemeContext"; const lightThemeColors = { background: '#FAFAFA', primary: '#0077C0', secondary: '#C7EEFF', text: '#1D242B', }; const darkThemeColors = { background: '#1D242B', primary: '#0077C0', secondary: '#2A3B4D', text: '#FAFAFA', cardText: '#E0E0E0', }; const useColors = (theme) => { return theme === 'dark' ? darkThemeColors : lightThemeColors; }; const DEFAULT_ENDPOINT = `${import.meta.env.VITE_REACT_APP_LEUMAS_API_ENDPOINT}/wildcards/bulk-request`; export const EndpointBuilder = () => { const auth = useAuthUser() const { theme } = useTheme(); const colors = useColors(theme); const [models , setModels] = useState([]); // Structuring data for your backend schema const [message, setMessage] = useState(""); const [messageType , setMessageType] = useState(""); const [isLoading, setIsLoading] = useState(false); const [results, setResults] = useState([]); const [selectedEndpoint, setSelectedEndpoint] = useState(null); const [endpointName, setEndpointName] = useState(""); const {id} = useParams() const [bulkEndpoints, setBulkEndpoints] = useState({ endpoints: [{ method: 'GET', endpoint: '', body: '{}', headers: '{}', params: '{}', }] }); console.log(models) const addBlock = () => { setBulkEndpoints(prev => ({ ...prev, endpoints: [ ...prev.endpoints, { method: 'GET', endpoint: '', body: '{}', headers: '{}', params: '{}', } ] })); }; const deleteBlock = (index) => { const newEndpoints = [...bulkEndpoints.endpoints]; newEndpoints.splice(index, 1); setBulkEndpoints({ ...bulkEndpoints, endpoints: newEndpoints }); }; const handleChange = (index, field, value) => { const newEndpoints = [...bulkEndpoints.endpoints]; newEndpoints[index][field] = value; setBulkEndpoints({ ...bulkEndpoints, endpoints: newEndpoints }); }; const handleRunBlocks = () => { setIsLoading(true); // Start the loading spinner runBlocks(DEFAULT_ENDPOINT, bulkEndpoints.endpoints, (data) => { console.log(data); setResults(data); setIsLoading(false); // Stop the loading spinner }, (error) => { console.error(error); setIsLoading(false); // Stop the loading spinner } ); }; const fetchEndpoints = () => { getItemsByOwner("Endpoint", auth?.id, "LeumasAPI", auth?.token) .then((data) => { if(!data || data.length === 0) { console.warn("No endpoints found for the user."); } else { setModels(data); console.log("Fetched endpoints:", data); } }) .catch((error) => { console.error("Error fetching endpoints:", error.message); }); }; useEffect(() => { getItemsByOwner("Endpoint", auth?.id, "LeumasAPI", auth?.token) .then((data) => { if (!data || data.length === 0) { console.warn("No endpoints found for the user."); } else { setModels(data); console.log("Fetched endpoints:", data); if (id) { alert("Existing ID " + id); console.log(data); const matchedEndpoint = data.find(item => item._id === id); if (matchedEndpoint) { setBulkEndpoints(matchedEndpoint); } } } }) .catch((error) => { console.error("Error fetching endpoints:", error.message); }); }, [auth?.id, id]); useEffect(() => { // When selectedEndpoint changes, update the state if (selectedEndpoint) { setBulkEndpoints(prev => ({ ...prev, endpoints: selectedEndpoint.endpoints })); } }, [selectedEndpoint]); const handleEndpointSelectChange = (e) => { console.log(e) setModels(e.endpoints) setBulkEndpoints(e) } const handleSaveSuccess = () => { fetchEndpoints(); // Refetch the QR codes setMessageType("success"); setMessage("Success in creating model, please refresh to view"); setIsLoading(false); }; const endpointData = { owner: auth?.id, ...bulkEndpoints, }; function getBorderColor(requestIndex) { const result = results.find(res => res.index === requestIndex); if (!result) return ''; if (result.success) return ' border-4 border-green-500'; if (!result.success) return ' border-4 border-red-500'; return ''; } const inputStyle = "border border-gray-300 rounded-lg px-3 py-2 w-full focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition bg-transparent"; const transparent = "bg-blue-400 text-white" return ( <div className="flex sm:flex-row flex-col flex-grow z-10 w-full"> <aside className='flex flex-col min-w-[150px] p-4' style={{ backgroundColor: colors.background, color: colors.text }}> <div className='flex sm:flex-col items-center justify-center'> <button onClick={addBlock} className={`${LeumasBaseStyle} max-w-[150px] `} style={{ backgroundColor: colors.primary, color: colors.text }}> Add New </button> <button onClick={handleRunBlocks} className={`${LeumasBaseStyle} max-w-[150px]`} style={{ backgroundColor: colors.primary, color: colors.text }}> Run Endpoints </button> <SaveButton model={"Endpoint"} data={models} editMode={id ? true : false} isLoading={isLoading} setIsLoading={setIsLoading} setMessage={setMessage} setMessageType={setMessageType} onSuccess={handleSaveSuccess} styles={` mb-3 p-0 border`} /> </div> <input type="text" id="endpointName" placeholder="Name" className={`w-full rounded-lg p-2`} value={endpointName} onChange={(e) => setEndpointName(e.target.value)} style={{ backgroundColor: colors.secondary, color: colors.text }} /> </aside> <div className='flex flex-col w-full'> <CustomDropdown model="Endpoint" modelArray={models} endpoint="LeumasAPI" token={auth?.token} onSelectedChange={(e) => window.location.href = `/endpoints/bulk/${e._id}`} /> <div className={`results w-full mx-auto border-2 rounded-lg shadow-lg overflow-auto max-h-[100px] min-h-[100px] overflow-y-scroll p-2`} style={{ backgroundColor: colors.secondary, borderColor: colors.primary, color: colors.text }}> {results.length <= 0 ? <p className='border h-full text-center flex items-center justify-center min-h-[80px] rounded-lg'>Sorry no results yet</p> : null} {results.map((result, index) => ( <div key={index} className="mb-4 last:mb-0"> <p className="font-mono" style={{ color: colors.primary }}>Block {result.index}: {result.message}</p> <pre className="whitespace-pre-wrap p-4 rounded" style={{ backgroundColor: colors.background, color: colors.cardText }}> {JSON.stringify(result.data || result.error, null, 2)} </pre> </div> ))} </div> <div className='grid sm:grid-cols-2 grid-cols-1 max-h-[800px] min-w-[400px] overflow-y-scroll w-full gap-2' style={{ backgroundColor: colors.background, color: colors.text }}> {isLoading ? ( <div className="col-span-2 flex justify-center items-center h-60"> <AtomSpinner /> </div> ) : ( bulkEndpoints.endpoints.map((request, index) => ( <div key={index} className={`${LeumasBaseStyle} min-w-[250px] ${getBorderColor(index)} border`} style={{ backgroundColor: colors.secondary, color: colors.text }}> <p style={{ color: colors.text }}>Block {index}</p> <div className="flex space-x-2"> <select value={request.method} onChange={(e) => handleChange(index, 'method', e.target.value)} className={`${inputStyle}`} style={{ backgroundColor: colors.secondary, color: colors.text }} > <option value="GET">GET</option> <option value="POST">POST</option> <option value="PUT">PUT</option> <option value="DELETE">DELETE</option> </select> <input type="text" value={request.endpoint} onChange={(e) => handleChange(index, 'endpoint', e.target.value)} className={`${inputStyle} flex-grow`} style={{ backgroundColor: colors.secondary, color: colors.text }} placeholder="Enter endpoint URL" /> </div> <label style={{ color: colors.text }} className="block mt-2">Body</label> <textarea value={request.body} onChange={(e) => handleChange(index, 'body', e.target.value)} className={inputStyle} style={{ backgroundColor: colors.secondary, color: colors.text }} placeholder="Body (JSON)" rows="3" /> <label style={{ color: colors.text }} className="block mt-2">Headers</label> <textarea value={request.headers} onChange={(e) => handleChange(index, 'headers', e.target.value)} className={inputStyle} style={{ backgroundColor: colors.secondary, color: colors.text }} placeholder="Headers (JSON)" rows="2" /> <label style={{ color: colors.text }} className="block mt-2">Params</label> <textarea value={request.params} onChange={(e) => handleChange(index, 'params', e.target.value)} className={inputStyle} style={{ backgroundColor: colors.secondary, color: colors.text }} placeholder="Params (JSON)" rows="2" /> <button onClick={() => deleteBlock(index)} className={LeumasBaseStyle} style={{ backgroundColor: colors.primary, color: colors.text }}>Delete</button> </div> )) )} </div> </div> </div> ); }; export default EndpointBuilder