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 @@
-
+
-
+
-
+
@@ -110,7 +110,7 @@
Widgets are individual query visualizations or text boxes you can place on your dashboard in various arrangements.
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) => {