mirror of
https://github.com/apache/superset.git
synced 2026-04-18 23:55:00 +00:00
fix(plugin-chart-period-over-period-kpi): Blank chart when switching from BigNumberTotal (#27203)
This commit is contained in:
committed by
GitHub
parent
f1cd8cc263
commit
54037972f2
@@ -0,0 +1,188 @@
|
||||
/**
|
||||
* 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, { createRef, useMemo } from 'react';
|
||||
import { css, styled, t, useTheme } from '@superset-ui/core';
|
||||
import { Tooltip } from '@superset-ui/chart-controls';
|
||||
import {
|
||||
PopKPIComparisonSymbolStyleProps,
|
||||
PopKPIComparisonValueStyleProps,
|
||||
PopKPIProps,
|
||||
} from './types';
|
||||
|
||||
const ComparisonValue = styled.div<PopKPIComparisonValueStyleProps>`
|
||||
${({ theme, subheaderFontSize }) => `
|
||||
font-weight: ${theme.typography.weights.light};
|
||||
width: 33%;
|
||||
display: table-cell;
|
||||
font-size: ${subheaderFontSize || 20}px;
|
||||
text-align: center;
|
||||
`}
|
||||
`;
|
||||
|
||||
const SymbolWrapper = styled.div<PopKPIComparisonSymbolStyleProps>`
|
||||
${({ theme, backgroundColor, textColor }) => `
|
||||
background-color: ${backgroundColor};
|
||||
color: ${textColor};
|
||||
padding: ${theme.gridUnit}px ${theme.gridUnit * 2}px;
|
||||
border-radius: ${theme.gridUnit * 2}px;
|
||||
display: inline-block;
|
||||
margin-right: ${theme.gridUnit}px;
|
||||
`}
|
||||
`;
|
||||
|
||||
export default function PopKPI(props: PopKPIProps) {
|
||||
const {
|
||||
height,
|
||||
width,
|
||||
bigNumber,
|
||||
prevNumber,
|
||||
valueDifference,
|
||||
percentDifferenceFormattedString,
|
||||
headerFontSize,
|
||||
subheaderFontSize,
|
||||
comparisonColorEnabled,
|
||||
percentDifferenceNumber,
|
||||
comparatorText,
|
||||
} = props;
|
||||
|
||||
const rootElem = createRef<HTMLDivElement>();
|
||||
const theme = useTheme();
|
||||
|
||||
const wrapperDivStyles = css`
|
||||
font-family: ${theme.typography.families.sansSerif};
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
padding: ${theme.gridUnit * 4}px;
|
||||
border-radius: ${theme.gridUnit * 2}px;
|
||||
height: ${height}px;
|
||||
width: ${width}px;
|
||||
`;
|
||||
|
||||
const bigValueContainerStyles = css`
|
||||
font-size: ${headerFontSize || 60}px;
|
||||
font-weight: ${theme.typography.weights.normal};
|
||||
text-align: center;
|
||||
`;
|
||||
|
||||
const getArrowIndicatorColor = () => {
|
||||
if (!comparisonColorEnabled) return theme.colors.grayscale.base;
|
||||
return percentDifferenceNumber > 0
|
||||
? theme.colors.success.base
|
||||
: theme.colors.error.base;
|
||||
};
|
||||
|
||||
const arrowIndicatorStyle = css`
|
||||
color: ${getArrowIndicatorColor()};
|
||||
margin-left: ${theme.gridUnit}px;
|
||||
`;
|
||||
|
||||
const defaultBackgroundColor = theme.colors.grayscale.light4;
|
||||
const defaultTextColor = theme.colors.grayscale.base;
|
||||
const { backgroundColor, textColor } = useMemo(() => {
|
||||
let bgColor = defaultBackgroundColor;
|
||||
let txtColor = defaultTextColor;
|
||||
if (percentDifferenceNumber > 0) {
|
||||
if (comparisonColorEnabled) {
|
||||
bgColor = theme.colors.success.light2;
|
||||
txtColor = theme.colors.success.base;
|
||||
}
|
||||
} else if (percentDifferenceNumber < 0) {
|
||||
if (comparisonColorEnabled) {
|
||||
bgColor = theme.colors.error.light2;
|
||||
txtColor = theme.colors.error.base;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
backgroundColor: bgColor,
|
||||
textColor: txtColor,
|
||||
};
|
||||
}, [theme, comparisonColorEnabled, percentDifferenceNumber]);
|
||||
|
||||
const SYMBOLS_WITH_VALUES = useMemo(
|
||||
() => [
|
||||
{
|
||||
symbol: '#',
|
||||
value: prevNumber,
|
||||
tooltipText: t('Data for %s', comparatorText),
|
||||
},
|
||||
{
|
||||
symbol: '△',
|
||||
value: valueDifference,
|
||||
tooltipText: t('Value difference between the time periods'),
|
||||
},
|
||||
{
|
||||
symbol: '%',
|
||||
value: percentDifferenceFormattedString,
|
||||
tooltipText: t('Percentage difference between the time periods'),
|
||||
},
|
||||
],
|
||||
[prevNumber, valueDifference, percentDifferenceFormattedString],
|
||||
);
|
||||
|
||||
return (
|
||||
<div ref={rootElem} css={wrapperDivStyles}>
|
||||
<div css={bigValueContainerStyles}>
|
||||
{bigNumber}
|
||||
{percentDifferenceNumber !== 0 && (
|
||||
<span css={arrowIndicatorStyle}>
|
||||
{percentDifferenceNumber > 0 ? '↑' : '↓'}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
<div
|
||||
css={css`
|
||||
width: 100%;
|
||||
display: table;
|
||||
`}
|
||||
>
|
||||
<div
|
||||
css={css`
|
||||
display: table-row;
|
||||
`}
|
||||
>
|
||||
{SYMBOLS_WITH_VALUES.map((symbol_with_value, index) => (
|
||||
<ComparisonValue
|
||||
key={`comparison-symbol-${symbol_with_value.symbol}`}
|
||||
subheaderFontSize={subheaderFontSize}
|
||||
>
|
||||
<Tooltip
|
||||
id="tooltip"
|
||||
placement="top"
|
||||
title={symbol_with_value.tooltipText}
|
||||
>
|
||||
<SymbolWrapper
|
||||
backgroundColor={
|
||||
index > 0 ? backgroundColor : defaultBackgroundColor
|
||||
}
|
||||
textColor={index > 0 ? textColor : defaultTextColor}
|
||||
>
|
||||
{symbol_with_value.symbol}
|
||||
</SymbolWrapper>
|
||||
{symbol_with_value.value}
|
||||
</Tooltip>
|
||||
</ComparisonValue>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
/**
|
||||
* 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 {
|
||||
buildQueryContext,
|
||||
getComparisonInfo,
|
||||
ComparisonTimeRangeType,
|
||||
QueryFormData,
|
||||
} from '@superset-ui/core';
|
||||
|
||||
export default function buildQuery(formData: QueryFormData) {
|
||||
const {
|
||||
cols: groupby,
|
||||
time_comparison: timeComparison,
|
||||
extra_form_data: extraFormData,
|
||||
} = formData;
|
||||
|
||||
const queryContextA = buildQueryContext(formData, baseQueryObject => [
|
||||
{
|
||||
...baseQueryObject,
|
||||
groupby,
|
||||
},
|
||||
]);
|
||||
|
||||
const comparisonFormData = getComparisonInfo(
|
||||
formData,
|
||||
timeComparison,
|
||||
extraFormData,
|
||||
);
|
||||
|
||||
const queryContextB = buildQueryContext(
|
||||
comparisonFormData,
|
||||
baseQueryObject => [
|
||||
{
|
||||
...baseQueryObject,
|
||||
groupby,
|
||||
extras: {
|
||||
...baseQueryObject.extras,
|
||||
instant_time_comparison_range:
|
||||
timeComparison !== ComparisonTimeRangeType.Custom
|
||||
? timeComparison
|
||||
: undefined,
|
||||
},
|
||||
},
|
||||
],
|
||||
);
|
||||
|
||||
return {
|
||||
...queryContextA,
|
||||
queries: [...queryContextA.queries, ...queryContextB.queries],
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
/**
|
||||
* 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 {
|
||||
ComparisonTimeRangeType,
|
||||
t,
|
||||
validateTimeComparisonRangeValues,
|
||||
} from '@superset-ui/core';
|
||||
import {
|
||||
ControlPanelConfig,
|
||||
ControlPanelState,
|
||||
ControlState,
|
||||
getStandardizedControls,
|
||||
sharedControls,
|
||||
} from '@superset-ui/chart-controls';
|
||||
import { headerFontSize, subheaderFontSize } from '../sharedControls';
|
||||
|
||||
const config: ControlPanelConfig = {
|
||||
controlPanelSections: [
|
||||
{
|
||||
label: t('Query'),
|
||||
expanded: true,
|
||||
controlSetRows: [
|
||||
['metric'],
|
||||
['adhoc_filters'],
|
||||
[
|
||||
{
|
||||
name: 'time_comparison',
|
||||
config: {
|
||||
type: 'SelectControl',
|
||||
label: t('Range for Comparison'),
|
||||
default: 'r',
|
||||
choices: [
|
||||
['r', 'Inherit range from time filters'],
|
||||
['y', 'Year'],
|
||||
['m', 'Month'],
|
||||
['w', 'Week'],
|
||||
['c', 'Custom'],
|
||||
],
|
||||
rerender: ['adhoc_custom'],
|
||||
description: t(
|
||||
'Set the time range that will be used for the comparison metrics. ' +
|
||||
'For example, "Year" will compare to the same dates one year earlier. ' +
|
||||
'Use "Inherit range from time filters" to shift the comparison time range' +
|
||||
'by the same length as your time range and use "Custom" to set a custom comparison range.',
|
||||
),
|
||||
},
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
name: `adhoc_custom`,
|
||||
config: {
|
||||
...sharedControls.adhoc_filters,
|
||||
label: t('Filters for Comparison'),
|
||||
description:
|
||||
'This only applies when selecting the Range for Comparison Type: Custom',
|
||||
visibility: ({ controls }) =>
|
||||
controls?.time_comparison?.value ===
|
||||
ComparisonTimeRangeType.Custom,
|
||||
mapStateToProps: (
|
||||
state: ControlPanelState,
|
||||
controlState: ControlState,
|
||||
) => ({
|
||||
...(sharedControls.adhoc_filters.mapStateToProps?.(
|
||||
state,
|
||||
controlState,
|
||||
) || {}),
|
||||
externalValidationErrors: validateTimeComparisonRangeValues(
|
||||
state.controls?.time_comparison?.value,
|
||||
controlState.value,
|
||||
),
|
||||
}),
|
||||
},
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
name: 'row_limit',
|
||||
config: sharedControls.row_limit,
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
{
|
||||
label: t('Chart Options'),
|
||||
expanded: true,
|
||||
controlSetRows: [
|
||||
['y_axis_format'],
|
||||
['currency_format'],
|
||||
[headerFontSize],
|
||||
[
|
||||
{
|
||||
...subheaderFontSize,
|
||||
config: {
|
||||
...subheaderFontSize.config,
|
||||
label: t('Comparison font size'),
|
||||
},
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
name: 'comparison_color_enabled',
|
||||
config: {
|
||||
type: 'CheckboxControl',
|
||||
label: t('Add color for positive/negative change'),
|
||||
renderTrigger: true,
|
||||
default: false,
|
||||
description: t('Add color for positive/negative change'),
|
||||
},
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
],
|
||||
controlOverrides: {
|
||||
y_axis_format: {
|
||||
label: t('Number format'),
|
||||
},
|
||||
},
|
||||
formDataOverrides: formData => ({
|
||||
...formData,
|
||||
metric: getStandardizedControls().shiftMetric(),
|
||||
}),
|
||||
};
|
||||
|
||||
export default config;
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 10 KiB |
@@ -0,0 +1,51 @@
|
||||
/**
|
||||
* 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 buildQuery from './buildQuery';
|
||||
import controlPanel from './controlPanel';
|
||||
import transformProps from './transformProps';
|
||||
import thumbnail from './images/thumbnail.png';
|
||||
|
||||
export default class PopKPIPlugin extends ChartPlugin {
|
||||
constructor() {
|
||||
const metadata = new ChartMetadata({
|
||||
category: t('KPI'),
|
||||
description:
|
||||
'Showcases a metric along with a comparison of value, change, and percent change for a selected time period.',
|
||||
name: t('Big Number with Time Period Comparison'),
|
||||
tags: [
|
||||
t('Comparison'),
|
||||
t('Business'),
|
||||
t('Percentages'),
|
||||
t('Report'),
|
||||
t('Description'),
|
||||
t('Advanced-Analytics'),
|
||||
],
|
||||
thumbnail,
|
||||
});
|
||||
|
||||
super({
|
||||
buildQuery,
|
||||
controlPanel,
|
||||
loadChart: () => import('./PopKPI'),
|
||||
metadata,
|
||||
transformProps,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,161 @@
|
||||
/**
|
||||
* 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 moment from 'moment';
|
||||
import {
|
||||
ChartProps,
|
||||
getMetricLabel,
|
||||
getValueFormatter,
|
||||
NumberFormats,
|
||||
getNumberFormatter,
|
||||
formatTimeRange,
|
||||
} from '@superset-ui/core';
|
||||
import { getComparisonFontSize, getHeaderFontSize } from './utils';
|
||||
|
||||
export const parseMetricValue = (metricValue: number | string | null) => {
|
||||
if (typeof metricValue === 'string') {
|
||||
const dateObject = moment.utc(metricValue, moment.ISO_8601, true);
|
||||
if (dateObject.isValid()) {
|
||||
return dateObject.valueOf();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return metricValue ?? 0;
|
||||
};
|
||||
|
||||
export default function transformProps(chartProps: ChartProps) {
|
||||
/**
|
||||
* This function is called after a successful response has been
|
||||
* received from the chart data endpoint, and is used to transform
|
||||
* the incoming data prior to being sent to the Visualization.
|
||||
*
|
||||
* The transformProps function is also quite useful to return
|
||||
* additional/modified props to your data viz component. The formData
|
||||
* can also be accessed from your CustomViz.tsx file, but
|
||||
* doing supplying custom props here is often handy for integrating third
|
||||
* party libraries that rely on specific props.
|
||||
*
|
||||
* A description of properties in `chartProps`:
|
||||
* - `height`, `width`: the height/width of the DOM element in which
|
||||
* the chart is located
|
||||
* - `formData`: the chart data request payload that was sent to the
|
||||
* backend.
|
||||
* - `queriesData`: the chart data response payload that was received
|
||||
* from the backend. Some notable properties of `queriesData`:
|
||||
* - `data`: an array with data, each row with an object mapping
|
||||
* the column/alias to its value. Example:
|
||||
* `[{ col1: 'abc', metric1: 10 }, { col1: 'xyz', metric1: 20 }]`
|
||||
* - `rowcount`: the number of rows in `data`
|
||||
* - `query`: the query that was issued.
|
||||
*
|
||||
* Please note: the transformProps function gets cached when the
|
||||
* application loads. When making changes to the `transformProps`
|
||||
* function during development with hot reloading, changes won't
|
||||
* be seen until restarting the development server.
|
||||
*/
|
||||
const {
|
||||
width,
|
||||
height,
|
||||
formData,
|
||||
queriesData,
|
||||
datasource: { currencyFormats = {}, columnFormats = {} },
|
||||
} = chartProps;
|
||||
const {
|
||||
boldText,
|
||||
headerFontSize,
|
||||
headerText,
|
||||
metric,
|
||||
yAxisFormat,
|
||||
currencyFormat,
|
||||
subheaderFontSize,
|
||||
comparisonColorEnabled,
|
||||
} = formData;
|
||||
const { data: dataA = [] } = queriesData[0];
|
||||
const {
|
||||
data: dataB = [],
|
||||
from_dttm: comparisonFromDatetime,
|
||||
to_dttm: comparisonToDatetime,
|
||||
} = queriesData[1];
|
||||
const data = dataA;
|
||||
const metricName = getMetricLabel(metric);
|
||||
let bigNumber: number | string =
|
||||
data.length === 0 ? 0 : parseMetricValue(data[0][metricName]);
|
||||
let prevNumber: number | string =
|
||||
data.length === 0 ? 0 : parseMetricValue(dataB[0][metricName]);
|
||||
|
||||
const numberFormatter = getValueFormatter(
|
||||
metric,
|
||||
currencyFormats,
|
||||
columnFormats,
|
||||
yAxisFormat,
|
||||
currencyFormat,
|
||||
);
|
||||
|
||||
const compTitles = {
|
||||
r: 'Range' as string,
|
||||
y: 'Year' as string,
|
||||
m: 'Month' as string,
|
||||
w: 'Week' as string,
|
||||
};
|
||||
|
||||
const formatPercentChange = getNumberFormatter(
|
||||
NumberFormats.PERCENT_SIGNED_1_POINT,
|
||||
);
|
||||
|
||||
let valueDifference: number | string = bigNumber - prevNumber;
|
||||
|
||||
let percentDifferenceNum;
|
||||
|
||||
if (!bigNumber && !prevNumber) {
|
||||
percentDifferenceNum = 0;
|
||||
} else if (!bigNumber || !prevNumber) {
|
||||
percentDifferenceNum = bigNumber ? 1 : -1;
|
||||
} else {
|
||||
percentDifferenceNum = (bigNumber - prevNumber) / Math.abs(prevNumber);
|
||||
}
|
||||
|
||||
const compType = compTitles[formData.timeComparison];
|
||||
bigNumber = numberFormatter(bigNumber);
|
||||
prevNumber = numberFormatter(prevNumber);
|
||||
valueDifference = numberFormatter(valueDifference);
|
||||
const percentDifference: string = formatPercentChange(percentDifferenceNum);
|
||||
const comparatorText = formatTimeRange('%Y-%m-%d', [
|
||||
comparisonFromDatetime,
|
||||
comparisonToDatetime,
|
||||
]);
|
||||
|
||||
return {
|
||||
width,
|
||||
height,
|
||||
data,
|
||||
metric,
|
||||
metricName,
|
||||
bigNumber,
|
||||
prevNumber,
|
||||
valueDifference,
|
||||
percentDifferenceFormattedString: percentDifference,
|
||||
boldText,
|
||||
headerFontSize: getHeaderFontSize(headerFontSize),
|
||||
subheaderFontSize: getComparisonFontSize(subheaderFontSize),
|
||||
headerText,
|
||||
compType,
|
||||
comparisonColorEnabled,
|
||||
percentDifferenceNumber: percentDifferenceNum,
|
||||
comparatorText,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/**
|
||||
* 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 {
|
||||
QueryFormData,
|
||||
supersetTheme,
|
||||
TimeseriesDataRecord,
|
||||
Metric,
|
||||
} from '@superset-ui/core';
|
||||
|
||||
export interface PopKPIStylesProps {
|
||||
height: number;
|
||||
width: number;
|
||||
headerFontSize: keyof typeof supersetTheme.typography.sizes;
|
||||
subheaderFontSize: keyof typeof supersetTheme.typography.sizes;
|
||||
boldText: boolean;
|
||||
comparisonColorEnabled: boolean;
|
||||
}
|
||||
|
||||
interface PopKPICustomizeProps {
|
||||
headerText: string;
|
||||
}
|
||||
|
||||
export interface PopKPIComparisonValueStyleProps {
|
||||
subheaderFontSize?: keyof typeof supersetTheme.typography.sizes;
|
||||
}
|
||||
|
||||
export interface PopKPIComparisonSymbolStyleProps {
|
||||
backgroundColor: string;
|
||||
textColor: string;
|
||||
}
|
||||
|
||||
export type PopKPIQueryFormData = QueryFormData &
|
||||
PopKPIStylesProps &
|
||||
PopKPICustomizeProps;
|
||||
|
||||
export type PopKPIProps = PopKPIStylesProps &
|
||||
PopKPICustomizeProps & {
|
||||
data: TimeseriesDataRecord[];
|
||||
metrics: Metric[];
|
||||
metricName: string;
|
||||
bigNumber: string;
|
||||
prevNumber: string;
|
||||
valueDifference: string;
|
||||
percentDifferenceFormattedString: string;
|
||||
compType: string;
|
||||
percentDifferenceNumber: number;
|
||||
comparatorText: string;
|
||||
};
|
||||
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* 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 { getComparisonFontSize, getHeaderFontSize } from './utils';
|
||||
|
||||
test('getHeaderFontSize', () => {
|
||||
expect(getHeaderFontSize(0.2)).toEqual(16);
|
||||
expect(getHeaderFontSize(0.3)).toEqual(20);
|
||||
expect(getHeaderFontSize(0.4)).toEqual(30);
|
||||
expect(getHeaderFontSize(0.5)).toEqual(48);
|
||||
expect(getHeaderFontSize(0.6)).toEqual(60);
|
||||
expect(getHeaderFontSize(0.15)).toEqual(60);
|
||||
expect(getHeaderFontSize(2)).toEqual(60);
|
||||
});
|
||||
|
||||
test('getComparisonFontSize', () => {
|
||||
expect(getComparisonFontSize(0.125)).toEqual(16);
|
||||
expect(getComparisonFontSize(0.15)).toEqual(20);
|
||||
expect(getComparisonFontSize(0.2)).toEqual(26);
|
||||
expect(getComparisonFontSize(0.3)).toEqual(32);
|
||||
expect(getComparisonFontSize(0.4)).toEqual(40);
|
||||
expect(getComparisonFontSize(0.05)).toEqual(40);
|
||||
expect(getComparisonFontSize(0.9)).toEqual(40);
|
||||
});
|
||||
@@ -0,0 +1,59 @@
|
||||
/**
|
||||
* 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 { headerFontSize, subheaderFontSize } from '../sharedControls';
|
||||
|
||||
const headerFontSizes = [16, 20, 30, 48, 60];
|
||||
const comparisonFontSizes = [16, 20, 26, 32, 40];
|
||||
|
||||
const headerProportionValues =
|
||||
headerFontSize.config.options.map(
|
||||
(option: { label: string; value: number }) => option.value,
|
||||
) ?? [];
|
||||
|
||||
const subheaderProportionValues =
|
||||
subheaderFontSize.config.options.map(
|
||||
(option: { label: string; value: number }) => option.value,
|
||||
) ?? [];
|
||||
|
||||
const getFontSizeMapping = (
|
||||
proportionValues: number[],
|
||||
actualSizes: number[],
|
||||
) =>
|
||||
proportionValues.reduce((acc, value, index) => {
|
||||
acc[value] = actualSizes[index] ?? actualSizes[actualSizes.length - 1];
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
const headerFontSizesMapping = getFontSizeMapping(
|
||||
headerProportionValues,
|
||||
headerFontSizes,
|
||||
);
|
||||
|
||||
const comparisonFontSizesMapping = getFontSizeMapping(
|
||||
subheaderProportionValues,
|
||||
comparisonFontSizes,
|
||||
);
|
||||
|
||||
export const getHeaderFontSize = (proportionValue: number) =>
|
||||
headerFontSizesMapping[proportionValue] ??
|
||||
headerFontSizes[headerFontSizes.length - 1];
|
||||
|
||||
export const getComparisonFontSize = (proportionValue: number) =>
|
||||
comparisonFontSizesMapping[proportionValue] ??
|
||||
comparisonFontSizes[comparisonFontSizes.length - 1];
|
||||
@@ -19,3 +19,4 @@
|
||||
|
||||
export { default as BigNumberChartPlugin } from './BigNumberWithTrendline';
|
||||
export { default as BigNumberTotalChartPlugin } from './BigNumberTotal';
|
||||
export { default as BigNumberPeriodOverPeriodChartPlugin } from './BigNumberPeriodOverPeriod';
|
||||
|
||||
@@ -32,7 +32,11 @@ export { default as EchartsRadarChartPlugin } from './Radar';
|
||||
export { default as EchartsFunnelChartPlugin } from './Funnel';
|
||||
export { default as EchartsTreeChartPlugin } from './Tree';
|
||||
export { default as EchartsTreemapChartPlugin } from './Treemap';
|
||||
export { BigNumberChartPlugin, BigNumberTotalChartPlugin } from './BigNumber';
|
||||
export {
|
||||
BigNumberChartPlugin,
|
||||
BigNumberTotalChartPlugin,
|
||||
BigNumberPeriodOverPeriodChartPlugin,
|
||||
} from './BigNumber';
|
||||
export { default as EchartsSunburstChartPlugin } from './Sunburst';
|
||||
export { default as EchartsBubbleChartPlugin } from './Bubble';
|
||||
export { default as EchartsWaterfallChartPlugin } from './Waterfall';
|
||||
|
||||
Reference in New Issue
Block a user