URL shortner for dashboards (#4760)

* Added support for URLShortLinkButton to work for the dashboard case

* Fix lint errors and test

* Change references to 'slice' to 'chart'.

* Add unit tests to improve coverage

* Fixing lint errors

* Refactor to make URLShortLink more generic. Remove history modification code, redirect should be handling this.

* Remove history modification code, redirect should be handling this

* Generate a shorter link without the directory, and delegate default linked to the contents of window.location

* Fix lint errors

* Fix test_shortner test to check for new pattern

* Remove usage of addHistory to manipulate explore shortlink redirection

* Address build failure and using better practices for shortlink defaults

* Fixing alphabetical order

* More syntax mistakes

* Revert explore view history changes

* Fix use of component props, & rebase
This commit is contained in:
Tamika Tannis 2018-06-02 11:08:43 -07:00 committed by Hugh A. Miles II
parent cc0942ac98
commit dc21e0dd78
6 changed files with 38 additions and 20 deletions

View File

@ -4,13 +4,13 @@ import { describe, it } from 'mocha';
import { shallow } from 'enzyme';
import { OverlayTrigger } from 'react-bootstrap';
import URLShortLinkButton from '../../../../src/explore/components/URLShortLinkButton';
import URLShortLinkButton from '../../../src/components/URLShortLinkButton';
describe('URLShortLinkButton', () => {
const defaultProps = {
slice: {
querystring: () => 'query string',
},
url: 'mockURL',
emailSubject: 'Mock Subject',
emailContent: 'mock content',
};
it('renders', () => {

View File

@ -1,13 +1,14 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Popover, OverlayTrigger } from 'react-bootstrap';
import CopyToClipboard from './../../components/CopyToClipboard';
import { getShortUrl } from '../../utils/common';
import { getExploreLongUrl } from '../exploreUtils';
import { t } from '../../locales';
import CopyToClipboard from './CopyToClipboard';
import { getShortUrl } from '../utils/common';
import { t } from '../locales';
const propTypes = {
latestQueryFormData: PropTypes.object.isRequired,
url: PropTypes.string,
emailSubject: PropTypes.string,
emailContent: PropTypes.string,
};
export default class URLShortLinkButton extends React.Component {
@ -25,12 +26,11 @@ export default class URLShortLinkButton extends React.Component {
}
getCopyUrl() {
const longUrl = getExploreLongUrl(this.props.latestQueryFormData);
getShortUrl(longUrl, this.onShortUrlSuccess.bind(this));
getShortUrl(this.props.url, this.onShortUrlSuccess.bind(this));
}
renderPopover() {
const emailBody = t('Check out this chart: %s', this.state.shortUrl);
const emailBody = t('%s%s', this.props.emailContent, this.state.shortUrl);
return (
<Popover id="shorturl-popover">
<CopyToClipboard
@ -38,7 +38,7 @@ export default class URLShortLinkButton extends React.Component {
copyNode={<i className="fa fa-clipboard" title={t('Copy to clipboard')} />}
/>
&nbsp;&nbsp;
<a href={`mailto:?Subject=Superset%20Slice%20&Body=${emailBody}`}>
<a href={`mailto:?Subject=${this.props.emailSubject}%20&Body=${emailBody}`}>
<i className="fa fa-envelope" />
</a>
</Popover>
@ -62,4 +62,10 @@ export default class URLShortLinkButton extends React.Component {
}
}
URLShortLinkButton.defaultProps = {
url: window.location.href.substring(window.location.origin.length),
emailSubject: '',
emailContent: '',
};
URLShortLinkButton.propTypes = propTypes;

View File

@ -5,6 +5,7 @@ import Controls from './Controls';
import EditableTitle from '../../components/EditableTitle';
import Button from '../../components/Button';
import FaveStar from '../../components/FaveStar';
import URLShortLinkButton from '../../components/URLShortLinkButton';
import InfoTooltipWithTrigger from '../../components/InfoTooltipWithTrigger';
import { t } from '../../locales';
@ -92,6 +93,12 @@ class Header extends React.PureComponent {
</h1>
</div>
<div className="pull-right" style={{ marginTop: '35px' }}>
<span className="m-r-5">
<URLShortLinkButton
emailSubject="Superset Dashboard"
emailContent="Check out this dashboard: "
/>
</span>
{this.renderEditButton()}
<Controls
dashboard={dashboard}

View File

@ -1,11 +1,11 @@
import React from 'react';
import PropTypes from 'prop-types';
import cx from 'classnames';
import URLShortLinkButton from './URLShortLinkButton';
import URLShortLinkButton from '../../components/URLShortLinkButton';
import EmbedCodeButton from './EmbedCodeButton';
import DisplayQueryButton from './DisplayQueryButton';
import { t } from '../../locales';
import { exportChart } from '../exploreUtils';
import { exportChart, getExploreLongUrl } from '../exploreUtils';
const propTypes = {
canDownload: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]).isRequired,
@ -25,7 +25,12 @@ export default function ExploreActionButtons({
return (
<div className="btn-group results" role="group">
{latestQueryFormData &&
<URLShortLinkButton latestQueryFormData={latestQueryFormData} />}
<URLShortLinkButton
url={getExploreLongUrl(latestQueryFormData)}
emailSubject="Superset Chart"
emailContent="Check out this chart: "
/>
}
{latestQueryFormData &&
<EmbedCodeButton latestQueryFormData={latestQueryFormData} />}

View File

@ -745,13 +745,12 @@ class R(BaseSupersetView):
@expose('/shortner/', methods=['POST', 'GET'])
def shortner(self):
url = request.form.get('data')
directory = url.split('?')[0][2:]
obj = models.Url(url=url)
db.session.add(obj)
db.session.commit()
return Response(
'{scheme}://{request.headers[Host]}/{directory}?r={obj.id}'.format(
scheme=request.scheme, request=request, directory=directory, obj=obj),
'{scheme}://{request.headers[Host]}/r/{obj.id}'.format(
scheme=request.scheme, request=request, obj=obj),
mimetype='text/plain')
@expose('/msg/')

View File

@ -13,6 +13,7 @@ import json
import logging
import os
import random
import re
import string
import unittest
@ -377,7 +378,7 @@ class CoreTests(SupersetTestCase):
'previous_viz_type=sankey'
)
resp = self.client.post('/r/shortner/', data=dict(data=data))
assert '?r=' in resp.data.decode('utf-8')
assert re.search(r'\/r\/[0-9]+', resp.data.decode('utf-8'))
def test_kv(self):
self.logout()