chore(superset-ui): clean up legacy-plugin-chart-time-table (#17626)

This commit is contained in:
Jesse Yang 2021-12-02 17:14:10 -08:00 committed by GitHub
parent 13e19291f2
commit 73e7928c4b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 4 additions and 1269 deletions

View File

@ -1,74 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
/* eslint-disable no-magic-numbers */
import React from 'react';
import { SuperChart } from '@superset-ui/core';
import TimeTableChartPlugin from '@superset-ui/legacy-plugin-chart-time-table';
import data from './data';
new TimeTableChartPlugin().configure({ key: 'time-table' }).register();
export default {
title: 'Legacy Chart Plugins/legacy-plugin-chart-time-table',
};
export const basic = () => (
<SuperChart
chartType="time-table"
width={400}
height={400}
queriesData={[
{
data: {
columns: [
'East Asia & Pacific',
'Latin America & Caribbean',
'Middle East & North Africa',
'Sub-Saharan Africa',
],
records: data,
},
},
]}
formData={{
adhocFilters: [],
groupby: ['region'],
columnCollection: [
{
bounds: [null, null],
colType: 'spark',
comparisonType: '',
d3format: '',
dateFormat: '',
height: '',
key: '0vFMepUDf',
label: 'Time Series Columns',
showYAxis: false,
timeLag: 0,
timeRatio: '',
tooltip: '',
width: '',
yAxisBounds: [null, null],
},
],
vizType: 'time-table',
}}
/>
);

View File

@ -1,230 +0,0 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
export default {
'1980-01-01 00:00:00': {
'East Asia & Pacific': 99,
'Latin America & Caribbean': 99,
'Middle East & North Africa': 88,
'Sub-Saharan Africa': 92,
},
'1981-01-01 00:00:00': {
'East Asia & Pacific': 99,
'Latin America & Caribbean': 98,
'Middle East & North Africa': 80,
'Sub-Saharan Africa': 96,
},
'1982-01-01 00:00:00': {
'East Asia & Pacific': 99,
'Latin America & Caribbean': 99,
'Middle East & North Africa': 89,
'Sub-Saharan Africa': 94,
},
'1983-01-01 00:00:00': {
'East Asia & Pacific': 99,
'Latin America & Caribbean': 99,
'Middle East & North Africa': 88,
'Sub-Saharan Africa': 98,
},
'1984-01-01 00:00:00': {
'East Asia & Pacific': 97,
'Latin America & Caribbean': 99,
'Middle East & North Africa': 91,
'Sub-Saharan Africa': 98,
},
'1985-01-01 00:00:00': {
'East Asia & Pacific': 99,
'Latin America & Caribbean': 99,
'Middle East & North Africa': 94,
'Sub-Saharan Africa': 97,
},
'1986-01-01 00:00:00': {
'East Asia & Pacific': 99,
'Latin America & Caribbean': 99,
'Middle East & North Africa': 98,
'Sub-Saharan Africa': 99,
},
'1987-01-01 00:00:00': {
'East Asia & Pacific': 98,
'Latin America & Caribbean': 98,
'Middle East & North Africa': 99,
'Sub-Saharan Africa': 99,
},
'1988-01-01 00:00:00': {
'East Asia & Pacific': 99,
'Latin America & Caribbean': 99,
'Middle East & North Africa': 98,
'Sub-Saharan Africa': 99,
},
'1989-01-01 00:00:00': {
'East Asia & Pacific': 99,
'Latin America & Caribbean': 99,
'Middle East & North Africa': 98,
'Sub-Saharan Africa': 99,
},
'1990-01-01 00:00:00': {
'East Asia & Pacific': 99,
'Latin America & Caribbean': 99,
'Middle East & North Africa': 99,
'Sub-Saharan Africa': 99,
},
'1991-01-01 00:00:00': {
'East Asia & Pacific': 99,
'Latin America & Caribbean': 99,
'Middle East & North Africa': 98,
'Sub-Saharan Africa': 99,
},
'1992-01-01 00:00:00': {
'East Asia & Pacific': 99,
'Latin America & Caribbean': 99,
'Middle East & North Africa': 99,
'Sub-Saharan Africa': 99,
},
'1993-01-01 00:00:00': {
'East Asia & Pacific': 99,
'Latin America & Caribbean': 99,
'Middle East & North Africa': 99,
'Sub-Saharan Africa': 99,
},
'1994-01-01 00:00:00': {
'East Asia & Pacific': 99,
'Latin America & Caribbean': 99,
'Middle East & North Africa': 99,
'Sub-Saharan Africa': 99,
},
'1995-01-01 00:00:00': {
'East Asia & Pacific': 99,
'Latin America & Caribbean': 99,
'Middle East & North Africa': 99,
'Sub-Saharan Africa': 99,
},
'1996-01-01 00:00:00': {
'East Asia & Pacific': 99,
'Latin America & Caribbean': 99,
'Middle East & North Africa': 98,
'Sub-Saharan Africa': 99,
},
'1997-01-01 00:00:00': {
'East Asia & Pacific': 99,
'Latin America & Caribbean': 99,
'Middle East & North Africa': 99,
'Sub-Saharan Africa': 99,
},
'1998-01-01 00:00:00': {
'East Asia & Pacific': 99,
'Latin America & Caribbean': 99,
'Middle East & North Africa': 99,
'Sub-Saharan Africa': 99,
},
'1999-01-01 00:00:00': {
'East Asia & Pacific': 99,
'Latin America & Caribbean': 99,
'Middle East & North Africa': 99,
'Sub-Saharan Africa': 99,
},
'2000-01-01 00:00:00': {
'East Asia & Pacific': 99,
'Latin America & Caribbean': 99,
'Middle East & North Africa': 99,
'Sub-Saharan Africa': 99,
},
'2001-01-01 00:00:00': {
'East Asia & Pacific': 99,
'Latin America & Caribbean': 99,
'Middle East & North Africa': 99,
'Sub-Saharan Africa': 99,
},
'2002-01-01 00:00:00': {
'East Asia & Pacific': 99,
'Latin America & Caribbean': 99,
'Middle East & North Africa': 99,
'Sub-Saharan Africa': 99,
},
'2003-01-01 00:00:00': {
'East Asia & Pacific': 99,
'Latin America & Caribbean': 99,
'Middle East & North Africa': 99,
'Sub-Saharan Africa': 99,
},
'2004-01-01 00:00:00': {
'East Asia & Pacific': 99,
'Latin America & Caribbean': 99,
'Middle East & North Africa': 99,
'Sub-Saharan Africa': 99,
},
'2005-01-01 00:00:00': {
'East Asia & Pacific': 99,
'Latin America & Caribbean': 99,
'Middle East & North Africa': 99,
'Sub-Saharan Africa': 99,
},
'2006-01-01 00:00:00': {
'East Asia & Pacific': 99,
'Latin America & Caribbean': 99,
'Middle East & North Africa': 99,
'Sub-Saharan Africa': 99,
},
'2007-01-01 00:00:00': {
'East Asia & Pacific': 99,
'Latin America & Caribbean': 99,
'Middle East & North Africa': 99,
'Sub-Saharan Africa': 99,
},
'2008-01-01 00:00:00': {
'East Asia & Pacific': 99,
'Latin America & Caribbean': 99,
'Middle East & North Africa': 99,
'Sub-Saharan Africa': 99,
},
'2009-01-01 00:00:00': {
'East Asia & Pacific': 99,
'Latin America & Caribbean': 99,
'Middle East & North Africa': 99,
'Sub-Saharan Africa': 99,
},
'2010-01-01 00:00:00': {
'East Asia & Pacific': 99,
'Latin America & Caribbean': 99,
'Middle East & North Africa': 99,
'Sub-Saharan Africa': 99,
},
'2011-01-01 00:00:00': {
'East Asia & Pacific': 99,
'Latin America & Caribbean': 99,
'Middle East & North Africa': 99,
'Sub-Saharan Africa': 99,
},
'2012-01-01 00:00:00': {
'East Asia & Pacific': 99,
'Latin America & Caribbean': 99,
'Middle East & North Africa': 99,
'Sub-Saharan Africa': 99,
},
'2013-01-01 00:00:00': {
'East Asia & Pacific': 99,
'Latin America & Caribbean': 99,
'Middle East & North Africa': 99,
'Sub-Saharan Africa': 99,
},
'2014-01-01 00:00:00': {
'East Asia & Pacific': 99,
'Latin America & Caribbean': 99,
'Middle East & North Africa': 99,
'Sub-Saharan Africa': 99,
},
};

View File

@ -1,43 +0,0 @@
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
# Change Log
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [0.18.0](https://github.com/apache-superset/superset-ui/compare/v0.17.87...v0.18.0) (2021-08-30)
**Note:** Version bump only for package @superset-ui/legacy-plugin-chart-time-table
## [0.17.63](https://github.com/apache-superset/superset-ui/compare/v0.17.62...v0.17.63) (2021-07-02)
**Note:** Version bump only for package @superset-ui/legacy-plugin-chart-time-table
## [0.17.61](https://github.com/apache-superset/superset-ui/compare/v0.17.60...v0.17.61) (2021-07-02)
**Note:** Version bump only for package @superset-ui/legacy-plugin-chart-time-table

View File

@ -1,52 +0,0 @@
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
## @superset-ui/plugin-chart-time-table
[![Version](https://img.shields.io/npm/v/@superset-ui/plugin-time-table.svg?style=flat-square)](https://www.npmjs.com/package/@superset-ui/plugin-chart-time-table)
[![David (path)](https://img.shields.io/david/apache-superset/superset-ui-plugins.svg?path=packages%2Fsuperset-ui-plugin-chart-time-table&style=flat-square)](https://david-dm.org/apache-superset/superset-ui-plugins?path=packages/superset-ui-plugin-chart-time-table)
This plugin provides Time Table for Superset.
### Usage
Configure `key`, which can be any `string`, and register the plugin. This `key` will be used to
lookup this chart throughout the app.
```js
import TimeTableChartPlugin from '@superset-ui/legacy-plugin-chart-time-table';
new TimeTableChartPlugin().configure({ key: 'time-table' }).register();
```
Then use it via `SuperChart`. See
[storybook](https://apache-superset.github.io/superset-ui-plugins/?selectedKind=plugin-chart-time-table)
for more details.
```js
<SuperChart
chartType="time-table"
width={600}
height={600}
formData={...}
queriesData={[{
data: {...},
}]}
/>
```

View File

@ -1,45 +0,0 @@
{
"name": "@superset-ui/legacy-plugin-chart-time-table",
"version": "0.18.25",
"description": "Superset Chart Plugin - Time Table",
"sideEffects": [
"*.css"
],
"main": "lib/index.js",
"module": "esm/index.js",
"files": [
"esm",
"lib"
],
"repository": {
"type": "git",
"url": "git+https://github.com/apache-superset/superset-ui.git"
},
"keywords": [
"superset"
],
"author": "Superset",
"license": "Apache-2.0",
"bugs": {
"url": "https://github.com/apache-superset/superset-ui/issues"
},
"homepage": "https://github.com/apache-superset/superset-ui#readme",
"publishConfig": {
"access": "public"
},
"dependencies": {
"@data-ui/sparkline": "^0.0.84",
"@superset-ui/chart-controls": "0.18.25",
"@superset-ui/core": "0.18.25",
"@types/d3-scale": "^2.0.2",
"d3-scale": "^3.2.1",
"moment": "^2.26.0",
"mustache": "^4.0.1",
"prop-types": "^15.7.2",
"reactable-arc": "^0.15.0"
},
"peerDependencies": {
"@types/react": "*",
"react": "^16.3.1"
}
}

View File

@ -1,34 +0,0 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import React from 'react';
import { formatNumber } from '@superset-ui/core';
interface Props {
format: string;
num: number;
}
function FormattedNumber({ num = 0, format = '' }: Props) {
if (format) {
return <span title={num.toString()}>{formatNumber(format, num)}</span>;
}
return <span>{num}</span>;
}
export default FormattedNumber;

View File

@ -1,330 +0,0 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import React from 'react';
import Mustache from 'mustache';
import { scaleLinear } from 'd3-scale';
import { Table, Thead, Th, Tr, Td } from 'reactable-arc';
import { formatNumber, formatTime, styled } from '@superset-ui/core';
import {
InfoTooltipWithTrigger,
MetricOption,
} from '@superset-ui/chart-controls';
import moment from 'moment';
import FormattedNumber from './FormattedNumber';
import SparklineCell from './SparklineCell';
const ACCESSIBLE_COLOR_BOUNDS = ['#ca0020', '#0571b0'];
interface ColorFromBoundProps {
value: number;
bounds: Array<string>;
colorBounds: Array<string>;
}
function colorFromBounds(
value: number,
bounds: number[],
colorBounds = ACCESSIBLE_COLOR_BOUNDS,
): ColorFromBoundProps | null {
if (bounds) {
const [min, max] = bounds;
const [minColor, maxColor] = colorBounds;
if (min !== null && max !== null) {
const colorScale = scaleLinear()
.domain([min, (max + min) / 2, max])
// @ts-ignore
.range([minColor, 'grey', maxColor]);
// @ts-ignore
return colorScale(value);
}
if (min !== null) {
// @ts-ignore
return value >= min ? maxColor : minColor;
}
if (max !== null) {
// @ts-ignore
return value < max ? maxColor : minColor;
}
}
return null;
}
interface ColumnConfigProps {
colType: string;
comparisonType: string;
d3format: string;
key: string;
label: string;
timeLag: number;
tooltip: any;
bounds: number[];
dateFormat: string;
width: string;
height: string;
yAxisBounds: number[];
showYAxis: boolean;
timeRatio: number;
}
interface RowData {
label: string;
// eslint-disable-next-line camelcase
metric_name: string;
}
interface ChartProps {
className: string | undefined;
columnConfigs: Array<ColumnConfigProps>;
data: object;
height: number;
rows: Array<RowData>;
rowType: string;
url: string;
row: Array<unknown>;
}
interface Entry {
[key: string]: number;
}
class TimeTable extends React.PureComponent<ChartProps, {}> {
renderLeftCell(row: RowData) {
const { rowType, url } = this.props;
const context = { metric: row };
const fullUrl = url ? Mustache.render(url, context) : null;
if (rowType === 'column') {
const column = row;
if (fullUrl) {
return (
<a href={fullUrl} rel="noopener noreferrer" target="_blank">
{column.label}
</a>
);
}
return column.label;
}
return (
<MetricOption
openInNewWindow
metric={row}
url={fullUrl}
showFormula={false}
/>
);
}
// eslint-disable-next-line class-methods-use-this
renderSparklineCell(
valueField: string,
column: ColumnConfigProps,
entries: Entry[],
) {
let sparkData: number[];
if (column.timeRatio) {
// Period ratio sparkline
sparkData = [];
for (let i = column.timeRatio; i < entries.length; i += 1) {
const prevData = entries[i - column.timeRatio][valueField];
if (prevData && prevData !== 0) {
sparkData.push(entries[i][valueField] / prevData);
} else {
// @ts-ignore
sparkData.push(null);
}
}
} else {
sparkData = entries.map(d => d[valueField]);
}
return (
<Td
key={column.key}
column={column.key}
value={sparkData[sparkData.length - 1]}
>
<SparklineCell
width={parseInt(column.width, 10) || 300}
height={parseInt(column.height, 10) || 50}
data={sparkData}
ariaLabel={`spark-${valueField}`}
numberFormat={column.d3format}
yAxisBounds={column.yAxisBounds}
showYAxis={column.showYAxis}
renderTooltip={({ index }: { index: number }) => (
<div>
<strong>{formatNumber(column.d3format, sparkData[index])}</strong>
<div>
{formatTime(
column.dateFormat,
moment.utc(entries[index].time).toDate(),
)}
</div>
</div>
)}
/>
</Td>
);
}
// eslint-disable-next-line class-methods-use-this
renderValueCell(
valueField: string,
column: ColumnConfigProps,
reversedEntries: Entry[],
) {
const recent = reversedEntries[0][valueField];
let v = 0;
let errorMsg;
if (column.colType === 'time') {
// Time lag ratio
const timeLag = column.timeLag || 0;
const totalLag = Object.keys(reversedEntries).length;
if (timeLag >= totalLag) {
errorMsg = `The time lag set at ${timeLag} is too large for the length of data at ${reversedEntries.length}. No data available.`;
} else {
v = reversedEntries[timeLag][valueField];
}
if (column.comparisonType === 'diff') {
v = recent - v;
} else if (column.comparisonType === 'perc') {
v = recent / v;
} else if (column.comparisonType === 'perc_change') {
v = recent / v - 1;
}
v = v || 0;
} else if (column.colType === 'contrib') {
// contribution to column total
v =
recent /
Object.keys(reversedEntries[0])
.map(k => (k === 'time' ? 0 : reversedEntries[0][k]))
.reduce((a, b) => a + b);
} else if (column.colType === 'avg') {
// Average over the last {timeLag}
v =
reversedEntries
.map((k: Entry, i: number) =>
i < column.timeLag ? k[valueField] : 0,
)
.reduce((a: number, b: number) => a + b) / column.timeLag;
}
const color = colorFromBounds(v, column.bounds);
return (
<Td
key={column.key}
column={column.key}
value={v}
style={
color && {
boxShadow: `inset 0px -2.5px 0px 0px ${color}`,
borderRight: '2px solid #fff',
}
}
>
{errorMsg ? (
<div>{errorMsg}</div>
) : (
// @ts-ignore
<div style={{ color }}>
<FormattedNumber num={v} format={column.d3format} />
</div>
)}
</Td>
);
}
renderRow(row: RowData, entries: Entry[], reversedEntries: Entry[]) {
const { columnConfigs } = this.props;
const valueField: string = row.label || row.metric_name;
const leftCell = this.renderLeftCell(row);
return (
<Tr key={leftCell}>
<Td column="metric" data={leftCell}>
{leftCell}
</Td>
{columnConfigs.map(c =>
c.colType === 'spark'
? this.renderSparklineCell(valueField, c, entries)
: this.renderValueCell(valueField, c, reversedEntries),
)}
</Tr>
);
}
render() {
const { className, height, data, columnConfigs, rowType, rows } =
this.props;
const entries = Object.keys(data)
.sort()
// @ts-ignore
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
.map(time => ({ ...data[time], time }));
const reversedEntries = entries.concat().reverse();
const defaultSort =
rowType === 'column' && columnConfigs.length > 0
? {
column: columnConfigs[0].key,
direction: 'desc',
}
: false;
return (
<div className={`time-table ${className}`} style={{ height }}>
<Table
className="table table-no-hover"
defaultSort={defaultSort}
sortBy={defaultSort}
sortable={columnConfigs.map(c => c.key)}
>
<Thead>
<Th column="metric">Metric</Th>
{columnConfigs.map((c, i) => (
<Th
key={c.key}
column={c.key}
width={c.colType === 'spark' ? '1%' : null}
>
{c?.label}{' '}
{c?.tooltip && (
<InfoTooltipWithTrigger
tooltip={c?.tooltip}
label={`tt-col-${i}`}
placement="top"
/>
)}
</Th>
))}
</Thead>
{rows.map(row => this.renderRow(row, entries, reversedEntries))}
</Table>
</div>
);
}
}
export default styled(TimeTable)`
.time-table {
overflow: auto;
}
`;

View File

@ -1,39 +0,0 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import { t, ChartMetadata, ChartPlugin } from '@superset-ui/core';
import transformProps from './transformProps';
import thumbnail from './images/thumbnail.png';
const metadata = new ChartMetadata({
name: t('Time-series Table'),
description: '',
thumbnail,
useLegacyApi: true,
});
export default class TimeTableChartPlugin extends ChartPlugin {
constructor() {
super({
metadata,
// @ts-ignore
transformProps,
loadChart: () => import('./TimeTable'),
});
}
}

View File

@ -1,68 +0,0 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import { t, validateNonEmpty } from '@superset-ui/core';
import { ControlPanelConfig, sections } from '@superset-ui/chart-controls';
const config: ControlPanelConfig = {
controlPanelSections: [
sections.legacyTimeseriesTime,
{
label: t('Query'),
expanded: true,
controlSetRows: [
['metrics'],
['adhoc_filters'],
['groupby'],
['limit'],
[
{
name: 'column_collection',
config: {
type: 'CollectionControl',
label: t('Time Series Columns'),
validators: [validateNonEmpty],
controlName: 'TimeSeriesColumnControl',
},
},
],
[
{
name: 'url',
config: {
type: 'TextControl',
label: t('URL'),
description: t(
"Templated link, it's possible to include {{ metric }} " +
'or other values coming from the controls.',
),
default: '',
},
},
],
],
},
],
controlOverrides: {
groupby: {
multiple: false,
},
},
};
export default config;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

View File

@ -1,52 +0,0 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import { t, ChartMetadata, ChartPlugin } from '@superset-ui/core';
import transformProps from './transformProps';
import thumbnail from './images/thumbnail.png';
import controlPanel from './controlPanel';
const metadata = new ChartMetadata({
category: t('Table'),
name: t('Time-series Table'),
description: t(
'Compare multiple time series charts (as sparklines) and related metrics quickly. ',
),
tags: [
t('Multi-Variables'),
t('Comparison'),
t('Legacy'),
t('Percentages'),
t('Tabular'),
t('Description'),
t('Trend'),
],
thumbnail,
useLegacyApi: true,
});
export default class TimeTableChartPlugin extends ChartPlugin {
constructor() {
super({
loadChart: () => import('./TimeTable'),
metadata,
// @ts-ignore
transformProps,
controlPanel,
});
}
}

View File

@ -1,25 +0,0 @@
{
"compilerOptions": {
"declarationDir": "lib",
"outDir": "lib",
"rootDir": "src"
},
"exclude": [
"lib",
"test"
],
"extends": "../../tsconfig.json",
"include": [
"src/**/*",
"types/**/*",
"../../types/**/*"
],
"references": [
{
"path": "../../packages/superset-ui-chart-controls"
},
{
"path": "../../packages/superset-ui-core"
}
]
}

View File

@ -1,203 +0,0 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import React from 'react';
import PropTypes from 'prop-types';
import {
Sparkline,
LineSeries,
PointSeries,
HorizontalReferenceLine,
VerticalReferenceLine,
WithTooltip,
} from '@data-ui/sparkline';
import { getTextDimension, formatNumber } from '@superset-ui/core';
const propTypes = {
className: PropTypes.string,
width: PropTypes.number,
height: PropTypes.number,
data: PropTypes.array.isRequired,
ariaLabel: PropTypes.string,
numberFormat: PropTypes.string,
yAxisBounds: PropTypes.array,
showYAxis: PropTypes.bool,
renderTooltip: PropTypes.func,
};
const defaultProps = {
className: '',
width: 300,
height: 50,
ariaLabel: '',
numberFormat: undefined,
yAxisBounds: [null, null],
showYAxis: false,
renderTooltip() {
return <div />;
},
};
const MARGIN = {
top: 8,
right: 8,
bottom: 8,
left: 8,
};
const tooltipProps = {
style: {
opacity: 0.8,
},
offsetTop: 0,
};
function getSparklineTextWidth(text) {
return (
getTextDimension({
text,
style: {
fontSize: '12px',
fontWeight: 200,
letterSpacing: 0.4,
},
}).width + 5
);
}
function isValidBoundValue(value) {
return (
value !== null &&
value !== undefined &&
value !== '' &&
!Number.isNaN(value)
);
}
class SparklineCell extends React.Component {
renderHorizontalReferenceLine(value, label) {
return (
<HorizontalReferenceLine
reference={value}
labelPosition="right"
renderLabel={() => label}
stroke="#bbb"
strokeDasharray="3 3"
strokeWidth={1}
/>
);
}
render() {
const {
width,
height,
data,
ariaLabel,
numberFormat,
yAxisBounds,
showYAxis,
renderTooltip,
} = this.props;
const yScale = {};
let hasMinBound = false;
let hasMaxBound = false;
if (yAxisBounds) {
const [minBound, maxBound] = yAxisBounds;
hasMinBound = isValidBoundValue(minBound);
if (hasMinBound) {
yScale.min = minBound;
}
hasMaxBound = isValidBoundValue(maxBound);
if (hasMaxBound) {
yScale.max = maxBound;
}
}
let min;
let max;
let minLabel;
let maxLabel;
let labelLength = 0;
if (showYAxis) {
const [minBound, maxBound] = yAxisBounds;
min = hasMinBound
? minBound
: data.reduce((acc, current) => Math.min(acc, current), data[0]);
max = hasMaxBound
? maxBound
: data.reduce((acc, current) => Math.max(acc, current), data[0]);
minLabel = formatNumber(numberFormat, min);
maxLabel = formatNumber(numberFormat, max);
labelLength = Math.max(
getSparklineTextWidth(minLabel),
getSparklineTextWidth(maxLabel),
);
}
const margin = {
...MARGIN,
right: MARGIN.right + labelLength,
};
return (
<WithTooltip
tooltipProps={tooltipProps}
hoverStyles={null}
renderTooltip={renderTooltip}
>
{({ onMouseLeave, onMouseMove, tooltipData }) => (
<Sparkline
ariaLabel={ariaLabel}
width={width}
height={height}
margin={margin}
data={data}
onMouseLeave={onMouseLeave}
onMouseMove={onMouseMove}
{...yScale}
>
{showYAxis && this.renderHorizontalReferenceLine(min, minLabel)}
{showYAxis && this.renderHorizontalReferenceLine(max, maxLabel)}
<LineSeries showArea={false} stroke="#767676" />
{tooltipData && (
<VerticalReferenceLine
reference={tooltipData.index}
strokeDasharray="3 3"
strokeWidth={1}
/>
)}
{tooltipData && (
<PointSeries
points={[tooltipData.index]}
fill="#767676"
strokeWidth={1}
/>
)}
</Sparkline>
)}
</WithTooltip>
);
}
}
SparklineCell.propTypes = propTypes;
SparklineCell.defaultProps = defaultProps;
export default SparklineCell;

View File

@ -1,62 +0,0 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
export default function transformProps(chartProps) {
const { height, datasource, formData, queriesData } = chartProps;
const { columnCollection = [], groupby, metrics, url } = formData;
const { records, columns } = queriesData[0].data;
const isGroupBy = groupby?.length > 0;
// When there is a "group by",
// each row in the table is a database column
// Otherwise,
// each row in the table is a metric
let rows;
if (isGroupBy) {
rows = columns.map(column =>
typeof column === 'object' ? column : { label: column },
);
} else {
const metricMap = datasource.metrics.reduce((acc, current) => {
const map = acc;
map[current.metric_name] = current;
return map;
}, {});
rows = metrics.map(metric =>
typeof metric === 'object' ? metric : metricMap[metric],
);
}
// TODO: Better parse this from controls instead of mutative value here.
columnCollection.forEach(column => {
const c = column;
if (c.timeLag !== undefined && c.timeLag !== null && c.timeLag !== '') {
c.timeLag = parseInt(c.timeLag, 10);
}
});
return {
height,
data: records,
columnConfigs: columnCollection,
rows,
rowType: isGroupBy ? 'column' : 'metric',
url,
};
}

View File

@ -42,14 +42,13 @@ interface ColumnData {
}
export default function transformProps(chartProps: TableChartProps) {
const { height, datasource, formData, queriesData } = chartProps;
const { columnCollection, groupby, metrics, url } = formData;
const { columnCollection = [], groupby, metrics, url } = formData;
const { records, columns } = queriesData[0].data;
const isGroupBy = groupby?.length > 0;
// When there is a "group by",
// each row in the table is a database column
// Otherwise,``
// each row in the table is a metric
// Otherwise each row in the table is a metric
let rows;
if (isGroupBy) {
rows = columns.map(column =>
@ -58,9 +57,7 @@ export default function transformProps(chartProps: TableChartProps) {
} else {
const metricMap = datasource.metrics.reduce((acc, current) => {
const map = acc;
if (current.metric_name) {
map[current.metric_name] = current;
}
return map;
}, {} as Record<string, Metric>);
rows = metrics.map(metric =>

View File

@ -1,4 +1,4 @@
/*
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
@ -16,8 +16,4 @@
* specific language governing permissions and limitations
* under the License.
*/
declare module '*.png';
declare module '@data-ui/sparkline';
declare module 'reactable-arc';
declare module 'mustache';

View File

@ -61,7 +61,6 @@ module.exports = {
'@superset-ui/legacy-plugin-chart-sankey',
'@superset-ui/legacy-plugin-chart-sankey-loop',
'@superset-ui/legacy-plugin-chart-sunburst',
'@superset-ui/legacy-plugin-chart-time-table',
'@superset-ui/legacy-plugin-chart-treemap',
'@superset-ui/legacy-plugin-chart-world-map',
'@superset-ui/legacy-preset-chart-big-number',