Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feat] add table config with custom number format #2192

Merged
merged 5 commits into from
Apr 12, 2023
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions src/actions/src/action-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ export const ActionTypes = {
SORT_TABLE_COLUMN: `${ACTION_PREFIX}SORT_TABLE_COLUMN`,
PIN_TABLE_COLUMN: `${ACTION_PREFIX}PIN_TABLE_COLUMN`,
COPY_TABLE_COLUMN: `${ACTION_PREFIX}COPY_TABLE_COLUMN`,
SET_COLUMN_DISPLAY_FORMAT: `${ACTION_PREFIX}SET_COLUMN_DISPLAY_FORMAT`,
NEXT_FILE_BATCH: `${ACTION_PREFIX}NEXT_FILE_BATCH`,
PROCESS_FILE_CONTENT: `${ACTION_PREFIX}PROCESS_FILE_CONTENT`,
UPDATE_TABLE_COLOR: `${ACTION_PREFIX}UPDATE_TABLE_COLOR`,
Expand Down
30 changes: 30 additions & 0 deletions src/actions/src/vis-state-actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -620,6 +620,36 @@ export function copyTableColumn(
};
}

export type SetColumnDisplayFormatUpdaterAction = {
dataId: string;
column: string;
displayFormat: string;
};

/**
* Set column display format
* @param dataId
* @param column
* @param displayFormat
* @returns action
* @public
*/
export function setColumnDisplayFormat(
dataId: string,
column: string,
displayFormat: string
): Merge<
SetColumnDisplayFormatUpdaterAction,
{type: typeof ActionTypes.SET_COLUMN_DISPLAY_FORMAT}
> {
return {
type: ActionTypes.SET_COLUMN_DISPLAY_FORMAT,
dataId,
column,
displayFormat
};
}

export type AddDataToMapUpdaterOptions = {
centrMap?: boolean;
readOnly?: boolean;
Expand Down
52 changes: 48 additions & 4 deletions src/components/src/common/data-table/header-cell.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import React, {CSSProperties, useCallback} from 'react';
import React, {CSSProperties, useState, useCallback} from 'react';
import styled from 'styled-components';
import classnames from 'classnames';
import Button from './button';
import {ArrowUp, ArrowDown, VertThreeDots} from '../../common/icons';
import OptionDropdown from './option-dropdown';
import {ArrowUp, ArrowDown, VertThreeDots, Hash} from '../../common/icons';
import {SORT_ORDER} from '@kepler.gl/constants';
import OptionDropdown, {FormatterDropdown} from './option-dropdown';
import {getFieldFormatLabels} from '@kepler.gl/utils';
import {ColMeta} from '@kepler.gl/types';
import FieldTokenFactory, {FieldTokenProps} from '../../common/field-token';
import {DataTableProps} from './index';

Expand Down Expand Up @@ -58,6 +60,12 @@ const StyledHeaderCell = styled.div`
.more {
margin-left: 5px;
}

.col-name__format svg {
width: 10px;
height: 10px;
stroke-width: 1;
}
`;

type CellInfo = {
Expand All @@ -74,6 +82,7 @@ type HeaderCellProps = {
// passed down from react virtualized Grid
cellInfo: CellInfo;
columns: DataTableProps['columns'];
colMeta?: ColMeta;
isPinned?: boolean;
showStats?: boolean;
props: DataTableProps;
Expand All @@ -91,19 +100,40 @@ const HeaderCellFactory = (FieldToken: React.FC<FieldTokenProps>) => {
moreOptionsColumn
}: HeaderCellProps) => {
const {columnIndex, key, style} = cellInfo;
const {colMeta, sortColumn = {}, sortTableColumn, pinTableColumn, copyTableColumn} = props;
const {
colMeta,
sortColumn,
sortTableColumn,
pinTableColumn,
copyTableColumn,
setDisplayFormat
} = props;
const [showFormatter, setShowFormatter] = useState(false);
const column = columns[columnIndex];

const isGhost = column.ghost;
const isSorted = sortColumn[column];
const firstCell = columnIndex === 0;
const isFormatted = Boolean(colMeta[column]?.displayFormat);
const formatLabels = isFormatted ? getFieldFormatLabels(colMeta[column].type) : [];
const onSortTable = useCallback(() => sortTableColumn(column), [sortTableColumn, column]);
const onToggleOptionMenu = useCallback(() => toggleMoreOptions(column), [
toggleMoreOptions,
column
]);
const onPin = useCallback(() => pinTableColumn(column), [pinTableColumn, column]);
const onCopy = useCallback(() => copyTableColumn(column), [copyTableColumn, column]);
const onSetDisplayFormat = useCallback(
displayFormat => {
setDisplayFormat(column, displayFormat.format);
},
[column, setDisplayFormat]
);

const onToggleDisplayFormat = useCallback(() => {
setShowFormatter(!showFormatter);
}, [showFormatter]);

return (
<StyledHeaderCell
className={classnames('header-cell', {
Expand Down Expand Up @@ -136,6 +166,18 @@ const HeaderCellFactory = (FieldToken: React.FC<FieldTokenProps>) => {
)
) : null}
</Button>
<Button className="col-name__format" onClick={onToggleDisplayFormat}>
{isFormatted ? <Hash height="14px" /> : null}
<FormatterDropdown
left={0}
top={0}
isOpened={isFormatted && showFormatter}
column={colMeta[column]}
setDisplayFormat={onSetDisplayFormat}
onClose={() => setShowFormatter(false)}
formatLabels={formatLabels}
/>
</Button>
</div>
<Button className="more" onClick={onToggleOptionMenu}>
<VertThreeDots height="14px" />
Expand All @@ -148,10 +190,12 @@ const HeaderCellFactory = (FieldToken: React.FC<FieldTokenProps>) => {
<OptionDropdown
isOpened={moreOptionsColumn === column}
column={column}
colMeta={colMeta}
toggleMoreOptions={toggleMoreOptions}
sortTableColumn={mode => sortTableColumn(column, mode)}
pinTableColumn={onPin}
copyTableColumn={onCopy}
setDisplayFormat={onSetDisplayFormat}
/>
</section>
</>
Expand Down
34 changes: 11 additions & 23 deletions src/components/src/common/data-table/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ import {CellSizeCache} from './cell-size';
import Grid from './grid';
import HeaderCellFactory from './header-cell';

import {parseFieldValue, DataContainerInterface} from '@kepler.gl/utils';
import {ColMeta} from '@kepler.gl/types';
import {parseFieldValue, getColumnFormatter, DataContainerInterface} from '@kepler.gl/utils';
import {adjustCellsToContainer} from './cell-size';

import {ALL_FIELD_TYPES} from '@kepler.gl/constants';
Expand Down Expand Up @@ -189,17 +190,6 @@ export const Container = styled.div`

const defaultColumnWidth = 200;

export type ColMeta = {
[key: string]: {
colIdx: number;
name: string;
displayName: string;
type: string;
format?: string;
columnStats?: any;
};
};

export type SortColumn = {
column?: string;
mode?: string;
Expand All @@ -221,20 +211,16 @@ interface GetRowCellProps {
/*
* This is an accessor method used to generalize getting a cell from a data row
*/
const getRowCell = ({
dataContainer,
columns,
column,
colMeta,
rowIndex,
sortOrder
}: GetRowCellProps) => {
const getRowCell = (
{dataContainer, columns, column, colMeta, rowIndex, sortOrder}: GetRowCellProps,
formatter
) => {
const rowIdx = sortOrder && sortOrder.length ? get(sortOrder, rowIndex) : rowIndex;
const {type} = colMeta[column];

let value = dataContainer.valueAt(rowIdx, columns.indexOf(column));
if (value === undefined) value = 'Err';
return parseFieldValue(value, type);
return formatter ? formatter(value) : parseFieldValue(value, type);
};

type StatsControlProps = {
Expand Down Expand Up @@ -401,9 +387,10 @@ export interface DataTableProps {
dataContainer: DataContainerInterface;
fixedHeight?: number;
colMeta: ColMeta;
sortColumn?: SortColumn;
sortColumn: SortColumn;
sortTableColumn: (column: string, mode?: string) => void;
pinTableColumn: (column: string) => void;
setDisplayFormat: (column: string, displayFormat: string) => void;
copyTableColumn: (column: string) => void;
sortOrder?: number[] | null;
showStats?: boolean;
Expand Down Expand Up @@ -509,7 +496,8 @@ function DataTableFactory(HeaderCell: ReturnType<typeof HeaderCellFactory>) {
const column = columns[columnIndex];
const isGhost = column.ghost;

const rowCell = isGhost ? '' : getRowCell({...props, column, rowIndex});
const formatter = isGhost ? null : getColumnFormatter(colMeta[column]);
const rowCell = isGhost ? '' : getRowCell({...props, column, rowIndex}, formatter);
const type = isGhost ? null : colMeta[column].type;

const lastRowIndex = dataContainer ? dataContainer.numRows() - 1 : 0;
Expand Down