You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@superset.apache.org by gr...@apache.org on 2017/11/03 19:37:18 UTC

[incubator-superset] branch master updated: [time table] add tooltip to sparkline (#3767)

This is an automated email from the ASF dual-hosted git repository.

graceguo pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-superset.git


The following commit(s) were added to refs/heads/master by this push:
     new 7f3edad  [time table] add tooltip to sparkline (#3767)
7f3edad is described below

commit 7f3edad1192d282aa025863edb4292cc86e17a14
Author: Chris Williams <wi...@users.noreply.github.com>
AuthorDate: Fri Nov 3 12:37:15 2017 -0700

    [time table] add tooltip to sparkline (#3767)
    
    * [time table] add tooltip to sparkline
    
    * [time table] open link in new tab
    
    * [time table] add back Mustache
---
 .../assets/javascripts/components/MetricOption.jsx |  5 +-
 superset/assets/javascripts/modules/dates.js       |  1 -
 superset/assets/package.json                       |  2 +-
 .../javascripts/components/MetricOption_spec.jsx   |  9 +++
 superset/assets/visualizations/time_table.jsx      | 71 ++++++++++++++--------
 superset/assets/webpack.config.js                  |  2 +-
 6 files changed, 58 insertions(+), 32 deletions(-)

diff --git a/superset/assets/javascripts/components/MetricOption.jsx b/superset/assets/javascripts/components/MetricOption.jsx
index d952b06..8d27ea4 100644
--- a/superset/assets/javascripts/components/MetricOption.jsx
+++ b/superset/assets/javascripts/components/MetricOption.jsx
@@ -5,6 +5,7 @@ import InfoTooltipWithTrigger from './InfoTooltipWithTrigger';
 
 const propTypes = {
   metric: PropTypes.object.isRequired,
+  openInNewWindow: PropTypes.bool,
   showFormula: PropTypes.bool,
   url: PropTypes.string,
 };
@@ -12,9 +13,9 @@ const defaultProps = {
   showFormula: true,
 };
 
-export default function MetricOption({ metric, showFormula, url }) {
+export default function MetricOption({ metric, openInNewWindow, showFormula, url }) {
   const verbose = metric.verbose_name || metric.metric_name;
-  const link = url ? <a href={url}>{verbose}</a> : verbose;
+  const link = url ? <a href={url} target={openInNewWindow ? '_blank' : null}>{verbose}</a> : verbose;
   return (
     <div>
       <span className="m-r-5 option-label">{link}</span>
diff --git a/superset/assets/javascripts/modules/dates.js b/superset/assets/javascripts/modules/dates.js
index 2c2815e..88b62c5 100644
--- a/superset/assets/javascripts/modules/dates.js
+++ b/superset/assets/javascripts/modules/dates.js
@@ -64,7 +64,6 @@ export const tickMultiFormat = d3.time.format.multi([
 ]);
 export const formatDate = function (dttm) {
   const d = UTC(new Date(dttm));
-  // d = new Date(d.getTime() - 1 * 60 * 60 * 1000);
   return tickMultiFormat(d);
 };
 export const fDuration = function (t1, t2, f = 'HH:mm:ss.SS') {
diff --git a/superset/assets/package.json b/superset/assets/package.json
index 62ae28c..6f6068d 100644
--- a/superset/assets/package.json
+++ b/superset/assets/package.json
@@ -40,7 +40,7 @@
   "homepage": "http://superset.apache.org/",
   "dependencies": {
     "@data-ui/event-flow": "0.0.8",
-    "@data-ui/sparkline": "0.0.1",
+    "@data-ui/sparkline": "0.0.47",
     "babel-register": "^6.24.1",
     "bootstrap": "^3.3.6",
     "brace": "^0.10.0",
diff --git a/superset/assets/spec/javascripts/components/MetricOption_spec.jsx b/superset/assets/spec/javascripts/components/MetricOption_spec.jsx
index 952e9fa..4eeb13e 100644
--- a/superset/assets/spec/javascripts/components/MetricOption_spec.jsx
+++ b/superset/assets/spec/javascripts/components/MetricOption_spec.jsx
@@ -50,4 +50,13 @@ describe('MetricOption', () => {
     wrapper = shallow(factory(props));
     expect(wrapper.find(InfoTooltipWithTrigger)).to.have.length(1);
   });
+  it('sets target="_blank" when openInNewWindow is true', () => {
+    props.url = 'https://github.com/apache/incubator-superset';
+    wrapper = shallow(factory(props));
+    expect(wrapper.find('a').prop('target')).to.equal(null);
+
+    props.openInNewWindow = true;
+    wrapper = shallow(factory(props));
+    expect(wrapper.find('a').prop('target')).to.equal('_blank');
+  });
 });
diff --git a/superset/assets/visualizations/time_table.jsx b/superset/assets/visualizations/time_table.jsx
index f99482d..11d7be1 100644
--- a/superset/assets/visualizations/time_table.jsx
+++ b/superset/assets/visualizations/time_table.jsx
@@ -3,16 +3,21 @@ import React from 'react';
 import propTypes from 'prop-types';
 import { Table, Thead, Th, Tr, Td } from 'reactable';
 import d3 from 'd3';
-import { Sparkline, LineSeries } from '@data-ui/sparkline';
 import Mustache from 'mustache';
+import { Sparkline, LineSeries, PointSeries, VerticalReferenceLine, WithTooltip } from '@data-ui/sparkline';
 
 import MetricOption from '../javascripts/components/MetricOption';
-import TooltipWrapper from '../javascripts/components/TooltipWrapper';
 import { d3format, brandColor } from '../javascripts/modules/utils';
+import { formatDate } from '../javascripts/modules/dates';
 import InfoTooltipWithTrigger from '../javascripts/components/InfoTooltipWithTrigger';
 import './time_table.css';
 
-const SPARK_MARGIN = 3;
+const SPARKLINE_MARGIN = {
+  top: 8,
+  right: 8,
+  bottom: 8,
+  left: 8,
+};
 const ACCESSIBLE_COLOR_BOUNDS = ['#ca0020', '#0571b0'];
 
 function FormattedNumber({ num, format }) {
@@ -23,6 +28,7 @@ function FormattedNumber({ num, format }) {
   }
   return <span>{num}</span>;
 }
+
 FormattedNumber.propTypes = {
   num: propTypes.number,
   format: propTypes.string,
@@ -30,14 +36,10 @@ FormattedNumber.propTypes = {
 
 function viz(slice, payload) {
   slice.container.css('height', slice.height());
-  const recs = payload.data.records;
+  const records = payload.data.records;
   const fd = payload.form_data;
-  const data = Object.keys(recs).sort().map((iso) => {
-    const o = recs[iso];
-    return o;
-  });
-  const reversedData = data.slice();
-  reversedData.reverse();
+  const data = Object.keys(records).sort().map(iso => ({ ...records[iso], iso }));
+  const reversedData = [...data].reverse();
   const metricMap = {};
   slice.datasource.metrics.forEach((m) => {
     metricMap[m.metric_name] = m;
@@ -53,13 +55,14 @@ function viz(slice, payload) {
   }
   const tableData = metrics.map((metric) => {
     let leftCell;
-    const context = Object.assign({}, fd, { metric });
+    const context = { ...fd, metric };
     const url = fd.url ? Mustache.render(fd.url, context) : null;
-
     if (!payload.data.is_group_by) {
-      leftCell = <MetricOption metric={metricMap[metric]} url={url}showFormula={false} />;
+      leftCell = (
+        <MetricOption metric={metricMap[metric]} url={url} showFormula={false} openInNewWindow />
+      );
     } else {
-      leftCell = url ? <a href={url}>{metric}</a> : metric;
+      leftCell = url ? <a href={url} target="_blank">{metric}</a> : metric;
     }
     const row = { metric: leftCell };
     fd.column_collection.forEach((c) => {
@@ -79,33 +82,47 @@ function viz(slice, payload) {
             }
           }
         }
-        const extent = d3.extent(sparkData);
-        const tooltip = `min: ${d3format(c.d3format, extent[0])}, \
-          max: ${d3format(c.d3format, extent[1])}`;
         row[c.key] = {
           data: sparkData[sparkData.length - 1],
           display: (
-            <TooltipWrapper label="tt-spark" tooltip={tooltip}>
-              <div>
+            <WithTooltip
+              renderTooltip={({ index }) => (
+                <div style={{ minWidth: 140 }}>
+                  <strong>{d3format(c.d3format, data[index][metric])}</strong>
+                  <div>{formatDate(data[index].iso)}</div>
+                </div>
+              )}
+            >
+              {({ onMouseLeave, onMouseMove, tooltipData }) => (
                 <Sparkline
                   ariaLabel={`spark-${metric}`}
                   width={parseInt(c.width, 10) || 300}
                   height={parseInt(c.height, 10) || 50}
-                  margin={{
-                    top: SPARK_MARGIN,
-                    bottom: SPARK_MARGIN,
-                    left: SPARK_MARGIN,
-                    right: SPARK_MARGIN,
-                  }}
+                  margin={SPARKLINE_MARGIN}
                   data={sparkData}
+                  onMouseLeave={onMouseLeave}
+                  onMouseMove={onMouseMove}
                 >
                   <LineSeries
                     showArea={false}
                     stroke={brandColor}
                   />
+                  {tooltipData &&
+                    <VerticalReferenceLine
+                      reference={tooltipData.index}
+                      strokeDasharray="3 3"
+                      strokeWidth={1}
+                    />}
+                  {tooltipData &&
+                    <PointSeries
+                      points={[tooltipData.index]}
+                      fill={brandColor}
+                      strokeWidth={1}
+                    />}
                 </Sparkline>
-              </div>
-            </TooltipWrapper>),
+              )}
+            </WithTooltip>
+          ),
         };
       } else {
         const recent = reversedData[0][metric];
diff --git a/superset/assets/webpack.config.js b/superset/assets/webpack.config.js
index 952f733..bb1729c 100644
--- a/superset/assets/webpack.config.js
+++ b/superset/assets/webpack.config.js
@@ -47,7 +47,7 @@ const config = {
       },
       {
         test: /\.jsx?$/,
-        exclude: APP_DIR + '/node_modules',
+        exclude: /node_modules/,
         loader: 'babel-loader',
         query: {
           presets: [

-- 
To stop receiving notification emails like this one, please contact
['"commits@superset.apache.org" <co...@superset.apache.org>'].