From 39c8aeb7b03b61316be5f71ad024f591741f224b Mon Sep 17 00:00:00 2001 From: Walter Rafelsberger Date: Fri, 18 Oct 2019 01:11:29 -0700 Subject: [PATCH] [ML] Transforms: Fix error toasts. (#48509) Previously, error messages were just output within the toast as raw text which could result in overflows and overall unreadable results. This update fixes it by providing a "View details" button which opens a modal with the properly formatted error message. Plain text error message up to 140 character will still be shown in the toast itself. --- .../transform/public/app/components/index.ts | 1 + .../toast_notification_text.test.tsx | 30 ++++++++ .../components/toast_notification_text.tsx | 75 +++++++++++++++++++ ..._transform.ts => use_delete_transform.tsx} | 12 ++- .../step_create/step_create_form.tsx | 52 +++++++------ .../step_details/step_details_form.tsx | 41 +++++----- .../translations/translations/ja-JP.json | 7 +- .../translations/translations/zh-CN.json | 7 +- 8 files changed, 166 insertions(+), 59 deletions(-) create mode 100644 x-pack/legacy/plugins/transform/public/app/components/toast_notification_text.test.tsx create mode 100644 x-pack/legacy/plugins/transform/public/app/components/toast_notification_text.tsx rename x-pack/legacy/plugins/transform/public/app/hooks/{use_delete_transform.ts => use_delete_transform.tsx} (87%) diff --git a/x-pack/legacy/plugins/transform/public/app/components/index.ts b/x-pack/legacy/plugins/transform/public/app/components/index.ts index dbef5a2dd46dc8..e19c8f96b9ac21 100644 --- a/x-pack/legacy/plugins/transform/public/app/components/index.ts +++ b/x-pack/legacy/plugins/transform/public/app/components/index.ts @@ -6,3 +6,4 @@ export { SectionError } from './section_error'; export { SectionLoading } from './section_loading'; +export { ToastNotificationText } from './toast_notification_text'; diff --git a/x-pack/legacy/plugins/transform/public/app/components/toast_notification_text.test.tsx b/x-pack/legacy/plugins/transform/public/app/components/toast_notification_text.test.tsx new file mode 100644 index 00000000000000..ffdb79a9d410b2 --- /dev/null +++ b/x-pack/legacy/plugins/transform/public/app/components/toast_notification_text.test.tsx @@ -0,0 +1,30 @@ +/* + * 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 React from 'react'; +import { cleanup, render } from 'react-testing-library'; +import { ToastNotificationText } from './toast_notification_text'; + +describe('ToastNotificationText', () => { + afterEach(cleanup); + + test('should render the text as plain text', () => { + const props = { + text: 'a short text message', + }; + const { container } = render(); + expect(container.textContent).toBe('a short text message'); + }); + + test('should render the text within a modal', () => { + const props = { + text: + 'a text message that is longer than 140 characters. a text message that is longer than 140 characters. a text message that is longer than 140 characters. ', + }; + const { container } = render(); + expect(container.textContent).toBe('View details'); + }); +}); diff --git a/x-pack/legacy/plugins/transform/public/app/components/toast_notification_text.tsx b/x-pack/legacy/plugins/transform/public/app/components/toast_notification_text.tsx new file mode 100644 index 00000000000000..15cb23415bb3ab --- /dev/null +++ b/x-pack/legacy/plugins/transform/public/app/components/toast_notification_text.tsx @@ -0,0 +1,75 @@ +/* + * 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 React, { FC } from 'react'; + +import { + EuiButtonEmpty, + EuiCodeBlock, + EuiModal, + EuiModalBody, + EuiModalFooter, + EuiModalHeader, + EuiModalHeaderTitle, +} from '@elastic/eui'; + +import { i18n } from '@kbn/i18n'; + +import { npStart } from 'ui/new_platform'; + +const MAX_SIMPLE_MESSAGE_LENGTH = 140; + +export const ToastNotificationText: FC<{ text: any }> = ({ text }) => { + if (typeof text === 'string' && text.length <= MAX_SIMPLE_MESSAGE_LENGTH) { + return text; + } + + if ( + typeof text === 'object' && + typeof text.message === 'string' && + text.message.length <= MAX_SIMPLE_MESSAGE_LENGTH + ) { + return text.message; + } + + const formattedText = text.message ? text.message : JSON.stringify(text, null, 2); + + const openModal = () => { + const modal = npStart.core.overlays.openModal( + modal.close()}> + + + {i18n.translate('xpack.transform.toastText.modalTitle', { + defaultMessage: 'Error details', + })} + + + + + {formattedText} + + + + modal.close()}> + {i18n.translate('xpack.transform.toastText.closeModalButtonText', { + defaultMessage: 'Close', + })} + + + + ); + }; + + return ( + <> + + {i18n.translate('xpack.transform.toastText.openModalButtonText', { + defaultMessage: 'View details', + })} + + + ); +}; diff --git a/x-pack/legacy/plugins/transform/public/app/hooks/use_delete_transform.ts b/x-pack/legacy/plugins/transform/public/app/hooks/use_delete_transform.tsx similarity index 87% rename from x-pack/legacy/plugins/transform/public/app/hooks/use_delete_transform.ts rename to x-pack/legacy/plugins/transform/public/app/hooks/use_delete_transform.tsx index de9c92e758aa3d..6a7804dcc6ac8f 100644 --- a/x-pack/legacy/plugins/transform/public/app/hooks/use_delete_transform.ts +++ b/x-pack/legacy/plugins/transform/public/app/hooks/use_delete_transform.tsx @@ -4,10 +4,13 @@ * you may not use this file except in compliance with the Elastic License. */ +import React from 'react'; + import { i18n } from '@kbn/i18n'; import { toastNotifications } from 'ui/notify'; import { TransformListRow, refreshTransformList$, REFRESH_TRANSFORM_LIST_STATE } from '../common'; +import { ToastNotificationText } from '../components'; import { useApi } from './use_api'; import { TransformEndpointRequest, TransformEndpointResult } from './use_api_types'; @@ -46,11 +49,12 @@ export const useDeleteTransforms = () => { refreshTransformList$.next(REFRESH_TRANSFORM_LIST_STATE.REFRESH); } catch (e) { - toastNotifications.addDanger( - i18n.translate('xpack.transform.transformList.deleteTransformGenericErrorMessage', { + toastNotifications.addDanger({ + title: i18n.translate('xpack.transform.transformList.deleteTransformGenericErrorMessage', { defaultMessage: 'An error occurred calling the API endpoint to delete transforms.', - }) - ); + }), + text: , + }); } }; }; diff --git a/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_create/step_create_form.tsx b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_create/step_create_form.tsx index 0c5ff048000378..c51144fd2d29c0 100644 --- a/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_create/step_create_form.tsx +++ b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_create/step_create_form.tsx @@ -29,6 +29,7 @@ import { EuiText, } from '@elastic/eui'; +import { ToastNotificationText } from '../../../../components'; import { useApi } from '../../../../hooks/use_api'; import { isKibanaContextInitialized, KibanaContext } from '../../../../lib/kibana'; import { RedirectToTransformManagement } from '../../../../common/navigation'; @@ -96,12 +97,13 @@ export const StepCreateForm: SFC = React.memo( ); } catch (e) { setCreated(false); - toastNotifications.addDanger( - i18n.translate('xpack.transform.stepCreateForm.createTransformErrorMessage', { - defaultMessage: 'An error occurred creating the transform {transformId}: {error}', - values: { transformId, error: JSON.stringify(e) }, - }) - ); + toastNotifications.addDanger({ + title: i18n.translate('xpack.transform.stepCreateForm.createTransformErrorMessage', { + defaultMessage: 'An error occurred creating the transform {transformId}:', + values: { transformId }, + }), + text: , + }); return false; } @@ -125,12 +127,13 @@ export const StepCreateForm: SFC = React.memo( ); } catch (e) { setStarted(false); - toastNotifications.addDanger( - i18n.translate('xpack.transform.stepCreateForm.startTransformErrorMessage', { - defaultMessage: 'An error occurred starting the transform {transformId}: {error}', - values: { transformId, error: JSON.stringify(e) }, - }) - ); + toastNotifications.addDanger({ + title: i18n.translate('xpack.transform.stepCreateForm.startTransformErrorMessage', { + defaultMessage: 'An error occurred starting the transform {transformId}:', + values: { transformId }, + }), + text: , + }); } } @@ -182,13 +185,14 @@ export const StepCreateForm: SFC = React.memo( setIndexPatternId(id); return true; } catch (e) { - toastNotifications.addDanger( - i18n.translate('xpack.transform.stepCreateForm.createIndexPatternErrorMessage', { + toastNotifications.addDanger({ + title: i18n.translate('xpack.transform.stepCreateForm.createIndexPatternErrorMessage', { defaultMessage: - 'An error occurred creating the Kibana index pattern {indexPatternName}: {error}', - values: { indexPatternName, error: JSON.stringify(e) }, - }) - ); + 'An error occurred creating the Kibana index pattern {indexPatternName}:', + values: { indexPatternName }, + }), + text: , + }); return false; } }; @@ -214,12 +218,12 @@ export const StepCreateForm: SFC = React.memo( } } } catch (e) { - toastNotifications.addDanger( - i18n.translate('xpack.transform.stepCreateForm.progressErrorMessage', { - defaultMessage: 'An error occurred getting the progress percentage: {error}', - values: { error: JSON.stringify(e) }, - }) - ); + toastNotifications.addDanger({ + title: i18n.translate('xpack.transform.stepCreateForm.progressErrorMessage', { + defaultMessage: 'An error occurred getting the progress percentage:', + }), + text: , + }); clearInterval(interval); } }, PROGRESS_REFRESH_INTERVAL_MS); diff --git a/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_details/step_details_form.tsx b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_details/step_details_form.tsx index 88cf1bf471c462..ba43e020674acf 100644 --- a/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_details/step_details_form.tsx +++ b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_details/step_details_form.tsx @@ -15,6 +15,7 @@ import { EuiLink, EuiSwitch, EuiFieldText, EuiForm, EuiFormRow, EuiSelect } from import { isKibanaContextInitialized, KibanaContext } from '../../../../lib/kibana'; import { isValidIndexName } from '../../../../../../common/utils/es_utils'; +import { ToastNotificationText } from '../../../../components'; import { useApi } from '../../../../hooks/use_api'; import { isTransformIdValid, TransformId, TransformPivotConfig } from '../../../../common'; @@ -86,35 +87,37 @@ export const StepDetailsForm: SFC = React.memo(({ overrides = {}, onChang ) ); } catch (e) { - toastNotifications.addDanger( - i18n.translate('xpack.transform.stepDetailsForm.errorGettingTransformList', { - defaultMessage: 'An error occurred getting the existing transform IDs: {error}', - values: { error: JSON.stringify(e) }, - }) - ); + toastNotifications.addDanger({ + title: i18n.translate('xpack.transform.stepDetailsForm.errorGettingTransformList', { + defaultMessage: 'An error occurred getting the existing transform IDs:', + }), + text: , + }); } try { setIndexNames((await api.getIndices()).map(index => index.name)); } catch (e) { - toastNotifications.addDanger( - i18n.translate('xpack.transform.stepDetailsForm.errorGettingIndexNames', { - defaultMessage: 'An error occurred getting the existing index names: {error}', - values: { error: JSON.stringify(e) }, - }) - ); + toastNotifications.addDanger({ + title: i18n.translate('xpack.transform.stepDetailsForm.errorGettingIndexNames', { + defaultMessage: 'An error occurred getting the existing index names:', + }), + text: , + }); } try { setIndexPatternTitles(await kibanaContext.indexPatterns.getTitles()); } catch (e) { - toastNotifications.addDanger( - i18n.translate('xpack.transform.stepDetailsForm.errorGettingIndexPatternTitles', { - defaultMessage: - 'An error occurred getting the existing index pattern titles: {error}', - values: { error: JSON.stringify(e) }, - }) - ); + toastNotifications.addDanger({ + title: i18n.translate( + 'xpack.transform.stepDetailsForm.errorGettingIndexPatternTitles', + { + defaultMessage: 'An error occurred getting the existing index pattern titles:', + } + ), + text: , + }); } } })(); diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 005f44a3842de1..1f48155128e17c 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -6975,21 +6975,16 @@ "xpack.transform.groupByLabelForm.editIntervalAriaLabel": "間隔を編集", "xpack.transform.stepCreateForm.copyTransformConfigToClipboardButton": "クリップボードにコピー", "xpack.transform.stepCreateForm.copyTransformConfigToClipboardDescription": "ジョブを作成する Kibana 開発コンソールのコマンドをクリップボードにコピーします。", - "xpack.transform.stepCreateForm.createIndexPatternErrorMessage": "Kibana インデックスパターン {indexPatternName} の作成中にエラーが発生しました: {error}", "xpack.transform.stepCreateForm.createIndexPatternLabel": "インデックスパターンを作成", - "xpack.transform.stepCreateForm.createTransformErrorMessage": "データフレームジョブ {transformId} の作成中にエラーが発生しました: {error}", "xpack.transform.stepCreateForm.createTransformSuccessMessage": "データフレームジョブ {transformId} が作成されました", "xpack.transform.stepCreateForm.creatingIndexPatternMessage": "Kibana インデックスパターンを作成中…", "xpack.transform.stepCreateForm.discoverCardDescription": "ディスカバリでデータフレームピボットを閲覧します。", "xpack.transform.stepCreateForm.discoverCardTitle": "ディスカバー", "xpack.transform.stepCreateForm.transformListCardDescription": "データフレームジョブの管理ページに戻ります。", "xpack.transform.stepCreateForm.transformListCardTitle": "データフレームジョブ", - "xpack.transform.stepCreateForm.progressErrorMessage": "進捗パーセンテージの取得中にエラーが発生しました: {error}", "xpack.transform.stepCreateForm.progressTitle": "進捗", "xpack.transform.stepCreateForm.createIndexPatternSuccessMessage": "Kibana インデックスパターン {indexPatternName} が作成されました", - "xpack.transform.stepCreateForm.startTransformErrorMessage": "データフレームジョブ {transformId} の開始中にエラーが発生しました: {error}", "xpack.transform.stepCreateForm.startTransformSuccessMessage": "データフレームジョブ {transformId} が開始しました", - "xpack.transform.stepDetailsForm.errorGettingIndexPatternTitles": "既存のインデックスパターンのタイトルの取得中にエラーが発生しました: {error}", "xpack.transform.stepDetailsForm.indexPatternTitleError": "このタイトルのインデックスパターンが既に存在します。", "xpack.transform.stepDetailsForm.transformIdInputAriaLabel": "固有のジョブ ID を選択してください。", "xpack.transform.stepDetailsForm.transformIdLabel": "ジョブ ID", @@ -10506,4 +10501,4 @@ "xpack.fileUpload.fileParser.errorReadingFile": "ファイルの読み込み中にエラーが発生しました", "xpack.fileUpload.fileParser.noFileProvided": "エラー、ファイルが提供されていません" } -} +} \ No newline at end of file diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index b7efba71b14326..9fe5ca801919fd 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -7133,21 +7133,16 @@ "xpack.transform.groupByLabelForm.editIntervalAriaLabel": "编辑时间间隔", "xpack.transform.stepCreateForm.copyTransformConfigToClipboardButton": "复制到剪贴板", "xpack.transform.stepCreateForm.copyTransformConfigToClipboardDescription": "将用于创建作业的 Kibana 开发控制台命令复制到剪贴板。", - "xpack.transform.stepCreateForm.createIndexPatternErrorMessage": "创建 Kibana 索引模式 {indexPatternName} 时发生错误:{error}", "xpack.transform.stepCreateForm.createIndexPatternLabel": "创建索引模式", - "xpack.transform.stepCreateForm.createTransformErrorMessage": "创建数据帧作业 {transformId} 时发生错误:{error}", "xpack.transform.stepCreateForm.createTransformSuccessMessage": "数据帧作业 {transformId} 创建成功。", "xpack.transform.stepCreateForm.creatingIndexPatternMessage": "正在创建 Kibana 索引模式......", "xpack.transform.stepCreateForm.discoverCardDescription": "使用 Discover 浏览数据帧透视表。", "xpack.transform.stepCreateForm.discoverCardTitle": "Discover", "xpack.transform.stepCreateForm.transformListCardDescription": "返回数据帧作业管理页面。", "xpack.transform.stepCreateForm.transformListCardTitle": "数据帧作业", - "xpack.transform.stepCreateForm.progressErrorMessage": "获取进度百分比时出错:{error}", "xpack.transform.stepCreateForm.progressTitle": "进度", "xpack.transform.stepCreateForm.createIndexPatternSuccessMessage": "Kibana 索引模式 {indexPatternName} 成功创建。", - "xpack.transform.stepCreateForm.startTransformErrorMessage": "启动数据帧作业 {transformId} 时发生错误:{error}", "xpack.transform.stepCreateForm.startTransformSuccessMessage": "数据帧作业 {transformId} 启动成功。", - "xpack.transform.stepDetailsForm.errorGettingIndexPatternTitles": "获取现有索引名称时发生错误:{error}", "xpack.transform.stepDetailsForm.indexPatternTitleError": "具有此名称的索引模式已存在。", "xpack.transform.stepDetailsForm.transformIdInputAriaLabel": "选择唯一的作业 ID。", "xpack.transform.stepDetailsForm.transformIdLabel": "作业 ID", @@ -10663,4 +10658,4 @@ "xpack.fileUpload.fileParser.errorReadingFile": "读取文件时出错", "xpack.fileUpload.fileParser.noFileProvided": "错误,未提供任何文件" } -} +} \ No newline at end of file