datajunction-ui
Version:
DataJunction UI
126 lines (117 loc) • 3.68 kB
JSX
import DJClientContext from '../../providers/djclient';
import { Light as SyntaxHighlighter } from 'react-syntax-highlighter';
import { useEffect, useRef, useState, useContext } from 'react';
import nightOwl from 'react-syntax-highlighter/dist/esm/styles/hljs/night-owl';
import PythonIcon from '../../icons/PythonIcon';
import LoadingIcon from 'app/icons/LoadingIcon';
export default function ClientCodePopover({ nodeName, buttonStyle }) {
const djClient = useContext(DJClientContext).DataJunctionAPI;
const [showModal, setShowModal] = useState(false);
const modalRef = useRef(null);
const [code, setCode] = useState(null);
// Drop any cached code when the node changes.
useEffect(() => {
setCode(null);
}, [nodeName]);
// The generated client code is only shown inside the modal, and generating it
// is expensive (~1s server round trip). Fetch it lazily the first time the
// popover is opened rather than on every node-page load.
useEffect(() => {
if (!showModal || code !== null) return;
let cancelled = false;
async function fetchCode() {
try {
const result = await djClient.clientCode(nodeName);
if (!cancelled) setCode(result);
} catch (err) {
console.log(err);
}
}
fetchCode();
return () => {
cancelled = true;
};
}, [showModal, nodeName, djClient, code]);
useEffect(() => {
const handleClickOutside = event => {
if (modalRef.current && !modalRef.current.contains(event.target)) {
setShowModal(false);
}
};
if (showModal) {
document.addEventListener('mousedown', handleClickOutside);
} else {
document.removeEventListener('mousedown', handleClickOutside);
}
return () => {
document.removeEventListener('mousedown', handleClickOutside);
};
}, [showModal]);
return (
<>
<button onClick={() => setShowModal(true)} style={buttonStyle}>
<PythonIcon /> Python
</button>
{showModal && (
<div
className="modal-backdrop fade in"
style={{
position: 'fixed',
top: 0,
left: 0,
width: '100vw',
height: '100vh',
backgroundColor: 'rgba(0, 0, 0, 0.5)',
zIndex: 9999,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
}}
>
<div
className="centerPopover"
ref={modalRef}
style={{
position: 'relative',
maxWidth: '80%',
width: '600px',
maxHeight: '80vh',
overflowY: 'auto',
padding: '1.5rem',
background: '#fff',
borderRadius: '10px',
boxShadow: '0 3px 10px rgba(0, 0, 0, 0.3)',
}}
>
<button
onClick={() => setShowModal(false)}
style={{
position: 'absolute',
top: '1rem',
right: '1rem',
background: 'none',
border: 'none',
fontSize: '1.5rem',
cursor: 'pointer',
color: '#999',
}}
aria-label="Close modal"
>
×
</button>
<h2>Python Client Code</h2>
{code ? (
<SyntaxHighlighter language="python" style={nightOwl}>
{code}
</SyntaxHighlighter>
) : (
<>
<LoadingIcon />
</>
)}
</div>
</div>
)}
</>
);
}