mirror of
https://github.com/apache/superset.git
synced 2026-04-19 16:14:52 +00:00
feat(charts): add subtitle option and metric customization controls (#32975)
This commit is contained in:
@@ -81,6 +81,8 @@ export default function PopKPI(props: PopKPIProps) {
|
||||
currentTimeRangeFilter,
|
||||
startDateOffset,
|
||||
shift,
|
||||
subtitle,
|
||||
subtitleFontSize,
|
||||
dashboardTimeRange,
|
||||
} = props;
|
||||
|
||||
@@ -140,6 +142,16 @@ export default function PopKPI(props: PopKPIProps) {
|
||||
margin-bottom: ${theme.gridUnit * 4}px;
|
||||
`;
|
||||
|
||||
const SubtitleText = styled.div`
|
||||
${({ theme }) => `
|
||||
font-family: ${theme.typography.families.sansSerif};
|
||||
font-weight: ${theme.typography.weights.medium};
|
||||
text-align: center;
|
||||
margin-top: -10px;
|
||||
margin-bottom: ${theme.gridUnit * 4}px;
|
||||
`}
|
||||
`;
|
||||
|
||||
const getArrowIndicatorColor = () => {
|
||||
if (!comparisonColorEnabled || percentDifferenceNumber === 0) {
|
||||
return theme.colors.grayscale.base;
|
||||
@@ -195,31 +207,40 @@ export default function PopKPI(props: PopKPIProps) {
|
||||
]);
|
||||
|
||||
const SYMBOLS_WITH_VALUES = useMemo(
|
||||
() => [
|
||||
{
|
||||
symbol: '#',
|
||||
value: prevNumber,
|
||||
tooltipText: t('Data for %s', comparisonRange || 'previous range'),
|
||||
columnKey: 'Previous value',
|
||||
},
|
||||
{
|
||||
symbol: '△',
|
||||
value: valueDifference,
|
||||
tooltipText: t('Value difference between the time periods'),
|
||||
columnKey: 'Delta',
|
||||
},
|
||||
{
|
||||
symbol: '%',
|
||||
value: percentDifferenceFormattedString,
|
||||
tooltipText: t('Percentage difference between the time periods'),
|
||||
columnKey: 'Percent change',
|
||||
},
|
||||
],
|
||||
() =>
|
||||
[
|
||||
{
|
||||
defaultSymbol: '#',
|
||||
value: prevNumber,
|
||||
tooltipText: t('Data for %s', comparisonRange || 'previous range'),
|
||||
columnKey: 'Previous value',
|
||||
},
|
||||
{
|
||||
defaultSymbol: '△',
|
||||
value: valueDifference,
|
||||
tooltipText: t('Value difference between the time periods'),
|
||||
columnKey: 'Delta',
|
||||
},
|
||||
{
|
||||
defaultSymbol: '%',
|
||||
value: percentDifferenceFormattedString,
|
||||
tooltipText: t('Percentage difference between the time periods'),
|
||||
columnKey: 'Percent change',
|
||||
},
|
||||
].map(item => {
|
||||
const config = props.columnConfig?.[item.columnKey];
|
||||
return {
|
||||
...item,
|
||||
symbol: config?.displayTypeIcon === false ? '' : item.defaultSymbol,
|
||||
label: config?.customColumnName || item.columnKey,
|
||||
};
|
||||
}),
|
||||
[
|
||||
comparisonRange,
|
||||
prevNumber,
|
||||
valueDifference,
|
||||
percentDifferenceFormattedString,
|
||||
props.columnConfig,
|
||||
],
|
||||
);
|
||||
|
||||
@@ -250,6 +271,15 @@ export default function PopKPI(props: PopKPIProps) {
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
{subtitle && (
|
||||
<SubtitleText
|
||||
style={{
|
||||
fontSize: `${subtitleFontSize * height * 0.4}px`,
|
||||
}}
|
||||
>
|
||||
{subtitle}
|
||||
</SubtitleText>
|
||||
)}
|
||||
|
||||
{visibleSymbols.length > 0 && (
|
||||
<div
|
||||
@@ -276,7 +306,7 @@ export default function PopKPI(props: PopKPIProps) {
|
||||
>
|
||||
{visibleSymbols.map((symbol_with_value, index) => (
|
||||
<ComparisonValue
|
||||
key={`comparison-symbol-${symbol_with_value.symbol}`}
|
||||
key={`comparison-symbol-${symbol_with_value.columnKey}`}
|
||||
subheaderFontSize={subheaderFontSize}
|
||||
>
|
||||
<Tooltip
|
||||
@@ -284,15 +314,19 @@ export default function PopKPI(props: PopKPIProps) {
|
||||
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}
|
||||
{symbol_with_value.symbol && (
|
||||
<SymbolWrapper
|
||||
backgroundColor={
|
||||
index > 0 ? backgroundColor : defaultBackgroundColor
|
||||
}
|
||||
textColor={index > 0 ? textColor : defaultTextColor}
|
||||
>
|
||||
{symbol_with_value.symbol}
|
||||
</SymbolWrapper>
|
||||
)}
|
||||
{symbol_with_value.value}{' '}
|
||||
{props.columnConfig?.[symbol_with_value.columnKey]
|
||||
?.customColumnName || ''}
|
||||
</Tooltip>
|
||||
</ComparisonValue>
|
||||
))}
|
||||
|
||||
@@ -23,7 +23,12 @@ import {
|
||||
sharedControls,
|
||||
sections,
|
||||
} from '@superset-ui/chart-controls';
|
||||
import { headerFontSize, subheaderFontSize } from '../sharedControls';
|
||||
import {
|
||||
headerFontSize,
|
||||
subheaderFontSize,
|
||||
subtitleControl,
|
||||
subtitleFontSize,
|
||||
} from '../sharedControls';
|
||||
import { ColorSchemeEnum } from './types';
|
||||
|
||||
const config: ControlPanelConfig = {
|
||||
@@ -63,6 +68,8 @@ const config: ControlPanelConfig = {
|
||||
config: { ...headerFontSize.config, default: 0.2 },
|
||||
},
|
||||
],
|
||||
[subtitleControl],
|
||||
[subtitleFontSize],
|
||||
[
|
||||
{
|
||||
...subheaderFontSize,
|
||||
@@ -120,7 +127,11 @@ const config: ControlPanelConfig = {
|
||||
[GenericDataType.Numeric]: [
|
||||
{
|
||||
tab: t('General'),
|
||||
children: [['visible']],
|
||||
children: [
|
||||
['customColumnName'],
|
||||
['displayTypeIcon'],
|
||||
['visible'],
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
@@ -89,6 +89,8 @@ export default function transformProps(chartProps: ChartProps) {
|
||||
comparisonColorScheme,
|
||||
comparisonColorEnabled,
|
||||
percentDifferenceFormat,
|
||||
subtitle = '',
|
||||
subtitleFontSize,
|
||||
columnConfig,
|
||||
} = formData;
|
||||
const { data: dataA = [] } = queriesData[0];
|
||||
@@ -183,6 +185,8 @@ export default function transformProps(chartProps: ChartProps) {
|
||||
valueDifference,
|
||||
percentDifferenceFormattedString: percentDifference,
|
||||
boldText,
|
||||
subtitle,
|
||||
subtitleFontSize,
|
||||
headerFontSize: getHeaderFontSize(headerFontSize),
|
||||
subheaderFontSize: getComparisonFontSize(subheaderFontSize),
|
||||
headerText,
|
||||
|
||||
@@ -35,6 +35,8 @@ export interface PopKPIStylesProps {
|
||||
|
||||
export type TableColumnConfig = {
|
||||
visible?: boolean;
|
||||
customColumnName?: string;
|
||||
displayTypeIcon?: boolean;
|
||||
};
|
||||
|
||||
interface PopKPICustomizeProps {
|
||||
@@ -61,6 +63,8 @@ export type PopKPIProps = PopKPIStylesProps &
|
||||
metricName: string;
|
||||
bigNumber: string;
|
||||
prevNumber: string;
|
||||
subtitle?: string;
|
||||
subtitleFontSize: number;
|
||||
valueDifference: string;
|
||||
percentDifferenceFormattedString: string;
|
||||
compType: string;
|
||||
|
||||
@@ -24,7 +24,11 @@ import {
|
||||
Dataset,
|
||||
getStandardizedControls,
|
||||
} from '@superset-ui/chart-controls';
|
||||
import { headerFontSize, subheaderFontSize } from '../sharedControls';
|
||||
import {
|
||||
headerFontSize,
|
||||
subtitleFontSize,
|
||||
subtitleControl,
|
||||
} from '../sharedControls';
|
||||
|
||||
export default {
|
||||
controlPanelSections: [
|
||||
@@ -33,32 +37,13 @@ export default {
|
||||
expanded: true,
|
||||
controlSetRows: [['metric'], ['adhoc_filters']],
|
||||
},
|
||||
{
|
||||
label: t('Display settings'),
|
||||
expanded: true,
|
||||
tabOverride: 'data',
|
||||
controlSetRows: [
|
||||
[
|
||||
{
|
||||
name: 'subheader',
|
||||
config: {
|
||||
type: 'TextControl',
|
||||
label: t('Subheader'),
|
||||
renderTrigger: true,
|
||||
description: t(
|
||||
'Description text that shows up below your Big Number',
|
||||
),
|
||||
},
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
{
|
||||
label: t('Chart Options'),
|
||||
expanded: true,
|
||||
controlSetRows: [
|
||||
[headerFontSize],
|
||||
[subheaderFontSize],
|
||||
[subtitleControl],
|
||||
[subtitleFontSize],
|
||||
['y_axis_format'],
|
||||
['currency_format'],
|
||||
[
|
||||
|
||||
@@ -47,8 +47,8 @@ export default function transformProps(
|
||||
const {
|
||||
headerFontSize,
|
||||
metric = 'value',
|
||||
subheader = '',
|
||||
subheaderFontSize,
|
||||
subtitle = '',
|
||||
subtitleFontSize,
|
||||
forceTimestampFormatting,
|
||||
timeFormat,
|
||||
yAxisFormat,
|
||||
@@ -59,7 +59,7 @@ export default function transformProps(
|
||||
const { data = [], coltypes = [] } = queriesData[0];
|
||||
const granularity = extractTimegrain(rawFormData as QueryFormData);
|
||||
const metricName = getMetricLabel(metric);
|
||||
const formattedSubheader = subheader;
|
||||
const formattedSubtitle = subtitle;
|
||||
const bigNumber =
|
||||
data.length === 0 ? null : parseMetricValue(data[0][metricName]);
|
||||
|
||||
@@ -105,8 +105,10 @@ export default function transformProps(
|
||||
bigNumber,
|
||||
headerFormatter,
|
||||
headerFontSize,
|
||||
subheaderFontSize,
|
||||
subheader: formattedSubheader,
|
||||
subtitleFontSize,
|
||||
subtitle: formattedSubtitle,
|
||||
subheader: '',
|
||||
subheaderFontSize: subtitleFontSize,
|
||||
onContextMenu,
|
||||
refs,
|
||||
colorThresholdFormatters,
|
||||
|
||||
@@ -229,6 +229,40 @@ class BigNumberVis extends PureComponent<BigNumberVizProps> {
|
||||
return null;
|
||||
}
|
||||
|
||||
renderSubtitle(maxHeight: number) {
|
||||
const { subtitle, width } = this.props;
|
||||
let fontSize = 0;
|
||||
|
||||
if (subtitle) {
|
||||
const container = this.createTemporaryContainer();
|
||||
document.body.append(container);
|
||||
try {
|
||||
fontSize = computeMaxFontSize({
|
||||
text: subtitle,
|
||||
maxWidth: width * 0.9,
|
||||
maxHeight,
|
||||
className: 'subtitle-line',
|
||||
container,
|
||||
});
|
||||
} finally {
|
||||
container.remove();
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className="subtitle-line"
|
||||
style={{
|
||||
fontSize,
|
||||
height: maxHeight,
|
||||
}}
|
||||
>
|
||||
{subtitle}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
renderTrendline(maxHeight: number) {
|
||||
const { width, trendLineData, echartOptions, refs } = this.props;
|
||||
|
||||
@@ -282,6 +316,7 @@ class BigNumberVis extends PureComponent<BigNumberVizProps> {
|
||||
kickerFontSize,
|
||||
headerFontSize,
|
||||
subheaderFontSize,
|
||||
subtitleFontSize,
|
||||
} = this.props;
|
||||
const className = this.getClassName();
|
||||
|
||||
@@ -306,6 +341,9 @@ class BigNumberVis extends PureComponent<BigNumberVizProps> {
|
||||
subheaderFontSize * (1 - PROPORTION.TRENDLINE) * height,
|
||||
),
|
||||
)}
|
||||
{this.renderSubtitle(
|
||||
Math.ceil(subtitleFontSize * (1 - PROPORTION.TRENDLINE) * height),
|
||||
)}
|
||||
</div>
|
||||
{this.renderTrendline(chartHeight)}
|
||||
</div>
|
||||
@@ -318,6 +356,7 @@ class BigNumberVis extends PureComponent<BigNumberVizProps> {
|
||||
{this.renderKicker((kickerFontSize || 0) * height)}
|
||||
{this.renderHeader(Math.ceil(headerFontSize * height))}
|
||||
{this.renderSubheader(Math.ceil(subheaderFontSize * height))}
|
||||
{this.renderSubtitle(Math.ceil(subtitleFontSize * height))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -368,7 +407,12 @@ export default styled(BigNumberVis)`
|
||||
|
||||
.subheader-line {
|
||||
line-height: 1em;
|
||||
padding-bottom: 0;
|
||||
padding-bottom: 0.3em;
|
||||
}
|
||||
|
||||
.subtitle-line {
|
||||
line-height: 1em;
|
||||
padding-top: 0.3em;
|
||||
}
|
||||
|
||||
&.is-fallback-value {
|
||||
|
||||
@@ -26,7 +26,12 @@ import {
|
||||
getStandardizedControls,
|
||||
temporalColumnMixin,
|
||||
} from '@superset-ui/chart-controls';
|
||||
import { headerFontSize, subheaderFontSize } from '../sharedControls';
|
||||
import {
|
||||
headerFontSize,
|
||||
subheaderFontSize,
|
||||
subtitleFontSize,
|
||||
subtitleControl,
|
||||
} from '../sharedControls';
|
||||
|
||||
const config: ControlPanelConfig = {
|
||||
controlPanelSections: [
|
||||
@@ -134,6 +139,8 @@ const config: ControlPanelConfig = {
|
||||
['color_picker', null],
|
||||
[headerFontSize],
|
||||
[subheaderFontSize],
|
||||
[subtitleControl],
|
||||
[subtitleFontSize],
|
||||
['y_axis_format'],
|
||||
['currency_format'],
|
||||
[
|
||||
|
||||
@@ -66,6 +66,8 @@ export default function transformProps(
|
||||
metric = 'value',
|
||||
showTimestamp,
|
||||
showTrendLine,
|
||||
subtitle = '',
|
||||
subtitleFontSize,
|
||||
aggregation,
|
||||
startYAxisAtZero,
|
||||
subheader = '',
|
||||
@@ -302,6 +304,8 @@ export default function transformProps(
|
||||
formatTime,
|
||||
formData,
|
||||
headerFontSize,
|
||||
subtitleFontSize,
|
||||
subtitle,
|
||||
subheaderFontSize,
|
||||
mainColor,
|
||||
showTimestamp,
|
||||
|
||||
@@ -55,6 +55,39 @@ export const headerFontSize: CustomControlItem = {
|
||||
},
|
||||
};
|
||||
|
||||
export const subtitleFontSize: CustomControlItem = {
|
||||
name: 'subtitle_font_size',
|
||||
config: {
|
||||
type: 'SelectControl',
|
||||
label: t('Subtitle Font Size'),
|
||||
renderTrigger: true,
|
||||
clearable: false,
|
||||
default: 0.15,
|
||||
// Values represent the percentage of space a subtitle should take
|
||||
options: [
|
||||
{
|
||||
label: t('Tiny'),
|
||||
value: 0.125,
|
||||
},
|
||||
{
|
||||
label: t('Small'),
|
||||
value: 0.15,
|
||||
},
|
||||
{
|
||||
label: t('Normal'),
|
||||
value: 0.2,
|
||||
},
|
||||
{
|
||||
label: t('Large'),
|
||||
value: 0.3,
|
||||
},
|
||||
{
|
||||
label: t('Huge'),
|
||||
value: 0.4,
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
export const subheaderFontSize: CustomControlItem = {
|
||||
name: 'subheader_font_size',
|
||||
config: {
|
||||
@@ -88,3 +121,13 @@ export const subheaderFontSize: CustomControlItem = {
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
export const subtitleControl: CustomControlItem = {
|
||||
name: 'subtitle',
|
||||
config: {
|
||||
type: 'TextControl',
|
||||
label: t('Subtitle'),
|
||||
renderTrigger: true,
|
||||
description: t('Description text that shows up below your Big Number'),
|
||||
},
|
||||
};
|
||||
|
||||
@@ -78,7 +78,9 @@ export type BigNumberVizProps = {
|
||||
headerFontSize: number;
|
||||
kickerFontSize?: number;
|
||||
subheader: string;
|
||||
subtitle: string;
|
||||
subheaderFontSize: number;
|
||||
subtitleFontSize: number;
|
||||
showTimestamp?: boolean;
|
||||
showTrendLine?: boolean;
|
||||
startYAxisAtZero?: boolean;
|
||||
|
||||
@@ -682,13 +682,33 @@ export default function TableChart<D extends DataRecord = DataRecord>(
|
||||
(column: DataColumnMeta, i: number): ColumnWithLooseAccessor<D> => {
|
||||
const {
|
||||
key,
|
||||
label,
|
||||
label: originalLabel,
|
||||
isNumeric,
|
||||
dataType,
|
||||
isMetric,
|
||||
isPercentMetric,
|
||||
config = {},
|
||||
} = column;
|
||||
const label = config.customColumnName || originalLabel;
|
||||
let displayLabel = label;
|
||||
|
||||
const isComparisonColumn = ['#', '△', '%', t('Main')].includes(
|
||||
column.label,
|
||||
);
|
||||
|
||||
if (isComparisonColumn) {
|
||||
if (column.label === t('Main')) {
|
||||
displayLabel = config.customColumnName || column.originalLabel || '';
|
||||
} else if (config.customColumnName) {
|
||||
displayLabel =
|
||||
config.displayTypeIcon !== false
|
||||
? `${column.label} ${config.customColumnName}`
|
||||
: config.customColumnName;
|
||||
} else if (config.displayTypeIcon === false) {
|
||||
displayLabel = '';
|
||||
}
|
||||
}
|
||||
|
||||
const columnWidth = Number.isNaN(Number(config.columnWidth))
|
||||
? config.columnWidth
|
||||
: Number(config.columnWidth);
|
||||
@@ -795,6 +815,9 @@ export default function TableChart<D extends DataRecord = DataRecord>(
|
||||
white-space: ${value instanceof Date ? 'nowrap' : undefined};
|
||||
position: relative;
|
||||
background: ${backgroundColor || undefined};
|
||||
padding-left: ${column.isChildColumn
|
||||
? `${theme.gridUnit * 5}px`
|
||||
: `${theme.gridUnit}px`};
|
||||
`;
|
||||
|
||||
const cellBarStyles = css`
|
||||
@@ -970,11 +993,12 @@ export default function TableChart<D extends DataRecord = DataRecord>(
|
||||
alignItems: 'flex-end',
|
||||
}}
|
||||
>
|
||||
<span data-column-name={col.id}>{label}</span>
|
||||
<span data-column-name={col.id}>{displayLabel}</span>
|
||||
<SortIcon column={col} />
|
||||
</div>
|
||||
</th>
|
||||
),
|
||||
|
||||
Footer: totals ? (
|
||||
i === 0 ? (
|
||||
<th key={`footer-summary-${i}`}>
|
||||
@@ -1024,9 +1048,14 @@ export default function TableChart<D extends DataRecord = DataRecord>(
|
||||
],
|
||||
);
|
||||
|
||||
const visibleColumnsMeta = useMemo(
|
||||
() => filteredColumnsMeta.filter(col => col.config?.visible !== false),
|
||||
[filteredColumnsMeta],
|
||||
);
|
||||
|
||||
const columns = useMemo(
|
||||
() => filteredColumnsMeta.map(getColumnConfigs),
|
||||
[filteredColumnsMeta, getColumnConfigs],
|
||||
() => visibleColumnsMeta.map(getColumnConfigs),
|
||||
[visibleColumnsMeta, getColumnConfigs],
|
||||
);
|
||||
|
||||
const handleServerPaginationChange = useCallback(
|
||||
|
||||
@@ -494,6 +494,7 @@ const config: ControlPanelConfig = {
|
||||
chart?.queriesResponse?.[0] ?? {};
|
||||
let colnames: string[] = _colnames || [];
|
||||
let coltypes: GenericDataType[] = _coltypes || [];
|
||||
const childColumnMap: Record<string, boolean> = {};
|
||||
|
||||
if (timeComparisonStatus) {
|
||||
/**
|
||||
@@ -501,15 +502,27 @@ const config: ControlPanelConfig = {
|
||||
*/
|
||||
const updatedColnames: string[] = [];
|
||||
const updatedColtypes: GenericDataType[] = [];
|
||||
|
||||
colnames.forEach((colname, index) => {
|
||||
if (coltypes[index] === GenericDataType.Numeric) {
|
||||
updatedColnames.push(
|
||||
...generateComparisonColumns(colname),
|
||||
);
|
||||
updatedColtypes.push(...generateComparisonColumnTypes(4));
|
||||
const comparisonColumns =
|
||||
generateComparisonColumns(colname);
|
||||
comparisonColumns.forEach((name, idx) => {
|
||||
updatedColnames.push(name);
|
||||
updatedColtypes.push(
|
||||
...generateComparisonColumnTypes(4),
|
||||
);
|
||||
|
||||
if (idx === 0 && name.startsWith('Main ')) {
|
||||
childColumnMap[name] = false;
|
||||
} else {
|
||||
childColumnMap[name] = true;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
updatedColnames.push(colname);
|
||||
updatedColtypes.push(coltypes[index]);
|
||||
childColumnMap[colname] = false;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -517,7 +530,7 @@ const config: ControlPanelConfig = {
|
||||
coltypes = updatedColtypes;
|
||||
}
|
||||
return {
|
||||
columnsPropsObject: { colnames, coltypes },
|
||||
columnsPropsObject: { colnames, coltypes, childColumnMap },
|
||||
};
|
||||
},
|
||||
},
|
||||
|
||||
@@ -49,6 +49,9 @@ export type TableColumnConfig = {
|
||||
colorPositiveNegative?: boolean;
|
||||
truncateLongCells?: boolean;
|
||||
currencyFormat?: Currency;
|
||||
visible?: boolean;
|
||||
customColumnName?: string;
|
||||
displayTypeIcon?: boolean;
|
||||
};
|
||||
|
||||
export interface DataColumnMeta {
|
||||
@@ -68,6 +71,7 @@ export interface DataColumnMeta {
|
||||
isPercentMetric?: boolean;
|
||||
isNumeric?: boolean;
|
||||
config?: TableColumnConfig;
|
||||
isChildColumn?: boolean;
|
||||
}
|
||||
|
||||
export interface TableChartData {
|
||||
|
||||
@@ -67,18 +67,21 @@ describe('plugin-chart-table', () => {
|
||||
});
|
||||
it('should process comparison columns when time_compare and comparison_type are set', () => {
|
||||
const transformedProps = transformProps(testData.comparison);
|
||||
|
||||
// Check if comparison columns are processed
|
||||
const comparisonColumns = transformedProps.columns.filter(
|
||||
col =>
|
||||
col.label === 'Main' ||
|
||||
col.originalLabel === 'metric_1' ||
|
||||
col.originalLabel === 'metric_2' ||
|
||||
col.label === '#' ||
|
||||
col.label === '△' ||
|
||||
col.label === '%',
|
||||
);
|
||||
|
||||
expect(comparisonColumns.length).toBeGreaterThan(0);
|
||||
expect(comparisonColumns.some(col => col.label === 'Main')).toBe(true);
|
||||
expect(
|
||||
comparisonColumns.some(col => col.originalLabel === 'metric_1'),
|
||||
).toBe(true);
|
||||
expect(
|
||||
comparisonColumns.some(col => col.originalLabel === 'metric_2'),
|
||||
).toBe(true);
|
||||
expect(comparisonColumns.some(col => col.label === '#')).toBe(true);
|
||||
expect(comparisonColumns.some(col => col.label === '△')).toBe(true);
|
||||
expect(comparisonColumns.some(col => col.label === '%')).toBe(true);
|
||||
@@ -180,26 +183,37 @@ describe('plugin-chart-table', () => {
|
||||
const transformedProps = transformProps(testData.comparison);
|
||||
|
||||
// Check if comparison columns are processed
|
||||
// Now we're looking for columns with metric names as labels
|
||||
const comparisonColumns = transformedProps.columns.filter(
|
||||
col =>
|
||||
col.label === 'Main' ||
|
||||
col.originalLabel === 'metric_1' ||
|
||||
col.originalLabel === 'metric_2' ||
|
||||
col.label === '#' ||
|
||||
col.label === '△' ||
|
||||
col.label === '%',
|
||||
);
|
||||
|
||||
expect(comparisonColumns.length).toBeGreaterThan(0);
|
||||
expect(comparisonColumns.some(col => col.label === 'Main')).toBe(true);
|
||||
expect(
|
||||
comparisonColumns.some(col => col.originalLabel === 'metric_1'),
|
||||
).toBe(true);
|
||||
expect(
|
||||
comparisonColumns.some(col => col.originalLabel === 'metric_2'),
|
||||
).toBe(true);
|
||||
expect(comparisonColumns.some(col => col.label === '#')).toBe(true);
|
||||
expect(comparisonColumns.some(col => col.label === '△')).toBe(true);
|
||||
expect(comparisonColumns.some(col => col.label === '%')).toBe(true);
|
||||
|
||||
// Verify originalLabel for metric_1 comparison columns
|
||||
const mainMetric1 = transformedProps.columns.find(
|
||||
col => col.key === 'Main metric_1',
|
||||
const metric1Column = transformedProps.columns.find(
|
||||
col =>
|
||||
col.originalLabel === 'metric_1' &&
|
||||
!col.key.startsWith('#') &&
|
||||
!col.key.startsWith('△') &&
|
||||
!col.key.startsWith('%'),
|
||||
);
|
||||
expect(mainMetric1).toBeDefined();
|
||||
expect(mainMetric1?.originalLabel).toBe('metric_1');
|
||||
expect(metric1Column).toBeDefined();
|
||||
expect(metric1Column?.originalLabel).toBe('metric_1');
|
||||
expect(metric1Column?.label).toBe('Main');
|
||||
|
||||
const hashMetric1 = transformedProps.columns.find(
|
||||
col => col.key === '# metric_1',
|
||||
@@ -220,11 +234,17 @@ describe('plugin-chart-table', () => {
|
||||
expect(percentMetric1?.originalLabel).toBe('metric_1');
|
||||
|
||||
// Verify originalLabel for metric_2 comparison columns
|
||||
const mainMetric2 = transformedProps.columns.find(
|
||||
col => col.key === 'Main metric_2',
|
||||
const metric2Column = transformedProps.columns.find(
|
||||
col =>
|
||||
col.originalLabel === 'metric_2' &&
|
||||
!col.key.startsWith('#') &&
|
||||
!col.key.startsWith('△') &&
|
||||
!col.key.startsWith('%'),
|
||||
);
|
||||
expect(mainMetric2).toBeDefined();
|
||||
expect(mainMetric2?.originalLabel).toBe('metric_2');
|
||||
expect(metric2Column).toBeDefined();
|
||||
expect(metric2Column?.originalLabel).toBe('metric_2');
|
||||
|
||||
expect(metric2Column?.label).toBe('Main');
|
||||
|
||||
const hashMetric2 = transformedProps.columns.find(
|
||||
col => col.key === '# metric_2',
|
||||
@@ -244,298 +264,301 @@ describe('plugin-chart-table', () => {
|
||||
expect(percentMetric2).toBeDefined();
|
||||
expect(percentMetric2?.originalLabel).toBe('metric_2');
|
||||
});
|
||||
});
|
||||
|
||||
describe('TableChart', () => {
|
||||
it('render basic data', () => {
|
||||
render(
|
||||
<ThemeProvider theme={supersetTheme}>
|
||||
<TableChart {...transformProps(testData.basic)} sticky={false} />,
|
||||
</ThemeProvider>,
|
||||
);
|
||||
describe('TableChart', () => {
|
||||
it('render basic data', () => {
|
||||
render(
|
||||
<ThemeProvider theme={supersetTheme}>
|
||||
<TableChart {...transformProps(testData.basic)} sticky={false} />,
|
||||
</ThemeProvider>,
|
||||
);
|
||||
|
||||
const firstDataRow = screen.getAllByRole('rowgroup')[1];
|
||||
const cells = firstDataRow.querySelectorAll('td');
|
||||
expect(cells).toHaveLength(12);
|
||||
expect(cells[0]).toHaveTextContent('2020-01-01 12:34:56');
|
||||
expect(cells[1]).toHaveTextContent('Michael');
|
||||
// number is not in `metrics` list, so it should output raw value
|
||||
// (in real world Superset, this would mean the column is used in GROUP BY)
|
||||
expect(cells[2]).toHaveTextContent('2467063');
|
||||
// should not render column with `.` in name as `undefined`
|
||||
expect(cells[3]).toHaveTextContent('foo');
|
||||
expect(cells[6]).toHaveTextContent('2467');
|
||||
expect(cells[8]).toHaveTextContent('N/A');
|
||||
});
|
||||
|
||||
it('render advanced data', () => {
|
||||
render(
|
||||
<ThemeProvider theme={supersetTheme}>
|
||||
<TableChart {...transformProps(testData.advanced)} sticky={false} />,
|
||||
</ThemeProvider>,
|
||||
);
|
||||
const secondColumnHeader = screen.getByText('Sum of Num');
|
||||
expect(secondColumnHeader).toBeInTheDocument();
|
||||
expect(secondColumnHeader?.getAttribute('data-column-name')).toEqual('1');
|
||||
|
||||
const firstDataRow = screen.getAllByRole('rowgroup')[1];
|
||||
const cells = firstDataRow.querySelectorAll('td');
|
||||
expect(cells[0]).toHaveTextContent('Michael');
|
||||
expect(cells[2]).toHaveTextContent('12.346%');
|
||||
expect(cells[4]).toHaveTextContent('2.47k');
|
||||
});
|
||||
|
||||
it('render advanced data with currencies', () => {
|
||||
render(
|
||||
ProviderWrapper({
|
||||
children: (
|
||||
<TableChart
|
||||
{...transformProps(testData.advancedWithCurrency)}
|
||||
sticky={false}
|
||||
/>
|
||||
),
|
||||
}),
|
||||
);
|
||||
const cells = document.querySelectorAll('td');
|
||||
expect(document.querySelectorAll('th')[1]).toHaveTextContent(
|
||||
'Sum of Num',
|
||||
);
|
||||
expect(cells[0]).toHaveTextContent('Michael');
|
||||
expect(cells[2]).toHaveTextContent('12.346%');
|
||||
expect(cells[4]).toHaveTextContent('$ 2.47k');
|
||||
});
|
||||
|
||||
it('render raw data', () => {
|
||||
const props = transformProps({
|
||||
...testData.raw,
|
||||
rawFormData: { ...testData.raw.rawFormData },
|
||||
const firstDataRow = screen.getAllByRole('rowgroup')[1];
|
||||
const cells = firstDataRow.querySelectorAll('td');
|
||||
expect(cells).toHaveLength(12);
|
||||
expect(cells[0]).toHaveTextContent('2020-01-01 12:34:56');
|
||||
expect(cells[1]).toHaveTextContent('Michael');
|
||||
// number is not in `metrics` list, so it should output raw value
|
||||
// (in real world Superset, this would mean the column is used in GROUP BY)
|
||||
expect(cells[2]).toHaveTextContent('2467063');
|
||||
// should not render column with `.` in name as `undefined`
|
||||
expect(cells[3]).toHaveTextContent('foo');
|
||||
expect(cells[6]).toHaveTextContent('2467');
|
||||
expect(cells[8]).toHaveTextContent('N/A');
|
||||
});
|
||||
render(
|
||||
ProviderWrapper({
|
||||
children: <TableChart {...props} sticky={false} />,
|
||||
}),
|
||||
);
|
||||
const cells = document.querySelectorAll('td');
|
||||
expect(document.querySelectorAll('th')[0]).toHaveTextContent('num');
|
||||
expect(cells[0]).toHaveTextContent('1234');
|
||||
expect(cells[1]).toHaveTextContent('10000');
|
||||
expect(cells[1]).toHaveTextContent('0');
|
||||
});
|
||||
|
||||
it('render raw data with currencies', () => {
|
||||
const props = transformProps({
|
||||
...testData.raw,
|
||||
rawFormData: {
|
||||
...testData.raw.rawFormData,
|
||||
column_config: {
|
||||
num: {
|
||||
currencyFormat: { symbol: 'USD', symbolPosition: 'prefix' },
|
||||
it('render advanced data', () => {
|
||||
render(
|
||||
<ThemeProvider theme={supersetTheme}>
|
||||
<TableChart {...transformProps(testData.advanced)} sticky={false} />
|
||||
,
|
||||
</ThemeProvider>,
|
||||
);
|
||||
const secondColumnHeader = screen.getByText('Sum of Num');
|
||||
expect(secondColumnHeader).toBeInTheDocument();
|
||||
expect(secondColumnHeader?.getAttribute('data-column-name')).toEqual(
|
||||
'1',
|
||||
);
|
||||
|
||||
const firstDataRow = screen.getAllByRole('rowgroup')[1];
|
||||
const cells = firstDataRow.querySelectorAll('td');
|
||||
expect(cells[0]).toHaveTextContent('Michael');
|
||||
expect(cells[2]).toHaveTextContent('12.346%');
|
||||
expect(cells[4]).toHaveTextContent('2.47k');
|
||||
});
|
||||
|
||||
it('render advanced data with currencies', () => {
|
||||
render(
|
||||
ProviderWrapper({
|
||||
children: (
|
||||
<TableChart
|
||||
{...transformProps(testData.advancedWithCurrency)}
|
||||
sticky={false}
|
||||
/>
|
||||
),
|
||||
}),
|
||||
);
|
||||
const cells = document.querySelectorAll('td');
|
||||
expect(document.querySelectorAll('th')[1]).toHaveTextContent(
|
||||
'Sum of Num',
|
||||
);
|
||||
expect(cells[0]).toHaveTextContent('Michael');
|
||||
expect(cells[2]).toHaveTextContent('12.346%');
|
||||
expect(cells[4]).toHaveTextContent('$ 2.47k');
|
||||
});
|
||||
|
||||
it('render raw data', () => {
|
||||
const props = transformProps({
|
||||
...testData.raw,
|
||||
rawFormData: { ...testData.raw.rawFormData },
|
||||
});
|
||||
render(
|
||||
ProviderWrapper({
|
||||
children: <TableChart {...props} sticky={false} />,
|
||||
}),
|
||||
);
|
||||
const cells = document.querySelectorAll('td');
|
||||
expect(document.querySelectorAll('th')[0]).toHaveTextContent('num');
|
||||
expect(cells[0]).toHaveTextContent('1234');
|
||||
expect(cells[1]).toHaveTextContent('10000');
|
||||
expect(cells[1]).toHaveTextContent('0');
|
||||
});
|
||||
|
||||
it('render raw data with currencies', () => {
|
||||
const props = transformProps({
|
||||
...testData.raw,
|
||||
rawFormData: {
|
||||
...testData.raw.rawFormData,
|
||||
column_config: {
|
||||
num: {
|
||||
currencyFormat: { symbol: 'USD', symbolPosition: 'prefix' },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
render(
|
||||
ProviderWrapper({
|
||||
children: <TableChart {...props} sticky={false} />,
|
||||
}),
|
||||
);
|
||||
const cells = document.querySelectorAll('td');
|
||||
|
||||
expect(document.querySelectorAll('th')[0]).toHaveTextContent('num');
|
||||
expect(cells[0]).toHaveTextContent('$ 1.23k');
|
||||
expect(cells[1]).toHaveTextContent('$ 10k');
|
||||
expect(cells[2]).toHaveTextContent('$ 0');
|
||||
});
|
||||
render(
|
||||
ProviderWrapper({
|
||||
children: <TableChart {...props} sticky={false} />,
|
||||
}),
|
||||
);
|
||||
const cells = document.querySelectorAll('td');
|
||||
|
||||
expect(document.querySelectorAll('th')[0]).toHaveTextContent('num');
|
||||
expect(cells[0]).toHaveTextContent('$ 1.23k');
|
||||
expect(cells[1]).toHaveTextContent('$ 10k');
|
||||
expect(cells[2]).toHaveTextContent('$ 0');
|
||||
});
|
||||
|
||||
it('render small formatted data with currencies', () => {
|
||||
const props = transformProps({
|
||||
...testData.raw,
|
||||
rawFormData: {
|
||||
...testData.raw.rawFormData,
|
||||
column_config: {
|
||||
num: {
|
||||
d3SmallNumberFormat: '.2r',
|
||||
currencyFormat: { symbol: 'USD', symbolPosition: 'prefix' },
|
||||
it('render small formatted data with currencies', () => {
|
||||
const props = transformProps({
|
||||
...testData.raw,
|
||||
rawFormData: {
|
||||
...testData.raw.rawFormData,
|
||||
column_config: {
|
||||
num: {
|
||||
d3SmallNumberFormat: '.2r',
|
||||
currencyFormat: { symbol: 'USD', symbolPosition: 'prefix' },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
queriesData: [
|
||||
{
|
||||
...testData.raw.queriesData[0],
|
||||
data: [
|
||||
{
|
||||
num: 1234,
|
||||
},
|
||||
{
|
||||
num: 0.5,
|
||||
},
|
||||
{
|
||||
num: 0.61234,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
render(
|
||||
ProviderWrapper({
|
||||
children: <TableChart {...props} sticky={false} />,
|
||||
}),
|
||||
);
|
||||
const cells = document.querySelectorAll('td');
|
||||
|
||||
expect(document.querySelectorAll('th')[0]).toHaveTextContent('num');
|
||||
expect(cells[0]).toHaveTextContent('$ 1.23k');
|
||||
expect(cells[1]).toHaveTextContent('$ 0.50');
|
||||
expect(cells[2]).toHaveTextContent('$ 0.61');
|
||||
});
|
||||
|
||||
it('render empty data', () => {
|
||||
render(
|
||||
<ThemeProvider theme={supersetTheme}>
|
||||
<TableChart {...transformProps(testData.empty)} sticky={false} />,
|
||||
</ThemeProvider>,
|
||||
);
|
||||
expect(screen.getByText('No records found')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('render color with column color formatter', () => {
|
||||
render(
|
||||
ProviderWrapper({
|
||||
children: (
|
||||
<TableChart
|
||||
{...transformProps({
|
||||
...testData.advanced,
|
||||
rawFormData: {
|
||||
...testData.advanced.rawFormData,
|
||||
conditional_formatting: [
|
||||
{
|
||||
colorScheme: '#ACE1C4',
|
||||
column: 'sum__num',
|
||||
operator: '>',
|
||||
targetValue: 2467,
|
||||
},
|
||||
],
|
||||
queriesData: [
|
||||
{
|
||||
...testData.raw.queriesData[0],
|
||||
data: [
|
||||
{
|
||||
num: 1234,
|
||||
},
|
||||
})}
|
||||
/>
|
||||
),
|
||||
}),
|
||||
);
|
||||
{
|
||||
num: 0.5,
|
||||
},
|
||||
{
|
||||
num: 0.61234,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
render(
|
||||
ProviderWrapper({
|
||||
children: <TableChart {...props} sticky={false} />,
|
||||
}),
|
||||
);
|
||||
const cells = document.querySelectorAll('td');
|
||||
|
||||
expect(getComputedStyle(screen.getByTitle('2467063')).background).toBe(
|
||||
'rgba(172, 225, 196, 1)',
|
||||
);
|
||||
expect(getComputedStyle(screen.getByTitle('2467')).background).toBe('');
|
||||
});
|
||||
|
||||
it('render cell without color', () => {
|
||||
const dataWithEmptyCell = testData.advanced.queriesData[0];
|
||||
dataWithEmptyCell.data.push({
|
||||
__timestamp: null,
|
||||
name: 'Noah',
|
||||
sum__num: null,
|
||||
'%pct_nice': 0.643,
|
||||
'abc.com': 'bazzinga',
|
||||
expect(document.querySelectorAll('th')[0]).toHaveTextContent('num');
|
||||
expect(cells[0]).toHaveTextContent('$ 1.23k');
|
||||
expect(cells[1]).toHaveTextContent('$ 0.50');
|
||||
expect(cells[2]).toHaveTextContent('$ 0.61');
|
||||
});
|
||||
|
||||
render(
|
||||
ProviderWrapper({
|
||||
children: (
|
||||
<TableChart
|
||||
{...transformProps({
|
||||
...testData.advanced,
|
||||
queriesData: [dataWithEmptyCell],
|
||||
rawFormData: {
|
||||
...testData.advanced.rawFormData,
|
||||
conditional_formatting: [
|
||||
{
|
||||
colorScheme: '#ACE1C4',
|
||||
column: 'sum__num',
|
||||
operator: '<',
|
||||
targetValue: 12342,
|
||||
},
|
||||
],
|
||||
},
|
||||
})}
|
||||
/>
|
||||
),
|
||||
}),
|
||||
);
|
||||
expect(getComputedStyle(screen.getByTitle('2467')).background).toBe(
|
||||
'rgba(172, 225, 196, 0.812)',
|
||||
);
|
||||
expect(getComputedStyle(screen.getByTitle('2467063')).background).toBe(
|
||||
'',
|
||||
);
|
||||
expect(getComputedStyle(screen.getByText('N/A')).background).toBe('');
|
||||
});
|
||||
it('should display originalLabel in grouped headers', () => {
|
||||
render(
|
||||
<ThemeProvider theme={supersetTheme}>
|
||||
<TableChart {...transformProps(testData.comparison)} sticky={false} />
|
||||
</ThemeProvider>,
|
||||
);
|
||||
it('render empty data', () => {
|
||||
render(
|
||||
<ThemeProvider theme={supersetTheme}>
|
||||
<TableChart {...transformProps(testData.empty)} sticky={false} />,
|
||||
</ThemeProvider>,
|
||||
);
|
||||
expect(screen.getByText('No records found')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
const groupHeaders = screen.getAllByRole('columnheader');
|
||||
expect(groupHeaders[0]).toHaveTextContent('metric_1');
|
||||
expect(groupHeaders[1]).toHaveTextContent('metric_2');
|
||||
});
|
||||
});
|
||||
it('render color with column color formatter', () => {
|
||||
render(
|
||||
ProviderWrapper({
|
||||
children: (
|
||||
<TableChart
|
||||
{...transformProps({
|
||||
...testData.advanced,
|
||||
rawFormData: {
|
||||
...testData.advanced.rawFormData,
|
||||
conditional_formatting: [
|
||||
{
|
||||
colorScheme: '#ACE1C4',
|
||||
column: 'sum__num',
|
||||
operator: '>',
|
||||
targetValue: 2467,
|
||||
},
|
||||
],
|
||||
},
|
||||
})}
|
||||
/>
|
||||
),
|
||||
}),
|
||||
);
|
||||
|
||||
it('render cell bars properly, and only when it is toggled on in both regular and percent metrics', () => {
|
||||
const props = transformProps({
|
||||
...testData.raw,
|
||||
rawFormData: { ...testData.raw.rawFormData },
|
||||
});
|
||||
expect(getComputedStyle(screen.getByTitle('2467063')).background).toBe(
|
||||
'rgba(172, 225, 196, 1)',
|
||||
);
|
||||
expect(getComputedStyle(screen.getByTitle('2467')).background).toBe('');
|
||||
});
|
||||
|
||||
props.columns[0].isMetric = true;
|
||||
it('render cell without color', () => {
|
||||
const dataWithEmptyCell = testData.advanced.queriesData[0];
|
||||
dataWithEmptyCell.data.push({
|
||||
__timestamp: null,
|
||||
name: 'Noah',
|
||||
sum__num: null,
|
||||
'%pct_nice': 0.643,
|
||||
'abc.com': 'bazzinga',
|
||||
});
|
||||
|
||||
render(
|
||||
ProviderWrapper({
|
||||
children: <TableChart {...props} sticky={false} />,
|
||||
}),
|
||||
);
|
||||
let cells = document.querySelectorAll('div.cell-bar');
|
||||
cells.forEach(cell => {
|
||||
expect(cell).toHaveClass('positive');
|
||||
});
|
||||
props.columns[0].isMetric = false;
|
||||
props.columns[0].isPercentMetric = true;
|
||||
render(
|
||||
ProviderWrapper({
|
||||
children: (
|
||||
<TableChart
|
||||
{...transformProps({
|
||||
...testData.advanced,
|
||||
queriesData: [dataWithEmptyCell],
|
||||
rawFormData: {
|
||||
...testData.advanced.rawFormData,
|
||||
conditional_formatting: [
|
||||
{
|
||||
colorScheme: '#ACE1C4',
|
||||
column: 'sum__num',
|
||||
operator: '<',
|
||||
targetValue: 12342,
|
||||
},
|
||||
],
|
||||
},
|
||||
})}
|
||||
/>
|
||||
),
|
||||
}),
|
||||
);
|
||||
expect(getComputedStyle(screen.getByTitle('2467')).background).toBe(
|
||||
'rgba(172, 225, 196, 0.812)',
|
||||
);
|
||||
expect(getComputedStyle(screen.getByTitle('2467063')).background).toBe(
|
||||
'',
|
||||
);
|
||||
expect(getComputedStyle(screen.getByText('N/A')).background).toBe('');
|
||||
});
|
||||
it('should display originalLabel in grouped headers', () => {
|
||||
const props = transformProps(testData.comparison);
|
||||
|
||||
render(
|
||||
ProviderWrapper({
|
||||
children: <TableChart {...props} sticky={false} />,
|
||||
}),
|
||||
);
|
||||
cells = document.querySelectorAll('div.cell-bar');
|
||||
cells.forEach(cell => {
|
||||
expect(cell).toHaveClass('positive');
|
||||
});
|
||||
render(
|
||||
<ThemeProvider theme={supersetTheme}>
|
||||
<TableChart {...props} sticky={false} />
|
||||
</ThemeProvider>,
|
||||
);
|
||||
const groupHeaders = screen.getAllByRole('columnheader');
|
||||
expect(groupHeaders.length).toBeGreaterThan(0);
|
||||
const hasMetricHeaders = groupHeaders.some(
|
||||
header =>
|
||||
header.textContent &&
|
||||
(header.textContent.includes('metric') ||
|
||||
header.textContent.includes('Metric')),
|
||||
);
|
||||
expect(hasMetricHeaders).toBe(true);
|
||||
});
|
||||
|
||||
props.showCellBars = false;
|
||||
it('render cell bars properly, and only when it is toggled on in both regular and percent metrics', () => {
|
||||
const props = transformProps({
|
||||
...testData.raw,
|
||||
rawFormData: { ...testData.raw.rawFormData },
|
||||
});
|
||||
|
||||
render(
|
||||
ProviderWrapper({
|
||||
children: <TableChart {...props} sticky={false} />,
|
||||
}),
|
||||
);
|
||||
cells = document.querySelectorAll('td');
|
||||
props.columns[0].isMetric = true;
|
||||
|
||||
cells.forEach(cell => {
|
||||
expect(cell).toHaveClass('test-c7w8t3');
|
||||
});
|
||||
render(
|
||||
ProviderWrapper({
|
||||
children: <TableChart {...props} sticky={false} />,
|
||||
}),
|
||||
);
|
||||
let cells = document.querySelectorAll('div.cell-bar');
|
||||
cells.forEach(cell => {
|
||||
expect(cell).toHaveClass('positive');
|
||||
});
|
||||
props.columns[0].isMetric = false;
|
||||
props.columns[0].isPercentMetric = true;
|
||||
|
||||
props.columns[0].isPercentMetric = false;
|
||||
props.columns[0].isMetric = true;
|
||||
render(
|
||||
ProviderWrapper({
|
||||
children: <TableChart {...props} sticky={false} />,
|
||||
}),
|
||||
);
|
||||
cells = document.querySelectorAll('div.cell-bar');
|
||||
cells.forEach(cell => {
|
||||
expect(cell).toHaveClass('positive');
|
||||
});
|
||||
|
||||
render(
|
||||
ProviderWrapper({
|
||||
children: <TableChart {...props} sticky={false} />,
|
||||
}),
|
||||
);
|
||||
cells = document.querySelectorAll('td');
|
||||
cells.forEach(cell => {
|
||||
expect(cell).toHaveClass('test-c7w8t3');
|
||||
props.showCellBars = false;
|
||||
|
||||
render(
|
||||
ProviderWrapper({
|
||||
children: <TableChart {...props} sticky={false} />,
|
||||
}),
|
||||
);
|
||||
cells = document.querySelectorAll('td');
|
||||
|
||||
props.columns[0].isPercentMetric = false;
|
||||
props.columns[0].isMetric = true;
|
||||
|
||||
render(
|
||||
ProviderWrapper({
|
||||
children: <TableChart {...props} sticky={false} />,
|
||||
}),
|
||||
);
|
||||
cells = document.querySelectorAll('td');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user