Skip to content

Commit

Permalink
Adding rowcount label to explore view header (apache#4059)
Browse files Browse the repository at this point in the history
  • Loading branch information
mistercrunch authored and michellethomas committed May 23, 2018
1 parent 643091c commit c4a7ae2
Show file tree
Hide file tree
Showing 6 changed files with 122 additions and 7 deletions.
Expand Up @@ -3,6 +3,7 @@ import PropTypes from 'prop-types';

import { chartPropType } from '../../chart/chartReducer';
import ExploreActionButtons from './ExploreActionButtons';
import RowCountLabel from './RowCountLabel';
import EditableTitle from '../../components/EditableTitle';
import AlteredSliceTag from '../../components/AlteredSliceTag';
import FaveStar from '../../components/FaveStar';
Expand Down Expand Up @@ -66,11 +67,12 @@ class ExploreChartHeader extends React.PureComponent {
}

render() {
const formData = this.props.form_data;
const queryResponse = this.props.chart.queryResponse;
const data = {
csv_endpoint: getExploreUrl(this.props.form_data, 'csv'),
json_endpoint: getExploreUrl(this.props.form_data, 'json'),
standalone_endpoint: getExploreUrl(this.props.form_data, 'standalone'),
csv_endpoint: getExploreUrl(formData, 'csv'),
json_endpoint: getExploreUrl(formData, 'json'),
standalone_endpoint: getExploreUrl(formData, 'standalone'),
};

return (
Expand Down Expand Up @@ -109,13 +111,20 @@ class ExploreChartHeader extends React.PureComponent {
{this.props.chart.sliceFormData &&
<AlteredSliceTag
origFormData={this.props.chart.sliceFormData}
currentFormData={this.props.form_data}
currentFormData={formData}
/>
}
<div className="pull-right">
{this.props.chart.chartStatus === 'success' && queryResponse &&
<RowCountLabel
rowcount={queryResponse.rowcount}
limit={formData.row_limit}
/>
}
{this.props.chart.chartStatus === 'success' &&
queryResponse &&
queryResponse.is_cached &&

<CachedLabel
onClick={this.runQuery.bind(this)}
cachedTimestamp={queryResponse.cached_dttm}
Expand All @@ -133,7 +142,7 @@ class ExploreChartHeader extends React.PureComponent {
canDownload={this.props.can_download}
chartStatus={this.props.chart.chartStatus}
queryResponse={queryResponse}
queryEndpoint={getExploreUrl(this.props.form_data, 'query')}
queryEndpoint={getExploreUrl(formData, 'query')}
/>
</div>
</div>
Expand Down
42 changes: 42 additions & 0 deletions superset/assets/javascripts/explore/components/RowCountLabel.jsx
@@ -0,0 +1,42 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Label } from 'react-bootstrap';

import { t } from '../../locales';
import { defaultNumberFormatter } from '../../modules/utils';
import TooltipWrapper from '../../components/TooltipWrapper';


const propTypes = {
rowcount: PropTypes.number,
limit: PropTypes.number,
};

const defaultProps = {
};

export default function RowCountLabel({ rowcount, limit }) {
const limitReached = rowcount === limit;
const bsStyle = (limitReached || rowcount === 0) ? 'warning' : 'default';
const formattedRowCount = defaultNumberFormatter(rowcount);
const tooltip = (
<span>
{limitReached &&
<div>{t('Limit reached')}</div>}
{rowcount}
</span>
);
return (
<TooltipWrapper label="tt-rowcount" tooltip={tooltip}>
<Label
bsStyle={bsStyle}
style={{ fontSize: '10px', marginRight: '5px', cursor: 'pointer' }}
>
{formattedRowCount} rows
</Label>
</TooltipWrapper>
);
}

RowCountLabel.propTypes = propTypes;
RowCountLabel.defaultProps = defaultProps;
13 changes: 12 additions & 1 deletion superset/assets/javascripts/modules/utils.js
Expand Up @@ -4,6 +4,17 @@ import $ from 'jquery';

import { formatDate, UTC } from './dates';

const siFormatter = d3.format('.3s');

export function defaultNumberFormatter(n) {
let si = siFormatter(n);
// Removing trailing `.00` if any
if (si.slice(-1) < 'A') {
si = parseFloat(si).toString();
}
return si;
}

export function d3FormatPreset(format) {
// like d3.format, but with support for presets like 'smart_date'
if (format === 'smart_date') {
Expand All @@ -12,7 +23,7 @@ export function d3FormatPreset(format) {
if (format) {
return d3.format(format);
}
return d3.format('.3s');
return defaultNumberFormatter;
}
export const d3TimeFormatPreset = function (format) {
const effFormat = format || 'smart_date';
Expand Down
@@ -0,0 +1,33 @@
import React from 'react';
import { expect } from 'chai';
import { describe, it } from 'mocha';
import { shallow } from 'enzyme';
import { Label } from 'react-bootstrap';

import TooltipWrapper from './../../../../javascripts/components/TooltipWrapper';

import RowCountLabel from '../../../../javascripts/explore/components/RowCountLabel';

describe('RowCountLabel', () => {
const defaultProps = {
rowcount: 51,
limit: 100,
};

it('is valid', () => {
expect(React.isValidElement(<RowCountLabel {...defaultProps} />)).to.equal(true);
});
it('renders a Label and a TooltipWrapper', () => {
const wrapper = shallow(<RowCountLabel {...defaultProps} />);
expect(wrapper.find(Label)).to.have.lengthOf(1);
expect(wrapper.find(TooltipWrapper)).to.have.lengthOf(1);
});
it('renders a warning when limit is reached', () => {
const props = {
rowcount: 100,
limit: 100,
};
const wrapper = shallow(<RowCountLabel {...props} />);
expect(wrapper.find(Label).first().props().bsStyle).to.equal('warning');
});
});
19 changes: 18 additions & 1 deletion superset/assets/spec/javascripts/modules/utils_spec.jsx
Expand Up @@ -2,7 +2,7 @@ import { it, describe } from 'mocha';
import { expect } from 'chai';
import {
tryNumify, slugify, formatSelectOptionsForRange, d3format,
d3FormatPreset, d3TimeFormatPreset,
d3FormatPreset, d3TimeFormatPreset, defaultNumberFormatter,
} from '../../../javascripts/modules/utils';

describe('utils', () => {
Expand Down Expand Up @@ -52,4 +52,21 @@ describe('utils', () => {
expect(d3FormatPreset('smart_date')(0)).to.equal('1970');
});
});
describe('d3TimeFormatPreset', () => {
expect(defaultNumberFormatter(10)).to.equal('10');
expect(defaultNumberFormatter(1)).to.equal('1');
expect(defaultNumberFormatter(1.0)).to.equal('1');
expect(defaultNumberFormatter(10.0)).to.equal('10');
expect(defaultNumberFormatter(10001)).to.equal('10.0k');
expect(defaultNumberFormatter(111000000)).to.equal('111M');
expect(defaultNumberFormatter(0.23)).to.equal('230m');

expect(defaultNumberFormatter(-10)).to.equal('-10');
expect(defaultNumberFormatter(-1)).to.equal('-1');
expect(defaultNumberFormatter(-1.0)).to.equal('-1');
expect(defaultNumberFormatter(-10.0)).to.equal('-10');
expect(defaultNumberFormatter(-10001)).to.equal('-10.0k');
expect(defaultNumberFormatter(-111000000)).to.equal('-111M');
expect(defaultNumberFormatter(-0.23)).to.equal('-230m');
});
});
3 changes: 3 additions & 0 deletions superset/viz.py
Expand Up @@ -273,11 +273,13 @@ def get_payload(self, force=False):
cache_timeout = self.cache_timeout
stacktrace = None
annotations = []
rowcount = None
try:
df = self.get_df()
if not self.error_message:
data = self.get_data(df)
annotations = self.get_annotations()
rowcount = len(df.index)
except Exception as e:
logging.exception(e)
if not self.error_message:
Expand All @@ -295,6 +297,7 @@ def get_payload(self, force=False):
'status': self.status,
'stacktrace': stacktrace,
'annotations': annotations,
'rowcount': rowcount,
}
payload['cached_dttm'] = datetime.utcnow().isoformat().split('.')[0]
logging.info('Caching for the next {} seconds'.format(
Expand Down

0 comments on commit c4a7ae2

Please sign in to comment.