mirror of
https://github.com/apache/superset.git
synced 2024-09-12 08:39:45 -04:00
Share query (#1154)
* In the tab's dropdown menu under SQL editors, copy query link option is added. A url with copied query will pop up a new editor tab. * Made changes based on comments * Move copy query button to right bottom of sql editor box * Added in Alanna's code for copy url under menu item * Fixed linting issues
This commit is contained in:
parent
1a29163530
commit
96844c5c12
@ -0,0 +1,54 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import CopyToClipboard from '../../components/CopyToClipboard';
|
||||||
|
|
||||||
|
const propTypes = {
|
||||||
|
qe: React.PropTypes.object,
|
||||||
|
};
|
||||||
|
|
||||||
|
const defaultProps = {
|
||||||
|
qe: null,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default class CopyQueryTabUrl extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
const uri = window.location.toString();
|
||||||
|
const search = window.location.search;
|
||||||
|
const cleanUri = search ? uri.substring(0, uri.indexOf('?')) : uri;
|
||||||
|
const query = search.substring(1);
|
||||||
|
this.state = {
|
||||||
|
uri,
|
||||||
|
cleanUri,
|
||||||
|
query,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
getQueryLink() {
|
||||||
|
const params = [];
|
||||||
|
const qe = this.props.qe;
|
||||||
|
if (qe.dbId) params.push('dbid=' + qe.dbId);
|
||||||
|
if (qe.title) params.push('title=' + qe.title);
|
||||||
|
if (qe.schema) params.push('schema=' + qe.schema);
|
||||||
|
if (qe.autorun) params.push('autorun=' + qe.autorun);
|
||||||
|
if (qe.sql) params.push('sql=' + qe.sql);
|
||||||
|
|
||||||
|
const queryString = params.join('&');
|
||||||
|
const queryLink = this.state.cleanUri + '?' + queryString;
|
||||||
|
|
||||||
|
return queryLink;
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<CopyToClipboard
|
||||||
|
inMenu
|
||||||
|
text={this.getQueryLink()}
|
||||||
|
copyNode={<span>copy query</span>}
|
||||||
|
shouldShowText={false}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CopyQueryTabUrl.propTypes = propTypes;
|
||||||
|
CopyQueryTabUrl.defaultProps = defaultProps;
|
@ -5,10 +5,53 @@ import { bindActionCreators } from 'redux';
|
|||||||
import * as Actions from '../actions';
|
import * as Actions from '../actions';
|
||||||
import SqlEditor from './SqlEditor';
|
import SqlEditor from './SqlEditor';
|
||||||
import shortid from 'shortid';
|
import shortid from 'shortid';
|
||||||
|
import { getParamFromQuery } from '../../../utils/common';
|
||||||
|
import CopyQueryTabUrl from './CopyQueryTabUrl';
|
||||||
|
|
||||||
let queryCount = 1;
|
let queryCount = 1;
|
||||||
|
|
||||||
class QueryEditors extends React.Component {
|
class TabbedSqlEditors extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
const uri = window.location.toString();
|
||||||
|
const search = window.location.search;
|
||||||
|
const cleanUri = search ? uri.substring(0, uri.indexOf('?')) : uri;
|
||||||
|
const query = search.substring(1);
|
||||||
|
this.state = {
|
||||||
|
uri,
|
||||||
|
cleanUri,
|
||||||
|
query,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
componentWillMount() {
|
||||||
|
if (this.state.query) {
|
||||||
|
queryCount++;
|
||||||
|
const queryEditorProps = {
|
||||||
|
id: shortid.generate(),
|
||||||
|
title: getParamFromQuery(this.state.query, 'title'),
|
||||||
|
dbId: getParamFromQuery(this.state.query, 'dbid'),
|
||||||
|
schema: getParamFromQuery(this.state.query, 'schema'),
|
||||||
|
autorun: getParamFromQuery(this.state.query, 'autorun'),
|
||||||
|
sql: getParamFromQuery(this.state.query, 'sql'),
|
||||||
|
};
|
||||||
|
this.props.actions.addQueryEditor(queryEditorProps);
|
||||||
|
// Clean the url in browser history
|
||||||
|
window.history.replaceState({}, document.title, this.state.cleanUri);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
getQueryLink(qe) {
|
||||||
|
const params = [];
|
||||||
|
if (qe.dbId) params.push('dbid=' + qe.dbId);
|
||||||
|
if (qe.title) params.push('title=' + qe.title);
|
||||||
|
if (qe.schema) params.push('schema=' + qe.schema);
|
||||||
|
if (qe.autorun) params.push('autorun=' + qe.autorun);
|
||||||
|
if (qe.sql) params.push('sql=' + qe.sql);
|
||||||
|
|
||||||
|
const queryString = params.join('&');
|
||||||
|
const queryLink = this.state.cleanUri + '?' + queryString;
|
||||||
|
|
||||||
|
return queryLink;
|
||||||
|
}
|
||||||
renameTab(qe) {
|
renameTab(qe) {
|
||||||
/* eslint no-alert: 0 */
|
/* eslint no-alert: 0 */
|
||||||
const newTitle = prompt('Enter a new title for the tab');
|
const newTitle = prompt('Enter a new title for the tab');
|
||||||
@ -64,6 +107,9 @@ class QueryEditors extends React.Component {
|
|||||||
<MenuItem eventKey="2" onClick={this.renameTab.bind(this, qe)}>
|
<MenuItem eventKey="2" onClick={this.renameTab.bind(this, qe)}>
|
||||||
<i className="fa fa-i-cursor" /> rename tab
|
<i className="fa fa-i-cursor" /> rename tab
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
|
<MenuItem eventKey="3">
|
||||||
|
<i className="fa fa-clipboard" /> <CopyQueryTabUrl qe={qe} />
|
||||||
|
</MenuItem>
|
||||||
</DropdownButton>
|
</DropdownButton>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@ -96,14 +142,14 @@ class QueryEditors extends React.Component {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
QueryEditors.propTypes = {
|
TabbedSqlEditors.propTypes = {
|
||||||
actions: React.PropTypes.object,
|
actions: React.PropTypes.object,
|
||||||
databases: React.PropTypes.object,
|
databases: React.PropTypes.object,
|
||||||
queries: React.PropTypes.object,
|
queries: React.PropTypes.object,
|
||||||
queryEditors: React.PropTypes.array,
|
queryEditors: React.PropTypes.array,
|
||||||
tabHistory: React.PropTypes.array,
|
tabHistory: React.PropTypes.array,
|
||||||
};
|
};
|
||||||
QueryEditors.defaultProps = {
|
TabbedSqlEditors.defaultProps = {
|
||||||
tabHistory: [],
|
tabHistory: [],
|
||||||
queryEditors: [],
|
queryEditors: [],
|
||||||
};
|
};
|
||||||
@ -122,4 +168,4 @@ function mapDispatchToProps(dispatch) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export default connect(mapStateToProps, mapDispatchToProps)(QueryEditors);
|
export default connect(mapStateToProps, mapDispatchToProps)(TabbedSqlEditors);
|
||||||
|
@ -6,12 +6,14 @@ const propTypes = {
|
|||||||
onCopyEnd: PropTypes.func,
|
onCopyEnd: PropTypes.func,
|
||||||
shouldShowText: PropTypes.bool,
|
shouldShowText: PropTypes.bool,
|
||||||
text: PropTypes.string.isRequired,
|
text: PropTypes.string.isRequired,
|
||||||
|
inMenu: PropTypes.bool,
|
||||||
};
|
};
|
||||||
|
|
||||||
const defaultProps = {
|
const defaultProps = {
|
||||||
copyNode: <span>Copy</span>,
|
copyNode: <span>Copy</span>,
|
||||||
onCopyEnd: () => {},
|
onCopyEnd: () => {},
|
||||||
shouldShowText: true,
|
shouldShowText: true,
|
||||||
|
inMenu: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default class CopyToClipboard extends React.Component {
|
export default class CopyToClipboard extends React.Component {
|
||||||
@ -71,20 +73,14 @@ export default class CopyToClipboard extends React.Component {
|
|||||||
return tooltipText;
|
return tooltipText;
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
renderLink() {
|
||||||
const tooltip = (
|
|
||||||
<Tooltip id="copy-to-clipboard-tooltip">
|
|
||||||
{this.tooltipText()}
|
|
||||||
</Tooltip>
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<span>
|
||||||
{this.props.shouldShowText &&
|
{this.props.shouldShowText &&
|
||||||
<span>{this.props.text}</span>
|
<span>{this.props.text}</span>
|
||||||
}
|
}
|
||||||
|
|
||||||
<OverlayTrigger placement="top" overlay={tooltip} trigger={['hover']}>
|
<OverlayTrigger placement="top" overlay={this.renderTooltip()} trigger={['hover']}>
|
||||||
<Button
|
<Button
|
||||||
bsStyle="link"
|
bsStyle="link"
|
||||||
onClick={this.copyToClipboard}
|
onClick={this.copyToClipboard}
|
||||||
@ -93,9 +89,40 @@ export default class CopyToClipboard extends React.Component {
|
|||||||
{this.props.copyNode}
|
{this.props.copyNode}
|
||||||
</Button>
|
</Button>
|
||||||
</OverlayTrigger>
|
</OverlayTrigger>
|
||||||
</div>
|
</span>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
renderInMenu() {
|
||||||
|
return (
|
||||||
|
<OverlayTrigger placement="top" overlay={this.renderTooltip()} trigger={['hover']}>
|
||||||
|
<span
|
||||||
|
onClick={this.copyToClipboard}
|
||||||
|
onMouseOut={this.onMouseOut}
|
||||||
|
>
|
||||||
|
{this.props.copyNode}
|
||||||
|
</span>
|
||||||
|
</OverlayTrigger>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderTooltip() {
|
||||||
|
return (
|
||||||
|
<Tooltip id="copy-to-clipboard-tooltip">
|
||||||
|
{this.tooltipText()}
|
||||||
|
</Tooltip>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
let html;
|
||||||
|
if (this.props.inMenu) {
|
||||||
|
html = this.renderInMenu();
|
||||||
|
} else {
|
||||||
|
html = this.renderLink();
|
||||||
|
}
|
||||||
|
return html;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CopyToClipboard.propTypes = propTypes;
|
CopyToClipboard.propTypes = propTypes;
|
||||||
|
@ -26,3 +26,14 @@ export function rgbLuminance(r, g, b) {
|
|||||||
// Formula: https://en.wikipedia.org/wiki/Relative_luminance
|
// Formula: https://en.wikipedia.org/wiki/Relative_luminance
|
||||||
return (LUMINANCE_RED_WEIGHT * r) + (LUMINANCE_GREEN_WEIGHT * g) + (LUMINANCE_BLUE_WEIGHT * b);
|
return (LUMINANCE_RED_WEIGHT * r) + (LUMINANCE_GREEN_WEIGHT * g) + (LUMINANCE_BLUE_WEIGHT * b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getParamFromQuery(query, param) {
|
||||||
|
const vars = query.split('&');
|
||||||
|
for (let i = 0; i < vars.length; i++) {
|
||||||
|
const pair = vars[i].split('=');
|
||||||
|
if (decodeURIComponent(pair[0]) === param) {
|
||||||
|
return decodeURIComponent(pair[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user