Skip to content
This repository has been archived by the owner on Dec 10, 2021. It is now read-only.

feat(plugin-chart-table): add small number formatter #1028

Merged
merged 2 commits into from
Mar 29, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ export function InfoTooltipWithTrigger({
onClick={onClick}
onKeyPress={
onClick &&
((event: React.KeyboardEvent) => {
(event => {
if (event.key === 'Enter' || event.key === ' ') {
onClick();
}
Expand Down
32 changes: 25 additions & 7 deletions packages/superset-ui-chart-controls/src/components/Select.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
* specific language governing permissions and limitations
* under the License.
*/
import React, { useState, ReactNode, ReactElement } from 'react';
import AntdSelect, { SelectProps as AntdSelectProps, OptionProps } from 'antd/lib/select';
import React, { useState, ReactNode } from 'react';
import AntdSelect, { SelectProps as AntdSelectProps } from 'antd/lib/select';

export const { Option } = AntdSelect;

Expand All @@ -34,12 +34,14 @@ export type SelectProps<VT> = Omit<AntdSelectProps<VT>, 'options'> & {
*/
export default function Select<VT extends string | number>({
creatable,
children,
onSearch,
dropdownMatchSelectWidth = false,
minWidth = '100%',
showSearch: showSearch_ = true,
onChange,
options,
children,
value,
...props
}: SelectProps<VT>) {
const [searchValue, setSearchValue] = useState<string>();
Expand All @@ -56,15 +58,26 @@ export default function Select<VT extends string | number>({
}
: undefined;

const searchValueNotFound = React.Children.toArray(children).every(
node => node && (node as ReactElement<OptionProps>).props.value !== searchValue,
);
const optionsHasSearchValue = options?.some(([val]) => val === searchValue);
const optionsHasValue = options?.some(([val]) => val === value);

const handleChange: SelectProps<VT>['onChange'] = showSearch
? (val, opt) => {
// reset input value once selected
setSearchValue('');
if (onChange) {
onChange(val, opt);
}
}
: onChange;

return (
<AntdSelect<VT>
dropdownMatchSelectWidth={dropdownMatchSelectWidth}
showSearch={showSearch}
onSearch={handleSearch}
onChange={handleChange}
value={value}
{...props}
css={{
minWidth,
Expand All @@ -74,7 +87,12 @@ export default function Select<VT extends string | number>({
<Option value={val}>{label}</Option>
))}
{children}
{searchValue && searchValueNotFound && (
{value && !optionsHasValue && (
<Option key={value} value={value}>
{value}
</Option>
)}
{searchValue && !optionsHasSearchValue && (
<Option key={searchValue} value={searchValue}>
{/* Unfortunately AntD select does not support displaying different
label for option vs select value, so we can't use
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,98 +34,116 @@ export type SharedColumnConfigProp =
| 'columnWidth'
| 'fractionDigits'
| 'd3NumberFormat'
| 'd3SmallNumberFormat'
| 'd3TimeFormat'
| 'horizontalAlign'
| 'showCellBars';

/**
* All configurable column formatting properties.
*/
export const SHARED_COLUMN_CONFIG_PROPS = {
d3NumberFormat: {
controlType: 'Select',
label: t('D3 format'),
description: D3_FORMAT_DOCS,
options: D3_FORMAT_OPTIONS,
defaultValue: D3_FORMAT_OPTIONS[0][0],
creatable: true,
minWidth: '10em',
debounceDelay: 400,
} as ControlFormItemSpec<'Select'>,
const d3NumberFormat: ControlFormItemSpec<'Select'> = {
controlType: 'Select',
label: t('D3 format'),
description: D3_FORMAT_DOCS,
options: D3_FORMAT_OPTIONS,
defaultValue: D3_FORMAT_OPTIONS[0][0],
creatable: true,
minWidth: '14em',
debounceDelay: 500,
};

d3TimeFormat: {
controlType: 'Select',
label: t('D3 format'),
description: D3_TIME_FORMAT_DOCS,
options: D3_TIME_FORMAT_OPTIONS,
defaultValue: D3_TIME_FORMAT_OPTIONS[0][0],
creatable: true,
minWidth: '10em',
debounceDelay: 400,
} as ControlFormItemSpec<'Select'>,
const d3TimeFormat: ControlFormItemSpec<'Select'> = {
controlType: 'Select',
label: t('D3 format'),
description: D3_TIME_FORMAT_DOCS,
options: D3_TIME_FORMAT_OPTIONS,
defaultValue: D3_TIME_FORMAT_OPTIONS[0][0],
creatable: true,
minWidth: '10em',
debounceDelay: 500,
};

fractionDigits: {
controlType: 'Slider',
label: t('Fraction digits'),
description: t('Number of decimal digits to round numbers to'),
min: 0,
step: 1,
max: 100,
defaultValue: 100,
} as ControlFormItemSpec<'Slider'>,
const fractionDigits: ControlFormItemSpec<'Slider'> = {
controlType: 'Slider',
label: t('Fraction digits'),
description: t('Number of decimal digits to round numbers to'),
min: 0,
step: 1,
max: 100,
defaultValue: 100,
};

columnWidth: {
controlType: 'InputNumber',
label: t('Width'),
description: t(
'Default column width in pixels, may still be restricted by the shortest/longest word in the column',
),
width: 120,
placeholder: 'auto',
debounceDelay: 400,
validators: [validateNumber],
} as ControlFormItemSpec<'InputNumber'>,
const columnWidth: ControlFormItemSpec<'InputNumber'> = {
controlType: 'InputNumber',
label: t('Width'),
description: t(
'Default column width in pixels, may still be restricted by the shortest/longest word in the column',
),
width: 120,
placeholder: 'auto',
debounceDelay: 400,
validators: [validateNumber],
};

horizontalAlign: {
controlType: 'RadioButtonControl',
label: t('Text align'),
description: t('Horizontal alignment'),
width: 130,
debounceDelay: 50,
defaultValue: 'left',
options: [
['left', <FaAlignLeft title={t('Left')} />],
['center', <FaAlignCenter title={t('Center')} />],
['right', <FaAlignRight title={t('Right')} />],
],
} as ControlFormItemSpec<'RadioButtonControl'> & {
value: 'left' | 'right' | 'center';
defaultValue: 'left' | 'right' | 'center';
},
const horizontalAlign: ControlFormItemSpec<'RadioButtonControl'> & {
value?: 'left' | 'right' | 'center';
defaultValue?: 'left' | 'right' | 'center';
} = {
controlType: 'RadioButtonControl',
label: t('Text align'),
description: t('Horizontal alignment'),
width: 130,
debounceDelay: 50,
defaultValue: 'left',
options: [
['left', <FaAlignLeft title={t('Left')} />],
['center', <FaAlignCenter title={t('Center')} />],
['right', <FaAlignRight title={t('Right')} />],
],
};

const showCellBars: ControlFormItemSpec<'Checkbox'> = {
controlType: 'Checkbox',
label: t('Show cell bars'),
description: t('Whether to display a bar chart background in table columns'),
defaultValue: true,
debounceDelay: 200,
};

showCellBars: {
controlType: 'Checkbox',
label: t('Show cell bars'),
description: t('Whether to display a bar chart background in table columns'),
defaultValue: true,
debounceDelay: 200,
} as ControlFormItemSpec<'Checkbox'>,
const alignPositiveNegative: ControlFormItemSpec<'Checkbox'> = {
controlType: 'Checkbox',
label: t('Align +/-'),
description: t('Whether to align positive and negative values in cell bar chart at 0'),
defaultValue: false,
debounceDelay: 200,
};

alignPositiveNegative: {
controlType: 'Checkbox',
label: t('Align +/-'),
description: t('Whether to align positive and negative values in cell bar chart at 0'),
defaultValue: false,
debounceDelay: 200,
} as ControlFormItemSpec<'Checkbox'>,
const colorPositiveNegative: ControlFormItemSpec<'Checkbox'> = {
controlType: 'Checkbox',
label: t('Color +/-'),
description: t('Whether to colorize numeric values by if they are positive or negative'),
defaultValue: false,
debounceDelay: 200,
};

colorPositiveNegative: {
controlType: 'Checkbox',
label: t('Color +/-'),
description: t('Whether to colorize numeric values by if they are positive or negative'),
defaultValue: false,
debounceDelay: 200,
} as ControlFormItemSpec<'Checkbox'>,
/**
* All configurable column formatting properties.
*/
export const SHARED_COLUMN_CONFIG_PROPS = {
d3NumberFormat,
d3SmallNumberFormat: {
...d3NumberFormat,
label: t('Small number format'),
description: t(
'D3 number format for numbers between -1.0 and 1.0, ' +
'useful when you want to have different siginificant digits for small and large numbers',
),
},
d3TimeFormat,
fractionDigits,
columnWidth,
horizontalAlign,
showCellBars,
alignPositiveNegative,
colorPositiveNegative,
};

export type SharedColumnConfig = {
Expand All @@ -139,7 +157,7 @@ export const DEFAULT_CONFIG_FORM_LAYOUT: ColumnConfigFormLayout = {
[GenericDataType.NUMERIC]: [
['columnWidth', { name: 'horizontalAlign', override: { defaultValue: 'right' } }],
['d3NumberFormat'],
['fractionDigits'],
['d3SmallNumberFormat'],
['alignPositiveNegative', 'colorPositiveNegative'],
['showCellBars'],
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ export const basic = ({ width, height }) => (
}}
width={width}
height={height}
queriesData={[{ data: basicData }]}
queriesData={[basicData]}
formData={basicFormData}
/>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,28 +16,38 @@
* specific language governing permissions and limitations
* under the License.
*/
import { TableChartProps } from '@superset-ui/plugin-chart-table/src';
import { ChartDataResponseResult, GenericDataType } from '@superset-ui/core/src';
import { TableChartFormData, TableChartProps } from '@superset-ui/plugin-chart-table/src';
// @ts-ignore
// eslint-disable-next-line import/extensions
import birthNamesJson from './birthNames.json';

export const birthNames = (birthNamesJson as unknown) as TableChartProps;
export const basicFormData = {
alignPn: false,
colorPn: false,
includeSearch: false,

export const basicFormData: TableChartFormData = {
datasource: '1__table',
viz_type: 'table',
align_pn: false,
color_pn: false,
include_search: true,
metrics: ['sum__num', 'MAX(ds)'],
orderDesc: true,
pageLength: 0,
percentMetrics: null,
showCellBars: true,
tableFilter: false,
tableTimestampFormat: 'smart_date',
timeseriesLimitMetric: null,
order_desc: true,
page_length: 0,
percent_metrics: null,
show_cell_bars: true,
table_filter: false,
table_timestamp_format: 'smart_date',
};
export const basicData = {
columns: ['name', 'sum__num', 'MAX(ds)', 'Abc.com'],
records: [

export const basicData: Partial<ChartDataResponseResult> = {
colnames: ['name', 'sum__num', 'MAX(ds)', 'Abc.com'],
coltypes: [
GenericDataType.STRING,
GenericDataType.NUMERIC,
GenericDataType.TEMPORAL,
GenericDataType.STRING,
],
data: [
{
name: 'Michael',
sum__num: 2467063,
Expand Down
Loading