Skip to content

Commit

Permalink
[UnifiedDocViewer] Redesign header and make actions responsive (elast…
Browse files Browse the repository at this point in the history
…ic#173780)

- Resolves elastic#163239
- Resolves elastic#164660
- Related PR elastic#173765

## Summary

- large screen and max 3 items => it will render an icon and a label for
each action:
<img width="500" alt="Screenshot 2024-01-03 at 18 02 23"
src="https://github.com/elastic/kibana/assets/1415710/f125a544-59c2-4ac9-aa87-9e72dd2c6deb">

- otherwise: max 3 icons and the rest in a context menu:
<img width="400" alt="Screenshot 2024-01-03 at 18 02 07"
src="https://github.com/elastic/kibana/assets/1415710/942b5cdb-2774-401a-9c68-daeb01b5d459">

- small screen: all items are in the context menu
<img width="678" alt="Screenshot 2024-01-03 at 18 01 39"
src="https://github.com/elastic/kibana/assets/1415710/52b9fb2a-b022-4a56-ad3c-e022b6876c0a">


I also extended "Discover customization" example plugin to showcase more
actions. For testing you can run kibana with `yarn start --run-examples`
and update number of additional actions locally via
https://github.com/jughosta/kibana/blob/690c38e689d8fb802cce8155c1a300f5ca9cb94f/examples/discover_customization_examples/public/plugin.tsx#L411

### Checklist

- [x] Any text added follows [EUI's writing
guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses
sentence case text and includes [i18n
support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md)
- [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: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
Co-authored-by: Davis McPhee <davismcphee@hotmail.com>
  • Loading branch information
3 people committed Jan 10, 2024
1 parent 517763e commit 1181251
Show file tree
Hide file tree
Showing 10 changed files with 403 additions and 145 deletions.
23 changes: 23 additions & 0 deletions examples/discover_customization_examples/public/plugin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
EuiFlexItem,
EuiPopover,
EuiWrappingPopover,
IconType,
} from '@elastic/eui';
import {
AppNavLinkStatus,
Expand Down Expand Up @@ -401,6 +402,28 @@ export class DiscoverCustomizationExamplesPlugin implements Plugin {
},
});

customizations.set({
id: 'flyout',
size: '60%',
title: 'Example custom flyout',
actions: {
getActionItems: () =>
Array.from({ length: 5 }, (_, i) => {
const index = i + 1;
return {
id: `action-item-${index}`,
enabled: true,
label: `Action ${index}`,
iconType: ['faceHappy', 'faceNeutral', 'faceSad', 'infinity', 'bell'].at(
i
) as IconType,
dataTestSubj: `customActionItem${index}`,
onClick: () => alert(index),
};
}),
},
});

return () => {
// eslint-disable-next-line no-console
console.log('Cleaning up Logs explorer customizations');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,14 +73,6 @@
min-height: 0;
}

.unifiedDataTable__flyoutHeader {
white-space: nowrap;
}

.unifiedDataTable__flyoutDocumentNavigation {
justify-content: flex-end;
}

// We only truncate if the cell is not a control column.
.euiDataGridHeader {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
*/

import React from 'react';
import { EuiButtonIcon, EuiContextMenuItem, EuiPopover } from '@elastic/eui';
import { findTestSubject } from '@elastic/eui/lib/test';
import { EuiFlexItem } from '@elastic/eui';
import { mountWithIntl } from '@kbn/test-jest-helpers';
import type { Query, AggregateQuery } from '@kbn/es-query';
import { DiscoverGridFlyout, DiscoverGridFlyoutProps } from './discover_grid_flyout';
Expand Down Expand Up @@ -36,6 +36,22 @@ jest.mock('../../customizations', () => ({
useDiscoverCustomization: jest.fn(),
}));

let mockBreakpointSize: string | null = null;

jest.mock('@elastic/eui', () => {
const original = jest.requireActual('@elastic/eui');
return {
...original,
useIsWithinBreakpoints: jest.fn((breakpoints: string[]) => {
if (mockBreakpointSize && breakpoints.includes(mockBreakpointSize)) {
return true;
}

return original.useIsWithinBreakpoints(breakpoints);
}),
};
});

const waitNextTick = () => new Promise((resolve) => setTimeout(resolve, 0));

const waitNextUpdate = async (component: ReactWrapper) => {
Expand Down Expand Up @@ -227,7 +243,7 @@ describe('Discover flyout', function () {
const singleDocumentView = findTestSubject(component, 'docTableRowAction');
expect(singleDocumentView.length).toBeFalsy();
const flyoutTitle = findTestSubject(component, 'docTableRowDetailsTitle');
expect(flyoutTitle.text()).toBe('Expanded row');
expect(flyoutTitle.text()).toBe('Row');
});

describe('with applied customizations', () => {
Expand All @@ -246,17 +262,32 @@ describe('Discover flyout', function () {

describe('when actions are customized', () => {
it('should display actions added by getActionItems', async () => {
mockBreakpointSize = 'xl';
mockFlyoutCustomization.actions = {
getActionItems: jest.fn(() => [
{
id: 'action-item-1',
enabled: true,
Content: () => <EuiFlexItem data-test-subj="customActionItem1">Action 1</EuiFlexItem>,
label: 'Action 1',
iconType: 'document',
dataTestSubj: 'customActionItem1',
onClick: jest.fn(),
},
{
id: 'action-item-2',
enabled: true,
Content: () => <EuiFlexItem data-test-subj="customActionItem2">Action 2</EuiFlexItem>,
label: 'Action 2',
iconType: 'document',
dataTestSubj: 'customActionItem2',
onClick: jest.fn(),
},
{
id: 'action-item-3',
enabled: false,
label: 'Action 3',
iconType: 'document',
dataTestSubj: 'customActionItem3',
onClick: jest.fn(),
},
]),
};
Expand All @@ -268,6 +299,88 @@ describe('Discover flyout', function () {

expect(action1.text()).toBe('Action 1');
expect(action2.text()).toBe('Action 2');
expect(findTestSubject(component, 'customActionItem3').exists()).toBe(false);
mockBreakpointSize = null;
});

it('should display multiple actions added by getActionItems', async () => {
mockFlyoutCustomization.actions = {
getActionItems: jest.fn(() =>
Array.from({ length: 5 }, (_, i) => ({
id: `action-item-${i}`,
enabled: true,
label: `Action ${i}`,
iconType: 'document',
dataTestSubj: `customActionItem${i}`,
onClick: jest.fn(),
}))
),
};

const { component } = await mountComponent({});
expect(
findTestSubject(component, 'docViewerFlyoutActions')
.find(EuiButtonIcon)
.map((button) => button.prop('data-test-subj'))
).toEqual([
'docTableRowAction',
'customActionItem0',
'customActionItem1',
'docViewerMoreFlyoutActionsButton',
]);

act(() => {
findTestSubject(component, 'docViewerMoreFlyoutActionsButton').simulate('click');
});

component.update();

expect(
component
.find(EuiPopover)
.find(EuiContextMenuItem)
.map((button) => button.prop('data-test-subj'))
).toEqual(['customActionItem2', 'customActionItem3', 'customActionItem4']);
});

it('should display multiple actions added by getActionItems in mobile view', async () => {
mockBreakpointSize = 's';

mockFlyoutCustomization.actions = {
getActionItems: jest.fn(() =>
Array.from({ length: 3 }, (_, i) => ({
id: `action-item-${i}`,
enabled: true,
label: `Action ${i}`,
iconType: 'document',
dataTestSubj: `customActionItem${i}`,
onClick: jest.fn(),
}))
),
};

const { component } = await mountComponent({});
expect(findTestSubject(component, 'docViewerFlyoutActions').length).toBe(0);

act(() => {
findTestSubject(component, 'docViewerMobileActionsButton').simulate('click');
});

component.update();

expect(
component
.find(EuiPopover)
.find(EuiContextMenuItem)
.map((button) => button.prop('data-test-subj'))
).toEqual([
'docTableRowAction',
'customActionItem0',
'customActionItem1',
'customActionItem2',
]);

mockBreakpointSize = null;
});

it('should allow disabling default actions', async () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

import React, { useMemo, useCallback } from 'react';
import { i18n } from '@kbn/i18n';
import { css } from '@emotion/react';
import type { DataView } from '@kbn/data-views-plugin/public';
import {
EuiFlexGroup,
Expand All @@ -29,6 +30,7 @@ import { useDiscoverServices } from '../../hooks/use_discover_services';
import { isTextBasedQuery } from '../../application/main/utils/is_text_based_query';
import { useFlyoutActions } from './use_flyout_actions';
import { useDiscoverCustomization } from '../../customizations';
import { DiscoverGridFlyoutActions } from './discover_grid_flyout_actions';

export interface DiscoverGridFlyoutProps {
savedSearchId?: string;
Expand Down Expand Up @@ -189,14 +191,13 @@ export function DiscoverGridFlyout({
);

const defaultFlyoutTitle = isPlainRecord
? i18n.translate('discover.grid.tableRow.textBasedDetailHeading', {
defaultMessage: 'Expanded row',
? i18n.translate('discover.grid.tableRow.docViewerTextBasedDetailHeading', {
defaultMessage: 'Row',
})
: i18n.translate('discover.grid.tableRow.detailHeading', {
defaultMessage: 'Expanded document',
: i18n.translate('discover.grid.tableRow.docViewerDetailHeading', {
defaultMessage: 'Document',
});
const flyoutTitle = flyoutCustomization?.title ?? defaultFlyoutTitle;

const flyoutSize = flyoutCustomization?.size ?? 'm';

return (
Expand All @@ -209,17 +210,24 @@ export function DiscoverGridFlyout({
ownFocus={false}
>
<EuiFlyoutHeader hasBorder>
<EuiTitle
size="s"
className="unifiedDataTable__flyoutHeader"
data-test-subj="docTableRowDetailsTitle"
<EuiFlexGroup
direction="row"
alignItems="center"
gutterSize="m"
responsive={false}
wrap={true}
>
<h2>{flyoutTitle}</h2>
</EuiTitle>
<EuiSpacer size="s" />
<EuiFlexGroup responsive={false} gutterSize="s" alignItems="center">
{!isPlainRecord &&
flyoutActions.map((action) => action.enabled && <action.Content key={action.id} />)}
<EuiFlexItem grow={false}>
<EuiTitle
size="s"
data-test-subj="docTableRowDetailsTitle"
css={css`
white-space: nowrap;
`}
>
<h2>{flyoutTitle}</h2>
</EuiTitle>
</EuiFlexItem>
{activePage !== -1 && (
<EuiFlexItem data-test-subj={`dscDocNavigationPage-${activePage}`}>
<EuiPagination
Expand All @@ -229,13 +237,18 @@ export function DiscoverGridFlyout({
pageCount={pageCount}
activePage={activePage}
onPageClick={setPage}
className="unifiedDataTable__flyoutDocumentNavigation"
compressed
data-test-subj="dscDocNavigation"
/>
</EuiFlexItem>
)}
</EuiFlexGroup>
{isPlainRecord || !flyoutActions.length ? null : (
<>
<EuiSpacer size="s" />
<DiscoverGridFlyoutActions flyoutActions={flyoutActions} />
</>
)}
</EuiFlyoutHeader>
<EuiFlyoutBody>{bodyContent}</EuiFlyoutBody>
</EuiFlyout>
Expand Down
Loading

0 comments on commit 1181251

Please sign in to comment.