mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
[Discover] Improve shard error message formatting (#161098)
- Closes https://github.com/elastic/kibana/issues/156645 ## Summary This PR updates UI of shards error modal. ### Updated design <img width="500" alt="Screenshot 2023-07-07 at 10 05 00" src="a099a436
-61fd-4522-b231-88a0d1179061">  ### Before <img width="500" alt="image 2" src="d3c067d9
-2d18-4fcc-8db0-573defcb9b44"> For testing, please follow instruction from https://github.com/elastic/kibana/pull/41649 and drop `targetfield` on Lens page. ### Checklist - [x] 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) - [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] 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: Andrea Del Rio <delrio.andre@gmail.com> Co-authored-by: Stratoula Kalafateli <efstratia.kalafateli@elastic.co>
This commit is contained in:
parent
0f889618a9
commit
41e236316c
13 changed files with 347 additions and 411 deletions
|
@ -1,192 +1,176 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`ShardFailureDescription renders matching snapshot given valid properties 1`] = `
|
||||
<div>
|
||||
<ShardFailureDescriptionHeader
|
||||
index="repro2"
|
||||
intl={
|
||||
<EuiFlexGroup
|
||||
alignItems="stretch"
|
||||
direction="column"
|
||||
gutterSize="none"
|
||||
>
|
||||
<EuiFlexItem
|
||||
grow={false}
|
||||
>
|
||||
<EuiDescriptionList
|
||||
className="shardFailureModal__desc"
|
||||
compressed={true}
|
||||
descriptionProps={
|
||||
Object {
|
||||
"className": "shardFailureModal__descValue",
|
||||
}
|
||||
}
|
||||
gutterSize="s"
|
||||
listItems={
|
||||
Array [
|
||||
Object {
|
||||
"description": 0,
|
||||
"title": "Shard",
|
||||
},
|
||||
Object {
|
||||
"description": "repro2",
|
||||
"title": "Index",
|
||||
},
|
||||
Object {
|
||||
"description": "script_exception",
|
||||
"title": "Type",
|
||||
},
|
||||
]
|
||||
}
|
||||
titleProps={
|
||||
Object {
|
||||
"className": "shardFailureModal__descTitle",
|
||||
}
|
||||
}
|
||||
type="responsiveColumn"
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem
|
||||
css={
|
||||
Object {
|
||||
"defaultFormats": Object {},
|
||||
"defaultLocale": "en",
|
||||
"formatDate": [Function],
|
||||
"formatHTMLMessage": [Function],
|
||||
"formatMessage": [Function],
|
||||
"formatNumber": [Function],
|
||||
"formatPlural": [Function],
|
||||
"formatRelative": [Function],
|
||||
"formatTime": [Function],
|
||||
"formats": Object {
|
||||
"date": Object {
|
||||
"full": Object {
|
||||
"day": "numeric",
|
||||
"month": "long",
|
||||
"weekday": "long",
|
||||
"year": "numeric",
|
||||
},
|
||||
"long": Object {
|
||||
"day": "numeric",
|
||||
"month": "long",
|
||||
"year": "numeric",
|
||||
},
|
||||
"medium": Object {
|
||||
"day": "numeric",
|
||||
"month": "short",
|
||||
"year": "numeric",
|
||||
},
|
||||
"short": Object {
|
||||
"day": "numeric",
|
||||
"month": "numeric",
|
||||
"year": "2-digit",
|
||||
},
|
||||
},
|
||||
"number": Object {
|
||||
"currency": Object {
|
||||
"style": "currency",
|
||||
},
|
||||
"percent": Object {
|
||||
"style": "percent",
|
||||
},
|
||||
},
|
||||
"relative": Object {
|
||||
"days": Object {
|
||||
"units": "day",
|
||||
},
|
||||
"hours": Object {
|
||||
"units": "hour",
|
||||
},
|
||||
"minutes": Object {
|
||||
"units": "minute",
|
||||
},
|
||||
"months": Object {
|
||||
"units": "month",
|
||||
},
|
||||
"seconds": Object {
|
||||
"units": "second",
|
||||
},
|
||||
"years": Object {
|
||||
"units": "year",
|
||||
},
|
||||
},
|
||||
"time": Object {
|
||||
"full": Object {
|
||||
"hour": "numeric",
|
||||
"minute": "numeric",
|
||||
"second": "numeric",
|
||||
"timeZoneName": "short",
|
||||
},
|
||||
"long": Object {
|
||||
"hour": "numeric",
|
||||
"minute": "numeric",
|
||||
"second": "numeric",
|
||||
"timeZoneName": "short",
|
||||
},
|
||||
"medium": Object {
|
||||
"hour": "numeric",
|
||||
"minute": "numeric",
|
||||
"second": "numeric",
|
||||
},
|
||||
"short": Object {
|
||||
"hour": "numeric",
|
||||
"minute": "numeric",
|
||||
},
|
||||
},
|
||||
},
|
||||
"formatters": Object {
|
||||
"getDateTimeFormat": [Function],
|
||||
"getMessageFormat": [Function],
|
||||
"getNumberFormat": [Function],
|
||||
"getPluralFormat": [Function],
|
||||
"getRelativeFormat": [Function],
|
||||
},
|
||||
"locale": "en",
|
||||
"messages": Object {},
|
||||
"now": [Function],
|
||||
"onError": [Function],
|
||||
"textComponent": Symbol(react.fragment),
|
||||
"timeZone": null,
|
||||
"map": undefined,
|
||||
"name": "1eu43fv",
|
||||
"next": undefined,
|
||||
"styles": "
|
||||
align-self: flex-start;
|
||||
",
|
||||
"toString": [Function],
|
||||
}
|
||||
}
|
||||
node="itsmeyournode"
|
||||
reason={
|
||||
Object {
|
||||
"caused_by": Object {
|
||||
"reason": "Gimme reason",
|
||||
"type": "illegal_argument_exception",
|
||||
},
|
||||
"lang": "painless",
|
||||
"reason": "runtime error",
|
||||
"script": "return doc['targetfield'].value;",
|
||||
"script_stack": Array [
|
||||
"return doc['targetfield'].value;",
|
||||
" ^---- HERE",
|
||||
],
|
||||
"type": "script_exception",
|
||||
}
|
||||
}
|
||||
shard={0}
|
||||
/>
|
||||
<EuiSpacer
|
||||
size="m"
|
||||
/>
|
||||
<EuiDescriptionList
|
||||
className="shardFailureModal__desc"
|
||||
compressed={true}
|
||||
descriptionProps={
|
||||
Object {
|
||||
"className": "shardFailureModal__descValue",
|
||||
}
|
||||
}
|
||||
listItems={
|
||||
Array [
|
||||
Object {
|
||||
"description": "script_exception",
|
||||
"title": "Type",
|
||||
},
|
||||
Object {
|
||||
"description": "runtime error",
|
||||
"title": "Reason",
|
||||
},
|
||||
Object {
|
||||
"description": <EuiCodeBlock
|
||||
isCopyable={true}
|
||||
language="java"
|
||||
paddingSize="s"
|
||||
>
|
||||
return doc['targetfield'].value;
|
||||
^---- HERE
|
||||
</EuiCodeBlock>,
|
||||
"title": "Script stack",
|
||||
},
|
||||
Object {
|
||||
"description": <EuiCodeBlock
|
||||
isCopyable={true}
|
||||
language="java"
|
||||
paddingSize="s"
|
||||
>
|
||||
return doc['targetfield'].value;
|
||||
</EuiCodeBlock>,
|
||||
"title": "Script",
|
||||
},
|
||||
Object {
|
||||
"description": "painless",
|
||||
"title": "Lang",
|
||||
},
|
||||
Object {
|
||||
"description": "illegal_argument_exception",
|
||||
"title": "Caused by type",
|
||||
},
|
||||
Object {
|
||||
"description": "Gimme reason",
|
||||
"title": "Caused by reason",
|
||||
},
|
||||
]
|
||||
}
|
||||
titleProps={
|
||||
Object {
|
||||
"className": "shardFailureModal__descTitle",
|
||||
}
|
||||
}
|
||||
type="column"
|
||||
/>
|
||||
</div>
|
||||
grow={false}
|
||||
>
|
||||
<EuiButtonEmpty
|
||||
flush="left"
|
||||
onClick={[Function]}
|
||||
size="s"
|
||||
>
|
||||
Show details
|
||||
</EuiButtonEmpty>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
`;
|
||||
|
||||
exports[`ShardFailureDescription should show more details when button is pressed 1`] = `
|
||||
<EuiFlexGroup
|
||||
alignItems="stretch"
|
||||
direction="column"
|
||||
gutterSize="none"
|
||||
>
|
||||
<EuiFlexItem
|
||||
grow={false}
|
||||
>
|
||||
<EuiDescriptionList
|
||||
className="shardFailureModal__desc"
|
||||
compressed={true}
|
||||
descriptionProps={
|
||||
Object {
|
||||
"className": "shardFailureModal__descValue",
|
||||
}
|
||||
}
|
||||
gutterSize="s"
|
||||
listItems={
|
||||
Array [
|
||||
Object {
|
||||
"description": 0,
|
||||
"title": "Shard",
|
||||
},
|
||||
Object {
|
||||
"description": "repro2",
|
||||
"title": "Index",
|
||||
},
|
||||
Object {
|
||||
"description": "script_exception",
|
||||
"title": "Type",
|
||||
},
|
||||
Object {
|
||||
"description": "itsmeyournode",
|
||||
"title": "Node",
|
||||
},
|
||||
Object {
|
||||
"description": "runtime error",
|
||||
"title": "Reason",
|
||||
},
|
||||
Object {
|
||||
"description": <EuiCodeBlock
|
||||
isCopyable={true}
|
||||
language="java"
|
||||
paddingSize="s"
|
||||
>
|
||||
return doc['targetfield'].value;
|
||||
^---- HERE
|
||||
</EuiCodeBlock>,
|
||||
"title": "Script stack",
|
||||
},
|
||||
Object {
|
||||
"description": <EuiCodeBlock
|
||||
isCopyable={true}
|
||||
language="java"
|
||||
paddingSize="s"
|
||||
>
|
||||
return doc['targetfield'].value;
|
||||
</EuiCodeBlock>,
|
||||
"title": "Script",
|
||||
},
|
||||
Object {
|
||||
"description": "painless",
|
||||
"title": "Lang",
|
||||
},
|
||||
Object {
|
||||
"description": "illegal_argument_exception",
|
||||
"title": "Caused by type",
|
||||
},
|
||||
Object {
|
||||
"description": "Gimme reason",
|
||||
"title": "Caused by reason",
|
||||
},
|
||||
]
|
||||
}
|
||||
titleProps={
|
||||
Object {
|
||||
"className": "shardFailureModal__descTitle",
|
||||
}
|
||||
}
|
||||
type="responsiveColumn"
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem
|
||||
css={
|
||||
Object {
|
||||
"map": undefined,
|
||||
"name": "1eu43fv",
|
||||
"next": undefined,
|
||||
"styles": "
|
||||
align-self: flex-start;
|
||||
",
|
||||
"toString": [Function],
|
||||
}
|
||||
}
|
||||
grow={false}
|
||||
>
|
||||
<EuiButtonEmpty
|
||||
flush="left"
|
||||
onClick={[Function]}
|
||||
size="s"
|
||||
>
|
||||
Show less
|
||||
</EuiButtonEmpty>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
`;
|
||||
|
|
|
@ -5,6 +5,7 @@ exports[`ShardFailureModal renders matching snapshot given valid properties 1`]
|
|||
<EuiModalHeader>
|
||||
<EuiModalHeaderTitle
|
||||
data-test-subj="shardFailureModalTitle"
|
||||
size="xs"
|
||||
>
|
||||
test
|
||||
</EuiModalHeaderTitle>
|
||||
|
|
|
@ -5,39 +5,50 @@ exports[`ShardFailureTable renders matching snapshot given valid properties 1`]
|
|||
columns={
|
||||
Array [
|
||||
Object {
|
||||
"align": "right",
|
||||
"isExpander": true,
|
||||
"render": [Function],
|
||||
"width": "40px",
|
||||
},
|
||||
Object {
|
||||
"field": "shard",
|
||||
"name": "Shard",
|
||||
"sortable": true,
|
||||
"truncateText": true,
|
||||
"width": "80px",
|
||||
},
|
||||
Object {
|
||||
"field": "index",
|
||||
"name": "Index",
|
||||
"sortable": true,
|
||||
"truncateText": true,
|
||||
},
|
||||
Object {
|
||||
"field": "node",
|
||||
"name": "Node",
|
||||
"sortable": true,
|
||||
"truncateText": true,
|
||||
},
|
||||
Object {
|
||||
"field": "reason.type",
|
||||
"mobileOptions": Object {
|
||||
"header": false,
|
||||
},
|
||||
"name": "Reason",
|
||||
"truncateText": true,
|
||||
"render": [Function],
|
||||
},
|
||||
]
|
||||
}
|
||||
css={
|
||||
Object {
|
||||
"map": undefined,
|
||||
"name": "1vv0je1",
|
||||
"next": undefined,
|
||||
"styles": "
|
||||
& .euiTableHeaderCell {
|
||||
|
||||
/* Take the element out of the layout */
|
||||
position: absolute;
|
||||
/* Keep it vertically inline */
|
||||
inset-block-start: auto;
|
||||
/* Chrome requires a left value, and Selenium (used by Kibana's FTR) requires an off-screen position for its .getVisibleText() to not register SR-only text */
|
||||
inset-inline-start: -10000px;
|
||||
/* The element must have a size (for some screen readers) */
|
||||
|
||||
inline-size: 1px;
|
||||
block-size: 1px;
|
||||
|
||||
/* But reduce the visible size to nothing */
|
||||
clip: rect(0 0 0 0);
|
||||
clip-path: inset(50%);
|
||||
/* And ensure no overflows occur */
|
||||
overflow: hidden;
|
||||
/* Chrome requires the negative margin to not cause overflows of parent containers */
|
||||
margin: -1px;
|
||||
|
||||
}
|
||||
& .euiTableRowCell {
|
||||
border-top: none;
|
||||
}
|
||||
",
|
||||
"toString": [Function],
|
||||
}
|
||||
}
|
||||
itemId="id"
|
||||
itemIdToExpandedRowMap={Object {}}
|
||||
items={
|
||||
Array [
|
||||
Object {
|
||||
|
@ -62,7 +73,7 @@ exports[`ShardFailureTable renders matching snapshot given valid properties 1`]
|
|||
},
|
||||
]
|
||||
}
|
||||
pagination={true}
|
||||
pagination={false}
|
||||
responsive={true}
|
||||
sorting={
|
||||
Object {
|
||||
|
|
|
@ -2,6 +2,16 @@
|
|||
.shardFailureModal {
|
||||
min-height: 75vh;
|
||||
width: 768px;
|
||||
|
||||
// show buttons at the bottom of the modal
|
||||
.kbnOverlayMountWrapper {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
// smaller gap between the modal title and body
|
||||
.euiModalHeader {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.shardFailureModal__desc {
|
||||
|
@ -11,31 +21,19 @@
|
|||
}
|
||||
|
||||
.shardFailureModal__descTitle {
|
||||
width: 20% !important;
|
||||
margin-top: $euiSizeS;
|
||||
width: 12% !important;
|
||||
}
|
||||
|
||||
.shardFailureModal__descValue {
|
||||
width: 80% !important;
|
||||
margin-top: $euiSizeS;
|
||||
}
|
||||
.shardFailureModal__keyValueTitle {
|
||||
padding-right: $euiSizeS;
|
||||
width: 88% !important;
|
||||
}
|
||||
|
||||
@include euiBreakpoint('xs','s') {
|
||||
.shardFailureModal__keyValueTitle {
|
||||
display: block;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.shardFailureModal__descTitle {
|
||||
display: block;
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
.shardFailureModal__descValue {
|
||||
display: block;
|
||||
width: 100% !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,16 +7,22 @@
|
|||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { EuiButtonEmpty } from '@elastic/eui';
|
||||
import { shallowWithIntl } from '@kbn/test-jest-helpers';
|
||||
import { ShardFailureDescription } from './shard_failure_description';
|
||||
import { shardFailureResponse } from './__mocks__/shard_failure_response';
|
||||
import { ShardFailure } from './shard_failure_types';
|
||||
|
||||
describe('ShardFailureDescription', () => {
|
||||
it('renders matching snapshot given valid properties', () => {
|
||||
// TODO: remove cast once https://github.com/elastic/elasticsearch-js/issues/1286 is resolved
|
||||
const failure = (shardFailureResponse._shards as any).failures[0] as ShardFailure;
|
||||
const failure = (shardFailureResponse._shards as any).failures[0];
|
||||
const component = shallowWithIntl(<ShardFailureDescription {...failure} />);
|
||||
expect(component).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should show more details when button is pressed', async () => {
|
||||
const failure = (shardFailureResponse._shards as any).failures[0];
|
||||
const component = shallowWithIntl(<ShardFailureDescription {...failure} />);
|
||||
await component.find(EuiButtonEmpty).simulate('click');
|
||||
expect(component).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -6,11 +6,18 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import React, { useState } from 'react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { css } from '@emotion/react';
|
||||
import { getFlattenedObject } from '@kbn/std';
|
||||
import { EuiCodeBlock, EuiDescriptionList, EuiSpacer } from '@elastic/eui';
|
||||
import {
|
||||
EuiButtonEmpty,
|
||||
EuiCodeBlock,
|
||||
EuiDescriptionList,
|
||||
EuiFlexGroup,
|
||||
EuiFlexItem,
|
||||
} from '@elastic/eui';
|
||||
import { ShardFailure } from './shard_failure_types';
|
||||
import { ShardFailureDescriptionHeader } from './shard_failure_description_header';
|
||||
|
||||
/**
|
||||
* Provides pretty formatting of a given key string
|
||||
|
@ -41,25 +48,84 @@ export function formatValueByKey(value: unknown, key: string): string | JSX.Elem
|
|||
}
|
||||
|
||||
export function ShardFailureDescription(props: ShardFailure) {
|
||||
const [showDetails, setShowDetails] = useState<boolean>(false);
|
||||
|
||||
const flattendReason = getFlattenedObject(props.reason);
|
||||
|
||||
const listItems = Object.entries(flattendReason).map(([key, value]) => ({
|
||||
title: formatKey(key),
|
||||
description: formatValueByKey(value, key),
|
||||
}));
|
||||
const reasonItems = Object.entries(flattendReason)
|
||||
.filter(([key]) => key !== 'type')
|
||||
.map(([key, value]) => ({
|
||||
title: formatKey(key),
|
||||
description: formatValueByKey(value, key),
|
||||
}));
|
||||
|
||||
const items = [
|
||||
{
|
||||
title: i18n.translate('data.search.searchSource.fetch.shardsFailedModal.shardTitle', {
|
||||
defaultMessage: 'Shard',
|
||||
}),
|
||||
description: props.shard,
|
||||
},
|
||||
{
|
||||
title: i18n.translate('data.search.searchSource.fetch.shardsFailedModal.indexTitle', {
|
||||
defaultMessage: 'Index',
|
||||
}),
|
||||
description: props.index,
|
||||
},
|
||||
{
|
||||
title: i18n.translate('data.search.searchSource.fetch.shardsFailedModal.reasonTypeTitle', {
|
||||
defaultMessage: 'Type',
|
||||
}),
|
||||
description: props.reason.type,
|
||||
},
|
||||
...(showDetails
|
||||
? [
|
||||
{
|
||||
title: i18n.translate('data.search.searchSource.fetch.shardsFailedModal.nodeTitle', {
|
||||
defaultMessage: 'Node',
|
||||
}),
|
||||
description: props.node,
|
||||
},
|
||||
...reasonItems,
|
||||
]
|
||||
: []),
|
||||
];
|
||||
|
||||
return (
|
||||
<div>
|
||||
<ShardFailureDescriptionHeader {...props} />
|
||||
<EuiSpacer size="m" />
|
||||
<EuiDescriptionList
|
||||
listItems={listItems}
|
||||
type="column"
|
||||
compressed
|
||||
className="shardFailureModal__desc"
|
||||
titleProps={{ className: 'shardFailureModal__descTitle' }}
|
||||
descriptionProps={{ className: 'shardFailureModal__descValue' }}
|
||||
/>
|
||||
</div>
|
||||
<EuiFlexGroup direction="column" gutterSize="none" alignItems="stretch">
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiDescriptionList
|
||||
type="responsiveColumn"
|
||||
gutterSize="s"
|
||||
listItems={items}
|
||||
compressed
|
||||
className="shardFailureModal__desc"
|
||||
titleProps={{ className: 'shardFailureModal__descTitle' }}
|
||||
descriptionProps={{ className: 'shardFailureModal__descValue' }}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem
|
||||
grow={false}
|
||||
css={css`
|
||||
align-self: flex-start;
|
||||
`}
|
||||
>
|
||||
<EuiButtonEmpty size="s" onClick={() => setShowDetails((prev) => !prev)} flush="left">
|
||||
{showDetails
|
||||
? i18n.translate(
|
||||
'data.search.searchSource.fetch.shardsFailedModal.showLessButtonLabel',
|
||||
{
|
||||
defaultMessage: 'Show less',
|
||||
}
|
||||
)
|
||||
: i18n.translate(
|
||||
'data.search.searchSource.fetch.shardsFailedModal.showMoreButtonLabel',
|
||||
{
|
||||
defaultMessage: 'Show details',
|
||||
}
|
||||
)}
|
||||
</EuiButtonEmpty>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,55 +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 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 { EuiCode, EuiTitle } from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { ShardFailure } from './shard_failure_types';
|
||||
|
||||
export function getFailurePropsForSummary(
|
||||
failure: ShardFailure
|
||||
): Array<{ key: string; value: string }> {
|
||||
const failureDetailProps: Array<keyof ShardFailure> = ['shard', 'index', 'node'];
|
||||
return failureDetailProps
|
||||
.filter((key) => typeof failure[key] === 'number' || typeof failure[key] === 'string')
|
||||
.map((key) => ({ key, value: String(failure[key]) }));
|
||||
}
|
||||
|
||||
export function getFailureSummaryText(failure: ShardFailure, failureDetails?: string): string {
|
||||
const failureName = failure.reason.type;
|
||||
const displayDetails =
|
||||
typeof failureDetails === 'string' ? failureDetails : getFailureSummaryDetailsText(failure);
|
||||
|
||||
return i18n.translate('data.search.searchSource.fetch.shardsFailedModal.failureHeader', {
|
||||
defaultMessage: '{failureName} at {failureDetails}',
|
||||
values: { failureName, failureDetails: displayDetails },
|
||||
description: 'Summary of shard failures, e.g. "IllegalArgumentException at shard 0 node xyz"',
|
||||
});
|
||||
}
|
||||
|
||||
export function getFailureSummaryDetailsText(failure: ShardFailure): string {
|
||||
return getFailurePropsForSummary(failure)
|
||||
.map(({ key, value }) => `${key}: ${value}`)
|
||||
.join(', ');
|
||||
}
|
||||
|
||||
export function ShardFailureDescriptionHeader(props: ShardFailure) {
|
||||
const failureDetails = getFailurePropsForSummary(props).map((kv) => (
|
||||
<span className="shardFailureModal__keyValueTitle" key={kv.key}>
|
||||
<EuiCode>{kv.key}</EuiCode> {kv.value}
|
||||
</span>
|
||||
));
|
||||
return (
|
||||
<EuiTitle size="xs">
|
||||
<h2>
|
||||
{getFailureSummaryText(props, '')}
|
||||
{failureDetails}
|
||||
</h2>
|
||||
</EuiTitle>
|
||||
);
|
||||
}
|
|
@ -94,7 +94,9 @@ export function ShardFailureModal({ request, response, title, onClose }: Props)
|
|||
return (
|
||||
<React.Fragment>
|
||||
<EuiModalHeader>
|
||||
<EuiModalHeaderTitle data-test-subj="shardFailureModalTitle">{title}</EuiModalHeaderTitle>
|
||||
<EuiModalHeaderTitle data-test-subj="shardFailureModalTitle" size="xs">
|
||||
{title}
|
||||
</EuiModalHeaderTitle>
|
||||
</EuiModalHeader>
|
||||
<EuiModalBody>
|
||||
<EuiTabbedContent tabs={tabs} initialSelectedTab={tabs[0]} autoFocus="selected" />
|
||||
|
|
|
@ -15,6 +15,7 @@ import { toMountPoint } from '@kbn/kibana-react-plugin/public';
|
|||
import { getOverlays } from '../services';
|
||||
import { ShardFailureModal } from './shard_failure_modal';
|
||||
import type { ShardFailureRequest } from './shard_failure_types';
|
||||
import './_shard_failure_modal.scss';
|
||||
|
||||
// @internal
|
||||
export interface ShardFailureOpenModalButtonProps {
|
||||
|
|
|
@ -6,100 +6,38 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import React, { useState, ReactElement } from 'react';
|
||||
// @ts-ignore
|
||||
import { EuiInMemoryTable, EuiButtonIcon } from '@elastic/eui';
|
||||
// @ts-ignore
|
||||
import { RIGHT_ALIGNMENT } from '@elastic/eui/lib/services';
|
||||
import React from 'react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { css } from '@emotion/react';
|
||||
import { EuiInMemoryTable, EuiInMemoryTableProps, euiScreenReaderOnly } from '@elastic/eui';
|
||||
import { ShardFailureDescription } from './shard_failure_description';
|
||||
import { ShardFailure } from './shard_failure_types';
|
||||
import { getFailureSummaryText } from './shard_failure_description_header';
|
||||
|
||||
export interface ListItem extends ShardFailure {
|
||||
id: string;
|
||||
}
|
||||
|
||||
const SORTING: EuiInMemoryTableProps<ListItem>['sorting'] = {
|
||||
sort: {
|
||||
field: 'index',
|
||||
direction: 'desc',
|
||||
},
|
||||
};
|
||||
|
||||
export function ShardFailureTable({ failures }: { failures: ShardFailure[] }) {
|
||||
const itemList = failures.map((failure, idx) => ({ ...{ id: String(idx) }, ...failure }));
|
||||
const initalMap = {} as Record<string, ReactElement>;
|
||||
|
||||
const [expandMap, setExpandMap] = useState(initalMap);
|
||||
|
||||
const columns = [
|
||||
{
|
||||
align: RIGHT_ALIGNMENT,
|
||||
width: '40px',
|
||||
isExpander: true,
|
||||
render: (item: ListItem) => {
|
||||
const failureSummeryText = getFailureSummaryText(item);
|
||||
const collapseLabel = i18n.translate(
|
||||
'data.search.searchSource.fetch.shardsFailedModal.tableRowCollapse',
|
||||
{
|
||||
defaultMessage: 'Collapse {rowDescription}',
|
||||
description: 'Collapse a row of a table with failures',
|
||||
values: { rowDescription: failureSummeryText },
|
||||
}
|
||||
);
|
||||
|
||||
const expandLabel = i18n.translate(
|
||||
'data.search.searchSource.fetch.shardsFailedModal.tableRowExpand',
|
||||
{
|
||||
defaultMessage: 'Expand {rowDescription}',
|
||||
description: 'Expand a row of a table with failures',
|
||||
values: { rowDescription: failureSummeryText },
|
||||
}
|
||||
);
|
||||
|
||||
return (
|
||||
<EuiButtonIcon
|
||||
onClick={() => {
|
||||
// toggle displaying the expanded view of the given list item
|
||||
const map = Object.assign({}, expandMap);
|
||||
if (map[item.id]) {
|
||||
delete map[item.id];
|
||||
} else {
|
||||
map[item.id] = <ShardFailureDescription {...item} />;
|
||||
}
|
||||
setExpandMap(map);
|
||||
}}
|
||||
aria-label={expandMap[item.id] ? collapseLabel : expandLabel}
|
||||
iconType={expandMap[item.id] ? 'arrowUp' : 'arrowDown'}
|
||||
/>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'shard',
|
||||
name: i18n.translate('data.search.searchSource.fetch.shardsFailedModal.tableColShard', {
|
||||
defaultMessage: 'Shard',
|
||||
}),
|
||||
sortable: true,
|
||||
truncateText: true,
|
||||
width: '80px',
|
||||
},
|
||||
{
|
||||
field: 'index',
|
||||
name: i18n.translate('data.search.searchSource.fetch.shardsFailedModal.tableColIndex', {
|
||||
defaultMessage: 'Index',
|
||||
}),
|
||||
sortable: true,
|
||||
truncateText: true,
|
||||
},
|
||||
{
|
||||
field: 'node',
|
||||
name: i18n.translate('data.search.searchSource.fetch.shardsFailedModal.tableColNode', {
|
||||
defaultMessage: 'Node',
|
||||
}),
|
||||
sortable: true,
|
||||
truncateText: true,
|
||||
},
|
||||
{
|
||||
field: 'reason.type',
|
||||
name: i18n.translate('data.search.searchSource.fetch.shardsFailedModal.tableColReason', {
|
||||
defaultMessage: 'Reason',
|
||||
}),
|
||||
truncateText: true,
|
||||
render: (item: ListItem) => {
|
||||
return <ShardFailureDescription {...item} />;
|
||||
},
|
||||
mobileOptions: {
|
||||
header: false,
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
|
@ -108,14 +46,16 @@ export function ShardFailureTable({ failures }: { failures: ShardFailure[] }) {
|
|||
itemId="id"
|
||||
items={itemList}
|
||||
columns={columns}
|
||||
pagination={true}
|
||||
sorting={{
|
||||
sort: {
|
||||
field: 'index',
|
||||
direction: 'desc',
|
||||
},
|
||||
}}
|
||||
itemIdToExpandedRowMap={expandMap}
|
||||
pagination={itemList.length > 10}
|
||||
sorting={SORTING}
|
||||
css={css`
|
||||
& .euiTableHeaderCell {
|
||||
${euiScreenReaderOnly()}
|
||||
}
|
||||
& .euiTableRowCell {
|
||||
border-top: none;
|
||||
}
|
||||
`}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1332,9 +1332,6 @@
|
|||
"data.search.aggs.rareTerms.aggTypesLabel": "Termes rares de {fieldName}",
|
||||
"data.search.es_search.queryTimeValue": "{queryTime} ms",
|
||||
"data.search.functions.geoBoundingBox.arguments.error": "Au moins un des groupes de paramètres suivants doit être fourni : {parameters}.",
|
||||
"data.search.searchSource.fetch.shardsFailedModal.failureHeader": "{failureName} à {failureDetails}",
|
||||
"data.search.searchSource.fetch.shardsFailedModal.tableRowCollapse": "Réduire {rowDescription}",
|
||||
"data.search.searchSource.fetch.shardsFailedModal.tableRowExpand": "Développer {rowDescription}",
|
||||
"data.search.searchSource.fetch.shardsFailedNotificationMessage": "Échec de {shardsFailed} des {shardsTotal} partitions",
|
||||
"data.search.searchSource.indexPatternIdDescription": "ID dans l'index {kibanaIndexPattern}.",
|
||||
"data.search.searchSource.queryTimeValue": "{queryTime} ms",
|
||||
|
@ -2089,10 +2086,7 @@
|
|||
"data.search.searchSource.fetch.shardsFailedModal.tabHeaderRequest": "Requête",
|
||||
"data.search.searchSource.fetch.shardsFailedModal.tabHeaderResponse": "Réponse",
|
||||
"data.search.searchSource.fetch.shardsFailedModal.tabHeaderShardFailures": "Échecs de partition",
|
||||
"data.search.searchSource.fetch.shardsFailedModal.tableColIndex": "Index",
|
||||
"data.search.searchSource.fetch.shardsFailedModal.tableColNode": "Nœud",
|
||||
"data.search.searchSource.fetch.shardsFailedModal.tableColReason": "Raison",
|
||||
"data.search.searchSource.fetch.shardsFailedModal.tableColShard": "Partition",
|
||||
"data.search.searchSource.fetch.shardsFailedNotificationDescription": "Les données peuvent être incomplètes ou erronées.",
|
||||
"data.search.searchSource.hitsDescription": "Le nombre de documents renvoyés par la requête.",
|
||||
"data.search.searchSource.hitsLabel": "Résultats",
|
||||
|
|
|
@ -1346,9 +1346,6 @@
|
|||
"data.search.aggs.rareTerms.aggTypesLabel": "{fieldName}の希少な用語",
|
||||
"data.search.es_search.queryTimeValue": "{queryTime}ms",
|
||||
"data.search.functions.geoBoundingBox.arguments.error": "次のパラメーターのグループの1つ以上を指定する必要があります:{parameters}。",
|
||||
"data.search.searchSource.fetch.shardsFailedModal.failureHeader": "{failureDetails}の{failureName}",
|
||||
"data.search.searchSource.fetch.shardsFailedModal.tableRowCollapse": "{rowDescription}を折りたたむ",
|
||||
"data.search.searchSource.fetch.shardsFailedModal.tableRowExpand": "{rowDescription}を展開",
|
||||
"data.search.searchSource.fetch.shardsFailedNotificationMessage": "{shardsTotal}件中{shardsFailed}件のシャードでエラーが発生しました",
|
||||
"data.search.searchSource.indexPatternIdDescription": "{kibanaIndexPattern}インデックス内のIDです。",
|
||||
"data.search.searchSource.queryTimeValue": "{queryTime}ms",
|
||||
|
@ -2103,10 +2100,7 @@
|
|||
"data.search.searchSource.fetch.shardsFailedModal.tabHeaderRequest": "リクエスト",
|
||||
"data.search.searchSource.fetch.shardsFailedModal.tabHeaderResponse": "応答",
|
||||
"data.search.searchSource.fetch.shardsFailedModal.tabHeaderShardFailures": "シャードエラー",
|
||||
"data.search.searchSource.fetch.shardsFailedModal.tableColIndex": "インデックス",
|
||||
"data.search.searchSource.fetch.shardsFailedModal.tableColNode": "ノード",
|
||||
"data.search.searchSource.fetch.shardsFailedModal.tableColReason": "理由",
|
||||
"data.search.searchSource.fetch.shardsFailedModal.tableColShard": "シャード",
|
||||
"data.search.searchSource.fetch.shardsFailedNotificationDescription": "データが不完全か誤りの可能性があります。",
|
||||
"data.search.searchSource.hitsDescription": "クエリにより返されたドキュメントの数です。",
|
||||
"data.search.searchSource.hitsLabel": "ヒット数",
|
||||
|
|
|
@ -1346,9 +1346,6 @@
|
|||
"data.search.aggs.rareTerms.aggTypesLabel": "{fieldName} 的稀有词",
|
||||
"data.search.es_search.queryTimeValue": "{queryTime}ms",
|
||||
"data.search.functions.geoBoundingBox.arguments.error": "必须至少提供一个以下参数组:{parameters}。",
|
||||
"data.search.searchSource.fetch.shardsFailedModal.failureHeader": "{failureName}于{failureDetails}",
|
||||
"data.search.searchSource.fetch.shardsFailedModal.tableRowCollapse": "折叠 {rowDescription}",
|
||||
"data.search.searchSource.fetch.shardsFailedModal.tableRowExpand": "展开 {rowDescription}",
|
||||
"data.search.searchSource.fetch.shardsFailedNotificationMessage": "{shardsTotal} 个分片有 {shardsFailed} 个失败",
|
||||
"data.search.searchSource.indexPatternIdDescription": "{kibanaIndexPattern} 索引中的 ID。",
|
||||
"data.search.searchSource.queryTimeValue": "{queryTime}ms",
|
||||
|
@ -2103,10 +2100,7 @@
|
|||
"data.search.searchSource.fetch.shardsFailedModal.tabHeaderRequest": "请求",
|
||||
"data.search.searchSource.fetch.shardsFailedModal.tabHeaderResponse": "响应",
|
||||
"data.search.searchSource.fetch.shardsFailedModal.tabHeaderShardFailures": "分片错误",
|
||||
"data.search.searchSource.fetch.shardsFailedModal.tableColIndex": "索引",
|
||||
"data.search.searchSource.fetch.shardsFailedModal.tableColNode": "节点",
|
||||
"data.search.searchSource.fetch.shardsFailedModal.tableColReason": "原因",
|
||||
"data.search.searchSource.fetch.shardsFailedModal.tableColShard": "分片",
|
||||
"data.search.searchSource.fetch.shardsFailedNotificationDescription": "数据可能不完整或有错误。",
|
||||
"data.search.searchSource.hitsDescription": "查询返回的文档数目。",
|
||||
"data.search.searchSource.hitsLabel": "命中数",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue