[Ingest Node Pipelines] Implement EuiInlineEdit into Inline Text Input Component (#162398)

Included in https://github.com/elastic/eui/issues/6778

## Summary
Hi team! EUI recently released the `EuiInlineEdit` component and the
Ingest Node Pipelines page was identified as a good candidate for the
new component. This PR is replaces the inner workings of the
`InlineTextInput` component and replaces it with the new `EuiInlineEdit`
component.

I've included screens below of this change, but would love to hear your
feedback and ensure this component installation meets all of the Ingest
Node Pipeline needs.

**Ingest Node Pipelines (Read Mode)**

![4ADF42EF-B796-4ACD-918A-164132117166](3d43e45f-9149-4ce8-9f4c-3c7c4bafcc88)


**Ingest Node Pipelines (Edit Mode)**

![739AA987-77E3-4D19-B04A-EF97982C41A7](9abddf40-8e76-4c34-b5e8-31578e655f3f)

---

Changes I'd like to call out:
- There's no tooltip surrounding inline edit that displays the
placeholder or text value. `EuiInlineEdit` includes a `title` for the
read mode button, so the value can be seen on hover. (This feature will
make it into the next Kibana upgrade and will not require any additional
changes).
- The `placeholder` styling is slightly different than the previous
version

Design Question:
Should the inline edit to be constrained to the left side of the
pipeline? I didn't want to change this aspect without prior input.



### Checklist

Delete any items that are not applicable to this PR.

- ~[ ] 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)~
- ~[ ]
[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html)
was added for features that require explanation or tutorials~
- [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] Any UI touched in this PR is usable by keyboard only (learn more
about [keyboard accessibility](https://webaim.org/techniques/keyboard/))
- [x] Any UI touched in this PR does not create any new axe failures
(run axe in browser:
[FF](https://addons.mozilla.org/en-US/firefox/addon/axe-devtools/),
[Chrome](https://chrome.google.com/webstore/detail/axe-web-accessibility-tes/lhdoppojpmngadmnindnejefpokejbdd?hl=en-US))
- ~[ ] If a plugin configuration key changed, check if it needs to be
allowlisted in the cloud and added to the [docker
list](https://github.com/elastic/kibana/blob/main/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker)~
- [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: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Bree Hall 2023-07-25 15:34:13 -04:00 committed by GitHub
parent ca9b4d0f35
commit 618c7fa32b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 10 additions and 112 deletions

View file

@ -1,106 +0,0 @@
/*
* 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 classNames from 'classnames';
import React, { useState, useEffect, useCallback, memo } from 'react';
import { EuiFieldText, EuiText, keys, EuiToolTip } from '@elastic/eui';
export interface Props {
placeholder: string;
ariaLabel: string;
onChange: (value: string) => void;
/**
* Whether the containing element of the text input can be focused.
*
* If it cannot be focused, this component cannot switch to showing
* the text input field.
*
* Defaults to false.
*/
disabled?: boolean;
text?: string;
}
function _InlineTextInput({
placeholder,
text,
ariaLabel,
disabled = false,
onChange,
}: Props): React.ReactElement<any, any> | null {
const [isShowingTextInput, setIsShowingTextInput] = useState<boolean>(false);
const [textValue, setTextValue] = useState<string>(() => text ?? '');
const containerClasses = classNames('pipelineProcessorsEditor__item__textContainer', {
'pipelineProcessorsEditor__item__textContainer--notEditing': !isShowingTextInput && !disabled,
});
const submitChange = useCallback(() => {
// Give any on blur handlers the chance to complete if the user is
// tabbing over this component.
setTimeout(() => {
setIsShowingTextInput(false);
onChange(textValue);
});
}, [setIsShowingTextInput, onChange, textValue]);
useEffect(() => {
setTextValue(text ?? '');
}, [text]);
useEffect(() => {
const keyboardListener = (event: KeyboardEvent) => {
if (event.key === keys.ESCAPE || event.code === 'Escape') {
setIsShowingTextInput(false);
}
if (event.key === keys.ENTER || event.code === 'Enter') {
submitChange();
}
};
if (isShowingTextInput) {
window.addEventListener('keyup', keyboardListener);
}
return () => {
window.removeEventListener('keyup', keyboardListener);
};
}, [isShowingTextInput, submitChange, setIsShowingTextInput]);
return isShowingTextInput && !disabled ? (
<div className={`pipelineProcessorsEditor__item__textContainer ${containerClasses}`}>
<EuiFieldText
controlOnly
onBlur={submitChange}
fullWidth
compressed
value={textValue}
aria-label={ariaLabel}
className="pipelineProcessorsEditor__item__textInput"
inputRef={(el) => el?.focus()}
onChange={(event) => setTextValue(event.target.value)}
/>
</div>
) : (
<div
className={containerClasses}
tabIndex={disabled ? -1 : 0}
onFocus={() => setIsShowingTextInput(true)}
>
<EuiToolTip content={text ?? placeholder}>
<EuiText size="s" color="subdued">
<div
className="pipelineProcessorsEditor__item__description"
data-test-subj="inlineTextInputNonEditableText"
>
{text || <em>{placeholder}</em>}
</div>
</EuiText>
</EuiToolTip>
</div>
);
}
export const InlineTextInput = memo(_InlineTextInput);

View file

@ -11,6 +11,7 @@ import {
EuiButtonIcon,
EuiFlexGroup,
EuiFlexItem,
EuiInlineEditText,
EuiLink,
EuiLoadingSpinner,
EuiPanel,
@ -30,7 +31,6 @@ import { getProcessorDescriptor } from '../shared';
import './pipeline_processors_editor_item.scss';
import { InlineTextInput } from './inline_text_input';
import { ContextMenu } from './context_menu';
import { i18nTexts } from './i18n_texts';
import { Handlers } from './types';
@ -213,12 +213,16 @@ export const PipelineProcessorsEditorItem: FunctionComponent<Props> = memo(
className={inlineTextInputContainerClasses}
grow={false}
>
<InlineTextInput
disabled={isEditorNotInIdleMode}
onChange={onDescriptionChange}
ariaLabel={i18nTexts.processorTypeLabel({ type: processor.type })}
text={description}
<EuiInlineEditText
size="s"
defaultValue={description || ''}
readModeProps={{ 'data-test-subj': 'inlineTextInputNonEditableText' }}
placeholder={defaultDescription ?? i18nTexts.descriptionPlaceholder}
inputAriaLabel={i18nTexts.processorTypeLabel({ type: processor.type })}
isReadOnly={isEditorNotInIdleMode}
onSave={(newTextValue) => {
onDescriptionChange(newTextValue);
}}
/>
</EuiFlexItem>
</EuiFlexGroup>