diff --git a/client/app/components/dashboards/AddWidgetDialog.jsx b/client/app/components/dashboards/AddWidgetDialog.jsx index f043fcd0eb..b1f8a85c94 100644 --- a/client/app/components/dashboards/AddWidgetDialog.jsx +++ b/client/app/components/dashboards/AddWidgetDialog.jsx @@ -1,8 +1,9 @@ import { debounce, each, values, map, includes, first } from 'lodash'; import React from 'react'; import PropTypes from 'prop-types'; -import { react2angular } from 'react2angular'; import Select from 'antd/lib/select'; +import Modal from 'antd/lib/modal'; +import ModalOpener from '@/hoc/ModalOpener'; import highlight from '@/lib/highlight'; import { MappingType, @@ -19,15 +20,14 @@ const { Option, OptGroup } = Select; class AddWidgetDialog extends React.Component { static propTypes = { - dashboard: PropTypes.object, // eslint-disable-line react/forbid-prop-types - close: PropTypes.func, - dismiss: PropTypes.func, + dashboard: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types + onClose: PropTypes.func, + onConfirm: PropTypes.func, }; static defaultProps = { - dashboard: null, - close: () => {}, - dismiss: () => {}, + onClose: () => {}, + onConfirm: () => {}, }; constructor(props) { @@ -40,12 +40,14 @@ class AddWidgetDialog extends React.Component { searchedQueries: [], selectedVis: null, parameterMappings: [], + showModal: false, // show only after recent queries populated to avoid height "jump" }; // Don't show draft (unpublished) queries in recent queries. Query.recent().$promise.then((items) => { this.setState({ recentQueries: items.filter(item => !item.is_draft), + showModal: true, }); }); @@ -57,6 +59,10 @@ class AddWidgetDialog extends React.Component { }; } + close = () => { + this.setState({ showModal: false }); + } + selectQuery(queryId) { // Clear previously selected query (if any) this.setState({ @@ -143,7 +149,8 @@ class AddWidgetDialog extends React.Component { .save() .then(() => { dashboard.widgets.push(widget); - this.props.close(); + this.props.onConfirm(); + this.close(); }) .catch(() => { toastr.error('Widget can not be added'); @@ -290,77 +297,37 @@ class AddWidgetDialog extends React.Component { ); return ( -
-
- -

Add Widget

-
-
- {this.renderQueryInput()} - {!this.state.selectedQuery && this.renderSearchQueryResults()} - {this.state.selectedQuery && this.renderVisualizationInput()} - - { - (this.state.parameterMappings.length > 0) && [ - , - this.updateParamMappings(mappings)} - />, - ] - } -
+ this.saveWidget()} + okButtonProps={{ + loading: this.state.saveInProgress, + disabled: !this.state.selectedQuery, + }} + okText="Add to Dashboard" + onCancel={this.close} + > + {this.renderQueryInput()} + {!this.state.selectedQuery && this.renderSearchQueryResults()} + {this.state.selectedQuery && this.renderVisualizationInput()} -
- - -
-
+ { + (this.state.parameterMappings.length > 0) && [ + , + this.updateParamMappings(mappings)} + />, + ] + } + ); } } -export default function init(ngModule) { - ngModule.component('addWidgetDialog', { - template: ` - - `, - bindings: { - resolve: '<', - close: '&', - dismiss: '&', - }, - }); - ngModule.component('addWidgetDialogImpl', react2angular(AddWidgetDialog)); -} - -init.init = true; +export default ModalOpener(AddWidgetDialog); diff --git a/client/app/components/dashboards/EditParameterMappingsDialog.jsx b/client/app/components/dashboards/EditParameterMappingsDialog.jsx index 56b438fa5d..c76ad5e724 100644 --- a/client/app/components/dashboards/EditParameterMappingsDialog.jsx +++ b/client/app/components/dashboards/EditParameterMappingsDialog.jsx @@ -1,7 +1,8 @@ import { map } from 'lodash'; import React from 'react'; import PropTypes from 'prop-types'; -import { react2angular } from 'react2angular'; +import Modal from 'antd/lib/modal'; +import ModalOpener from '@/hoc/ModalOpener'; import { ParameterMappingListInput, parameterMappingsToEditableMappings, @@ -10,17 +11,15 @@ import { class EditParameterMappingsDialog extends React.Component { static propTypes = { - dashboard: PropTypes.object, // eslint-disable-line react/forbid-prop-types - widget: PropTypes.object, // eslint-disable-line react/forbid-prop-types - close: PropTypes.func, - dismiss: PropTypes.func, + dashboard: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types + widget: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types + onClose: PropTypes.func, + onConfirm: PropTypes.func, }; static defaultProps = { - dashboard: null, - widget: null, - close: () => {}, - dismiss: () => {}, + onClose: () => {}, + onConfirm: () => {}, }; constructor(props) { @@ -32,9 +31,14 @@ class EditParameterMappingsDialog extends React.Component { props.widget.query.getParametersDefs(), map(this.props.dashboard.getParametersDefs(), p => p.name), ), + showModal: true, }; } + close = () => { + this.setState({ showModal: false }); + } + saveWidget() { const toastr = this.props.toastr; // eslint-disable-line react/prop-types const widget = this.props.widget; @@ -45,7 +49,8 @@ class EditParameterMappingsDialog extends React.Component { widget .save() .then(() => { - this.props.close(); + this.props.onConfirm(); + this.close(); }) .catch(() => { toastr.error('Widget cannot be updated'); @@ -66,69 +71,24 @@ class EditParameterMappingsDialog extends React.Component { ); return ( -
-
- -

Parameters

-
-
- {(this.state.parameterMappings.length > 0) && ( - this.updateParamMappings(mappings)} - /> - )} -
- -
- - -
-
+ this.saveWidget()} + okButtonProps={{ loading: this.state.saveInProgress }} + onCancel={this.close} + > + {(this.state.parameterMappings.length > 0) && ( + this.updateParamMappings(mappings)} + /> + )} + ); } } -export default function init(ngModule) { - ngModule.component('editParameterMappingsDialog', { - template: ` - - `, - bindings: { - resolve: '<', - close: '&', - dismiss: '&', - }, - }); - ngModule.component('editParameterMappingsDialogImpl', react2angular(EditParameterMappingsDialog)); -} - -init.init = true; +export default ModalOpener(EditParameterMappingsDialog); diff --git a/client/app/components/dashboards/widget.html b/client/app/components/dashboards/widget.html index 6a37d4676b..94954841f7 100644 --- a/client/app/components/dashboards/widget.html +++ b/client/app/components/dashboards/widget.html @@ -21,7 +21,9 @@
  • View Query
  • -
  • Edit Parameters
  • +
  • +
  • Edit Parameters
  • +
  • Remove from Dashboard
  • diff --git a/client/app/components/dashboards/widget.js b/client/app/components/dashboards/widget.js index d8e7f9653d..61069f15d3 100644 --- a/client/app/components/dashboards/widget.js +++ b/client/app/components/dashboards/widget.js @@ -2,6 +2,7 @@ import { filter } from 'lodash'; import template from './widget.html'; import editTextBoxTemplate from './edit-text-box.html'; import widgetDialogTemplate from './widget-dialog.html'; +import editParameterMappingsDialog from '@/components/dashboards/EditParameterMappingsDialog'; import './widget.less'; import './widget-dialog.less'; @@ -78,13 +79,9 @@ function DashboardWidgetCtrl($location, $uibModal, $window, $rootScope, Events, this.hasParameters = () => this.widget.query.getParametersDefs().length > 0; this.editParameterMappings = () => { - $uibModal.open({ - component: 'editParameterMappingsDialog', - resolve: { - dashboard: this.dashboard, - widget: this.widget, - }, - size: 'lg', + editParameterMappingsDialog.open({ + dashboard: this.dashboard, + widget: this.widget, }).result.then(() => { this.localParameters = null; $rootScope.$broadcast('dashboard.update-parameters'); diff --git a/client/app/hoc/ModalOpener.jsx b/client/app/hoc/ModalOpener.jsx new file mode 100644 index 0000000000..e9e3801a2c --- /dev/null +++ b/client/app/hoc/ModalOpener.jsx @@ -0,0 +1,36 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; + +const ModalOpener = (WrappedComponent) => { + const container = document.createElement('div'); + + const render = (component) => { + ReactDOM.render(component, container); + document.body.appendChild(container); + }; + + const destroy = () => { + ReactDOM.unmountComponentAtNode(container); + document.body.removeChild(container); + }; + + const getResult = props => new Promise((resolve) => { + const component = ( + + ); + + render(component); + }); + + return { + open: props => ({ + result: getResult(props), + }), + }; +}; + +export default ModalOpener; diff --git a/client/app/pages/dashboards/dashboard.html b/client/app/pages/dashboards/dashboard.html index c28ec8ebd9..a6ae111b7a 100644 --- a/client/app/pages/dashboards/dashboard.html +++ b/client/app/pages/dashboards/dashboard.html @@ -5,13 +5,13 @@

    - + {{$ctrl.dashboard.user.name}} - + - +
    @@ -110,7 +110,7 @@

    - Add Textbox + Add Textbox Add Widget
    diff --git a/client/app/pages/dashboards/dashboard.js b/client/app/pages/dashboards/dashboard.js index 2c317e691d..e6be3262f7 100644 --- a/client/app/pages/dashboards/dashboard.js +++ b/client/app/pages/dashboards/dashboard.js @@ -5,6 +5,7 @@ import { policy } from '@/services/policy'; import { durationHumanize } from '@/filters'; import template from './dashboard.html'; import shareDashboardTemplate from './share-dashboard.html'; +import AddWidgetDialog from '@/components/dashboards/AddWidgetDialog'; import './dashboard.less'; function isWidgetPositionChanged(oldPosition, newPosition) { @@ -318,26 +319,32 @@ function DashboardCtrl( ); }; - this.addWidget = (widgetType) => { - const widgetTypes = { - textbox: 'addTextboxDialog', - widget: 'addWidgetDialog', - }; + this.addTextBox = () => { $uibModal .open({ - component: widgetTypes[widgetType], + component: 'addTextboxDialog', resolve: { dashboard: () => this.dashboard, }, }) - .result.then(() => { - this.extractGlobalParameters(); - // Save position of newly added widget (but not entire layout) - const widget = _.last(this.dashboard.widgets); - if (_.isObject(widget)) { - return widget.save(); - } - }); + .result.then(this.onWidgetAdded); + }; + + this.addWidget = () => { + AddWidgetDialog + .open({ + dashboard: this.dashboard, + }) + .result.then(this.onWidgetAdded); + }; + + this.onWidgetAdded = () => { + this.extractGlobalParameters(); + // Save position of newly added widget (but not entire layout) + const widget = _.last(this.dashboard.widgets); + if (_.isObject(widget)) { + return widget.save(); + } }; this.removeWidget = (widgetId) => {