Replace Alertify alert and confirm with React-based model dialog. Fixes #7053

This commit is contained in:
Akshay Joshi
2021-12-07 18:52:40 +05:30
parent e327066523
commit fd53e4f5f9
62 changed files with 393 additions and 398 deletions

View File

@@ -29,7 +29,6 @@ import { MappedFormControl } from './MappedControl';
import gettext from 'sources/gettext';
import BaseUISchema from 'sources/SchemaView/base_schema.ui';
import FormView, { getFieldMetaData } from './FormView';
import { pgAlertify } from '../helpers/legacyConnector';
import PropTypes from 'prop-types';
import CustomPropTypes from '../custom_prop_types';
import { parseApiError } from '../api_instance';
@@ -37,6 +36,7 @@ import DepListener, {DepListenerContext} from './DepListener';
import FieldSetView from './FieldSetView';
import DataGridView from './DataGridView';
import { useIsMounted } from '../custom_hooks';
import Notify from '../helpers/Notifier';
const useDialogStyles = makeStyles((theme)=>({
root: {
@@ -514,6 +514,14 @@ function SchemaDialogView({
});
setFormReady(true);
setLoaderText('');
}).catch((err)=>{
setLoaderText('');
if (err.response && err.response.data && err.response.data.errormsg) {
Notify.alert(
gettext(err.response.statusText),
gettext(err.response.data.errormsg)
);
}
});
} else {
/* Use the defaults as the initital data */
@@ -552,17 +560,14 @@ function SchemaDialogView({
};
/* Confirm before reset */
if(props.confirmOnCloseReset) {
pgAlertify().confirm(
Notify.confirm(
gettext('Warning'),
gettext('Changes will be lost. Are you sure you want to reset?'),
resetIt,
function() {
return true;
}
).set('labels', {
ok: gettext('Yes'),
cancel: gettext('No'),
}).show();
},
);
} else {
resetIt();
}
@@ -582,7 +587,7 @@ function SchemaDialogView({
changeData[schema.idAttribute] = schema.origData[schema.idAttribute];
}
if (schema.warningText) {
pgAlertify().confirm(
Notify.confirm(
gettext('Warning'),
schema.warningText,
()=> {
@@ -592,7 +597,7 @@ function SchemaDialogView({
setSaving(false);
setLoaderText('');
return true;
}
},
);
} else {
save(changeData);
@@ -603,7 +608,7 @@ function SchemaDialogView({
props.onSave(isNew, changeData)
.then(()=>{
if(schema.informText) {
pgAlertify().alert(
Notify.alert(
gettext('Warning'),
schema.informText,
);
@@ -791,6 +796,14 @@ function SchemaPropertiesView({
setOrigData(data || {});
setLoaderText('');
}
}).catch((err)=>{
setLoaderText('');
if (err.response && err.response.data && err.response.data.errormsg) {
Notify.alert(
gettext(err.response.statusText),
gettext(err.response.data.errormsg)
);
}
});
}, [getInitData]);

View File

@@ -453,7 +453,7 @@ define([
);
}
} else {
Alertify.alert(gettext('Edit object'), gettext('This object is not user editable.'),
Notify.alert(gettext('Edit object'), gettext('This object is not user editable.'),
function() {
return true;
});
@@ -528,7 +528,7 @@ define([
this.column.get('customDeleteMsg') : that.defaults.defaultDeleteMsg;
var delete_title = !_.isUndefined(this.column.get('customDeleteTitle')) ?
this.column.get('customDeleteTitle') : that.defaults.defaultDeleteTitle;
Alertify.confirm(
Notify.confirm(
delete_title,
delete_msg,
function() {
@@ -548,7 +548,7 @@ define([
}
);
} else {
Alertify.alert(gettext('Delete object'), gettext('This object cannot be deleted.'),
Notify.alert(gettext('Delete object'), gettext('This object cannot be deleted.'),
function() {
return true;
}
@@ -630,7 +630,7 @@ define([
this.column.get('customClearMsg') : that.defaults.defaultClearMsg;
var clear_title = !_.isUndefined(this.column.get('customClearTitle')) ?
this.column.get('customClearTitle') : that.defaults.defaultClearTitle;
Alertify.confirm(
Notify.confirm(
clear_title,
clear_msg,
function() {
@@ -2413,7 +2413,7 @@ define([
val = this.formatter.toRaw(this.$input.prop('value'), model);
if (_.isNull(val) || val.trim() === '') {
Alertify.alert(gettext('Validate Path'), gettext('Path should not be empty.'));
Notify.alert(gettext('Validate Path'), gettext('Path should not be empty.'));
}
$.ajax({
@@ -2425,7 +2425,7 @@ define([
}),
})
.done(function(res) {
Alertify.alert(gettext('Validate binary path'), gettext(res.data));
Notify.alert(gettext('Validate binary path'), gettext(res.data));
})
.fail(function(xhr, error) {
Notify.pgNotifier(error, xhr, gettext('Failed to validate binary path.'));

View File

@@ -15,6 +15,7 @@ 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';
const ModalContext = React.createContext({});
@@ -77,7 +78,7 @@ function ModalContainer({id, title, content}) {
>
<DialogTitle>
<Box marginRight="0.25rem">{title}</Box>
<Box marginLeft="auto"><PgIconButton icon={<CloseIcon />} size="xs" noBorder onClick={closeModal}/></Box>
<Box marginLeft="auto"><PgIconButton title={gettext('Close')} icon={<CloseIcon />} size="xs" noBorder onClick={closeModal}/></Box>
</DialogTitle>
<DialogContent>
{content(closeModal)}
@@ -88,5 +89,5 @@ function ModalContainer({id, title, content}) {
ModalContainer.propTypes = {
id: PropTypes.string,
title: CustomPropTypes.children,
content: CustomPropTypes.children,
content: PropTypes.func,
};

View File

@@ -15,7 +15,6 @@ import { NotifierMessage, MESSAGE_TYPE } from '../components/FormComponents';
import CustomPropTypes from '../custom_prop_types';
import gettext from 'sources/gettext';
import pgWindow from 'sources/window';
import Alertify from 'pgadmin.alertifyjs';
import ModalProvider, { useModal } from './ModalProvider';
import { DefaultButton, PrimaryButton } from '../components/Buttons';
import { Box } from '@material-ui/core';
@@ -35,6 +34,12 @@ export function initializeNotifier(notifierContainer) {
snackbarRef = useSnackbar();
return <></>;
};
if (!notifierContainer) {
notifierContainer = document.createElement('div');
document.body.appendChild(notifierContainer);
}
ReactDOM.render(
<Theme>
<SnackbarProvider
@@ -54,6 +59,12 @@ export function initializeModalProvider(modalContainer) {
modalRef = useModal();
return <></>;
};
if (!modalContainer) {
modalContainer = document.createElement('div');
document.body.appendChild(modalContainer);
}
ReactDOM.render(
<Theme>
<ModalProvider>
@@ -82,16 +93,16 @@ const useAlertStyles = makeStyles((theme)=>({
marginLeft: '0.25rem',
}
}));
function AlertContent({text, confirm, onOkClick, onCancelClick}) {
function AlertContent({text, confirm, okLabel=gettext('OK'), cancelLabel=gettext('Cancel'), onOkClick, onCancelClick}) {
const classes = useAlertStyles();
return (
<Box display="flex" flexDirection="column" height="100%">
<Box flexGrow="1" p={2}>{HTMLReactParse(text)}</Box>
<Box className={classes.footer}>
<DefaultButton startIcon={<CloseIcon />} onClick={onCancelClick} autoFocus={!confirm}>Close</DefaultButton>
{confirm &&
<PrimaryButton className={classes.margin} startIcon={<CheckRoundedIcon />} onClick={onOkClick} autoFocus={confirm}>OK</PrimaryButton>
<DefaultButton startIcon={<CloseIcon />} onClick={onCancelClick} >{cancelLabel}</DefaultButton>
}
<PrimaryButton className={classes.margin} startIcon={<CheckRoundedIcon />} onClick={onOkClick} autoFocus={true} >{okLabel}</PrimaryButton>
</Box>
</Box>
);
@@ -101,6 +112,8 @@ AlertContent.propTypes = {
confirm: PropTypes.bool,
onOkClick: PropTypes.func,
onCancelClick: PropTypes.func,
okLabel: PropTypes.string,
cancelLabel: PropTypes.string,
};
var Notifier = {
@@ -194,54 +207,33 @@ var Notifier = {
msg = _.escape(resp.result) || _.escape(resp.errormsg) || 'Unknown error';
}
if (contentType.indexOf('text/html') == 0) {
var alertMessage = promptmsg;
if (type === 'error') {
alertMessage =
'<div class="media text-danger text-14">'
+ '<div class="media-body media-middle">'
+ '<div class="alert-text" role="alert">' + promptmsg + '</div><br/>'
+ '<div class="alert-text" role="alert">' + gettext('Click for details.') + '</div>'
+ '</div>'
+ '</div>';
this.alert('Error', promptmsg);
}
Alertify.notify(
alertMessage, type, 0,
function() {
Alertify.pgIframeDialog().show().set({
frameless: false,
}).set(
'pg_msg', msg
);
});
return;
}
} catch (e) {
Alertify.alert().show().set('message', e.message).set(
'title', 'Error'
).set('closable', true);
this.alert('Error', e.message);
}
}
}
Alertify.alert().show().set(
'message', msg.replace(new RegExp(/\r?\n/, 'g'), '<br />')
).set('title', promptmsg).set('closable', true);
this.alert(promptmsg, msg.replace(new RegExp(/\r?\n/, 'g'), '<br />'));
},
alert: (title, text, onCancelClick)=>{
alert: (title, text, okLabel=gettext('OK'), onOkClick)=>{
if(!modalInitialized) {
initializeModalProvider(document.getElementById('modalContainer'));
}
modalRef.showModal(title, (closeModal)=>{
const onCancelClickClose = ()=>{
onCancelClick && onCancelClick();
const onOkClickClose = ()=>{
onOkClick && onOkClick();
closeModal();
};
return (
<AlertContent text={text} onCancelClick={onCancelClickClose} />
<AlertContent text={text} onOkClick={onOkClickClose} okLabel={okLabel} />
);
});
},
confirm: (title, text, onOkClick, onCancelClick)=>{
confirm: (title, text, onOkClick, onCancelClick, okLabel=gettext('Yes'), cancelLabel=gettext('No'))=>{
if(!modalInitialized) {
initializeModalProvider(document.getElementById('modalContainer'));
}
@@ -255,14 +247,14 @@ var Notifier = {
closeModal();
};
return (
<AlertContent text={text} confirm onOkClick={onOkClickClose} onCancelClick={onCancelClickClose} />
<AlertContent text={text} confirm onOkClick={onOkClickClose} onCancelClick={onCancelClickClose} okLabel={okLabel} cancelLabel={cancelLabel}/>
);
});
},
};
if(window.frameElement) {
Notifier = pgWindow.Notifier;
Notifier = pgWindow.Notifier || Notifier;
} else {
pgWindow.Notifier = Notifier;
}

View File

@@ -12,12 +12,12 @@
* These functions may not be needed once all are migrated
*/
import Alertify from 'pgadmin.alertifyjs';
import gettext from 'sources/gettext';
import pgAdmin from 'sources/pgadmin';
import Notify from './Notifier';
export function confirmDeleteRow(onOK, onCancel, title, message) {
Alertify.confirm(
Notify.confirm(
title || gettext('Delete Row'),
message || gettext('Are you sure you wish to delete this row?'),
function() {
@@ -31,11 +31,6 @@ export function confirmDeleteRow(onOK, onCancel, title, message) {
);
}
/* Don't import alertfiy directly in react files. Not good for testability */
export function pgAlertify() {
return Alertify;
}
/* Used by file select component to re-use existing logic */
export function showFileDialog(dialogParams, onFileSelect) {
let params = {

View File

@@ -7,7 +7,9 @@
//
//////////////////////////////////////////////////////////////
define(['sources/gettext', 'alertify'], function (gettext, alertify) {
import Notify from '../helpers/Notifier';
define(['sources/gettext'], function (gettext) {
var clipboard = {
copyTextToClipboard: function (text) {
var textArea = document.createElement('textarea');
@@ -79,7 +81,7 @@ define(['sources/gettext', 'alertify'], function (gettext, alertify) {
// triggered on document and then we can set clipboardData.
document.execCommand('copy');
} catch (err) {
alertify.alert(
Notify.alert(
gettext('Error'),
gettext('Oops, unable to copy to clipboard'));
}

View File

@@ -242,7 +242,7 @@ let FilterDialog = {
}, 10
);
} else {
Alertify.alert(
Notify.alert(
gettext('Validation Error'),
filterResponse.result
);

View File

@@ -308,7 +308,7 @@ let MacroDialog = {
}, 10
);
} else {
Alertify.alert(
Notify.alert(
gettext('Validation Error'),
macroResponse.result
);

View File

@@ -14,7 +14,7 @@ import Backgrid from 'pgadmin.backgrid';
import url_for from 'sources/url_for';
import $ from 'jquery';
import _ from 'underscore';
import Alertify from 'pgadmin.alertifyjs';
import Notify from '../helpers/Notifier';
export default function macroModel(transId) {
@@ -129,7 +129,7 @@ export default function macroModel(transId) {
let macros = that.collection.toJSON().filter(m => m.name !== undefined && m.name !== null);
if (macros.length > 0) {
Alertify.confirm(
Notify.confirm(
gettext('Clear All Rows'),
gettext('Are you sure you wish to clear all rows?'),
function() {

View File

@@ -272,7 +272,7 @@ let NewConnectionDialog = {
Alertify.newConnectionDialog('Connect to server.').resizeTo(pgAdmin.Browser.stdW.md,pgAdmin.Browser.stdH.md);
}, 500);
}).fail(function() {
Alertify.alert().setting({
Notify.alert().setting({
'title': gettext('Connection lost'),
'label':gettext('OK'),
'message': gettext('Connection to the server has been lost.'),

View File

@@ -8,8 +8,9 @@
//////////////////////////////////////////////////////////////////////////
import gettext from 'sources/gettext';
import Notify from '../helpers/Notifier';
export function retrieveAncestorOfTypeServer(pgBrowser, item, errorAlertTitle, alertify) {
export function retrieveAncestorOfTypeServer(pgBrowser, item, errorAlertTitle) {
let serverInformation = null;
let aciTreeItem = item || pgBrowser.tree.selected();
let treeNode = pgBrowser.tree.findNodeByDomElement(aciTreeItem);
@@ -30,7 +31,7 @@ export function retrieveAncestorOfTypeServer(pgBrowser, item, errorAlertTitle, a
if (databaseNode !== null) {
if (nodeData._label.indexOf('=') >= 0) {
alertify.alert(
Notify.alert(
gettext(errorAlertTitle),
gettext(
'Databases with = symbols in the name cannot be backed up or restored using this utility.'
@@ -47,7 +48,7 @@ export function retrieveAncestorOfTypeServer(pgBrowser, item, errorAlertTitle, a
}
if (serverInformation === null) {
alertify.alert(
Notify.alert(
gettext(errorAlertTitle),
gettext('Please select server or child node from the browser tree.')
);
@@ -56,7 +57,7 @@ export function retrieveAncestorOfTypeServer(pgBrowser, item, errorAlertTitle, a
return serverInformation;
}
export function retrieveAncestorOfTypeDatabase(pgBrowser, item, errorAlertTitle, alertify) {
export function retrieveAncestorOfTypeDatabase(pgBrowser, item, errorAlertTitle) {
let databaseInfo = null;
let aciTreeItem = item || pgBrowser.tree.selected();
let treeNode = pgBrowser.tree.findNodeByDomElement(aciTreeItem);
@@ -79,7 +80,7 @@ export function retrieveAncestorOfTypeDatabase(pgBrowser, item, errorAlertTitle,
}
if (databaseInfo === null) {
alertify.alert(
Notify.alert(
gettext(errorAlertTitle),
gettext('Please select a database or its child node from the browser.')
);

View File

@@ -11,6 +11,7 @@ import _ from 'underscore';
import $ from 'jquery';
import gettext from 'sources/gettext';
import 'wcdocker';
import Notify from './helpers/Notifier';
var wcDocker = window.wcDocker;
@@ -363,7 +364,7 @@ export function CSVToArray( strData, strDelimiter, quoteChar){
return arrData;
}
export function hasBinariesConfiguration(pgBrowser, serverInformation, alertify) {
export function hasBinariesConfiguration(pgBrowser, serverInformation) {
const module = 'paths';
let preference_name = 'pg_bin_dir';
let msg = gettext('Please configure the PostgreSQL Binary Path in the Preferences dialog.');
@@ -378,11 +379,11 @@ export function hasBinariesConfiguration(pgBrowser, serverInformation, alertify)
if (preference) {
if (_.isUndefined(preference.value) || !checkBinaryPathExists(preference.value, serverInformation.version)) {
alertify.alert(gettext('Configuration required'), msg);
Notify.alert(gettext('Configuration required'), msg);
return false;
}
} else {
alertify.alert(
Notify.alert(
gettext('Preferences Error'),
gettext('Failed to load preference %s of module %s', preference_name, module)
);