diff --git a/superset/assets/src/components/Hotkeys.jsx b/superset/assets/src/components/Hotkeys.jsx index 8936eed20e..36e7d572d3 100644 --- a/superset/assets/src/components/Hotkeys.jsx +++ b/superset/assets/src/components/Hotkeys.jsx @@ -28,6 +28,7 @@ const propTypes = { func: PropTypes.func.isRequired, })).isRequired, header: PropTypes.string, + placement: PropTypes.string, }; const defaultProps = { @@ -42,7 +43,6 @@ export default class Hotkeys extends React.PureComponent { } renderPopover() { const { header, hotkeys } = this.props; - return ( @@ -68,7 +68,7 @@ export default class Hotkeys extends React.PureComponent { diff --git a/superset/assets/src/explore/components/ExploreViewContainer.jsx b/superset/assets/src/explore/components/ExploreViewContainer.jsx index b2081c3b51..2548005b1e 100644 --- a/superset/assets/src/explore/components/ExploreViewContainer.jsx +++ b/superset/assets/src/explore/components/ExploreViewContainer.jsx @@ -35,6 +35,25 @@ import * as saveModalActions from '../actions/saveModalActions'; import * as chartActions from '../../chart/chartAction'; import { fetchDatasourceMetadata } from '../../dashboard/actions/datasources'; import { Logger, ActionLog, EXPLORE_EVENT_NAMES, LOG_ACTIONS_MOUNT_EXPLORER } from '../../logger'; +import Hotkeys from '../../components/Hotkeys'; + +// Prolly need to move this to a global context +const keymap = { + RUN: 'ctrl + r, ctrl + enter', + SAVE: 'ctrl + s', +}; + +const getHotKeys = () => { + const d = []; + Object.keys(keymap).forEach((k) => { + d.push({ + name: k, + descr: keymap[k], + key: k, + }); + }); + return d; +}; const propTypes = { actions: PropTypes.object.isRequired, @@ -75,11 +94,13 @@ class ExploreViewContainer extends React.Component { this.onStop = this.onStop.bind(this); this.onQuery = this.onQuery.bind(this); this.toggleModal = this.toggleModal.bind(this); + this.handleKeydown = this.handleKeydown.bind(this); } componentDidMount() { window.addEventListener('resize', this.handleResize); window.addEventListener('popstate', this.handlePopstate); + document.addEventListener('keydown', this.handleKeydown); this.addHistory({ isReplace: true }); Logger.append(LOG_ACTIONS_MOUNT_EXPLORER); } @@ -129,6 +150,7 @@ class ExploreViewContainer extends React.Component { componentWillUnmount() { window.removeEventListener('resize', this.handleResize); window.removeEventListener('popstate', this.handlePopstate); + document.removeEventListener('keydown', this.handleKeydown); } onQuery() { @@ -158,6 +180,29 @@ class ExploreViewContainer extends React.Component { return `${window.innerHeight - navHeight}px`; } + handleKeydown(event) { + const controlOrCommand = event.ctrlKey || event.metaKey; + if (controlOrCommand) { + const isEnter = event.key === 'Enter' || event.keyCode === 13; + const isS = event.key === 's' || event.keyCode === 83; + if (isEnter) { + this.onQuery(); + } else if (isS) { + if (this.props.slice) { + this.props.actions.saveSlice(this.props.form_data, { + action: 'overwrite', + slice_id: this.props.slice.slice_id, + slice_name: this.props.slice.slice_name, + add_to_dash: 'noSave', + goto_dash: false, + }).then(({ data }) => { + window.location = data.slice.slice_url; + }); + } + } + } + } + findChangedControlKeys(prevControls, currentControls) { return Object.keys(currentControls).filter( key => @@ -273,10 +318,7 @@ class ExploreViewContainer extends React.Component {
{this.state.showModal && (
- +
+ +
+ +
+