mistercrunch closed pull request #4059: [explore] add row count label to 
explore view header
URL: https://github.com/apache/incubator-superset/pull/4059
 
 
   

This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:

As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):

diff --git 
a/superset/assets/javascripts/explore/components/ExploreChartHeader.jsx 
b/superset/assets/javascripts/explore/components/ExploreChartHeader.jsx
index b8b52e36fd..30b47994eb 100644
--- a/superset/assets/javascripts/explore/components/ExploreChartHeader.jsx
+++ b/superset/assets/javascripts/explore/components/ExploreChartHeader.jsx
@@ -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';
@@ -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 (
@@ -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}
@@ -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>
diff --git a/superset/assets/javascripts/explore/components/RowCountLabel.jsx 
b/superset/assets/javascripts/explore/components/RowCountLabel.jsx
new file mode 100644
index 0000000000..1b29a0309e
--- /dev/null
+++ b/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;
diff --git a/superset/assets/javascripts/modules/utils.js 
b/superset/assets/javascripts/modules/utils.js
index e7757d4b06..b5590f0e79 100644
--- a/superset/assets/javascripts/modules/utils.js
+++ b/superset/assets/javascripts/modules/utils.js
@@ -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') {
@@ -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';
diff --git 
a/superset/assets/spec/javascripts/explore/components/RowCountLabel_spec.jsx 
b/superset/assets/spec/javascripts/explore/components/RowCountLabel_spec.jsx
new file mode 100644
index 0000000000..1642fd7df6
--- /dev/null
+++ b/superset/assets/spec/javascripts/explore/components/RowCountLabel_spec.jsx
@@ -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');
+  });
+});
diff --git a/superset/assets/spec/javascripts/modules/utils_spec.jsx 
b/superset/assets/spec/javascripts/modules/utils_spec.jsx
index 1e3f2d4007..174e0e1e61 100644
--- a/superset/assets/spec/javascripts/modules/utils_spec.jsx
+++ b/superset/assets/spec/javascripts/modules/utils_spec.jsx
@@ -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', () => {
@@ -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');
+  });
 });
diff --git a/superset/viz.py b/superset/viz.py
index 0eeed238b6..a5040b2df0 100644
--- a/superset/viz.py
+++ b/superset/viz.py
@@ -272,11 +272,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:
@@ -294,6 +296,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(


 

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
[email protected]


With regards,
Apache Git Services

Reply via email to