From 916c1c7dd4957c9181f3cbded57e5cb75d2a92cd Mon Sep 17 00:00:00 2001 From: Constance Chen Date: Tue, 9 Nov 2021 09:56:08 -0800 Subject: [PATCH 01/28] Rename styleSelector to displaySelector + update types & docs --- .../src/views/datagrid/datagrid_example.js | 23 ++++++++++--- .../datagrid_height_options_example.js | 32 +++++++++---------- .../datagrid/datagrid_styling_example.js | 11 ++++--- .../__snapshots__/data_grid.test.tsx.snap | 16 +++++----- ...sx.snap => display_selector.test.tsx.snap} | 14 ++++---- .../controls/data_grid_toolbar.test.tsx | 6 ++-- .../datagrid/controls/data_grid_toolbar.tsx | 6 ++-- ...tor.test.tsx => display_selector.test.tsx} | 16 +++++----- ...tyle_selector.tsx => display_selector.tsx} | 20 ++++++------ src/components/datagrid/controls/index.ts | 2 +- src/components/datagrid/data_grid.test.tsx | 4 +-- src/components/datagrid/data_grid.tsx | 6 ++-- src/components/datagrid/data_grid_types.ts | 22 ++++++++++++- src/components/datagrid/index.ts | 2 +- 14 files changed, 107 insertions(+), 73 deletions(-) rename src/components/datagrid/controls/__snapshots__/{style_selector.test.tsx.snap => display_selector.test.tsx.snap} (70%) rename src/components/datagrid/controls/{style_selector.test.tsx => display_selector.test.tsx} (81%) rename src/components/datagrid/controls/{style_selector.tsx => display_selector.tsx} (89%) diff --git a/src-docs/src/views/datagrid/datagrid_example.js b/src-docs/src/views/datagrid/datagrid_example.js index 4c5e4285dad..312adb29443 100644 --- a/src-docs/src/views/datagrid/datagrid_example.js +++ b/src-docs/src/views/datagrid/datagrid_example.js @@ -96,7 +96,7 @@ const gridSnippet = ` // The prop also accepts a boolean if you want to toggle the entire toolbar on/off. toolbarVisibility={{ showColumnSelector: false, - showStyleSelector: false, + showDisplaySelector: false, showSortSelector: false, showFullScreenSelector: false, additionalControls: { @@ -247,6 +247,13 @@ const gridConcepts = [ Data grid row heights options {' '} for more details and examples. +
+ Settings provided may be overwritten or merged with user defined + preferences if{' '} + + toolbarVisibility.showDisplaySelector.allowRowHeight + {' '} + is set to true (which is the default). ), }, @@ -255,10 +262,16 @@ const gridConcepts = [ description: ( Defines the look of the grid. Accepts a partial{' '} - EuiDataGridStyle object. Settings provided may be - overwritten or merged with user defined preferences if{' '} - toolbarVisibility.showStyleSelector is set to true - (which is the default). + EuiDataGridStyle object. See{' '} + + Data grid styling and control + {' '} + for more details and examples. +
+ Settings provided may be overwritten or merged with user defined + preferences if{' '} + toolbarVisibility.showDisplaySelector.allowDensity is + set to true (which is the default).
), }, diff --git a/src-docs/src/views/datagrid/datagrid_height_options_example.js b/src-docs/src/views/datagrid/datagrid_height_options_example.js index 596d9d2afd9..eec44f7f011 100644 --- a/src-docs/src/views/datagrid/datagrid_height_options_example.js +++ b/src-docs/src/views/datagrid/datagrid_height_options_example.js @@ -201,26 +201,26 @@ export const DataGridRowHeightOptionsExample = { text: (

- You can change the default height for all rows by passing a line - count or pixel value to the defaultHeight{' '} - property, and customize the line height of all cells with the{' '} - lineHeight property. + You can change the default height for all rows via the{' '} + defaultHeight property. Note that the{' '} + showDisplaySelector.allowRowHeight setting in{' '} + toolbarVisibility means the user has the ability + to override this default height. Users will be able to toggle + between single rows, a configurable line count, or{' '} + "auto". +

+

+ You can also customize the line height of all cells with the{' '} + lineHeight property. However, if you wrap your + cell content with CSS that overrides/sets line-height (e.g. in an{' '} + EuiText), your row heights will not be calculated + correctly - make sure to match the passed{' '} + lineHeight property to the actual cell content + line height.

{lineHeightSnippet} - -

- If you wrap your cell content with CSS that overrides/sets - line-height (e.g. in an EuiText), your row - heights will not be calculated correctly! Make sure to match or - inherit the passed lineHeight property to the - actual cell content line height. -

-
), components: { DataGridRowLineHeight }, diff --git a/src-docs/src/views/datagrid/datagrid_styling_example.js b/src-docs/src/views/datagrid/datagrid_styling_example.js index 332c4b1bc23..40cafa9aff3 100644 --- a/src-docs/src/views/datagrid/datagrid_styling_example.js +++ b/src-docs/src/views/datagrid/datagrid_styling_example.js @@ -55,7 +55,7 @@ const gridSnippet = `

- With the default settings, the showStyleSelector{' '} - setting in toolbarVisibility means the user has - the ability to override the padding and font size passed into{' '} + With the default settings, the{' '} + showDisplaySelector.allowDensity setting in{' '} + toolbarVisibility means the user has the ability + to override the padding and font size passed into{' '} gridStyle by the engineer. The font size overriding only works with text or elements that can inherit the parent font size or elements that use units relative to the parent diff --git a/src/components/datagrid/__snapshots__/data_grid.test.tsx.snap b/src/components/datagrid/__snapshots__/data_grid.test.tsx.snap index 02f793e0220..e7b8a263bb5 100644 --- a/src/components/datagrid/__snapshots__/data_grid.test.tsx.snap +++ b/src/components/datagrid/__snapshots__/data_grid.test.tsx.snap @@ -981,7 +981,7 @@ Array [ >

} closePopover={[Function]} - data-test-subj="dataGridStyleSelectorPopover" + data-test-subj="dataGridDisplaySelectorPopover" display="inlineBlock" hasArrow={true} isOpen={false} @@ -42,10 +42,10 @@ exports[`useDataGridStyleSelector styleSelector renders a toolbar button/popover } tokens={ Array [ - "euiStyleSelector.densityLabel", - "euiStyleSelector.labelCompact", - "euiStyleSelector.labelNormal", - "euiStyleSelector.labelExpanded", + "euiDisplaySelector.densityLabel", + "euiDisplaySelector.labelCompact", + "euiDisplaySelector.labelNormal", + "euiDisplaySelector.labelExpanded", ] } > diff --git a/src/components/datagrid/controls/data_grid_toolbar.test.tsx b/src/components/datagrid/controls/data_grid_toolbar.test.tsx index 4621c2f7c95..efe057bb6cc 100644 --- a/src/components/datagrid/controls/data_grid_toolbar.test.tsx +++ b/src/components/datagrid/controls/data_grid_toolbar.test.tsx @@ -20,7 +20,7 @@ describe('EuiDataGridToolbar', () => { gridWidth: 500, toolbarVisibility: true, isFullScreen: false, - styleSelector: React.createElement('div', null, 'mock style selector'), + displaySelector: React.createElement('div', null, 'mock style selector'), controlBtnClasses: '', columnSelector: React.createElement('div', null, 'mock column selector'), columnSorting:
mock column sorting
, @@ -99,7 +99,7 @@ describe('EuiDataGridToolbar', () => { {...requiredProps} toolbarVisibility={{ showColumnSelector: false, - showStyleSelector: false, + showDisplaySelector: false, showSortSelector: false, showFullScreenSelector: false, additionalControls: { @@ -159,7 +159,7 @@ describe('EuiDataGridToolbar', () => { }); describe('checkOrDefaultToolBarDisplayOptions', () => { - const key = 'showStyleSelector'; + const key = 'showDisplaySelector'; it('returns boolean `toolbarVisibility`s as-is', () => { expect(checkOrDefaultToolBarDisplayOptions(true, key)).toEqual(true); diff --git a/src/components/datagrid/controls/data_grid_toolbar.tsx b/src/components/datagrid/controls/data_grid_toolbar.tsx index d1b29488865..7574df594de 100644 --- a/src/components/datagrid/controls/data_grid_toolbar.tsx +++ b/src/components/datagrid/controls/data_grid_toolbar.tsx @@ -32,7 +32,7 @@ export const EuiDataGridToolbar = ({ toolbarVisibility, isFullScreen, controlBtnClasses, - styleSelector, + displaySelector, columnSelector, columnSorting, setRef, @@ -112,9 +112,9 @@ export const EuiDataGridToolbar = ({ {renderAdditionalControls(toolbarVisibility, 'right')} {checkOrDefaultToolBarDisplayOptions( toolbarVisibility, - 'showStyleSelector' + 'showDisplaySelector' ) - ? styleSelector + ? displaySelector : null} {checkOrDefaultToolBarDisplayOptions( toolbarVisibility, diff --git a/src/components/datagrid/controls/style_selector.test.tsx b/src/components/datagrid/controls/display_selector.test.tsx similarity index 81% rename from src/components/datagrid/controls/style_selector.test.tsx rename to src/components/datagrid/controls/display_selector.test.tsx index 509667f00ff..a78d73f7fd1 100644 --- a/src/components/datagrid/controls/style_selector.test.tsx +++ b/src/components/datagrid/controls/display_selector.test.tsx @@ -10,14 +10,14 @@ import React from 'react'; import { act } from 'react-dom/test-utils'; import { shallow, mount } from 'enzyme'; -import { useDataGridStyleSelector, startingStyles } from './style_selector'; +import { useDataGridDisplaySelector, startingStyles } from './display_selector'; -describe('useDataGridStyleSelector', () => { - describe('styleSelector', () => { +describe('useDataGridDisplaySelector', () => { + describe('displaySelector', () => { // Hooks can only be called inside function components const MockComponent = () => { - const [styleSelector] = useDataGridStyleSelector({}); - return <>{styleSelector}; + const [displaySelector] = useDataGridDisplaySelector({}); + return <>{displaySelector}; }; it('renders a toolbar button/popover allowing users to customize styles', () => { @@ -30,7 +30,7 @@ describe('useDataGridStyleSelector', () => { // Open popover component - .find('[data-test-subj="dataGridStyleSelectorButton"]') + .find('[data-test-subj="dataGridDisplaySelectorButton"]') .last() .simulate('click'); @@ -45,7 +45,7 @@ describe('useDataGridStyleSelector', () => { // Close popover act(() => { (component - .find('[data-test-subj="dataGridStyleSelectorPopover"]') + .find('[data-test-subj="dataGridDisplaySelectorPopover"]') .first() .prop('closePopover') as Function)(); }); @@ -56,7 +56,7 @@ describe('useDataGridStyleSelector', () => { it('returns an object of grid styles with user overrides', () => { const initialStyles = { ...startingStyles, stripes: true }; const MockComponent = () => { - const [, gridStyles] = useDataGridStyleSelector(initialStyles); + const [, gridStyles] = useDataGridDisplaySelector(initialStyles); return ; }; const component = shallow(); diff --git a/src/components/datagrid/controls/style_selector.tsx b/src/components/datagrid/controls/display_selector.tsx similarity index 89% rename from src/components/datagrid/controls/style_selector.tsx rename to src/components/datagrid/controls/display_selector.tsx index 7d46e2a2eb4..409f2598f23 100644 --- a/src/components/datagrid/controls/style_selector.tsx +++ b/src/components/datagrid/controls/display_selector.tsx @@ -44,7 +44,7 @@ const densityStyles: { [key: string]: Partial } = { // Used to correctly format the icon name for the grid density icon const capitalizeDensityString = (s: string) => s[0].toUpperCase() + s.slice(1); -export const useDataGridStyleSelector = ( +export const useDataGridDisplaySelector = ( initialStyles: EuiDataGridStyle ): [ReactElement, EuiDataGridStyle] => { // track styles specified by the user at run time @@ -66,13 +66,13 @@ export const useDataGridStyleSelector = ( }; const buttonLabel = useEuiI18n( - 'euiStyleSelector.buttonText', + 'euiDisplaySelector.buttonText', 'Display options' ); - const styleSelector = ( + const displaySelector = ( setIsOpen(false)} anchorPosition="downRight" @@ -85,7 +85,7 @@ export const useDataGridStyleSelector = ( iconType={`tableDensity${capitalizeDensityString(gridDensity)}`} className="euiDataGrid__controlBtn" color="text" - data-test-subj="dataGridStyleSelectorButton" + data-test-subj="dataGridDisplaySelectorButton" onClick={() => setIsOpen(!isOpen)} aria-label={buttonLabel} /> @@ -94,10 +94,10 @@ export const useDataGridStyleSelector = ( > @@ -135,5 +135,5 @@ export const useDataGridStyleSelector = ( ); - return [styleSelector, gridStyles]; + return [displaySelector, gridStyles]; }; diff --git a/src/components/datagrid/controls/index.ts b/src/components/datagrid/controls/index.ts index c3c5cce82f7..0c0ca128208 100644 --- a/src/components/datagrid/controls/index.ts +++ b/src/components/datagrid/controls/index.ts @@ -8,7 +8,7 @@ export { useDataGridColumnSelector } from './column_selector'; export { useDataGridColumnSorting } from './column_sorting'; -export { useDataGridStyleSelector, startingStyles } from './style_selector'; +export { useDataGridDisplaySelector, startingStyles } from './display_selector'; export { checkOrDefaultToolBarDisplayOptions, EuiDataGridToolbar, diff --git a/src/components/datagrid/data_grid.test.tsx b/src/components/datagrid/data_grid.test.tsx index a05f1df80be..bd58ee30e25 100644 --- a/src/components/datagrid/data_grid.test.tsx +++ b/src/components/datagrid/data_grid.test.tsx @@ -752,7 +752,7 @@ describe('EuiDataGrid', () => { toolbarVisibility: { showFullScreenSelector: false, showSortSelector: false, - showStyleSelector: true, + showDisplaySelector: true, }, }); @@ -769,7 +769,7 @@ describe('EuiDataGrid', () => { // style selector component.debug(); expect( - findTestSubject(component, 'dataGridStyleSelectorButton').length + findTestSubject(component, 'dataGridDisplaySelectorButton').length ).toBe(1); // column selector diff --git a/src/components/datagrid/data_grid.tsx b/src/components/datagrid/data_grid.tsx index e9908d8b22c..eed3486d8c2 100644 --- a/src/components/datagrid/data_grid.tsx +++ b/src/components/datagrid/data_grid.tsx @@ -27,7 +27,7 @@ import { EuiDataGridBody, VIRTUALIZED_CONTAINER_CLASS } from './body'; import { useDataGridColumnSelector, useDataGridColumnSorting, - useDataGridStyleSelector, + useDataGridDisplaySelector, startingStyles, checkOrDefaultToolBarDisplayOptions, EuiDataGridToolbar, @@ -648,7 +648,7 @@ export const EuiDataGrid: FunctionComponent = (props) => { allSchemaDetectors, displayValues ); - const [styleSelector, gridStyles] = useDataGridStyleSelector( + const [displaySelector, gridStyles] = useDataGridDisplaySelector( gridStyleWithDefaults ); @@ -808,7 +808,7 @@ export const EuiDataGrid: FunctionComponent = (props) => { gridWidth={gridWidth} minSizeForControls={minSizeForControls} toolbarVisibility={toolbarVisibility} - styleSelector={styleSelector} + displaySelector={displaySelector} isFullScreen={isFullScreen} setIsFullScreen={setIsFullScreen} controlBtnClasses={controlBtnClasses} diff --git a/src/components/datagrid/data_grid_types.ts b/src/components/datagrid/data_grid_types.ts index 0a992ffffe1..df7be70488a 100644 --- a/src/components/datagrid/data_grid_types.ts +++ b/src/components/datagrid/data_grid_types.ts @@ -30,7 +30,7 @@ export interface EuiDataGridToolbarProps { gridWidth: number; minSizeForControls?: number; toolbarVisibility: boolean | EuiDataGridToolBarVisibilityOptions; - styleSelector: ReactElement; + displaySelector: ReactElement; isFullScreen: boolean; controlBtnClasses: string; columnSelector: ReactElement; @@ -589,6 +589,17 @@ export interface EuiDataGridToolBarVisibilityColumnSelectorOptions { allowReorder?: boolean; } +export interface EuiDataGridToolBarVisibilityDisplaySelectorOptions { + /** + * When `false`, removes the ability to change density display through the UI + */ + allowDensity?: boolean; + /** + * When `false`, removes the ability to change row height display through the UI + */ + allowRowHeight?: boolean; +} + export interface EuiDataGridToolBarVisibilityOptions { /** * Allows the ability for the user to hide fields and sort columns, boolean or a #EuiDataGridToolBarVisibilityColumnSelectorOptions @@ -596,8 +607,17 @@ export interface EuiDataGridToolBarVisibilityOptions { showColumnSelector?: | boolean | EuiDataGridToolBarVisibilityColumnSelectorOptions; + /** + * Allows the ability for the user to customize display settings such as grid density and row heights. + * User changes will override what is provided in #EuiDataGridStyle and #EuiDataGridRowHeightsOptions + */ + showDisplaySelector?: + | boolean + | EuiDataGridToolBarVisibilityDisplaySelectorOptions; /** * Allows the ability for the user to set the grid density. If on, this merges against what is provided in #EuiDataGridStyle + * + * **DEPRECATED: Use `showDisplaySelector.allowDensity`** */ showStyleSelector?: boolean; /** diff --git a/src/components/datagrid/index.ts b/src/components/datagrid/index.ts index 8dad0388361..7d32fd2d869 100644 --- a/src/components/datagrid/index.ts +++ b/src/components/datagrid/index.ts @@ -10,7 +10,7 @@ export { EuiDataGrid } from './data_grid'; export { useDataGridColumnSelector, useDataGridColumnSorting, - useDataGridStyleSelector, + useDataGridDisplaySelector, } from './controls'; export * from './data_grid_types'; From 79c878d3e42813938101823ab72e6277841de409 Mon Sep 17 00:00:00 2001 From: Constance Chen Date: Tue, 9 Nov 2021 11:56:33 -0800 Subject: [PATCH 02/28] Refactor out nested object helper - so that both the columnSelector and displaySelector can use it --- .../datagrid/controls/column_selector.tsx | 25 ++++++------------- .../controls/data_grid_toolbar.test.tsx | 19 ++++++++++++++ .../datagrid/controls/data_grid_toolbar.tsx | 18 +++++++++++++ 3 files changed, 45 insertions(+), 17 deletions(-) diff --git a/src/components/datagrid/controls/column_selector.tsx b/src/components/datagrid/controls/column_selector.tsx index a701bab82e6..175423ba094 100644 --- a/src/components/datagrid/controls/column_selector.tsx +++ b/src/components/datagrid/controls/column_selector.tsx @@ -15,12 +15,6 @@ import React, { ChangeEvent, } from 'react'; import classNames from 'classnames'; -import { - EuiDataGridColumn, - EuiDataGridColumnVisibility, - EuiDataGridToolBarVisibilityColumnSelectorOptions, - EuiDataGridToolBarVisibilityOptions, -} from '../data_grid_types'; import { EuiPopover, EuiPopoverFooter, EuiPopoverTitle } from '../../popover'; import { EuiI18n } from '../../i18n'; import { EuiButtonEmpty } from '../../button'; @@ -36,15 +30,12 @@ import { DropResult } from 'react-beautiful-dnd'; import { EuiIcon } from '../../icon'; import { useDependentState } from '../../../services'; -const getShowColumnSelectorValue = ( - showColumnSelector: EuiDataGridToolBarVisibilityOptions['showColumnSelector'], - valueName: keyof EuiDataGridToolBarVisibilityColumnSelectorOptions -) => { - if (showColumnSelector === false) return false; - if (showColumnSelector == null) return true; - if (showColumnSelector === true) return true; - return showColumnSelector[valueName] !== false; -}; +import { + EuiDataGridColumn, + EuiDataGridColumnVisibility, + EuiDataGridToolBarVisibilityOptions, +} from '../data_grid_types'; +import { getNestedObjectOptions } from './data_grid_toolbar'; export const useDataGridColumnSelector = ( availableColumns: EuiDataGridColumn[], @@ -57,11 +48,11 @@ export const useDataGridColumnSelector = ( (columns: string[]) => void, (colFrom: string, colTo: string) => void ] => { - const allowColumnHiding = getShowColumnSelectorValue( + const allowColumnHiding = getNestedObjectOptions( showColumnSelector, 'allowHide' ); - const allowColumnReorder = getShowColumnSelectorValue( + const allowColumnReorder = getNestedObjectOptions( showColumnSelector, 'allowReorder' ); diff --git a/src/components/datagrid/controls/data_grid_toolbar.test.tsx b/src/components/datagrid/controls/data_grid_toolbar.test.tsx index efe057bb6cc..39d0273b9e4 100644 --- a/src/components/datagrid/controls/data_grid_toolbar.test.tsx +++ b/src/components/datagrid/controls/data_grid_toolbar.test.tsx @@ -13,6 +13,7 @@ import { EuiDataGridToolbar, checkOrDefaultToolBarDisplayOptions, renderAdditionalControls, + getNestedObjectOptions, } from './data_grid_toolbar'; describe('EuiDataGridToolbar', () => { @@ -253,3 +254,21 @@ describe('renderAdditionalControls', () => { }); }); }); + +describe('getNestedObjectOptions', () => { + it('returns the passed boolean if the option is set to a boolean instead of an object', () => { + expect(getNestedObjectOptions(true, 'someKey')).toEqual(true); + expect(getNestedObjectOptions(false, 'someKey')).toEqual(false); + }); + + it('returns true if the option is undefined', () => { + expect(getNestedObjectOptions(undefined, 'someKey')).toEqual(true); + }); + + it('returns the nested object boolean if the option is an object configuration', () => { + expect(getNestedObjectOptions({ someKey: true }, 'someKey')).toEqual(true); + expect(getNestedObjectOptions({ someKey: false }, 'someKey')).toEqual( + false + ); + }); +}); diff --git a/src/components/datagrid/controls/data_grid_toolbar.tsx b/src/components/datagrid/controls/data_grid_toolbar.tsx index 7574df594de..f6b333b024c 100644 --- a/src/components/datagrid/controls/data_grid_toolbar.tsx +++ b/src/components/datagrid/controls/data_grid_toolbar.tsx @@ -184,3 +184,21 @@ export function renderAdditionalControls( return null; } + +/** + * Utility helper for selectors/controls that allow nested options + * (e.g. column selector, display selector) + */ + +export function getNestedObjectOptions( + controlOption: undefined | boolean | any, // any is in place here so we don't have to pass in each config obj manually + objectKey: string +): boolean { + // If the config is a boolean, nested options follow that boolean + if (controlOption === false) return false; + if (controlOption === true) return true; + // If config is not defined, default to enabled + if (controlOption == null) return true; + // Otherwise, type should be an object of boolean values - dive into it and return the value + return controlOption[objectKey] !== false; +} From 58fe94fc9424ecf275191afbf0dbd94a0fbfcc3e Mon Sep 17 00:00:00 2001 From: Constance Chen Date: Tue, 9 Nov 2021 12:06:15 -0800 Subject: [PATCH 03/28] Update displaySelector with conditional density/row height options + update docs: - reorder UI to match toolbar layout - fix legends + add unit tests (& improve some existing unit tests) --- src-docs/src/views/datagrid/styling.js | 210 ++++++++++++------ .../display_selector.test.tsx.snap | 2 +- .../controls/display_selector.test.tsx | 96 ++++++-- .../datagrid/controls/display_selector.tsx | 109 +++++---- src/components/datagrid/data_grid.tsx | 8 +- 5 files changed, 286 insertions(+), 139 deletions(-) diff --git a/src-docs/src/views/datagrid/styling.js b/src-docs/src/views/datagrid/styling.js index 0750486c839..addddfae77d 100644 --- a/src-docs/src/views/datagrid/styling.js +++ b/src-docs/src/views/datagrid/styling.js @@ -1,4 +1,4 @@ -import React, { useState, Fragment, useCallback } from 'react'; +import React, { useState, Fragment, useCallback, useMemo } from 'react'; import { fake } from 'faker'; import { @@ -155,7 +155,7 @@ const DataGrid = () => { }, ]; - const showSortSelectorOptions = [ + const showColumnSelectorOptions = [ { id: 'true', label: 'True', @@ -165,8 +165,17 @@ const DataGrid = () => { label: 'False', }, ]; - - const showStyleSelectorOptions = [ + const allowHideColumnsOptions = [ + { + id: 'true', + label: 'True', + }, + { + id: 'false', + label: 'False', + }, + ]; + const allowOrderingColumnsOptions = [ { id: 'true', label: 'True', @@ -177,7 +186,7 @@ const DataGrid = () => { }, ]; - const showColumnSelectorOptions = [ + const showSortSelectorOptions = [ { id: 'true', label: 'True', @@ -188,7 +197,7 @@ const DataGrid = () => { }, ]; - const allowHideColumnsOptions = [ + const showDisplaySelectorOptions = [ { id: 'true', label: 'True', @@ -199,7 +208,17 @@ const DataGrid = () => { }, ]; - const allowOrderingColumnsOptions = [ + const allowDensityOptions = [ + { + id: 'true', + label: 'True', + }, + { + id: 'false', + label: 'False', + }, + ]; + const allowRowHeightOptions = [ { id: 'true', label: 'True', @@ -252,7 +271,9 @@ const DataGrid = () => { const [headerSelected, setHeaderSelected] = useState('underline'); const [footerSelected, setFooterSelected] = useState('overline'); const [showSortSelector, setShowSortSelector] = useState(true); - const [showStyleSelector, setShowStyleSelector] = useState(true); + const [showDisplaySelector, setShowDisplaySelector] = useState(true); + const [allowDensity, setAllowDensity] = useState(true); + const [allowRowHeight, setAllowRowHeight] = useState(true); const [showColumnSelector, setShowColumnSelector] = useState(true); const [allowHideColumns, setAllowHideColumns] = useState(true); const [allowOrderingColumns, setAllowOrderingColumns] = useState(true); @@ -297,26 +318,30 @@ const DataGrid = () => { setFooterSelected(optionId); }; - const onShowSortSelectorChange = (optionId) => { - setShowSortSelector(optionId === 'true'); - }; - - const onShowStyleSelectorChange = (optionId) => { - setShowStyleSelector(optionId === 'true'); - }; - const onShowColumnSelectorChange = (optionId) => { setShowColumnSelector(optionId === 'true'); }; - const onAllowHideColumnsChange = (optionId) => { setAllowHideColumns(optionId === 'true'); }; - const onAllowOrderingColumnsChange = (optionId) => { setAllowOrderingColumns(optionId === 'true'); }; + const onShowSortSelectorChange = (optionId) => { + setShowSortSelector(optionId === 'true'); + }; + + const onShowDisplaySelectorChange = (optionId) => { + setShowDisplaySelector(optionId === 'true'); + }; + const onAllowDensityChange = (optionId) => { + setAllowDensity(optionId === 'true'); + }; + const onAllowRowHeightChange = (optionId) => { + setAllowRowHeight(optionId === 'true'); + }; + const onShowFullScreenSelectorChange = (optionId) => { setShowFullScreenSelector(optionId === 'true'); }; @@ -389,20 +414,35 @@ const DataGrid = () => { toolbarVisibility options ); - let displayColumnSelector = showColumnSelector; - if ( - displayColumnSelector === true && - (allowHideColumns === false || allowOrderingColumns === false) - ) { - displayColumnSelector = { - allowHide: allowHideColumns, - allowReorder: allowOrderingColumns, - }; - } + + const toggleColumnSelector = useMemo(() => { + if ( + showColumnSelector === true && + (allowHideColumns === false || allowOrderingColumns === false) + ) { + return { + allowHide: allowHideColumns, + allowReorder: allowOrderingColumns, + }; + } else { + return showColumnSelector; + } + }, [showColumnSelector, allowHideColumns, allowOrderingColumns]); + + const toggleDisplaySelector = useMemo(() => { + if ( + showDisplaySelector === true && + (allowDensity === false || allowRowHeight === false) + ) { + return { allowDensity, allowRowHeight }; + } else { + return showDisplaySelector; + } + }, [showDisplaySelector, allowDensity, allowRowHeight]); const toolbarVisibilityOptions = { - showColumnSelector: displayColumnSelector, - showStyleSelector: showStyleSelector, + showColumnSelector: toggleColumnSelector, + showDisplaySelector: toggleDisplaySelector, showSortSelector: showSortSelector, showFullScreenSelector: showFullScreenSelector, }; @@ -453,7 +493,7 @@ const DataGrid = () => { { { + {toggleColumnSelector && ( + <> + + + + + + + + )} { { - - - - - {displayColumnSelector && ( + {toggleDisplaySelector && ( <> )} + + + + ) : ( { describe('displaySelector', () => { // Hooks can only be called inside function components - const MockComponent = () => { - const [displaySelector] = useDataGridDisplaySelector({}); + const MockComponent = ({ + showDisplaySelector = true as EuiDataGridToolBarVisibilityOptions['showDisplaySelector'], + gridStyles = {}, + showStyleSelector = undefined as boolean | undefined, + }) => { + const [displaySelector] = useDataGridDisplaySelector( + showDisplaySelector, + gridStyles, + showStyleSelector + ); return <>{displaySelector}; }; - - it('renders a toolbar button/popover allowing users to customize styles', () => { - const component = shallow(); - expect(component).toMatchSnapshot(); - }); - - it('renders display density buttons that change grid density on click', () => { - const component = mount(); - - // Open popover + const openPopover = (component: ReactWrapper) => { component .find('[data-test-subj="dataGridDisplaySelectorButton"]') .last() .simulate('click'); - - // Click density 'buttons' (actually hidden radios) - component.find('[data-test-subj="expanded"]').simulate('change'); - component.find('[data-test-subj="normal"]').simulate('change'); - component.find('[data-test-subj="compact"]').simulate('change'); - expect(component.find('EuiButtonGroup').prop('idSelected')).toEqual( - 'compact' - ); - - // Close popover + }; + const closePopover = (component: ReactWrapper) => { act(() => { (component .find('[data-test-subj="dataGridDisplaySelectorPopover"]') .first() .prop('closePopover') as Function)(); }); + }; + + it('renders a toolbar button/popover allowing users to customize display settings', () => { + const component = shallow(); + expect(component).toMatchSnapshot(); + }); + + describe('density', () => { + const getSelection = (component: ReactWrapper) => + component + .find('EuiButtonGroup[data-test-subj="densityButtonGroup"]') + .prop('idSelected'); + + it('renders display density buttons that change grid density on click', () => { + const component = mount(); + openPopover(component); + + // Click density 'buttons' (actually hidden radios) + component.find('[data-test-subj="expanded"]').simulate('change'); + expect(getSelection(component)).toEqual('expanded'); + component.find('[data-test-subj="normal"]').simulate('change'); + expect(getSelection(component)).toEqual('normal'); + component.find('[data-test-subj="compact"]').simulate('change'); + expect(getSelection(component)).toEqual('compact'); + + // Should have changed the main toolbar icon accordingly + closePopover(component); + expect( + component + .find('[data-test-subj="dataGridDisplaySelectorButton"]') + .first() + .prop('iconType') + ).toEqual('tableDensityCompact'); + }); + + it('hides the density buttongroup if allowDensity is set to false', () => { + const component = mount( + + ); + openPopover(component); + + expect( + component.find('[data-test-subj="densityButtonGroup"]') + ).toHaveLength(0); + }); + + // TODO: Deprecate + it('hides the density buttongroup if showStyleSelector is set to false', () => { + const component = mount(); + openPopover(component); + + expect( + component.find('[data-test-subj="densityButtonGroup"]') + ).toHaveLength(0); + }); }); }); @@ -56,7 +104,7 @@ describe('useDataGridDisplaySelector', () => { it('returns an object of grid styles with user overrides', () => { const initialStyles = { ...startingStyles, stripes: true }; const MockComponent = () => { - const [, gridStyles] = useDataGridDisplaySelector(initialStyles); + const [, gridStyles] = useDataGridDisplaySelector(true, initialStyles); return
; }; const component = shallow(); diff --git a/src/components/datagrid/controls/display_selector.tsx b/src/components/datagrid/controls/display_selector.tsx index 409f2598f23..068563423e7 100644 --- a/src/components/datagrid/controls/display_selector.tsx +++ b/src/components/datagrid/controls/display_selector.tsx @@ -7,13 +7,19 @@ */ import React, { ReactElement, useState } from 'react'; -import { EuiDataGridStyle } from '../data_grid_types'; + import { EuiI18n, useEuiI18n } from '../../i18n'; import { EuiPopover } from '../../popover'; import { EuiButtonIcon, EuiButtonGroup } from '../../button'; import { EuiFormRow } from '../../form'; import { EuiToolTip } from '../../tool_tip'; +import { + EuiDataGridToolBarVisibilityOptions, + EuiDataGridStyle, +} from '../data_grid_types'; +import { getNestedObjectOptions } from './data_grid_toolbar'; + export const startingStyles: EuiDataGridStyle = { cellPadding: 'm', fontSize: 'm', @@ -45,13 +51,24 @@ const densityStyles: { [key: string]: Partial } = { const capitalizeDensityString = (s: string) => s[0].toUpperCase() + s.slice(1); export const useDataGridDisplaySelector = ( - initialStyles: EuiDataGridStyle + showDisplaySelector: EuiDataGridToolBarVisibilityOptions['showDisplaySelector'], + initialStyles: EuiDataGridStyle, + showStyleSelector?: EuiDataGridToolBarVisibilityOptions['showStyleSelector'] // TODO: Deprecate ): [ReactElement, EuiDataGridStyle] => { + const [isOpen, setIsOpen] = useState(false); + + const showDensityControls = + showStyleSelector ?? + getNestedObjectOptions(showDisplaySelector, 'allowDensity'); + + const showRowHeightControls = getNestedObjectOptions( + showDisplaySelector, + 'allowRowHeight' + ); + // track styles specified by the user at run time const [userGridStyles, setUserGridStyles] = useState({}); - const [isOpen, setIsOpen] = useState(false); - // Normal is the default density const [gridDensity, _setGridDensity] = useState(densityOptions[1]); const setGridDensity = (density: string) => { @@ -92,46 +109,50 @@ export const useDataGridDisplaySelector = ( } > - - {([ - densityLabel, - labelCompact, - labelNormal, - labelExpanded, - ]: string[]) => ( - - - - )} - + {showDensityControls && ( + + {([ + densityLabel, + labelCompact, + labelNormal, + labelExpanded, + ]: string[]) => ( + + + + )} + + )} + {showRowHeightControls && <>TODO: ROW HEIGHT OPTIONS} ); diff --git a/src/components/datagrid/data_grid.tsx b/src/components/datagrid/data_grid.tsx index eed3486d8c2..fa0d7c7a581 100644 --- a/src/components/datagrid/data_grid.tsx +++ b/src/components/datagrid/data_grid.tsx @@ -649,7 +649,13 @@ export const EuiDataGrid: FunctionComponent = (props) => { displayValues ); const [displaySelector, gridStyles] = useDataGridDisplaySelector( - gridStyleWithDefaults + checkOrDefaultToolBarDisplayOptions( + toolbarVisibility, + 'showDisplaySelector' + ), + gridStyleWithDefaults, + // @ts-ignore - showStyleSelector will be deprecated + toolbarVisibility?.showStyleSelector ); // compute the default column width from the container's clientWidth and count of visible columns From 37aecd6c92a51f484a6470e75cac8e92075efbbf Mon Sep 17 00:00:00 2001 From: Constance Chen Date: Wed, 10 Nov 2021 11:22:36 -0800 Subject: [PATCH 04/28] Add rowHeightsOptions controls to popover NYI: conditional lineCount controls + unit tests --- .../display_selector.test.tsx.snap | 22 +++ .../controls/display_selector.test.tsx | 155 +++++++++++++++++- .../datagrid/controls/display_selector.tsx | 111 ++++++++++++- src/components/datagrid/data_grid.tsx | 9 +- 4 files changed, 284 insertions(+), 13 deletions(-) diff --git a/src/components/datagrid/controls/__snapshots__/display_selector.test.tsx.snap b/src/components/datagrid/controls/__snapshots__/display_selector.test.tsx.snap index 0310a04097c..ac16b5d0c76 100644 --- a/src/components/datagrid/controls/__snapshots__/display_selector.test.tsx.snap +++ b/src/components/datagrid/controls/__snapshots__/display_selector.test.tsx.snap @@ -51,6 +51,28 @@ exports[`useDataGridDisplaySelector displaySelector renders a toolbar button/pop > + + + `; diff --git a/src/components/datagrid/controls/display_selector.test.tsx b/src/components/datagrid/controls/display_selector.test.tsx index e2c084b981c..5892b310978 100644 --- a/src/components/datagrid/controls/display_selector.test.tsx +++ b/src/components/datagrid/controls/display_selector.test.tsx @@ -8,9 +8,12 @@ import React from 'react'; import { act } from 'react-dom/test-utils'; -import { shallow, mount, ReactWrapper } from 'enzyme'; +import { shallow, mount, ShallowWrapper, ReactWrapper } from 'enzyme'; -import { EuiDataGridToolBarVisibilityOptions } from '../data_grid_types'; +import { + EuiDataGridToolBarVisibilityOptions, + EuiDataGridRowHeightsOptions, +} from '../data_grid_types'; import { useDataGridDisplaySelector, startingStyles } from './display_selector'; @@ -20,11 +23,13 @@ describe('useDataGridDisplaySelector', () => { const MockComponent = ({ showDisplaySelector = true as EuiDataGridToolBarVisibilityOptions['showDisplaySelector'], gridStyles = {}, + rowHeightsOptions = undefined as EuiDataGridRowHeightsOptions | undefined, showStyleSelector = undefined as boolean | undefined, }) => { const [displaySelector] = useDataGridDisplaySelector( showDisplaySelector, gridStyles, + rowHeightsOptions, showStyleSelector ); return <>{displaySelector}; @@ -98,13 +103,84 @@ describe('useDataGridDisplaySelector', () => { ).toHaveLength(0); }); }); + + describe('row height', () => { + const getSelection = (component: ReactWrapper) => + component + .find('EuiButtonGroup[data-test-subj="rowHeightButtonGroup"]') + .prop('idSelected'); + + it('renders row height buttons that toggle betwen undefined, auto, and lineCount', () => { + const component = mount(); + openPopover(component); + expect(getSelection(component)).toEqual('undefined'); + + component.find('[data-test-subj="auto"]').simulate('change'); + expect(getSelection(component)).toEqual('auto'); + }); + + it('hides the row height buttongroup if allowRowHeight is set to false', () => { + const component = mount( + + ); + openPopover(component); + + expect( + component.find('[data-test-subj="rowHeightButtonGroup"]') + ).toHaveLength(0); + }); + + describe('convertRowHeightsOptionsToSelection (loading initial state from passed rowHeightsOptions)', () => { + test('auto', () => { + const component = mount( + + ); + openPopover(component); + expect(getSelection(component)).toEqual('auto'); + }); + + test('lineCount', () => { + const component = mount( + + ); + openPopover(component); + expect(getSelection(component)).toEqual('lineCount'); + }); + + test('undefined', () => { + const component = mount( + + ); + openPopover(component); + expect(getSelection(component)).toEqual('undefined'); + }); + + test('height should fall back to undefined', () => { + const component = mount( + + ); + openPopover(component); + expect(getSelection(component)).toEqual('undefined'); + }); + }); + + describe('lineCount', () => { + // TODO + }); + }); }); describe('gridStyles', () => { it('returns an object of grid styles with user overrides', () => { const initialStyles = { ...startingStyles, stripes: true }; const MockComponent = () => { - const [, gridStyles] = useDataGridDisplaySelector(true, initialStyles); + const [, gridStyles] = useDataGridDisplaySelector( + true, + initialStyles, + {} + ); return
; }; const component = shallow(); @@ -123,4 +199,77 @@ describe('useDataGridDisplaySelector', () => { `); }); }); + + describe('rowHeightsOptions', () => { + // Test helpers + const MockComponent = ({ + initialRowHeightsOptions = undefined as + | EuiDataGridRowHeightsOptions + | undefined, + }) => { + const [displaySelector, , rowHeightsOptions] = useDataGridDisplaySelector( + true, + {}, + initialRowHeightsOptions + ); + return ( + <> + {displaySelector} +
{JSON.stringify(rowHeightsOptions)}
+ + ); + }; + const diveIntoEuiI18n = (component: ShallowWrapper) => { + return (component + .find('EuiI18n') + .last() + .renderProp('children') as Function)(['', '', '', '']); + }; + const setRowHeight = (component: ShallowWrapper, selection = '') => { + diveIntoEuiI18n(component) + .find('[data-test-subj="rowHeightButtonGroup"]') + .simulate('change', selection); + }; + const getOutput = (component: ShallowWrapper) => { + return JSON.parse(component.find('[data-test-subj="output"]').text()); + }; + + it('returns an object of rowHeightsOptions with user overrides', () => { + const component = shallow( + + ); + + setRowHeight(component, 'lineCount'); + + expect(getOutput(component)).toEqual({ + lineHeight: '2em', + defaultHeight: { lineCount: 1 }, + }); + }); + + it('handles undefined rowHeightsObjects (from the developer)', () => { + const component = shallow( + + ); + expect(getOutput(component)).toEqual({}); + + setRowHeight(component, 'auto'); + + expect(getOutput(component)).toEqual({ + defaultHeight: 'auto', + }); + }); + + it('handles undefined rowHeightsOptions (from the user)', () => { + const component = shallow( + + ); + + setRowHeight(component, 'undefined'); + + expect(getOutput(component)).toEqual({ + lineHeight: '2em', + }); + }); + }); }); diff --git a/src/components/datagrid/controls/display_selector.tsx b/src/components/datagrid/controls/display_selector.tsx index 068563423e7..5c65abbfff5 100644 --- a/src/components/datagrid/controls/display_selector.tsx +++ b/src/components/datagrid/controls/display_selector.tsx @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import React, { ReactElement, useState } from 'react'; +import React, { ReactElement, useState, useMemo, useCallback } from 'react'; import { EuiI18n, useEuiI18n } from '../../i18n'; import { EuiPopover } from '../../popover'; @@ -17,6 +17,7 @@ import { EuiToolTip } from '../../tool_tip'; import { EuiDataGridToolBarVisibilityOptions, EuiDataGridStyle, + EuiDataGridRowHeightsOptions, } from '../data_grid_types'; import { getNestedObjectOptions } from './data_grid_toolbar'; @@ -50,11 +51,30 @@ const densityStyles: { [key: string]: Partial } = { // Used to correctly format the icon name for the grid density icon const capitalizeDensityString = (s: string) => s[0].toUpperCase() + s.slice(1); +// Row height options and utilities +const rowHeightButtonOptions: string[] = ['undefined', 'auto', 'lineCount']; +const convertRowHeightsOptionsToSelection = ( + rowHeightsOptions?: EuiDataGridRowHeightsOptions +) => { + if (rowHeightsOptions) { + const { defaultHeight } = rowHeightsOptions; + + if (defaultHeight === 'auto') { + return rowHeightButtonOptions[1]; + } + if (typeof defaultHeight === 'object' && defaultHeight?.lineCount) { + return rowHeightButtonOptions[2]; + } + } + return rowHeightButtonOptions[0]; +}; + export const useDataGridDisplaySelector = ( showDisplaySelector: EuiDataGridToolBarVisibilityOptions['showDisplaySelector'], initialStyles: EuiDataGridStyle, + initialRowHeightsOptions?: EuiDataGridRowHeightsOptions, showStyleSelector?: EuiDataGridToolBarVisibilityOptions['showStyleSelector'] // TODO: Deprecate -): [ReactElement, EuiDataGridStyle] => { +): [ReactElement, EuiDataGridStyle, EuiDataGridRowHeightsOptions] => { const [isOpen, setIsOpen] = useState(false); const showDensityControls = @@ -68,6 +88,9 @@ export const useDataGridDisplaySelector = ( // track styles specified by the user at run time const [userGridStyles, setUserGridStyles] = useState({}); + const [userRowHeightsOptions, setUserRowHeightsOptions] = useState( + initialRowHeightsOptions // Set initial state from the developer-passed props + ); // Normal is the default density const [gridDensity, _setGridDensity] = useState(densityOptions[1]); @@ -76,11 +99,39 @@ export const useDataGridDisplaySelector = ( setUserGridStyles(densityStyles[density]); }; + // Row height state + const [rowHeightSelection, setRowHeightSelection] = useState( + convertRowHeightsOptionsToSelection(initialRowHeightsOptions) + ); + const setRowHeight = useCallback((option: string) => { + let rowHeightsOptions: EuiDataGridRowHeightsOptions | undefined; + + if (option === 'auto') { + rowHeightsOptions = { defaultHeight: 'auto' }; + } else if (option === 'lineCount') { + rowHeightsOptions = { defaultHeight: { lineCount: 3 } }; // TODO + } else { + rowHeightsOptions = { defaultHeight: undefined }; + } + + setRowHeightSelection(option); + setUserRowHeightsOptions(rowHeightsOptions); + }, []); + // merge the developer-specified styles with any user overrides - const gridStyles = { - ...initialStyles, - ...userGridStyles, - }; + const gridStyles = useMemo(() => { + return { + ...initialStyles, + ...userGridStyles, + }; + }, [initialStyles, userGridStyles]); + + const rowHeightsOptions = useMemo(() => { + return { + ...initialRowHeightsOptions, + ...userRowHeightsOptions, + }; + }, [initialRowHeightsOptions, userRowHeightsOptions]); const buttonLabel = useEuiI18n( 'euiDisplaySelector.buttonText', @@ -152,9 +203,53 @@ export const useDataGridDisplaySelector = ( )} )} - {showRowHeightControls && <>TODO: ROW HEIGHT OPTIONS} + {showRowHeightControls && ( + + {([ + rowHeightLabel, + labelSingle, + labelAuto, + labelCustom, + ]: string[]) => ( + <> + + + + + )} + + )} ); - return [displaySelector, gridStyles]; + return [displaySelector, gridStyles, rowHeightsOptions]; }; diff --git a/src/components/datagrid/data_grid.tsx b/src/components/datagrid/data_grid.tsx index fa0d7c7a581..7d6c3bc1fce 100644 --- a/src/components/datagrid/data_grid.tsx +++ b/src/components/datagrid/data_grid.tsx @@ -488,7 +488,7 @@ export const EuiDataGrid: FunctionComponent = (props) => { minSizeForControls, height, width, - rowHeightsOptions, + rowHeightsOptions: _rowHeightsOptions, virtualizationOptions, ...rest } = props; @@ -648,12 +648,17 @@ export const EuiDataGrid: FunctionComponent = (props) => { allSchemaDetectors, displayValues ); - const [displaySelector, gridStyles] = useDataGridDisplaySelector( + const [ + displaySelector, + gridStyles, + rowHeightsOptions, + ] = useDataGridDisplaySelector( checkOrDefaultToolBarDisplayOptions( toolbarVisibility, 'showDisplaySelector' ), gridStyleWithDefaults, + _rowHeightsOptions, // @ts-ignore - showStyleSelector will be deprecated toolbarVisibility?.showStyleSelector ); From 129b2bb2267e8e8d73ffc35874c7b20ee0c1f7c4 Mon Sep 17 00:00:00 2001 From: Constance Chen Date: Wed, 10 Nov 2021 13:32:34 -0800 Subject: [PATCH 05/28] Add conditional lineCount row and logic + fix cell height to dynamically on lineCount change --- .../datagrid/body/data_grid_cell.test.tsx | 12 ++++ .../datagrid/body/data_grid_cell.tsx | 8 +++ .../controls/display_selector.test.tsx | 61 ++++++++++++++++++- .../datagrid/controls/display_selector.tsx | 60 +++++++++++++----- 4 files changed, 125 insertions(+), 16 deletions(-) diff --git a/src/components/datagrid/body/data_grid_cell.test.tsx b/src/components/datagrid/body/data_grid_cell.test.tsx index ee8aa2fd257..a842d19ff12 100644 --- a/src/components/datagrid/body/data_grid_cell.test.tsx +++ b/src/components/datagrid/body/data_grid_cell.test.tsx @@ -222,6 +222,18 @@ describe('EuiDataGridCell', () => { expect(setRowHeight).toHaveBeenCalled(); }); + it('recalculates when rowHeightsOptions.defaultHeight.lineCount changes', () => { + const component = mountEuiDataGridCellWithContext({ + rowHeightsOptions: { defaultHeight: { lineCount: 7 } }, + setRowHeight, + }); + + component.setProps({ + rowHeightsOptions: { defaultHeight: { lineCount: 6 } }, + }); + expect(setRowHeight).toHaveBeenCalled(); + }); + it('does nothing if cell height is not set to lineCount', () => { const component = mountEuiDataGridCellWithContext({ rowHeightsOptions: { defaultHeight: 34 }, diff --git a/src/components/datagrid/body/data_grid_cell.tsx b/src/components/datagrid/body/data_grid_cell.tsx index 581c89706e5..a5af1a63296 100644 --- a/src/components/datagrid/body/data_grid_cell.tsx +++ b/src/components/datagrid/body/data_grid_cell.tsx @@ -233,6 +233,14 @@ export class EuiDataGridCell extends Component< componentDidUpdate(prevProps: EuiDataGridCellProps) { this.recalculateAutoHeight(); + if ( + // @ts-ignore - optional chaining operator handles types & cases that aren't lineCount + this.props.rowHeightsOptions?.defaultHeight?.lineCount !== // @ts-ignore - see above + prevProps.rowHeightsOptions?.defaultHeight?.lineCount + ) { + this.recalculateLineCountHeight(); + } + if (this.props.columnId !== prevProps.columnId) { this.setCellProps({}); } diff --git a/src/components/datagrid/controls/display_selector.test.tsx b/src/components/datagrid/controls/display_selector.test.tsx index 5892b310978..f2079e81f5a 100644 --- a/src/components/datagrid/controls/display_selector.test.tsx +++ b/src/components/datagrid/controls/display_selector.test.tsx @@ -167,7 +167,58 @@ describe('useDataGridDisplaySelector', () => { }); describe('lineCount', () => { - // TODO + const getLineCountNumber = (component: ReactWrapper) => + component + .find('EuiFieldNumber[data-test-subj="lineCountFieldNumber"]') + .prop('value'); + + it('conditionally displays a line count number input when the lineCount button is selected', () => { + const component = mount(); + openPopover(component); + expect( + component.find('[data-test-subj="lineCountFieldNumber"]').exists() + ).toBe(false); + + component.find('[data-test-subj="lineCount"]').simulate('change'); + expect(getSelection(component)).toEqual('lineCount'); + + expect( + component.find('[data-test-subj="lineCountFieldNumber"]').exists() + ).toBe(true); + }); + + it('displays the defaultHeight.lineCount passed in by the developer', () => { + const component = mount( + + ); + openPopover(component); + + expect(getLineCountNumber(component)).toEqual(5); + }); + + it('defaults to a lineCount of 1 when no developer settings have been passed', () => { + const component = mount(); + openPopover(component); + component.find('[data-test-subj="lineCount"]').simulate('change'); + + expect(getLineCountNumber(component)).toEqual(1); + }); + + it('increments the rowHeightOptions line count number', () => { + const component = mount( + + ); + openPopover(component); + + component + .find('input[data-test-subj="lineCountFieldNumber"]') + .simulate('change', { target: { value: 3 } }); + expect(getLineCountNumber(component)).toEqual(3); + }); }); }); }); @@ -230,6 +281,11 @@ describe('useDataGridDisplaySelector', () => { .find('[data-test-subj="rowHeightButtonGroup"]') .simulate('change', selection); }; + const setLineCount = (component: ShallowWrapper, lineCount = 1) => { + diveIntoEuiI18n(component) + .find('[data-test-subj="lineCountFieldNumber"]') + .simulate('change', { target: { value: lineCount } }); + }; const getOutput = (component: ShallowWrapper) => { return JSON.parse(component.find('[data-test-subj="output"]').text()); }; @@ -240,10 +296,11 @@ describe('useDataGridDisplaySelector', () => { ); setRowHeight(component, 'lineCount'); + setLineCount(component, 5); expect(getOutput(component)).toEqual({ lineHeight: '2em', - defaultHeight: { lineCount: 1 }, + defaultHeight: { lineCount: 5 }, }); }); diff --git a/src/components/datagrid/controls/display_selector.tsx b/src/components/datagrid/controls/display_selector.tsx index 5c65abbfff5..086b5a600af 100644 --- a/src/components/datagrid/controls/display_selector.tsx +++ b/src/components/datagrid/controls/display_selector.tsx @@ -11,7 +11,7 @@ import React, { ReactElement, useState, useMemo, useCallback } from 'react'; import { EuiI18n, useEuiI18n } from '../../i18n'; import { EuiPopover } from '../../popover'; import { EuiButtonIcon, EuiButtonGroup } from '../../button'; -import { EuiFormRow } from '../../form'; +import { EuiFormRow, EuiFieldNumber } from '../../form'; import { EuiToolTip } from '../../tool_tip'; import { @@ -100,22 +100,34 @@ export const useDataGridDisplaySelector = ( }; // Row height state + const [lineCount, setLineCount] = useState( + // @ts-ignore - optional chaining operator handles types & cases that aren't lineCount + initialRowHeightsOptions?.defaultHeight?.lineCount || 1 + ); const [rowHeightSelection, setRowHeightSelection] = useState( convertRowHeightsOptionsToSelection(initialRowHeightsOptions) ); - const setRowHeight = useCallback((option: string) => { - let rowHeightsOptions: EuiDataGridRowHeightsOptions | undefined; - - if (option === 'auto') { - rowHeightsOptions = { defaultHeight: 'auto' }; - } else if (option === 'lineCount') { - rowHeightsOptions = { defaultHeight: { lineCount: 3 } }; // TODO - } else { - rowHeightsOptions = { defaultHeight: undefined }; - } + const setRowHeight = useCallback( + (option: string) => { + let rowHeightsOptions: EuiDataGridRowHeightsOptions | undefined; + + if (option === 'auto') { + rowHeightsOptions = { defaultHeight: 'auto' }; + } else if (option === 'lineCount') { + rowHeightsOptions = { defaultHeight: { lineCount } }; + } else { + rowHeightsOptions = { defaultHeight: undefined }; + } - setRowHeightSelection(option); - setUserRowHeightsOptions(rowHeightsOptions); + setRowHeightSelection(option); + setUserRowHeightsOptions(rowHeightsOptions); + }, + [lineCount] + ); + const setLineCountHeight = useCallback((event) => { + const newLineCount = Number(event.target.value); + setLineCount(newLineCount); + setUserRowHeightsOptions({ defaultHeight: { lineCount: newLineCount } }); }, []); // merge the developer-specified styles with any user overrides @@ -210,14 +222,22 @@ export const useDataGridDisplaySelector = ( 'euiDisplaySelector.labelSingle', 'euiDisplaySelector.labelAuto', 'euiDisplaySelector.labelCustom', + 'euiDisplaySelector.lineCountLabel', + ]} + defaults={[ + 'Row height', + 'Single', + 'Auto fit', + 'Custom', + 'Lines per row', ]} - defaults={['Row height', 'Single', 'Auto fit', 'Custom']} > {([ rowHeightLabel, labelSingle, labelAuto, labelCustom, + lineCountLabel, ]: string[]) => ( <> @@ -244,6 +264,18 @@ export const useDataGridDisplaySelector = ( data-test-subj="rowHeightButtonGroup" /> + {rowHeightSelection === rowHeightButtonOptions[2] && ( + + + + )} )} From 742051db5d072e0e2385643f16499d602bcac953 Mon Sep 17 00:00:00 2001 From: Constance Chen Date: Thu, 11 Nov 2021 10:51:26 -0800 Subject: [PATCH 06/28] Fix styles not applying correctly for rowHeightsOptions that have undefined heights but defined rowHeightsOptions objects e.g. - empty objs, or lineHeight set but nothing else + simplify this.props --- .../data_grid_cell.test.tsx.snap | 1 + .../datagrid/body/data_grid_cell.tsx | 28 +++++++++++-------- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/src/components/datagrid/body/__snapshots__/data_grid_cell.test.tsx.snap b/src/components/datagrid/body/__snapshots__/data_grid_cell.test.tsx.snap index d8d42027616..848116558f7 100644 --- a/src/components/datagrid/body/__snapshots__/data_grid_cell.test.tsx.snap +++ b/src/components/datagrid/body/__snapshots__/data_grid_cell.test.tsx.snap @@ -66,6 +66,7 @@ exports[`EuiDataGridCell renders 1`] = ` = memo( ({ @@ -51,6 +52,7 @@ const EuiDataGridCellContent: FunctionComponent< rowIndex, colIndex, rowHeightUtils, + isDefinedHeight, ...rest }) => { // React is more permissible than the TS types indicate @@ -64,11 +66,6 @@ const EuiDataGridCellContent: FunctionComponent< { row: rowIndex + 1, col: colIndex + 1 } ); - const isDefinedHeight = !!rowHeightUtils?.getRowHeightOption( - rowIndex, - rowHeightsOptions - ); - return ( <>
{ this.setState({ isEntered: false }, this.preventTabbing); }} - style={this.props.rowHeightsOptions ? { height: '100%' } : {}} + style={isDefinedHeight ? { height: '100%' } : {}} clickOutsideDisables={true} >
@@ -541,7 +545,7 @@ export class EuiDataGridCell extends Component< innerContent = (
Date: Wed, 10 Nov 2021 14:12:17 -0800 Subject: [PATCH 07/28] Fix multiline content not top-aligning correctly when in single/undefined mode - Multiline content includes items with `
`/`

` tags etc that end up incorrectly vertically centered to their increased height --- src/components/datagrid/_data_grid_data_row.scss | 7 ++----- src/components/datagrid/body/data_grid_cell.tsx | 4 +--- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/src/components/datagrid/_data_grid_data_row.scss b/src/components/datagrid/_data_grid_data_row.scss index b84a33d38c6..c171e272447 100644 --- a/src/components/datagrid/_data_grid_data_row.scss +++ b/src/components/datagrid/_data_grid_data_row.scss @@ -20,6 +20,7 @@ > * { max-width: 100%; width: 100%; + height: 100%; } &.euiDataGridRowCell--firstColumn { @@ -139,7 +140,7 @@ .euiDataGridRowCell__expandFlex { position: relative; // for positioning expand button display: flex; - align-items: center; + align-items: baseline; height: 100%; } @@ -152,10 +153,6 @@ height: 100%; } -.euiDataGridRowCell__alignBaseLine { - align-items: baseline; -} - .euiDataGridRowCell__expandButton { display: flex; flex-grow: 0; diff --git a/src/components/datagrid/body/data_grid_cell.tsx b/src/components/datagrid/body/data_grid_cell.tsx index 5f808948cce..6f4c5700752 100644 --- a/src/components/datagrid/body/data_grid_cell.tsx +++ b/src/components/datagrid/body/data_grid_cell.tsx @@ -483,9 +483,7 @@ export class EuiDataGridCell extends Component< isDefinedHeight, }; - const anchorClass = classNames('euiDataGridRowCell__expandFlex', { - euiDataGridRowCell__alignBaseLine: isDefinedHeight, - }); + const anchorClass = 'euiDataGridRowCell__expandFlex'; const expandClass = isDefinedHeight ? 'euiDataGridRowCell__contentByHeight' : 'euiDataGridRowCell__expandContent'; From 75e933a6b4c701dd50155c1348abd16bfb22dd74 Mon Sep 17 00:00:00 2001 From: Constance Chen Date: Thu, 11 Nov 2021 11:24:19 -0800 Subject: [PATCH 08/28] Fix single/undefined row heights to account for passed lineHeight API + density - by giving it the same setRowHeight logic as line counts with a single line + rename recalculateLineCountHeight for clarity now that it's no longer being used for just lineCount --- .../datagrid/body/data_grid_cell.test.tsx | 19 ++++++++++++++++--- .../datagrid/body/data_grid_cell.tsx | 16 +++++++++------- 2 files changed, 25 insertions(+), 10 deletions(-) diff --git a/src/components/datagrid/body/data_grid_cell.test.tsx b/src/components/datagrid/body/data_grid_cell.test.tsx index a842d19ff12..e6474137b78 100644 --- a/src/components/datagrid/body/data_grid_cell.test.tsx +++ b/src/components/datagrid/body/data_grid_cell.test.tsx @@ -205,12 +205,12 @@ describe('EuiDataGridCell', () => { }); }); - describe('recalculateLineCountHeight', () => { + describe('recalculateLineHeight', () => { const setRowHeight = jest.fn(); beforeEach(() => setRowHeight.mockClear()); const callMethod = (component: ReactWrapper) => - (component.instance() as any).recalculateLineCountHeight(); + (component.instance() as any).recalculateLineHeight(); it('observes the first cell for size changes and calls this.props.setRowHeight on change', () => { const component = mountEuiDataGridCellWithContext({ @@ -234,7 +234,20 @@ describe('EuiDataGridCell', () => { expect(setRowHeight).toHaveBeenCalled(); }); - it('does nothing if cell height is not set to lineCount', () => { + it('calculates undefined heights as single rows with a lineCount of 1', () => { + const component = mountEuiDataGridCellWithContext({ + rowHeightsOptions: { defaultHeight: undefined }, + setRowHeight, + }); + + callMethod(component); + expect( + mockRowHeightUtils.calculateHeightForLineCount + ).toHaveBeenCalledWith(expect.any(HTMLElement), 1); + expect(setRowHeight).toHaveBeenCalled(); + }); + + it('does nothing if cell height is not lineCount or undefined', () => { const component = mountEuiDataGridCellWithContext({ rowHeightsOptions: { defaultHeight: 34 }, setRowHeight, diff --git a/src/components/datagrid/body/data_grid_cell.tsx b/src/components/datagrid/body/data_grid_cell.tsx index 6f4c5700752..c5634a51619 100644 --- a/src/components/datagrid/body/data_grid_cell.tsx +++ b/src/components/datagrid/body/data_grid_cell.tsx @@ -184,7 +184,7 @@ export class EuiDataGridCell extends Component< } }; - recalculateLineCountHeight = () => { + recalculateLineHeight = () => { if (!this.props.setRowHeight) return; // setRowHeight is only passed by data_grid_body into one cell per row if (!this.cellContentsRef) return; @@ -193,7 +193,10 @@ export class EuiDataGridCell extends Component< rowIndex, rowHeightsOptions ); - const lineCount = rowHeightUtils?.getLineCount(rowHeightOption); + const isSingleLine = rowHeightOption == null; // Undefined rowHeightsOptions default to a single line + const lineCount = isSingleLine + ? 1 + : rowHeightUtils?.getLineCount(rowHeightOption); if (lineCount) { const height = rowHeightUtils!.calculateHeightForLineCount( @@ -231,11 +234,10 @@ export class EuiDataGridCell extends Component< this.recalculateAutoHeight(); if ( - // @ts-ignore - optional chaining operator handles types & cases that aren't lineCount - this.props.rowHeightsOptions?.defaultHeight?.lineCount !== // @ts-ignore - see above - prevProps.rowHeightsOptions?.defaultHeight?.lineCount + this.props.rowHeightsOptions?.defaultHeight !== + prevProps.rowHeightsOptions?.defaultHeight ) { - this.recalculateLineCountHeight(); + this.recalculateLineHeight(); } if (this.props.columnId !== prevProps.columnId) { @@ -292,7 +294,7 @@ export class EuiDataGridCell extends Component< if (ref && hasResizeObserver) { this.contentObserver = new (window as any).ResizeObserver(() => { this.recalculateAutoHeight(); - this.recalculateLineCountHeight(); + this.recalculateLineHeight(); }); this.contentObserver.observe(ref); } else if (this.contentObserver) { From 39aa176494246ff0fb9abdf53cb4a47ed823303e Mon Sep 17 00:00:00 2001 From: Constance Chen Date: Thu, 11 Nov 2021 10:04:34 -0800 Subject: [PATCH 09/28] Add changelog entry --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7c40777caf7..436f64545a8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ ## [`main`](https://github.com/elastic/eui/tree/main) - Updated the organization of `EuiDataGrid`'s toolbar/grid controls ([#5334](https://github.com/elastic/eui/pull/5334)) +- Added the ability for users to configure `EuiDataGrid`'s default row heights ([#5372](https://github.com/elastic/eui/pull/5372)) - Added `layout` and `footer` props to `EuiEmptyPrompt` ([#5275](https://github.com/elastic/eui/pull/5275)) - Updated `EuiEmptyPrompt` to extend `EuiPanelProps` ([#5275](https://github.com/elastic/eui/pull/5275)) - Add `data-icon-type` to `EuiIcon` `` for easier debugging of `iconType` [#5366](https://github.com/elastic/eui/pull/5366)) @@ -13,6 +14,10 @@ - Fixed `analyzeEvent` icon to be horizontally centered [#5365](https://github.com/elastic/eui/pull/5365)) - Fixed persistent `EuiDataGrid` full screen `` class ([#5354](https://github.com/elastic/eui/pull/5354)) +**Breaking changes** + +- Deprecated `toolbarVisibility`'s `showStyleSelector` prop of `EuiDataGrid` in favor of `showDisplaySelector`, which allows users to configure both grid density and row height ([#5372](https://github.com/elastic/eui/pull/5372)) + ## [`41.0.0`](https://github.com/elastic/eui/tree/v41.0.0) - Added `EuiAutoSizer` component for setting dimensions on virtualized lists ([#5278](https://github.com/elastic/eui/pull/5278)) From 8580dc8f6994aa107d97fef200fbabc784d6eec8 Mon Sep 17 00:00:00 2001 From: Constance Chen Date: Tue, 16 Nov 2021 10:08:05 -0800 Subject: [PATCH 10/28] [PR feedback] Increase default lineCount to 2 - to make the difference more obvious when switching between single and custom --- src/components/datagrid/controls/display_selector.test.tsx | 4 ++-- src/components/datagrid/controls/display_selector.tsx | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/datagrid/controls/display_selector.test.tsx b/src/components/datagrid/controls/display_selector.test.tsx index f2079e81f5a..76f050b6f99 100644 --- a/src/components/datagrid/controls/display_selector.test.tsx +++ b/src/components/datagrid/controls/display_selector.test.tsx @@ -198,12 +198,12 @@ describe('useDataGridDisplaySelector', () => { expect(getLineCountNumber(component)).toEqual(5); }); - it('defaults to a lineCount of 1 when no developer settings have been passed', () => { + it('defaults to a lineCount of 2 when no developer settings have been passed', () => { const component = mount(); openPopover(component); component.find('[data-test-subj="lineCount"]').simulate('change'); - expect(getLineCountNumber(component)).toEqual(1); + expect(getLineCountNumber(component)).toEqual(2); }); it('increments the rowHeightOptions line count number', () => { diff --git a/src/components/datagrid/controls/display_selector.tsx b/src/components/datagrid/controls/display_selector.tsx index 086b5a600af..8164585a624 100644 --- a/src/components/datagrid/controls/display_selector.tsx +++ b/src/components/datagrid/controls/display_selector.tsx @@ -102,7 +102,7 @@ export const useDataGridDisplaySelector = ( // Row height state const [lineCount, setLineCount] = useState( // @ts-ignore - optional chaining operator handles types & cases that aren't lineCount - initialRowHeightsOptions?.defaultHeight?.lineCount || 1 + initialRowHeightsOptions?.defaultHeight?.lineCount || 2 ); const [rowHeightSelection, setRowHeightSelection] = useState( convertRowHeightsOptionsToSelection(initialRowHeightsOptions) From 7e34537aed6763067f977a5aabcfaa8c3a65c959 Mon Sep 17 00:00:00 2001 From: Constance Chen Date: Tue, 16 Nov 2021 18:19:32 -0800 Subject: [PATCH 11/28] Fix changelog --- CHANGELOG.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 02e0a59ec90..0d532c10ee1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ - Fixed persistent `EuiDataGrid` full screen `` class ([#5354](https://github.com/elastic/eui/pull/5354)) +**Breaking changes** + +- Deprecated `toolbarVisibility`'s `showStyleSelector` prop of `EuiDataGrid` in favor of `showDisplaySelector`, which allows users to configure both grid density and row height ([#5372](https://github.com/elastic/eui/pull/5372)) + ## END FEATURE BRANCH - Added `aria-label` and `aria-labelledby` props to `EuiComboBox` ([#5360](https://github.com/elastic/eui/issues/5360)) @@ -28,10 +32,6 @@ - Fixed `EuiErrorBoundary` overflow scrolling by wrapping contents in `EuiCodeBlock` ([#5359](https://github.com/elastic/eui/pull/5359)) - Fixed `analyzeEvent` icon to be horizontally centered [#5365](https://github.com/elastic/eui/pull/5365)) -**Breaking changes** - -- Deprecated `toolbarVisibility`'s `showStyleSelector` prop of `EuiDataGrid` in favor of `showDisplaySelector`, which allows users to configure both grid density and row height ([#5372](https://github.com/elastic/eui/pull/5372)) - ## [`41.0.0`](https://github.com/elastic/eui/tree/v41.0.0) - Added `EuiAutoSizer` component for setting dimensions on virtualized lists ([#5278](https://github.com/elastic/eui/pull/5278)) From d31a66d92131a08b94d774636b205fd0715f9813 Mon Sep 17 00:00:00 2001 From: Constance Chen Date: Wed, 17 Nov 2021 12:29:13 -0800 Subject: [PATCH 12/28] Fix control column appearance by switching them back to vertical centering --- src/components/datagrid/_data_grid_data_row.scss | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/components/datagrid/_data_grid_data_row.scss b/src/components/datagrid/_data_grid_data_row.scss index c171e272447..e6bf9e6771b 100644 --- a/src/components/datagrid/_data_grid_data_row.scss +++ b/src/components/datagrid/_data_grid_data_row.scss @@ -142,6 +142,10 @@ display: flex; align-items: baseline; height: 100%; + + .euiDataGridRowCell--controlColumn & { + align-items: center; + } } .euiDataGridRowCell__expandContent { From 670dc2c5cac9e92e5d8822dd8461aec3e0fc29c0 Mon Sep 17 00:00:00 2001 From: Constance Chen Date: Wed, 17 Nov 2021 13:18:34 -0800 Subject: [PATCH 13/28] Tweak various height alignments on compressed grid settings - expand buttons on single lines should now be more vertically aligned - The manual button/checkbox changes for control columns is somewhat required for auto height to not be dramatically different for single lines --- .../datagrid/_data_grid_data_row.scss | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/components/datagrid/_data_grid_data_row.scss b/src/components/datagrid/_data_grid_data_row.scss index e6bf9e6771b..4e30d5c7d17 100644 --- a/src/components/datagrid/_data_grid_data_row.scss +++ b/src/components/datagrid/_data_grid_data_row.scss @@ -256,6 +256,24 @@ } } +// Compressed density grids - height tweaks +@include euiDataGridStyles(fontSizeSmall, paddingSmall) { + .euiDataGridRowCell__contentByHeight + .euiDataGridRowCell__expandButton { + padding: ($euiDataGridCellPaddingS / 2) 0; + } + .euiDataGridRowCell__expandContent + .euiDataGridRowCell__expandButton { + transform: translateY(1px); + } + .euiDataGridRowCell--controlColumn { + .euiButtonIcon { + height: $euiSize; + } + .euiCheckbox { + transform: scale(0.9); + } + } +} + @keyframes euiDataGridCellButtonSlideIn { from { margin-left: 0; From c3f237deb11d0c42fc4cd05b9f0a98e3bb3d1d5f Mon Sep 17 00:00:00 2001 From: Constance Chen Date: Wed, 17 Nov 2021 13:19:32 -0800 Subject: [PATCH 14/28] Fix expand action button background color mismatch for auto/lineCount rows - when hovering over rows - on striped rows - Not caused by this PR, but this was really annoying me, haha --- src/components/datagrid/_data_grid_data_row.scss | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/components/datagrid/_data_grid_data_row.scss b/src/components/datagrid/_data_grid_data_row.scss index 4e30d5c7d17..3dfa800c415 100644 --- a/src/components/datagrid/_data_grid_data_row.scss +++ b/src/components/datagrid/_data_grid_data_row.scss @@ -203,6 +203,9 @@ // Needed to overtake striping background-color: $euiColorHighlight !important; } + .euiDataGridRowCell__contentByHeight + .euiDataGridRowCell__expandButton { + background-color: $euiColorHighlight !important; + } } } @@ -211,6 +214,10 @@ @include euiDataGridRowCell { &.euiDataGridRowCell--stripe { background: $euiColorLightestShade; + + .euiDataGridRowCell__contentByHeight + .euiDataGridRowCell__expandButton { + background-color: $euiColorLightestShade; + } } } } From 4dac79ec9f4ca6767c52ca0a91de5182f3c241c7 Mon Sep 17 00:00:00 2001 From: Constance Chen Date: Thu, 18 Nov 2021 09:49:19 -0800 Subject: [PATCH 15/28] PR feedback: convert cell actions CSS selectors to mixin - Slightly less grody to look at in-code, and allows us to provide more comments for context The more I look at __expandButton the more I dislike the naming also but it would involve too many changes right now to rename button->actions, so I added a TODO --- .../datagrid/_data_grid_data_row.scss | 28 +++++++++++-------- src/components/datagrid/_mixins.scss | 15 ++++++++++ 2 files changed, 31 insertions(+), 12 deletions(-) diff --git a/src/components/datagrid/_data_grid_data_row.scss b/src/components/datagrid/_data_grid_data_row.scss index 3dfa800c415..1391bb6b9c9 100644 --- a/src/components/datagrid/_data_grid_data_row.scss +++ b/src/components/datagrid/_data_grid_data_row.scss @@ -157,17 +157,21 @@ height: 100%; } +// Cell actions +// Could probably be more precisely named than '__expandButton', since there can be multiple actions/buttons +// TODO: Consider renaming this when working on https://github.com/elastic/eui/issues/5132 .euiDataGridRowCell__expandButton { display: flex; +} +@include euiDataGridRowCellActions($definedHeight: false) { flex-grow: 0; - - .euiDataGridRowCell__contentByHeight + & { - background-color: $euiColorEmptyShade; - position: absolute; - right: 0; - top: 0; - padding: $euiDataGridCellPaddingM 0; - } +} +@include euiDataGridRowCellActions($definedHeight: true) { + background-color: $euiColorEmptyShade; + position: absolute; + right: 0; + top: 0; + padding: $euiDataGridCellPaddingM 0; } .euiDataGridRowCell__expandButtonIcon { @@ -203,7 +207,7 @@ // Needed to overtake striping background-color: $euiColorHighlight !important; } - .euiDataGridRowCell__contentByHeight + .euiDataGridRowCell__expandButton { + @include euiDataGridRowCellActions($definedHeight: true) { background-color: $euiColorHighlight !important; } } @@ -215,7 +219,7 @@ &.euiDataGridRowCell--stripe { background: $euiColorLightestShade; - .euiDataGridRowCell__contentByHeight + .euiDataGridRowCell__expandButton { + @include euiDataGridRowCellActions($definedHeight: true) { background-color: $euiColorLightestShade; } } @@ -265,10 +269,10 @@ // Compressed density grids - height tweaks @include euiDataGridStyles(fontSizeSmall, paddingSmall) { - .euiDataGridRowCell__contentByHeight + .euiDataGridRowCell__expandButton { + @include euiDataGridRowCellActions($definedHeight: true) { padding: ($euiDataGridCellPaddingS / 2) 0; } - .euiDataGridRowCell__expandContent + .euiDataGridRowCell__expandButton { + @include euiDataGridRowCellActions($definedHeight: false) { transform: translateY(1px); } .euiDataGridRowCell--controlColumn { diff --git a/src/components/datagrid/_mixins.scss b/src/components/datagrid/_mixins.scss index c50a74f26b3..87f53255081 100644 --- a/src/components/datagrid/_mixins.scss +++ b/src/components/datagrid/_mixins.scss @@ -82,3 +82,18 @@ $euiDataGridStyles: ( @content; } } + +@mixin euiDataGridRowCellActions($definedHeight: false) { + @if $definedHeight { + // Defined heights are cells with row heights of auto, lineCount, or a static height + // that set the __contentByHeight class + .euiDataGridRowCell__contentByHeight + .euiDataGridRowCell__expandButton { + @content; + } + } @else { + // Otherwise, an undefined height (single flex row) will set __expandContent + .euiDataGridRowCell__expandContent + .euiDataGridRowCell__expandButton { + @content; + } + } +} From cb51f97e3388db392938e962566966b9039cfead Mon Sep 17 00:00:00 2001 From: Constance Chen Date: Thu, 18 Nov 2021 10:29:25 -0800 Subject: [PATCH 16/28] Fix sasslint issues --- src/components/datagrid/_data_grid_data_row.scss | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/components/datagrid/_data_grid_data_row.scss b/src/components/datagrid/_data_grid_data_row.scss index 1391bb6b9c9..ea2835d51a7 100644 --- a/src/components/datagrid/_data_grid_data_row.scss +++ b/src/components/datagrid/_data_grid_data_row.scss @@ -208,6 +208,8 @@ background-color: $euiColorHighlight !important; } @include euiDataGridRowCellActions($definedHeight: true) { + // sass-lint:disable-block no-important + // Needed to overtake striping background-color: $euiColorHighlight !important; } } @@ -217,11 +219,10 @@ @include euiDataGridStyles(stripes) { @include euiDataGridRowCell { &.euiDataGridRowCell--stripe { - background: $euiColorLightestShade; - @include euiDataGridRowCellActions($definedHeight: true) { background-color: $euiColorLightestShade; } + background: $euiColorLightestShade; } } } @@ -275,12 +276,14 @@ @include euiDataGridRowCellActions($definedHeight: false) { transform: translateY(1px); } + .euiDataGridRowCell--controlColumn { .euiButtonIcon { height: $euiSize; } + .euiCheckbox { - transform: scale(0.9); + transform: scale(.9); } } } From b70aa3d3e2286c8531cd42ee4b7a4c1ca5a20050 Mon Sep 17 00:00:00 2001 From: Constance Chen Date: Thu, 18 Nov 2021 10:33:03 -0800 Subject: [PATCH 17/28] PR feedback: Change line count number to EuiRange + Remove ability to set negative or zero numbers, which causes the grid to flip out --- .../controls/display_selector.test.tsx | 31 ++++++++++++++----- .../datagrid/controls/display_selector.tsx | 11 +++++-- 2 files changed, 32 insertions(+), 10 deletions(-) diff --git a/src/components/datagrid/controls/display_selector.test.tsx b/src/components/datagrid/controls/display_selector.test.tsx index 76f050b6f99..bf5439deac5 100644 --- a/src/components/datagrid/controls/display_selector.test.tsx +++ b/src/components/datagrid/controls/display_selector.test.tsx @@ -169,21 +169,25 @@ describe('useDataGridDisplaySelector', () => { describe('lineCount', () => { const getLineCountNumber = (component: ReactWrapper) => component - .find('EuiFieldNumber[data-test-subj="lineCountFieldNumber"]') + .find('EuiRange[data-test-subj="lineCountNumber"]') .prop('value'); + const setLineCountNumber = (component: ReactWrapper, number: number) => + component + .find('input[type="range"][data-test-subj="lineCountNumber"]') + .simulate('change', { target: { value: number } }); it('conditionally displays a line count number input when the lineCount button is selected', () => { const component = mount(); openPopover(component); expect( - component.find('[data-test-subj="lineCountFieldNumber"]').exists() + component.find('[data-test-subj="lineCountNumber"]').exists() ).toBe(false); component.find('[data-test-subj="lineCount"]').simulate('change'); expect(getSelection(component)).toEqual('lineCount'); expect( - component.find('[data-test-subj="lineCountFieldNumber"]').exists() + component.find('[data-test-subj="lineCountNumber"]').exists() ).toBe(true); }); @@ -214,11 +218,24 @@ describe('useDataGridDisplaySelector', () => { ); openPopover(component); - component - .find('input[data-test-subj="lineCountFieldNumber"]') - .simulate('change', { target: { value: 3 } }); + setLineCountNumber(component, 3); expect(getLineCountNumber(component)).toEqual(3); }); + + it('does not allow zero or negative line count values', () => { + const component = mount( + + ); + openPopover(component); + + setLineCountNumber(component, 0); + expect(getLineCountNumber(component)).toEqual(2); + + setLineCountNumber(component, -50); + expect(getLineCountNumber(component)).toEqual(2); + }); }); }); }); @@ -283,7 +300,7 @@ describe('useDataGridDisplaySelector', () => { }; const setLineCount = (component: ShallowWrapper, lineCount = 1) => { diveIntoEuiI18n(component) - .find('[data-test-subj="lineCountFieldNumber"]') + .find('[data-test-subj="lineCountNumber"]') .simulate('change', { target: { value: lineCount } }); }; const getOutput = (component: ShallowWrapper) => { diff --git a/src/components/datagrid/controls/display_selector.tsx b/src/components/datagrid/controls/display_selector.tsx index 8164585a624..728f8f1de9e 100644 --- a/src/components/datagrid/controls/display_selector.tsx +++ b/src/components/datagrid/controls/display_selector.tsx @@ -11,7 +11,7 @@ import React, { ReactElement, useState, useMemo, useCallback } from 'react'; import { EuiI18n, useEuiI18n } from '../../i18n'; import { EuiPopover } from '../../popover'; import { EuiButtonIcon, EuiButtonGroup } from '../../button'; -import { EuiFormRow, EuiFieldNumber } from '../../form'; +import { EuiFormRow, EuiRange } from '../../form'; import { EuiToolTip } from '../../tool_tip'; import { @@ -126,6 +126,8 @@ export const useDataGridDisplaySelector = ( ); const setLineCountHeight = useCallback((event) => { const newLineCount = Number(event.target.value); + if (newLineCount < 1) return; // Don't let users set a 0 or negative line count + setLineCount(newLineCount); setUserRowHeightsOptions({ defaultHeight: { lineCount: newLineCount } }); }, []); @@ -266,13 +268,16 @@ export const useDataGridDisplaySelector = ( {rowHeightSelection === rowHeightButtonOptions[2] && ( - )} From 52d70e3739fdf49427d61778c958e61e71fa406c Mon Sep 17 00:00:00 2001 From: Constance Chen Date: Thu, 18 Nov 2021 11:31:15 -0800 Subject: [PATCH 18/28] PR feedback - remove height tweaks for compressed auto fit --- src/components/datagrid/_data_grid_data_row.scss | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/components/datagrid/_data_grid_data_row.scss b/src/components/datagrid/_data_grid_data_row.scss index ea2835d51a7..88498aeaa5d 100644 --- a/src/components/datagrid/_data_grid_data_row.scss +++ b/src/components/datagrid/_data_grid_data_row.scss @@ -276,16 +276,6 @@ @include euiDataGridRowCellActions($definedHeight: false) { transform: translateY(1px); } - - .euiDataGridRowCell--controlColumn { - .euiButtonIcon { - height: $euiSize; - } - - .euiCheckbox { - transform: scale(.9); - } - } } @keyframes euiDataGridCellButtonSlideIn { From 38913667acbca06e41002430311bbd1cb36aa385 Mon Sep 17 00:00:00 2001 From: Constance Chen Date: Thu, 18 Nov 2021 12:38:10 -0800 Subject: [PATCH 19/28] [PR feedback] Remove `showStyleSelector` --- CHANGELOG.md | 2 +- .../datagrid/controls/display_selector.test.tsx | 14 +------------- .../datagrid/controls/display_selector.tsx | 10 +++++----- src/components/datagrid/data_grid.tsx | 4 +--- src/components/datagrid/data_grid_types.ts | 6 ------ 5 files changed, 8 insertions(+), 28 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0d532c10ee1..704a88ccb65 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,7 @@ **Breaking changes** -- Deprecated `toolbarVisibility`'s `showStyleSelector` prop of `EuiDataGrid` in favor of `showDisplaySelector`, which allows users to configure both grid density and row height ([#5372](https://github.com/elastic/eui/pull/5372)) +- Removed `toolbarVisibility`'s `showStyleSelector` prop of `EuiDataGrid` in favor of `showDisplaySelector`, which allows users to configure both grid density and row height ([#5372](https://github.com/elastic/eui/pull/5372)) ## END FEATURE BRANCH diff --git a/src/components/datagrid/controls/display_selector.test.tsx b/src/components/datagrid/controls/display_selector.test.tsx index bf5439deac5..f2f16d9c5fd 100644 --- a/src/components/datagrid/controls/display_selector.test.tsx +++ b/src/components/datagrid/controls/display_selector.test.tsx @@ -24,13 +24,11 @@ describe('useDataGridDisplaySelector', () => { showDisplaySelector = true as EuiDataGridToolBarVisibilityOptions['showDisplaySelector'], gridStyles = {}, rowHeightsOptions = undefined as EuiDataGridRowHeightsOptions | undefined, - showStyleSelector = undefined as boolean | undefined, }) => { const [displaySelector] = useDataGridDisplaySelector( showDisplaySelector, gridStyles, - rowHeightsOptions, - showStyleSelector + rowHeightsOptions ); return <>{displaySelector}; }; @@ -92,16 +90,6 @@ describe('useDataGridDisplaySelector', () => { component.find('[data-test-subj="densityButtonGroup"]') ).toHaveLength(0); }); - - // TODO: Deprecate - it('hides the density buttongroup if showStyleSelector is set to false', () => { - const component = mount(); - openPopover(component); - - expect( - component.find('[data-test-subj="densityButtonGroup"]') - ).toHaveLength(0); - }); }); describe('row height', () => { diff --git a/src/components/datagrid/controls/display_selector.tsx b/src/components/datagrid/controls/display_selector.tsx index 728f8f1de9e..8ad7bac12ca 100644 --- a/src/components/datagrid/controls/display_selector.tsx +++ b/src/components/datagrid/controls/display_selector.tsx @@ -72,14 +72,14 @@ const convertRowHeightsOptionsToSelection = ( export const useDataGridDisplaySelector = ( showDisplaySelector: EuiDataGridToolBarVisibilityOptions['showDisplaySelector'], initialStyles: EuiDataGridStyle, - initialRowHeightsOptions?: EuiDataGridRowHeightsOptions, - showStyleSelector?: EuiDataGridToolBarVisibilityOptions['showStyleSelector'] // TODO: Deprecate + initialRowHeightsOptions?: EuiDataGridRowHeightsOptions ): [ReactElement, EuiDataGridStyle, EuiDataGridRowHeightsOptions] => { const [isOpen, setIsOpen] = useState(false); - const showDensityControls = - showStyleSelector ?? - getNestedObjectOptions(showDisplaySelector, 'allowDensity'); + const showDensityControls = getNestedObjectOptions( + showDisplaySelector, + 'allowDensity' + ); const showRowHeightControls = getNestedObjectOptions( showDisplaySelector, diff --git a/src/components/datagrid/data_grid.tsx b/src/components/datagrid/data_grid.tsx index 7d6c3bc1fce..af29264c086 100644 --- a/src/components/datagrid/data_grid.tsx +++ b/src/components/datagrid/data_grid.tsx @@ -658,9 +658,7 @@ export const EuiDataGrid: FunctionComponent = (props) => { 'showDisplaySelector' ), gridStyleWithDefaults, - _rowHeightsOptions, - // @ts-ignore - showStyleSelector will be deprecated - toolbarVisibility?.showStyleSelector + _rowHeightsOptions ); // compute the default column width from the container's clientWidth and count of visible columns diff --git a/src/components/datagrid/data_grid_types.ts b/src/components/datagrid/data_grid_types.ts index df7be70488a..c3624eb1fcb 100644 --- a/src/components/datagrid/data_grid_types.ts +++ b/src/components/datagrid/data_grid_types.ts @@ -614,12 +614,6 @@ export interface EuiDataGridToolBarVisibilityOptions { showDisplaySelector?: | boolean | EuiDataGridToolBarVisibilityDisplaySelectorOptions; - /** - * Allows the ability for the user to set the grid density. If on, this merges against what is provided in #EuiDataGridStyle - * - * **DEPRECATED: Use `showDisplaySelector.allowDensity`** - */ - showStyleSelector?: boolean; /** * Allows the ability for the user to sort rows based upon column values */ From cab4a0695a8560174b0e64e9ced8af07b87b7320 Mon Sep 17 00:00:00 2001 From: Constance Chen Date: Thu, 18 Nov 2021 13:30:34 -0800 Subject: [PATCH 20/28] Remove unused unit tests - This should have been done in 79c878d, but I missed it --- .../controls/column_selector.test.tsx | 32 ------------------- 1 file changed, 32 deletions(-) diff --git a/src/components/datagrid/controls/column_selector.test.tsx b/src/components/datagrid/controls/column_selector.test.tsx index 31f4957cdfb..028ec1d676c 100644 --- a/src/components/datagrid/controls/column_selector.test.tsx +++ b/src/components/datagrid/controls/column_selector.test.tsx @@ -83,38 +83,6 @@ describe('useDataGridColumnSelector', () => { closePopover(component); }); - describe('getShowColumnSelectorValue', () => { - it('renders both hiding and reordering functionality when showColumnSelector is true', () => { - const component = mount(); - openPopover(component); - - expect(component.find('EuiSwitch')).toHaveLength(2); - expect(component.find('EuiIcon[type="grab"]')).toHaveLength(2); - }); - - it('defaults to enabling all functionality when showColumnSelector is not defined', () => { - const component = mount( - // @ts-ignore - normally this would be undefined and not null, but we have = fallbacks up above for testing QOL - - ); - openPopover(component); - - expect(component.find('EuiSwitch')).toHaveLength(2); - expect(component.find('EuiIcon[type="grab"]')).toHaveLength(2); - }); - - it('does not render either hiding or reordering when showColumnSelector is false', () => { - const component = mount(); - openPopover(component); - - expect(component.find('EuiSwitch')).toHaveLength(0); - expect(component.find('EuiIcon[type="grab"]')).toHaveLength(0); - expect(component.find('EuiDroppable').prop('isDropDisabled')).toEqual( - true - ); - }); - }); - describe('column filtering', () => { const showColumnSelector = { allowHide: true, allowReorder: true }; From 571be25bf0f35111de86e03714a67883dcc249a6 Mon Sep 17 00:00:00 2001 From: Constance Chen Date: Thu, 18 Nov 2021 13:33:36 -0800 Subject: [PATCH 21/28] [PR feedback] Intelligently disable toolbar control if all nested options are disabled Notes: - Strongly recommend turning off whitespace changes to reduce indentation noise - This could have been done at the `data_grid_toolbar` level and could be a microperf optimization to do so, but since this is a relatively unlikely edge case in any case I don't think it's worth the overoptimization when this approach is relatively straightforward to implement --- .../controls/column_selector.test.tsx | 12 + .../datagrid/controls/column_selector.tsx | 308 +++++++++--------- .../controls/data_grid_toolbar.test.tsx | 4 +- .../controls/display_selector.test.tsx | 12 + .../datagrid/controls/display_selector.tsx | 245 +++++++------- src/components/datagrid/data_grid_types.ts | 4 +- 6 files changed, 307 insertions(+), 278 deletions(-) diff --git a/src/components/datagrid/controls/column_selector.test.tsx b/src/components/datagrid/controls/column_selector.test.tsx index 028ec1d676c..7fdb2ae8cd8 100644 --- a/src/components/datagrid/controls/column_selector.test.tsx +++ b/src/components/datagrid/controls/column_selector.test.tsx @@ -83,6 +83,18 @@ describe('useDataGridColumnSelector', () => { closePopover(component); }); + it('does not render if all valid sub-options are disabled', () => { + const component = shallow( + + ); + expect(component.text()).toEqual(''); + }); + describe('column filtering', () => { const showColumnSelector = { allowHide: true, allowReorder: true }; diff --git a/src/components/datagrid/controls/column_selector.tsx b/src/components/datagrid/controls/column_selector.tsx index 175423ba094..52d22129abd 100644 --- a/src/components/datagrid/controls/column_selector.tsx +++ b/src/components/datagrid/controls/column_selector.tsx @@ -11,7 +11,7 @@ import React, { useState, useMemo, useCallback, - ReactElement, + ReactNode, ChangeEvent, } from 'react'; import classNames from 'classnames'; @@ -43,7 +43,7 @@ export const useDataGridColumnSelector = ( showColumnSelector: EuiDataGridToolBarVisibilityOptions['showColumnSelector'], displayValues: { [key: string]: string } ): [ - ReactElement, + ReactNode, EuiDataGridColumn[], (columns: string[]) => void, (colFrom: string, colTo: string) => void @@ -139,159 +139,163 @@ export const useDataGridColumnSelector = ( ); } - const columnSelector = ( - setIsOpen(false)} - anchorPosition="downLeft" - panelPaddingSize="s" - panelClassName="euiDataGrid__controlPopoverWithDragDrop" - button={ - setIsOpen(!isOpen)} - > - {buttonText} - - } - > -

- {allowColumnHiding && ( - - - {([search, searchcolumns]: string[]) => ( - ) => - setColumnSearchText(e.currentTarget.value) - } - data-test-subj="dataGridColumnSelectorSearch" - /> - )} - - - )} -
- - - - {filteredColumns.map((id, index) => ( - - {(provided, state) => ( -
- - - {allowColumnHiding ? ( - { - const { - target: { checked }, - } = event; - const nextVisibleColumns = sortedColumns.filter( - (columnId) => - checked - ? visibleColumnIds.has(columnId) || - id === columnId - : visibleColumnIds.has(columnId) && - id !== columnId - ); - setVisibleColumns(nextVisibleColumns); - }} - data-test-subj={`dataGridColumnSelectorToggleColumnVisibility-${id}`} - /> - ) : ( - - {id} - - )} - - {isDragEnabled && ( - - - - )} - -
- )} -
- ))} -
-
-
-
-
- {allowColumnHiding && ( - - setIsOpen(false)} + anchorPosition="downLeft" + panelPaddingSize="s" + panelClassName="euiDataGrid__controlPopoverWithDragDrop" + button={ + setIsOpen(!isOpen)} > - - setVisibleColumns(sortedColumns)} - data-test-subj="dataGridColumnSelectorShowAllButton" + {buttonText} + + } + > +
+ {allowColumnHiding && ( + + - - - - - setVisibleColumns([])} - data-test-subj="dataGridColumnSelectorHideAllButton" + {([search, searchcolumns]: string[]) => ( + ) => + setColumnSearchText(e.currentTarget.value) + } + data-test-subj="dataGridColumnSelectorSearch" + /> + )} + + + )} +
+ + - - - - - - )} - - ); + + {filteredColumns.map((id, index) => ( + + {(provided, state) => ( +
+ + + {allowColumnHiding ? ( + { + const { + target: { checked }, + } = event; + const nextVisibleColumns = sortedColumns.filter( + (columnId) => + checked + ? visibleColumnIds.has(columnId) || + id === columnId + : visibleColumnIds.has(columnId) && + id !== columnId + ); + setVisibleColumns(nextVisibleColumns); + }} + data-test-subj={`dataGridColumnSelectorToggleColumnVisibility-${id}`} + /> + ) : ( + + {id} + + )} + + {isDragEnabled && ( + + + + )} + +
+ )} +
+ ))} +
+
+
+
+
+ {allowColumnHiding && ( + + + + setVisibleColumns(sortedColumns)} + data-test-subj="dataGridColumnSelectorShowAllButton" + > + + + + + setVisibleColumns([])} + data-test-subj="dataGridColumnSelectorHideAllButton" + > + + + + + + )} + + ) : null; const orderedVisibleColumns = useMemo( () => diff --git a/src/components/datagrid/controls/data_grid_toolbar.test.tsx b/src/components/datagrid/controls/data_grid_toolbar.test.tsx index 39d0273b9e4..eaa3a4615ab 100644 --- a/src/components/datagrid/controls/data_grid_toolbar.test.tsx +++ b/src/components/datagrid/controls/data_grid_toolbar.test.tsx @@ -21,9 +21,9 @@ describe('EuiDataGridToolbar', () => { gridWidth: 500, toolbarVisibility: true, isFullScreen: false, - displaySelector: React.createElement('div', null, 'mock style selector'), + displaySelector:
mock style selector
, controlBtnClasses: '', - columnSelector: React.createElement('div', null, 'mock column selector'), + columnSelector:
mock column selector
, columnSorting:
mock column sorting
, setRef: jest.fn(), setIsFullScreen: jest.fn(), diff --git a/src/components/datagrid/controls/display_selector.test.tsx b/src/components/datagrid/controls/display_selector.test.tsx index f2f16d9c5fd..cd302c0acf6 100644 --- a/src/components/datagrid/controls/display_selector.test.tsx +++ b/src/components/datagrid/controls/display_selector.test.tsx @@ -52,6 +52,18 @@ describe('useDataGridDisplaySelector', () => { expect(component).toMatchSnapshot(); }); + it('does not render if all valid sub-options are disabled', () => { + const component = shallow( + + ); + expect(component.text()).toEqual(''); + }); + describe('density', () => { const getSelection = (component: ReactWrapper) => component diff --git a/src/components/datagrid/controls/display_selector.tsx b/src/components/datagrid/controls/display_selector.tsx index 8ad7bac12ca..451653e169d 100644 --- a/src/components/datagrid/controls/display_selector.tsx +++ b/src/components/datagrid/controls/display_selector.tsx @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import React, { ReactElement, useState, useMemo, useCallback } from 'react'; +import React, { ReactNode, useState, useMemo, useCallback } from 'react'; import { EuiI18n, useEuiI18n } from '../../i18n'; import { EuiPopover } from '../../popover'; @@ -73,7 +73,7 @@ export const useDataGridDisplaySelector = ( showDisplaySelector: EuiDataGridToolBarVisibilityOptions['showDisplaySelector'], initialStyles: EuiDataGridStyle, initialRowHeightsOptions?: EuiDataGridRowHeightsOptions -): [ReactElement, EuiDataGridStyle, EuiDataGridRowHeightsOptions] => { +): [ReactNode, EuiDataGridStyle, EuiDataGridRowHeightsOptions] => { const [isOpen, setIsOpen] = useState(false); const showDensityControls = getNestedObjectOptions( @@ -152,141 +152,142 @@ export const useDataGridDisplaySelector = ( 'Display options' ); - const displaySelector = ( - setIsOpen(false)} - anchorPosition="downRight" - panelPaddingSize="s" - panelClassName="euiDataGrid__displayPopoverPanel" - button={ - - setIsOpen(!isOpen)} - aria-label={buttonLabel} - /> - - } - > - {showDensityControls && ( - - {([ - densityLabel, - labelCompact, - labelNormal, - labelExpanded, - ]: string[]) => ( - - - - )} - - )} - {showRowHeightControls && ( - - {([ - rowHeightLabel, - labelSingle, - labelAuto, - labelCustom, - lineCountLabel, - ]: string[]) => ( - <> - + const displaySelector = + showDensityControls || showRowHeightControls ? ( + setIsOpen(false)} + anchorPosition="downRight" + panelPaddingSize="s" + panelClassName="euiDataGrid__displayPopoverPanel" + button={ + + setIsOpen(!isOpen)} + aria-label={buttonLabel} + /> + + } + > + {showDensityControls && ( + + {([ + densityLabel, + labelCompact, + labelNormal, + labelExpanded, + ]: string[]) => ( + - {rowHeightSelection === rowHeightButtonOptions[2] && ( - - + )} + {showRowHeightControls && ( + + {([ + rowHeightLabel, + labelSingle, + labelAuto, + labelCustom, + lineCountLabel, + ]: string[]) => ( + <> + + - )} - - )} - - )} - - ); + {rowHeightSelection === rowHeightButtonOptions[2] && ( + + + + )} + + )} + + )} + + ) : null; return [displaySelector, gridStyles, rowHeightsOptions]; }; diff --git a/src/components/datagrid/data_grid_types.ts b/src/components/datagrid/data_grid_types.ts index c3624eb1fcb..92e3e3450a6 100644 --- a/src/components/datagrid/data_grid_types.ts +++ b/src/components/datagrid/data_grid_types.ts @@ -30,10 +30,10 @@ export interface EuiDataGridToolbarProps { gridWidth: number; minSizeForControls?: number; toolbarVisibility: boolean | EuiDataGridToolBarVisibilityOptions; - displaySelector: ReactElement; + displaySelector: ReactNode; isFullScreen: boolean; controlBtnClasses: string; - columnSelector: ReactElement; + columnSelector: ReactNode; columnSorting: ReactNode; setRef: RefCallback; setIsFullScreen: Dispatch>; From 3dd2d3fc0568ccc26b2edd8ca865d879b035114d Mon Sep 17 00:00:00 2001 From: Constance Chen Date: Tue, 23 Nov 2021 08:53:30 -0800 Subject: [PATCH 22/28] Do not fall back to undefined/single for static heights --- .../datagrid/controls/display_selector.test.tsx | 16 ++++++++++++---- .../datagrid/controls/display_selector.tsx | 6 ++++++ 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/components/datagrid/controls/display_selector.test.tsx b/src/components/datagrid/controls/display_selector.test.tsx index cd302c0acf6..6d91111d6fb 100644 --- a/src/components/datagrid/controls/display_selector.test.tsx +++ b/src/components/datagrid/controls/display_selector.test.tsx @@ -157,12 +157,20 @@ describe('useDataGridDisplaySelector', () => { expect(getSelection(component)).toEqual('undefined'); }); - test('height should fall back to undefined', () => { - const component = mount( + test('height should not select any buttons', () => { + const component1 = mount( ); - openPopover(component); - expect(getSelection(component)).toEqual('undefined'); + openPopover(component1); + expect(getSelection(component1)).toEqual(''); + + const component2 = mount( + + ); + openPopover(component2); + expect(getSelection(component2)).toEqual(''); }); }); diff --git a/src/components/datagrid/controls/display_selector.tsx b/src/components/datagrid/controls/display_selector.tsx index 451653e169d..fd4e1ae6874 100644 --- a/src/components/datagrid/controls/display_selector.tsx +++ b/src/components/datagrid/controls/display_selector.tsx @@ -65,6 +65,12 @@ const convertRowHeightsOptionsToSelection = ( if (typeof defaultHeight === 'object' && defaultHeight?.lineCount) { return rowHeightButtonOptions[2]; } + if ( + typeof defaultHeight === 'number' || + (typeof defaultHeight === 'object' && defaultHeight.height) + ) { + return ''; + } } return rowHeightButtonOptions[0]; }; From 0ab5aac2be840abc7a8f05063cb3389b9e7e2da9 Mon Sep 17 00:00:00 2001 From: Constance Date: Tue, 23 Nov 2021 08:55:40 -0800 Subject: [PATCH 23/28] PR changelog feedback Co-authored-by: Caroline Horn <549577+cchaos@users.noreply.github.com> --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 854721879a1..8d2019a7cb0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,7 @@ ## [`main`](https://github.com/elastic/eui/tree/main) - Updated the organization of `EuiDataGrid`'s toolbar/grid controls ([#5334](https://github.com/elastic/eui/pull/5334)) -- Added the ability for users to configure `EuiDataGrid`'s default row heights ([#5372](https://github.com/elastic/eui/pull/5372)) +- Added a row height control to `EuiDataGrid`'s toolbar ([#5372](https://github.com/elastic/eui/pull/5372)) **Bug fixes** @@ -9,7 +9,7 @@ **Breaking changes** -- Removed `toolbarVisibility`'s `showStyleSelector` prop of `EuiDataGrid` in favor of `showDisplaySelector`, which allows users to configure both grid density and row height ([#5372](https://github.com/elastic/eui/pull/5372)) +- Removed `toolbarVisibility`'s `showStyleSelector` prop of `EuiDataGrid` in favor of `showDisplaySelector`, which allows configuration of both grid density and row height ([#5372](https://github.com/elastic/eui/pull/5372)) ## END FEATURE BRANCH From f226ad7274fad4d061e1795160aeae116de1ad2b Mon Sep 17 00:00:00 2001 From: Constance Chen Date: Tue, 23 Nov 2021 09:40:19 -0800 Subject: [PATCH 24/28] Update grid density to also intelligently detect initial state + not set a button state if custom fontSize/cellPadding don't match our defined density states --- .../controls/display_selector.test.tsx | 34 +++++++++++++++++++ .../datagrid/controls/display_selector.tsx | 24 ++++++++++--- 2 files changed, 53 insertions(+), 5 deletions(-) diff --git a/src/components/datagrid/controls/display_selector.test.tsx b/src/components/datagrid/controls/display_selector.test.tsx index 6d91111d6fb..88b699a8d01 100644 --- a/src/components/datagrid/controls/display_selector.test.tsx +++ b/src/components/datagrid/controls/display_selector.test.tsx @@ -102,6 +102,40 @@ describe('useDataGridDisplaySelector', () => { component.find('[data-test-subj="densityButtonGroup"]') ).toHaveLength(0); }); + + describe('convertGridStylesToSelection (loading initial state from passed gridStyles', () => { + it('should set compact state if both fontSize and cellPadding are s', () => { + const component = mount( + + ); + openPopover(component); + expect(getSelection(component)).toEqual('compact'); + }); + + it('should set normal state if both fontSize and cellPadding are m', () => { + const component = mount( + + ); + openPopover(component); + expect(getSelection(component)).toEqual('normal'); + }); + + it('should set compact state if both fontSize and cellPadding are l', () => { + const component = mount( + + ); + openPopover(component); + expect(getSelection(component)).toEqual('expanded'); + }); + + it('should not select any buttons if fontSize and cellPadding do not match a set density state', () => { + const component = mount( + + ); + openPopover(component); + expect(getSelection(component)).toEqual(''); + }); + }); }); describe('row height', () => { diff --git a/src/components/datagrid/controls/display_selector.tsx b/src/components/datagrid/controls/display_selector.tsx index fd4e1ae6874..bafc4591c46 100644 --- a/src/components/datagrid/controls/display_selector.tsx +++ b/src/components/datagrid/controls/display_selector.tsx @@ -48,6 +48,16 @@ const densityStyles: { [key: string]: Partial } = { cellPadding: 's', }, }; +const convertGridStylesToSelection = (gridStyles: EuiDataGridStyle) => { + if (gridStyles?.fontSize === 's' && gridStyles?.cellPadding === 's') + return 'compact'; + if (gridStyles?.fontSize === 'm' && gridStyles?.cellPadding === 'm') + return 'normal'; + if (gridStyles?.fontSize === 'l' && gridStyles?.cellPadding === 'l') + return 'expanded'; + return ''; +}; + // Used to correctly format the icon name for the grid density icon const capitalizeDensityString = (s: string) => s[0].toUpperCase() + s.slice(1); @@ -94,12 +104,12 @@ export const useDataGridDisplaySelector = ( // track styles specified by the user at run time const [userGridStyles, setUserGridStyles] = useState({}); - const [userRowHeightsOptions, setUserRowHeightsOptions] = useState( - initialRowHeightsOptions // Set initial state from the developer-passed props - ); + const [userRowHeightsOptions, setUserRowHeightsOptions] = useState({}); // Normal is the default density - const [gridDensity, _setGridDensity] = useState(densityOptions[1]); + const [gridDensity, _setGridDensity] = useState( + convertGridStylesToSelection(initialStyles) + ); const setGridDensity = (density: string) => { _setGridDensity(density); setUserGridStyles(densityStyles[density]); @@ -171,7 +181,11 @@ export const useDataGridDisplaySelector = ( Date: Wed, 24 Nov 2021 08:10:26 -0800 Subject: [PATCH 25/28] [PR feedback] Improve typing to avoid any usage + improve unit tests to cover undefined nested object key case --- .../controls/data_grid_toolbar.test.tsx | 42 ++++++++++++++----- .../datagrid/controls/data_grid_toolbar.tsx | 8 ++-- 2 files changed, 35 insertions(+), 15 deletions(-) diff --git a/src/components/datagrid/controls/data_grid_toolbar.test.tsx b/src/components/datagrid/controls/data_grid_toolbar.test.tsx index fe16a585220..411fa9b891d 100644 --- a/src/components/datagrid/controls/data_grid_toolbar.test.tsx +++ b/src/components/datagrid/controls/data_grid_toolbar.test.tsx @@ -329,19 +329,39 @@ describe('renderAdditionalControls', () => { }); describe('getNestedObjectOptions', () => { - it('returns the passed boolean if the option is set to a boolean instead of an object', () => { - expect(getNestedObjectOptions(true, 'someKey')).toEqual(true); - expect(getNestedObjectOptions(false, 'someKey')).toEqual(false); - }); + interface MockOptions { + someKey?: boolean; + } + + describe('non-object configuration', () => { + it('returns passed booleans', () => { + expect(getNestedObjectOptions(true, 'someKey')).toEqual( + true + ); + expect(getNestedObjectOptions(false, 'someKey')).toEqual( + false + ); + }); - it('returns true if the option is undefined', () => { - expect(getNestedObjectOptions(undefined, 'someKey')).toEqual(true); + it('returns true if the option is undefined', () => { + expect(getNestedObjectOptions(undefined, 'someKey')).toEqual( + true + ); + }); }); - it('returns the nested object boolean if the option is an object configuration', () => { - expect(getNestedObjectOptions({ someKey: true }, 'someKey')).toEqual(true); - expect(getNestedObjectOptions({ someKey: false }, 'someKey')).toEqual( - false - ); + describe('object configuration', () => { + it('returns nested object booleans', () => { + expect( + getNestedObjectOptions({ someKey: true }, 'someKey') + ).toEqual(true); + expect( + getNestedObjectOptions({ someKey: false }, 'someKey') + ).toEqual(false); + }); + + it('returns true if the nested object key is undefined', () => { + expect(getNestedObjectOptions({}, 'someKey')).toEqual(true); + }); }); }); diff --git a/src/components/datagrid/controls/data_grid_toolbar.tsx b/src/components/datagrid/controls/data_grid_toolbar.tsx index 8981540fa40..028ad58a926 100644 --- a/src/components/datagrid/controls/data_grid_toolbar.tsx +++ b/src/components/datagrid/controls/data_grid_toolbar.tsx @@ -206,9 +206,9 @@ export function renderAdditionalControls( * (e.g. column selector, display selector) */ -export function getNestedObjectOptions( - controlOption: undefined | boolean | any, // any is in place here so we don't have to pass in each config obj manually - objectKey: string +export function getNestedObjectOptions( + controlOption: undefined | boolean | T, + objectKey: keyof T ): boolean { // If the config is a boolean, nested options follow that boolean if (controlOption === false) return false; @@ -216,5 +216,5 @@ export function getNestedObjectOptions( // If config is not defined, default to enabled if (controlOption == null) return true; // Otherwise, type should be an object of boolean values - dive into it and return the value - return controlOption[objectKey] !== false; + return !!(controlOption[objectKey] ?? true); } From 4250a73a8103566e8ed40df3629eb674db4a6863 Mon Sep 17 00:00:00 2001 From: Constance Chen Date: Wed, 24 Nov 2021 08:44:46 -0800 Subject: [PATCH 26/28] [PR feedback] Document recommendation for disabling row height switcher when using `rowHeights` @see https://github.com/elastic/eui/issues/5411 --- .../datagrid/datagrid_height_options_example.js | 15 +++++++++++++++ src-docs/src/views/datagrid/row_height_fixed.tsx | 3 +++ src/components/datagrid/data_grid_types.ts | 3 +++ 3 files changed, 21 insertions(+) diff --git a/src-docs/src/views/datagrid/datagrid_height_options_example.js b/src-docs/src/views/datagrid/datagrid_height_options_example.js index 0dcc4e92b72..fcaf9d43aa8 100644 --- a/src-docs/src/views/datagrid/datagrid_height_options_example.js +++ b/src-docs/src/views/datagrid/datagrid_height_options_example.js @@ -75,6 +75,9 @@ const rowHeightsFullSnippet = `const rowHeightsOptions = useMemo( inMemory={{ level: 'sorting' }} sorting={{ columns: sortingColumns, onSort }} rowHeightsOptions={rowHeightsOptions} + toolbarVisibility={{ + showDisplaySelelector: { allowRowHeight: false }, + }} pagination={{ ...pagination, pageSizeOptions: [50, 250, 1000], @@ -243,6 +246,18 @@ export const DataGridRowHeightOptionsExample = { {rowHeightsSnippet} + + When using rowHeights overrides, we recommend + setting{' '} + + toolbarVisibility.showDisplaySelector.allowRowHeight + {' '} + to false, as users will otherwise be confused + when switching row heights does not affect specific overriden rows. + ), components: { DataGridRowHeightOptions }, diff --git a/src-docs/src/views/datagrid/row_height_fixed.tsx b/src-docs/src/views/datagrid/row_height_fixed.tsx index 91df500a1ca..ff6230e1e6a 100644 --- a/src-docs/src/views/datagrid/row_height_fixed.tsx +++ b/src-docs/src/views/datagrid/row_height_fixed.tsx @@ -215,6 +215,9 @@ export default () => { inMemory={{ level: 'sorting' }} sorting={{ columns: sortingColumns, onSort }} rowHeightsOptions={rowHeightsOptions} + toolbarVisibility={{ + showDisplaySelector: { allowRowHeight: false }, + }} virtualizationOptions={{ // rough average of the cell heights in the example // accurately setting this smooths out the scrolling experience diff --git a/src/components/datagrid/data_grid_types.ts b/src/components/datagrid/data_grid_types.ts index f71e8e76557..9b1b15ab9e8 100644 --- a/src/components/datagrid/data_grid_types.ts +++ b/src/components/datagrid/data_grid_types.ts @@ -758,6 +758,9 @@ export interface EuiDataGridRowHeightsOptions { defaultHeight?: EuiDataGridRowHeightOption; /** * Defines the height for a specific row. It can be line count or just height. + * + * When using row height overrides, we strongly setting the `showDisplaySelector: allowRowHeight` + * toolbar control to `false` in #EuiDataGridToolBarVisibilityOptions */ rowHeights?: Record; /** From fc4105c71d2cfc780e326e0591f408ad7d214553 Mon Sep 17 00:00:00 2001 From: Constance Chen Date: Wed, 24 Nov 2021 09:26:07 -0800 Subject: [PATCH 27/28] [Pr feedback] Simplify getNestedObjectOptions --- src/components/datagrid/controls/data_grid_toolbar.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/components/datagrid/controls/data_grid_toolbar.tsx b/src/components/datagrid/controls/data_grid_toolbar.tsx index 028ad58a926..81b610aadb0 100644 --- a/src/components/datagrid/controls/data_grid_toolbar.tsx +++ b/src/components/datagrid/controls/data_grid_toolbar.tsx @@ -211,8 +211,7 @@ export function getNestedObjectOptions( objectKey: keyof T ): boolean { // If the config is a boolean, nested options follow that boolean - if (controlOption === false) return false; - if (controlOption === true) return true; + if (controlOption === false || controlOption === true) return controlOption; // If config is not defined, default to enabled if (controlOption == null) return true; // Otherwise, type should be an object of boolean values - dive into it and return the value From 0b9ca2185f125de970902ecdb8850fe3ef72c70d Mon Sep 17 00:00:00 2001 From: Constance Chen Date: Wed, 24 Nov 2021 11:46:16 -0800 Subject: [PATCH 28/28] Add workaround for failing Cypress tests Also see https://stackoverflow.com/questions/49384120/resizeobserver-loop-limit-exceeded --- cypress/support/index.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/cypress/support/index.js b/cypress/support/index.js index 9bc34e3acd7..6ba42a3fcf9 100644 --- a/cypress/support/index.js +++ b/cypress/support/index.js @@ -15,3 +15,10 @@ import '@cypress/code-coverage/support'; require(THEME_IMPORT); // defined by DefinePlugin in the cypress webpack config + +// @see https://github.com/quasarframework/quasar/issues/2233#issuecomment-492975745 +Cypress.on('uncaught:exception', (err) => { + if (err.message.includes('> ResizeObserver loop limit exceeded')) { + return false; + } +});