mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
[APM] Improve service groups error messages and validatons (#162556)
## Summary closes https://github.com/elastic/kibana/issues/150288 closes https://github.com/elastic/kibana/issues/160713 ### Before <img width="1344" alt="image" src="6a1b2f0a
-9f62-48f1-a14d-fbd9bc0b41d6"> ### Afterf2f90dba
-a6c2-46e4-87c6-7f4a7cb59839 #### Invalid query syntax  #### Not supported field <img width="1652" alt="image" src="e6401a74
-24f7-4544-86a5-8ac0fce11f01"> #### Invalid HEX <img width="1652" alt="image" src="d92a999f
-9a34-460d-9a06-aedc445cf684"> ## Notes 1. The validations run when the user refreshes/submits a new search. Previously it was running every time the query was changing. 2. change the width from 600 to 700 2. The layout issues were attributed to the error message, so I changed the error message as a callout, similar to the style used by Discover. This change allows the user to easily spot the error and address it more effectively.
This commit is contained in:
parent
68fec4bc64
commit
73d53dc6d6
2 changed files with 62 additions and 37 deletions
|
@ -18,6 +18,7 @@ import {
|
|||
EuiFormRow,
|
||||
useColorPickerState,
|
||||
EuiText,
|
||||
isValidHex,
|
||||
} from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
|
@ -44,6 +45,7 @@ export function GroupDetails({
|
|||
const [color, setColor, colorPickerErrors] = useColorPickerState(
|
||||
serviceGroup?.color || '#5094C4'
|
||||
);
|
||||
|
||||
const [description, setDescription] = useState<string | undefined>(
|
||||
serviceGroup?.description
|
||||
);
|
||||
|
@ -53,7 +55,7 @@ export function GroupDetails({
|
|||
if (serviceGroup.color) {
|
||||
setColor(serviceGroup.color, {
|
||||
hex: serviceGroup.color,
|
||||
isValid: true,
|
||||
isValid: isValidHex(color),
|
||||
});
|
||||
}
|
||||
setDescription(serviceGroup.description);
|
||||
|
@ -61,7 +63,7 @@ export function GroupDetails({
|
|||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [serviceGroup]); // setColor omitted: new reference each render
|
||||
|
||||
const isInvalidColor = !!colorPickerErrors?.length;
|
||||
const isInvalidColor = !!colorPickerErrors?.length || !isValidHex(color);
|
||||
const isInvalidName = !name;
|
||||
const isInvalid = isInvalidName || isInvalidColor;
|
||||
|
||||
|
@ -121,13 +123,17 @@ export function GroupDetails({
|
|||
'xpack.apm.serviceGroups.groupDetailsForm.invalidColorError',
|
||||
{
|
||||
defaultMessage:
|
||||
'Please provide a valid color value',
|
||||
'Please provide a valid HEX color value',
|
||||
}
|
||||
)
|
||||
: undefined
|
||||
}
|
||||
>
|
||||
<EuiColorPicker onChange={setColor} color={color} />
|
||||
<EuiColorPicker
|
||||
onChange={setColor}
|
||||
color={color}
|
||||
isInvalid={isInvalidColor}
|
||||
/>
|
||||
</EuiFormRow>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
|
|
|
@ -7,7 +7,9 @@
|
|||
import {
|
||||
EuiButton,
|
||||
EuiButtonEmpty,
|
||||
EuiCallOut,
|
||||
EuiFlexGroup,
|
||||
useEuiTheme,
|
||||
EuiFlexItem,
|
||||
EuiLoadingSpinner,
|
||||
EuiModalBody,
|
||||
|
@ -19,6 +21,7 @@ import {
|
|||
EuiText,
|
||||
} from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { css } from '@emotion/react';
|
||||
import React, { useEffect, useState, useMemo } from 'react';
|
||||
import styled from 'styled-components';
|
||||
import { isEmpty } from 'lodash';
|
||||
|
@ -44,7 +47,6 @@ const MODAL_HEADER_HEIGHT = 180;
|
|||
const MODAL_FOOTER_HEIGHT = 80;
|
||||
|
||||
const Container = styled.div`
|
||||
width: 600px;
|
||||
height: ${MAX_CONTAINER_HEIGHT}px;
|
||||
`;
|
||||
|
||||
|
@ -71,6 +73,8 @@ export function SelectServices({
|
|||
string | undefined
|
||||
>();
|
||||
|
||||
const { euiTheme } = useEuiTheme();
|
||||
|
||||
useEffect(() => {
|
||||
if (isEdit) {
|
||||
setKuery(serviceGroup.kuery);
|
||||
|
@ -78,14 +82,6 @@ export function SelectServices({
|
|||
}
|
||||
}, [isEdit, serviceGroup.kuery]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!stagedKuery) {
|
||||
return;
|
||||
}
|
||||
const { message } = validateServiceGroupKuery(stagedKuery);
|
||||
setKueryValidationMessage(message);
|
||||
}, [stagedKuery]);
|
||||
|
||||
const { start, end } = useMemo(
|
||||
() =>
|
||||
getDateRange({
|
||||
|
@ -110,6 +106,18 @@ export function SelectServices({
|
|||
|
||||
const isServiceListPreviewLoading = status === FETCH_STATUS.LOADING;
|
||||
|
||||
const handleOnSubmit = () => {
|
||||
if (!stagedKuery) {
|
||||
return;
|
||||
}
|
||||
const { message } = validateServiceGroupKuery(stagedKuery);
|
||||
setKueryValidationMessage(message);
|
||||
|
||||
if (!message) {
|
||||
setKuery(stagedKuery);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Container>
|
||||
<EuiModalHeader>
|
||||
|
@ -132,11 +140,6 @@ export function SelectServices({
|
|||
}
|
||||
)}
|
||||
</EuiText>
|
||||
{kueryValidationMessage && (
|
||||
<EuiText color="danger" size="s">
|
||||
{kueryValidationMessage}
|
||||
</EuiText>
|
||||
)}
|
||||
<EuiSpacer size="s" />
|
||||
<EuiFlexGroup gutterSize="s">
|
||||
<EuiFlexItem>
|
||||
|
@ -145,9 +148,7 @@ export function SelectServices({
|
|||
'xpack.apm.serviceGroups.selectServicesForm.kql',
|
||||
{ defaultMessage: 'E.g. labels.team: "web"' }
|
||||
)}
|
||||
onSubmit={(value) => {
|
||||
setKuery(value);
|
||||
}}
|
||||
onSubmit={handleOnSubmit}
|
||||
onChange={(value) => {
|
||||
setStagedKuery(value);
|
||||
}}
|
||||
|
@ -169,9 +170,7 @@ export function SelectServices({
|
|||
<EuiFlexItem grow={false}>
|
||||
<EuiButton
|
||||
data-test-subj="apmSelectServicesButton"
|
||||
onClick={() => {
|
||||
setKuery(stagedKuery);
|
||||
}}
|
||||
onClick={handleOnSubmit}
|
||||
iconType={!kuery ? 'search' : 'refresh'}
|
||||
isDisabled={isServiceListPreviewLoading || !stagedKuery}
|
||||
>
|
||||
|
@ -215,7 +214,36 @@ export function SelectServices({
|
|||
>
|
||||
<EuiFlexItem>
|
||||
<EuiPanel hasShadow={false} hasBorder paddingSize="s">
|
||||
{!kuery && (
|
||||
{!data && isServiceListPreviewLoading && <EuiLoadingSpinner />}
|
||||
{kueryValidationMessage?.length ? (
|
||||
<CentralizedContainer>
|
||||
<EuiCallOut
|
||||
title={i18n.translate(
|
||||
'xpack.apm.serviceGroups.searchResults.error',
|
||||
{
|
||||
defaultMessage: 'Error retrieving search results',
|
||||
}
|
||||
)}
|
||||
color="danger"
|
||||
iconType="error"
|
||||
>
|
||||
<p
|
||||
css={css`
|
||||
white-space: break-spaces;
|
||||
font-family: ${euiTheme.font.familyCode};
|
||||
`}
|
||||
data-test-subj="discoverErrorCalloutMessage"
|
||||
>
|
||||
{kueryValidationMessage}
|
||||
</p>
|
||||
</EuiCallOut>
|
||||
</CentralizedContainer>
|
||||
) : kuery && data ? (
|
||||
<ServiceListPreview
|
||||
items={data.items}
|
||||
isLoading={isServiceListPreviewLoading}
|
||||
/>
|
||||
) : (
|
||||
<CentralizedContainer>
|
||||
<EuiText size="s" color="subdued">
|
||||
{i18n.translate(
|
||||
|
@ -225,17 +253,6 @@ export function SelectServices({
|
|||
</EuiText>
|
||||
</CentralizedContainer>
|
||||
)}
|
||||
{!data && isServiceListPreviewLoading && (
|
||||
<CentralizedContainer>
|
||||
<EuiLoadingSpinner />
|
||||
</CentralizedContainer>
|
||||
)}
|
||||
{kuery && data && (
|
||||
<ServiceListPreview
|
||||
items={data.items}
|
||||
isLoading={isServiceListPreviewLoading}
|
||||
/>
|
||||
)}
|
||||
</EuiPanel>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
|
@ -279,7 +296,9 @@ export function SelectServices({
|
|||
onClick={() => {
|
||||
onSaveClick({ ...serviceGroup, kuery });
|
||||
}}
|
||||
isDisabled={isLoading || !kuery}
|
||||
isDisabled={
|
||||
isLoading || !kuery || !isEmpty(kueryValidationMessage)
|
||||
}
|
||||
>
|
||||
{i18n.translate(
|
||||
'xpack.apm.serviceGroups.selectServicesForm.saveGroup',
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue