Skip to content

Commit

Permalink
[EuiBasicTable][EuiInMemoryTable] Enable more action props to accept …
Browse files Browse the repository at this point in the history
…an optional callback + fix missing tooltips on collapsed actions (#7373)
  • Loading branch information
cee-chen authored Nov 20, 2023
1 parent 16396c0 commit ada8592
Show file tree
Hide file tree
Showing 17 changed files with 382 additions and 212 deletions.
17 changes: 17 additions & 0 deletions changelogs/upcoming/7373.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
- Updated the actions column in `EuiBasicTable` and `EuiInMemoryTable`s. Alongside `name`, the `description`, `href`, and `data-test-subj` properties now also accept an optional callback that the current `item` will be passed to
- Updated `EuiContextMenuItem` with a new `toolTipProps` prop

**Bug fixes**

- Fixed `EuiBasicTable` and `EuiInMemoryTable` actions not showing tooltip descriptions when rendered in the all actions popover menu
- Fixed missing underlines on `EuiContextMenu` link hover

**Deprecations**

- Deprecated `EuiContextMenuItem`'s `toolTipTitle` prop. Use `toolTipProps.title` instead
- Deprecated `EuiContextMenuItem`'s `toolTipPosition` prop. Use `toolTipProps.position` instead

**Accessibility**

- Fixed `EuiBasicTable` and `EuiInMemoryTable` actions not correctly reading out action descriptions to screen readers
- Fixed `EuiBasicTable` and `EuiInMemoryTable` primary actions not visibly appearing on keyboard focus
11 changes: 11 additions & 0 deletions scripts/jest/setup/throw_on_console_error.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,17 @@ console.error = (message, ...rest) => {
return;
}

// Silence RTL act() errors, that appear to primarily come from the fact
// that we have multiple versions of `@testing-library/dom` installed
if (
typeof message === 'string' &&
message.startsWith(
'Warning: The current testing environment is not configured to support act(...)'
)
) {
return;
}

// Print React validateDOMNesting warning as a console.warn instead
// of throwing an error.
// TODO: Remove when edge-case DOM nesting is fixed in all components
Expand Down
18 changes: 11 additions & 7 deletions src-docs/src/views/tables/actions/actions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -183,13 +183,15 @@ export default () => {
} else {
let actions: Array<DefaultItemAction<User>> = [
{
name: 'Elastic.co',
description: 'Go to elastic.co',
name: 'User profile',
description: ({ firstName, lastName }) =>
`Visit ${firstName} ${lastName}'s profile`,
icon: 'editorLink',
color: 'primary',
type: 'icon',
href: 'https://elastic.co',
target: '_blank',
enabled: ({ online }) => !!online,
href: ({ id }) => `${window.location.href}?id=${id}`,
target: '_self',
'data-test-subj': 'action-outboundlink',
},
];
Expand All @@ -205,18 +207,20 @@ export default () => {
},
{
name: (user: User) => (user.id ? 'Delete' : 'Remove'),
description: 'Delete this user',
description: ({ firstName, lastName }) =>
`Delete ${firstName} ${lastName}`,
icon: 'trash',
color: 'danger',
type: 'icon',
onClick: deleteUser,
isPrimary: true,
'data-test-subj': 'action-delete',
'data-test-subj': ({ id }) => `action-delete-${id}`,
},
{
name: 'Edit',
isPrimary: true,
available: ({ online }: { online: boolean }) => !online,
available: ({ online }) => !online,
enabled: ({ online }) => !!online,
description: 'Edit this user',
icon: 'pencil',
type: 'icon',
Expand Down
10 changes: 8 additions & 2 deletions src-docs/src/views/tables/actions/actions_section.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
import React from 'react';
import { EuiBasicTable } from '../../../../../src/components';

import { EuiBasicTable, EuiCode } from '../../../../../src/components';

import { GuideSectionTypes } from '../../../components';

import { EuiTableActionsColumnType } from '!!prop-loader!../../../../../src/components/basic_table/table_types';
import { CustomItemAction } from '!!prop-loader!../../../../../src/components/basic_table/action_types';
import { DefaultItemActionProps as DefaultItemAction } from '../props/props';

import Table from './actions';
import { EuiCode } from '../../../../../src/components/code';
const source = require('!!raw-loader!./actions');

export const section = {
Expand Down Expand Up @@ -40,5 +45,6 @@ export const section = {
</>
),
components: { EuiBasicTable },
props: { EuiTableActionsColumnType, DefaultItemAction, CustomItemAction },
demo: <Table />,
};
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`CollapsedItemActions custom actions 1`] = `
<body>
<body
class=""
>
<div>
<div
class="euiPopover euiPopover-isOpen emotion-euiPopover-inline-block"
Expand Down Expand Up @@ -176,29 +178,38 @@ exports[`CollapsedItemActions default actions 1`] = `
tabindex="-1"
>
<div>
<button
class="euiContextMenuItem euiBasicTable__collapsedAction emotion-euiContextMenuItem-m-center"
data-test-subj="defaultAction"
type="button"
<span
class="euiToolTipAnchor eui-displayBlock emotion-euiToolTipAnchor-inlineBlock"
>
<span
class="euiContextMenuItem__text emotion-euiContextMenuItem__text"
<button
class="euiContextMenuItem euiBasicTable__collapsedAction emotion-euiContextMenuItem-m-center"
data-test-subj="defaultAction"
type="button"
>
default1
</span>
</button>
<a
class="euiContextMenuItem euiBasicTable__collapsedAction emotion-euiContextMenuItem-m-center"
href="https://www.elastic.co/"
rel="noopener noreferrer"
target="_blank"
<span
class="euiContextMenuItem__text emotion-euiContextMenuItem__text"
>
default1
</span>
</button>
</span>
<span
class="euiToolTipAnchor eui-displayBlock emotion-euiToolTipAnchor-inlineBlock"
>
<span
class="euiContextMenuItem__text emotion-euiContextMenuItem__text"
<a
class="euiContextMenuItem euiBasicTable__collapsedAction emotion-euiContextMenuItem-m-center"
data-test-subj="xyz-link"
href="#/xyz"
rel="noopener noreferrer"
target="_blank"
>
default2
</span>
</a>
<span
class="euiContextMenuItem__text emotion-euiContextMenuItem__text"
>
name xyz
</span>
</a>
</span>
</div>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,86 +1,51 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`DefaultItemAction render - button 1`] = `
<EuiToolTip
content="action 1"
delay="long"
display="inlineBlock"
position="top"
exports[`DefaultItemAction renders an EuiButtonEmpty when \`type="button" 1`] = `
<span
class="euiToolTipAnchor emotion-euiToolTipAnchor-inlineBlock"
>
<EuiButtonEmpty
color="primary"
flush="right"
isDisabled={false}
onClick={[Function]}
size="s"
<button
class="euiButtonEmpty emotion-euiButtonDisplay-euiButtonEmpty-s-empty-primary-flush-right"
type="button"
>
action1
</EuiButtonEmpty>
</EuiToolTip>
`;

exports[`DefaultItemAction render - default button 1`] = `
<EuiToolTip
content="action 1"
delay="long"
display="inlineBlock"
position="top"
>
<EuiButtonEmpty
color="primary"
flush="right"
isDisabled={false}
onClick={[Function]}
size="s"
>
action1
</EuiButtonEmpty>
</EuiToolTip>
`;

exports[`DefaultItemAction render - icon 1`] = `
<EuiToolTip
content="action 1"
delay="long"
display="inlineBlock"
position="top"
>
<EuiButtonIcon
aria-labelledby="generated-id"
color="primary"
iconType="trash"
isDisabled={false}
onClick={[Function]}
/>
<EuiScreenReaderOnly>
<span
id="generated-id"
class="euiButtonEmpty__content emotion-euiButtonDisplayContent"
>
<span>
<span
class="eui-textTruncate euiButtonEmpty__text"
>
action1
</span>
</span>
</EuiScreenReaderOnly>
</EuiToolTip>
</button>
</span>
`;

exports[`DefaultItemAction render - name 1`] = `
<EuiToolTip
content="action 1"
delay="long"
display="inlineBlock"
position="top"
>
<EuiButtonEmpty
color="primary"
flush="right"
isDisabled={false}
onClick={[Function]}
size="s"
exports[`DefaultItemAction renders an EuiButtonIcon with screen reader text when \`type="icon"\` 1`] = `
<div>
<span
class="euiToolTipAnchor emotion-euiToolTipAnchor-inlineBlock"
>
<button
aria-labelledby="generated-id"
class="euiButtonIcon emotion-euiButtonIcon-xs-empty-primary"
type="button"
>
<span
aria-hidden="true"
class="euiButtonIcon__icon"
color="inherit"
data-euiicon-type="trash"
/>
</button>
</span>
<span
class="emotion-euiScreenReaderOnly"
id="generated-id"
>
<span>
xyz
action1
</span>
</EuiButtonEmpty>
</EuiToolTip>
</span>
</div>
`;
21 changes: 13 additions & 8 deletions src/components/basic_table/action_types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,18 @@ type EuiButtonIconColorFunction<T> = (item: T) => ButtonColor;

export interface DefaultItemActionBase<T> {
/**
* The display name of the action (will be the button caption)
* The display name of the action (will render as visible text if rendered within a collapsed menu)
*/
name: ReactNode | ((item: T) => ReactNode);
/**
* Describes the action (will be the button title)
* Describes the action (will render as tooltip content)
*/
description: string;
description: string | ((item: T) => string);
/**
* A handler function to execute the action
*/
onClick?: (item: T) => void;
href?: string;
href?: string | ((item: T) => string);
target?: string;
/**
* A callback function that determines whether the action is available
Expand All @@ -40,7 +40,7 @@ export interface DefaultItemActionBase<T> {
*/
enabled?: (item: T) => boolean;
isPrimary?: boolean;
'data-test-subj'?: string;
'data-test-subj'?: string | ((item: T) => string);
}

export interface DefaultItemEmptyButtonAction<T>
Expand Down Expand Up @@ -88,8 +88,13 @@ export interface CustomItemAction<T> {

export type Action<T> = DefaultItemAction<T> | CustomItemAction<T>;

export const isCustomItemAction = (
action: DefaultItemAction<any> | CustomItemAction<any>
): action is CustomItemAction<any> => {
export const isCustomItemAction = <T>(
action: DefaultItemAction<T> | CustomItemAction<T>
): action is CustomItemAction<T> => {
return action.hasOwnProperty('render');
};

export const callWithItemIfFunction =
<T>(item: T) =>
<U>(prop: U | ((item: T) => U)): U =>
typeof prop === 'function' ? (prop as Function)(item) : prop;
Loading

0 comments on commit ada8592

Please sign in to comment.