Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,8 @@ define('pgadmin.node.database', [
},
function() { return true;},
gettext('Disconnect'),
gettext('Cancel')
gettext('Cancel'),
'disconnect'
);
}

Expand Down Expand Up @@ -565,7 +566,8 @@ define('pgadmin.node.database', [
},
function() { return true; },
gettext('Disconnect'),
gettext('Cancel')
gettext('Cancel'),
'disconnect'
);
} else {
disconnect();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,7 @@ define('pgadmin.node.server', [
function() { return true;},
gettext('Disconnect'),
gettext('Cancel'),
'disconnect'
);
}
return false;
Expand Down Expand Up @@ -868,7 +869,8 @@ define('pgadmin.node.server', [
function() { disconnect(); },
function() { return true;},
gettext('Disconnect'),
gettext('Cancel')
gettext('Cancel'),
'disconnect'
);
} else {
disconnect();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import React, { useEffect, useMemo } from 'react';
import { FileType } from 'react-aspen';
import { Box } from '@mui/material';
import PropTypes from 'prop-types';
import CloseIcon from '@mui/icons-material/CloseRounded';
import HTMLReactParser from 'html-react-parser/lib/index';
import SchemaView from '../../../../static/js/SchemaView';
import getApiInstance from '../../../../static/js/api_instance';
import CloseSharpIcon from '@mui/icons-material/CloseSharp';
Expand Down Expand Up @@ -85,6 +87,16 @@ const StyledBox = styled(Box)(({theme}) => ({
marginLeft: '0.5em'
},
},

},
'& .Alert-footer': {
display: 'flex',
justifyContent: 'flex-end',
padding: '0.5rem',
...theme.mixins.panelBorder.top,
},
'& .Alert-margin': {
marginLeft: '0.25rem',
},
}));

Expand Down Expand Up @@ -655,36 +667,31 @@ export default function PreferencesComponent({ ...props }) {
};

const reset = () => {
pgAdmin.Browser.notifier.confirm(
const text = `${gettext('All preferences will be reset to their default values.')}<br><br>${gettext('Do you want to proceed?')}<br><br>
${gettext('Note:')}<br> <ul style="padding-left:20px"><li style="list-style-type:disc">${gettext('The object explorer tree will be refreshed automatically to reflect the changes.')}</li>
<li style="list-style-type:disc">${gettext('If the application language changes, a reload of the application will be required. You can choose to reload later at your convenience.')}</li></ul>`;

pgAdmin.Browser.notifier.showModal(
gettext('Reset all preferences'),
`${gettext('All preferences will be reset to their default values.')}<br><br>${gettext('Do you want to proceed?')}<br><br>
${gettext('Note:')}<br> <ul style="padding-left:20px"><li style="list-style-type:disc">${gettext('The object explorer tree will be refreshed automatically to reflect the changes.')}</li>
<li style="list-style-type:disc">${gettext('If the application language changes, a reload of the application will be required. You can choose to reload later at your convenience.')}</li></ul>`,
function () {},
function () {},
'',
'Cancel',
function (closeModal) {
return [
{
type: 'default',
icon: <SaveSharpIcon />,
label: gettext('Save & Reload'),
onclick: () => {
resetPrefsToDefault(true);
closeModal();
}
}, {
type: 'primary',
icon: <SaveSharpIcon />,
label: gettext('Save & Reload Later'),
onclick: () => {
resetPrefsToDefault(false);
closeModal();
}
}
];
}
(closeModal)=>{
const onClick = (reset) => {
resetPrefsToDefault(reset);
closeModal();
};
return(
<StyledBox display="flex" flexDirection="column" height="100%">
<Box flexGrow="1" p={2}>
{HTMLReactParser(text)}
</Box>
<Box className='Alert-footer'>
<DefaultButton className='Alert-margin' startIcon={<CloseIcon />} onClick={()=> closeModal()}>{'Cancel'}</DefaultButton>
<DefaultButton className='Alert-margin' startIcon={<SaveSharpIcon />} onClick={() => onClick(true)} >{gettext('Save & Reload')}</DefaultButton>
<PrimaryButton className='Alert-margin' startIcon={ <SaveSharpIcon />} onClick={()=>onClick(false)}>{gettext('Save & Reload Later')}</PrimaryButton>
</Box>
</StyledBox>
);
},
{ isFullScreen: false, isResizeable: false, showFullScreen: false, isFullWidth: false, showTitle: true},
);
};

Expand Down
4 changes: 2 additions & 2 deletions web/pgadmin/static/js/components/ExternalIcon.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,8 @@ ClearIcon.propTypes = {style: PropTypes.object};
export const ConnectedIcon = ({style})=><ExternalIcon Icon={ConnectedSvg} style={{height: '1rem', ...style}} data-label="ConnectedIcon" />;
ConnectedIcon.propTypes = {style: PropTypes.object};

export const DisonnectedIcon = ({style})=><ExternalIcon Icon={DisconnectedSvg} style={{height: '1rem', ...style}} data-label="DisonnectedIcon" />;
DisonnectedIcon.propTypes = {style: PropTypes.object};
export const DisconnectedIcon = ({style})=><ExternalIcon Icon={DisconnectedSvg} style={{height: '1rem', ...style}} data-label="DisconnectedIcon" />;
DisconnectedIcon.propTypes = {style: PropTypes.object};

export const RegexIcon = ({style})=><ExternalIcon Icon={RegexSvg} style={style} data-label="RegexIcon" />;
RegexIcon.propTypes = {style: PropTypes.object};
Expand Down
65 changes: 40 additions & 25 deletions web/pgadmin/static/js/helpers/ModalProvider.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,14 @@ import { getEpoch } from 'sources/utils';
import { DefaultButton, PgIconButton, PrimaryButton } from '../components/Buttons';
import Draggable from 'react-draggable';
import CloseIcon from '@mui/icons-material/CloseRounded';
import DeleteIcon from '@mui/icons-material/Delete';
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 '@mui/icons-material/CheckRounded';
import { Rnd } from 'react-rnd';
import { ExpandDialogIcon, MinimizeDialogIcon } from '../components/ExternalIcon';
import { ExpandDialogIcon, MinimizeDialogIcon, DisconnectedIcon } from '../components/ExternalIcon';
import { styled } from '@mui/material/styles';

export const ModalContext = React.createContext({});
Expand All @@ -37,35 +38,24 @@ const StyledBox = styled(Box)(({theme}) => ({
},
}));

const buttonIconMap = {
disconnect: <DisconnectedIcon />,
default: <CheckRoundedIcon />
};

export function useModal() {
return React.useContext(ModalContext);
}

function renderExtraButtons(button) {
switch(button.type) {
case 'primary':
return <PrimaryButton className='Alert-margin' startIcon={button.icon} onClick={button.onClick}>{button.label}</PrimaryButton>;
case 'default':
return <DefaultButton className='Alert-margin' startIcon={button.icon} onClick={button.onClick} color={button?.color}>{button.label}</DefaultButton>;
default:
return <DefaultButton className='Alert-margin' startIcon={button.icon} onClick={button.onClick}>{button.label}</DefaultButton>;
};
}

function AlertContent({ text, confirm, okLabel = gettext('OK'), cancelLabel = gettext('Cancel'), onOkClick, onCancelClick, extraButtons }) {
function AlertContent({ text, confirm, okLabel = gettext('OK'), cancelLabel = gettext('Cancel'), onOkClick, onCancelClick, okIcon = 'default'}) {
return (
<StyledBox display="flex" flexDirection="column" height="100%">
<Box flexGrow="1" p={2}>{typeof (text) == 'string' ? HTMLReactParser(text) : text}</Box>
<Box className='Alert-footer'>
{confirm &&
<DefaultButton startIcon={<CloseIcon />} onClick={onCancelClick} autoFocus={true}>{cancelLabel}</DefaultButton>
}
{
extraButtons?.length ?
extraButtons.map(button=>renderExtraButtons(button))
:
<PrimaryButton className='Alert-margin' startIcon={<CheckRoundedIcon />} onClick={onOkClick}>{okLabel}</PrimaryButton>
<DefaultButton startIcon={<CloseIcon />} onClick={onCancelClick}>{cancelLabel}</DefaultButton>
}
<PrimaryButton className='Alert-margin' startIcon={buttonIconMap[okIcon]} onClick={onOkClick} autoFocus>{okLabel}</PrimaryButton>
</Box>
</StyledBox>
);
Expand All @@ -77,7 +67,7 @@ AlertContent.propTypes = {
onCancelClick: PropTypes.func,
okLabel: PropTypes.string,
cancelLabel: PropTypes.string,
extraButtons: PropTypes.array
okIcon : PropTypes.string
};

function alert(title, text, onOkClick, okLabel = gettext('OK')) {
Expand All @@ -93,7 +83,7 @@ function alert(title, text, onOkClick, okLabel = gettext('OK')) {
});
}

function confirm(title, text, onOkClick, onCancelClick, okLabel = gettext('Yes'), cancelLabel = gettext('No'), extras = null) {
function confirm(title, text, onOkClick, onCancelClick, okLabel = gettext('Yes'), cancelLabel = gettext('No'), okIcon) {
// bind the modal provider before calling
this.showModal(title, (closeModal) => {
const onCancelClickClose = () => {
Expand All @@ -105,12 +95,36 @@ function confirm(title, text, onOkClick, onCancelClick, okLabel = gettext('Yes')
onOkClick?.();
closeModal();
};
const extraButtons = extras?.(closeModal);
return (
<AlertContent text={text} confirm onOkClick={onOkClickClose} onCancelClick={onCancelClickClose} okLabel={okLabel} cancelLabel={cancelLabel} extraButtons={extraButtons} />
<AlertContent text={text} confirm onOkClick={onOkClickClose} onCancelClick={onCancelClickClose} okLabel={okLabel} cancelLabel={cancelLabel} okIcon={okIcon}/>
);
});
}

function confirmDelete(title, text, onDeleteClick, onCancelClick, deleteLabel = gettext('Delete'), cancelLabel = gettext('Cancel')) {
this.showModal(
title,
(closeModal)=>{
const handleOkClose = (callback) => {
callback();
closeModal();
};
return (
<StyledBox display="flex" flexDirection="column" height="100%">
<Box flexGrow="1" p={2}>
{typeof (text) == 'string' ? HTMLReactParser(text) : text}
</Box>
<Box className='Alert-footer'>
<DefaultButton className='Alert-margin' startIcon={<CloseIcon />} onClick={() => handleOkClose(onCancelClick)} autoFocus>{cancelLabel}</DefaultButton>
<DefaultButton className='Alert-margin' color={'error'} startIcon={<DeleteIcon/> } onClick={() => handleOkClose(onDeleteClick)}>{deleteLabel}</DefaultButton>
</Box>
</StyledBox>
);
},
{ isFullScreen: false, isResizeable: false, showFullScreen: false, isFullWidth: false, showTitle: true},
);
}

export default function ModalProvider({ children }) {
const [modals, setModals] = React.useState([]);

Expand Down Expand Up @@ -143,7 +157,8 @@ export default function ModalProvider({ children }) {
const modalContext = React.useMemo(() => ({
...modalContextBase,
confirm: confirm.bind(modalContextBase),
alert: alert.bind(modalContextBase)
alert: alert.bind(modalContextBase),
confirmDelete: confirmDelete.bind(modalContextBase)
}), []);
return (
<ModalContext.Provider value={modalContext}>
Expand Down
23 changes: 4 additions & 19 deletions web/pgadmin/static/js/helpers/Notifier.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -175,29 +175,14 @@ class Notifier {
this.modal.alert(title, text, onOkClick, okLabel);
}

confirm(title, text, onOkClick, onCancelClick, okLabel=gettext('Yes'), cancelLabel=gettext('No'), extras=null) {
confirm(title, text, onOkClick, onCancelClick, okLabel=gettext('Yes'), cancelLabel=gettext('No'), okIcon) {
/* Use this if you want to use pgAdmin global notifier.
Or else, if you want to use modal inside iframe only then use ModalProvider eg- query tool */
this.modal.confirm(title, text, onOkClick, onCancelClick, okLabel, cancelLabel, extras);
this.modal.confirm(title, text, onOkClick, onCancelClick, okLabel, cancelLabel, okIcon);
}

confirmDelete(title, text, onOkClick, onCancelClick,okLabel = gettext('Yes'), cancelLabel = gettext('No')){

const extraButtons = (closeModal) => {
return [
{
type: 'default',
icon: <CheckRoundedIcon />,
label: okLabel,
onClick: ()=>{
onOkClick();
closeModal();
},
color: 'error',
},
];
};
this.modal.confirm(title, text, onOkClick, onCancelClick, okLabel, cancelLabel, extraButtons);
confirmDelete(title, text, onDeleteClick, onCancelClick, okLabel = gettext('Delete'), cancelLabel = gettext('Cancel')){
this.modal.confirmDelete(title, text, onDeleteClick, onCancelClick, okLabel, cancelLabel);
}

showModal(title, content, modalOptions) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import gettext from 'sources/gettext';
import PropTypes from 'prop-types';
import { DefaultButton, PgButtonGroup, PgIconButton } from '../../../../../../static/js/components/Buttons';
import { Box, Tooltip, CircularProgress } from '@mui/material';
import { ConnectedIcon, DisonnectedIcon } from '../../../../../../static/js/components/ExternalIcon';
import { ConnectedIcon, DisconnectedIcon } from '../../../../../../static/js/components/ExternalIcon';

const StyledBox = styled(Box)(({theme}) => ({
padding: '2px 4px',
Expand Down Expand Up @@ -45,7 +45,7 @@ function ConnectionStatusIcon({status}) {
} else if(status == STATUS.CONNECTED || status == STATUS.FAILED) {
return <ConnectedIcon />;
} else {
return <DisonnectedIcon />;
return <DisconnectedIcon />;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { styled } from '@mui/material/styles';
import { Box, CircularProgress, Tooltip } from '@mui/material';
import { DefaultButton, PgButtonGroup, PgIconButton } from '../../../../../../static/js/components/Buttons';
import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown';
import { ConnectedIcon, DisonnectedIcon, QueryToolIcon } from '../../../../../../static/js/components/ExternalIcon';
import { ConnectedIcon, DisconnectedIcon, QueryToolIcon } from '../../../../../../static/js/components/ExternalIcon';
import { QueryToolContext } from '../QueryToolComponent';
import { CONNECTION_STATUS, CONNECTION_STATUS_MESSAGE } from '../QueryToolConstants';
import HourglassEmptyRoundedIcon from '@mui/icons-material/HourglassEmptyRounded';
Expand Down Expand Up @@ -65,7 +65,7 @@ function ConnectionStatusIcon({connected, connecting, status}) {
return <ConnectedIcon />;
}
} else {
return <DisonnectedIcon />;
return <DisconnectedIcon />;
}
}

Expand Down