diff --git a/superset/assets/javascripts/components/MetricOption.jsx b/superset/assets/javascripts/components/MetricOption.jsx
index d952b06aec..8d27ea4de5 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 ? {verbose} : verbose;
+ const link = url ? {verbose} : verbose;
return (
{link}
diff --git a/superset/assets/javascripts/modules/dates.js b/superset/assets/javascripts/modules/dates.js
index 2c2815e8a1..88b62c5890 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 62ae28cc00..6f6068d6e5 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 952e9fa125..4eeb13ed1f 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 f99482d8eb..11d7be1160 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
{num};
}
+
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 =
;
+ leftCell = (
+
+ );
} else {
- leftCell = url ?
{metric} : metric;
+ leftCell = url ?
{metric} : 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: (
-
-
+
(
+
+
{d3format(c.d3format, data[index][metric])}
+
{formatDate(data[index].iso)}
+
+ )}
+ >
+ {({ onMouseLeave, onMouseMove, tooltipData }) => (
+ {tooltipData &&
+ }
+ {tooltipData &&
+ }
-
- ),
+ )}
+
+ ),
};
} else {
const recent = reversedData[0][metric];
diff --git a/superset/assets/webpack.config.js b/superset/assets/webpack.config.js
index 952f733263..bb1729c144 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: [