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:
vera-liu 2016-09-27 22:48:01 -07:00 committed by GitHub
parent 1a29163530
commit 96844c5c12
4 changed files with 152 additions and 14 deletions

View File

@ -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;

View File

@ -5,10 +5,53 @@ import { bindActionCreators } from 'redux';
import * as Actions from '../actions';
import SqlEditor from './SqlEditor';
import shortid from 'shortid';
import { getParamFromQuery } from '../../../utils/common';
import CopyQueryTabUrl from './CopyQueryTabUrl';
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) {
/* eslint no-alert: 0 */
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)}>
<i className="fa fa-i-cursor" /> rename tab
</MenuItem>
<MenuItem eventKey="3">
<i className="fa fa-clipboard" /> <CopyQueryTabUrl qe={qe} />
</MenuItem>
</DropdownButton>
</div>
);
@ -96,14 +142,14 @@ class QueryEditors extends React.Component {
);
}
}
QueryEditors.propTypes = {
TabbedSqlEditors.propTypes = {
actions: React.PropTypes.object,
databases: React.PropTypes.object,
queries: React.PropTypes.object,
queryEditors: React.PropTypes.array,
tabHistory: React.PropTypes.array,
};
QueryEditors.defaultProps = {
TabbedSqlEditors.defaultProps = {
tabHistory: [],
queryEditors: [],
};
@ -122,4 +168,4 @@ function mapDispatchToProps(dispatch) {
};
}
export default connect(mapStateToProps, mapDispatchToProps)(QueryEditors);
export default connect(mapStateToProps, mapDispatchToProps)(TabbedSqlEditors);

View File

@ -6,12 +6,14 @@ const propTypes = {
onCopyEnd: PropTypes.func,
shouldShowText: PropTypes.bool,
text: PropTypes.string.isRequired,
inMenu: PropTypes.bool,
};
const defaultProps = {
copyNode: <span>Copy</span>,
onCopyEnd: () => {},
shouldShowText: true,
inMenu: false,
};
export default class CopyToClipboard extends React.Component {
@ -71,20 +73,14 @@ export default class CopyToClipboard extends React.Component {
return tooltipText;
}
render() {
const tooltip = (
<Tooltip id="copy-to-clipboard-tooltip">
{this.tooltipText()}
</Tooltip>
);
renderLink() {
return (
<div>
<span>
{this.props.shouldShowText &&
<span>{this.props.text}</span>
}
&nbsp;&nbsp;&nbsp;&nbsp;
<OverlayTrigger placement="top" overlay={tooltip} trigger={['hover']}>
<OverlayTrigger placement="top" overlay={this.renderTooltip()} trigger={['hover']}>
<Button
bsStyle="link"
onClick={this.copyToClipboard}
@ -93,9 +89,40 @@ export default class CopyToClipboard extends React.Component {
{this.props.copyNode}
</Button>
</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;

View File

@ -26,3 +26,14 @@ export function rgbLuminance(r, g, b) {
// Formula: https://en.wikipedia.org/wiki/Relative_luminance
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;
}