@kbn/search-errors package (#171563)

Part of https://github.com/elastic/kibana/issues/171570

PR breaks EsError out of data plugin and into @kbn/search-errors
package. This will allow for future efforts to move [lens error
handing](https://github.com/elastic/kibana/blob/main/x-pack/plugins/lens/public/editor_frame_service/error_helper.tsx)
into this package and more closely align error handling across kibana.

An unplanned part of this PR was moving `BfetchRequestError` into its
own package `@kbn/bfetch`. This is required because `@kbn/search-errors`
package can not import code from a plugin. `BfetchRequestError` could
not be part of `@kbn/search-errors` because that created a circular
dependency graph.

Another unexpected problem found while working on this PR is that the
package had to be included in `ui-shared-deps`. The reason for this is
that `renderSearchError` uses `instanceof EsError` check to determine if
an error is an EsError. This check failed when the package was not
included in `ui-shared-deps` because each plugin got its own copy of
`kbn/search-error` plugin. This meant that `data` plugin had its own
copy of `EsError` class when the error is generated, then `discover`
plugin had its own copy of `EsError` class when the instanceof check
occurs. `instanceof` check unexpectedly returned false in this case.
Moving plugin to `ui-shared-deps` results in a single instance of the
plugin. Thanks @mistic for the help with moving package into
`ui-shared-deps`

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
Co-authored-by: Tiago Costa <tiago.costa@elastic.co>
Co-authored-by: Davis McPhee <davismcphee@hotmail.com>
This commit is contained in:
Nathan Reese 2023-12-07 10:39:19 -07:00 committed by GitHub
parent 12dccd3421
commit bb84e24637
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
66 changed files with 477 additions and 180 deletions

2
.github/CODEOWNERS vendored
View file

@ -56,6 +56,7 @@ packages/kbn-babel-register @elastic/kibana-operations
packages/kbn-babel-transform @elastic/kibana-operations
x-pack/plugins/banners @elastic/appex-sharedux
packages/kbn-bazel-runner @elastic/kibana-operations
packages/kbn-bfetch-error @elastic/appex-sharedux
examples/bfetch_explorer @elastic/appex-sharedux
src/plugins/bfetch @elastic/appex-sharedux
packages/kbn-calculate-auto @elastic/obs-ux-management-team
@ -650,6 +651,7 @@ x-pack/examples/screenshotting_example @elastic/appex-sharedux
x-pack/plugins/screenshotting @elastic/kibana-reporting-services
packages/kbn-search-api-panels @elastic/enterprise-search-frontend
packages/kbn-search-connectors @elastic/enterprise-search-frontend
packages/kbn-search-errors @elastic/kibana-data-discovery
examples/search_examples @elastic/kibana-data-discovery
packages/kbn-search-index-documents @elastic/enterprise-search-frontend
packages/kbn-search-response-warnings @elastic/kibana-data-discovery

View file

@ -9,6 +9,7 @@
"apmOss": "src/plugins/apm_oss",
"autocomplete": "packages/kbn-securitysolution-autocomplete/src",
"bfetch": "src/plugins/bfetch",
"bfetchError": "packages/kbn-bfetch-error",
"cases": ["packages/kbn-cases-components"],
"cellActions": "packages/kbn-cell-actions",
"charts": "src/plugins/charts",
@ -102,6 +103,7 @@
"share": "src/plugins/share",
"sharedUXPackages": "packages/shared-ux",
"searchApiPanels": "packages/kbn-search-api-panels/",
"searchErrors": "packages/kbn-search-errors",
"searchIndexDocuments": "packages/kbn-search-index-documents",
"searchResponseWarnings": "packages/kbn-search-response-warnings",
"securitySolutionPackages": "x-pack/packages/security-solution",

View file

@ -168,6 +168,7 @@
"@kbn/assetManager-plugin": "link:x-pack/plugins/asset_manager",
"@kbn/audit-log-plugin": "link:x-pack/test/security_api_integration/plugins/audit_log",
"@kbn/banners-plugin": "link:x-pack/plugins/banners",
"@kbn/bfetch-error": "link:packages/kbn-bfetch-error",
"@kbn/bfetch-explorer-plugin": "link:examples/bfetch_explorer",
"@kbn/bfetch-plugin": "link:src/plugins/bfetch",
"@kbn/calculate-auto": "link:packages/kbn-calculate-auto",
@ -653,6 +654,7 @@
"@kbn/screenshotting-plugin": "link:x-pack/plugins/screenshotting",
"@kbn/search-api-panels": "link:packages/kbn-search-api-panels",
"@kbn/search-connectors": "link:packages/kbn-search-connectors",
"@kbn/search-errors": "link:packages/kbn-search-errors",
"@kbn/search-examples-plugin": "link:examples/search_examples",
"@kbn/search-index-documents": "link:packages/kbn-search-index-documents",
"@kbn/search-response-warnings": "link:packages/kbn-search-response-warnings",

View file

@ -0,0 +1,35 @@
load("@build_bazel_rules_nodejs//:index.bzl", "js_library")
SRCS = glob(
[
"**/*.ts",
"**/*.tsx",
],
exclude = [
"**/test_helpers.ts",
"**/*.config.js",
"**/*.mock.*",
"**/*.test.*",
"**/*.stories.*",
"**/__snapshots__/**",
"**/integration_tests/**",
"**/mocks/**",
"**/scripts/**",
"**/storybook/**",
"**/test_fixtures/**",
"**/test_helpers/**",
],
)
BUNDLER_DEPS = [
"//packages/kbn-i18n",
"@npm//tslib",
]
js_library(
name = "kbn-bfetch-error",
package_name = "@kbn/bfetch-error",
srcs = ["package.json"] + SRCS,
deps = BUNDLER_DEPS,
visibility = ["//visibility:public"],
)

View file

@ -0,0 +1,3 @@
# @kbn/bfetch-error
package isolating befetch error logic

View file

@ -6,9 +6,4 @@
* Side Public License, v 1.
*/
export * from './es_error';
export * from './painless_error';
export * from './timeout_error';
export * from './utils';
export * from './types';
export * from './search_session_incomplete_warning';
export { BfetchRequestError } from './src/bfetch_error';

View file

@ -0,0 +1,13 @@
/*
* 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.
*/
module.exports = {
preset: '@kbn/test',
rootDir: '../..',
roots: ['<rootDir>/packages/kbn-bfetch-error'],
};

View file

@ -0,0 +1,5 @@
{
"type": "shared-common",
"id": "@kbn/bfetch-error",
"owner": "@elastic/appex-sharedux"
}

View file

@ -0,0 +1,6 @@
{
"name": "@kbn/bfetch-error",
"private": true,
"version": "1.0.0",
"license": "SSPL-1.0 OR Elastic License 2.0"
}

View file

@ -20,10 +20,10 @@ export class BfetchRequestError extends Error {
constructor(code: number) {
const message =
code === 0
? i18n.translate('bfetch.networkError', {
? i18n.translate('bfetchError.networkError', {
defaultMessage: 'Check your network connection and try again.',
})
: i18n.translate('bfetch.networkErrorWithStatus', {
: i18n.translate('bfetchError.networkErrorWithStatus', {
defaultMessage: 'Check your network connection and try again. Code {code}',
values: { code },
});

View file

@ -0,0 +1,21 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"outDir": "target/types",
"types": [
"jest",
"node",
"react"
]
},
"include": [
"**/*.ts",
"**/*.tsx",
],
"exclude": [
"target/**/*"
],
"kbn_references": [
"@kbn/i18n",
]
}

View file

@ -0,0 +1,39 @@
load("@build_bazel_rules_nodejs//:index.bzl", "js_library")
SRCS = glob(
[
"**/*.ts",
"**/*.tsx",
],
exclude = [
"**/test_helpers.ts",
"**/*.config.js",
"**/*.mock.*",
"**/*.test.*",
"**/*.stories.*",
"**/__snapshots__/**",
"**/integration_tests/**",
"**/mocks/**",
"**/scripts/**",
"**/storybook/**",
"**/test_fixtures/**",
"**/test_helpers/**",
],
)
BUNDLER_DEPS = [
"//packages/kbn-bfetch-error",
"//packages/kbn-i18n",
"@npm//@elastic/elasticsearch",
"@npm//@elastic/eui",
"@npm//react",
"@npm//tslib",
]
js_library(
name = "kbn-search-errors",
package_name = "@kbn/search-errors",
srcs = ["package.json"] + SRCS,
deps = BUNDLER_DEPS,
visibility = ["//visibility:public"],
)

View file

@ -0,0 +1,3 @@
# @kbn/search-errors
Package isolating elasticsearch search error logic

View file

@ -0,0 +1,12 @@
/*
* 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.
*/
export { isEsError, EsError } from './src/es_error';
export { isPainlessError, PainlessError } from './src/painless_error';
export { renderSearchError } from './src/render_search_error';
export type { IEsError } from './src/types';

View file

@ -0,0 +1,13 @@
/*
* 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.
*/
module.exports = {
preset: '@kbn/test',
rootDir: '../..',
roots: ['<rootDir>/packages/kbn-search-errors'],
};

View file

@ -0,0 +1,5 @@
{
"type": "shared-common",
"id": "@kbn/search-errors",
"owner": "@elastic/kibana-data-discovery"
}

View file

@ -0,0 +1,6 @@
{
"name": "@kbn/search-errors",
"private": true,
"version": "1.0.0",
"license": "SSPL-1.0 OR Elastic License 2.0"
}

View file

@ -9,22 +9,32 @@
import React from 'react';
import { EuiButton, EuiCodeBlock, EuiSpacer } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { ApplicationStart } from '@kbn/core/public';
import { KbnError } from '@kbn/kibana-utils-plugin/common';
import type { ApplicationStart } from '@kbn/core/public';
import { IEsError } from './types';
import { getRootCause } from './utils';
export class EsError extends KbnError {
/**
* Checks if a given errors originated from Elasticsearch.
* Those params are assigned to the attributes property of an error.
*
* @param e
*/
export function isEsError(e: any): e is IEsError {
return !!e.attributes;
}
export class EsError extends Error {
readonly attributes: IEsError['attributes'];
constructor(protected readonly err: IEsError, private readonly openInInspector: () => void) {
super(
`EsError: ${
getRootCause(err?.attributes?.error)?.reason ||
i18n.translate('data.esError.unknownRootCause', { defaultMessage: 'unknown' })
i18n.translate('searchErrors.esError.unknownRootCause', { defaultMessage: 'unknown' })
}`
);
this.attributes = err.attributes;
Object.setPrototypeOf(this, new.target.prototype);
}
public getErrorMessage() {
@ -48,8 +58,14 @@ export class EsError extends KbnError {
public getActions(application: ApplicationStart) {
return [
<EuiButton key="viewRequestDetails" color="primary" onClick={this.openInInspector} size="s">
{i18n.translate('data.esError.viewDetailsButtonLabel', {
<EuiButton
data-test-subj="viewEsErrorButton"
key="viewRequestDetails"
color="primary"
onClick={this.openInInspector}
size="s"
>
{i18n.translate('searchErrors.esError.viewDetailsButtonLabel', {
defaultMessage: 'View details',
})}
</EuiButton>,

View file

@ -12,7 +12,53 @@ const startMock = coreMock.createStart();
import { mount } from 'enzyme';
import { PainlessError } from './painless_error';
import { findTestSubject } from '@elastic/eui/lib/test';
import * as searchPhaseException from '../../../common/search/test_data/search_phase_execution_exception.json';
const searchPhaseException = {
error: {
root_cause: [
{
type: 'script_exception',
reason: 'compile error',
script_stack: ['invalid', '^---- HERE'],
script: 'invalid',
lang: 'painless',
position: {
offset: 0,
start: 0,
end: 7,
},
},
],
type: 'search_phase_execution_exception',
reason: 'all shards failed',
phase: 'query',
grouped: true,
failed_shards: [
{
shard: 0,
index: '.kibana_11',
node: 'b3HX8C96Q7q1zgfVLxEsPA',
reason: {
type: 'script_exception',
reason: 'compile error',
script_stack: ['invalid', '^---- HERE'],
script: 'invalid',
lang: 'painless',
position: {
offset: 0,
start: 0,
end: 7,
},
caused_by: {
type: 'illegal_argument_exception',
reason: 'cannot resolve symbol [invalid]',
},
},
},
],
},
status: 400,
};
describe('PainlessError', () => {
beforeEach(() => {

View file

@ -9,10 +9,10 @@
import React from 'react';
import { i18n } from '@kbn/i18n';
import { EuiButtonEmpty, EuiSpacer, EuiText, EuiCodeBlock } from '@elastic/eui';
import { ApplicationStart } from '@kbn/core/public';
import type { ApplicationStart } from '@kbn/core/public';
import type { DataView } from '@kbn/data-views-plugin/common';
import { IEsError, isEsError } from './types';
import { EsError } from './es_error';
import type { IEsError } from './types';
import { EsError, isEsError } from './es_error';
import { getRootCause } from './utils';
export class PainlessError extends EsError {
@ -37,7 +37,7 @@ export class PainlessError extends EsError {
return (
<>
<EuiText size="s" data-test-subj="painlessScript">
{i18n.translate('data.painlessError.painlessScriptedFieldErrorMessage', {
{i18n.translate('searchErrors.painlessError.painlessScriptedFieldErrorMessage', {
defaultMessage:
'Error executing runtime field or scripted field on index pattern {indexPatternName}',
values: {
@ -73,7 +73,7 @@ export class PainlessError extends EsError {
onClick={() => onClick(this?.indexPattern?.id)}
size="s"
>
{i18n.translate('data.painlessError.buttonTxt', {
{i18n.translate('searchErrors.painlessError.buttonTxt', {
defaultMessage: 'Edit script',
})}
</EuiButtonEmpty>

View file

@ -6,19 +6,13 @@
* Side Public License, v 1.
*/
import stringify from 'json-stable-stringify';
import { Sha256 } from '@kbn/crypto-browser';
import { i18n } from '@kbn/i18n';
import { ReactNode } from 'react';
import { BfetchRequestError } from '@kbn/bfetch-plugin/public';
import { ApplicationStart } from '@kbn/core-application-browser';
import { EsError } from '../errors';
import { BfetchRequestError } from '@kbn/bfetch-error';
import type { ApplicationStart } from '@kbn/core-application-browser';
import { EsError } from './es_error';
export async function createRequestHash(keys: Record<string, any>) {
return new Sha256().update(stringify(keys), 'utf8').digest('hex');
}
export function getSearchErrorOverrideDisplay({
export function renderSearchError({
error,
application,
}: {
@ -27,7 +21,7 @@ export function getSearchErrorOverrideDisplay({
}): { title: string; body: ReactNode; actions?: ReactNode[] } | undefined {
if (error instanceof EsError) {
return {
title: i18n.translate('data.search.esErrorTitle', {
title: i18n.translate('searchErrors.search.esErrorTitle', {
defaultMessage: 'Cannot retrieve search results',
}),
body: error.getErrorMessage(),
@ -36,12 +30,12 @@ export function getSearchErrorOverrideDisplay({
}
if (error.constructor.name === 'HttpFetchError' || error instanceof BfetchRequestError) {
const defaultMsg = i18n.translate('data.errors.fetchError', {
const defaultMsg = i18n.translate('searchErrors.errors.fetchError', {
defaultMessage: 'Check your network connection and try again.',
});
return {
title: i18n.translate('data.search.httpErrorTitle', {
title: i18n.translate('searchErrors.search.httpErrorTitle', {
defaultMessage: 'Unable to connect to the Kibana server',
}),
body: error.message || defaultMsg,

View file

@ -0,0 +1,24 @@
/*
* 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 { estypes } from '@elastic/elasticsearch';
import type { ConnectionRequestParams } from '@elastic/transport';
import type { KibanaServerError } from '@kbn/kibana-utils-plugin/common';
type SanitizedConnectionRequestParams = Pick<
ConnectionRequestParams,
'method' | 'path' | 'querystring'
>;
interface IEsErrorAttributes {
error?: estypes.ErrorCause;
rawResponse?: estypes.SearchResponseBody;
requestParams?: SanitizedConnectionRequestParams;
}
export type IEsError = KibanaServerError<IEsErrorAttributes>;

View file

@ -0,0 +1,26 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"outDir": "target/types",
"types": [
"jest",
"node",
"react"
]
},
"include": [
"**/*.ts",
"**/*.tsx",
],
"exclude": [
"target/**/*"
],
"kbn_references": [
"@kbn/i18n",
"@kbn/core",
"@kbn/kibana-utils-plugin",
"@kbn/data-views-plugin",
"@kbn/core-application-browser",
"@kbn/bfetch-error",
]
}

View file

@ -28,6 +28,7 @@ webpack_cli(
"//packages/kbn-datemath",
"//packages/kbn-analytics",
"//packages/kbn-es-query",
"//packages/kbn-search-errors",
"//packages/kbn-std",
"//packages/kbn-safer-lodash-set",
"//packages/kbn-peggy",

View file

@ -89,6 +89,7 @@ const externals = {
uuid: '__kbnSharedDeps__.Uuid',
'@kbn/analytics': '__kbnSharedDeps__.KbnAnalytics',
'@kbn/es-query': '__kbnSharedDeps__.KbnEsQuery',
'@kbn/search-errors': '__kbnSharedDeps__.KbnSearchErrors',
'@kbn/std': '__kbnSharedDeps__.KbnStd',
'@kbn/safer-lodash-set': '__kbnSharedDeps__.SaferLodashSet',
'@kbn/shared-ux-error-boundary': '__kbnSharedDeps__.KbnSharedUxErrorBoundary',

View file

@ -64,6 +64,7 @@ export const TsLib = require('tslib');
export const Uuid = require('uuid');
export const KbnAnalytics = require('@kbn/analytics');
export const KbnEsQuery = require('@kbn/es-query');
export const KbnSearchErrors = require('@kbn/search-errors');
export const KbnStd = require('@kbn/std');
export const SaferLodashSet = require('@kbn/safer-lodash-set');

View file

@ -11,22 +11,11 @@
"**/*.js",
],
"exclude": [
"src/entry.js",
"**/*.config.js",
"target/**/*",
],
"kbn_references": [
"@kbn/ui-theme",
"@kbn/i18n",
"@kbn/i18n-react",
"@kbn/monaco",
"@kbn/datemath",
"@kbn/flot-charts",
"@kbn/analytics",
"@kbn/es-query",
"@kbn/rison",
"@kbn/std",
"@kbn/safer-lodash-set",
"@kbn/repo-info",
"@kbn/shared-ux-error-boundary"
]
}

View file

@ -16,4 +16,3 @@ export {
DISABLE_BFETCH,
BFETCH_ROUTE_VERSION_LATEST,
} from './constants';
export { BfetchRequestError } from './bfetch_error';

View file

@ -6,8 +6,8 @@
* Side Public License, v 1.
*/
import { BfetchRequestError } from '@kbn/bfetch-error';
import { ErrorLike } from '../batch';
import { BfetchRequestError } from '..';
export const normalizeError = <E extends ErrorLike = ErrorLike>(err: any): E => {
if (!err) {

View file

@ -15,7 +15,6 @@ export { split } from './streaming';
export type { BatchedFunc } from './batching/types';
export { DISABLE_BFETCH } from '../common/constants';
export { BfetchRequestError } from '../common/bfetch_error';
export function plugin(initializerContext: PluginInitializerContext) {
return new BfetchPublicPlugin(initializerContext);

View file

@ -7,7 +7,7 @@
*/
import { Observable, Subject } from 'rxjs';
import { BfetchRequestError } from '../../common';
import { BfetchRequestError } from '@kbn/bfetch-error';
/**
* Creates observable from streaming XMLHttpRequest, where each event

View file

@ -11,6 +11,7 @@
"@kbn/config-schema",
"@kbn/std",
"@kbn/core-http-common",
"@kbn/bfetch-error",
],
"exclude": [
"target/**/*",

View file

@ -165,8 +165,6 @@ export type {
SearchRequest,
SearchSourceFields,
SerializedSearchSourceFields,
// errors
IEsError,
WaitUntilNextSessionCompletesOptions,
} from './search';
@ -178,8 +176,6 @@ export {
noSearchSessionStorageCapabilityMessage,
SEARCH_SESSIONS_MANAGEMENT_ID,
waitUntilNextSessionCompletes$,
isEsError,
getSearchErrorOverrideDisplay,
SearchSource,
SearchSessionState,
SortDirection,

View file

@ -1,22 +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 { KibanaServerError } from '@kbn/kibana-utils-plugin/common';
import { IEsErrorAttributes } from '../../../common';
export type IEsError = KibanaServerError<IEsErrorAttributes>;
/**
* Checks if a given errors originated from Elasticsearch.
* Those params are assigned to the attributes property of an error.
*
* @param e
*/
export function isEsError(e: any): e is IEsError {
return !!e.attributes;
}

View file

@ -56,7 +56,5 @@ export { getEsPreference } from './es_search';
export type { SearchInterceptorDeps } from './search_interceptor';
export { SearchInterceptor } from './search_interceptor';
export { getSearchErrorOverrideDisplay } from './search_interceptor/utils';
export * from './errors';
export { SearchService } from './search_service';

View file

@ -0,0 +1,14 @@
/*
* 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 { Sha256 } from '@kbn/crypto-browser';
import stringify from 'json-stable-stringify';
export async function createRequestHash(keys: Record<string, any>) {
return new Sha256().update(stringify(keys), 'utf8').digest('hex');
}

View file

@ -12,7 +12,7 @@ import { coreMock, themeServiceMock } from '@kbn/core/public/mocks';
import { IEsSearchRequest } from '../../../common/search';
import { SearchInterceptor } from './search_interceptor';
import { AbortError } from '@kbn/kibana-utils-plugin/public';
import { SearchTimeoutError, PainlessError, TimeoutErrorMode, EsError } from '../errors';
import { PainlessError, EsError, type IEsError } from '@kbn/search-errors';
import { ISessionService, SearchSessionState } from '..';
import { bfetchPluginMock } from '@kbn/bfetch-plugin/public/mocks';
import { BfetchPublicSetup } from '@kbn/bfetch-plugin/public';
@ -22,12 +22,12 @@ import * as resourceNotFoundException from '../../../common/search/test_data/res
import { BehaviorSubject } from 'rxjs';
import { dataPluginMock } from '../../mocks';
import { UI_SETTINGS } from '../../../common';
import type { IEsError } from '../errors';
import type { SearchServiceStartDependencies } from '../search_service';
import type { Start as InspectorStart } from '@kbn/inspector-plugin/public';
import { SearchTimeoutError, TimeoutErrorMode } from './timeout_error';
jest.mock('./utils', () => {
const originalModule = jest.requireActual('./utils');
jest.mock('./create_request_hash', () => {
const originalModule = jest.requireActual('./create_request_hash');
return {
...originalModule,
createRequestHash: jest.fn().mockImplementation((input) => {
@ -36,11 +36,11 @@ jest.mock('./utils', () => {
};
});
jest.mock('../errors/search_session_incomplete_warning', () => ({
jest.mock('./search_session_incomplete_warning', () => ({
SearchSessionIncompleteWarning: jest.fn(),
}));
import { SearchSessionIncompleteWarning } from '../errors/search_session_incomplete_warning';
import { SearchSessionIncompleteWarning } from './search_session_incomplete_warning';
import { getMockSearchConfig } from '../../../config.mock';
let searchInterceptor: SearchInterceptor;

View file

@ -34,7 +34,6 @@ import { estypes } from '@elastic/elasticsearch';
import { i18n } from '@kbn/i18n';
import { PublicMethodsOf } from '@kbn/utility-types';
import type { HttpSetup, IHttpFetchError } from '@kbn/core-http-browser';
import { BfetchRequestError } from '@kbn/bfetch-plugin/public';
import { type Start as InspectorStart, RequestAdapter } from '@kbn/inspector-plugin/public';
import {
@ -50,6 +49,14 @@ import {
import { BatchedFunc, BfetchPublicSetup, DISABLE_BFETCH } from '@kbn/bfetch-plugin/public';
import { toMountPoint } from '@kbn/kibana-react-plugin/public';
import { AbortError, KibanaServerError } from '@kbn/kibana-utils-plugin/public';
import { BfetchRequestError } from '@kbn/bfetch-error';
import {
EsError,
isEsError,
isPainlessError,
PainlessError,
renderSearchError,
} from '@kbn/search-errors';
import {
ENHANCED_ES_SEARCH_STRATEGY,
IAsyncSearchOptions,
@ -63,21 +70,14 @@ import {
type SanitizedConnectionRequestParams,
} from '../../../common';
import { SearchUsageCollector } from '../collectors';
import {
EsError,
isEsError,
isPainlessError,
PainlessError,
SearchTimeoutError,
TimeoutErrorMode,
SearchSessionIncompleteWarning,
} from '../errors';
import { SearchTimeoutError, TimeoutErrorMode } from './timeout_error';
import { SearchSessionIncompleteWarning } from './search_session_incomplete_warning';
import { ISessionService, SearchSessionState } from '../session';
import { SearchResponseCache } from './search_response_cache';
import { createRequestHash, getSearchErrorOverrideDisplay } from './utils';
import { SearchAbortController } from './search_abort_controller';
import { SearchConfigSchema } from '../../../config';
import type { SearchServiceStartDependencies } from '../search_service';
import { createRequestHash } from './create_request_hash';
export interface SearchInterceptorDeps {
bfetch: BfetchPublicSetup;
@ -585,15 +585,15 @@ export class SearchInterceptor {
return;
}
const overrideDisplay = getSearchErrorOverrideDisplay({
const searchErrorDisplay = renderSearchError({
error: e,
application: this.application,
});
if (overrideDisplay) {
if (searchErrorDisplay) {
this.deps.toasts.addDanger({
title: overrideDisplay.title,
text: toMountPoint(overrideDisplay.body, { theme$: this.deps.theme.theme$ }),
title: searchErrorDisplay.title,
text: toMountPoint(searchErrorDisplay.body, { theme$: this.deps.theme.theme$ }),
});
} else {
this.deps.toasts.addError(e, {

View file

@ -43,13 +43,14 @@
"@kbn/crypto-browser",
"@kbn/config",
"@kbn/config-schema",
"@kbn/core-application-browser",
"@kbn/core-saved-objects-server",
"@kbn/core-saved-objects-utils-server",
"@kbn/data-service",
"@kbn/react-kibana-context-render",
"@kbn/search-errors",
"@kbn/search-response-warnings",
"@kbn/shared-ux-link-redirect-app"
"@kbn/shared-ux-link-redirect-app",
"@kbn/bfetch-error"
],
"exclude": [
"target/**/*",

View file

@ -14,13 +14,13 @@ import React, { ReactNode } from 'react';
import { discoverServiceMock } from '../../__mocks__/services';
import { ErrorCallout } from './error_callout';
const mockGetSearchErrorOverrideDisplay = jest.fn();
const mockRenderSearchError = jest.fn();
jest.mock('@kbn/data-plugin/public', () => {
const originalModule = jest.requireActual('@kbn/data-plugin/public');
jest.mock('@kbn/search-errors', () => {
const originalModule = jest.requireActual('@kbn/search-errors');
return {
...originalModule,
getSearchErrorOverrideDisplay: () => mockGetSearchErrorOverrideDisplay(),
renderSearchError: () => mockRenderSearchError(),
};
});
@ -31,7 +31,7 @@ describe('ErrorCallout', () => {
);
afterEach(() => {
mockGetSearchErrorOverrideDisplay.mockReset();
mockRenderSearchError.mockReset();
});
it('should render', () => {
@ -54,7 +54,7 @@ describe('ErrorCallout', () => {
const title = 'Override title';
const error = new Error('My error');
const overrideDisplay = <div>Override display</div>;
mockGetSearchErrorOverrideDisplay.mockReturnValue({ title, body: overrideDisplay });
mockRenderSearchError.mockReturnValue({ title, body: overrideDisplay });
const wrapper = mountWithServices(<ErrorCallout title="Original title" error={error} />);
const prompt = wrapper.find(EuiEmptyPrompt);
expect(prompt).toHaveLength(1);

View file

@ -8,7 +8,7 @@
import { EuiButton, EuiEmptyPrompt, useEuiTheme } from '@elastic/eui';
import { css } from '@emotion/react';
import { getSearchErrorOverrideDisplay } from '@kbn/data-plugin/public';
import { renderSearchError } from '@kbn/search-errors';
import { i18n } from '@kbn/i18n';
import React from 'react';
import { useDiscoverServices } from '../../hooks/use_discover_services';
@ -22,7 +22,7 @@ export const ErrorCallout = ({ title, error }: Props) => {
const { core } = useDiscoverServices();
const { euiTheme } = useEuiTheme();
const overrideDisplay = getSearchErrorOverrideDisplay({
const searchErrorDisplay = renderSearchError({
error,
application: core.application,
});
@ -31,15 +31,17 @@ export const ErrorCallout = ({ title, error }: Props) => {
<EuiEmptyPrompt
iconType="error"
color="danger"
title={<h2 data-test-subj="discoverErrorCalloutTitle">{overrideDisplay?.title ?? title}</h2>}
actions={overrideDisplay?.actions ?? []}
title={
<h2 data-test-subj="discoverErrorCalloutTitle">{searchErrorDisplay?.title ?? title}</h2>
}
actions={searchErrorDisplay?.actions ?? []}
body={
<div
css={css`
text-align: left;
`}
>
{overrideDisplay?.body ?? (
{searchErrorDisplay?.body ?? (
<>
<p
css={css`

View file

@ -63,6 +63,7 @@
"@kbn/core-application-browser",
"@kbn/core-saved-objects-server",
"@kbn/discover-utils",
"@kbn/search-errors",
"@kbn/search-response-warnings",
"@kbn/content-management-plugin",
"@kbn/unified-doc-viewer",

View file

@ -13,7 +13,7 @@ import { EuiButtonEmpty, EuiEmptyPrompt, EuiText } from '@elastic/eui';
import type { MaybePromise } from '@kbn/utility-types';
import { Markdown } from '@kbn/kibana-react-plugin/public';
import { getSearchErrorOverrideDisplay } from '@kbn/data-plugin/public';
import { renderSearchError } from '@kbn/search-errors';
import { ErrorLike } from '@kbn/expressions-plugin/common';
import { core } from '../kibana_services';
@ -53,12 +53,12 @@ export function EmbeddablePanelError({
[label, title]
);
const overrideDisplay = getSearchErrorOverrideDisplay({
const searchErrorDisplay = renderSearchError({
error,
application: core.application,
});
const actions = overrideDisplay?.actions ?? [];
const actions = searchErrorDisplay?.actions ?? [];
if (isEditable) {
actions.push(
<EuiButtonEmpty aria-label={ariaLabel} onClick={handleErrorClick} size="s">
@ -81,7 +81,7 @@ export function EmbeddablePanelError({
return (
<EuiEmptyPrompt
body={
overrideDisplay?.body ?? (
searchErrorDisplay?.body ?? (
<EuiText size="s">
<Markdown
markdown={error.message}

View file

@ -34,6 +34,7 @@
"@kbn/react-kibana-mount",
"@kbn/unified-search-plugin",
"@kbn/data-views-plugin",
"@kbn/search-errors",
"@kbn/panel-loader",
],
"exclude": ["target/**/*"]

View file

@ -106,6 +106,8 @@
"@kbn/banners-plugin/*": ["x-pack/plugins/banners/*"],
"@kbn/bazel-runner": ["packages/kbn-bazel-runner"],
"@kbn/bazel-runner/*": ["packages/kbn-bazel-runner/*"],
"@kbn/bfetch-error": ["packages/kbn-bfetch-error"],
"@kbn/bfetch-error/*": ["packages/kbn-bfetch-error/*"],
"@kbn/bfetch-explorer-plugin": ["examples/bfetch_explorer"],
"@kbn/bfetch-explorer-plugin/*": ["examples/bfetch_explorer/*"],
"@kbn/bfetch-plugin": ["src/plugins/bfetch"],
@ -1294,6 +1296,8 @@
"@kbn/search-api-panels/*": ["packages/kbn-search-api-panels/*"],
"@kbn/search-connectors": ["packages/kbn-search-connectors"],
"@kbn/search-connectors/*": ["packages/kbn-search-connectors/*"],
"@kbn/search-errors": ["packages/kbn-search-errors"],
"@kbn/search-errors/*": ["packages/kbn-search-errors/*"],
"@kbn/search-examples-plugin": ["examples/search_examples"],
"@kbn/search-examples-plugin/*": ["examples/search_examples/*"],
"@kbn/search-index-documents": ["packages/kbn-search-index-documents"],

View file

@ -10,7 +10,7 @@ import { isEqual, uniqWith } from 'lodash';
import { estypes } from '@elastic/elasticsearch';
import { ExpressionRenderError } from '@kbn/expressions-plugin/public';
import type { CoreStart } from '@kbn/core/public';
import { isEsError } from '@kbn/data-plugin/public';
import { isEsError } from '@kbn/search-errors';
import React from 'react';
import { EuiLink } from '@elastic/eui';
import { RemovableUserMessage } from '../types';

View file

@ -87,6 +87,7 @@
"@kbn/serverless",
"@kbn/ebt-tools",
"@kbn/chart-expressions-common",
"@kbn/search-errors",
"@kbn/search-response-warnings",
"@kbn/logging",
"@kbn/core-plugins-server",

View file

@ -8,7 +8,7 @@
/* eslint-disable max-classes-per-file */
import React, { ReactNode } from 'react';
import { getSearchErrorOverrideDisplay } from '@kbn/data-plugin/public';
import { renderSearchError } from '@kbn/search-errors';
import { getApplication } from '../../kibana_services';
import type { DataRequestDescriptor, DataRequestMeta } from '../../../common/descriptor_types';
@ -60,21 +60,21 @@ export class DataRequest {
return null;
}
const overrideDisplay = getSearchErrorOverrideDisplay({
const searchErrorDisplay = renderSearchError({
error: this._descriptor.error,
application: getApplication(),
});
const body = overrideDisplay?.body ? (
overrideDisplay.body
const body = searchErrorDisplay?.body ? (
searchErrorDisplay.body
) : (
<p>{this._descriptor.error.message}</p>
);
return overrideDisplay?.actions ? (
return searchErrorDisplay?.actions ? (
<>
{body}
{overrideDisplay.actions}
{searchErrorDisplay.actions}
</>
) : (
body

View file

@ -74,6 +74,7 @@
"@kbn/content-management-table-list-view",
"@kbn/serverless",
"@kbn/logging",
"@kbn/search-errors",
"@kbn/search-response-warnings",
"@kbn/calculate-width-from-char-count",
"@kbn/content-management-table-list-view-common",

View file

@ -6,7 +6,7 @@
*/
import { renderHook } from '@testing-library/react-hooks';
import type { IEsError } from '@kbn/data-plugin/public';
import type { IEsError } from '@kbn/search-errors';
import type { KibanaError, SecurityAppError } from '@kbn/securitysolution-t-grid';
import { useToasts } from '../lib/kibana';

View file

@ -10,8 +10,7 @@ import { isString } from 'lodash/fp';
import type { AppError } from '@kbn/securitysolution-t-grid';
import { isAppError, isKibanaError, isSecurityAppError } from '@kbn/securitysolution-t-grid';
import type { IEsError } from '@kbn/data-plugin/public';
import { isEsError } from '@kbn/data-plugin/public';
import { type IEsError, isEsError } from '@kbn/search-errors';
import type { ErrorToastOptions, ToastsStart, Toast } from '@kbn/core/public';
import { useToasts } from '../lib/kibana';

View file

@ -182,6 +182,7 @@
"@kbn/shared-ux-error-boundary",
"@kbn/zod-helpers",
"@kbn/core-http-common",
"@kbn/search-errors",
"@kbn/stack-connectors-plugin"
]
}

View file

@ -12,7 +12,7 @@ import type { AppError } from '@kbn/securitysolution-t-grid';
import { useKibana } from '@kbn/kibana-react-plugin/public';
import type { ErrorToastOptions, ToastsStart, Toast, NotificationsStart } from '@kbn/core/public';
import { IEsError, isEsError } from '@kbn/data-plugin/public';
import { IEsError, isEsError } from '@kbn/search-errors';
export type UseAppToasts = Pick<ToastsStart, 'addSuccess' | 'addWarning'> & {
api: ToastsStart;

View file

@ -34,6 +34,7 @@
"@kbn/safer-lodash-set",
"@kbn/alerts-as-data-utils",
"@kbn/logging",
"@kbn/search-errors",
],
"exclude": [
"target/**/*",

View file

@ -147,12 +147,12 @@
"autocomplete.loadingDescription": "Chargement...",
"autocomplete.seeDocumentation": "Consultez la documentation",
"autocomplete.selectField": "Veuillez d'abord sélectionner un champ...",
"bfetch.networkErrorWithStatus": "Vérifiez votre connexion réseau et réessayez. Code {code}",
"bfetch.disableBfetch": "Désactiver la mise en lots de requêtes",
"bfetch.disableBfetchCompression": "Désactiver la compression par lots",
"bfetch.disableBfetchCompressionDesc": "Vous pouvez désactiver la compression par lots. Cela permet de déboguer des requêtes individuelles, mais augmente la taille des réponses.",
"bfetch.disableBfetchDesc": "Désactive la mise en lot des requêtes. Cette option augmente le nombre de requêtes HTTP depuis Kibana, mais permet de les déboguer individuellement.",
"bfetch.networkError": "Vérifiez votre connexion réseau et réessayez.",
"bfetchError.networkError": "Vérifiez votre connexion réseau et réessayez.",
"bfetchError.networkErrorWithStatus": "Vérifiez votre connexion réseau et réessayez. Code {code}",
"cellActions.youAreInADialogContainingOptionsScreenReaderOnly": "Vous êtes dans une boîte de dialogue contenant des options pour le champ {fieldName}. Appuyez sur Tab pour naviguer entre les options. Appuyez sur Échap pour quitter.",
"cellActions.actions.copyToClipboard.displayName": "Copier dans le Presse-papiers",
"cellActions.actions.copyToClipboard.successMessage": "Copié dans le presse-papiers",
@ -1349,7 +1349,6 @@
"data.mgmt.searchSessions.status.expiresSoonInHoursTooltip": "{numHours} heures",
"data.mgmt.searchSessions.status.message.createdOn": "Expire le {expireDate}",
"data.mgmt.searchSessions.status.message.expiredOn": "Expiré le {expireDate}",
"data.painlessError.painlessScriptedFieldErrorMessage": "Erreur d'exécution du champ d'exécution ou du champ scripté sur le modèle d'indexation {indexPatternName}",
"data.parseEsInterval.invalidEsCalendarIntervalErrorMessage": "Intervalle de calendrier non valide : {interval}, la valeur doit être 1",
"data.parseEsInterval.invalidEsIntervalFormatErrorMessage": "Format d'intervalle non valide : {interval}",
"data.search.aggs.aggTypesLabel": "Plages {fieldName}",
@ -1461,8 +1460,6 @@
"data.advancedSettings.timepicker.thisWeek": "Cette semaine",
"data.advancedSettings.timepicker.timeDefaultsTitle": "Filtre temporel par défaut",
"data.advancedSettings.timepicker.today": "Aujourd'hui",
"data.errors.fetchError": "Vérifiez votre connexion réseau et réessayez.",
"data.esError.unknownRootCause": "inconnue",
"data.functions.esaggs.help": "Exécuter l'agrégation AggConfig",
"data.functions.esaggs.inspector.dataRequest.description": "Cette requête interroge Elasticsearch pour récupérer les données pour la visualisation.",
"data.functions.esaggs.inspector.dataRequest.title": "Données",
@ -1531,7 +1528,6 @@
"data.mgmt.searchSessions.table.notRestorableWarning": "La session de recherche va être de nouveau exécutée. Vous pouvez ensuite l'enregistrer pour une utilisation ultérieure.",
"data.mgmt.searchSessions.table.numSearches": "# recherches",
"data.mgmt.searchSessions.table.versionIncompatibleWarning": "Cette session de recherche a été créée dans une instance Kibana exécutant une version différente. Il se peut qu'elle ne soit pas correctement restaurée.",
"data.painlessError.buttonTxt": "Modifier le script",
"data.search.aggs.aggGroups.bucketsText": "Compartiments",
"data.search.aggs.aggGroups.metricsText": "Indicateurs",
"data.search.aggs.aggGroups.noneText": "Aucun",
@ -2048,7 +2044,6 @@
"data.search.esdsl.index.help": "Index Elasticsearch à interroger",
"data.search.esdsl.q.help": "Requête DSL",
"data.search.esdsl.size.help": "Paramètre de taille de lAPI de recherche dElasticsearch",
"data.search.esErrorTitle": "Impossible dextraire les résultats de recherche",
"data.search.esql.help": "Interroge Elasticsearch avec ES|QL.",
"data.search.esql.query.help": "Une recherche ES|QL.",
"data.search.essql.count.help": "Nombre de documents à récupérer. Pour de meilleures performances, utilisez un ensemble de données plus petit.",
@ -2141,7 +2136,6 @@
"data.search.functions.timerange.help": "Créer une plage temporelle Kibana",
"data.search.functions.timerange.mode.help": "Spécifier le mode (absolu ou relatif)",
"data.search.functions.timerange.to.help": "Spécifier la date de fin",
"data.search.httpErrorTitle": "Impossible de se connecter au serveur Kibana",
"data.search.searchSource.dataViewDescription": "La vue de données qui a été interrogée.",
"data.search.searchSource.dataViewIdLabel": "ID de vue de données",
"data.search.searchSource.dataViewLabel": "Vue de données",
@ -5204,6 +5198,12 @@
"searchApiPanels.welcomeBanner.selectClient.heading": "Choisissez-en un",
"searchApiPanels.welcomeBanner.selectClient.title": "Sélectionner votre client",
"searchApiPanels.welcomeBanner.tryInConsoleButton": "Essayer dans la console",
"searchErrors.painlessError.painlessScriptedFieldErrorMessage": "Erreur d'exécution du champ d'exécution ou du champ scripté sur le modèle d'indexation {indexPatternName}",
"searchErrors.errors.fetchError": "Vérifiez votre connexion réseau et réessayez.",
"searchErrors.esError.unknownRootCause": "inconnue",
"searchErrors.painlessError.buttonTxt": "Modifier le script",
"searchErrors.search.esErrorTitle": "Impossible dextraire les résultats de recherche",
"searchErrors.search.httpErrorTitle": "Impossible de se connecter au serveur Kibana",
"searchResponseWarnings.badgeButtonLabel": "{warningCount} {warningCount, plural, one {avertissement} many {avertissements} other {avertissements}}",
"searchResponseWarnings.noResultsTitle": "Résultat introuvable",
"securitySolutionPackages.dataTable.eventsTab.unit": "{totalCount, plural, =1 {alerte} one {alertes} many {alertes} other {alertes}}",

View file

@ -147,12 +147,12 @@
"autocomplete.loadingDescription": "読み込み中...",
"autocomplete.seeDocumentation": "ドキュメントを参照",
"autocomplete.selectField": "最初にフィールドを選択してください...",
"bfetch.networkErrorWithStatus": "ネットワーク接続を確認して再試行してください。コード{code}",
"bfetch.disableBfetch": "リクエストバッチを無効にする",
"bfetch.disableBfetchCompression": "バッチ圧縮を無効にする",
"bfetch.disableBfetchCompressionDesc": "バッチ圧縮を無効にします。個別の要求をデバッグできますが、応答サイズが大きくなります。",
"bfetch.disableBfetchDesc": "リクエストバッチを無効にします。これにより、KibanaからのHTTPリクエスト数は減りますが、個別にリクエストをデバッグできます。",
"bfetch.networkError": "ネットワーク接続を確認して再試行してください。",
"bfetchError.networkError": "ネットワーク接続を確認して再試行してください。",
"bfetchError.networkErrorWithStatus": "ネットワーク接続を確認して再試行してください。コード{code}",
"cellActions.youAreInADialogContainingOptionsScreenReaderOnly": "フィールド{fieldName}のオプションを含むダイアログを表示しています。Tabを押すと、オプションを操作します。Escapeを押すと、終了します。",
"cellActions.actions.copyToClipboard.displayName": "クリップボードにコピー",
"cellActions.actions.copyToClipboard.successMessage": "クリップボードにコピーしました",
@ -1363,7 +1363,6 @@
"data.mgmt.searchSessions.status.expiresSoonInHoursTooltip": "{numHours}時間",
"data.mgmt.searchSessions.status.message.createdOn": "{expireDate}に有効期限",
"data.mgmt.searchSessions.status.message.expiredOn": "{expireDate}に有効期限切れ",
"data.painlessError.painlessScriptedFieldErrorMessage": "インデックスパターン{indexPatternName}でのランタイムフィールドまたはスクリプトフィールドの実行エラー",
"data.parseEsInterval.invalidEsCalendarIntervalErrorMessage": "無効なカレンダー間隔:{interval}、1よりも大きな値が必要です",
"data.parseEsInterval.invalidEsIntervalFormatErrorMessage": "無効な間隔フォーマット:{interval}",
"data.search.aggs.aggTypesLabel": "{fieldName}範囲",
@ -1475,8 +1474,6 @@
"data.advancedSettings.timepicker.thisWeek": "今週",
"data.advancedSettings.timepicker.timeDefaultsTitle": "デフォルトのタイムピッカー",
"data.advancedSettings.timepicker.today": "今日",
"data.errors.fetchError": "ネットワーク接続を確認して再試行してください。",
"data.esError.unknownRootCause": "不明",
"data.functions.esaggs.help": "AggConfig 集約を実行します",
"data.functions.esaggs.inspector.dataRequest.description": "このリクエストはElasticsearchにクエリし、ビジュアライゼーション用のデータを取得します。",
"data.functions.esaggs.inspector.dataRequest.title": "データ",
@ -1545,7 +1542,6 @@
"data.mgmt.searchSessions.table.notRestorableWarning": "検索セッションはもう一度実行されます。今後使用するために保存できます。",
"data.mgmt.searchSessions.table.numSearches": "# 検索",
"data.mgmt.searchSessions.table.versionIncompatibleWarning": "この検索は別のバージョンを実行しているKibanaインスタンスで作成されました。正常に復元されない可能性があります。",
"data.painlessError.buttonTxt": "スクリプトを編集",
"data.search.aggs.aggGroups.bucketsText": "バケット",
"data.search.aggs.aggGroups.metricsText": "メトリック",
"data.search.aggs.aggGroups.noneText": "なし",
@ -2062,7 +2058,6 @@
"data.search.esdsl.index.help": "クエリするElasticsearchインデックス",
"data.search.esdsl.q.help": "クエリDSL",
"data.search.esdsl.size.help": "Elasticsearch 検索 API サイズパラメーター",
"data.search.esErrorTitle": "検索結果を取得できません",
"data.search.esql.help": "ES|QLを使用してElasticsearchを照会します。",
"data.search.esql.query.help": "ES|QLクエリ。",
"data.search.essql.count.help": "取得するドキュメント数です。パフォーマンスを向上させるには、小さなデータセットを使用します。",
@ -2155,7 +2150,6 @@
"data.search.functions.timerange.help": "Kibana timerangeを作成",
"data.search.functions.timerange.mode.help": "モードを指定(絶対または相対)",
"data.search.functions.timerange.to.help": "終了日を指定",
"data.search.httpErrorTitle": "Kibanaサーバーに接続できません",
"data.search.searchSource.dataViewDescription": "照会されたデータビュー。",
"data.search.searchSource.dataViewIdLabel": "データビューID",
"data.search.searchSource.dataViewLabel": "データビュー",
@ -5219,6 +5213,12 @@
"searchApiPanels.welcomeBanner.selectClient.heading": "1つ選択",
"searchApiPanels.welcomeBanner.selectClient.title": "クライアントを選択",
"searchApiPanels.welcomeBanner.tryInConsoleButton": "コンソールで試す",
"searchErrors.painlessError.painlessScriptedFieldErrorMessage": "インデックスパターン{indexPatternName}でのランタイムフィールドまたはスクリプトフィールドの実行エラー",
"searchErrors.errors.fetchError": "ネットワーク接続を確認して再試行してください。",
"searchErrors.esError.unknownRootCause": "不明",
"searchErrors.painlessError.buttonTxt": "スクリプトを編集",
"searchErrors.search.esErrorTitle": "検索結果を取得できません",
"searchErrors.search.httpErrorTitle": "Kibanaサーバーに接続できません",
"searchResponseWarnings.badgeButtonLabel": "{warningCount} {warningCount, plural, other {警告}}",
"searchResponseWarnings.noResultsTitle": "結果が見つかりませんでした",
"securitySolutionPackages.dataTable.eventsTab.unit": "{totalCount, plural, =1 {アラート} other {アラート}}",

View file

@ -147,12 +147,12 @@
"autocomplete.loadingDescription": "正在加载……",
"autocomplete.seeDocumentation": "参阅文档",
"autocomplete.selectField": "请首先选择字段......",
"bfetch.networkErrorWithStatus": "检查您的网络连接,然后重试。代码 {code}",
"bfetch.disableBfetch": "禁用请求批处理",
"bfetch.disableBfetchCompression": "禁用批量压缩",
"bfetch.disableBfetchCompressionDesc": "禁用批量压缩。这允许您对单个请求进行故障排查,但会增加响应大小。",
"bfetch.disableBfetchDesc": "禁用请求批处理。这会增加来自 Kibana 的 HTTP 请求数,但允许对单个请求进行故障排查。",
"bfetch.networkError": "检查您的网络连接,然后重试。",
"bfetchError.networkError": "检查您的网络连接,然后重试。",
"bfetchError.networkErrorWithStatus": "检查您的网络连接,然后重试。代码 {code}",
"cellActions.youAreInADialogContainingOptionsScreenReaderOnly": "您在对话框中,其中包含 {fieldName} 字段的选项。按 tab 键导航选项。按 escape 退出。",
"cellActions.actions.copyToClipboard.displayName": "复制到剪贴板",
"cellActions.actions.copyToClipboard.successMessage": "已复制到剪贴板",
@ -1363,7 +1363,6 @@
"data.mgmt.searchSessions.status.expiresSoonInHoursTooltip": "{numHours} 小时",
"data.mgmt.searchSessions.status.message.createdOn": "于 {expireDate}过期",
"data.mgmt.searchSessions.status.message.expiredOn": "已于 {expireDate}过期",
"data.painlessError.painlessScriptedFieldErrorMessage": "在索引模式 {indexPatternName} 上执行运行时字段或脚本字段时出错",
"data.parseEsInterval.invalidEsCalendarIntervalErrorMessage": "无效的日历时间间隔:{interval},值必须为 1",
"data.parseEsInterval.invalidEsIntervalFormatErrorMessage": "时间间隔格式无效:{interval}",
"data.search.aggs.aggTypesLabel": "{fieldName} 范围",
@ -1475,8 +1474,6 @@
"data.advancedSettings.timepicker.thisWeek": "本周",
"data.advancedSettings.timepicker.timeDefaultsTitle": "时间筛选默认值",
"data.advancedSettings.timepicker.today": "今日",
"data.errors.fetchError": "检查您的网络连接,然后重试。",
"data.esError.unknownRootCause": "未知",
"data.functions.esaggs.help": "运行 AggConfig 聚合",
"data.functions.esaggs.inspector.dataRequest.description": "此请求查询 Elasticsearch以获取可视化的数据。",
"data.functions.esaggs.inspector.dataRequest.title": "数据",
@ -1545,7 +1542,6 @@
"data.mgmt.searchSessions.table.notRestorableWarning": "搜索会话将重新执行。然后,您可以将其保存,供未来使用。",
"data.mgmt.searchSessions.table.numSearches": "搜索数",
"data.mgmt.searchSessions.table.versionIncompatibleWarning": "此搜索会话在运行不同版本的 Kibana 实例中已创建。其可能不会正确还原。",
"data.painlessError.buttonTxt": "编辑脚本",
"data.search.aggs.aggGroups.bucketsText": "存储桶",
"data.search.aggs.aggGroups.metricsText": "指标",
"data.search.aggs.aggGroups.noneText": "无",
@ -2062,7 +2058,6 @@
"data.search.esdsl.index.help": "要查询的 ElasticSearch 索引",
"data.search.esdsl.q.help": "查询 DSL",
"data.search.esdsl.size.help": "ElasticSearch searchAPI 大小参数",
"data.search.esErrorTitle": "无法检索搜索结果",
"data.search.esql.help": "使用 ES|QL 查询 Elasticsearch。",
"data.search.esql.query.help": "ES|QL 查询。",
"data.search.essql.count.help": "要检索的文档数目。要获取更佳的性能,请使用较小的数据集。",
@ -2155,7 +2150,6 @@
"data.search.functions.timerange.help": "创建 kibana 时间戳",
"data.search.functions.timerange.mode.help": "指定模式(绝对或相对)",
"data.search.functions.timerange.to.help": "指定结束日期",
"data.search.httpErrorTitle": "无法连接到 Kibana 服务器",
"data.search.searchSource.dataViewDescription": "被查询的数据视图。",
"data.search.searchSource.dataViewIdLabel": "数据视图 ID",
"data.search.searchSource.dataViewLabel": "数据视图",
@ -5218,6 +5212,12 @@
"searchApiPanels.welcomeBanner.selectClient.heading": "选择一个",
"searchApiPanels.welcomeBanner.selectClient.title": "选择客户端",
"searchApiPanels.welcomeBanner.tryInConsoleButton": "在 Console 中试用",
"searchErrors.painlessError.painlessScriptedFieldErrorMessage": "在索引模式 {indexPatternName} 上执行运行时字段或脚本字段时出错",
"searchErrors.errors.fetchError": "检查您的网络连接,然后重试。",
"searchErrors.esError.unknownRootCause": "未知",
"searchErrors.painlessError.buttonTxt": "编辑脚本",
"searchErrors.search.esErrorTitle": "无法检索搜索结果",
"searchErrors.search.httpErrorTitle": "无法连接到 Kibana 服务器",
"searchResponseWarnings.badgeButtonLabel": "{warningCount} {warningCount, plural, other {警告}}",
"searchResponseWarnings.noResultsTitle": "找不到结果",
"securitySolutionPackages.dataTable.eventsTab.unit": "{totalCount, plural, =1 {告警} other {告警}}",

View file

@ -55,7 +55,7 @@ export default function ({ getService }: FtrProviderContext) {
basemaps: {},
joins: { term: { min: 1, max: 1, total: 4, avg: 0.14814814814814814 } },
layerTypes: {
es_docs: { min: 1, max: 2, total: 19, avg: 0.7037037037037037 },
es_docs: { min: 1, max: 3, total: 20, avg: 0.7407407407407407 },
es_agg_grids: { min: 1, max: 1, total: 6, avg: 0.2222222222222222 },
es_point_to_point: { min: 1, max: 1, total: 1, avg: 0.037037037037037035 },
es_top_hits: { min: 1, max: 1, total: 2, avg: 0.07407407407407407 },
@ -69,7 +69,7 @@ export default function ({ getService }: FtrProviderContext) {
super_fine: { min: 1, max: 1, total: 3, avg: 0.1111111111111111 },
},
scalingOptions: {
limit: { min: 1, max: 2, total: 14, avg: 0.5185185185185185 },
limit: { min: 1, max: 3, total: 15, avg: 0.5555555555555556 },
clusters: { min: 1, max: 1, total: 1, avg: 0.037037037037037035 },
mvt: { min: 1, max: 1, total: 4, avg: 0.14814814814814814 },
},
@ -80,8 +80,8 @@ export default function ({ getService }: FtrProviderContext) {
min: 0,
},
dataSourcesCount: {
avg: 1.1481481481481481,
max: 5,
avg: 1.1851851851851851,
max: 6,
min: 1,
},
emsVectorLayersCount: {
@ -103,8 +103,8 @@ export default function ({ getService }: FtrProviderContext) {
min: 1,
},
GEOJSON_VECTOR: {
avg: 0.7777777777777778,
max: 4,
avg: 0.8148148148148148,
max: 5,
min: 1,
},
HEATMAP: {
@ -124,8 +124,8 @@ export default function ({ getService }: FtrProviderContext) {
},
},
layersCount: {
avg: 1.1851851851851851,
max: 6,
avg: 1.2222222222222223,
max: 7,
min: 1,
},
},

View file

@ -7,14 +7,37 @@
import expect from '@kbn/expect';
export default function ({ getPageObjects }) {
export default function ({ getPageObjects, getService }) {
const PageObjects = getPageObjects(['maps', 'header']);
const inspector = getService('inspector');
const testSubjects = getService('testSubjects');
describe('layer errors', () => {
before(async () => {
await PageObjects.maps.loadSavedMap('layer with errors');
});
describe('Layer with EsError', () => {
after(async () => {
await inspector.close();
});
it('should diplay error icon in legend', async () => {
await PageObjects.maps.hasErrorIconExistsOrFail('connections');
});
it('should display "View details" button', async () => {
await testSubjects.existOrFail('viewEsErrorButton');
});
it('should open request in inspector', async () => {
await testSubjects.click('viewEsErrorButton');
const selectedRequest = await testSubjects.getVisibleText('euiComboBoxPill');
expect(selectedRequest).to.equal('load layer features (connections)');
});
});
describe('ESSearchSource with missing index pattern id', () => {
const LAYER_NAME = 'idThatDoesNotExitForESSearchSource';

File diff suppressed because one or more lines are too long

View file

@ -3147,6 +3147,10 @@
version "0.0.0"
uid ""
"@kbn/bfetch-error@link:packages/kbn-bfetch-error":
version "0.0.0"
uid ""
"@kbn/bfetch-explorer-plugin@link:examples/bfetch_explorer":
version "0.0.0"
uid ""
@ -5523,6 +5527,10 @@
version "0.0.0"
uid ""
"@kbn/search-errors@link:packages/kbn-search-errors":
version "0.0.0"
uid ""
"@kbn/search-examples-plugin@link:examples/search_examples":
version "0.0.0"
uid ""