diff --git a/superset/assets/spec/javascripts/utils/common_spec.jsx b/superset/assets/spec/javascripts/utils/common_spec.jsx index b6fc39fd42b..eabb69e8607 100644 --- a/superset/assets/spec/javascripts/utils/common_spec.jsx +++ b/superset/assets/spec/javascripts/utils/common_spec.jsx @@ -1,4 +1,4 @@ -import { isTruthy, optionFromValue } from '../../../src/utils/common'; +import { isTruthy, optionFromValue, prepareCopyToClipboardTabularData } from '../../../src/utils/common'; describe('utils/common', () => { describe('isTruthy', () => { @@ -48,4 +48,17 @@ describe('utils/common', () => { expect(optionFromValue(5)).toEqual({ value: 5, label: '5' }); }); }); + describe('prepareCopyToClipboardTabularData', () => { + it('converts empty array', () => { + const array = []; + expect(prepareCopyToClipboardTabularData(array)).toEqual(''); + }); + it('converts non empty array', () => { + const array = [ + { column1: 'lorem', column2: 'ipsum' }, + { column1: 'dolor', column2: 'sit', column3: 'amet' }, + ]; + expect(prepareCopyToClipboardTabularData(array)).toEqual('lorem\tipsum\ndolor\tsit\tamet\n'); + }); + }); }); diff --git a/superset/assets/src/SqlLab/components/ResultSet.jsx b/superset/assets/src/SqlLab/components/ResultSet.jsx index c7c10cd586b..a9416d4140f 100644 --- a/superset/assets/src/SqlLab/components/ResultSet.jsx +++ b/superset/assets/src/SqlLab/components/ResultSet.jsx @@ -9,6 +9,8 @@ import ExploreResultsButton from './ExploreResultsButton'; import HighlightedSql from './HighlightedSql'; import FilterableTable from '../../components/FilterableTable/FilterableTable'; import QueryStateLabel from './QueryStateLabel'; +import CopyToClipboard from '../../components/CopyToClipboard'; +import { prepareCopyToClipboardTabularData } from '../../utils/common'; const propTypes = { actions: PropTypes.object, @@ -112,6 +114,16 @@ export default class ResultSet extends React.PureComponent { } + + + {t('Clipboard')} + + } + />
diff --git a/superset/assets/src/components/CopyToClipboard.jsx b/superset/assets/src/components/CopyToClipboard.jsx index 199e8d430f7..433ebcf0c73 100644 --- a/superset/assets/src/components/CopyToClipboard.jsx +++ b/superset/assets/src/components/CopyToClipboard.jsx @@ -10,6 +10,7 @@ const propTypes = { shouldShowText: PropTypes.bool, text: PropTypes.string, inMenu: PropTypes.bool, + wrapped: PropTypes.bool, tooltipText: PropTypes.string, }; @@ -18,6 +19,7 @@ const defaultProps = { onCopyEnd: () => {}, shouldShowText: true, inMenu: false, + wrapped: true, tooltipText: t('Copy to clipboard'), }; @@ -94,6 +96,23 @@ export default class CopyToClipboard extends React.Component { return this.props.tooltipText; } + renderNotWrapped() { + const { copyNode } = this.props; + return ( + + {copyNode} + + ); + } + renderLink() { return ( @@ -139,7 +158,11 @@ export default class CopyToClipboard extends React.Component { } render() { - return this.props.inMenu ? this.renderInMenu() : this.renderLink(); + const { wrapped, inMenu } = this.props; + if (!wrapped) { + return this.renderNotWrapped(); + } + return inMenu ? this.renderInMenu() : this.renderLink(); } } diff --git a/superset/assets/src/explore/components/DisplayQueryButton.jsx b/superset/assets/src/explore/components/DisplayQueryButton.jsx index 042ca24d83e..1497e508929 100644 --- a/superset/assets/src/explore/components/DisplayQueryButton.jsx +++ b/superset/assets/src/explore/components/DisplayQueryButton.jsx @@ -19,6 +19,7 @@ import Loading from '../../components/Loading'; import ModalTrigger from './../../components/ModalTrigger'; import Button from '../../components/Button'; import RowCountLabel from './RowCountLabel'; +import { prepareCopyToClipboardTabularData } from '../../utils/common'; registerLanguage('markdown', markdownSyntax); registerLanguage('html', htmlSyntax); @@ -130,6 +131,15 @@ export default class DisplayQueryButton extends React.PureComponent { + + + + } + />