///////////////////////////////////////////////////////////// // // pgAdmin 4 - PostgreSQL Tools // // Copyright (C) 2013 - 2022, The pgAdmin Development Team // This software is released under the PostgreSQL Licence // ////////////////////////////////////////////////////////////// import { Box, Dialog, DialogContent, DialogTitle, makeStyles, Paper } from '@material-ui/core'; import React, { useState } from 'react'; import clsx from 'clsx'; import { getEpoch } from 'sources/utils'; import { DefaultButton, PgIconButton, PrimaryButton } from '../components/Buttons'; import Draggable from 'react-draggable'; import CloseIcon from '@material-ui/icons/CloseRounded'; import CustomPropTypes from '../custom_prop_types'; import PropTypes from 'prop-types'; import gettext from 'sources/gettext'; import HTMLReactParser from 'html-react-parser'; import CheckRoundedIcon from '@material-ui/icons/CheckRounded'; import { Rnd } from 'react-rnd'; import { ExpandDialogIcon, MinimizeDialogIcon } from '../components/ExternalIcon'; export const ModalContext = React.createContext({}); const MIN_HEIGHT = 190; const MIN_WIDTH = 500; export function useModal() { return React.useContext(ModalContext); } const useAlertStyles = makeStyles((theme) => ({ footer: { display: 'flex', justifyContent: 'flex-end', padding: '0.5rem', ...theme.mixins.panelBorder.top, }, margin: { marginLeft: '0.25rem', } })); function AlertContent({ text, confirm, okLabel = gettext('OK'), cancelLabel = gettext('Cancel'), onOkClick, onCancelClick }) { const classes = useAlertStyles(); return ( {typeof (text) == 'string' ? HTMLReactParser(text) : text} {confirm && } onClick={onCancelClick} >{cancelLabel} } } onClick={onOkClick} autoFocus={true} >{okLabel} ); } AlertContent.propTypes = { text: PropTypes.string, confirm: PropTypes.bool, onOkClick: PropTypes.func, onCancelClick: PropTypes.func, okLabel: PropTypes.string, cancelLabel: PropTypes.string, }; function alert(title, text, onOkClick, okLabel = gettext('OK')) { // bind the modal provider before calling this.showModal(title, (closeModal) => { const onOkClickClose = () => { onOkClick && onOkClick(); closeModal(); }; return ( ); }); } function confirm(title, text, onOkClick, onCancelClick, okLabel = gettext('Yes'), cancelLabel = gettext('No')) { // bind the modal provider before calling this.showModal(title, (closeModal) => { const onCancelClickClose = () => { onCancelClick && onCancelClick(); closeModal(); }; const onOkClickClose = () => { onOkClick && onOkClick(); closeModal(); }; return ( ); }); } export default function ModalProvider({ children }) { const [modals, setModals] = React.useState([]); const showModal = (title, content, modalOptions) => { let id = getEpoch().toString() + Math.random(); setModals((prev) => [...prev, { id: id, title: title, content: content, ...modalOptions, }]); }; const closeModal = (id) => { setModals((prev) => { return prev.filter((o) => o.id != id); }); }; const fullScreenModal = (fullScreen) => { setModals((prev) => [...prev, { fullScreen: fullScreen, }]); }; const modalContextBase = { showModal: showModal, closeModal: closeModal, fullScreenModal: fullScreenModal }; const modalContext = React.useMemo(() => ({ ...modalContextBase, confirm: confirm.bind(modalContextBase), alert: alert.bind(modalContextBase) }), []); return ( {children} {modals.map((modalOptions, i) => ( ))} ); } ModalProvider.propTypes = { children: CustomPropTypes.children, }; const dialogStyle = makeStyles((theme) => ({ dialog: { display: 'flex', alignItems: 'center', justifyContent: 'center', border: '1px solid ' + theme.otherVars.inputBorderColor, borderRadius: theme.shape.borderRadius, }, fullScreen: { transform: 'none !important' } })); function PaperComponent({minHeight, minWidth, ...props}) { let classes = dialogStyle(); let [dialogPosition, setDialogPosition] = useState(null); let resizeable = props.isresizeable == 'true' ? true : false; const setEnableResizing = () => { return props.isfullscreen == 'true' ? false : resizeable; }; const setConditionalPosition = () => { return props.isfullscreen == 'true' ? { x: 0, y: 0 } : dialogPosition && { x: dialogPosition.x, y: dialogPosition.y }; }; const y_position = window.innerHeight*0.02; // 2% of total height const x_position = props.width ? (window.innerWidth/2) - (props.width/2) : (window.innerWidth/2) - (MIN_WIDTH/2); return ( props.isresizeable == 'true' ? { if (props.isfullscreen !== 'true') { setDialogPosition({ ...position, }); } }} onResize={(e, direction, ref, delta, position) => { setDialogPosition({ ...position, }); }} dragHandleClassName="modal-drag-area" > : ); } PaperComponent.propTypes = { isfullscreen: PropTypes.string, isresizeable: PropTypes.string, width: PropTypes.number, height: PropTypes.number, minWidth: PropTypes.number, minHeight: PropTypes.number, }; export const useModalStyles = makeStyles((theme) => ({ container: { backgroundColor: theme.palette.background.default }, titleBar: { display: 'flex', flexGrow: 1 }, title: { flexGrow: 1 }, icon: { fill: 'currentColor', width: '1em', height: '1em', display: 'inline-block', fontSize: '1.5rem', transition: 'none', flexShrink: 0, userSelect: 'none', }, footer: { display: 'flex', justifyContent: 'flex-end', padding: '0.5rem', ...theme.mixins.panelBorder?.top, }, margin: { marginLeft: '0.25rem', }, iconButtonStyle: { marginLeft: 'auto', marginRight: '4px' } })); function ModalContainer({ id, title, content, dialogHeight, dialogWidth, onClose, fullScreen = false, isFullWidth = false, showFullScreen = false, isResizeable = false, minHeight = MIN_HEIGHT, minWidth = MIN_WIDTH }) { let useModalRef = useModal(); const classes = useModalStyles(); let closeModal = (_e, reason) => { useModalRef.closeModal(id); if(reason == 'escapeKeyDown') { onClose?.(); } }; const [isfullScreen, setIsFullScreen] = useState(fullScreen); return ( {title} { showFullScreen && !isfullScreen && } size="xs" noBorder onClick={() => { setIsFullScreen(!isfullScreen); }} /> } { showFullScreen && isfullScreen && } size="xs" noBorder onClick={() => { setIsFullScreen(!isfullScreen); }} /> } } size="xs" noBorder onClick={closeModal} /> {content(closeModal)} ); } ModalContainer.propTypes = { id: PropTypes.string, title: CustomPropTypes.children, content: PropTypes.func, fullScreen: PropTypes.bool, maxWidth: PropTypes.string, isFullWidth: PropTypes.bool, showFullScreen: PropTypes.bool, isResizeable: PropTypes.bool, dialogHeight: PropTypes.number, dialogWidth: PropTypes.number, onClose: PropTypes.func, minWidth: PropTypes.number, minHeight: PropTypes.number, };