Skip to content

Commit 6f7bc21

Browse files
authored
[ResponseOps][Cases] Design Review changes #1 (elastic#192356)
Connected to elastic#188187 ## Summary - Changed the cases `Settings` button and icon - Changed the the `Additional fields` title to `Custom fields` for consistency <img width="1728" alt="Screenshot 2024-09-09 at 20 15 39" src="https://github.com/user-attachments/assets/1fb1232a-f958-4d4d-8694-f85cc8872237"> <img width="1443" alt="Screenshot 2024-09-09 at 20 34 27" src="https://github.com/user-attachments/assets/0fbdae02-65a6-4128-adc7-39f51cc2d5e6"> <img width="1370" alt="Screenshot 2024-09-09 at 20 34 57" src="https://github.com/user-attachments/assets/c216407a-ac13-4579-8007-531c79d52de7">
1 parent e01dc14 commit 6f7bc21

File tree

7 files changed

+65
-94
lines changed

7 files changed

+65
-94
lines changed

x-pack/plugins/cases/public/components/case_form_fields/custom_fields.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ const CustomFieldsComponent: React.FC<Props> = ({
5858
<EuiFormRow fullWidth>
5959
<EuiFlexGroup direction="column" gutterSize="s">
6060
<EuiText size="m">
61-
<h3>{i18n.ADDITIONAL_FIELDS}</h3>
61+
<h3>{i18n.CUSTOM_FIELDS}</h3>
6262
</EuiText>
6363
<EuiSpacer size="xs" />
6464
<EuiFlexItem data-test-subj="caseCustomFields">{customFieldsComponents}</EuiFlexItem>

x-pack/plugins/cases/public/components/case_form_fields/translations.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,6 @@ import { i18n } from '@kbn/i18n';
99

1010
export * from '../../common/translations';
1111

12-
export const ADDITIONAL_FIELDS = i18n.translate('xpack.cases.additionalFields', {
13-
defaultMessage: 'Additional fields',
12+
export const CUSTOM_FIELDS = i18n.translate('xpack.cases.customFields', {
13+
defaultMessage: 'Custom fields',
1414
});

x-pack/plugins/cases/public/components/links/index.test.tsx

Lines changed: 47 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,8 @@
66
*/
77

88
import React from 'react';
9-
import type { ComponentType, ReactWrapper } from 'enzyme';
10-
import { mount } from 'enzyme';
119
import { render, screen } from '@testing-library/react';
1210
import userEvent from '@testing-library/user-event';
13-
import { EuiText } from '@elastic/eui';
1411

1512
import type { ConfigureCaseButtonProps, CaseDetailsLinkProps } from '.';
1613
import { ConfigureCaseButton, CaseDetailsLink } from '.';
@@ -20,89 +17,53 @@ import { useCaseViewNavigation } from '../../common/navigation/hooks';
2017
jest.mock('../../common/navigation/hooks');
2118

2219
describe('Configuration button', () => {
23-
let wrapper: ReactWrapper;
2420
const props: ConfigureCaseButtonProps = {
2521
label: 'My label',
2622
msgTooltip: <></>,
2723
showToolTip: false,
2824
titleTooltip: '',
2925
};
3026

31-
beforeAll(() => {
32-
wrapper = mount(<ConfigureCaseButton {...props} />, {
33-
wrappingComponent: TestProviders as ComponentType<React.PropsWithChildren<{}>>,
34-
});
35-
});
36-
37-
test('it renders without the tooltip', () => {
38-
expect(wrapper.find('[data-test-subj="configure-case-button"]').first().exists()).toBe(true);
27+
it('renders without the tooltip', async () => {
28+
render(
29+
<TestProviders>
30+
<ConfigureCaseButton {...props} />
31+
</TestProviders>
32+
);
3933

40-
expect(wrapper.find('[data-test-subj="configure-case-tooltip"]').first().exists()).toBe(false);
41-
});
34+
const configureButton = await screen.findByTestId('configure-case-button');
4235

43-
test('it pass the correct props to the button', () => {
44-
expect(wrapper.find('[data-test-subj="configure-case-button"]').first().props()).toMatchObject({
45-
href: `/app/security/cases/configure`,
46-
iconType: 'controlsHorizontal',
47-
isDisabled: false,
48-
'aria-label': 'My label',
49-
children: 'My label',
50-
});
36+
expect(configureButton).toBeEnabled();
37+
expect(configureButton).toHaveAttribute('href', '/app/security/cases/configure');
38+
expect(configureButton).toHaveAttribute('aria-label', 'My label');
5139
});
5240

53-
test('it renders the tooltip', () => {
54-
const msgTooltip = <EuiText>{'My message tooltip'}</EuiText>;
55-
56-
const newWrapper = mount(
57-
<ConfigureCaseButton
58-
{...props}
59-
showToolTip={true}
60-
titleTooltip={'My tooltip title'}
61-
msgTooltip={msgTooltip}
62-
/>,
63-
{
64-
wrappingComponent: TestProviders as ComponentType<React.PropsWithChildren<{}>>,
65-
}
66-
);
67-
68-
expect(newWrapper.find('[data-test-subj="configure-case-tooltip"]').first().exists()).toBe(
69-
true
70-
);
41+
it('renders the tooltip correctly when hovering the button', async () => {
42+
jest.useFakeTimers();
7143

72-
expect(wrapper.find('[data-test-subj="configure-case-button"]').first().exists()).toBe(true);
73-
});
44+
const user = userEvent.setup({
45+
advanceTimers: jest.advanceTimersByTime,
46+
pointerEventsCheck: 0,
47+
});
7448

75-
test('it shows the tooltip when hovering the button', () => {
76-
// Use fake timers so we don't have to wait for the EuiToolTip timeout
77-
jest.useFakeTimers({ legacyFakeTimers: true });
78-
79-
const msgTooltip = 'My message tooltip';
80-
const titleTooltip = 'My title';
81-
82-
const newWrapper = mount(
83-
<ConfigureCaseButton
84-
{...props}
85-
showToolTip={true}
86-
titleTooltip={titleTooltip}
87-
msgTooltip={<>{msgTooltip}</>}
88-
/>,
89-
{
90-
wrappingComponent: TestProviders as ComponentType<React.PropsWithChildren<{}>>,
91-
}
49+
render(
50+
<TestProviders>
51+
<ConfigureCaseButton
52+
{...props}
53+
showToolTip={true}
54+
titleTooltip={'My title'}
55+
msgTooltip={<>{'My message tooltip'}</>}
56+
/>
57+
</TestProviders>
9258
);
9359

94-
newWrapper.find('a[data-test-subj="configure-case-button"]').first().simulate('mouseOver');
60+
await user.hover(await screen.findByTestId('configure-case-button'));
9561

96-
// Run the timers so the EuiTooltip will be visible
97-
jest.runAllTimers();
62+
expect(await screen.findByTestId('configure-case-tooltip')).toBeInTheDocument();
63+
expect(await screen.findByText('My title')).toBeInTheDocument();
64+
expect(await screen.findByText('My message tooltip')).toBeInTheDocument();
9865

99-
newWrapper.update();
100-
expect(newWrapper.find('.euiToolTipPopover').last().text()).toBe(
101-
`${titleTooltip}${msgTooltip}`
102-
);
103-
104-
// Clearing all mocks will also reset fake timers.
105-
jest.clearAllMocks();
66+
jest.useRealTimers();
10667
});
10768
});
10869

@@ -120,31 +81,33 @@ describe('CaseDetailsLink', () => {
12081
useCaseViewNavigationMock.mockReturnValue({ getCaseViewUrl, navigateToCaseView });
12182
});
12283

123-
test('it renders', () => {
84+
it('renders', async () => {
12485
render(<CaseDetailsLink {...props} />);
125-
expect(screen.getByText('test detail name')).toBeInTheDocument();
86+
expect(await screen.findByText('test detail name')).toBeInTheDocument();
12687
});
12788

128-
test('it renders the children instead of the detail name if provided', () => {
89+
it('renders the children instead of the detail name if provided', async () => {
12990
render(<CaseDetailsLink {...props}>{'children'}</CaseDetailsLink>);
13091
expect(screen.queryByText('test detail name')).toBeFalsy();
131-
expect(screen.getByText('children')).toBeInTheDocument();
92+
expect(await screen.findByText('children')).toBeInTheDocument();
13293
});
13394

134-
test('it uses the detailName in the aria-label if the title is not provided', () => {
95+
it('uses the detailName in the aria-label if the title is not provided', async () => {
13596
render(<CaseDetailsLink {...props} />);
13697
expect(
137-
screen.getByLabelText(`click to visit case with title ${props.detailName}`)
98+
await screen.findByLabelText(`click to visit case with title ${props.detailName}`)
13899
).toBeInTheDocument();
139100
});
140101

141-
test('it uses the title in the aria-label if provided', () => {
102+
it('uses the title in the aria-label if provided', async () => {
142103
render(<CaseDetailsLink {...props} title={'my title'} />);
143-
expect(screen.getByText('test detail name')).toBeInTheDocument();
144-
expect(screen.getByLabelText(`click to visit case with title my title`)).toBeInTheDocument();
104+
expect(await screen.findByText('test detail name')).toBeInTheDocument();
105+
expect(
106+
await screen.findByLabelText(`click to visit case with title my title`)
107+
).toBeInTheDocument();
145108
});
146109

147-
test('it calls navigateToCaseViewClick on click', async () => {
110+
it('calls navigateToCaseViewClick on click', async () => {
148111
// Workaround for timeout via https://github.com/testing-library/user-event/issues/833#issuecomment-1171452841
149112
jest.useFakeTimers();
150113
const user = userEvent.setup({
@@ -153,19 +116,21 @@ describe('CaseDetailsLink', () => {
153116
});
154117

155118
render(<CaseDetailsLink {...props} />);
156-
await user.click(screen.getByText('test detail name'));
119+
120+
await user.click(await screen.findByText('test detail name'));
121+
157122
expect(navigateToCaseView).toHaveBeenCalledWith({
158123
detailName: props.detailName,
159124
});
160125

161126
jest.useRealTimers();
162127
});
163128

164-
test('it set the href correctly', () => {
129+
it('sets the href correctly', async () => {
165130
render(<CaseDetailsLink {...props} />);
166131
expect(getCaseViewUrl).toHaveBeenCalledWith({
167132
detailName: props.detailName,
168133
});
169-
expect(screen.getByRole('link')).toHaveAttribute('href', '/cases/test');
134+
expect(await screen.findByRole('link')).toHaveAttribute('href', '/cases/test');
170135
});
171136
});

x-pack/plugins/cases/public/components/links/index.tsx

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
*/
77

88
import type { EuiButtonProps, EuiLinkProps, PropsForAnchor, PropsForButton } from '@elastic/eui';
9-
import { EuiButton, EuiLink, EuiToolTip } from '@elastic/eui';
9+
import { EuiButton, EuiLink, EuiToolTip, EuiButtonEmpty } from '@elastic/eui';
1010
import React, { useCallback, useMemo } from 'react';
1111
import { useCaseViewNavigation, useConfigureCasesNavigation } from '../../common/navigation';
1212
import * as i18n from './translations';
@@ -18,10 +18,17 @@ export interface CasesNavigation<T = React.MouseEvent | MouseEvent | null, K = n
1818
: (arg: T) => Promise<void> | void;
1919
}
2020

21-
export const LinkButton: React.FC<PropsForButton<EuiButtonProps> | PropsForAnchor<EuiButtonProps>> =
22-
// TODO: Fix this manually. Issue #123375
23-
// eslint-disable-next-line react/display-name
24-
({ children, ...props }) => <EuiButton {...props}>{children}</EuiButton>;
21+
type LinkButtonProps = React.FC<
22+
(PropsForButton<EuiButtonProps> | PropsForAnchor<EuiButtonProps>) & { isEmpty?: boolean }
23+
>;
24+
25+
export const LinkButton: LinkButtonProps = ({ children, isEmpty, ...props }) =>
26+
isEmpty ? (
27+
<EuiButtonEmpty {...props}>{children}</EuiButtonEmpty>
28+
) : (
29+
<EuiButton {...props}>{children}</EuiButton>
30+
);
31+
LinkButton.displayName = 'LinkButton';
2532

2633
// TODO: Fix this manually. Issue #123375
2734
// eslint-disable-next-line react/display-name
@@ -62,6 +69,7 @@ const CaseDetailsLinkComponent: React.FC<CaseDetailsLinkProps> = ({
6269
</LinkAnchor>
6370
);
6471
};
72+
6573
export const CaseDetailsLink = React.memo(CaseDetailsLinkComponent);
6674
CaseDetailsLink.displayName = 'CaseDetailsLink';
6775

@@ -95,9 +103,10 @@ const ConfigureCaseButtonComponent: React.FC<ConfigureCaseButtonProps> = ({
95103
<LinkButton
96104
onClick={navigateToConfigureCasesClick}
97105
href={getConfigureCasesUrl()}
98-
iconType="controlsHorizontal"
106+
iconType="gear"
99107
isDisabled={false}
100108
aria-label={label}
109+
isEmpty={true}
101110
data-test-subj="configure-case-button"
102111
>
103112
{label}

x-pack/plugins/translations/translations/fr-FR.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13103,7 +13103,6 @@
1310313103
"xpack.cases.actions.viewCase": "Afficher le cas",
1310413104
"xpack.cases.actions.visualizationActions.addToExistingCase.displayName": "Ajouter au cas",
1310513105
"xpack.cases.addConnector.title": "Ajouter un connecteur",
13106-
"xpack.cases.additionalFields": "Champs supplémentaires",
1310713106
"xpack.cases.allCases.actions": "Actions",
1310813107
"xpack.cases.allCases.comments": "Commentaires",
1310913108
"xpack.cases.allCases.noCategoriesAvailable": "Pas de catégories disponibles",

x-pack/plugins/translations/translations/ja-JP.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13094,7 +13094,6 @@
1309413094
"xpack.cases.actions.viewCase": "ケースの表示",
1309513095
"xpack.cases.actions.visualizationActions.addToExistingCase.displayName": "ケースに追加",
1309613096
"xpack.cases.addConnector.title": "コネクターの追加",
13097-
"xpack.cases.additionalFields": "追加フィールド",
1309813097
"xpack.cases.allCases.actions": "アクション",
1309913098
"xpack.cases.allCases.comments": "コメント",
1310013099
"xpack.cases.allCases.noCategoriesAvailable": "カテゴリがありません",

x-pack/plugins/translations/translations/zh-CN.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13116,7 +13116,6 @@
1311613116
"xpack.cases.actions.viewCase": "查看案例",
1311713117
"xpack.cases.actions.visualizationActions.addToExistingCase.displayName": "添加到案例",
1311813118
"xpack.cases.addConnector.title": "添加连接器",
13119-
"xpack.cases.additionalFields": "其他字段",
1312013119
"xpack.cases.allCases.actions": "操作",
1312113120
"xpack.cases.allCases.comments": "注释",
1312213121
"xpack.cases.allCases.noCategoriesAvailable": "没有可用类别",

0 commit comments

Comments
 (0)