-
Notifications
You must be signed in to change notification settings - Fork 8.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Response Ops][Rule Form V2] Rule Form V2: Rule Details (#183352)
## Summary Issue: #179105 Related PR: #180539 Part 1: #183325 Part 2 of 3 PRs of new rule form. This PR depends on the code from part 1, so only merge this when part 1 has been merged. This PR extracts the last section of the rule form, the rule details, from the original PR. The design philosophy in the PR is to create components that are devoid of any fetching or form logic. These are simply dumb components. I have also created a example plugin to demonstrate this PR. To access: 1. Run the branch with yarn start --run-examples 2. Navigate to http://localhost:5601/app/triggersActionsUiExample/rule_details And you should be able to play around with the components in this PR: <img width="1281" alt="Screenshot 2024-05-13 at 9 44 14 PM" src="https://github.com/elastic/kibana/assets/74562234/7ca900e3-ca9a-4810-8b24-7c3ea41055d6"> ### 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 --------- Co-authored-by: Zacqary <[email protected]> Co-authored-by: kibanamachine <[email protected]>
- Loading branch information
Showing
12 changed files
with
386 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
9 changes: 9 additions & 0 deletions
9
packages/kbn-alerts-ui-shared/src/rule_form/rule_actions/index.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License | ||
* 2.0 and the Server Side Public License, v 1; you may not use this file except | ||
* in compliance with, at your election, the Elastic License 2.0 or the Server | ||
* Side Public License, v 1. | ||
*/ | ||
|
||
export * from './rule_actions'; |
33 changes: 33 additions & 0 deletions
33
packages/kbn-alerts-ui-shared/src/rule_form/rule_actions/rule_actions.test.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License | ||
* 2.0 and the Server Side Public License, v 1; you may not use this file except | ||
* in compliance with, at your election, the Elastic License 2.0 or the Server | ||
* Side Public License, v 1. | ||
*/ | ||
|
||
import React from 'react'; | ||
import { render, screen, fireEvent } from '@testing-library/react'; | ||
import { RuleActions } from './rule_actions'; | ||
|
||
const mockOnChange = jest.fn(); | ||
|
||
describe('Rule actions', () => { | ||
afterEach(() => { | ||
jest.resetAllMocks(); | ||
}); | ||
|
||
test('Renders correctly', () => { | ||
render(<RuleActions onClick={mockOnChange} />); | ||
|
||
expect(screen.getByTestId('ruleActions')).toBeInTheDocument(); | ||
}); | ||
|
||
test('Calls onChange when button is click', () => { | ||
render(<RuleActions onClick={mockOnChange} />); | ||
|
||
fireEvent.click(screen.getByTestId('ruleActionsAddActionButton')); | ||
|
||
expect(mockOnChange).toHaveBeenCalled(); | ||
}); | ||
}); |
31 changes: 31 additions & 0 deletions
31
packages/kbn-alerts-ui-shared/src/rule_form/rule_actions/rule_actions.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License | ||
* 2.0 and the Server Side Public License, v 1; you may not use this file except | ||
* in compliance with, at your election, the Elastic License 2.0 or the Server | ||
* Side Public License, v 1. | ||
*/ | ||
|
||
import React from 'react'; | ||
import { EuiButton } from '@elastic/eui'; | ||
import { ADD_ACTION_TEXT } from '../translations'; | ||
|
||
export interface RuleActionsProps { | ||
onClick: () => void; | ||
} | ||
|
||
export const RuleActions = (props: RuleActionsProps) => { | ||
const { onClick } = props; | ||
return ( | ||
<div data-test-subj="ruleActions"> | ||
<EuiButton | ||
iconType="push" | ||
iconSide="left" | ||
onClick={onClick} | ||
data-test-subj="ruleActionsAddActionButton" | ||
> | ||
{ADD_ACTION_TEXT} | ||
</EuiButton> | ||
</div> | ||
); | ||
}; |
9 changes: 9 additions & 0 deletions
9
packages/kbn-alerts-ui-shared/src/rule_form/rule_details/index.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License | ||
* 2.0 and the Server Side Public License, v 1; you may not use this file except | ||
* in compliance with, at your election, the Elastic License 2.0 or the Server | ||
* Side Public License, v 1. | ||
*/ | ||
|
||
export * from './rule_details'; |
79 changes: 79 additions & 0 deletions
79
packages/kbn-alerts-ui-shared/src/rule_form/rule_details/rule_details.test.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License | ||
* 2.0 and the Server Side Public License, v 1; you may not use this file except | ||
* in compliance with, at your election, the Elastic License 2.0 or the Server | ||
* Side Public License, v 1. | ||
*/ | ||
|
||
import React from 'react'; | ||
import { fireEvent, render, screen } from '@testing-library/react'; | ||
import userEvent from '@testing-library/user-event'; | ||
import { RuleDetails } from './rule_details'; | ||
|
||
const mockOnChange = jest.fn(); | ||
|
||
describe('RuleDetails', () => { | ||
test('Renders correctly', () => { | ||
render( | ||
<RuleDetails | ||
formValues={{ | ||
name: 'test', | ||
tags: [], | ||
}} | ||
onChange={mockOnChange} | ||
/> | ||
); | ||
|
||
expect(screen.getByTestId('ruleDetails')).toBeInTheDocument(); | ||
}); | ||
|
||
test('Should allow name to be changed', () => { | ||
render( | ||
<RuleDetails | ||
formValues={{ | ||
name: 'test', | ||
tags: [], | ||
}} | ||
onChange={mockOnChange} | ||
/> | ||
); | ||
|
||
fireEvent.change(screen.getByTestId('ruleDetailsNameInput'), { target: { value: 'hello' } }); | ||
expect(mockOnChange).toHaveBeenCalledWith('name', 'hello'); | ||
}); | ||
|
||
test('Should allow tags to be changed', () => { | ||
render( | ||
<RuleDetails | ||
formValues={{ | ||
name: 'test', | ||
tags: [], | ||
}} | ||
onChange={mockOnChange} | ||
/> | ||
); | ||
|
||
userEvent.type(screen.getByTestId('comboBoxInput'), 'tag{enter}'); | ||
expect(mockOnChange).toHaveBeenCalledWith('tags', ['tag']); | ||
}); | ||
|
||
test('Should display error', () => { | ||
render( | ||
<RuleDetails | ||
formValues={{ | ||
name: 'test', | ||
tags: [], | ||
}} | ||
errors={{ | ||
name: 'name is invalid', | ||
tags: 'tags is invalid', | ||
}} | ||
onChange={mockOnChange} | ||
/> | ||
); | ||
|
||
expect(screen.getByText('name is invalid')).toBeInTheDocument(); | ||
expect(screen.getByText('tags is invalid')).toBeInTheDocument(); | ||
}); | ||
}); |
117 changes: 117 additions & 0 deletions
117
packages/kbn-alerts-ui-shared/src/rule_form/rule_details/rule_details.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License | ||
* 2.0 and the Server Side Public License, v 1; you may not use this file except | ||
* in compliance with, at your election, the Elastic License 2.0 or the Server | ||
* Side Public License, v 1. | ||
*/ | ||
|
||
import React, { useCallback, useMemo } from 'react'; | ||
import { | ||
EuiDescribedFormGroup, | ||
EuiFormRow, | ||
EuiFieldText, | ||
EuiComboBox, | ||
EuiComboBoxOptionOption, | ||
EuiText, | ||
} from '@elastic/eui'; | ||
import type { SanitizedRule, RuleTypeParams } from '@kbn/alerting-types'; | ||
import type { RuleFormErrors } from '../types'; | ||
import { | ||
RULE_DETAILS_TITLE, | ||
RULE_DETAILS_DESCRIPTION, | ||
RULE_NAME_INPUT_TITLE, | ||
RULE_TAG_INPUT_TITLE, | ||
} from '../translations'; | ||
|
||
export interface RuleDetailsProps { | ||
formValues: { | ||
tags?: SanitizedRule<RuleTypeParams>['tags']; | ||
name: SanitizedRule<RuleTypeParams>['name']; | ||
}; | ||
errors?: RuleFormErrors; | ||
onChange: (property: string, value: unknown) => void; | ||
} | ||
|
||
export const RuleDetails = (props: RuleDetailsProps) => { | ||
const { formValues, errors = {}, onChange } = props; | ||
|
||
const { tags = [], name } = formValues; | ||
|
||
const tagsOptions = useMemo(() => { | ||
return tags.map((tag: string) => ({ label: tag })); | ||
}, [tags]); | ||
|
||
const onNameChange = useCallback( | ||
(e: React.ChangeEvent<HTMLInputElement>) => { | ||
onChange('name', e.target.value); | ||
}, | ||
[onChange] | ||
); | ||
|
||
const onAddTag = useCallback( | ||
(searchValue: string) => { | ||
onChange('tags', tags.concat([searchValue])); | ||
}, | ||
[onChange, tags] | ||
); | ||
|
||
const onSetTag = useCallback( | ||
(options: Array<EuiComboBoxOptionOption<string>>) => { | ||
onChange( | ||
'tags', | ||
options.map((selectedOption) => selectedOption.label) | ||
); | ||
}, | ||
[onChange] | ||
); | ||
|
||
const onBlur = useCallback(() => { | ||
if (!tags) { | ||
onChange('tags', []); | ||
} | ||
}, [onChange, tags]); | ||
|
||
return ( | ||
<EuiDescribedFormGroup | ||
fullWidth | ||
title={<h3>{RULE_DETAILS_TITLE}</h3>} | ||
description={ | ||
<EuiText> | ||
<p>{RULE_DETAILS_DESCRIPTION}</p> | ||
</EuiText> | ||
} | ||
data-test-subj="ruleDetails" | ||
> | ||
<EuiFormRow | ||
fullWidth | ||
label={RULE_NAME_INPUT_TITLE} | ||
isInvalid={errors.name?.length > 0} | ||
error={errors.name} | ||
> | ||
<EuiFieldText | ||
fullWidth | ||
value={name} | ||
onChange={onNameChange} | ||
data-test-subj="ruleDetailsNameInput" | ||
/> | ||
</EuiFormRow> | ||
<EuiFormRow | ||
fullWidth | ||
label={RULE_TAG_INPUT_TITLE} | ||
isInvalid={errors.tags?.length > 0} | ||
error={errors.tags} | ||
> | ||
<EuiComboBox | ||
fullWidth | ||
noSuggestions | ||
data-test-subj="ruleDetailsTagsInput" | ||
selectedOptions={tagsOptions} | ||
onCreateOption={onAddTag} | ||
onChange={onSetTag} | ||
onBlur={onBlur} | ||
/> | ||
</EuiFormRow> | ||
</EuiDescribedFormGroup> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
13 changes: 13 additions & 0 deletions
13
...examples/triggers_actions_ui_example/public/components/rule_form/rule_actions_sandbox.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License | ||
* 2.0; you may not use this file except in compliance with the Elastic License | ||
* 2.0. | ||
*/ | ||
|
||
import React from 'react'; | ||
import { RuleActions } from '@kbn/alerts-ui-shared/src/rule_form'; | ||
|
||
export const RuleActionsSandbox = () => { | ||
return <RuleActions onClick={() => {}} />; | ||
}; |
Oops, something went wrong.