diff --git a/client/src/lib/bootstrap-components.js b/client/src/lib/bootstrap-components.js index b58c5458..7b609580 100644 --- a/client/src/lib/bootstrap-components.js +++ b/client/src/lib/bootstrap-components.js @@ -85,53 +85,69 @@ class ModalDialog extends Component { this.state = { buttons: this.props.buttons || [ { label: t('Close'), className: 'btn-default', onClickAsync: null } ] }; - - this.buttonClicked = null; } static propTypes = { title: PropTypes.string, onCloseAsync: PropTypes.func, onButtonClickAsync: PropTypes.func, - buttons: PropTypes.array + buttons: PropTypes.array, + hidden: PropTypes.bool } + /* + this.props.hidden - this is the desired state of the modal + this.hidden - this is the actual state of the modal - this is because there is no public API on Bootstrap modal to know whether the modal is shown or not + */ + componentDidMount() { const jqModal = jQuery(this.domModal); jqModal.on('shown.bs.modal', () => jqModal.focus()); - jqModal.on('hidden.bs.modal', () => this.onHide()); - jqModal.modal(); + jqModal.on('hide.bs.modal', ::this.onHide); + this.hidden = this.props.hidden; + jqModal.modal({ + show: !this.props.hidden + }); } - close() { - const jqModal = jQuery(this.domModal); - jqModal.modal('hide'); + componentDidUpdate() { + if (this.props.hidden != this.hidden) { + const jqModal = jQuery(this.domModal); + this.hidden = this.props.hidden; + jqModal.modal(this.props.hidden ? 'hide' : 'show'); + } + } + + componentWillUnmount() { + // We discard the modal in a hard way (without hiding it). Thus we have to take care of the backgrop too. + jQuery('.modal-backdrop').remove(); + } + + onHide(evt) { + // Hide event is emited is both when hidden through user action or through API. We have to let the API + // calls through, otherwise the modal would never hide. The user actions, which change the desired state, + // are capture, converted to onClose callback and prevented. It's up to the parent to decide whether to + // hide the modal or not. + if (!this.props.hidden) { + this.onClose(); + evt.preventDefault(); + } } @withAsyncErrorHandler - async onHide() { - if (this.buttonClicked === null) { - if (this.props.onCloseAsync) { - await this.props.onCloseAsync(); - } - } else { - const idx = this.buttonClicked; - this.buttonClicked = null; - - const buttonSpec = this.state.buttons[idx]; - if (buttonSpec.onClickAsync) { - await buttonSpec.onClickAsync(idx); - } - + async onClose() { + if (this.props.onCloseAsync) { + await this.props.onCloseAsync(); } } async onButtonClick(idx) { - this.buttonClicked = idx; - const jqModal = jQuery(this.domModal); - jqModal.modal('hide'); + const buttonSpec = this.state.buttons[idx]; + if (buttonSpec.onClickAsync) { + await buttonSpec.onClickAsync(idx); + } } render() { @@ -150,7 +166,7 @@ class ModalDialog extends Component {
- +

{this.props.title}

{this.props.children}
diff --git a/client/src/namespaces/CUD.js b/client/src/namespaces/CUD.js index fb90eb5a..24ab26fd 100644 --- a/client/src/namespaces/CUD.js +++ b/client/src/namespaces/CUD.js @@ -163,10 +163,10 @@ export default class CUD extends Component { } async performDelete() { - await this.hideDeleteModal(); - const t = this.props.t; + await this.hideDeleteModal(); + try { this.disableForm(); this.setFormStatusMessage('info', t('Deleting namespace...')); @@ -198,8 +198,8 @@ export default class CUD extends Component { return (
- {!this.isEditGlobal() && deleteConfirmationShown && -