Skip to content

Commit

Permalink
[Discover] Custom grid toolbar (elastic#166744)
Browse files Browse the repository at this point in the history
- Closes elastic#167245

## Summary

This PR customizes the grid toolbar for Discover. The controls will have
the "ToolbarButton" look.

<img width="600" alt="Screenshot 2023-10-17 at 11 23 16"
src="https://github.com/elastic/kibana/assets/1415710/0fbc67a5-af2c-4642-8b89-ae384ea4a608">
<img width="600" alt="Screenshot 2023-10-17 at 11 23 00"
src="https://github.com/elastic/kibana/assets/1415710/82e2605f-5d98-4035-835e-619a4c7cfde7">
<img width="600" alt="Screenshot 2023-10-17 at 11 23 44"
src="https://github.com/elastic/kibana/assets/1415710/147f084c-d3d1-455f-b02b-399724e07fb9">


 

### Checklist

- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios
- [x] This renders correctly on smaller devices using a responsive
layout. (You can test this [in your
browser](https://www.browserstack.com/guide/responsive-testing-on-local-server))
- [x] This was checked for [cross-browser
compatibility](https://www.elastic.co/support/matrix#matrix_browsers)

---------

Co-authored-by: Davis McPhee <davis.mcphee@elastic.co>
  • Loading branch information
2 people authored and benakansara committed Oct 22, 2023
1 parent 36114b0 commit ba9b99f
Show file tree
Hide file tree
Showing 35 changed files with 1,069 additions and 216 deletions.
18 changes: 15 additions & 3 deletions packages/kbn-resizable-layout/src/panels_resizable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,17 @@ export const PanelsResizable = ({
() => setResizeWithPortalsHackIsResizing(false),
[]
);
const baseButtonCss = css`
background-color: transparent !important;
gap: 0 !important;
&:not(:hover):not(:focus) {
&:before,
&:after {
width: 0;
}
}
`;
const defaultButtonCss = css`
z-index: 3;
`;
Expand Down Expand Up @@ -207,9 +218,10 @@ export const PanelsResizable = ({
</EuiResizablePanel>
<EuiResizableButton
className={resizeButtonClassName}
css={
resizeWithPortalsHackIsResizing ? resizeWithPortalsHackButtonCss : defaultButtonCss
}
css={[
baseButtonCss,
resizeWithPortalsHackIsResizing ? resizeWithPortalsHackButtonCss : defaultButtonCss,
]}
data-test-subj={`${dataTestSubj}ResizableButton`}
/>
<EuiResizablePanel
Expand Down
6 changes: 5 additions & 1 deletion packages/kbn-unified-data-table/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@
*/

export { UnifiedDataTable, DataLoadingState } from './src/components/data_table';
export type { UnifiedDataTableProps } from './src/components/data_table';
export type {
UnifiedDataTableProps,
UnifiedDataTableRenderCustomToolbar,
UnifiedDataTableRenderCustomToolbarProps,
} from './src/components/data_table';
export { getDisplayedColumns } from './src/utils/columns';
export { getTextBasedColumnTypes } from './src/utils/get_column_types';
export { ROWS_HEIGHT_OPTIONS } from './src/constants';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@
.euiDataGrid--rowHoverHighlight .euiDataGridRow:hover .euiDataGridRowCell__actions--overlay {
background-color: tintOrShade($euiColorLightShade, 50%, 0);
}

.euiDataGrid__scrollOverlay .euiDataGrid__scrollBarOverlayRight {
background-color: transparent; // otherwise the grid scrollbar border visually conflicts with the grid toolbar controls
}
}

.unifiedDataTable__table {
Expand Down
52 changes: 49 additions & 3 deletions packages/kbn-unified-data-table/src/components/data_table.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,7 @@ describe('UnifiedDataTable', () => {

expect(component.find(EuiDataGrid).prop('toolbarVisibility')).toMatchInlineSnapshot(`
Object {
"additionalControls": <React.Fragment />,
"additionalControls": null,
"showColumnSelector": false,
"showDisplaySelector": Object {
"additionalDisplaySettings": <UnifiedDataTableAdditionalDisplaySettings
Expand All @@ -339,7 +339,7 @@ describe('UnifiedDataTable', () => {

expect(component.find(EuiDataGrid).prop('toolbarVisibility')).toMatchInlineSnapshot(`
Object {
"additionalControls": <React.Fragment />,
"additionalControls": null,
"showColumnSelector": false,
"showDisplaySelector": Object {
"allowDensity": false,
Expand All @@ -360,7 +360,7 @@ describe('UnifiedDataTable', () => {

expect(component.find(EuiDataGrid).prop('toolbarVisibility')).toMatchInlineSnapshot(`
Object {
"additionalControls": <React.Fragment />,
"additionalControls": null,
"showColumnSelector": false,
"showDisplaySelector": undefined,
"showFullScreenSelector": true,
Expand Down Expand Up @@ -511,6 +511,52 @@ describe('UnifiedDataTable', () => {
});
});

describe('renderCustomToolbar', () => {
it('should render a custom toolbar', async () => {
let toolbarParams: Record<string, unknown> = {};
let gridParams: Record<string, unknown> = {};
const renderCustomToolbarMock = jest.fn((props) => {
toolbarParams = props.toolbarProps;
gridParams = props.gridProps;
return <div data-test-subj="custom-toolbar">Custom layout</div>;
});
const component = await getComponent({
...getProps(),
renderCustomToolbar: renderCustomToolbarMock,
});

// custom toolbar should be rendered
expect(findTestSubject(component, 'custom-toolbar').exists()).toBe(true);

expect(renderCustomToolbarMock).toHaveBeenLastCalledWith(
expect.objectContaining({
toolbarProps: expect.objectContaining({
hasRoomForGridControls: true,
}),
gridProps: expect.objectContaining({
additionalControls: null,
}),
})
);

// the default eui controls should be available for custom rendering
expect(toolbarParams?.columnSortingControl).toBeTruthy();
expect(toolbarParams?.keyboardShortcutsControl).toBeTruthy();
expect(gridParams?.additionalControls).toBe(null);

// additional controls become available after selecting a document
act(() => {
component
.find('[data-gridcell-column-id="select"] .euiCheckbox__input')
.first()
.simulate('change');
});

expect(toolbarParams?.keyboardShortcutsControl).toBeTruthy();
expect(gridParams?.additionalControls).toBeTruthy();
});
});

describe('gridStyleOverride', () => {
it('should render the grid with the default style if no gridStyleOverride is provided', async () => {
const component = await getComponent({
Expand Down
48 changes: 44 additions & 4 deletions packages/kbn-unified-data-table/src/components/data_table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,11 @@ import {
EuiDataGridControlColumn,
EuiDataGridCustomBodyProps,
EuiDataGridCellValueElementProps,
EuiDataGridCustomToolbarProps,
EuiDataGridToolBarVisibilityOptions,
EuiDataGridToolBarVisibilityDisplaySelectorOptions,
EuiDataGridStyle,
EuiDataGridProps,
} from '@elastic/eui';
import type { DataView } from '@kbn/data-views-plugin/public';
import {
Expand Down Expand Up @@ -66,6 +69,17 @@ import {
import { UnifiedDataTableFooter } from './data_table_footer';
import { UnifiedDataTableAdditionalDisplaySettings } from './data_table_additional_display_settings';

export interface UnifiedDataTableRenderCustomToolbarProps {
toolbarProps: EuiDataGridCustomToolbarProps;
gridProps: {
additionalControls?: EuiDataGridToolBarVisibilityOptions['additionalControls'];
};
}

export type UnifiedDataTableRenderCustomToolbar = (
props: UnifiedDataTableRenderCustomToolbarProps
) => React.ReactElement;

export type SortOrder = [string, string];

export enum DataLoadingState {
Expand Down Expand Up @@ -288,6 +302,12 @@ export interface UnifiedDataTableProps {
* It receives #EuiDataGridCustomBodyProps as its only argument.
*/
renderCustomGridBody?: (args: EuiDataGridCustomBodyProps) => React.ReactNode;
/**
* Optional render for the grid toolbar
* @param toolbarProps
* @param gridProps
*/
renderCustomToolbar?: UnifiedDataTableRenderCustomToolbar;
/**
* An optional list of the EuiDataGridControlColumn type for setting trailing control columns standard for EuiDataGrid.
*/
Expand Down Expand Up @@ -360,6 +380,7 @@ export const UnifiedDataTable = ({
onFieldEdited,
services,
renderCustomGridBody,
renderCustomToolbar,
trailingControlColumns,
totalHits,
onFetchMoreRecords,
Expand Down Expand Up @@ -709,8 +730,12 @@ export const UnifiedDataTable = ({
: internalControlColumns;
}, [canSetExpandedDoc, externalControlColumns, controlColumnIds]);

const additionalControls = useMemo(
() => (
const additionalControls = useMemo(() => {
if (!externalAdditionalControls && !usedSelectedDocs.length) {
return null;
}

return (
<>
{usedSelectedDocs.length ? (
<DataTableDocumentToolbarBtn
Expand All @@ -723,8 +748,21 @@ export const UnifiedDataTable = ({
) : null}
{externalAdditionalControls}
</>
),
[usedSelectedDocs, isFilterActive, rows, externalAdditionalControls]
);
}, [usedSelectedDocs, isFilterActive, rows, externalAdditionalControls]);

const renderCustomToolbarFn: EuiDataGridProps['renderCustomToolbar'] | undefined = useMemo(
() =>
renderCustomToolbar
? (toolbarProps) =>
renderCustomToolbar({
toolbarProps,
gridProps: {
additionalControls,
},
})
: undefined,
[renderCustomToolbar, additionalControls]
);

const showDisplaySelector = useMemo(() => {
Expand Down Expand Up @@ -852,10 +890,12 @@ export const UnifiedDataTable = ({
inMemory={inMemory}
gridStyle={gridStyleOverride ?? GRID_STYLE}
renderCustomGridBody={renderCustomGridBody}
renderCustomToolbar={renderCustomToolbarFn}
trailingControlColumns={trailingControlColumns}
/>
</div>
{loadingState !== DataLoadingState.loading &&
!usedSelectedDocs.length && // hide footer when showing selected documents
isPaginationEnabled && ( // we hide the footer for Surrounding Documents page
<UnifiedDataTableFooter
isLoadingMore={loadingState === DataLoadingState.loadingMore}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
EuiContextMenuPanel,
EuiCopy,
EuiDataGridCellValueElementProps,
EuiNotificationBadge,
EuiPopover,
EuiFlexGroup,
EuiFlexItem,
Expand Down Expand Up @@ -196,11 +197,18 @@ export function DataTableDocumentToolbarBtn({
'euiDataGrid__controlBtn--active': isFilterActive,
})}
>
<FormattedMessage
id="unifiedDataTable.selectedDocumentsNumber"
defaultMessage="{nr} documents selected"
values={{ nr: selectedDocs.length }}
/>
<EuiFlexGroup responsive={false} direction="row" alignItems="center" gutterSize="s">
<EuiFlexItem grow={false}>
<FormattedMessage
id="unifiedDataTable.selectedRowsButtonLabel"
defaultMessage="Selected"
description="Selected documents"
/>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiNotificationBadge color="subdued">{selectedDocs.length}</EuiNotificationBadge>
</EuiFlexItem>
</EuiFlexGroup>
</EuiButtonEmpty>
}
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,5 +104,6 @@ describe('ContextAppContent test', () => {
it('should render discover grid correctly', async () => {
const component = await mountComponent({ isLegacy: false });
expect(component.find(UnifiedDataTable).length).toBe(1);
expect(findTestSubject(component, 'dscGridToolbar').exists()).toBe(true);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,9 @@ import {
ROW_HEIGHT_OPTION,
SHOW_MULTIFIELDS,
} from '@kbn/discover-utils';
import { DataLoadingState, UnifiedDataTable } from '@kbn/unified-data-table';
import { DataLoadingState } from '@kbn/unified-data-table';
import { DocViewFilterFn } from '@kbn/unified-doc-viewer/types';
import { DiscoverGrid } from '../../components/discover_grid';
import { getDefaultRowsPerPage } from '../../../common/constants';
import { LoadingStatus } from './services/context_query_state';
import { ActionBar } from './components/action_bar/action_bar';
Expand All @@ -37,7 +38,6 @@ import { MAX_CONTEXT_SIZE, MIN_CONTEXT_SIZE } from './services/constants';
import { DocTableContext } from '../../components/doc_table/doc_table_context';
import { useDiscoverServices } from '../../hooks/use_discover_services';
import { DiscoverGridFlyout } from '../../components/discover_grid_flyout';
import { DISCOVER_TOUR_STEP_ANCHOR_IDS } from '../../components/discover_tour';

export interface ContextAppContentProps {
columns: string[];
Expand Down Expand Up @@ -66,7 +66,7 @@ export function clamp(value: number) {
return Math.max(Math.min(MAX_CONTEXT_SIZE, value), MIN_CONTEXT_SIZE);
}

const DiscoverGridMemoized = React.memo(UnifiedDataTable);
const DiscoverGridMemoized = React.memo(DiscoverGrid);
const DocTableContextMemoized = React.memo(DocTableContext);
const ActionBarMemoized = React.memo(ActionBar);

Expand Down Expand Up @@ -191,7 +191,6 @@ export function ContextAppContent({
<CellActionsProvider getTriggerCompatibleActions={uiActions.getTriggerCompatibleActions}>
<DiscoverGridMemoized
ariaLabelledBy="surDocumentsAriaLabel"
showColumnTokens
columns={columns}
rows={rows}
dataView={dataView}
Expand All @@ -213,7 +212,6 @@ export function ContextAppContent({
maxDocFieldsDisplayed={services.uiSettings.get(MAX_DOC_FIELDS_DISPLAYED)}
renderDocumentView={renderDocumentView}
services={services}
componentsTourSteps={{ expandButton: DISCOVER_TOUR_STEP_ANCHOR_IDS.expandDocument }}
/>
</CellActionsProvider>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ export const DocumentExplorerCallout = () => {

return (
<EuiCallOut
data-test-subj="dscDocumentExplorerLegacyCallout"
className="dscDocumentExplorerCallout"
title={<CalloutTitle onCloseCallout={onCloseCallout} />}
iconType="search"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ export const DocumentExplorerUpdateCallout = () => {

return (
<EuiCallOut
data-test-subj="dscDocumentExplorerTourCallout"
className="dscDocumentExplorerCallout"
title={<CalloutTitle onCloseCallout={onCloseCallout} />}
iconType="tableDensityNormal"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import React from 'react';
import { act } from 'react-dom/test-utils';
import { BehaviorSubject } from 'rxjs';
import { findTestSubject } from '@elastic/eui/lib/test';
import { mountWithIntl } from '@kbn/test-jest-helpers';
import { setHeaderActionMenuMounter } from '../../../../kibana_services';
import { DataDocuments$ } from '../../services/discover_data_state_container';
Expand Down Expand Up @@ -40,6 +41,7 @@ async function mountComponent(fetchStatus: FetchStatus, hits: EsHitRecord[]) {
stateContainer.dataState.data$.documents$ = documents$;

const props = {
viewModeToggle: <div data-test-subj="viewModeToggle">test</div>,
dataView: dataViewMock,
onAddFilter: jest.fn(),
stateContainer,
Expand Down Expand Up @@ -76,6 +78,9 @@ describe('Discover documents layout', () => {
const component = await mountComponent(FetchStatus.COMPLETE, esHitsMock);
expect(component.find('.dscDocuments__loading').exists()).toBeFalsy();
expect(component.find('.dscTable').exists()).toBeTruthy();
expect(findTestSubject(component, 'dscGridToolbar').exists()).toBe(true);
expect(findTestSubject(component, 'dscGridToolbarBottom').exists()).toBe(true);
expect(findTestSubject(component, 'viewModeToggle').exists()).toBe(true);
});

test('should set rounded width to state on resize column', () => {
Expand Down
Loading

0 comments on commit ba9b99f

Please sign in to comment.