Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

[EuiDataGrid] Update display selector UI when gridStyle and rowHeightsOptions props change #5526

Merged
merged 10 commits into from
Jan 12, 2022
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
## [`main`](https://github.com/elastic/eui/tree/main)

**Bug fixes**

- Fixed `EuiDataGrid`'s display toolbar control to update initial UI state when developer `gridStyle` or `rowHeightsOptions` props are updated ([#5525](https://github.com/elastic/eui/pull/5525))

**Breaking changes**

- Changed `EuiSearchBar` to preserve phrases with leading and trailing spaces, instead of dropping surrounding whitespace ([#5514](https://github.com/elastic/eui/pull/5514))
Expand Down
9 changes: 9 additions & 0 deletions src-docs/src/views/datagrid/styling.js
Original file line number Diff line number Diff line change
Expand Up @@ -455,6 +455,9 @@ const DataGrid = () => {
toolbarConfig = toolbarVisibilityOptions;
}

const [rowHeight, setRowHeight] = useState();
const setRowHeightAuto = () => setRowHeight('auto');

return (
<div>
<EuiFlexGroup gutterSize="s">
Expand Down Expand Up @@ -705,6 +708,11 @@ const DataGrid = () => {
</div>
</EuiPopover>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiButton size="s" onClick={setRowHeightAuto}>
[TEST] Set row height to auto
</EuiButton>
</EuiFlexItem>
</EuiFlexGroup>

{footerSelected === 'striped' ? (
Expand Down Expand Up @@ -738,6 +746,7 @@ const DataGrid = () => {
header: headerSelected,
footer: footerSelected,
}}
rowHeightsOptions={{ defaultHeight: rowHeight }}
toolbarVisibility={toolbarConfig}
renderCellValue={({ rowIndex, columnId }) => data[rowIndex][columnId]}
renderFooterCellValue={renderFooterCellValue}
Expand Down
45 changes: 33 additions & 12 deletions src/components/datagrid/controls/display_selector.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ describe('useDataGridDisplaySelector', () => {
).toHaveLength(0);
});

describe('convertGridStylesToSelection (loading initial state from passed gridStyles', () => {
describe('convertGridStylesToSelection', () => {
it('should set compact state if both fontSize and cellPadding are s', () => {
const component = mount(
<MockComponent gridStyles={{ fontSize: 's', cellPadding: 's' }} />
Expand Down Expand Up @@ -155,6 +155,18 @@ describe('useDataGridDisplaySelector', () => {
});
});

it('updates grid density whenever new developer styles are passed in', () => {
const component = mount(
<MockComponent gridStyles={{ fontSize: 'l', cellPadding: 'l' }} />
);
openPopover(component);
expect(getSelection(component)).toEqual('expanded');

component.setProps({ gridStyles: { fontSize: 's', cellPadding: 's' } });
component.update();
expect(getSelection(component)).toEqual('compact');
});

it('correctly resets density to initial developer-passed state', () => {
const component = mount(
<MockComponent gridStyles={{ fontSize: 'l', cellPadding: 'l' }} />
Expand Down Expand Up @@ -216,7 +228,7 @@ describe('useDataGridDisplaySelector', () => {
).toHaveLength(0);
});

describe('convertRowHeightsOptionsToSelection (loading initial state from passed rowHeightsOptions)', () => {
describe('convertRowHeightsOptionsToSelection', () => {
test('auto', () => {
const component = mount(
<MockComponent rowHeightsOptions={{ defaultHeight: 'auto' }} />
Expand Down Expand Up @@ -260,6 +272,20 @@ describe('useDataGridDisplaySelector', () => {
});
});

it('updates row height whenever new developer settings are passed in', () => {
const component = mount(
<MockComponent rowHeightsOptions={{ defaultHeight: 'auto' }} />
);
openPopover(component);
expect(getSelection(component)).toEqual('auto');

component.setProps({
rowHeightsOptions: { defaultHeight: { lineCount: 3 } },
});
component.update();
expect(getSelection(component)).toEqual('lineCount');
});

it('correctly resets row height to initial developer-passed state', () => {
const component = mount(
<MockComponent rowHeightsOptions={{ defaultHeight: undefined }} />
Expand Down Expand Up @@ -380,9 +406,10 @@ describe('useDataGridDisplaySelector', () => {
component.find('[data-test-subj="resetDisplaySelector"]').exists()
).toBe(true);

// Should hide the reset button again when changing back to the initial configuration
component.find('[data-test-subj="normal"]').simulate('change');
component.find('[data-test-subj="undefined"]').simulate('change');
// Should hide the reset button again after it's been clicked
component
.find('button[data-test-subj="resetDisplaySelector"]')
.simulate('click');
expect(
component.find('[data-test-subj="resetDisplaySelector"]').exists()
).toBe(false);
Expand Down Expand Up @@ -447,11 +474,6 @@ describe('useDataGridDisplaySelector', () => {
.find('[data-test-subj="rowHeightButtonGroup"]')
.simulate('change', selection);
};
const setLineCount = (component: ShallowWrapper, lineCount = 1) => {
diveIntoEuiI18n(component)
.find('[data-test-subj="lineCountNumber"]')
.simulate('change', { target: { value: lineCount } });
};
const getOutput = (component: ShallowWrapper) => {
return JSON.parse(component.find('[data-test-subj="output"]').text());
};
Expand Down Expand Up @@ -481,11 +503,10 @@ describe('useDataGridDisplaySelector', () => {
);

setRowHeight(component, 'lineCount');
setLineCount(component, 5);

expect(getOutput(component)).toEqual({
lineHeight: '2em',
defaultHeight: { lineCount: 5 },
defaultHeight: { lineCount: 2 },
rowHeights: {},
});
});
Expand Down
119 changes: 57 additions & 62 deletions src/components/datagrid/controls/display_selector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,13 @@
* Side Public License, v 1.
*/

import React, { ReactNode, useState, useMemo, useCallback } from 'react';
import React, {
ReactNode,
useState,
useMemo,
useCallback,
useEffect,
} from 'react';

import { useUpdateEffect } from '../../../services';
import { EuiI18n, useEuiI18n } from '../../i18n';
Expand Down Expand Up @@ -51,11 +57,11 @@ const densityStyles: { [key: string]: Partial<EuiDataGridStyle> } = {
},
};
const convertGridStylesToSelection = (gridStyles: EuiDataGridStyle) => {
if (gridStyles?.fontSize === 's' && gridStyles?.cellPadding === 's')
if (gridStyles.fontSize === 's' && gridStyles.cellPadding === 's')
return 'compact';
if (gridStyles?.fontSize === 'm' && gridStyles?.cellPadding === 'm')
if (gridStyles.fontSize === 'm' && gridStyles.cellPadding === 'm')
return 'normal';
if (gridStyles?.fontSize === 'l' && gridStyles?.cellPadding === 'l')
if (gridStyles.fontSize === 'l' && gridStyles.cellPadding === 'l')
return 'expanded';
return '';
};
Expand All @@ -66,23 +72,21 @@ 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
rowHeightsOptions: EuiDataGridRowHeightsOptions
) => {
if (rowHeightsOptions) {
const { defaultHeight } = rowHeightsOptions;
const { defaultHeight } = rowHeightsOptions;

if (defaultHeight === 'auto') {
return rowHeightButtonOptions[1];
}
if (typeof defaultHeight === 'object' && defaultHeight?.lineCount) {
return rowHeightButtonOptions[2];
}
if (
typeof defaultHeight === 'number' ||
(typeof defaultHeight === 'object' && defaultHeight.height)
) {
return '';
}
if (defaultHeight === 'auto') {
return rowHeightButtonOptions[1];
}
if (typeof defaultHeight === 'object' && defaultHeight?.lineCount) {
return rowHeightButtonOptions[2];
}
if (
typeof defaultHeight === 'number' ||
(typeof defaultHeight === 'object' && defaultHeight.height)
) {
return '';
}
return rowHeightButtonOptions[0];
};
Expand All @@ -104,37 +108,19 @@ export const useDataGridDisplaySelector = (
'allowRowHeight'
);

// Get initial state (also used when resetting)
const initialDensity = useMemo(
() => convertGridStylesToSelection(initialStyles),
[initialStyles]
);
const initialRowHeight = useMemo(
() => convertRowHeightsOptionsToSelection(initialRowHeightsOptions),
[initialRowHeightsOptions]
);
const initialLineCount = useMemo(
// @ts-ignore - optional chaining operator handles types & cases that aren't lineCount
() => initialRowHeightsOptions?.defaultHeight?.lineCount || 2,
[initialRowHeightsOptions?.defaultHeight]
);

// Track styles specified by the user at run time
const [userGridStyles, setUserGridStyles] = useState({});
const [userRowHeightsOptions, setUserRowHeightsOptions] = useState({});

// Density state
const [gridDensity, _setGridDensity] = useState(initialDensity);
const setGridDensity = (density: string) => {
_setGridDensity(density);
const [gridDensity, setGridDensity] = useState('');
const setGridStyles = (density: string) => {
setUserGridStyles(densityStyles[density]);
};

// Row height state
const [lineCount, setLineCount] = useState(initialLineCount);
const [rowHeightSelection, setRowHeightSelection] = useState(
initialRowHeight
);
const [lineCount, setLineCount] = useState(2);
const [rowHeightSelection, setRowHeightSelection] = useState('');
const setRowHeight = useCallback(
(option: string) => {
const rowHeightsOptions: EuiDataGridRowHeightsOptions = {
Expand All @@ -149,7 +135,6 @@ export const useDataGridDisplaySelector = (
rowHeightsOptions.defaultHeight = undefined;
}

setRowHeightSelection(option);
setUserRowHeightsOptions(rowHeightsOptions);
},
[lineCount]
Expand Down Expand Up @@ -180,39 +165,49 @@ export const useDataGridDisplaySelector = (
};
}, [initialRowHeightsOptions, userRowHeightsOptions]);

// Invoke onChange callbacks on user input (removing the callback value itself, so that only configuration values are returned)
// Update UI controls based on current settings, on init & when either developer or user settings change
useEffect(() => {
setGridDensity(convertGridStylesToSelection(gridStyles));
chandlerprall marked this conversation as resolved.
Show resolved Hide resolved
}, [gridStyles]);

useEffect(() => {
setRowHeightSelection(
convertRowHeightsOptionsToSelection(rowHeightsOptions)
);
}, [rowHeightsOptions]);

useEffect(() => {
// @ts-ignore - optional chaining operator handles types & cases that aren't lineCount
setLineCount(rowHeightsOptions?.defaultHeight?.lineCount || 2);
// @ts-ignore - same as above
}, [rowHeightsOptions?.defaultHeight?.lineCount]);

// Show a reset button whenever users manually change settings, and
// invoke onChange callbacks (removing the callback value itself, so that only configuration values are returned)
const [showResetButton, setShowResetButton] = useState(false);

useUpdateEffect(() => {
const hasUserChanges = Object.keys(userGridStyles).length > 0;
if (hasUserChanges) setShowResetButton(true);

const { onChange, ...currentGridStyles } = gridStyles;
initialStyles?.onChange?.(currentGridStyles);
}, [userGridStyles]);

useUpdateEffect(() => {
const hasUserChanges = Object.keys(userRowHeightsOptions).length > 0;
if (hasUserChanges) setShowResetButton(true);

const { onChange, ...currentRowHeightsOptions } = rowHeightsOptions;
initialRowHeightsOptions?.onChange?.(currentRowHeightsOptions);
}, [userRowHeightsOptions]);

// Allow resetting to initial developer-specified configurations
const resetToInitialState = useCallback(() => {
chandlerprall marked this conversation as resolved.
Show resolved Hide resolved
setGridDensity(initialDensity);
setUserGridStyles({});
setRowHeightSelection(initialRowHeight);
setUserRowHeightsOptions({});
setLineCount(initialLineCount);
}, [initialDensity, initialRowHeight, initialLineCount]);

const showResetButton = useMemo(() => {
if (initialDensity !== gridDensity) return true;
if (initialRowHeight !== rowHeightSelection) return true;
if (initialLineCount !== lineCount) return true;
return false;
}, [
initialDensity,
gridDensity,
initialRowHeight,
rowHeightSelection,
initialLineCount,
lineCount,
]);
setShowResetButton(false);
}, []);

const buttonLabel = useEuiI18n(
'euiDisplaySelector.buttonText',
Expand Down Expand Up @@ -285,7 +280,7 @@ export const useDataGridDisplaySelector = (
label: labelExpanded,
},
]}
onChange={setGridDensity}
onChange={setGridStyles}
idSelected={gridDensity}
data-test-subj="densityButtonGroup"
/>
Expand Down