diff --git a/caravel/assets/javascripts/SqlLab/components/CopyQueryTabUrl.jsx b/caravel/assets/javascripts/SqlLab/components/CopyQueryTabUrl.jsx new file mode 100644 index 0000000000..13957e2c22 --- /dev/null +++ b/caravel/assets/javascripts/SqlLab/components/CopyQueryTabUrl.jsx @@ -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 ( + copy query} + shouldShowText={false} + /> + ); + } +} + +CopyQueryTabUrl.propTypes = propTypes; +CopyQueryTabUrl.defaultProps = defaultProps; diff --git a/caravel/assets/javascripts/SqlLab/components/TabbedSqlEditors.jsx b/caravel/assets/javascripts/SqlLab/components/TabbedSqlEditors.jsx index 15ca8bd1a6..8d65c9be0e 100644 --- a/caravel/assets/javascripts/SqlLab/components/TabbedSqlEditors.jsx +++ b/caravel/assets/javascripts/SqlLab/components/TabbedSqlEditors.jsx @@ -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 { rename tab + + + ); @@ -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); diff --git a/caravel/assets/javascripts/components/CopyToClipboard.jsx b/caravel/assets/javascripts/components/CopyToClipboard.jsx index c39d7ff950..367306e31b 100644 --- a/caravel/assets/javascripts/components/CopyToClipboard.jsx +++ b/caravel/assets/javascripts/components/CopyToClipboard.jsx @@ -6,12 +6,14 @@ const propTypes = { onCopyEnd: PropTypes.func, shouldShowText: PropTypes.bool, text: PropTypes.string.isRequired, + inMenu: PropTypes.bool, }; const defaultProps = { copyNode: Copy, 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 = ( - - {this.tooltipText()} - - ); - + renderLink() { return ( -
+ {this.props.shouldShowText && {this.props.text} }      - +
+ ); } + + renderInMenu() { + return ( + + + {this.props.copyNode} + + + ); + } + + renderTooltip() { + return ( + + {this.tooltipText()} + + ); + } + + render() { + let html; + if (this.props.inMenu) { + html = this.renderInMenu(); + } else { + html = this.renderLink(); + } + return html; + } } CopyToClipboard.propTypes = propTypes; diff --git a/caravel/assets/utils/common.js b/caravel/assets/utils/common.js index a6aa001e41..f96c33bf70 100644 --- a/caravel/assets/utils/common.js +++ b/caravel/assets/utils/common.js @@ -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; +}