Skip to content

Commit

Permalink
[Feat] Add display format setting for table/tooltip (#2199)
Browse files Browse the repository at this point in the history
  • Loading branch information
igorDykhta committed Apr 18, 2023
1 parent 87b79c3 commit 3b73dc0
Show file tree
Hide file tree
Showing 19 changed files with 469 additions and 88 deletions.
16 changes: 8 additions & 8 deletions src/actions/src/vis-state-actions.ts
Expand Up @@ -622,31 +622,31 @@ export function copyTableColumn(

export type SetColumnDisplayFormatUpdaterAction = {
dataId: string;
column: string;
displayFormat: string;
formats: {
[key: string]: string;
};
};

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

Expand Down
177 changes: 177 additions & 0 deletions src/components/src/common/data-table/display-format.tsx
@@ -0,0 +1,177 @@
// Copyright (c) 2023 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

import React, {useCallback, useState} from 'react';
import styled from 'styled-components';

import {getFieldFormatLabels} from '@kepler.gl/utils';
import {ALL_FIELD_TYPES, TooltipFormat} from '@kepler.gl/constants';
import {ColMeta, ColMetaProps} from '@kepler.gl/types';

import {InputLight} from '../../common/styled-components';
import {FormatterDropdown} from './option-dropdown';

const StyledConfigPanel = styled.div`
background-color: ${props => props.theme.headerCellBackground};
box-shadow: 0 10px 18px 0 rgb(0 0 0 / 36%);
flex-grow: 1;
`;
const StyledConfigPanelContent = styled.div`
padding: 20px;
min-width: 230px;
max-height: 400px;
overflow: overlay;
`;

const StyledTableConfigGroup = styled.div`
margin-bottom: 10px;
display: flex;
align-items: center;
input {
cursor: pointer !important;
width: 184px;
height: 22px;
}
`;

export type DataTableConfigProps = {
title: string;
id: string;
defaultFormat: string;
options: TooltipFormat[];
columns: {name: string}[];
colMeta: ColMeta;
setColumnDisplayFormat: (formats: {[key: string]: string}) => void;
onClose: () => void;
};

export const NumberFormatConfig: React.FC<DataTableConfigProps> = ({
title,
id,
defaultFormat,
options,
columns,
setColumnDisplayFormat,
onClose
}: DataTableConfigProps) => {
const [showFormatter, setShowFormatter] = useState(false);
const [format, setFormat] = useState(defaultFormat);

const onSetDisplayFormat = useCallback(
(option: TooltipFormat) => {
setFormat(option.label);
const formats: {[key: string]: string} = columns.reduce((prev, col) => {
prev[col.name] = option.format;
return prev;
}, {});
setColumnDisplayFormat(formats);
onClose();
},
[columns, setColumnDisplayFormat, onClose]
);

return (
<StyledTableConfigGroup>
<InputLight
id={id}
type="text"
value={title}
data-tip={format}
readOnly
onClick={() => setShowFormatter(true)}
/>
<FormatterDropdown
left={-185}
top={10}
isOpened={showFormatter}
displayFormat={format}
setDisplayFormat={onSetDisplayFormat}
onClose={() => setShowFormatter(false)}
formatLabels={options}
/>
</StyledTableConfigGroup>
);
};

function DataTableConfigFactory() {
const getColumnsByFieldType = (columns: string[], colMeta: ColMeta, fieldType: string) => {
const result: ColMetaProps[] = [];
columns.forEach(colName => {
if (colMeta[colName]?.type === fieldType) {
result.push(colMeta[colName]);
}
});
return result;
};

const DataTableConfig = ({columns, colMeta, setColumnDisplayFormat, onClose}) => {
const formatConfigs = [
{
title: '# Set Integer Number Format',
id: 'input-iteger-format',
displayType: ALL_FIELD_TYPES.integer
},
{
title: '# Set Float Number Format',
id: 'input-float-format',
displayType: ALL_FIELD_TYPES.real
},
{
title: '# Set Timestamp Format',
id: 'input-datetime-format',
displayType: ALL_FIELD_TYPES.timestamp
},
{
title: '# Set Date Format',
id: 'input-date-format',
displayType: ALL_FIELD_TYPES.date
},
{
title: '# Set Boolean Format',
id: 'input-bool-format',
displayType: ALL_FIELD_TYPES.boolean
}
];

return (
<StyledConfigPanel>
<StyledConfigPanelContent>
{formatConfigs.map((config, index) => (
<NumberFormatConfig
title={`${config.title}`}
key={index}
id={config.id}
defaultFormat={'None'}
colMeta={colMeta}
options={getFieldFormatLabels(`${config.displayType}`)}
columns={getColumnsByFieldType(columns, colMeta, `${config.displayType}`)}
setColumnDisplayFormat={setColumnDisplayFormat}
onClose={onClose}
/>
))}
</StyledConfigPanelContent>
</StyledConfigPanel>
);
};
return DataTableConfig;
}

export default DataTableConfigFactory;
8 changes: 4 additions & 4 deletions src/components/src/common/data-table/header-cell.tsx
Expand Up @@ -106,7 +106,7 @@ const HeaderCellFactory = (FieldToken: React.FC<FieldTokenProps>) => {
sortTableColumn,
pinTableColumn,
copyTableColumn,
setDisplayFormat
setColumnDisplayFormat
} = props;
const [showFormatter, setShowFormatter] = useState(false);
const column = columns[columnIndex];
Expand All @@ -125,9 +125,9 @@ const HeaderCellFactory = (FieldToken: React.FC<FieldTokenProps>) => {
const onCopy = useCallback(() => copyTableColumn(column), [copyTableColumn, column]);
const onSetDisplayFormat = useCallback(
displayFormat => {
setDisplayFormat(column, displayFormat.format);
setColumnDisplayFormat({[column]: displayFormat.format});
},
[column, setDisplayFormat]
[column, setColumnDisplayFormat]
);

const onToggleDisplayFormat = useCallback(() => {
Expand Down Expand Up @@ -172,7 +172,7 @@ const HeaderCellFactory = (FieldToken: React.FC<FieldTokenProps>) => {
left={0}
top={0}
isOpened={isFormatted && showFormatter}
column={colMeta[column]}
displayFormat={colMeta[column].displayFormat}
setDisplayFormat={onSetDisplayFormat}
onClose={() => setShowFormatter(false)}
formatLabels={formatLabels}
Expand Down
2 changes: 1 addition & 1 deletion src/components/src/common/data-table/index.tsx
Expand Up @@ -390,7 +390,7 @@ export interface DataTableProps {
sortColumn: SortColumn;
sortTableColumn: (column: string, mode?: string) => void;
pinTableColumn: (column: string) => void;
setDisplayFormat: (column: string, displayFormat: string) => void;
setColumnDisplayFormat: (formats: {[key: string]: string}) => void;
copyTableColumn: (column: string) => void;
sortOrder?: number[] | null;
showStats?: boolean;
Expand Down
22 changes: 15 additions & 7 deletions src/components/src/common/data-table/option-dropdown.tsx
Expand Up @@ -24,7 +24,7 @@ import Portaled from '../portaled';
import DropdownList from '../item-selector/dropdown-list';
import {SORT_ORDER, TABLE_OPTION, TABLE_OPTION_LIST, TooltipFormat} from '@kepler.gl/constants';
import {getFieldFormatLabels} from '@kepler.gl/utils';
import {ColMeta, ColMetaProps} from '@kepler.gl/types';
import {ColMeta} from '@kepler.gl/types';
import {ArrowDown, ArrowUp, Clipboard, Pin, Cancel, Hash} from '../icons';

const ListItem = ({value}) => (
Expand Down Expand Up @@ -80,17 +80,25 @@ export type FormatterDropdownProps = {
left: number;
top: number;
isOpened: boolean;
column: ColMetaProps;
setDisplayFormat: (displayFormat: string) => void;
displayFormat?: string;
setDisplayFormat: (displayFormat: TooltipFormat) => void;
onClose: () => void;
formatLabels: TooltipFormat[];
};

export const FormatterDropdown: React.FC<FormatterDropdownProps> = (
props: FormatterDropdownProps
) => {
const {left, top, isOpened, column, setDisplayFormat, onClose, formatLabels} = props;
const selectionIndex = formatLabels.findIndex(label => label.format === column.displayFormat);
const {
left,
top,
isOpened,
displayFormat = 'None',
setDisplayFormat,
onClose,
formatLabels
} = props;
const selectionIndex = formatLabels.findIndex(label => label.format === displayFormat);

const onSelectDisplayFormat = useCallback(
(result, e) => {
Expand Down Expand Up @@ -123,7 +131,7 @@ interface OptionDropdownProps {
sortTableColumn: (sort: string) => void;
pinTableColumn: () => void;
copyTableColumn: () => void;
setDisplayFormat: (displayFormat: string) => void;
setDisplayFormat: (displayFormat: any) => void;
sortMode?: string;
isSorted?: string;
isPinned?: boolean;
Expand Down Expand Up @@ -214,7 +222,7 @@ const OptionDropdown = (props: OptionDropdownProps) => {
top={-10}
isOpened={Boolean(isOpened && showFormatter)}
formatLabels={formatLabels}
column={colMeta[column]}
displayFormat={colMeta[column]?.displayFormat}
setDisplayFormat={setDisplayFormat}
onClose={onClose}
/>
Expand Down
2 changes: 1 addition & 1 deletion src/components/src/common/field-selector.tsx
Expand Up @@ -107,7 +107,7 @@ interface FieldSelectorFactoryProps {
closeOnSelect?: boolean;
showToken?: boolean;
suggested?: ReadonlyArray<string | number | boolean | object> | null;
CustomChickletComponent?: ComponentType;
CustomChickletComponent?: ComponentType<any>;
size?: string;
}

Expand Down
1 change: 1 addition & 0 deletions src/components/src/index.ts
Expand Up @@ -222,6 +222,7 @@ export {default as SliderHandle} from './common/slider/slider-handle';
export {default as SliderBarHandle} from './common/slider/slider-bar-handle';
export {default as ActionPanel, ActionPanelItem} from './common/action-panel';
export {default as HeaderCellFactory} from './common/data-table/header-cell';
export {default as DataTableConfigFactory, NumberFormatConfig} from './common/data-table/display-format';
export {default as DataTableFactory} from './common/data-table';
export {default as CanvasHack} from './common/data-table/canvas';
export {default as OptionDropdown, FormatterDropdown} from './common/data-table/option-dropdown';
Expand Down
17 changes: 9 additions & 8 deletions src/components/src/map/layer-hover-info.tsx
Expand Up @@ -133,14 +133,15 @@ const EntryInfoRow = ({item, fields, data, primaryData, compareType}) => {
const value = data.valueAt(fieldIdx);
const displayValue = getTooltipDisplayValue({item, field, value});

const displayDeltaValue = getTooltipDisplayDeltaValue({
item,
field,
data,
fieldIdx,
primaryData,
compareType
});
const displayDeltaValue = primaryData
? getTooltipDisplayDeltaValue({
field,
data,
fieldIdx,
primaryData,
compareType
})
: null;

return (
<Row
Expand Down

0 comments on commit 3b73dc0

Please sign in to comment.