From 08054ecfc310245fb62ae09726732ed79b8e3efd Mon Sep 17 00:00:00 2001 From: Kerry Gallagher Date: Thu, 14 Feb 2019 15:38:23 +0000 Subject: [PATCH] [InfraUI] Fix / add context to Metrics error (#30383) (#31114) * Add a custom and specific InvalidNode Error so that more helpful information can be displayed on the Metrics page Add a custom error for an invalid node check Add a component for displaying help when using an invalid node Throw the specific error from kibana_metrics_adapter Add an enum for specific error codes Look for and handle invalid node error in metrics/index Amend container to pass Error instance Add source configuration flyout to metrics/index to facilitate change source config button * Add explicit type for err parameter * Remove i18n injection, use FormattedMessage component * Stylistic index changes * Move Error typings to common --- x-pack/plugins/infra/common/errors/index.ts | 7 ++ x-pack/plugins/infra/common/errors/metrics.ts | 9 +++ .../components/metrics/invalid_node.tsx | 76 +++++++++++++++++++ .../containers/metrics/with_metrics.tsx | 6 +- .../infra/public/pages/metrics/index.tsx | 16 +++- .../metrics/kibana_metrics_adapter.ts | 3 +- .../server/lib/adapters/metrics/lib/errors.ts | 15 ++++ 7 files changed, 127 insertions(+), 5 deletions(-) create mode 100644 x-pack/plugins/infra/common/errors/index.ts create mode 100644 x-pack/plugins/infra/common/errors/metrics.ts create mode 100644 x-pack/plugins/infra/public/components/metrics/invalid_node.tsx create mode 100644 x-pack/plugins/infra/server/lib/adapters/metrics/lib/errors.ts diff --git a/x-pack/plugins/infra/common/errors/index.ts b/x-pack/plugins/infra/common/errors/index.ts new file mode 100644 index 0000000000000..88b76eb0ef775 --- /dev/null +++ b/x-pack/plugins/infra/common/errors/index.ts @@ -0,0 +1,7 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export * from './metrics'; diff --git a/x-pack/plugins/infra/common/errors/metrics.ts b/x-pack/plugins/infra/common/errors/metrics.ts new file mode 100644 index 0000000000000..08d58a7db326e --- /dev/null +++ b/x-pack/plugins/infra/common/errors/metrics.ts @@ -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; + * you may not use this file except in compliance with the Elastic License. + */ + +export enum InfraMetricsErrorCodes { + invalid_node = 'METRICS_INVALID_NODE', +} diff --git a/x-pack/plugins/infra/public/components/metrics/invalid_node.tsx b/x-pack/plugins/infra/public/components/metrics/invalid_node.tsx new file mode 100644 index 0000000000000..041b650fee9a5 --- /dev/null +++ b/x-pack/plugins/infra/public/components/metrics/invalid_node.tsx @@ -0,0 +1,76 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { EuiButton, EuiEmptyPrompt, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n/react'; +import React from 'react'; +import styled from 'styled-components'; +import { WithSourceConfigurationFlyoutState } from '../../components/source_configuration/source_configuration_flyout_state'; +import { WithKibanaChrome } from '../../containers/with_kibana_chrome'; + +interface InvalidNodeErrorProps { + nodeName: string; +} + +export const InvalidNodeError: React.SFC = ({ nodeName }) => ( + + {({ basePath }) => ( + + + + } + body={ +

+ +

+ } + actions={ + + + + + + + + + {({ enable }) => ( + + + + )} + + + + } + /> + )} +
+); + +const CenteredEmptyPrompt = styled(EuiEmptyPrompt)` + align-self: center; +`; diff --git a/x-pack/plugins/infra/public/containers/metrics/with_metrics.tsx b/x-pack/plugins/infra/public/containers/metrics/with_metrics.tsx index 181133cfc917c..b04a40778dc22 100644 --- a/x-pack/plugins/infra/public/containers/metrics/with_metrics.tsx +++ b/x-pack/plugins/infra/public/containers/metrics/with_metrics.tsx @@ -3,7 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ - +import { ApolloError } from 'apollo-client'; import React from 'react'; import { Query } from 'react-apollo'; import { @@ -18,7 +18,7 @@ import { metricsQuery } from './metrics.gql_query'; interface WithMetricsArgs { metrics: InfraMetricData[]; - error?: string | undefined; + error?: ApolloError | undefined; loading: boolean; refetch: () => void; } @@ -63,7 +63,7 @@ export const WithMetrics = ({ {({ data, error, loading, refetch }) => { return children({ metrics: filterOnlyInfraMetricData(data && data.source && data.source.metrics), - error: error && error.message, + error, loading, refetch, }); diff --git a/x-pack/plugins/infra/public/pages/metrics/index.tsx b/x-pack/plugins/infra/public/pages/metrics/index.tsx index d775d5e5d236f..6560764e740f9 100644 --- a/x-pack/plugins/infra/public/pages/metrics/index.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/index.tsx @@ -14,15 +14,19 @@ import { EuiTitle, } from '@elastic/eui'; import { InjectedIntl, injectI18n } from '@kbn/i18n/react'; +import { GraphQLFormattedError } from 'graphql'; import React from 'react'; import styled, { withTheme } from 'styled-components'; +import { InfraMetricsErrorCodes } from '../../../common/errors'; import { AutoSizer } from '../../components/auto_sizer'; import { Header } from '../../components/header'; import { Metrics } from '../../components/metrics'; +import { InvalidNodeError } from '../../components/metrics/invalid_node'; import { MetricsSideNav } from '../../components/metrics/side_nav'; import { MetricsTimeControls } from '../../components/metrics/time_controls'; import { ColumnarPage, PageContent } from '../../components/page'; +import { SourceConfigurationFlyout } from '../../components/source_configuration'; import { WithMetadata } from '../../containers/metadata/with_metadata'; import { WithMetrics } from '../../containers/metrics/with_metrics'; import { @@ -113,6 +117,7 @@ export const MetricDetail = withTheme( return (
+ {({ metrics, error, loading, refetch }) => { if (error) { - return ; + const invalidNodeError = error.graphQLErrors.some( + (err: GraphQLFormattedError) => + err.code === InfraMetricsErrorCodes.invalid_node + ); + + if (invalidNodeError) { + return ; + } + + return ; } return ( diff --git a/x-pack/plugins/infra/server/lib/adapters/metrics/kibana_metrics_adapter.ts b/x-pack/plugins/infra/server/lib/adapters/metrics/kibana_metrics_adapter.ts index 02fe9020edc28..2eb0cdc0c4f5b 100644 --- a/x-pack/plugins/infra/server/lib/adapters/metrics/kibana_metrics_adapter.ts +++ b/x-pack/plugins/infra/server/lib/adapters/metrics/kibana_metrics_adapter.ts @@ -11,6 +11,7 @@ import { InfraMetric, InfraMetricData, InfraNodeType } from '../../../graphql/ty import { InfraBackendFrameworkAdapter, InfraFrameworkRequest } from '../framework'; import { InfraMetricsAdapter, InfraMetricsRequestOptions } from './adapter_types'; import { checkValidNode } from './lib/check_valid_node'; +import { InvalidNodeError } from './lib/errors'; import { metricModels } from './models'; export class KibanaMetricsAdapter implements InfraMetricsAdapter { @@ -45,7 +46,7 @@ export class KibanaMetricsAdapter implements InfraMetricsAdapter { const validNode = await checkValidNode(search, indexPattern, nodeField, options.nodeId); if (!validNode) { - throw new Error( + throw new InvalidNodeError( i18n.translate('xpack.infra.kibanaMetrics.nodeDoesNotExistErrorMessage', { defaultMessage: '{nodeId} does not exist.', values: { diff --git a/x-pack/plugins/infra/server/lib/adapters/metrics/lib/errors.ts b/x-pack/plugins/infra/server/lib/adapters/metrics/lib/errors.ts new file mode 100644 index 0000000000000..750858f3ce1fa --- /dev/null +++ b/x-pack/plugins/infra/server/lib/adapters/metrics/lib/errors.ts @@ -0,0 +1,15 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { ApolloError } from 'apollo-server-errors'; +import { InfraMetricsErrorCodes } from '../../../../../common/errors'; + +export class InvalidNodeError extends ApolloError { + constructor(message: string) { + super(message, InfraMetricsErrorCodes.invalid_node); + Object.defineProperty(this, 'name', { value: 'InvalidNodeError' }); + } +}