Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Widget Params] Migrated edit params + new widget dialog to Ant Modal #3387

Merged
merged 5 commits into from
Feb 4, 2019
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
121 changes: 44 additions & 77 deletions client/app/components/dashboards/AddWidgetDialog.jsx
Original file line number Diff line number Diff line change
@@ -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,
Expand All @@ -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) {
Expand All @@ -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,
});
});

Expand All @@ -57,6 +59,10 @@ class AddWidgetDialog extends React.Component {
};
}

close = () => {
this.setState({ showModal: false });
}

selectQuery(queryId) {
// Clear previously selected query (if any)
this.setState({
Expand Down Expand Up @@ -143,7 +149,8 @@ class AddWidgetDialog extends React.Component {
.save()
.then(() => {
dashboard.widgets.push(widget);
this.props.close();
this.props.onConfirm();
this.close();
ranbena marked this conversation as resolved.
Show resolved Hide resolved
})
.catch(() => {
toastr.error('Widget can not be added');
Expand Down Expand Up @@ -290,77 +297,37 @@ class AddWidgetDialog extends React.Component {
);

return (
<div>
<div className="modal-header">
<button
type="button"
className="close"
disabled={this.state.saveInProgress}
aria-hidden="true"
onClick={this.props.dismiss}
>
&times;
</button>
<h4 className="modal-title">Add Widget</h4>
</div>
<div className="modal-body">
{this.renderQueryInput()}
{!this.state.selectedQuery && this.renderSearchQueryResults()}
{this.state.selectedQuery && this.renderVisualizationInput()}

{
(this.state.parameterMappings.length > 0) && [
<label key="parameters-title" htmlFor="parameter-mappings">Parameters</label>,
<ParameterMappingListInput
key="parameters-list"
id="parameter-mappings"
mappings={this.state.parameterMappings}
existingParams={existingParams}
onChange={mappings => this.updateParamMappings(mappings)}
/>,
]
}
</div>
<Modal
visible={this.state.showModal}
afterClose={this.props.onClose}
title="Add Widget"
onOk={() => 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()}

<div className="modal-footer">
<button
type="button"
className="btn btn-default"
disabled={this.state.saveInProgress}
onClick={this.props.dismiss}
>
Close
</button>
<button
type="button"
className="btn btn-primary"
disabled={this.state.saveInProgress || !this.state.selectedQuery}
onClick={() => this.saveWidget()}
>
Add to Dashboard
</button>
</div>
</div>
{
(this.state.parameterMappings.length > 0) && [
<label key="parameters-title" htmlFor="parameter-mappings">Parameters</label>,
<ParameterMappingListInput
key="parameters-list"
id="parameter-mappings"
mappings={this.state.parameterMappings}
existingParams={existingParams}
onChange={mappings => this.updateParamMappings(mappings)}
/>,
]
}
</Modal>
);
}
}

export default function init(ngModule) {
ngModule.component('addWidgetDialog', {
template: `
<add-widget-dialog-impl
dashboard="$ctrl.resolve.dashboard"
close="$ctrl.close"
dismiss="$ctrl.dismiss"
></add-widget-dialog-impl>
`,
bindings: {
resolve: '<',
close: '&',
dismiss: '&',
},
});
ngModule.component('addWidgetDialogImpl', react2angular(AddWidgetDialog));
}

init.init = true;
export default ModalOpener(AddWidgetDialog);
104 changes: 32 additions & 72 deletions client/app/components/dashboards/EditParameterMappingsDialog.jsx
Original file line number Diff line number Diff line change
@@ -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,
Expand All @@ -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) {
Expand All @@ -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;
Expand All @@ -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');
Expand All @@ -66,69 +71,24 @@ class EditParameterMappingsDialog extends React.Component {
);

return (
<div>
<div className="modal-header">
<button
type="button"
className="close"
disabled={this.state.saveInProgress}
aria-hidden="true"
onClick={this.props.dismiss}
>
&times;
</button>
<h4 className="modal-title">Parameters</h4>
</div>
<div className="modal-body">
{(this.state.parameterMappings.length > 0) && (
<ParameterMappingListInput
mappings={this.state.parameterMappings}
existingParams={existingParams}
onChange={mappings => this.updateParamMappings(mappings)}
/>
)}
</div>

<div className="modal-footer">
<button
type="button"
className="btn btn-default"
disabled={this.state.saveInProgress}
onClick={this.props.dismiss}
>
Close
</button>
<button
type="button"
className="btn btn-primary"
disabled={this.state.saveInProgress}
onClick={() => this.saveWidget()}
>
Save
</button>
</div>
</div>
<Modal
visible={this.state.showModal}
afterClose={this.props.onClose}
title="Parameters"
onOk={() => this.saveWidget()}
okButtonProps={{ loading: this.state.saveInProgress }}
onCancel={this.close}
>
{(this.state.parameterMappings.length > 0) && (
<ParameterMappingListInput
mappings={this.state.parameterMappings}
existingParams={existingParams}
onChange={mappings => this.updateParamMappings(mappings)}
/>
)}
</Modal>
);
}
}

export default function init(ngModule) {
ngModule.component('editParameterMappingsDialog', {
template: `
<edit-parameter-mappings-dialog-impl
dashboard="$ctrl.resolve.dashboard"
widget="$ctrl.resolve.widget"
close="$ctrl.close"
dismiss="$ctrl.dismiss"
></edit-parameter-mappings-dialog-impl>
`,
bindings: {
resolve: '<',
close: '&',
dismiss: '&',
},
});
ngModule.component('editParameterMappingsDialogImpl', react2angular(EditParameterMappingsDialog));
}

init.init = true;
export default ModalOpener(EditParameterMappingsDialog);
4 changes: 3 additions & 1 deletion client/app/components/dashboards/widget.html
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@

<li ng-if="$ctrl.canViewQuery || ($ctrl.dashboard.canEdit() && $ctrl.hasParameters())" class="divider"></li>
<li ng-if="$ctrl.canViewQuery"><a ng-href="{{$ctrl.widget.getQuery().getUrl(true, $ctrl.widget.visualization.id)}}">View Query</a></li>
<li ng-if="$ctrl.dashboard.canEdit() && $ctrl.hasParameters()"><a ng-click="$ctrl.editParameterMappings()">Edit Parameters</a></li>
<li ng-if="$ctrl.dashboard.canEdit() && $ctrl.hasParameters()">
<li ng-if="$ctrl.dashboard.canEdit() && $ctrl.hasParameters()"><a ng-click="$ctrl.editParameterMappings()">Edit Parameters</a></li>
</li>

<li ng-if="$ctrl.dashboard.canEdit()" class="divider"></li>
<li ng-if="$ctrl.dashboard.canEdit()"><a ng-click="$ctrl.deleteWidget()">Remove from Dashboard</a></li>
Expand Down
11 changes: 4 additions & 7 deletions client/app/components/dashboards/widget.js
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand Down Expand Up @@ -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');
Expand Down
36 changes: 36 additions & 0 deletions client/app/hoc/ModalOpener.jsx
Original file line number Diff line number Diff line change
@@ -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 = (
<WrappedComponent
onClose={destroy}
onConfirm={resolve}
{...props}
/>
);

render(component);
});

return {
open: props => ({
result: getResult(props),
}),
};
};

export default ModalOpener;
Loading