diff --git a/packages/kbn-optimizer/limits.yml b/packages/kbn-optimizer/limits.yml index 344f60d1fe274..2af3df248d209 100644 --- a/packages/kbn-optimizer/limits.yml +++ b/packages/kbn-optimizer/limits.yml @@ -68,7 +68,7 @@ pageLoadAssetSize: searchprofiler: 67224 security: 189428 securityOss: 30806 - securitySolution: 622387 + securitySolution: 283440 share: 99205 snapshotRestore: 79176 spaces: 389643 diff --git a/packages/kbn-storybook/lib/default_config.ts b/packages/kbn-storybook/lib/default_config.ts index dc2647b7b5757..c3bc65059d4a6 100644 --- a/packages/kbn-storybook/lib/default_config.ts +++ b/packages/kbn-storybook/lib/default_config.ts @@ -20,12 +20,7 @@ import { StorybookConfig } from '@storybook/core/types'; export const defaultConfig: StorybookConfig = { - addons: [ - '@kbn/storybook/preset', - '@storybook/addon-a11y', - '@storybook/addon-knobs', - '@storybook/addon-essentials', - ], + addons: ['@kbn/storybook/preset', '@storybook/addon-a11y', '@storybook/addon-essentials'], stories: ['../**/*.stories.tsx'], typescript: { reactDocgen: false, diff --git a/packages/kbn-utility-types/index.ts b/packages/kbn-utility-types/index.ts index d3fb5bdf36194..093cd29ba5507 100644 --- a/packages/kbn-utility-types/index.ts +++ b/packages/kbn-utility-types/index.ts @@ -110,3 +110,10 @@ export type MethodKeysOf = { * Returns an object with public methods only. */ export type PublicMethodsOf = Pick>; + +/** + * Makes an object with readonly properties mutable. + */ +export type Writable = { + -readonly [K in keyof T]: T[K]; +}; diff --git a/src/core/typings.ts b/packages/kbn-utility-types/jest/index.ts similarity index 90% rename from src/core/typings.ts rename to packages/kbn-utility-types/jest/index.ts index f271d0b03e0d3..8b3d926b8e8df 100644 --- a/src/core/typings.ts +++ b/packages/kbn-utility-types/jest/index.ts @@ -16,12 +16,11 @@ * specific language governing permissions and limitations * under the License. */ - -type DeeplyMockedKeys = { +export type DeeplyMockedKeys = { [P in keyof T]: T[P] extends (...args: any[]) => any ? jest.MockInstance, Parameters> : DeeplyMockedKeys; } & T; -type MockedKeys = { [P in keyof T]: jest.Mocked }; +export type MockedKeys = { [P in keyof T]: jest.Mocked }; diff --git a/packages/kbn-utility-types/jest/package.json b/packages/kbn-utility-types/jest/package.json new file mode 100644 index 0000000000000..9f92fc5e94528 --- /dev/null +++ b/packages/kbn-utility-types/jest/package.json @@ -0,0 +1,3 @@ +{ + "types": "../target/jest/index.d.ts" +} diff --git a/packages/kbn-utility-types/test-d/method_keys_of.ts b/packages/kbn-utility-types/test-d/method_keys_of.ts new file mode 100644 index 0000000000000..46cb17122f416 --- /dev/null +++ b/packages/kbn-utility-types/test-d/method_keys_of.ts @@ -0,0 +1,34 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { expectType } from 'tsd'; +import { MethodKeysOf } from '../index'; + +class Test { + public name: string = ''; + getName() { + return this.name; + } + // @ts-ignore + private getDoubleName() { + return this.name.repeat(2); + } +} + +expectType>('getName'); diff --git a/packages/kbn-utility-types/test-d/public_methods_of.ts b/packages/kbn-utility-types/test-d/public_methods_of.ts new file mode 100644 index 0000000000000..3f5d442342b15 --- /dev/null +++ b/packages/kbn-utility-types/test-d/public_methods_of.ts @@ -0,0 +1,50 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { expectAssignable, expectNotAssignable } from 'tsd'; +import { PublicMethodsOf } from '../index'; + +class Test { + public name: string = ''; + getName() { + return this.name; + } + // @ts-ignore + private getDoubleName() { + return this.name.repeat(2); + } +} + +expectAssignable>({ + getName() { + return ''; + }, +}); + +expectNotAssignable>({ + getName() { + return 1; + }, +}); + +expectNotAssignable>({ + getDoubleName() { + return 1; + }, +}); diff --git a/packages/kbn-utility-types/test-d/writable.ts b/packages/kbn-utility-types/test-d/writable.ts new file mode 100644 index 0000000000000..0771fa926c4ec --- /dev/null +++ b/packages/kbn-utility-types/test-d/writable.ts @@ -0,0 +1,29 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { expectAssignable } from 'tsd'; +import { Writable } from '../index'; + +type WritableArray = Writable; +expectAssignable(['1']); + +type WritableObject = Writable<{ + readonly name: string; +}>; +expectAssignable({ name: '1' }); diff --git a/packages/kbn-utility-types/tsconfig.json b/packages/kbn-utility-types/tsconfig.json index 79cf423fe78ac..c2d206526e6f4 100644 --- a/packages/kbn-utility-types/tsconfig.json +++ b/packages/kbn-utility-types/tsconfig.json @@ -7,10 +7,11 @@ "stripInternal": true, "declarationMap": true, "types": [ - "node" + "node", + "jest" ] }, - "include": ["index.ts", "test-d/**/*"], + "include": ["index.ts", "jest/**/*", "test-d/**/*"], "exclude": [ "target" ] diff --git a/src/core/public/apm_system.test.ts b/src/core/public/apm_system.test.ts index f88cdd899ef81..be1cb6dc68208 100644 --- a/src/core/public/apm_system.test.ts +++ b/src/core/public/apm_system.test.ts @@ -18,6 +18,7 @@ */ jest.mock('@elastic/apm-rum'); +import type { DeeplyMockedKeys } from '@kbn/utility-types/jest'; import { init, apm } from '@elastic/apm-rum'; import { ApmSystem } from './apm_system'; diff --git a/src/core/public/chrome/chrome_service.mock.ts b/src/core/public/chrome/chrome_service.mock.ts index 9cd96763d2e79..cbcd23615d34c 100644 --- a/src/core/public/chrome/chrome_service.mock.ts +++ b/src/core/public/chrome/chrome_service.mock.ts @@ -18,6 +18,7 @@ */ import { BehaviorSubject } from 'rxjs'; import type { PublicMethodsOf } from '@kbn/utility-types'; +import type { DeeplyMockedKeys } from '@kbn/utility-types/jest'; import { ChromeBadge, ChromeBrand, ChromeBreadcrumb, ChromeService, InternalChromeStart } from './'; const createStartContractMock = () => { diff --git a/src/core/public/notifications/notifications_service.mock.ts b/src/core/public/notifications/notifications_service.mock.ts index 990ab479d35c3..b69b4604d0788 100644 --- a/src/core/public/notifications/notifications_service.mock.ts +++ b/src/core/public/notifications/notifications_service.mock.ts @@ -17,6 +17,7 @@ * under the License. */ import type { PublicMethodsOf } from '@kbn/utility-types'; +import type { MockedKeys } from '@kbn/utility-types/jest'; import { NotificationsService, NotificationsSetup, diff --git a/src/core/public/overlays/overlay_service.mock.ts b/src/core/public/overlays/overlay_service.mock.ts index 66ba36b20b45c..595813972b8bc 100644 --- a/src/core/public/overlays/overlay_service.mock.ts +++ b/src/core/public/overlays/overlay_service.mock.ts @@ -17,6 +17,7 @@ * under the License. */ import type { PublicMethodsOf } from '@kbn/utility-types'; +import type { DeeplyMockedKeys } from '@kbn/utility-types/jest'; import { OverlayService, OverlayStart } from './overlay_service'; import { overlayBannersServiceMock } from './banners/banners_service.mock'; import { overlayFlyoutServiceMock } from './flyout/flyout_service.mock'; diff --git a/src/core/server/core_context.mock.ts b/src/core/server/core_context.mock.ts index bbf04783278f7..4df0b2dfb9d8a 100644 --- a/src/core/server/core_context.mock.ts +++ b/src/core/server/core_context.mock.ts @@ -18,6 +18,7 @@ */ import { REPO_ROOT } from '@kbn/dev-utils'; +import type { DeeplyMockedKeys } from '@kbn/utility-types/jest'; import { CoreContext } from './core_context'; import { Env, IConfigService } from './config'; import { configServiceMock, getEnvOptions } from './config/mocks'; diff --git a/src/core/server/elasticsearch/client/mocks.ts b/src/core/server/elasticsearch/client/mocks.ts index fb2826c787718..bedd0e65c5a83 100644 --- a/src/core/server/elasticsearch/client/mocks.ts +++ b/src/core/server/elasticsearch/client/mocks.ts @@ -18,6 +18,7 @@ */ import { Client, ApiResponse } from '@elastic/elasticsearch'; import { TransportRequestPromise } from '@elastic/elasticsearch/lib/Transport'; +import type { DeeplyMockedKeys } from '@kbn/utility-types/jest'; import { ElasticsearchClient } from './types'; import { ICustomClusterClient } from './cluster_client'; diff --git a/src/core/server/mocks.ts b/src/core/server/mocks.ts index e47d06409894e..7551f53ab27de 100644 --- a/src/core/server/mocks.ts +++ b/src/core/server/mocks.ts @@ -19,6 +19,7 @@ import { of } from 'rxjs'; import { duration } from 'moment'; import { ByteSizeValue } from '@kbn/config-schema'; +import type { MockedKeys } from '@kbn/utility-types/jest'; import { PluginInitializerContext, CoreSetup, CoreStart, StartServicesAccessor } from '.'; import { loggingSystemMock } from './logging/logging_system.mock'; import { loggingServiceMock } from './logging/logging_service.mock'; diff --git a/src/core/server/saved_objects/export/inject_nested_depdendencies.test.ts b/src/core/server/saved_objects/export/inject_nested_depdendencies.test.ts index 1d5ce5625bf48..862d11cfa663a 100644 --- a/src/core/server/saved_objects/export/inject_nested_depdendencies.test.ts +++ b/src/core/server/saved_objects/export/inject_nested_depdendencies.test.ts @@ -78,7 +78,7 @@ describe('getObjectReferencesToFetch()', () => { `); }); - test(`doesn't deal with circular dependencies`, () => { + test('does not fail on circular dependencies', () => { const map = new Map(); map.set('index-pattern:1', { id: '1', @@ -527,7 +527,7 @@ describe('injectNestedDependencies', () => { `); }); - test(`doesn't deal with circular dependencies`, async () => { + test('does not fail on circular dependencies', async () => { const savedObjects = [ { id: '2', diff --git a/src/core/server/saved_objects/export/sort_objects.test.ts b/src/core/server/saved_objects/export/sort_objects.test.ts index 7b6698dfaf887..cd116d767b0c3 100644 --- a/src/core/server/saved_objects/export/sort_objects.test.ts +++ b/src/core/server/saved_objects/export/sort_objects.test.ts @@ -46,27 +46,27 @@ describe('sortObjects()', () => { }, ]; expect(sortObjects(docs)).toMatchInlineSnapshot(` -Array [ - Object { - "attributes": Object {}, - "id": "1", - "references": Array [], - "type": "index-pattern", - }, - Object { - "attributes": Object {}, - "id": "2", - "references": Array [ - Object { - "id": "1", - "name": "ref1", - "type": "index-pattern", - }, - ], - "type": "search", - }, -] -`); + Array [ + Object { + "attributes": Object {}, + "id": "1", + "references": Array [], + "type": "index-pattern", + }, + Object { + "attributes": Object {}, + "id": "2", + "references": Array [ + Object { + "id": "1", + "name": "ref1", + "type": "index-pattern", + }, + ], + "type": "search", + }, + ] + `); }); test('should not mutate parameter', () => { @@ -91,49 +91,49 @@ Array [ }, ]; expect(sortObjects(docs)).toMatchInlineSnapshot(` -Array [ - Object { - "attributes": Object {}, - "id": "1", - "references": Array [], - "type": "index-pattern", - }, - Object { - "attributes": Object {}, - "id": "2", - "references": Array [ - Object { - "id": "1", - "name": "ref1", - "type": "index-pattern", - }, - ], - "type": "search", - }, -] -`); + Array [ + Object { + "attributes": Object {}, + "id": "1", + "references": Array [], + "type": "index-pattern", + }, + Object { + "attributes": Object {}, + "id": "2", + "references": Array [ + Object { + "id": "1", + "name": "ref1", + "type": "index-pattern", + }, + ], + "type": "search", + }, + ] + `); expect(docs).toMatchInlineSnapshot(` -Array [ - Object { - "attributes": Object {}, - "id": "2", - "references": Array [ - Object { - "id": "1", - "name": "ref1", - "type": "index-pattern", - }, - ], - "type": "search", - }, - Object { - "attributes": Object {}, - "id": "1", - "references": Array [], - "type": "index-pattern", - }, -] -`); + Array [ + Object { + "attributes": Object {}, + "id": "2", + "references": Array [ + Object { + "id": "1", + "name": "ref1", + "type": "index-pattern", + }, + ], + "type": "search", + }, + Object { + "attributes": Object {}, + "id": "1", + "references": Array [], + "type": "index-pattern", + }, + ] + `); }); test('should sort unordered array', () => { @@ -199,71 +199,71 @@ Array [ }, ]; expect(sortObjects(docs)).toMatchInlineSnapshot(` -Array [ - Object { - "attributes": Object {}, - "id": "1", - "references": Array [], - "type": "index-pattern", - }, - Object { - "attributes": Object {}, - "id": "2", - "references": Array [ - Object { - "id": "1", - "name": "ref1", - "type": "index-pattern", - }, - ], - "type": "search", - }, - Object { - "attributes": Object {}, - "id": "3", - "references": Array [ - Object { - "id": "2", - "name": "ref1", - "type": "search", - }, - ], - "type": "visualization", - }, - Object { - "attributes": Object {}, - "id": "4", - "references": Array [ - Object { - "id": "1", - "name": "ref1", - "type": "index-pattern", - }, - ], - "type": "visualization", - }, - Object { - "attributes": Object {}, - "id": "5", - "references": Array [ - Object { - "id": "3", - "name": "ref1", - "type": "visualization", - }, - Object { - "id": "4", - "name": "ref2", - "type": "visualization", - }, - ], - "type": "dashboard", - }, -] -`); + Array [ + Object { + "attributes": Object {}, + "id": "1", + "references": Array [], + "type": "index-pattern", + }, + Object { + "attributes": Object {}, + "id": "2", + "references": Array [ + Object { + "id": "1", + "name": "ref1", + "type": "index-pattern", + }, + ], + "type": "search", + }, + Object { + "attributes": Object {}, + "id": "3", + "references": Array [ + Object { + "id": "2", + "name": "ref1", + "type": "search", + }, + ], + "type": "visualization", + }, + Object { + "attributes": Object {}, + "id": "4", + "references": Array [ + Object { + "id": "1", + "name": "ref1", + "type": "index-pattern", + }, + ], + "type": "visualization", + }, + Object { + "attributes": Object {}, + "id": "5", + "references": Array [ + Object { + "id": "3", + "name": "ref1", + "type": "visualization", + }, + Object { + "id": "4", + "name": "ref2", + "type": "visualization", + }, + ], + "type": "dashboard", + }, + ] + `); }); - test('detects circular dependencies', () => { + test('should not fail on circular dependencies', () => { const docs = [ { id: '1', @@ -290,8 +290,149 @@ Array [ ], }, ]; - expect(() => sortObjects(docs)).toThrowErrorMatchingInlineSnapshot( - `"circular reference: [foo:1] ref-> [foo:2] ref-> [foo:1]"` - ); + + expect(sortObjects(docs)).toMatchInlineSnapshot(` + Array [ + Object { + "attributes": Object {}, + "id": "2", + "references": Array [ + Object { + "id": "1", + "name": "ref1", + "type": "foo", + }, + ], + "type": "foo", + }, + Object { + "attributes": Object {}, + "id": "1", + "references": Array [ + Object { + "id": "2", + "name": "ref1", + "type": "foo", + }, + ], + "type": "foo", + }, + ] + `); + }); + test('should not fail on complex circular dependencies', () => { + const docs = [ + { + id: '1', + type: 'foo', + attributes: {}, + references: [ + { + name: 'ref12', + type: 'foo', + id: '2', + }, + { + name: 'ref13', + type: 'baz', + id: '3', + }, + ], + }, + { + id: '2', + type: 'foo', + attributes: {}, + references: [ + { + name: 'ref13', + type: 'foo', + id: '3', + }, + ], + }, + { + id: '3', + type: 'baz', + attributes: {}, + references: [ + { + name: 'ref13', + type: 'xyz', + id: '4', + }, + ], + }, + { + id: '4', + type: 'xyz', + attributes: {}, + references: [ + { + name: 'ref14', + type: 'foo', + id: '1', + }, + ], + }, + ]; + + expect(sortObjects(docs)).toMatchInlineSnapshot(` + Array [ + Object { + "attributes": Object {}, + "id": "2", + "references": Array [ + Object { + "id": "3", + "name": "ref13", + "type": "foo", + }, + ], + "type": "foo", + }, + Object { + "attributes": Object {}, + "id": "4", + "references": Array [ + Object { + "id": "1", + "name": "ref14", + "type": "foo", + }, + ], + "type": "xyz", + }, + Object { + "attributes": Object {}, + "id": "3", + "references": Array [ + Object { + "id": "4", + "name": "ref13", + "type": "xyz", + }, + ], + "type": "baz", + }, + Object { + "attributes": Object {}, + "id": "1", + "references": Array [ + Object { + "id": "2", + "name": "ref12", + "type": "foo", + }, + Object { + "id": "3", + "name": "ref13", + "type": "baz", + }, + ], + "type": "foo", + }, + ] + `); }); }); diff --git a/src/core/server/saved_objects/export/sort_objects.ts b/src/core/server/saved_objects/export/sort_objects.ts index 64bab9f43bf14..ec83b687527fc 100644 --- a/src/core/server/saved_objects/export/sort_objects.ts +++ b/src/core/server/saved_objects/export/sort_objects.ts @@ -17,7 +17,6 @@ * under the License. */ -import Boom from 'boom'; import { SavedObject } from '../types'; export function sortObjects(savedObjects: SavedObject[]): SavedObject[] { @@ -30,11 +29,7 @@ export function sortObjects(savedObjects: SavedObject[]): SavedObject[] { function includeObjects(objects: SavedObject[]) { for (const object of objects) { if (path.has(object)) { - throw Boom.badRequest( - `circular reference: ${[...path, object] - .map((obj) => `[${obj.type}:${obj.id}]`) - .join(' ref-> ')}` - ); + continue; } const refdObjects = object.references diff --git a/src/core/tsconfig.json b/src/core/tsconfig.json index a3531057767d4..4281559c9aa14 100644 --- a/src/core/tsconfig.json +++ b/src/core/tsconfig.json @@ -13,8 +13,7 @@ "types/**/*", "test_helpers/**/*", "utils/**/*", - "index.ts", - "typings.ts" + "index.ts" ], "references": [ { "path": "../test_utils/" } diff --git a/src/legacy/server/i18n/get_kibana_translation_paths.test.ts b/src/legacy/server/i18n/get_kibana_translation_paths.test.ts new file mode 100644 index 0000000000000..0f202c4d433c0 --- /dev/null +++ b/src/legacy/server/i18n/get_kibana_translation_paths.test.ts @@ -0,0 +1,58 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { I18N_RC } from './constants'; +import { fromRoot } from '../../../core/server/utils'; + +jest.mock('./get_translation_paths', () => ({ getTranslationPaths: jest.fn() })); +import { getKibanaTranslationPaths } from './get_kibana_translation_paths'; +import { getTranslationPaths as mockGetTranslationPaths } from './get_translation_paths'; + +describe('getKibanaTranslationPaths', () => { + const mockConfig = { get: jest.fn() }; + + beforeEach(() => { + jest.resetAllMocks(); + }); + + it('calls getTranslationPaths against kibana root and kibana-extra', async () => { + mockConfig.get.mockReturnValue([]); + await getKibanaTranslationPaths(mockConfig); + expect(mockGetTranslationPaths).toHaveBeenNthCalledWith(1, { + cwd: fromRoot('.'), + glob: `*/${I18N_RC}`, + }); + + expect(mockGetTranslationPaths).toHaveBeenNthCalledWith(2, { + cwd: fromRoot('../kibana-extra'), + glob: `*/${I18N_RC}`, + }); + }); + + it('calls getTranslationPaths for each config returned in plugin.paths and plugins.scanDirs', async () => { + mockConfig.get.mockReturnValueOnce(['a', 'b']).mockReturnValueOnce(['c']); + await getKibanaTranslationPaths(mockConfig); + expect(mockConfig.get).toHaveBeenNthCalledWith(1, 'plugins.paths'); + expect(mockConfig.get).toHaveBeenNthCalledWith(2, 'plugins.scanDirs'); + + expect(mockGetTranslationPaths).toHaveBeenNthCalledWith(2, { cwd: 'a', glob: I18N_RC }); + expect(mockGetTranslationPaths).toHaveBeenNthCalledWith(3, { cwd: 'b', glob: I18N_RC }); + expect(mockGetTranslationPaths).toHaveBeenNthCalledWith(4, { cwd: 'c', glob: `*/${I18N_RC}` }); + }); +}); diff --git a/src/legacy/server/i18n/get_kibana_translation_paths.ts b/src/legacy/server/i18n/get_kibana_translation_paths.ts new file mode 100644 index 0000000000000..d7f77d3185ba4 --- /dev/null +++ b/src/legacy/server/i18n/get_kibana_translation_paths.ts @@ -0,0 +1,42 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { KibanaConfig } from '../kbn_server'; +import { fromRoot } from '../../../core/server/utils'; +import { I18N_RC } from './constants'; +import { getTranslationPaths } from './get_translation_paths'; + +export async function getKibanaTranslationPaths(config: Pick) { + return await Promise.all([ + getTranslationPaths({ + cwd: fromRoot('.'), + glob: `*/${I18N_RC}`, + }), + ...(config.get('plugins.paths') as string[]).map((cwd) => + getTranslationPaths({ cwd, glob: I18N_RC }) + ), + ...(config.get('plugins.scanDirs') as string[]).map((cwd) => + getTranslationPaths({ cwd, glob: `*/${I18N_RC}` }) + ), + getTranslationPaths({ + cwd: fromRoot('../kibana-extra'), + glob: `*/${I18N_RC}`, + }), + ]); +} diff --git a/src/legacy/server/i18n/get_translations_path.ts b/src/legacy/server/i18n/get_translation_paths.ts similarity index 100% rename from src/legacy/server/i18n/get_translations_path.ts rename to src/legacy/server/i18n/get_translation_paths.ts diff --git a/src/legacy/server/i18n/i18n_mixin.ts b/src/legacy/server/i18n/i18n_mixin.ts new file mode 100644 index 0000000000000..4f77fa8df96cd --- /dev/null +++ b/src/legacy/server/i18n/i18n_mixin.ts @@ -0,0 +1,63 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { i18n, i18nLoader } from '@kbn/i18n'; +import { basename } from 'path'; +import { Server } from 'hapi'; +import type { UsageCollectionSetup } from '../../../plugins/usage_collection/server'; +import { getKibanaTranslationPaths } from './get_kibana_translation_paths'; +import KbnServer, { KibanaConfig } from '../kbn_server'; +import { registerLocalizationUsageCollector } from './localization'; + +export async function i18nMixin( + kbnServer: KbnServer, + server: Server, + config: Pick +) { + const locale = config.get('i18n.locale') as string; + + const translationPaths = await getKibanaTranslationPaths(config); + + const currentTranslationPaths = ([] as string[]) + .concat(...translationPaths) + .filter((translationPath) => basename(translationPath, '.json') === locale); + i18nLoader.registerTranslationFiles(currentTranslationPaths); + + const translations = await i18nLoader.getTranslationsByLocale(locale); + i18n.init( + Object.freeze({ + locale, + ...translations, + }) + ); + + const getTranslationsFilePaths = () => currentTranslationPaths; + + server.decorate('server', 'getTranslationsFilePaths', getTranslationsFilePaths); + + if (kbnServer.newPlatform.setup.plugins.usageCollection) { + const { usageCollection } = kbnServer.newPlatform.setup.plugins as { + usageCollection: UsageCollectionSetup; + }; + registerLocalizationUsageCollector(usageCollection, { + getLocale: () => config.get('i18n.locale') as string, + getTranslationsFilePaths, + }); + } +} diff --git a/src/legacy/server/i18n/index.ts b/src/legacy/server/i18n/index.ts index 61caefb2fb599..a7ef49f44532c 100644 --- a/src/legacy/server/i18n/index.ts +++ b/src/legacy/server/i18n/index.ts @@ -17,60 +17,4 @@ * under the License. */ -import { i18n, i18nLoader } from '@kbn/i18n'; -import { basename } from 'path'; -import { Server } from 'hapi'; -import { fromRoot } from '../../../core/server/utils'; -import type { UsageCollectionSetup } from '../../../plugins/usage_collection/server'; -import { getTranslationPaths } from './get_translations_path'; -import { I18N_RC } from './constants'; -import KbnServer, { KibanaConfig } from '../kbn_server'; -import { registerLocalizationUsageCollector } from './localization'; - -export async function i18nMixin(kbnServer: KbnServer, server: Server, config: KibanaConfig) { - const locale = config.get('i18n.locale') as string; - - const translationPaths = await Promise.all([ - getTranslationPaths({ - cwd: fromRoot('.'), - glob: `*/${I18N_RC}`, - }), - ...(config.get('plugins.paths') as string[]).map((cwd) => - getTranslationPaths({ cwd, glob: I18N_RC }) - ), - ...(config.get('plugins.scanDirs') as string[]).map((cwd) => - getTranslationPaths({ cwd, glob: `*/${I18N_RC}` }) - ), - getTranslationPaths({ - cwd: fromRoot('../kibana-extra'), - glob: `*/${I18N_RC}`, - }), - ]); - - const currentTranslationPaths = ([] as string[]) - .concat(...translationPaths) - .filter((translationPath) => basename(translationPath, '.json') === locale); - i18nLoader.registerTranslationFiles(currentTranslationPaths); - - const translations = await i18nLoader.getTranslationsByLocale(locale); - i18n.init( - Object.freeze({ - locale, - ...translations, - }) - ); - - const getTranslationsFilePaths = () => currentTranslationPaths; - - server.decorate('server', 'getTranslationsFilePaths', getTranslationsFilePaths); - - if (kbnServer.newPlatform.setup.plugins.usageCollection) { - const { usageCollection } = kbnServer.newPlatform.setup.plugins as { - usageCollection: UsageCollectionSetup; - }; - registerLocalizationUsageCollector(usageCollection, { - getLocale: () => config.get('i18n.locale') as string, - getTranslationsFilePaths, - }); - } -} +export { i18nMixin } from './i18n_mixin'; diff --git a/src/plugins/dashboard/public/application/actions/library_notification_popover.tsx b/src/plugins/dashboard/public/application/actions/library_notification_popover.tsx index 8bc81b3296c3d..6ec5b0d637556 100644 --- a/src/plugins/dashboard/public/application/actions/library_notification_popover.tsx +++ b/src/plugins/dashboard/public/application/actions/library_notification_popover.tsx @@ -72,7 +72,7 @@ export function LibraryNotificationPopover({

{i18n.translate('dashboard.panel.libraryNotification.toolTip', { defaultMessage: - 'This panel is linked to a library item. Editing the panel might affect other dashboards.', + 'Editing this panel might affect other dashboards. To change to this panel only, unlink it from the library.', })}

diff --git a/src/plugins/data/common/field_formats/index.ts b/src/plugins/data/common/field_formats/index.ts index c1b1619abd247..1f6496ba6ac7a 100644 --- a/src/plugins/data/common/field_formats/index.ts +++ b/src/plugins/data/common/field_formats/index.ts @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ - +import { PublicMethodsOf } from '@kbn/utility-types'; import { FieldFormatsRegistry } from './field_formats_registry'; type IFieldFormatsRegistry = PublicMethodsOf; diff --git a/src/plugins/data/common/field_formats/types.ts b/src/plugins/data/common/field_formats/types.ts index af956a20c0dc5..5a830586b8d05 100644 --- a/src/plugins/data/common/field_formats/types.ts +++ b/src/plugins/data/common/field_formats/types.ts @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ - +import { PublicMethodsOf } from '@kbn/utility-types'; import { GetConfigFn } from '../types'; import { FieldFormat } from './field_format'; import { FieldFormatsRegistry } from './field_formats_registry'; diff --git a/src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts b/src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts index b07540b9ac0cc..300421cc1d617 100644 --- a/src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts +++ b/src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts @@ -18,6 +18,7 @@ */ import { i18n } from '@kbn/i18n'; +import { PublicMethodsOf } from '@kbn/utility-types'; import { SavedObjectsClientCommon } from '../..'; import { createIndexPatternCache } from '.'; diff --git a/src/plugins/data/common/search/aggs/utils/get_format_with_aggs.test.ts b/src/plugins/data/common/search/aggs/utils/get_format_with_aggs.test.ts index 28646c092c01c..826e402b14682 100644 --- a/src/plugins/data/common/search/aggs/utils/get_format_with_aggs.test.ts +++ b/src/plugins/data/common/search/aggs/utils/get_format_with_aggs.test.ts @@ -79,6 +79,33 @@ describe('getFormatWithAggs', () => { expect(getFormat).toHaveBeenCalledTimes(1); }); + test('creates alternative format for range using the template parameter', () => { + const mapping = { id: 'range', params: { template: 'arrow_right' } }; + const getFieldFormat = getFormatWithAggs(getFormat); + const format = getFieldFormat(mapping); + + expect(format.convert({ gte: 1, lt: 20 })).toBe('1 → 20'); + expect(getFormat).toHaveBeenCalledTimes(1); + }); + + test('handles Infinity values internally when no nestedFormatter is passed', () => { + const mapping = { id: 'range', params: { replaceInfinity: true } }; + const getFieldFormat = getFormatWithAggs(getFormat); + const format = getFieldFormat(mapping); + + expect(format.convert({ gte: -Infinity, lt: Infinity })).toBe('≥ −∞ and < +∞'); + expect(getFormat).toHaveBeenCalledTimes(1); + }); + + test('lets Infinity values handling to nestedFormatter even when flag is on', () => { + const mapping = { id: 'range', params: { replaceInfinity: true, id: 'any' } }; + const getFieldFormat = getFormatWithAggs(getFormat); + const format = getFieldFormat(mapping); + + expect(format.convert({ gte: -Infinity, lt: Infinity })).toBe('≥ -Infinity and < Infinity'); + expect(getFormat).toHaveBeenCalledTimes(1); + }); + test('returns custom label for range if provided', () => { const mapping = { id: 'range', params: {} }; const getFieldFormat = getFormatWithAggs(getFormat); diff --git a/src/plugins/data/common/search/aggs/utils/get_format_with_aggs.ts b/src/plugins/data/common/search/aggs/utils/get_format_with_aggs.ts index a8134619fec0d..6b03dc5f70edc 100644 --- a/src/plugins/data/common/search/aggs/utils/get_format_with_aggs.ts +++ b/src/plugins/data/common/search/aggs/utils/get_format_with_aggs.ts @@ -56,15 +56,35 @@ export function getFormatWithAggs(getFieldFormat: GetFieldFormat): GetFieldForma id: nestedFormatter.id, params: nestedFormatter.params, }); + const gte = '\u2265'; const lt = '\u003c'; + let fromValue = format.convert(range.gte); + let toValue = format.convert(range.lt); + // In case of identity formatter and a specific flag, replace Infinity values by specific strings + if (params.replaceInfinity && nestedFormatter.id == null) { + const FROM_PLACEHOLDER = '\u2212\u221E'; + const TO_PLACEHOLDER = '+\u221E'; + fromValue = isFinite(range.gte) ? fromValue : FROM_PLACEHOLDER; + toValue = isFinite(range.lt) ? toValue : TO_PLACEHOLDER; + } + + if (params.template === 'arrow_right') { + return i18n.translate('data.aggTypes.buckets.ranges.rangesFormatMessageArrowRight', { + defaultMessage: '{from} → {to}', + values: { + from: fromValue, + to: toValue, + }, + }); + } return i18n.translate('data.aggTypes.buckets.ranges.rangesFormatMessage', { defaultMessage: '{gte} {from} and {lt} {to}', values: { gte, - from: format.convert(range.gte), + from: fromValue, lt, - to: format.convert(range.lt), + to: toValue, }, }); }); diff --git a/src/plugins/data/common/search/search_source/legacy/default_search_strategy.test.ts b/src/plugins/data/common/search/search_source/legacy/default_search_strategy.test.ts index 3badd456bd72a..b13f6ad266546 100644 --- a/src/plugins/data/common/search/search_source/legacy/default_search_strategy.test.ts +++ b/src/plugins/data/common/search/search_source/legacy/default_search_strategy.test.ts @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ - +import type { MockedKeys } from '@kbn/utility-types/jest'; import { defaultSearchStrategy } from './default_search_strategy'; import { LegacyFetchHandlers, SearchStrategySearchParams } from './types'; import { BehaviorSubject } from 'rxjs'; diff --git a/src/plugins/data/common/search/search_source/mocks.ts b/src/plugins/data/common/search/search_source/mocks.ts index d4c0707f950bb..ea7d6b4441ccf 100644 --- a/src/plugins/data/common/search/search_source/mocks.ts +++ b/src/plugins/data/common/search/search_source/mocks.ts @@ -18,6 +18,7 @@ */ import { BehaviorSubject } from 'rxjs'; +import type { MockedKeys } from '@kbn/utility-types/jest'; import { uiSettingsServiceMock } from '../../../../../core/public/mocks'; import { SearchSource } from './search_source'; diff --git a/src/plugins/data/public/field_formats/mocks.ts b/src/plugins/data/public/field_formats/mocks.ts index ec1233a085bce..ba1e9de71bab1 100644 --- a/src/plugins/data/public/field_formats/mocks.ts +++ b/src/plugins/data/public/field_formats/mocks.ts @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ - +import type { PublicMethodsOf } from '@kbn/utility-types'; import { FieldFormatsStart, FieldFormatsSetup, FieldFormatsService } from '.'; import { fieldFormatsMock } from '../../common/field_formats/mocks'; diff --git a/src/plugins/data/public/query/mocks.ts b/src/plugins/data/public/query/mocks.ts index 53c177de0fa39..f8376d7834873 100644 --- a/src/plugins/data/public/query/mocks.ts +++ b/src/plugins/data/public/query/mocks.ts @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ - +import type { PublicMethodsOf } from '@kbn/utility-types'; import { Observable } from 'rxjs'; import { QueryService, QuerySetup, QueryStart } from '.'; import { timefilterServiceMock } from './timefilter/timefilter_service.mock'; diff --git a/src/plugins/data/public/query/query_string/query_string_manager.ts b/src/plugins/data/public/query/query_string/query_string_manager.ts index 50732c99a62d9..90a622fada95b 100644 --- a/src/plugins/data/public/query/query_string/query_string_manager.ts +++ b/src/plugins/data/public/query/query_string/query_string_manager.ts @@ -19,6 +19,7 @@ import { BehaviorSubject } from 'rxjs'; import { skip } from 'rxjs/operators'; +import { PublicMethodsOf } from '@kbn/utility-types'; import { CoreStart } from 'kibana/public'; import { IStorageWrapper } from 'src/plugins/kibana_utils/public'; import { Query, UI_SETTINGS } from '../../../common'; diff --git a/src/plugins/data/public/query/timefilter/time_history.ts b/src/plugins/data/public/query/timefilter/time_history.ts index fe73fd85b164d..24786c5eed623 100644 --- a/src/plugins/data/public/query/timefilter/time_history.ts +++ b/src/plugins/data/public/query/timefilter/time_history.ts @@ -18,6 +18,7 @@ */ import moment from 'moment'; +import { PublicMethodsOf } from '@kbn/utility-types'; import { IStorageWrapper } from 'src/plugins/kibana_utils/public'; import { PersistedLog } from '../persisted_log'; import { TimeRange } from '../../../common'; diff --git a/src/plugins/data/public/query/timefilter/timefilter.ts b/src/plugins/data/public/query/timefilter/timefilter.ts index 01b82087cf354..49a8c68f6916f 100644 --- a/src/plugins/data/public/query/timefilter/timefilter.ts +++ b/src/plugins/data/public/query/timefilter/timefilter.ts @@ -20,6 +20,7 @@ import _ from 'lodash'; import { Subject, BehaviorSubject } from 'rxjs'; import moment from 'moment'; +import { PublicMethodsOf } from '@kbn/utility-types'; import { areRefreshIntervalsDifferent, areTimeRangesDifferent } from './lib/diff_time_picker_vals'; import { getForceNow } from './lib/get_force_now'; import { TimefilterConfig, InputTimeRange, TimeRangeBounds } from './types'; diff --git a/src/plugins/data/public/query/timefilter/timefilter_service.mock.ts b/src/plugins/data/public/query/timefilter/timefilter_service.mock.ts index 060257a880528..9f1c64a1739a5 100644 --- a/src/plugins/data/public/query/timefilter/timefilter_service.mock.ts +++ b/src/plugins/data/public/query/timefilter/timefilter_service.mock.ts @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ - +import type { PublicMethodsOf } from '@kbn/utility-types'; import { TimefilterService, TimeHistoryContract, TimefilterContract } from '.'; import { Observable } from 'rxjs'; diff --git a/src/plugins/data/public/search/collectors/create_usage_collector.test.ts b/src/plugins/data/public/search/collectors/create_usage_collector.test.ts index 9cadb1e796ad6..b87ac11e810c9 100644 --- a/src/plugins/data/public/search/collectors/create_usage_collector.test.ts +++ b/src/plugins/data/public/search/collectors/create_usage_collector.test.ts @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ - +import type { MockedKeys } from '@kbn/utility-types/jest'; import { CoreSetup, CoreStart } from '../../../../../core/public'; import { coreMock } from '../../../../../core/public/mocks'; import { usageCollectionPluginMock, Setup } from '../../../../usage_collection/public/mocks'; diff --git a/src/plugins/data/public/search/es_search/get_es_preference.test.ts b/src/plugins/data/public/search/es_search/get_es_preference.test.ts index 05a74b3e6205a..8b3d335b38d17 100644 --- a/src/plugins/data/public/search/es_search/get_es_preference.test.ts +++ b/src/plugins/data/public/search/es_search/get_es_preference.test.ts @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ - +import type { MockedKeys } from '@kbn/utility-types/jest'; import { getEsPreference } from './get_es_preference'; import { CoreStart } from '../../../../../core/public'; import { coreMock } from '../../../../../core/public/mocks'; diff --git a/src/plugins/data/public/search/search_interceptor.test.ts b/src/plugins/data/public/search/search_interceptor.test.ts index e8a728bb9cec3..472caa5e4f45f 100644 --- a/src/plugins/data/public/search/search_interceptor.test.ts +++ b/src/plugins/data/public/search/search_interceptor.test.ts @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ - +import type { MockedKeys } from '@kbn/utility-types/jest'; import { CoreSetup, CoreStart } from '../../../../core/public'; import { coreMock } from '../../../../core/public/mocks'; import { IEsSearchRequest } from '../../common/search'; diff --git a/src/plugins/data/public/search/search_interceptor.ts b/src/plugins/data/public/search/search_interceptor.ts index 1afcf4615ab5a..087ca9e4f5c47 100644 --- a/src/plugins/data/public/search/search_interceptor.ts +++ b/src/plugins/data/public/search/search_interceptor.ts @@ -20,6 +20,7 @@ import { get, memoize, trimEnd } from 'lodash'; import { BehaviorSubject, throwError, timer, defer, from, Observable, NEVER } from 'rxjs'; import { catchError, finalize } from 'rxjs/operators'; +import { PublicMethodsOf } from '@kbn/utility-types'; import { CoreStart, CoreSetup, ToastsSetup } from 'kibana/public'; import { i18n } from '@kbn/i18n'; import { diff --git a/src/plugins/data/public/search/search_service.test.ts b/src/plugins/data/public/search/search_service.test.ts index b59fa6fa16bf6..20041a02067d9 100644 --- a/src/plugins/data/public/search/search_service.test.ts +++ b/src/plugins/data/public/search/search_service.test.ts @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ - +import type { MockedKeys } from '@kbn/utility-types/jest'; import { coreMock } from '../../../../core/public/mocks'; import { CoreSetup, CoreStart } from '../../../../core/public'; diff --git a/src/plugins/data/server/search/routes/call_msearch.test.ts b/src/plugins/data/server/search/routes/call_msearch.test.ts index 3d409e22aaa88..183c2334b4e32 100644 --- a/src/plugins/data/server/search/routes/call_msearch.test.ts +++ b/src/plugins/data/server/search/routes/call_msearch.test.ts @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ - +import type { DeeplyMockedKeys } from '@kbn/utility-types/jest'; import { Observable } from 'rxjs'; import { IUiSettingsClient, IScopedClusterClient, SharedGlobalConfig } from 'src/core/server'; diff --git a/src/plugins/data/server/search/routes/msearch.test.ts b/src/plugins/data/server/search/routes/msearch.test.ts index 2f414fe0b4920..e2e5818cf9a72 100644 --- a/src/plugins/data/server/search/routes/msearch.test.ts +++ b/src/plugins/data/server/search/routes/msearch.test.ts @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ - +import type { MockedKeys } from '@kbn/utility-types/jest'; import { Observable } from 'rxjs'; import { diff --git a/src/plugins/data/server/search/routes/search.test.ts b/src/plugins/data/server/search/routes/search.test.ts index 834e5de5c3121..845ab3bbe4eb1 100644 --- a/src/plugins/data/server/search/routes/search.test.ts +++ b/src/plugins/data/server/search/routes/search.test.ts @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ - +import type { MockedKeys } from '@kbn/utility-types/jest'; import { Observable, from } from 'rxjs'; import { diff --git a/src/plugins/data/server/search/search_service.test.ts b/src/plugins/data/server/search/search_service.test.ts index a001d56b36514..2b513be147e9d 100644 --- a/src/plugins/data/server/search/search_service.test.ts +++ b/src/plugins/data/server/search/search_service.test.ts @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ - +import type { MockedKeys } from '@kbn/utility-types/jest'; import { CoreSetup, CoreStart } from '../../../../core/server'; import { coreMock } from '../../../../core/server/mocks'; diff --git a/src/plugins/data/server/search/search_source/mocks.ts b/src/plugins/data/server/search/search_source/mocks.ts index 7e9cc8f2ff42c..73b39b416316e 100644 --- a/src/plugins/data/server/search/search_source/mocks.ts +++ b/src/plugins/data/server/search/search_source/mocks.ts @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ - +import type { MockedKeys } from '@kbn/utility-types/jest'; import { KibanaRequest } from 'src/core/server'; import { searchSourceCommonMock } from '../../../common/search/search_source/mocks'; diff --git a/src/plugins/data/server/server.api.md b/src/plugins/data/server/server.api.md index 37f3e5ca6e5d1..2f2f472f5c45a 100644 --- a/src/plugins/data/server/server.api.md +++ b/src/plugins/data/server/server.api.md @@ -37,6 +37,7 @@ import { PathConfigType } from '@kbn/utils'; import { Plugin as Plugin_2 } from 'src/core/server'; import { Plugin as Plugin_3 } from 'kibana/server'; import { PluginInitializerContext as PluginInitializerContext_2 } from 'src/core/server'; +import { PublicMethodsOf } from '@kbn/utility-types'; import { RecursiveReadonly } from '@kbn/utility-types'; import { RequestAdapter } from 'src/plugins/inspector/common'; import { RequestHandlerContext } from 'src/core/server'; diff --git a/src/plugins/embeddable/public/components/panel_options_menu/__examples__/panel_options_menu.stories.tsx b/src/plugins/embeddable/public/components/panel_options_menu/__examples__/panel_options_menu.stories.tsx index 33724068a6ba8..551caa28d2291 100644 --- a/src/plugins/embeddable/public/components/panel_options_menu/__examples__/panel_options_menu.stories.tsx +++ b/src/plugins/embeddable/public/components/panel_options_menu/__examples__/panel_options_menu.stories.tsx @@ -17,37 +17,45 @@ * under the License. */ -import * as React from 'react'; -import { storiesOf } from '@storybook/react'; import { action } from '@storybook/addon-actions'; -import { withKnobs, boolean } from '@storybook/addon-knobs'; +import * as React from 'react'; import { PanelOptionsMenu } from '..'; -const euiContextDescriptors = { - id: 'mainMenu', - title: 'Options', - items: [ - { - name: 'Inspect', - icon: 'inspect', - onClick: action('onClick(inspect)'), - }, - { - name: 'Full screen', - icon: 'expand', - onClick: action('onClick(expand)'), +export default { + title: 'components/PanelOptionsMenu', + component: PanelOptionsMenu, + argTypes: { + isViewMode: { + control: { type: 'boolean' }, }, + }, + decorators: [ + (Story: React.ComponentType) => ( +
+ +
+ ), ], }; -storiesOf('components/PanelOptionsMenu', module) - .addDecorator(withKnobs) - .add('default', () => { - const isViewMode = boolean('isViewMode', false); +export function Default({ isViewMode }: React.ComponentProps) { + const euiContextDescriptors = { + id: 'mainMenu', + title: 'Options', + items: [ + { + name: 'Inspect', + icon: 'inspect', + onClick: action('onClick(inspect)'), + }, + { + name: 'Full screen', + icon: 'expand', + onClick: action('onClick(expand)'), + }, + ], + }; - return ( -
- -
- ); - }); + return ; +} +Default.args = { isViewMode: false } as React.ComponentProps; diff --git a/src/plugins/home/public/services/environment/environment.mock.ts b/src/plugins/home/public/services/environment/environment.mock.ts index d8be02bf6552c..7b1fb0a85e0d9 100644 --- a/src/plugins/home/public/services/environment/environment.mock.ts +++ b/src/plugins/home/public/services/environment/environment.mock.ts @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ - +import type { PublicMethodsOf } from '@kbn/utility-types'; import { EnvironmentService, EnvironmentServiceSetup } from './environment'; const createSetupMock = (): jest.Mocked => { diff --git a/src/plugins/home/public/services/feature_catalogue/feature_catalogue_registry.mock.ts b/src/plugins/home/public/services/feature_catalogue/feature_catalogue_registry.mock.ts index e1a415ba2d571..6cb4bb1db90a7 100644 --- a/src/plugins/home/public/services/feature_catalogue/feature_catalogue_registry.mock.ts +++ b/src/plugins/home/public/services/feature_catalogue/feature_catalogue_registry.mock.ts @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ - +import type { PublicMethodsOf } from '@kbn/utility-types'; import { FeatureCatalogueRegistrySetup, FeatureCatalogueRegistry, diff --git a/src/plugins/home/public/services/tutorials/tutorial_service.mock.ts b/src/plugins/home/public/services/tutorials/tutorial_service.mock.ts index 667730e25a2e3..7aa1aec0898fe 100644 --- a/src/plugins/home/public/services/tutorials/tutorial_service.mock.ts +++ b/src/plugins/home/public/services/tutorials/tutorial_service.mock.ts @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ - +import type { PublicMethodsOf } from '@kbn/utility-types'; import { TutorialService, TutorialServiceSetup } from './tutorial_service'; const createSetupMock = (): jest.Mocked => { diff --git a/src/plugins/home/server/services/sample_data/sample_data_registry.mock.ts b/src/plugins/home/server/services/sample_data/sample_data_registry.mock.ts index 4d0fb4f96023a..717f21576def9 100644 --- a/src/plugins/home/server/services/sample_data/sample_data_registry.mock.ts +++ b/src/plugins/home/server/services/sample_data/sample_data_registry.mock.ts @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ - +import type { PublicMethodsOf } from '@kbn/utility-types'; import { SampleDataRegistrySetup, SampleDataRegistryStart, diff --git a/src/plugins/home/server/services/tutorials/tutorials_registry.mock.ts b/src/plugins/home/server/services/tutorials/tutorials_registry.mock.ts index 5ff0152062f4b..162216161342c 100644 --- a/src/plugins/home/server/services/tutorials/tutorials_registry.mock.ts +++ b/src/plugins/home/server/services/tutorials/tutorials_registry.mock.ts @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ - +import type { PublicMethodsOf } from '@kbn/utility-types'; import { TutorialsRegistrySetup, TutorialsRegistryStart, diff --git a/src/plugins/home/server/services/tutorials/tutorials_registry.test.ts b/src/plugins/home/server/services/tutorials/tutorials_registry.test.ts index b91a265da7d18..96dab89bb1702 100644 --- a/src/plugins/home/server/services/tutorials/tutorials_registry.test.ts +++ b/src/plugins/home/server/services/tutorials/tutorials_registry.test.ts @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ - +import type { MockedKeys } from '@kbn/utility-types/jest'; import { TutorialsRegistry } from './tutorials_registry'; import { coreMock } from '../../../../../core/server/mocks'; import { CoreSetup } from '../../../../../core/server'; diff --git a/src/plugins/index_pattern_management/public/service/environment/environment.mock.ts b/src/plugins/index_pattern_management/public/service/environment/environment.mock.ts index 2c2c68b8ead2d..5ddbca67d9fec 100644 --- a/src/plugins/index_pattern_management/public/service/environment/environment.mock.ts +++ b/src/plugins/index_pattern_management/public/service/environment/environment.mock.ts @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ - +import type { PublicMethodsOf } from '@kbn/utility-types'; import { EnvironmentService, EnvironmentServiceSetup } from './environment'; import { MlCardState } from '../../types'; diff --git a/src/plugins/index_pattern_management/server/routes/preview_scripted_field.test.ts b/src/plugins/index_pattern_management/server/routes/preview_scripted_field.test.ts index 5de6ddf351c02..9d4c1bf005e63 100644 --- a/src/plugins/index_pattern_management/server/routes/preview_scripted_field.test.ts +++ b/src/plugins/index_pattern_management/server/routes/preview_scripted_field.test.ts @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ - +import type { MockedKeys } from '@kbn/utility-types/jest'; import { CoreSetup, RequestHandlerContext } from 'src/core/server'; import { coreMock, httpServerMock } from '../../../../../src/core/server/mocks'; import { registerPreviewScriptedFieldRoute } from './preview_scripted_field'; diff --git a/src/plugins/kibana_legacy/public/angular/kbn_top_nav.d.ts b/src/plugins/kibana_legacy/public/angular/kbn_top_nav.d.ts new file mode 100644 index 0000000000000..3d1dcdbef3f4b --- /dev/null +++ b/src/plugins/kibana_legacy/public/angular/kbn_top_nav.d.ts @@ -0,0 +1,31 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { Injectable, IDirectiveFactory, IScope, IAttributes, IController } from 'angular'; + +export const createTopNavDirective: Injectable>; +export const createTopNavHelper: ( + options: unknown +) => Injectable>; +export function loadKbnTopNavDirectives(navUi: unknown): void; diff --git a/src/plugins/kibana_legacy/public/angular/promises.d.ts b/src/plugins/kibana_legacy/public/angular/promises.d.ts new file mode 100644 index 0000000000000..1a2ce66834d7b --- /dev/null +++ b/src/plugins/kibana_legacy/public/angular/promises.d.ts @@ -0,0 +1,20 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +export function PromiseServiceCreator($q: unknown, $timeout: unknown): (fn: unknown) => unknown; diff --git a/src/plugins/kibana_legacy/public/angular/watch_multi.d.ts b/src/plugins/kibana_legacy/public/angular/watch_multi.d.ts new file mode 100644 index 0000000000000..7c73abf2f9aa2 --- /dev/null +++ b/src/plugins/kibana_legacy/public/angular/watch_multi.d.ts @@ -0,0 +1,20 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +export function watchMultiDecorator($provide: unknown): void; diff --git a/src/plugins/kibana_legacy/public/utils/kbn_accessible_click.d.ts b/src/plugins/kibana_legacy/public/utils/kbn_accessible_click.d.ts new file mode 100644 index 0000000000000..e4ef43fe8d443 --- /dev/null +++ b/src/plugins/kibana_legacy/public/utils/kbn_accessible_click.d.ts @@ -0,0 +1,27 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { Injectable, IDirectiveFactory, IScope, IAttributes, IController } from 'angular'; + +export const KbnAccessibleClickProvider: Injectable>; diff --git a/src/plugins/kibana_legacy/public/utils/private.d.ts b/src/plugins/kibana_legacy/public/utils/private.d.ts index 3efc9cd5308f7..00b0220316ead 100644 --- a/src/plugins/kibana_legacy/public/utils/private.d.ts +++ b/src/plugins/kibana_legacy/public/utils/private.d.ts @@ -17,4 +17,8 @@ * under the License. */ +import { IServiceProvider } from 'angular'; + export type IPrivate = (provider: (...injectable: any[]) => T) => T; + +export function PrivateProvider(): IServiceProvider; diff --git a/src/plugins/kibana_legacy/public/utils/register_listen_event_listener.d.ts b/src/plugins/kibana_legacy/public/utils/register_listen_event_listener.d.ts new file mode 100644 index 0000000000000..eff9b4b871f56 --- /dev/null +++ b/src/plugins/kibana_legacy/public/utils/register_listen_event_listener.d.ts @@ -0,0 +1,20 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +export function registerListenEventListener($rootScope: unknown): void; diff --git a/src/plugins/kibana_utils/public/storage/storage.test.ts b/src/plugins/kibana_utils/public/storage/storage.test.ts index 8c5d3d11a21fe..293194cae55a6 100644 --- a/src/plugins/kibana_utils/public/storage/storage.test.ts +++ b/src/plugins/kibana_utils/public/storage/storage.test.ts @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ - +import type { MockedKeys } from '@kbn/utility-types/jest'; import { Storage } from './storage'; import { IStorage, IStorageWrapper } from './types'; diff --git a/src/plugins/saved_objects_management/public/services/action_service.mock.ts b/src/plugins/saved_objects_management/public/services/action_service.mock.ts index 97c95a589b925..dfa5f47325eb6 100644 --- a/src/plugins/saved_objects_management/public/services/action_service.mock.ts +++ b/src/plugins/saved_objects_management/public/services/action_service.mock.ts @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ - +import type { PublicMethodsOf } from '@kbn/utility-types'; import { SavedObjectsManagementActionService, SavedObjectsManagementActionServiceSetup, diff --git a/src/plugins/saved_objects_management/public/services/column_service.mock.ts b/src/plugins/saved_objects_management/public/services/column_service.mock.ts index 977b2099771ba..9dfa130d463c5 100644 --- a/src/plugins/saved_objects_management/public/services/column_service.mock.ts +++ b/src/plugins/saved_objects_management/public/services/column_service.mock.ts @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ - +import type { PublicMethodsOf } from '@kbn/utility-types'; import { SavedObjectsManagementColumnService, SavedObjectsManagementColumnServiceSetup, diff --git a/src/plugins/saved_objects_management/public/services/service_registry.ts b/src/plugins/saved_objects_management/public/services/service_registry.ts index 2d6ec0b92047a..d4dc6d6166e46 100644 --- a/src/plugins/saved_objects_management/public/services/service_registry.ts +++ b/src/plugins/saved_objects_management/public/services/service_registry.ts @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ - +import type { PublicMethodsOf } from '@kbn/utility-types'; import { SavedObjectLoader } from '../../../saved_objects/public'; export interface SavedObjectsManagementServiceRegistryEntry { diff --git a/src/plugins/saved_objects_management/server/services/management.mock.ts b/src/plugins/saved_objects_management/server/services/management.mock.ts index 85c2d3e4b08d9..d765607316591 100644 --- a/src/plugins/saved_objects_management/server/services/management.mock.ts +++ b/src/plugins/saved_objects_management/server/services/management.mock.ts @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ - +import type { PublicMethodsOf } from '@kbn/utility-types'; import { SavedObjectsManagement } from './management'; type Management = PublicMethodsOf; diff --git a/src/plugins/saved_objects_management/server/services/management.ts b/src/plugins/saved_objects_management/server/services/management.ts index 499f37990c346..f24226d798fae 100644 --- a/src/plugins/saved_objects_management/server/services/management.ts +++ b/src/plugins/saved_objects_management/server/services/management.ts @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ - +import type { PublicMethodsOf } from '@kbn/utility-types'; import { ISavedObjectTypeRegistry, SavedObject } from 'src/core/server'; export type ISavedObjectsManagement = PublicMethodsOf; diff --git a/src/plugins/security_oss/public/plugin.mock.ts b/src/plugins/security_oss/public/plugin.mock.ts index c513d241dccbb..bb6e1c6bc6545 100644 --- a/src/plugins/security_oss/public/plugin.mock.ts +++ b/src/plugins/security_oss/public/plugin.mock.ts @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ - +import type { DeeplyMockedKeys } from '@kbn/utility-types/jest'; import { mockInsecureClusterService } from './insecure_cluster_service/insecure_cluster_service.mock'; import { SecurityOssPluginSetup, SecurityOssPluginStart } from './plugin'; diff --git a/src/plugins/share/public/services/share_menu_manager.mock.ts b/src/plugins/share/public/services/share_menu_manager.mock.ts index 7104abeb26090..c20543fea16db 100644 --- a/src/plugins/share/public/services/share_menu_manager.mock.ts +++ b/src/plugins/share/public/services/share_menu_manager.mock.ts @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ - +import type { PublicMethodsOf } from '@kbn/utility-types'; import { ShareMenuManager, ShareMenuManagerStart } from './share_menu_manager'; const createStartMock = (): jest.Mocked => { diff --git a/src/plugins/share/public/services/share_menu_registry.mock.ts b/src/plugins/share/public/services/share_menu_registry.mock.ts index b69032f0b3e09..2645b7a73fdfd 100644 --- a/src/plugins/share/public/services/share_menu_registry.mock.ts +++ b/src/plugins/share/public/services/share_menu_registry.mock.ts @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ - +import type { PublicMethodsOf } from '@kbn/utility-types'; import { ShareMenuRegistry, ShareMenuRegistrySetup, diff --git a/src/plugins/ui_actions/public/plugin.ts b/src/plugins/ui_actions/public/plugin.ts index f83cc97c2a8ef..87a1df959ccbd 100644 --- a/src/plugins/ui_actions/public/plugin.ts +++ b/src/plugins/ui_actions/public/plugin.ts @@ -18,6 +18,7 @@ */ import { CoreStart, CoreSetup, Plugin, PluginInitializerContext } from 'src/core/public'; +import { PublicMethodsOf } from '@kbn/utility-types'; import { UiActionsService } from './service'; import { selectRangeTrigger, diff --git a/src/plugins/ui_actions/public/public.api.md b/src/plugins/ui_actions/public/public.api.md index 229997281db49..8393f7480d4e4 100644 --- a/src/plugins/ui_actions/public/public.api.md +++ b/src/plugins/ui_actions/public/public.api.md @@ -12,6 +12,7 @@ import { Observable } from 'rxjs'; import { PackageInfo } from '@kbn/config'; import { Plugin } from 'src/core/public'; import { PluginInitializerContext as PluginInitializerContext_2 } from 'src/core/public'; +import { PublicMethodsOf } from '@kbn/utility-types'; import React from 'react'; import * as Rx from 'rxjs'; import { UiComponent } from 'src/plugins/kibana_utils/public'; diff --git a/src/plugins/url_forwarding/tsconfig.json b/src/plugins/url_forwarding/tsconfig.json new file mode 100644 index 0000000000000..8e867a6bad14f --- /dev/null +++ b/src/plugins/url_forwarding/tsconfig.json @@ -0,0 +1,15 @@ +{ + "extends": "../../../tsconfig.base.json", + "compilerOptions": { + "composite": true, + "outDir": "./target/types", + "emitDeclarationOnly": true, + "declaration": true, + "declarationMap": true + }, + "include": ["public/**/*"], + "references": [ + { "path": "../../core/tsconfig.json" }, + { "path": "../kibana_legacy/tsconfig.json" } + ] +} diff --git a/test/api_integration/apis/saved_objects/export.js b/test/api_integration/apis/saved_objects/export.ts similarity index 88% rename from test/api_integration/apis/saved_objects/export.js rename to test/api_integration/apis/saved_objects/export.ts index 0c37e6b782a35..7254f3b3fcf31 100644 --- a/test/api_integration/apis/saved_objects/export.js +++ b/test/api_integration/apis/saved_objects/export.ts @@ -18,8 +18,12 @@ */ import expect from '@kbn/expect'; +import type { FtrProviderContext } from '../../ftr_provider_context'; -export default function ({ getService }) { +function ndjsonToObject(input: string) { + return input.split('\n').map((str) => JSON.parse(str)); +} +export default function ({ getService }: FtrProviderContext) { const supertest = getService('supertest'); const es = getService('legacyEs'); const esArchiver = getService('esArchiver'); @@ -38,7 +42,7 @@ export default function ({ getService }) { }) .expect(200) .then((resp) => { - const objects = resp.text.split('\n').map(JSON.parse); + const objects = ndjsonToObject(resp.text); expect(objects).to.have.length(4); expect(objects[0]).to.have.property('id', '91200a00-9efd-11e7-acb3-3dab96693fab'); expect(objects[0]).to.have.property('type', 'index-pattern'); @@ -61,7 +65,7 @@ export default function ({ getService }) { }) .expect(200) .then((resp) => { - const objects = resp.text.split('\n').map(JSON.parse); + const objects = ndjsonToObject(resp.text); expect(objects).to.have.length(3); expect(objects[0]).to.have.property('id', '91200a00-9efd-11e7-acb3-3dab96693fab'); expect(objects[0]).to.have.property('type', 'index-pattern'); @@ -86,7 +90,7 @@ export default function ({ getService }) { }) .expect(200) .then((resp) => { - const objects = resp.text.split('\n').map(JSON.parse); + const objects = ndjsonToObject(resp.text); expect(objects).to.have.length(4); expect(objects[0]).to.have.property('id', '91200a00-9efd-11e7-acb3-3dab96693fab'); expect(objects[0]).to.have.property('type', 'index-pattern'); @@ -109,7 +113,7 @@ export default function ({ getService }) { }) .expect(200) .then((resp) => { - const objects = resp.text.split('\n').map(JSON.parse); + const objects = resp.text.split('\n').map((str) => JSON.parse(str)); expect(objects).to.have.length(4); expect(objects[0]).to.have.property('id', '91200a00-9efd-11e7-acb3-3dab96693fab'); expect(objects[0]).to.have.property('type', 'index-pattern'); @@ -133,7 +137,7 @@ export default function ({ getService }) { }) .expect(200) .then((resp) => { - const objects = resp.text.split('\n').map(JSON.parse); + const objects = ndjsonToObject(resp.text); expect(objects).to.have.length(4); expect(objects[0]).to.have.property('id', '91200a00-9efd-11e7-acb3-3dab96693fab'); expect(objects[0]).to.have.property('type', 'index-pattern'); @@ -217,6 +221,51 @@ export default function ({ getService }) { }); }); }); + + it('should export object with circular refs', async () => { + const soWithCycliRefs = [ + { + type: 'dashboard', + id: 'dashboard-a', + attributes: { + title: 'dashboard-a', + }, + references: [ + { + name: 'circular-dashboard-ref', + id: 'dashboard-b', + type: 'dashboard', + }, + ], + }, + { + type: 'dashboard', + id: 'dashboard-b', + attributes: { + title: 'dashboard-b', + }, + references: [ + { + name: 'circular-dashboard-ref', + id: 'dashboard-a', + type: 'dashboard', + }, + ], + }, + ]; + await supertest.post('/api/saved_objects/_bulk_create').send(soWithCycliRefs).expect(200); + const resp = await supertest + .post('/api/saved_objects/_export') + .send({ + includeReferencesDeep: true, + type: ['dashboard'], + }) + .expect(200); + + const objects = ndjsonToObject(resp.text); + expect(objects.find((o) => o.id === 'dashboard-a')).to.be.ok(); + expect(objects.find((o) => o.id === 'dashboard-b')).to.be.ok(); + }); }); describe('10,000 objects', () => { @@ -245,11 +294,11 @@ export default function ({ getService }) { }) .expect(200) .then((resp) => { - expect(resp.headers['content-disposition']).to.eql( + expect(resp.header['content-disposition']).to.eql( 'attachment; filename="export.ndjson"' ); - expect(resp.headers['content-type']).to.eql('application/ndjson'); - const objects = resp.text.split('\n').map(JSON.parse); + expect(resp.header['content-type']).to.eql('application/ndjson'); + const objects = ndjsonToObject(resp.text); expect(objects).to.eql([ { attributes: { @@ -304,11 +353,11 @@ export default function ({ getService }) { }) .expect(200) .then((resp) => { - expect(resp.headers['content-disposition']).to.eql( + expect(resp.header['content-disposition']).to.eql( 'attachment; filename="export.ndjson"' ); - expect(resp.headers['content-type']).to.eql('application/ndjson'); - const objects = resp.text.split('\n').map(JSON.parse); + expect(resp.header['content-type']).to.eql('application/ndjson'); + const objects = ndjsonToObject(resp.text); expect(objects).to.eql([ { attributes: { @@ -368,11 +417,11 @@ export default function ({ getService }) { }) .expect(200) .then((resp) => { - expect(resp.headers['content-disposition']).to.eql( + expect(resp.header['content-disposition']).to.eql( 'attachment; filename="export.ndjson"' ); - expect(resp.headers['content-type']).to.eql('application/ndjson'); - const objects = resp.text.split('\n').map(JSON.parse); + expect(resp.header['content-type']).to.eql('application/ndjson'); + const objects = ndjsonToObject(resp.text); expect(objects).to.eql([ { attributes: { @@ -443,7 +492,7 @@ export default function ({ getService }) { }); describe('10,001 objects', () => { - let customVisId; + let customVisId: string; before(async () => { await esArchiver.load('saved_objects/10k'); await supertest diff --git a/test/api_integration/apis/saved_objects/import.js b/test/api_integration/apis/saved_objects/import.ts similarity index 78% rename from test/api_integration/apis/saved_objects/import.js rename to test/api_integration/apis/saved_objects/import.ts index 1666df2c83e5a..bdb695ef20dd1 100644 --- a/test/api_integration/apis/saved_objects/import.js +++ b/test/api_integration/apis/saved_objects/import.ts @@ -19,8 +19,19 @@ import expect from '@kbn/expect'; import { join } from 'path'; +import dedent from 'dedent'; +import type { SavedObjectsImportError } from 'src/core/server'; +import type { FtrProviderContext } from '../../ftr_provider_context'; -export default function ({ getService }) { +const createConflictError = ( + object: Omit +): SavedObjectsImportError => ({ + ...object, + title: object.meta.title, + error: { type: 'conflict' }, +}); + +export default function ({ getService }: FtrProviderContext) { const supertest = getService('supertest'); const esArchiver = getService('esArchiver'); @@ -41,11 +52,6 @@ export default function ({ getService }) { id: 'be3733a0-9efe-11e7-acb3-3dab96693fab', meta: { title: 'Requests', icon: 'dashboardApp' }, }; - const createError = (object, type) => ({ - ...object, - title: object.meta.title, - error: { type }, - }); describe('with kibana index', () => { describe('with basic data existing', () => { @@ -75,9 +81,9 @@ export default function ({ getService }) { success: false, successCount: 0, errors: [ - createError(indexPattern, 'conflict'), - createError(visualization, 'conflict'), - createError(dashboard, 'conflict'), + createConflictError(indexPattern), + createConflictError(visualization), + createConflictError(dashboard), ], }); }); @@ -128,6 +134,43 @@ export default function ({ getService }) { }); }); + it('should return 200 when importing SO with circular refs', async () => { + const fileBuffer = Buffer.from( + dedent` + {"attributes":{"title":"dashboard-b"},"id":"dashboard-b","references":[{"id":"dashboard-a","name":"circular-dashboard-ref","type":"dashboard"}],"type":"dashboard"} + {"attributes":{"title":"dashboard-a"},"id":"dashboard-a","references":[{"id":"dashboard-b","name":"circular-dashboard-ref","type":"dashboard"}],"type":"dashboard"} + `, + 'utf8' + ); + const resp = await supertest + .post('/api/saved_objects/_import') + .attach('file', fileBuffer, 'export.ndjson') + .expect(200); + + expect(resp.body).to.eql({ + success: true, + successCount: 2, + successResults: [ + { + id: 'dashboard-b', + meta: { + icon: 'dashboardApp', + title: 'dashboard-b', + }, + type: 'dashboard', + }, + { + id: 'dashboard-a', + meta: { + icon: 'dashboardApp', + title: 'dashboard-a', + }, + type: 'dashboard', + }, + ], + }); + }); + it('should return 400 when trying to import more than 10,000 objects', async () => { const fileChunks = []; for (let i = 0; i < 10001; i++) { diff --git a/test/functional/apps/management/_import_objects.js b/test/functional/apps/management/_import_objects.ts similarity index 94% rename from test/functional/apps/management/_import_objects.js rename to test/functional/apps/management/_import_objects.ts index 3941b117e6efe..0b417d7d23e93 100644 --- a/test/functional/apps/management/_import_objects.js +++ b/test/functional/apps/management/_import_objects.ts @@ -20,10 +20,14 @@ import expect from '@kbn/expect'; import path from 'path'; import { keyBy } from 'lodash'; +import { FtrProviderContext } from '../../ftr_provider_context'; -const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); +const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); +function uniq(input: T[]): T[] { + return [...new Set(input)]; +} -export default function ({ getService, getPageObjects }) { +export default function ({ getService, getPageObjects }: FtrProviderContext) { const kibanaServer = getService('kibanaServer'); const esArchiver = getService('esArchiver'); const PageObjects = getPageObjects(['common', 'settings', 'header', 'savedObjects']); @@ -67,6 +71,24 @@ export default function ({ getService, getPageObjects }) { expect(flyout['Log Agents'].relationship).to.eql('Parent'); }); + it('should import saved objects with circular refs', async function () { + await PageObjects.savedObjects.importFile( + path.join(__dirname, 'exports', '_import_objects_circular_refs.ndjson') + ); + await PageObjects.savedObjects.checkImportSucceeded(); + await PageObjects.savedObjects.clickImportDone(); + + await PageObjects.savedObjects.clickRelationshipsByTitle('dashboard-a'); + + const flyoutContent = await PageObjects.savedObjects.getRelationshipFlyout(); + + expect(uniq(flyoutContent.map(({ relationship }) => relationship).sort())).to.eql([ + 'Child', + 'Parent', + ]); + expect(uniq(flyoutContent.map(({ title }) => title))).to.eql(['dashboard-b']); + }); + it('should provide dialog to allow the importing of saved objects with index pattern conflicts', async function () { await PageObjects.savedObjects.importFile( path.join(__dirname, 'exports', '_import_objects_conflicts.ndjson') diff --git a/test/functional/apps/management/exports/_import_objects_circular_refs.ndjson b/test/functional/apps/management/exports/_import_objects_circular_refs.ndjson new file mode 100644 index 0000000000000..44297e9e8f3e0 --- /dev/null +++ b/test/functional/apps/management/exports/_import_objects_circular_refs.ndjson @@ -0,0 +1,2 @@ +{"attributes":{"title":"dashboard-b"},"id":"dashboard-b","references":[{"id":"dashboard-a","name":"circular-dashboard-ref","type":"dashboard"}],"type":"dashboard"} +{"attributes":{"title":"dashboard-a"},"id":"dashboard-a","references":[{"id":"dashboard-b","name":"circular-dashboard-ref","type":"dashboard"}],"type":"dashboard"} diff --git a/test/functional/apps/management/index.js b/test/functional/apps/management/index.ts similarity index 94% rename from test/functional/apps/management/index.js rename to test/functional/apps/management/index.ts index d5f0c286af7a5..7365f912ea4fa 100644 --- a/test/functional/apps/management/index.js +++ b/test/functional/apps/management/index.ts @@ -16,8 +16,9 @@ * specific language governing permissions and limitations * under the License. */ +import { FtrProviderContext } from '../../ftr_provider_context'; -export default function ({ getService, loadTestFile }) { +export default function ({ getService, loadTestFile }: FtrProviderContext) { const esArchiver = getService('esArchiver'); describe('management', function () { diff --git a/test/functional/services/common/failure_debugging.ts b/test/functional/services/common/failure_debugging.ts index aa67c455e0100..8b0e095b71ff8 100644 --- a/test/functional/services/common/failure_debugging.ts +++ b/test/functional/services/common/failure_debugging.ts @@ -38,7 +38,7 @@ export async function FailureDebuggingProvider({ getService }: FtrProviderContex const log = getService('log'); const browser = getService('browser'); - if (process.env.CI !== 'true') { + if (process.env.CI !== 'true' && !process.env.stack_functional_integration) { await del(config.get('failureDebugging.htmlDirectory')); } diff --git a/test/functional/services/common/screenshots.ts b/test/functional/services/common/screenshots.ts index daa55240f3eb7..5bce0d4cf6c87 100644 --- a/test/functional/services/common/screenshots.ts +++ b/test/functional/services/common/screenshots.ts @@ -40,7 +40,7 @@ export async function ScreenshotsProvider({ getService }: FtrProviderContext) { const FAILURE_DIRECTORY = resolve(config.get('screenshots.directory'), 'failure'); const BASELINE_DIRECTORY = resolve(config.get('screenshots.directory'), 'baseline'); - if (process.env.CI !== 'true') { + if (process.env.CI !== 'true' && !process.env.stack_functional_integration) { await del([SESSION_DIRECTORY, FAILURE_DIRECTORY]); } diff --git a/test/functional/services/common/snapshots.ts b/test/functional/services/common/snapshots.ts index 2e0b360e594e5..03eadff82e31f 100644 --- a/test/functional/services/common/snapshots.ts +++ b/test/functional/services/common/snapshots.ts @@ -35,7 +35,7 @@ export async function SnapshotsProvider({ getService }: FtrProviderContext) { const SESSION_DIRECTORY = resolve(config.get('snapshots.directory'), 'session'); const BASELINE_DIRECTORY = resolve(config.get('snapshots.directory'), 'baseline'); - if (process.env.CI !== 'true') { + if (process.env.CI !== 'true' && !process.env.stack_functional_integration) { await del([SESSION_DIRECTORY]); } diff --git a/tsconfig.json b/tsconfig.json index a5775240cd302..f43f79389e30f 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -13,8 +13,9 @@ "src/plugins/kibana_usage_collection/**/*", "src/plugins/kibana_utils/**/*", "src/plugins/newsfeed/**/*", - "src/plugins/telemetry/**/*", "src/plugins/telemetry_collection_manager/**/*", + "src/plugins/telemetry/**/*", + "src/plugins/url_forwarding/**/*", "src/plugins/usage_collection/**/*" // In the build we actually exclude **/public/**/* from this config so that // we can run the TSC on both this and the .browser version of this config diff --git a/tsconfig.refs.json b/tsconfig.refs.json index bb1bdc08cafd6..6247761812581 100644 --- a/tsconfig.refs.json +++ b/tsconfig.refs.json @@ -1,14 +1,16 @@ { "include": [], "references": [ - { "path": "./src/test_utils/tsconfig.json" }, { "path": "./src/core/tsconfig.json" }, - { "path": "./src/plugins/kibana_utils/tsconfig.json" }, + { "path": "./src/test_utils/tsconfig.json" }, + { "path": "./src/plugins/kibana_legacy/tsconfig.json" }, { "path": "./src/plugins/kibana_react/tsconfig.json" }, - { "path": "./src/plugins/usage_collection/tsconfig.json" }, - { "path": "./src/plugins/telemetry_collection_manager/tsconfig.json" }, - { "path": "./src/plugins/telemetry/tsconfig.json" }, { "path": "./src/plugins/kibana_usage_collection/tsconfig.json" }, + { "path": "./src/plugins/kibana_utils/tsconfig.json" }, { "path": "./src/plugins/newsfeed/tsconfig.json" }, + { "path": "./src/plugins/telemetry/tsconfig.json" }, + { "path": "./src/plugins/telemetry_collection_manager/tsconfig.json" }, + { "path": "./src/plugins/url_forwarding/tsconfig.json" }, + { "path": "./src/plugins/usage_collection/tsconfig.json" } ] } diff --git a/typings/index.d.ts b/typings/index.d.ts index db6530d3f9e0b..fc16aa32fe3f9 100644 --- a/typings/index.d.ts +++ b/typings/index.d.ts @@ -34,22 +34,3 @@ declare module '*.svg' { // eslint-disable-next-line import/no-default-export export default content; } - -type MethodKeysOf = { - [K in keyof T]: T[K] extends (...args: any[]) => any ? K : never; -}[keyof T]; - -type PublicMethodsOf = Pick>; - -type MockedKeys = { [P in keyof T]: jest.Mocked }; - -type DeeplyMockedKeys = { - [P in keyof T]: T[P] extends (...args: any[]) => any - ? jest.MockInstance, Parameters> - : DeeplyMockedKeys; -} & - T; - -type Writable = { - -readonly [K in keyof T]: T[K]; -}; diff --git a/x-pack/.i18nrc.json b/x-pack/.i18nrc.json index 6c244d17dbdda..d71606e9b34e3 100644 --- a/x-pack/.i18nrc.json +++ b/x-pack/.i18nrc.json @@ -27,7 +27,7 @@ "xpack.idxMgmt": "plugins/index_management", "xpack.indexLifecycleMgmt": "plugins/index_lifecycle_management", "xpack.infra": "plugins/infra", - "xpack.ingestManager": "plugins/ingest_manager", + "xpack.fleet": "plugins/ingest_manager", "xpack.ingestPipelines": "plugins/ingest_pipelines", "xpack.lens": "plugins/lens", "xpack.licenseMgmt": "plugins/license_management", @@ -56,9 +56,7 @@ "xpack.watcher": "plugins/watcher", "xpack.observability": "plugins/observability" }, - "exclude": [ - "examples" - ], + "exclude": ["examples"], "translations": [ "plugins/translations/translations/zh-CN.json", "plugins/translations/translations/ja-JP.json" diff --git a/x-pack/plugins/actions/server/actions_client.mock.ts b/x-pack/plugins/actions/server/actions_client.mock.ts index 0c16c88ad7a89..2c2a818eb6eb2 100644 --- a/x-pack/plugins/actions/server/actions_client.mock.ts +++ b/x-pack/plugins/actions/server/actions_client.mock.ts @@ -3,7 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ - +import type { PublicMethodsOf } from '@kbn/utility-types'; import { ActionsClient } from './actions_client'; type ActionsClientContract = PublicMethodsOf; diff --git a/x-pack/plugins/actions/server/authorization/actions_authorization.mock.ts b/x-pack/plugins/actions/server/authorization/actions_authorization.mock.ts index 6b55c18241c55..59887f405a7dc 100644 --- a/x-pack/plugins/actions/server/authorization/actions_authorization.mock.ts +++ b/x-pack/plugins/actions/server/authorization/actions_authorization.mock.ts @@ -3,7 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ - +import type { PublicMethodsOf } from '@kbn/utility-types'; import { ActionsAuthorization } from './actions_authorization'; export type ActionsAuthorizationMock = jest.Mocked>; diff --git a/x-pack/plugins/actions/server/builtin_action_types/webhook.test.ts b/x-pack/plugins/actions/server/builtin_action_types/webhook.test.ts index 23ce527d4ae0d..74feb8ee57d48 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/webhook.test.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/webhook.test.ts @@ -90,8 +90,9 @@ describe('config validation', () => { }; test('config validation passes when only required fields are provided', () => { - const config: Record = { + const config: Record = { url: 'http://mylisteningserver:9200/endpoint', + hasAuth: true, }; expect(validateConfig(actionType, config)).toEqual({ ...defaultValues, @@ -101,9 +102,10 @@ describe('config validation', () => { test('config validation passes when valid methods are provided', () => { ['post', 'put'].forEach((method) => { - const config: Record = { + const config: Record = { url: 'http://mylisteningserver:9200/endpoint', method, + hasAuth: true, }; expect(validateConfig(actionType, config)).toEqual({ ...defaultValues, @@ -127,8 +129,9 @@ describe('config validation', () => { }); test('config validation passes when a url is specified', () => { - const config: Record = { + const config: Record = { url: 'http://mylisteningserver:9200/endpoint', + hasAuth: true, }; expect(validateConfig(actionType, config)).toEqual({ ...defaultValues, @@ -155,6 +158,7 @@ describe('config validation', () => { headers: { 'Content-Type': 'application/json', }, + hasAuth: true, }; expect(validateConfig(actionType, config)).toEqual({ ...defaultValues, @@ -184,6 +188,7 @@ describe('config validation', () => { headers: { 'Content-Type': 'application/json', }, + hasAuth: true, }; expect(validateConfig(actionType, config)).toEqual({ @@ -263,6 +268,7 @@ describe('execute()', () => { headers: { aheader: 'a value', }, + hasAuth: true, }; await actionType.executor({ actionId: 'some-id', @@ -320,6 +326,7 @@ describe('execute()', () => { headers: { aheader: 'a value', }, + hasAuth: false, }; const secrets: ActionTypeSecretsType = { user: null, password: null }; await actionType.executor({ diff --git a/x-pack/plugins/actions/server/builtin_action_types/webhook.ts b/x-pack/plugins/actions/server/builtin_action_types/webhook.ts index d0ec31721685e..dc9de86d3d951 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/webhook.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/webhook.ts @@ -42,6 +42,7 @@ const configSchemaProps = { defaultValue: WebhookMethods.POST, }), headers: nullableType(HeadersSchema), + hasAuth: schema.boolean({ defaultValue: true }), }; const ConfigSchema = schema.object(configSchemaProps); export type ActionTypeConfigType = TypeOf; @@ -128,12 +129,12 @@ export async function executor( execOptions: WebhookActionTypeExecutorOptions ): Promise> { const actionId = execOptions.actionId; - const { method, url, headers = {} } = execOptions.config; + const { method, url, headers = {}, hasAuth } = execOptions.config; const { body: data } = execOptions.params; const secrets: ActionTypeSecretsType = execOptions.secrets; const basicAuth = - isString(secrets.user) && isString(secrets.password) + hasAuth && isString(secrets.user) && isString(secrets.password) ? { auth: { username: secrets.user, password: secrets.password } } : {}; diff --git a/x-pack/plugins/actions/server/index.ts b/x-pack/plugins/actions/server/index.ts index bbe298c0585a3..39bfe2c2820e2 100644 --- a/x-pack/plugins/actions/server/index.ts +++ b/x-pack/plugins/actions/server/index.ts @@ -3,7 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ - +import type { PublicMethodsOf } from '@kbn/utility-types'; import { PluginInitializerContext, PluginConfigDescriptor } from '../../../../src/core/server'; import { ActionsPlugin } from './plugin'; import { configSchema } from './config'; diff --git a/x-pack/plugins/actions/server/lib/action_executor.ts b/x-pack/plugins/actions/server/lib/action_executor.ts index 0015b417d72ce..af70fbf2ec896 100644 --- a/x-pack/plugins/actions/server/lib/action_executor.ts +++ b/x-pack/plugins/actions/server/lib/action_executor.ts @@ -3,7 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ - +import type { PublicMethodsOf } from '@kbn/utility-types'; import { Logger, KibanaRequest } from 'src/core/server'; import { validateParams, validateConfig, validateSecrets } from './validate_with_schema'; import { diff --git a/x-pack/plugins/actions/server/lib/license_state.ts b/x-pack/plugins/actions/server/lib/license_state.ts index 902fadb3da170..e8cd0aa841cd9 100644 --- a/x-pack/plugins/actions/server/lib/license_state.ts +++ b/x-pack/plugins/actions/server/lib/license_state.ts @@ -5,6 +5,7 @@ */ import { i18n } from '@kbn/i18n'; +import type { PublicMethodsOf } from '@kbn/utility-types'; import { Observable, Subscription } from 'rxjs'; import { assertNever } from '@kbn/std'; import { ILicense } from '../../../licensing/common/types'; diff --git a/x-pack/plugins/actions/server/plugin.ts b/x-pack/plugins/actions/server/plugin.ts index 668e8b849b8a7..d0c7bf350504b 100644 --- a/x-pack/plugins/actions/server/plugin.ts +++ b/x-pack/plugins/actions/server/plugin.ts @@ -3,7 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ - +import type { PublicMethodsOf } from '@kbn/utility-types'; import { first, map } from 'rxjs/operators'; import { UsageCollectionSetup } from 'src/plugins/usage_collection/server'; import { diff --git a/x-pack/plugins/actions/server/routes/_mock_handler_arguments.ts b/x-pack/plugins/actions/server/routes/_mock_handler_arguments.ts index 06f65ff23106c..7b8b5f7b7f0e2 100644 --- a/x-pack/plugins/actions/server/routes/_mock_handler_arguments.ts +++ b/x-pack/plugins/actions/server/routes/_mock_handler_arguments.ts @@ -6,6 +6,7 @@ import { RequestHandlerContext, KibanaRequest, KibanaResponseFactory } from 'kibana/server'; import { identity } from 'lodash'; +import type { MethodKeysOf } from '@kbn/utility-types'; import { httpServerMock } from '../../../../../src/core/server/mocks'; import { ActionType } from '../../common'; import { ActionsClientMock, actionsClientMock } from '../actions_client.mock'; diff --git a/x-pack/plugins/actions/server/saved_objects/migrations.test.ts b/x-pack/plugins/actions/server/saved_objects/migrations.test.ts index 947d84fcfc638..f1bd1ba2aeb60 100644 --- a/x-pack/plugins/actions/server/saved_objects/migrations.test.ts +++ b/x-pack/plugins/actions/server/saved_objects/migrations.test.ts @@ -58,6 +58,63 @@ describe('7.10.0', () => { }); }); +describe('7.11.0', () => { + beforeEach(() => { + jest.resetAllMocks(); + encryptedSavedObjectsSetup.createMigration.mockImplementation( + (shouldMigrateWhenPredicate, migration) => migration + ); + }); + + test('add hasAuth = true for .webhook actions with user and password', () => { + const migration711 = getMigrations(encryptedSavedObjectsSetup)['7.11.0']; + const action = getMockDataForWebhook({}, true); + expect(migration711(action, context)).toMatchObject({ + ...action, + attributes: { + ...action.attributes, + config: { + hasAuth: true, + }, + }, + }); + }); + + test('add hasAuth = false for .webhook actions without user and password', () => { + const migration711 = getMigrations(encryptedSavedObjectsSetup)['7.11.0']; + const action = getMockDataForWebhook({}, false); + expect(migration711(action, context)).toMatchObject({ + ...action, + attributes: { + ...action.attributes, + config: { + hasAuth: false, + }, + }, + }); + }); +}); + +function getMockDataForWebhook( + overwrites: Record = {}, + hasUserAndPassword: boolean +): SavedObjectUnsanitizedDoc { + const secrets = hasUserAndPassword + ? { user: 'test', password: '123' } + : { user: '', password: '' }; + return { + attributes: { + name: 'abc', + actionTypeId: '.webhook', + config: {}, + secrets, + ...overwrites, + }, + id: uuid.v4(), + type: 'action', + }; +} + function getMockDataForEmail( overwrites: Record = {} ): SavedObjectUnsanitizedDoc { diff --git a/x-pack/plugins/actions/server/saved_objects/migrations.ts b/x-pack/plugins/actions/server/saved_objects/migrations.ts index 35d30accecedb..1e2290b14ec1b 100644 --- a/x-pack/plugins/actions/server/saved_objects/migrations.ts +++ b/x-pack/plugins/actions/server/saved_objects/migrations.ts @@ -25,8 +25,18 @@ export function getMigrations( pipeMigrations(renameCasesConfigurationObject, addHasAuthConfigurationObject) ); + const migrationWebhookConnectorHasAuth = encryptedSavedObjects.createMigration< + RawAction, + RawAction + >( + (doc): doc is SavedObjectUnsanitizedDoc => + doc.attributes.actionTypeId === '.webhook', + pipeMigrations(addHasAuthConfigurationObject) + ); + return { '7.10.0': executeMigrationWithErrorHandling(migrationActions, '7.10.0'), + '7.11.0': executeMigrationWithErrorHandling(migrationWebhookConnectorHasAuth, '7.11.0'), }; } @@ -70,7 +80,7 @@ function renameCasesConfigurationObject( const addHasAuthConfigurationObject = ( doc: SavedObjectUnsanitizedDoc ): SavedObjectUnsanitizedDoc => { - if (doc.attributes.actionTypeId !== '.email') { + if (doc.attributes.actionTypeId !== '.email' && doc.attributes.actionTypeId !== '.webhook') { return doc; } const hasAuth = !!doc.attributes.secrets.user || !!doc.attributes.secrets.password; diff --git a/x-pack/plugins/actions/server/types.ts b/x-pack/plugins/actions/server/types.ts index a8db8bfd7344c..1867815bd5f90 100644 --- a/x-pack/plugins/actions/server/types.ts +++ b/x-pack/plugins/actions/server/types.ts @@ -3,7 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ - +import type { PublicMethodsOf } from '@kbn/utility-types'; import { ActionTypeRegistry } from './action_type_registry'; import { PluginSetupContract, PluginStartContract } from './plugin'; import { ActionsClient } from './actions_client'; diff --git a/x-pack/plugins/alerts/public/alert_navigation_registry/alert_navigation_registry.mock.ts b/x-pack/plugins/alerts/public/alert_navigation_registry/alert_navigation_registry.mock.ts index 792bd8e885ea6..c800579fddffd 100644 --- a/x-pack/plugins/alerts/public/alert_navigation_registry/alert_navigation_registry.mock.ts +++ b/x-pack/plugins/alerts/public/alert_navigation_registry/alert_navigation_registry.mock.ts @@ -3,7 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ - +import type { PublicMethodsOf } from '@kbn/utility-types'; import { AlertNavigationRegistry } from './alert_navigation_registry'; type Schema = PublicMethodsOf; diff --git a/x-pack/plugins/alerts/server/alert_type_registry.mock.ts b/x-pack/plugins/alerts/server/alert_type_registry.mock.ts index b6b36e4d4b7e0..39d15eba014c9 100644 --- a/x-pack/plugins/alerts/server/alert_type_registry.mock.ts +++ b/x-pack/plugins/alerts/server/alert_type_registry.mock.ts @@ -3,7 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ - +import type { PublicMethodsOf } from '@kbn/utility-types'; import { AlertTypeRegistry } from './alert_type_registry'; type Schema = PublicMethodsOf; diff --git a/x-pack/plugins/alerts/server/alerts_client.mock.ts b/x-pack/plugins/alerts/server/alerts_client.mock.ts index b28e9f805f725..c9063457fac80 100644 --- a/x-pack/plugins/alerts/server/alerts_client.mock.ts +++ b/x-pack/plugins/alerts/server/alerts_client.mock.ts @@ -3,7 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ - +import type { PublicMethodsOf } from '@kbn/utility-types'; import { AlertsClient } from './alerts_client'; type Schema = PublicMethodsOf; diff --git a/x-pack/plugins/alerts/server/authorization/alerts_authorization.mock.ts b/x-pack/plugins/alerts/server/authorization/alerts_authorization.mock.ts index 3728daa946d5b..171e3978d0d0d 100644 --- a/x-pack/plugins/alerts/server/authorization/alerts_authorization.mock.ts +++ b/x-pack/plugins/alerts/server/authorization/alerts_authorization.mock.ts @@ -3,7 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ - +import type { PublicMethodsOf } from '@kbn/utility-types'; import { AlertsAuthorization } from './alerts_authorization'; type Schema = PublicMethodsOf; diff --git a/x-pack/plugins/alerts/server/index.ts b/x-pack/plugins/alerts/server/index.ts index 72d3a65220565..1e442c5196cf2 100644 --- a/x-pack/plugins/alerts/server/index.ts +++ b/x-pack/plugins/alerts/server/index.ts @@ -3,7 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ - +import type { PublicMethodsOf } from '@kbn/utility-types'; import { AlertsClient as AlertsClientClass } from './alerts_client'; import { PluginInitializerContext } from '../../../../src/core/server'; import { AlertingPlugin } from './plugin'; diff --git a/x-pack/plugins/alerts/server/plugin.ts b/x-pack/plugins/alerts/server/plugin.ts index 03302d5e6e7db..565b2992b1f7a 100644 --- a/x-pack/plugins/alerts/server/plugin.ts +++ b/x-pack/plugins/alerts/server/plugin.ts @@ -3,7 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ - +import type { PublicMethodsOf } from '@kbn/utility-types'; import { first, map } from 'rxjs/operators'; import { UsageCollectionSetup } from 'src/plugins/usage_collection/server'; import { SecurityPluginSetup } from '../../security/server'; diff --git a/x-pack/plugins/alerts/server/routes/_mock_handler_arguments.ts b/x-pack/plugins/alerts/server/routes/_mock_handler_arguments.ts index 548495866ec21..3d13fc65ab260 100644 --- a/x-pack/plugins/alerts/server/routes/_mock_handler_arguments.ts +++ b/x-pack/plugins/alerts/server/routes/_mock_handler_arguments.ts @@ -11,6 +11,7 @@ import { ILegacyClusterClient, } from 'kibana/server'; import { identity } from 'lodash'; +import type { MethodKeysOf } from '@kbn/utility-types'; import { httpServerMock } from '../../../../../src/core/server/mocks'; import { alertsClientMock, AlertsClientMock } from '../alerts_client.mock'; import { AlertType } from '../../common'; diff --git a/x-pack/plugins/alerts/server/task_runner/task_runner.ts b/x-pack/plugins/alerts/server/task_runner/task_runner.ts index 7da16717aef9f..954c5675df89c 100644 --- a/x-pack/plugins/alerts/server/task_runner/task_runner.ts +++ b/x-pack/plugins/alerts/server/task_runner/task_runner.ts @@ -3,7 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ - +import type { PublicMethodsOf } from '@kbn/utility-types'; import { pickBy, mapValues, without } from 'lodash'; import { Logger, KibanaRequest } from '../../../../../src/core/server'; import { TaskRunnerContext } from './task_runner_factory'; diff --git a/x-pack/plugins/alerts/server/task_runner/task_runner_factory.ts b/x-pack/plugins/alerts/server/task_runner/task_runner_factory.ts index 944c4dc64ce7a..df6f306c6ccc5 100644 --- a/x-pack/plugins/alerts/server/task_runner/task_runner_factory.ts +++ b/x-pack/plugins/alerts/server/task_runner/task_runner_factory.ts @@ -3,6 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ +import type { PublicMethodsOf } from '@kbn/utility-types'; import { Logger, KibanaRequest, ISavedObjectsRepository } from '../../../../../src/core/server'; import { RunContext } from '../../../task_manager/server'; import { EncryptedSavedObjectsClient } from '../../../encrypted_saved_objects/server'; diff --git a/x-pack/plugins/alerts/server/types.ts b/x-pack/plugins/alerts/server/types.ts index 74153d1ca6b1d..42eef9bba10e5 100644 --- a/x-pack/plugins/alerts/server/types.ts +++ b/x-pack/plugins/alerts/server/types.ts @@ -3,7 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ - +import type { PublicMethodsOf } from '@kbn/utility-types'; import { AlertInstance } from './alert_instance'; import { AlertTypeRegistry as OrigAlertTypeRegistry } from './alert_type_registry'; import { PluginSetupContract, PluginStartContract } from './plugin'; diff --git a/x-pack/plugins/apm/e2e/cypress/support/step_definitions/csm/js_errors.ts b/x-pack/plugins/apm/e2e/cypress/support/step_definitions/csm/js_errors.ts index 0dbefb73e68c4..9e10e2fd59914 100644 --- a/x-pack/plugins/apm/e2e/cypress/support/step_definitions/csm/js_errors.ts +++ b/x-pack/plugins/apm/e2e/cypress/support/step_definitions/csm/js_errors.ts @@ -12,12 +12,7 @@ Then(`it displays list of relevant js errors`, () => { cy.get('.euiBasicTable-loading').should('not.be.visible'); cy.get('.euiStat__title-isLoading').should('not.be.visible'); - getDataTestSubj('uxJsErrorsTotal').should('have.text', 'Total errors110'); - - getDataTestSubj('uxJsErrorRate').should( - 'have.text', - 'Error rate100 %Error rate 100 %' - ); + getDataTestSubj('uxJsErrorsTotal').should('have.text', 'Total errors112'); getDataTestSubj('uxJsErrorTable').within(() => { cy.get('tr.euiTableRow', DEFAULT_TIMEOUT) diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/ImpactfulMetrics/JSErrors.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/ImpactfulMetrics/JSErrors.tsx index 7a7c051817555..58f00604b8fda 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/ImpactfulMetrics/JSErrors.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/ImpactfulMetrics/JSErrors.tsx @@ -15,7 +15,6 @@ import { EuiToolTip, } from '@elastic/eui'; import numeral from '@elastic/numeral'; -import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import { useUrlParams } from '../../../../hooks/useUrlParams'; import { useFetcher } from '../../../../hooks/useFetcher'; @@ -102,11 +101,6 @@ export function JSErrors() { }); }; - const errorRate = - totalPageViews > 0 - ? ((data?.totalErrorPages ?? 0) / totalPageViews) * 100 - : 0; - const totalErrors = data?.totalErrors ?? 0; return ( @@ -133,20 +127,6 @@ export function JSErrors() { isLoading={status !== 'success'} /> - - - {' '} void; popoverIsOpen: boolean; + initialValue?: string; setPopoverIsOpen: React.Dispatch>; } @@ -80,6 +82,7 @@ export function SelectableUrlList({ onClose, popoverIsOpen, setPopoverIsOpen, + initialValue, }: Props) { const [darkMode] = useUiSetting$('theme:darkMode'); @@ -92,6 +95,9 @@ export function SelectableUrlList({ if (evt.key.toLowerCase() === 'enter') { onTermChange(); setPopoverIsOpen(false); + if (searchRef) { + searchRef.blur(); + } } }; @@ -126,6 +132,16 @@ export function SelectableUrlList({ } }; + useEffect(() => { + if (searchRef && initialValue) { + searchRef.value = initialValue; + } + + // only want to call it at initial render to set value + // coming from initial value/url + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [searchRef]); + const loadingMessage = ( @@ -165,12 +181,12 @@ export function SelectableUrlList({ renderOption={selectableRenderOptions} singleSelection={false} searchProps={{ - placeholder: I18LABELS.searchByUrl, isClearable: true, onFocus: searchOnFocus, onBlur: searchOnBlur, onInput: onSearchInput, inputRef: setSearchRef, + placeholder: I18LABELS.searchByUrl, }} listProps={{ rowHeight: 68, @@ -197,7 +213,7 @@ export function SelectableUrlList({ {searchValue}, icon: ( diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/URLFilter/URLSearch/__tests__/SelectableUrlList.test.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/URLFilter/URLSearch/__tests__/SelectableUrlList.test.tsx new file mode 100644 index 0000000000000..abafdf089748b --- /dev/null +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/URLFilter/URLSearch/__tests__/SelectableUrlList.test.tsx @@ -0,0 +1,41 @@ +/* + * 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 { createMemoryHistory } from 'history'; +import * as fetcherHook from '../../../../../../hooks/useFetcher'; +import { SelectableUrlList } from '../SelectableUrlList'; +import { render } from '../../../utils/test_helper'; + +describe('SelectableUrlList', () => { + it('it uses search term value from url', () => { + jest.spyOn(fetcherHook, 'useFetcher').mockReturnValue({ + data: {}, + status: fetcherHook.FETCH_STATUS.SUCCESS, + refetch: jest.fn(), + }); + + const customHistory = createMemoryHistory({ + initialEntries: ['/?searchTerm=blog'], + }); + + const { getByDisplayValue } = render( + , + { customHistory } + ); + expect(getByDisplayValue('blog')).toBeInTheDocument(); + }); +}); diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/URLFilter/URLSearch/index.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/URLFilter/URLSearch/index.tsx index 661f4406990f6..02334be5f722e 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/URLFilter/URLSearch/index.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/URLFilter/URLSearch/index.tsx @@ -30,9 +30,9 @@ export function URLSearch({ onChange: onFilterChange }: Props) { const [popoverIsOpen, setPopoverIsOpen] = useState(false); - const [searchValue, setSearchValue] = useState(''); + const [searchValue, setSearchValue] = useState(searchTerm ?? ''); - const [debouncedValue, setDebouncedValue] = useState(''); + const [debouncedValue, setDebouncedValue] = useState(searchTerm ?? ''); useDebounce( () => { @@ -44,12 +44,16 @@ export function URLSearch({ onChange: onFilterChange }: Props) { const updateSearchTerm = useCallback( (searchTermN: string) => { + const newQuery = { + ...toQuery(history.location.search), + searchTerm: searchTermN || undefined, + }; + if (!searchTermN) { + delete newQuery.searchTerm; + } const newLocation = { ...history.location, - search: fromQuery({ - ...toQuery(history.location.search), - searchTerm: searchTermN, - }), + search: fromQuery(newQuery), }; history.push(newLocation); }, @@ -133,6 +137,7 @@ export function URLSearch({ onChange: onFilterChange }: Props) {

{I18LABELS.url}

true, + get$: (key: string) => of(true), + }, +} as unknown) as CoreStart; + +export const render = ( + component: React.ReactNode, + options: { customHistory: MemoryHistory } +) => { + const history = options?.customHistory ?? createMemoryHistory(); + + history.location.key = 'TestKeyForTesting'; + + return testLibRender( + + + + {component} + + + + ); +}; diff --git a/x-pack/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/SyncBadge.stories.tsx b/x-pack/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/SyncBadge.stories.tsx index a5393995f0864..0e517f6bf6212 100644 --- a/x-pack/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/SyncBadge.stories.tsx +++ b/x-pack/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/SyncBadge.stories.tsx @@ -4,27 +4,20 @@ * you may not use this file except in compliance with the Elastic License. */ -import { boolean, withKnobs } from '@storybook/addon-knobs'; -import { storiesOf } from '@storybook/react'; -import React from 'react'; +import React, { ComponentProps } from 'react'; import { SyncBadge } from './SyncBadge'; -storiesOf('app/TransactionDetails/SyncBadge', module) - .addDecorator(withKnobs) - .add( - 'example', - () => { - return ; +export default { + title: 'app/TransactionDetails/SyncBadge', + component: SyncBadge, + argTypes: { + sync: { + control: { type: 'inline-radio', options: [true, false, undefined] }, }, - { - showPanel: true, - info: { source: false }, - } - ) - .add( - 'sync=undefined', - () => { - return ; - }, - { info: { source: false } } - ); + }, +}; + +export function Example({ sync }: ComponentProps) { + return ; +} +Example.args = { sync: true } as ComponentProps; diff --git a/x-pack/plugins/apm/server/lib/rum_client/__snapshots__/queries.test.ts.snap b/x-pack/plugins/apm/server/lib/rum_client/__snapshots__/queries.test.ts.snap index 1fafa08082443..eedc3a83cd376 100644 --- a/x-pack/plugins/apm/server/lib/rum_client/__snapshots__/queries.test.ts.snap +++ b/x-pack/plugins/apm/server/lib/rum_client/__snapshots__/queries.test.ts.snap @@ -9,31 +9,35 @@ Object { }, "body": Object { "aggs": Object { - "backEnd": Object { - "percentiles": Object { - "field": "transaction.marks.agent.timeToFirstByte", - "hdr": Object { - "number_of_significant_value_digits": 3, + "hasFetchStartField": Object { + "aggs": Object { + "backEnd": Object { + "percentiles": Object { + "field": "transaction.marks.agent.timeToFirstByte", + "hdr": Object { + "number_of_significant_value_digits": 3, + }, + "percents": Array [ + 50, + ], + }, }, - "percents": Array [ - 50, - ], - }, - }, - "domInteractive": Object { - "percentiles": Object { - "field": "transaction.marks.agent.domInteractive", - "hdr": Object { - "number_of_significant_value_digits": 3, + "domInteractive": Object { + "percentiles": Object { + "field": "transaction.marks.agent.domInteractive", + "hdr": Object { + "number_of_significant_value_digits": 3, + }, + "percents": Array [ + 50, + ], + }, }, - "percents": Array [ - 50, - ], }, - }, - "pageViews": Object { - "value_count": Object { - "field": "transaction.duration.us", + "filter": Object { + "exists": Object { + "field": "transaction.marks.navigationTiming.fetchStart", + }, }, }, }, @@ -54,11 +58,6 @@ Object { "transaction.type": "page-load", }, }, - Object { - "exists": Object { - "field": "transaction.marks.navigationTiming.fetchStart", - }, - }, Object { "term": Object { "service.environment": "test", @@ -68,6 +67,7 @@ Object { }, }, "size": 0, + "track_total_hits": true, }, } `; @@ -139,11 +139,6 @@ Object { "agent.name": "rum-js", }, }, - Object { - "term": Object { - "transaction.type": "page-load", - }, - }, Object { "term": Object { "service.language.name": "javascript", @@ -545,11 +540,6 @@ Object { "transaction.type": "page-load", }, }, - Object { - "exists": Object { - "field": "transaction.marks.navigationTiming.fetchStart", - }, - }, Object { "term": Object { "service.environment": "test", diff --git a/x-pack/plugins/apm/server/lib/rum_client/get_client_metrics.ts b/x-pack/plugins/apm/server/lib/rum_client/get_client_metrics.ts index 6d596246d6af9..da65e69e7eb7c 100644 --- a/x-pack/plugins/apm/server/lib/rum_client/get_client_metrics.ts +++ b/x-pack/plugins/apm/server/lib/rum_client/get_client_metrics.ts @@ -4,7 +4,6 @@ * you may not use this file except in compliance with the Elastic License. */ -import { TRANSACTION_DURATION } from '../../../common/elasticsearch_fieldnames'; import { getRumPageLoadTransactionsProjection } from '../../projections/rum_page_load_transactions'; import { mergeProjection } from '../../projections/util/merge_projection'; import { Setup, SetupTimeRange } from '../helpers/setup_request'; @@ -25,32 +24,36 @@ export async function getClientMetrics({ const projection = getRumPageLoadTransactionsProjection({ setup, urlQuery, + checkFetchStartFieldExists: false, }); const params = mergeProjection(projection, { body: { size: 0, + track_total_hits: true, aggs: { - pageViews: { - value_count: { - field: TRANSACTION_DURATION, + hasFetchStartField: { + filter: { + exists: { field: 'transaction.marks.navigationTiming.fetchStart' }, }, - }, - backEnd: { - percentiles: { - field: TRANSACTION_TIME_TO_FIRST_BYTE, - percents: [percentile], - hdr: { - number_of_significant_value_digits: 3, + aggs: { + backEnd: { + percentiles: { + field: TRANSACTION_TIME_TO_FIRST_BYTE, + percents: [percentile], + hdr: { + number_of_significant_value_digits: 3, + }, + }, }, - }, - }, - domInteractive: { - percentiles: { - field: TRANSACTION_DOM_INTERACTIVE, - percents: [percentile], - hdr: { - number_of_significant_value_digits: 3, + domInteractive: { + percentiles: { + field: TRANSACTION_DOM_INTERACTIVE, + percents: [percentile], + hdr: { + number_of_significant_value_digits: 3, + }, + }, }, }, }, @@ -59,15 +62,16 @@ export async function getClientMetrics({ }); const { apmEventClient } = setup; - const response = await apmEventClient.search(params); - const { backEnd, domInteractive, pageViews } = response.aggregations!; + const { + hasFetchStartField: { backEnd, domInteractive }, + } = response.aggregations!; const pkey = percentile.toFixed(1); // Divide by 1000 to convert ms into seconds return { - pageViews, + pageViews: { value: response.hits.total.value ?? 0 }, backEnd: { value: backEnd.values[pkey] || 0 }, frontEnd: { value: (domInteractive.values[pkey] || 0) - (backEnd.values[pkey] || 0), diff --git a/x-pack/plugins/apm/server/lib/rum_client/get_page_view_trends.ts b/x-pack/plugins/apm/server/lib/rum_client/get_page_view_trends.ts index c1a602c33feae..f483acba4b934 100644 --- a/x-pack/plugins/apm/server/lib/rum_client/get_page_view_trends.ts +++ b/x-pack/plugins/apm/server/lib/rum_client/get_page_view_trends.ts @@ -20,6 +20,7 @@ export async function getPageViewTrends({ const projection = getRumPageLoadTransactionsProjection({ setup, urlQuery, + checkFetchStartFieldExists: false, }); let breakdownItem: BreakdownItem | null = null; if (breakdowns) { diff --git a/x-pack/plugins/apm/server/projections/rum_page_load_transactions.ts b/x-pack/plugins/apm/server/projections/rum_page_load_transactions.ts index 530ca36b5dc9f..9c33da2278694 100644 --- a/x-pack/plugins/apm/server/projections/rum_page_load_transactions.ts +++ b/x-pack/plugins/apm/server/projections/rum_page_load_transactions.ts @@ -17,9 +17,11 @@ import { TRANSACTION_PAGE_LOAD } from '../../common/transaction_types'; export function getRumPageLoadTransactionsProjection({ setup, urlQuery, + checkFetchStartFieldExists = true, }: { setup: Setup & SetupTimeRange; urlQuery?: string; + checkFetchStartFieldExists?: boolean; }) { const { start, end, esFilter } = setup; @@ -27,13 +29,17 @@ export function getRumPageLoadTransactionsProjection({ filter: [ { range: rangeFilter(start, end) }, { term: { [TRANSACTION_TYPE]: TRANSACTION_PAGE_LOAD } }, - { - // Adding this filter to cater for some inconsistent rum data - // not available on aggregated transactions - exists: { - field: 'transaction.marks.navigationTiming.fetchStart', - }, - }, + ...(checkFetchStartFieldExists + ? [ + { + // Adding this filter to cater for some inconsistent rum data + // not available on aggregated transactions + exists: { + field: 'transaction.marks.navigationTiming.fetchStart', + }, + }, + ] + : []), ...(urlQuery ? [ { @@ -74,7 +80,6 @@ export function getRumErrorsProjection({ filter: [ { range: rangeFilter(start, end) }, { term: { [AGENT_NAME]: 'rum-js' } }, - { term: { [TRANSACTION_TYPE]: TRANSACTION_PAGE_LOAD } }, { term: { [SERVICE_LANGUAGE_NAME]: 'javascript', diff --git a/x-pack/plugins/case/server/client/cases/create.test.ts b/x-pack/plugins/case/server/client/cases/create.test.ts new file mode 100644 index 0000000000000..f253dd9f4feb4 --- /dev/null +++ b/x-pack/plugins/case/server/client/cases/create.test.ts @@ -0,0 +1,335 @@ +/* + * 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 { ConnectorTypes, CasePostRequest } from '../../../common/api'; + +import { + createMockSavedObjectsRepository, + mockCaseConfigure, + mockCases, +} from '../../routes/api/__fixtures__'; +import { createCaseClientWithMockSavedObjectsClient } from '../mocks'; + +describe('create', () => { + beforeEach(async () => { + jest.restoreAllMocks(); + const spyOnDate = jest.spyOn(global, 'Date') as jest.SpyInstance<{}, []>; + spyOnDate.mockImplementation(() => ({ + toISOString: jest.fn().mockReturnValue('2019-11-25T21:54:48.952Z'), + })); + }); + + describe('happy path', () => { + test('it creates the case correctly', async () => { + const postCase = { + description: 'This is a brand new case of a bad meanie defacing data', + title: 'Super Bad Security Issue', + tags: ['defacement'], + connector: { + id: '123', + name: 'Jira', + type: ConnectorTypes.jira, + fields: { issueType: 'Task', priority: 'High', parent: null }, + }, + } as CasePostRequest; + + const savedObjectsClient = createMockSavedObjectsRepository({ + caseSavedObject: mockCases, + caseConfigureSavedObject: mockCaseConfigure, + }); + const caseClient = await createCaseClientWithMockSavedObjectsClient(savedObjectsClient); + const res = await caseClient.client.create({ theCase: postCase }); + + expect(res).toEqual({ + id: 'mock-it', + comments: [], + totalComment: 0, + closed_at: null, + closed_by: null, + connector: { + id: '123', + name: 'Jira', + type: ConnectorTypes.jira, + fields: { issueType: 'Task', priority: 'High', parent: null }, + }, + created_at: '2019-11-25T21:54:48.952Z', + created_by: { full_name: 'Awesome D00d', email: 'd00d@awesome.com', username: 'awesome' }, + description: 'This is a brand new case of a bad meanie defacing data', + external_service: null, + title: 'Super Bad Security Issue', + status: 'open', + tags: ['defacement'], + updated_at: null, + updated_by: null, + version: 'WzksMV0=', + }); + + expect( + caseClient.services.userActionService.postUserActions.mock.calls[0][0].actions + ).toEqual([ + { + attributes: { + action: 'create', + action_at: '2019-11-25T21:54:48.952Z', + action_by: { + email: 'd00d@awesome.com', + full_name: 'Awesome D00d', + username: 'awesome', + }, + action_field: ['description', 'status', 'tags', 'title', 'connector'], + new_value: + '{"description":"This is a brand new case of a bad meanie defacing data","title":"Super Bad Security Issue","tags":["defacement"],"connector":{"id":"123","name":"Jira","type":".jira","fields":{"issueType":"Task","priority":"High","parent":null}}}', + old_value: null, + }, + references: [ + { + id: 'mock-it', + name: 'associated-cases', + type: 'cases', + }, + ], + }, + ]); + }); + + test('it creates the case without connector in the configuration', async () => { + const postCase = { + description: 'This is a brand new case of a bad meanie defacing data', + title: 'Super Bad Security Issue', + tags: ['defacement'], + connector: { + id: 'none', + name: 'none', + type: ConnectorTypes.none, + fields: null, + }, + }; + + const savedObjectsClient = createMockSavedObjectsRepository({ + caseSavedObject: mockCases, + }); + const caseClient = await createCaseClientWithMockSavedObjectsClient(savedObjectsClient); + const res = await caseClient.client.create({ theCase: postCase }); + + expect(res).toEqual({ + id: 'mock-it', + comments: [], + totalComment: 0, + closed_at: null, + closed_by: null, + connector: { id: 'none', name: 'none', type: ConnectorTypes.none, fields: null }, + created_at: '2019-11-25T21:54:48.952Z', + created_by: { full_name: 'Awesome D00d', email: 'd00d@awesome.com', username: 'awesome' }, + description: 'This is a brand new case of a bad meanie defacing data', + external_service: null, + title: 'Super Bad Security Issue', + status: 'open', + tags: ['defacement'], + updated_at: null, + updated_by: null, + version: 'WzksMV0=', + }); + }); + + test('Allow user to create case without authentication', async () => { + const postCase = { + description: 'This is a brand new case of a bad meanie defacing data', + title: 'Super Bad Security Issue', + tags: ['defacement'], + connector: { + id: 'none', + name: 'none', + type: ConnectorTypes.none, + fields: null, + }, + }; + + const savedObjectsClient = createMockSavedObjectsRepository({ + caseSavedObject: mockCases, + }); + const caseClient = await createCaseClientWithMockSavedObjectsClient(savedObjectsClient, true); + const res = await caseClient.client.create({ theCase: postCase }); + + expect(res).toEqual({ + id: 'mock-it', + comments: [], + totalComment: 0, + closed_at: null, + closed_by: null, + connector: { id: 'none', name: 'none', type: ConnectorTypes.none, fields: null }, + created_at: '2019-11-25T21:54:48.952Z', + created_by: { + email: null, + full_name: null, + username: null, + }, + description: 'This is a brand new case of a bad meanie defacing data', + external_service: null, + title: 'Super Bad Security Issue', + status: 'open', + tags: ['defacement'], + updated_at: null, + updated_by: null, + version: 'WzksMV0=', + }); + }); + }); + + describe('unhappy path', () => { + test('it throws when missing title', async () => { + expect.assertions(1); + const postCase = { + description: 'This is a brand new case of a bad meanie defacing data', + tags: ['defacement'], + connector: { + id: 'none', + name: 'none', + type: ConnectorTypes.none, + fields: null, + }, + }; + + const savedObjectsClient = createMockSavedObjectsRepository({ + caseSavedObject: mockCases, + }); + const caseClient = await createCaseClientWithMockSavedObjectsClient(savedObjectsClient); + caseClient.client + // @ts-expect-error + .create({ theCase: postCase }) + .catch((e) => expect(e).not.toBeNull()); + }); + + test('it throws when missing description', async () => { + expect.assertions(1); + const postCase = { + title: 'a title', + tags: ['defacement'], + connector: { + id: 'none', + name: 'none', + type: ConnectorTypes.none, + fields: null, + }, + }; + + const savedObjectsClient = createMockSavedObjectsRepository({ + caseSavedObject: mockCases, + }); + const caseClient = await createCaseClientWithMockSavedObjectsClient(savedObjectsClient); + caseClient.client + // @ts-expect-error + .create({ theCase: postCase }) + .catch((e) => expect(e).not.toBeNull()); + }); + + test('it throws when missing tags', async () => { + expect.assertions(1); + const postCase = { + title: 'a title', + description: 'This is a brand new case of a bad meanie defacing data', + connector: { + id: 'none', + name: 'none', + type: ConnectorTypes.none, + fields: null, + }, + }; + + const savedObjectsClient = createMockSavedObjectsRepository({ + caseSavedObject: mockCases, + }); + const caseClient = await createCaseClientWithMockSavedObjectsClient(savedObjectsClient); + caseClient.client + // @ts-expect-error + .create({ theCase: postCase }) + .catch((e) => expect(e).not.toBeNull()); + }); + + test('it throws when missing connector ', async () => { + expect.assertions(1); + const postCase = { + title: 'a title', + description: 'This is a brand new case of a bad meanie defacing data', + tags: ['defacement'], + }; + + const savedObjectsClient = createMockSavedObjectsRepository({ + caseSavedObject: mockCases, + }); + const caseClient = await createCaseClientWithMockSavedObjectsClient(savedObjectsClient); + caseClient.client + // @ts-expect-error + .create({ theCase: postCase }) + .catch((e) => expect(e).not.toBeNull()); + }); + + test('it throws when connector missing the right fields', async () => { + expect.assertions(1); + const postCase = { + title: 'a title', + description: 'This is a brand new case of a bad meanie defacing data', + tags: ['defacement'], + connector: { + id: '123', + name: 'Jira', + type: ConnectorTypes.jira, + fields: {}, + }, + }; + + const savedObjectsClient = createMockSavedObjectsRepository({ + caseSavedObject: mockCases, + }); + const caseClient = await createCaseClientWithMockSavedObjectsClient(savedObjectsClient); + caseClient.client + // @ts-expect-error + .create({ theCase: postCase }) + .catch((e) => expect(e).not.toBeNull()); + }); + + test('it throws if you passing status for a new case', async () => { + expect.assertions(1); + const postCase = { + title: 'a title', + description: 'This is a brand new case of a bad meanie defacing data', + tags: ['defacement'], + status: 'closed', + connector: { + id: 'none', + name: 'none', + type: ConnectorTypes.none, + fields: null, + }, + }; + + const savedObjectsClient = createMockSavedObjectsRepository({ + caseSavedObject: mockCases, + }); + const caseClient = await createCaseClientWithMockSavedObjectsClient(savedObjectsClient); + caseClient.client.create({ theCase: postCase }).catch((e) => expect(e).not.toBeNull()); + }); + + it(`Returns an error if postNewCase throws`, async () => { + const postCase = { + description: 'Throw an error', + title: 'Super Bad Security Issue', + tags: ['error'], + connector: { + id: 'none', + name: 'none', + type: ConnectorTypes.none, + fields: null, + }, + }; + const savedObjectsClient = createMockSavedObjectsRepository({ + caseSavedObject: mockCases, + }); + const caseClient = await createCaseClientWithMockSavedObjectsClient(savedObjectsClient); + + caseClient.client.create({ theCase: postCase }).catch((e) => expect(e).not.toBeNull()); + }); + }); +}); diff --git a/x-pack/plugins/case/server/client/cases/create.ts b/x-pack/plugins/case/server/client/cases/create.ts new file mode 100644 index 0000000000000..3379099419a75 --- /dev/null +++ b/x-pack/plugins/case/server/client/cases/create.ts @@ -0,0 +1,78 @@ +/* + * 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 Boom from 'boom'; +import { pipe } from 'fp-ts/lib/pipeable'; +import { fold } from 'fp-ts/lib/Either'; +import { identity } from 'fp-ts/lib/function'; + +import { flattenCaseSavedObject, transformNewCase } from '../../routes/api/utils'; + +import { + CasePostRequestRt, + throwErrors, + excess, + CaseResponseRt, + CaseResponse, +} from '../../../common/api'; +import { buildCaseUserActionItem } from '../../services/user_actions/helpers'; +import { + getConnectorFromConfiguration, + transformCaseConnectorToEsConnector, +} from '../../routes/api/cases/helpers'; + +import { CaseClientCreate, CaseClientFactoryArguments } from '../types'; + +export const create = ({ + savedObjectsClient, + caseService, + caseConfigureService, + userActionService, + request, +}: CaseClientFactoryArguments) => async ({ theCase }: CaseClientCreate): Promise => { + const query = pipe( + excess(CasePostRequestRt).decode(theCase), + fold(throwErrors(Boom.badRequest), identity) + ); + + // eslint-disable-next-line @typescript-eslint/naming-convention + const { username, full_name, email } = await caseService.getUser({ request }); + const createdDate = new Date().toISOString(); + const myCaseConfigure = await caseConfigureService.find({ client: savedObjectsClient }); + const caseConfigureConnector = getConnectorFromConfiguration(myCaseConfigure); + + const newCase = await caseService.postNewCase({ + client: savedObjectsClient, + attributes: transformNewCase({ + createdDate, + newCase: query, + username, + full_name, + email, + connector: transformCaseConnectorToEsConnector(query.connector ?? caseConfigureConnector), + }), + }); + + await userActionService.postUserActions({ + client: savedObjectsClient, + actions: [ + buildCaseUserActionItem({ + action: 'create', + actionAt: createdDate, + actionBy: { username, full_name, email }, + caseId: newCase.id, + fields: ['description', 'status', 'tags', 'title', 'connector'], + newValue: JSON.stringify(query), + }), + ], + }); + + return CaseResponseRt.encode( + flattenCaseSavedObject({ + savedObject: newCase, + }) + ); +}; diff --git a/x-pack/plugins/case/server/client/cases/update.test.ts b/x-pack/plugins/case/server/client/cases/update.test.ts new file mode 100644 index 0000000000000..62d897999c11a --- /dev/null +++ b/x-pack/plugins/case/server/client/cases/update.test.ts @@ -0,0 +1,383 @@ +/* + * 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 { ConnectorTypes, CasesPatchRequest } from '../../../common/api'; +import { + createMockSavedObjectsRepository, + mockCaseNoConnectorId, + mockCases, +} from '../../routes/api/__fixtures__'; +import { createCaseClientWithMockSavedObjectsClient } from '../mocks'; + +describe('update', () => { + beforeEach(async () => { + jest.restoreAllMocks(); + const spyOnDate = jest.spyOn(global, 'Date') as jest.SpyInstance<{}, []>; + spyOnDate.mockImplementation(() => ({ + toISOString: jest.fn().mockReturnValue('2019-11-25T21:54:48.952Z'), + })); + }); + + describe('happy path', () => { + test('it closes the case correctly', async () => { + const patchCases = { + cases: [ + { + id: 'mock-id-1', + status: 'closed' as const, + version: 'WzAsMV0=', + }, + ], + }; + + const savedObjectsClient = createMockSavedObjectsRepository({ + caseSavedObject: mockCases, + }); + + const caseClient = await createCaseClientWithMockSavedObjectsClient(savedObjectsClient); + const res = await caseClient.client.update({ cases: patchCases }); + + expect(res).toEqual([ + { + closed_at: '2019-11-25T21:54:48.952Z', + closed_by: { email: 'd00d@awesome.com', full_name: 'Awesome D00d', username: 'awesome' }, + comments: [], + connector: { + id: 'none', + name: 'none', + type: ConnectorTypes.none, + fields: null, + }, + created_at: '2019-11-25T21:54:48.952Z', + created_by: { email: 'testemail@elastic.co', full_name: 'elastic', username: 'elastic' }, + description: 'This is a brand new case of a bad meanie defacing data', + id: 'mock-id-1', + external_service: null, + status: 'closed', + tags: ['defacement'], + title: 'Super Bad Security Issue', + totalComment: 0, + updated_at: '2019-11-25T21:54:48.952Z', + updated_by: { email: 'd00d@awesome.com', full_name: 'Awesome D00d', username: 'awesome' }, + version: 'WzE3LDFd', + }, + ]); + + expect( + caseClient.services.userActionService.postUserActions.mock.calls[0][0].actions + ).toEqual([ + { + attributes: { + action: 'update', + action_at: '2019-11-25T21:54:48.952Z', + action_by: { + email: 'd00d@awesome.com', + full_name: 'Awesome D00d', + username: 'awesome', + }, + action_field: ['status'], + new_value: 'closed', + old_value: 'open', + }, + references: [ + { + id: 'mock-id-1', + name: 'associated-cases', + type: 'cases', + }, + ], + }, + ]); + }); + + test('it opens the case correctly', async () => { + const patchCases = { + cases: [ + { + id: 'mock-id-1', + status: 'open' as const, + version: 'WzAsMV0=', + }, + ], + }; + + const savedObjectsClient = createMockSavedObjectsRepository({ + caseSavedObject: [ + { ...mockCases[0], attributes: { ...mockCases[0].attributes, status: 'closed' } }, + ...mockCases.slice(1), + ], + }); + + const caseClient = await createCaseClientWithMockSavedObjectsClient(savedObjectsClient); + const res = await caseClient.client.update({ cases: patchCases }); + + expect(res).toEqual([ + { + closed_at: null, + closed_by: null, + comments: [], + connector: { + id: 'none', + name: 'none', + type: ConnectorTypes.none, + fields: null, + }, + created_at: '2019-11-25T21:54:48.952Z', + created_by: { email: 'testemail@elastic.co', full_name: 'elastic', username: 'elastic' }, + description: 'This is a brand new case of a bad meanie defacing data', + id: 'mock-id-1', + external_service: null, + status: 'open', + tags: ['defacement'], + title: 'Super Bad Security Issue', + totalComment: 0, + updated_at: '2019-11-25T21:54:48.952Z', + updated_by: { email: 'd00d@awesome.com', full_name: 'Awesome D00d', username: 'awesome' }, + version: 'WzE3LDFd', + }, + ]); + }); + + test('it updates a case without a connector.id', async () => { + const patchCases = { + cases: [ + { + id: 'mock-no-connector_id', + status: 'closed' as const, + version: 'WzAsMV0=', + }, + ], + }; + + const savedObjectsClient = createMockSavedObjectsRepository({ + caseSavedObject: [mockCaseNoConnectorId], + }); + + const caseClient = await createCaseClientWithMockSavedObjectsClient(savedObjectsClient); + const res = await caseClient.client.update({ cases: patchCases }); + + expect(res).toEqual([ + { + id: 'mock-no-connector_id', + comments: [], + totalComment: 0, + closed_at: '2019-11-25T21:54:48.952Z', + closed_by: { email: 'd00d@awesome.com', full_name: 'Awesome D00d', username: 'awesome' }, + connector: { + id: 'none', + name: 'none', + type: ConnectorTypes.none, + fields: null, + }, + created_at: '2019-11-25T21:54:48.952Z', + created_by: { full_name: 'elastic', email: 'testemail@elastic.co', username: 'elastic' }, + description: 'This is a brand new case of a bad meanie defacing data', + external_service: null, + title: 'Super Bad Security Issue', + status: 'closed', + tags: ['defacement'], + updated_at: '2019-11-25T21:54:48.952Z', + updated_by: { email: 'd00d@awesome.com', full_name: 'Awesome D00d', username: 'awesome' }, + version: 'WzE3LDFd', + }, + ]); + }); + + test('it updates the connector correctly', async () => { + const patchCases = ({ + cases: [ + { + id: 'mock-id-3', + connector: { + id: '456', + name: 'My connector 2', + type: ConnectorTypes.jira, + fields: { issueType: 'Bug', priority: 'Low', parent: null }, + }, + version: 'WzUsMV0=', + }, + ], + } as unknown) as CasesPatchRequest; + + const savedObjectsClient = createMockSavedObjectsRepository({ + caseSavedObject: mockCases, + }); + + const caseClient = await createCaseClientWithMockSavedObjectsClient(savedObjectsClient); + const res = await caseClient.client.update({ cases: patchCases }); + + expect(res).toEqual([ + { + id: 'mock-id-3', + comments: [], + totalComment: 0, + closed_at: null, + closed_by: null, + connector: { + id: '456', + name: 'My connector 2', + type: ConnectorTypes.jira, + fields: { issueType: 'Bug', priority: 'Low', parent: null }, + }, + created_at: '2019-11-25T22:32:17.947Z', + created_by: { + full_name: 'elastic', + email: 'testemail@elastic.co', + username: 'elastic', + }, + description: 'Oh no, a bad meanie going LOLBins all over the place!', + external_service: null, + title: 'Another bad one', + status: 'open', + tags: ['LOLBins'], + updated_at: '2019-11-25T21:54:48.952Z', + updated_by: { + full_name: 'Awesome D00d', + email: 'd00d@awesome.com', + username: 'awesome', + }, + version: 'WzE3LDFd', + }, + ]); + }); + }); + + describe('unhappy path', () => { + test('it throws when missing id', async () => { + expect.assertions(1); + const patchCases = { + cases: [ + { + connector: { + id: 'none', + name: 'none', + type: ConnectorTypes.none, + fields: null, + }, + version: 'WzUsMV0=', + }, + ], + }; + + const savedObjectsClient = createMockSavedObjectsRepository({ + caseSavedObject: mockCases, + }); + + const caseClient = await createCaseClientWithMockSavedObjectsClient(savedObjectsClient); + caseClient.client + // @ts-expect-error + .update({ cases: patchCases }) + .catch((e) => expect(e).not.toBeNull()); + }); + + test('it throws when missing version', async () => { + expect.assertions(1); + const patchCases = { + cases: [ + { + id: 'mock-id-3', + connector: { + id: 'none', + name: 'none', + type: ConnectorTypes.none, + fields: null, + }, + }, + ], + }; + + const savedObjectsClient = createMockSavedObjectsRepository({ + caseSavedObject: mockCases, + }); + + const caseClient = await createCaseClientWithMockSavedObjectsClient(savedObjectsClient); + caseClient.client + // @ts-expect-error + .update({ cases: patchCases }) + .catch((e) => expect(e).not.toBeNull()); + }); + + test('it throws when fields are identical', async () => { + expect.assertions(1); + const patchCases = { + cases: [ + { + id: 'mock-id-1', + status: 'open' as const, + version: 'WzAsMV0=', + }, + ], + }; + + const savedObjectsClient = createMockSavedObjectsRepository({ + caseSavedObject: mockCases, + }); + + const caseClient = await createCaseClientWithMockSavedObjectsClient(savedObjectsClient); + caseClient.client + .update({ cases: patchCases }) + .catch((e) => + expect(e.message).toBe('All update fields are identical to current version.') + ); + }); + + test('it throws when case does not exist', async () => { + const patchCases = { + cases: [ + { + id: 'not-exists', + connector: { + id: 'none', + name: 'none', + type: ConnectorTypes.none, + fields: null, + }, + version: 'WzUsMV0=', + }, + ], + }; + + const savedObjectsClient = createMockSavedObjectsRepository({ + caseSavedObject: mockCases, + }); + + const caseClient = await createCaseClientWithMockSavedObjectsClient(savedObjectsClient); + caseClient.client + .update({ cases: patchCases }) + .catch((e) => + expect(e.message).toBe( + 'These cases not-exists do not exist. Please check you have the correct ids.' + ) + ); + }); + + test('it throws when cases conflicts', async () => { + expect.assertions(1); + const patchCases = { + cases: [ + { + id: 'mock-id-1', + version: 'WzAsMV1=', + title: 'Super Bad Security Issue', + }, + ], + }; + + const savedObjectsClient = createMockSavedObjectsRepository({ + caseSavedObject: mockCases, + }); + + const caseClient = await createCaseClientWithMockSavedObjectsClient(savedObjectsClient); + caseClient.client + .update({ cases: patchCases }) + .catch((e) => + expect(e.message).toBe( + 'These cases mock-id-1 has been updated. Please refresh before saving additional updates.' + ) + ); + }); + }); +}); diff --git a/x-pack/plugins/case/server/client/cases/update.ts b/x-pack/plugins/case/server/client/cases/update.ts new file mode 100644 index 0000000000000..424f51ee40f08 --- /dev/null +++ b/x-pack/plugins/case/server/client/cases/update.ts @@ -0,0 +1,155 @@ +/* + * 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 Boom from 'boom'; +import { pipe } from 'fp-ts/lib/pipeable'; +import { fold } from 'fp-ts/lib/Either'; +import { identity } from 'fp-ts/lib/function'; + +import { flattenCaseSavedObject } from '../../routes/api/utils'; + +import { + throwErrors, + excess, + CasesResponseRt, + CasesPatchRequestRt, + ESCasePatchRequest, + CasePatchRequest, + CasesResponse, +} from '../../../common/api'; +import { buildCaseUserActions } from '../../services/user_actions/helpers'; +import { + getCaseToUpdate, + transformCaseConnectorToEsConnector, +} from '../../routes/api/cases/helpers'; + +import { CaseClientUpdate, CaseClientFactoryArguments } from '../types'; + +export const update = ({ + savedObjectsClient, + caseService, + userActionService, + request, +}: CaseClientFactoryArguments) => async ({ cases }: CaseClientUpdate): Promise => { + const query = pipe( + excess(CasesPatchRequestRt).decode(cases), + fold(throwErrors(Boom.badRequest), identity) + ); + + const myCases = await caseService.getCases({ + client: savedObjectsClient, + caseIds: query.cases.map((q) => q.id), + }); + + let nonExistingCases: CasePatchRequest[] = []; + const conflictedCases = query.cases.filter((q) => { + const myCase = myCases.saved_objects.find((c) => c.id === q.id); + + if (myCase && myCase.error) { + nonExistingCases = [...nonExistingCases, q]; + return false; + } + return myCase == null || myCase?.version !== q.version; + }); + + if (nonExistingCases.length > 0) { + throw Boom.notFound( + `These cases ${nonExistingCases + .map((c) => c.id) + .join(', ')} do not exist. Please check you have the correct ids.` + ); + } + + if (conflictedCases.length > 0) { + throw Boom.conflict( + `These cases ${conflictedCases + .map((c) => c.id) + .join(', ')} has been updated. Please refresh before saving additional updates.` + ); + } + + const updateCases: ESCasePatchRequest[] = query.cases.map((updateCase) => { + const currentCase = myCases.saved_objects.find((c) => c.id === updateCase.id); + const { connector, ...thisCase } = updateCase; + return currentCase != null + ? getCaseToUpdate(currentCase.attributes, { + ...thisCase, + ...(connector != null + ? { connector: transformCaseConnectorToEsConnector(connector) } + : {}), + }) + : { id: thisCase.id, version: thisCase.version }; + }); + + const updateFilterCases = updateCases.filter((updateCase) => { + const { id, version, ...updateCaseAttributes } = updateCase; + return Object.keys(updateCaseAttributes).length > 0; + }); + + if (updateFilterCases.length > 0) { + // eslint-disable-next-line @typescript-eslint/naming-convention + const { username, full_name, email } = await caseService.getUser({ request }); + const updatedDt = new Date().toISOString(); + const updatedCases = await caseService.patchCases({ + client: savedObjectsClient, + cases: updateFilterCases.map((thisCase) => { + const { id: caseId, version, ...updateCaseAttributes } = thisCase; + let closedInfo = {}; + if (updateCaseAttributes.status && updateCaseAttributes.status === 'closed') { + closedInfo = { + closed_at: updatedDt, + closed_by: { email, full_name, username }, + }; + } else if (updateCaseAttributes.status && updateCaseAttributes.status === 'open') { + closedInfo = { + closed_at: null, + closed_by: null, + }; + } + return { + caseId, + updatedAttributes: { + ...updateCaseAttributes, + ...closedInfo, + updated_at: updatedDt, + updated_by: { email, full_name, username }, + }, + version, + }; + }), + }); + + const returnUpdatedCase = myCases.saved_objects + .filter((myCase) => + updatedCases.saved_objects.some((updatedCase) => updatedCase.id === myCase.id) + ) + .map((myCase) => { + const updatedCase = updatedCases.saved_objects.find((c) => c.id === myCase.id); + return flattenCaseSavedObject({ + savedObject: { + ...myCase, + ...updatedCase, + attributes: { ...myCase.attributes, ...updatedCase?.attributes }, + references: myCase.references, + version: updatedCase?.version ?? myCase.version, + }, + }); + }); + + await userActionService.postUserActions({ + client: savedObjectsClient, + actions: buildCaseUserActions({ + originalCases: myCases.saved_objects, + updatedCases: updatedCases.saved_objects, + actionDate: updatedDt, + actionBy: { email, full_name, username }, + }), + }); + + return CasesResponseRt.encode(returnUpdatedCase); + } + throw Boom.notAcceptable('All update fields are identical to current version.'); +}; diff --git a/x-pack/plugins/case/server/client/comments/add.test.ts b/x-pack/plugins/case/server/client/comments/add.test.ts new file mode 100644 index 0000000000000..8a316740e41e0 --- /dev/null +++ b/x-pack/plugins/case/server/client/comments/add.test.ts @@ -0,0 +1,212 @@ +/* + * 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 { + createMockSavedObjectsRepository, + mockCaseComments, + mockCases, +} from '../../routes/api/__fixtures__'; +import { createCaseClientWithMockSavedObjectsClient } from '../mocks'; + +describe('addComment', () => { + beforeEach(async () => { + jest.restoreAllMocks(); + const spyOnDate = jest.spyOn(global, 'Date') as jest.SpyInstance<{}, []>; + spyOnDate.mockImplementation(() => ({ + toISOString: jest.fn().mockReturnValue('2020-10-23T21:54:48.952Z'), + })); + }); + + describe('happy path', () => { + test('it adds a comment correctly', async () => { + const savedObjectsClient = createMockSavedObjectsRepository({ + caseSavedObject: mockCases, + caseCommentSavedObject: mockCaseComments, + }); + + const caseClient = await createCaseClientWithMockSavedObjectsClient(savedObjectsClient); + const res = await caseClient.client.addComment({ + caseId: 'mock-id-1', + comment: { comment: 'Wow, good luck catching that bad meanie!' }, + }); + + expect(res.id).toEqual('mock-id-1'); + expect(res.totalComment).toEqual(res.comments!.length); + expect(res.comments![res.comments!.length - 1]).toEqual({ + comment: 'Wow, good luck catching that bad meanie!', + created_at: '2020-10-23T21:54:48.952Z', + created_by: { + email: 'd00d@awesome.com', + full_name: 'Awesome D00d', + username: 'awesome', + }, + id: 'mock-comment', + pushed_at: null, + pushed_by: null, + updated_at: null, + updated_by: null, + version: 'WzksMV0=', + }); + }); + + test('it updates the case correctly after adding a comment', async () => { + const savedObjectsClient = createMockSavedObjectsRepository({ + caseSavedObject: mockCases, + caseCommentSavedObject: mockCaseComments, + }); + + const caseClient = await createCaseClientWithMockSavedObjectsClient(savedObjectsClient); + const res = await caseClient.client.addComment({ + caseId: 'mock-id-1', + comment: { comment: 'Wow, good luck catching that bad meanie!' }, + }); + + expect(res.updated_at).toEqual('2020-10-23T21:54:48.952Z'); + expect(res.updated_by).toEqual({ + email: 'd00d@awesome.com', + full_name: 'Awesome D00d', + username: 'awesome', + }); + }); + + test('it creates a user action', async () => { + const savedObjectsClient = createMockSavedObjectsRepository({ + caseSavedObject: mockCases, + caseCommentSavedObject: mockCaseComments, + }); + + const caseClient = await createCaseClientWithMockSavedObjectsClient(savedObjectsClient); + await caseClient.client.addComment({ + caseId: 'mock-id-1', + comment: { comment: 'Wow, good luck catching that bad meanie!' }, + }); + + expect( + caseClient.services.userActionService.postUserActions.mock.calls[0][0].actions + ).toEqual([ + { + attributes: { + action: 'create', + action_at: '2020-10-23T21:54:48.952Z', + action_by: { + email: 'd00d@awesome.com', + full_name: 'Awesome D00d', + username: 'awesome', + }, + action_field: ['comment'], + new_value: 'Wow, good luck catching that bad meanie!', + old_value: null, + }, + references: [ + { + id: 'mock-id-1', + name: 'associated-cases', + type: 'cases', + }, + { + id: 'mock-comment', + name: 'associated-cases-comments', + type: 'cases-comments', + }, + ], + }, + ]); + }); + + test('it allow user to create comments without authentications', async () => { + const savedObjectsClient = createMockSavedObjectsRepository({ + caseSavedObject: mockCases, + caseCommentSavedObject: mockCaseComments, + }); + + const caseClient = await createCaseClientWithMockSavedObjectsClient(savedObjectsClient, true); + const res = await caseClient.client.addComment({ + caseId: 'mock-id-1', + comment: { comment: 'Wow, good luck catching that bad meanie!' }, + }); + + expect(res.id).toEqual('mock-id-1'); + expect(res.comments![res.comments!.length - 1]).toEqual({ + comment: 'Wow, good luck catching that bad meanie!', + created_at: '2020-10-23T21:54:48.952Z', + created_by: { + email: null, + full_name: null, + username: null, + }, + id: 'mock-comment', + pushed_at: null, + pushed_by: null, + updated_at: null, + updated_by: null, + version: 'WzksMV0=', + }); + }); + }); + + describe('unhappy path', () => { + test('it throws when missing comment', async () => { + expect.assertions(3); + + const savedObjectsClient = createMockSavedObjectsRepository({ + caseSavedObject: mockCases, + caseCommentSavedObject: mockCaseComments, + }); + const caseClient = await createCaseClientWithMockSavedObjectsClient(savedObjectsClient); + caseClient.client + .addComment({ + caseId: 'mock-id-1', + // @ts-expect-error + comment: {}, + }) + .catch((e) => { + expect(e).not.toBeNull(); + expect(e.isBoom).toBe(true); + expect(e.output.statusCode).toBe(400); + }); + }); + + test('it throws when the case does not exists', async () => { + expect.assertions(3); + + const savedObjectsClient = createMockSavedObjectsRepository({ + caseSavedObject: mockCases, + caseCommentSavedObject: mockCaseComments, + }); + const caseClient = await createCaseClientWithMockSavedObjectsClient(savedObjectsClient); + caseClient.client + .addComment({ + caseId: 'not-exists', + comment: { comment: 'Wow, good luck catching that bad meanie!' }, + }) + .catch((e) => { + expect(e).not.toBeNull(); + expect(e.isBoom).toBe(true); + expect(e.output.statusCode).toBe(404); + }); + }); + + test('it throws when postNewCase throws', async () => { + expect.assertions(3); + + const savedObjectsClient = createMockSavedObjectsRepository({ + caseSavedObject: mockCases, + caseCommentSavedObject: mockCaseComments, + }); + const caseClient = await createCaseClientWithMockSavedObjectsClient(savedObjectsClient); + caseClient.client + .addComment({ + caseId: 'mock-id-1', + comment: { comment: 'Throw an error' }, + }) + .catch((e) => { + expect(e).not.toBeNull(); + expect(e.isBoom).toBe(true); + expect(e.output.statusCode).toBe(400); + }); + }); + }); +}); diff --git a/x-pack/plugins/case/server/client/comments/add.ts b/x-pack/plugins/case/server/client/comments/add.ts new file mode 100644 index 0000000000000..765eb2c873765 --- /dev/null +++ b/x-pack/plugins/case/server/client/comments/add.ts @@ -0,0 +1,126 @@ +/* + * 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 Boom from 'boom'; +import { pipe } from 'fp-ts/lib/pipeable'; +import { fold } from 'fp-ts/lib/Either'; +import { identity } from 'fp-ts/lib/function'; + +import { flattenCaseSavedObject, transformNewComment } from '../../routes/api/utils'; + +import { + throwErrors, + excess, + CaseResponseRt, + CommentRequestRt, + CaseResponse, +} from '../../../common/api'; +import { buildCommentUserActionItem } from '../../services/user_actions/helpers'; + +import { CaseClientAddComment, CaseClientFactoryArguments } from '../types'; +import { CASE_SAVED_OBJECT } from '../../saved_object_types'; + +export const addComment = ({ + savedObjectsClient, + caseService, + userActionService, + request, +}: CaseClientFactoryArguments) => async ({ + caseId, + comment, +}: CaseClientAddComment): Promise => { + const query = pipe( + excess(CommentRequestRt).decode(comment), + fold(throwErrors(Boom.badRequest), identity) + ); + + const myCase = await caseService.getCase({ + client: savedObjectsClient, + caseId, + }); + + // eslint-disable-next-line @typescript-eslint/naming-convention + const { username, full_name, email } = await caseService.getUser({ request }); + const createdDate = new Date().toISOString(); + + const [newComment, updatedCase] = await Promise.all([ + caseService.postNewComment({ + client: savedObjectsClient, + attributes: transformNewComment({ + createdDate, + ...query, + username, + full_name, + email, + }), + references: [ + { + type: CASE_SAVED_OBJECT, + name: `associated-${CASE_SAVED_OBJECT}`, + id: myCase.id, + }, + ], + }), + caseService.patchCase({ + client: savedObjectsClient, + caseId, + updatedAttributes: { + updated_at: createdDate, + updated_by: { username, full_name, email }, + }, + version: myCase.version, + }), + ]); + + const totalCommentsFindByCases = await caseService.getAllCaseComments({ + client: savedObjectsClient, + caseId, + options: { + fields: [], + page: 1, + perPage: 1, + }, + }); + + const [comments] = await Promise.all([ + caseService.getAllCaseComments({ + client: savedObjectsClient, + caseId, + options: { + fields: [], + page: 1, + perPage: totalCommentsFindByCases.total, + }, + }), + userActionService.postUserActions({ + client: savedObjectsClient, + actions: [ + buildCommentUserActionItem({ + action: 'create', + actionAt: createdDate, + actionBy: { username, full_name, email }, + caseId: myCase.id, + commentId: newComment.id, + fields: ['comment'], + newValue: query.comment, + }), + ], + }), + ]); + + return CaseResponseRt.encode( + flattenCaseSavedObject({ + savedObject: { + ...myCase, + ...updatedCase, + attributes: { ...myCase.attributes, ...updatedCase.attributes }, + version: updatedCase.version ?? myCase.version, + references: myCase.references, + }, + comments: comments.saved_objects, + }) + ); +}; diff --git a/x-pack/plugins/case/server/client/index.test.ts b/x-pack/plugins/case/server/client/index.test.ts new file mode 100644 index 0000000000000..1ecdc8ea96dea --- /dev/null +++ b/x-pack/plugins/case/server/client/index.test.ts @@ -0,0 +1,68 @@ +/* + * 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 { KibanaRequest } from 'kibana/server'; +import { savedObjectsClientMock } from '../../../../../src/core/server/mocks'; +import { createCaseClient } from '.'; +import { + createCaseServiceMock, + createConfigureServiceMock, + createUserActionServiceMock, +} from '../services/mocks'; + +import { create } from './cases/create'; +import { update } from './cases/update'; +import { addComment } from './comments/add'; + +jest.mock('./cases/create'); +jest.mock('./cases/update'); +jest.mock('./comments/add'); + +const caseService = createCaseServiceMock(); +const caseConfigureService = createConfigureServiceMock(); +const userActionService = createUserActionServiceMock(); +const savedObjectsClient = savedObjectsClientMock.create(); +const request = {} as KibanaRequest; + +const createMock = create as jest.Mock; +const updateMock = update as jest.Mock; +const addCommentMock = addComment as jest.Mock; + +describe('createCaseClient()', () => { + test('it creates the client correctly', async () => { + createCaseClient({ + savedObjectsClient, + request, + caseConfigureService, + caseService, + userActionService, + }); + + expect(createMock).toHaveBeenCalledWith({ + savedObjectsClient, + request, + caseConfigureService, + caseService, + userActionService, + }); + + expect(updateMock).toHaveBeenCalledWith({ + savedObjectsClient, + request, + caseConfigureService, + caseService, + userActionService, + }); + + expect(addCommentMock).toHaveBeenCalledWith({ + savedObjectsClient, + request, + caseConfigureService, + caseService, + userActionService, + }); + }); +}); diff --git a/x-pack/plugins/case/server/client/index.ts b/x-pack/plugins/case/server/client/index.ts new file mode 100644 index 0000000000000..75e9e3c4cfebc --- /dev/null +++ b/x-pack/plugins/case/server/client/index.ts @@ -0,0 +1,44 @@ +/* + * 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 { CaseClientFactoryArguments, CaseClient } from './types'; +import { create } from './cases/create'; +import { update } from './cases/update'; +import { addComment } from './comments/add'; + +export { CaseClient } from './types'; + +export const createCaseClient = ({ + savedObjectsClient, + request, + caseConfigureService, + caseService, + userActionService, +}: CaseClientFactoryArguments): CaseClient => { + return { + create: create({ + savedObjectsClient, + request, + caseConfigureService, + caseService, + userActionService, + }), + update: update({ + savedObjectsClient, + request, + caseConfigureService, + caseService, + userActionService, + }), + addComment: addComment({ + savedObjectsClient, + request, + caseConfigureService, + caseService, + userActionService, + }), + }; +}; diff --git a/x-pack/plugins/case/server/client/mocks.ts b/x-pack/plugins/case/server/client/mocks.ts new file mode 100644 index 0000000000000..243dd884f9ef6 --- /dev/null +++ b/x-pack/plugins/case/server/client/mocks.ts @@ -0,0 +1,53 @@ +/* + * 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 { KibanaRequest } from 'kibana/server'; +import { loggingSystemMock } from '../../../../../src/core/server/mocks'; +import { CaseService, CaseConfigureService, CaseUserActionServiceSetup } from '../services'; +import { CaseClient } from './types'; +import { authenticationMock } from '../routes/api/__fixtures__'; +import { createCaseClient } from '.'; + +export type CaseClientMock = jest.Mocked; +export const createCaseClientMock = (): CaseClientMock => ({ + create: jest.fn(), + update: jest.fn(), + addComment: jest.fn(), +}); + +export const createCaseClientWithMockSavedObjectsClient = async ( + savedObjectsClient: any, + badAuth: boolean = false +): Promise<{ + client: CaseClient; + services: { userActionService: jest.Mocked }; +}> => { + const log = loggingSystemMock.create().get('case'); + const request = {} as KibanaRequest; + + const caseServicePlugin = new CaseService(log); + const caseConfigureServicePlugin = new CaseConfigureService(log); + + const caseService = await caseServicePlugin.setup({ + authentication: badAuth ? authenticationMock.createInvalid() : authenticationMock.create(), + }); + const caseConfigureService = await caseConfigureServicePlugin.setup(); + const userActionService = { + postUserActions: jest.fn(), + getUserActions: jest.fn(), + }; + + return { + client: createCaseClient({ + savedObjectsClient, + request, + caseService, + caseConfigureService, + userActionService, + }), + services: { userActionService }, + }; +}; diff --git a/x-pack/plugins/case/server/client/types.ts b/x-pack/plugins/case/server/client/types.ts new file mode 100644 index 0000000000000..8db7d8a5747d7 --- /dev/null +++ b/x-pack/plugins/case/server/client/types.ts @@ -0,0 +1,46 @@ +/* + * 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 { KibanaRequest, SavedObjectsClientContract } from '../../../../../src/core/server'; +import { + CasePostRequest, + CasesPatchRequest, + CommentRequest, + CaseResponse, + CasesResponse, +} from '../../common/api'; +import { + CaseConfigureServiceSetup, + CaseServiceSetup, + CaseUserActionServiceSetup, +} from '../services'; + +export interface CaseClientCreate { + theCase: CasePostRequest; +} + +export interface CaseClientUpdate { + cases: CasesPatchRequest; +} + +export interface CaseClientAddComment { + caseId: string; + comment: CommentRequest; +} + +export interface CaseClientFactoryArguments { + savedObjectsClient: SavedObjectsClientContract; + request: KibanaRequest; + caseConfigureService: CaseConfigureServiceSetup; + caseService: CaseServiceSetup; + userActionService: CaseUserActionServiceSetup; +} + +export interface CaseClient { + create: (args: CaseClientCreate) => Promise; + update: (args: CaseClientUpdate) => Promise; + addComment: (args: CaseClientAddComment) => Promise; +} diff --git a/x-pack/plugins/case/server/plugin.ts b/x-pack/plugins/case/server/plugin.ts index 9cf045da3e700..5398f8ed0ae83 100644 --- a/x-pack/plugins/case/server/plugin.ts +++ b/x-pack/plugins/case/server/plugin.ts @@ -5,10 +5,17 @@ */ import { first, map } from 'rxjs/operators'; -import { Logger, PluginInitializerContext } from 'kibana/server'; -import { CoreSetup } from 'src/core/server'; +import { + IContextProvider, + KibanaRequest, + Logger, + PluginInitializerContext, + RequestHandler, +} from 'kibana/server'; +import { CoreSetup, CoreStart } from 'src/core/server'; import { SecurityPluginSetup } from '../../security/server'; +import { APP_ID } from '../common/constants'; import { ConfigType } from './config'; import { initCaseApi } from './routes/api'; @@ -18,7 +25,15 @@ import { caseCommentSavedObjectType, caseUserActionSavedObjectType, } from './saved_object_types'; -import { CaseConfigureService, CaseService, CaseUserActionService } from './services'; +import { + CaseConfigureService, + CaseConfigureServiceSetup, + CaseService, + CaseServiceSetup, + CaseUserActionService, + CaseUserActionServiceSetup, +} from './services'; +import { createCaseClient } from './client'; function createConfig$(context: PluginInitializerContext) { return context.config.create().pipe(map((config) => config)); @@ -30,6 +45,9 @@ export interface PluginsSetup { export class CasePlugin { private readonly log: Logger; + private caseService?: CaseServiceSetup; + private caseConfigureService?: CaseConfigureServiceSetup; + private userActionService?: CaseUserActionServiceSetup; constructor(private readonly initializerContext: PluginInitializerContext) { this.log = this.initializerContext.logger.get(); @@ -47,36 +65,83 @@ export class CasePlugin { core.savedObjects.registerType(caseConfigureSavedObjectType); core.savedObjects.registerType(caseUserActionSavedObjectType); - const caseServicePlugin = new CaseService(this.log); - const caseConfigureServicePlugin = new CaseConfigureService(this.log); - const userActionServicePlugin = new CaseUserActionService(this.log); - this.log.debug( `Setting up Case Workflow with core contract [${Object.keys( core )}] and plugins [${Object.keys(plugins)}]` ); - const caseService = await caseServicePlugin.setup({ + this.caseService = await new CaseService(this.log).setup({ authentication: plugins.security != null ? plugins.security.authc : null, }); - const caseConfigureService = await caseConfigureServicePlugin.setup(); - const userActionService = await userActionServicePlugin.setup(); + this.caseConfigureService = await new CaseConfigureService(this.log).setup(); + this.userActionService = await new CaseUserActionService(this.log).setup(); + + core.http.registerRouteHandlerContext( + APP_ID, + this.createRouteHandlerContext({ + core, + caseService: this.caseService, + caseConfigureService: this.caseConfigureService, + userActionService: this.userActionService, + }) + ); const router = core.http.createRouter(); initCaseApi({ - caseConfigureService, - caseService, - userActionService, + caseService: this.caseService, + caseConfigureService: this.caseConfigureService, + userActionService: this.userActionService, router, }); } - public start() { + public async start(core: CoreStart) { this.log.debug(`Starting Case Workflow`); + + const getCaseClientWithRequest = async (request: KibanaRequest) => { + return createCaseClient({ + savedObjectsClient: core.savedObjects.getScopedClient(request), + request, + caseService: this.caseService!, + caseConfigureService: this.caseConfigureService!, + userActionService: this.userActionService!, + }); + }; + + return { + getCaseClientWithRequest, + }; } public stop() { this.log.debug(`Stopping Case Workflow`); } + + private createRouteHandlerContext = ({ + core, + caseService, + caseConfigureService, + userActionService, + }: { + core: CoreSetup; + caseService: CaseServiceSetup; + caseConfigureService: CaseConfigureServiceSetup; + userActionService: CaseUserActionServiceSetup; + }): IContextProvider, typeof APP_ID> => { + return async (context, request) => { + const [{ savedObjects }] = await core.getStartServices(); + return { + getCaseClient: () => { + return createCaseClient({ + savedObjectsClient: savedObjects.getScopedClient(request), + caseService, + caseConfigureService, + userActionService, + request, + }); + }, + }; + }; + }; } diff --git a/x-pack/plugins/case/server/routes/api/__fixtures__/create_mock_so_repository.ts b/x-pack/plugins/case/server/routes/api/__fixtures__/create_mock_so_repository.ts index c2df91148a53a..8bbd419e6315b 100644 --- a/x-pack/plugins/case/server/routes/api/__fixtures__/create_mock_so_repository.ts +++ b/x-pack/plugins/case/server/routes/api/__fixtures__/create_mock_so_repository.ts @@ -39,7 +39,15 @@ export const createMockSavedObjectsRepository = ({ } const result = caseSavedObject.filter((s) => s.id === id); if (!result.length) { - throw SavedObjectsErrorHelpers.createGenericNotFoundError(type, id); + return { + id, + type, + error: { + statusCode: 404, + error: 'Not Found', + message: 'Saved object [cases/not-exist] not found', + }, + }; } return result[0]; }), diff --git a/x-pack/plugins/case/server/routes/api/__fixtures__/mock_saved_objects.ts b/x-pack/plugins/case/server/routes/api/__fixtures__/mock_saved_objects.ts index 265970b1abdec..e7ea381da9955 100644 --- a/x-pack/plugins/case/server/routes/api/__fixtures__/mock_saved_objects.ts +++ b/x-pack/plugins/case/server/routes/api/__fixtures__/mock_saved_objects.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { SavedObject } from 'kibana/server'; +import { SavedObject, SavedObjectsFindResponse } from 'kibana/server'; import { ESCasesConfigureAttributes, CommentAttributes, @@ -325,3 +325,12 @@ export const mockCaseConfigure: Array> = version: 'WzYsMV0=', }, ]; + +export const mockCaseConfigureFind: Array> = [ + { + page: 1, + per_page: 5, + total: mockCaseConfigure.length, + saved_objects: [{ ...mockCaseConfigure[0], score: 0 }], + }, +]; diff --git a/x-pack/plugins/case/server/routes/api/__fixtures__/route_contexts.ts b/x-pack/plugins/case/server/routes/api/__fixtures__/route_contexts.ts index d947ffbaf181d..67890599fa417 100644 --- a/x-pack/plugins/case/server/routes/api/__fixtures__/route_contexts.ts +++ b/x-pack/plugins/case/server/routes/api/__fixtures__/route_contexts.ts @@ -4,13 +4,36 @@ * you may not use this file except in compliance with the Elastic License. */ -import { RequestHandlerContext } from 'src/core/server'; +import { RequestHandlerContext, KibanaRequest } from 'src/core/server'; +import { loggingSystemMock } from 'src/core/server/mocks'; import { actionsClientMock } from '../../../../../actions/server/mocks'; +import { createCaseClient } from '../../../client'; +import { CaseService, CaseConfigureService } from '../../../services'; import { getActions } from '../__mocks__/request_responses'; +import { authenticationMock } from '../__fixtures__'; -export const createRouteContext = (client: any) => { +export const createRouteContext = async (client: any, badAuth = false) => { const actionsMock = actionsClientMock.create(); actionsMock.getAll.mockImplementation(() => Promise.resolve(getActions())); + const log = loggingSystemMock.create().get('case'); + + const caseServicePlugin = new CaseService(log); + const caseConfigureServicePlugin = new CaseConfigureService(log); + + const caseService = await caseServicePlugin.setup({ + authentication: badAuth ? authenticationMock.createInvalid() : authenticationMock.create(), + }); + const caseConfigureService = await caseConfigureServicePlugin.setup(); + const caseClient = createCaseClient({ + savedObjectsClient: client, + request: {} as KibanaRequest, + caseService, + caseConfigureService, + userActionService: { + postUserActions: jest.fn(), + getUserActions: jest.fn(), + }, + }); return ({ core: { @@ -19,5 +42,8 @@ export const createRouteContext = (client: any) => { }, }, actions: { getActionsClient: () => actionsMock }, + case: { + getCaseClient: () => caseClient, + }, } as unknown) as RequestHandlerContext; }; diff --git a/x-pack/plugins/case/server/routes/api/cases/comments/delete_comment.test.ts b/x-pack/plugins/case/server/routes/api/cases/comments/delete_comment.test.ts index 67cb998409570..986ad3a54496f 100644 --- a/x-pack/plugins/case/server/routes/api/cases/comments/delete_comment.test.ts +++ b/x-pack/plugins/case/server/routes/api/cases/comments/delete_comment.test.ts @@ -32,7 +32,7 @@ describe('DELETE comment', () => { }, }); - const theContext = createRouteContext( + const theContext = await createRouteContext( createMockSavedObjectsRepository({ caseSavedObject: mockCases, caseCommentSavedObject: mockCaseComments, @@ -52,7 +52,7 @@ describe('DELETE comment', () => { }, }); - const theContext = createRouteContext( + const theContext = await createRouteContext( createMockSavedObjectsRepository({ caseSavedObject: mockCases, caseCommentSavedObject: mockCaseComments, diff --git a/x-pack/plugins/case/server/routes/api/cases/comments/get_comment.test.ts b/x-pack/plugins/case/server/routes/api/cases/comments/get_comment.test.ts index 24a03b217ab7c..23f64151a78d7 100644 --- a/x-pack/plugins/case/server/routes/api/cases/comments/get_comment.test.ts +++ b/x-pack/plugins/case/server/routes/api/cases/comments/get_comment.test.ts @@ -32,7 +32,7 @@ describe('GET comment', () => { }, }); - const theContext = createRouteContext( + const theContext = await createRouteContext( createMockSavedObjectsRepository({ caseSavedObject: mockCases, caseCommentSavedObject: mockCaseComments, @@ -57,7 +57,7 @@ describe('GET comment', () => { }, }); - const theContext = createRouteContext( + const theContext = await createRouteContext( createMockSavedObjectsRepository({ caseCommentSavedObject: mockCaseComments, }) diff --git a/x-pack/plugins/case/server/routes/api/cases/comments/patch_comment.test.ts b/x-pack/plugins/case/server/routes/api/cases/comments/patch_comment.test.ts index 04473e302e468..400e8ca404ca5 100644 --- a/x-pack/plugins/case/server/routes/api/cases/comments/patch_comment.test.ts +++ b/x-pack/plugins/case/server/routes/api/cases/comments/patch_comment.test.ts @@ -35,7 +35,7 @@ describe('PATCH comment', () => { }, }); - const theContext = createRouteContext( + const theContext = await createRouteContext( createMockSavedObjectsRepository({ caseSavedObject: mockCases, caseCommentSavedObject: mockCaseComments, @@ -63,7 +63,7 @@ describe('PATCH comment', () => { }, }); - const theContext = createRouteContext( + const theContext = await createRouteContext( createMockSavedObjectsRepository({ caseSavedObject: mockCases, caseCommentSavedObject: mockCaseComments, @@ -87,7 +87,7 @@ describe('PATCH comment', () => { }, }); - const theContext = createRouteContext( + const theContext = await createRouteContext( createMockSavedObjectsRepository({ caseSavedObject: mockCases, caseCommentSavedObject: mockCaseComments, diff --git a/x-pack/plugins/case/server/routes/api/cases/comments/post_comment.test.ts b/x-pack/plugins/case/server/routes/api/cases/comments/post_comment.test.ts index 9006470f36f36..acc23815e3a39 100644 --- a/x-pack/plugins/case/server/routes/api/cases/comments/post_comment.test.ts +++ b/x-pack/plugins/case/server/routes/api/cases/comments/post_comment.test.ts @@ -26,6 +26,7 @@ describe('POST comment', () => { toISOString: jest.fn().mockReturnValue('2019-11-25T21:54:48.952Z'), })); }); + it(`Posts a new comment`, async () => { const request = httpServerMock.createKibanaRequest({ path: CASE_COMMENTS_URL, @@ -38,7 +39,7 @@ describe('POST comment', () => { }, }); - const theContext = createRouteContext( + const theContext = await createRouteContext( createMockSavedObjectsRepository({ caseSavedObject: mockCases, caseCommentSavedObject: mockCaseComments, @@ -51,6 +52,7 @@ describe('POST comment', () => { 'mock-comment' ); }); + it(`Returns an error if the case does not exist`, async () => { const request = httpServerMock.createKibanaRequest({ path: CASE_COMMENTS_URL, @@ -63,7 +65,7 @@ describe('POST comment', () => { }, }); - const theContext = createRouteContext( + const theContext = await createRouteContext( createMockSavedObjectsRepository({ caseSavedObject: mockCases, caseCommentSavedObject: mockCaseComments, @@ -74,6 +76,7 @@ describe('POST comment', () => { expect(response.status).toEqual(404); expect(response.payload.isBoom).toEqual(true); }); + it(`Returns an error if postNewCase throws`, async () => { const request = httpServerMock.createKibanaRequest({ path: CASE_COMMENTS_URL, @@ -86,7 +89,7 @@ describe('POST comment', () => { }, }); - const theContext = createRouteContext( + const theContext = await createRouteContext( createMockSavedObjectsRepository({ caseSavedObject: mockCases, caseCommentSavedObject: mockCaseComments, @@ -97,6 +100,7 @@ describe('POST comment', () => { expect(response.status).toEqual(400); expect(response.payload.isBoom).toEqual(true); }); + it(`Allow user to create comments without authentications`, async () => { routeHandler = await createRoute(initPostCommentApi, 'post', true); @@ -111,11 +115,12 @@ describe('POST comment', () => { }, }); - const theContext = createRouteContext( + const theContext = await createRouteContext( createMockSavedObjectsRepository({ caseSavedObject: mockCases, caseCommentSavedObject: mockCaseComments, - }) + }), + true ); const response = await routeHandler(theContext, request, kibanaResponseFactory); diff --git a/x-pack/plugins/case/server/routes/api/cases/comments/post_comment.ts b/x-pack/plugins/case/server/routes/api/cases/comments/post_comment.ts index 3c5b72eba5d13..08d442bccf2cb 100644 --- a/x-pack/plugins/case/server/routes/api/cases/comments/post_comment.ts +++ b/x-pack/plugins/case/server/routes/api/cases/comments/post_comment.ts @@ -5,24 +5,12 @@ */ import { schema } from '@kbn/config-schema'; -import Boom from 'boom'; -import { pipe } from 'fp-ts/lib/pipeable'; -import { fold } from 'fp-ts/lib/Either'; -import { identity } from 'fp-ts/lib/function'; - -import { CaseResponseRt, CommentRequestRt, excess, throwErrors } from '../../../../../common/api'; -import { CASE_SAVED_OBJECT } from '../../../../saved_object_types'; -import { buildCommentUserActionItem } from '../../../../services/user_actions/helpers'; -import { escapeHatch, transformNewComment, wrapError, flattenCaseSavedObject } from '../../utils'; +import { escapeHatch, wrapError } from '../../utils'; import { RouteDeps } from '../../types'; import { CASE_COMMENTS_URL } from '../../../../../common/constants'; +import { CommentRequest } from '../../../../../common/api'; -export function initPostCommentApi({ - caseConfigureService, - caseService, - router, - userActionService, -}: RouteDeps) { +export function initPostCommentApi({ router }: RouteDeps) { router.post( { path: CASE_COMMENTS_URL, @@ -34,101 +22,17 @@ export function initPostCommentApi({ }, }, async (context, request, response) => { - try { - const client = context.core.savedObjects.client; - const caseId = request.params.case_id; - const query = pipe( - excess(CommentRequestRt).decode(request.body), - fold(throwErrors(Boom.badRequest), identity) - ); - - const myCase = await caseService.getCase({ - client, - caseId, - }); - - // eslint-disable-next-line @typescript-eslint/naming-convention - const { username, full_name, email } = await caseService.getUser({ request, response }); - const createdDate = new Date().toISOString(); - - const [newComment, updatedCase] = await Promise.all([ - caseService.postNewComment({ - client, - attributes: transformNewComment({ - createdDate, - ...query, - username, - full_name, - email, - }), - references: [ - { - type: CASE_SAVED_OBJECT, - name: `associated-${CASE_SAVED_OBJECT}`, - id: myCase.id, - }, - ], - }), - caseService.patchCase({ - client, - caseId, - updatedAttributes: { - updated_at: createdDate, - updated_by: { username, full_name, email }, - }, - version: myCase.version, - }), - ]); - - const totalCommentsFindByCases = await caseService.getAllCaseComments({ - client, - caseId, - options: { - fields: [], - page: 1, - perPage: 1, - }, - }); + if (!context.case) { + return response.badRequest({ body: 'RouteHandlerContext is not registered for cases' }); + } - const [comments] = await Promise.all([ - caseService.getAllCaseComments({ - client, - caseId, - options: { - fields: [], - page: 1, - perPage: totalCommentsFindByCases.total, - }, - }), - userActionService.postUserActions({ - client, - actions: [ - buildCommentUserActionItem({ - action: 'create', - actionAt: createdDate, - actionBy: { username, full_name, email }, - caseId: myCase.id, - commentId: newComment.id, - fields: ['comment'], - newValue: query.comment, - }), - ], - }), - ]); + const caseClient = context.case.getCaseClient(); + const caseId = request.params.case_id; + const comment = request.body as CommentRequest; + try { return response.ok({ - body: CaseResponseRt.encode( - flattenCaseSavedObject({ - savedObject: { - ...myCase, - ...updatedCase, - attributes: { ...myCase.attributes, ...updatedCase.attributes }, - version: updatedCase.version ?? myCase.version, - references: myCase.references, - }, - comments: comments.saved_objects, - }) - ), + body: await caseClient.addComment({ caseId, comment }), }); } catch (error) { return response.customError(wrapError(error)); diff --git a/x-pack/plugins/case/server/routes/api/cases/configure/get_configure.test.ts b/x-pack/plugins/case/server/routes/api/cases/configure/get_configure.test.ts index 45ce19fca9d20..cc4f208758369 100644 --- a/x-pack/plugins/case/server/routes/api/cases/configure/get_configure.test.ts +++ b/x-pack/plugins/case/server/routes/api/cases/configure/get_configure.test.ts @@ -29,7 +29,7 @@ describe('GET configuration', () => { method: 'get', }); - const context = createRouteContext( + const context = await createRouteContext( createMockSavedObjectsRepository({ caseConfigureSavedObject: mockCaseConfigure, }) @@ -49,7 +49,7 @@ describe('GET configuration', () => { method: 'get', }); - const context = createRouteContext( + const context = await createRouteContext( createMockSavedObjectsRepository({ caseConfigureSavedObject: [{ ...mockCaseConfigure[0], version: undefined }], }) @@ -87,7 +87,7 @@ describe('GET configuration', () => { method: 'get', }); - const context = createRouteContext( + const context = await createRouteContext( createMockSavedObjectsRepository({ caseConfigureSavedObject: [], }) @@ -105,7 +105,7 @@ describe('GET configuration', () => { method: 'get', }); - const context = createRouteContext( + const context = await createRouteContext( createMockSavedObjectsRepository({ caseConfigureSavedObject: [{ ...mockCaseConfigure[0], id: 'throw-error-find' }], }) diff --git a/x-pack/plugins/case/server/routes/api/cases/configure/get_connectors.test.ts b/x-pack/plugins/case/server/routes/api/cases/configure/get_connectors.test.ts index ee4dcc8e81b95..2eab4ac756361 100644 --- a/x-pack/plugins/case/server/routes/api/cases/configure/get_connectors.test.ts +++ b/x-pack/plugins/case/server/routes/api/cases/configure/get_connectors.test.ts @@ -29,7 +29,7 @@ describe('GET connectors', () => { method: 'get', }); - const context = createRouteContext( + const context = await createRouteContext( createMockSavedObjectsRepository({ caseConfigureSavedObject: mockCaseConfigure, }) @@ -106,7 +106,7 @@ describe('GET connectors', () => { method: 'get', }); - const context = createRouteContext( + const context = await createRouteContext( createMockSavedObjectsRepository({ caseConfigureSavedObject: mockCaseConfigure, }) diff --git a/x-pack/plugins/case/server/routes/api/cases/configure/patch_configure.test.ts b/x-pack/plugins/case/server/routes/api/cases/configure/patch_configure.test.ts index 8fcb769225d44..261cd3e6b0884 100644 --- a/x-pack/plugins/case/server/routes/api/cases/configure/patch_configure.test.ts +++ b/x-pack/plugins/case/server/routes/api/cases/configure/patch_configure.test.ts @@ -39,7 +39,7 @@ describe('PATCH configuration', () => { }, }); - const context = createRouteContext( + const context = await createRouteContext( createMockSavedObjectsRepository({ caseConfigureSavedObject: mockCaseConfigure, }) @@ -72,7 +72,7 @@ describe('PATCH configuration', () => { }, }); - const context = createRouteContext( + const context = await createRouteContext( createMockSavedObjectsRepository({ caseConfigureSavedObject: mockCaseConfigure, }) @@ -110,7 +110,7 @@ describe('PATCH configuration', () => { }, }); - const context = createRouteContext( + const context = await createRouteContext( createMockSavedObjectsRepository({ caseConfigureSavedObject: mockCaseConfigure, }) @@ -141,7 +141,7 @@ describe('PATCH configuration', () => { }, }); - const context = createRouteContext( + const context = await createRouteContext( createMockSavedObjectsRepository({ caseConfigureSavedObject: [], }) @@ -163,7 +163,7 @@ describe('PATCH configuration', () => { }, }); - const context = createRouteContext( + const context = await createRouteContext( createMockSavedObjectsRepository({ caseConfigureSavedObject: mockCaseConfigure, }) @@ -190,7 +190,7 @@ describe('PATCH configuration', () => { }, }); - const context = createRouteContext( + const context = await createRouteContext( createMockSavedObjectsRepository({ caseConfigureSavedObject: mockCaseConfigure, }) diff --git a/x-pack/plugins/case/server/routes/api/cases/configure/post_configure.test.ts b/x-pack/plugins/case/server/routes/api/cases/configure/post_configure.test.ts index 27df19d8f823a..7ef3bdb4a700a 100644 --- a/x-pack/plugins/case/server/routes/api/cases/configure/post_configure.test.ts +++ b/x-pack/plugins/case/server/routes/api/cases/configure/post_configure.test.ts @@ -37,7 +37,7 @@ describe('POST configuration', () => { body: newConfiguration, }); - const context = createRouteContext( + const context = await createRouteContext( createMockSavedObjectsRepository({ caseConfigureSavedObject: mockCaseConfigure, }) @@ -72,7 +72,7 @@ describe('POST configuration', () => { body: newConfiguration, }); - const context = createRouteContext( + const context = await createRouteContext( createMockSavedObjectsRepository({ caseConfigureSavedObject: mockCaseConfigure, }) @@ -112,7 +112,7 @@ describe('POST configuration', () => { }, }); - const context = createRouteContext( + const context = await createRouteContext( createMockSavedObjectsRepository({ caseConfigureSavedObject: mockCaseConfigure, }) @@ -137,7 +137,7 @@ describe('POST configuration', () => { }, }); - const context = createRouteContext( + const context = await createRouteContext( createMockSavedObjectsRepository({ caseConfigureSavedObject: mockCaseConfigure, }) @@ -162,7 +162,7 @@ describe('POST configuration', () => { }, }); - const context = createRouteContext( + const context = await createRouteContext( createMockSavedObjectsRepository({ caseConfigureSavedObject: mockCaseConfigure, }) @@ -187,7 +187,7 @@ describe('POST configuration', () => { }, }); - const context = createRouteContext( + const context = await createRouteContext( createMockSavedObjectsRepository({ caseConfigureSavedObject: mockCaseConfigure, }) @@ -212,7 +212,7 @@ describe('POST configuration', () => { }, }); - const context = createRouteContext( + const context = await createRouteContext( createMockSavedObjectsRepository({ caseConfigureSavedObject: mockCaseConfigure, }) @@ -234,7 +234,7 @@ describe('POST configuration', () => { caseConfigureSavedObject: mockCaseConfigure, }); - const context = createRouteContext(savedObjectRepository); + const context = await createRouteContext(savedObjectRepository); const res = await routeHandler(context, req, kibanaResponseFactory); @@ -253,7 +253,7 @@ describe('POST configuration', () => { caseConfigureSavedObject: [], }); - const context = createRouteContext(savedObjectRepository); + const context = await createRouteContext(savedObjectRepository); const res = await routeHandler(context, req, kibanaResponseFactory); @@ -275,7 +275,7 @@ describe('POST configuration', () => { ], }); - const context = createRouteContext(savedObjectRepository); + const context = await createRouteContext(savedObjectRepository); const res = await routeHandler(context, req, kibanaResponseFactory); @@ -291,7 +291,7 @@ describe('POST configuration', () => { body: newConfiguration, }); - const context = createRouteContext( + const context = await createRouteContext( createMockSavedObjectsRepository({ caseConfigureSavedObject: [{ ...mockCaseConfigure[0], id: 'throw-error-find' }], }) @@ -309,7 +309,7 @@ describe('POST configuration', () => { body: newConfiguration, }); - const context = createRouteContext( + const context = await createRouteContext( createMockSavedObjectsRepository({ caseConfigureSavedObject: [{ ...mockCaseConfigure[0], id: 'throw-error-delete' }], }) @@ -334,7 +334,7 @@ describe('POST configuration', () => { }, }); - const context = createRouteContext( + const context = await createRouteContext( createMockSavedObjectsRepository({ caseConfigureSavedObject: mockCaseConfigure, }) @@ -360,7 +360,7 @@ describe('POST configuration', () => { }, }); - const context = createRouteContext( + const context = await createRouteContext( createMockSavedObjectsRepository({ caseConfigureSavedObject: mockCaseConfigure, }) @@ -385,7 +385,7 @@ describe('POST configuration', () => { }, }); - const context = createRouteContext( + const context = await createRouteContext( createMockSavedObjectsRepository({ caseConfigureSavedObject: mockCaseConfigure, }) @@ -406,7 +406,7 @@ describe('POST configuration', () => { }, }); - const context = createRouteContext( + const context = await createRouteContext( createMockSavedObjectsRepository({ caseConfigureSavedObject: mockCaseConfigure, }) diff --git a/x-pack/plugins/case/server/routes/api/cases/delete_cases.test.ts b/x-pack/plugins/case/server/routes/api/cases/delete_cases.test.ts index e655339e05eb1..3970534140cd8 100644 --- a/x-pack/plugins/case/server/routes/api/cases/delete_cases.test.ts +++ b/x-pack/plugins/case/server/routes/api/cases/delete_cases.test.ts @@ -32,7 +32,7 @@ describe('DELETE case', () => { }, }); - const theContext = createRouteContext( + const theContext = await createRouteContext( createMockSavedObjectsRepository({ caseSavedObject: mockCases, caseCommentSavedObject: mockCaseComments, @@ -51,7 +51,7 @@ describe('DELETE case', () => { }, }); - const theContext = createRouteContext( + const theContext = await createRouteContext( createMockSavedObjectsRepository({ caseSavedObject: mockCases, caseCommentSavedObject: mockCaseComments, @@ -70,7 +70,7 @@ describe('DELETE case', () => { }, }); - const theContext = createRouteContext( + const theContext = await createRouteContext( createMockSavedObjectsRepository({ caseSavedObject: mockCasesErrorTriggerData, caseCommentSavedObject: mockCaseComments, @@ -89,7 +89,7 @@ describe('DELETE case', () => { }, }); - const theContext = createRouteContext( + const theContext = await createRouteContext( createMockSavedObjectsRepository({ caseSavedObject: mockCasesErrorTriggerData, caseCommentSavedObject: mockCasesErrorTriggerData, diff --git a/x-pack/plugins/case/server/routes/api/cases/find_cases.test.ts b/x-pack/plugins/case/server/routes/api/cases/find_cases.test.ts index df27551d2c922..b2ba8b2fcb33a 100644 --- a/x-pack/plugins/case/server/routes/api/cases/find_cases.test.ts +++ b/x-pack/plugins/case/server/routes/api/cases/find_cases.test.ts @@ -29,7 +29,7 @@ describe('FIND all cases', () => { method: 'get', }); - const theContext = createRouteContext( + const theContext = await createRouteContext( createMockSavedObjectsRepository({ caseSavedObject: mockCases, }) @@ -46,7 +46,7 @@ describe('FIND all cases', () => { method: 'get', }); - const theContext = createRouteContext( + const theContext = await createRouteContext( createMockSavedObjectsRepository({ caseSavedObject: mockCases, }) @@ -63,7 +63,7 @@ describe('FIND all cases', () => { method: 'get', }); - const theContext = createRouteContext( + const theContext = await createRouteContext( createMockSavedObjectsRepository({ caseSavedObject: [mockCaseNoConnectorId], }) @@ -80,7 +80,7 @@ describe('FIND all cases', () => { method: 'get', }); - const theContext = createRouteContext( + const theContext = await createRouteContext( createMockSavedObjectsRepository({ caseSavedObject: [mockCaseNoConnectorId], caseConfigureSavedObject: mockCaseConfigure, diff --git a/x-pack/plugins/case/server/routes/api/cases/get_case.test.ts b/x-pack/plugins/case/server/routes/api/cases/get_case.test.ts index 224da4464e1c2..01de9abac16af 100644 --- a/x-pack/plugins/case/server/routes/api/cases/get_case.test.ts +++ b/x-pack/plugins/case/server/routes/api/cases/get_case.test.ts @@ -39,7 +39,7 @@ describe('GET case', () => { }, }); - const theContext = createRouteContext( + const theContext = await createRouteContext( createMockSavedObjectsRepository({ caseSavedObject: mockCases, }) @@ -70,7 +70,7 @@ describe('GET case', () => { }, }); - const theContext = createRouteContext( + const theContext = await createRouteContext( createMockSavedObjectsRepository({ caseSavedObject: mockCases, }) @@ -94,7 +94,7 @@ describe('GET case', () => { }, }); - const theContext = createRouteContext( + const theContext = await createRouteContext( createMockSavedObjectsRepository({ caseSavedObject: mockCases, caseCommentSavedObject: mockCaseComments, @@ -119,7 +119,7 @@ describe('GET case', () => { }, }); - const theContext = createRouteContext( + const theContext = await createRouteContext( createMockSavedObjectsRepository({ caseSavedObject: mockCasesErrorTriggerData, }) @@ -142,7 +142,7 @@ describe('GET case', () => { }, }); - const theContext = createRouteContext( + const theContext = await createRouteContext( createMockSavedObjectsRepository({ caseSavedObject: [mockCaseNoConnectorId], }) @@ -171,7 +171,7 @@ describe('GET case', () => { }, }); - const theContext = createRouteContext( + const theContext = await createRouteContext( createMockSavedObjectsRepository({ caseSavedObject: [mockCaseNoConnectorId], caseConfigureSavedObject: mockCaseConfigure, @@ -201,7 +201,7 @@ describe('GET case', () => { }, }); - const theContext = createRouteContext( + const theContext = await createRouteContext( createMockSavedObjectsRepository({ caseSavedObject: mockCases, caseConfigureSavedObject: mockCaseConfigure, diff --git a/x-pack/plugins/case/server/routes/api/cases/patch_cases.test.ts b/x-pack/plugins/case/server/routes/api/cases/patch_cases.test.ts index c0d19edcad91f..ea69ee77c5802 100644 --- a/x-pack/plugins/case/server/routes/api/cases/patch_cases.test.ts +++ b/x-pack/plugins/case/server/routes/api/cases/patch_cases.test.ts @@ -43,7 +43,7 @@ describe('PATCH cases', () => { }, }); - const theContext = createRouteContext( + const theContext = await createRouteContext( createMockSavedObjectsRepository({ caseSavedObject: mockCases, }) @@ -93,7 +93,7 @@ describe('PATCH cases', () => { }, }); - const theContext = createRouteContext( + const theContext = await createRouteContext( createMockSavedObjectsRepository({ caseSavedObject: mockCases, caseConfigureSavedObject: mockCaseConfigure, @@ -144,7 +144,7 @@ describe('PATCH cases', () => { }, }); - const theContext = createRouteContext( + const theContext = await createRouteContext( createMockSavedObjectsRepository({ caseSavedObject: [mockCaseNoConnectorId], }) @@ -170,7 +170,7 @@ describe('PATCH cases', () => { }, }); - const theContext = createRouteContext( + const theContext = await createRouteContext( createMockSavedObjectsRepository({ caseSavedObject: mockCases, }) @@ -201,7 +201,7 @@ describe('PATCH cases', () => { }, }); - const theContext = createRouteContext( + const theContext = await createRouteContext( createMockSavedObjectsRepository({ caseSavedObject: mockCases, }) @@ -232,7 +232,7 @@ describe('PATCH cases', () => { }, }); - const theContext = createRouteContext( + const theContext = await createRouteContext( createMockSavedObjectsRepository({ caseSavedObject: mockCases, }) @@ -257,7 +257,7 @@ describe('PATCH cases', () => { }, }); - const theContext = createRouteContext( + const theContext = await createRouteContext( createMockSavedObjectsRepository({ caseSavedObject: mockCases, caseCommentSavedObject: mockCaseComments, @@ -283,7 +283,7 @@ describe('PATCH cases', () => { }, }); - const theContext = createRouteContext( + const theContext = await createRouteContext( createMockSavedObjectsRepository({ caseSavedObject: mockCases, }) diff --git a/x-pack/plugins/case/server/routes/api/cases/patch_cases.ts b/x-pack/plugins/case/server/routes/api/cases/patch_cases.ts index 79e2e99731546..873671a909801 100644 --- a/x-pack/plugins/case/server/routes/api/cases/patch_cases.ts +++ b/x-pack/plugins/case/server/routes/api/cases/patch_cases.ts @@ -4,31 +4,12 @@ * you may not use this file except in compliance with the Elastic License. */ -import Boom from 'boom'; -import { pipe } from 'fp-ts/lib/pipeable'; -import { fold } from 'fp-ts/lib/Either'; -import { identity } from 'fp-ts/lib/function'; - -import { - CasesPatchRequestRt, - CasesResponseRt, - CasePatchRequest, - excess, - throwErrors, - ESCasePatchRequest, -} from '../../../../common/api'; -import { escapeHatch, wrapError, flattenCaseSavedObject } from '../utils'; +import { escapeHatch, wrapError } from '../utils'; import { RouteDeps } from '../types'; -import { getCaseToUpdate, transformCaseConnectorToEsConnector } from './helpers'; -import { buildCaseUserActions } from '../../../services/user_actions/helpers'; import { CASES_URL } from '../../../../common/constants'; +import { CasesPatchRequest } from '../../../../common/api'; -export function initPatchCasesApi({ - caseConfigureService, - caseService, - router, - userActionService, -}: RouteDeps) { +export function initPatchCasesApi({ router }: RouteDeps) { router.patch( { path: CASES_URL, @@ -37,126 +18,17 @@ export function initPatchCasesApi({ }, }, async (context, request, response) => { - try { - const client = context.core.savedObjects.client; - const query = pipe( - excess(CasesPatchRequestRt).decode(request.body), - fold(throwErrors(Boom.badRequest), identity) - ); - - const myCases = await caseService.getCases({ - client, - caseIds: query.cases.map((q) => q.id), - }); - - let nonExistingCases: CasePatchRequest[] = []; - const conflictedCases = query.cases.filter((q) => { - const myCase = myCases.saved_objects.find((c) => c.id === q.id); - - if (myCase && myCase.error) { - nonExistingCases = [...nonExistingCases, q]; - return false; - } - return myCase == null || myCase?.version !== q.version; - }); - if (nonExistingCases.length > 0) { - throw Boom.notFound( - `These cases ${nonExistingCases - .map((c) => c.id) - .join(', ')} do not exist. Please check you have the correct ids.` - ); - } - if (conflictedCases.length > 0) { - throw Boom.conflict( - `These cases ${conflictedCases - .map((c) => c.id) - .join(', ')} has been updated. Please refresh before saving additional updates.` - ); - } + if (!context.case) { + return response.badRequest({ body: 'RouteHandlerContext is not registered for cases' }); + } - const updateCases: ESCasePatchRequest[] = query.cases.map((updateCase) => { - const currentCase = myCases.saved_objects.find((c) => c.id === updateCase.id); - const { connector, ...thisCase } = updateCase; - return currentCase != null - ? getCaseToUpdate(currentCase.attributes, { - ...thisCase, - ...(connector != null - ? { connector: transformCaseConnectorToEsConnector(connector) } - : {}), - }) - : { id: thisCase.id, version: thisCase.version }; - }); + const caseClient = context.case.getCaseClient(); + const cases = request.body as CasesPatchRequest; - const updateFilterCases = updateCases.filter((updateCase) => { - const { id, version, ...updateCaseAttributes } = updateCase; - return Object.keys(updateCaseAttributes).length > 0; + try { + return response.ok({ + body: await caseClient.update({ cases }), }); - - if (updateFilterCases.length > 0) { - // eslint-disable-next-line @typescript-eslint/naming-convention - const { username, full_name, email } = await caseService.getUser({ request, response }); - const updatedDt = new Date().toISOString(); - const updatedCases = await caseService.patchCases({ - client, - cases: updateFilterCases.map((thisCase) => { - const { id: caseId, version, ...updateCaseAttributes } = thisCase; - let closedInfo = {}; - if (updateCaseAttributes.status && updateCaseAttributes.status === 'closed') { - closedInfo = { - closed_at: updatedDt, - closed_by: { email, full_name, username }, - }; - } else if (updateCaseAttributes.status && updateCaseAttributes.status === 'open') { - closedInfo = { - closed_at: null, - closed_by: null, - }; - } - return { - caseId, - updatedAttributes: { - ...updateCaseAttributes, - ...closedInfo, - updated_at: updatedDt, - updated_by: { email, full_name, username }, - }, - version, - }; - }), - }); - - const returnUpdatedCase = myCases.saved_objects - .filter((myCase) => - updatedCases.saved_objects.some((updatedCase) => updatedCase.id === myCase.id) - ) - .map((myCase) => { - const updatedCase = updatedCases.saved_objects.find((c) => c.id === myCase.id); - return flattenCaseSavedObject({ - savedObject: { - ...myCase, - ...updatedCase, - attributes: { ...myCase.attributes, ...updatedCase?.attributes }, - references: myCase.references, - version: updatedCase?.version ?? myCase.version, - }, - }); - }); - - await userActionService.postUserActions({ - client, - actions: buildCaseUserActions({ - originalCases: myCases.saved_objects, - updatedCases: updatedCases.saved_objects, - actionDate: updatedDt, - actionBy: { email, full_name, username }, - }), - }); - - return response.ok({ - body: CasesResponseRt.encode(returnUpdatedCase), - }); - } - throw Boom.notAcceptable('All update fields are identical to current version.'); } catch (error) { return response.customError(wrapError(error)); } diff --git a/x-pack/plugins/case/server/routes/api/cases/post_case.test.ts b/x-pack/plugins/case/server/routes/api/cases/post_case.test.ts index be1ed4166ab7b..1e1b19baa1c47 100644 --- a/x-pack/plugins/case/server/routes/api/cases/post_case.test.ts +++ b/x-pack/plugins/case/server/routes/api/cases/post_case.test.ts @@ -45,7 +45,7 @@ describe('POST cases', () => { }, }); - const theContext = createRouteContext( + const theContext = await createRouteContext( createMockSavedObjectsRepository({ caseSavedObject: mockCases, }) @@ -80,7 +80,7 @@ describe('POST cases', () => { }, }); - const theContext = createRouteContext( + const theContext = await createRouteContext( createMockSavedObjectsRepository({ caseSavedObject: mockCases, caseConfigureSavedObject: mockCaseConfigure, @@ -110,7 +110,7 @@ describe('POST cases', () => { }, }); - const theContext = createRouteContext( + const theContext = await createRouteContext( createMockSavedObjectsRepository({ caseSavedObject: mockCases, }) @@ -132,7 +132,7 @@ describe('POST cases', () => { }, }); - const theContext = createRouteContext( + const theContext = await createRouteContext( createMockSavedObjectsRepository({ caseSavedObject: mockCases, }) @@ -162,11 +162,12 @@ describe('POST cases', () => { }, }); - const theContext = createRouteContext( + const theContext = await createRouteContext( createMockSavedObjectsRepository({ caseSavedObject: mockCases, caseConfigureSavedObject: mockCaseConfigure, - }) + }), + true ); const response = await routeHandler(theContext, request, kibanaResponseFactory); diff --git a/x-pack/plugins/case/server/routes/api/cases/post_case.ts b/x-pack/plugins/case/server/routes/api/cases/post_case.ts index 5d8113b685741..663d502d548d5 100644 --- a/x-pack/plugins/case/server/routes/api/cases/post_case.ts +++ b/x-pack/plugins/case/server/routes/api/cases/post_case.ts @@ -4,25 +4,13 @@ * you may not use this file except in compliance with the Elastic License. */ -import Boom from 'boom'; -import { pipe } from 'fp-ts/lib/pipeable'; -import { fold } from 'fp-ts/lib/Either'; -import { identity } from 'fp-ts/lib/function'; +import { wrapError, escapeHatch } from '../utils'; -import { flattenCaseSavedObject, transformNewCase, wrapError, escapeHatch } from '../utils'; - -import { CasePostRequestRt, throwErrors, excess, CaseResponseRt } from '../../../../common/api'; -import { buildCaseUserActionItem } from '../../../services/user_actions/helpers'; import { RouteDeps } from '../types'; import { CASES_URL } from '../../../../common/constants'; -import { getConnectorFromConfiguration, transformCaseConnectorToEsConnector } from './helpers'; +import { CasePostRequest } from '../../../../common/api'; -export function initPostCaseApi({ - caseService, - caseConfigureService, - router, - userActionService, -}: RouteDeps) { +export function initPostCaseApi({ router }: RouteDeps) { router.post( { path: CASES_URL, @@ -31,53 +19,15 @@ export function initPostCaseApi({ }, }, async (context, request, response) => { - try { - const client = context.core.savedObjects.client; - const query = pipe( - excess(CasePostRequestRt).decode(request.body), - fold(throwErrors(Boom.badRequest), identity) - ); - - // eslint-disable-next-line @typescript-eslint/naming-convention - const { username, full_name, email } = await caseService.getUser({ request, response }); - const createdDate = new Date().toISOString(); - const myCaseConfigure = await caseConfigureService.find({ client }); - const caseConfigureConnector = getConnectorFromConfiguration(myCaseConfigure); - - const newCase = await caseService.postNewCase({ - client, - attributes: transformNewCase({ - createdDate, - newCase: query, - username, - full_name, - email, - connector: transformCaseConnectorToEsConnector( - query.connector ?? caseConfigureConnector - ), - }), - }); - - await userActionService.postUserActions({ - client, - actions: [ - buildCaseUserActionItem({ - action: 'create', - actionAt: createdDate, - actionBy: { username, full_name, email }, - caseId: newCase.id, - fields: ['description', 'status', 'tags', 'title', 'connector'], - newValue: JSON.stringify(query), - }), - ], - }); + if (!context.case) { + return response.badRequest({ body: 'RouteHandlerContext is not registered for cases' }); + } + const caseClient = context.case.getCaseClient(); + const theCase = request.body as CasePostRequest; + try { return response.ok({ - body: CaseResponseRt.encode( - flattenCaseSavedObject({ - savedObject: newCase, - }) - ), + body: await caseClient.create({ theCase }), }); } catch (error) { return response.customError(wrapError(error)); diff --git a/x-pack/plugins/case/server/routes/api/cases/push_case.test.ts b/x-pack/plugins/case/server/routes/api/cases/push_case.test.ts index c68b4b0c91735..eee59a974b37b 100644 --- a/x-pack/plugins/case/server/routes/api/cases/push_case.test.ts +++ b/x-pack/plugins/case/server/routes/api/cases/push_case.test.ts @@ -44,7 +44,7 @@ describe('Push case', () => { body: caseExternalServiceRequestBody, }); - const theContext = createRouteContext( + const theContext = await createRouteContext( createMockSavedObjectsRepository({ caseSavedObject: mockCases, }) @@ -66,7 +66,7 @@ describe('Push case', () => { body: caseExternalServiceRequestBody, }); - const theContext = createRouteContext( + const theContext = await createRouteContext( createMockSavedObjectsRepository({ caseSavedObject: mockCases, caseConfigureSavedObject: [ @@ -97,7 +97,7 @@ describe('Push case', () => { }, }); - const theContext = createRouteContext( + const theContext = await createRouteContext( createMockSavedObjectsRepository({ caseSavedObject: mockCases, }) diff --git a/x-pack/plugins/case/server/routes/api/utils.ts b/x-pack/plugins/case/server/routes/api/utils.ts index 2202bda2be087..90066bf29ae66 100644 --- a/x-pack/plugins/case/server/routes/api/utils.ts +++ b/x-pack/plugins/case/server/routes/api/utils.ts @@ -121,7 +121,7 @@ export const flattenCaseSavedObjects = ( export const flattenCaseSavedObject = ({ savedObject, comments = [], - totalComment = 0, + totalComment = comments.length, }: { savedObject: SavedObject; comments?: Array>; diff --git a/x-pack/plugins/case/server/services/index.ts b/x-pack/plugins/case/server/services/index.ts index 3db83331a0ab9..cab8cb499c3fa 100644 --- a/x-pack/plugins/case/server/services/index.ts +++ b/x-pack/plugins/case/server/services/index.ts @@ -96,7 +96,7 @@ interface PatchComments extends ClientArgs { interface GetUserArgs { request: KibanaRequest; - response: KibanaResponseFactory; + response?: KibanaResponseFactory; } interface CaseServiceDeps { diff --git a/x-pack/plugins/case/server/services/mocks.ts b/x-pack/plugins/case/server/services/mocks.ts new file mode 100644 index 0000000000000..287f80a60ab07 --- /dev/null +++ b/x-pack/plugins/case/server/services/mocks.ts @@ -0,0 +1,43 @@ +/* + * 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 { CaseConfigureServiceSetup, CaseServiceSetup, CaseUserActionServiceSetup } from '.'; + +export type CaseServiceMock = jest.Mocked; +export type CaseConfigureServiceMock = jest.Mocked; +export type CaseUserActionServiceMock = jest.Mocked; + +export const createCaseServiceMock = (): CaseServiceMock => ({ + deleteCase: jest.fn(), + deleteComment: jest.fn(), + findCases: jest.fn(), + getAllCaseComments: jest.fn(), + getCase: jest.fn(), + getCases: jest.fn(), + getComment: jest.fn(), + getTags: jest.fn(), + getReporters: jest.fn(), + getUser: jest.fn(), + postNewCase: jest.fn(), + postNewComment: jest.fn(), + patchCase: jest.fn(), + patchCases: jest.fn(), + patchComment: jest.fn(), + patchComments: jest.fn(), +}); + +export const createConfigureServiceMock = (): CaseConfigureServiceMock => ({ + delete: jest.fn(), + get: jest.fn(), + find: jest.fn(), + patch: jest.fn(), + post: jest.fn(), +}); + +export const createUserActionServiceMock = (): CaseUserActionServiceMock => ({ + getUserActions: jest.fn(), + postUserActions: jest.fn(), +}); diff --git a/x-pack/plugins/case/server/types.ts b/x-pack/plugins/case/server/types.ts new file mode 100644 index 0000000000000..b95060ef30452 --- /dev/null +++ b/x-pack/plugins/case/server/types.ts @@ -0,0 +1,17 @@ +/* + * 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 { CaseClient } from './client'; + +export interface CaseRequestContext { + getCaseClient: () => CaseClient; +} + +declare module 'src/core/server' { + interface RequestHandlerContext { + case?: CaseRequestContext; + } +} diff --git a/x-pack/plugins/data_enhanced/public/search/search_interceptor.test.ts b/x-pack/plugins/data_enhanced/public/search/search_interceptor.test.ts index 3187b41a2c55f..f47d2b39a89a9 100644 --- a/x-pack/plugins/data_enhanced/public/search/search_interceptor.test.ts +++ b/x-pack/plugins/data_enhanced/public/search/search_interceptor.test.ts @@ -3,7 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ - +import type { MockedKeys } from '@kbn/utility-types/jest'; import { coreMock } from '../../../../../src/core/public/mocks'; import { EnhancedSearchInterceptor } from './search_interceptor'; import { CoreSetup, CoreStart } from 'kibana/public'; diff --git a/x-pack/plugins/encrypted_saved_objects/server/crypto/encryption_key_rotation_service.ts b/x-pack/plugins/encrypted_saved_objects/server/crypto/encryption_key_rotation_service.ts index fb1b6db45e762..44b040d19909c 100644 --- a/x-pack/plugins/encrypted_saved_objects/server/crypto/encryption_key_rotation_service.ts +++ b/x-pack/plugins/encrypted_saved_objects/server/crypto/encryption_key_rotation_service.ts @@ -3,7 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ - +import type { PublicMethodsOf } from '@kbn/utility-types'; import { ISavedObjectTypeRegistry, KibanaRequest, diff --git a/x-pack/plugins/encrypted_saved_objects/server/routes/index.ts b/x-pack/plugins/encrypted_saved_objects/server/routes/index.ts index 72af8060de827..f68e920e14de9 100644 --- a/x-pack/plugins/encrypted_saved_objects/server/routes/index.ts +++ b/x-pack/plugins/encrypted_saved_objects/server/routes/index.ts @@ -3,7 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ - +import type { PublicMethodsOf } from '@kbn/utility-types'; import { IRouter, Logger } from '../../../../../src/core/server'; import { ConfigType } from '../config'; import { EncryptionKeyRotationService } from '../crypto'; diff --git a/x-pack/plugins/encrypted_saved_objects/server/saved_objects/index.ts b/x-pack/plugins/encrypted_saved_objects/server/saved_objects/index.ts index 0e5be4e4eee5a..0191c1fbb830d 100644 --- a/x-pack/plugins/encrypted_saved_objects/server/saved_objects/index.ts +++ b/x-pack/plugins/encrypted_saved_objects/server/saved_objects/index.ts @@ -3,7 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ - +import type { PublicMethodsOf } from '@kbn/utility-types'; import { StartServicesAccessor, SavedObject, diff --git a/x-pack/plugins/event_log/server/es/cluster_client_adapter.ts b/x-pack/plugins/event_log/server/es/cluster_client_adapter.ts index 8c3e6e11b75c5..fa9f9c36052a1 100644 --- a/x-pack/plugins/event_log/server/es/cluster_client_adapter.ts +++ b/x-pack/plugins/event_log/server/es/cluster_client_adapter.ts @@ -6,6 +6,7 @@ import { reject, isUndefined } from 'lodash'; import { SearchResponse, Client } from 'elasticsearch'; +import type { PublicMethodsOf } from '@kbn/utility-types'; import { Logger, LegacyClusterClient } from 'src/core/server'; import { IValidatedEvent, SAVED_OBJECT_REL_PRIMARY } from '../types'; diff --git a/x-pack/plugins/event_log/server/routes/_mock_handler_arguments.ts b/x-pack/plugins/event_log/server/routes/_mock_handler_arguments.ts index b0ce5605d0e51..0ea5419b113d2 100644 --- a/x-pack/plugins/event_log/server/routes/_mock_handler_arguments.ts +++ b/x-pack/plugins/event_log/server/routes/_mock_handler_arguments.ts @@ -6,6 +6,7 @@ import { identity, merge } from 'lodash'; import { RequestHandlerContext, KibanaRequest, KibanaResponseFactory } from 'src/core/server'; +import type { MethodKeysOf } from '@kbn/utility-types'; import { httpServerMock } from 'src/core/server/mocks'; import { IEventLogClient } from '../types'; diff --git a/x-pack/plugins/features/server/ui_capabilities_for_features.ts b/x-pack/plugins/features/server/ui_capabilities_for_features.ts index d582dbfdab50c..03773a4d8f616 100644 --- a/x-pack/plugins/features/server/ui_capabilities_for_features.ts +++ b/x-pack/plugins/features/server/ui_capabilities_for_features.ts @@ -5,7 +5,7 @@ */ import _ from 'lodash'; -import { RecursiveReadonly } from '@kbn/utility-types'; +import type { RecursiveReadonly, Writable } from '@kbn/utility-types'; import { Capabilities as UICapabilities } from '../../../../src/core/server'; import { ElasticsearchFeature, KibanaFeature } from '../common'; diff --git a/x-pack/plugins/global_search/common/license_checker.ts b/x-pack/plugins/global_search/common/license_checker.ts index d201b31802b32..7524d0ad52e45 100644 --- a/x-pack/plugins/global_search/common/license_checker.ts +++ b/x-pack/plugins/global_search/common/license_checker.ts @@ -5,6 +5,7 @@ */ import { Observable, Subscription } from 'rxjs'; +import type { PublicMethodsOf } from '@kbn/utility-types'; import { ILicense } from '../../licensing/common/types'; export type LicenseState = { valid: false; message: string } | { valid: true }; diff --git a/x-pack/plugins/index_management/public/services/extensions_service.mock.ts b/x-pack/plugins/index_management/public/services/extensions_service.mock.ts index 3075a114eedd1..6cf533d67662f 100644 --- a/x-pack/plugins/index_management/public/services/extensions_service.mock.ts +++ b/x-pack/plugins/index_management/public/services/extensions_service.mock.ts @@ -3,7 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ - +import type { PublicMethodsOf } from '@kbn/utility-types'; import { ExtensionsService, ExtensionsSetup } from './extensions_service'; export type ExtensionsSetupMock = jest.Mocked; diff --git a/x-pack/plugins/infra/common/http_api/log_entries/entries.ts b/x-pack/plugins/infra/common/http_api/log_entries/entries.ts index 5014aeb52a3f7..d38b4690fed71 100644 --- a/x-pack/plugins/infra/common/http_api/log_entries/entries.ts +++ b/x-pack/plugins/infra/common/http_api/log_entries/entries.ts @@ -5,6 +5,7 @@ */ import * as rt from 'io-ts'; +import { jsonArrayRT } from '../../typed_json'; import { logEntriesCursorRT } from './common'; export const LOG_ENTRIES_PATH = '/api/log_entries/entries'; @@ -54,7 +55,7 @@ export const logMessageConstantPartRT = rt.type({ }); export const logMessageFieldPartRT = rt.type({ field: rt.string, - value: rt.unknown, + value: jsonArrayRT, highlights: rt.array(rt.string), }); @@ -64,7 +65,7 @@ export const logTimestampColumnRT = rt.type({ columnId: rt.string, timestamp: rt export const logFieldColumnRT = rt.type({ columnId: rt.string, field: rt.string, - value: rt.unknown, + value: jsonArrayRT, highlights: rt.array(rt.string), }); export const logMessageColumnRT = rt.type({ diff --git a/x-pack/plugins/infra/common/http_api/log_entries/item.ts b/x-pack/plugins/infra/common/http_api/log_entries/item.ts index 02335d68402c0..5f9457b8228ac 100644 --- a/x-pack/plugins/infra/common/http_api/log_entries/item.ts +++ b/x-pack/plugins/infra/common/http_api/log_entries/item.ts @@ -16,7 +16,7 @@ export const logEntriesItemRequestRT = rt.type({ export type LogEntriesItemRequest = rt.TypeOf; -const logEntriesItemFieldRT = rt.type({ field: rt.string, value: rt.string }); +const logEntriesItemFieldRT = rt.type({ field: rt.string, value: rt.array(rt.string) }); const logEntriesItemRT = rt.type({ id: rt.string, index: rt.string, diff --git a/x-pack/plugins/infra/common/typed_json.ts b/x-pack/plugins/infra/common/typed_json.ts index 98b5456fe44b8..0ff9e42942ef2 100644 --- a/x-pack/plugins/infra/common/typed_json.ts +++ b/x-pack/plugins/infra/common/typed_json.ts @@ -4,11 +4,21 @@ * you may not use this file except in compliance with the Elastic License. */ -export type JsonValue = null | boolean | number | string | JsonObject | JsonArray; +import * as rt from 'io-ts'; +import { JsonArray, JsonObject, JsonValue } from '../../../../src/plugins/kibana_utils/common'; -// eslint-disable-next-line @typescript-eslint/no-empty-interface -export interface JsonArray extends Array {} +export const jsonScalarRT = rt.union([rt.null, rt.boolean, rt.number, rt.string]); -export interface JsonObject { - [key: string]: JsonValue; -} +export const jsonValueRT: rt.Type = rt.recursion('JsonValue', () => + rt.union([jsonScalarRT, jsonArrayRT, jsonObjectRT]) +); + +export const jsonArrayRT: rt.Type = rt.recursion('JsonArray', () => + rt.array(jsonValueRT) +); + +export const jsonObjectRT: rt.Type = rt.recursion('JsonObject', () => + rt.record(rt.string, jsonValueRT) +); + +export { JsonValue, JsonArray, JsonObject }; diff --git a/x-pack/plugins/infra/public/components/logging/log_entry_flyout/log_entry_actions_menu.test.tsx b/x-pack/plugins/infra/public/components/logging/log_entry_flyout/log_entry_actions_menu.test.tsx index b4fa6b8800fba..77154474077c8 100644 --- a/x-pack/plugins/infra/public/components/logging/log_entry_flyout/log_entry_actions_menu.test.tsx +++ b/x-pack/plugins/infra/public/components/logging/log_entry_flyout/log_entry_actions_menu.test.tsx @@ -29,7 +29,7 @@ describe('LogEntryActionsMenu component', () => { { { { { { { .filter(({ field, value }) => value != null && UPTIME_FIELDS.includes(field)) .reduce((acc, fieldItem) => { const { field, value } = fieldItem; - try { - const parsedValue = decodeOrThrow(rt.array(rt.string))(JSON.parse(value)); - return acc.concat(parsedValue.map((val) => `${field}:${val}`)); - } catch (e) { - return acc.concat([`${field}:${value}`]); - } + return acc.concat(value.map((val) => `${field}:${val}`)); }, []); if (searchExpressions.length === 0) { @@ -119,7 +112,7 @@ const getUptimeLink = (logItem: LogEntriesItem): LinkDescriptor | undefined => { const getAPMLink = (logItem: LogEntriesItem): LinkDescriptor | undefined => { const traceIdEntry = logItem.fields.find( - ({ field, value }) => value != null && field === 'trace.id' + ({ field, value }) => value[0] != null && field === 'trace.id' ); if (!traceIdEntry) { @@ -127,7 +120,7 @@ const getAPMLink = (logItem: LogEntriesItem): LinkDescriptor | undefined => { } const timestampField = logItem.fields.find(({ field }) => field === '@timestamp'); - const timestamp = timestampField ? timestampField.value : null; + const timestamp = timestampField ? timestampField.value[0] : null; const { rangeFrom, rangeTo } = timestamp ? (() => { const from = new Date(timestamp); @@ -142,6 +135,6 @@ const getAPMLink = (logItem: LogEntriesItem): LinkDescriptor | undefined => { return { app: 'apm', - hash: getTraceUrl({ traceId: traceIdEntry.value, rangeFrom, rangeTo }), + hash: getTraceUrl({ traceId: traceIdEntry.value[0], rangeFrom, rangeTo }), }; }; diff --git a/x-pack/plugins/infra/public/components/logging/log_entry_flyout/log_entry_flyout.tsx b/x-pack/plugins/infra/public/components/logging/log_entry_flyout/log_entry_flyout.tsx index 76ffada510e51..b07d8c9dce23c 100644 --- a/x-pack/plugins/infra/public/components/logging/log_entry_flyout/log_entry_flyout.tsx +++ b/x-pack/plugins/infra/public/components/logging/log_entry_flyout/log_entry_flyout.tsx @@ -94,7 +94,7 @@ export const LogEntryFlyout = ({ onClick={createFilterHandler(item)} /> - {item.value} + {formatValue(item.value)} ), }, @@ -147,3 +147,7 @@ export const InfraFlyoutLoadingPanel = euiStyled.div` bottom: 0; left: 0; `; + +function formatValue(value: string[]) { + return value.length > 1 ? value.join(', ') : value[0]; +} diff --git a/x-pack/plugins/infra/public/components/logging/log_text_stream/field_value.tsx b/x-pack/plugins/infra/public/components/logging/log_text_stream/field_value.tsx new file mode 100644 index 0000000000000..7caf34c0cd6b7 --- /dev/null +++ b/x-pack/plugins/infra/public/components/logging/log_text_stream/field_value.tsx @@ -0,0 +1,66 @@ +/* + * 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 stringify from 'json-stable-stringify'; +import React from 'react'; +import { euiStyled } from '../../../../../observability/public'; +import { JsonArray, JsonValue } from '../../../../common/typed_json'; +import { ActiveHighlightMarker, highlightFieldValue, HighlightMarker } from './highlighting'; + +export const FieldValue: React.FC<{ + highlightTerms: string[]; + isActiveHighlight: boolean; + value: JsonArray; +}> = React.memo(({ highlightTerms, isActiveHighlight, value }) => { + if (value.length === 1) { + return ( + <> + {highlightFieldValue( + formatValue(value[0]), + highlightTerms, + isActiveHighlight ? ActiveHighlightMarker : HighlightMarker + )} + + ); + } else if (value.length > 1) { + return ( +
    + {value.map((entry, i) => ( + + {highlightFieldValue( + formatValue(entry), + highlightTerms, + isActiveHighlight ? ActiveHighlightMarker : HighlightMarker + )} + + ))} +
+ ); + } + + return null; +}); + +const formatValue = (value: JsonValue): string => { + if (typeof value === 'string') { + return value; + } + + return stringify(value); +}; + +const CommaSeparatedLi = euiStyled.li` + display: inline; + &:not(:last-child) { + margin-right: 1ex; + &::after { + content: ','; + } + } +`; diff --git a/x-pack/plugins/infra/public/components/logging/log_text_stream/log_entry_column.tsx b/x-pack/plugins/infra/public/components/logging/log_text_stream/log_entry_column.tsx index 51488f088e75a..9b039b7f2f3ba 100644 --- a/x-pack/plugins/infra/public/components/logging/log_text_stream/log_entry_column.tsx +++ b/x-pack/plugins/infra/public/components/logging/log_text_stream/log_entry_column.tsx @@ -39,7 +39,9 @@ export const LogEntryColumn = euiStyled.div.attrs(() => ({ overflow: hidden; `; -export const LogEntryColumnContent = euiStyled.div` +export const LogEntryColumnContent = euiStyled.div.attrs({ + 'data-test-subj': 'LogEntryColumnContent', +})` flex: 1 0 0%; padding: 2px ${COLUMN_PADDING}px; `; diff --git a/x-pack/plugins/infra/public/components/logging/log_text_stream/log_entry_field_column.test.tsx b/x-pack/plugins/infra/public/components/logging/log_text_stream/log_entry_field_column.test.tsx index d6068b6e60992..5813f08497a74 100644 --- a/x-pack/plugins/infra/public/components/logging/log_text_stream/log_entry_field_column.test.tsx +++ b/x-pack/plugins/infra/public/components/logging/log_text_stream/log_entry_field_column.test.tsx @@ -4,85 +4,113 @@ * you may not use this file except in compliance with the Elastic License. */ -import { mount } from 'enzyme'; +import { render } from '@testing-library/react'; import React from 'react'; - import { EuiThemeProvider } from '../../../../../observability/public'; +import { LogFieldColumn } from '../../../../common/http_api'; import { LogEntryFieldColumn } from './log_entry_field_column'; -import { LogColumn } from '../../../../common/http_api'; describe('LogEntryFieldColumn', () => { - it('should output a
    when displaying an Array of values', () => { - const column: LogColumn = { + it('renders a single value without a wrapping list', () => { + const column: LogFieldColumn = { + columnId: 'TEST_COLUMN', + field: 'TEST_FIELD', + value: ['a'], + highlights: [], + }; + + const renderResult = render( + , + { wrapper: EuiThemeProvider } + ); + + expect(renderResult.getByTestId('LogEntryColumnContent')).toHaveTextContent(/^a$/); + expect(renderResult.queryByTestId('LogEntryFieldValues')).toBe(null); + }); + + it('renders an array of values as a list', () => { + const column: LogFieldColumn = { columnId: 'TEST_COLUMN', field: 'TEST_FIELD', value: ['a', 'b', 'c'], highlights: [], }; - const component = mount( + const renderResult = render( , - { wrappingComponent: EuiThemeProvider } as any // https://github.com/DefinitelyTyped/DefinitelyTyped/issues/36075 + { wrapper: EuiThemeProvider } ); - expect(component.exists('ul')).toBe(true); - expect( - component.containsAllMatchingElements([ -
  • a
  • , -
  • b
  • , -
  • c
  • , - ]) - ).toBe(true); + expect(renderResult.getByTestId('LogEntryFieldValues')).not.toBeEmptyDOMElement(); + expect(renderResult.getByTestId('LogEntryFieldValue-0')).toHaveTextContent('a'); + expect(renderResult.getByTestId('LogEntryFieldValue-1')).toHaveTextContent('b'); + expect(renderResult.getByTestId('LogEntryFieldValue-2')).toHaveTextContent('c'); }); - it('should output a text representation of a passed complex value', () => { - const column: LogColumn = { + it('renders a text representation of a single complex object', () => { + const column: LogFieldColumn = { columnId: 'TEST_COLUMN', field: 'TEST_FIELD', - value: { - lat: 1, - lon: 2, - }, + value: [ + { + lat: 1, + lon: 2, + }, + ], highlights: [], }; - const component = mount( + const renderResult = render( , - { wrappingComponent: EuiThemeProvider } as any // https://github.com/DefinitelyTyped/DefinitelyTyped/issues/36075 + { wrapper: EuiThemeProvider } ); - expect(component.text()).toEqual('{"lat":1,"lon":2}'); + expect(renderResult.getByTestId('LogEntryColumnContent')).toHaveTextContent( + '{"lat":1,"lon":2}' + ); }); - it('should output just text when passed a non-Array', () => { - const column: LogColumn = { + it('renders text representations of a multiple complex objects', () => { + const column: LogFieldColumn = { columnId: 'TEST_COLUMN', field: 'TEST_FIELD', - value: 'foo', + value: [ + { + lat: 1, + lon: 2, + }, + [3, 4], + ], highlights: [], }; - const component = mount( + const renderResult = render( , - { wrappingComponent: EuiThemeProvider } as any // https://github.com/DefinitelyTyped/DefinitelyTyped/issues/36075 + { wrapper: EuiThemeProvider } ); - expect(component.exists('ul')).toBe(false); - expect(component.text()).toEqual('foo'); + expect(renderResult.getByTestId('LogEntryFieldValues')).not.toBeEmptyDOMElement(); + expect(renderResult.getByTestId('LogEntryFieldValue-0')).toHaveTextContent('{"lat":1,"lon":2}'); + expect(renderResult.getByTestId('LogEntryFieldValue-1')).toHaveTextContent('[3,4]'); }); }); diff --git a/x-pack/plugins/infra/public/components/logging/log_text_stream/log_entry_field_column.tsx b/x-pack/plugins/infra/public/components/logging/log_text_stream/log_entry_field_column.tsx index 4e9611f7a8d2f..cdffe3742b534 100644 --- a/x-pack/plugins/infra/public/components/logging/log_text_stream/log_entry_field_column.tsx +++ b/x-pack/plugins/infra/public/components/logging/log_text_stream/log_entry_field_column.tsx @@ -4,14 +4,12 @@ * you may not use this file except in compliance with the Elastic License. */ -import stringify from 'json-stable-stringify'; -import React, { useMemo } from 'react'; - +import React from 'react'; import { euiStyled } from '../../../../../observability/public'; +import { LogColumn } from '../../../../common/http_api'; import { isFieldColumn, isHighlightFieldColumn } from '../../../utils/log_entry'; -import { ActiveHighlightMarker, highlightFieldValue, HighlightMarker } from './highlighting'; +import { FieldValue } from './field_value'; import { LogEntryColumnContent } from './log_entry_column'; -import { LogColumn } from '../../../../common/http_api'; import { longWrappedContentStyle, preWrappedContentStyle, @@ -32,44 +30,20 @@ export const LogEntryFieldColumn: React.FunctionComponent { - const value = useMemo(() => { - if (isFieldColumn(columnValue)) { - return columnValue.value; - } + if (isFieldColumn(columnValue)) { + return ( + + + + ); + } else { return null; - }, [columnValue]); - const formattedValue = Array.isArray(value) ? ( -
      - {value.map((entry, i) => ( - - {highlightFieldValue( - entry, - isHighlightFieldColumn(firstHighlight) ? firstHighlight.highlights : [], - isActiveHighlight ? ActiveHighlightMarker : HighlightMarker - )} - - ))} -
    - ) : ( - highlightFieldValue( - typeof value === 'string' ? value : stringify(value), - isHighlightFieldColumn(firstHighlight) ? firstHighlight.highlights : [], - isActiveHighlight ? ActiveHighlightMarker : HighlightMarker - ) - ); - - return {formattedValue}; -}; - -const CommaSeparatedLi = euiStyled.li` - display: inline; - &:not(:last-child) { - margin-right: 1ex; - &::after { - content: ','; - } } -`; +}; interface LogEntryColumnContentProps { wrapMode: WrapMode; diff --git a/x-pack/plugins/infra/public/components/logging/log_text_stream/log_entry_message_column.test.tsx b/x-pack/plugins/infra/public/components/logging/log_text_stream/log_entry_message_column.test.tsx new file mode 100644 index 0000000000000..b9871cc3b36f4 --- /dev/null +++ b/x-pack/plugins/infra/public/components/logging/log_text_stream/log_entry_message_column.test.tsx @@ -0,0 +1,82 @@ +/* + * 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 { render } from '@testing-library/react'; +import React from 'react'; +import { EuiThemeProvider } from '../../../../../observability/public'; +import { LogMessageColumn } from '../../../../common/http_api'; +import { LogEntryMessageColumn } from './log_entry_message_column'; + +describe('LogEntryMessageColumn', () => { + it('renders a single scalar field value without a wrapping list', () => { + const column: LogMessageColumn = { + columnId: 'TEST_COLUMN', + message: [{ field: 'TEST_FIELD', value: ['VALUE'], highlights: [] }], + }; + + const renderResult = render( + , + { wrapper: EuiThemeProvider } + ); + + expect(renderResult.getByTestId('LogEntryColumnContent')).toHaveTextContent(/^VALUE$/); + expect(renderResult.queryByTestId('LogEntryFieldValues')).toBe(null); + }); + + it('renders a single array of scalar field values as a list', () => { + const column: LogMessageColumn = { + columnId: 'TEST_COLUMN', + message: [{ field: 'TEST_FIELD', value: ['VALUE_1', 'VALUE_2'], highlights: [] }], + }; + + const renderResult = render( + , + { wrapper: EuiThemeProvider } + ); + + expect(renderResult.getByTestId('LogEntryFieldValues')).not.toBeEmptyDOMElement(); + expect(renderResult.getByTestId('LogEntryFieldValue-0')).toHaveTextContent('VALUE_1'); + expect(renderResult.getByTestId('LogEntryFieldValue-1')).toHaveTextContent('VALUE_2'); + }); + + it('renders a complex message with an array of complex field values', () => { + const column: LogMessageColumn = { + columnId: 'TEST_COLUMN', + message: [ + { constant: 'CONSTANT_1' }, + { field: 'TEST_FIELD', value: [{ lat: 1, lon: 2 }, 'VALUE_2'], highlights: [] }, + { constant: 'CONSTANT_2' }, + ], + }; + + const renderResult = render( + , + { wrapper: EuiThemeProvider } + ); + + expect(renderResult.getByTestId('LogEntryColumnContent')).toHaveTextContent( + /^CONSTANT_1.*{"lat":1,"lon":2}.*VALUE_2.*CONSTANT_2$/ + ); + expect(renderResult.getByTestId('LogEntryFieldValues')).not.toBeEmptyDOMElement(); + expect(renderResult.getByTestId('LogEntryFieldValue-0')).toHaveTextContent('{"lat":1,"lon":2}'); + expect(renderResult.getByTestId('LogEntryFieldValue-1')).toHaveTextContent('VALUE_2'); + }); +}); diff --git a/x-pack/plugins/infra/public/components/logging/log_text_stream/log_entry_message_column.tsx b/x-pack/plugins/infra/public/components/logging/log_text_stream/log_entry_message_column.tsx index f83a0a222d3dc..b7ff6b1409bd5 100644 --- a/x-pack/plugins/infra/public/components/logging/log_text_stream/log_entry_message_column.tsx +++ b/x-pack/plugins/infra/public/components/logging/log_text_stream/log_entry_message_column.tsx @@ -5,17 +5,16 @@ */ import React, { memo, useMemo } from 'react'; -import stringify from 'json-stable-stringify'; - import { euiStyled } from '../../../../../observability/public'; +import { LogColumn, LogMessagePart } from '../../../../common/http_api'; import { isConstantSegment, isFieldSegment, + isHighlightFieldSegment, isHighlightMessageColumn, isMessageColumn, - isHighlightFieldSegment, } from '../../../utils/log_entry'; -import { ActiveHighlightMarker, highlightFieldValue, HighlightMarker } from './highlighting'; +import { FieldValue } from './field_value'; import { LogEntryColumnContent } from './log_entry_column'; import { longWrappedContentStyle, @@ -23,7 +22,6 @@ import { unwrappedContentStyle, WrapMode, } from './text_styles'; -import { LogColumn, LogMessagePart } from '../../../../common/http_api'; interface LogEntryMessageColumnProps { columnValue: LogColumn; @@ -65,10 +63,10 @@ const formatMessageSegments = ( highlights: LogColumn[], isActiveHighlight: boolean ) => - messageSegments.map((messageSegment, index) => - formatMessageSegment( - messageSegment, - highlights.map((highlight) => { + messageSegments.map((messageSegment, index) => { + if (isFieldSegment(messageSegment)) { + // we only support one highlight for now + const [firstHighlight = []] = highlights.map((highlight) => { if (isHighlightMessageColumn(highlight)) { const segment = highlight.message[index]; if (isHighlightFieldSegment(segment)) { @@ -76,30 +74,19 @@ const formatMessageSegments = ( } } return []; - }), - isActiveHighlight - ) - ); + }); -const formatMessageSegment = ( - messageSegment: LogMessagePart, - [firstHighlight = []]: string[][], // we only support one highlight for now - isActiveHighlight: boolean -): React.ReactNode => { - if (isFieldSegment(messageSegment)) { - const value = - typeof messageSegment.value === 'string' - ? messageSegment.value - : stringify(messageSegment.value); - - return highlightFieldValue( - value, - firstHighlight, - isActiveHighlight ? ActiveHighlightMarker : HighlightMarker - ); - } else if (isConstantSegment(messageSegment)) { - return messageSegment.constant; - } + return ( + + ); + } else if (isConstantSegment(messageSegment)) { + return messageSegment.constant; + } - return 'failed to format message'; -}; + return 'failed to format message'; + }); diff --git a/x-pack/plugins/infra/public/pages/logs/log_entry_categories/sections/top_categories/category_example_message.tsx b/x-pack/plugins/infra/public/pages/logs/log_entry_categories/sections/top_categories/category_example_message.tsx index 7bcc05280994c..84d7e198636e9 100644 --- a/x-pack/plugins/infra/public/pages/logs/log_entry_categories/sections/top_categories/category_example_message.tsx +++ b/x-pack/plugins/infra/public/pages/logs/log_entry_categories/sections/top_categories/category_example_message.tsx @@ -86,7 +86,7 @@ export const CategoryExampleMessage: React.FunctionComponent<{ = ({ = ({ columnValue={{ columnId: datasetColumnId, field: 'event.dataset', - value: humanFriendlyDataset, + value: [humanFriendlyDataset], highlights: [], }} highlights={noHighlights} diff --git a/x-pack/plugins/infra/server/lib/adapters/framework/adapter_types.ts b/x-pack/plugins/infra/server/lib/adapters/framework/adapter_types.ts index 0b7ee6e66db2f..f6b18a449c82a 100644 --- a/x-pack/plugins/infra/server/lib/adapters/framework/adapter_types.ts +++ b/x-pack/plugins/infra/server/lib/adapters/framework/adapter_types.ts @@ -15,6 +15,7 @@ import { PluginSetupContract as FeaturesPluginSetup } from '../../../../../../pl import { SpacesPluginSetup } from '../../../../../../plugins/spaces/server'; import { PluginSetupContract as AlertingPluginContract } from '../../../../../alerts/server'; import { MlPluginSetup } from '../../../../../ml/server'; +import { JsonArray, JsonValue } from '../../../../common/typed_json'; export interface InfraServerPluginDeps { home: HomeServerPluginSetup; @@ -108,7 +109,10 @@ export type SearchHit = SearchResponse['hits']['hits'][0]; export interface SortedSearchHit extends SearchHit { sort: any[]; _source: { - [field: string]: any; + [field: string]: JsonValue; + }; + fields: { + [field: string]: JsonArray; }; } diff --git a/x-pack/plugins/infra/server/lib/adapters/log_entries/kibana_log_entries_adapter.ts b/x-pack/plugins/infra/server/lib/adapters/log_entries/kibana_log_entries_adapter.ts index c5b667fb20538..9309ad85a3570 100644 --- a/x-pack/plugins/infra/server/lib/adapters/log_entries/kibana_log_entries_adapter.ts +++ b/x-pack/plugins/infra/server/lib/adapters/log_entries/kibana_log_entries_adapter.ts @@ -4,18 +4,17 @@ * you may not use this file except in compliance with the Elastic License. */ -/* eslint-disable @typescript-eslint/no-empty-interface */ - import { timeMilliseconds } from 'd3-time'; +import { fold, map } from 'fp-ts/lib/Either'; +import { constant, identity } from 'fp-ts/lib/function'; +import { pipe } from 'fp-ts/lib/pipeable'; import * as runtimeTypes from 'io-ts'; import { compact, first } from 'lodash'; -import { pipe } from 'fp-ts/lib/pipeable'; -import { map, fold } from 'fp-ts/lib/Either'; -import { identity, constant } from 'fp-ts/lib/function'; import { RequestHandlerContext } from 'src/core/server'; -import { JsonValue } from '../../../../common/typed_json'; +import { JsonArray } from '../../../../common/typed_json'; import { LogEntriesAdapter, + LogItemHit, LogEntriesParams, LogEntryDocument, LogEntryQuery, @@ -28,13 +27,6 @@ import { KibanaFramework } from '../framework/kibana_framework_adapter'; const TIMESTAMP_FORMAT = 'epoch_millis'; -interface LogItemHit { - _index: string; - _id: string; - fields: { [key: string]: [value: unknown] }; - sort: [number, number]; -} - export class InfraKibanaLogEntriesAdapter implements LogEntriesAdapter { constructor(private readonly framework: KibanaFramework) {} @@ -231,13 +223,14 @@ export class InfraKibanaLogEntriesAdapter implements LogEntriesAdapter { function mapHitsToLogEntryDocuments(hits: SortedSearchHit[], fields: string[]): LogEntryDocument[] { return hits.map((hit) => { - const logFields = fields.reduce<{ [fieldName: string]: JsonValue }>( - (flattenedFields, field) => { - if (field in hit.fields) { - flattenedFields[field] = hit.fields[field][0]; - } - return flattenedFields; - }, + const logFields = fields.reduce<{ [fieldName: string]: JsonArray }>( + (flattenedFields, field) => + field in hit.fields + ? { + ...flattenedFields, + [field]: hit.fields[field], + } + : flattenedFields, {} ); @@ -338,8 +331,9 @@ const LogSummaryDateRangeBucketRuntimeType = runtimeTypes.intersection([ }), ]); -export interface LogSummaryDateRangeBucket - extends runtimeTypes.TypeOf {} +export type LogSummaryDateRangeBucket = runtimeTypes.TypeOf< + typeof LogSummaryDateRangeBucketRuntimeType +>; const LogSummaryResponseRuntimeType = runtimeTypes.type({ aggregations: runtimeTypes.type({ @@ -349,5 +343,4 @@ const LogSummaryResponseRuntimeType = runtimeTypes.type({ }), }); -export interface LogSummaryResponse - extends runtimeTypes.TypeOf {} +export type LogSummaryResponse = runtimeTypes.TypeOf; diff --git a/x-pack/plugins/infra/server/lib/domains/log_entries_domain/builtin_rules/filebeat_apache2.test.ts b/x-pack/plugins/infra/server/lib/domains/log_entries_domain/builtin_rules/filebeat_apache2.test.ts index 367ae6a0cae89..e7e381dc7f8f6 100644 --- a/x-pack/plugins/infra/server/lib/domains/log_entries_domain/builtin_rules/filebeat_apache2.test.ts +++ b/x-pack/plugins/infra/server/lib/domains/log_entries_domain/builtin_rules/filebeat_apache2.test.ts @@ -13,251 +13,290 @@ describe('Filebeat Rules', () => { describe('in ECS format', () => { test('Apache2 Access', () => { const flattenedDocument = { - '@timestamp': '2016-12-26T16:22:13.000Z', - 'ecs.version': '1.0.0-beta2', - 'event.dataset': 'apache.access', - 'event.module': 'apache', - 'fileset.name': 'access', - 'http.request.method': 'GET', - 'http.request.referrer': '-', - 'http.response.body.bytes': 499, - 'http.response.status_code': 404, - 'http.version': '1.1', - 'input.type': 'log', - 'log.offset': 73, - 'service.type': 'apache', - 'source.address': '192.168.33.1', - 'source.ip': '192.168.33.1', - 'url.original': '/hello', - 'user.name': '-', - 'user_agent.device': 'Other', - 'user_agent.major': '50', - 'user_agent.minor': '0', - 'user_agent.name': 'Firefox', - 'user_agent.original': + '@timestamp': ['2016-12-26T16:22:13.000Z'], + 'ecs.version': ['1.0.0-beta2'], + 'event.dataset': ['apache.access'], + 'event.module': ['apache'], + 'fileset.name': ['access'], + 'http.request.method': ['GET'], + 'http.request.referrer': ['-'], + 'http.response.body.bytes': [499], + 'http.response.status_code': [404], + 'http.version': ['1.1'], + 'input.type': ['log'], + 'log.offset': [73], + 'service.type': ['apache'], + 'source.address': ['192.168.33.1'], + 'source.ip': ['192.168.33.1'], + 'url.original': ['/hello'], + 'user.name': ['-'], + 'user_agent.device': ['Other'], + 'user_agent.major': ['50'], + 'user_agent.minor': ['0'], + 'user_agent.name': ['Firefox'], + 'user_agent.original': [ 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:50.0) Gecko/20100101 Firefox/50.0', - 'user_agent.os.full_name': 'Mac OS X 10.12', - 'user_agent.os.major': '10', - 'user_agent.os.minor': '12', - 'user_agent.os.name': 'Mac OS X', + ], + 'user_agent.os.full_name': ['Mac OS X 10.12'], + 'user_agent.os.major': ['10'], + 'user_agent.os.minor': ['12'], + 'user_agent.os.name': ['Mac OS X'], }; const highlights = { 'http.request.method': ['GET'], }; expect(format(flattenedDocument, highlights)).toMatchInlineSnapshot(` -Array [ - Object { - "constant": "[", - }, - Object { - "field": "event.module", - "highlights": Array [], - "value": "apache", - }, - Object { - "constant": "][access] ", - }, - Object { - "field": "source.ip", - "highlights": Array [], - "value": "192.168.33.1", - }, - Object { - "constant": " ", - }, - Object { - "field": "user.name", - "highlights": Array [], - "value": "-", - }, - Object { - "constant": " \\"", - }, - Object { - "field": "http.request.method", - "highlights": Array [ - "GET", - ], - "value": "GET", - }, - Object { - "constant": " ", - }, - Object { - "field": "url.original", - "highlights": Array [], - "value": "/hello", - }, - Object { - "constant": " HTTP/", - }, - Object { - "field": "http.version", - "highlights": Array [], - "value": "1.1", - }, - Object { - "constant": "\\" ", - }, - Object { - "field": "http.response.status_code", - "highlights": Array [], - "value": "404", - }, - Object { - "constant": " ", - }, - Object { - "field": "http.response.body.bytes", - "highlights": Array [], - "value": "499", - }, -] -`); + Array [ + Object { + "constant": "[", + }, + Object { + "field": "event.module", + "highlights": Array [], + "value": Array [ + "apache", + ], + }, + Object { + "constant": "][access] ", + }, + Object { + "field": "source.ip", + "highlights": Array [], + "value": Array [ + "192.168.33.1", + ], + }, + Object { + "constant": " ", + }, + Object { + "field": "user.name", + "highlights": Array [], + "value": Array [ + "-", + ], + }, + Object { + "constant": " \\"", + }, + Object { + "field": "http.request.method", + "highlights": Array [ + "GET", + ], + "value": Array [ + "GET", + ], + }, + Object { + "constant": " ", + }, + Object { + "field": "url.original", + "highlights": Array [], + "value": Array [ + "/hello", + ], + }, + Object { + "constant": " HTTP/", + }, + Object { + "field": "http.version", + "highlights": Array [], + "value": Array [ + "1.1", + ], + }, + Object { + "constant": "\\" ", + }, + Object { + "field": "http.response.status_code", + "highlights": Array [], + "value": Array [ + 404, + ], + }, + Object { + "constant": " ", + }, + Object { + "field": "http.response.body.bytes", + "highlights": Array [], + "value": Array [ + 499, + ], + }, + ] + `); }); test('Apache2 Error', () => { const flattenedDocument = { - '@timestamp': '2016-12-26T16:22:08.000Z', - 'ecs.version': '1.0.0-beta2', - 'event.dataset': 'apache.error', - 'event.module': 'apache', - 'fileset.name': 'error', - 'input.type': 'log', - 'log.level': 'error', - 'log.offset': 0, - message: 'File does not exist: /var/www/favicon.ico', - 'service.type': 'apache', - 'source.address': '192.168.33.1', - 'source.ip': '192.168.33.1', + '@timestamp': ['2016-12-26T16:22:08.000Z'], + 'ecs.version': ['1.0.0-beta2'], + 'event.dataset': ['apache.error'], + 'event.module': ['apache'], + 'fileset.name': ['error'], + 'input.type': ['log'], + 'log.level': ['error'], + 'log.offset': [0], + message: ['File does not exist: /var/www/favicon.ico'], + 'service.type': ['apache'], + 'source.address': ['192.168.33.1'], + 'source.ip': ['192.168.33.1'], }; expect(format(flattenedDocument, {})).toMatchInlineSnapshot(` -Array [ - Object { - "constant": "[apache][", - }, - Object { - "field": "log.level", - "highlights": Array [], - "value": "error", - }, - Object { - "constant": "] ", - }, - Object { - "field": "message", - "highlights": Array [], - "value": "File does not exist: /var/www/favicon.ico", - }, -] -`); + Array [ + Object { + "constant": "[apache][", + }, + Object { + "field": "log.level", + "highlights": Array [], + "value": Array [ + "error", + ], + }, + Object { + "constant": "] ", + }, + Object { + "field": "message", + "highlights": Array [], + "value": Array [ + "File does not exist: /var/www/favicon.ico", + ], + }, + ] + `); }); }); describe('in pre-ECS format', () => { test('Apache2 Access', () => { const flattenedDocument = { - 'apache2.access': true, - 'apache2.access.remote_ip': '192.168.1.42', - 'apache2.access.user_name': 'admin', - 'apache2.access.method': 'GET', - 'apache2.access.url': '/faqs', - 'apache2.access.http_version': '1.1', - 'apache2.access.response_code': '200', - 'apache2.access.body_sent.bytes': 1024, + 'apache2.access.remote_ip': ['192.168.1.42'], + 'apache2.access.user_name': ['admin'], + 'apache2.access.method': ['GET'], + 'apache2.access.url': ['/faqs'], + 'apache2.access.http_version': ['1.1'], + 'apache2.access.response_code': ['200'], + 'apache2.access.body_sent.bytes': [1024], }; expect(format(flattenedDocument, {})).toMatchInlineSnapshot(` -Array [ - Object { - "constant": "[apache][access] ", - }, - Object { - "field": "apache2.access.remote_ip", - "highlights": Array [], - "value": "192.168.1.42", - }, - Object { - "constant": " ", - }, - Object { - "field": "apache2.access.user_name", - "highlights": Array [], - "value": "admin", - }, - Object { - "constant": " \\"", - }, - Object { - "field": "apache2.access.method", - "highlights": Array [], - "value": "GET", - }, - Object { - "constant": " ", - }, - Object { - "field": "apache2.access.url", - "highlights": Array [], - "value": "/faqs", - }, - Object { - "constant": " HTTP/", - }, - Object { - "field": "apache2.access.http_version", - "highlights": Array [], - "value": "1.1", - }, - Object { - "constant": "\\" ", - }, - Object { - "field": "apache2.access.response_code", - "highlights": Array [], - "value": "200", - }, - Object { - "constant": " ", - }, - Object { - "field": "apache2.access.body_sent.bytes", - "highlights": Array [], - "value": "1024", - }, -] -`); + Array [ + Object { + "constant": "[apache][access] ", + }, + Object { + "field": "apache2.access.remote_ip", + "highlights": Array [], + "value": Array [ + "192.168.1.42", + ], + }, + Object { + "constant": " ", + }, + Object { + "field": "apache2.access.user_name", + "highlights": Array [], + "value": Array [ + "admin", + ], + }, + Object { + "constant": " \\"", + }, + Object { + "field": "apache2.access.method", + "highlights": Array [], + "value": Array [ + "GET", + ], + }, + Object { + "constant": " ", + }, + Object { + "field": "apache2.access.url", + "highlights": Array [], + "value": Array [ + "/faqs", + ], + }, + Object { + "constant": " HTTP/", + }, + Object { + "field": "apache2.access.http_version", + "highlights": Array [], + "value": Array [ + "1.1", + ], + }, + Object { + "constant": "\\" ", + }, + Object { + "field": "apache2.access.response_code", + "highlights": Array [], + "value": Array [ + "200", + ], + }, + Object { + "constant": " ", + }, + Object { + "field": "apache2.access.body_sent.bytes", + "highlights": Array [], + "value": Array [ + 1024, + ], + }, + ] + `); }); test('Apache2 Error', () => { const flattenedDocument = { - 'apache2.error.message': + 'apache2.error.message': [ 'AH00489: Apache/2.4.18 (Ubuntu) configured -- resuming normal operations', - 'apache2.error.level': 'notice', + ], + 'apache2.error.level': ['notice'], }; expect(format(flattenedDocument, {})).toMatchInlineSnapshot(` -Array [ - Object { - "constant": "[apache][", - }, - Object { - "field": "apache2.error.level", - "highlights": Array [], - "value": "notice", - }, - Object { - "constant": "] ", - }, - Object { - "field": "apache2.error.message", - "highlights": Array [], - "value": "AH00489: Apache/2.4.18 (Ubuntu) configured -- resuming normal operations", - }, -] -`); + Array [ + Object { + "constant": "[apache][", + }, + Object { + "field": "apache2.error.level", + "highlights": Array [], + "value": Array [ + "notice", + ], + }, + Object { + "constant": "] ", + }, + Object { + "field": "apache2.error.message", + "highlights": Array [], + "value": Array [ + "AH00489: Apache/2.4.18 (Ubuntu) configured -- resuming normal operations", + ], + }, + ] + `); }); }); }); diff --git a/x-pack/plugins/infra/server/lib/domains/log_entries_domain/builtin_rules/filebeat_apache2.ts b/x-pack/plugins/infra/server/lib/domains/log_entries_domain/builtin_rules/filebeat_apache2.ts index fe7ebffe91329..3698753ef42ea 100644 --- a/x-pack/plugins/infra/server/lib/domains/log_entries_domain/builtin_rules/filebeat_apache2.ts +++ b/x-pack/plugins/infra/server/lib/domains/log_entries_domain/builtin_rules/filebeat_apache2.ts @@ -8,7 +8,7 @@ export const filebeatApache2Rules = [ { // pre-ECS when: { - exists: ['apache2.access'], + existsPrefix: ['apache2.access'], }, format: [ { diff --git a/x-pack/plugins/infra/server/lib/domains/log_entries_domain/builtin_rules/filebeat_auditd.test.ts b/x-pack/plugins/infra/server/lib/domains/log_entries_domain/builtin_rules/filebeat_auditd.test.ts index aa490c595d9fd..4481ff434802f 100644 --- a/x-pack/plugins/infra/server/lib/domains/log_entries_domain/builtin_rules/filebeat_auditd.test.ts +++ b/x-pack/plugins/infra/server/lib/domains/log_entries_domain/builtin_rules/filebeat_auditd.test.ts @@ -13,345 +13,605 @@ describe('Filebeat Rules', () => { describe('in ECS format', () => { test('auditd log with outcome', () => { const flattenedDocument = { - '@timestamp': '2016-12-07T02:17:21.515Z', - 'auditd.log': { - addr: '96.241.146.97', - cipher: 'chacha20-poly1305@openssh.com', - direction: 'from-server', - ksize: '512', - laddr: '10.142.0.2', - lport: '22', - pfs: 'curve25519-sha256@libssh.org', - rport: '63927', - sequence: 406, - ses: '4294967295', - spid: '1299', - subj: 'system_u:system_r:sshd_t:s0-s0:c0.c1023', - }, - 'ecs.version': '1.0.0-beta2', - 'event.action': 'crypto_session', - 'event.dataset': 'auditd.log', - 'event.module': 'auditd', - 'event.outcome': 'success', - 'fileset.name': 'log', - 'input.type': 'log', - 'log.offset': 783, - message: 'op=start', - process: { executable: '/usr/sbin/sshd', pid: 1298 }, - 'service.type': 'auditd', - user: { 'audit.id': '4294967295', id: '0', 'saved.id': '74' }, + '@timestamp': ['2016-12-07T02:17:21.515Z'], + 'auditd.log.addr': ['96.241.146.97'], + 'auditd.log.cipher': ['chacha20-poly1305@openssh.com'], + 'auditd.log.direction': ['from-server'], + 'auditd.log.ksize': ['512'], + 'auditd.log.laddr': ['10.142.0.2'], + 'auditd.log.lport': ['22'], + 'auditd.log.pfs': ['curve25519-sha256@libssh.org'], + 'auditd.log.rport': ['63927'], + 'auditd.log.sequence': [406], + 'auditd.log.ses': ['4294967295'], + 'auditd.log.spid': ['1299'], + 'auditd.log.subj': ['system_u:system_r:sshd_t:s0-s0:c0.c1023'], + 'ecs.version': ['1.0.0-beta2'], + 'event.action': ['crypto_session'], + 'event.dataset': ['auditd.log'], + 'event.module': ['auditd'], + 'event.outcome': ['success'], + 'fileset.name': ['log'], + 'input.type': ['log'], + 'log.offset': [783], + message: ['op=start'], + 'process.executable': ['/usr/sbin/sshd'], + 'process.pid': [1298], + 'service.type': ['auditd'], + 'user.audit.id': ['4294967295'], + 'user.id': ['0'], + 'user.saved.id': ['74'], }; expect(format(flattenedDocument, {})).toMatchInlineSnapshot(` -Array [ - Object { - "constant": "[AuditD][", - }, - Object { - "field": "event.action", - "highlights": Array [], - "value": "crypto_session", - }, - Object { - "constant": "]", - }, - Object { - "constant": " ", - }, - Object { - "field": "event.outcome", - "highlights": Array [], - "value": "success", - }, - Object { - "constant": " ", - }, - Object { - "constant": "user", - }, - Object { - "constant": "=", - }, - Object { - "field": "user", - "highlights": Array [], - "value": "{\\"audit.id\\":\\"4294967295\\",\\"id\\":\\"0\\",\\"saved.id\\":\\"74\\"}", - }, - Object { - "constant": " ", - }, - Object { - "constant": "process", - }, - Object { - "constant": "=", - }, - Object { - "field": "process", - "highlights": Array [], - "value": "{\\"executable\\":\\"/usr/sbin/sshd\\",\\"pid\\":1298}", - }, - Object { - "constant": " ", - }, - Object { - "field": "auditd.log", - "highlights": Array [], - "value": "{\\"addr\\":\\"96.241.146.97\\",\\"cipher\\":\\"chacha20-poly1305@openssh.com\\",\\"direction\\":\\"from-server\\",\\"ksize\\":\\"512\\",\\"laddr\\":\\"10.142.0.2\\",\\"lport\\":\\"22\\",\\"pfs\\":\\"curve25519-sha256@libssh.org\\",\\"rport\\":\\"63927\\",\\"sequence\\":406,\\"ses\\":\\"4294967295\\",\\"spid\\":\\"1299\\",\\"subj\\":\\"system_u:system_r:sshd_t:s0-s0:c0.c1023\\"}", - }, - Object { - "constant": " ", - }, - Object { - "field": "message", - "highlights": Array [], - "value": "op=start", - }, -] -`); + Array [ + Object { + "constant": "[AuditD][", + }, + Object { + "field": "event.action", + "highlights": Array [], + "value": Array [ + "crypto_session", + ], + }, + Object { + "constant": "]", + }, + Object { + "constant": " ", + }, + Object { + "field": "event.outcome", + "highlights": Array [], + "value": Array [ + "success", + ], + }, + Object { + "constant": " ", + }, + Object { + "constant": "user", + }, + Object { + "constant": "=", + }, + Object { + "field": "user.audit.id", + "highlights": Array [], + "value": Array [ + "4294967295", + ], + }, + Object { + "field": "user.id", + "highlights": Array [], + "value": Array [ + "0", + ], + }, + Object { + "field": "user.saved.id", + "highlights": Array [], + "value": Array [ + "74", + ], + }, + Object { + "constant": " ", + }, + Object { + "constant": "process", + }, + Object { + "constant": "=", + }, + Object { + "field": "process.executable", + "highlights": Array [], + "value": Array [ + "/usr/sbin/sshd", + ], + }, + Object { + "field": "process.pid", + "highlights": Array [], + "value": Array [ + 1298, + ], + }, + Object { + "constant": " ", + }, + Object { + "field": "auditd.log.addr", + "highlights": Array [], + "value": Array [ + "96.241.146.97", + ], + }, + Object { + "field": "auditd.log.cipher", + "highlights": Array [], + "value": Array [ + "chacha20-poly1305@openssh.com", + ], + }, + Object { + "field": "auditd.log.direction", + "highlights": Array [], + "value": Array [ + "from-server", + ], + }, + Object { + "field": "auditd.log.ksize", + "highlights": Array [], + "value": Array [ + "512", + ], + }, + Object { + "field": "auditd.log.laddr", + "highlights": Array [], + "value": Array [ + "10.142.0.2", + ], + }, + Object { + "field": "auditd.log.lport", + "highlights": Array [], + "value": Array [ + "22", + ], + }, + Object { + "field": "auditd.log.pfs", + "highlights": Array [], + "value": Array [ + "curve25519-sha256@libssh.org", + ], + }, + Object { + "field": "auditd.log.rport", + "highlights": Array [], + "value": Array [ + "63927", + ], + }, + Object { + "field": "auditd.log.sequence", + "highlights": Array [], + "value": Array [ + 406, + ], + }, + Object { + "field": "auditd.log.ses", + "highlights": Array [], + "value": Array [ + "4294967295", + ], + }, + Object { + "field": "auditd.log.spid", + "highlights": Array [], + "value": Array [ + "1299", + ], + }, + Object { + "field": "auditd.log.subj", + "highlights": Array [], + "value": Array [ + "system_u:system_r:sshd_t:s0-s0:c0.c1023", + ], + }, + Object { + "constant": " ", + }, + Object { + "field": "message", + "highlights": Array [], + "value": Array [ + "op=start", + ], + }, + ] + `); }); test('auditd log without outcome', () => { const flattenedDocument = { - '@timestamp': '2017-01-31T20:17:14.891Z', - 'auditd.log': { - a0: '9', - a1: '7f564b2672a0', - a2: 'b8', - a3: '0', - exit: '184', - items: '0', - sequence: 18877199, - ses: '4294967295', - success: 'yes', - syscall: '44', - tty: '(none)', - }, - 'ecs.version': '1.0.0-beta2', - 'event.action': 'syscall', - 'event.dataset': 'auditd.log', - 'event.module': 'auditd', - 'fileset.name': 'log', - 'host.architecture': 'x86_64', - 'input.type': 'log', - 'log.offset': 174, - process: { - executable: '/usr/libexec/strongswan/charon (deleted)', - name: 'charon', - pid: 1281, - ppid: 1240, - }, - 'service.type': 'auditd', - user: { - 'audit.id': '4294967295', - 'effective.group.id': '0', - 'effective.id': '0', - 'filesystem.group.id': '0', - 'filesystem.id': '0', - 'group.id': '0', - id: '0', - 'saved.group.id': '0', - 'saved.id': '0', - }, + '@timestamp': ['2017-01-31T20:17:14.891Z'], + 'auditd.log.a0': ['9'], + 'auditd.log.a1': ['7f564b2672a0'], + 'auditd.log.a2': ['b8'], + 'auditd.log.a3': ['0'], + 'auditd.log.exit': ['184'], + 'auditd.log.items': ['0'], + 'auditd.log.sequence': [18877199], + 'auditd.log.ses': ['4294967295'], + 'auditd.log.success': ['yes'], + 'auditd.log.syscall': ['44'], + 'auditd.log.tty': ['(none)'], + 'ecs.version': ['1.0.0-beta2'], + 'event.action': ['syscall'], + 'event.dataset': ['auditd.log'], + 'event.module': ['auditd'], + 'fileset.name': ['log'], + 'host.architecture': ['x86_64'], + 'input.type': ['log'], + 'log.offset': [174], + 'process.executable': ['/usr/libexec/strongswan/charon (deleted)'], + 'process.name': ['charon'], + 'process.pid': [1281], + 'process.ppid': [1240], + 'service.type': ['auditd'], + 'user.audit.id': ['4294967295'], + 'user.effective.group.id': ['0'], + 'user.effective.id': ['0'], + 'user.filesystem.group.id': ['0'], + 'user.filesystem.id': ['0'], + 'user.group.id': ['0'], + 'user.id': ['0'], + 'user.saved.group.id': ['0'], + 'user.saved.id': ['0'], }; expect(format(flattenedDocument, {})).toMatchInlineSnapshot(` -Array [ - Object { - "constant": "[AuditD][", - }, - Object { - "field": "event.action", - "highlights": Array [], - "value": "syscall", - }, - Object { - "constant": "]", - }, - Object { - "constant": " ", - }, - Object { - "constant": "user", - }, - Object { - "constant": "=", - }, - Object { - "field": "user", - "highlights": Array [], - "value": "{\\"audit.id\\":\\"4294967295\\",\\"effective.group.id\\":\\"0\\",\\"effective.id\\":\\"0\\",\\"filesystem.group.id\\":\\"0\\",\\"filesystem.id\\":\\"0\\",\\"group.id\\":\\"0\\",\\"id\\":\\"0\\",\\"saved.group.id\\":\\"0\\",\\"saved.id\\":\\"0\\"}", - }, - Object { - "constant": " ", - }, - Object { - "constant": "process", - }, - Object { - "constant": "=", - }, - Object { - "field": "process", - "highlights": Array [], - "value": "{\\"executable\\":\\"/usr/libexec/strongswan/charon (deleted)\\",\\"name\\":\\"charon\\",\\"pid\\":1281,\\"ppid\\":1240}", - }, - Object { - "constant": " ", - }, - Object { - "field": "auditd.log", - "highlights": Array [], - "value": "{\\"a0\\":\\"9\\",\\"a1\\":\\"7f564b2672a0\\",\\"a2\\":\\"b8\\",\\"a3\\":\\"0\\",\\"exit\\":\\"184\\",\\"items\\":\\"0\\",\\"sequence\\":18877199,\\"ses\\":\\"4294967295\\",\\"success\\":\\"yes\\",\\"syscall\\":\\"44\\",\\"tty\\":\\"(none)\\"}", - }, - Object { - "constant": " ", - }, - Object { - "field": "message", - "highlights": Array [], - "value": "undefined", - }, -] -`); + Array [ + Object { + "constant": "[AuditD][", + }, + Object { + "field": "event.action", + "highlights": Array [], + "value": Array [ + "syscall", + ], + }, + Object { + "constant": "]", + }, + Object { + "constant": " ", + }, + Object { + "constant": "user", + }, + Object { + "constant": "=", + }, + Object { + "field": "user.audit.id", + "highlights": Array [], + "value": Array [ + "4294967295", + ], + }, + Object { + "field": "user.effective.group.id", + "highlights": Array [], + "value": Array [ + "0", + ], + }, + Object { + "field": "user.effective.id", + "highlights": Array [], + "value": Array [ + "0", + ], + }, + Object { + "field": "user.filesystem.group.id", + "highlights": Array [], + "value": Array [ + "0", + ], + }, + Object { + "field": "user.filesystem.id", + "highlights": Array [], + "value": Array [ + "0", + ], + }, + Object { + "field": "user.group.id", + "highlights": Array [], + "value": Array [ + "0", + ], + }, + Object { + "field": "user.id", + "highlights": Array [], + "value": Array [ + "0", + ], + }, + Object { + "field": "user.saved.group.id", + "highlights": Array [], + "value": Array [ + "0", + ], + }, + Object { + "field": "user.saved.id", + "highlights": Array [], + "value": Array [ + "0", + ], + }, + Object { + "constant": " ", + }, + Object { + "constant": "process", + }, + Object { + "constant": "=", + }, + Object { + "field": "process.executable", + "highlights": Array [], + "value": Array [ + "/usr/libexec/strongswan/charon (deleted)", + ], + }, + Object { + "field": "process.name", + "highlights": Array [], + "value": Array [ + "charon", + ], + }, + Object { + "field": "process.pid", + "highlights": Array [], + "value": Array [ + 1281, + ], + }, + Object { + "field": "process.ppid", + "highlights": Array [], + "value": Array [ + 1240, + ], + }, + Object { + "constant": " ", + }, + Object { + "field": "auditd.log.a0", + "highlights": Array [], + "value": Array [ + "9", + ], + }, + Object { + "field": "auditd.log.a1", + "highlights": Array [], + "value": Array [ + "7f564b2672a0", + ], + }, + Object { + "field": "auditd.log.a2", + "highlights": Array [], + "value": Array [ + "b8", + ], + }, + Object { + "field": "auditd.log.a3", + "highlights": Array [], + "value": Array [ + "0", + ], + }, + Object { + "field": "auditd.log.exit", + "highlights": Array [], + "value": Array [ + "184", + ], + }, + Object { + "field": "auditd.log.items", + "highlights": Array [], + "value": Array [ + "0", + ], + }, + Object { + "field": "auditd.log.sequence", + "highlights": Array [], + "value": Array [ + 18877199, + ], + }, + Object { + "field": "auditd.log.ses", + "highlights": Array [], + "value": Array [ + "4294967295", + ], + }, + Object { + "field": "auditd.log.success", + "highlights": Array [], + "value": Array [ + "yes", + ], + }, + Object { + "field": "auditd.log.syscall", + "highlights": Array [], + "value": Array [ + "44", + ], + }, + Object { + "field": "auditd.log.tty", + "highlights": Array [], + "value": Array [ + "(none)", + ], + }, + Object { + "constant": " ", + }, + Object { + "field": "message", + "highlights": Array [], + "value": Array [], + }, + ] + `); }); }); describe('in pre-ECS format', () => { test('auditd IPSEC rule', () => { const event = { - '@timestamp': '2017-01-31T20:17:14.891Z', - 'auditd.log.auid': '4294967295', - 'auditd.log.dst': '192.168.0.0', - 'auditd.log.dst_prefixlen': '16', - 'auditd.log.op': 'SPD-delete', - 'auditd.log.record_type': 'MAC_IPSEC_EVENT', - 'auditd.log.res': '1', - 'auditd.log.sequence': 18877201, - 'auditd.log.ses': '4294967295', - 'auditd.log.src': '192.168.2.0', - 'auditd.log.src_prefixlen': '24', - 'ecs.version': '1.0.0-beta2', - 'event.dataset': 'auditd.log', - 'event.module': 'auditd', - 'fileset.name': 'log', - 'input.type': 'log', - 'log.offset': 0, + '@timestamp': ['2017-01-31T20:17:14.891Z'], + 'auditd.log.auid': ['4294967295'], + 'auditd.log.dst': ['192.168.0.0'], + 'auditd.log.dst_prefixlen': ['16'], + 'auditd.log.op': ['SPD-delete'], + 'auditd.log.record_type': ['MAC_IPSEC_EVENT'], + 'auditd.log.res': ['1'], + 'auditd.log.sequence': [18877201], + 'auditd.log.ses': ['4294967295'], + 'auditd.log.src': ['192.168.2.0'], + 'auditd.log.src_prefixlen': ['24'], + 'ecs.version': ['1.0.0-beta2'], + 'event.dataset': ['auditd.log'], + 'event.module': ['auditd'], + 'fileset.name': ['log'], + 'input.type': ['log'], + 'log.offset': [0], }; const message = format(event, {}); expect(message).toEqual([ { constant: '[AuditD][' }, - { field: 'auditd.log.record_type', highlights: [], value: 'MAC_IPSEC_EVENT' }, + { field: 'auditd.log.record_type', highlights: [], value: ['MAC_IPSEC_EVENT'] }, { constant: '] src:' }, - { field: 'auditd.log.src', highlights: [], value: '192.168.2.0' }, + { field: 'auditd.log.src', highlights: [], value: ['192.168.2.0'] }, { constant: ' dst:' }, - { field: 'auditd.log.dst', highlights: [], value: '192.168.0.0' }, + { field: 'auditd.log.dst', highlights: [], value: ['192.168.0.0'] }, { constant: ' op:' }, - { field: 'auditd.log.op', highlights: [], value: 'SPD-delete' }, + { field: 'auditd.log.op', highlights: [], value: ['SPD-delete'] }, ]); }); test('AuditD SYSCALL rule', () => { const event = { - '@timestamp': '2017-01-31T20:17:14.891Z', - 'auditd.log.a0': '9', - 'auditd.log.a1': '7f564b2672a0', - 'auditd.log.a2': 'b8', - 'auditd.log.a3': '0', - 'auditd.log.arch': 'x86_64', - 'auditd.log.auid': '4294967295', - 'auditd.log.comm': 'charon', - 'auditd.log.egid': '0', - 'auditd.log.euid': '0', - 'auditd.log.exe': '/usr/libexec/strongswan/charon (deleted)', - 'auditd.log.exit': '184', - 'auditd.log.fsgid': '0', - 'auditd.log.fsuid': '0', - 'auditd.log.gid': '0', - 'auditd.log.items': '0', - 'auditd.log.pid': '1281', - 'auditd.log.ppid': '1240', - 'auditd.log.record_type': 'SYSCALL', - 'auditd.log.sequence': 18877199, - 'auditd.log.ses': '4294967295', - 'auditd.log.sgid': '0', - 'auditd.log.success': 'yes', - 'auditd.log.suid': '0', - 'auditd.log.syscall': '44', - 'auditd.log.tty': '(none)', - 'auditd.log.uid': '0', - 'ecs.version': '1.0.0-beta2', - 'event.dataset': 'auditd.log', - 'event.module': 'auditd', - 'fileset.name': 'log', - 'input.type': 'log', - 'log.offset': 174, + '@timestamp': ['2017-01-31T20:17:14.891Z'], + 'auditd.log.a0': ['9'], + 'auditd.log.a1': ['7f564b2672a0'], + 'auditd.log.a2': ['b8'], + 'auditd.log.a3': ['0'], + 'auditd.log.arch': ['x86_64'], + 'auditd.log.auid': ['4294967295'], + 'auditd.log.comm': ['charon'], + 'auditd.log.egid': ['0'], + 'auditd.log.euid': ['0'], + 'auditd.log.exe': ['/usr/libexec/strongswan/charon (deleted)'], + 'auditd.log.exit': ['184'], + 'auditd.log.fsgid': ['0'], + 'auditd.log.fsuid': ['0'], + 'auditd.log.gid': ['0'], + 'auditd.log.items': ['0'], + 'auditd.log.pid': ['1281'], + 'auditd.log.ppid': ['1240'], + 'auditd.log.record_type': ['SYSCALL'], + 'auditd.log.sequence': [18877199], + 'auditd.log.ses': ['4294967295'], + 'auditd.log.sgid': ['0'], + 'auditd.log.success': ['yes'], + 'auditd.log.suid': ['0'], + 'auditd.log.syscall': ['44'], + 'auditd.log.tty': ['(none)'], + 'auditd.log.uid': ['0'], + 'ecs.version': ['1.0.0-beta2'], + 'event.dataset': ['auditd.log'], + 'event.module': ['auditd'], + 'fileset.name': ['log'], + 'input.type': ['log'], + 'log.offset': [174], }; const message = format(event, {}); expect(message).toEqual([ { constant: '[AuditD][' }, - { field: 'auditd.log.record_type', highlights: [], value: 'SYSCALL' }, + { field: 'auditd.log.record_type', highlights: [], value: ['SYSCALL'] }, { constant: '] exe:' }, { field: 'auditd.log.exe', highlights: [], - value: '/usr/libexec/strongswan/charon (deleted)', + value: ['/usr/libexec/strongswan/charon (deleted)'], }, { constant: ' gid:' }, - { field: 'auditd.log.gid', highlights: [], value: '0' }, + { field: 'auditd.log.gid', highlights: [], value: ['0'] }, { constant: ' uid:' }, - { field: 'auditd.log.uid', highlights: [], value: '0' }, + { field: 'auditd.log.uid', highlights: [], value: ['0'] }, { constant: ' tty:' }, - { field: 'auditd.log.tty', highlights: [], value: '(none)' }, + { field: 'auditd.log.tty', highlights: [], value: ['(none)'] }, { constant: ' pid:' }, - { field: 'auditd.log.pid', highlights: [], value: '1281' }, + { field: 'auditd.log.pid', highlights: [], value: ['1281'] }, { constant: ' ppid:' }, - { field: 'auditd.log.ppid', highlights: [], value: '1240' }, + { field: 'auditd.log.ppid', highlights: [], value: ['1240'] }, ]); }); test('AuditD events with msg rule', () => { const event = { - '@timestamp': '2017-01-31T20:17:14.891Z', - 'auditd.log.auid': '4294967295', - 'auditd.log.record_type': 'EXAMPLE', - 'auditd.log.msg': 'some kind of message', - 'ecs.version': '1.0.0-beta2', - 'event.dataset': 'auditd.log', - 'event.module': 'auditd', - 'fileset.name': 'log', - 'input.type': 'log', - 'log.offset': 174, + '@timestamp': ['2017-01-31T20:17:14.891Z'], + 'auditd.log.auid': ['4294967295'], + 'auditd.log.record_type': ['EXAMPLE'], + 'auditd.log.msg': ['some kind of message'], + 'ecs.version': ['1.0.0-beta2'], + 'event.dataset': ['auditd.log'], + 'event.module': ['auditd'], + 'fileset.name': ['log'], + 'input.type': ['log'], + 'log.offset': [174], }; const message = format(event, {}); expect(message).toEqual([ { constant: '[AuditD][' }, - { field: 'auditd.log.record_type', highlights: [], value: 'EXAMPLE' }, + { field: 'auditd.log.record_type', highlights: [], value: ['EXAMPLE'] }, { constant: '] ' }, { field: 'auditd.log.msg', highlights: [], - value: 'some kind of message', + value: ['some kind of message'], }, ]); }); test('AuditD catchall rule', () => { const event = { - '@timestamp': '2017-01-31T20:17:14.891Z', - 'auditd.log.auid': '4294967295', - 'auditd.log.record_type': 'EXAMPLE', - 'ecs.version': '1.0.0-beta2', - 'event.dataset': 'auditd.log', - 'event.module': 'auditd', - 'fileset.name': 'log', - 'input.type': 'log', - 'log.offset': 174, + '@timestamp': ['2017-01-31T20:17:14.891Z'], + 'auditd.log.auid': ['4294967295'], + 'auditd.log.record_type': ['EXAMPLE'], + 'ecs.version': ['1.0.0-beta2'], + 'event.dataset': ['auditd.log'], + 'event.module': ['auditd'], + 'fileset.name': ['log'], + 'input.type': ['log'], + 'log.offset': [174], }; const message = format(event, {}); expect(message).toEqual([ { constant: '[AuditD][' }, - { field: 'auditd.log.record_type', highlights: [], value: 'EXAMPLE' }, + { field: 'auditd.log.record_type', highlights: [], value: ['EXAMPLE'] }, { constant: '] Event without message.' }, ]); }); diff --git a/x-pack/plugins/infra/server/lib/domains/log_entries_domain/builtin_rules/filebeat_auditd.ts b/x-pack/plugins/infra/server/lib/domains/log_entries_domain/builtin_rules/filebeat_auditd.ts index d2557cf1599ce..cd64697db6d1c 100644 --- a/x-pack/plugins/infra/server/lib/domains/log_entries_domain/builtin_rules/filebeat_auditd.ts +++ b/x-pack/plugins/infra/server/lib/domains/log_entries_domain/builtin_rules/filebeat_auditd.ts @@ -4,24 +4,28 @@ * you may not use this file except in compliance with the Elastic License. */ -import { labelField } from './helpers'; +import { LogMessageFormattingRule } from '../rule_types'; +import { labelFieldsPrefix } from './helpers'; const commonActionField = [{ constant: '[AuditD][' }, { field: 'event.action' }, { constant: ']' }]; const commonOutcomeField = [{ constant: ' ' }, { field: 'event.outcome' }]; -export const filebeatAuditdRules = [ +export const filebeatAuditdRules: LogMessageFormattingRule[] = [ { // ECS format with outcome when: { - exists: ['ecs.version', 'event.action', 'event.outcome', 'auditd.log'], + all: [ + { exists: ['ecs.version', 'event.action', 'event.outcome'] }, + { existsPrefix: ['auditd.log'] }, + ], }, format: [ ...commonActionField, ...commonOutcomeField, - ...labelField('user', 'user'), - ...labelField('process', 'process'), + ...labelFieldsPrefix('user', 'user'), + ...labelFieldsPrefix('process', 'process'), { constant: ' ' }, - { field: 'auditd.log' }, + { fieldsPrefix: 'auditd.log' }, { constant: ' ' }, { field: 'message' }, ], @@ -29,14 +33,14 @@ export const filebeatAuditdRules = [ { // ECS format without outcome when: { - exists: ['ecs.version', 'event.action', 'auditd.log'], + all: [{ exists: ['ecs.version', 'event.action'] }, { existsPrefix: ['auditd.log'] }], }, format: [ ...commonActionField, - ...labelField('user', 'user'), - ...labelField('process', 'process'), + ...labelFieldsPrefix('user', 'user'), + ...labelFieldsPrefix('process', 'process'), { constant: ' ' }, - { field: 'auditd.log' }, + { fieldsPrefix: 'auditd.log' }, { constant: ' ' }, { field: 'message' }, ], @@ -44,10 +48,10 @@ export const filebeatAuditdRules = [ { // pre-ECS IPSEC_EVENT Rule when: { - exists: ['auditd.log.record_type', 'auditd.log.src', 'auditd.log.dst', 'auditd.log.op'], - values: { - 'auditd.log.record_type': 'MAC_IPSEC_EVENT', - }, + all: [ + { exists: ['auditd.log.record_type', 'auditd.log.src', 'auditd.log.dst', 'auditd.log.op'] }, + { values: { 'auditd.log.record_type': 'MAC_IPSEC_EVENT' } }, + ], }, format: [ { constant: '[AuditD][' }, @@ -63,18 +67,20 @@ export const filebeatAuditdRules = [ { // pre-ECS SYSCALL Rule when: { - exists: [ - 'auditd.log.record_type', - 'auditd.log.exe', - 'auditd.log.gid', - 'auditd.log.uid', - 'auditd.log.tty', - 'auditd.log.pid', - 'auditd.log.ppid', + all: [ + { + exists: [ + 'auditd.log.record_type', + 'auditd.log.exe', + 'auditd.log.gid', + 'auditd.log.uid', + 'auditd.log.tty', + 'auditd.log.pid', + 'auditd.log.ppid', + ], + }, + { values: { 'auditd.log.record_type': 'SYSCALL' } }, ], - values: { - 'auditd.log.record_type': 'SYSCALL', - }, }, format: [ { constant: '[AuditD][' }, diff --git a/x-pack/plugins/infra/server/lib/domains/log_entries_domain/builtin_rules/filebeat_haproxy.test.ts b/x-pack/plugins/infra/server/lib/domains/log_entries_domain/builtin_rules/filebeat_haproxy.test.ts index 752b61684887e..40e8ea0fad857 100644 --- a/x-pack/plugins/infra/server/lib/domains/log_entries_domain/builtin_rules/filebeat_haproxy.test.ts +++ b/x-pack/plugins/infra/server/lib/domains/log_entries_domain/builtin_rules/filebeat_haproxy.test.ts @@ -13,779 +13,917 @@ describe('Filebeat Rules', () => { describe('in ECS format', () => { test('haproxy default log', () => { const flattenedDocument = { - 'destination.ip': '1.2.3.4', - 'destination.port': 5000, - 'ecs.version': '1.0.0-beta2', - 'event.dataset': 'haproxy.log', - 'event.module': 'haproxy', - 'fileset.name': 'log', - 'haproxy.frontend_name': 'main', - 'haproxy.mode': 'HTTP', - 'haproxy.source': '1.2.3.4', - 'input.type': 'log', - 'log.offset': 0, - 'process.name': 'haproxy', - 'process.pid': 24551, - 'service.type': 'haproxy', - 'source.address': '1.2.3.4', - 'source.geo.continent_name': 'North America', - 'source.geo.country_iso_code': 'US', - 'source.geo.location.lat': 37.751, - 'source.geo.location.lon': -97.822, - 'source.ip': '1.2.3.4', - 'source.port': 40780, + 'destination.ip': ['1.2.3.4'], + 'destination.port': [5000], + 'ecs.version': ['1.0.0-beta2'], + 'event.dataset': ['haproxy.log'], + 'event.module': ['haproxy'], + 'fileset.name': ['log'], + 'haproxy.frontend_name': ['main'], + 'haproxy.mode': ['HTTP'], + 'haproxy.source': ['1.2.3.4'], + 'input.type': ['log'], + 'log.offset': [0], + 'process.name': ['haproxy'], + 'process.pid': [24551], + 'service.type': ['haproxy'], + 'source.address': ['1.2.3.4'], + 'source.geo.continent_name': ['North America'], + 'source.geo.country_iso_code': ['US'], + 'source.geo.location.lat': [37.751], + 'source.geo.location.lon': [-97.822], + 'source.ip': ['1.2.3.4'], + 'source.port': [40780], }; expect(format(flattenedDocument, {})).toMatchInlineSnapshot(` -Array [ - Object { - "constant": "[HAProxy] ", - }, - Object { - "field": "source.address", - "highlights": Array [], - "value": "1.2.3.4", - }, - Object { - "constant": ":", - }, - Object { - "field": "source.port", - "highlights": Array [], - "value": "40780", - }, - Object { - "constant": " ", - }, - Object { - "field": "haproxy.frontend_name", - "highlights": Array [], - "value": "main", - }, -] -`); + Array [ + Object { + "constant": "[HAProxy] ", + }, + Object { + "field": "source.address", + "highlights": Array [], + "value": Array [ + "1.2.3.4", + ], + }, + Object { + "constant": ":", + }, + Object { + "field": "source.port", + "highlights": Array [], + "value": Array [ + 40780, + ], + }, + Object { + "constant": " ", + }, + Object { + "field": "haproxy.frontend_name", + "highlights": Array [], + "value": Array [ + "main", + ], + }, + ] + `); }); test('haproxy tcp log', () => { const flattenedDocument = { - 'ecs.version': '1.0.0-beta2', - 'event.dataset': 'haproxy.log', - 'event.duration': 1000000, - 'event.module': 'haproxy', - 'fileset.name': 'log', - 'haproxy.backend_name': 'app', - 'haproxy.backend_queue': 0, - 'haproxy.bytes_read': 212, - 'haproxy.connection_wait_time_ms': -1, - 'haproxy.connections.active': 1, - 'haproxy.connections.backend': 0, - 'haproxy.connections.frontend': 1, - 'haproxy.connections.retries': 0, - 'haproxy.connections.server': 0, - 'haproxy.frontend_name': 'main', - 'haproxy.server_name': '', - 'haproxy.server_queue': 0, - 'haproxy.source': '127.0.0.1', - 'haproxy.termination_state': 'SC', - 'haproxy.total_waiting_time_ms': -1, - 'input.type': 'log', - 'log.offset': 0, - 'process.name': 'haproxy', - 'process.pid': 25457, - 'service.type': 'haproxy', - 'source.address': '127.0.0.1', - 'source.ip': '127.0.0.1', - 'source.port': 40962, + 'ecs.version': ['1.0.0-beta2'], + 'event.dataset': ['haproxy.log'], + 'event.duration': [1000000], + 'event.module': ['haproxy'], + 'fileset.name': ['log'], + 'haproxy.backend_name': ['app'], + 'haproxy.backend_queue': [0], + 'haproxy.bytes_read': [212], + 'haproxy.connection_wait_time_ms': [-1], + 'haproxy.connections.active': [1], + 'haproxy.connections.backend': [0], + 'haproxy.connections.frontend': [1], + 'haproxy.connections.retries': [0], + 'haproxy.connections.server': [0], + 'haproxy.frontend_name': ['main'], + 'haproxy.server_name': [''], + 'haproxy.server_queue': [0], + 'haproxy.source': ['127.0.0.1'], + 'haproxy.termination_state': ['SC'], + 'haproxy.total_waiting_time_ms': [-1], + 'input.type': ['log'], + 'log.offset': [0], + 'process.name': ['haproxy'], + 'process.pid': [25457], + 'service.type': ['haproxy'], + 'source.address': ['127.0.0.1'], + 'source.ip': ['127.0.0.1'], + 'source.port': [40962], }; expect(format(flattenedDocument, {})).toMatchInlineSnapshot(` -Array [ - Object { - "constant": "[HAProxy][tcp] ", - }, - Object { - "field": "source.address", - "highlights": Array [], - "value": "127.0.0.1", - }, - Object { - "constant": ":", - }, - Object { - "field": "source.port", - "highlights": Array [], - "value": "40962", - }, - Object { - "constant": " ", - }, - Object { - "field": "haproxy.frontend_name", - "highlights": Array [], - "value": "main", - }, - Object { - "constant": " -> ", - }, - Object { - "field": "haproxy.backend_name", - "highlights": Array [], - "value": "app", - }, - Object { - "constant": "/", - }, - Object { - "field": "haproxy.server_name", - "highlights": Array [], - "value": "", - }, - Object { - "constant": " ", - }, - Object { - "field": "haproxy.connections.active", - "highlights": Array [], - "value": "1", - }, - Object { - "constant": "/", - }, - Object { - "field": "haproxy.connections.frontend", - "highlights": Array [], - "value": "1", - }, - Object { - "constant": "/", - }, - Object { - "field": "haproxy.connections.backend", - "highlights": Array [], - "value": "0", - }, - Object { - "constant": "/", - }, - Object { - "field": "haproxy.connections.server", - "highlights": Array [], - "value": "0", - }, - Object { - "constant": "/", - }, - Object { - "field": "haproxy.connections.retries", - "highlights": Array [], - "value": "0", - }, - Object { - "constant": " ", - }, - Object { - "field": "haproxy.server_queue", - "highlights": Array [], - "value": "0", - }, - Object { - "constant": "/", - }, - Object { - "field": "haproxy.backend_queue", - "highlights": Array [], - "value": "0", - }, -] -`); + Array [ + Object { + "constant": "[HAProxy][tcp] ", + }, + Object { + "field": "source.address", + "highlights": Array [], + "value": Array [ + "127.0.0.1", + ], + }, + Object { + "constant": ":", + }, + Object { + "field": "source.port", + "highlights": Array [], + "value": Array [ + 40962, + ], + }, + Object { + "constant": " ", + }, + Object { + "field": "haproxy.frontend_name", + "highlights": Array [], + "value": Array [ + "main", + ], + }, + Object { + "constant": " -> ", + }, + Object { + "field": "haproxy.backend_name", + "highlights": Array [], + "value": Array [ + "app", + ], + }, + Object { + "constant": "/", + }, + Object { + "field": "haproxy.server_name", + "highlights": Array [], + "value": Array [ + "", + ], + }, + Object { + "constant": " ", + }, + Object { + "field": "haproxy.connections.active", + "highlights": Array [], + "value": Array [ + 1, + ], + }, + Object { + "constant": "/", + }, + Object { + "field": "haproxy.connections.frontend", + "highlights": Array [], + "value": Array [ + 1, + ], + }, + Object { + "constant": "/", + }, + Object { + "field": "haproxy.connections.backend", + "highlights": Array [], + "value": Array [ + 0, + ], + }, + Object { + "constant": "/", + }, + Object { + "field": "haproxy.connections.server", + "highlights": Array [], + "value": Array [ + 0, + ], + }, + Object { + "constant": "/", + }, + Object { + "field": "haproxy.connections.retries", + "highlights": Array [], + "value": Array [ + 0, + ], + }, + Object { + "constant": " ", + }, + Object { + "field": "haproxy.server_queue", + "highlights": Array [], + "value": Array [ + 0, + ], + }, + Object { + "constant": "/", + }, + Object { + "field": "haproxy.backend_queue", + "highlights": Array [], + "value": Array [ + 0, + ], + }, + ] + `); }); test('haproxy http log', () => { const flattenedDocument = { - 'ecs.version': '1.0.0-beta2', - 'event.dataset': 'haproxy.log', - 'event.duration': 2000000, - 'event.module': 'haproxy', - 'fileset.name': 'log', - 'haproxy.backend_name': 'docs_microservice', - 'haproxy.backend_queue': 0, - 'haproxy.bytes_read': 168, - 'haproxy.connection_wait_time_ms': 1, - 'haproxy.connections.active': 6, - 'haproxy.connections.backend': 0, - 'haproxy.connections.frontend': 6, - 'haproxy.connections.retries': 0, - 'haproxy.connections.server': 0, - 'haproxy.frontend_name': 'incoming~', - 'haproxy.http.request.captured_cookie': '-', + 'ecs.version': ['1.0.0-beta2'], + 'event.dataset': ['haproxy.log'], + 'event.duration': [2000000], + 'event.module': ['haproxy'], + 'fileset.name': ['log'], + 'haproxy.backend_name': ['docs_microservice'], + 'haproxy.backend_queue': [0], + 'haproxy.bytes_read': [168], + 'haproxy.connection_wait_time_ms': [1], + 'haproxy.connections.active': [6], + 'haproxy.connections.backend': [0], + 'haproxy.connections.frontend': [6], + 'haproxy.connections.retries': [0], + 'haproxy.connections.server': [0], + 'haproxy.frontend_name': ['incoming~'], + 'haproxy.http.request.captured_cookie': ['-'], 'haproxy.http.request.captured_headers': ['docs.example.internal'], - 'haproxy.http.request.raw_request_line': + 'haproxy.http.request.raw_request_line': [ 'GET /component---src-pages-index-js-4b15624544f97cf0bb8f.js HTTP/1.1', - 'haproxy.http.request.time_wait_ms': 0, - 'haproxy.http.request.time_wait_without_data_ms': 0, - 'haproxy.http.response.captured_cookie': '-', + ], + 'haproxy.http.request.time_wait_ms': [0], + 'haproxy.http.request.time_wait_without_data_ms': [0], + 'haproxy.http.response.captured_cookie': ['-'], 'haproxy.http.response.captured_headers': [], - 'haproxy.server_name': 'docs', - 'haproxy.server_queue': 0, - 'haproxy.termination_state': '----', - 'haproxy.total_waiting_time_ms': 0, - 'http.response.bytes': 168, - 'http.response.status_code': 304, - 'input.type': 'log', - 'log.offset': 0, - 'process.name': 'haproxy', - 'process.pid': 32450, - 'service.type': 'haproxy', - 'source.address': '1.2.3.4', - 'source.geo.continent_name': 'North America', - 'source.geo.country_iso_code': 'US', - 'source.geo.location.lat': 37.751, - 'source.geo.location.lon': -97.822, - 'source.ip': '1.2.3.4', - 'source.port': 38862, + 'haproxy.server_name': ['docs'], + 'haproxy.server_queue': [0], + 'haproxy.termination_state': ['----'], + 'haproxy.total_waiting_time_ms': [0], + 'http.response.bytes': [168], + 'http.response.status_code': [304], + 'input.type': ['log'], + 'log.offset': [0], + 'process.name': ['haproxy'], + 'process.pid': [32450], + 'service.type': ['haproxy'], + 'source.address': ['1.2.3.4'], + 'source.geo.continent_name': ['North America'], + 'source.geo.country_iso_code': ['US'], + 'source.geo.location.lat': [37.751], + 'source.geo.location.lon': [-97.822], + 'source.ip': ['1.2.3.4'], + 'source.port': [38862], }; expect(format(flattenedDocument, {})).toMatchInlineSnapshot(` -Array [ - Object { - "constant": "[HAProxy][http] ", - }, - Object { - "field": "source.address", - "highlights": Array [], - "value": "1.2.3.4", - }, - Object { - "constant": ":", - }, - Object { - "field": "source.port", - "highlights": Array [], - "value": "38862", - }, - Object { - "constant": " ", - }, - Object { - "field": "haproxy.frontend_name", - "highlights": Array [], - "value": "incoming~", - }, - Object { - "constant": " -> ", - }, - Object { - "field": "haproxy.backend_name", - "highlights": Array [], - "value": "docs_microservice", - }, - Object { - "constant": "/", - }, - Object { - "field": "haproxy.server_name", - "highlights": Array [], - "value": "docs", - }, - Object { - "constant": " \\"", - }, - Object { - "field": "haproxy.http.request.raw_request_line", - "highlights": Array [], - "value": "GET /component---src-pages-index-js-4b15624544f97cf0bb8f.js HTTP/1.1", - }, - Object { - "constant": "\\" ", - }, - Object { - "field": "http.response.status_code", - "highlights": Array [], - "value": "304", - }, - Object { - "constant": " ", - }, - Object { - "field": "haproxy.http.request.time_wait_ms", - "highlights": Array [], - "value": "0", - }, - Object { - "constant": "/", - }, - Object { - "field": "event.duration", - "highlights": Array [], - "value": "2000000", - }, - Object { - "constant": "/", - }, - Object { - "field": "haproxy.connection_wait_time_ms", - "highlights": Array [], - "value": "1", - }, - Object { - "constant": "/", - }, - Object { - "field": "haproxy.http.request.time_wait_without_data_ms", - "highlights": Array [], - "value": "0", - }, - Object { - "constant": "/", - }, - Object { - "field": "event.duration", - "highlights": Array [], - "value": "2000000", - }, - Object { - "constant": " ", - }, - Object { - "field": "haproxy.connections.active", - "highlights": Array [], - "value": "6", - }, - Object { - "constant": "/", - }, - Object { - "field": "haproxy.connections.frontend", - "highlights": Array [], - "value": "6", - }, - Object { - "constant": "/", - }, - Object { - "field": "haproxy.connections.backend", - "highlights": Array [], - "value": "0", - }, - Object { - "constant": "/", - }, - Object { - "field": "haproxy.connections.server", - "highlights": Array [], - "value": "0", - }, - Object { - "constant": "/", - }, - Object { - "field": "haproxy.connections.retries", - "highlights": Array [], - "value": "0", - }, - Object { - "constant": " ", - }, - Object { - "field": "haproxy.server_queue", - "highlights": Array [], - "value": "0", - }, - Object { - "constant": "/", - }, - Object { - "field": "haproxy.backend_queue", - "highlights": Array [], - "value": "0", - }, -] -`); + Array [ + Object { + "constant": "[HAProxy][http] ", + }, + Object { + "field": "source.address", + "highlights": Array [], + "value": Array [ + "1.2.3.4", + ], + }, + Object { + "constant": ":", + }, + Object { + "field": "source.port", + "highlights": Array [], + "value": Array [ + 38862, + ], + }, + Object { + "constant": " ", + }, + Object { + "field": "haproxy.frontend_name", + "highlights": Array [], + "value": Array [ + "incoming~", + ], + }, + Object { + "constant": " -> ", + }, + Object { + "field": "haproxy.backend_name", + "highlights": Array [], + "value": Array [ + "docs_microservice", + ], + }, + Object { + "constant": "/", + }, + Object { + "field": "haproxy.server_name", + "highlights": Array [], + "value": Array [ + "docs", + ], + }, + Object { + "constant": " \\"", + }, + Object { + "field": "haproxy.http.request.raw_request_line", + "highlights": Array [], + "value": Array [ + "GET /component---src-pages-index-js-4b15624544f97cf0bb8f.js HTTP/1.1", + ], + }, + Object { + "constant": "\\" ", + }, + Object { + "field": "http.response.status_code", + "highlights": Array [], + "value": Array [ + 304, + ], + }, + Object { + "constant": " ", + }, + Object { + "field": "haproxy.http.request.time_wait_ms", + "highlights": Array [], + "value": Array [ + 0, + ], + }, + Object { + "constant": "/", + }, + Object { + "field": "event.duration", + "highlights": Array [], + "value": Array [ + 2000000, + ], + }, + Object { + "constant": "/", + }, + Object { + "field": "haproxy.connection_wait_time_ms", + "highlights": Array [], + "value": Array [ + 1, + ], + }, + Object { + "constant": "/", + }, + Object { + "field": "haproxy.http.request.time_wait_without_data_ms", + "highlights": Array [], + "value": Array [ + 0, + ], + }, + Object { + "constant": "/", + }, + Object { + "field": "event.duration", + "highlights": Array [], + "value": Array [ + 2000000, + ], + }, + Object { + "constant": " ", + }, + Object { + "field": "haproxy.connections.active", + "highlights": Array [], + "value": Array [ + 6, + ], + }, + Object { + "constant": "/", + }, + Object { + "field": "haproxy.connections.frontend", + "highlights": Array [], + "value": Array [ + 6, + ], + }, + Object { + "constant": "/", + }, + Object { + "field": "haproxy.connections.backend", + "highlights": Array [], + "value": Array [ + 0, + ], + }, + Object { + "constant": "/", + }, + Object { + "field": "haproxy.connections.server", + "highlights": Array [], + "value": Array [ + 0, + ], + }, + Object { + "constant": "/", + }, + Object { + "field": "haproxy.connections.retries", + "highlights": Array [], + "value": Array [ + 0, + ], + }, + Object { + "constant": " ", + }, + Object { + "field": "haproxy.server_queue", + "highlights": Array [], + "value": Array [ + 0, + ], + }, + Object { + "constant": "/", + }, + Object { + "field": "haproxy.backend_queue", + "highlights": Array [], + "value": Array [ + 0, + ], + }, + ] + `); }); }); describe('in pre-ECS format', () => { test('haproxy default log', () => { const flattenedDocument = { - 'event.dataset': 'haproxy.log', - 'fileset.module': 'haproxy', - 'fileset.name': 'log', - 'haproxy.client.ip': '1.2.3.4', - 'haproxy.client.port': '40780', - 'haproxy.destination.ip': '1.2.3.4', - 'haproxy.destination.port': '5000', - 'haproxy.frontend_name': 'main', - 'haproxy.geoip.continent_name': 'North America', - 'haproxy.geoip.country_iso_code': 'US', - 'haproxy.geoip.location.lat': 37.751, - 'haproxy.geoip.location.lon': -97.822, - 'haproxy.mode': 'HTTP', - 'haproxy.pid': '24551', - 'haproxy.process_name': 'haproxy', - 'haproxy.source': '1.2.3.4', - 'input.type': 'log', - offset: 0, - 'prospector.type': 'log', + 'event.dataset': ['haproxy.log'], + 'fileset.module': ['haproxy'], + 'fileset.name': ['log'], + 'haproxy.client.ip': ['1.2.3.4'], + 'haproxy.client.port': ['40780'], + 'haproxy.destination.ip': ['1.2.3.4'], + 'haproxy.destination.port': ['5000'], + 'haproxy.frontend_name': ['main'], + 'haproxy.geoip.continent_name': ['North America'], + 'haproxy.geoip.country_iso_code': ['US'], + 'haproxy.geoip.location.lat': [37.751], + 'haproxy.geoip.location.lon': [-97.822], + 'haproxy.mode': ['HTTP'], + 'haproxy.pid': ['24551'], + 'haproxy.process_name': ['haproxy'], + 'haproxy.source': ['1.2.3.4'], + 'input.type': ['log'], + offset: [0], + 'prospector.type': ['log'], }; expect(format(flattenedDocument, {})).toMatchInlineSnapshot(` -Array [ - Object { - "constant": "[HAProxy] ", - }, - Object { - "field": "haproxy.client.ip", - "highlights": Array [], - "value": "1.2.3.4", - }, - Object { - "constant": ":", - }, - Object { - "field": "haproxy.client.port", - "highlights": Array [], - "value": "40780", - }, - Object { - "constant": " ", - }, - Object { - "field": "haproxy.frontend_name", - "highlights": Array [], - "value": "main", - }, -] -`); + Array [ + Object { + "constant": "[HAProxy] ", + }, + Object { + "field": "haproxy.client.ip", + "highlights": Array [], + "value": Array [ + "1.2.3.4", + ], + }, + Object { + "constant": ":", + }, + Object { + "field": "haproxy.client.port", + "highlights": Array [], + "value": Array [ + "40780", + ], + }, + Object { + "constant": " ", + }, + Object { + "field": "haproxy.frontend_name", + "highlights": Array [], + "value": Array [ + "main", + ], + }, + ] + `); }); test('haproxy tcp log', () => { const flattenedDocument = { - 'event.dataset': 'haproxy.log', - 'fileset.module': 'haproxy', - 'fileset.name': 'log', - 'haproxy.backend_name': 'app', - 'haproxy.backend_queue': 0, - 'haproxy.bytes_read': 212, - 'haproxy.client.ip': '127.0.0.1', - 'haproxy.client.port': 40962, - 'haproxy.connection_wait_time_ms': -1, - 'haproxy.connections.active': 1, - 'haproxy.connections.backend': 0, - 'haproxy.connections.frontend': 1, - 'haproxy.connections.retries': 0, - 'haproxy.connections.server': 0, - 'haproxy.frontend_name': 'main', - 'haproxy.pid': 25457, - 'haproxy.process_name': 'haproxy', - 'haproxy.server_name': '', - 'haproxy.server_queue': 0, - 'haproxy.source': '127.0.0.1', - 'haproxy.tcp.processing_time_ms': 0, - 'haproxy.termination_state': 'SC', - 'haproxy.total_waiting_time_ms': -1, - 'input.type': 'log', - offset: 0, - 'prospector.type': 'log', + 'event.dataset': ['haproxy.log'], + 'fileset.module': ['haproxy'], + 'fileset.name': ['log'], + 'haproxy.backend_name': ['app'], + 'haproxy.backend_queue': [0], + 'haproxy.bytes_read': [212], + 'haproxy.client.ip': ['127.0.0.1'], + 'haproxy.client.port': [40962], + 'haproxy.connection_wait_time_ms': [-1], + 'haproxy.connections.active': [1], + 'haproxy.connections.backend': [0], + 'haproxy.connections.frontend': [1], + 'haproxy.connections.retries': [0], + 'haproxy.connections.server': [0], + 'haproxy.frontend_name': ['main'], + 'haproxy.pid': [25457], + 'haproxy.process_name': ['haproxy'], + 'haproxy.server_name': [''], + 'haproxy.server_queue': [0], + 'haproxy.source': ['127.0.0.1'], + 'haproxy.tcp.processing_time_ms': [0], + 'haproxy.termination_state': ['SC'], + 'haproxy.total_waiting_time_ms': [-1], + 'input.type': ['log'], + offset: [0], + 'prospector.type': ['log'], }; expect(format(flattenedDocument, {})).toMatchInlineSnapshot(` -Array [ - Object { - "constant": "[HAProxy][tcp] ", - }, - Object { - "field": "haproxy.client.ip", - "highlights": Array [], - "value": "127.0.0.1", - }, - Object { - "constant": ":", - }, - Object { - "field": "haproxy.client.port", - "highlights": Array [], - "value": "40962", - }, - Object { - "constant": " ", - }, - Object { - "field": "haproxy.frontend_name", - "highlights": Array [], - "value": "main", - }, - Object { - "constant": " -> ", - }, - Object { - "field": "haproxy.backend_name", - "highlights": Array [], - "value": "app", - }, - Object { - "constant": "/", - }, - Object { - "field": "haproxy.server_name", - "highlights": Array [], - "value": "", - }, - Object { - "constant": " ", - }, - Object { - "field": "haproxy.connections.active", - "highlights": Array [], - "value": "1", - }, - Object { - "constant": "/", - }, - Object { - "field": "haproxy.connections.frontend", - "highlights": Array [], - "value": "1", - }, - Object { - "constant": "/", - }, - Object { - "field": "haproxy.connections.backend", - "highlights": Array [], - "value": "0", - }, - Object { - "constant": "/", - }, - Object { - "field": "haproxy.connections.server", - "highlights": Array [], - "value": "0", - }, - Object { - "constant": "/", - }, - Object { - "field": "haproxy.connections.retries", - "highlights": Array [], - "value": "0", - }, - Object { - "constant": " ", - }, - Object { - "field": "haproxy.server_queue", - "highlights": Array [], - "value": "0", - }, - Object { - "constant": "/", - }, - Object { - "field": "haproxy.backend_queue", - "highlights": Array [], - "value": "0", - }, -] -`); + Array [ + Object { + "constant": "[HAProxy][tcp] ", + }, + Object { + "field": "haproxy.client.ip", + "highlights": Array [], + "value": Array [ + "127.0.0.1", + ], + }, + Object { + "constant": ":", + }, + Object { + "field": "haproxy.client.port", + "highlights": Array [], + "value": Array [ + 40962, + ], + }, + Object { + "constant": " ", + }, + Object { + "field": "haproxy.frontend_name", + "highlights": Array [], + "value": Array [ + "main", + ], + }, + Object { + "constant": " -> ", + }, + Object { + "field": "haproxy.backend_name", + "highlights": Array [], + "value": Array [ + "app", + ], + }, + Object { + "constant": "/", + }, + Object { + "field": "haproxy.server_name", + "highlights": Array [], + "value": Array [ + "", + ], + }, + Object { + "constant": " ", + }, + Object { + "field": "haproxy.connections.active", + "highlights": Array [], + "value": Array [ + 1, + ], + }, + Object { + "constant": "/", + }, + Object { + "field": "haproxy.connections.frontend", + "highlights": Array [], + "value": Array [ + 1, + ], + }, + Object { + "constant": "/", + }, + Object { + "field": "haproxy.connections.backend", + "highlights": Array [], + "value": Array [ + 0, + ], + }, + Object { + "constant": "/", + }, + Object { + "field": "haproxy.connections.server", + "highlights": Array [], + "value": Array [ + 0, + ], + }, + Object { + "constant": "/", + }, + Object { + "field": "haproxy.connections.retries", + "highlights": Array [], + "value": Array [ + 0, + ], + }, + Object { + "constant": " ", + }, + Object { + "field": "haproxy.server_queue", + "highlights": Array [], + "value": Array [ + 0, + ], + }, + Object { + "constant": "/", + }, + Object { + "field": "haproxy.backend_queue", + "highlights": Array [], + "value": Array [ + 0, + ], + }, + ] + `); }); test('haproxy http log', () => { const flattenedDocument = { - 'event.dataset': 'haproxy.log', - 'fileset.module': 'haproxy', - 'fileset.name': 'log', - 'haproxy.backend_name': 'docs_microservice', - 'haproxy.backend_queue': 0, - 'haproxy.bytes_read': 168, - 'haproxy.client.ip': '1.2.3.4', - 'haproxy.client.port': 38862, - 'haproxy.connection_wait_time_ms': 1, - 'haproxy.connections.active': 6, - 'haproxy.connections.backend': 0, - 'haproxy.connections.frontend': 6, - 'haproxy.connections.retries': 0, - 'haproxy.connections.server': 0, - 'haproxy.frontend_name': 'incoming~', - 'haproxy.geoip.continent_name': 'North America', - 'haproxy.geoip.country_iso_code': 'US', - 'haproxy.geoip.location.lat': 37.751, - 'haproxy.geoip.location.lon': -97.822, - 'haproxy.http.request.captured_cookie': '-', - 'haproxy.http.request.raw_request_line': + 'event.dataset': ['haproxy.log'], + 'fileset.module': ['haproxy'], + 'fileset.name': ['log'], + 'haproxy.backend_name': ['docs_microservice'], + 'haproxy.backend_queue': [0], + 'haproxy.bytes_read': [168], + 'haproxy.client.ip': ['1.2.3.4'], + 'haproxy.client.port': [38862], + 'haproxy.connection_wait_time_ms': [1], + 'haproxy.connections.active': [6], + 'haproxy.connections.backend': [0], + 'haproxy.connections.frontend': [6], + 'haproxy.connections.retries': [0], + 'haproxy.connections.server': [0], + 'haproxy.frontend_name': ['incoming~'], + 'haproxy.geoip.continent_name': ['North America'], + 'haproxy.geoip.country_iso_code': ['US'], + 'haproxy.geoip.location.lat': [37.751], + 'haproxy.geoip.location.lon': [-97.822], + 'haproxy.http.request.captured_cookie': ['-'], + 'haproxy.http.request.raw_request_line': [ 'GET /component---src-pages-index-js-4b15624544f97cf0bb8f.js HTTP/1.1', - 'haproxy.http.request.time_active_ms': 2, - 'haproxy.http.request.time_wait_ms': 0, - 'haproxy.http.request.time_wait_without_data_ms': 0, - 'haproxy.http.response.captured_cookie': '-', - 'haproxy.http.response.status_code': 304, - 'haproxy.pid': 32450, - 'haproxy.process_name': 'haproxy', - 'haproxy.server_name': 'docs', - 'haproxy.server_queue': 0, - 'haproxy.termination_state': '----', - 'haproxy.total_waiting_time_ms': 0, - 'input.type': 'log', - offset: 0, - 'prospector.type': 'log', + ], + 'haproxy.http.request.time_active_ms': [2], + 'haproxy.http.request.time_wait_ms': [0], + 'haproxy.http.request.time_wait_without_data_ms': [0], + 'haproxy.http.response.captured_cookie': ['-'], + 'haproxy.http.response.status_code': [304], + 'haproxy.pid': [32450], + 'haproxy.process_name': ['haproxy'], + 'haproxy.server_name': ['docs'], + 'haproxy.server_queue': [0], + 'haproxy.termination_state': ['----'], + 'haproxy.total_waiting_time_ms': [0], + 'input.type': ['log'], + offset: [0], + 'prospector.type': ['log'], }; expect(format(flattenedDocument, {})).toMatchInlineSnapshot(` -Array [ - Object { - "constant": "[HAProxy][http] ", - }, - Object { - "field": "haproxy.client.ip", - "highlights": Array [], - "value": "1.2.3.4", - }, - Object { - "constant": ":", - }, - Object { - "field": "haproxy.client.port", - "highlights": Array [], - "value": "38862", - }, - Object { - "constant": " ", - }, - Object { - "field": "haproxy.frontend_name", - "highlights": Array [], - "value": "incoming~", - }, - Object { - "constant": " -> ", - }, - Object { - "field": "haproxy.backend_name", - "highlights": Array [], - "value": "docs_microservice", - }, - Object { - "constant": "/", - }, - Object { - "field": "haproxy.server_name", - "highlights": Array [], - "value": "docs", - }, - Object { - "constant": " \\"", - }, - Object { - "field": "haproxy.http.request.raw_request_line", - "highlights": Array [], - "value": "GET /component---src-pages-index-js-4b15624544f97cf0bb8f.js HTTP/1.1", - }, - Object { - "constant": "\\" ", - }, - Object { - "field": "haproxy.http.response.status_code", - "highlights": Array [], - "value": "304", - }, - Object { - "constant": " ", - }, - Object { - "field": "haproxy.http.request.time_wait_ms", - "highlights": Array [], - "value": "0", - }, - Object { - "constant": "/", - }, - Object { - "field": "haproxy.total_waiting_time_ms", - "highlights": Array [], - "value": "0", - }, - Object { - "constant": "/", - }, - Object { - "field": "haproxy.connection_wait_time_ms", - "highlights": Array [], - "value": "1", - }, - Object { - "constant": "/", - }, - Object { - "field": "haproxy.http.request.time_wait_without_data_ms", - "highlights": Array [], - "value": "0", - }, - Object { - "constant": "/", - }, - Object { - "field": "haproxy.http.request.time_active_ms", - "highlights": Array [], - "value": "2", - }, - Object { - "constant": " ", - }, - Object { - "field": "haproxy.connections.active", - "highlights": Array [], - "value": "6", - }, - Object { - "constant": "/", - }, - Object { - "field": "haproxy.connections.frontend", - "highlights": Array [], - "value": "6", - }, - Object { - "constant": "/", - }, - Object { - "field": "haproxy.connections.backend", - "highlights": Array [], - "value": "0", - }, - Object { - "constant": "/", - }, - Object { - "field": "haproxy.connections.server", - "highlights": Array [], - "value": "0", - }, - Object { - "constant": "/", - }, - Object { - "field": "haproxy.connections.retries", - "highlights": Array [], - "value": "0", - }, - Object { - "constant": " ", - }, - Object { - "field": "haproxy.server_queue", - "highlights": Array [], - "value": "0", - }, - Object { - "constant": "/", - }, - Object { - "field": "haproxy.backend_queue", - "highlights": Array [], - "value": "0", - }, -] -`); + Array [ + Object { + "constant": "[HAProxy][http] ", + }, + Object { + "field": "haproxy.client.ip", + "highlights": Array [], + "value": Array [ + "1.2.3.4", + ], + }, + Object { + "constant": ":", + }, + Object { + "field": "haproxy.client.port", + "highlights": Array [], + "value": Array [ + 38862, + ], + }, + Object { + "constant": " ", + }, + Object { + "field": "haproxy.frontend_name", + "highlights": Array [], + "value": Array [ + "incoming~", + ], + }, + Object { + "constant": " -> ", + }, + Object { + "field": "haproxy.backend_name", + "highlights": Array [], + "value": Array [ + "docs_microservice", + ], + }, + Object { + "constant": "/", + }, + Object { + "field": "haproxy.server_name", + "highlights": Array [], + "value": Array [ + "docs", + ], + }, + Object { + "constant": " \\"", + }, + Object { + "field": "haproxy.http.request.raw_request_line", + "highlights": Array [], + "value": Array [ + "GET /component---src-pages-index-js-4b15624544f97cf0bb8f.js HTTP/1.1", + ], + }, + Object { + "constant": "\\" ", + }, + Object { + "field": "haproxy.http.response.status_code", + "highlights": Array [], + "value": Array [ + 304, + ], + }, + Object { + "constant": " ", + }, + Object { + "field": "haproxy.http.request.time_wait_ms", + "highlights": Array [], + "value": Array [ + 0, + ], + }, + Object { + "constant": "/", + }, + Object { + "field": "haproxy.total_waiting_time_ms", + "highlights": Array [], + "value": Array [ + 0, + ], + }, + Object { + "constant": "/", + }, + Object { + "field": "haproxy.connection_wait_time_ms", + "highlights": Array [], + "value": Array [ + 1, + ], + }, + Object { + "constant": "/", + }, + Object { + "field": "haproxy.http.request.time_wait_without_data_ms", + "highlights": Array [], + "value": Array [ + 0, + ], + }, + Object { + "constant": "/", + }, + Object { + "field": "haproxy.http.request.time_active_ms", + "highlights": Array [], + "value": Array [ + 2, + ], + }, + Object { + "constant": " ", + }, + Object { + "field": "haproxy.connections.active", + "highlights": Array [], + "value": Array [ + 6, + ], + }, + Object { + "constant": "/", + }, + Object { + "field": "haproxy.connections.frontend", + "highlights": Array [], + "value": Array [ + 6, + ], + }, + Object { + "constant": "/", + }, + Object { + "field": "haproxy.connections.backend", + "highlights": Array [], + "value": Array [ + 0, + ], + }, + Object { + "constant": "/", + }, + Object { + "field": "haproxy.connections.server", + "highlights": Array [], + "value": Array [ + 0, + ], + }, + Object { + "constant": "/", + }, + Object { + "field": "haproxy.connections.retries", + "highlights": Array [], + "value": Array [ + 0, + ], + }, + Object { + "constant": " ", + }, + Object { + "field": "haproxy.server_queue", + "highlights": Array [], + "value": Array [ + 0, + ], + }, + Object { + "constant": "/", + }, + Object { + "field": "haproxy.backend_queue", + "highlights": Array [], + "value": Array [ + 0, + ], + }, + ] + `); }); }); }); diff --git a/x-pack/plugins/infra/server/lib/domains/log_entries_domain/builtin_rules/filebeat_icinga.test.ts b/x-pack/plugins/infra/server/lib/domains/log_entries_domain/builtin_rules/filebeat_icinga.test.ts index 120137f15b883..00d282e1833d8 100644 --- a/x-pack/plugins/infra/server/lib/domains/log_entries_domain/builtin_rules/filebeat_icinga.test.ts +++ b/x-pack/plugins/infra/server/lib/domains/log_entries_domain/builtin_rules/filebeat_icinga.test.ts @@ -13,135 +13,155 @@ describe('Filebeat Rules', () => { describe('in pre-ECS format', () => { test('icinga debug log', () => { const flattenedDocument = { - '@timestamp': '2017-04-04T11:43:09.000Z', - 'event.dataset': 'icinga.debug', - 'fileset.module': 'icinga', - 'fileset.name': 'debug', - 'icinga.debug.facility': 'GraphiteWriter', - 'icinga.debug.message': + '@timestamp': ['2017-04-04T11:43:09.000Z'], + 'event.dataset': ['icinga.debug'], + 'fileset.module': ['icinga'], + 'fileset.name': ['debug'], + 'icinga.debug.facility': ['GraphiteWriter'], + 'icinga.debug.message': [ "Add to metric list:'icinga2.demo.services.procs.procs.perfdata.procs.warn 250 1491306189'.", - 'icinga.debug.severity': 'debug', - 'input.type': 'log', - offset: 0, - 'prospector.type': 'log', + ], + 'icinga.debug.severity': ['debug'], + 'input.type': ['log'], + offset: [0], + 'prospector.type': ['log'], }; expect(format(flattenedDocument, {})).toMatchInlineSnapshot(` -Array [ - Object { - "constant": "[Icinga][", - }, - Object { - "field": "icinga.debug.facility", - "highlights": Array [], - "value": "GraphiteWriter", - }, - Object { - "constant": "][", - }, - Object { - "field": "icinga.debug.severity", - "highlights": Array [], - "value": "debug", - }, - Object { - "constant": "] ", - }, - Object { - "field": "icinga.debug.message", - "highlights": Array [], - "value": "Add to metric list:'icinga2.demo.services.procs.procs.perfdata.procs.warn 250 1491306189'.", - }, -] -`); + Array [ + Object { + "constant": "[Icinga][", + }, + Object { + "field": "icinga.debug.facility", + "highlights": Array [], + "value": Array [ + "GraphiteWriter", + ], + }, + Object { + "constant": "][", + }, + Object { + "field": "icinga.debug.severity", + "highlights": Array [], + "value": Array [ + "debug", + ], + }, + Object { + "constant": "] ", + }, + Object { + "field": "icinga.debug.message", + "highlights": Array [], + "value": Array [ + "Add to metric list:'icinga2.demo.services.procs.procs.perfdata.procs.warn 250 1491306189'.", + ], + }, + ] + `); }); test('icinga main log', () => { const flattenedDocument = { - '@timestamp': '2017-04-04T09:16:34.000Z', - 'event.dataset': 'icinga.main', - 'fileset.module': 'icinga', - 'fileset.name': 'main', - 'icinga.main.facility': 'Notification', - 'icinga.main.message': + '@timestamp': ['2017-04-04T09:16:34.000Z'], + 'event.dataset': ['icinga.main'], + 'fileset.module': ['icinga'], + 'fileset.name': ['main'], + 'icinga.main.facility': ['Notification'], + 'icinga.main.message': [ "Sending 'Recovery' notification 'demo!load!mail-icingaadmin for user 'on-call'", - 'icinga.main.severity': 'information', - 'input.type': 'log', - offset: 0, - 'prospector.type': 'log', + ], + 'icinga.main.severity': ['information'], + 'input.type': ['log'], + offset: [0], + 'prospector.type': ['log'], }; expect(format(flattenedDocument, {})).toMatchInlineSnapshot(` -Array [ - Object { - "constant": "[Icinga][", - }, - Object { - "field": "icinga.main.facility", - "highlights": Array [], - "value": "Notification", - }, - Object { - "constant": "][", - }, - Object { - "field": "icinga.main.severity", - "highlights": Array [], - "value": "information", - }, - Object { - "constant": "] ", - }, - Object { - "field": "icinga.main.message", - "highlights": Array [], - "value": "Sending 'Recovery' notification 'demo!load!mail-icingaadmin for user 'on-call'", - }, -] -`); + Array [ + Object { + "constant": "[Icinga][", + }, + Object { + "field": "icinga.main.facility", + "highlights": Array [], + "value": Array [ + "Notification", + ], + }, + Object { + "constant": "][", + }, + Object { + "field": "icinga.main.severity", + "highlights": Array [], + "value": Array [ + "information", + ], + }, + Object { + "constant": "] ", + }, + Object { + "field": "icinga.main.message", + "highlights": Array [], + "value": Array [ + "Sending 'Recovery' notification 'demo!load!mail-icingaadmin for user 'on-call'", + ], + }, + ] + `); }); test('icinga startup log', () => { const flattenedDocument = { - 'event.dataset': 'icinga.startup', - 'fileset.module': 'icinga', - 'fileset.name': 'startup', - 'icinga.startup.facility': 'cli', - 'icinga.startup.message': 'Icinga application loader (version: r2.6.3-1)', - 'icinga.startup.severity': 'information', - 'input.type': 'log', - offset: 0, - 'prospector.type': 'log', + 'event.dataset': ['icinga.startup'], + 'fileset.module': ['icinga'], + 'fileset.name': ['startup'], + 'icinga.startup.facility': ['cli'], + 'icinga.startup.message': ['Icinga application loader (version: r2.6.3-1)'], + 'icinga.startup.severity': ['information'], + 'input.type': ['log'], + offset: [0], + 'prospector.type': ['log'], }; expect(format(flattenedDocument, {})).toMatchInlineSnapshot(` -Array [ - Object { - "constant": "[Icinga][", - }, - Object { - "field": "icinga.startup.facility", - "highlights": Array [], - "value": "cli", - }, - Object { - "constant": "][", - }, - Object { - "field": "icinga.startup.severity", - "highlights": Array [], - "value": "information", - }, - Object { - "constant": "] ", - }, - Object { - "field": "icinga.startup.message", - "highlights": Array [], - "value": "Icinga application loader (version: r2.6.3-1)", - }, -] -`); + Array [ + Object { + "constant": "[Icinga][", + }, + Object { + "field": "icinga.startup.facility", + "highlights": Array [], + "value": Array [ + "cli", + ], + }, + Object { + "constant": "][", + }, + Object { + "field": "icinga.startup.severity", + "highlights": Array [], + "value": Array [ + "information", + ], + }, + Object { + "constant": "] ", + }, + Object { + "field": "icinga.startup.message", + "highlights": Array [], + "value": Array [ + "Icinga application loader (version: r2.6.3-1)", + ], + }, + ] + `); }); }); }); diff --git a/x-pack/plugins/infra/server/lib/domains/log_entries_domain/builtin_rules/filebeat_iis.test.ts b/x-pack/plugins/infra/server/lib/domains/log_entries_domain/builtin_rules/filebeat_iis.test.ts index 72449c03b63a6..5238d5fe1da95 100644 --- a/x-pack/plugins/infra/server/lib/domains/log_entries_domain/builtin_rules/filebeat_iis.test.ts +++ b/x-pack/plugins/infra/server/lib/domains/log_entries_domain/builtin_rules/filebeat_iis.test.ts @@ -13,550 +13,622 @@ describe('Filebeat Rules', () => { describe('in ECS format', () => { test('iis access log', () => { const flattenedDocument = { - '@timestamp': '2018-01-01T10:11:12.000Z', - 'destination.address': '127.0.0.1', - 'destination.domain': 'example.com', - 'destination.ip': '127.0.0.1', - 'destination.port': 80, - 'ecs.version': '1.0.0-beta2', - 'event.dataset': 'iis.access', - 'event.duration': 789000000, - 'event.module': 'iis', - 'fileset.name': 'access', - 'http.request.body.bytes': 456, - 'http.request.method': 'GET', - 'http.request.referrer': '-', - 'http.response.body.bytes': 123, - 'http.response.status_code': 200, - 'http.version': '1.1', - 'iis.access.cookie': '-', - 'iis.access.server_name': 'MACHINE-NAME', - 'iis.access.site_name': 'W3SVC1', - 'iis.access.sub_status': 0, - 'iis.access.win32_status': 0, - 'input.type': 'log', - 'log.offset': 1204, - 'service.type': 'iis', - 'source.address': '85.181.35.98', - 'source.geo.city_name': 'Berlin', - 'source.geo.continent_name': 'Europe', - 'source.geo.country_iso_code': 'DE', - 'source.geo.location.lat': 52.4908, - 'source.geo.location.lon': 13.3275, - 'source.geo.region_iso_code': 'DE-BE', - 'source.geo.region_name': 'Land Berlin', - 'source.ip': '85.181.35.98', - 'url.path': '/', - 'url.query': 'q=100', - 'user.name': '-', - 'user_agent.device.name': 'Other', - 'user_agent.name': 'Chrome', - 'user_agent.original': + '@timestamp': ['2018-01-01T10:11:12.000Z'], + 'destination.address': ['127.0.0.1'], + 'destination.domain': ['example.com'], + 'destination.ip': ['127.0.0.1'], + 'destination.port': [80], + 'ecs.version': ['1.0.0-beta2'], + 'event.dataset': ['iis.access'], + 'event.duration': [789000000], + 'event.module': ['iis'], + 'fileset.name': ['access'], + 'http.request.body.bytes': [456], + 'http.request.method': ['GET'], + 'http.request.referrer': ['-'], + 'http.response.body.bytes': [123], + 'http.response.status_code': [200], + 'http.version': ['1.1'], + 'iis.access.cookie': ['-'], + 'iis.access.server_name': ['MACHINE-NAME'], + 'iis.access.site_name': ['W3SVC1'], + 'iis.access.sub_status': [0], + 'iis.access.win32_status': [0], + 'input.type': ['log'], + 'log.offset': [1204], + 'service.type': ['iis'], + 'source.address': ['85.181.35.98'], + 'source.geo.city_name': ['Berlin'], + 'source.geo.continent_name': ['Europe'], + 'source.geo.country_iso_code': ['DE'], + 'source.geo.location.lat': [52.4908], + 'source.geo.location.lon': [13.3275], + 'source.geo.region_iso_code': ['DE-BE'], + 'source.geo.region_name': ['Land Berlin'], + 'source.ip': ['85.181.35.98'], + 'url.path': ['/'], + 'url.query': ['q=100'], + 'user.name': ['-'], + 'user_agent.device.name': ['Other'], + 'user_agent.name': ['Chrome'], + 'user_agent.original': [ 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36', - 'user_agent.os.full': 'Mac OS X 10.14.0', - 'user_agent.os.name': 'Mac OS X', - 'user_agent.os.version': '10.14.0', - 'user_agent.version': '70.0.3538', + ], + 'user_agent.os.full': ['Mac OS X 10.14.0'], + 'user_agent.os.name': ['Mac OS X'], + 'user_agent.os.version': ['10.14.0'], + 'user_agent.version': ['70.0.3538'], }; expect(format(flattenedDocument, {})).toMatchInlineSnapshot(` -Array [ - Object { - "constant": "[", - }, - Object { - "field": "event.module", - "highlights": Array [], - "value": "iis", - }, - Object { - "constant": "][access] ", - }, - Object { - "field": "source.ip", - "highlights": Array [], - "value": "85.181.35.98", - }, - Object { - "constant": " ", - }, - Object { - "field": "user.name", - "highlights": Array [], - "value": "-", - }, - Object { - "constant": " \\"", - }, - Object { - "field": "http.request.method", - "highlights": Array [], - "value": "GET", - }, - Object { - "constant": " ", - }, - Object { - "field": "url.path", - "highlights": Array [], - "value": "/", - }, - Object { - "constant": "?", - }, - Object { - "field": "url.query", - "highlights": Array [], - "value": "q=100", - }, - Object { - "constant": " HTTP/", - }, - Object { - "field": "http.version", - "highlights": Array [], - "value": "1.1", - }, - Object { - "constant": "\\" ", - }, - Object { - "field": "http.response.status_code", - "highlights": Array [], - "value": "200", - }, - Object { - "constant": " ", - }, - Object { - "field": "http.response.body.bytes", - "highlights": Array [], - "value": "123", - }, -] -`); + Array [ + Object { + "constant": "[", + }, + Object { + "field": "event.module", + "highlights": Array [], + "value": Array [ + "iis", + ], + }, + Object { + "constant": "][access] ", + }, + Object { + "field": "source.ip", + "highlights": Array [], + "value": Array [ + "85.181.35.98", + ], + }, + Object { + "constant": " ", + }, + Object { + "field": "user.name", + "highlights": Array [], + "value": Array [ + "-", + ], + }, + Object { + "constant": " \\"", + }, + Object { + "field": "http.request.method", + "highlights": Array [], + "value": Array [ + "GET", + ], + }, + Object { + "constant": " ", + }, + Object { + "field": "url.path", + "highlights": Array [], + "value": Array [ + "/", + ], + }, + Object { + "constant": "?", + }, + Object { + "field": "url.query", + "highlights": Array [], + "value": Array [ + "q=100", + ], + }, + Object { + "constant": " HTTP/", + }, + Object { + "field": "http.version", + "highlights": Array [], + "value": Array [ + "1.1", + ], + }, + Object { + "constant": "\\" ", + }, + Object { + "field": "http.response.status_code", + "highlights": Array [], + "value": Array [ + 200, + ], + }, + Object { + "constant": " ", + }, + Object { + "field": "http.response.body.bytes", + "highlights": Array [], + "value": Array [ + 123, + ], + }, + ] + `); }); test('iis 7.5 access log', () => { const flattenedDocument = { - '@timestamp': '2018-08-28T18:24:25.000Z', - 'destination.address': '10.100.220.70', - 'destination.ip': '10.100.220.70', - 'destination.port': 80, - 'ecs.version': '1.0.0-beta2', - 'event.dataset': 'iis.access', - 'event.duration': 792000000, - 'event.module': 'iis', - 'fileset.name': 'access', - 'http.request.method': 'GET', - 'http.response.status_code': 404, - 'iis.access.sub_status': 4, - 'iis.access.win32_status': 2, - 'input.type': 'log', - 'log.offset': 244, - 'service.type': 'iis', - 'source.address': '10.100.118.31', - 'source.ip': '10.100.118.31', - 'url.path': '/', - 'url.query': 'q=100', - 'user.name': '-', - 'user_agent.device.name': 'Other', - 'user_agent.name': 'IE', - 'user_agent.original': - 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.3; WOW64; Trident/7.0; .NET4.0E; .NET4.0C; .NET CLR 3.5.30729; .NET CLR[ 2.0.50727](tel: 2050727); .NET CLR 3.0.30729)', - 'user_agent.os.name': 'Windows 8.1', - 'user_agent.version': '7.0', + '@timestamp': ['2018-08-28T18:24:25.000Z'], + 'destination.address': ['10.100.220.70'], + 'destination.ip': ['10.100.220.70'], + 'destination.port': [80], + 'ecs.version': ['1.0.0-beta2'], + 'event.dataset': ['iis.access'], + 'event.duration': [792000000], + 'event.module': ['iis'], + 'fileset.name': ['access'], + 'http.request.method': ['GET'], + 'http.response.status_code': [404], + 'iis.access.sub_status': [4], + 'iis.access.win32_status': [2], + 'input.type': ['log'], + 'log.offset': [244], + 'service.type': ['iis'], + 'source.address': ['10.100.118.31'], + 'source.ip': ['10.100.118.31'], + 'url.path': ['/'], + 'url.query': ['q=100'], + 'user.name': ['-'], + 'user_agent.device.name': ['Other'], + 'user_agent.name': ['IE'], + 'user_agent.original': [ + 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.3; WOW64; Trident/7.0; .NET4.0E; .NET4.0C; .NET CLR 3.5.30729; .NET CLR[ 2.0.50727](tel: [2050727); .NET CLR 3.0.30729)', + ], + 'user_agent.os.name': ['Windows 8.1'], + 'user_agent.version': ['7.0'], }; expect(format(flattenedDocument, {})).toMatchInlineSnapshot(` -Array [ - Object { - "constant": "[", - }, - Object { - "field": "event.module", - "highlights": Array [], - "value": "iis", - }, - Object { - "constant": "][access] ", - }, - Object { - "field": "source.ip", - "highlights": Array [], - "value": "10.100.118.31", - }, - Object { - "constant": " ", - }, - Object { - "field": "user.name", - "highlights": Array [], - "value": "-", - }, - Object { - "constant": " \\"", - }, - Object { - "field": "http.request.method", - "highlights": Array [], - "value": "GET", - }, - Object { - "constant": " ", - }, - Object { - "field": "url.path", - "highlights": Array [], - "value": "/", - }, - Object { - "constant": "?", - }, - Object { - "field": "url.query", - "highlights": Array [], - "value": "q=100", - }, - Object { - "constant": " HTTP/", - }, - Object { - "field": "http.version", - "highlights": Array [], - "value": "undefined", - }, - Object { - "constant": "\\" ", - }, - Object { - "field": "http.response.status_code", - "highlights": Array [], - "value": "404", - }, - Object { - "constant": " ", - }, - Object { - "field": "http.response.body.bytes", - "highlights": Array [], - "value": "undefined", - }, -] -`); + Array [ + Object { + "constant": "[", + }, + Object { + "field": "event.module", + "highlights": Array [], + "value": Array [ + "iis", + ], + }, + Object { + "constant": "][access] ", + }, + Object { + "field": "source.ip", + "highlights": Array [], + "value": Array [ + "10.100.118.31", + ], + }, + Object { + "constant": " ", + }, + Object { + "field": "user.name", + "highlights": Array [], + "value": Array [ + "-", + ], + }, + Object { + "constant": " \\"", + }, + Object { + "field": "http.request.method", + "highlights": Array [], + "value": Array [ + "GET", + ], + }, + Object { + "constant": " ", + }, + Object { + "field": "url.path", + "highlights": Array [], + "value": Array [ + "/", + ], + }, + Object { + "constant": "?", + }, + Object { + "field": "url.query", + "highlights": Array [], + "value": Array [ + "q=100", + ], + }, + Object { + "constant": " HTTP/", + }, + Object { + "field": "http.version", + "highlights": Array [], + "value": Array [], + }, + Object { + "constant": "\\" ", + }, + Object { + "field": "http.response.status_code", + "highlights": Array [], + "value": Array [ + 404, + ], + }, + Object { + "constant": " ", + }, + Object { + "field": "http.response.body.bytes", + "highlights": Array [], + "value": Array [], + }, + ] + `); }); test('iis error log', () => { const flattenedDocument = { - '@timestamp': '2018-01-01T08:09:10.000Z', - 'destination.address': '172.31.77.6', - 'destination.ip': '172.31.77.6', - 'destination.port': 80, - 'ecs.version': '1.0.0-beta2', - 'event.dataset': 'iis.error', - 'event.module': 'iis', - 'fileset.name': 'error', - 'http.request.method': 'GET', - 'http.response.status_code': 503, - 'http.version': '1.1', - 'iis.error.queue_name': '-', - 'iis.error.reason_phrase': 'ConnLimit', - 'input.type': 'log', - 'log.offset': 186, - 'service.type': 'iis', - 'source.address': '172.31.77.6', - 'source.ip': '172.31.77.6', - 'source.port': 2094, - 'url.original': '/qos/1kbfile.txt', + '@timestamp': ['2018-01-01T08:09:10.000Z'], + 'destination.address': ['172.31.77.6'], + 'destination.ip': ['172.31.77.6'], + 'destination.port': [80], + 'ecs.version': ['1.0.0-beta2'], + 'event.dataset': ['iis.error'], + 'event.module': ['iis'], + 'fileset.name': ['error'], + 'http.request.method': ['GET'], + 'http.response.status_code': [503], + 'http.version': ['1.1'], + 'iis.error.queue_name': ['-'], + 'iis.error.reason_phrase': ['ConnLimit'], + 'input.type': ['log'], + 'log.offset': [186], + 'service.type': ['iis'], + 'source.address': ['172.31.77.6'], + 'source.ip': ['172.31.77.6'], + 'source.port': [2094], + 'url.original': ['/qos/1kbfile.txt'], }; expect(format(flattenedDocument, {})).toMatchInlineSnapshot(` -Array [ - Object { - "constant": "[iis][error] ", - }, - Object { - "field": "source.ip", - "highlights": Array [], - "value": "172.31.77.6", - }, - Object { - "constant": " ", - }, - Object { - "field": "iis.error.reason_phrase", - "highlights": Array [], - "value": "ConnLimit", - }, -] -`); + Array [ + Object { + "constant": "[iis][error] ", + }, + Object { + "field": "source.ip", + "highlights": Array [], + "value": Array [ + "172.31.77.6", + ], + }, + Object { + "constant": " ", + }, + Object { + "field": "iis.error.reason_phrase", + "highlights": Array [], + "value": Array [ + "ConnLimit", + ], + }, + ] + `); }); }); describe('in pre-ECS format', () => { test('iis access log', () => { const flattenedDocument = { - '@timestamp': '2018-01-01T08:09:10.000Z', - 'event.dataset': 'iis.access', - 'fileset.module': 'iis', - 'fileset.name': 'access', - 'iis.access.geoip.city_name': 'Berlin', - 'iis.access.geoip.continent_name': 'Europe', - 'iis.access.geoip.country_iso_code': 'DE', - 'iis.access.geoip.location.lat': 52.4908, - 'iis.access.geoip.location.lon': 13.3275, - 'iis.access.geoip.region_iso_code': 'DE-BE', - 'iis.access.geoip.region_name': 'Land Berlin', - 'iis.access.method': 'GET', - 'iis.access.port': '80', - 'iis.access.query_string': 'q=100', - 'iis.access.referrer': '-', - 'iis.access.remote_ip': '85.181.35.98', - 'iis.access.request_time_ms': '123', - 'iis.access.response_code': '200', - 'iis.access.server_ip': '127.0.0.1', - 'iis.access.sub_status': '0', - 'iis.access.url': '/', - 'iis.access.user_agent.device': 'Other', - 'iis.access.user_agent.major': '57', - 'iis.access.user_agent.minor': '0', - 'iis.access.user_agent.name': 'Firefox', - 'iis.access.user_agent.original': + '@timestamp': ['2018-01-01T08:09:10.000Z'], + 'event.dataset': ['iis.access'], + 'fileset.module': ['iis'], + 'fileset.name': ['access'], + 'iis.access.geoip.city_name': ['Berlin'], + 'iis.access.geoip.continent_name': ['Europe'], + 'iis.access.geoip.country_iso_code': ['DE'], + 'iis.access.geoip.location.lat': [52.4908], + 'iis.access.geoip.location.lon': [13.3275], + 'iis.access.geoip.region_iso_code': ['DE-BE'], + 'iis.access.geoip.region_name': ['Land Berlin'], + 'iis.access.method': ['GET'], + 'iis.access.port': ['80'], + 'iis.access.query_string': ['q=100'], + 'iis.access.referrer': ['-'], + 'iis.access.remote_ip': ['85.181.35.98'], + 'iis.access.request_time_ms': ['123'], + 'iis.access.response_code': ['200'], + 'iis.access.server_ip': ['127.0.0.1'], + 'iis.access.sub_status': ['0'], + 'iis.access.url': ['/'], + 'iis.access.user_agent.device': ['Other'], + 'iis.access.user_agent.major': ['57'], + 'iis.access.user_agent.minor': ['0'], + 'iis.access.user_agent.name': ['Firefox'], + 'iis.access.user_agent.original': [ 'Mozilla/5.0+(Windows+NT+6.1;+Win64;+x64;+rv:57.0)+Gecko/20100101+Firefox/57.0', - 'iis.access.user_agent.os': 'Windows', - 'iis.access.user_agent.os_name': 'Windows', - 'iis.access.user_name': '-', - 'iis.access.win32_status': '0', - 'input.type': 'log', - offset: 257, - 'prospector.type': 'log', + ], + 'iis.access.user_agent.os': ['Windows'], + 'iis.access.user_agent.os_name': ['Windows'], + 'iis.access.user_name': ['-'], + 'iis.access.win32_status': ['0'], + 'input.type': ['log'], + offset: [257], + 'prospector.type': ['log'], }; expect(format(flattenedDocument, {})).toMatchInlineSnapshot(` -Array [ - Object { - "constant": "[iis][access] ", - }, - Object { - "field": "iis.access.remote_ip", - "highlights": Array [], - "value": "85.181.35.98", - }, - Object { - "constant": " ", - }, - Object { - "field": "iis.access.user_name", - "highlights": Array [], - "value": "-", - }, - Object { - "constant": " \\"", - }, - Object { - "field": "iis.access.method", - "highlights": Array [], - "value": "GET", - }, - Object { - "constant": " ", - }, - Object { - "field": "iis.access.url", - "highlights": Array [], - "value": "/", - }, - Object { - "constant": " HTTP/", - }, - Object { - "field": "iis.access.http_version", - "highlights": Array [], - "value": "undefined", - }, - Object { - "constant": "\\" ", - }, - Object { - "field": "iis.access.response_code", - "highlights": Array [], - "value": "200", - }, - Object { - "constant": " ", - }, - Object { - "field": "iis.access.body_sent.bytes", - "highlights": Array [], - "value": "undefined", - }, -] -`); + Array [ + Object { + "constant": "[iis][access] ", + }, + Object { + "field": "iis.access.remote_ip", + "highlights": Array [], + "value": Array [ + "85.181.35.98", + ], + }, + Object { + "constant": " ", + }, + Object { + "field": "iis.access.user_name", + "highlights": Array [], + "value": Array [ + "-", + ], + }, + Object { + "constant": " \\"", + }, + Object { + "field": "iis.access.method", + "highlights": Array [], + "value": Array [ + "GET", + ], + }, + Object { + "constant": " ", + }, + Object { + "field": "iis.access.url", + "highlights": Array [], + "value": Array [ + "/", + ], + }, + Object { + "constant": " HTTP/", + }, + Object { + "field": "iis.access.http_version", + "highlights": Array [], + "value": Array [], + }, + Object { + "constant": "\\" ", + }, + Object { + "field": "iis.access.response_code", + "highlights": Array [], + "value": Array [ + "200", + ], + }, + Object { + "constant": " ", + }, + Object { + "field": "iis.access.body_sent.bytes", + "highlights": Array [], + "value": Array [], + }, + ] + `); }); test('iis 7.5 access log', () => { const flattenedDocument = { - '@timestamp': '2018-08-28T18:24:25.000Z', - 'event.dataset': 'iis.access', - 'fileset.module': 'iis', - 'fileset.name': 'access', - 'iis.access.method': 'GET', - 'iis.access.port': '80', - 'iis.access.query_string': '-', - 'iis.access.remote_ip': '10.100.118.31', - 'iis.access.request_time_ms': '792', - 'iis.access.response_code': '404', - 'iis.access.server_ip': '10.100.220.70', - 'iis.access.sub_status': '4', - 'iis.access.url': '/', - 'iis.access.user_agent.device': 'Other', - 'iis.access.user_agent.name': 'Other', - 'iis.access.user_agent.original': + '@timestamp': ['2018-08-28T18:24:25.000Z'], + 'event.dataset': ['iis.access'], + 'fileset.module': ['iis'], + 'fileset.name': ['access'], + 'iis.access.method': ['GET'], + 'iis.access.port': ['80'], + 'iis.access.query_string': ['-'], + 'iis.access.remote_ip': ['10.100.118.31'], + 'iis.access.request_time_ms': ['792'], + 'iis.access.response_code': ['404'], + 'iis.access.server_ip': ['10.100.220.70'], + 'iis.access.sub_status': ['4'], + 'iis.access.url': ['/'], + 'iis.access.user_agent.device': ['Other'], + 'iis.access.user_agent.name': ['Other'], + 'iis.access.user_agent.original': [ 'Mozilla/4.0+(compatible;+MSIE+7.0;+Windows+NT+6.3;+WOW64;+Trident/7.0;+.NET4.0E;+.NET4.0C;+.NET+CLR+3.5.30729;+.NET+CLR[+2.0.50727](tel:+2050727);+.NET+CLR+3.0.30729)', - 'iis.access.user_agent.os': 'Windows', - 'iis.access.user_agent.os_name': 'Windows', - 'iis.access.user_name': '-', - 'iis.access.win32_status': '2', - 'input.type': 'log', - offset: 244, - 'prospector.type': 'log', + ], + 'iis.access.user_agent.os': ['Windows'], + 'iis.access.user_agent.os_name': ['Windows'], + 'iis.access.user_name': ['-'], + 'iis.access.win32_status': ['2'], + 'input.type': ['log'], + offset: [244], + 'prospector.type': ['log'], }; expect(format(flattenedDocument, {})).toMatchInlineSnapshot(` -Array [ - Object { - "constant": "[iis][access] ", - }, - Object { - "field": "iis.access.remote_ip", - "highlights": Array [], - "value": "10.100.118.31", - }, - Object { - "constant": " ", - }, - Object { - "field": "iis.access.user_name", - "highlights": Array [], - "value": "-", - }, - Object { - "constant": " \\"", - }, - Object { - "field": "iis.access.method", - "highlights": Array [], - "value": "GET", - }, - Object { - "constant": " ", - }, - Object { - "field": "iis.access.url", - "highlights": Array [], - "value": "/", - }, - Object { - "constant": " HTTP/", - }, - Object { - "field": "iis.access.http_version", - "highlights": Array [], - "value": "undefined", - }, - Object { - "constant": "\\" ", - }, - Object { - "field": "iis.access.response_code", - "highlights": Array [], - "value": "404", - }, - Object { - "constant": " ", - }, - Object { - "field": "iis.access.body_sent.bytes", - "highlights": Array [], - "value": "undefined", - }, -] -`); + Array [ + Object { + "constant": "[iis][access] ", + }, + Object { + "field": "iis.access.remote_ip", + "highlights": Array [], + "value": Array [ + "10.100.118.31", + ], + }, + Object { + "constant": " ", + }, + Object { + "field": "iis.access.user_name", + "highlights": Array [], + "value": Array [ + "-", + ], + }, + Object { + "constant": " \\"", + }, + Object { + "field": "iis.access.method", + "highlights": Array [], + "value": Array [ + "GET", + ], + }, + Object { + "constant": " ", + }, + Object { + "field": "iis.access.url", + "highlights": Array [], + "value": Array [ + "/", + ], + }, + Object { + "constant": " HTTP/", + }, + Object { + "field": "iis.access.http_version", + "highlights": Array [], + "value": Array [], + }, + Object { + "constant": "\\" ", + }, + Object { + "field": "iis.access.response_code", + "highlights": Array [], + "value": Array [ + "404", + ], + }, + Object { + "constant": " ", + }, + Object { + "field": "iis.access.body_sent.bytes", + "highlights": Array [], + "value": Array [], + }, + ] + `); }); test('iis error log', () => { const flattenedDocument = { - '@timestamp': '2018-01-01T08:09:10.000Z', - 'event.dataset': 'iis.error', - 'fileset.module': 'iis', - 'fileset.name': 'error', - 'iis.error.http_version': '1.1', - 'iis.error.method': 'GET', - 'iis.error.queue_name': '-', - 'iis.error.reason_phrase': 'ConnLimit', - 'iis.error.remote_ip': '172.31.77.6', - 'iis.error.remote_port': '2094', - 'iis.error.response_code': '503', - 'iis.error.server_ip': '172.31.77.6', - 'iis.error.server_port': '80', - 'iis.error.url': '/qos/1kbfile.txt', - 'input.type': 'log', - offset: 186, - 'prospector.type': 'log', + '@timestamp': ['2018-01-01T08:09:10.000Z'], + 'event.dataset': ['iis.error'], + 'fileset.module': ['iis'], + 'fileset.name': ['error'], + 'iis.error.http_version': ['1.1'], + 'iis.error.method': ['GET'], + 'iis.error.queue_name': ['-'], + 'iis.error.reason_phrase': ['ConnLimit'], + 'iis.error.remote_ip': ['172.31.77.6'], + 'iis.error.remote_port': ['2094'], + 'iis.error.response_code': ['503'], + 'iis.error.server_ip': ['172.31.77.6'], + 'iis.error.server_port': ['80'], + 'iis.error.url': ['/qos/1kbfile.txt'], + 'input.type': ['log'], + offset: [186], + 'prospector.type': ['log'], }; expect(format(flattenedDocument, {})).toMatchInlineSnapshot(` -Array [ - Object { - "constant": "[iis][error] ", - }, - Object { - "field": "iis.error.remote_ip", - "highlights": Array [], - "value": "172.31.77.6", - }, - Object { - "constant": " \\"", - }, - Object { - "field": "iis.error.method", - "highlights": Array [], - "value": "GET", - }, - Object { - "constant": " ", - }, - Object { - "field": "iis.error.url", - "highlights": Array [], - "value": "/qos/1kbfile.txt", - }, - Object { - "constant": " HTTP/", - }, - Object { - "field": "iis.error.http_version", - "highlights": Array [], - "value": "1.1", - }, - Object { - "constant": "\\" ", - }, - Object { - "field": "iis.error.response_code", - "highlights": Array [], - "value": "503", - }, - Object { - "constant": " ", - }, - Object { - "field": "iis.error.reason_phrase", - "highlights": Array [], - "value": "ConnLimit", - }, -] -`); + Array [ + Object { + "constant": "[iis][error] ", + }, + Object { + "field": "iis.error.remote_ip", + "highlights": Array [], + "value": Array [ + "172.31.77.6", + ], + }, + Object { + "constant": " \\"", + }, + Object { + "field": "iis.error.method", + "highlights": Array [], + "value": Array [ + "GET", + ], + }, + Object { + "constant": " ", + }, + Object { + "field": "iis.error.url", + "highlights": Array [], + "value": Array [ + "/qos/1kbfile.txt", + ], + }, + Object { + "constant": " HTTP/", + }, + Object { + "field": "iis.error.http_version", + "highlights": Array [], + "value": Array [ + "1.1", + ], + }, + Object { + "constant": "\\" ", + }, + Object { + "field": "iis.error.response_code", + "highlights": Array [], + "value": Array [ + "503", + ], + }, + Object { + "constant": " ", + }, + Object { + "field": "iis.error.reason_phrase", + "highlights": Array [], + "value": Array [ + "ConnLimit", + ], + }, + ] + `); }); }); }); diff --git a/x-pack/plugins/infra/server/lib/domains/log_entries_domain/builtin_rules/filebeat_kafka.test.ts b/x-pack/plugins/infra/server/lib/domains/log_entries_domain/builtin_rules/filebeat_kafka.test.ts index 19cb5f6e31118..4ea3cec8e91f6 100644 --- a/x-pack/plugins/infra/server/lib/domains/log_entries_domain/builtin_rules/filebeat_kafka.test.ts +++ b/x-pack/plugins/infra/server/lib/domains/log_entries_domain/builtin_rules/filebeat_kafka.test.ts @@ -13,48 +13,54 @@ describe('Filebeat Rules', () => { describe('in ECS format', () => { test('kafka log', () => { const flattenedDocument = { - '@timestamp': '2017-08-04T10:48:21.063Z', - 'ecs.version': '1.0.0-beta2', - 'event.dataset': 'kafka.log', - 'event.module': 'kafka', - 'fileset.name': 'log', - 'input.type': 'log', - 'kafka.log.class': 'kafka.controller.KafkaController', - 'kafka.log.component': 'Controller 0', - 'log.level': 'INFO', - 'log.offset': 131, - message: '0 successfully elected as the controller', - 'service.type': 'kafka', + '@timestamp': ['2017-08-04T10:48:21.063Z'], + 'ecs.version': ['1.0.0-beta2'], + 'event.dataset': ['kafka.log'], + 'event.module': ['kafka'], + 'fileset.name': ['log'], + 'input.type': ['log'], + 'kafka.log.class': ['kafka.controller.KafkaController'], + 'kafka.log.component': ['Controller 0'], + 'log.level': ['INFO'], + 'log.offset': [131], + message: ['0 successfully elected as the controller'], + 'service.type': ['kafka'], }; expect(format(flattenedDocument, {})).toMatchInlineSnapshot(` -Array [ - Object { - "constant": "[", - }, - Object { - "field": "event.dataset", - "highlights": Array [], - "value": "kafka.log", - }, - Object { - "constant": "][", - }, - Object { - "field": "log.level", - "highlights": Array [], - "value": "INFO", - }, - Object { - "constant": "] ", - }, - Object { - "field": "message", - "highlights": Array [], - "value": "0 successfully elected as the controller", - }, -] -`); + Array [ + Object { + "constant": "[", + }, + Object { + "field": "event.dataset", + "highlights": Array [], + "value": Array [ + "kafka.log", + ], + }, + Object { + "constant": "][", + }, + Object { + "field": "log.level", + "highlights": Array [], + "value": Array [ + "INFO", + ], + }, + Object { + "constant": "] ", + }, + Object { + "field": "message", + "highlights": Array [], + "value": Array [ + "0 successfully elected as the controller", + ], + }, + ] + `); }); }); }); diff --git a/x-pack/plugins/infra/server/lib/domains/log_entries_domain/builtin_rules/filebeat_logstash.test.ts b/x-pack/plugins/infra/server/lib/domains/log_entries_domain/builtin_rules/filebeat_logstash.test.ts index edc534d9c345f..022ea4921d9ad 100644 --- a/x-pack/plugins/infra/server/lib/domains/log_entries_domain/builtin_rules/filebeat_logstash.test.ts +++ b/x-pack/plugins/infra/server/lib/domains/log_entries_domain/builtin_rules/filebeat_logstash.test.ts @@ -13,194 +13,256 @@ describe('Filebeat Rules', () => { describe('in ECS format', () => { test('logstash log', () => { const flattenedDocument = { - '@timestamp': '2017-10-23T14:20:12.046Z', - 'ecs.version': '1.0.0-beta2', - 'event.dataset': 'logstash.log', - 'event.module': 'logstash', - 'fileset.name': 'log', - 'input.type': 'log', - 'log.level': 'INFO', - 'log.offset': 0, - 'logstash.log.module': 'logstash.modules.scaffold', - message: + '@timestamp': ['2017-10-23T14:20:12.046Z'], + 'ecs.version': ['1.0.0-beta2'], + 'event.dataset': ['logstash.log'], + 'event.module': ['logstash'], + 'fileset.name': ['log'], + 'input.type': ['log'], + 'log.level': ['INFO'], + 'log.offset': [0], + 'logstash.log.module': ['logstash.modules.scaffold'], + message: [ 'Initializing module {:module_name=>"fb_apache", :directory=>"/usr/share/logstash/modules/fb_apache/configuration"}', - 'service.type': 'logstash', + ], + 'service.type': ['logstash'], }; expect(format(flattenedDocument, {})).toMatchInlineSnapshot(` -Array [ - Object { - "constant": "[", - }, - Object { - "field": "event.dataset", - "highlights": Array [], - "value": "logstash.log", - }, - Object { - "constant": "][", - }, - Object { - "field": "log.level", - "highlights": Array [], - "value": "INFO", - }, - Object { - "constant": "] ", - }, - Object { - "field": "message", - "highlights": Array [], - "value": "Initializing module {:module_name=>\\"fb_apache\\", :directory=>\\"/usr/share/logstash/modules/fb_apache/configuration\\"}", - }, -] -`); + Array [ + Object { + "constant": "[", + }, + Object { + "field": "event.dataset", + "highlights": Array [], + "value": Array [ + "logstash.log", + ], + }, + Object { + "constant": "][", + }, + Object { + "field": "log.level", + "highlights": Array [], + "value": Array [ + "INFO", + ], + }, + Object { + "constant": "] ", + }, + Object { + "field": "message", + "highlights": Array [], + "value": Array [ + "Initializing module {:module_name=>\\"fb_apache\\", :directory=>\\"/usr/share/logstash/modules/fb_apache/configuration\\"}", + ], + }, + ] + `); }); test('logstash slowlog', () => { const flattenedDocument = { - '@timestamp': '2017-10-30T09:57:58.243Z', - 'ecs.version': '1.0.0-beta2', - 'event.dataset': 'logstash.slowlog', - 'event.duration': 3027675106, - 'event.module': 'logstash', - 'fileset.name': 'slowlog', - 'input.type': 'log', - 'log.level': 'WARN', - 'log.offset': 0, - 'logstash.slowlog': { - event: - '"{\\"@version\\":\\"1\\",\\"@timestamp\\":\\"2017-10-30T13:57:55.130Z\\",\\"host\\":\\"sashimi\\",\\"sequence\\":0,\\"message\\":\\"Hello world!\\"}"', - module: 'slowlog.logstash.filters.sleep', - plugin_name: 'sleep', - plugin_params: - '{"time"=>3, "id"=>"e4e12a4e3082615c5427079bf4250dbfa338ebac10f8ea9912d7b98a14f56b8c"}', - plugin_type: 'filters', - took_in_millis: 3027, - }, - 'service.type': 'logstash', + '@timestamp': ['2017-10-30T09:57:58.243Z'], + 'ecs.version': ['1.0.0-beta2'], + 'event.dataset': ['logstash.slowlog'], + 'event.duration': [3027675106], + 'event.module': ['logstash'], + 'fileset.name': ['slowlog'], + 'input.type': ['log'], + 'log.level': ['WARN'], + 'log.offset': [0], + 'logstash.slowlog.event': [ + '"{\\"@version\\":\\"1\\",\\"@timestamp\\":\\"2017-10-30T13:57:55.130Z\\",\\"host\\":\\"sashimi\\",\\"sequence\\":0,\\"message\\":\\"Hello world!\\"}"', + ], + 'logstash.slowlog.module': ['slowlog.logstash.filters.sleep'], + 'logstash.slowlog.plugin_name': ['sleep'], + 'logstash.slowlog.plugin_params': [ + '{"time"=>3, "id"=>"e4e12a4e3082615c5427079bf4250dbfa338ebac10f8ea9912d7b98a14f56b8c"}', + ], + 'logstash.slowlog.plugin_type': ['filters'], + 'logstash.slowlog.took_in_millis': [3027], + 'service.type': ['logstash'], }; expect(format(flattenedDocument, {})).toMatchInlineSnapshot(` -Array [ - Object { - "constant": "[Logstash][", - }, - Object { - "field": "log.level", - "highlights": Array [], - "value": "WARN", - }, - Object { - "constant": "] ", - }, - Object { - "field": "logstash.slowlog", - "highlights": Array [], - "value": "{\\"event\\":\\"\\\\\\"{\\\\\\\\\\\\\\"@version\\\\\\\\\\\\\\":\\\\\\\\\\\\\\"1\\\\\\\\\\\\\\",\\\\\\\\\\\\\\"@timestamp\\\\\\\\\\\\\\":\\\\\\\\\\\\\\"2017-10-30T13:57:55.130Z\\\\\\\\\\\\\\",\\\\\\\\\\\\\\"host\\\\\\\\\\\\\\":\\\\\\\\\\\\\\"sashimi\\\\\\\\\\\\\\",\\\\\\\\\\\\\\"sequence\\\\\\\\\\\\\\":0,\\\\\\\\\\\\\\"message\\\\\\\\\\\\\\":\\\\\\\\\\\\\\"Hello world!\\\\\\\\\\\\\\"}\\\\\\"\\",\\"module\\":\\"slowlog.logstash.filters.sleep\\",\\"plugin_name\\":\\"sleep\\",\\"plugin_params\\":\\"{\\\\\\"time\\\\\\"=>3, \\\\\\"id\\\\\\"=>\\\\\\"e4e12a4e3082615c5427079bf4250dbfa338ebac10f8ea9912d7b98a14f56b8c\\\\\\"}\\",\\"plugin_type\\":\\"filters\\",\\"took_in_millis\\":3027}", - }, -] -`); + Array [ + Object { + "constant": "[Logstash][", + }, + Object { + "field": "log.level", + "highlights": Array [], + "value": Array [ + "WARN", + ], + }, + Object { + "constant": "] ", + }, + Object { + "field": "logstash.slowlog.event", + "highlights": Array [], + "value": Array [ + "\\"{\\\\\\"@version\\\\\\":\\\\\\"1\\\\\\",\\\\\\"@timestamp\\\\\\":\\\\\\"2017-10-30T13:57:55.130Z\\\\\\",\\\\\\"host\\\\\\":\\\\\\"sashimi\\\\\\",\\\\\\"sequence\\\\\\":0,\\\\\\"message\\\\\\":\\\\\\"Hello world!\\\\\\"}\\"", + ], + }, + Object { + "field": "logstash.slowlog.module", + "highlights": Array [], + "value": Array [ + "slowlog.logstash.filters.sleep", + ], + }, + Object { + "field": "logstash.slowlog.plugin_name", + "highlights": Array [], + "value": Array [ + "sleep", + ], + }, + Object { + "field": "logstash.slowlog.plugin_params", + "highlights": Array [], + "value": Array [ + "{\\"time\\"=>3, \\"id\\"=>\\"e4e12a4e3082615c5427079bf4250dbfa338ebac10f8ea9912d7b98a14f56b8c\\"}", + ], + }, + Object { + "field": "logstash.slowlog.plugin_type", + "highlights": Array [], + "value": Array [ + "filters", + ], + }, + Object { + "field": "logstash.slowlog.took_in_millis", + "highlights": Array [], + "value": Array [ + 3027, + ], + }, + ] + `); }); }); describe('in pre-ECS format', () => { test('logstash log', () => { const flattenedDocument = { - '@timestamp': '2017-10-23T14:20:12.046Z', - 'event.dataset': 'logstash.log', - 'fileset.module': 'logstash', - 'fileset.name': 'log', - 'input.type': 'log', - 'logstash.log.level': 'INFO', - 'logstash.log.message': + '@timestamp': ['2017-10-23T14:20:12.046Z'], + 'event.dataset': ['logstash.log'], + 'fileset.module': ['logstash'], + 'fileset.name': ['log'], + 'input.type': ['log'], + 'logstash.log.level': ['INFO'], + 'logstash.log.message': [ 'Initializing module {:module_name=>"fb_apache", :directory=>"/usr/share/logstash/modules/fb_apache/configuration"}', - 'logstash.log.module': 'logstash.modules.scaffold', - offset: 0, - 'prospector.type': 'log', + ], + 'logstash.log.module': ['logstash.modules.scaffold'], + offset: [0], + 'prospector.type': ['log'], }; expect(format(flattenedDocument, {})).toMatchInlineSnapshot(` -Array [ - Object { - "constant": "[Logstash][", - }, - Object { - "field": "logstash.log.level", - "highlights": Array [], - "value": "INFO", - }, - Object { - "constant": "] ", - }, - Object { - "field": "logstash.log.module", - "highlights": Array [], - "value": "logstash.modules.scaffold", - }, - Object { - "constant": " - ", - }, - Object { - "field": "logstash.log.message", - "highlights": Array [], - "value": "Initializing module {:module_name=>\\"fb_apache\\", :directory=>\\"/usr/share/logstash/modules/fb_apache/configuration\\"}", - }, -] -`); + Array [ + Object { + "constant": "[Logstash][", + }, + Object { + "field": "logstash.log.level", + "highlights": Array [], + "value": Array [ + "INFO", + ], + }, + Object { + "constant": "] ", + }, + Object { + "field": "logstash.log.module", + "highlights": Array [], + "value": Array [ + "logstash.modules.scaffold", + ], + }, + Object { + "constant": " - ", + }, + Object { + "field": "logstash.log.message", + "highlights": Array [], + "value": Array [ + "Initializing module {:module_name=>\\"fb_apache\\", :directory=>\\"/usr/share/logstash/modules/fb_apache/configuration\\"}", + ], + }, + ] + `); }); test('logstash slowlog', () => { const flattenedDocument = { - '@timestamp': '2017-10-30T09:57:58.243Z', - 'event.dataset': 'logstash.slowlog', - 'fileset.module': 'logstash', - 'fileset.name': 'slowlog', - 'input.type': 'log', - 'logstash.slowlog.event': + '@timestamp': ['2017-10-30T09:57:58.243Z'], + 'event.dataset': ['logstash.slowlog'], + 'fileset.module': ['logstash'], + 'fileset.name': ['slowlog'], + 'input.type': ['log'], + 'logstash.slowlog.event': [ '"{\\"@version\\":\\"1\\",\\"@timestamp\\":\\"2017-10-30T13:57:55.130Z\\",\\"host\\":\\"sashimi\\",\\"sequence\\":0,\\"message\\":\\"Hello world!\\"}"', - 'logstash.slowlog.level': 'WARN', - 'logstash.slowlog.message': + ], + 'logstash.slowlog.level': ['WARN'], + 'logstash.slowlog.message': [ 'event processing time {:plugin_params=>{"time"=>3, "id"=>"e4e12a4e3082615c5427079bf4250dbfa338ebac10f8ea9912d7b98a14f56b8c"}, :took_in_nanos=>3027675106, :took_in_millis=>3027, :event=>"{\\"@version\\":\\"1\\",\\"@timestamp\\":\\"2017-10-30T13:57:55.130Z\\",\\"host\\":\\"sashimi\\",\\"sequence\\":0,\\"message\\":\\"Hello world!\\"}"}', - 'logstash.slowlog.module': 'slowlog.logstash.filters.sleep', - 'logstash.slowlog.plugin_name': 'sleep', - 'logstash.slowlog.plugin_params': + ], + 'logstash.slowlog.module': ['slowlog.logstash.filters.sleep'], + 'logstash.slowlog.plugin_name': ['sleep'], + 'logstash.slowlog.plugin_params': [ '{"time"=>3, "id"=>"e4e12a4e3082615c5427079bf4250dbfa338ebac10f8ea9912d7b98a14f56b8c"}', - 'logstash.slowlog.plugin_type': 'filters', - 'logstash.slowlog.took_in_millis': 3027, - 'logstash.slowlog.took_in_nanos': 3027675106, - offset: 0, - 'prospector.type': 'log', + ], + 'logstash.slowlog.plugin_type': ['filters'], + 'logstash.slowlog.took_in_millis': [3027], + 'logstash.slowlog.took_in_nanos': [3027675106], + offset: [0], + 'prospector.type': ['log'], }; expect(format(flattenedDocument, {})).toMatchInlineSnapshot(` -Array [ - Object { - "constant": "[Logstash][", - }, - Object { - "field": "logstash.slowlog.level", - "highlights": Array [], - "value": "WARN", - }, - Object { - "constant": "] ", - }, - Object { - "field": "logstash.slowlog.module", - "highlights": Array [], - "value": "slowlog.logstash.filters.sleep", - }, - Object { - "constant": " - ", - }, - Object { - "field": "logstash.slowlog.message", - "highlights": Array [], - "value": "event processing time {:plugin_params=>{\\"time\\"=>3, \\"id\\"=>\\"e4e12a4e3082615c5427079bf4250dbfa338ebac10f8ea9912d7b98a14f56b8c\\"}, :took_in_nanos=>3027675106, :took_in_millis=>3027, :event=>\\"{\\\\\\"@version\\\\\\":\\\\\\"1\\\\\\",\\\\\\"@timestamp\\\\\\":\\\\\\"2017-10-30T13:57:55.130Z\\\\\\",\\\\\\"host\\\\\\":\\\\\\"sashimi\\\\\\",\\\\\\"sequence\\\\\\":0,\\\\\\"message\\\\\\":\\\\\\"Hello world!\\\\\\"}\\"}", - }, -] -`); + Array [ + Object { + "constant": "[Logstash][", + }, + Object { + "field": "logstash.slowlog.level", + "highlights": Array [], + "value": Array [ + "WARN", + ], + }, + Object { + "constant": "] ", + }, + Object { + "field": "logstash.slowlog.module", + "highlights": Array [], + "value": Array [ + "slowlog.logstash.filters.sleep", + ], + }, + Object { + "constant": " - ", + }, + Object { + "field": "logstash.slowlog.message", + "highlights": Array [], + "value": Array [ + "event processing time {:plugin_params=>{\\"time\\"=>3, \\"id\\"=>\\"e4e12a4e3082615c5427079bf4250dbfa338ebac10f8ea9912d7b98a14f56b8c\\"}, :took_in_nanos=>3027675106, :took_in_millis=>3027, :event=>\\"{\\\\\\"@version\\\\\\":\\\\\\"1\\\\\\",\\\\\\"@timestamp\\\\\\":\\\\\\"2017-10-30T13:57:55.130Z\\\\\\",\\\\\\"host\\\\\\":\\\\\\"sashimi\\\\\\",\\\\\\"sequence\\\\\\":0,\\\\\\"message\\\\\\":\\\\\\"Hello world!\\\\\\"}\\"}", + ], + }, + ] + `); }); }); }); diff --git a/x-pack/plugins/infra/server/lib/domains/log_entries_domain/builtin_rules/filebeat_logstash.ts b/x-pack/plugins/infra/server/lib/domains/log_entries_domain/builtin_rules/filebeat_logstash.ts index 39b2058ca7cdb..9471465183670 100644 --- a/x-pack/plugins/infra/server/lib/domains/log_entries_domain/builtin_rules/filebeat_logstash.ts +++ b/x-pack/plugins/infra/server/lib/domains/log_entries_domain/builtin_rules/filebeat_logstash.ts @@ -34,7 +34,7 @@ export const filebeatLogstashRules = [ { // ECS when: { - exists: ['ecs.version', 'logstash.slowlog'], + all: [{ exists: ['ecs.version'] }, { existsPrefix: ['logstash.slowlog'] }], }, format: [ { @@ -47,7 +47,7 @@ export const filebeatLogstashRules = [ constant: '] ', }, { - field: 'logstash.slowlog', + fieldsPrefix: 'logstash.slowlog', }, ], }, diff --git a/x-pack/plugins/infra/server/lib/domains/log_entries_domain/builtin_rules/filebeat_mongodb.test.ts b/x-pack/plugins/infra/server/lib/domains/log_entries_domain/builtin_rules/filebeat_mongodb.test.ts index 3df7ebec241cc..108ec29f550d2 100644 --- a/x-pack/plugins/infra/server/lib/domains/log_entries_domain/builtin_rules/filebeat_mongodb.test.ts +++ b/x-pack/plugins/infra/server/lib/domains/log_entries_domain/builtin_rules/filebeat_mongodb.test.ts @@ -13,40 +13,45 @@ describe('Filebeat Rules', () => { describe('in pre-ECS format', () => { test('mongodb log', () => { const flattenedDocument = { - '@timestamp': '2018-02-05T12:44:56.677Z', - 'event.dataset': 'mongodb.log', - 'fileset.module': 'mongodb', - 'fileset.name': 'log', - 'input.type': 'log', - 'mongodb.log.component': 'STORAGE', - 'mongodb.log.context': 'initandlisten', - 'mongodb.log.message': + '@timestamp': ['2018-02-05T12:44:56.677Z'], + 'event.dataset': ['mongodb.log'], + 'fileset.module': ['mongodb'], + 'fileset.name': ['log'], + 'input.type': ['log'], + 'mongodb.log.component': ['STORAGE'], + 'mongodb.log.context': ['initandlisten'], + 'mongodb.log.message': [ 'wiredtiger_open config: create,cache_size=8G,session_max=20000,eviction=(threads_max=4),config_base=false,statistics=(fast),log=(enabled=true,archive=true,path=journal,compressor=snappy),file_manager=(close_idle_time=100000),checkpoint=(wait=60,log_size=2GB),statistics_log=(wait=0),', - 'mongodb.log.severity': 'I', - offset: 281, - 'prospector.type': 'log', + ], + 'mongodb.log.severity': ['I'], + offset: [281], + 'prospector.type': ['log'], }; expect(format(flattenedDocument, {})).toMatchInlineSnapshot(` -Array [ - Object { - "constant": "[MongoDB][", - }, - Object { - "field": "mongodb.log.component", - "highlights": Array [], - "value": "STORAGE", - }, - Object { - "constant": "] ", - }, - Object { - "field": "mongodb.log.message", - "highlights": Array [], - "value": "wiredtiger_open config: create,cache_size=8G,session_max=20000,eviction=(threads_max=4),config_base=false,statistics=(fast),log=(enabled=true,archive=true,path=journal,compressor=snappy),file_manager=(close_idle_time=100000),checkpoint=(wait=60,log_size=2GB),statistics_log=(wait=0),", - }, -] -`); + Array [ + Object { + "constant": "[MongoDB][", + }, + Object { + "field": "mongodb.log.component", + "highlights": Array [], + "value": Array [ + "STORAGE", + ], + }, + Object { + "constant": "] ", + }, + Object { + "field": "mongodb.log.message", + "highlights": Array [], + "value": Array [ + "wiredtiger_open config: create,cache_size=8G,session_max=20000,eviction=(threads_max=4),config_base=false,statistics=(fast),log=(enabled=true,archive=true,path=journal,compressor=snappy),file_manager=(close_idle_time=100000),checkpoint=(wait=60,log_size=2GB),statistics_log=(wait=0),", + ], + }, + ] + `); }); }); }); diff --git a/x-pack/plugins/infra/server/lib/domains/log_entries_domain/builtin_rules/filebeat_mysql.test.ts b/x-pack/plugins/infra/server/lib/domains/log_entries_domain/builtin_rules/filebeat_mysql.test.ts index 0329d53f92d08..99e83e9602480 100644 --- a/x-pack/plugins/infra/server/lib/domains/log_entries_domain/builtin_rules/filebeat_mysql.test.ts +++ b/x-pack/plugins/infra/server/lib/domains/log_entries_domain/builtin_rules/filebeat_mysql.test.ts @@ -13,139 +13,158 @@ describe('Filebeat Rules', () => { describe('in ECS format', () => { test('mysql error log', () => { const flattenedDocument = { - '@timestamp': '2016-12-09T12:08:33.335Z', - 'ecs.version': '1.0.0-beta2', - 'event.dataset': 'mysql.error', - 'event.module': 'mysql', - 'fileset.name': 'error', - 'input.type': 'log', - 'log.level': 'Warning', - 'log.offset': 92, - message: + '@timestamp': ['2016-12-09T12:08:33.335Z'], + 'ecs.version': ['1.0.0-beta2'], + 'event.dataset': ['mysql.error'], + 'event.module': ['mysql'], + 'fileset.name': ['error'], + 'input.type': ['log'], + 'log.level': ['Warning'], + 'log.offset': [92], + message: [ 'TIMESTAMP with implicit DEFAULT value is deprecated. Please use --explicit_defaults_for_timestamp server option (see documentation for more details).', - 'mysql.thread_id': 0, - 'service.type': 'mysql', + ], + 'mysql.thread_id': [0], + 'service.type': ['mysql'], }; expect(format(flattenedDocument, {})).toMatchInlineSnapshot(` -Array [ - Object { - "constant": "[", - }, - Object { - "field": "event.dataset", - "highlights": Array [], - "value": "mysql.error", - }, - Object { - "constant": "][", - }, - Object { - "field": "log.level", - "highlights": Array [], - "value": "Warning", - }, - Object { - "constant": "] ", - }, - Object { - "field": "message", - "highlights": Array [], - "value": "TIMESTAMP with implicit DEFAULT value is deprecated. Please use --explicit_defaults_for_timestamp server option (see documentation for more details).", - }, -] -`); + Array [ + Object { + "constant": "[", + }, + Object { + "field": "event.dataset", + "highlights": Array [], + "value": Array [ + "mysql.error", + ], + }, + Object { + "constant": "][", + }, + Object { + "field": "log.level", + "highlights": Array [], + "value": Array [ + "Warning", + ], + }, + Object { + "constant": "] ", + }, + Object { + "field": "message", + "highlights": Array [], + "value": Array [ + "TIMESTAMP with implicit DEFAULT value is deprecated. Please use --explicit_defaults_for_timestamp server option (see documentation for more details).", + ], + }, + ] + `); }); test('mysql slowlog', () => { const flattenedDocument = { - '@timestamp': '2018-08-07T08:27:47.000Z', - 'ecs.version': '1.0.0-beta2', - 'event.dataset': 'mysql.slowlog', - 'event.duration': 4071491000, - 'event.module': 'mysql', - 'fileset.name': 'slowlog', - 'input.type': 'log', + '@timestamp': ['2018-08-07T08:27:47.000Z'], + 'ecs.version': ['1.0.0-beta2'], + 'event.dataset': ['mysql.slowlog'], + 'event.duration': [4071491000], + 'event.module': ['mysql'], + 'fileset.name': ['slowlog'], + 'input.type': ['log'], 'log.flags': ['multiline'], - 'log.offset': 526, - 'mysql.slowlog.current_user': 'appuser', - 'mysql.slowlog.lock_time.sec': 0.000212, - 'mysql.slowlog.query': + 'log.offset': [526], + 'mysql.slowlog.current_user': ['appuser'], + 'mysql.slowlog.lock_time.sec': [0.000212], + 'mysql.slowlog.query': [ 'SELECT mcu.mcu_guid, mcu.cus_guid, mcu.mcu_url, mcu.mcu_crawlelements, mcu.mcu_order, GROUP_CONCAT(mca.mca_guid SEPARATOR ";") as mca_guid\n FROM kat_mailcustomerurl mcu, kat_customer cus, kat_mailcampaign mca\n WHERE cus.cus_guid = mcu.cus_guid\n AND cus.pro_code = \'CYB\'\n AND cus.cus_offline = 0\n AND mca.cus_guid = cus.cus_guid\n AND (mcu.mcu_date IS NULL OR mcu.mcu_date < CURDATE())\n AND mcu.mcu_crawlelements IS NOT NULL\n GROUP BY mcu.mcu_guid\n ORDER BY mcu.mcu_order ASC\n LIMIT 1000;', - 'mysql.slowlog.rows_examined': 1489615, - 'mysql.slowlog.rows_sent': 1000, - 'mysql.thread_id': 10997316, - 'service.type': 'mysql', - 'source.domain': 'apphost', - 'source.ip': '1.1.1.1', - 'user.name': 'appuser', + ], + 'mysql.slowlog.rows_examined': [1489615], + 'mysql.slowlog.rows_sent': [1000], + 'mysql.thread_id': [10997316], + 'service.type': ['mysql'], + 'source.domain': ['apphost'], + 'source.ip': ['1.1.1.1'], + 'user.name': ['appuser'], }; expect(format(flattenedDocument, {})).toMatchInlineSnapshot(` -Array [ - Object { - "constant": "[MySQL][slowlog] ", - }, - Object { - "field": "user.name", - "highlights": Array [], - "value": "appuser", - }, - Object { - "constant": "@", - }, - Object { - "field": "source.domain", - "highlights": Array [], - "value": "apphost", - }, - Object { - "constant": " [", - }, - Object { - "field": "source.ip", - "highlights": Array [], - "value": "1.1.1.1", - }, - Object { - "constant": "] ", - }, - Object { - "constant": " - ", - }, - Object { - "field": "event.duration", - "highlights": Array [], - "value": "4071491000", - }, - Object { - "constant": " ns - ", - }, - Object { - "field": "mysql.slowlog.query", - "highlights": Array [], - "value": "SELECT mcu.mcu_guid, mcu.cus_guid, mcu.mcu_url, mcu.mcu_crawlelements, mcu.mcu_order, GROUP_CONCAT(mca.mca_guid SEPARATOR \\";\\") as mca_guid - FROM kat_mailcustomerurl mcu, kat_customer cus, kat_mailcampaign mca - WHERE cus.cus_guid = mcu.cus_guid - AND cus.pro_code = 'CYB' - AND cus.cus_offline = 0 - AND mca.cus_guid = cus.cus_guid - AND (mcu.mcu_date IS NULL OR mcu.mcu_date < CURDATE()) - AND mcu.mcu_crawlelements IS NOT NULL - GROUP BY mcu.mcu_guid - ORDER BY mcu.mcu_order ASC - LIMIT 1000;", - }, -] -`); + Array [ + Object { + "constant": "[MySQL][slowlog] ", + }, + Object { + "field": "user.name", + "highlights": Array [], + "value": Array [ + "appuser", + ], + }, + Object { + "constant": "@", + }, + Object { + "field": "source.domain", + "highlights": Array [], + "value": Array [ + "apphost", + ], + }, + Object { + "constant": " [", + }, + Object { + "field": "source.ip", + "highlights": Array [], + "value": Array [ + "1.1.1.1", + ], + }, + Object { + "constant": "] ", + }, + Object { + "constant": " - ", + }, + Object { + "field": "event.duration", + "highlights": Array [], + "value": Array [ + 4071491000, + ], + }, + Object { + "constant": " ns - ", + }, + Object { + "field": "mysql.slowlog.query", + "highlights": Array [], + "value": Array [ + "SELECT mcu.mcu_guid, mcu.cus_guid, mcu.mcu_url, mcu.mcu_crawlelements, mcu.mcu_order, GROUP_CONCAT(mca.mca_guid SEPARATOR \\";\\") as mca_guid + FROM kat_mailcustomerurl mcu, kat_customer cus, kat_mailcampaign mca + WHERE cus.cus_guid = mcu.cus_guid + AND cus.pro_code = 'CYB' + AND cus.cus_offline = 0 + AND mca.cus_guid = cus.cus_guid + AND (mcu.mcu_date IS NULL OR mcu.mcu_date < CURDATE()) + AND mcu.mcu_crawlelements IS NOT NULL + GROUP BY mcu.mcu_guid + ORDER BY mcu.mcu_order ASC + LIMIT 1000;", + ], + }, + ] + `); }); }); describe('in pre-ECS format', () => { test('mysql error log', () => { const errorDoc = { - 'mysql.error.message': + 'mysql.error.message': [ "Access denied for user 'petclinicdd'@'47.153.152.234' (using password: YES)", + ], }; const message = format(errorDoc, {}); expect(message).toEqual([ @@ -155,18 +174,18 @@ Array [ { field: 'mysql.error.message', highlights: [], - value: "Access denied for user 'petclinicdd'@'47.153.152.234' (using password: YES)", + value: ["Access denied for user 'petclinicdd'@'47.153.152.234' (using password: YES)"], }, ]); }); test('mysql slow log', () => { const errorDoc = { - 'mysql.slowlog.query': 'select * from hosts', - 'mysql.slowlog.query_time.sec': 5, - 'mysql.slowlog.user': 'admin', - 'mysql.slowlog.ip': '192.168.1.42', - 'mysql.slowlog.host': 'webserver-01', + 'mysql.slowlog.query': ['select * from hosts'], + 'mysql.slowlog.query_time.sec': [5], + 'mysql.slowlog.user': ['admin'], + 'mysql.slowlog.ip': ['192.168.1.42'], + 'mysql.slowlog.host': ['webserver-01'], }; const message = format(errorDoc, {}); expect(message).toEqual([ @@ -176,7 +195,7 @@ Array [ { field: 'mysql.slowlog.user', highlights: [], - value: 'admin', + value: ['admin'], }, { constant: '@', @@ -184,7 +203,7 @@ Array [ { field: 'mysql.slowlog.host', highlights: [], - value: 'webserver-01', + value: ['webserver-01'], }, { constant: ' [', @@ -192,7 +211,7 @@ Array [ { field: 'mysql.slowlog.ip', highlights: [], - value: '192.168.1.42', + value: ['192.168.1.42'], }, { constant: '] ', @@ -203,7 +222,7 @@ Array [ { field: 'mysql.slowlog.query_time.sec', highlights: [], - value: '5', + value: [5], }, { constant: ' s - ', @@ -211,7 +230,7 @@ Array [ { field: 'mysql.slowlog.query', highlights: [], - value: 'select * from hosts', + value: ['select * from hosts'], }, ]); }); diff --git a/x-pack/plugins/infra/server/lib/domains/log_entries_domain/builtin_rules/filebeat_nginx.test.ts b/x-pack/plugins/infra/server/lib/domains/log_entries_domain/builtin_rules/filebeat_nginx.test.ts index 0bc8ae1e907b8..62f48007eb0e3 100644 --- a/x-pack/plugins/infra/server/lib/domains/log_entries_domain/builtin_rules/filebeat_nginx.test.ts +++ b/x-pack/plugins/infra/server/lib/domains/log_entries_domain/builtin_rules/filebeat_nginx.test.ts @@ -13,252 +13,293 @@ describe('Filebeat Rules', () => { describe('in ECS format', () => { test('Nginx Access', () => { const flattenedDocument = { - '@timestamp': '2017-05-29T19:02:48.000Z', - 'ecs.version': '1.0.0-beta2', - 'event.dataset': 'nginx.access', - 'event.module': 'nginx', - 'fileset.name': 'access', - 'http.request.method': 'GET', - 'http.request.referrer': '-', - 'http.response.body.bytes': 612, - 'http.response.status_code': 404, - 'http.version': '1.1', - 'input.type': 'log', - 'log.offset': 183, - 'service.type': 'nginx', - 'source.ip': '172.17.0.1', - 'url.original': '/stringpatch', - 'user.name': '-', - 'user_agent.device': 'Other', - 'user_agent.major': '15', - 'user_agent.minor': '0', - 'user_agent.name': 'Firefox Alpha', - 'user_agent.original': + '@timestamp': ['2017-05-29T19:02:48.000Z'], + 'ecs.version': ['1.0.0-beta2'], + 'event.dataset': ['nginx.access'], + 'event.module': ['nginx'], + 'fileset.name': ['access'], + 'http.request.method': ['GET'], + 'http.request.referrer': ['-'], + 'http.response.body.bytes': [612], + 'http.response.status_code': [404], + 'http.version': ['1.1'], + 'input.type': ['log'], + 'log.offset': [183], + 'service.type': ['nginx'], + 'source.ip': ['172.17.0.1'], + 'url.original': ['/stringpatch'], + 'user.name': ['-'], + 'user_agent.device': ['Other'], + 'user_agent.major': ['15'], + 'user_agent.minor': ['0'], + 'user_agent.name': ['Firefox Alpha'], + 'user_agent.original': [ 'Mozilla/5.0 (Windows NT 6.1; rv:15.0) Gecko/20120716 Firefox/15.0a2', - 'user_agent.os.full_name': 'Windows 7', - 'user_agent.os.name': 'Windows 7', - 'user_agent.patch': 'a2', + ], + 'user_agent.os.full_name': ['Windows 7'], + 'user_agent.os.name': ['Windows 7'], + 'user_agent.patch': ['a2'], }; expect(format(flattenedDocument, {})).toMatchInlineSnapshot(` -Array [ - Object { - "constant": "[", - }, - Object { - "field": "event.module", - "highlights": Array [], - "value": "nginx", - }, - Object { - "constant": "][access] ", - }, - Object { - "field": "source.ip", - "highlights": Array [], - "value": "172.17.0.1", - }, - Object { - "constant": " ", - }, - Object { - "field": "user.name", - "highlights": Array [], - "value": "-", - }, - Object { - "constant": " \\"", - }, - Object { - "field": "http.request.method", - "highlights": Array [], - "value": "GET", - }, - Object { - "constant": " ", - }, - Object { - "field": "url.original", - "highlights": Array [], - "value": "/stringpatch", - }, - Object { - "constant": " HTTP/", - }, - Object { - "field": "http.version", - "highlights": Array [], - "value": "1.1", - }, - Object { - "constant": "\\" ", - }, - Object { - "field": "http.response.status_code", - "highlights": Array [], - "value": "404", - }, - Object { - "constant": " ", - }, - Object { - "field": "http.response.body.bytes", - "highlights": Array [], - "value": "612", - }, -] -`); + Array [ + Object { + "constant": "[", + }, + Object { + "field": "event.module", + "highlights": Array [], + "value": Array [ + "nginx", + ], + }, + Object { + "constant": "][access] ", + }, + Object { + "field": "source.ip", + "highlights": Array [], + "value": Array [ + "172.17.0.1", + ], + }, + Object { + "constant": " ", + }, + Object { + "field": "user.name", + "highlights": Array [], + "value": Array [ + "-", + ], + }, + Object { + "constant": " \\"", + }, + Object { + "field": "http.request.method", + "highlights": Array [], + "value": Array [ + "GET", + ], + }, + Object { + "constant": " ", + }, + Object { + "field": "url.original", + "highlights": Array [], + "value": Array [ + "/stringpatch", + ], + }, + Object { + "constant": " HTTP/", + }, + Object { + "field": "http.version", + "highlights": Array [], + "value": Array [ + "1.1", + ], + }, + Object { + "constant": "\\" ", + }, + Object { + "field": "http.response.status_code", + "highlights": Array [], + "value": Array [ + 404, + ], + }, + Object { + "constant": " ", + }, + Object { + "field": "http.response.body.bytes", + "highlights": Array [], + "value": Array [ + 612, + ], + }, + ] + `); }); test('Nginx Error', () => { const flattenedDocument = { - '@timestamp': '2016-10-25T14:49:34.000Z', - 'ecs.version': '1.0.0-beta2', - 'event.dataset': 'nginx.error', - 'event.module': 'nginx', - 'fileset.name': 'error', - 'input.type': 'log', - 'log.level': 'error', - 'log.offset': 0, - message: + '@timestamp': ['2016-10-25T14:49:34.000Z'], + 'ecs.version': ['1.0.0-beta2'], + 'event.dataset': ['nginx.error'], + 'event.module': ['nginx'], + 'fileset.name': ['error'], + 'input.type': ['log'], + 'log.level': ['error'], + 'log.offset': [0], + message: [ 'open() "/usr/local/Cellar/nginx/1.10.2_1/html/favicon.ico" failed (2: No such file or directory), client: 127.0.0.1, server: localhost, request: "GET /favicon.ico HTTP/1.1", host: "localhost:8080", referrer: "http://localhost:8080/"', - 'nginx.error.connection_id': 1, - 'process.pid': 54053, - 'process.thread.id': 0, - 'service.type': 'nginx', + ], + 'nginx.error.connection_id': [1], + 'process.pid': [54053], + 'process.thread.id': [0], + 'service.type': ['nginx'], }; expect(format(flattenedDocument, {})).toMatchInlineSnapshot(` -Array [ - Object { - "constant": "[nginx]", - }, - Object { - "constant": "[", - }, - Object { - "field": "log.level", - "highlights": Array [], - "value": "error", - }, - Object { - "constant": "] ", - }, - Object { - "field": "message", - "highlights": Array [], - "value": "open() \\"/usr/local/Cellar/nginx/1.10.2_1/html/favicon.ico\\" failed (2: No such file or directory), client: 127.0.0.1, server: localhost, request: \\"GET /favicon.ico HTTP/1.1\\", host: \\"localhost:8080\\", referrer: \\"http://localhost:8080/\\"", - }, -] -`); + Array [ + Object { + "constant": "[nginx]", + }, + Object { + "constant": "[", + }, + Object { + "field": "log.level", + "highlights": Array [], + "value": Array [ + "error", + ], + }, + Object { + "constant": "] ", + }, + Object { + "field": "message", + "highlights": Array [], + "value": Array [ + "open() \\"/usr/local/Cellar/nginx/1.10.2_1/html/favicon.ico\\" failed (2: No such file or directory), client: 127.0.0.1, server: localhost, request: \\"GET /favicon.ico HTTP/1.1\\", host: \\"localhost:8080\\", referrer: \\"http://localhost:8080/\\"", + ], + }, + ] + `); }); }); describe('in pre-ECS format', () => { test('Nginx Access', () => { const flattenedDocument = { - 'nginx.access': true, - 'nginx.access.remote_ip': '192.168.1.42', - 'nginx.access.user_name': 'admin', - 'nginx.access.method': 'GET', - 'nginx.access.url': '/faq', - 'nginx.access.http_version': '1.1', - 'nginx.access.body_sent.bytes': 1024, - 'nginx.access.response_code': 200, + 'nginx.access': [true], + 'nginx.access.remote_ip': ['192.168.1.42'], + 'nginx.access.user_name': ['admin'], + 'nginx.access.method': ['GET'], + 'nginx.access.url': ['/faq'], + 'nginx.access.http_version': ['1.1'], + 'nginx.access.body_sent.bytes': [1024], + 'nginx.access.response_code': [200], }; expect(format(flattenedDocument, {})).toMatchInlineSnapshot(` -Array [ - Object { - "constant": "[nginx][access] ", - }, - Object { - "field": "nginx.access.remote_ip", - "highlights": Array [], - "value": "192.168.1.42", - }, - Object { - "constant": " ", - }, - Object { - "field": "nginx.access.user_name", - "highlights": Array [], - "value": "admin", - }, - Object { - "constant": " \\"", - }, - Object { - "field": "nginx.access.method", - "highlights": Array [], - "value": "GET", - }, - Object { - "constant": " ", - }, - Object { - "field": "nginx.access.url", - "highlights": Array [], - "value": "/faq", - }, - Object { - "constant": " HTTP/", - }, - Object { - "field": "nginx.access.http_version", - "highlights": Array [], - "value": "1.1", - }, - Object { - "constant": "\\" ", - }, - Object { - "field": "nginx.access.response_code", - "highlights": Array [], - "value": "200", - }, - Object { - "constant": " ", - }, - Object { - "field": "nginx.access.body_sent.bytes", - "highlights": Array [], - "value": "1024", - }, -] -`); + Array [ + Object { + "constant": "[nginx][access] ", + }, + Object { + "field": "nginx.access.remote_ip", + "highlights": Array [], + "value": Array [ + "192.168.1.42", + ], + }, + Object { + "constant": " ", + }, + Object { + "field": "nginx.access.user_name", + "highlights": Array [], + "value": Array [ + "admin", + ], + }, + Object { + "constant": " \\"", + }, + Object { + "field": "nginx.access.method", + "highlights": Array [], + "value": Array [ + "GET", + ], + }, + Object { + "constant": " ", + }, + Object { + "field": "nginx.access.url", + "highlights": Array [], + "value": Array [ + "/faq", + ], + }, + Object { + "constant": " HTTP/", + }, + Object { + "field": "nginx.access.http_version", + "highlights": Array [], + "value": Array [ + "1.1", + ], + }, + Object { + "constant": "\\" ", + }, + Object { + "field": "nginx.access.response_code", + "highlights": Array [], + "value": Array [ + 200, + ], + }, + Object { + "constant": " ", + }, + Object { + "field": "nginx.access.body_sent.bytes", + "highlights": Array [], + "value": Array [ + 1024, + ], + }, + ] + `); }); test('Nginx Error', () => { const flattenedDocument = { - 'nginx.error.message': + 'nginx.error.message': [ 'connect() failed (111: Connection refused) while connecting to upstream, client: 127.0.0.1, server: localhost, request: "GET /php-status?json= HTTP/1.1", upstream: "fastcgi://[::1]:9000", host: "localhost"', - 'nginx.error.level': 'error', + ], + 'nginx.error.level': ['error'], }; expect(format(flattenedDocument, {})).toMatchInlineSnapshot(` -Array [ - Object { - "constant": "[nginx]", - }, - Object { - "constant": "[", - }, - Object { - "field": "nginx.error.level", - "highlights": Array [], - "value": "error", - }, - Object { - "constant": "] ", - }, - Object { - "field": "nginx.error.message", - "highlights": Array [], - "value": "connect() failed (111: Connection refused) while connecting to upstream, client: 127.0.0.1, server: localhost, request: \\"GET /php-status?json= HTTP/1.1\\", upstream: \\"fastcgi://[::1]:9000\\", host: \\"localhost\\"", - }, -] -`); + Array [ + Object { + "constant": "[nginx]", + }, + Object { + "constant": "[", + }, + Object { + "field": "nginx.error.level", + "highlights": Array [], + "value": Array [ + "error", + ], + }, + Object { + "constant": "] ", + }, + Object { + "field": "nginx.error.message", + "highlights": Array [], + "value": Array [ + "connect() failed (111: Connection refused) while connecting to upstream, client: 127.0.0.1, server: localhost, request: \\"GET /php-status?json= HTTP/1.1\\", upstream: \\"fastcgi://[::1]:9000\\", host: \\"localhost\\"", + ], + }, + ] + `); }); }); }); diff --git a/x-pack/plugins/infra/server/lib/domains/log_entries_domain/builtin_rules/filebeat_osquery.test.ts b/x-pack/plugins/infra/server/lib/domains/log_entries_domain/builtin_rules/filebeat_osquery.test.ts index 8dc70053e2022..513a9a8fcd910 100644 --- a/x-pack/plugins/infra/server/lib/domains/log_entries_domain/builtin_rules/filebeat_osquery.test.ts +++ b/x-pack/plugins/infra/server/lib/domains/log_entries_domain/builtin_rules/filebeat_osquery.test.ts @@ -13,65 +13,139 @@ describe('Filebeat Rules', () => { describe('in pre-ECS format', () => { test('osquery result log', () => { const flattenedDocument = { - '@timestamp': '2017-12-28T14:40:08.000Z', - 'event.dataset': 'osquery.result', - 'fileset.module': 'osquery', - 'fileset.name': 'result', - 'input.type': 'log', - offset: 0, - 'osquery.result.action': 'removed', - 'osquery.result.calendar_time': 'Thu Dec 28 14:40:08 2017 UTC', - 'osquery.result.columns': { - blocks: '122061322', - blocks_available: '75966945', - blocks_free: '121274885', - blocks_size: '4096', - device: '/dev/disk1s4', - device_alias: '/dev/disk1s4', - flags: '345018372', - inodes: '9223372036854775807', - inodes_free: '9223372036854775804', - path: '/private/var/vm', - type: 'apfs', - }, - 'osquery.result.counter': '1', - 'osquery.result.decorations.host_uuid': '4AB2906D-5516-5794-AF54-86D1D7F533F3', - 'osquery.result.decorations.username': 'tsg', - 'osquery.result.epoch': '0', - 'osquery.result.host_identifier': '192-168-0-4.rdsnet.ro', - 'osquery.result.name': 'pack_it-compliance_mounts', - 'osquery.result.unix_time': '1514472008', - 'prospector.type': 'log', + '@timestamp': ['2017-12-28T14:40:08.000Z'], + 'event.dataset': ['osquery.result'], + 'fileset.module': ['osquery'], + 'fileset.name': ['result'], + 'input.type': ['log'], + offset: [0], + 'osquery.result.action': ['removed'], + 'osquery.result.calendar_time': ['Thu Dec 28 14:40:08 2017 UTC'], + 'osquery.result.columns.blocks': ['122061322'], + 'osquery.result.columns.blocks_available': ['75966945'], + 'osquery.result.columns.blocks_free': ['121274885'], + 'osquery.result.columns.blocks_size': ['4096'], + 'osquery.result.columns.device': ['/dev/disk1s4'], + 'osquery.result.columns.device_alias': ['/dev/disk1s4'], + 'osquery.result.columns.flags': ['345018372'], + 'osquery.result.columns.inodes': ['9223372036854775807'], + 'osquery.result.columns.inodes_free': ['9223372036854775804'], + 'osquery.result.columns.path': ['/private/var/vm'], + 'osquery.result.columns.type': ['apfs'], + 'osquery.result.counter': ['1'], + 'osquery.result.decorations.host_uuid': ['4AB2906D-5516-5794-AF54-86D1D7F533F3'], + 'osquery.result.decorations.username': ['tsg'], + 'osquery.result.epoch': ['0'], + 'osquery.result.host_identifier': ['192-168-0-4.rdsnet.ro'], + 'osquery.result.name': ['pack_it-compliance_mounts'], + 'osquery.result.unix_time': ['1514472008'], + 'prospector.type': ['log'], }; expect(format(flattenedDocument, {})).toMatchInlineSnapshot(` -Array [ - Object { - "constant": "[Osquery][", - }, - Object { - "field": "osquery.result.action", - "highlights": Array [], - "value": "removed", - }, - Object { - "constant": "] ", - }, - Object { - "field": "osquery.result.host_identifier", - "highlights": Array [], - "value": "192-168-0-4.rdsnet.ro", - }, - Object { - "constant": " ", - }, - Object { - "field": "osquery.result.columns", - "highlights": Array [], - "value": "{\\"blocks\\":\\"122061322\\",\\"blocks_available\\":\\"75966945\\",\\"blocks_free\\":\\"121274885\\",\\"blocks_size\\":\\"4096\\",\\"device\\":\\"/dev/disk1s4\\",\\"device_alias\\":\\"/dev/disk1s4\\",\\"flags\\":\\"345018372\\",\\"inodes\\":\\"9223372036854775807\\",\\"inodes_free\\":\\"9223372036854775804\\",\\"path\\":\\"/private/var/vm\\",\\"type\\":\\"apfs\\"}", - }, -] -`); + Array [ + Object { + "constant": "[Osquery][", + }, + Object { + "field": "osquery.result.action", + "highlights": Array [], + "value": Array [ + "removed", + ], + }, + Object { + "constant": "] ", + }, + Object { + "field": "osquery.result.host_identifier", + "highlights": Array [], + "value": Array [ + "192-168-0-4.rdsnet.ro", + ], + }, + Object { + "constant": " ", + }, + Object { + "field": "osquery.result.columns.blocks", + "highlights": Array [], + "value": Array [ + "122061322", + ], + }, + Object { + "field": "osquery.result.columns.blocks_available", + "highlights": Array [], + "value": Array [ + "75966945", + ], + }, + Object { + "field": "osquery.result.columns.blocks_free", + "highlights": Array [], + "value": Array [ + "121274885", + ], + }, + Object { + "field": "osquery.result.columns.blocks_size", + "highlights": Array [], + "value": Array [ + "4096", + ], + }, + Object { + "field": "osquery.result.columns.device", + "highlights": Array [], + "value": Array [ + "/dev/disk1s4", + ], + }, + Object { + "field": "osquery.result.columns.device_alias", + "highlights": Array [], + "value": Array [ + "/dev/disk1s4", + ], + }, + Object { + "field": "osquery.result.columns.flags", + "highlights": Array [], + "value": Array [ + "345018372", + ], + }, + Object { + "field": "osquery.result.columns.inodes", + "highlights": Array [], + "value": Array [ + "9223372036854775807", + ], + }, + Object { + "field": "osquery.result.columns.inodes_free", + "highlights": Array [], + "value": Array [ + "9223372036854775804", + ], + }, + Object { + "field": "osquery.result.columns.path", + "highlights": Array [], + "value": Array [ + "/private/var/vm", + ], + }, + Object { + "field": "osquery.result.columns.type", + "highlights": Array [], + "value": Array [ + "apfs", + ], + }, + ] + `); }); }); }); diff --git a/x-pack/plugins/infra/server/lib/domains/log_entries_domain/builtin_rules/filebeat_osquery.ts b/x-pack/plugins/infra/server/lib/domains/log_entries_domain/builtin_rules/filebeat_osquery.ts index b3a6ee8c5cb47..638fd01d50c90 100644 --- a/x-pack/plugins/infra/server/lib/domains/log_entries_domain/builtin_rules/filebeat_osquery.ts +++ b/x-pack/plugins/infra/server/lib/domains/log_entries_domain/builtin_rules/filebeat_osquery.ts @@ -27,7 +27,7 @@ export const filebeatOsqueryRules = [ constant: ' ', }, { - field: 'osquery.result.columns', + fieldsPrefix: 'osquery.result.columns', }, ], }, diff --git a/x-pack/plugins/infra/server/lib/domains/log_entries_domain/builtin_rules/filebeat_traefik.test.ts b/x-pack/plugins/infra/server/lib/domains/log_entries_domain/builtin_rules/filebeat_traefik.test.ts index b19124558fdd0..d5d16f26a282a 100644 --- a/x-pack/plugins/infra/server/lib/domains/log_entries_domain/builtin_rules/filebeat_traefik.test.ts +++ b/x-pack/plugins/infra/server/lib/domains/log_entries_domain/builtin_rules/filebeat_traefik.test.ts @@ -13,112 +13,129 @@ describe('Filebeat Rules', () => { describe('in pre-ECS format', () => { test('traefik access log', () => { const flattenedDocument = { - '@timestamp': '2017-10-02T20:22:08.000Z', - 'event.dataset': 'traefik.access', - 'fileset.module': 'traefik', - 'fileset.name': 'access', - 'input.type': 'log', - offset: 280, - 'prospector.type': 'log', - 'traefik.access.backend_url': 'http://172.19.0.3:5601', - 'traefik.access.body_sent.bytes': 0, - 'traefik.access.duration': 3, - 'traefik.access.frontend_name': 'Host-host1', - 'traefik.access.geoip.city_name': 'Berlin', - 'traefik.access.geoip.continent_name': 'Europe', - 'traefik.access.geoip.country_iso_code': 'DE', - 'traefik.access.geoip.location.lat': 52.4908, - 'traefik.access.geoip.location.lon': 13.3275, - 'traefik.access.geoip.region_iso_code': 'DE-BE', - 'traefik.access.geoip.region_name': 'Land Berlin', - 'traefik.access.http_version': '1.1', - 'traefik.access.method': 'GET', - 'traefik.access.referrer': 'http://example.com/login', - 'traefik.access.remote_ip': '85.181.35.98', - 'traefik.access.request_count': 271, - 'traefik.access.response_code': '304', - 'traefik.access.url': '/ui/favicons/favicon.ico', - 'traefik.access.user_agent.device': 'Other', - 'traefik.access.user_agent.major': '61', - 'traefik.access.user_agent.minor': '0', - 'traefik.access.user_agent.name': 'Chrome', - 'traefik.access.user_agent.original': + '@timestamp': ['2017-10-02T20:22:08.000Z'], + 'event.dataset': ['traefik.access'], + 'fileset.module': ['traefik'], + 'fileset.name': ['access'], + 'input.type': ['log'], + offset: [280], + 'prospector.type': ['log'], + 'traefik.access.backend_url': ['http://172.19.0.3:5601'], + 'traefik.access.body_sent.bytes': [0], + 'traefik.access.duration': [3], + 'traefik.access.frontend_name': ['Host-host1'], + 'traefik.access.geoip.city_name': ['Berlin'], + 'traefik.access.geoip.continent_name': ['Europe'], + 'traefik.access.geoip.country_iso_code': ['DE'], + 'traefik.access.geoip.location.lat': [52.4908], + 'traefik.access.geoip.location.lon': [13.3275], + 'traefik.access.geoip.region_iso_code': ['DE-BE'], + 'traefik.access.geoip.region_name': ['Land Berlin'], + 'traefik.access.http_version': ['1.1'], + 'traefik.access.method': ['GET'], + 'traefik.access.referrer': ['http://example.com/login'], + 'traefik.access.remote_ip': ['85.181.35.98'], + 'traefik.access.request_count': [271], + 'traefik.access.response_code': ['304'], + 'traefik.access.url': ['/ui/favicons/favicon.ico'], + 'traefik.access.user_agent.device': ['Other'], + 'traefik.access.user_agent.major': ['61'], + 'traefik.access.user_agent.minor': ['0'], + 'traefik.access.user_agent.name': ['Chrome'], + 'traefik.access.user_agent.original': [ 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36', - 'traefik.access.user_agent.os': 'Linux', - 'traefik.access.user_agent.os_name': 'Linux', - 'traefik.access.user_agent.patch': '3163', - 'traefik.access.user_identifier': '-', - 'traefik.access.user_name': '-', + ], + 'traefik.access.user_agent.os': ['Linux'], + 'traefik.access.user_agent.os_name': ['Linux'], + 'traefik.access.user_agent.patch': ['3163'], + 'traefik.access.user_identifier': ['-'], + 'traefik.access.user_name': ['-'], }; expect(format(flattenedDocument, {})).toMatchInlineSnapshot(` -Array [ - Object { - "constant": "[traefik][access] ", - }, - Object { - "field": "traefik.access.remote_ip", - "highlights": Array [], - "value": "85.181.35.98", - }, - Object { - "constant": " ", - }, - Object { - "field": "traefik.access.frontend_name", - "highlights": Array [], - "value": "Host-host1", - }, - Object { - "constant": " -> ", - }, - Object { - "field": "traefik.access.backend_url", - "highlights": Array [], - "value": "http://172.19.0.3:5601", - }, - Object { - "constant": " \\"", - }, - Object { - "field": "traefik.access.method", - "highlights": Array [], - "value": "GET", - }, - Object { - "constant": " ", - }, - Object { - "field": "traefik.access.url", - "highlights": Array [], - "value": "/ui/favicons/favicon.ico", - }, - Object { - "constant": " HTTP/", - }, - Object { - "field": "traefik.access.http_version", - "highlights": Array [], - "value": "1.1", - }, - Object { - "constant": "\\" ", - }, - Object { - "field": "traefik.access.response_code", - "highlights": Array [], - "value": "304", - }, - Object { - "constant": " ", - }, - Object { - "field": "traefik.access.body_sent.bytes", - "highlights": Array [], - "value": "0", - }, -] -`); + Array [ + Object { + "constant": "[traefik][access] ", + }, + Object { + "field": "traefik.access.remote_ip", + "highlights": Array [], + "value": Array [ + "85.181.35.98", + ], + }, + Object { + "constant": " ", + }, + Object { + "field": "traefik.access.frontend_name", + "highlights": Array [], + "value": Array [ + "Host-host1", + ], + }, + Object { + "constant": " -> ", + }, + Object { + "field": "traefik.access.backend_url", + "highlights": Array [], + "value": Array [ + "http://172.19.0.3:5601", + ], + }, + Object { + "constant": " \\"", + }, + Object { + "field": "traefik.access.method", + "highlights": Array [], + "value": Array [ + "GET", + ], + }, + Object { + "constant": " ", + }, + Object { + "field": "traefik.access.url", + "highlights": Array [], + "value": Array [ + "/ui/favicons/favicon.ico", + ], + }, + Object { + "constant": " HTTP/", + }, + Object { + "field": "traefik.access.http_version", + "highlights": Array [], + "value": Array [ + "1.1", + ], + }, + Object { + "constant": "\\" ", + }, + Object { + "field": "traefik.access.response_code", + "highlights": Array [], + "value": Array [ + "304", + ], + }, + Object { + "constant": " ", + }, + Object { + "field": "traefik.access.body_sent.bytes", + "highlights": Array [], + "value": Array [ + 0, + ], + }, + ] + `); }); }); }); diff --git a/x-pack/plugins/infra/server/lib/domains/log_entries_domain/builtin_rules/generic.test.ts b/x-pack/plugins/infra/server/lib/domains/log_entries_domain/builtin_rules/generic.test.ts index d168273626cfa..eba0563be3aaa 100644 --- a/x-pack/plugins/infra/server/lib/domains/log_entries_domain/builtin_rules/generic.test.ts +++ b/x-pack/plugins/infra/server/lib/domains/log_entries_domain/builtin_rules/generic.test.ts @@ -15,154 +15,174 @@ describe('Generic Rules', () => { describe('configurable message rules', () => { test('includes the event.dataset and log.level if present', () => { const flattenedDocument = { - '@timestamp': '2016-12-26T16:22:13.000Z', - 'event.dataset': 'generic.test', - 'log.level': 'TEST_LEVEL', - first_generic_message: 'TEST_MESSAGE', + '@timestamp': ['2016-12-26T16:22:13.000Z'], + 'event.dataset': ['generic.test'], + 'log.level': ['TEST_LEVEL'], + first_generic_message: ['TEST_MESSAGE'], }; const highlights = { first_generic_message: ['TEST'], }; expect(format(flattenedDocument, highlights)).toMatchInlineSnapshot(` -Array [ - Object { - "constant": "[", - }, - Object { - "field": "event.dataset", - "highlights": Array [], - "value": "generic.test", - }, - Object { - "constant": "][", - }, - Object { - "field": "log.level", - "highlights": Array [], - "value": "TEST_LEVEL", - }, - Object { - "constant": "] ", - }, - Object { - "field": "first_generic_message", - "highlights": Array [ - "TEST", - ], - "value": "TEST_MESSAGE", - }, -] -`); + Array [ + Object { + "constant": "[", + }, + Object { + "field": "event.dataset", + "highlights": Array [], + "value": Array [ + "generic.test", + ], + }, + Object { + "constant": "][", + }, + Object { + "field": "log.level", + "highlights": Array [], + "value": Array [ + "TEST_LEVEL", + ], + }, + Object { + "constant": "] ", + }, + Object { + "field": "first_generic_message", + "highlights": Array [ + "TEST", + ], + "value": Array [ + "TEST_MESSAGE", + ], + }, + ] + `); }); test('includes the log.level if present', () => { const flattenedDocument = { - '@timestamp': '2016-12-26T16:22:13.000Z', - 'log.level': 'TEST_LEVEL', - first_generic_message: 'TEST_MESSAGE', + '@timestamp': ['2016-12-26T16:22:13.000Z'], + 'log.level': ['TEST_LEVEL'], + first_generic_message: ['TEST_MESSAGE'], }; expect(format(flattenedDocument, {})).toMatchInlineSnapshot(` -Array [ - Object { - "constant": "[", - }, - Object { - "field": "log.level", - "highlights": Array [], - "value": "TEST_LEVEL", - }, - Object { - "constant": "] ", - }, - Object { - "field": "first_generic_message", - "highlights": Array [], - "value": "TEST_MESSAGE", - }, -] -`); + Array [ + Object { + "constant": "[", + }, + Object { + "field": "log.level", + "highlights": Array [], + "value": Array [ + "TEST_LEVEL", + ], + }, + Object { + "constant": "] ", + }, + Object { + "field": "first_generic_message", + "highlights": Array [], + "value": Array [ + "TEST_MESSAGE", + ], + }, + ] + `); }); test('includes the message', () => { const firstFlattenedDocument = { - '@timestamp': '2016-12-26T16:22:13.000Z', - first_generic_message: 'FIRST_TEST_MESSAGE', + '@timestamp': ['2016-12-26T16:22:13.000Z'], + first_generic_message: ['FIRST_TEST_MESSAGE'], }; expect(format(firstFlattenedDocument, {})).toMatchInlineSnapshot(` -Array [ - Object { - "field": "first_generic_message", - "highlights": Array [], - "value": "FIRST_TEST_MESSAGE", - }, -] -`); + Array [ + Object { + "field": "first_generic_message", + "highlights": Array [], + "value": Array [ + "FIRST_TEST_MESSAGE", + ], + }, + ] + `); const secondFlattenedDocument = { - '@timestamp': '2016-12-26T16:22:13.000Z', - second_generic_message: 'SECOND_TEST_MESSAGE', + '@timestamp': ['2016-12-26T16:22:13.000Z'], + second_generic_message: ['SECOND_TEST_MESSAGE'], }; expect(format(secondFlattenedDocument, {})).toMatchInlineSnapshot(` -Array [ - Object { - "field": "second_generic_message", - "highlights": Array [], - "value": "SECOND_TEST_MESSAGE", - }, -] -`); + Array [ + Object { + "field": "second_generic_message", + "highlights": Array [], + "value": Array [ + "SECOND_TEST_MESSAGE", + ], + }, + ] + `); }); }); describe('log.original fallback', () => { test('includes the event.dataset if present', () => { const flattenedDocument = { - '@timestamp': '2016-12-26T16:22:13.000Z', - 'event.dataset': 'generic.test', - 'log.original': 'TEST_MESSAGE', + '@timestamp': ['2016-12-26T16:22:13.000Z'], + 'event.dataset': ['generic.test'], + 'log.original': ['TEST_MESSAGE'], }; expect(format(flattenedDocument, {})).toMatchInlineSnapshot(` -Array [ - Object { - "constant": "[", - }, - Object { - "field": "event.dataset", - "highlights": Array [], - "value": "generic.test", - }, - Object { - "constant": "] ", - }, - Object { - "field": "log.original", - "highlights": Array [], - "value": "TEST_MESSAGE", - }, -] -`); + Array [ + Object { + "constant": "[", + }, + Object { + "field": "event.dataset", + "highlights": Array [], + "value": Array [ + "generic.test", + ], + }, + Object { + "constant": "] ", + }, + Object { + "field": "log.original", + "highlights": Array [], + "value": Array [ + "TEST_MESSAGE", + ], + }, + ] + `); }); test('includes the original message', () => { const flattenedDocument = { - '@timestamp': '2016-12-26T16:22:13.000Z', - 'log.original': 'TEST_MESSAGE', + '@timestamp': ['2016-12-26T16:22:13.000Z'], + 'log.original': ['TEST_MESSAGE'], }; expect(format(flattenedDocument, {})).toMatchInlineSnapshot(` -Array [ - Object { - "field": "log.original", - "highlights": Array [], - "value": "TEST_MESSAGE", - }, -] -`); + Array [ + Object { + "field": "log.original", + "highlights": Array [], + "value": Array [ + "TEST_MESSAGE", + ], + }, + ] + `); }); }); }); diff --git a/x-pack/plugins/infra/server/lib/domains/log_entries_domain/builtin_rules/helpers.ts b/x-pack/plugins/infra/server/lib/domains/log_entries_domain/builtin_rules/helpers.ts index 9a6fa30e17e89..e925fab75d984 100644 --- a/x-pack/plugins/infra/server/lib/domains/log_entries_domain/builtin_rules/helpers.ts +++ b/x-pack/plugins/infra/server/lib/domains/log_entries_domain/builtin_rules/helpers.ts @@ -10,3 +10,10 @@ export const labelField = (label: string, field: string) => [ { constant: '=' }, { field }, ]; + +export const labelFieldsPrefix = (label: string, fieldsPrefix: string) => [ + { constant: ' ' }, + { constant: label }, + { constant: '=' }, + { fieldsPrefix }, +]; diff --git a/x-pack/plugins/infra/server/lib/domains/log_entries_domain/convert_document_source_to_log_item_fields.test.ts b/x-pack/plugins/infra/server/lib/domains/log_entries_domain/convert_document_source_to_log_item_fields.test.ts index 98d1e2cd89b01..7b79a1bf0386a 100644 --- a/x-pack/plugins/infra/server/lib/domains/log_entries_domain/convert_document_source_to_log_item_fields.test.ts +++ b/x-pack/plugins/infra/server/lib/domains/log_entries_domain/convert_document_source_to_log_item_fields.test.ts @@ -4,66 +4,62 @@ * you may not use this file except in compliance with the Elastic License. */ -import { convertDocumentSourceToLogItemFields } from './convert_document_source_to_log_item_fields'; +import { convertESFieldsToLogItemFields } from './convert_document_source_to_log_item_fields'; -describe('convertDocumentSourceToLogItemFields', () => { - test('should convert document', () => { - const doc = { - agent: { - hostname: 'demo-stack-client-01', - id: '7adef8b6-2ab7-45cd-a0d5-b3baad735f1b', - type: 'filebeat', - ephemeral_id: 'a0c8164b-3564-4e32-b0bf-f4db5a7ae566', - version: '7.0.0', - }, +describe('convertESFieldsToLogItemFields', () => { + test('Converts the fields collection to LogItemFields', () => { + const esFields = { + 'agent.hostname': ['demo-stack-client-01'], + 'agent.id': ['7adef8b6-2ab7-45cd-a0d5-b3baad735f1b'], + 'agent.type': ['filebeat'], + 'agent.ephemeral_id': ['a0c8164b-3564-4e32-b0bf-f4db5a7ae566'], + 'agent.version': ['7.0.0'], tags: ['prod', 'web'], metadata: [ { key: 'env', value: 'prod' }, { key: 'stack', value: 'web' }, ], - host: { - hostname: 'packer-virtualbox-iso-1546820004', - name: 'demo-stack-client-01', - }, + 'host.hostname': ['packer-virtualbox-iso-1546820004'], + 'host.name': ['demo-stack-client-01'], }; - const fields = convertDocumentSourceToLogItemFields(doc); + const fields = convertESFieldsToLogItemFields(esFields); expect(fields).toEqual([ { field: 'agent.hostname', - value: 'demo-stack-client-01', + value: ['demo-stack-client-01'], }, { field: 'agent.id', - value: '7adef8b6-2ab7-45cd-a0d5-b3baad735f1b', + value: ['7adef8b6-2ab7-45cd-a0d5-b3baad735f1b'], }, { field: 'agent.type', - value: 'filebeat', + value: ['filebeat'], }, { field: 'agent.ephemeral_id', - value: 'a0c8164b-3564-4e32-b0bf-f4db5a7ae566', + value: ['a0c8164b-3564-4e32-b0bf-f4db5a7ae566'], }, { field: 'agent.version', - value: '7.0.0', + value: ['7.0.0'], }, { field: 'tags', - value: '["prod","web"]', + value: ['prod', 'web'], }, { field: 'metadata', - value: '[{"key":"env","value":"prod"},{"key":"stack","value":"web"}]', + value: ['{"key":"env","value":"prod"}', '{"key":"stack","value":"web"}'], }, { field: 'host.hostname', - value: 'packer-virtualbox-iso-1546820004', + value: ['packer-virtualbox-iso-1546820004'], }, { field: 'host.name', - value: 'demo-stack-client-01', + value: ['demo-stack-client-01'], }, ]); }); diff --git a/x-pack/plugins/infra/server/lib/domains/log_entries_domain/convert_document_source_to_log_item_fields.ts b/x-pack/plugins/infra/server/lib/domains/log_entries_domain/convert_document_source_to_log_item_fields.ts index 7c8560d72ff97..a1d855bfdaa48 100644 --- a/x-pack/plugins/infra/server/lib/domains/log_entries_domain/convert_document_source_to_log_item_fields.ts +++ b/x-pack/plugins/infra/server/lib/domains/log_entries_domain/convert_document_source_to_log_item_fields.ts @@ -5,39 +5,21 @@ */ import stringify from 'json-stable-stringify'; -import { isArray, isPlainObject } from 'lodash'; - -import { JsonObject } from '../../../../common/typed_json'; import { LogEntriesItemField } from '../../../../common/http_api'; +import { JsonArray } from '../../../../common/typed_json'; -const isJsonObject = (subject: any): subject is JsonObject => { - return isPlainObject(subject); +const serializeValue = (value: JsonArray): string[] => { + return value.map((v) => { + if (typeof v === 'object' && v != null) { + return stringify(v); + } else { + return `${v}`; + } + }); }; -const serializeValue = (value: any): string => { - if (isArray(value) || isPlainObject(value)) { - return stringify(value); - } - return `${value}`; -}; export const convertESFieldsToLogItemFields = (fields: { - [field: string]: [value: unknown]; + [field: string]: JsonArray; }): LogEntriesItemField[] => { - return Object.keys(fields).map((field) => ({ field, value: serializeValue(fields[field][0]) })); -}; - -export const convertDocumentSourceToLogItemFields = ( - source: JsonObject, - path: string[] = [], - fields: LogEntriesItemField[] = [] -): LogEntriesItemField[] => { - return Object.keys(source).reduce((acc, key) => { - const value = source[key]; - const nextPath = [...path, key]; - if (isJsonObject(value)) { - return convertDocumentSourceToLogItemFields(value, nextPath, acc); - } - const field = { field: nextPath.join('.'), value: serializeValue(value) }; - return [...acc, field]; - }, fields); + return Object.keys(fields).map((field) => ({ field, value: serializeValue(fields[field]) })); }; diff --git a/x-pack/plugins/infra/server/lib/domains/log_entries_domain/log_entries_domain.ts b/x-pack/plugins/infra/server/lib/domains/log_entries_domain/log_entries_domain.ts index e211f72b4e076..cc9d4c749c77d 100644 --- a/x-pack/plugins/infra/server/lib/domains/log_entries_domain/log_entries_domain.ts +++ b/x-pack/plugins/infra/server/lib/domains/log_entries_domain/log_entries_domain.ts @@ -7,7 +7,7 @@ import { sortBy } from 'lodash'; import { RequestHandlerContext } from 'src/core/server'; -import { JsonObject } from '../../../../common/typed_json'; +import { JsonArray, JsonObject } from '../../../../common/typed_json'; import { LogEntriesSummaryBucket, LogEntriesSummaryHighlightsBucket, @@ -163,8 +163,8 @@ export class InfraLogEntriesDomain { return { columnId: column.fieldColumn.id, field: column.fieldColumn.field, - value: doc.fields[column.fieldColumn.field], - highlights: doc.highlights[column.fieldColumn.field] || [], + value: doc.fields[column.fieldColumn.field] ?? [], + highlights: doc.highlights[column.fieldColumn.field] ?? [], }; } } @@ -252,8 +252,8 @@ export class InfraLogEntriesDomain { ): Promise { const document = await this.adapter.getLogItem(requestContext, id, sourceConfiguration); const defaultFields = [ - { field: '_index', value: document._index }, - { field: '_id', value: document._id }, + { field: '_index', value: [document._index] }, + { field: '_id', value: [document._id] }, ]; return { @@ -310,10 +310,10 @@ export class InfraLogEntriesDomain { } } -interface LogItemHit { +export interface LogItemHit { _index: string; _id: string; - fields: { [field: string]: [value: unknown] }; + fields: { [field: string]: [value: JsonArray] }; sort: [number, number]; } @@ -400,9 +400,9 @@ const createHighlightQueryDsl = (phrase: string, fields: string[]) => ({ const getContextFromDoc = (doc: LogEntryDocument): LogEntry['context'] => { // Get all context fields, then test for the presence and type of the ones that go together - const containerId = doc.fields['container.id']; - const hostName = doc.fields['host.name']; - const logFilePath = doc.fields['log.file.path']; + const containerId = doc.fields['container.id']?.[0]; + const hostName = doc.fields['host.name']?.[0]; + const logFilePath = doc.fields['log.file.path']?.[0]; if (typeof containerId === 'string') { return { 'container.id': containerId }; diff --git a/x-pack/plugins/infra/server/lib/domains/log_entries_domain/message.ts b/x-pack/plugins/infra/server/lib/domains/log_entries_domain/message.ts index b8cadaa06f61b..f9775e127088a 100644 --- a/x-pack/plugins/infra/server/lib/domains/log_entries_domain/message.ts +++ b/x-pack/plugins/infra/server/lib/domains/log_entries_domain/message.ts @@ -4,11 +4,11 @@ * you may not use this file except in compliance with the Elastic License. */ -import stringify from 'json-stable-stringify'; - -import { InfraLogMessageSegment } from '../../../graphql/types'; +import { LogMessagePart } from '../../../../common/http_api/log_entries'; +import { JsonArray, JsonValue } from '../../../../common/typed_json'; import { LogMessageFormattingCondition, + LogMessageFormattingFieldValueConditionValue, LogMessageFormattingInstruction, LogMessageFormattingRule, } from './rule_types'; @@ -30,7 +30,7 @@ export function compileFormattingRules( ) ) ), - format(fields, highlights): InfraLogMessageSegment[] { + format(fields, highlights): LogMessagePart[] { for (const compiledRule of compiledRules) { if (compiledRule.fulfillsCondition(fields)) { return compiledRule.format(fields, highlights); @@ -59,16 +59,34 @@ const compileRule = (rule: LogMessageFormattingRule): CompiledLogMessageFormatti const compileCondition = ( condition: LogMessageFormattingCondition ): CompiledLogMessageFormattingCondition => - [compileExistsCondition, compileFieldValueCondition].reduce( - (compiledCondition, compile) => compile(condition) || compiledCondition, - catchAllCondition - ); + [ + compileAllCondition, + compileExistsCondition, + compileExistsPrefixCondition, + compileFieldValueCondition, + ].reduce((compiledCondition, compile) => compile(condition) || compiledCondition, falseCondition); -const catchAllCondition: CompiledLogMessageFormattingCondition = { +const falseCondition: CompiledLogMessageFormattingCondition = { conditionFields: [] as string[], fulfillsCondition: () => false, }; +const compileAllCondition = ( + condition: LogMessageFormattingCondition +): CompiledLogMessageFormattingCondition | null => { + if (!('all' in condition)) { + return null; + } + + const compiledConditions = condition.all.map(compileCondition); + + return { + conditionFields: compiledConditions.flatMap(({ conditionFields }) => conditionFields), + fulfillsCondition: (fields: Fields) => + compiledConditions.every(({ fulfillsCondition }) => fulfillsCondition(fields)), + }; +}; + const compileExistsCondition = (condition: LogMessageFormattingCondition) => 'exists' in condition ? { @@ -78,13 +96,24 @@ const compileExistsCondition = (condition: LogMessageFormattingCondition) => } : null; +const compileExistsPrefixCondition = (condition: LogMessageFormattingCondition) => + 'existsPrefix' in condition + ? { + conditionFields: condition.existsPrefix.map((prefix) => `${prefix}.*`), + fulfillsCondition: (fields: Fields) => + condition.existsPrefix.every((fieldNamePrefix) => + Object.keys(fields).some((field) => field.startsWith(`${fieldNamePrefix}.`)) + ), + } + : null; + const compileFieldValueCondition = (condition: LogMessageFormattingCondition) => 'values' in condition ? { conditionFields: Object.keys(condition.values), fulfillsCondition: (fields: Fields) => - Object.entries(condition.values).every( - ([fieldName, expectedValue]) => fields[fieldName] === expectedValue + Object.entries(condition.values).every(([fieldName, expectedValue]) => + equalsOrContains(fields[fieldName] ?? [], expectedValue) ), } : null; @@ -116,7 +145,11 @@ const compileFormattingInstructions = ( const compileFormattingInstruction = ( formattingInstruction: LogMessageFormattingInstruction ): CompiledLogMessageFormattingInstruction => - [compileFieldReferenceFormattingInstruction, compileConstantFormattingInstruction].reduce( + [ + compileFieldReferenceFormattingInstruction, + compileFieldsPrefixReferenceFormattingInstruction, + compileConstantFormattingInstruction, + ].reduce( (compiledFormattingInstruction, compile) => compile(formattingInstruction) || compiledFormattingInstruction, catchAllFormattingInstruction @@ -138,19 +171,44 @@ const compileFieldReferenceFormattingInstruction = ( ? { formattingFields: [formattingInstruction.field], format: (fields, highlights) => { - const value = fields[formattingInstruction.field]; - const highlightedValues = highlights[formattingInstruction.field]; + const value = fields[formattingInstruction.field] ?? []; + const highlightedValues = highlights[formattingInstruction.field] ?? []; return [ { field: formattingInstruction.field, - value: typeof value === 'object' ? stringify(value) : `${value}`, - highlights: highlightedValues || [], + value, + highlights: highlightedValues, }, ]; }, } : null; +const compileFieldsPrefixReferenceFormattingInstruction = ( + formattingInstruction: LogMessageFormattingInstruction +): CompiledLogMessageFormattingInstruction | null => + 'fieldsPrefix' in formattingInstruction + ? { + formattingFields: [`${formattingInstruction.fieldsPrefix}.*`], + format: (fields, highlights) => { + const matchingFields = Object.keys(fields).filter((field) => + field.startsWith(`${formattingInstruction.fieldsPrefix}.`) + ); + return matchingFields.flatMap((field) => { + const value = fields[field] ?? []; + const highlightedValues = highlights[field] ?? []; + return [ + { + field, + value, + highlights: highlightedValues, + }, + ]; + }); + }, + } + : null; + const compileConstantFormattingInstruction = ( formattingInstruction: LogMessageFormattingInstruction ): CompiledLogMessageFormattingInstruction | null => @@ -165,8 +223,21 @@ const compileConstantFormattingInstruction = ( } : null; +const equalsOrContains = ( + operand: JsonValue, + value: LogMessageFormattingFieldValueConditionValue +): boolean => { + if (Array.isArray(operand)) { + return operand.includes(value); + } else if (typeof operand === 'object' && operand !== null) { + return Object.values(operand).includes(value); + } else { + return operand === value; + } +}; + export interface Fields { - [fieldName: string]: string | number | object | boolean | null; + [fieldName: string]: JsonArray; } export interface Highlights { @@ -176,7 +247,7 @@ export interface Highlights { export interface CompiledLogMessageFormattingRule { requiredFields: string[]; fulfillsCondition(fields: Fields): boolean; - format(fields: Fields, highlights: Highlights): InfraLogMessageSegment[]; + format(fields: Fields, highlights: Highlights): LogMessagePart[]; } export interface CompiledLogMessageFormattingCondition { @@ -186,5 +257,5 @@ export interface CompiledLogMessageFormattingCondition { export interface CompiledLogMessageFormattingInstruction { formattingFields: string[]; - format(fields: Fields, highlights: Highlights): InfraLogMessageSegment[]; + format(fields: Fields, highlights: Highlights): LogMessagePart[]; } diff --git a/x-pack/plugins/infra/server/lib/domains/log_entries_domain/rule_types.ts b/x-pack/plugins/infra/server/lib/domains/log_entries_domain/rule_types.ts index 6107fc362f8e3..4569f4b8e8a91 100644 --- a/x-pack/plugins/infra/server/lib/domains/log_entries_domain/rule_types.ts +++ b/x-pack/plugins/infra/server/lib/domains/log_entries_domain/rule_types.ts @@ -4,33 +4,52 @@ * you may not use this file except in compliance with the Elastic License. */ +import { JsonValue } from '../../../../common/typed_json'; + export interface LogMessageFormattingRule { when: LogMessageFormattingCondition; format: LogMessageFormattingInstruction[]; } export type LogMessageFormattingCondition = + | LogMessageFormattingAllCondition | LogMessageFormattingExistsCondition + | LogMessageFormattingExistsPrefixCondition | LogMessageFormattingFieldValueCondition; +export interface LogMessageFormattingAllCondition { + all: LogMessageFormattingCondition[]; +} + export interface LogMessageFormattingExistsCondition { exists: string[]; } +export interface LogMessageFormattingExistsPrefixCondition { + existsPrefix: string[]; +} + export interface LogMessageFormattingFieldValueCondition { values: { - [fieldName: string]: string | number | boolean | null; + [fieldName: string]: LogMessageFormattingFieldValueConditionValue; }; } +export type LogMessageFormattingFieldValueConditionValue = JsonValue; + export type LogMessageFormattingInstruction = | LogMessageFormattingFieldReference + | LogMessageFormattingFieldsPrefixReference | LogMessageFormattingConstant; export interface LogMessageFormattingFieldReference { field: string; } +export interface LogMessageFormattingFieldsPrefixReference { + fieldsPrefix: string; +} + export interface LogMessageFormattingConstant { constant: string; } diff --git a/x-pack/plugins/ingest_manager/common/services/is_valid_namespace.ts b/x-pack/plugins/ingest_manager/common/services/is_valid_namespace.ts index 43aa64f677263..8bd8349580edc 100644 --- a/x-pack/plugins/ingest_manager/common/services/is_valid_namespace.ts +++ b/x-pack/plugins/ingest_manager/common/services/is_valid_namespace.ts @@ -12,26 +12,23 @@ export function isValidNamespace(namespace: string): { valid: boolean; error?: s if (!namespace.trim()) { return { valid: false, - error: i18n.translate('xpack.ingestManager.namespaceValidation.requiredErrorMessage', { + error: i18n.translate('xpack.fleet.namespaceValidation.requiredErrorMessage', { defaultMessage: 'Namespace is required', }), }; } else if (namespace !== namespace.toLowerCase()) { return { valid: false, - error: i18n.translate('xpack.ingestManager.namespaceValidation.lowercaseErrorMessage', { + error: i18n.translate('xpack.fleet.namespaceValidation.lowercaseErrorMessage', { defaultMessage: 'Namespace must be lowercase', }), }; } else if (/[\*\\/\?"<>|\s,#:]+/.test(namespace)) { return { valid: false, - error: i18n.translate( - 'xpack.ingestManager.namespaceValidation.invalidCharactersErrorMessage', - { - defaultMessage: 'Namespace contains invalid characters', - } - ), + error: i18n.translate('xpack.fleet.namespaceValidation.invalidCharactersErrorMessage', { + defaultMessage: 'Namespace contains invalid characters', + }), }; } // Node.js doesn't have Blob, and browser doesn't have Buffer :) @@ -41,7 +38,7 @@ export function isValidNamespace(namespace: string): { valid: boolean; error?: s ) { return { valid: false, - error: i18n.translate('xpack.ingestManager.namespaceValidation.tooLongErrorMessage', { + error: i18n.translate('xpack.fleet.namespaceValidation.tooLongErrorMessage', { defaultMessage: 'Namespace cannot be more than 100 bytes', }), }; diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/components/alpha_flyout.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/components/alpha_flyout.tsx index e321dfb1826f7..a6a162dbdeafa 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/components/alpha_flyout.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/components/alpha_flyout.tsx @@ -27,7 +27,7 @@ export const AlphaFlyout: React.FunctionComponent = ({ onClose }) => {

    @@ -37,13 +37,13 @@ export const AlphaFlyout: React.FunctionComponent = ({ onClose }) => {

    = ({ onClose }) => { target="_blank" > @@ -61,7 +61,7 @@ export const AlphaFlyout: React.FunctionComponent = ({ onClose }) => { forumLink: ( @@ -74,7 +74,7 @@ export const AlphaFlyout: React.FunctionComponent = ({ onClose }) => { diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/components/alpha_messaging.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/components/alpha_messaging.tsx index 62158483518dd..e39d07eec395e 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/components/alpha_messaging.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/components/alpha_messaging.tsx @@ -26,20 +26,17 @@ export const AlphaMessaging: React.FC<{}> = () => {

    - + {' – '} {' '} setIsAlphaFlyoutOpen(true)}> diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/components/context_menu_actions.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/components/context_menu_actions.tsx index 7d1f12447340f..29e42363e9865 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/components/context_menu_actions.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/components/context_menu_actions.tsx @@ -63,7 +63,7 @@ export const ContextMenuActions = React.memo(({ button, onChange, isOpen, diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/components/enrollment_instructions/manual/index.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/components/enrollment_instructions/manual/index.tsx index a24640af7438f..343ddfab23c71 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/components/enrollment_instructions/manual/index.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/components/enrollment_instructions/manual/index.tsx @@ -38,7 +38,7 @@ export const ManualInstructions: React.FunctionComponent = ({ <> @@ -46,7 +46,7 @@ export const ManualInstructions: React.FunctionComponent = ({

    @@ -59,7 +59,7 @@ export const ManualInstructions: React.FunctionComponent = ({

    @@ -71,7 +71,7 @@ export const ManualInstructions: React.FunctionComponent = ({ = ({ href="https://www.elastic.co/guide/en/ingest-management/current/elastic-agent-installation-configuration.html" > diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/components/home_integration/tutorial_directory_header_link.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/components/home_integration/tutorial_directory_header_link.tsx index 2fd99a88c3c89..88759791a5300 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/components/home_integration/tutorial_directory_header_link.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/components/home_integration/tutorial_directory_header_link.tsx @@ -33,7 +33,7 @@ const TutorialDirectoryHeaderLink: TutorialDirectoryHeaderLinkComponent = memo(( return hasIngestManager && noticeState.settingsDataLoaded && noticeState.hasSeenNotice ? ( diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/components/home_integration/tutorial_directory_notice.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/components/home_integration/tutorial_directory_notice.tsx index 64dbb3f43312c..87fd58861b274 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/components/home_integration/tutorial_directory_notice.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/components/home_integration/tutorial_directory_notice.tsx @@ -60,13 +60,13 @@ const TutorialDirectoryNotice: TutorialDirectoryNoticeComponent = memo(() => { iconType="cheer" title={ @@ -77,7 +77,7 @@ const TutorialDirectoryNotice: TutorialDirectoryNoticeComponent = memo(() => { >

    { blogPostLink: ( @@ -98,7 +98,7 @@ const TutorialDirectoryNotice: TutorialDirectoryNoticeComponent = memo(() => {

    @@ -113,7 +113,7 @@ const TutorialDirectoryNotice: TutorialDirectoryNoticeComponent = memo(() => { }} > diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/components/home_integration/tutorial_module_notice.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/components/home_integration/tutorial_module_notice.tsx index 7fec1909ba22b..3430a4eb5b258 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/components/home_integration/tutorial_module_notice.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/components/home_integration/tutorial_module_notice.tsx @@ -26,14 +26,14 @@ const TutorialModuleNotice: TutorialModuleNoticeComponent = memo(({ moduleName }

    @@ -45,7 +45,7 @@ const TutorialModuleNotice: TutorialModuleNoticeComponent = memo(({ moduleName } })} > @@ -57,7 +57,7 @@ const TutorialModuleNotice: TutorialModuleNoticeComponent = memo(({ moduleName } target="_blank" > diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/components/search_bar.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/components/search_bar.tsx index 9069cc0f73806..24a5b7e4c2bc0 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/components/search_bar.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/components/search_bar.tsx @@ -61,7 +61,7 @@ export const SearchBar: React.FunctionComponent = ({ icon={'search'} placeholder={ placeholder || - i18n.translate('xpack.ingestManager.defaultSearchPlaceholderText', { + i18n.translate('xpack.fleet.defaultSearchPlaceholderText', { defaultMessage: 'Search', }) } diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/components/settings_flyout.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/components/settings_flyout.tsx index 7f80863faee45..80ecaa2493278 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/components/settings_flyout.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/components/settings_flyout.tsx @@ -41,21 +41,21 @@ function useSettingsForm(outputId: string | undefined, onSuccess: () => void) { const kibanaUrlsInput = useComboInput([], (value) => { if (value.length === 0) { return [ - i18n.translate('xpack.ingestManager.settings.kibanaUrlEmptyError', { + i18n.translate('xpack.fleet.settings.kibanaUrlEmptyError', { defaultMessage: 'At least one URL is required', }), ]; } if (value.some((v) => !v.match(URL_REGEX))) { return [ - i18n.translate('xpack.ingestManager.settings.kibanaUrlError', { + i18n.translate('xpack.fleet.settings.kibanaUrlError', { defaultMessage: 'Invalid URL', }), ]; } if (isDiffPathProtocol(value)) { return [ - i18n.translate('xpack.ingestManager.settings.kibanaUrlDifferentPathOrProtocolError', { + i18n.translate('xpack.fleet.settings.kibanaUrlDifferentPathOrProtocolError', { defaultMessage: 'Protocol and path must be the same for each URL', }), ]; @@ -64,7 +64,7 @@ function useSettingsForm(outputId: string | undefined, onSuccess: () => void) { const elasticsearchUrlInput = useComboInput([], (value) => { if (value.some((v) => !v.match(URL_REGEX))) { return [ - i18n.translate('xpack.ingestManager.settings.elasticHostError', { + i18n.translate('xpack.fleet.settings.elasticHostError', { defaultMessage: 'Invalid URL', }), ]; @@ -77,7 +77,7 @@ function useSettingsForm(outputId: string | undefined, onSuccess: () => void) { return; } catch (error) { return [ - i18n.translate('xpack.ingestManager.settings.invalidYamlFormatErrorMessage', { + i18n.translate('xpack.fleet.settings.invalidYamlFormatErrorMessage', { defaultMessage: 'Invalid YAML: {reason}', values: { reason: error.message }, }), @@ -114,7 +114,7 @@ function useSettingsForm(outputId: string | undefined, onSuccess: () => void) { throw settingsResponse.error; } notifications.toasts.addSuccess( - i18n.translate('xpack.ingestManager.settings.success.message', { + i18n.translate('xpack.fleet.settings.success.message', { defaultMessage: 'Settings saved', }) ); @@ -166,7 +166,7 @@ export const SettingFlyout: React.FunctionComponent = ({ onClose }) => { options={[ { id: 'enabled', - label: i18n.translate('xpack.ingestManager.settings.autoUpgradeEnabledLabel', { + label: i18n.translate('xpack.fleet.settings.autoUpgradeEnabledLabel', { defaultMessage: 'Automatically update agent binaries to use the latest minor version.', }), @@ -174,7 +174,7 @@ export const SettingFlyout: React.FunctionComponent = ({ onClose }) => { { id: 'disabled', disabled: true, - label: i18n.translate('xpack.ingestManager.settings.autoUpgradeDisabledLabel', { + label: i18n.translate('xpack.fleet.settings.autoUpgradeDisabledLabel', { defaultMessage: 'Manually manage agent binary versions. Requires a Gold subscription.', }), @@ -187,7 +187,7 @@ export const SettingFlyout: React.FunctionComponent = ({ onClose }) => {

    @@ -200,23 +200,17 @@ export const SettingFlyout: React.FunctionComponent = ({ onClose }) => { options={[ { id: 'enabled', - label: i18n.translate( - 'xpack.ingestManager.settings.integrationUpgradeEnabledFieldLabel', - { - defaultMessage: - 'Automatically update integrations to the latest version to get the latest assets. You might need to update agent policies to use new features.', - } - ), + label: i18n.translate('xpack.fleet.settings.integrationUpgradeEnabledFieldLabel', { + defaultMessage: + 'Automatically update integrations to the latest version to get the latest assets. You might need to update agent policies to use new features.', + }), }, { id: 'disabled', disabled: true, - label: i18n.translate( - 'xpack.ingestManager.settings.integrationUpgradeDisabledFieldLabel', - { - defaultMessage: 'Manually manage integration versions yourself.', - } - ), + label: i18n.translate('xpack.fleet.settings.integrationUpgradeDisabledFieldLabel', { + defaultMessage: 'Manually manage integration versions yourself.', + }), }, ]} idSelected={'enabled'} @@ -226,7 +220,7 @@ export const SettingFlyout: React.FunctionComponent = ({ onClose }) => {

    @@ -238,7 +232,7 @@ export const SettingFlyout: React.FunctionComponent = ({ onClose }) => {

    @@ -246,14 +240,14 @@ export const SettingFlyout: React.FunctionComponent = ({ onClose }) => { = ({ onClose }) => { = ({ onClose }) => { = ({ onClose }) => {

    @@ -317,7 +311,7 @@ export const SettingFlyout: React.FunctionComponent = ({ onClose }) => { @@ -325,7 +319,7 @@ export const SettingFlyout: React.FunctionComponent = ({ onClose }) => { diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/hooks/use_breadcrumbs.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/hooks/use_breadcrumbs.tsx index ccd889dec5b9f..ed38e1a5ce4a1 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/hooks/use_breadcrumbs.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/hooks/use_breadcrumbs.tsx @@ -10,7 +10,7 @@ import { useCore } from './use_core'; const BASE_BREADCRUMB: ChromeBreadcrumb = { href: pagePathGetters.overview(), - text: i18n.translate('xpack.ingestManager.breadcrumbs.appTitle', { + text: i18n.translate('xpack.fleet.breadcrumbs.appTitle', { defaultMessage: 'Fleet', }), }; @@ -22,7 +22,7 @@ const breadcrumbGetters: { overview: () => [ BASE_BREADCRUMB, { - text: i18n.translate('xpack.ingestManager.breadcrumbs.overviewPageTitle', { + text: i18n.translate('xpack.fleet.breadcrumbs.overviewPageTitle', { defaultMessage: 'Overview', }), }, @@ -30,7 +30,7 @@ const breadcrumbGetters: { integrations: () => [ BASE_BREADCRUMB, { - text: i18n.translate('xpack.ingestManager.breadcrumbs.integrationsPageTitle', { + text: i18n.translate('xpack.fleet.breadcrumbs.integrationsPageTitle', { defaultMessage: 'Integrations', }), }, @@ -39,12 +39,12 @@ const breadcrumbGetters: { BASE_BREADCRUMB, { href: pagePathGetters.integrations(), - text: i18n.translate('xpack.ingestManager.breadcrumbs.integrationsPageTitle', { + text: i18n.translate('xpack.fleet.breadcrumbs.integrationsPageTitle', { defaultMessage: 'Integrations', }), }, { - text: i18n.translate('xpack.ingestManager.breadcrumbs.allIntegrationsPageTitle', { + text: i18n.translate('xpack.fleet.breadcrumbs.allIntegrationsPageTitle', { defaultMessage: 'All', }), }, @@ -53,12 +53,12 @@ const breadcrumbGetters: { BASE_BREADCRUMB, { href: pagePathGetters.integrations(), - text: i18n.translate('xpack.ingestManager.breadcrumbs.integrationsPageTitle', { + text: i18n.translate('xpack.fleet.breadcrumbs.integrationsPageTitle', { defaultMessage: 'Integrations', }), }, { - text: i18n.translate('xpack.ingestManager.breadcrumbs.installedIntegrationsPageTitle', { + text: i18n.translate('xpack.fleet.breadcrumbs.installedIntegrationsPageTitle', { defaultMessage: 'Installed', }), }, @@ -67,7 +67,7 @@ const breadcrumbGetters: { BASE_BREADCRUMB, { href: pagePathGetters.integrations(), - text: i18n.translate('xpack.ingestManager.breadcrumbs.integrationsPageTitle', { + text: i18n.translate('xpack.fleet.breadcrumbs.integrationsPageTitle', { defaultMessage: 'Integrations', }), }, @@ -76,7 +76,7 @@ const breadcrumbGetters: { policies: () => [ BASE_BREADCRUMB, { - text: i18n.translate('xpack.ingestManager.breadcrumbs.policiesPageTitle', { + text: i18n.translate('xpack.fleet.breadcrumbs.policiesPageTitle', { defaultMessage: 'Policies', }), }, @@ -84,7 +84,7 @@ const breadcrumbGetters: { policies_list: () => [ BASE_BREADCRUMB, { - text: i18n.translate('xpack.ingestManager.breadcrumbs.policiesPageTitle', { + text: i18n.translate('xpack.fleet.breadcrumbs.policiesPageTitle', { defaultMessage: 'Policies', }), }, @@ -93,7 +93,7 @@ const breadcrumbGetters: { BASE_BREADCRUMB, { href: pagePathGetters.policies(), - text: i18n.translate('xpack.ingestManager.breadcrumbs.policiesPageTitle', { + text: i18n.translate('xpack.fleet.breadcrumbs.policiesPageTitle', { defaultMessage: 'Policies', }), }, @@ -103,7 +103,7 @@ const breadcrumbGetters: { BASE_BREADCRUMB, { href: pagePathGetters.policies(), - text: i18n.translate('xpack.ingestManager.breadcrumbs.policiesPageTitle', { + text: i18n.translate('xpack.fleet.breadcrumbs.policiesPageTitle', { defaultMessage: 'Policies', }), }, @@ -112,7 +112,7 @@ const breadcrumbGetters: { text: policyName, }, { - text: i18n.translate('xpack.ingestManager.breadcrumbs.addPackagePolicyPageTitle', { + text: i18n.translate('xpack.fleet.breadcrumbs.addPackagePolicyPageTitle', { defaultMessage: 'Add integration', }), }, @@ -121,7 +121,7 @@ const breadcrumbGetters: { BASE_BREADCRUMB, { href: pagePathGetters.integrations(), - text: i18n.translate('xpack.ingestManager.breadcrumbs.integrationsPageTitle', { + text: i18n.translate('xpack.fleet.breadcrumbs.integrationsPageTitle', { defaultMessage: 'Integrations', }), }, @@ -130,7 +130,7 @@ const breadcrumbGetters: { text: pkgTitle, }, { - text: i18n.translate('xpack.ingestManager.breadcrumbs.addPackagePolicyPageTitle', { + text: i18n.translate('xpack.fleet.breadcrumbs.addPackagePolicyPageTitle', { defaultMessage: 'Add integration', }), }, @@ -139,7 +139,7 @@ const breadcrumbGetters: { BASE_BREADCRUMB, { href: pagePathGetters.policies(), - text: i18n.translate('xpack.ingestManager.breadcrumbs.policiesPageTitle', { + text: i18n.translate('xpack.fleet.breadcrumbs.policiesPageTitle', { defaultMessage: 'Policies', }), }, @@ -148,7 +148,7 @@ const breadcrumbGetters: { text: policyName, }, { - text: i18n.translate('xpack.ingestManager.breadcrumbs.editPackagePolicyPageTitle', { + text: i18n.translate('xpack.fleet.breadcrumbs.editPackagePolicyPageTitle', { defaultMessage: 'Edit integration', }), }, @@ -156,7 +156,7 @@ const breadcrumbGetters: { fleet: () => [ BASE_BREADCRUMB, { - text: i18n.translate('xpack.ingestManager.breadcrumbs.agentsPageTitle', { + text: i18n.translate('xpack.fleet.breadcrumbs.agentsPageTitle', { defaultMessage: 'Agents', }), }, @@ -164,7 +164,7 @@ const breadcrumbGetters: { fleet_agent_list: () => [ BASE_BREADCRUMB, { - text: i18n.translate('xpack.ingestManager.breadcrumbs.agentsPageTitle', { + text: i18n.translate('xpack.fleet.breadcrumbs.agentsPageTitle', { defaultMessage: 'Agents', }), }, @@ -173,7 +173,7 @@ const breadcrumbGetters: { BASE_BREADCRUMB, { href: pagePathGetters.fleet(), - text: i18n.translate('xpack.ingestManager.breadcrumbs.agentsPageTitle', { + text: i18n.translate('xpack.fleet.breadcrumbs.agentsPageTitle', { defaultMessage: 'Agents', }), }, @@ -183,12 +183,12 @@ const breadcrumbGetters: { BASE_BREADCRUMB, { href: pagePathGetters.fleet(), - text: i18n.translate('xpack.ingestManager.breadcrumbs.agentsPageTitle', { + text: i18n.translate('xpack.fleet.breadcrumbs.agentsPageTitle', { defaultMessage: 'Agents', }), }, { - text: i18n.translate('xpack.ingestManager.breadcrumbs.enrollmentTokensPageTitle', { + text: i18n.translate('xpack.fleet.breadcrumbs.enrollmentTokensPageTitle', { defaultMessage: 'Enrollment tokens', }), }, @@ -196,7 +196,7 @@ const breadcrumbGetters: { data_streams: () => [ BASE_BREADCRUMB, { - text: i18n.translate('xpack.ingestManager.breadcrumbs.datastreamsPageTitle', { + text: i18n.translate('xpack.fleet.breadcrumbs.datastreamsPageTitle', { defaultMessage: 'Data streams', }), }, diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/index.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/index.tsx index 12d6e1c9ed0b4..34c5742ee96a3 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/index.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/index.tsx @@ -115,16 +115,13 @@ const IngestManagerRoutes = memo<{ history: AppMountParameters['history']; basep } - error={i18n.translate( - 'xpack.ingestManager.permissionsRequestErrorMessageDescription', - { - defaultMessage: 'There was a problem checking Fleet permissions', - } - )} + error={i18n.translate('xpack.fleet.permissionsRequestErrorMessageDescription', { + defaultMessage: 'There was a problem checking Fleet permissions', + })} /> ) : ( @@ -134,12 +131,12 @@ const IngestManagerRoutes = memo<{ history: AppMountParameters['history']; basep

    {permissionsError === 'MISSING_SUPERUSER_ROLE' ? ( ) : ( )} @@ -149,13 +146,13 @@ const IngestManagerRoutes = memo<{ history: AppMountParameters['history']; basep

    {permissionsError === 'MISSING_SUPERUSER_ROLE' ? ( superuser }} /> ) : ( )} @@ -175,7 +172,7 @@ const IngestManagerRoutes = memo<{ history: AppMountParameters['history']; basep } diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/layouts/default.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/layouts/default.tsx index 5d39995922b93..376de7e2e6a07 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/layouts/default.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/layouts/default.tsx @@ -63,19 +63,19 @@ export const DefaultLayout: React.FunctionComponent = ({ @@ -85,13 +85,13 @@ export const DefaultLayout: React.FunctionComponent = ({ disabled={!agents?.enabled} > @@ -106,7 +106,7 @@ export const DefaultLayout: React.FunctionComponent = ({ target="_blank" > @@ -115,7 +115,7 @@ export const DefaultLayout: React.FunctionComponent = ({ setIsSettingsFlyoutOpen(true)}> diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/components/actions_menu.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/components/actions_menu.tsx index 691de5f259134..55872aee5c3d3 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/components/actions_menu.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/components/actions_menu.tsx @@ -69,7 +69,7 @@ export const AgentPolicyActionMenu = memo<{ }, children: ( ), @@ -84,7 +84,7 @@ export const AgentPolicyActionMenu = memo<{ key="enrollAgents" > , @@ -94,7 +94,7 @@ export const AgentPolicyActionMenu = memo<{ key="viewPolicy" > , @@ -107,7 +107,7 @@ export const AgentPolicyActionMenu = memo<{ key="copyPolicy" > , diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/components/agent_policy_copy_provider.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/components/agent_policy_copy_provider.tsx index fefbe1fa82a0c..41201f9612f13 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/components/agent_policy_copy_provider.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/components/agent_policy_copy_provider.tsx @@ -37,13 +37,10 @@ export const AgentPolicyCopyProvider: React.FunctionComponent = ({ childr setIsModalOpen(true); setAgentPolicy(agentPolicyToCopy); setNewAgentPolicy({ - name: i18n.translate( - 'xpack.ingestManager.copyAgentPolicy.confirmModal.defaultNewPolicyName', - { - defaultMessage: '{name} (copy)', - values: { name: agentPolicyToCopy.name }, - } - ), + name: i18n.translate('xpack.fleet.copyAgentPolicy.confirmModal.defaultNewPolicyName', { + defaultMessage: '{name} (copy)', + values: { name: agentPolicyToCopy.name }, + }), description: agentPolicyToCopy.description, }); onSuccessCallback.current = onSuccess; @@ -63,7 +60,7 @@ export const AgentPolicyCopyProvider: React.FunctionComponent = ({ childr if (data) { notifications.toasts.addSuccess( - i18n.translate('xpack.ingestManager.copyAgentPolicy.successNotificationTitle', { + i18n.translate('xpack.fleet.copyAgentPolicy.successNotificationTitle', { defaultMessage: 'Agent policy copied', }) ); @@ -72,7 +69,7 @@ export const AgentPolicyCopyProvider: React.FunctionComponent = ({ childr } } else { notifications.toasts.addDanger( - i18n.translate('xpack.ingestManager.copyAgentPolicy.failureNotificationTitle', { + i18n.translate('xpack.fleet.copyAgentPolicy.failureNotificationTitle', { defaultMessage: "Error copying agent policy '{id}'", values: { id: agentPolicy!.id }, }) @@ -80,7 +77,7 @@ export const AgentPolicyCopyProvider: React.FunctionComponent = ({ childr } } catch (e) { notifications.toasts.addDanger( - i18n.translate('xpack.ingestManager.copyAgentPolicy.fatalErrorNotificationTitle', { + i18n.translate('xpack.fleet.copyAgentPolicy.fatalErrorNotificationTitle', { defaultMessage: 'Error copying agent policy', }) ); @@ -99,7 +96,7 @@ export const AgentPolicyCopyProvider: React.FunctionComponent = ({ childr title={ = ({ childr onConfirm={copyAgentPolicy} cancelButtonText={ } confirmButtonText={ } @@ -125,14 +122,14 @@ export const AgentPolicyCopyProvider: React.FunctionComponent = ({ childr >

    } @@ -147,7 +144,7 @@ export const AgentPolicyCopyProvider: React.FunctionComponent = ({ childr } diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/components/agent_policy_delete_provider.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/components/agent_policy_delete_provider.tsx index ab8a9c99227c5..41704f69958a0 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/components/agent_policy_delete_provider.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/components/agent_policy_delete_provider.tsx @@ -61,7 +61,7 @@ export const AgentPolicyDeleteProvider: React.FunctionComponent = ({ chil if (data) { notifications.toasts.addSuccess( - i18n.translate('xpack.ingestManager.deleteAgentPolicy.successSingleNotificationTitle', { + i18n.translate('xpack.fleet.deleteAgentPolicy.successSingleNotificationTitle', { defaultMessage: "Deleted agent policy '{id}'", values: { id: data.name || data.id }, }) @@ -71,7 +71,7 @@ export const AgentPolicyDeleteProvider: React.FunctionComponent = ({ chil } } else { notifications.toasts.addDanger( - i18n.translate('xpack.ingestManager.deleteAgentPolicy.failureSingleNotificationTitle', { + i18n.translate('xpack.fleet.deleteAgentPolicy.failureSingleNotificationTitle', { defaultMessage: "Error deleting agent policy '{id}'", values: { id: agentPolicy }, }) @@ -79,7 +79,7 @@ export const AgentPolicyDeleteProvider: React.FunctionComponent = ({ chil } } catch (e) { notifications.toasts.addDanger( - i18n.translate('xpack.ingestManager.deleteAgentPolicy.fatalErrorNotificationTitle', { + i18n.translate('xpack.fleet.deleteAgentPolicy.fatalErrorNotificationTitle', { defaultMessage: 'Error deleting agent policy', }) ); @@ -113,7 +113,7 @@ export const AgentPolicyDeleteProvider: React.FunctionComponent = ({ chil } @@ -121,19 +121,19 @@ export const AgentPolicyDeleteProvider: React.FunctionComponent = ({ chil onConfirm={deleteAgentPolicy} cancelButtonText={ } confirmButtonText={ isLoading || isLoadingAgentsCount ? ( ) : ( ) @@ -143,21 +143,21 @@ export const AgentPolicyDeleteProvider: React.FunctionComponent = ({ chil > {isLoadingAgentsCount ? ( ) : agentsCount ? ( = ({ chil ) : ( )} diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/components/agent_policy_form.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/components/agent_policy_form.tsx index c716f7b12e78c..919b6d3669a6b 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/components/agent_policy_form.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/components/agent_policy_form.tsx @@ -46,7 +46,7 @@ export const agentPolicyFormValidation = ( if (!agentPolicy.name?.trim()) { errors.name = [ , ]; @@ -88,12 +88,9 @@ export const AgentPolicyForm: React.FunctionComponent = ({ { name: 'name', label: ( - + ), - placeholder: i18n.translate('xpack.ingestManager.agentPolicyForm.nameFieldPlaceholder', { + placeholder: i18n.translate('xpack.fleet.agentPolicyForm.nameFieldPlaceholder', { defaultMessage: 'Choose a name', }), }, @@ -101,16 +98,13 @@ export const AgentPolicyForm: React.FunctionComponent = ({ name: 'description', label: ( ), - placeholder: i18n.translate( - 'xpack.ingestManager.agentPolicyForm.descriptionFieldPlaceholder', - { - defaultMessage: 'How will this policy be used?', - } - ), + placeholder: i18n.translate('xpack.fleet.agentPolicyForm.descriptionFieldPlaceholder', { + defaultMessage: 'How will this policy be used?', + }), }, ]; }, []); @@ -120,14 +114,14 @@ export const AgentPolicyForm: React.FunctionComponent = ({ title={

    } description={ } @@ -163,14 +157,14 @@ export const AgentPolicyForm: React.FunctionComponent = ({ title={

    } description={ } @@ -202,14 +196,14 @@ export const AgentPolicyForm: React.FunctionComponent = ({ title={

    } description={ } @@ -221,12 +215,12 @@ export const AgentPolicyForm: React.FunctionComponent = ({ label: ( <> {' '} = ({ label: ( <> {' '} = ({ title={

    @@ -298,7 +292,7 @@ export const AgentPolicyForm: React.FunctionComponent = ({ description={ <> @@ -311,7 +305,7 @@ export const AgentPolicyForm: React.FunctionComponent = ({ onClick={() => deleteAgentPolicyPrompt(agentPolicy.id!, onDelete)} > @@ -323,7 +317,7 @@ export const AgentPolicyForm: React.FunctionComponent = ({ @@ -343,7 +337,7 @@ export const AgentPolicyForm: React.FunctionComponent = ({ } @@ -353,12 +347,12 @@ export const AgentPolicyForm: React.FunctionComponent = ({ label={ <> {' '} = ({ id="advancedOptions" buttonContent={ } diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/components/agent_policy_yaml_flyout.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/components/agent_policy_yaml_flyout.tsx index fefb427df5ea6..773d53484147a 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/components/agent_policy_yaml_flyout.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/components/agent_policy_yaml_flyout.tsx @@ -41,7 +41,7 @@ export const AgentPolicyYamlFlyout = memo<{ policyId: string; onClose: () => voi } @@ -69,13 +69,13 @@ export const AgentPolicyYamlFlyout = memo<{ policyId: string; onClose: () => voi

    {agentPolicyData?.item ? ( ) : ( )} @@ -88,7 +88,7 @@ export const AgentPolicyYamlFlyout = memo<{ policyId: string; onClose: () => voi @@ -100,7 +100,7 @@ export const AgentPolicyYamlFlyout = memo<{ policyId: string; onClose: () => voi isDisabled={Boolean(isLoadingYaml && !yamlData)} > diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/components/confirm_deploy_modal.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/components/confirm_deploy_modal.tsx index d1a9b4812bfe0..9b88ee24651ba 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/components/confirm_deploy_modal.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/components/confirm_deploy_modal.tsx @@ -21,7 +21,7 @@ export const ConfirmDeployAgentPolicyModal: React.FunctionComponent<{ } @@ -29,13 +29,13 @@ export const ConfirmDeployAgentPolicyModal: React.FunctionComponent<{ onConfirm={onConfirm} cancelButtonText={ } confirmButtonText={ } @@ -43,7 +43,7 @@ export const ConfirmDeployAgentPolicyModal: React.FunctionComponent<{ >
    diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/components/linked_agent_count.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/components/linked_agent_count.tsx index 72e60ae678739..c602f492f74c6 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/components/linked_agent_count.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/components/linked_agent_count.tsx @@ -15,7 +15,7 @@ export const LinkedAgentCount = memo<{ count: number; agentPolicyId: string }>( const { getHref } = useLink(); const displayValue = ( diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/components/package_policy_delete_provider.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/components/package_policy_delete_provider.tsx index ff5961b94f726..8de40edc40331 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/components/package_policy_delete_provider.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/components/package_policy_delete_provider.tsx @@ -95,40 +95,28 @@ export const PackagePolicyDeleteProvider: React.FunctionComponent = ({ if (successfulResults.length) { const hasMultipleSuccesses = successfulResults.length > 1; const successMessage = hasMultipleSuccesses - ? i18n.translate( - 'xpack.ingestManager.deletePackagePolicy.successMultipleNotificationTitle', - { - defaultMessage: 'Deleted {count} integrations', - values: { count: successfulResults.length }, - } - ) - : i18n.translate( - 'xpack.ingestManager.deletePackagePolicy.successSingleNotificationTitle', - { - defaultMessage: "Deleted integration '{id}'", - values: { id: successfulResults[0].name || successfulResults[0].id }, - } - ); + ? i18n.translate('xpack.fleet.deletePackagePolicy.successMultipleNotificationTitle', { + defaultMessage: 'Deleted {count} integrations', + values: { count: successfulResults.length }, + }) + : i18n.translate('xpack.fleet.deletePackagePolicy.successSingleNotificationTitle', { + defaultMessage: "Deleted integration '{id}'", + values: { id: successfulResults[0].name || successfulResults[0].id }, + }); notifications.toasts.addSuccess(successMessage); } if (failedResults.length) { const hasMultipleFailures = failedResults.length > 1; const failureMessage = hasMultipleFailures - ? i18n.translate( - 'xpack.ingestManager.deletePackagePolicy.failureMultipleNotificationTitle', - { - defaultMessage: 'Error deleting {count} integrations', - values: { count: failedResults.length }, - } - ) - : i18n.translate( - 'xpack.ingestManager.deletePackagePolicy.failureSingleNotificationTitle', - { - defaultMessage: "Error deleting integration '{id}'", - values: { id: failedResults[0].id }, - } - ); + ? i18n.translate('xpack.fleet.deletePackagePolicy.failureMultipleNotificationTitle', { + defaultMessage: 'Error deleting {count} integrations', + values: { count: failedResults.length }, + }) + : i18n.translate('xpack.fleet.deletePackagePolicy.failureSingleNotificationTitle', { + defaultMessage: "Error deleting integration '{id}'", + values: { id: failedResults[0].id }, + }); notifications.toasts.addDanger(failureMessage); } @@ -137,7 +125,7 @@ export const PackagePolicyDeleteProvider: React.FunctionComponent = ({ } } catch (e) { notifications.toasts.addDanger( - i18n.translate('xpack.ingestManager.deletePackagePolicy.fatalErrorNotificationTitle', { + i18n.translate('xpack.fleet.deletePackagePolicy.fatalErrorNotificationTitle', { defaultMessage: 'Error deleting integration', }) ); @@ -157,7 +145,7 @@ export const PackagePolicyDeleteProvider: React.FunctionComponent = ({ @@ -166,19 +154,19 @@ export const PackagePolicyDeleteProvider: React.FunctionComponent = ({ onConfirm={deletePackagePolicies} cancelButtonText={ } confirmButtonText={ isLoading || isLoadingAgentsCount ? ( ) : ( = ({ > {isLoadingAgentsCount ? ( ) : agentsCount ? ( @@ -200,14 +188,14 @@ export const PackagePolicyDeleteProvider: React.FunctionComponent = ({ color="danger" title={ } > {agentPolicy.name}, @@ -219,7 +207,7 @@ export const PackagePolicyDeleteProvider: React.FunctionComponent = ({ ) : null} {!isLoadingAgentsCount && ( )} diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/create_package_policy_page/components/custom_package_policy.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/create_package_policy_page/components/custom_package_policy.tsx index 47c14ce0a3e81..d5163e1b9abbe 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/create_package_policy_page/components/custom_package_policy.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/create_package_policy_page/components/custom_package_policy.tsx @@ -46,7 +46,7 @@ const EmptyPackagePolicy: CustomConfigurePackagePolicyContent = () => (

    diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/create_package_policy_page/components/layout.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/create_package_policy_page/components/layout.tsx index 6edce74d162bb..9188f0069b8bf 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/create_package_policy_page/components/layout.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/create_package_policy_page/components/layout.tsx @@ -54,7 +54,7 @@ export const CreatePackagePolicyPageLayout: React.FunctionComponent<{

    {from === 'edit' ? ( ) : (

    @@ -89,7 +89,7 @@ export const CreatePackagePolicyPageLayout: React.FunctionComponent<{

    @@ -100,17 +100,17 @@ export const CreatePackagePolicyPageLayout: React.FunctionComponent<{ const pageDescription = useMemo(() => { return from === 'edit' ? ( ) : from === 'policy' ? ( ) : ( ); @@ -129,7 +129,7 @@ export const CreatePackagePolicyPageLayout: React.FunctionComponent<{ data-test-subj={`${dataTestSubj}_cancelBackLink`} > @@ -149,7 +149,7 @@ export const CreatePackagePolicyPageLayout: React.FunctionComponent<{ diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/create_package_policy_page/components/package_policy_input_config.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/create_package_policy_page/components/package_policy_input_config.tsx index e966ca30c4c97..175bfb1469902 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/create_package_policy_page/components/package_policy_input_config.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/create_package_policy_page/components/package_policy_input_config.tsx @@ -76,7 +76,7 @@ export const PackagePolicyInputConfig: React.FunctionComponent<{

    @@ -85,7 +85,7 @@ export const PackagePolicyInputConfig: React.FunctionComponent<{

    @@ -133,7 +133,7 @@ export const PackagePolicyInputConfig: React.FunctionComponent<{ flush="left" > @@ -142,7 +142,7 @@ export const PackagePolicyInputConfig: React.FunctionComponent<{ diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/create_package_policy_page/components/package_policy_input_panel.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/create_package_policy_page/components/package_policy_input_panel.tsx index 13504a1ed355a..1e43cc0d5938e 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/create_package_policy_page/components/package_policy_input_panel.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/create_package_policy_page/components/package_policy_input_panel.tsx @@ -133,7 +133,7 @@ export const PackagePolicyInputPanel: React.FunctionComponent<{ @@ -148,7 +148,7 @@ export const PackagePolicyInputPanel: React.FunctionComponent<{ aria-label={ isShowingStreams ? i18n.translate( - 'xpack.ingestManager.createPackagePolicy.stepConfigure.hideStreamsAriaLabel', + 'xpack.fleet.createPackagePolicy.stepConfigure.hideStreamsAriaLabel', { defaultMessage: 'Hide {type} inputs', values: { @@ -157,7 +157,7 @@ export const PackagePolicyInputPanel: React.FunctionComponent<{ } ) : i18n.translate( - 'xpack.ingestManager.createPackagePolicy.stepConfigure.showStreamsAriaLabel', + 'xpack.fleet.createPackagePolicy.stepConfigure.showStreamsAriaLabel', { defaultMessage: 'Show {type} inputs', values: { diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/create_package_policy_page/components/package_policy_input_stream.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/create_package_policy_page/components/package_policy_input_stream.tsx index cbc23f4079d9b..3d33edd468151 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/create_package_policy_page/components/package_policy_input_stream.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/create_package_policy_page/components/package_policy_input_stream.tsx @@ -135,7 +135,7 @@ export const PackagePolicyInputStreamConfig: React.FunctionComponent<{ flush="left" > @@ -144,7 +144,7 @@ export const PackagePolicyInputStreamConfig: React.FunctionComponent<{ diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/create_package_policy_page/components/package_policy_input_var_field.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/create_package_policy_page/components/package_policy_input_var_field.tsx index 3620b11948b54..9d036f5154b8f 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/create_package_policy_page/components/package_policy_input_var_field.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/create_package_policy_page/components/package_policy_input_var_field.tsx @@ -78,7 +78,7 @@ export const PackagePolicyInputVarField: React.FunctionComponent<{ !required ? ( diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/create_package_policy_page/index.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/create_package_policy_page/index.tsx index 70e11d46aa7f6..b45794b9f87db 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/create_package_policy_page/index.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/create_package_policy_page/index.tsx @@ -241,7 +241,7 @@ export const CreatePackagePolicyPage: React.FunctionComponent = () => { } notifications.toasts.addSuccess({ - title: i18n.translate('xpack.ingestManager.createPackagePolicy.addedNotificationTitle', { + title: i18n.translate('xpack.fleet.createPackagePolicy.addedNotificationTitle', { defaultMessage: `'{packagePolicyName}' integration added.`, values: { packagePolicyName: packagePolicy.name, @@ -249,7 +249,7 @@ export const CreatePackagePolicyPage: React.FunctionComponent = () => { }), text: agentCount && agentPolicy - ? i18n.translate('xpack.ingestManager.createPackagePolicy.addedNotificationMessage', { + ? i18n.translate('xpack.fleet.createPackagePolicy.addedNotificationMessage', { defaultMessage: `Fleet will deploy updates to all agents that use the '{agentPolicyName}' policy.`, values: { agentPolicyName: agentPolicy.name, @@ -338,27 +338,21 @@ export const CreatePackagePolicyPage: React.FunctionComponent = () => { const steps: EuiStepProps[] = [ from === 'package' ? { - title: i18n.translate( - 'xpack.ingestManager.createPackagePolicy.stepSelectAgentPolicyTitle', - { - defaultMessage: 'Select an agent policy', - } - ), + title: i18n.translate('xpack.fleet.createPackagePolicy.stepSelectAgentPolicyTitle', { + defaultMessage: 'Select an agent policy', + }), children: stepSelectAgentPolicy, } : { - title: i18n.translate('xpack.ingestManager.createPackagePolicy.stepSelectPackageTitle', { + title: i18n.translate('xpack.fleet.createPackagePolicy.stepSelectPackageTitle', { defaultMessage: 'Select an integration', }), children: stepSelectPackage, }, { - title: i18n.translate( - 'xpack.ingestManager.createPackagePolicy.stepConfigurePackagePolicyTitle', - { - defaultMessage: 'Configure integration', - } - ), + title: i18n.translate('xpack.fleet.createPackagePolicy.stepConfigurePackagePolicyTitle', { + defaultMessage: 'Configure integration', + }), status: !packageInfo || !agentPolicy || isLoadingSecondStep ? 'disabled' : undefined, 'data-test-subj': 'dataCollectionSetupStep', children: stepConfigurePackagePolicy, @@ -392,7 +386,7 @@ export const CreatePackagePolicyPage: React.FunctionComponent = () => { {!isLoadingSecondStep && agentPolicy && packageInfo && formState === 'INVALID' ? ( ) : null} @@ -408,7 +402,7 @@ export const CreatePackagePolicyPage: React.FunctionComponent = () => { data-test-subj="createPackagePolicyCancelButton" > @@ -424,7 +418,7 @@ export const CreatePackagePolicyPage: React.FunctionComponent = () => { data-test-subj="createPackagePolicySaveButton" > diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/create_package_policy_page/services/validate_package_policy.ts b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/create_package_policy_page/services/validate_package_policy.ts index 04cd21884e8f2..9ce73c0690ccb 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/create_package_policy_page/services/validate_package_policy.ts +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/create_package_policy_page/services/validate_package_policy.ts @@ -54,7 +54,7 @@ export const validatePackagePolicy = ( if (!packagePolicy.name.trim()) { validationResults.name = [ - i18n.translate('xpack.ingestManager.packagePolicyValidation.nameRequiredErrorMessage', { + i18n.translate('xpack.fleet.packagePolicyValidation.nameRequiredErrorMessage', { defaultMessage: 'Name is required', }), ]; @@ -183,7 +183,7 @@ export const validatePackagePolicyConfig = ( if (varDef.required) { if (parsedValue === undefined || (typeof parsedValue === 'string' && !parsedValue)) { errors.push( - i18n.translate('xpack.ingestManager.packagePolicyValidation.requiredErrorMessage', { + i18n.translate('xpack.fleet.packagePolicyValidation.requiredErrorMessage', { defaultMessage: '{fieldName} is required', values: { fieldName: varDef.title || varDef.name, @@ -198,12 +198,9 @@ export const validatePackagePolicyConfig = ( parsedValue = safeLoad(value); } catch (e) { errors.push( - i18n.translate( - 'xpack.ingestManager.packagePolicyValidation.invalidYamlFormatErrorMessage', - { - defaultMessage: 'Invalid YAML format', - } - ) + i18n.translate('xpack.fleet.packagePolicyValidation.invalidYamlFormatErrorMessage', { + defaultMessage: 'Invalid YAML format', + }) ); } } @@ -211,7 +208,7 @@ export const validatePackagePolicyConfig = ( if (varDef.multi) { if (parsedValue && !Array.isArray(parsedValue)) { errors.push( - i18n.translate('xpack.ingestManager.packagePolicyValidation.invalidArrayErrorMessage', { + i18n.translate('xpack.fleet.packagePolicyValidation.invalidArrayErrorMessage', { defaultMessage: 'Invalid format', }) ); @@ -221,7 +218,7 @@ export const validatePackagePolicyConfig = ( (!parsedValue || (Array.isArray(parsedValue) && parsedValue.length === 0)) ) { errors.push( - i18n.translate('xpack.ingestManager.packagePolicyValidation.requiredErrorMessage', { + i18n.translate('xpack.fleet.packagePolicyValidation.requiredErrorMessage', { defaultMessage: '{fieldName} is required', values: { fieldName: varDef.title || varDef.name, diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/create_package_policy_page/step_define_package_policy.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/create_package_policy_page/step_define_package_policy.tsx index 86f69208e0638..1d242848c3e2e 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/create_package_policy_page/step_define_package_policy.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/create_package_policy_page/step_define_package_policy.tsx @@ -87,14 +87,14 @@ export const StepDefinePackagePolicy: React.FunctionComponent<{ title={

    } description={ } @@ -106,7 +106,7 @@ export const StepDefinePackagePolicy: React.FunctionComponent<{ error={validationResults.name} label={ } @@ -126,14 +126,14 @@ export const StepDefinePackagePolicy: React.FunctionComponent<{ } labelAppend={ @@ -162,7 +162,7 @@ export const StepDefinePackagePolicy: React.FunctionComponent<{ flush="left" > @@ -171,7 +171,7 @@ export const StepDefinePackagePolicy: React.FunctionComponent<{ @@ -190,7 +190,7 @@ export const StepDefinePackagePolicy: React.FunctionComponent<{ error={validationResults.namespace} label={ } diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/create_package_policy_page/step_select_agent_policy.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/create_package_policy_page/step_select_agent_policy.tsx index ccf9e45ebc4fa..525a224146994 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/create_package_policy_page/step_select_agent_policy.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/create_package_policy_page/step_select_agent_policy.tsx @@ -171,7 +171,7 @@ export const StepSelectAgentPolicy: React.FunctionComponent<{ } @@ -186,7 +186,7 @@ export const StepSelectAgentPolicy: React.FunctionComponent<{ } @@ -219,7 +219,7 @@ export const StepSelectAgentPolicy: React.FunctionComponent<{ @@ -230,7 +230,7 @@ export const StepSelectAgentPolicy: React.FunctionComponent<{ onClick={() => setIsCreateAgentPolicyFlyoutOpen(true)} > @@ -241,7 +241,7 @@ export const StepSelectAgentPolicy: React.FunctionComponent<{ helpText={ isFleetReady && selectedPolicyId ? ( } diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/create_package_policy_page/step_select_package.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/create_package_policy_page/step_select_package.tsx index 704455b21d64a..8c646323c312c 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/create_package_policy_page/step_select_package.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/create_package_policy_page/step_select_package.tsx @@ -103,7 +103,7 @@ export const StepSelectPackage: React.FunctionComponent<{ } @@ -118,7 +118,7 @@ export const StepSelectPackage: React.FunctionComponent<{ } @@ -157,7 +157,7 @@ export const StepSelectPackage: React.FunctionComponent<{ }} searchProps={{ placeholder: i18n.translate( - 'xpack.ingestManager.createPackagePolicy.stepSelectPackage.filterPackagesInputPlaceholder', + 'xpack.fleet.createPackagePolicy.stepSelectPackage.filterPackagesInputPlaceholder', { defaultMessage: 'Search for integrations', } @@ -190,7 +190,7 @@ export const StepSelectPackage: React.FunctionComponent<{ } diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/details_page/components/package_policies/no_package_policies.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/details_page/components/package_policies/no_package_policies.tsx index b84466ee073eb..40682a28515ff 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/details_page/components/package_policies/no_package_policies.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/details_page/components/package_policies/no_package_policies.tsx @@ -18,14 +18,14 @@ export const NoPackagePolicies = memo<{ policyId: string }>(({ policyId }) => { title={

    } body={ } @@ -36,7 +36,7 @@ export const NoPackagePolicies = memo<{ policyId: string }>(({ policyId }) => { href={getHref('add_integration_from_policy', { policyId })} > diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/details_page/components/package_policies/package_policies_table.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/details_page/components/package_policies/package_policies_table.tsx index af4c2f78f14a2..c7268d581acc0 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/details_page/components/package_policies/package_policies_table.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/details_page/components/package_policies/package_policies_table.tsx @@ -84,12 +84,9 @@ export const PackagePoliciesTable: React.FunctionComponent = ({ { field: 'name', sortable: true, - name: i18n.translate( - 'xpack.ingestManager.policyDetails.packagePoliciesTable.nameColumnTitle', - { - defaultMessage: 'Name', - } - ), + name: i18n.translate('xpack.fleet.policyDetails.packagePoliciesTable.nameColumnTitle', { + defaultMessage: 'Name', + }), render: (value: string) => ( {value} @@ -99,7 +96,7 @@ export const PackagePoliciesTable: React.FunctionComponent = ({ { field: 'description', name: i18n.translate( - 'xpack.ingestManager.policyDetails.packagePoliciesTable.descriptionColumnTitle', + 'xpack.fleet.policyDetails.packagePoliciesTable.descriptionColumnTitle', { defaultMessage: 'Description', } @@ -114,7 +111,7 @@ export const PackagePoliciesTable: React.FunctionComponent = ({ field: 'packageTitle', sortable: true, name: i18n.translate( - 'xpack.ingestManager.policyDetails.packagePoliciesTable.packageNameColumnTitle', + 'xpack.fleet.policyDetails.packagePoliciesTable.packageNameColumnTitle', { defaultMessage: 'Integration', } @@ -140,7 +137,7 @@ export const PackagePoliciesTable: React.FunctionComponent = ({ { field: 'namespace', name: i18n.translate( - 'xpack.ingestManager.policyDetails.packagePoliciesTable.namespaceColumnTitle', + 'xpack.fleet.policyDetails.packagePoliciesTable.namespaceColumnTitle', { defaultMessage: 'Namespace', } @@ -150,12 +147,9 @@ export const PackagePoliciesTable: React.FunctionComponent = ({ }, }, { - name: i18n.translate( - 'xpack.ingestManager.policyDetails.packagePoliciesTable.actionsColumnTitle', - { - defaultMessage: 'Actions', - } - ), + name: i18n.translate('xpack.fleet.policyDetails.packagePoliciesTable.actionsColumnTitle', { + defaultMessage: 'Actions', + }), actions: [ { render: (packagePolicy: InMemoryPackagePolicy) => ( @@ -169,7 +163,7 @@ export const PackagePoliciesTable: React.FunctionComponent = ({ // key="packagePolicyView" // > // // , @@ -183,14 +177,14 @@ export const PackagePoliciesTable: React.FunctionComponent = ({ key="packagePolicyEdit" > , // FIXME: implement Copy package policy action // {}} key="packagePolicyCopy"> // // , @@ -205,7 +199,7 @@ export const PackagePoliciesTable: React.FunctionComponent = ({ }} > @@ -243,7 +237,7 @@ export const PackagePoliciesTable: React.FunctionComponent = ({ href={getHref('add_integration_from_policy', { policyId: agentPolicy.id })} > , diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/details_page/components/settings/index.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/details_page/components/settings/index.tsx index bc0457ffa0d43..fe3955c84dec3 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/details_page/components/settings/index.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/details_page/components/settings/index.tsx @@ -71,7 +71,7 @@ export const SettingsView = memo<{ agentPolicy: AgentPolicy }>( }); if (data) { notifications.toasts.addSuccess( - i18n.translate('xpack.ingestManager.editAgentPolicy.successNotificationTitle', { + i18n.translate('xpack.fleet.editAgentPolicy.successNotificationTitle', { defaultMessage: "Successfully updated '{name}' settings", values: { name: agentPolicy.name }, }) @@ -82,14 +82,14 @@ export const SettingsView = memo<{ agentPolicy: AgentPolicy }>( notifications.toasts.addDanger( error ? error.message - : i18n.translate('xpack.ingestManager.editAgentPolicy.errorNotificationTitle', { + : i18n.translate('xpack.fleet.editAgentPolicy.errorNotificationTitle', { defaultMessage: 'Unable to update agent policy', }) ); } } catch (e) { notifications.toasts.addDanger( - i18n.translate('xpack.ingestManager.editAgentPolicy.errorNotificationTitle', { + i18n.translate('xpack.fleet.editAgentPolicy.errorNotificationTitle', { defaultMessage: 'Unable to update agent policy', }) ); @@ -145,7 +145,7 @@ export const SettingsView = memo<{ agentPolicy: AgentPolicy }>( @@ -160,7 +160,7 @@ export const SettingsView = memo<{ agentPolicy: AgentPolicy }>( }} > @@ -178,12 +178,12 @@ export const SettingsView = memo<{ agentPolicy: AgentPolicy }>( > {isLoading ? ( ) : ( )} diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/details_page/index.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/details_page/index.tsx index 4be3108dd6eff..7528c923f0abd 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/details_page/index.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/details_page/index.tsx @@ -74,7 +74,7 @@ export const AgentPolicyDetailsPage: React.FunctionComponent = () => { size="xs" > @@ -87,7 +87,7 @@ export const AgentPolicyDetailsPage: React.FunctionComponent = () => { ) : ( (agentPolicy && agentPolicy.name) || ( { {[ { - label: i18n.translate('xpack.ingestManager.policyDetails.summary.revision', { + label: i18n.translate('xpack.fleet.policyDetails.summary.revision', { defaultMessage: 'Revision', }), content: agentPolicy?.revision ?? 0, }, { isDivider: true }, { - label: i18n.translate('xpack.ingestManager.policyDetails.summary.integrations', { + label: i18n.translate('xpack.fleet.policyDetails.summary.integrations', { defaultMessage: 'Integrations', }), content: ( @@ -141,7 +141,7 @@ export const AgentPolicyDetailsPage: React.FunctionComponent = () => { }, { isDivider: true }, { - label: i18n.translate('xpack.ingestManager.policyDetails.summary.usedBy', { + label: i18n.translate('xpack.fleet.policyDetails.summary.usedBy', { defaultMessage: 'Used by', }), content: ( @@ -153,7 +153,7 @@ export const AgentPolicyDetailsPage: React.FunctionComponent = () => { }, { isDivider: true }, { - label: i18n.translate('xpack.ingestManager.policyDetails.summary.lastUpdated', { + label: i18n.translate('xpack.fleet.policyDetails.summary.lastUpdated', { defaultMessage: 'Last updated on', }), content: @@ -217,7 +217,7 @@ export const AgentPolicyDetailsPage: React.FunctionComponent = () => { return [ { id: 'integrations', - name: i18n.translate('xpack.ingestManager.policyDetails.subTabs.packagePoliciesTabText', { + name: i18n.translate('xpack.fleet.policyDetails.subTabs.packagePoliciesTabText', { defaultMessage: 'Integrations', }), href: getHref('policy_details', { policyId, tabId: 'integrations' }), @@ -225,7 +225,7 @@ export const AgentPolicyDetailsPage: React.FunctionComponent = () => { }, { id: 'settings', - name: i18n.translate('xpack.ingestManager.policyDetails.subTabs.settingsTabText', { + name: i18n.translate('xpack.fleet.policyDetails.subTabs.settingsTabText', { defaultMessage: 'Settings', }), href: getHref('policy_details', { policyId, tabId: 'settings' }), @@ -248,7 +248,7 @@ export const AgentPolicyDetailsPage: React.FunctionComponent = () => { } @@ -262,11 +262,11 @@ export const AgentPolicyDetailsPage: React.FunctionComponent = () => { } - error={i18n.translate('xpack.ingestManager.policyDetails.policyNotFoundErrorTitle', { + error={i18n.translate('xpack.fleet.policyDetails.policyNotFoundErrorTitle', { defaultMessage: "Policy '{id}' not found", values: { id: policyId, diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/edit_package_policy_page/index.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/edit_package_policy_page/index.tsx index af4ffab12a791..d642619515a57 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/edit_package_policy_page/index.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/edit_package_policy_page/index.tsx @@ -214,7 +214,7 @@ export const EditPackagePolicyPage: React.FunctionComponent = () => { if (!error) { history.push(getPath('policy_details', { policyId })); notifications.toasts.addSuccess({ - title: i18n.translate('xpack.ingestManager.editPackagePolicy.updatedNotificationTitle', { + title: i18n.translate('xpack.fleet.editPackagePolicy.updatedNotificationTitle', { defaultMessage: `Successfully updated '{packagePolicyName}'`, values: { packagePolicyName: packagePolicy.name, @@ -222,7 +222,7 @@ export const EditPackagePolicyPage: React.FunctionComponent = () => { }), text: agentCount && agentPolicy - ? i18n.translate('xpack.ingestManager.editPackagePolicy.updatedNotificationMessage', { + ? i18n.translate('xpack.fleet.editPackagePolicy.updatedNotificationMessage', { defaultMessage: `Fleet will deploy updates to all agents that use the '{agentPolicyName}' policy`, values: { agentPolicyName: agentPolicy.name, @@ -233,14 +233,14 @@ export const EditPackagePolicyPage: React.FunctionComponent = () => { } else { if (error.statusCode === 409) { notifications.toasts.addError(error, { - title: i18n.translate('xpack.ingestManager.editPackagePolicy.failedNotificationTitle', { + title: i18n.translate('xpack.fleet.editPackagePolicy.failedNotificationTitle', { defaultMessage: `Error updating '{packagePolicyName}'`, values: { packagePolicyName: packagePolicy.name, }, }), toastMessage: i18n.translate( - 'xpack.ingestManager.editPackagePolicy.failedConflictNotificationMessage', + 'xpack.fleet.editPackagePolicy.failedConflictNotificationMessage', { defaultMessage: `Data is out of date. Refresh the page to get the latest policy.`, } @@ -248,7 +248,7 @@ export const EditPackagePolicyPage: React.FunctionComponent = () => { }); } else { notifications.toasts.addError(error, { - title: i18n.translate('xpack.ingestManager.editPackagePolicy.failedNotificationTitle', { + title: i18n.translate('xpack.fleet.editPackagePolicy.failedNotificationTitle', { defaultMessage: `Error updating '{packagePolicyName}'`, values: { packagePolicyName: packagePolicy.name, @@ -309,13 +309,13 @@ export const EditPackagePolicyPage: React.FunctionComponent = () => { } error={ loadingError || - i18n.translate('xpack.ingestManager.editPackagePolicy.errorLoadingDataMessage', { + i18n.translate('xpack.fleet.editPackagePolicy.errorLoadingDataMessage', { defaultMessage: 'There was an error loading this intergration information', }) } @@ -338,7 +338,7 @@ export const EditPackagePolicyPage: React.FunctionComponent = () => { {agentPolicy && packageInfo && formState === 'INVALID' ? ( ) : null} @@ -348,7 +348,7 @@ export const EditPackagePolicyPage: React.FunctionComponent = () => { @@ -363,7 +363,7 @@ export const EditPackagePolicyPage: React.FunctionComponent = () => { fill > diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/list_page/components/create_agent_policy.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/list_page/components/create_agent_policy.tsx index e3e2975777e17..d2c3fc64aa9e6 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/list_page/components/create_agent_policy.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/list_page/components/create_agent_policy.tsx @@ -66,7 +66,7 @@ export const CreateAgentPolicyFlyout: React.FunctionComponent = ({

    @@ -75,7 +75,7 @@ export const CreateAgentPolicyFlyout: React.FunctionComponent = ({

    @@ -101,7 +101,7 @@ export const CreateAgentPolicyFlyout: React.FunctionComponent = ({ onClose()} flush="left"> @@ -118,31 +118,25 @@ export const CreateAgentPolicyFlyout: React.FunctionComponent = ({ setIsLoading(false); if (data) { notifications.toasts.addSuccess( - i18n.translate( - 'xpack.ingestManager.createAgentPolicy.successNotificationTitle', - { - defaultMessage: "Agent policy '{name}' created", - values: { name: agentPolicy.name }, - } - ) + i18n.translate('xpack.fleet.createAgentPolicy.successNotificationTitle', { + defaultMessage: "Agent policy '{name}' created", + values: { name: agentPolicy.name }, + }) ); onClose(data.item); } else { notifications.toasts.addDanger( error ? error.message - : i18n.translate( - 'xpack.ingestManager.createAgentPolicy.errorNotificationTitle', - { - defaultMessage: 'Unable to create agent policy', - } - ) + : i18n.translate('xpack.fleet.createAgentPolicy.errorNotificationTitle', { + defaultMessage: 'Unable to create agent policy', + }) ); } } catch (e) { setIsLoading(false); notifications.toasts.addDanger( - i18n.translate('xpack.ingestManager.createAgentPolicy.errorNotificationTitle', { + i18n.translate('xpack.fleet.createAgentPolicy.errorNotificationTitle', { defaultMessage: 'Unable to create agent policy', }) ); @@ -150,7 +144,7 @@ export const CreateAgentPolicyFlyout: React.FunctionComponent = ({ }} > diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/list_page/index.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/list_page/index.tsx index aa4b42986a4f5..8c2fe838bfa43 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/list_page/index.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/list_page/index.tsx @@ -46,7 +46,7 @@ const AgentPolicyListPageLayout: React.FunctionComponent = ({ children }) => (

    @@ -56,7 +56,7 @@ const AgentPolicyListPageLayout: React.FunctionComponent = ({ children }) => (

    @@ -124,7 +124,7 @@ export const AgentPolicyListPage: React.FunctionComponent<{}> = () => { { field: 'name', sortable: true, - name: i18n.translate('xpack.ingestManager.agentPolicyList.nameColumnTitle', { + name: i18n.translate('xpack.fleet.agentPolicyList.nameColumnTitle', { defaultMessage: 'Name', }), width: '20%', @@ -142,7 +142,7 @@ export const AgentPolicyListPage: React.FunctionComponent<{}> = () => { @@ -153,7 +153,7 @@ export const AgentPolicyListPage: React.FunctionComponent<{}> = () => { }, { field: 'description', - name: i18n.translate('xpack.ingestManager.agentPolicyList.descriptionColumnTitle', { + name: i18n.translate('xpack.fleet.agentPolicyList.descriptionColumnTitle', { defaultMessage: 'Description', }), width: '35%', @@ -166,7 +166,7 @@ export const AgentPolicyListPage: React.FunctionComponent<{}> = () => { { field: 'updated_at', sortable: true, - name: i18n.translate('xpack.ingestManager.agentPolicyList.updatedOnColumnTitle', { + name: i18n.translate('xpack.fleet.agentPolicyList.updatedOnColumnTitle', { defaultMessage: 'Last updated on', }), render: (date: AgentPolicy['updated_at']) => ( @@ -175,7 +175,7 @@ export const AgentPolicyListPage: React.FunctionComponent<{}> = () => { }, { field: 'agents', - name: i18n.translate('xpack.ingestManager.agentPolicyList.agentsColumnTitle', { + name: i18n.translate('xpack.fleet.agentPolicyList.agentsColumnTitle', { defaultMessage: 'Agents', }), dataType: 'number', @@ -185,18 +185,15 @@ export const AgentPolicyListPage: React.FunctionComponent<{}> = () => { }, { field: 'package_policies', - name: i18n.translate( - 'xpack.ingestManager.agentPolicyList.packagePoliciesCountColumnTitle', - { - defaultMessage: 'Integrations', - } - ), + name: i18n.translate('xpack.fleet.agentPolicyList.packagePoliciesCountColumnTitle', { + defaultMessage: 'Integrations', + }), dataType: 'number', render: (packagePolicies: AgentPolicy['package_policies']) => packagePolicies ? packagePolicies.length : 0, }, { - name: i18n.translate('xpack.ingestManager.agentPolicyList.actionsColumnTitle', { + name: i18n.translate('xpack.fleet.agentPolicyList.actionsColumnTitle', { defaultMessage: 'Actions', }), actions: [ @@ -229,7 +226,7 @@ export const AgentPolicyListPage: React.FunctionComponent<{}> = () => { onClick={() => setIsCreateAgentPolicyFlyoutOpen(true)} > @@ -243,7 +240,7 @@ export const AgentPolicyListPage: React.FunctionComponent<{}> = () => { title={

    @@ -291,7 +288,7 @@ export const AgentPolicyListPage: React.FunctionComponent<{}> = () => { resendRequest()}> @@ -306,20 +303,20 @@ export const AgentPolicyListPage: React.FunctionComponent<{}> = () => { noItemsMessage={ isLoading ? ( ) : !search.trim() && (agentPolicyData?.total ?? 0) === 0 ? ( emptyPrompt ) : ( setSearch('')}> diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/data_stream/list_page/components/data_stream_row_actions.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/data_stream/list_page/components/data_stream_row_actions.tsx index 057970aa1ee92..90c0d848a5079 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/data_stream/list_page/components/data_stream_row_actions.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/data_stream/list_page/components/data_stream_row_actions.tsx @@ -16,18 +16,18 @@ export const DataStreamRowActions = memo<{ datastream: DataStream }>(({ datastre const panels = []; const actionNameSingular = ( ); const actionNamePlural = ( ); - const panelTitle = i18n.translate('xpack.ingestManager.dataStreamList.viewDashboardsPanelTitle', { + const panelTitle = i18n.translate('xpack.fleet.dataStreamList.viewDashboardsPanelTitle', { defaultMessage: 'View dashboards', }); diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/data_stream/list_page/index.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/data_stream/list_page/index.tsx index 4e32fa0bbc1b9..533c273681122 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/data_stream/list_page/index.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/data_stream/list_page/index.tsx @@ -31,7 +31,7 @@ const DataStreamListPageLayout: React.FunctionComponent = ({ children }) => (

    @@ -41,7 +41,7 @@ const DataStreamListPageLayout: React.FunctionComponent = ({ children }) => (

    @@ -75,21 +75,21 @@ export const DataStreamListPage: React.FunctionComponent<{}> = () => { field: 'dataset', sortable: true, width: '25%', - name: i18n.translate('xpack.ingestManager.dataStreamList.datasetColumnTitle', { + name: i18n.translate('xpack.fleet.dataStreamList.datasetColumnTitle', { defaultMessage: 'Dataset', }), }, { field: 'type', sortable: true, - name: i18n.translate('xpack.ingestManager.dataStreamList.typeColumnTitle', { + name: i18n.translate('xpack.fleet.dataStreamList.typeColumnTitle', { defaultMessage: 'Type', }), }, { field: 'namespace', sortable: true, - name: i18n.translate('xpack.ingestManager.dataStreamList.namespaceColumnTitle', { + name: i18n.translate('xpack.fleet.dataStreamList.namespaceColumnTitle', { defaultMessage: 'Namespace', }), render: (namespace: string) => { @@ -99,7 +99,7 @@ export const DataStreamListPage: React.FunctionComponent<{}> = () => { { field: 'package', sortable: true, - name: i18n.translate('xpack.ingestManager.dataStreamList.integrationColumnTitle', { + name: i18n.translate('xpack.fleet.dataStreamList.integrationColumnTitle', { defaultMessage: 'Integration', }), render(pkg: DataStream['package'], datastream: DataStream) { @@ -125,7 +125,7 @@ export const DataStreamListPage: React.FunctionComponent<{}> = () => { sortable: true, width: '25%', dataType: 'date', - name: i18n.translate('xpack.ingestManager.dataStreamList.lastActivityColumnTitle', { + name: i18n.translate('xpack.fleet.dataStreamList.lastActivityColumnTitle', { defaultMessage: 'Last activity', }), render: (date: DataStream['last_activity']) => { @@ -140,7 +140,7 @@ export const DataStreamListPage: React.FunctionComponent<{}> = () => { { field: 'size_in_bytes', sortable: true, - name: i18n.translate('xpack.ingestManager.dataStreamList.sizeColumnTitle', { + name: i18n.translate('xpack.fleet.dataStreamList.sizeColumnTitle', { defaultMessage: 'Size', }), render: (size: DataStream['size_in_bytes']) => { @@ -153,7 +153,7 @@ export const DataStreamListPage: React.FunctionComponent<{}> = () => { }, }, { - name: i18n.translate('xpack.ingestManager.dataStreamList.actionsColumnTitle', { + name: i18n.translate('xpack.fleet.dataStreamList.actionsColumnTitle', { defaultMessage: 'Actions', }), actions: [ @@ -172,7 +172,7 @@ export const DataStreamListPage: React.FunctionComponent<{}> = () => { title={

    @@ -236,14 +236,14 @@ export const DataStreamListPage: React.FunctionComponent<{}> = () => { message={ isLoading ? ( ) : dataStreamsData && !dataStreamsData.data_streams.length ? ( emptyPrompt ) : ( ) @@ -265,25 +265,22 @@ export const DataStreamListPage: React.FunctionComponent<{}> = () => { onClick={() => resendRequest()} > , ], box: { - placeholder: i18n.translate( - 'xpack.ingestManager.dataStreamList.searchPlaceholderTitle', - { - defaultMessage: 'Filter data streams', - } - ), + placeholder: i18n.translate('xpack.fleet.dataStreamList.searchPlaceholderTitle', { + defaultMessage: 'Filter data streams', + }), incremental: true, }, filters: [ { type: 'field_value_selection', field: 'dataset', - name: i18n.translate('xpack.ingestManager.dataStreamList.datasetColumnTitle', { + name: i18n.translate('xpack.fleet.dataStreamList.datasetColumnTitle', { defaultMessage: 'Dataset', }), multiSelect: 'or', @@ -293,7 +290,7 @@ export const DataStreamListPage: React.FunctionComponent<{}> = () => { { type: 'field_value_selection', field: 'type', - name: i18n.translate('xpack.ingestManager.dataStreamList.typeColumnTitle', { + name: i18n.translate('xpack.fleet.dataStreamList.typeColumnTitle', { defaultMessage: 'Type', }), multiSelect: 'or', @@ -303,7 +300,7 @@ export const DataStreamListPage: React.FunctionComponent<{}> = () => { { type: 'field_value_selection', field: 'namespace', - name: i18n.translate('xpack.ingestManager.dataStreamList.namespaceColumnTitle', { + name: i18n.translate('xpack.fleet.dataStreamList.namespaceColumnTitle', { defaultMessage: 'Namespace', }), multiSelect: 'or', @@ -313,7 +310,7 @@ export const DataStreamListPage: React.FunctionComponent<{}> = () => { { type: 'field_value_selection', field: 'package', - name: i18n.translate('xpack.ingestManager.dataStreamList.integrationColumnTitle', { + name: i18n.translate('xpack.fleet.dataStreamList.integrationColumnTitle', { defaultMessage: 'Integration', }), multiSelect: 'or', diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/components/assets_facet_group.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/components/assets_facet_group.tsx index b8fab92e40da8..87f83d39ad366 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/components/assets_facet_group.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/components/assets_facet_group.tsx @@ -79,7 +79,7 @@ export function AssetsFacetGroup({ assets }: { assets: AssetsGroupedByServiceByT

    ( diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/components/package_list_grid.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/components/package_list_grid.tsx index 0c1199f7c8867..ef3b94081b1d8 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/components/package_list_grid.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/components/package_list_grid.tsx @@ -75,7 +75,7 @@ export function PackageListGrid({ isLoading, controls, title, list }: ListProps)

    diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/components/release_badge.ts b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/components/release_badge.ts index f3520b4e7a9b3..735a5285baccd 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/components/release_badge.ts +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/components/release_badge.ts @@ -7,19 +7,19 @@ import { i18n } from '@kbn/i18n'; import { RegistryRelease } from '../../../types'; export const RELEASE_BADGE_LABEL: { [key in Exclude]: string } = { - beta: i18n.translate('xpack.ingestManager.epm.releaseBadge.betaLabel', { + beta: i18n.translate('xpack.fleet.epm.releaseBadge.betaLabel', { defaultMessage: 'Beta', }), - experimental: i18n.translate('xpack.ingestManager.epm.releaseBadge.experimentalLabel', { + experimental: i18n.translate('xpack.fleet.epm.releaseBadge.experimentalLabel', { defaultMessage: 'Experimental', }), }; export const RELEASE_BADGE_DESCRIPTION: { [key in Exclude]: string } = { - beta: i18n.translate('xpack.ingestManager.epm.releaseBadge.betaDescription', { + beta: i18n.translate('xpack.fleet.epm.releaseBadge.betaDescription', { defaultMessage: 'This integration is not recommended for use in production environments.', }), - experimental: i18n.translate('xpack.ingestManager.epm.releaseBadge.experimentalDescription', { + experimental: i18n.translate('xpack.fleet.epm.releaseBadge.experimentalDescription', { defaultMessage: 'This integration may have breaking changes or be removed in a future release.', }), }; diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/hooks/use_package_install.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/hooks/use_package_install.tsx index 2342a79932c85..8ab738fd8ff58 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/hooks/use_package_install.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/hooks/use_package_install.tsx @@ -73,14 +73,14 @@ function usePackageInstall({ notifications }: { notifications: NotificationsStar notifications.toasts.addWarning({ title: toMountPoint( ), text: toMountPoint( ), @@ -98,14 +98,14 @@ function usePackageInstall({ notifications }: { notifications: NotificationsStar notifications.toasts.addSuccess({ title: toMountPoint( ), text: toMountPoint( @@ -127,14 +127,14 @@ function usePackageInstall({ notifications }: { notifications: NotificationsStar notifications.toasts.addWarning({ title: toMountPoint( ), text: toMountPoint( ), @@ -146,14 +146,14 @@ function usePackageInstall({ notifications }: { notifications: NotificationsStar notifications.toasts.addSuccess({ title: toMountPoint( ), text: toMountPoint( diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/screens/detail/confirm_package_install.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/screens/detail/confirm_package_install.tsx index ac30815a941ee..d34d947de33ab 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/screens/detail/confirm_package_install.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/screens/detail/confirm_package_install.tsx @@ -20,7 +20,7 @@ export const ConfirmPackageInstall = (props: ConfirmPackageInstallProps) => { @@ -29,13 +29,13 @@ export const ConfirmPackageInstall = (props: ConfirmPackageInstallProps) => { onConfirm={onConfirm} cancelButtonText={ } confirmButtonText={ @@ -46,7 +46,7 @@ export const ConfirmPackageInstall = (props: ConfirmPackageInstallProps) => { iconType="iInCircle" title={ @@ -55,7 +55,7 @@ export const ConfirmPackageInstall = (props: ConfirmPackageInstallProps) => {

    diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/screens/detail/confirm_package_uninstall.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/screens/detail/confirm_package_uninstall.tsx index f4d5226ebe950..24ef18e1f979c 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/screens/detail/confirm_package_uninstall.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/screens/detail/confirm_package_uninstall.tsx @@ -20,7 +20,7 @@ export const ConfirmPackageUninstall = (props: ConfirmPackageUninstallProps) => @@ -29,13 +29,13 @@ export const ConfirmPackageUninstall = (props: ConfirmPackageUninstallProps) => onConfirm={onConfirm} cancelButtonText={ } confirmButtonText={ @@ -47,7 +47,7 @@ export const ConfirmPackageUninstall = (props: ConfirmPackageUninstallProps) => color="danger" title={ @@ -55,7 +55,7 @@ export const ConfirmPackageUninstall = (props: ConfirmPackageUninstallProps) => >

    @@ -63,7 +63,7 @@ export const ConfirmPackageUninstall = (props: ConfirmPackageUninstallProps) =>

    diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/screens/detail/index.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/screens/detail/index.tsx index 84d3f97f3ee05..7e7958ce91afe 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/screens/detail/index.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/screens/detail/index.tsx @@ -109,7 +109,7 @@ export function Detail() { href={getHref('integrations_all')} > @@ -161,7 +161,7 @@ export function Detail() { {[ { - label: i18n.translate('xpack.ingestManager.epm.versionLabel', { + label: i18n.translate('xpack.fleet.epm.versionLabel', { defaultMessage: 'Version', }), content: ( @@ -187,7 +187,7 @@ export function Detail() { })} > } diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/screens/detail/installation_button.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/screens/detail/installation_button.tsx index cdad67fd87548..306865075c63b 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/screens/detail/installation_button.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/screens/detail/installation_button.tsx @@ -66,7 +66,7 @@ export function InstallationButton(props: InstallationButtonProps) { {isInstalling ? ( ) : ( @@ -103,7 +103,7 @@ export function InstallationButton(props: InstallationButtonProps) { > {isRemoving ? ( ) : (

    - +

    diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/screens/detail/settings_panel.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/screens/detail/settings_panel.tsx index 4ac6fe6872e17..814b05163d20c 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/screens/detail/settings_panel.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/screens/detail/settings_panel.tsx @@ -27,7 +27,7 @@ const UpdatesAvailableMsgContainer = styled.span` const NoteLabel = () => ( ); @@ -35,7 +35,7 @@ const UpdatesAvailableMsg = () => ( @@ -67,7 +67,7 @@ export const SettingsPanel = (

    @@ -78,7 +78,7 @@ export const SettingsPanel = (

    @@ -106,7 +106,7 @@ export const SettingsPanel = ( @@ -139,7 +139,7 @@ export const SettingsPanel = (

    @@ -193,7 +193,7 @@ export const SettingsPanel = ( {packageHasUsages && removable === true && (

    & { }; const PanelDisplayNames: Record = { - overview: i18n.translate('xpack.ingestManager.epm.packageDetailsNav.overviewLinkText', { + overview: i18n.translate('xpack.fleet.epm.packageDetailsNav.overviewLinkText', { defaultMessage: 'Overview', }), - usages: i18n.translate('xpack.ingestManager.epm.packageDetailsNav.packagePoliciesLinkText', { + usages: i18n.translate('xpack.fleet.epm.packageDetailsNav.packagePoliciesLinkText', { defaultMessage: 'Usages', }), - settings: i18n.translate('xpack.ingestManager.epm.packageDetailsNav.settingsLinkText', { + settings: i18n.translate('xpack.fleet.epm.packageDetailsNav.settingsLinkText', { defaultMessage: 'Settings', }), }; diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/screens/home/header.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/screens/home/header.tsx index 363b1ede89e9e..e9704cd16b219 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/screens/home/header.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/screens/home/header.tsx @@ -18,10 +18,7 @@ export const HeroCopy = memo(() => {

    - +

    @@ -29,7 +26,7 @@ export const HeroCopy = memo(() => {

    @@ -51,7 +48,7 @@ export const HeroImage = memo(() => { return ( ), @@ -91,7 +91,7 @@ export const AgentDetailsActionMenu: React.FunctionComponent<{ key="reassignPolicy" > , @@ -104,12 +104,12 @@ export const AgentDetailsActionMenu: React.FunctionComponent<{ > {isUnenrolling ? ( ) : ( )} @@ -122,7 +122,7 @@ export const AgentDetailsActionMenu: React.FunctionComponent<{ }} > , diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_details_page/components/agent_details.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_details_page/components/agent_details.tsx index 2493fda3317d2..5ce757734e637 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_details_page/components/agent_details.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_details_page/components/agent_details.tsx @@ -31,7 +31,7 @@ export const AgentDetailsContent: React.FunctionComponent<{ {[ { - title: i18n.translate('xpack.ingestManager.agentDetails.hostNameLabel', { + title: i18n.translate('xpack.fleet.agentDetails.hostNameLabel', { defaultMessage: 'Host name', }), description: @@ -41,19 +41,19 @@ export const AgentDetailsContent: React.FunctionComponent<{ : '-', }, { - title: i18n.translate('xpack.ingestManager.agentDetails.hostIdLabel', { + title: i18n.translate('xpack.fleet.agentDetails.hostIdLabel', { defaultMessage: 'Agent ID', }), description: agent.id, }, { - title: i18n.translate('xpack.ingestManager.agentDetails.statusLabel', { + title: i18n.translate('xpack.fleet.agentDetails.statusLabel', { defaultMessage: 'Status', }), description: , }, { - title: i18n.translate('xpack.ingestManager.agentDetails.agentPolicyLabel', { + title: i18n.translate('xpack.fleet.agentDetails.agentPolicyLabel', { defaultMessage: 'Agent policy', }), description: agentPolicy ? ( @@ -68,7 +68,7 @@ export const AgentDetailsContent: React.FunctionComponent<{ ), }, { - title: i18n.translate('xpack.ingestManager.agentDetails.versionLabel', { + title: i18n.translate('xpack.fleet.agentDetails.versionLabel', { defaultMessage: 'Agent version', }), description: @@ -85,7 +85,7 @@ export const AgentDetailsContent: React.FunctionComponent<{  
    @@ -97,7 +97,7 @@ export const AgentDetailsContent: React.FunctionComponent<{ ), }, { - title: i18n.translate('xpack.ingestManager.agentDetails.releaseLabel', { + title: i18n.translate('xpack.fleet.agentDetails.releaseLabel', { defaultMessage: 'Agent release', }), description: @@ -110,7 +110,7 @@ export const AgentDetailsContent: React.FunctionComponent<{ : '-', }, { - title: i18n.translate('xpack.ingestManager.agentDetails.platformLabel', { + title: i18n.translate('xpack.fleet.agentDetails.platformLabel', { defaultMessage: 'Platform', }), description: diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_details_page/components/agent_events_table.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_details_page/components/agent_events_table.tsx index e11863a2db85f..c1a1b3862728d 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_details_page/components/agent_events_table.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_details_page/components/agent_events_table.tsx @@ -78,7 +78,7 @@ export const AgentEventsTable: React.FunctionComponent<{ agent: Agent }> = ({ ag @@ -92,7 +92,7 @@ export const AgentEventsTable: React.FunctionComponent<{ agent: Agent }> = ({ ag @@ -113,7 +113,7 @@ export const AgentEventsTable: React.FunctionComponent<{ agent: Agent }> = ({ ag const columns = [ { field: 'timestamp', - name: i18n.translate('xpack.ingestManager.agentEventsList.timestampColumnTitle', { + name: i18n.translate('xpack.fleet.agentEventsList.timestampColumnTitle', { defaultMessage: 'Timestamp', }), render: (timestamp: string) => ( @@ -132,7 +132,7 @@ export const AgentEventsTable: React.FunctionComponent<{ agent: Agent }> = ({ ag }, { field: 'type', - name: i18n.translate('xpack.ingestManager.agentEventsList.typeColumnTitle', { + name: i18n.translate('xpack.fleet.agentEventsList.typeColumnTitle', { defaultMessage: 'Type', }), width: '10%', @@ -141,7 +141,7 @@ export const AgentEventsTable: React.FunctionComponent<{ agent: Agent }> = ({ ag }, { field: 'subtype', - name: i18n.translate('xpack.ingestManager.agentEventsList.subtypeColumnTitle', { + name: i18n.translate('xpack.fleet.agentEventsList.subtypeColumnTitle', { defaultMessage: 'Subtype', }), width: '13%', @@ -150,7 +150,7 @@ export const AgentEventsTable: React.FunctionComponent<{ agent: Agent }> = ({ ag }, { field: 'message', - name: i18n.translate('xpack.ingestManager.agentEventsList.messageColumnTitle', { + name: i18n.translate('xpack.fleet.agentEventsList.messageColumnTitle', { defaultMessage: 'Message', }), render: (value: string) => ( @@ -168,10 +168,10 @@ export const AgentEventsTable: React.FunctionComponent<{ agent: Agent }> = ({ ag onClick={() => toggleDetails(agentEvent)} aria-label={ itemIdToExpandedRowMap[agentEvent.id] - ? i18n.translate('xpack.ingestManager.agentEventsList.collapseDetailsAriaLabel', { + ? i18n.translate('xpack.fleet.agentEventsList.collapseDetailsAriaLabel', { defaultMessage: 'Hide details', }) - : i18n.translate('xpack.ingestManager.agentEventsList.expandDetailsAriaLabel', { + : i18n.translate('xpack.fleet.agentEventsList.expandDetailsAriaLabel', { defaultMessage: 'Show details', }) } @@ -203,16 +203,15 @@ export const AgentEventsTable: React.FunctionComponent<{ agent: Agent }> = ({ ag value={search} onChange={setSearch} fieldPrefix={AGENT_EVENT_SAVED_OBJECT_TYPE} - placeholder={i18n.translate( - 'xpack.ingestManager.agentEventsList.searchPlaceholderText', - { defaultMessage: 'Search for activity logs' } - )} + placeholder={i18n.translate('xpack.fleet.agentEventsList.searchPlaceholderText', { + defaultMessage: 'Search for activity logs', + })} /> diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_details_page/components/metadata_flyout.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_details_page/components/metadata_flyout.tsx index 96c09677a677f..f808f4ade107b 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_details_page/components/metadata_flyout.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_details_page/components/metadata_flyout.tsx @@ -41,7 +41,7 @@ export const AgentMetadataFlyout: React.FunctionComponent = ({ agent, fly

    @@ -51,7 +51,7 @@ export const AgentMetadataFlyout: React.FunctionComponent = ({ agent, fly

    @@ -62,7 +62,7 @@ export const AgentMetadataFlyout: React.FunctionComponent = ({ agent, fly

    diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_details_page/components/metadata_form.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_details_page/components/metadata_form.tsx index af7e8c674db4c..fd8de709c172a 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_details_page/components/metadata_form.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_details_page/components/metadata_form.tsx @@ -106,10 +106,7 @@ export const MetadataForm: React.FunctionComponent<{ agent: Agent }> = ({ agent const button = ( setOpen(true)} color={'text'}> - + ); return ( @@ -128,7 +125,7 @@ export const MetadataForm: React.FunctionComponent<{ agent: Agent }> = ({ agent @@ -137,7 +134,7 @@ export const MetadataForm: React.FunctionComponent<{ agent: Agent }> = ({ agent @@ -148,7 +145,7 @@ export const MetadataForm: React.FunctionComponent<{ agent: Agent }> = ({ agent diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_details_page/components/type_labels.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_details_page/components/type_labels.tsx index f597b9c72ab02..dbe18ab333736 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_details_page/components/type_labels.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_details_page/components/type_labels.tsx @@ -12,28 +12,25 @@ import { AgentEvent } from '../../../../types'; export const TYPE_LABEL: { [key in AgentEvent['type']]: JSX.Element } = { STATE: ( - + ), ERROR: ( - + ), ACTION_RESULT: ( ), ACTION: ( - + ), }; @@ -41,16 +38,13 @@ export const TYPE_LABEL: { [key in AgentEvent['type']]: JSX.Element } = { export const SUBTYPE_LABEL: { [key in AgentEvent['subtype']]: JSX.Element } = { RUNNING: ( - + ), STARTING: ( @@ -58,47 +52,38 @@ export const SUBTYPE_LABEL: { [key in AgentEvent['subtype']]: JSX.Element } = { IN_PROGRESS: ( ), CONFIG: ( - + ), FAILED: ( - + ), STOPPING: ( ), STOPPED: ( - + ), DEGRADED: ( @@ -106,7 +91,7 @@ export const SUBTYPE_LABEL: { [key in AgentEvent['subtype']]: JSX.Element } = { DATA_DUMP: ( @@ -114,7 +99,7 @@ export const SUBTYPE_LABEL: { [key in AgentEvent['subtype']]: JSX.Element } = { ACKNOWLEDGED: ( @@ -122,17 +107,14 @@ export const SUBTYPE_LABEL: { [key in AgentEvent['subtype']]: JSX.Element } = { UPDATING: ( ), UNKNOWN: ( - + ), }; diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_details_page/index.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_details_page/index.tsx index ddd234aaa1da0..7d60ae23deac6 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_details_page/index.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_details_page/index.tsx @@ -89,7 +89,7 @@ export const AgentDetailsPage: React.FunctionComponent = () => { size="xs" > @@ -104,7 +104,7 @@ export const AgentDetailsPage: React.FunctionComponent = () => { agentData.item.local_metadata.host.hostname ) : ( { {[ { - label: i18n.translate('xpack.ingestManager.agentDetails.statusLabel', { + label: i18n.translate('xpack.fleet.agentDetails.statusLabel', { defaultMessage: 'Status', }), content: , }, { isDivider: true }, { - label: i18n.translate('xpack.ingestManager.agentDetails.policyLabel', { + label: i18n.translate('xpack.fleet.agentDetails.policyLabel', { defaultMessage: 'Policy', }), content: isAgentPolicyLoading ? ( @@ -150,7 +150,7 @@ export const AgentDetailsPage: React.FunctionComponent = () => { }, { isDivider: true }, { - label: i18n.translate('xpack.ingestManager.agentDetails.agentVersionLabel', { + label: i18n.translate('xpack.fleet.agentDetails.agentVersionLabel', { defaultMessage: 'Agent version', }), content: @@ -165,7 +165,7 @@ export const AgentDetailsPage: React.FunctionComponent = () => { { type="alert" color="warning" content={i18n.translate( - 'xpack.ingestManager.agentDetails.upgradeAvailableTooltip', + 'xpack.fleet.agentDetails.upgradeAvailableTooltip', { defaultMessage: 'Upgrade available', } @@ -225,7 +225,7 @@ export const AgentDetailsPage: React.FunctionComponent = () => { return [ { id: 'activity_log', - name: i18n.translate('xpack.ingestManager.agentDetails.subTabs.activityLogTab', { + name: i18n.translate('xpack.fleet.agentDetails.subTabs.activityLogTab', { defaultMessage: 'Activity log', }), href: getHref('fleet_agent_details', { agentId, tabId: 'activity' }), @@ -233,7 +233,7 @@ export const AgentDetailsPage: React.FunctionComponent = () => { }, { id: 'details', - name: i18n.translate('xpack.ingestManager.agentDetails.subTabs.detailsTab', { + name: i18n.translate('xpack.fleet.agentDetails.subTabs.detailsTab', { defaultMessage: 'Agent details', }), href: getHref('fleet_agent_details', { agentId, tabId: 'details' }), @@ -262,7 +262,7 @@ export const AgentDetailsPage: React.FunctionComponent = () => { } @@ -274,19 +274,16 @@ export const AgentDetailsPage: React.FunctionComponent = () => { } - error={i18n.translate( - 'xpack.ingestManager.agentDetails.agentNotFoundErrorDescription', - { - defaultMessage: 'Cannot find agent ID {agentId}', - values: { - agentId, - }, - } - )} + error={i18n.translate('xpack.fleet.agentDetails.agentNotFoundErrorDescription', { + defaultMessage: 'Cannot find agent ID {agentId}', + values: { + agentId, + }, + })} /> )} diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/components/bulk_actions.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/components/bulk_actions.tsx index b628cc662f829..15b4a75188061 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/components/bulk_actions.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/components/bulk_actions.tsx @@ -88,7 +88,7 @@ export const AgentBulkActions: React.FunctionComponent<{ { name: ( ), @@ -102,7 +102,7 @@ export const AgentBulkActions: React.FunctionComponent<{ { name: ( ), @@ -116,7 +116,7 @@ export const AgentBulkActions: React.FunctionComponent<{ { name: ( ), @@ -130,7 +130,7 @@ export const AgentBulkActions: React.FunctionComponent<{ { name: ( ), @@ -192,7 +192,7 @@ export const AgentBulkActions: React.FunctionComponent<{ {totalAgents > SO_SEARCH_LIMIT ? ( , @@ -201,7 +201,7 @@ export const AgentBulkActions: React.FunctionComponent<{ /> ) : ( @@ -226,7 +226,7 @@ export const AgentBulkActions: React.FunctionComponent<{ onClick={openMenu} > setSelectionMode('query')} > diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/index.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/index.tsx index bc37338f04394..d46d2aa442745 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/index.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/index.tsx @@ -53,26 +53,26 @@ const REFRESH_INTERVAL_MS = 5000; const statusFilters = [ { status: 'online', - label: i18n.translate('xpack.ingestManager.agentList.statusOnlineFilterText', { + label: i18n.translate('xpack.fleet.agentList.statusOnlineFilterText', { defaultMessage: 'Online', }), }, { status: 'offline', - label: i18n.translate('xpack.ingestManager.agentList.statusOfflineFilterText', { + label: i18n.translate('xpack.fleet.agentList.statusOfflineFilterText', { defaultMessage: 'Offline', }), }, , { status: 'error', - label: i18n.translate('xpack.ingestManager.agentList.statusErrorFilterText', { + label: i18n.translate('xpack.fleet.agentList.statusErrorFilterText', { defaultMessage: 'Error', }), }, { status: 'updating', - label: i18n.translate('xpack.ingestManager.agentList.statusUpdatingFilterText', { + label: i18n.translate('xpack.fleet.agentList.statusUpdatingFilterText', { defaultMessage: 'Updating', }), }, @@ -101,10 +101,7 @@ const RowActions = React.memo<{ href={getHref('fleet_agent_details', { agentId: agent.id })} key="viewAgent" > - + , , @@ -128,12 +125,12 @@ const RowActions = React.memo<{ > {isUnenrolling ? ( ) : ( )} @@ -146,7 +143,7 @@ const RowActions = React.memo<{ }} > , @@ -294,7 +291,7 @@ export const AgentListPage: React.FunctionComponent<{}> = () => { const columns = [ { field: 'local_metadata.host.hostname', - name: i18n.translate('xpack.ingestManager.agentList.hostColumnTitle', { + name: i18n.translate('xpack.fleet.agentList.hostColumnTitle', { defaultMessage: 'Host', }), render: (host: string, agent: Agent) => ( @@ -306,14 +303,14 @@ export const AgentListPage: React.FunctionComponent<{}> = () => { { field: 'active', width: '120px', - name: i18n.translate('xpack.ingestManager.agentList.statusColumnTitle', { + name: i18n.translate('xpack.fleet.agentList.statusColumnTitle', { defaultMessage: 'Status', }), render: (active: boolean, agent: any) => , }, { field: 'policy_id', - name: i18n.translate('xpack.ingestManager.agentList.policyColumnTitle', { + name: i18n.translate('xpack.fleet.agentList.policyColumnTitle', { defaultMessage: 'Agent policy', }), render: (policyId: string, agent: Agent) => { @@ -333,7 +330,7 @@ export const AgentListPage: React.FunctionComponent<{}> = () => { @@ -351,7 +348,7 @@ export const AgentListPage: React.FunctionComponent<{}> = () => { {true && ( <> @@ -366,7 +363,7 @@ export const AgentListPage: React.FunctionComponent<{}> = () => { { field: 'local_metadata.elastic.agent.version', width: '200px', - name: i18n.translate('xpack.ingestManager.agentList.versionTitle', { + name: i18n.translate('xpack.fleet.agentList.versionTitle', { defaultMessage: 'Version', }), render: (version: string, agent: Agent) => ( @@ -380,7 +377,7 @@ export const AgentListPage: React.FunctionComponent<{}> = () => {   @@ -391,14 +388,14 @@ export const AgentListPage: React.FunctionComponent<{}> = () => { }, { field: 'last_checkin', - name: i18n.translate('xpack.ingestManager.agentList.lastCheckinTitle', { + name: i18n.translate('xpack.fleet.agentList.lastCheckinTitle', { defaultMessage: 'Last activity', }), render: (lastCheckin: string, agent: any) => lastCheckin ? : null, }, { - name: i18n.translate('xpack.ingestManager.agentList.actionsColumnTitle', { + name: i18n.translate('xpack.fleet.agentList.actionsColumnTitle', { defaultMessage: 'Actions', }), actions: [ @@ -425,7 +422,7 @@ export const AgentListPage: React.FunctionComponent<{}> = () => { title={

    @@ -433,10 +430,7 @@ export const AgentListPage: React.FunctionComponent<{}> = () => { actions={ hasWriteCapabilites ? ( setIsEnrollmentFlyoutOpen(true)}> - + ) : null } @@ -521,7 +515,7 @@ export const AgentListPage: React.FunctionComponent<{}> = () => { disabled={isAgentPoliciesLoading} > @@ -561,7 +555,7 @@ export const AgentListPage: React.FunctionComponent<{}> = () => { disabled={isAgentPoliciesLoading} > @@ -595,7 +589,7 @@ export const AgentListPage: React.FunctionComponent<{}> = () => { }} > @@ -604,7 +598,7 @@ export const AgentListPage: React.FunctionComponent<{}> = () => { onClick={() => setShowInactive(!showInactive)} > @@ -645,18 +639,18 @@ export const AgentListPage: React.FunctionComponent<{}> = () => { noItemsMessage={ isLoading && agentsRequest.isInitialRequest ? ( ) : isUsingFilter ? ( clearFilters()}> diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/components/agent_enrollment_flyout/agent_policy_selection.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/components/agent_enrollment_flyout/agent_policy_selection.tsx index 874d42a8db095..758497607c057 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/components/agent_enrollment_flyout/agent_policy_selection.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/components/agent_enrollment_flyout/agent_policy_selection.tsx @@ -155,7 +155,7 @@ export const EnrollmentStepAgentPolicy: React.FC = (props) => { prepend={ @@ -172,10 +172,9 @@ export const EnrollmentStepAgentPolicy: React.FC = (props) => { enrollmentAPIKeyId: undefined, }) } - aria-label={i18n.translate( - 'xpack.ingestManager.enrollmentStepAgentPolicy.policySelectAriaLabel', - { defaultMessage: 'Agent policy' } - )} + aria-label={i18n.translate('xpack.fleet.enrollmentStepAgentPolicy.policySelectAriaLabel', { + defaultMessage: 'Agent policy', + })} /> {selectedState.agentPolicyId && ( @@ -190,7 +189,7 @@ export const EnrollmentStepAgentPolicy: React.FC = (props) => { onClick={() => setIsAuthenticationSettingsOpen(!isAuthenticationSettingsOpen)} > @@ -207,7 +206,7 @@ export const EnrollmentStepAgentPolicy: React.FC = (props) => { prepend={ diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/components/agent_enrollment_flyout/index.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/components/agent_enrollment_flyout/index.tsx index 05817f28f9292..cc7c2ea778951 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/components/agent_enrollment_flyout/index.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/components/agent_enrollment_flyout/index.tsx @@ -41,7 +41,7 @@ export const AgentEnrollmentFlyout: React.FunctionComponent = ({

    @@ -49,7 +49,7 @@ export const AgentEnrollmentFlyout: React.FunctionComponent = ({ @@ -57,13 +57,13 @@ export const AgentEnrollmentFlyout: React.FunctionComponent = ({ setMode('managed')}> setMode('standalone')}> @@ -82,7 +82,7 @@ export const AgentEnrollmentFlyout: React.FunctionComponent = ({ @@ -90,7 +90,7 @@ export const AgentEnrollmentFlyout: React.FunctionComponent = ({ diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/components/agent_enrollment_flyout/managed_instructions.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/components/agent_enrollment_flyout/managed_instructions.tsx index e620424f88f4e..656493e31e5f5 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/components/agent_enrollment_flyout/managed_instructions.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/components/agent_enrollment_flyout/managed_instructions.tsx @@ -45,7 +45,7 @@ export const ManagedInstructions = React.memo(({ agentPolicies }) => { DownloadStep(), AgentPolicySelectionStep({ agentPolicies, setSelectedAPIKeyId }), { - title: i18n.translate('xpack.ingestManager.agentEnrollment.stepEnrollAndRunAgentTitle', { + title: i18n.translate('xpack.fleet.agentEnrollment.stepEnrollAndRunAgentTitle', { defaultMessage: 'Enroll and start the Elastic Agent', }), children: apiKey.data && ( @@ -62,7 +62,7 @@ export const ManagedInstructions = React.memo(({ agentPolicies }) => { <> @@ -74,13 +74,13 @@ export const ManagedInstructions = React.memo(({ agentPolicies }) => { ) : ( <> diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/components/agent_enrollment_flyout/standalone_instructions.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/components/agent_enrollment_flyout/standalone_instructions.tsx index 3e5cf236e63dc..a2daf2d10c271 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/components/agent_enrollment_flyout/standalone_instructions.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/components/agent_enrollment_flyout/standalone_instructions.tsx @@ -75,14 +75,14 @@ export const StandaloneInstructions = React.memo(({ agentPolicies }) => { DownloadStep(), AgentPolicySelectionStep({ agentPolicies, setSelectedPolicyId }), { - title: i18n.translate('xpack.ingestManager.agentEnrollment.stepConfigureAgentTitle', { + title: i18n.translate('xpack.fleet.agentEnrollment.stepConfigureAgentTitle', { defaultMessage: 'Configure the agent', }), children: ( <> elastic-agent.yml, @@ -98,7 +98,7 @@ export const StandaloneInstructions = React.memo(({ agentPolicies }) => { {(copy) => ( @@ -108,7 +108,7 @@ export const StandaloneInstructions = React.memo(({ agentPolicies }) => { @@ -123,14 +123,14 @@ export const StandaloneInstructions = React.memo(({ agentPolicies }) => { ), }, { - title: i18n.translate('xpack.ingestManager.agentEnrollment.stepRunAgentTitle', { + title: i18n.translate('xpack.fleet.agentEnrollment.stepRunAgentTitle', { defaultMessage: 'Start the agent', }), children: ( <> @@ -140,7 +140,7 @@ export const StandaloneInstructions = React.memo(({ agentPolicies }) => { {(copy) => ( @@ -151,20 +151,20 @@ export const StandaloneInstructions = React.memo(({ agentPolicies }) => { ), }, { - title: i18n.translate('xpack.ingestManager.agentEnrollment.stepCheckForDataTitle', { + title: i18n.translate('xpack.fleet.agentEnrollment.stepCheckForDataTitle', { defaultMessage: 'Check for data', }), children: ( <> @@ -181,7 +181,7 @@ export const StandaloneInstructions = React.memo(({ agentPolicies }) => { <> diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/components/agent_enrollment_flyout/steps.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/components/agent_enrollment_flyout/steps.tsx index 0ae61ff421ffa..05ef733923d48 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/components/agent_enrollment_flyout/steps.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/components/agent_enrollment_flyout/steps.tsx @@ -13,14 +13,14 @@ import { AgentPolicy } from '../../../../types'; export const DownloadStep = () => { return { - title: i18n.translate('xpack.ingestManager.agentEnrollment.stepDownloadAgentTitle', { + title: i18n.translate('xpack.fleet.agentEnrollment.stepDownloadAgentTitle', { defaultMessage: 'Download the Elastic Agent to your host', }), children: ( <> @@ -32,7 +32,7 @@ export const DownloadStep = () => { iconType="popout" > @@ -51,7 +51,7 @@ export const AgentPolicySelectionStep = ({ setSelectedPolicyId?: (policyId: string) => void; }) => { return { - title: i18n.translate('xpack.ingestManager.agentEnrollment.stepChooseAgentPolicyTitle', { + title: i18n.translate('xpack.fleet.agentEnrollment.stepChooseAgentPolicyTitle', { defaultMessage: 'Choose an agent policy', }), children: ( diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/components/agent_health.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/components/agent_health.tsx index a16d4e7347ad1..45017ac8532da 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/components/agent_health.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/components/agent_health.tsx @@ -15,56 +15,38 @@ interface Props { const Status = { Online: ( - + ), Offline: ( - + ), Inactive: ( - + ), Warning: ( - + ), Error: ( - + ), Degraded: ( - + ), Enrolling: ( @@ -72,17 +54,14 @@ const Status = { Unenrolling: ( ), Upgrading: ( - + ), }; @@ -121,7 +100,7 @@ export const AgentHealth: React.FunctionComponent = ({ agent }) => { msLastCheckIn ? ( <> , @@ -133,7 +112,7 @@ export const AgentHealth: React.FunctionComponent = ({ agent }) => { ) : ( ) diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/components/agent_policy_package_badges.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/components/agent_policy_package_badges.tsx index 0a3d6d54da834..08835cc872b82 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/components/agent_policy_package_badges.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/components/agent_policy_package_badges.tsx @@ -25,7 +25,7 @@ export const AgentPolicyPackageBadges: React.FunctionComponent = ({ agent <> = ({ } setIsSubmitting(false); const successMessage = i18n.translate( - 'xpack.ingestManager.agentReassignPolicy.successSingleNotificationTitle', + 'xpack.fleet.agentReassignPolicy.successSingleNotificationTitle', { defaultMessage: 'Agent policy reassigned', } @@ -97,7 +97,7 @@ export const AgentReassignAgentPolicyFlyout: React.FunctionComponent = ({

    @@ -105,7 +105,7 @@ export const AgentReassignAgentPolicyFlyout: React.FunctionComponent = ({ = ({ @@ -146,7 +146,7 @@ export const AgentReassignAgentPolicyFlyout: React.FunctionComponent = ({ @@ -159,7 +159,7 @@ export const AgentReassignAgentPolicyFlyout: React.FunctionComponent = ({ isLoading={isSubmitting} > diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/components/agent_unenroll_modal/index.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/components/agent_unenroll_modal/index.tsx index d756b1f4daf02..74f2303c70c0a 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/components/agent_unenroll_modal/index.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/components/agent_unenroll_modal/index.tsx @@ -45,21 +45,19 @@ export const AgentUnenrollAgentModal: React.FunctionComponent = ({ setIsSubmitting(false); if (forceUnenroll) { const successMessage = isSingleAgent - ? i18n.translate( - 'xpack.ingestManager.unenrollAgents.successForceSingleNotificationTitle', - { defaultMessage: 'Agent unenrolled' } - ) - : i18n.translate( - 'xpack.ingestManager.unenrollAgents.successForceMultiNotificationTitle', - { defaultMessage: 'Agents unenrolled' } - ); + ? i18n.translate('xpack.fleet.unenrollAgents.successForceSingleNotificationTitle', { + defaultMessage: 'Agent unenrolled', + }) + : i18n.translate('xpack.fleet.unenrollAgents.successForceMultiNotificationTitle', { + defaultMessage: 'Agents unenrolled', + }); notifications.toasts.addSuccess(successMessage); } else { const successMessage = isSingleAgent - ? i18n.translate('xpack.ingestManager.unenrollAgents.successSingleNotificationTitle', { + ? i18n.translate('xpack.fleet.unenrollAgents.successSingleNotificationTitle', { defaultMessage: 'Unenrolling agent', }) - : i18n.translate('xpack.ingestManager.unenrollAgents.successMultiNotificationTitle', { + : i18n.translate('xpack.fleet.unenrollAgents.successMultiNotificationTitle', { defaultMessage: 'Unenrolling agents', }); notifications.toasts.addSuccess(successMessage); @@ -68,7 +66,7 @@ export const AgentUnenrollAgentModal: React.FunctionComponent = ({ } catch (error) { setIsSubmitting(false); notifications.toasts.addError(error, { - title: i18n.translate('xpack.ingestManager.unenrollAgents.fatalErrorNotificationTitle', { + title: i18n.translate('xpack.fleet.unenrollAgents.fatalErrorNotificationTitle', { defaultMessage: 'Error unenrolling {count, plural, one {agent} other {agents}}', values: { count: agentCount }, }), @@ -82,12 +80,12 @@ export const AgentUnenrollAgentModal: React.FunctionComponent = ({ title={ isSingleAgent ? ( ) : ( @@ -97,7 +95,7 @@ export const AgentUnenrollAgentModal: React.FunctionComponent = ({ onConfirm={onSubmit} cancelButtonText={ } @@ -105,12 +103,12 @@ export const AgentUnenrollAgentModal: React.FunctionComponent = ({ confirmButtonText={ isSingleAgent ? ( ) : ( @@ -121,14 +119,14 @@ export const AgentUnenrollAgentModal: React.FunctionComponent = ({

    {isSingleAgent ? ( ) : ( @@ -138,7 +136,7 @@ export const AgentUnenrollAgentModal: React.FunctionComponent = ({ legend={{ children: ( @@ -149,7 +147,7 @@ export const AgentUnenrollAgentModal: React.FunctionComponent = ({ id="ingestManagerForceUnenrollAgents" label={ = ({ } setIsSubmitting(false); const successMessage = isSingleAgent - ? i18n.translate('xpack.ingestManager.upgradeAgents.successSingleNotificationTitle', { + ? i18n.translate('xpack.fleet.upgradeAgents.successSingleNotificationTitle', { defaultMessage: 'Upgrading agent', }) - : i18n.translate('xpack.ingestManager.upgradeAgents.successMultiNotificationTitle', { + : i18n.translate('xpack.fleet.upgradeAgents.successMultiNotificationTitle', { defaultMessage: 'Upgrading agents', }); notifications.toasts.addSuccess(successMessage); @@ -53,7 +53,7 @@ export const AgentUpgradeAgentModal: React.FunctionComponent = ({ } catch (error) { setIsSubmitting(false); notifications.toasts.addError(error, { - title: i18n.translate('xpack.ingestManager.upgradeAgents.fatalErrorNotificationTitle', { + title: i18n.translate('xpack.fleet.upgradeAgents.fatalErrorNotificationTitle', { defaultMessage: 'Error upgrading {count, plural, one {agent} other {agents}}', values: { count: agentCount }, }), @@ -67,12 +67,12 @@ export const AgentUpgradeAgentModal: React.FunctionComponent = ({ title={ isSingleAgent ? ( ) : ( @@ -82,7 +82,7 @@ export const AgentUpgradeAgentModal: React.FunctionComponent = ({ onConfirm={onSubmit} cancelButtonText={ } @@ -90,12 +90,12 @@ export const AgentUpgradeAgentModal: React.FunctionComponent = ({ confirmButtonText={ isSingleAgent ? ( ) : ( @@ -105,7 +105,7 @@ export const AgentUpgradeAgentModal: React.FunctionComponent = ({

    {isSingleAgent ? ( = ({ /> ) : ( diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/components/list_layout.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/components/list_layout.tsx index 278beb5dfe35f..bf0163fe904e6 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/components/list_layout.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/components/list_layout.tsx @@ -53,7 +53,7 @@ export const ListLayout: React.FunctionComponent<{}> = ({ children }) => { titleSize="xs" textAlign="right" title={} - description={i18n.translate('xpack.ingestManager.agentListStatus.totalLabel', { + description={i18n.translate('xpack.fleet.agentListStatus.totalLabel', { defaultMessage: 'Agents', })} /> @@ -79,7 +79,7 @@ export const ListLayout: React.FunctionComponent<{}> = ({ children }) => { } - description={i18n.translate('xpack.ingestManager.agentListStatus.onlineLabel', { + description={i18n.translate('xpack.fleet.agentListStatus.onlineLabel', { defaultMessage: 'Online', })} /> @@ -89,7 +89,7 @@ export const ListLayout: React.FunctionComponent<{}> = ({ children }) => { textAlign="right" titleSize="xs" title={} - description={i18n.translate('xpack.ingestManager.agentListStatus.offlineLabel', { + description={i18n.translate('xpack.fleet.agentListStatus.offlineLabel', { defaultMessage: 'Offline', })} /> @@ -99,7 +99,7 @@ export const ListLayout: React.FunctionComponent<{}> = ({ children }) => { textAlign="right" titleSize="xs" title={} - description={i18n.translate('xpack.ingestManager.agentListStatus.errorLabel', { + description={i18n.translate('xpack.fleet.agentListStatus.errorLabel', { defaultMessage: 'Error', })} /> @@ -112,7 +112,7 @@ export const ListLayout: React.FunctionComponent<{}> = ({ children }) => { setIsEnrollmentFlyoutOpen(true)}> @@ -126,7 +126,7 @@ export const ListLayout: React.FunctionComponent<{}> = ({ children }) => {

    - +

    @@ -134,7 +134,7 @@ export const ListLayout: React.FunctionComponent<{}> = ({ children }) => {

    @@ -159,19 +159,14 @@ export const ListLayout: React.FunctionComponent<{}> = ({ children }) => { tabs={ ([ { - name: ( - - ), + name: , isSelected: routeMatch.path === PAGE_ROUTING_PATHS.fleet_agent_list, href: getHref('fleet_agent_list'), }, { name: ( ), diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/enrollment_token_list_page/components/confirm_delete_modal.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/enrollment_token_list_page/components/confirm_delete_modal.tsx index a115e03a369a2..45fd380a06f34 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/enrollment_token_list_page/components/confirm_delete_modal.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/enrollment_token_list_page/components/confirm_delete_modal.tsx @@ -20,28 +20,22 @@ export const ConfirmEnrollmentTokenDelete = (props: Props) => { return ( = ({
    @@ -102,7 +102,7 @@ export const NewEnrollmentTokenFlyout: React.FunctionComponent = ({ @@ -118,7 +118,7 @@ export const NewEnrollmentTokenFlyout: React.FunctionComponent = ({ @@ -132,7 +132,7 @@ export const NewEnrollmentTokenFlyout: React.FunctionComponent = ({

    @@ -144,7 +144,7 @@ export const NewEnrollmentTokenFlyout: React.FunctionComponent = ({ diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/enrollment_token_list_page/index.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/enrollment_token_list_page/index.tsx index f447469a02df2..7e5d07b2319d3 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/enrollment_token_list_page/index.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/enrollment_token_list_page/index.tsx @@ -73,10 +73,10 @@ const ApiKeyField: React.FunctionComponent<{ apiKeyId: string }> = ({ apiKeyId } = ({ apiKeyId } )} setState('CONFIRM_VISIBLE')} iconType="trash" color="danger" @@ -178,7 +175,7 @@ export const EnrollmentTokenListPage: React.FunctionComponent<{}> = () => { const columns = [ { field: 'name', - name: i18n.translate('xpack.ingestManager.enrollmentTokensList.nameTitle', { + name: i18n.translate('xpack.fleet.enrollmentTokensList.nameTitle', { defaultMessage: 'Name', }), render: (value: string) => ( @@ -189,7 +186,7 @@ export const EnrollmentTokenListPage: React.FunctionComponent<{}> = () => { }, { field: 'id', - name: i18n.translate('xpack.ingestManager.enrollmentTokensList.secretTitle', { + name: i18n.translate('xpack.fleet.enrollmentTokensList.secretTitle', { defaultMessage: 'Secret', }), width: '215px', @@ -199,7 +196,7 @@ export const EnrollmentTokenListPage: React.FunctionComponent<{}> = () => { }, { field: 'policy_id', - name: i18n.translate('xpack.ingestManager.enrollmentTokensList.policyTitle', { + name: i18n.translate('xpack.fleet.enrollmentTokensList.policyTitle', { defaultMessage: 'Agent policy', }), render: (policyId: string) => { @@ -214,7 +211,7 @@ export const EnrollmentTokenListPage: React.FunctionComponent<{}> = () => { }, { field: 'created_at', - name: i18n.translate('xpack.ingestManager.enrollmentTokensList.createdAtTitle', { + name: i18n.translate('xpack.fleet.enrollmentTokensList.createdAtTitle', { defaultMessage: 'Created on', }), width: '150px', @@ -226,7 +223,7 @@ export const EnrollmentTokenListPage: React.FunctionComponent<{}> = () => { }, { field: 'active', - name: i18n.translate('xpack.ingestManager.enrollmentTokensList.activeTitle', { + name: i18n.translate('xpack.fleet.enrollmentTokensList.activeTitle', { defaultMessage: 'Active', }), width: '70px', @@ -237,7 +234,7 @@ export const EnrollmentTokenListPage: React.FunctionComponent<{}> = () => { }, { field: 'actions', - name: i18n.translate('xpack.ingestManager.enrollmentTokensList.actionsTitle', { + name: i18n.translate('xpack.fleet.enrollmentTokensList.actionsTitle', { defaultMessage: 'Actions', }), width: '70px', @@ -267,7 +264,7 @@ export const EnrollmentTokenListPage: React.FunctionComponent<{}> = () => { )} @@ -289,7 +286,7 @@ export const EnrollmentTokenListPage: React.FunctionComponent<{}> = () => { setFlyoutOpen(true)}> @@ -302,12 +299,12 @@ export const EnrollmentTokenListPage: React.FunctionComponent<{}> = () => { noItemsMessage={ enrollmentAPIKeysRequest.isLoading && enrollmentAPIKeysRequest.isInitialRequest ? ( ) : ( ) diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/error_pages/enforce_security.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/error_pages/enforce_security.tsx index e131da159d6cb..7d547228f9c6c 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/error_pages/enforce_security.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/error_pages/enforce_security.tsx @@ -11,14 +11,14 @@ import { NoDataLayout } from './components/no_data_layout'; export const EnforceSecurityPage = injectI18n(({ intl }) => (

    diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/error_pages/invalid_license.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/error_pages/invalid_license.tsx index 883e41fea95b8..2632b6435cbd8 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/error_pages/invalid_license.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/error_pages/invalid_license.tsx @@ -11,14 +11,14 @@ import { NoDataLayout } from './components/no_data_layout'; export const InvalidLicensePage = injectI18n(({ intl }) => (

    diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/error_pages/no_access.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/error_pages/no_access.tsx index 5a3afd6216824..014ea6c04f2a2 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/error_pages/no_access.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/error_pages/no_access.tsx @@ -11,14 +11,14 @@ import { NoDataLayout } from './components/no_data_layout'; export const NoAccessPage = injectI18n(({ intl }) => (

    diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/setup_page/index.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/setup_page/index.tsx index bac551818ec87..884a2a12f71c5 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/setup_page/index.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/setup_page/index.tsx @@ -86,7 +86,7 @@ export const SetupPage: React.FunctionComponent<{

    @@ -94,7 +94,7 @@ export const SetupPage: React.FunctionComponent<{ @@ -102,7 +102,7 @@ export const SetupPage: React.FunctionComponent<{ @@ -119,26 +119,26 @@ export const SetupPage: React.FunctionComponent<{ @@ -161,7 +161,7 @@ export const SetupPage: React.FunctionComponent<{ xpack.security.authc.api_key.enabled, @@ -173,7 +173,7 @@ export const SetupPage: React.FunctionComponent<{ external > @@ -188,13 +188,13 @@ xpack.security.authc.api_key.enabled: true`} @@ -216,10 +216,7 @@ xpack.security.authc.api_key.enabled: true`} target="_blank" external > - + ), tlsFlag: xpack.fleet.agents.tlsCheckDisabled, @@ -234,7 +231,7 @@ xpack.security.authc.api_key.enabled: true`} )} > @@ -260,7 +257,7 @@ xpack.encryptedSavedObjects.encryptionKey: "something_at_least_32_characters"`} diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/overview/components/agent_policy_section.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/overview/components/agent_policy_section.tsx index e54eff1cbd4a5..c49f99cfe8a04 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/overview/components/agent_policy_section.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/overview/components/agent_policy_section.tsx @@ -32,14 +32,14 @@ export const OverviewPolicySection: React.FC<{ agentPolicies: AgentPolicy[] }> = return ( @@ -50,7 +50,7 @@ export const OverviewPolicySection: React.FC<{ agentPolicies: AgentPolicy[] }> = <> @@ -59,7 +59,7 @@ export const OverviewPolicySection: React.FC<{ agentPolicies: AgentPolicy[] }> = diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/overview/components/agent_section.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/overview/components/agent_section.tsx index 482105cdea300..5fbdf62d138d4 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/overview/components/agent_section.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/overview/components/agent_section.tsx @@ -25,15 +25,15 @@ export const OverviewAgentSection = () => { return ( @@ -44,7 +44,7 @@ export const OverviewAgentSection = () => { <> @@ -53,7 +53,7 @@ export const OverviewAgentSection = () => { @@ -62,7 +62,7 @@ export const OverviewAgentSection = () => { @@ -70,10 +70,7 @@ export const OverviewAgentSection = () => { - + diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/overview/components/datastream_section.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/overview/components/datastream_section.tsx index bece6ec074b88..3b645f7aa9d66 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/overview/components/datastream_section.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/overview/components/datastream_section.tsx @@ -46,14 +46,14 @@ export const OverviewDatastreamSection: React.FC = () => { return ( @@ -64,7 +64,7 @@ export const OverviewDatastreamSection: React.FC = () => { <> @@ -73,7 +73,7 @@ export const OverviewDatastreamSection: React.FC = () => { @@ -82,7 +82,7 @@ export const OverviewDatastreamSection: React.FC = () => { diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/overview/components/integration_section.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/overview/components/integration_section.tsx index 1e138ae922afc..1ba1424d21b3a 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/overview/components/integration_section.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/overview/components/integration_section.tsx @@ -32,15 +32,15 @@ export const OverviewIntegrationSection: React.FC = () => { return ( @@ -51,7 +51,7 @@ export const OverviewIntegrationSection: React.FC = () => { <> @@ -60,7 +60,7 @@ export const OverviewIntegrationSection: React.FC = () => { @@ -69,7 +69,7 @@ export const OverviewIntegrationSection: React.FC = () => { diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/overview/index.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/overview/index.tsx index c2aa98358c3d3..c997caa90c653 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/overview/index.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/overview/index.tsx @@ -45,20 +45,17 @@ export const IngestManagerOverview: React.FunctionComponent = () => {

    - +

    {

    @@ -83,7 +80,7 @@ export const IngestManagerOverview: React.FunctionComponent = () => { setIsEnrollmentFlyoutOpen(true)}> diff --git a/x-pack/plugins/ingest_manager/public/plugin.ts b/x-pack/plugins/ingest_manager/public/plugin.ts index a6a514e85da0c..6847a39819e8e 100644 --- a/x-pack/plugins/ingest_manager/public/plugin.ts +++ b/x-pack/plugins/ingest_manager/public/plugin.ts @@ -82,7 +82,7 @@ export class IngestManagerPlugin core.application.register({ id: PLUGIN_ID, category: DEFAULT_APP_CATEGORIES.management, - title: i18n.translate('xpack.ingestManager.appTitle', { defaultMessage: 'Fleet' }), + title: i18n.translate('xpack.fleet.appTitle', { defaultMessage: 'Fleet' }), order: 9020, euiIconType: 'logoElastic', async mount(params: AppMountParameters) { @@ -109,10 +109,10 @@ export class IngestManagerPlugin deps.home.featureCatalogue.register({ id: 'ingestManager', - title: i18n.translate('xpack.ingestManager.featureCatalogueTitle', { + title: i18n.translate('xpack.fleet.featureCatalogueTitle', { defaultMessage: 'Add Elastic Agent', }), - description: i18n.translate('xpack.ingestManager.featureCatalogueDescription', { + description: i18n.translate('xpack.fleet.featureCatalogueDescription', { defaultMessage: 'Add and manage your fleet of Elastic Agents and integrations.', }), icon: 'indexManagementApp', diff --git a/x-pack/plugins/lens/public/editor_frame_service/format_column.ts b/x-pack/plugins/lens/public/editor_frame_service/format_column.ts deleted file mode 100644 index 2da6e7195a5e1..0000000000000 --- a/x-pack/plugins/lens/public/editor_frame_service/format_column.ts +++ /dev/null @@ -1,100 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import { ExpressionFunctionDefinition, Datatable } from 'src/plugins/expressions/public'; - -interface FormatColumn { - format: string; - columnId: string; - decimals?: number; -} - -const supportedFormats: Record string }> = { - number: { - decimalsToPattern: (decimals = 2) => { - if (decimals === 0) { - return `0,0`; - } - return `0,0.${'0'.repeat(decimals)}`; - }, - }, - percent: { - decimalsToPattern: (decimals = 2) => { - if (decimals === 0) { - return `0,0%`; - } - return `0,0.${'0'.repeat(decimals)}%`; - }, - }, - bytes: { - decimalsToPattern: (decimals = 2) => { - if (decimals === 0) { - return `0,0b`; - } - return `0,0.${'0'.repeat(decimals)}b`; - }, - }, -}; - -export const formatColumn: ExpressionFunctionDefinition< - 'lens_format_column', - Datatable, - FormatColumn, - Datatable -> = { - name: 'lens_format_column', - type: 'datatable', - help: '', - args: { - format: { - types: ['string'], - help: '', - required: true, - }, - columnId: { - types: ['string'], - help: '', - required: true, - }, - decimals: { - types: ['number'], - help: '', - }, - }, - inputTypes: ['datatable'], - fn(input, { format, columnId, decimals }: FormatColumn) { - return { - ...input, - columns: input.columns.map((col) => { - if (col.id === columnId) { - if (supportedFormats[format]) { - return { - ...col, - meta: { - ...col.meta, - params: { - id: format, - params: { pattern: supportedFormats[format].decimalsToPattern(decimals) }, - }, - }, - }; - } else { - return { - ...col, - meta: { - ...col.meta, - params: { - id: format, - }, - }, - }; - } - } - return col; - }), - }; - }, -}; diff --git a/x-pack/plugins/lens/public/editor_frame_service/service.tsx b/x-pack/plugins/lens/public/editor_frame_service/service.tsx index e2a382133cb3c..d1df63780594e 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/service.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/service.tsx @@ -23,7 +23,6 @@ import { } from '../types'; import { Document } from '../persistence/saved_object_store'; import { mergeTables } from './merge_tables'; -import { formatColumn } from './format_column'; import { EmbeddableFactory, LensEmbeddableStartServices } from './embeddable/embeddable_factory'; import { UiActionsStart } from '../../../../../src/plugins/ui_actions/public'; import { DashboardStart } from '../../../../../src/plugins/dashboard/public'; @@ -86,7 +85,6 @@ export class EditorFrameService { getAttributeService: () => Promise ): EditorFrameSetup { plugins.expressions.registerFunction(() => mergeTables); - plugins.expressions.registerFunction(() => formatColumn); const getStartServices = async (): Promise => { const [coreStart, deps] = await core.getStartServices(); diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/dimension_editor.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/dimension_editor.tsx index 310548e5ab817..9500d4b44b79e 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/dimension_editor.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/dimension_editor.tsx @@ -435,7 +435,8 @@ export function DimensionEditor(props: DimensionEditorProps) { /> )} - {selectedColumn && selectedColumn.dataType === 'number' ? ( + {selectedColumn && + (selectedColumn.dataType === 'number' || selectedColumn.operationType === 'range') ? ( { diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/format_column.ts b/x-pack/plugins/lens/public/indexpattern_datasource/format_column.ts new file mode 100644 index 0000000000000..3666528f43166 --- /dev/null +++ b/x-pack/plugins/lens/public/indexpattern_datasource/format_column.ts @@ -0,0 +1,137 @@ +/* + * 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 { + ExpressionFunctionDefinition, + Datatable, + DatatableColumn, +} from 'src/plugins/expressions/public'; + +interface FormatColumn { + format: string; + columnId: string; + decimals?: number; + parentFormat?: string; +} + +export const supportedFormats: Record< + string, + { decimalsToPattern: (decimals?: number) => string } +> = { + number: { + decimalsToPattern: (decimals = 2) => { + if (decimals === 0) { + return `0,0`; + } + return `0,0.${'0'.repeat(decimals)}`; + }, + }, + percent: { + decimalsToPattern: (decimals = 2) => { + if (decimals === 0) { + return `0,0%`; + } + return `0,0.${'0'.repeat(decimals)}%`; + }, + }, + bytes: { + decimalsToPattern: (decimals = 2) => { + if (decimals === 0) { + return `0,0b`; + } + return `0,0.${'0'.repeat(decimals)}b`; + }, + }, +}; + +export const formatColumn: ExpressionFunctionDefinition< + 'lens_format_column', + Datatable, + FormatColumn, + Datatable +> = { + name: 'lens_format_column', + type: 'datatable', + help: '', + args: { + format: { + types: ['string'], + help: '', + required: true, + }, + columnId: { + types: ['string'], + help: '', + required: true, + }, + decimals: { + types: ['number'], + help: '', + }, + parentFormat: { + types: ['string'], + help: '', + }, + }, + inputTypes: ['datatable'], + fn(input, { format, columnId, decimals, parentFormat }: FormatColumn) { + return { + ...input, + columns: input.columns.map((col) => { + if (col.id === columnId) { + if (!parentFormat) { + if (supportedFormats[format]) { + return withParams(col, { + id: format, + params: { pattern: supportedFormats[format].decimalsToPattern(decimals) }, + }); + } else if (format) { + return withParams(col, { id: format }); + } else { + return col; + } + } + + const parsedParentFormat = JSON.parse(parentFormat); + const parentFormatId = parsedParentFormat.id; + const parentFormatParams = parsedParentFormat.params ?? {}; + + if (!parentFormatId) { + return col; + } + + if (format && supportedFormats[format]) { + return withParams(col, { + id: parentFormatId, + params: { + id: format, + params: { + pattern: supportedFormats[format].decimalsToPattern(decimals), + }, + ...parentFormatParams, + }, + }); + } + if (parentFormatParams) { + const innerParams = (col.meta.params?.params as Record) ?? {}; + return withParams(col, { + ...col.meta.params, + params: { + ...innerParams, + ...parentFormatParams, + }, + }); + } + } + return col; + }), + }; + }, +}; + +function withParams(col: DatatableColumn, params: Record) { + return { ...col, meta: { ...col.meta, params } }; +} diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/index.ts b/x-pack/plugins/lens/public/indexpattern_datasource/index.ts index 4fbed04112632..35987656f6670 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/index.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/index.ts @@ -33,8 +33,11 @@ export class IndexPatternDatasource { { expressions, editorFrame, charts }: IndexPatternDatasourceSetupPlugins ) { editorFrame.registerDatasource(async () => { - const { getIndexPatternDatasource, renameColumns } = await import('../async_services'); + const { getIndexPatternDatasource, renameColumns, formatColumn } = await import( + '../async_services' + ); expressions.registerFunction(renameColumns); + expressions.registerFunction(formatColumn); return core.getStartServices().then(([coreStart, { data }]) => getIndexPatternDatasource({ core: coreStart, diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern.tsx index 28aeac223e4a6..a6edfd71c93ca 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern.tsx @@ -107,6 +107,7 @@ export function uniqueLabels(layers: Record) { } export * from './rename_columns'; +export * from './format_column'; export function getIndexPatternDatasource({ core, diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/loader.test.ts b/x-pack/plugins/lens/public/indexpattern_datasource/loader.test.ts index 06cfdf7e03481..4222c02388433 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/loader.test.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/loader.test.ts @@ -117,6 +117,7 @@ const indexPattern2 = ({ title: 'my-fake-restricted-pattern', timeFieldName: 'timestamp', hasRestrictions: true, + fieldFormatMap: { bytes: { id: 'bytes', params: { pattern: '0.0' } } }, fields: [ { name: 'timestamp', diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/loader.ts b/x-pack/plugins/lens/public/indexpattern_datasource/loader.ts index fd8e071d524ee..70079cce6cc46 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/loader.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/loader.ts @@ -103,7 +103,14 @@ export async function loadIndexPatterns({ id: indexPattern.id!, // id exists for sure because we got index patterns by id title, timeFieldName, - fieldFormatMap, + fieldFormatMap: + fieldFormatMap && + Object.fromEntries( + Object.entries(fieldFormatMap).map(([id, format]) => [ + id, + 'toJSON' in format ? format.toJSON() : format, + ]) + ), fields: newFields, hasRestrictions: !!typeMeta?.aggs, }; diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/mocks.ts b/x-pack/plugins/lens/public/indexpattern_datasource/mocks.ts index 21ed23321cf57..744a9f6743d09 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/mocks.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/mocks.ts @@ -82,6 +82,7 @@ export const createMockedRestrictedIndexPattern = () => ({ title: 'my-fake-restricted-pattern', timeFieldName: 'timestamp', hasRestrictions: true, + fieldFormatMap: { bytes: { id: 'bytes', params: { pattern: '0.0' } } }, fields: [ { name: 'timestamp', diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/ranges/advanced_editor.scss b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/ranges/advanced_editor.scss index b1658043f3204..4af490e7479da 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/ranges/advanced_editor.scss +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/ranges/advanced_editor.scss @@ -3,4 +3,8 @@ @include euiFontSizeS; min-height: $euiSizeXL; width: 100%; -} \ No newline at end of file +} + +.lnsRangesOperation__popoverNumberField { + width: 14ch; // Roughly 10 characters plus extra for the padding +} diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/ranges/advanced_editor.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/ranges/advanced_editor.tsx index 96f4120e3df78..c6773e806aef8 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/ranges/advanced_editor.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/ranges/advanced_editor.tsx @@ -20,8 +20,8 @@ import { EuiPopover, EuiToolTip, htmlIdGenerator, + keys, } from '@elastic/eui'; -import { keys } from '@elastic/eui'; import { IFieldFormat } from '../../../../../../../../src/plugins/data/common'; import { RangeTypeLens, isValidRange, isValidNumber } from './ranges'; import { FROM_PLACEHOLDER, TO_PLACEHOLDER, TYPING_DEBOUNCE_TIME } from './constants'; @@ -39,8 +39,8 @@ type LocalRangeType = RangeTypeLens & { id: string }; const getBetterLabel = (range: RangeTypeLens, formatter: IFieldFormat) => range.label || formatter.convert({ - gte: isValidNumber(range.from) ? range.from : FROM_PLACEHOLDER, - lt: isValidNumber(range.to) ? range.to : TO_PLACEHOLDER, + gte: isValidNumber(range.from) ? range.from : -Infinity, + lt: isValidNumber(range.to) ? range.to : Infinity, }); export const RangePopover = ({ @@ -55,7 +55,6 @@ export const RangePopover = ({ Button: React.FunctionComponent<{ onClick: MouseEventHandler }>; isOpenByCreation: boolean; setIsOpenByCreation: (open: boolean) => void; - formatter: IFieldFormat; }) => { const [isPopoverOpen, setIsPopoverOpen] = useState(false); const [tempRange, setTempRange] = useState(range); @@ -112,6 +111,7 @@ export const RangePopover = ({ { const newRange = { @@ -126,7 +126,6 @@ export const RangePopover = ({ {lteAppendLabel}
    } - fullWidth compressed placeholder={FROM_PLACEHOLDER} isInvalid={!isValidRange(tempRange)} @@ -137,6 +136,7 @@ export const RangePopover = ({
    { const newRange = { @@ -151,7 +151,6 @@ export const RangePopover = ({ {ltPrependLabel} } - fullWidth compressed placeholder={TO_PLACEHOLDER} isInvalid={!isValidRange(tempRange)} @@ -180,6 +179,7 @@ export const RangePopover = ({ { defaultMessage: 'Custom label' } )} onSubmit={onSubmit} + compressed dataTestSubj="indexPattern-ranges-label" /> @@ -284,7 +284,6 @@ export const AdvancedRangeEditor = ({ } setLocalRanges(newRanges); }} - formatter={formatter} Button={({ onClick }: { onClick: MouseEventHandler }) => ( { - return { convert: ({ gte, lt }: { gte: string; lt: string }) => `${gte} - ${lt}` }; +dataPluginMockValue.fieldFormats.deserialize = jest.fn().mockImplementation(({ params }) => { + return { + convert: ({ gte, lt }: { gte: string; lt: string }) => { + if (params?.id === 'custom') { + return `Custom format: ${gte} - ${lt}`; + } + if (params?.id === 'bytes') { + return `Bytes format: ${gte} - ${lt}`; + } + return `${gte} - ${lt}`; + }, + }; }); type ReactMouseEvent = React.MouseEvent & @@ -74,7 +90,14 @@ describe('ranges', () => { function getDefaultState(): IndexPatternPrivateState { return { indexPatternRefs: [], - indexPatterns: {}, + indexPatterns: { + '1': { + id: '1', + title: 'my_index_pattern', + hasRestrictions: false, + fields: [{ name: sourceField, type: 'number', displayName: sourceField }], + }, + }, existingFields: {}, currentIndexPatternId: '1', isFirstExistenceFetch: false, @@ -396,7 +419,7 @@ describe('ranges', () => { /> ); - // This series of act clojures are made to make it work properly the update flush + // This series of act closures are made to make it work properly the update flush act(() => { instance.find(EuiButtonEmpty).prop('onClick')!({} as ReactMouseEvent); }); @@ -453,7 +476,7 @@ describe('ranges', () => { /> ); - // This series of act clojures are made to make it work properly the update flush + // This series of act closures are made to make it work properly the update flush act(() => { instance.find(EuiButtonEmpty).prop('onClick')!({} as ReactMouseEvent); }); @@ -510,7 +533,7 @@ describe('ranges', () => { /> ); - // This series of act clojures are made to make it work properly the update flush + // This series of act closures are made to make it work properly the update flush act(() => { instance.find(RangePopover).find(EuiLink).prop('onClick')!({} as ReactMouseEvent); }); @@ -667,6 +690,60 @@ describe('ranges', () => { ); }); }); + + it('should correctly handle the default formatter for the field', () => { + const setStateSpy = jest.fn(); + + // set a default formatter for the sourceField used + state.indexPatterns['1'].fieldFormatMap = { + MyField: { id: 'custom', params: {} }, + }; + + const instance = mount( + + ); + + expect(instance.find(RangePopover).find(EuiText).prop('children')).toMatch( + /^Custom format:/ + ); + }); + + it('should correctly pick the dimension formatter for the field', () => { + const setStateSpy = jest.fn(); + + // set a default formatter for the sourceField used + state.indexPatterns['1'].fieldFormatMap = { + MyField: { id: 'custom', params: {} }, + }; + + // now set a format on the range operation + (state.layers.first.columns.col1 as RangeIndexPatternColumn).params.format = { + id: 'bytes', + params: { decimals: 0 }, + }; + + const instance = mount( + + ); + + expect(instance.find(RangePopover).find(EuiText).prop('children')).toMatch( + /^Bytes format:/ + ); + }); }); }); }); diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/ranges/ranges.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/ranges/ranges.tsx index a256f5e4ecfa1..1050eef45a71c 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/ranges/ranges.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/ranges/ranges.tsx @@ -13,7 +13,9 @@ import { RangeEditor } from './range_editor'; import { OperationDefinition } from '../index'; import { FieldBasedIndexPatternColumn } from '../column_types'; import { updateColumnParam, changeColumn } from '../../../state_helpers'; +import { supportedFormats } from '../../../format_column'; import { MODES, AUTO_BARS, DEFAULT_INTERVAL, MIN_HISTOGRAM_BARS, SLICES } from './constants'; +import { IndexPattern, IndexPatternField } from '../../../types'; type RangeType = Omit; // Try to cover all possible serialized states for ranges @@ -32,6 +34,11 @@ export interface RangeIndexPatternColumn extends FieldBasedIndexPatternColumn { type: MODES_TYPES; maxBars: typeof AUTO_BARS | number; ranges: RangeTypeLens[]; + format?: { id: string; params?: { decimals: number } }; + parentFormat?: { + id: string; + params?: { id?: string; template?: string; replaceInfinity?: boolean }; + }; }; } @@ -55,6 +62,15 @@ export const isValidRange = (range: RangeTypeLens): boolean => { return true; }; +function getFieldDefaultFormat(indexPattern: IndexPattern, field: IndexPatternField | undefined) { + if (field) { + if (indexPattern.fieldFormatMap && indexPattern.fieldFormatMap[field.name]) { + return indexPattern.fieldFormatMap[field.name]; + } + } + return undefined; +} + function getEsAggsParams({ sourceField, params }: RangeIndexPatternColumn) { if (params.type === MODES.Range) { return { @@ -105,7 +121,7 @@ export const rangeOperation: OperationDefinition { - const rangeFormatter = data.fieldFormats.deserialize({ id: 'range' }); + const indexPattern = state.indexPatterns[state.layers[layerId].indexPatternId]; + const currentField = indexPattern.fields.find( + (field) => field.name === currentColumn.sourceField + ); + const numberFormat = currentColumn.params.format; + const numberFormatterPattern = + numberFormat && + supportedFormats[numberFormat.id] && + supportedFormats[numberFormat.id].decimalsToPattern(numberFormat.params?.decimals || 0); + + const rangeFormatter = data.fieldFormats.deserialize({ + ...currentColumn.params.parentFormat, + params: { + ...currentColumn.params.parentFormat?.params, + ...(numberFormat + ? { id: numberFormat.id, params: { pattern: numberFormatterPattern } } + : getFieldDefaultFormat(indexPattern, currentField)), + }, + }); + const MAX_HISTOGRAM_BARS = uiSettings.get(UI_SETTINGS.HISTOGRAM_MAX_BARS); const granularityStep = (MAX_HISTOGRAM_BARS - MIN_HISTOGRAM_BARS) / SLICES; const maxBarsDefaultValue = (MAX_HISTOGRAM_BARS - MIN_HISTOGRAM_BARS) / 2; @@ -171,6 +208,10 @@ export const rangeOperation: OperationDefinition { const scale = newMode === MODES.Range ? 'ordinal' : 'interval'; const dataType = newMode === MODES.Range ? 'string' : 'number'; + const parentFormat = + newMode === MODES.Range + ? { id: 'range', params: { template: 'arrow_right', replaceInfinity: true } } + : undefined; setState( changeColumn({ state, @@ -184,6 +225,8 @@ export const rangeOperation: OperationDefinition void; @@ -23,6 +24,7 @@ export const LabelInput = ({ inputRef?: React.MutableRefObject; onSubmit?: () => void; dataTestSubj?: string; + compressed?: boolean; }) => { const [inputValue, setInputValue] = useState(value); @@ -57,6 +59,7 @@ export const LabelInput = ({ prepend={i18n.translate('xpack.lens.labelInput.label', { defaultMessage: 'Label', })} + compressed={compressed} /> ); }; diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/to_expression.ts b/x-pack/plugins/lens/public/indexpattern_datasource/to_expression.ts index 1b87c48dc7193..e2c4323b56c2a 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/to_expression.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/to_expression.ts @@ -63,32 +63,50 @@ function getExpressionForLayer( }; }, {} as Record); - type FormattedColumn = Required>; + type FormattedColumn = Required< + Extract< + IndexPatternColumn, + | { + params?: { + format: unknown; + }; + } + // when formatters are nested there's a slightly different format + | { + params: { + format?: unknown; + parentFormat?: unknown; + }; + } + > + >; const columnsWithFormatters = columnEntries.filter( - ([, col]) => col.params && 'format' in col.params && col.params.format + ([, col]) => + col.params && + (('format' in col.params && col.params.format) || + ('parentFormat' in col.params && col.params.parentFormat)) ) as Array<[string, FormattedColumn]>; - const formatterOverrides: ExpressionFunctionAST[] = columnsWithFormatters.map(([id, col]) => { - const format = (col as FormattedColumn).params!.format; - const base: ExpressionFunctionAST = { - type: 'function', - function: 'lens_format_column', - arguments: { - format: [format.id], - columnId: [id], - }, - }; - if (typeof format.params?.decimals === 'number') { - return { - ...base, + const formatterOverrides: ExpressionFunctionAST[] = columnsWithFormatters.map( + ([id, col]: [string, FormattedColumn]) => { + // TODO: improve the type handling here + const parentFormat = 'parentFormat' in col.params ? col.params!.parentFormat! : undefined; + const format = (col as FormattedColumn).params!.format; + + const base: ExpressionFunctionAST = { + type: 'function', + function: 'lens_format_column', arguments: { - ...base.arguments, - decimals: [format.params.decimals], + format: format ? [format.id] : [''], + columnId: [id], + decimals: typeof format?.params?.decimals === 'number' ? [format.params.decimals] : [], + parentFormat: parentFormat ? [JSON.stringify(parentFormat)] : [], }, }; + + return base; } - return base; - }); + ); const allDateHistogramFields = Object.values(columns) .map((column) => diff --git a/x-pack/plugins/lens/server/plugin.tsx b/x-pack/plugins/lens/server/plugin.tsx index b801d30f5ba9b..a8f9bef92349c 100644 --- a/x-pack/plugins/lens/server/plugin.tsx +++ b/x-pack/plugins/lens/server/plugin.tsx @@ -29,13 +29,13 @@ export class LensServerPlugin implements Plugin<{}, {}, {}, {}> { private readonly kibanaIndexConfig: Observable<{ kibana: { index: string } }>; private readonly telemetryLogger: Logger; - constructor(initializerContext: PluginInitializerContext) { + constructor(private initializerContext: PluginInitializerContext) { this.kibanaIndexConfig = initializerContext.config.legacy.globalConfig$; this.telemetryLogger = initializerContext.logger.get('usage'); } setup(core: CoreSetup, plugins: PluginSetupContract) { setupSavedObjects(core); - setupRoutes(core); + setupRoutes(core, this.initializerContext.logger.get()); if (plugins.usageCollection && plugins.taskManager) { registerLensUsageCollector( plugins.usageCollection, diff --git a/x-pack/plugins/lens/server/routes/existing_fields.ts b/x-pack/plugins/lens/server/routes/existing_fields.ts index c925517b572da..d3b2314a199cb 100644 --- a/x-pack/plugins/lens/server/routes/existing_fields.ts +++ b/x-pack/plugins/lens/server/routes/existing_fields.ts @@ -7,10 +7,14 @@ import Boom from 'boom'; import { schema } from '@kbn/config-schema'; import { ILegacyScopedClusterClient, SavedObject, RequestHandlerContext } from 'src/core/server'; -import { CoreSetup } from 'src/core/server'; +import { CoreSetup, Logger } from 'src/core/server'; import { BASE_API_URL } from '../../common'; import { IndexPatternAttributes, UI_SETTINGS } from '../../../../../src/plugins/data/server'; +export function isBoomError(error: { isBoom?: boolean }): error is Boom { + return error.isBoom === true; +} + /** * The number of docs to sample to determine field empty status. */ @@ -24,7 +28,7 @@ export interface Field { script?: string; } -export async function existingFieldsRoute(setup: CoreSetup) { +export async function existingFieldsRoute(setup: CoreSetup, logger: Logger) { const router = setup.http.createRouter(); router.post( @@ -52,14 +56,17 @@ export async function existingFieldsRoute(setup: CoreSetup) { }), }); } catch (e) { + logger.info( + `Field existence check failed: ${isBoomError(e) ? e.output.payload.message : e.message}` + ); if (e.status === 404) { - return res.notFound(); + return res.notFound({ body: e.message }); } - if (e.isBoom) { + if (isBoomError(e)) { if (e.output.statusCode === 404) { - return res.notFound(); + return res.notFound({ body: e.output.payload.message }); } - return res.internalError(e.output.message); + return res.internalError({ body: e.output.payload.message }); } else { return res.internalError({ body: Boom.internal(e.message || e.name), diff --git a/x-pack/plugins/lens/server/routes/index.ts b/x-pack/plugins/lens/server/routes/index.ts index 8bc04a56e16d5..01018d8cd7fe5 100644 --- a/x-pack/plugins/lens/server/routes/index.ts +++ b/x-pack/plugins/lens/server/routes/index.ts @@ -4,13 +4,13 @@ * you may not use this file except in compliance with the Elastic License. */ -import { CoreSetup } from 'src/core/server'; +import { CoreSetup, Logger } from 'src/core/server'; import { existingFieldsRoute } from './existing_fields'; import { initFieldsRoute } from './field_stats'; import { initLensUsageRoute } from './telemetry'; -export function setupRoutes(setup: CoreSetup) { - existingFieldsRoute(setup); +export function setupRoutes(setup: CoreSetup, logger: Logger) { + existingFieldsRoute(setup, logger); initFieldsRoute(setup); initLensUsageRoute(setup); } diff --git a/x-pack/plugins/licensing/public/services/feature_usage_service.mock.ts b/x-pack/plugins/licensing/public/services/feature_usage_service.mock.ts index b2390ea35c140..eb07a07d3b52f 100644 --- a/x-pack/plugins/licensing/public/services/feature_usage_service.mock.ts +++ b/x-pack/plugins/licensing/public/services/feature_usage_service.mock.ts @@ -3,6 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ +import type { PublicMethodsOf } from '@kbn/utility-types'; import { FeatureUsageService, diff --git a/x-pack/plugins/licensing/server/services/feature_usage_service.mock.ts b/x-pack/plugins/licensing/server/services/feature_usage_service.mock.ts index f247c6ffcb526..b882219b2e29d 100644 --- a/x-pack/plugins/licensing/server/services/feature_usage_service.mock.ts +++ b/x-pack/plugins/licensing/server/services/feature_usage_service.mock.ts @@ -3,6 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ +import type { PublicMethodsOf } from '@kbn/utility-types'; import { FeatureUsageService, diff --git a/x-pack/plugins/security/public/account_management/account_management_page.tsx b/x-pack/plugins/security/public/account_management/account_management_page.tsx index 6615e8fee9412..2c870bf788ceb 100644 --- a/x-pack/plugins/security/public/account_management/account_management_page.tsx +++ b/x-pack/plugins/security/public/account_management/account_management_page.tsx @@ -6,6 +6,7 @@ import React, { useEffect, useState } from 'react'; import ReactDOM from 'react-dom'; import { EuiPage, EuiPageBody, EuiPanel, EuiSpacer, EuiText } from '@elastic/eui'; +import type { PublicMethodsOf } from '@kbn/utility-types'; import { CoreStart, NotificationsStart } from 'src/core/public'; import { getUserDisplayName, AuthenticatedUser } from '../../common/model'; import { AuthenticationServiceSetup } from '../authentication'; diff --git a/x-pack/plugins/security/public/account_management/change_password/change_password.tsx b/x-pack/plugins/security/public/account_management/change_password/change_password.tsx index 5b27df24f975c..031a70c497469 100644 --- a/x-pack/plugins/security/public/account_management/change_password/change_password.tsx +++ b/x-pack/plugins/security/public/account_management/change_password/change_password.tsx @@ -6,6 +6,7 @@ import React, { Component } from 'react'; import { EuiDescribedFormGroup } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; +import type { PublicMethodsOf } from '@kbn/utility-types'; import { NotificationsSetup } from 'src/core/public'; import { AuthenticatedUser, canUserChangePassword } from '../../../common/model'; import { UserAPIClient } from '../../management/users'; diff --git a/x-pack/plugins/security/public/management/api_keys/api_keys_grid/api_keys_grid_page.test.tsx b/x-pack/plugins/security/public/management/api_keys/api_keys_grid/api_keys_grid_page.test.tsx index 94f9de010cc2a..192d554bdc873 100644 --- a/x-pack/plugins/security/public/management/api_keys/api_keys_grid/api_keys_grid_page.test.tsx +++ b/x-pack/plugins/security/public/management/api_keys/api_keys_grid/api_keys_grid_page.test.tsx @@ -8,6 +8,7 @@ import { mountWithIntl } from 'test_utils/enzyme_helpers'; import React from 'react'; import { ReactWrapper } from 'enzyme'; import { EuiCallOut } from '@elastic/eui'; +import type { PublicMethodsOf } from '@kbn/utility-types'; import { NotEnabled } from './not_enabled'; import { PermissionDenied } from './permission_denied'; diff --git a/x-pack/plugins/security/public/management/api_keys/api_keys_grid/api_keys_grid_page.tsx b/x-pack/plugins/security/public/management/api_keys/api_keys_grid/api_keys_grid_page.tsx index 8621b01299e4f..b4ea91ea024f9 100644 --- a/x-pack/plugins/security/public/management/api_keys/api_keys_grid/api_keys_grid_page.tsx +++ b/x-pack/plugins/security/public/management/api_keys/api_keys_grid/api_keys_grid_page.tsx @@ -26,6 +26,7 @@ import { } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; +import type { PublicMethodsOf } from '@kbn/utility-types'; import moment from 'moment-timezone'; import { ApplicationStart, NotificationsStart } from 'src/core/public'; import { SectionLoading } from '../../../../../../../src/plugins/es_ui_shared/public'; diff --git a/x-pack/plugins/security/public/management/api_keys/api_keys_grid/invalidate_provider/invalidate_provider.tsx b/x-pack/plugins/security/public/management/api_keys/api_keys_grid/invalidate_provider/invalidate_provider.tsx index 1f47a426e6ae9..3c1e608f97727 100644 --- a/x-pack/plugins/security/public/management/api_keys/api_keys_grid/invalidate_provider/invalidate_provider.tsx +++ b/x-pack/plugins/security/public/management/api_keys/api_keys_grid/invalidate_provider/invalidate_provider.tsx @@ -6,6 +6,7 @@ import React, { Fragment, useRef, useState } from 'react'; import { EuiConfirmModal, EuiOverlayMask } from '@elastic/eui'; +import type { PublicMethodsOf } from '@kbn/utility-types'; import { i18n } from '@kbn/i18n'; import { NotificationsStart } from 'src/core/public'; import { ApiKeyToInvalidate } from '../../../../../common/model'; diff --git a/x-pack/plugins/security/public/management/role_mappings/components/delete_provider/delete_provider.tsx b/x-pack/plugins/security/public/management/role_mappings/components/delete_provider/delete_provider.tsx index 7abf34700ad7a..49dd83ac1bd26 100644 --- a/x-pack/plugins/security/public/management/role_mappings/components/delete_provider/delete_provider.tsx +++ b/x-pack/plugins/security/public/management/role_mappings/components/delete_provider/delete_provider.tsx @@ -7,6 +7,7 @@ import React, { Fragment, useRef, useState, ReactElement } from 'react'; import { EuiConfirmModal, EuiOverlayMask } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; +import type { PublicMethodsOf } from '@kbn/utility-types'; import { NotificationsStart } from 'src/core/public'; import { RoleMapping } from '../../../../../common/model'; import { RoleMappingsAPIClient } from '../../role_mappings_api_client'; diff --git a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/edit_role_mapping_page.test.tsx b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/edit_role_mapping_page.test.tsx index 04dc9c6dfa950..aff8ed12bceb6 100644 --- a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/edit_role_mapping_page.test.tsx +++ b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/edit_role_mapping_page.test.tsx @@ -5,6 +5,7 @@ */ import React from 'react'; +import type { PublicMethodsOf } from '@kbn/utility-types'; import { mountWithIntl, nextTick } from 'test_utils/enzyme_helpers'; import { findTestSubject } from 'test_utils/find_test_subject'; diff --git a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/edit_role_mapping_page.tsx b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/edit_role_mapping_page.tsx index b4e3627039ecb..30584348960a5 100644 --- a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/edit_role_mapping_page.tsx +++ b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/edit_role_mapping_page.tsx @@ -19,6 +19,7 @@ import { } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; +import type { PublicMethodsOf } from '@kbn/utility-types'; import { NotificationsStart, ScopedHistory } from 'src/core/public'; import { RoleMapping } from '../../../../common/model'; import { RuleEditorPanel } from './rule_editor_panel'; diff --git a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/mapping_info_panel/mapping_info_panel.test.tsx b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/mapping_info_panel/mapping_info_panel.test.tsx index 9b62ca27ca569..aaf223f5a8dcb 100644 --- a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/mapping_info_panel/mapping_info_panel.test.tsx +++ b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/mapping_info_panel/mapping_info_panel.test.tsx @@ -5,6 +5,7 @@ */ import React from 'react'; +import type { PublicMethodsOf } from '@kbn/utility-types'; import { mountWithIntl } from 'test_utils/enzyme_helpers'; import { findTestSubject } from 'test_utils/find_test_subject'; import { Role, RoleMapping } from '../../../../../common/model'; diff --git a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/mapping_info_panel/mapping_info_panel.tsx b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/mapping_info_panel/mapping_info_panel.tsx index 3df9987141fb2..faf0278e5d8f3 100644 --- a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/mapping_info_panel/mapping_info_panel.tsx +++ b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/mapping_info_panel/mapping_info_panel.tsx @@ -19,6 +19,7 @@ import { } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; +import type { PublicMethodsOf } from '@kbn/utility-types'; import { RoleMapping } from '../../../../../common/model'; import { RolesAPIClient } from '../../../roles'; import { diff --git a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/role_selector/role_selector.test.tsx b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/role_selector/role_selector.test.tsx index 62f53acb05462..29c5acdb1dda4 100644 --- a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/role_selector/role_selector.test.tsx +++ b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/role_selector/role_selector.test.tsx @@ -8,6 +8,7 @@ import React from 'react'; import { mountWithIntl } from 'test_utils/enzyme_helpers'; import { findTestSubject } from 'test_utils/find_test_subject'; import { EuiComboBox } from '@elastic/eui'; +import type { PublicMethodsOf } from '@kbn/utility-types'; import { RoleSelector } from './role_selector'; import { Role, RoleMapping } from '../../../../../common/model'; import { RoleTemplateEditor } from './role_template_editor'; diff --git a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/role_selector/role_selector.tsx b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/role_selector/role_selector.tsx index b0f558ee71be8..163637abae1a2 100644 --- a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/role_selector/role_selector.tsx +++ b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/role_selector/role_selector.tsx @@ -8,6 +8,7 @@ import React, { Fragment } from 'react'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import { EuiFormRow, EuiHorizontalRule } from '@elastic/eui'; +import type { PublicMethodsOf } from '@kbn/utility-types'; import { RoleMapping, Role, isRoleDeprecated } from '../../../../../common/model'; import { RolesAPIClient } from '../../../roles'; import { AddRoleTemplateButton } from './add_role_template_button'; diff --git a/x-pack/plugins/security/public/management/role_mappings/role_mappings_grid/role_mappings_grid_page.tsx b/x-pack/plugins/security/public/management/role_mappings/role_mappings_grid/role_mappings_grid_page.tsx index cf0cb21598c62..98e59eb95f0da 100644 --- a/x-pack/plugins/security/public/management/role_mappings/role_mappings_grid/role_mappings_grid_page.tsx +++ b/x-pack/plugins/security/public/management/role_mappings/role_mappings_grid/role_mappings_grid_page.tsx @@ -24,6 +24,7 @@ import { } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; +import type { PublicMethodsOf } from '@kbn/utility-types'; import { NotificationsStart, ApplicationStart, ScopedHistory } from 'src/core/public'; import { RoleMapping, Role } from '../../../../common/model'; import { EmptyPrompt } from './empty_prompt'; diff --git a/x-pack/plugins/security/public/management/roles/edit_role/edit_role_page.tsx b/x-pack/plugins/security/public/management/roles/edit_role/edit_role_page.tsx index 650d7c9c86c2b..d24191c54bd94 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/edit_role_page.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/edit_role_page.tsx @@ -30,6 +30,7 @@ import React, { useRef, useState, } from 'react'; +import type { PublicMethodsOf } from '@kbn/utility-types'; import { Capabilities, FatalErrorsSetup, diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/es/elasticsearch_privileges.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/es/elasticsearch_privileges.tsx index 46e0183b2f38c..8fc09ce167400 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/es/elasticsearch_privileges.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/es/elasticsearch_privileges.tsx @@ -17,6 +17,7 @@ import { } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; +import type { PublicMethodsOf } from '@kbn/utility-types'; import React, { Component, Fragment } from 'react'; import { Role, BuiltinESPrivileges } from '../../../../../../common/model'; import { SecurityLicense } from '../../../../../../common/licensing'; diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/es/index_privileges.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/es/index_privileges.tsx index e4a2bbd260deb..5bc957993dd4a 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/es/index_privileges.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/es/index_privileges.tsx @@ -5,6 +5,7 @@ */ import _ from 'lodash'; import React, { Component, Fragment } from 'react'; +import type { PublicMethodsOf } from '@kbn/utility-types'; import { Role, RoleIndexPrivilege, diff --git a/x-pack/plugins/security/public/management/roles/roles_grid/confirm_delete/confirm_delete.tsx b/x-pack/plugins/security/public/management/roles/roles_grid/confirm_delete/confirm_delete.tsx index d1b266d2a68fe..a6429a87101b3 100644 --- a/x-pack/plugins/security/public/management/roles/roles_grid/confirm_delete/confirm_delete.tsx +++ b/x-pack/plugins/security/public/management/roles/roles_grid/confirm_delete/confirm_delete.tsx @@ -18,6 +18,7 @@ import { } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; +import type { PublicMethodsOf } from '@kbn/utility-types'; import { NotificationsStart } from 'src/core/public'; import { RolesAPIClient } from '../../roles_api_client'; diff --git a/x-pack/plugins/security/public/management/roles/roles_grid/roles_grid_page.test.tsx b/x-pack/plugins/security/public/management/roles/roles_grid/roles_grid_page.test.tsx index eb6d25c9ef5ab..1ee621f9ba12d 100644 --- a/x-pack/plugins/security/public/management/roles/roles_grid/roles_grid_page.test.tsx +++ b/x-pack/plugins/security/public/management/roles/roles_grid/roles_grid_page.test.tsx @@ -5,6 +5,7 @@ */ import { EuiIcon, EuiBasicTable } from '@elastic/eui'; +import type { PublicMethodsOf } from '@kbn/utility-types'; import { ReactWrapper } from 'enzyme'; import React from 'react'; import { mountWithIntl } from 'test_utils/enzyme_helpers'; diff --git a/x-pack/plugins/security/public/management/roles/roles_grid/roles_grid_page.tsx b/x-pack/plugins/security/public/management/roles/roles_grid/roles_grid_page.tsx index 327ecb4b7dc49..c1487f7c37a2a 100644 --- a/x-pack/plugins/security/public/management/roles/roles_grid/roles_grid_page.tsx +++ b/x-pack/plugins/security/public/management/roles/roles_grid/roles_grid_page.tsx @@ -25,6 +25,7 @@ import { } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; +import type { PublicMethodsOf } from '@kbn/utility-types'; import { NotificationsStart } from 'src/core/public'; import { ScopedHistory } from 'kibana/public'; import { diff --git a/x-pack/plugins/security/public/management/users/components/change_password_form/change_password_form.tsx b/x-pack/plugins/security/public/management/users/components/change_password_form/change_password_form.tsx index 5d889abdf46ce..c7ecdd1bc5564 100644 --- a/x-pack/plugins/security/public/management/users/components/change_password_form/change_password_form.tsx +++ b/x-pack/plugins/security/public/management/users/components/change_password_form/change_password_form.tsx @@ -15,6 +15,7 @@ import { import _ from 'lodash'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; +import type { PublicMethodsOf } from '@kbn/utility-types'; import React, { ChangeEvent, Component } from 'react'; import { NotificationsStart } from 'src/core/public'; import { User } from '../../../../../common/model'; diff --git a/x-pack/plugins/security/public/management/users/components/confirm_delete_users/confirm_delete_users.tsx b/x-pack/plugins/security/public/management/users/components/confirm_delete_users/confirm_delete_users.tsx index a6fbc6be945c9..5d3e6d40f2c24 100644 --- a/x-pack/plugins/security/public/management/users/components/confirm_delete_users/confirm_delete_users.tsx +++ b/x-pack/plugins/security/public/management/users/components/confirm_delete_users/confirm_delete_users.tsx @@ -8,6 +8,7 @@ import React, { Component, Fragment } from 'react'; import { EuiOverlayMask, EuiConfirmModal } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; +import type { PublicMethodsOf } from '@kbn/utility-types'; import { NotificationsStart } from 'src/core/public'; import { UserAPIClient } from '../..'; diff --git a/x-pack/plugins/security/public/management/users/edit_user/edit_user_page.tsx b/x-pack/plugins/security/public/management/users/edit_user/edit_user_page.tsx index 9a62187cffd33..dc0c3336cb85f 100644 --- a/x-pack/plugins/security/public/management/users/edit_user/edit_user_page.tsx +++ b/x-pack/plugins/security/public/management/users/edit_user/edit_user_page.tsx @@ -30,6 +30,7 @@ import { } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; +import type { PublicMethodsOf } from '@kbn/utility-types'; import { NotificationsStart, ScopedHistory } from 'src/core/public'; import { User, EditUser, Role, isRoleDeprecated } from '../../../../common/model'; import { AuthenticationServiceSetup } from '../../../authentication'; diff --git a/x-pack/plugins/security/public/management/users/users_grid/users_grid_page.tsx b/x-pack/plugins/security/public/management/users/users_grid/users_grid_page.tsx index debe1c5e82d3b..2b7ed0079f291 100644 --- a/x-pack/plugins/security/public/management/users/users_grid/users_grid_page.tsx +++ b/x-pack/plugins/security/public/management/users/users_grid/users_grid_page.tsx @@ -23,6 +23,7 @@ import { } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; +import type { PublicMethodsOf } from '@kbn/utility-types'; import { NotificationsStart, ApplicationStart, ScopedHistory } from 'src/core/public'; import { User, Role } from '../../../../common/model'; import { ConfirmDeleteUsers } from '../components'; diff --git a/x-pack/plugins/security/server/authentication/authenticator.test.ts b/x-pack/plugins/security/server/authentication/authenticator.test.ts index 2e627de6c694c..91a7ef320c2dd 100644 --- a/x-pack/plugins/security/server/authentication/authenticator.test.ts +++ b/x-pack/plugins/security/server/authentication/authenticator.test.ts @@ -10,7 +10,7 @@ jest.mock('./providers/saml'); jest.mock('./providers/http'); import Boom from 'boom'; - +import type { PublicMethodsOf } from '@kbn/utility-types'; import { loggingSystemMock, httpServiceMock, diff --git a/x-pack/plugins/security/server/authentication/authenticator.ts b/x-pack/plugins/security/server/authentication/authenticator.ts index b1b73f1e5d028..aa3346c9f1237 100644 --- a/x-pack/plugins/security/server/authentication/authenticator.ts +++ b/x-pack/plugins/security/server/authentication/authenticator.ts @@ -3,7 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ - +import type { PublicMethodsOf } from '@kbn/utility-types'; import { KibanaRequest, LoggerFactory, diff --git a/x-pack/plugins/security/server/authentication/index.test.ts b/x-pack/plugins/security/server/authentication/index.test.ts index 989c3bad10139..e26ba875bb646 100644 --- a/x-pack/plugins/security/server/authentication/index.test.ts +++ b/x-pack/plugins/security/server/authentication/index.test.ts @@ -8,6 +8,7 @@ jest.mock('./api_keys'); jest.mock('./authenticator'); import Boom from 'boom'; +import type { PublicMethodsOf } from '@kbn/utility-types'; import { loggingSystemMock, diff --git a/x-pack/plugins/security/server/authentication/index.ts b/x-pack/plugins/security/server/authentication/index.ts index 24c0f14250d1b..13cc107edd64a 100644 --- a/x-pack/plugins/security/server/authentication/index.ts +++ b/x-pack/plugins/security/server/authentication/index.ts @@ -3,7 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import { UnwrapPromise } from '@kbn/utility-types'; +import type { PublicMethodsOf, UnwrapPromise } from '@kbn/utility-types'; import { ILegacyClusterClient, KibanaRequest, diff --git a/x-pack/plugins/security/server/authentication/providers/base.ts b/x-pack/plugins/security/server/authentication/providers/base.ts index 64d20e021fb8f..8d7e38357f245 100644 --- a/x-pack/plugins/security/server/authentication/providers/base.ts +++ b/x-pack/plugins/security/server/authentication/providers/base.ts @@ -5,6 +5,7 @@ */ import { deepFreeze } from '@kbn/std'; +import type { PublicMethodsOf } from '@kbn/utility-types'; import { KibanaRequest, Logger, diff --git a/x-pack/plugins/security/server/routes/index.ts b/x-pack/plugins/security/server/routes/index.ts index 7880e95240ff0..079c9e8ab9ce7 100644 --- a/x-pack/plugins/security/server/routes/index.ts +++ b/x-pack/plugins/security/server/routes/index.ts @@ -3,7 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ - +import type { PublicMethodsOf } from '@kbn/utility-types'; import { KibanaFeature } from '../../../features/server'; import { HttpResources, diff --git a/x-pack/plugins/security/server/routes/session_management/info.test.ts b/x-pack/plugins/security/server/routes/session_management/info.test.ts index fa9cba61df018..a104336f2e6ba 100644 --- a/x-pack/plugins/security/server/routes/session_management/info.test.ts +++ b/x-pack/plugins/security/server/routes/session_management/info.test.ts @@ -11,6 +11,7 @@ import { RequestHandlerContext, RouteConfig, } from '../../../../../../src/core/server'; +import type { PublicMethodsOf } from '@kbn/utility-types'; import { Session } from '../../session_management'; import { defineSessionInfoRoutes } from './info'; diff --git a/x-pack/plugins/security/server/routes/users/change_password.test.ts b/x-pack/plugins/security/server/routes/users/change_password.test.ts index 51bee1c74afa7..5e0f0a6005fb2 100644 --- a/x-pack/plugins/security/server/routes/users/change_password.test.ts +++ b/x-pack/plugins/security/server/routes/users/change_password.test.ts @@ -6,6 +6,7 @@ import { errors } from 'elasticsearch'; import { ObjectType } from '@kbn/config-schema'; +import type { PublicMethodsOf } from '@kbn/utility-types'; import { ILegacyClusterClient, IRouter, diff --git a/x-pack/plugins/security/server/routes/views/access_agreement.test.ts b/x-pack/plugins/security/server/routes/views/access_agreement.test.ts index 9b73358223b3d..b513230b3ba6f 100644 --- a/x-pack/plugins/security/server/routes/views/access_agreement.test.ts +++ b/x-pack/plugins/security/server/routes/views/access_agreement.test.ts @@ -3,7 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ - +import type { PublicMethodsOf } from '@kbn/utility-types'; import { RequestHandler, RouteConfig, diff --git a/x-pack/plugins/security/server/routes/views/logged_out.test.ts b/x-pack/plugins/security/server/routes/views/logged_out.test.ts index c160c4a26a187..31096bc33d686 100644 --- a/x-pack/plugins/security/server/routes/views/logged_out.test.ts +++ b/x-pack/plugins/security/server/routes/views/logged_out.test.ts @@ -3,7 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ - +import type { PublicMethodsOf } from '@kbn/utility-types'; import { HttpResourcesRequestHandler, RouteConfig } from '../../../../../../src/core/server'; import { Session } from '../../session_management'; import { defineLoggedOutRoutes } from './logged_out'; diff --git a/x-pack/plugins/security/server/saved_objects/secure_saved_objects_client_wrapper.ts b/x-pack/plugins/security/server/saved_objects/secure_saved_objects_client_wrapper.ts index c7a3f31cc517e..85e8e21da81b0 100644 --- a/x-pack/plugins/security/server/saved_objects/secure_saved_objects_client_wrapper.ts +++ b/x-pack/plugins/security/server/saved_objects/secure_saved_objects_client_wrapper.ts @@ -3,7 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ - +import type { PublicMethodsOf } from '@kbn/utility-types'; import { SavedObjectsBaseOptions, SavedObjectsBulkCreateObject, diff --git a/x-pack/plugins/security/server/session_management/session.mock.ts b/x-pack/plugins/security/server/session_management/session.mock.ts index c09d24ba315c8..973341acbfce3 100644 --- a/x-pack/plugins/security/server/session_management/session.mock.ts +++ b/x-pack/plugins/security/server/session_management/session.mock.ts @@ -3,7 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ - +import type { PublicMethodsOf } from '@kbn/utility-types'; import { mockAuthenticatedUser } from '../../common/model/authenticated_user.mock'; import { Session, SessionValue } from './session'; import { sessionIndexMock } from './session_index.mock'; diff --git a/x-pack/plugins/security/server/session_management/session.test.ts b/x-pack/plugins/security/server/session_management/session.test.ts index c4d2342df36dc..3010e70c31421 100644 --- a/x-pack/plugins/security/server/session_management/session.test.ts +++ b/x-pack/plugins/security/server/session_management/session.test.ts @@ -6,6 +6,7 @@ import crypto from 'crypto'; import nodeCrypto from '@elastic/node-crypto'; +import type { PublicMethodsOf } from '@kbn/utility-types'; import { ConfigSchema, createConfig } from '../config'; import { Session, SessionValueContentToEncrypt } from './session'; import { SessionIndex } from './session_index'; diff --git a/x-pack/plugins/security/server/session_management/session.ts b/x-pack/plugins/security/server/session_management/session.ts index 57c6509147665..a85369a6f4032 100644 --- a/x-pack/plugins/security/server/session_management/session.ts +++ b/x-pack/plugins/security/server/session_management/session.ts @@ -5,6 +5,7 @@ */ import nodeCrypto, { Crypto } from '@elastic/node-crypto'; +import type { PublicMethodsOf } from '@kbn/utility-types'; import { promisify } from 'util'; import { randomBytes, createHash } from 'crypto'; import { Duration } from 'moment'; diff --git a/x-pack/plugins/security/server/session_management/session_cookie.mock.ts b/x-pack/plugins/security/server/session_management/session_cookie.mock.ts index 026117f227561..998bc0ff01b23 100644 --- a/x-pack/plugins/security/server/session_management/session_cookie.mock.ts +++ b/x-pack/plugins/security/server/session_management/session_cookie.mock.ts @@ -3,7 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ - +import type { PublicMethodsOf } from '@kbn/utility-types'; import { SessionCookie, SessionCookieValue } from './session_cookie'; export const sessionCookieMock = { diff --git a/x-pack/plugins/security/server/session_management/session_index.mock.ts b/x-pack/plugins/security/server/session_management/session_index.mock.ts index 81dbe4b7410b8..ee8f5063655cc 100644 --- a/x-pack/plugins/security/server/session_management/session_index.mock.ts +++ b/x-pack/plugins/security/server/session_management/session_index.mock.ts @@ -3,7 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ - +import type { PublicMethodsOf } from '@kbn/utility-types'; import { SessionIndex, SessionIndexValue } from './session_index'; export const sessionIndexMock = { diff --git a/x-pack/plugins/security_solution/cypress/integration/overview.spec.ts b/x-pack/plugins/security_solution/cypress/integration/overview.spec.ts index 7ccd588e16a89..542cf4ad8178f 100644 --- a/x-pack/plugins/security_solution/cypress/integration/overview.spec.ts +++ b/x-pack/plugins/security_solution/cypress/integration/overview.spec.ts @@ -12,7 +12,7 @@ import { loginAndWaitForPage } from '../tasks/login'; import { OVERVIEW_URL } from '../urls/navigation'; import { esArchiverUnload, esArchiverLoad } from '../tasks/es_archiver'; -describe('Overview Page', () => { +describe.skip('Overview Page', () => { before(() => { cy.stubSearchStrategyApi('overviewHostQuery', 'overview_search_strategy'); cy.stubSearchStrategyApi('overviewNetworkQuery', 'overview_search_strategy'); @@ -35,7 +35,7 @@ describe('Overview Page', () => { }); }); - describe('with no data', () => { + describe.skip('with no data', () => { before(() => { esArchiverUnload('auditbeat'); loginAndWaitForPage(OVERVIEW_URL); diff --git a/x-pack/plugins/security_solution/cypress/screens/alerts_detection_rules.ts b/x-pack/plugins/security_solution/cypress/screens/alerts_detection_rules.ts index f68ad88f578c7..0d0ea8460edf1 100644 --- a/x-pack/plugins/security_solution/cypress/screens/alerts_detection_rules.ts +++ b/x-pack/plugins/security_solution/cypress/screens/alerts_detection_rules.ts @@ -47,9 +47,9 @@ export const RULE_CHECKBOX = '.euiTableRow .euiCheckbox__input'; export const RULE_NAME = '[data-test-subj="ruleName"]'; -export const RULE_SWITCH = '[data-test-subj="rule-switch"]'; +export const RULE_SWITCH = '[data-test-subj="ruleSwitch"]'; -export const RULE_SWITCH_LOADER = '[data-test-subj="rule-switch-loader"]'; +export const RULE_SWITCH_LOADER = '[data-test-subj="ruleSwitchLoader"]'; export const RULES_TABLE = '[data-test-subj="rules-table"]'; diff --git a/x-pack/plugins/security_solution/public/common/components/threat_match/translations.ts b/x-pack/plugins/security_solution/public/common/components/threat_match/translations.ts index ca9f6a13856cf..57e7416731486 100644 --- a/x-pack/plugins/security_solution/public/common/components/threat_match/translations.ts +++ b/x-pack/plugins/security_solution/public/common/components/threat_match/translations.ts @@ -13,7 +13,7 @@ export const FIELD = i18n.translate('xpack.securitySolution.threatMatch.fieldDes export const THREAT_FIELD = i18n.translate( 'xpack.securitySolution.threatMatch.threatFieldDescription', { - defaultMessage: 'Threat index field', + defaultMessage: 'Indicator index field', } ); diff --git a/x-pack/plugins/security_solution/public/common/containers/source/index.test.tsx b/x-pack/plugins/security_solution/public/common/containers/source/index.test.tsx new file mode 100644 index 0000000000000..e81b52f281519 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/containers/source/index.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 { IndexField } from '../../../../common/search_strategy/index_fields'; +import { getBrowserFields } from '.'; +import { mockBrowserFields, mocksSource } from './mock'; + +describe('source/index.tsx', () => { + describe('getBrowserFields', () => { + test('it returns an empty object given an empty array', () => { + const fields = getBrowserFields('title 1', []); + expect(fields).toEqual({}); + }); + + test('it returns the same input with the same title', () => { + getBrowserFields('title 1', []); + // Since it is memoized it will return the same output which is empty object given 'title 1' a second time + const fields = getBrowserFields('title 1', mocksSource.indexFields as IndexField[]); + expect(fields).toEqual({}); + }); + + test('it transforms input into output as expected', () => { + const fields = getBrowserFields('title 2', mocksSource.indexFields as IndexField[]); + expect(fields).toEqual(mockBrowserFields); + }); + }); +}); diff --git a/x-pack/plugins/security_solution/public/common/containers/source/index.tsx b/x-pack/plugins/security_solution/public/common/containers/source/index.tsx index 2cc1c75015e07..47e550b2ced0f 100644 --- a/x-pack/plugins/security_solution/public/common/containers/source/index.tsx +++ b/x-pack/plugins/security_solution/public/common/containers/source/index.tsx @@ -4,7 +4,6 @@ * you may not use this file except in compliance with the Elastic License. */ -import { set } from '@elastic/safer-lodash-set/fp'; import { keyBy, pick, isEmpty, isEqual, isUndefined } from 'lodash/fp'; import memoizeOne from 'memoize-one'; import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; @@ -55,15 +54,31 @@ export const getIndexFields = memoizeOne( (newArgs, lastArgs) => newArgs[0] === lastArgs[0] && newArgs[1].length === lastArgs[1].length ); +/** + * HOT Code path where the fields can be 16087 in length or larger. This is + * VERY mutatious on purpose to improve the performance of the transform. + */ export const getBrowserFields = memoizeOne( - (_title: string, fields: IndexField[]): BrowserFields => - fields && fields.length > 0 - ? fields.reduce( - (accumulator: BrowserFields, field: IndexField) => - set([field.category, 'fields', field.name], field, accumulator), - {} - ) - : {}, + (_title: string, fields: IndexField[]): BrowserFields => { + // Adds two dangerous casts to allow for mutations within this function + type DangerCastForMutation = Record; + type DangerCastForBrowserFieldsMutation = Record< + string, + Omit & { fields: Record } + >; + + // We mutate this instead of using lodash/set to keep this as fast as possible + return fields.reduce((accumulator, field) => { + if (accumulator[field.category] == null) { + (accumulator as DangerCastForMutation)[field.category] = {}; + } + if (accumulator[field.category].fields == null) { + accumulator[field.category].fields = {}; + } + accumulator[field.category].fields[field.name] = (field as unknown) as BrowserField; + return accumulator; + }, {}); + }, // Update the value only if _title has changed (newArgs, lastArgs) => newArgs[0] === lastArgs[0] ); diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/description_step/helpers.test.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/description_step/helpers.test.tsx index ebdfdcc262b34..ee1edecbdc54a 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/description_step/helpers.test.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/description_step/helpers.test.tsx @@ -437,7 +437,7 @@ describe('helpers', () => { it('returns a humanized description for a threat_match type', () => { const [result]: ListItems[] = buildRuleTypeDescription('Test label', 'threat_match'); - expect(result.description).toEqual('Threat Match'); + expect(result.description).toEqual('Indicator Match'); }); }); }); diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/description_step/translations.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/description_step/translations.tsx index d9186c2da7225..04647871f212e 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/description_step/translations.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/description_step/translations.tsx @@ -65,7 +65,7 @@ export const THRESHOLD_TYPE_DESCRIPTION = i18n.translate( export const THREAT_MATCH_TYPE_DESCRIPTION = i18n.translate( 'xpack.securitySolution.detectionEngine.createRule.threatMatchRuleTypeDescription', { - defaultMessage: 'Threat Match', + defaultMessage: 'Indicator Match', } ); diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/rule_switch/__snapshots__/index.test.tsx.snap b/x-pack/plugins/security_solution/public/detections/components/rules/rule_switch/__snapshots__/index.test.tsx.snap deleted file mode 100644 index 604f86866d565..0000000000000 --- a/x-pack/plugins/security_solution/public/detections/components/rules/rule_switch/__snapshots__/index.test.tsx.snap +++ /dev/null @@ -1,20 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`RuleSwitch renders correctly against snapshot 1`] = ` - - - - - -`; diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/rule_switch/index.test.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/rule_switch/index.test.tsx index 104eff34c91b3..910a28927fd93 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/rule_switch/index.test.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/rule_switch/index.test.tsx @@ -4,16 +4,173 @@ * you may not use this file except in compliance with the Elastic License. */ -import { shallow } from 'enzyme'; +import { mount } from 'enzyme'; import React from 'react'; +import { ThemeProvider } from 'styled-components'; +import euiLightVars from '@elastic/eui/dist/eui_theme_light.json'; +import { waitFor } from '@testing-library/react'; +import { enableRules } from '../../../containers/detection_engine/rules'; +import { enableRulesAction } from '../../../pages/detection_engine/rules/all/actions'; import { RuleSwitchComponent } from './index'; +import { getRulesSchemaMock } from '../../../../../common/detection_engine/schemas/response/rules_schema.mocks'; +import { RulesSchema } from '../../../../../common/detection_engine/schemas/response/rules_schema'; +import { useStateToaster, displayErrorToast } from '../../../../common/components/toasters'; + +jest.mock('../../../../common/components/toasters'); +jest.mock('../../../containers/detection_engine/rules'); +jest.mock('../../../pages/detection_engine/rules/all/actions'); describe('RuleSwitch', () => { - test('renders correctly against snapshot', () => { - const wrapper = shallow( - + beforeEach(() => { + (useStateToaster as jest.Mock).mockImplementation(() => [[], jest.fn()]); + (enableRules as jest.Mock).mockResolvedValue([getRulesSchemaMock()]); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + test('it renders loader if "isLoading" is true', () => { + const wrapper = mount( + ({ eui: euiLightVars, darkMode: false })}> + + + ); + + expect(wrapper.find('[data-test-subj="ruleSwitchLoader"]').exists()).toBeTruthy(); + expect(wrapper.find('[data-test-subj="ruleSwitch"]').exists()).toBeFalsy(); + }); + + test('it renders switch disabled if "isDisabled" is true', () => { + const wrapper = mount( + ({ eui: euiLightVars, darkMode: false })}> + + + ); + + expect(wrapper.find('[data-test-subj="ruleSwitch"]').at(0).props().disabled).toBeTruthy(); + }); + + test('it renders switch enabled if "enabled" is true', () => { + const wrapper = mount( + ({ eui: euiLightVars, darkMode: false })}> + + + ); + expect(wrapper.find('[data-test-subj="ruleSwitch"]').at(0).props().checked).toBeTruthy(); + }); + + test('it renders switch disabled if "enabled" is false', () => { + const wrapper = mount( + ({ eui: euiLightVars, darkMode: false })}> + + + ); + expect(wrapper.find('[data-test-subj="ruleSwitch"]').at(0).props().checked).toBeFalsy(); + }); + + test('it renders an off switch enabled on click', async () => { + const wrapper = mount( + ({ eui: euiLightVars, darkMode: false })}> + + + ); + wrapper.find('[data-test-subj="ruleSwitch"]').at(2).simulate('click'); + + await waitFor(() => { + wrapper.update(); + expect(wrapper.find('[data-test-subj="ruleSwitch"]').at(1).props().checked).toBeTruthy(); + }); + }); + + test('it renders an on switch off on click', async () => { + const rule: RulesSchema = { ...getRulesSchemaMock(), enabled: false }; + + (enableRules as jest.Mock).mockResolvedValue([rule]); + + const wrapper = mount( + ({ eui: euiLightVars, darkMode: false })}> + + + ); + wrapper.find('[data-test-subj="ruleSwitch"]').at(2).simulate('click'); + + await waitFor(() => { + wrapper.update(); + expect(wrapper.find('[data-test-subj="ruleSwitch"]').at(1).props().checked).toBeFalsy(); + }); + }); + + test('it dispatches error toaster if "enableRules" call rejects', async () => { + const mockError = new Error('uh oh'); + (enableRules as jest.Mock).mockRejectedValue(mockError); + + const wrapper = mount( + ({ eui: euiLightVars, darkMode: false })}> + + ); - expect(wrapper).toMatchSnapshot(); + wrapper.find('[data-test-subj="ruleSwitch"]').at(2).simulate('click'); + + await waitFor(() => { + wrapper.update(); + expect(displayErrorToast).toHaveBeenCalledTimes(1); + }); + }); + + test('it dispatches error toaster if "enableRules" call resolves with some errors', async () => { + (enableRules as jest.Mock).mockResolvedValue([ + getRulesSchemaMock(), + { error: { status_code: 400, message: 'error' } }, + { error: { status_code: 400, message: 'error' } }, + ]); + + const wrapper = mount( + ({ eui: euiLightVars, darkMode: false })}> + + + ); + wrapper.find('[data-test-subj="ruleSwitch"]').at(2).simulate('click'); + + await waitFor(() => { + wrapper.update(); + expect(displayErrorToast).toHaveBeenCalledTimes(1); + }); + }); + + test('it invokes "enableRulesAction" if dispatch is passed through', async () => { + const wrapper = mount( + ({ eui: euiLightVars, darkMode: false })}> + + + ); + wrapper.find('[data-test-subj="ruleSwitch"]').at(2).simulate('click'); + + await waitFor(() => { + wrapper.update(); + expect(enableRulesAction).toHaveBeenCalledTimes(1); + }); }); }); diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/rule_switch/index.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/rule_switch/index.tsx index 73d66bf024a62..1a9bcca7eb601 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/rule_switch/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/rule_switch/index.tsx @@ -13,7 +13,7 @@ import { } from '@elastic/eui'; import { isEmpty } from 'lodash/fp'; import styled from 'styled-components'; -import React, { useCallback, useState, useEffect } from 'react'; +import React, { useMemo, useCallback, useState, useEffect } from 'react'; import * as i18n from '../../../pages/detection_engine/rules/translations'; import { enableRules } from '../../../containers/detection_engine/rules'; @@ -63,8 +63,11 @@ export const RuleSwitchComponent = ({ if (dispatch != null) { await enableRulesAction([id], event.target.checked!, dispatch, dispatchToaster); } else { + const enabling = event.target.checked!; + const title = enabling + ? i18n.BATCH_ACTION_ACTIVATE_SELECTED_ERROR(1) + : i18n.BATCH_ACTION_DEACTIVATE_SELECTED_ERROR(1); try { - const enabling = event.target.checked!; const response = await enableRules({ ids: [id], enabled: enabling, @@ -73,9 +76,7 @@ export const RuleSwitchComponent = ({ if (errors.length > 0) { setMyIsLoading(false); - const title = enabling - ? i18n.BATCH_ACTION_ACTIVATE_SELECTED_ERROR(1) - : i18n.BATCH_ACTION_DEACTIVATE_SELECTED_ERROR(1); + displayErrorToast( title, errors.map((e) => e.error.message), @@ -88,8 +89,9 @@ export const RuleSwitchComponent = ({ onChange(rule.enabled); } } - } catch { + } catch (err) { setMyIsLoading(false); + displayErrorToast(title, err.message, dispatchToaster); } } setMyIsLoading(false); @@ -105,21 +107,22 @@ export const RuleSwitchComponent = ({ // eslint-disable-next-line react-hooks/exhaustive-deps }, [enabled]); - useEffect(() => { + const showLoader = useMemo((): boolean => { if (myIsLoading !== isLoading) { - setMyIsLoading(isLoading ?? false); + return isLoading ?? false; } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [isLoading]); + + return myIsLoading; + }, [myIsLoading, isLoading]); return ( - {myIsLoading ? ( - + {showLoader ? ( + ) : ( = { label: i18n.translate( 'xpack.securitySolution.detectionEngine.createRule.stepDefineRule.fieldThreatIndexPatternsLabel', { - defaultMessage: 'Threat index patterns', + defaultMessage: 'Indicator Index Patterns', } ), helpText: {THREAT_MATCH_INDEX_HELPER_TEXT}, @@ -265,7 +265,7 @@ export const schema: FormSchema = { label: i18n.translate( 'xpack.securitySolution.detectionEngine.createRule.stepDefineRule.fieldThreatMappingLabel', { - defaultMessage: 'Threat Mapping', + defaultMessage: 'Indicator Mapping', } ), validations: [ @@ -301,7 +301,7 @@ export const schema: FormSchema = { label: i18n.translate( 'xpack.securitySolution.detectionEngine.createRule.stepDefineRule.fieldThreatQueryBarLabel', { - defaultMessage: 'Threat index query', + defaultMessage: 'Indicator Index Query', } ), validations: [ diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/patch_rules_bulk_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/patch_rules_bulk_route.ts index 081e804cf7356..1875e0cd83cf8 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/patch_rules_bulk_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/patch_rules_bulk_route.ts @@ -183,12 +183,7 @@ export const patchRulesBulkRoute = (router: IRouter, ml: SetupPlugins['ml']) => search: rule.id, searchFields: ['alertId'], }); - return transformValidateBulkError( - rule.id, - rule, - ruleActions, - ruleStatuses.saved_objects[0] - ); + return transformValidateBulkError(rule.id, rule, ruleActions, ruleStatuses); } else { return getIdBulkError({ id, ruleId }); } diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_bulk_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_bulk_route.ts index 8828bbe6c9826..ddc2ade9b5ac9 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_bulk_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_bulk_route.ts @@ -50,7 +50,6 @@ export const updateRulesBulkRoute = (router: IRouter, ml: SetupPlugins['ml']) => if (!siemClient || !alertsClient) { return siemResponse.error({ statusCode: 404 }); } - const mlAuthz = buildMlAuthz({ license: context.licensing.license, ml, request }); const ruleStatusClient = ruleStatusSavedObjectsClientFactory(savedObjectsClient); const rules = await Promise.all( @@ -192,12 +191,7 @@ export const updateRulesBulkRoute = (router: IRouter, ml: SetupPlugins['ml']) => search: rule.id, searchFields: ['alertId'], }); - return transformValidateBulkError( - rule.id, - rule, - ruleActions, - ruleStatuses.saved_objects[0] - ); + return transformValidateBulkError(rule.id, rule, ruleActions, ruleStatuses); } else { return getIdBulkError({ id, ruleId }); } diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/validate.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/validate.test.ts index 06ec22b2f61b4..6bdbfedf625dd 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/validate.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/validate.test.ts @@ -9,13 +9,13 @@ import { transformValidateFindAlerts, transformValidateBulkError, } from './validate'; -import { getResult } from '../__mocks__/request_responses'; import { FindResult } from '../../../../../../alerts/server'; import { BulkError } from '../utils'; -import { RulesSchema } from '../../../../../common/detection_engine/schemas/response/rules_schema'; +import { RulesSchema } from '../../../../../common/detection_engine/schemas/response'; +import { getResult, getFindResultStatus } from '../__mocks__/request_responses'; import { getListArrayMock } from '../../../../../common/detection_engine/schemas/types/lists.mock'; -export const ruleOutput: RulesSchema = { +export const ruleOutput = (): RulesSchema => ({ actions: [], author: ['Elastic'], created_at: '2019-12-13T16:40:33.400Z', @@ -80,14 +80,14 @@ export const ruleOutput: RulesSchema = { note: '# Investigative notes', timeline_title: 'some-timeline-title', timeline_id: 'some-timeline-id', -}; +}); describe('validate', () => { describe('transformValidate', () => { test('it should do a validation correctly of a partial alert', () => { const ruleAlert = getResult(); const [validated, errors] = transformValidate(ruleAlert); - expect(validated).toEqual(ruleOutput); + expect(validated).toEqual(ruleOutput()); expect(errors).toEqual(null); }); @@ -103,14 +103,35 @@ describe('validate', () => { describe('transformValidateFindAlerts', () => { test('it should do a validation correctly of a find alert', () => { - const findResult: FindResult = { data: [getResult()], page: 1, perPage: 0, total: 0 }; + const findResult: FindResult = { + data: [getResult()], + page: 1, + perPage: 0, + total: 0, + }; const [validated, errors] = transformValidateFindAlerts(findResult, []); - expect(validated).toEqual({ data: [ruleOutput], page: 1, perPage: 0, total: 0 }); + const expected: { + page: number; + perPage: number; + total: number; + data: Array>; + } | null = { + data: [ruleOutput()], + page: 1, + perPage: 0, + total: 0, + }; + expect(validated).toEqual(expected); expect(errors).toEqual(null); }); test('it should do an in-validation correctly of a partial alert', () => { - const findResult: FindResult = { data: [getResult()], page: 1, perPage: 0, total: 0 }; + const findResult: FindResult = { + data: [getResult()], + page: 1, + perPage: 0, + total: 0, + }; // @ts-expect-error delete findResult.page; const [validated, errors] = transformValidateFindAlerts(findResult, []); @@ -123,7 +144,7 @@ describe('validate', () => { test('it should do a validation correctly of a rule id', () => { const ruleAlert = getResult(); const validatedOrError = transformValidateBulkError('rule-1', ruleAlert); - expect(validatedOrError).toEqual(ruleOutput); + expect(validatedOrError).toEqual(ruleOutput()); }); test('it should do an in-validation correctly of a rule id', () => { @@ -140,5 +161,34 @@ describe('validate', () => { }; expect(validatedOrError).toEqual(expected); }); + + test('it should do a validation correctly of a rule id with ruleStatus passed in', () => { + const ruleStatus = getFindResultStatus(); + const ruleAlert = getResult(); + const validatedOrError = transformValidateBulkError('rule-1', ruleAlert, null, ruleStatus); + const expected: RulesSchema = { + ...ruleOutput(), + status: 'succeeded', + status_date: '2020-02-18T15:26:49.783Z', + last_success_at: '2020-02-18T15:26:49.783Z', + last_success_message: 'succeeded', + }; + expect(validatedOrError).toEqual(expected); + }); + + test('it should return error object if "alert" is not expected alert type', () => { + const ruleAlert = getResult(); + // @ts-expect-error + delete ruleAlert.alertTypeId; + const validatedOrError = transformValidateBulkError('rule-1', ruleAlert); + const expected: BulkError = { + error: { + message: 'Internal error transforming', + status_code: 500, + }, + rule_id: 'rule-1', + }; + expect(validatedOrError).toEqual(expected); + }); }); }); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/validate.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/validate.ts index 983382b28ab38..27100eaebea15 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/validate.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/validate.ts @@ -22,6 +22,7 @@ import { isAlertType, IRuleSavedAttributesSavedObjectAttributes, isRuleStatusFindType, + IRuleStatusSOAttributes, } from '../../rules/types'; import { createBulkErrorObject, BulkError } from '../utils'; import { transformFindAlerts, transform, transformAlertToRule } from './utils'; @@ -74,7 +75,7 @@ export const transformValidateBulkError = ( ruleId: string, alert: PartialAlert, ruleActions?: RuleActions | null, - ruleStatus?: unknown + ruleStatus?: SavedObjectsFindResponse ): RulesSchema | BulkError => { if (isAlertType(alert)) { if (isRuleStatusFindType(ruleStatus) && ruleStatus?.saved_objects.length > 0) { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/rules/queries/query_with_threat_mapping.json b/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/rules/queries/query_with_threat_mapping.json index 1e2f217751e96..ed9356f46501c 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/rules/queries/query_with_threat_mapping.json +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/rules/queries/query_with_threat_mapping.json @@ -1,5 +1,5 @@ { - "name": "Query with a threat mapping", + "name": "Query with a indicator mapping", "description": "Query with a threat mapping", "rule_id": "threat-mapping", "risk_score": 1, diff --git a/x-pack/plugins/spaces/server/default_space/default_space_service.test.ts b/x-pack/plugins/spaces/server/default_space/default_space_service.test.ts index 311bedd0bf9e7..047dadb446289 100644 --- a/x-pack/plugins/spaces/server/default_space/default_space_service.test.ts +++ b/x-pack/plugins/spaces/server/default_space/default_space_service.test.ts @@ -4,6 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ import * as Rx from 'rxjs'; +import type { Writable } from '@kbn/utility-types'; import { DefaultSpaceService, RETRY_SCALE_DURATION, diff --git a/x-pack/plugins/stack_alerts/server/alert_types/index_threshold/alert_type.test.ts b/x-pack/plugins/stack_alerts/server/alert_types/index_threshold/alert_type.test.ts index e33a3e775ca96..2f0cf3cbbcd16 100644 --- a/x-pack/plugins/stack_alerts/server/alert_types/index_threshold/alert_type.test.ts +++ b/x-pack/plugins/stack_alerts/server/alert_types/index_threshold/alert_type.test.ts @@ -3,7 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ - +import type { Writable } from '@kbn/utility-types'; import { loggingSystemMock } from '../../../../../../src/core/server/mocks'; import { getAlertType } from './alert_type'; import { Params } from './alert_type_params'; diff --git a/x-pack/plugins/stack_alerts/server/alert_types/index_threshold/alert_type_params.test.ts b/x-pack/plugins/stack_alerts/server/alert_types/index_threshold/alert_type_params.test.ts index c209894fb6e89..3b771403b8b1a 100644 --- a/x-pack/plugins/stack_alerts/server/alert_types/index_threshold/alert_type_params.test.ts +++ b/x-pack/plugins/stack_alerts/server/alert_types/index_threshold/alert_type_params.test.ts @@ -7,6 +7,7 @@ import { ParamsSchema, Params } from './alert_type_params'; import { runTests } from './lib/core_query_types.test'; import { TypeOf } from '@kbn/config-schema'; +import type { Writable } from '@kbn/utility-types'; const DefaultParams: Writable> = { index: 'index-name', diff --git a/x-pack/plugins/stack_alerts/server/alert_types/index_threshold/lib/core_query_types.test.ts b/x-pack/plugins/stack_alerts/server/alert_types/index_threshold/lib/core_query_types.test.ts index 6c9c3542aea03..be8e61eac8cb4 100644 --- a/x-pack/plugins/stack_alerts/server/alert_types/index_threshold/lib/core_query_types.test.ts +++ b/x-pack/plugins/stack_alerts/server/alert_types/index_threshold/lib/core_query_types.test.ts @@ -7,6 +7,7 @@ // tests of common properties on time_series_query and alert_type_params import { ObjectType } from '@kbn/config-schema'; +import type { Writable } from '@kbn/utility-types'; import { CoreQueryParams } from './core_query_types'; import { MAX_GROUPS } from '../index'; diff --git a/x-pack/plugins/stack_alerts/server/alert_types/index_threshold/lib/time_series_types.test.ts b/x-pack/plugins/stack_alerts/server/alert_types/index_threshold/lib/time_series_types.test.ts index ec164122032cb..58f7652eaf074 100644 --- a/x-pack/plugins/stack_alerts/server/alert_types/index_threshold/lib/time_series_types.test.ts +++ b/x-pack/plugins/stack_alerts/server/alert_types/index_threshold/lib/time_series_types.test.ts @@ -3,7 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ - +import type { Writable } from '@kbn/utility-types'; import { TimeSeriesQuerySchema, TimeSeriesQuery } from './time_series_types'; import { runTests } from './core_query_types.test'; import { TypeOf } from '@kbn/config-schema'; diff --git a/x-pack/plugins/task_manager/server/routes/_mock_handler_arguments.ts b/x-pack/plugins/task_manager/server/routes/_mock_handler_arguments.ts index c9f4de25afaf7..2affbc7dbf7ee 100644 --- a/x-pack/plugins/task_manager/server/routes/_mock_handler_arguments.ts +++ b/x-pack/plugins/task_manager/server/routes/_mock_handler_arguments.ts @@ -4,6 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ +import type { MethodKeysOf } from '@kbn/utility-types'; import { RequestHandlerContext, KibanaRequest, KibanaResponseFactory } from 'kibana/server'; import { identity } from 'lodash'; import { httpServerMock } from '../../../../../src/core/server/mocks'; diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 0e826b19dba80..6c1185c7315c1 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -5045,7 +5045,6 @@ "xpack.apm.rum.filters.url.noResults": "結果がありません", "xpack.apm.rum.jsErrors.errorMessage": "エラーメッセージ", "xpack.apm.rum.jsErrors.errorRate": "エラー率", - "xpack.apm.rum.jsErrors.errorRateValue": "{errorRate} %", "xpack.apm.rum.jsErrors.impactedPageLoads": "影響を受けるページ読み込み数", "xpack.apm.rum.jsErrors.totalErrors": "合計エラー数", "xpack.apm.rum.userExperienceMetrics": "ユーザーエクスペリエンスメトリック", @@ -7219,6 +7218,578 @@ "xpack.fileUpload.jsonUploadAndParse.writingToIndex": "インデックスに書き込み中", "xpack.fileUpload.noIndexSuppliedErrorMessage": "インデックスが指定されていません。", "xpack.fileUpload.patternReader.featuresOmitted": "ジオメトリのない一部の機能は省略されました", + "xpack.fleet.agentBulkActions.agentsSelected": "{count, plural, one {#個のエージェント} other {#個のエージェント}}が選択されました", + "xpack.fleet.agentBulkActions.clearSelection": "選択した項目をクリア", + "xpack.fleet.agentBulkActions.reassignPolicy": "新しいポリシーに割り当てる", + "xpack.fleet.agentBulkActions.selectAll": "すべてのページのすべての項目を選択", + "xpack.fleet.agentBulkActions.totalAgents": "{count, plural, one {#個のエージェント} other {#個のエージェント}}を表示しています", + "xpack.fleet.agentBulkActions.totalAgentsWithLimit": "{count}/{total}個のエージェントを表示しています", + "xpack.fleet.agentBulkActions.unenrollAgents": "エージェントの登録を解除", + "xpack.fleet.agentBulkActions.upgradeAgents": "エージェントをアップグレード", + "xpack.fleet.agentDetails.actionsButton": "アクション", + "xpack.fleet.agentDetails.agentDetailsTitle": "エージェント'{id}'", + "xpack.fleet.agentDetails.agentNotFoundErrorDescription": "エージェントID {agentId}が見つかりません", + "xpack.fleet.agentDetails.agentNotFoundErrorTitle": "エージェントが見つかりません", + "xpack.fleet.agentDetails.agentPolicyLabel": "エージェントポリシー", + "xpack.fleet.agentDetails.agentVersionLabel": "エージェントバージョン", + "xpack.fleet.agentDetails.hostIdLabel": "エージェントID", + "xpack.fleet.agentDetails.hostNameLabel": "ホスト名", + "xpack.fleet.agentDetails.localMetadataSectionSubtitle": "メタデータを読み込み中", + "xpack.fleet.agentDetails.metadataSectionTitle": "メタデータ", + "xpack.fleet.agentDetails.platformLabel": "プラットフォーム", + "xpack.fleet.agentDetails.policyLabel": "ポリシー", + "xpack.fleet.agentDetails.releaseLabel": "エージェントリリース", + "xpack.fleet.agentDetails.statusLabel": "ステータス", + "xpack.fleet.agentDetails.subTabs.activityLogTab": "アクティビティログ", + "xpack.fleet.agentDetails.subTabs.detailsTab": "エージェントの詳細", + "xpack.fleet.agentDetails.unexceptedErrorTitle": "エージェントの読み込み中にエラーが発生しました", + "xpack.fleet.agentDetails.upgradeAvailableTooltip": "アップグレードが利用可能です", + "xpack.fleet.agentDetails.userProvidedMetadataSectionSubtitle": "ユーザー提供メタデータ", + "xpack.fleet.agentDetails.versionLabel": "エージェントバージョン", + "xpack.fleet.agentDetails.viewAgentListTitle": "すべてのエージェントを表示", + "xpack.fleet.agentEnrollment.agentDescription": "Elasticエージェントをホストに追加し、データを収集して、Elastic Stackに送信します。", + "xpack.fleet.agentEnrollment.agentsNotInitializedText": "エージェントを登録する前に、{link}。", + "xpack.fleet.agentEnrollment.cancelButtonLabel": "キャンセル", + "xpack.fleet.agentEnrollment.continueButtonLabel": "続行", + "xpack.fleet.agentEnrollment.copyPolicyButton": "クリップボードにコピー", + "xpack.fleet.agentEnrollment.copyRunInstructionsButton": "クリップボードにコピー", + "xpack.fleet.agentEnrollment.downloadDescription": "Elasticエージェントダウンロードページでは、エージェントバイナリと検証署名をダウンロードできます。", + "xpack.fleet.agentEnrollment.downloadLink": "ダウンロードページに移動", + "xpack.fleet.agentEnrollment.downloadPolicyButton": "ダウンロードポリシー", + "xpack.fleet.agentEnrollment.enrollFleetTabLabel": "Fleetで登録", + "xpack.fleet.agentEnrollment.enrollStandaloneTabLabel": "スタンドアロンで実行", + "xpack.fleet.agentEnrollment.flyoutTitle": "エージェントの追加", + "xpack.fleet.agentEnrollment.goToDataStreamsLink": "データストリーム", + "xpack.fleet.agentEnrollment.managedDescription": "ElasticエージェントをFleetに登録して、自動的に更新をデプロイしたり、一元的にエージェントを管理したりします。", + "xpack.fleet.agentEnrollment.setUpAgentsLink": "Elasticエージェントの集中管理を設定", + "xpack.fleet.agentEnrollment.standaloneDescription": "Elasticエージェントをスタンドアロンで実行して、エージェントがインストールされているホストで、手動でエージェントを構成および更新します。", + "xpack.fleet.agentEnrollment.stepCheckForDataDescription": "エージェントがデータの送信を開始します。{link}に移動して、データを表示してください。", + "xpack.fleet.agentEnrollment.stepCheckForDataTitle": "データを確認", + "xpack.fleet.agentEnrollment.stepChooseAgentPolicyTitle": "エージェントポリシーを選択", + "xpack.fleet.agentEnrollment.stepConfigureAgentDescription": "Elasticエージェントがインストールされているホストで、このポリシーを{fileName}にコピーします。Elasticsearch資格情報を使用するには、{fileName}の{outputSection}セクションで、{ESUsernameVariable}と{ESPasswordVariable}を変更します。", + "xpack.fleet.agentEnrollment.stepConfigureAgentTitle": "エージェントの構成", + "xpack.fleet.agentEnrollment.stepDownloadAgentTitle": "Elasticエージェントをホストにダウンロード", + "xpack.fleet.agentEnrollment.stepEnrollAndRunAgentTitle": "Elasticエージェントを登録して実行", + "xpack.fleet.agentEnrollment.stepRunAgentDescription": "エージェントのディレクトリから、このコマンドを実行し、Elasticエージェントを、インストール、登録、起動します。このコマンドを再利用すると、複数のホストでエージェントを設定できます。管理者権限が必要です。", + "xpack.fleet.agentEnrollment.stepRunAgentTitle": "エージェントの起動", + "xpack.fleet.agentEventsList.collapseDetailsAriaLabel": "詳細を非表示", + "xpack.fleet.agentEventsList.expandDetailsAriaLabel": "詳細を表示", + "xpack.fleet.agentEventsList.messageColumnTitle": "メッセージ", + "xpack.fleet.agentEventsList.messageDetailsTitle": "メッセージ", + "xpack.fleet.agentEventsList.payloadDetailsTitle": "ペイロード", + "xpack.fleet.agentEventsList.refreshButton": "更新", + "xpack.fleet.agentEventsList.searchPlaceholderText": "アクティビティログを検索", + "xpack.fleet.agentEventsList.subtypeColumnTitle": "サブタイプ", + "xpack.fleet.agentEventsList.timestampColumnTitle": "タイムスタンプ", + "xpack.fleet.agentEventsList.typeColumnTitle": "タイプ", + "xpack.fleet.agentEventSubtype.acknowledgedLabel": "認識", + "xpack.fleet.agentEventSubtype.dataDumpLabel": "データダンプ", + "xpack.fleet.agentEventSubtype.degradedLabel": "劣化", + "xpack.fleet.agentEventSubtype.failedLabel": "失敗", + "xpack.fleet.agentEventSubtype.inProgressLabel": "進行中", + "xpack.fleet.agentEventSubtype.policyLabel": "ポリシー", + "xpack.fleet.agentEventSubtype.runningLabel": "実行中", + "xpack.fleet.agentEventSubtype.startingLabel": "開始中", + "xpack.fleet.agentEventSubtype.stoppedLabel": "停止", + "xpack.fleet.agentEventSubtype.stoppingLabel": "停止中", + "xpack.fleet.agentEventSubtype.unknownLabel": "不明", + "xpack.fleet.agentEventSubtype.updatingLabel": "更新中", + "xpack.fleet.agentEventType.actionLabel": "アクション", + "xpack.fleet.agentEventType.actionResultLabel": "アクション結果", + "xpack.fleet.agentEventType.errorLabel": "エラー", + "xpack.fleet.agentEventType.stateLabel": "ステータス", + "xpack.fleet.agentHealth.checkInTooltipText": "前回のチェックイン {lastCheckIn}", + "xpack.fleet.agentHealth.degradedStatusText": "劣化", + "xpack.fleet.agentHealth.enrollingStatusText": "登録中", + "xpack.fleet.agentHealth.errorStatusText": "エラー", + "xpack.fleet.agentHealth.inactiveStatusText": "非アクティブ", + "xpack.fleet.agentHealth.noCheckInTooltipText": "チェックインしない", + "xpack.fleet.agentHealth.offlineStatusText": "オフライン", + "xpack.fleet.agentHealth.onlineStatusText": "オンライン", + "xpack.fleet.agentHealth.unenrollingStatusText": "登録解除中", + "xpack.fleet.agentHealth.updatingStatusText": "更新中", + "xpack.fleet.agentHealth.warningStatusText": "エラー", + "xpack.fleet.agentList.actionsColumnTitle": "アクション", + "xpack.fleet.agentList.addButton": "エージェントの追加", + "xpack.fleet.agentList.agentUpgradeLabel": "アップグレードが利用可能です", + "xpack.fleet.agentList.clearFiltersLinkText": "フィルターを消去", + "xpack.fleet.agentList.enrollButton": "エージェントの追加", + "xpack.fleet.agentList.forceUnenrollOneButton": "強制的に登録解除する", + "xpack.fleet.agentList.hostColumnTitle": "ホスト", + "xpack.fleet.agentList.lastCheckinTitle": "前回のアクティビティ", + "xpack.fleet.agentList.loadingAgentsMessage": "エージェントを読み込み中...", + "xpack.fleet.agentList.noAgentsPrompt": "エージェントが登録されていません", + "xpack.fleet.agentList.noFilteredAgentsPrompt": "エージェントが見つかりません。{clearFiltersLink}", + "xpack.fleet.agentList.outOfDateLabel": "最新ではありません", + "xpack.fleet.agentList.policyColumnTitle": "エージェントポリシー", + "xpack.fleet.agentList.policyFilterText": "エージェントポリシー", + "xpack.fleet.agentList.reassignActionText": "新しいポリシーに割り当てる", + "xpack.fleet.agentList.revisionNumber": "rev. {revNumber}", + "xpack.fleet.agentList.showInactiveSwitchLabel": "非アクティブ", + "xpack.fleet.agentList.showUpgradeableFilterLabel": "アップグレードが利用可能です", + "xpack.fleet.agentList.statusColumnTitle": "ステータス", + "xpack.fleet.agentList.statusErrorFilterText": "エラー", + "xpack.fleet.agentList.statusFilterText": "ステータス", + "xpack.fleet.agentList.statusOfflineFilterText": "オフライン", + "xpack.fleet.agentList.statusOnlineFilterText": "オンライン", + "xpack.fleet.agentList.statusUpdatingFilterText": "更新中", + "xpack.fleet.agentList.unenrollOneButton": "エージェントの登録解除", + "xpack.fleet.agentList.upgradeOneButton": "エージェントをアップグレード", + "xpack.fleet.agentList.versionTitle": "バージョン", + "xpack.fleet.agentList.viewActionText": "エージェントを表示", + "xpack.fleet.agentListStatus.errorLabel": "エラー", + "xpack.fleet.agentListStatus.offlineLabel": "オフライン", + "xpack.fleet.agentListStatus.onlineLabel": "オンライン", + "xpack.fleet.agentListStatus.totalLabel": "エージェント", + "xpack.fleet.agentPolicy.confirmModalCalloutDescription": "選択されたエージェントポリシー{policyName}が一部のエージェントですでに使用されていることをFleetが検出しました。このアクションの結果として、Fleetはこのポリシーで使用されているすべてのエージェントに更新をデプロイします。", + "xpack.fleet.agentPolicy.confirmModalCancelButtonLabel": "キャンセル", + "xpack.fleet.agentPolicy.confirmModalConfirmButtonLabel": "変更を保存してデプロイ", + "xpack.fleet.agentPolicy.confirmModalDescription": "このアクションは元に戻せません。続行していいですか?", + "xpack.fleet.agentPolicy.confirmModalTitle": "変更を保存してデプロイ", + "xpack.fleet.agentPolicy.linkedAgentCountText": "{count, plural, one {#件のエージェント} other {#件のエージェント}}", + "xpack.fleet.agentPolicyActionMenu.buttonText": "アクション", + "xpack.fleet.agentPolicyActionMenu.copyPolicyActionText": "ポリシーをコピー", + "xpack.fleet.agentPolicyActionMenu.enrollAgentActionText": "エージェントの追加", + "xpack.fleet.agentPolicyActionMenu.viewPolicyText": "ポリシーを表示", + "xpack.fleet.agentPolicyForm.advancedOptionsToggleLabel": "高度なオプション", + "xpack.fleet.agentPolicyForm.descriptionFieldLabel": "説明", + "xpack.fleet.agentPolicyForm.descriptionFieldPlaceholder": "どのようにこのポリシーを使用しますか?", + "xpack.fleet.agentPolicyForm.monitoringDescription": "パフォーマンスのデバッグと追跡のために、エージェントに関するデータを収集します。", + "xpack.fleet.agentPolicyForm.monitoringLabel": "アラート監視", + "xpack.fleet.agentPolicyForm.monitoringLogsFieldLabel": "エージェントログを収集", + "xpack.fleet.agentPolicyForm.monitoringLogsTooltipText": "このポリシーを使用するElasticエージェントからログを収集します。", + "xpack.fleet.agentPolicyForm.monitoringMetricsFieldLabel": "エージェントメトリックを収集", + "xpack.fleet.agentPolicyForm.monitoringMetricsTooltipText": "このポリシーを使用するElasticエージェントからメトリックを収集します。", + "xpack.fleet.agentPolicyForm.nameFieldLabel": "名前", + "xpack.fleet.agentPolicyForm.nameFieldPlaceholder": "名前を選択", + "xpack.fleet.agentPolicyForm.nameRequiredErrorMessage": "エージェントポリシー名が必要です。", + "xpack.fleet.agentPolicyForm.namespaceFieldDescription": "このポリシーを使用する統合にデフォルトの名前空間を適用します。統合はその独自の名前空間を指定できます。", + "xpack.fleet.agentPolicyForm.namespaceFieldLabel": "デフォルト名前空間", + "xpack.fleet.agentPolicyForm.systemMonitoringFieldLabel": "システム監視", + "xpack.fleet.agentPolicyForm.systemMonitoringText": "システムメトリックを収集", + "xpack.fleet.agentPolicyForm.systemMonitoringTooltipText": "このオプションを有効にすると、システムメトリックと情報を収集する統合でポリシーをブートストラップできます。", + "xpack.fleet.agentPolicyList.actionsColumnTitle": "アクション", + "xpack.fleet.agentPolicyList.addButton": "エージェントポリシーを作成", + "xpack.fleet.agentPolicyList.agentsColumnTitle": "エージェント", + "xpack.fleet.agentPolicyList.clearFiltersLinkText": "フィルターを消去", + "xpack.fleet.agentPolicyList.descriptionColumnTitle": "説明", + "xpack.fleet.agentPolicyList.loadingAgentPoliciesMessage": "エージェントポリシーの読み込み中...", + "xpack.fleet.agentPolicyList.nameColumnTitle": "名前", + "xpack.fleet.agentPolicyList.noAgentPoliciesPrompt": "エージェントポリシーがありません", + "xpack.fleet.agentPolicyList.noFilteredAgentPoliciesPrompt": "エージェントポリシーが見つかりません。{clearFiltersLink}", + "xpack.fleet.agentPolicyList.packagePoliciesCountColumnTitle": "統合", + "xpack.fleet.agentPolicyList.pageSubtitle": "エージェントポリシーを使用すると、エージェントとエージェントが収集するデータを管理できます。", + "xpack.fleet.agentPolicyList.pageTitle": "エージェントポリシー", + "xpack.fleet.agentPolicyList.reloadAgentPoliciesButtonText": "再読み込み", + "xpack.fleet.agentPolicyList.revisionNumber": "rev. {revNumber}", + "xpack.fleet.agentPolicyList.updatedOnColumnTitle": "最終更新日", + "xpack.fleet.agentReassignPolicy.cancelButtonLabel": "キャンセル", + "xpack.fleet.agentReassignPolicy.continueButtonLabel": "ポリシーの割り当て", + "xpack.fleet.agentReassignPolicy.flyoutDescription": "選択した{count, plural, one {エージェント} other {エージェント}}を割り当てる新しいエージェントポリシーを選択します。", + "xpack.fleet.agentReassignPolicy.flyoutTitle": "新しいエージェントポリシーを割り当てる", + "xpack.fleet.agentReassignPolicy.policyDescription": "選択したエージェントポリシーは、{count, plural, one {{countValue}個の統合} other {{countValue}個の統合}}のデータを収集します。", + "xpack.fleet.agentReassignPolicy.selectPolicyLabel": "エージェントポリシー", + "xpack.fleet.agentReassignPolicy.successSingleNotificationTitle": "エージェントポリシーが再割り当てされました", + "xpack.fleet.agents.pageSubtitle": "ポリシーの更新を管理し、任意のサイズのエージェントのグループにデプロイします。", + "xpack.fleet.agents.pageTitle": "エージェント", + "xpack.fleet.alphaMessageDescription": "Ingest Managerは本番環境用ではありません。", + "xpack.fleet.alphaMessageLinkText": "詳細を参照してください。", + "xpack.fleet.alphaMessageTitle": "ベータリリース", + "xpack.fleet.alphaMessaging.docsLink": "ドキュメンテーション", + "xpack.fleet.alphaMessaging.feedbackText": "{docsLink}をご覧ください。質問やフィードバックについては、{forumLink}にアクセスしてください。", + "xpack.fleet.alphaMessaging.flyoutTitle": "このリリースについて", + "xpack.fleet.alphaMessaging.forumLink": "ディスカッションフォーラム", + "xpack.fleet.alphaMessaging.introText": "Ingest Managerは開発中であり、本番環境用ではありません。このベータリリースは、ユーザーがIngest Managerと新しいElasticエージェントをテストしてフィードバックを提供することを目的としています。このプラグインには、サポートSLAが適用されません。", + "xpack.fleet.alphaMessging.closeFlyoutLabel": "閉じる", + "xpack.fleet.appNavigation.agentsLinkText": "エージェント", + "xpack.fleet.appNavigation.dataStreamsLinkText": "データストリーム", + "xpack.fleet.appNavigation.epmLinkText": "統合", + "xpack.fleet.appNavigation.overviewLinkText": "概要", + "xpack.fleet.appNavigation.policiesLinkText": "ポリシー", + "xpack.fleet.appNavigation.sendFeedbackButton": "フィードバックを送信", + "xpack.fleet.appNavigation.settingsButton": "設定", + "xpack.fleet.appTitle": "Fleet", + "xpack.fleet.betaBadge.labelText": "ベータ", + "xpack.fleet.betaBadge.tooltipText": "このプラグインは本番環境用ではありません。バグについてはディスカッションフォーラムで報告してください。", + "xpack.fleet.breadcrumbs.addPackagePolicyPageTitle": "統合の追加", + "xpack.fleet.breadcrumbs.agentsPageTitle": "エージェント", + "xpack.fleet.breadcrumbs.allIntegrationsPageTitle": "すべて", + "xpack.fleet.breadcrumbs.appTitle": "Fleet", + "xpack.fleet.breadcrumbs.datastreamsPageTitle": "データストリーム", + "xpack.fleet.breadcrumbs.editPackagePolicyPageTitle": "統合の編集", + "xpack.fleet.breadcrumbs.enrollmentTokensPageTitle": "登録トークン", + "xpack.fleet.breadcrumbs.installedIntegrationsPageTitle": "インストール済み", + "xpack.fleet.breadcrumbs.integrationsPageTitle": "統合", + "xpack.fleet.breadcrumbs.overviewPageTitle": "概要", + "xpack.fleet.breadcrumbs.policiesPageTitle": "ポリシー", + "xpack.fleet.copyAgentPolicy.confirmModal.cancelButtonLabel": "キャンセル", + "xpack.fleet.copyAgentPolicy.confirmModal.confirmButtonLabel": "ポリシーをコピー", + "xpack.fleet.copyAgentPolicy.confirmModal.copyPolicyPrompt": "新しいエージェントポリシーの名前と説明を選択してください。", + "xpack.fleet.copyAgentPolicy.confirmModal.copyPolicyTitle": "「{name}」エージェントポリシーをコピー", + "xpack.fleet.copyAgentPolicy.confirmModal.defaultNewPolicyName": "{name}(コピー)", + "xpack.fleet.copyAgentPolicy.confirmModal.newDescriptionLabel": "説明", + "xpack.fleet.copyAgentPolicy.confirmModal.newNameLabel": "新しいポリシー名", + "xpack.fleet.copyAgentPolicy.failureNotificationTitle": "エージェントポリシー「{id}」のコピーエラー", + "xpack.fleet.copyAgentPolicy.fatalErrorNotificationTitle": "エージェントポリシーのコピーエラー", + "xpack.fleet.copyAgentPolicy.successNotificationTitle": "エージェントポリシーがコピーされました", + "xpack.fleet.createAgentPolicy.cancelButtonLabel": "キャンセル", + "xpack.fleet.createAgentPolicy.errorNotificationTitle": "エージェントポリシーを作成できません", + "xpack.fleet.createAgentPolicy.flyoutTitle": "エージェントポリシーを作成", + "xpack.fleet.createAgentPolicy.flyoutTitleDescription": "エージェントポリシーは、エージェントのグループ全体にわたる設定を管理する目的で使用されます。エージェントポリシーに統合を追加すると、エージェントで収集するデータを指定できます。エージェントポリシーの編集時には、フリートを使用して、指定したエージェントのグループに更新をデプロイできます。", + "xpack.fleet.createAgentPolicy.submitButtonLabel": "エージェントポリシーを作成", + "xpack.fleet.createAgentPolicy.successNotificationTitle": "エージェントポリシー「{name}」が作成されました", + "xpack.fleet.createPackagePolicy.addedNotificationMessage": "Fleetは'{agentPolicyName}'ポリシーで使用されているすべてのエージェントに更新をデプロイします。", + "xpack.fleet.createPackagePolicy.addedNotificationTitle": "「{packagePolicyName}」統合が追加されました。", + "xpack.fleet.createPackagePolicy.agentPolicyNameLabel": "エージェントポリシー", + "xpack.fleet.createPackagePolicy.cancelButton": "キャンセル", + "xpack.fleet.createPackagePolicy.cancelLinkText": "キャンセル", + "xpack.fleet.createPackagePolicy.errorOnSaveText": "統合ポリシーにはエラーがあります。保存前に修正してください。", + "xpack.fleet.createPackagePolicy.pageDescriptionfromPackage": "次の手順に従い、この統合をエージェントポリシーに追加します。", + "xpack.fleet.createPackagePolicy.pageDescriptionfromPolicy": "選択したエージェントポリシーの統合を構成します。", + "xpack.fleet.createPackagePolicy.pageTitle": "統合の追加", + "xpack.fleet.createPackagePolicy.pageTitleWithPackageName": "{packageName}統合の追加", + "xpack.fleet.createPackagePolicy.saveButton": "統合の保存", + "xpack.fleet.createPackagePolicy.stepConfigure.advancedOptionsToggleLinkText": "高度なオプション", + "xpack.fleet.createPackagePolicy.stepConfigure.errorCountText": "{count, plural, one {件のエラー} other {件のエラー}}", + "xpack.fleet.createPackagePolicy.stepConfigure.hideStreamsAriaLabel": "{type}入力を非表示", + "xpack.fleet.createPackagePolicy.stepConfigure.inputSettingsDescription": "次の設定は以下のすべての入力に適用されます。", + "xpack.fleet.createPackagePolicy.stepConfigure.inputSettingsTitle": "設定", + "xpack.fleet.createPackagePolicy.stepConfigure.inputVarFieldOptionalLabel": "オプション", + "xpack.fleet.createPackagePolicy.stepConfigure.integrationSettingsSectionDescription": "この統合の使用方法を識別できるように、名前と説明を選択してください。", + "xpack.fleet.createPackagePolicy.stepConfigure.integrationSettingsSectionTitle": "統合設定", + "xpack.fleet.createPackagePolicy.stepConfigure.noPolicyOptionsMessage": "構成するものがありません", + "xpack.fleet.createPackagePolicy.stepConfigure.packagePolicyDescriptionInputLabel": "説明", + "xpack.fleet.createPackagePolicy.stepConfigure.packagePolicyNameInputLabel": "統合名", + "xpack.fleet.createPackagePolicy.stepConfigure.packagePolicyNamespaceInputLabel": "名前空間", + "xpack.fleet.createPackagePolicy.stepConfigure.showStreamsAriaLabel": "{type}入力を表示", + "xpack.fleet.createPackagePolicy.stepConfigure.toggleAdvancedOptionsButtonText": "高度なオプション", + "xpack.fleet.createPackagePolicy.stepConfigurePackagePolicyTitle": "統合の構成", + "xpack.fleet.createPackagePolicy.stepSelectAgentPolicyTitle": "エージェントポリシーを選択", + "xpack.fleet.createPackagePolicy.stepSelectPackage.errorLoadingPackagesTitle": "統合の読み込みエラー", + "xpack.fleet.createPackagePolicy.stepSelectPackage.errorLoadingPolicyTitle": "エージェントポリシー情報の読み込みエラー", + "xpack.fleet.createPackagePolicy.stepSelectPackage.errorLoadingSelectedPackageTitle": "選択した統合の読み込みエラー", + "xpack.fleet.createPackagePolicy.stepSelectPackage.filterPackagesInputPlaceholder": "統合を検索", + "xpack.fleet.createPackagePolicy.stepSelectPackageTitle": "統合を選択", + "xpack.fleet.createPackagePolicy.StepSelectPolicy.addButton": "エージェントポリシーを作成", + "xpack.fleet.createPackagePolicy.StepSelectPolicy.agentPolicyAgentsCountText": "{count, plural, one {#個のエージェント} other {#個のエージェント}}が登録されました", + "xpack.fleet.createPackagePolicy.StepSelectPolicy.agentPolicyAgentsDescriptionText": "選択したエージェントポリシーで{count, plural, one {#個のエージェント} other {#個のエージェント}}が登録されました。", + "xpack.fleet.createPackagePolicy.StepSelectPolicy.agentPolicyLabel": "エージェントポリシー", + "xpack.fleet.createPackagePolicy.StepSelectPolicy.agentPolicyPlaceholderText": "この統合を追加するエージェントポリシーを選択", + "xpack.fleet.createPackagePolicy.StepSelectPolicy.errorLoadingAgentPoliciesTitle": "エージェントポリシーの読み込みエラー", + "xpack.fleet.createPackagePolicy.StepSelectPolicy.errorLoadingPackageTitle": "パッケージ情報の読み込みエラー", + "xpack.fleet.createPackagePolicy.StepSelectPolicy.errorLoadingSelectedAgentPolicyTitle": "選択したエージェントポリシーの読み込みエラー", + "xpack.fleet.dataStreamList.actionsColumnTitle": "アクション", + "xpack.fleet.dataStreamList.datasetColumnTitle": "データセット", + "xpack.fleet.dataStreamList.integrationColumnTitle": "統合", + "xpack.fleet.dataStreamList.lastActivityColumnTitle": "前回のアクティビティ", + "xpack.fleet.dataStreamList.loadingDataStreamsMessage": "データストリームを読み込んでいます...", + "xpack.fleet.dataStreamList.namespaceColumnTitle": "名前空間", + "xpack.fleet.dataStreamList.noDataStreamsPrompt": "データストリームがありません", + "xpack.fleet.dataStreamList.noFilteredDataStreamsMessage": "一致するデータストリームが見つかりません", + "xpack.fleet.dataStreamList.pageSubtitle": "エージェントが作成したデータを管理します。", + "xpack.fleet.dataStreamList.pageTitle": "データストリーム", + "xpack.fleet.dataStreamList.reloadDataStreamsButtonText": "再読み込み", + "xpack.fleet.dataStreamList.searchPlaceholderTitle": "データストリームをフィルター", + "xpack.fleet.dataStreamList.sizeColumnTitle": "サイズ", + "xpack.fleet.dataStreamList.typeColumnTitle": "タイプ", + "xpack.fleet.dataStreamList.viewDashboardActionText": "ダッシュボードを表示", + "xpack.fleet.dataStreamList.viewDashboardsActionText": "ダッシュボードを表示", + "xpack.fleet.dataStreamList.viewDashboardsPanelTitle": "ダッシュボードを表示", + "xpack.fleet.defaultSearchPlaceholderText": "検索", + "xpack.fleet.deleteAgentPolicy.confirmModal.affectedAgentsMessage": "{agentsCount, plural, one {#個のエージェントは} other {#個のエージェントは}}このエージェントポリシーに割り当てられました。このポリシーを削除する前に、これらのエージェントの割り当てを解除します。", + "xpack.fleet.deleteAgentPolicy.confirmModal.affectedAgentsTitle": "使用中のポリシー", + "xpack.fleet.deleteAgentPolicy.confirmModal.cancelButtonLabel": "キャンセル", + "xpack.fleet.deleteAgentPolicy.confirmModal.confirmButtonLabel": "ポリシーを削除", + "xpack.fleet.deleteAgentPolicy.confirmModal.deletePolicyTitle": "このエージェントポリシーを削除しますか?", + "xpack.fleet.deleteAgentPolicy.confirmModal.irreversibleMessage": "この操作は元に戻すことができません。", + "xpack.fleet.deleteAgentPolicy.confirmModal.loadingAgentsCountMessage": "影響があるエージェントの数を確認中...", + "xpack.fleet.deleteAgentPolicy.confirmModal.loadingButtonLabel": "読み込み中...", + "xpack.fleet.deleteAgentPolicy.failureSingleNotificationTitle": "エージェントポリシー「{id}」の削除エラー", + "xpack.fleet.deleteAgentPolicy.fatalErrorNotificationTitle": "エージェントポリシーの削除エラー", + "xpack.fleet.deleteAgentPolicy.successSingleNotificationTitle": "エージェントポリシー「{id}」が削除されました", + "xpack.fleet.deletePackagePolicy.confirmModal.affectedAgentsMessage": "{agentPolicyName}が一部のエージェントですでに使用されていることをFleetが検出しました。", + "xpack.fleet.deletePackagePolicy.confirmModal.affectedAgentsTitle": "このアクションは {agentsCount} {agentsCount, plural, one {# エージェント} other {# エージェント}}に影響します", + "xpack.fleet.deletePackagePolicy.confirmModal.cancelButtonLabel": "キャンセル", + "xpack.fleet.deletePackagePolicy.confirmModal.deleteMultipleTitle": "{count, plural, one {個の統合} other {個の統合}}を削除しますか?", + "xpack.fleet.deletePackagePolicy.confirmModal.generalMessage": "このアクションは元に戻せません。続行していいですか?", + "xpack.fleet.deletePackagePolicy.confirmModal.loadingAgentsCountMessage": "影響があるエージェントを確認中...", + "xpack.fleet.deletePackagePolicy.confirmModal.loadingButtonLabel": "読み込み中...", + "xpack.fleet.deletePackagePolicy.failureMultipleNotificationTitle": "{count}個の統合の削除エラー", + "xpack.fleet.deletePackagePolicy.failureSingleNotificationTitle": "統合「{id}」の削除エラー", + "xpack.fleet.deletePackagePolicy.fatalErrorNotificationTitle": "統合の削除エラー", + "xpack.fleet.deletePackagePolicy.successMultipleNotificationTitle": "{count}個の統合を削除しました", + "xpack.fleet.deletePackagePolicy.successSingleNotificationTitle": "統合「{id}」を削除しました", + "xpack.fleet.disabledSecurityDescription": "Elastic Fleet を使用するには、Kibana と Elasticsearch でセキュリティを有効にする必要があります。", + "xpack.fleet.disabledSecurityTitle": "セキュリティが有効ではありません", + "xpack.fleet.editAgentPolicy.cancelButtonText": "キャンセル", + "xpack.fleet.editAgentPolicy.errorNotificationTitle": "エージェントポリシーを更新できません", + "xpack.fleet.editAgentPolicy.saveButtonText": "変更を保存", + "xpack.fleet.editAgentPolicy.savingButtonText": "保存中…", + "xpack.fleet.editAgentPolicy.successNotificationTitle": "正常に「{name}」設定を更新しました", + "xpack.fleet.editAgentPolicy.unsavedChangesText": "保存されていない変更があります", + "xpack.fleet.editPackagePolicy.cancelButton": "キャンセル", + "xpack.fleet.editPackagePolicy.errorLoadingDataMessage": "この統合情報の読み込みエラーが発生しました", + "xpack.fleet.editPackagePolicy.errorLoadingDataTitle": "データの読み込み中にエラーが発生", + "xpack.fleet.editPackagePolicy.failedConflictNotificationMessage": "データが最新ではありません。最新のポリシーを取得するには、ページを更新してください。", + "xpack.fleet.editPackagePolicy.failedNotificationTitle": "「{packagePolicyName}」の更新エラー", + "xpack.fleet.editPackagePolicy.pageDescription": "統合設定を修正し、選択したエージェントポリシーに変更をデプロイします。", + "xpack.fleet.editPackagePolicy.pageTitle": "統合の編集", + "xpack.fleet.editPackagePolicy.pageTitleWithPackageName": "{packageName}統合の編集", + "xpack.fleet.editPackagePolicy.saveButton": "統合の保存", + "xpack.fleet.editPackagePolicy.updatedNotificationMessage": "Fleetは'{agentPolicyName}'ポリシーで使用されているすべてのエージェントに更新をデプロイします", + "xpack.fleet.editPackagePolicy.updatedNotificationTitle": "正常に「{packagePolicyName}」を更新しました", + "xpack.fleet.enrollemntAPIKeyList.emptyMessage": "登録トークンが見つかりません。", + "xpack.fleet.enrollemntAPIKeyList.loadingTokensMessage": "登録トークンを読み込んでいます...", + "xpack.fleet.enrollmentInstructions.descriptionText": "エージェントのディレクトリから、該当するコマンドを実行し、Elasticエージェントをインストール、登録、起動します。これらのコマンドを再利用すると、複数のホストでエージェントを設定できます。管理者権限が必要です。", + "xpack.fleet.enrollmentInstructions.linuxMacOSTitle": "Linux、MacOS", + "xpack.fleet.enrollmentInstructions.moreInstructionsLink": "Elasticエージェントドキュメント", + "xpack.fleet.enrollmentInstructions.moreInstructionsText": "手順とオプションの詳細については、{link}を参照してください。", + "xpack.fleet.enrollmentInstructions.windowsTitle": "Windows", + "xpack.fleet.enrollmentStepAgentPolicy.enrollmentTokenSelectLabel": "登録トークン", + "xpack.fleet.enrollmentStepAgentPolicy.policySelectAriaLabel": "エージェントポリシー", + "xpack.fleet.enrollmentStepAgentPolicy.policySelectLabel": "エージェントポリシー", + "xpack.fleet.enrollmentStepAgentPolicy.showAuthenticationSettingsButton": "認証設定", + "xpack.fleet.enrollmentTokenDeleteModal.cancelButton": "キャンセル", + "xpack.fleet.enrollmentTokenDeleteModal.deleteButton": "登録トークンを取り消し", + "xpack.fleet.enrollmentTokenDeleteModal.description": "{keyName}を取り消してよろしいですか?このトークンを使用するエージェントは、ポリシーにアクセスしたり、データを送信したりできなくなります。 ", + "xpack.fleet.enrollmentTokenDeleteModal.title": "登録トークンを取り消し", + "xpack.fleet.enrollmentTokensList.actionsTitle": "アクション", + "xpack.fleet.enrollmentTokensList.activeTitle": "アクティブ", + "xpack.fleet.enrollmentTokensList.createdAtTitle": "作成日時", + "xpack.fleet.enrollmentTokensList.hideTokenButtonLabel": "トークンを非表示", + "xpack.fleet.enrollmentTokensList.nameTitle": "名前", + "xpack.fleet.enrollmentTokensList.newKeyButton": "登録トークンを作成", + "xpack.fleet.enrollmentTokensList.pageDescription": "登録トークンを作成して取り消します。登録トークンを使用すると、1つ以上のエージェントをFleetに登録し、データを送信できます。", + "xpack.fleet.enrollmentTokensList.policyTitle": "エージェントポリシー", + "xpack.fleet.enrollmentTokensList.revokeTokenButtonLabel": "トークンを取り消す", + "xpack.fleet.enrollmentTokensList.secretTitle": "シークレット", + "xpack.fleet.enrollmentTokensList.showTokenButtonLabel": "トークンを表示", + "xpack.fleet.epm.addPackagePolicyButtonText": "{packageName}の追加", + "xpack.fleet.epm.assetGroupTitle": "{assetType}アセット", + "xpack.fleet.epm.browseAllButtonText": "すべての統合を参照", + "xpack.fleet.epm.illustrationAltText": "統合の例", + "xpack.fleet.epm.loadingIntegrationErrorTitle": "統合詳細の読み込みエラー", + "xpack.fleet.epm.packageDetailsNav.overviewLinkText": "概要", + "xpack.fleet.epm.packageDetailsNav.packagePoliciesLinkText": "使用", + "xpack.fleet.epm.packageDetailsNav.settingsLinkText": "設定", + "xpack.fleet.epm.pageSubtitle": "一般的なアプリやサービスの統合を参照する", + "xpack.fleet.epm.pageTitle": "統合", + "xpack.fleet.epm.releaseBadge.betaDescription": "この統合は本番環境用ではありません。", + "xpack.fleet.epm.releaseBadge.betaLabel": "ベータ", + "xpack.fleet.epm.releaseBadge.experimentalDescription": "この統合は、急に変更されたり、将来のリリースで削除されたりする可能性があります。", + "xpack.fleet.epm.releaseBadge.experimentalLabel": "実験的", + "xpack.fleet.epm.screenshotsTitle": "スクリーンショット", + "xpack.fleet.epm.updateAvailableTooltip": "更新が利用可能です", + "xpack.fleet.epm.versionLabel": "バージョン", + "xpack.fleet.epmList.allFilterLinkText": "すべて", + "xpack.fleet.epmList.allPackagesFilterLinkText": "すべて", + "xpack.fleet.epmList.allTabText": "すべての統合", + "xpack.fleet.epmList.allTitle": "カテゴリで参照", + "xpack.fleet.epmList.installedTabText": "インストールされている統合", + "xpack.fleet.epmList.installedTitle": "インストールされている統合", + "xpack.fleet.epmList.noPackagesFoundPlaceholder": "パッケージが見つかりません", + "xpack.fleet.epmList.searchPackagesPlaceholder": "統合を検索", + "xpack.fleet.epmList.updatesAvailableFilterLinkText": "更新が可能です", + "xpack.fleet.featureCatalogueDescription": "Elasticエージェントと統合のFleetを追加して管理します。", + "xpack.fleet.featureCatalogueTitle": "Elasticエージェントの追加", + "xpack.fleet.genericActionsMenuText": "開く", + "xpack.fleet.homeIntegration.tutorialDirectory.dismissNoticeButtonText": "メッセージを消去", + "xpack.fleet.homeIntegration.tutorialDirectory.noticeText": "Elasticエージェントでは、シンプルかつ統合された方法で、ログ、メトリック、他の種類のデータの監視をホストに追加することができます。複数のBeatsと他のエージェントをインストールする必要はありません。このため、インフラストラクチャ全体でのポリシーのデプロイが簡単で高速になりました。詳細については、{blogPostLink}をお読みください。", + "xpack.fleet.homeIntegration.tutorialDirectory.noticeText.blogPostLink": "発表ブログ投稿", + "xpack.fleet.homeIntegration.tutorialDirectory.noticeTitle": "{newPrefix} ElasticエージェントおよびIngest Managerベータ", + "xpack.fleet.homeIntegration.tutorialDirectory.noticeTitle.newPrefix": "新規:", + "xpack.fleet.homeIntegration.tutorialModule.noticeText": "{notePrefix}このモジュールの新しいバージョンは、Ingest Managerベータの{availableAsIntegrationLink}です。エージェントポリシーと新しいElasticエージェントの詳細については、{blogPostLink}をお読みください。", + "xpack.fleet.homeIntegration.tutorialModule.noticeText.blogPostLink": "発表ブログ投稿", + "xpack.fleet.homeIntegration.tutorialModule.noticeText.integrationLink": "統合として利用可能", + "xpack.fleet.homeIntegration.tutorialModule.noticeText.notePrefix": "注:", + "xpack.fleet.initializationErrorMessageTitle": "Ingest Manager を初期化できません", + "xpack.fleet.integrations.installPackage.installingPackageButtonLabel": "{title}アセットをインストールしています", + "xpack.fleet.integrations.installPackage.installPackageButtonLabel": "{title}アセットをインストール", + "xpack.fleet.integrations.packageInstallErrorDescription": "このパッケージのインストール中に問題が発生しました。しばらくたってから再試行してください。", + "xpack.fleet.integrations.packageInstallErrorTitle": "{title}パッケージをインストールできませんでした", + "xpack.fleet.integrations.packageInstallSuccessDescription": "正常に{title}をインストールしました", + "xpack.fleet.integrations.packageInstallSuccessTitle": "{title}をインストールしました", + "xpack.fleet.integrations.packageUninstallErrorDescription": "このパッケージのアンインストール中に問題が発生しました。しばらくたってから再試行してください。", + "xpack.fleet.integrations.packageUninstallErrorTitle": "{title}パッケージをアンインストールできませんでした", + "xpack.fleet.integrations.packageUninstallSuccessDescription": "正常に{title}をアンインストールしました", + "xpack.fleet.integrations.packageUninstallSuccessTitle": "{title}をアンインストールしました", + "xpack.fleet.integrations.settings.confirmInstallModal.cancelButtonLabel": "キャンセル", + "xpack.fleet.integrations.settings.confirmInstallModal.installButtonLabel": "{packageName}をインストール", + "xpack.fleet.integrations.settings.confirmInstallModal.installCalloutTitle": "{numOfAssets}個のアセットがインストールされます", + "xpack.fleet.integrations.settings.confirmInstallModal.installDescription": "Kibanaアセットは現在のスペース(既定)にインストールされ、このスペースを表示する権限があるユーザーのみがアクセスできます。Elasticsearchアセットはグローバルでインストールされ、すべてのKibanaユーザーがアクセスできます。", + "xpack.fleet.integrations.settings.confirmInstallModal.installTitle": "{packageName}をインストール", + "xpack.fleet.integrations.settings.confirmUninstallModal.cancelButtonLabel": "キャンセル", + "xpack.fleet.integrations.settings.confirmUninstallModal.uninstallButtonLabel": "{packageName}をアンインストール", + "xpack.fleet.integrations.settings.confirmUninstallModal.uninstallCallout.description": "この統合によって作成されたKibanaおよびElasticsearchアセットは削除されます。エージェントポリシーとエージェントによって送信されたデータは影響を受けません。", + "xpack.fleet.integrations.settings.confirmUninstallModal.uninstallCallout.title": "{numOfAssets}個のアセットが削除されます", + "xpack.fleet.integrations.settings.confirmUninstallModal.uninstallDescription": "この操作は元に戻すことができません。続行していいですか?", + "xpack.fleet.integrations.settings.confirmUninstallModal.uninstallTitle": "{packageName}をアンインストール", + "xpack.fleet.integrations.settings.packageInstallDescription": "この統合をインストールして、{title}データ向けに設計されたKibanaおよびElasticsearchアセットをセットアップします。", + "xpack.fleet.integrations.settings.packageInstallTitle": "{title}をインストール", + "xpack.fleet.integrations.settings.packageSettingsTitle": "設定", + "xpack.fleet.integrations.settings.packageUninstallDescription": "この統合によってインストールされたKibanaおよびElasticsearchアセットを削除します。", + "xpack.fleet.integrations.settings.packageUninstallNoteDescription.packageUninstallNoteDetail": "{strongNote} {title}をアンインストールできません。この統合を使用しているアクティブなエージェントがあります。アンインストールするには、エージェントポリシーからすべての{title}統合を削除します。", + "xpack.fleet.integrations.settings.packageUninstallNoteDescription.packageUninstallNoteLabel": "注:", + "xpack.fleet.integrations.settings.packageUninstallNoteDescription.packageUninstallUninstallableNoteDetail": "{strongNote} {title}統合は既定でインストールされているため、削除できません。", + "xpack.fleet.integrations.settings.packageUninstallTitle": "{title}をアンインストール", + "xpack.fleet.integrations.settings.packageVersionTitle": "{title}バージョン", + "xpack.fleet.integrations.settings.versionInfo.installedVersion": "インストールされているバージョン", + "xpack.fleet.integrations.settings.versionInfo.latestVersion": "最新バージョン", + "xpack.fleet.integrations.settings.versionInfo.updatesAvailable": "更新が利用可能です", + "xpack.fleet.integrations.uninstallPackage.uninstallingPackageButtonLabel": "{title}をアンインストールしています", + "xpack.fleet.integrations.uninstallPackage.uninstallPackageButtonLabel": "{title}をアンインストール", + "xpack.fleet.integrations.updatePackage.updatePackageButtonLabel": "最新バージョンに更新", + "xpack.fleet.invalidLicenseDescription": "現在のライセンスは期限切れです。登録されたビートエージェントは引き続き動作しますが、Elastic Fleet インターフェースにアクセスするには有効なライセンスが必要です。", + "xpack.fleet.invalidLicenseTitle": "ライセンスの期限切れ", + "xpack.fleet.listTabs.agentTitle": "エージェント", + "xpack.fleet.listTabs.enrollmentTokensTitle": "登録トークン", + "xpack.fleet.metadataForm.addButton": "+ メタデータを追加", + "xpack.fleet.metadataForm.keyLabel": "キー", + "xpack.fleet.metadataForm.submitButtonText": "追加", + "xpack.fleet.metadataForm.valueLabel": "値", + "xpack.fleet.namespaceValidation.invalidCharactersErrorMessage": "名前空間に無効な文字が含まれています", + "xpack.fleet.namespaceValidation.lowercaseErrorMessage": "名前空間は小文字で指定する必要があります", + "xpack.fleet.namespaceValidation.requiredErrorMessage": "名前空間は必須です", + "xpack.fleet.namespaceValidation.tooLongErrorMessage": "名前空間は100バイト以下でなければなりません", + "xpack.fleet.newEnrollmentKey.cancelButtonLabel": "キャンセル", + "xpack.fleet.newEnrollmentKey.flyoutTitle": "登録トークンを作成", + "xpack.fleet.newEnrollmentKey.keyCreatedToasts": "登録トークンが作成されました。", + "xpack.fleet.newEnrollmentKey.nameLabel": "名前", + "xpack.fleet.newEnrollmentKey.policyLabel": "ポリシー", + "xpack.fleet.newEnrollmentKey.submitButton": "登録トークンを作成", + "xpack.fleet.noAccess.accessDeniedDescription": "Elastic Fleet にアクセスする権限がありません。Elastic Fleet を使用するには、このアプリケーションの読み取り権または全権を含むユーザーロールが必要です。", + "xpack.fleet.noAccess.accessDeniedTitle": "アクセスが拒否されました", + "xpack.fleet.overviewAgentActiveTitle": "アクティブ", + "xpack.fleet.overviewAgentErrorTitle": "エラー", + "xpack.fleet.overviewAgentOfflineTitle": "オフライン", + "xpack.fleet.overviewAgentTotalTitle": "合計エージェント数", + "xpack.fleet.overviewDatastreamNamespacesTitle": "名前空間", + "xpack.fleet.overviewDatastreamSizeTitle": "合計サイズ", + "xpack.fleet.overviewDatastreamTotalTitle": "データストリーム", + "xpack.fleet.overviewIntegrationsInstalledTitle": "インストール済み", + "xpack.fleet.overviewIntegrationsTotalTitle": "合計利用可能数", + "xpack.fleet.overviewIntegrationsUpdatesAvailableTitle": "更新が可能です", + "xpack.fleet.overviewPackagePolicyTitle": "使用済みの統合", + "xpack.fleet.overviewPageAgentsPanelTitle": "エージェント", + "xpack.fleet.overviewPageDataStreamsPanelAction": "データストリームを表示", + "xpack.fleet.overviewPageDataStreamsPanelTitle": "データストリーム", + "xpack.fleet.overviewPageDataStreamsPanelTooltip": "エージェントが収集するデータはさまざまなデータストリームに整理されます。", + "xpack.fleet.overviewPageEnrollAgentButton": "エージェントの追加", + "xpack.fleet.overviewPageFleetPanelAction": "エージェントを表示", + "xpack.fleet.overviewPageFleetPanelTooltip": "Fleetを使用して、中央の場所からエージェントを登録し、ポリシーを管理します。", + "xpack.fleet.overviewPageIntegrationsPanelAction": "統合を表示", + "xpack.fleet.overviewPageIntegrationsPanelTitle": "統合", + "xpack.fleet.overviewPageIntegrationsPanelTooltip": "Elastic Stackの統合を参照し、インストールします。統合をエージェントポリシーに追加し、データの送信を開始します。", + "xpack.fleet.overviewPagePoliciesPanelAction": "ポリシーを表示", + "xpack.fleet.overviewPagePoliciesPanelTitle": "エージェントポリシー", + "xpack.fleet.overviewPagePoliciesPanelTooltip": "エージェントポリシーを使用すると、エージェントが収集するデータを管理できます。", + "xpack.fleet.overviewPageSubtitle": "Elasticエージェントとポリシーを中央の場所で管理します。", + "xpack.fleet.overviewPageTitle": "Fleet", + "xpack.fleet.overviewPolicyTotalTitle": "合計利用可能数", + "xpack.fleet.packagePolicyValidation.invalidArrayErrorMessage": "無効なフォーマット", + "xpack.fleet.packagePolicyValidation.invalidYamlFormatErrorMessage": "YAML形式が無効です", + "xpack.fleet.packagePolicyValidation.nameRequiredErrorMessage": "名前が必要です", + "xpack.fleet.packagePolicyValidation.requiredErrorMessage": "{fieldName}が必要です", + "xpack.fleet.permissionDeniedErrorMessage": "Ingest Managerにアクセスする権限がありません。Ingest Managerには{roleName}権限が必要です。", + "xpack.fleet.permissionDeniedErrorTitle": "パーミッションが拒否されました", + "xpack.fleet.permissionsRequestErrorMessageDescription": "Ingest Managerアクセス権の確認中に問題が発生しました", + "xpack.fleet.permissionsRequestErrorMessageTitle": "アクセス権を確認できません", + "xpack.fleet.policyDetails.addPackagePolicyButtonText": "統合の追加", + "xpack.fleet.policyDetails.ErrorGettingFullAgentPolicy": "エージェントポリシーの読み込みエラー", + "xpack.fleet.policyDetails.packagePoliciesTable.actionsColumnTitle": "アクション", + "xpack.fleet.policyDetails.packagePoliciesTable.deleteActionTitle": "統合の削除", + "xpack.fleet.policyDetails.packagePoliciesTable.descriptionColumnTitle": "説明", + "xpack.fleet.policyDetails.packagePoliciesTable.editActionTitle": "統合の編集", + "xpack.fleet.policyDetails.packagePoliciesTable.nameColumnTitle": "名前", + "xpack.fleet.policyDetails.packagePoliciesTable.namespaceColumnTitle": "名前空間", + "xpack.fleet.policyDetails.packagePoliciesTable.packageNameColumnTitle": "統合", + "xpack.fleet.policyDetails.policyDetailsTitle": "ポリシー「{id}」", + "xpack.fleet.policyDetails.policyNotFoundErrorTitle": "ポリシー「{id}」が見つかりません", + "xpack.fleet.policyDetails.subTabs.packagePoliciesTabText": "統合", + "xpack.fleet.policyDetails.subTabs.settingsTabText": "設定", + "xpack.fleet.policyDetails.summary.integrations": "統合", + "xpack.fleet.policyDetails.summary.lastUpdated": "最終更新日", + "xpack.fleet.policyDetails.summary.revision": "リビジョン", + "xpack.fleet.policyDetails.summary.usedBy": "使用者", + "xpack.fleet.policyDetails.unexceptedErrorTitle": "エージェントポリシーの読み込み中にエラーが発生しました", + "xpack.fleet.policyDetails.viewAgentListTitle": "すべてのエージェントポリシーを表示", + "xpack.fleet.policyDetails.yamlDownloadButtonLabel": "ダウンロードポリシー", + "xpack.fleet.policyDetails.yamlFlyoutCloseButtonLabel": "閉じる", + "xpack.fleet.policyDetails.yamlflyoutTitleWithName": "「{name}」エージェントポリシー", + "xpack.fleet.policyDetails.yamlflyoutTitleWithoutName": "エージェントポリシー", + "xpack.fleet.policyDetailsPackagePolicies.createFirstButtonText": "統合の追加", + "xpack.fleet.policyDetailsPackagePolicies.createFirstMessage": "このポリシーにはまだ統合がありません。", + "xpack.fleet.policyDetailsPackagePolicies.createFirstTitle": "最初の統合を追加", + "xpack.fleet.policyForm.deletePolicyActionText": "ポリシーを削除", + "xpack.fleet.policyForm.deletePolicyGroupDescription": "既存のデータは削除されません。", + "xpack.fleet.policyForm.deletePolicyGroupTitle": "ポリシーを削除", + "xpack.fleet.policyForm.generalSettingsGroupDescription": "エージェントポリシーの名前と説明を選択してください。", + "xpack.fleet.policyForm.generalSettingsGroupTitle": "一般設定", + "xpack.fleet.policyForm.unableToDeleteDefaultPolicyText": "デフォルトポリシーは削除できません", + "xpack.fleet.securityRequiredErrorMessage": "Ingest Managerを使用するには、KibanaとElasticsearchでセキュリティを有効にする必要があります。", + "xpack.fleet.securityRequiredErrorTitle": "セキュリティが有効ではありません", + "xpack.fleet.settings.additionalYamlConfig": "Elasticsearch出力構成", + "xpack.fleet.settings.autoUpgradeDisabledLabel": "エージェントバイナリバージョンを手動で管理します。サブスクリプションが必要です。", + "xpack.fleet.settings.autoUpgradeEnabledLabel": "エージェントバイナリを自動的に更新し、最新マイナーバージョンを使用します。", + "xpack.fleet.settings.autoUpgradeFieldLabel": "Elasticエージェントバイナリバージョン", + "xpack.fleet.settings.cancelButtonLabel": "キャンセル", + "xpack.fleet.settings.elasticHostError": "無効なURL", + "xpack.fleet.settings.elasticsearchUrlLabel": "Elasticsearch URL", + "xpack.fleet.settings.flyoutTitle": "Ingest Manager設定", + "xpack.fleet.settings.globalOutputDescription": "データを送信する場所を指定します。これらの設定はすべてのElasticエージェントポリシーに適用されます。", + "xpack.fleet.settings.globalOutputTitle": "グローバル出力", + "xpack.fleet.settings.integrationUpgradeDisabledFieldLabel": "統合バージョンを手動で管理します。", + "xpack.fleet.settings.integrationUpgradeEnabledFieldLabel": "自動的に統合を最新バージョンに更新し、最新のアセットを取得します。新機能を使用するには、エージェントポリシーを更新しなければならない場合があります。", + "xpack.fleet.settings.integrationUpgradeFieldLabel": "統合バージョン", + "xpack.fleet.settings.invalidYamlFormatErrorMessage": "無効なYAML形式:{reason}", + "xpack.fleet.settings.kibanaUrlDifferentPathOrProtocolError": "各URLのプロトコルとパスは同じでなければなりません", + "xpack.fleet.settings.kibanaUrlEmptyError": "1つ以上のURLが必要です。", + "xpack.fleet.settings.kibanaUrlError": "無効なURL", + "xpack.fleet.settings.kibanaUrlLabel": "Kibana URL", + "xpack.fleet.settings.saveButtonLabel": "設定を保存", + "xpack.fleet.settings.success.message": "設定が保存されました", + "xpack.fleet.setupPage.apiKeyServiceLink": "APIキーサービス", + "xpack.fleet.setupPage.elasticsearchApiKeyFlagText": "{apiKeyLink}.{apiKeyFlag}を{true}に設定します。", + "xpack.fleet.setupPage.elasticsearchSecurityFlagText": "{esSecurityLink}.{securityFlag}を{true}に設定します。", + "xpack.fleet.setupPage.elasticsearchSecurityLink": "Elasticsearchセキュリティ", + "xpack.fleet.setupPage.enableCentralManagement": "ユーザーを作成し、集中管理を有効にする", + "xpack.fleet.setupPage.enableText": "集中管理には、APIキーを作成し、log-*とmetrics-*に書き込むことができるElasticユーザーが必要です。", + "xpack.fleet.setupPage.enableTitle": "ElasticElasticエージェントの集中管理を有効にする", + "xpack.fleet.setupPage.encryptionKeyFlagText": "{encryptionKeyLink}.{keyFlag}を32文字以上の英数字に設定します。", + "xpack.fleet.setupPage.gettingStartedLink": "はじめに", + "xpack.fleet.setupPage.gettingStartedText": "詳細については、{link}ガイドをお読みください。", + "xpack.fleet.setupPage.kibanaEncryptionLink": "Kibana暗号化鍵", + "xpack.fleet.setupPage.kibanaSecurityLink": "Kibanaセキュリティ", + "xpack.fleet.setupPage.missingRequirementsCalloutDescription": "Elasticエージェントの集中管理を使用するには、次のElasticsearchとKibanaセキュリティ機能を有効にする必要があります。", + "xpack.fleet.setupPage.missingRequirementsCalloutTitle": "不足しているセキュリティ要件", + "xpack.fleet.setupPage.missingRequirementsElasticsearchTitle": "Elasticsearchポリシーでは、次のことができます。", + "xpack.fleet.setupPage.missingRequirementsKibanaTitle": "Kibanaポリシーでは、次のことができます。", + "xpack.fleet.setupPage.tlsFlagText": "{kibanaSecurityLink}.{securityFlag}を{true}に設定します。開発目的では、危険な代替として{tlsFlag}を{true}に設定して、{tlsLink}を無効化できます。", + "xpack.fleet.setupPage.tlsLink": "TLS", + "xpack.fleet.unenrollAgents.cancelButtonLabel": "キャンセル", + "xpack.fleet.unenrollAgents.confirmMultipleButtonLabel": "{count}個のエージェントを登録解除", + "xpack.fleet.unenrollAgents.confirmSingleButtonLabel": "エージェントの登録解除", + "xpack.fleet.unenrollAgents.deleteMultipleDescription": "このアクションにより、複数のエージェントがFleetから削除され、新しいデータを取り込めなくなります。これらのエージェントによってすでに送信されたデータは一切影響を受けません。この操作は元に戻すことができません。", + "xpack.fleet.unenrollAgents.deleteSingleDescription": "このアクションにより、「{hostName}」で実行中の選択したエージェントがFleetから削除されます。エージェントによってすでに送信されたデータは一切削除されません。この操作は元に戻すことができません。", + "xpack.fleet.unenrollAgents.deleteSingleTitle": "エージェントの登録解除", + "xpack.fleet.unenrollAgents.fatalErrorNotificationTitle": "{count, plural, one {エージェント} other {エージェント}}の登録解除エラー", + "xpack.fleet.unenrollAgents.forceDeleteMultipleTitle": "{count}個のエージェントを登録解除", + "xpack.fleet.unenrollAgents.forceUnenrollCheckboxLabel": "{count, plural, one {エージェント} other {エージェント}}がただちに削除されました。エージェントが最後のデータを送信するまで待機しない。", + "xpack.fleet.unenrollAgents.forceUnenrollLegendText": "{count, plural, one {エージェント} other {エージェント}}を強制的に登録解除", + "xpack.fleet.unenrollAgents.successForceMultiNotificationTitle": "エージェントが登録解除されました", + "xpack.fleet.unenrollAgents.successForceSingleNotificationTitle": "エージェントが登録解除されました", + "xpack.fleet.unenrollAgents.successMultiNotificationTitle": "エージェントを登録解除しています", + "xpack.fleet.unenrollAgents.successSingleNotificationTitle": "エージェントを登録解除しています", + "xpack.fleet.upgradeAgents.cancelButtonLabel": "キャンセル", + "xpack.fleet.upgradeAgents.confirmMultipleButtonLabel": "{count}個のエージェントをアップグレード", + "xpack.fleet.upgradeAgents.confirmSingleButtonLabel": "エージェントをアップグレード", + "xpack.fleet.upgradeAgents.deleteMultipleTitle": "{count}個のエージェントをアップグレード", + "xpack.fleet.upgradeAgents.deleteSingleTitle": "エージェントをアップグレード", + "xpack.fleet.upgradeAgents.fatalErrorNotificationTitle": "{count, plural, one {エージェント} other {エージェント}}のアップグレードエラー", + "xpack.fleet.upgradeAgents.successMultiNotificationTitle": "エージェントをアップグレード中...", + "xpack.fleet.upgradeAgents.successSingleNotificationTitle": "エージェントをアップグレード中", + "xpack.fleet.upgradeAgents.upgradeMultipleDescription": "このアクションにより、複数のエージェントがバージョン{version}にアップグレードされます。この操作は元に戻すことができません。続行していいですか?", + "xpack.fleet.upgradeAgents.upgradeSingleDescription": "このアクションにより、「{hostName}」で実行中の選択したエージェントがバージョン{version}にアップグレードされます。この操作は元に戻すことができません。続行していいですか?", "xpack.globalSearch.find.invalidLicenseError": "GlobalSearch APIは、ライセンス状態が無効であるため、無効になっています。{errorMessage}", "xpack.globalSearchBar.searchBar.mobileSearchButtonAriaLabel": "サイト検索", "xpack.globalSearchBar.searchBar.noResults": "アプリケーション、ダッシュボード、ビジュアライゼーションなどを検索してみてください。", @@ -9631,578 +10202,6 @@ "xpack.infra.waffle.unableToSelectMetricErrorTitle": "メトリックのオプションまたは値を選択できません", "xpack.infra.waffleTime.autoRefreshButtonLabel": "自動更新", "xpack.infra.waffleTime.stopRefreshingButtonLabel": "更新中止", - "xpack.ingestManager.agentBulkActions.agentsSelected": "{count, plural, one {#個のエージェント} other {#個のエージェント}}が選択されました", - "xpack.ingestManager.agentBulkActions.clearSelection": "選択した項目をクリア", - "xpack.ingestManager.agentBulkActions.reassignPolicy": "新しいポリシーに割り当てる", - "xpack.ingestManager.agentBulkActions.selectAll": "すべてのページのすべての項目を選択", - "xpack.ingestManager.agentBulkActions.totalAgents": "{count, plural, one {#個のエージェント} other {#個のエージェント}}を表示しています", - "xpack.ingestManager.agentBulkActions.totalAgentsWithLimit": "{count}/{total}個のエージェントを表示しています", - "xpack.ingestManager.agentBulkActions.unenrollAgents": "エージェントの登録を解除", - "xpack.ingestManager.agentBulkActions.upgradeAgents": "エージェントをアップグレード", - "xpack.ingestManager.agentDetails.actionsButton": "アクション", - "xpack.ingestManager.agentDetails.agentDetailsTitle": "エージェント'{id}'", - "xpack.ingestManager.agentDetails.agentNotFoundErrorDescription": "エージェントID {agentId}が見つかりません", - "xpack.ingestManager.agentDetails.agentNotFoundErrorTitle": "エージェントが見つかりません", - "xpack.ingestManager.agentDetails.agentPolicyLabel": "エージェントポリシー", - "xpack.ingestManager.agentDetails.agentVersionLabel": "エージェントバージョン", - "xpack.ingestManager.agentDetails.hostIdLabel": "エージェントID", - "xpack.ingestManager.agentDetails.hostNameLabel": "ホスト名", - "xpack.ingestManager.agentDetails.localMetadataSectionSubtitle": "メタデータを読み込み中", - "xpack.ingestManager.agentDetails.metadataSectionTitle": "メタデータ", - "xpack.ingestManager.agentDetails.platformLabel": "プラットフォーム", - "xpack.ingestManager.agentDetails.policyLabel": "ポリシー", - "xpack.ingestManager.agentDetails.releaseLabel": "エージェントリリース", - "xpack.ingestManager.agentDetails.statusLabel": "ステータス", - "xpack.ingestManager.agentDetails.subTabs.activityLogTab": "アクティビティログ", - "xpack.ingestManager.agentDetails.subTabs.detailsTab": "エージェントの詳細", - "xpack.ingestManager.agentDetails.unexceptedErrorTitle": "エージェントの読み込み中にエラーが発生しました", - "xpack.ingestManager.agentDetails.upgradeAvailableTooltip": "アップグレードが利用可能です", - "xpack.ingestManager.agentDetails.userProvidedMetadataSectionSubtitle": "ユーザー提供メタデータ", - "xpack.ingestManager.agentDetails.versionLabel": "エージェントバージョン", - "xpack.ingestManager.agentDetails.viewAgentListTitle": "すべてのエージェントを表示", - "xpack.ingestManager.agentEnrollment.agentDescription": "Elasticエージェントをホストに追加し、データを収集して、Elastic Stackに送信します。", - "xpack.ingestManager.agentEnrollment.agentsNotInitializedText": "エージェントを登録する前に、{link}。", - "xpack.ingestManager.agentEnrollment.cancelButtonLabel": "キャンセル", - "xpack.ingestManager.agentEnrollment.continueButtonLabel": "続行", - "xpack.ingestManager.agentEnrollment.copyPolicyButton": "クリップボードにコピー", - "xpack.ingestManager.agentEnrollment.copyRunInstructionsButton": "クリップボードにコピー", - "xpack.ingestManager.agentEnrollment.downloadDescription": "Elasticエージェントダウンロードページでは、エージェントバイナリと検証署名をダウンロードできます。", - "xpack.ingestManager.agentEnrollment.downloadLink": "ダウンロードページに移動", - "xpack.ingestManager.agentEnrollment.downloadPolicyButton": "ダウンロードポリシー", - "xpack.ingestManager.agentEnrollment.enrollFleetTabLabel": "Fleetで登録", - "xpack.ingestManager.agentEnrollment.enrollStandaloneTabLabel": "スタンドアロンで実行", - "xpack.ingestManager.agentEnrollment.flyoutTitle": "エージェントの追加", - "xpack.ingestManager.agentEnrollment.goToDataStreamsLink": "データストリーム", - "xpack.ingestManager.agentEnrollment.managedDescription": "ElasticエージェントをFleetに登録して、自動的に更新をデプロイしたり、一元的にエージェントを管理したりします。", - "xpack.ingestManager.agentEnrollment.setUpAgentsLink": "Elasticエージェントの集中管理を設定", - "xpack.ingestManager.agentEnrollment.standaloneDescription": "Elasticエージェントをスタンドアロンで実行して、エージェントがインストールされているホストで、手動でエージェントを構成および更新します。", - "xpack.ingestManager.agentEnrollment.stepCheckForDataDescription": "エージェントがデータの送信を開始します。{link}に移動して、データを表示してください。", - "xpack.ingestManager.agentEnrollment.stepCheckForDataTitle": "データを確認", - "xpack.ingestManager.agentEnrollment.stepChooseAgentPolicyTitle": "エージェントポリシーを選択", - "xpack.ingestManager.agentEnrollment.stepConfigureAgentDescription": "Elasticエージェントがインストールされているホストで、このポリシーを{fileName}にコピーします。Elasticsearch資格情報を使用するには、{fileName}の{outputSection}セクションで、{ESUsernameVariable}と{ESPasswordVariable}を変更します。", - "xpack.ingestManager.agentEnrollment.stepConfigureAgentTitle": "エージェントの構成", - "xpack.ingestManager.agentEnrollment.stepDownloadAgentTitle": "Elasticエージェントをホストにダウンロード", - "xpack.ingestManager.agentEnrollment.stepEnrollAndRunAgentTitle": "Elasticエージェントを登録して実行", - "xpack.ingestManager.agentEnrollment.stepRunAgentDescription": "エージェントのディレクトリから、このコマンドを実行し、Elasticエージェントを、インストール、登録、起動します。このコマンドを再利用すると、複数のホストでエージェントを設定できます。管理者権限が必要です。", - "xpack.ingestManager.agentEnrollment.stepRunAgentTitle": "エージェントの起動", - "xpack.ingestManager.agentEventsList.collapseDetailsAriaLabel": "詳細を非表示", - "xpack.ingestManager.agentEventsList.expandDetailsAriaLabel": "詳細を表示", - "xpack.ingestManager.agentEventsList.messageColumnTitle": "メッセージ", - "xpack.ingestManager.agentEventsList.messageDetailsTitle": "メッセージ", - "xpack.ingestManager.agentEventsList.payloadDetailsTitle": "ペイロード", - "xpack.ingestManager.agentEventsList.refreshButton": "更新", - "xpack.ingestManager.agentEventsList.searchPlaceholderText": "アクティビティログを検索", - "xpack.ingestManager.agentEventsList.subtypeColumnTitle": "サブタイプ", - "xpack.ingestManager.agentEventsList.timestampColumnTitle": "タイムスタンプ", - "xpack.ingestManager.agentEventsList.typeColumnTitle": "タイプ", - "xpack.ingestManager.agentEventSubtype.acknowledgedLabel": "認識", - "xpack.ingestManager.agentEventSubtype.dataDumpLabel": "データダンプ", - "xpack.ingestManager.agentEventSubtype.degradedLabel": "劣化", - "xpack.ingestManager.agentEventSubtype.failedLabel": "失敗", - "xpack.ingestManager.agentEventSubtype.inProgressLabel": "進行中", - "xpack.ingestManager.agentEventSubtype.policyLabel": "ポリシー", - "xpack.ingestManager.agentEventSubtype.runningLabel": "実行中", - "xpack.ingestManager.agentEventSubtype.startingLabel": "開始中", - "xpack.ingestManager.agentEventSubtype.stoppedLabel": "停止", - "xpack.ingestManager.agentEventSubtype.stoppingLabel": "停止中", - "xpack.ingestManager.agentEventSubtype.unknownLabel": "不明", - "xpack.ingestManager.agentEventSubtype.updatingLabel": "更新中", - "xpack.ingestManager.agentEventType.actionLabel": "アクション", - "xpack.ingestManager.agentEventType.actionResultLabel": "アクション結果", - "xpack.ingestManager.agentEventType.errorLabel": "エラー", - "xpack.ingestManager.agentEventType.stateLabel": "ステータス", - "xpack.ingestManager.agentHealth.checkInTooltipText": "前回のチェックイン {lastCheckIn}", - "xpack.ingestManager.agentHealth.degradedStatusText": "劣化", - "xpack.ingestManager.agentHealth.enrollingStatusText": "登録中", - "xpack.ingestManager.agentHealth.errorStatusText": "エラー", - "xpack.ingestManager.agentHealth.inactiveStatusText": "非アクティブ", - "xpack.ingestManager.agentHealth.noCheckInTooltipText": "チェックインしない", - "xpack.ingestManager.agentHealth.offlineStatusText": "オフライン", - "xpack.ingestManager.agentHealth.onlineStatusText": "オンライン", - "xpack.ingestManager.agentHealth.unenrollingStatusText": "登録解除中", - "xpack.ingestManager.agentHealth.updatingStatusText": "更新中", - "xpack.ingestManager.agentHealth.warningStatusText": "エラー", - "xpack.ingestManager.agentList.actionsColumnTitle": "アクション", - "xpack.ingestManager.agentList.addButton": "エージェントの追加", - "xpack.ingestManager.agentList.agentUpgradeLabel": "アップグレードが利用可能です", - "xpack.ingestManager.agentList.clearFiltersLinkText": "フィルターを消去", - "xpack.ingestManager.agentList.enrollButton": "エージェントの追加", - "xpack.ingestManager.agentList.forceUnenrollOneButton": "強制的に登録解除する", - "xpack.ingestManager.agentList.hostColumnTitle": "ホスト", - "xpack.ingestManager.agentList.lastCheckinTitle": "前回のアクティビティ", - "xpack.ingestManager.agentList.loadingAgentsMessage": "エージェントを読み込み中...", - "xpack.ingestManager.agentList.noAgentsPrompt": "エージェントが登録されていません", - "xpack.ingestManager.agentList.noFilteredAgentsPrompt": "エージェントが見つかりません。{clearFiltersLink}", - "xpack.ingestManager.agentList.outOfDateLabel": "最新ではありません", - "xpack.ingestManager.agentList.policyColumnTitle": "エージェントポリシー", - "xpack.ingestManager.agentList.policyFilterText": "エージェントポリシー", - "xpack.ingestManager.agentList.reassignActionText": "新しいポリシーに割り当てる", - "xpack.ingestManager.agentList.revisionNumber": "rev. {revNumber}", - "xpack.ingestManager.agentList.showInactiveSwitchLabel": "非アクティブ", - "xpack.ingestManager.agentList.showUpgradeableFilterLabel": "アップグレードが利用可能です", - "xpack.ingestManager.agentList.statusColumnTitle": "ステータス", - "xpack.ingestManager.agentList.statusErrorFilterText": "エラー", - "xpack.ingestManager.agentList.statusFilterText": "ステータス", - "xpack.ingestManager.agentList.statusOfflineFilterText": "オフライン", - "xpack.ingestManager.agentList.statusOnlineFilterText": "オンライン", - "xpack.ingestManager.agentList.statusUpdatingFilterText": "更新中", - "xpack.ingestManager.agentList.unenrollOneButton": "エージェントの登録解除", - "xpack.ingestManager.agentList.upgradeOneButton": "エージェントをアップグレード", - "xpack.ingestManager.agentList.versionTitle": "バージョン", - "xpack.ingestManager.agentList.viewActionText": "エージェントを表示", - "xpack.ingestManager.agentListStatus.errorLabel": "エラー", - "xpack.ingestManager.agentListStatus.offlineLabel": "オフライン", - "xpack.ingestManager.agentListStatus.onlineLabel": "オンライン", - "xpack.ingestManager.agentListStatus.totalLabel": "エージェント", - "xpack.ingestManager.agentPolicy.confirmModalCalloutDescription": "選択されたエージェントポリシー{policyName}が一部のエージェントですでに使用されていることをFleetが検出しました。このアクションの結果として、Fleetはこのポリシーで使用されているすべてのエージェントに更新をデプロイします。", - "xpack.ingestManager.agentPolicy.confirmModalCancelButtonLabel": "キャンセル", - "xpack.ingestManager.agentPolicy.confirmModalConfirmButtonLabel": "変更を保存してデプロイ", - "xpack.ingestManager.agentPolicy.confirmModalDescription": "このアクションは元に戻せません。続行していいですか?", - "xpack.ingestManager.agentPolicy.confirmModalTitle": "変更を保存してデプロイ", - "xpack.ingestManager.agentPolicy.linkedAgentCountText": "{count, plural, one {#件のエージェント} other {#件のエージェント}}", - "xpack.ingestManager.agentPolicyActionMenu.buttonText": "アクション", - "xpack.ingestManager.agentPolicyActionMenu.copyPolicyActionText": "ポリシーをコピー", - "xpack.ingestManager.agentPolicyActionMenu.enrollAgentActionText": "エージェントの追加", - "xpack.ingestManager.agentPolicyActionMenu.viewPolicyText": "ポリシーを表示", - "xpack.ingestManager.agentPolicyForm.advancedOptionsToggleLabel": "高度なオプション", - "xpack.ingestManager.agentPolicyForm.descriptionFieldLabel": "説明", - "xpack.ingestManager.agentPolicyForm.descriptionFieldPlaceholder": "どのようにこのポリシーを使用しますか?", - "xpack.ingestManager.agentPolicyForm.monitoringDescription": "パフォーマンスのデバッグと追跡のために、エージェントに関するデータを収集します。", - "xpack.ingestManager.agentPolicyForm.monitoringLabel": "アラート監視", - "xpack.ingestManager.agentPolicyForm.monitoringLogsFieldLabel": "エージェントログを収集", - "xpack.ingestManager.agentPolicyForm.monitoringLogsTooltipText": "このポリシーを使用するElasticエージェントからログを収集します。", - "xpack.ingestManager.agentPolicyForm.monitoringMetricsFieldLabel": "エージェントメトリックを収集", - "xpack.ingestManager.agentPolicyForm.monitoringMetricsTooltipText": "このポリシーを使用するElasticエージェントからメトリックを収集します。", - "xpack.ingestManager.agentPolicyForm.nameFieldLabel": "名前", - "xpack.ingestManager.agentPolicyForm.nameFieldPlaceholder": "名前を選択", - "xpack.ingestManager.agentPolicyForm.nameRequiredErrorMessage": "エージェントポリシー名が必要です。", - "xpack.ingestManager.agentPolicyForm.namespaceFieldDescription": "このポリシーを使用する統合にデフォルトの名前空間を適用します。統合はその独自の名前空間を指定できます。", - "xpack.ingestManager.agentPolicyForm.namespaceFieldLabel": "デフォルト名前空間", - "xpack.ingestManager.agentPolicyForm.systemMonitoringFieldLabel": "システム監視", - "xpack.ingestManager.agentPolicyForm.systemMonitoringText": "システムメトリックを収集", - "xpack.ingestManager.agentPolicyForm.systemMonitoringTooltipText": "このオプションを有効にすると、システムメトリックと情報を収集する統合でポリシーをブートストラップできます。", - "xpack.ingestManager.agentPolicyList.actionsColumnTitle": "アクション", - "xpack.ingestManager.agentPolicyList.addButton": "エージェントポリシーを作成", - "xpack.ingestManager.agentPolicyList.agentsColumnTitle": "エージェント", - "xpack.ingestManager.agentPolicyList.clearFiltersLinkText": "フィルターを消去", - "xpack.ingestManager.agentPolicyList.descriptionColumnTitle": "説明", - "xpack.ingestManager.agentPolicyList.loadingAgentPoliciesMessage": "エージェントポリシーの読み込み中...", - "xpack.ingestManager.agentPolicyList.nameColumnTitle": "名前", - "xpack.ingestManager.agentPolicyList.noAgentPoliciesPrompt": "エージェントポリシーがありません", - "xpack.ingestManager.agentPolicyList.noFilteredAgentPoliciesPrompt": "エージェントポリシーが見つかりません。{clearFiltersLink}", - "xpack.ingestManager.agentPolicyList.packagePoliciesCountColumnTitle": "統合", - "xpack.ingestManager.agentPolicyList.pageSubtitle": "エージェントポリシーを使用すると、エージェントとエージェントが収集するデータを管理できます。", - "xpack.ingestManager.agentPolicyList.pageTitle": "エージェントポリシー", - "xpack.ingestManager.agentPolicyList.reloadAgentPoliciesButtonText": "再読み込み", - "xpack.ingestManager.agentPolicyList.revisionNumber": "rev. {revNumber}", - "xpack.ingestManager.agentPolicyList.updatedOnColumnTitle": "最終更新日", - "xpack.ingestManager.agentReassignPolicy.cancelButtonLabel": "キャンセル", - "xpack.ingestManager.agentReassignPolicy.continueButtonLabel": "ポリシーの割り当て", - "xpack.ingestManager.agentReassignPolicy.flyoutDescription": "選択した{count, plural, one {エージェント} other {エージェント}}を割り当てる新しいエージェントポリシーを選択します。", - "xpack.ingestManager.agentReassignPolicy.flyoutTitle": "新しいエージェントポリシーを割り当てる", - "xpack.ingestManager.agentReassignPolicy.policyDescription": "選択したエージェントポリシーは、{count, plural, one {{countValue}個の統合} other {{countValue}個の統合}}のデータを収集します。", - "xpack.ingestManager.agentReassignPolicy.selectPolicyLabel": "エージェントポリシー", - "xpack.ingestManager.agentReassignPolicy.successSingleNotificationTitle": "エージェントポリシーが再割り当てされました", - "xpack.ingestManager.agents.pageSubtitle": "ポリシーの更新を管理し、任意のサイズのエージェントのグループにデプロイします。", - "xpack.ingestManager.agents.pageTitle": "エージェント", - "xpack.ingestManager.alphaMessageDescription": "Ingest Managerは本番環境用ではありません。", - "xpack.ingestManager.alphaMessageLinkText": "詳細を参照してください。", - "xpack.ingestManager.alphaMessageTitle": "ベータリリース", - "xpack.ingestManager.alphaMessaging.docsLink": "ドキュメンテーション", - "xpack.ingestManager.alphaMessaging.feedbackText": "{docsLink}をご覧ください。質問やフィードバックについては、{forumLink}にアクセスしてください。", - "xpack.ingestManager.alphaMessaging.flyoutTitle": "このリリースについて", - "xpack.ingestManager.alphaMessaging.forumLink": "ディスカッションフォーラム", - "xpack.ingestManager.alphaMessaging.introText": "Ingest Managerは開発中であり、本番環境用ではありません。このベータリリースは、ユーザーがIngest Managerと新しいElasticエージェントをテストしてフィードバックを提供することを目的としています。このプラグインには、サポートSLAが適用されません。", - "xpack.ingestManager.alphaMessging.closeFlyoutLabel": "閉じる", - "xpack.ingestManager.appNavigation.agentsLinkText": "エージェント", - "xpack.ingestManager.appNavigation.dataStreamsLinkText": "データストリーム", - "xpack.ingestManager.appNavigation.epmLinkText": "統合", - "xpack.ingestManager.appNavigation.overviewLinkText": "概要", - "xpack.ingestManager.appNavigation.policiesLinkText": "ポリシー", - "xpack.ingestManager.appNavigation.sendFeedbackButton": "フィードバックを送信", - "xpack.ingestManager.appNavigation.settingsButton": "設定", - "xpack.ingestManager.appTitle": "Fleet", - "xpack.ingestManager.betaBadge.labelText": "ベータ", - "xpack.ingestManager.betaBadge.tooltipText": "このプラグインは本番環境用ではありません。バグについてはディスカッションフォーラムで報告してください。", - "xpack.ingestManager.breadcrumbs.addPackagePolicyPageTitle": "統合の追加", - "xpack.ingestManager.breadcrumbs.agentsPageTitle": "エージェント", - "xpack.ingestManager.breadcrumbs.allIntegrationsPageTitle": "すべて", - "xpack.ingestManager.breadcrumbs.appTitle": "Fleet", - "xpack.ingestManager.breadcrumbs.datastreamsPageTitle": "データストリーム", - "xpack.ingestManager.breadcrumbs.editPackagePolicyPageTitle": "統合の編集", - "xpack.ingestManager.breadcrumbs.enrollmentTokensPageTitle": "登録トークン", - "xpack.ingestManager.breadcrumbs.installedIntegrationsPageTitle": "インストール済み", - "xpack.ingestManager.breadcrumbs.integrationsPageTitle": "統合", - "xpack.ingestManager.breadcrumbs.overviewPageTitle": "概要", - "xpack.ingestManager.breadcrumbs.policiesPageTitle": "ポリシー", - "xpack.ingestManager.copyAgentPolicy.confirmModal.cancelButtonLabel": "キャンセル", - "xpack.ingestManager.copyAgentPolicy.confirmModal.confirmButtonLabel": "ポリシーをコピー", - "xpack.ingestManager.copyAgentPolicy.confirmModal.copyPolicyPrompt": "新しいエージェントポリシーの名前と説明を選択してください。", - "xpack.ingestManager.copyAgentPolicy.confirmModal.copyPolicyTitle": "「{name}」エージェントポリシーをコピー", - "xpack.ingestManager.copyAgentPolicy.confirmModal.defaultNewPolicyName": "{name}(コピー)", - "xpack.ingestManager.copyAgentPolicy.confirmModal.newDescriptionLabel": "説明", - "xpack.ingestManager.copyAgentPolicy.confirmModal.newNameLabel": "新しいポリシー名", - "xpack.ingestManager.copyAgentPolicy.failureNotificationTitle": "エージェントポリシー「{id}」のコピーエラー", - "xpack.ingestManager.copyAgentPolicy.fatalErrorNotificationTitle": "エージェントポリシーのコピーエラー", - "xpack.ingestManager.copyAgentPolicy.successNotificationTitle": "エージェントポリシーがコピーされました", - "xpack.ingestManager.createAgentPolicy.cancelButtonLabel": "キャンセル", - "xpack.ingestManager.createAgentPolicy.errorNotificationTitle": "エージェントポリシーを作成できません", - "xpack.ingestManager.createAgentPolicy.flyoutTitle": "エージェントポリシーを作成", - "xpack.ingestManager.createAgentPolicy.flyoutTitleDescription": "エージェントポリシーは、エージェントのグループ全体にわたる設定を管理する目的で使用されます。エージェントポリシーに統合を追加すると、エージェントで収集するデータを指定できます。エージェントポリシーの編集時には、フリートを使用して、指定したエージェントのグループに更新をデプロイできます。", - "xpack.ingestManager.createAgentPolicy.submitButtonLabel": "エージェントポリシーを作成", - "xpack.ingestManager.createAgentPolicy.successNotificationTitle": "エージェントポリシー「{name}」が作成されました", - "xpack.ingestManager.createPackagePolicy.addedNotificationMessage": "Fleetは'{agentPolicyName}'ポリシーで使用されているすべてのエージェントに更新をデプロイします。", - "xpack.ingestManager.createPackagePolicy.addedNotificationTitle": "「{packagePolicyName}」統合が追加されました。", - "xpack.ingestManager.createPackagePolicy.agentPolicyNameLabel": "エージェントポリシー", - "xpack.ingestManager.createPackagePolicy.cancelButton": "キャンセル", - "xpack.ingestManager.createPackagePolicy.cancelLinkText": "キャンセル", - "xpack.ingestManager.createPackagePolicy.errorOnSaveText": "統合ポリシーにはエラーがあります。保存前に修正してください。", - "xpack.ingestManager.createPackagePolicy.pageDescriptionfromPackage": "次の手順に従い、この統合をエージェントポリシーに追加します。", - "xpack.ingestManager.createPackagePolicy.pageDescriptionfromPolicy": "選択したエージェントポリシーの統合を構成します。", - "xpack.ingestManager.createPackagePolicy.pageTitle": "統合の追加", - "xpack.ingestManager.createPackagePolicy.pageTitleWithPackageName": "{packageName}統合の追加", - "xpack.ingestManager.createPackagePolicy.saveButton": "統合の保存", - "xpack.ingestManager.createPackagePolicy.stepConfigure.advancedOptionsToggleLinkText": "高度なオプション", - "xpack.ingestManager.createPackagePolicy.stepConfigure.errorCountText": "{count, plural, one {件のエラー} other {件のエラー}}", - "xpack.ingestManager.createPackagePolicy.stepConfigure.hideStreamsAriaLabel": "{type}入力を非表示", - "xpack.ingestManager.createPackagePolicy.stepConfigure.inputSettingsDescription": "次の設定は以下のすべての入力に適用されます。", - "xpack.ingestManager.createPackagePolicy.stepConfigure.inputSettingsTitle": "設定", - "xpack.ingestManager.createPackagePolicy.stepConfigure.inputVarFieldOptionalLabel": "オプション", - "xpack.ingestManager.createPackagePolicy.stepConfigure.integrationSettingsSectionDescription": "この統合の使用方法を識別できるように、名前と説明を選択してください。", - "xpack.ingestManager.createPackagePolicy.stepConfigure.integrationSettingsSectionTitle": "統合設定", - "xpack.ingestManager.createPackagePolicy.stepConfigure.noPolicyOptionsMessage": "構成するものがありません", - "xpack.ingestManager.createPackagePolicy.stepConfigure.packagePolicyDescriptionInputLabel": "説明", - "xpack.ingestManager.createPackagePolicy.stepConfigure.packagePolicyNameInputLabel": "統合名", - "xpack.ingestManager.createPackagePolicy.stepConfigure.packagePolicyNamespaceInputLabel": "名前空間", - "xpack.ingestManager.createPackagePolicy.stepConfigure.showStreamsAriaLabel": "{type}入力を表示", - "xpack.ingestManager.createPackagePolicy.stepConfigure.toggleAdvancedOptionsButtonText": "高度なオプション", - "xpack.ingestManager.createPackagePolicy.stepConfigurePackagePolicyTitle": "統合の構成", - "xpack.ingestManager.createPackagePolicy.stepSelectAgentPolicyTitle": "エージェントポリシーを選択", - "xpack.ingestManager.createPackagePolicy.stepSelectPackage.errorLoadingPackagesTitle": "統合の読み込みエラー", - "xpack.ingestManager.createPackagePolicy.stepSelectPackage.errorLoadingPolicyTitle": "エージェントポリシー情報の読み込みエラー", - "xpack.ingestManager.createPackagePolicy.stepSelectPackage.errorLoadingSelectedPackageTitle": "選択した統合の読み込みエラー", - "xpack.ingestManager.createPackagePolicy.stepSelectPackage.filterPackagesInputPlaceholder": "統合を検索", - "xpack.ingestManager.createPackagePolicy.stepSelectPackageTitle": "統合を選択", - "xpack.ingestManager.createPackagePolicy.StepSelectPolicy.addButton": "エージェントポリシーを作成", - "xpack.ingestManager.createPackagePolicy.StepSelectPolicy.agentPolicyAgentsCountText": "{count, plural, one {#個のエージェント} other {#個のエージェント}}が登録されました", - "xpack.ingestManager.createPackagePolicy.StepSelectPolicy.agentPolicyAgentsDescriptionText": "選択したエージェントポリシーで{count, plural, one {#個のエージェント} other {#個のエージェント}}が登録されました。", - "xpack.ingestManager.createPackagePolicy.StepSelectPolicy.agentPolicyLabel": "エージェントポリシー", - "xpack.ingestManager.createPackagePolicy.StepSelectPolicy.agentPolicyPlaceholderText": "この統合を追加するエージェントポリシーを選択", - "xpack.ingestManager.createPackagePolicy.StepSelectPolicy.errorLoadingAgentPoliciesTitle": "エージェントポリシーの読み込みエラー", - "xpack.ingestManager.createPackagePolicy.StepSelectPolicy.errorLoadingPackageTitle": "パッケージ情報の読み込みエラー", - "xpack.ingestManager.createPackagePolicy.StepSelectPolicy.errorLoadingSelectedAgentPolicyTitle": "選択したエージェントポリシーの読み込みエラー", - "xpack.ingestManager.dataStreamList.actionsColumnTitle": "アクション", - "xpack.ingestManager.dataStreamList.datasetColumnTitle": "データセット", - "xpack.ingestManager.dataStreamList.integrationColumnTitle": "統合", - "xpack.ingestManager.dataStreamList.lastActivityColumnTitle": "前回のアクティビティ", - "xpack.ingestManager.dataStreamList.loadingDataStreamsMessage": "データストリームを読み込んでいます...", - "xpack.ingestManager.dataStreamList.namespaceColumnTitle": "名前空間", - "xpack.ingestManager.dataStreamList.noDataStreamsPrompt": "データストリームがありません", - "xpack.ingestManager.dataStreamList.noFilteredDataStreamsMessage": "一致するデータストリームが見つかりません", - "xpack.ingestManager.dataStreamList.pageSubtitle": "エージェントが作成したデータを管理します。", - "xpack.ingestManager.dataStreamList.pageTitle": "データストリーム", - "xpack.ingestManager.dataStreamList.reloadDataStreamsButtonText": "再読み込み", - "xpack.ingestManager.dataStreamList.searchPlaceholderTitle": "データストリームをフィルター", - "xpack.ingestManager.dataStreamList.sizeColumnTitle": "サイズ", - "xpack.ingestManager.dataStreamList.typeColumnTitle": "タイプ", - "xpack.ingestManager.dataStreamList.viewDashboardActionText": "ダッシュボードを表示", - "xpack.ingestManager.dataStreamList.viewDashboardsActionText": "ダッシュボードを表示", - "xpack.ingestManager.dataStreamList.viewDashboardsPanelTitle": "ダッシュボードを表示", - "xpack.ingestManager.defaultSearchPlaceholderText": "検索", - "xpack.ingestManager.deleteAgentPolicy.confirmModal.affectedAgentsMessage": "{agentsCount, plural, one {#個のエージェントは} other {#個のエージェントは}}このエージェントポリシーに割り当てられました。このポリシーを削除する前に、これらのエージェントの割り当てを解除します。", - "xpack.ingestManager.deleteAgentPolicy.confirmModal.affectedAgentsTitle": "使用中のポリシー", - "xpack.ingestManager.deleteAgentPolicy.confirmModal.cancelButtonLabel": "キャンセル", - "xpack.ingestManager.deleteAgentPolicy.confirmModal.confirmButtonLabel": "ポリシーを削除", - "xpack.ingestManager.deleteAgentPolicy.confirmModal.deletePolicyTitle": "このエージェントポリシーを削除しますか?", - "xpack.ingestManager.deleteAgentPolicy.confirmModal.irreversibleMessage": "この操作は元に戻すことができません。", - "xpack.ingestManager.deleteAgentPolicy.confirmModal.loadingAgentsCountMessage": "影響があるエージェントの数を確認中...", - "xpack.ingestManager.deleteAgentPolicy.confirmModal.loadingButtonLabel": "読み込み中...", - "xpack.ingestManager.deleteAgentPolicy.failureSingleNotificationTitle": "エージェントポリシー「{id}」の削除エラー", - "xpack.ingestManager.deleteAgentPolicy.fatalErrorNotificationTitle": "エージェントポリシーの削除エラー", - "xpack.ingestManager.deleteAgentPolicy.successSingleNotificationTitle": "エージェントポリシー「{id}」が削除されました", - "xpack.ingestManager.deletePackagePolicy.confirmModal.affectedAgentsMessage": "{agentPolicyName}が一部のエージェントですでに使用されていることをFleetが検出しました。", - "xpack.ingestManager.deletePackagePolicy.confirmModal.affectedAgentsTitle": "このアクションは {agentsCount} {agentsCount, plural, one {# エージェント} other {# エージェント}}に影響します", - "xpack.ingestManager.deletePackagePolicy.confirmModal.cancelButtonLabel": "キャンセル", - "xpack.ingestManager.deletePackagePolicy.confirmModal.deleteMultipleTitle": "{count, plural, one {個の統合} other {個の統合}}を削除しますか?", - "xpack.ingestManager.deletePackagePolicy.confirmModal.generalMessage": "このアクションは元に戻せません。続行していいですか?", - "xpack.ingestManager.deletePackagePolicy.confirmModal.loadingAgentsCountMessage": "影響があるエージェントを確認中...", - "xpack.ingestManager.deletePackagePolicy.confirmModal.loadingButtonLabel": "読み込み中...", - "xpack.ingestManager.deletePackagePolicy.failureMultipleNotificationTitle": "{count}個の統合の削除エラー", - "xpack.ingestManager.deletePackagePolicy.failureSingleNotificationTitle": "統合「{id}」の削除エラー", - "xpack.ingestManager.deletePackagePolicy.fatalErrorNotificationTitle": "統合の削除エラー", - "xpack.ingestManager.deletePackagePolicy.successMultipleNotificationTitle": "{count}個の統合を削除しました", - "xpack.ingestManager.deletePackagePolicy.successSingleNotificationTitle": "統合「{id}」を削除しました", - "xpack.ingestManager.disabledSecurityDescription": "Elastic Fleet を使用するには、Kibana と Elasticsearch でセキュリティを有効にする必要があります。", - "xpack.ingestManager.disabledSecurityTitle": "セキュリティが有効ではありません", - "xpack.ingestManager.editAgentPolicy.cancelButtonText": "キャンセル", - "xpack.ingestManager.editAgentPolicy.errorNotificationTitle": "エージェントポリシーを更新できません", - "xpack.ingestManager.editAgentPolicy.saveButtonText": "変更を保存", - "xpack.ingestManager.editAgentPolicy.savingButtonText": "保存中…", - "xpack.ingestManager.editAgentPolicy.successNotificationTitle": "正常に「{name}」設定を更新しました", - "xpack.ingestManager.editAgentPolicy.unsavedChangesText": "保存されていない変更があります", - "xpack.ingestManager.editPackagePolicy.cancelButton": "キャンセル", - "xpack.ingestManager.editPackagePolicy.errorLoadingDataMessage": "この統合情報の読み込みエラーが発生しました", - "xpack.ingestManager.editPackagePolicy.errorLoadingDataTitle": "データの読み込み中にエラーが発生", - "xpack.ingestManager.editPackagePolicy.failedConflictNotificationMessage": "データが最新ではありません。最新のポリシーを取得するには、ページを更新してください。", - "xpack.ingestManager.editPackagePolicy.failedNotificationTitle": "「{packagePolicyName}」の更新エラー", - "xpack.ingestManager.editPackagePolicy.pageDescription": "統合設定を修正し、選択したエージェントポリシーに変更をデプロイします。", - "xpack.ingestManager.editPackagePolicy.pageTitle": "統合の編集", - "xpack.ingestManager.editPackagePolicy.pageTitleWithPackageName": "{packageName}統合の編集", - "xpack.ingestManager.editPackagePolicy.saveButton": "統合の保存", - "xpack.ingestManager.editPackagePolicy.updatedNotificationMessage": "Fleetは'{agentPolicyName}'ポリシーで使用されているすべてのエージェントに更新をデプロイします", - "xpack.ingestManager.editPackagePolicy.updatedNotificationTitle": "正常に「{packagePolicyName}」を更新しました", - "xpack.ingestManager.enrollemntAPIKeyList.emptyMessage": "登録トークンが見つかりません。", - "xpack.ingestManager.enrollemntAPIKeyList.loadingTokensMessage": "登録トークンを読み込んでいます...", - "xpack.ingestManager.enrollmentInstructions.descriptionText": "エージェントのディレクトリから、該当するコマンドを実行し、Elasticエージェントをインストール、登録、起動します。これらのコマンドを再利用すると、複数のホストでエージェントを設定できます。管理者権限が必要です。", - "xpack.ingestManager.enrollmentInstructions.linuxMacOSTitle": "Linux、MacOS", - "xpack.ingestManager.enrollmentInstructions.moreInstructionsLink": "Elasticエージェントドキュメント", - "xpack.ingestManager.enrollmentInstructions.moreInstructionsText": "手順とオプションの詳細については、{link}を参照してください。", - "xpack.ingestManager.enrollmentInstructions.windowsTitle": "Windows", - "xpack.ingestManager.enrollmentStepAgentPolicy.enrollmentTokenSelectLabel": "登録トークン", - "xpack.ingestManager.enrollmentStepAgentPolicy.policySelectAriaLabel": "エージェントポリシー", - "xpack.ingestManager.enrollmentStepAgentPolicy.policySelectLabel": "エージェントポリシー", - "xpack.ingestManager.enrollmentStepAgentPolicy.showAuthenticationSettingsButton": "認証設定", - "xpack.ingestManager.enrollmentTokenDeleteModal.cancelButton": "キャンセル", - "xpack.ingestManager.enrollmentTokenDeleteModal.deleteButton": "登録トークンを取り消し", - "xpack.ingestManager.enrollmentTokenDeleteModal.description": "{keyName}を取り消してよろしいですか?このトークンを使用するエージェントは、ポリシーにアクセスしたり、データを送信したりできなくなります。 ", - "xpack.ingestManager.enrollmentTokenDeleteModal.title": "登録トークンを取り消し", - "xpack.ingestManager.enrollmentTokensList.actionsTitle": "アクション", - "xpack.ingestManager.enrollmentTokensList.activeTitle": "アクティブ", - "xpack.ingestManager.enrollmentTokensList.createdAtTitle": "作成日時", - "xpack.ingestManager.enrollmentTokensList.hideTokenButtonLabel": "トークンを非表示", - "xpack.ingestManager.enrollmentTokensList.nameTitle": "名前", - "xpack.ingestManager.enrollmentTokensList.newKeyButton": "登録トークンを作成", - "xpack.ingestManager.enrollmentTokensList.pageDescription": "登録トークンを作成して取り消します。登録トークンを使用すると、1つ以上のエージェントをFleetに登録し、データを送信できます。", - "xpack.ingestManager.enrollmentTokensList.policyTitle": "エージェントポリシー", - "xpack.ingestManager.enrollmentTokensList.revokeTokenButtonLabel": "トークンを取り消す", - "xpack.ingestManager.enrollmentTokensList.secretTitle": "シークレット", - "xpack.ingestManager.enrollmentTokensList.showTokenButtonLabel": "トークンを表示", - "xpack.ingestManager.epm.addPackagePolicyButtonText": "{packageName}の追加", - "xpack.ingestManager.epm.assetGroupTitle": "{assetType}アセット", - "xpack.ingestManager.epm.browseAllButtonText": "すべての統合を参照", - "xpack.ingestManager.epm.illustrationAltText": "統合の例", - "xpack.ingestManager.epm.loadingIntegrationErrorTitle": "統合詳細の読み込みエラー", - "xpack.ingestManager.epm.packageDetailsNav.overviewLinkText": "概要", - "xpack.ingestManager.epm.packageDetailsNav.packagePoliciesLinkText": "使用", - "xpack.ingestManager.epm.packageDetailsNav.settingsLinkText": "設定", - "xpack.ingestManager.epm.pageSubtitle": "一般的なアプリやサービスの統合を参照する", - "xpack.ingestManager.epm.pageTitle": "統合", - "xpack.ingestManager.epm.releaseBadge.betaDescription": "この統合は本番環境用ではありません。", - "xpack.ingestManager.epm.releaseBadge.betaLabel": "ベータ", - "xpack.ingestManager.epm.releaseBadge.experimentalDescription": "この統合は、急に変更されたり、将来のリリースで削除されたりする可能性があります。", - "xpack.ingestManager.epm.releaseBadge.experimentalLabel": "実験的", - "xpack.ingestManager.epm.screenshotsTitle": "スクリーンショット", - "xpack.ingestManager.epm.updateAvailableTooltip": "更新が利用可能です", - "xpack.ingestManager.epm.versionLabel": "バージョン", - "xpack.ingestManager.epmList.allFilterLinkText": "すべて", - "xpack.ingestManager.epmList.allPackagesFilterLinkText": "すべて", - "xpack.ingestManager.epmList.allTabText": "すべての統合", - "xpack.ingestManager.epmList.allTitle": "カテゴリで参照", - "xpack.ingestManager.epmList.installedTabText": "インストールされている統合", - "xpack.ingestManager.epmList.installedTitle": "インストールされている統合", - "xpack.ingestManager.epmList.noPackagesFoundPlaceholder": "パッケージが見つかりません", - "xpack.ingestManager.epmList.searchPackagesPlaceholder": "統合を検索", - "xpack.ingestManager.epmList.updatesAvailableFilterLinkText": "更新が可能です", - "xpack.ingestManager.featureCatalogueDescription": "Elasticエージェントと統合のFleetを追加して管理します。", - "xpack.ingestManager.featureCatalogueTitle": "Elasticエージェントの追加", - "xpack.ingestManager.genericActionsMenuText": "開く", - "xpack.ingestManager.homeIntegration.tutorialDirectory.dismissNoticeButtonText": "メッセージを消去", - "xpack.ingestManager.homeIntegration.tutorialDirectory.noticeText": "Elasticエージェントでは、シンプルかつ統合された方法で、ログ、メトリック、他の種類のデータの監視をホストに追加することができます。複数のBeatsと他のエージェントをインストールする必要はありません。このため、インフラストラクチャ全体でのポリシーのデプロイが簡単で高速になりました。詳細については、{blogPostLink}をお読みください。", - "xpack.ingestManager.homeIntegration.tutorialDirectory.noticeText.blogPostLink": "発表ブログ投稿", - "xpack.ingestManager.homeIntegration.tutorialDirectory.noticeTitle": "{newPrefix} ElasticエージェントおよびIngest Managerベータ", - "xpack.ingestManager.homeIntegration.tutorialDirectory.noticeTitle.newPrefix": "新規:", - "xpack.ingestManager.homeIntegration.tutorialModule.noticeText": "{notePrefix}このモジュールの新しいバージョンは、Ingest Managerベータの{availableAsIntegrationLink}です。エージェントポリシーと新しいElasticエージェントの詳細については、{blogPostLink}をお読みください。", - "xpack.ingestManager.homeIntegration.tutorialModule.noticeText.blogPostLink": "発表ブログ投稿", - "xpack.ingestManager.homeIntegration.tutorialModule.noticeText.integrationLink": "統合として利用可能", - "xpack.ingestManager.homeIntegration.tutorialModule.noticeText.notePrefix": "注:", - "xpack.ingestManager.initializationErrorMessageTitle": "Ingest Manager を初期化できません", - "xpack.ingestManager.integrations.installPackage.installingPackageButtonLabel": "{title}アセットをインストールしています", - "xpack.ingestManager.integrations.installPackage.installPackageButtonLabel": "{title}アセットをインストール", - "xpack.ingestManager.integrations.packageInstallErrorDescription": "このパッケージのインストール中に問題が発生しました。しばらくたってから再試行してください。", - "xpack.ingestManager.integrations.packageInstallErrorTitle": "{title}パッケージをインストールできませんでした", - "xpack.ingestManager.integrations.packageInstallSuccessDescription": "正常に{title}をインストールしました", - "xpack.ingestManager.integrations.packageInstallSuccessTitle": "{title}をインストールしました", - "xpack.ingestManager.integrations.packageUninstallErrorDescription": "このパッケージのアンインストール中に問題が発生しました。しばらくたってから再試行してください。", - "xpack.ingestManager.integrations.packageUninstallErrorTitle": "{title}パッケージをアンインストールできませんでした", - "xpack.ingestManager.integrations.packageUninstallSuccessDescription": "正常に{title}をアンインストールしました", - "xpack.ingestManager.integrations.packageUninstallSuccessTitle": "{title}をアンインストールしました", - "xpack.ingestManager.integrations.settings.confirmInstallModal.cancelButtonLabel": "キャンセル", - "xpack.ingestManager.integrations.settings.confirmInstallModal.installButtonLabel": "{packageName}をインストール", - "xpack.ingestManager.integrations.settings.confirmInstallModal.installCalloutTitle": "{numOfAssets}個のアセットがインストールされます", - "xpack.ingestManager.integrations.settings.confirmInstallModal.installDescription": "Kibanaアセットは現在のスペース(既定)にインストールされ、このスペースを表示する権限があるユーザーのみがアクセスできます。Elasticsearchアセットはグローバルでインストールされ、すべてのKibanaユーザーがアクセスできます。", - "xpack.ingestManager.integrations.settings.confirmInstallModal.installTitle": "{packageName}をインストール", - "xpack.ingestManager.integrations.settings.confirmUninstallModal.cancelButtonLabel": "キャンセル", - "xpack.ingestManager.integrations.settings.confirmUninstallModal.uninstallButtonLabel": "{packageName}をアンインストール", - "xpack.ingestManager.integrations.settings.confirmUninstallModal.uninstallCallout.description": "この統合によって作成されたKibanaおよびElasticsearchアセットは削除されます。エージェントポリシーとエージェントによって送信されたデータは影響を受けません。", - "xpack.ingestManager.integrations.settings.confirmUninstallModal.uninstallCallout.title": "{numOfAssets}個のアセットが削除されます", - "xpack.ingestManager.integrations.settings.confirmUninstallModal.uninstallDescription": "この操作は元に戻すことができません。続行していいですか?", - "xpack.ingestManager.integrations.settings.confirmUninstallModal.uninstallTitle": "{packageName}をアンインストール", - "xpack.ingestManager.integrations.settings.packageInstallDescription": "この統合をインストールして、{title}データ向けに設計されたKibanaおよびElasticsearchアセットをセットアップします。", - "xpack.ingestManager.integrations.settings.packageInstallTitle": "{title}をインストール", - "xpack.ingestManager.integrations.settings.packageSettingsTitle": "設定", - "xpack.ingestManager.integrations.settings.packageUninstallDescription": "この統合によってインストールされたKibanaおよびElasticsearchアセットを削除します。", - "xpack.ingestManager.integrations.settings.packageUninstallNoteDescription.packageUninstallNoteDetail": "{strongNote} {title}をアンインストールできません。この統合を使用しているアクティブなエージェントがあります。アンインストールするには、エージェントポリシーからすべての{title}統合を削除します。", - "xpack.ingestManager.integrations.settings.packageUninstallNoteDescription.packageUninstallNoteLabel": "注:", - "xpack.ingestManager.integrations.settings.packageUninstallNoteDescription.packageUninstallUninstallableNoteDetail": "{strongNote} {title}統合は既定でインストールされているため、削除できません。", - "xpack.ingestManager.integrations.settings.packageUninstallTitle": "{title}をアンインストール", - "xpack.ingestManager.integrations.settings.packageVersionTitle": "{title}バージョン", - "xpack.ingestManager.integrations.settings.versionInfo.installedVersion": "インストールされているバージョン", - "xpack.ingestManager.integrations.settings.versionInfo.latestVersion": "最新バージョン", - "xpack.ingestManager.integrations.settings.versionInfo.updatesAvailable": "更新が利用可能です", - "xpack.ingestManager.integrations.uninstallPackage.uninstallingPackageButtonLabel": "{title}をアンインストールしています", - "xpack.ingestManager.integrations.uninstallPackage.uninstallPackageButtonLabel": "{title}をアンインストール", - "xpack.ingestManager.integrations.updatePackage.updatePackageButtonLabel": "最新バージョンに更新", - "xpack.ingestManager.invalidLicenseDescription": "現在のライセンスは期限切れです。登録されたビートエージェントは引き続き動作しますが、Elastic Fleet インターフェースにアクセスするには有効なライセンスが必要です。", - "xpack.ingestManager.invalidLicenseTitle": "ライセンスの期限切れ", - "xpack.ingestManager.listTabs.agentTitle": "エージェント", - "xpack.ingestManager.listTabs.enrollmentTokensTitle": "登録トークン", - "xpack.ingestManager.metadataForm.addButton": "+ メタデータを追加", - "xpack.ingestManager.metadataForm.keyLabel": "キー", - "xpack.ingestManager.metadataForm.submitButtonText": "追加", - "xpack.ingestManager.metadataForm.valueLabel": "値", - "xpack.ingestManager.namespaceValidation.invalidCharactersErrorMessage": "名前空間に無効な文字が含まれています", - "xpack.ingestManager.namespaceValidation.lowercaseErrorMessage": "名前空間は小文字で指定する必要があります", - "xpack.ingestManager.namespaceValidation.requiredErrorMessage": "名前空間は必須です", - "xpack.ingestManager.namespaceValidation.tooLongErrorMessage": "名前空間は100バイト以下でなければなりません", - "xpack.ingestManager.newEnrollmentKey.cancelButtonLabel": "キャンセル", - "xpack.ingestManager.newEnrollmentKey.flyoutTitle": "登録トークンを作成", - "xpack.ingestManager.newEnrollmentKey.keyCreatedToasts": "登録トークンが作成されました。", - "xpack.ingestManager.newEnrollmentKey.nameLabel": "名前", - "xpack.ingestManager.newEnrollmentKey.policyLabel": "ポリシー", - "xpack.ingestManager.newEnrollmentKey.submitButton": "登録トークンを作成", - "xpack.ingestManager.noAccess.accessDeniedDescription": "Elastic Fleet にアクセスする権限がありません。Elastic Fleet を使用するには、このアプリケーションの読み取り権または全権を含むユーザーロールが必要です。", - "xpack.ingestManager.noAccess.accessDeniedTitle": "アクセスが拒否されました", - "xpack.ingestManager.overviewAgentActiveTitle": "アクティブ", - "xpack.ingestManager.overviewAgentErrorTitle": "エラー", - "xpack.ingestManager.overviewAgentOfflineTitle": "オフライン", - "xpack.ingestManager.overviewAgentTotalTitle": "合計エージェント数", - "xpack.ingestManager.overviewDatastreamNamespacesTitle": "名前空間", - "xpack.ingestManager.overviewDatastreamSizeTitle": "合計サイズ", - "xpack.ingestManager.overviewDatastreamTotalTitle": "データストリーム", - "xpack.ingestManager.overviewIntegrationsInstalledTitle": "インストール済み", - "xpack.ingestManager.overviewIntegrationsTotalTitle": "合計利用可能数", - "xpack.ingestManager.overviewIntegrationsUpdatesAvailableTitle": "更新が可能です", - "xpack.ingestManager.overviewPackagePolicyTitle": "使用済みの統合", - "xpack.ingestManager.overviewPageAgentsPanelTitle": "エージェント", - "xpack.ingestManager.overviewPageDataStreamsPanelAction": "データストリームを表示", - "xpack.ingestManager.overviewPageDataStreamsPanelTitle": "データストリーム", - "xpack.ingestManager.overviewPageDataStreamsPanelTooltip": "エージェントが収集するデータはさまざまなデータストリームに整理されます。", - "xpack.ingestManager.overviewPageEnrollAgentButton": "エージェントの追加", - "xpack.ingestManager.overviewPageFleetPanelAction": "エージェントを表示", - "xpack.ingestManager.overviewPageFleetPanelTooltip": "Fleetを使用して、中央の場所からエージェントを登録し、ポリシーを管理します。", - "xpack.ingestManager.overviewPageIntegrationsPanelAction": "統合を表示", - "xpack.ingestManager.overviewPageIntegrationsPanelTitle": "統合", - "xpack.ingestManager.overviewPageIntegrationsPanelTooltip": "Elastic Stackの統合を参照し、インストールします。統合をエージェントポリシーに追加し、データの送信を開始します。", - "xpack.ingestManager.overviewPagePoliciesPanelAction": "ポリシーを表示", - "xpack.ingestManager.overviewPagePoliciesPanelTitle": "エージェントポリシー", - "xpack.ingestManager.overviewPagePoliciesPanelTooltip": "エージェントポリシーを使用すると、エージェントが収集するデータを管理できます。", - "xpack.ingestManager.overviewPageSubtitle": "Elasticエージェントとポリシーを中央の場所で管理します。", - "xpack.ingestManager.overviewPageTitle": "Fleet", - "xpack.ingestManager.overviewPolicyTotalTitle": "合計利用可能数", - "xpack.ingestManager.packagePolicyValidation.invalidArrayErrorMessage": "無効なフォーマット", - "xpack.ingestManager.packagePolicyValidation.invalidYamlFormatErrorMessage": "YAML形式が無効です", - "xpack.ingestManager.packagePolicyValidation.nameRequiredErrorMessage": "名前が必要です", - "xpack.ingestManager.packagePolicyValidation.requiredErrorMessage": "{fieldName}が必要です", - "xpack.ingestManager.permissionDeniedErrorMessage": "Ingest Managerにアクセスする権限がありません。Ingest Managerには{roleName}権限が必要です。", - "xpack.ingestManager.permissionDeniedErrorTitle": "パーミッションが拒否されました", - "xpack.ingestManager.permissionsRequestErrorMessageDescription": "Ingest Managerアクセス権の確認中に問題が発生しました", - "xpack.ingestManager.permissionsRequestErrorMessageTitle": "アクセス権を確認できません", - "xpack.ingestManager.policyDetails.addPackagePolicyButtonText": "統合の追加", - "xpack.ingestManager.policyDetails.ErrorGettingFullAgentPolicy": "エージェントポリシーの読み込みエラー", - "xpack.ingestManager.policyDetails.packagePoliciesTable.actionsColumnTitle": "アクション", - "xpack.ingestManager.policyDetails.packagePoliciesTable.deleteActionTitle": "統合の削除", - "xpack.ingestManager.policyDetails.packagePoliciesTable.descriptionColumnTitle": "説明", - "xpack.ingestManager.policyDetails.packagePoliciesTable.editActionTitle": "統合の編集", - "xpack.ingestManager.policyDetails.packagePoliciesTable.nameColumnTitle": "名前", - "xpack.ingestManager.policyDetails.packagePoliciesTable.namespaceColumnTitle": "名前空間", - "xpack.ingestManager.policyDetails.packagePoliciesTable.packageNameColumnTitle": "統合", - "xpack.ingestManager.policyDetails.policyDetailsTitle": "ポリシー「{id}」", - "xpack.ingestManager.policyDetails.policyNotFoundErrorTitle": "ポリシー「{id}」が見つかりません", - "xpack.ingestManager.policyDetails.subTabs.packagePoliciesTabText": "統合", - "xpack.ingestManager.policyDetails.subTabs.settingsTabText": "設定", - "xpack.ingestManager.policyDetails.summary.integrations": "統合", - "xpack.ingestManager.policyDetails.summary.lastUpdated": "最終更新日", - "xpack.ingestManager.policyDetails.summary.revision": "リビジョン", - "xpack.ingestManager.policyDetails.summary.usedBy": "使用者", - "xpack.ingestManager.policyDetails.unexceptedErrorTitle": "エージェントポリシーの読み込み中にエラーが発生しました", - "xpack.ingestManager.policyDetails.viewAgentListTitle": "すべてのエージェントポリシーを表示", - "xpack.ingestManager.policyDetails.yamlDownloadButtonLabel": "ダウンロードポリシー", - "xpack.ingestManager.policyDetails.yamlFlyoutCloseButtonLabel": "閉じる", - "xpack.ingestManager.policyDetails.yamlflyoutTitleWithName": "「{name}」エージェントポリシー", - "xpack.ingestManager.policyDetails.yamlflyoutTitleWithoutName": "エージェントポリシー", - "xpack.ingestManager.policyDetailsPackagePolicies.createFirstButtonText": "統合の追加", - "xpack.ingestManager.policyDetailsPackagePolicies.createFirstMessage": "このポリシーにはまだ統合がありません。", - "xpack.ingestManager.policyDetailsPackagePolicies.createFirstTitle": "最初の統合を追加", - "xpack.ingestManager.policyForm.deletePolicyActionText": "ポリシーを削除", - "xpack.ingestManager.policyForm.deletePolicyGroupDescription": "既存のデータは削除されません。", - "xpack.ingestManager.policyForm.deletePolicyGroupTitle": "ポリシーを削除", - "xpack.ingestManager.policyForm.generalSettingsGroupDescription": "エージェントポリシーの名前と説明を選択してください。", - "xpack.ingestManager.policyForm.generalSettingsGroupTitle": "一般設定", - "xpack.ingestManager.policyForm.unableToDeleteDefaultPolicyText": "デフォルトポリシーは削除できません", - "xpack.ingestManager.securityRequiredErrorMessage": "Ingest Managerを使用するには、KibanaとElasticsearchでセキュリティを有効にする必要があります。", - "xpack.ingestManager.securityRequiredErrorTitle": "セキュリティが有効ではありません", - "xpack.ingestManager.settings.additionalYamlConfig": "Elasticsearch出力構成", - "xpack.ingestManager.settings.autoUpgradeDisabledLabel": "エージェントバイナリバージョンを手動で管理します。サブスクリプションが必要です。", - "xpack.ingestManager.settings.autoUpgradeEnabledLabel": "エージェントバイナリを自動的に更新し、最新マイナーバージョンを使用します。", - "xpack.ingestManager.settings.autoUpgradeFieldLabel": "Elasticエージェントバイナリバージョン", - "xpack.ingestManager.settings.cancelButtonLabel": "キャンセル", - "xpack.ingestManager.settings.elasticHostError": "無効なURL", - "xpack.ingestManager.settings.elasticsearchUrlLabel": "Elasticsearch URL", - "xpack.ingestManager.settings.flyoutTitle": "Ingest Manager設定", - "xpack.ingestManager.settings.globalOutputDescription": "データを送信する場所を指定します。これらの設定はすべてのElasticエージェントポリシーに適用されます。", - "xpack.ingestManager.settings.globalOutputTitle": "グローバル出力", - "xpack.ingestManager.settings.integrationUpgradeDisabledFieldLabel": "統合バージョンを手動で管理します。", - "xpack.ingestManager.settings.integrationUpgradeEnabledFieldLabel": "自動的に統合を最新バージョンに更新し、最新のアセットを取得します。新機能を使用するには、エージェントポリシーを更新しなければならない場合があります。", - "xpack.ingestManager.settings.integrationUpgradeFieldLabel": "統合バージョン", - "xpack.ingestManager.settings.invalidYamlFormatErrorMessage": "無効なYAML形式:{reason}", - "xpack.ingestManager.settings.kibanaUrlDifferentPathOrProtocolError": "各URLのプロトコルとパスは同じでなければなりません", - "xpack.ingestManager.settings.kibanaUrlEmptyError": "1つ以上のURLが必要です。", - "xpack.ingestManager.settings.kibanaUrlError": "無効なURL", - "xpack.ingestManager.settings.kibanaUrlLabel": "Kibana URL", - "xpack.ingestManager.settings.saveButtonLabel": "設定を保存", - "xpack.ingestManager.settings.success.message": "設定が保存されました", - "xpack.ingestManager.setupPage.apiKeyServiceLink": "APIキーサービス", - "xpack.ingestManager.setupPage.elasticsearchApiKeyFlagText": "{apiKeyLink}.{apiKeyFlag}を{true}に設定します。", - "xpack.ingestManager.setupPage.elasticsearchSecurityFlagText": "{esSecurityLink}.{securityFlag}を{true}に設定します。", - "xpack.ingestManager.setupPage.elasticsearchSecurityLink": "Elasticsearchセキュリティ", - "xpack.ingestManager.setupPage.enableCentralManagement": "ユーザーを作成し、集中管理を有効にする", - "xpack.ingestManager.setupPage.enableText": "集中管理には、APIキーを作成し、log-*とmetrics-*に書き込むことができるElasticユーザーが必要です。", - "xpack.ingestManager.setupPage.enableTitle": "ElasticElasticエージェントの集中管理を有効にする", - "xpack.ingestManager.setupPage.encryptionKeyFlagText": "{encryptionKeyLink}.{keyFlag}を32文字以上の英数字に設定します。", - "xpack.ingestManager.setupPage.gettingStartedLink": "はじめに", - "xpack.ingestManager.setupPage.gettingStartedText": "詳細については、{link}ガイドをお読みください。", - "xpack.ingestManager.setupPage.kibanaEncryptionLink": "Kibana暗号化鍵", - "xpack.ingestManager.setupPage.kibanaSecurityLink": "Kibanaセキュリティ", - "xpack.ingestManager.setupPage.missingRequirementsCalloutDescription": "Elasticエージェントの集中管理を使用するには、次のElasticsearchとKibanaセキュリティ機能を有効にする必要があります。", - "xpack.ingestManager.setupPage.missingRequirementsCalloutTitle": "不足しているセキュリティ要件", - "xpack.ingestManager.setupPage.missingRequirementsElasticsearchTitle": "Elasticsearchポリシーでは、次のことができます。", - "xpack.ingestManager.setupPage.missingRequirementsKibanaTitle": "Kibanaポリシーでは、次のことができます。", - "xpack.ingestManager.setupPage.tlsFlagText": "{kibanaSecurityLink}.{securityFlag}を{true}に設定します。開発目的では、危険な代替として{tlsFlag}を{true}に設定して、{tlsLink}を無効化できます。", - "xpack.ingestManager.setupPage.tlsLink": "TLS", - "xpack.ingestManager.unenrollAgents.cancelButtonLabel": "キャンセル", - "xpack.ingestManager.unenrollAgents.confirmMultipleButtonLabel": "{count}個のエージェントを登録解除", - "xpack.ingestManager.unenrollAgents.confirmSingleButtonLabel": "エージェントの登録解除", - "xpack.ingestManager.unenrollAgents.deleteMultipleDescription": "このアクションにより、複数のエージェントがFleetから削除され、新しいデータを取り込めなくなります。これらのエージェントによってすでに送信されたデータは一切影響を受けません。この操作は元に戻すことができません。", - "xpack.ingestManager.unenrollAgents.deleteSingleDescription": "このアクションにより、「{hostName}」で実行中の選択したエージェントがFleetから削除されます。エージェントによってすでに送信されたデータは一切削除されません。この操作は元に戻すことができません。", - "xpack.ingestManager.unenrollAgents.deleteSingleTitle": "エージェントの登録解除", - "xpack.ingestManager.unenrollAgents.fatalErrorNotificationTitle": "{count, plural, one {エージェント} other {エージェント}}の登録解除エラー", - "xpack.ingestManager.unenrollAgents.forceDeleteMultipleTitle": "{count}個のエージェントを登録解除", - "xpack.ingestManager.unenrollAgents.forceUnenrollCheckboxLabel": "{count, plural, one {エージェント} other {エージェント}}がただちに削除されました。エージェントが最後のデータを送信するまで待機しない。", - "xpack.ingestManager.unenrollAgents.forceUnenrollLegendText": "{count, plural, one {エージェント} other {エージェント}}を強制的に登録解除", - "xpack.ingestManager.unenrollAgents.successForceMultiNotificationTitle": "エージェントが登録解除されました", - "xpack.ingestManager.unenrollAgents.successForceSingleNotificationTitle": "エージェントが登録解除されました", - "xpack.ingestManager.unenrollAgents.successMultiNotificationTitle": "エージェントを登録解除しています", - "xpack.ingestManager.unenrollAgents.successSingleNotificationTitle": "エージェントを登録解除しています", - "xpack.ingestManager.upgradeAgents.cancelButtonLabel": "キャンセル", - "xpack.ingestManager.upgradeAgents.confirmMultipleButtonLabel": "{count}個のエージェントをアップグレード", - "xpack.ingestManager.upgradeAgents.confirmSingleButtonLabel": "エージェントをアップグレード", - "xpack.ingestManager.upgradeAgents.deleteMultipleTitle": "{count}個のエージェントをアップグレード", - "xpack.ingestManager.upgradeAgents.deleteSingleTitle": "エージェントをアップグレード", - "xpack.ingestManager.upgradeAgents.fatalErrorNotificationTitle": "{count, plural, one {エージェント} other {エージェント}}のアップグレードエラー", - "xpack.ingestManager.upgradeAgents.successMultiNotificationTitle": "エージェントをアップグレード中...", - "xpack.ingestManager.upgradeAgents.successSingleNotificationTitle": "エージェントをアップグレード中", - "xpack.ingestManager.upgradeAgents.upgradeMultipleDescription": "このアクションにより、複数のエージェントがバージョン{version}にアップグレードされます。この操作は元に戻すことができません。続行していいですか?", - "xpack.ingestManager.upgradeAgents.upgradeSingleDescription": "このアクションにより、「{hostName}」で実行中の選択したエージェントがバージョン{version}にアップグレードされます。この操作は元に戻すことができません。続行していいですか?", "xpack.ingestPipelines.addProcesorFormOnFailureFlyout.cancelButtonLabel": "キャンセル", "xpack.ingestPipelines.addProcessorFormOnFailureFlyout.addButtonLabel": "追加", "xpack.ingestPipelines.app.checkingPrivilegesDescription": "権限を確認中…", @@ -20257,7 +20256,6 @@ "xpack.triggersActionsUI.sections.actionsConnectorsList.unableToLoadActionTypesMessage": "アクションタイプを読み込めません", "xpack.triggersActionsUI.sections.addAction.webhookAction.error.requiredHeaderKeyText": "キーが必要です。", "xpack.triggersActionsUI.sections.addAction.webhookAction.error.requiredHeaderValueText": "値が必要です。", - "xpack.triggersActionsUI.sections.addAction.webhookAction.error.requiredHostText": "ユーザー名が必要です。", "xpack.triggersActionsUI.sections.addAction.webhookAction.error.requiredMethodText": "メソッドが必要です", "xpack.triggersActionsUI.sections.addAction.webhookAction.error.requiredPasswordText": "パスワードが必要です。", "xpack.triggersActionsUI.sections.addAlert.error.greaterThenThreshold0Text": "しきい値 1 はしきい値 0 よりも大きい値にしてください。", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 19ad6f68988dc..df4d7dde407f0 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -5049,7 +5049,6 @@ "xpack.apm.rum.filters.url.noResults": "没有可用结果", "xpack.apm.rum.jsErrors.errorMessage": "错误消息", "xpack.apm.rum.jsErrors.errorRate": "错误率", - "xpack.apm.rum.jsErrors.errorRateValue": "{errorRate}%", "xpack.apm.rum.jsErrors.impactedPageLoads": "受影响的页面加载", "xpack.apm.rum.jsErrors.totalErrors": "错误总数", "xpack.apm.rum.userExperienceMetrics": "用户体验指标", @@ -7225,6 +7224,580 @@ "xpack.fileUpload.jsonUploadAndParse.writingToIndex": "正在写入索引", "xpack.fileUpload.noIndexSuppliedErrorMessage": "未提供任何索引。", "xpack.fileUpload.patternReader.featuresOmitted": "不具有几何形状的一些特征已省略", + "xpack.fleet.agentBulkActions.agentsSelected": "已选择 {count, plural, one {# 个代理} other {# 个代理}}", + "xpack.fleet.agentBulkActions.clearSelection": "清除所选内容", + "xpack.fleet.agentBulkActions.reassignPolicy": "分配到新策略", + "xpack.fleet.agentBulkActions.selectAll": "选择所有页面上的所有内容", + "xpack.fleet.agentBulkActions.totalAgents": "正在显示 {count, plural, one {# 个代理} other {# 个代理}}", + "xpack.fleet.agentBulkActions.totalAgentsWithLimit": "正在显示 {count} 个代理(共 {total} 个)", + "xpack.fleet.agentBulkActions.unenrollAgents": "取消注册代理", + "xpack.fleet.agentBulkActions.upgradeAgents": "升级代理", + "xpack.fleet.agentDetails.actionsButton": "操作", + "xpack.fleet.agentDetails.agentDetailsTitle": "代理“{id}”", + "xpack.fleet.agentDetails.agentNotFoundErrorDescription": "找不到代理 ID {agentId}", + "xpack.fleet.agentDetails.agentNotFoundErrorTitle": "未找到代理", + "xpack.fleet.agentDetails.agentPolicyLabel": "代理策略", + "xpack.fleet.agentDetails.agentVersionLabel": "代理版本", + "xpack.fleet.agentDetails.hostIdLabel": "代理 ID", + "xpack.fleet.agentDetails.hostNameLabel": "主机名", + "xpack.fleet.agentDetails.localMetadataSectionSubtitle": "本地元数据", + "xpack.fleet.agentDetails.metadataSectionTitle": "元数据", + "xpack.fleet.agentDetails.platformLabel": "平台", + "xpack.fleet.agentDetails.policyLabel": "策略", + "xpack.fleet.agentDetails.releaseLabel": "代理发行版", + "xpack.fleet.agentDetails.statusLabel": "状态", + "xpack.fleet.agentDetails.subTabs.activityLogTab": "活动日志", + "xpack.fleet.agentDetails.subTabs.detailsTab": "代理详情", + "xpack.fleet.agentDetails.unexceptedErrorTitle": "加载代理时出错", + "xpack.fleet.agentDetails.upgradeAvailableTooltip": "升级可用", + "xpack.fleet.agentDetails.userProvidedMetadataSectionSubtitle": "用户提供的元数据", + "xpack.fleet.agentDetails.versionLabel": "代理版本", + "xpack.fleet.agentDetails.viewAgentListTitle": "查看所有代理", + "xpack.fleet.agentEnrollment.agentDescription": "将 Elastic 代理添加到您的主机,以收集数据并将其发送到 Elastic Stack。", + "xpack.fleet.agentEnrollment.agentsNotInitializedText": "注册代理前,请{link}。", + "xpack.fleet.agentEnrollment.cancelButtonLabel": "取消", + "xpack.fleet.agentEnrollment.continueButtonLabel": "继续", + "xpack.fleet.agentEnrollment.copyPolicyButton": "复制到剪贴板", + "xpack.fleet.agentEnrollment.copyRunInstructionsButton": "复制到剪贴板", + "xpack.fleet.agentEnrollment.downloadDescription": "可从 Elastic 代理下载页面下载代理二进制文件及其验证签名。", + "xpack.fleet.agentEnrollment.downloadLink": "前往下载页面", + "xpack.fleet.agentEnrollment.downloadPolicyButton": "下载策略", + "xpack.fleet.agentEnrollment.enrollFleetTabLabel": "在 Fleet 中注册", + "xpack.fleet.agentEnrollment.enrollStandaloneTabLabel": "独立运行", + "xpack.fleet.agentEnrollment.flyoutTitle": "添加代理", + "xpack.fleet.agentEnrollment.goToDataStreamsLink": "数据流", + "xpack.fleet.agentEnrollment.managedDescription": "在 Fleet 中注册 Elastic 代理,以便自动部署更新并集中管理该代理。", + "xpack.fleet.agentEnrollment.setUpAgentsLink": "为 Elastic 代理设置集中管理", + "xpack.fleet.agentEnrollment.standaloneDescription": "独立运行 Elastic 代理,以在安装代理的主机上手动配置和更新代理。", + "xpack.fleet.agentEnrollment.stepCheckForDataDescription": "该代理应该开始发送数据。前往 {link} 以查看您的数据。", + "xpack.fleet.agentEnrollment.stepCheckForDataTitle": "检查数据", + "xpack.fleet.agentEnrollment.stepChooseAgentPolicyTitle": "选择代理策略", + "xpack.fleet.agentEnrollment.stepConfigureAgentDescription": "在安装 Elastic 代理的主机上将此策略复制到 {fileName}。在 {fileName} 的 {outputSection} 部分中修改 {ESUsernameVariable} 和 {ESPasswordVariable},以使用您的 Elasticsearch 凭据。", + "xpack.fleet.agentEnrollment.stepConfigureAgentTitle": "配置代理", + "xpack.fleet.agentEnrollment.stepDownloadAgentTitle": "将 Elastic 代理下载到您的主机", + "xpack.fleet.agentEnrollment.stepEnrollAndRunAgentTitle": "注册并启动 Elastic 代理", + "xpack.fleet.agentEnrollment.stepRunAgentDescription": "从代理目录运行此命令,以安装、注册并启动 Elastic 代理。您可以重复使用此命令在多个主机上设置代理。需要管理员权限。", + "xpack.fleet.agentEnrollment.stepRunAgentTitle": "启动代理", + "xpack.fleet.agentEventsList.collapseDetailsAriaLabel": "隐藏详情", + "xpack.fleet.agentEventsList.expandDetailsAriaLabel": "显示详情", + "xpack.fleet.agentEventsList.messageColumnTitle": "消息", + "xpack.fleet.agentEventsList.messageDetailsTitle": "消息", + "xpack.fleet.agentEventsList.payloadDetailsTitle": "负载", + "xpack.fleet.agentEventsList.refreshButton": "刷新", + "xpack.fleet.agentEventsList.searchPlaceholderText": "搜索活动日志", + "xpack.fleet.agentEventsList.subtypeColumnTitle": "子类型", + "xpack.fleet.agentEventsList.timestampColumnTitle": "时间戳", + "xpack.fleet.agentEventsList.typeColumnTitle": "类型", + "xpack.fleet.agentEventSubtype.acknowledgedLabel": "已确认", + "xpack.fleet.agentEventSubtype.dataDumpLabel": "数据转储", + "xpack.fleet.agentEventSubtype.degradedLabel": "已降级", + "xpack.fleet.agentEventSubtype.failedLabel": "失败", + "xpack.fleet.agentEventSubtype.inProgressLabel": "进行中", + "xpack.fleet.agentEventSubtype.policyLabel": "策略", + "xpack.fleet.agentEventSubtype.runningLabel": "正在运行", + "xpack.fleet.agentEventSubtype.startingLabel": "正在启动", + "xpack.fleet.agentEventSubtype.stoppedLabel": "已停止", + "xpack.fleet.agentEventSubtype.stoppingLabel": "正在停止", + "xpack.fleet.agentEventSubtype.unknownLabel": "未知", + "xpack.fleet.agentEventSubtype.updatingLabel": "正在更新", + "xpack.fleet.agentEventType.actionLabel": "操作", + "xpack.fleet.agentEventType.actionResultLabel": "操作结果", + "xpack.fleet.agentEventType.errorLabel": "错误", + "xpack.fleet.agentEventType.stateLabel": "状态", + "xpack.fleet.agentHealth.checkInTooltipText": "上次签入时间 {lastCheckIn}", + "xpack.fleet.agentHealth.degradedStatusText": "已降级", + "xpack.fleet.agentHealth.enrollingStatusText": "正在注册", + "xpack.fleet.agentHealth.errorStatusText": "错误", + "xpack.fleet.agentHealth.inactiveStatusText": "非活动", + "xpack.fleet.agentHealth.noCheckInTooltipText": "未签入", + "xpack.fleet.agentHealth.offlineStatusText": "脱机", + "xpack.fleet.agentHealth.onlineStatusText": "联机", + "xpack.fleet.agentHealth.unenrollingStatusText": "正在取消注册", + "xpack.fleet.agentHealth.updatingStatusText": "正在更新", + "xpack.fleet.agentHealth.warningStatusText": "错误", + "xpack.fleet.agentList.actionsColumnTitle": "操作", + "xpack.fleet.agentList.addButton": "添加代理", + "xpack.fleet.agentList.agentUpgradeLabel": "升级可用", + "xpack.fleet.agentList.clearFiltersLinkText": "清除筛选", + "xpack.fleet.agentList.enrollButton": "添加代理", + "xpack.fleet.agentList.forceUnenrollOneButton": "强制取消注册", + "xpack.fleet.agentList.hostColumnTitle": "主机", + "xpack.fleet.agentList.lastCheckinTitle": "上次活动", + "xpack.fleet.agentList.loadingAgentsMessage": "正在加载代理……", + "xpack.fleet.agentList.noAgentsPrompt": "未注册任何代理", + "xpack.fleet.agentList.noFilteredAgentsPrompt": "未找到任何代理。{clearFiltersLink}", + "xpack.fleet.agentList.outOfDateLabel": "过时", + "xpack.fleet.agentList.policyColumnTitle": "代理策略", + "xpack.fleet.agentList.policyFilterText": "代理策略", + "xpack.fleet.agentList.reassignActionText": "分配到新策略", + "xpack.fleet.agentList.revisionNumber": "修订 {revNumber}", + "xpack.fleet.agentList.showInactiveSwitchLabel": "非活动", + "xpack.fleet.agentList.showUpgradeableFilterLabel": "升级可用", + "xpack.fleet.agentList.statusColumnTitle": "状态", + "xpack.fleet.agentList.statusErrorFilterText": "错误", + "xpack.fleet.agentList.statusFilterText": "状态", + "xpack.fleet.agentList.statusOfflineFilterText": "脱机", + "xpack.fleet.agentList.statusOnlineFilterText": "联机", + "xpack.fleet.agentList.statusUpdatingFilterText": "正在更新", + "xpack.fleet.agentList.unenrollOneButton": "取消注册代理", + "xpack.fleet.agentList.upgradeOneButton": "升级代理", + "xpack.fleet.agentList.versionTitle": "版本", + "xpack.fleet.agentList.viewActionText": "查看代理", + "xpack.fleet.agentListStatus.errorLabel": "错误", + "xpack.fleet.agentListStatus.offlineLabel": "脱机", + "xpack.fleet.agentListStatus.onlineLabel": "联机", + "xpack.fleet.agentListStatus.totalLabel": "代理", + "xpack.fleet.agentPolicy.confirmModalCalloutDescription": "Fleet 检测到您的部分代理已在使用选定代理策略 {policyName}。由于此操作,Fleet 会将更新部署到使用此策略的所有代理。", + "xpack.fleet.agentPolicy.confirmModalCalloutTitle": "此操作将更新 {agentCount, plural, one {# 个代理} other {# 个代理}}", + "xpack.fleet.agentPolicy.confirmModalCancelButtonLabel": "取消", + "xpack.fleet.agentPolicy.confirmModalConfirmButtonLabel": "保存并部署更改", + "xpack.fleet.agentPolicy.confirmModalDescription": "此操作无法撤消。是否确定要继续?", + "xpack.fleet.agentPolicy.confirmModalTitle": "保存并部署更改", + "xpack.fleet.agentPolicy.linkedAgentCountText": "{count, plural, one {# 个代理} other {# 个代理}}", + "xpack.fleet.agentPolicyActionMenu.buttonText": "操作", + "xpack.fleet.agentPolicyActionMenu.copyPolicyActionText": "复制策略", + "xpack.fleet.agentPolicyActionMenu.enrollAgentActionText": "添加代理", + "xpack.fleet.agentPolicyActionMenu.viewPolicyText": "查看策略", + "xpack.fleet.agentPolicyForm.advancedOptionsToggleLabel": "高级选项", + "xpack.fleet.agentPolicyForm.descriptionFieldLabel": "描述", + "xpack.fleet.agentPolicyForm.descriptionFieldPlaceholder": "此策略将如何使用?", + "xpack.fleet.agentPolicyForm.monitoringDescription": "收集有关代理的数据,用于调试和跟踪性能。", + "xpack.fleet.agentPolicyForm.monitoringLabel": "代理监测", + "xpack.fleet.agentPolicyForm.monitoringLogsFieldLabel": "收集代理日志", + "xpack.fleet.agentPolicyForm.monitoringLogsTooltipText": "从使用此策略的 Elastic 代理收集日志。", + "xpack.fleet.agentPolicyForm.monitoringMetricsFieldLabel": "收集代理指标", + "xpack.fleet.agentPolicyForm.monitoringMetricsTooltipText": "从使用此策略的 Elastic 代理收集指标。", + "xpack.fleet.agentPolicyForm.nameFieldLabel": "名称", + "xpack.fleet.agentPolicyForm.nameFieldPlaceholder": "选择名称", + "xpack.fleet.agentPolicyForm.nameRequiredErrorMessage": "“代理策略名称”必填。", + "xpack.fleet.agentPolicyForm.namespaceFieldDescription": "将默认命名空间应用于使用此策略的集成。集成可以指定自己的命名空间。", + "xpack.fleet.agentPolicyForm.namespaceFieldLabel": "默认命名空间", + "xpack.fleet.agentPolicyForm.systemMonitoringFieldLabel": "系统监测", + "xpack.fleet.agentPolicyForm.systemMonitoringText": "收集系统指标", + "xpack.fleet.agentPolicyForm.systemMonitoringTooltipText": "启用此选项可使用收集系统指标和信息的集成启动您的策略。", + "xpack.fleet.agentPolicyList.actionsColumnTitle": "操作", + "xpack.fleet.agentPolicyList.addButton": "创建代理策略", + "xpack.fleet.agentPolicyList.agentsColumnTitle": "代理", + "xpack.fleet.agentPolicyList.clearFiltersLinkText": "清除筛选", + "xpack.fleet.agentPolicyList.descriptionColumnTitle": "描述", + "xpack.fleet.agentPolicyList.loadingAgentPoliciesMessage": "正在加载代理策略…...", + "xpack.fleet.agentPolicyList.nameColumnTitle": "名称", + "xpack.fleet.agentPolicyList.noAgentPoliciesPrompt": "无代理策略", + "xpack.fleet.agentPolicyList.noFilteredAgentPoliciesPrompt": "找不到任何代理策略。{clearFiltersLink}", + "xpack.fleet.agentPolicyList.packagePoliciesCountColumnTitle": "集成", + "xpack.fleet.agentPolicyList.pageSubtitle": "使用代理策略管理代理及其收集的数据。", + "xpack.fleet.agentPolicyList.pageTitle": "代理策略", + "xpack.fleet.agentPolicyList.reloadAgentPoliciesButtonText": "重新加载", + "xpack.fleet.agentPolicyList.revisionNumber": "修订版 {revNumber}", + "xpack.fleet.agentPolicyList.updatedOnColumnTitle": "上次更新时间", + "xpack.fleet.agentReassignPolicy.cancelButtonLabel": "取消", + "xpack.fleet.agentReassignPolicy.continueButtonLabel": "分配策略", + "xpack.fleet.agentReassignPolicy.flyoutDescription": "选择要将选定{count, plural, one {代理} other {代理}}分配到的新代理策略。", + "xpack.fleet.agentReassignPolicy.flyoutTitle": "分配新代理策略", + "xpack.fleet.agentReassignPolicy.policyDescription": "选定代理策略将收集 {count, plural, one {{countValue} 个集成} other {{countValue} 个集成}}的数据:", + "xpack.fleet.agentReassignPolicy.selectPolicyLabel": "代理策略", + "xpack.fleet.agentReassignPolicy.successSingleNotificationTitle": "代理策略已重新分配", + "xpack.fleet.agents.pageSubtitle": "管理策略更新并将其部署到一组任意大小的代理。", + "xpack.fleet.agents.pageTitle": "代理", + "xpack.fleet.alphaMessageDescription": "不推荐在生产环境中使用采集管理器。", + "xpack.fleet.alphaMessageLinkText": "查看更多详情。", + "xpack.fleet.alphaMessageTitle": "公测版", + "xpack.fleet.alphaMessaging.docsLink": "文档", + "xpack.fleet.alphaMessaging.feedbackText": "阅读我们的{docsLink}或前往我们的{forumLink},以了解问题或提供反馈。", + "xpack.fleet.alphaMessaging.flyoutTitle": "关于本版本", + "xpack.fleet.alphaMessaging.forumLink": "讨论论坛", + "xpack.fleet.alphaMessaging.introText": "采集管理器仍处于开发状态,不适用于生产环境。此公测版用于用户测试采集管理器和新 Elastic 代理并提供相关反馈。此插件不受支持 SLA 的约束。", + "xpack.fleet.alphaMessging.closeFlyoutLabel": "关闭", + "xpack.fleet.appNavigation.agentsLinkText": "代理", + "xpack.fleet.appNavigation.dataStreamsLinkText": "数据流", + "xpack.fleet.appNavigation.epmLinkText": "集成", + "xpack.fleet.appNavigation.overviewLinkText": "概览", + "xpack.fleet.appNavigation.policiesLinkText": "策略", + "xpack.fleet.appNavigation.sendFeedbackButton": "发送反馈", + "xpack.fleet.appNavigation.settingsButton": "设置", + "xpack.fleet.appTitle": "Fleet", + "xpack.fleet.betaBadge.labelText": "公测版", + "xpack.fleet.betaBadge.tooltipText": "不推荐在生产环境中使用此插件。请在我们讨论论坛中报告错误。", + "xpack.fleet.breadcrumbs.addPackagePolicyPageTitle": "添加集成", + "xpack.fleet.breadcrumbs.agentsPageTitle": "代理", + "xpack.fleet.breadcrumbs.allIntegrationsPageTitle": "全部", + "xpack.fleet.breadcrumbs.appTitle": "Fleet", + "xpack.fleet.breadcrumbs.datastreamsPageTitle": "数据流", + "xpack.fleet.breadcrumbs.editPackagePolicyPageTitle": "编辑集成", + "xpack.fleet.breadcrumbs.enrollmentTokensPageTitle": "注册令牌", + "xpack.fleet.breadcrumbs.installedIntegrationsPageTitle": "已安装", + "xpack.fleet.breadcrumbs.integrationsPageTitle": "集成", + "xpack.fleet.breadcrumbs.overviewPageTitle": "概览", + "xpack.fleet.breadcrumbs.policiesPageTitle": "策略", + "xpack.fleet.copyAgentPolicy.confirmModal.cancelButtonLabel": "取消", + "xpack.fleet.copyAgentPolicy.confirmModal.confirmButtonLabel": "复制策略", + "xpack.fleet.copyAgentPolicy.confirmModal.copyPolicyPrompt": "为您的新代理策略选择名称和描述。", + "xpack.fleet.copyAgentPolicy.confirmModal.copyPolicyTitle": "复制代理策略“{name}”", + "xpack.fleet.copyAgentPolicy.confirmModal.defaultNewPolicyName": "{name}(副本)", + "xpack.fleet.copyAgentPolicy.confirmModal.newDescriptionLabel": "描述", + "xpack.fleet.copyAgentPolicy.confirmModal.newNameLabel": "新策略名称", + "xpack.fleet.copyAgentPolicy.failureNotificationTitle": "复制代理策略“{id}”时出错", + "xpack.fleet.copyAgentPolicy.fatalErrorNotificationTitle": "复制代理策略时出错", + "xpack.fleet.copyAgentPolicy.successNotificationTitle": "代理策略已复制", + "xpack.fleet.createAgentPolicy.cancelButtonLabel": "取消", + "xpack.fleet.createAgentPolicy.errorNotificationTitle": "无法创建代理策略", + "xpack.fleet.createAgentPolicy.flyoutTitle": "创建代理策略", + "xpack.fleet.createAgentPolicy.flyoutTitleDescription": "代理策略用于管理一组代理的设置。您可以将集成添加到代理策略,以指定代理收集的数据。编辑代理策略时,可以使用 Fleet 将更新部署到一组指定代理。", + "xpack.fleet.createAgentPolicy.submitButtonLabel": "创建代理策略", + "xpack.fleet.createAgentPolicy.successNotificationTitle": "代理策略“{name}”已创建", + "xpack.fleet.createPackagePolicy.addedNotificationMessage": "Fleet 会将更新部署到所有使用策略“{agentPolicyName}”的代理。", + "xpack.fleet.createPackagePolicy.addedNotificationTitle": "“{packagePolicyName}”集成已添加。", + "xpack.fleet.createPackagePolicy.agentPolicyNameLabel": "代理策略", + "xpack.fleet.createPackagePolicy.cancelButton": "取消", + "xpack.fleet.createPackagePolicy.cancelLinkText": "取消", + "xpack.fleet.createPackagePolicy.errorOnSaveText": "您的集成策略有错误。请在保存前修复这些错误。", + "xpack.fleet.createPackagePolicy.pageDescriptionfromPackage": "按照以下说明将此集成添加到代理策略。", + "xpack.fleet.createPackagePolicy.pageDescriptionfromPolicy": "为选定代理策略配置集成。", + "xpack.fleet.createPackagePolicy.pageTitle": "添加集成", + "xpack.fleet.createPackagePolicy.pageTitleWithPackageName": "添加 {packageName} 集成", + "xpack.fleet.createPackagePolicy.saveButton": "保存集成", + "xpack.fleet.createPackagePolicy.stepConfigure.advancedOptionsToggleLinkText": "高级选项", + "xpack.fleet.createPackagePolicy.stepConfigure.errorCountText": "{count, plural, one {# 个错误} other {# 个错误}}", + "xpack.fleet.createPackagePolicy.stepConfigure.hideStreamsAriaLabel": "隐藏 {type} 输入", + "xpack.fleet.createPackagePolicy.stepConfigure.inputSettingsDescription": "以下设置适用于下面的所有输入。", + "xpack.fleet.createPackagePolicy.stepConfigure.inputSettingsTitle": "设置", + "xpack.fleet.createPackagePolicy.stepConfigure.inputVarFieldOptionalLabel": "可选", + "xpack.fleet.createPackagePolicy.stepConfigure.integrationSettingsSectionDescription": "选择有助于确定如何使用此集成的名称和描述。", + "xpack.fleet.createPackagePolicy.stepConfigure.integrationSettingsSectionTitle": "集成设置", + "xpack.fleet.createPackagePolicy.stepConfigure.noPolicyOptionsMessage": "没有可配置的内容", + "xpack.fleet.createPackagePolicy.stepConfigure.packagePolicyDescriptionInputLabel": "描述", + "xpack.fleet.createPackagePolicy.stepConfigure.packagePolicyNameInputLabel": "集成名称", + "xpack.fleet.createPackagePolicy.stepConfigure.packagePolicyNamespaceInputLabel": "命名空间", + "xpack.fleet.createPackagePolicy.stepConfigure.showStreamsAriaLabel": "显示 {type} 输入", + "xpack.fleet.createPackagePolicy.stepConfigure.toggleAdvancedOptionsButtonText": "高级选项", + "xpack.fleet.createPackagePolicy.stepConfigurePackagePolicyTitle": "配置集成", + "xpack.fleet.createPackagePolicy.stepSelectAgentPolicyTitle": "选择代理策略", + "xpack.fleet.createPackagePolicy.stepSelectPackage.errorLoadingPackagesTitle": "加载集成时出错", + "xpack.fleet.createPackagePolicy.stepSelectPackage.errorLoadingPolicyTitle": "加载代理策略信息时出错", + "xpack.fleet.createPackagePolicy.stepSelectPackage.errorLoadingSelectedPackageTitle": "加载选定集成时出错", + "xpack.fleet.createPackagePolicy.stepSelectPackage.filterPackagesInputPlaceholder": "搜索集成", + "xpack.fleet.createPackagePolicy.stepSelectPackageTitle": "选择集成", + "xpack.fleet.createPackagePolicy.StepSelectPolicy.addButton": "创建代理策略", + "xpack.fleet.createPackagePolicy.StepSelectPolicy.agentPolicyAgentsCountText": "{count, plural, one {# 个代理} other {# 个代理}}已注册", + "xpack.fleet.createPackagePolicy.StepSelectPolicy.agentPolicyAgentsDescriptionText": "{count, plural, one {# 个代理} other {# 个代理}}已注册到选定代理策略中。", + "xpack.fleet.createPackagePolicy.StepSelectPolicy.agentPolicyLabel": "代理策略", + "xpack.fleet.createPackagePolicy.StepSelectPolicy.agentPolicyPlaceholderText": "选择要将此集成添加到的代理策略", + "xpack.fleet.createPackagePolicy.StepSelectPolicy.errorLoadingAgentPoliciesTitle": "加载代理策略时出错", + "xpack.fleet.createPackagePolicy.StepSelectPolicy.errorLoadingPackageTitle": "加载软件包信息时出错", + "xpack.fleet.createPackagePolicy.StepSelectPolicy.errorLoadingSelectedAgentPolicyTitle": "加载选定代理策略时出错", + "xpack.fleet.dataStreamList.actionsColumnTitle": "操作", + "xpack.fleet.dataStreamList.datasetColumnTitle": "数据集", + "xpack.fleet.dataStreamList.integrationColumnTitle": "集成", + "xpack.fleet.dataStreamList.lastActivityColumnTitle": "上次活动", + "xpack.fleet.dataStreamList.loadingDataStreamsMessage": "正在加载数据流……", + "xpack.fleet.dataStreamList.namespaceColumnTitle": "命名空间", + "xpack.fleet.dataStreamList.noDataStreamsPrompt": "无数据流", + "xpack.fleet.dataStreamList.noFilteredDataStreamsMessage": "找不到匹配的数据流", + "xpack.fleet.dataStreamList.pageSubtitle": "管理您的代理创建的数据。", + "xpack.fleet.dataStreamList.pageTitle": "数据流", + "xpack.fleet.dataStreamList.reloadDataStreamsButtonText": "重新加载", + "xpack.fleet.dataStreamList.searchPlaceholderTitle": "筛选数据流", + "xpack.fleet.dataStreamList.sizeColumnTitle": "大小", + "xpack.fleet.dataStreamList.typeColumnTitle": "类型", + "xpack.fleet.dataStreamList.viewDashboardActionText": "查看仪表板", + "xpack.fleet.dataStreamList.viewDashboardsActionText": "查看仪表板", + "xpack.fleet.dataStreamList.viewDashboardsPanelTitle": "查看仪表板", + "xpack.fleet.defaultSearchPlaceholderText": "搜索", + "xpack.fleet.deleteAgentPolicy.confirmModal.affectedAgentsMessage": "{agentsCount, plural, one {# 个代理} other {# 个代理}}已分配到此代理策略。在删除此策略前取消分配这些代理。", + "xpack.fleet.deleteAgentPolicy.confirmModal.affectedAgentsTitle": "在用的策略", + "xpack.fleet.deleteAgentPolicy.confirmModal.cancelButtonLabel": "取消", + "xpack.fleet.deleteAgentPolicy.confirmModal.confirmButtonLabel": "删除策略", + "xpack.fleet.deleteAgentPolicy.confirmModal.deletePolicyTitle": "删除此代理策略?", + "xpack.fleet.deleteAgentPolicy.confirmModal.irreversibleMessage": "此操作无法撤消。", + "xpack.fleet.deleteAgentPolicy.confirmModal.loadingAgentsCountMessage": "正在检查受影响的代理数量……", + "xpack.fleet.deleteAgentPolicy.confirmModal.loadingButtonLabel": "正在加载……", + "xpack.fleet.deleteAgentPolicy.failureSingleNotificationTitle": "删除代理策略“{id}”时出错", + "xpack.fleet.deleteAgentPolicy.fatalErrorNotificationTitle": "删除代理策略时出错", + "xpack.fleet.deleteAgentPolicy.successSingleNotificationTitle": "已删除代理策略“{id}”", + "xpack.fleet.deletePackagePolicy.confirmModal.affectedAgentsMessage": "Fleet 检测到您的部分代理已在使用 {agentPolicyName}。", + "xpack.fleet.deletePackagePolicy.confirmModal.affectedAgentsTitle": "此操作将影响 {agentsCount} 个{agentsCount, plural, one {代理} other {代理}}。", + "xpack.fleet.deletePackagePolicy.confirmModal.cancelButtonLabel": "取消", + "xpack.fleet.deletePackagePolicy.confirmModal.confirmButtonLabel": "删除{agentPoliciesCount, plural, one {集成} other {集成}}", + "xpack.fleet.deletePackagePolicy.confirmModal.deleteMultipleTitle": "删除 {count, plural, one {集成} other {# 个集成}}?", + "xpack.fleet.deletePackagePolicy.confirmModal.generalMessage": "此操作无法撤消。是否确定要继续?", + "xpack.fleet.deletePackagePolicy.confirmModal.loadingAgentsCountMessage": "正在检查受影响的代理……", + "xpack.fleet.deletePackagePolicy.confirmModal.loadingButtonLabel": "正在加载……", + "xpack.fleet.deletePackagePolicy.failureMultipleNotificationTitle": "删除 {count} 个集成时出错", + "xpack.fleet.deletePackagePolicy.failureSingleNotificationTitle": "删除集成“{id}”时出错", + "xpack.fleet.deletePackagePolicy.fatalErrorNotificationTitle": "删除集成时出错", + "xpack.fleet.deletePackagePolicy.successMultipleNotificationTitle": "已删除 {count} 个集成", + "xpack.fleet.deletePackagePolicy.successSingleNotificationTitle": "已删除集成“{id}”", + "xpack.fleet.disabledSecurityDescription": "必须在 Kibana 和 Elasticsearch 启用安全性,才能使用 Elastic Fleet。", + "xpack.fleet.disabledSecurityTitle": "安全性未启用", + "xpack.fleet.editAgentPolicy.cancelButtonText": "取消", + "xpack.fleet.editAgentPolicy.errorNotificationTitle": "无法更新代理策略", + "xpack.fleet.editAgentPolicy.saveButtonText": "保存更改", + "xpack.fleet.editAgentPolicy.savingButtonText": "正在保存……", + "xpack.fleet.editAgentPolicy.successNotificationTitle": "已成功更新“{name}”设置", + "xpack.fleet.editAgentPolicy.unsavedChangesText": "您有未保存的更改", + "xpack.fleet.editPackagePolicy.cancelButton": "取消", + "xpack.fleet.editPackagePolicy.errorLoadingDataMessage": "加载此集成信息时出错", + "xpack.fleet.editPackagePolicy.errorLoadingDataTitle": "加载数据时出错", + "xpack.fleet.editPackagePolicy.failedConflictNotificationMessage": "数据已过时。刷新页面以获取最新策略。", + "xpack.fleet.editPackagePolicy.failedNotificationTitle": "更新“{packagePolicyName}”时出错", + "xpack.fleet.editPackagePolicy.pageDescription": "修改集成设置并将更改部署到选定代理策略。", + "xpack.fleet.editPackagePolicy.pageTitle": "编辑集成", + "xpack.fleet.editPackagePolicy.pageTitleWithPackageName": "编辑 {packageName} 集成", + "xpack.fleet.editPackagePolicy.saveButton": "保存集成", + "xpack.fleet.editPackagePolicy.updatedNotificationMessage": "Fleet 会将更新部署到所有使用策略“{agentPolicyName}”的代理", + "xpack.fleet.editPackagePolicy.updatedNotificationTitle": "已成功更新“{packagePolicyName}”", + "xpack.fleet.enrollemntAPIKeyList.emptyMessage": "未找到任何注册令牌。", + "xpack.fleet.enrollemntAPIKeyList.loadingTokensMessage": "正在加载注册令牌......", + "xpack.fleet.enrollmentInstructions.descriptionText": "从代理目录运行相应命令,以安装、注册并启动 Elastic 代理。您可以重复使用这些命令在多个主机上设置代理。需要管理员权限。", + "xpack.fleet.enrollmentInstructions.linuxMacOSTitle": "Linux、macOS", + "xpack.fleet.enrollmentInstructions.moreInstructionsLink": "Elastic 代理文档", + "xpack.fleet.enrollmentInstructions.moreInstructionsText": "有关更多说明和选项,请参见 {link}。", + "xpack.fleet.enrollmentInstructions.windowsTitle": "Windows", + "xpack.fleet.enrollmentStepAgentPolicy.enrollmentTokenSelectLabel": "注册令牌", + "xpack.fleet.enrollmentStepAgentPolicy.policySelectAriaLabel": "代理策略", + "xpack.fleet.enrollmentStepAgentPolicy.policySelectLabel": "代理策略", + "xpack.fleet.enrollmentStepAgentPolicy.showAuthenticationSettingsButton": "身份验证设置", + "xpack.fleet.enrollmentTokenDeleteModal.cancelButton": "取消", + "xpack.fleet.enrollmentTokenDeleteModal.deleteButton": "撤销注册令牌", + "xpack.fleet.enrollmentTokenDeleteModal.description": "确定要撤销 {keyName}?使用此令牌的代理将无法再访问策略或发送数据。 ", + "xpack.fleet.enrollmentTokenDeleteModal.title": "撤销注册令牌", + "xpack.fleet.enrollmentTokensList.actionsTitle": "操作", + "xpack.fleet.enrollmentTokensList.activeTitle": "活动", + "xpack.fleet.enrollmentTokensList.createdAtTitle": "创建日期", + "xpack.fleet.enrollmentTokensList.hideTokenButtonLabel": "隐藏令牌", + "xpack.fleet.enrollmentTokensList.nameTitle": "名称", + "xpack.fleet.enrollmentTokensList.newKeyButton": "创建注册令牌", + "xpack.fleet.enrollmentTokensList.pageDescription": "创建和撤销注册令牌。注册令牌允许一个或多个代理注册于 Fleet 中并发送数据。", + "xpack.fleet.enrollmentTokensList.policyTitle": "代理策略", + "xpack.fleet.enrollmentTokensList.revokeTokenButtonLabel": "撤销令牌", + "xpack.fleet.enrollmentTokensList.secretTitle": "密钥", + "xpack.fleet.enrollmentTokensList.showTokenButtonLabel": "显示令牌", + "xpack.fleet.epm.addPackagePolicyButtonText": "添加 {packageName}", + "xpack.fleet.epm.assetGroupTitle": "{assetType} 资产", + "xpack.fleet.epm.browseAllButtonText": "浏览所有集成", + "xpack.fleet.epm.illustrationAltText": "集成的图示", + "xpack.fleet.epm.loadingIntegrationErrorTitle": "加载集成详情时出错", + "xpack.fleet.epm.packageDetailsNav.overviewLinkText": "概览", + "xpack.fleet.epm.packageDetailsNav.packagePoliciesLinkText": "使用情况", + "xpack.fleet.epm.packageDetailsNav.settingsLinkText": "设置", + "xpack.fleet.epm.pageSubtitle": "浏览集成以了解热门应用和服务。", + "xpack.fleet.epm.pageTitle": "集成", + "xpack.fleet.epm.releaseBadge.betaDescription": "在生产环境中不推荐使用此集成。", + "xpack.fleet.epm.releaseBadge.betaLabel": "公测版", + "xpack.fleet.epm.releaseBadge.experimentalDescription": "此集成可能有重大更改或将在未来版本中移除。", + "xpack.fleet.epm.releaseBadge.experimentalLabel": "实验性", + "xpack.fleet.epm.screenshotsTitle": "屏幕截图", + "xpack.fleet.epm.updateAvailableTooltip": "有可用更新", + "xpack.fleet.epm.versionLabel": "版本", + "xpack.fleet.epmList.allFilterLinkText": "全部", + "xpack.fleet.epmList.allPackagesFilterLinkText": "全部", + "xpack.fleet.epmList.allTabText": "所有集成", + "xpack.fleet.epmList.allTitle": "按类别浏览", + "xpack.fleet.epmList.installedTabText": "已安装集成", + "xpack.fleet.epmList.installedTitle": "已安装集成", + "xpack.fleet.epmList.noPackagesFoundPlaceholder": "未找到任何软件包", + "xpack.fleet.epmList.searchPackagesPlaceholder": "搜索集成", + "xpack.fleet.epmList.updatesAvailableFilterLinkText": "有可用更新", + "xpack.fleet.featureCatalogueDescription": "添加并管理您所有的 Elastic 代理和集成。", + "xpack.fleet.featureCatalogueTitle": "添加 Elastic 代理", + "xpack.fleet.genericActionsMenuText": "打开", + "xpack.fleet.homeIntegration.tutorialDirectory.dismissNoticeButtonText": "关闭消息", + "xpack.fleet.homeIntegration.tutorialDirectory.noticeText": "通过 Elastic 代理,可以简单统一的方式将日志、指标和其他类型数据的监测添加到主机。不再需要安装多个 Beats 和其他代理,这样将策略部署到整个基础架构更容易也更快速。有关更多信息,请阅读我们的{blogPostLink}。", + "xpack.fleet.homeIntegration.tutorialDirectory.noticeText.blogPostLink": "公告博客", + "xpack.fleet.homeIntegration.tutorialDirectory.noticeTitle": "{newPrefix}Elastic 代理和采集管理器公测版", + "xpack.fleet.homeIntegration.tutorialDirectory.noticeTitle.newPrefix": "新通告:", + "xpack.fleet.homeIntegration.tutorialModule.noticeText": "{notePrefix}此模块的较新版本在采集管理器公测版中{availableAsIntegrationLink}。要详细了解代理策略和新的 Elastic 代理,请阅读我们的{blogPostLink}。", + "xpack.fleet.homeIntegration.tutorialModule.noticeText.blogPostLink": "公告博客", + "xpack.fleet.homeIntegration.tutorialModule.noticeText.integrationLink": "作为集成提供", + "xpack.fleet.homeIntegration.tutorialModule.noticeText.notePrefix": "注意:", + "xpack.fleet.initializationErrorMessageTitle": "无法初始化 Ingest Manager", + "xpack.fleet.integrations.installPackage.installingPackageButtonLabel": "正在安装 {title} 资产", + "xpack.fleet.integrations.installPackage.installPackageButtonLabel": "安装 {title} 资产", + "xpack.fleet.integrations.packageInstallErrorDescription": "尝试安装此软件包时出现问题。请稍后重试。", + "xpack.fleet.integrations.packageInstallErrorTitle": "无法安装 {title} 软件包", + "xpack.fleet.integrations.packageInstallSuccessDescription": "已成功安装 {title}", + "xpack.fleet.integrations.packageInstallSuccessTitle": "已安装 {title}", + "xpack.fleet.integrations.packageUninstallErrorDescription": "尝试卸载此软件包时出现问题。请稍后重试。", + "xpack.fleet.integrations.packageUninstallErrorTitle": "无法卸载 {title} 软件包", + "xpack.fleet.integrations.packageUninstallSuccessDescription": "已成功卸载 {title}", + "xpack.fleet.integrations.packageUninstallSuccessTitle": "已卸载 {title}", + "xpack.fleet.integrations.settings.confirmInstallModal.cancelButtonLabel": "取消", + "xpack.fleet.integrations.settings.confirmInstallModal.installButtonLabel": "安装 {packageName}", + "xpack.fleet.integrations.settings.confirmInstallModal.installCalloutTitle": "此操作将安装 {numOfAssets} 个资产", + "xpack.fleet.integrations.settings.confirmInstallModal.installDescription": "Kibana 资产将安装在当前工作区中(默认),仅有权查看此工作区的用户可访问。Elasticsearch 资产为全局安装,所有 Kibana 用户可访问。", + "xpack.fleet.integrations.settings.confirmInstallModal.installTitle": "安装 {packageName}", + "xpack.fleet.integrations.settings.confirmUninstallModal.cancelButtonLabel": "取消", + "xpack.fleet.integrations.settings.confirmUninstallModal.uninstallButtonLabel": "卸载 {packageName}", + "xpack.fleet.integrations.settings.confirmUninstallModal.uninstallCallout.description": "将会移除由此集成创建的 Kibana 和 Elasticsearch 资产。将不会影响代理策略以及您的代理发送的任何数据。", + "xpack.fleet.integrations.settings.confirmUninstallModal.uninstallCallout.title": "此操作将移除 {numOfAssets} 个资产", + "xpack.fleet.integrations.settings.confirmUninstallModal.uninstallDescription": "此操作无法撤消。是否确定要继续?", + "xpack.fleet.integrations.settings.confirmUninstallModal.uninstallTitle": "卸载 {packageName}", + "xpack.fleet.integrations.settings.packageInstallDescription": "安装此集成以设置专用于 {title} 数据的Kibana 和 Elasticsearch 资产。", + "xpack.fleet.integrations.settings.packageInstallTitle": "安装 {title}", + "xpack.fleet.integrations.settings.packageSettingsTitle": "设置", + "xpack.fleet.integrations.settings.packageUninstallDescription": "移除此集成安装的 Kibana 和 Elasticsearch 资产。", + "xpack.fleet.integrations.settings.packageUninstallNoteDescription.packageUninstallNoteDetail": "{strongNote}{title} 无法卸载,因为存在使用此集成的活动代理。要卸载,请从您的代理策略中移除所有 {title} 集成。", + "xpack.fleet.integrations.settings.packageUninstallNoteDescription.packageUninstallNoteLabel": "注意:", + "xpack.fleet.integrations.settings.packageUninstallNoteDescription.packageUninstallUninstallableNoteDetail": "{strongNote} {title} 集成默认安装,无法移除。", + "xpack.fleet.integrations.settings.packageUninstallTitle": "卸载 {title}", + "xpack.fleet.integrations.settings.packageVersionTitle": "{title} 版本", + "xpack.fleet.integrations.settings.versionInfo.installedVersion": "已安装版本", + "xpack.fleet.integrations.settings.versionInfo.latestVersion": "最新版本", + "xpack.fleet.integrations.settings.versionInfo.updatesAvailable": "更新可用", + "xpack.fleet.integrations.uninstallPackage.uninstallingPackageButtonLabel": "正在卸载 {title}", + "xpack.fleet.integrations.uninstallPackage.uninstallPackageButtonLabel": "卸载 {title}", + "xpack.fleet.integrations.updatePackage.updatePackageButtonLabel": "更新到最新版本", + "xpack.fleet.invalidLicenseDescription": "您当前的许可证已过期。已注册 Beats 代理将继续工作,但您需要有效的许可证,才能访问 Elastic Fleet 界面。", + "xpack.fleet.invalidLicenseTitle": "已过期许可证", + "xpack.fleet.listTabs.agentTitle": "代理", + "xpack.fleet.listTabs.enrollmentTokensTitle": "注册令牌", + "xpack.fleet.metadataForm.addButton": "+ 添加元数据", + "xpack.fleet.metadataForm.keyLabel": "键", + "xpack.fleet.metadataForm.submitButtonText": "添加", + "xpack.fleet.metadataForm.valueLabel": "值", + "xpack.fleet.namespaceValidation.invalidCharactersErrorMessage": "命名空间包含无效字符", + "xpack.fleet.namespaceValidation.lowercaseErrorMessage": "命名空间必须小写", + "xpack.fleet.namespaceValidation.requiredErrorMessage": "“命名空间”必填", + "xpack.fleet.namespaceValidation.tooLongErrorMessage": "命名空间不能超过 100 个字节", + "xpack.fleet.newEnrollmentKey.cancelButtonLabel": "取消", + "xpack.fleet.newEnrollmentKey.flyoutTitle": "创建注册令牌", + "xpack.fleet.newEnrollmentKey.keyCreatedToasts": "注册令牌已创建。", + "xpack.fleet.newEnrollmentKey.nameLabel": "名称", + "xpack.fleet.newEnrollmentKey.policyLabel": "策略", + "xpack.fleet.newEnrollmentKey.submitButton": "创建注册令牌", + "xpack.fleet.noAccess.accessDeniedDescription": "您无权访问 Elastic Fleet。要使用 Elastic Fleet,您需要包含此应用程序读取权限或所有权限的用户角色。", + "xpack.fleet.noAccess.accessDeniedTitle": "访问被拒绝", + "xpack.fleet.overviewAgentActiveTitle": "活动", + "xpack.fleet.overviewAgentErrorTitle": "错误", + "xpack.fleet.overviewAgentOfflineTitle": "脱机", + "xpack.fleet.overviewAgentTotalTitle": "代理总数", + "xpack.fleet.overviewDatastreamNamespacesTitle": "命名空间", + "xpack.fleet.overviewDatastreamSizeTitle": "总大小", + "xpack.fleet.overviewDatastreamTotalTitle": "数据流", + "xpack.fleet.overviewIntegrationsInstalledTitle": "安装时间", + "xpack.fleet.overviewIntegrationsTotalTitle": "可用总计", + "xpack.fleet.overviewIntegrationsUpdatesAvailableTitle": "可用更新", + "xpack.fleet.overviewPackagePolicyTitle": "已使用的集成", + "xpack.fleet.overviewPageAgentsPanelTitle": "代理", + "xpack.fleet.overviewPageDataStreamsPanelAction": "查看数据流", + "xpack.fleet.overviewPageDataStreamsPanelTitle": "数据流", + "xpack.fleet.overviewPageDataStreamsPanelTooltip": "您的代理收集的数据组织到各种数据流中。", + "xpack.fleet.overviewPageEnrollAgentButton": "添加代理", + "xpack.fleet.overviewPageFleetPanelAction": "查看代理", + "xpack.fleet.overviewPageFleetPanelTooltip": "使用 Fleet 注册代理并从中央位置管理其策略。", + "xpack.fleet.overviewPageIntegrationsPanelAction": "查看集成", + "xpack.fleet.overviewPageIntegrationsPanelTitle": "集成", + "xpack.fleet.overviewPageIntegrationsPanelTooltip": "浏览并安装适用于 Elastic Stack 的集成。将集成添加到您的代理策略,以开始发送数据。", + "xpack.fleet.overviewPagePoliciesPanelAction": "查看策略", + "xpack.fleet.overviewPagePoliciesPanelTitle": "代理策略", + "xpack.fleet.overviewPagePoliciesPanelTooltip": "使用代理策略控制您的代理收集的数据。", + "xpack.fleet.overviewPageSubtitle": "在集中位置管理 Elastic 代理及其策略。", + "xpack.fleet.overviewPageTitle": "Fleet", + "xpack.fleet.overviewPolicyTotalTitle": "可用总计", + "xpack.fleet.packagePolicyValidation.invalidArrayErrorMessage": "格式无效", + "xpack.fleet.packagePolicyValidation.invalidYamlFormatErrorMessage": "YAML 格式无效", + "xpack.fleet.packagePolicyValidation.nameRequiredErrorMessage": "“名称”必填", + "xpack.fleet.packagePolicyValidation.requiredErrorMessage": "“{fieldName}”必填", + "xpack.fleet.permissionDeniedErrorMessage": "您无权访问 Ingest Manager。Ingest Manager 需要{roleName}权限。", + "xpack.fleet.permissionDeniedErrorTitle": "权限被拒绝", + "xpack.fleet.permissionsRequestErrorMessageDescription": "检查 Ingest Manager 权限时出现问题", + "xpack.fleet.permissionsRequestErrorMessageTitle": "无法检查权限", + "xpack.fleet.policyDetails.addPackagePolicyButtonText": "添加集成", + "xpack.fleet.policyDetails.ErrorGettingFullAgentPolicy": "加载代理策略时出错", + "xpack.fleet.policyDetails.packagePoliciesTable.actionsColumnTitle": "操作", + "xpack.fleet.policyDetails.packagePoliciesTable.deleteActionTitle": "删除集成", + "xpack.fleet.policyDetails.packagePoliciesTable.descriptionColumnTitle": "描述", + "xpack.fleet.policyDetails.packagePoliciesTable.editActionTitle": "编辑集成", + "xpack.fleet.policyDetails.packagePoliciesTable.nameColumnTitle": "名称", + "xpack.fleet.policyDetails.packagePoliciesTable.namespaceColumnTitle": "命名空间", + "xpack.fleet.policyDetails.packagePoliciesTable.packageNameColumnTitle": "集成", + "xpack.fleet.policyDetails.policyDetailsTitle": "策略“{id}”", + "xpack.fleet.policyDetails.policyNotFoundErrorTitle": "找不到策略“{id}”", + "xpack.fleet.policyDetails.subTabs.packagePoliciesTabText": "集成", + "xpack.fleet.policyDetails.subTabs.settingsTabText": "设置", + "xpack.fleet.policyDetails.summary.integrations": "集成", + "xpack.fleet.policyDetails.summary.lastUpdated": "上次更新时间", + "xpack.fleet.policyDetails.summary.revision": "修订", + "xpack.fleet.policyDetails.summary.usedBy": "使用者", + "xpack.fleet.policyDetails.unexceptedErrorTitle": "加载代理策略时发生错误", + "xpack.fleet.policyDetails.viewAgentListTitle": "查看所有代理策略", + "xpack.fleet.policyDetails.yamlDownloadButtonLabel": "下载策略", + "xpack.fleet.policyDetails.yamlFlyoutCloseButtonLabel": "关闭", + "xpack.fleet.policyDetails.yamlflyoutTitleWithName": "代理策略“{name}”", + "xpack.fleet.policyDetails.yamlflyoutTitleWithoutName": "代理策略", + "xpack.fleet.policyDetailsPackagePolicies.createFirstButtonText": "添加集成", + "xpack.fleet.policyDetailsPackagePolicies.createFirstMessage": "此策略尚无任何集成。", + "xpack.fleet.policyDetailsPackagePolicies.createFirstTitle": "添加您的首个集成", + "xpack.fleet.policyForm.deletePolicyActionText": "删除策略", + "xpack.fleet.policyForm.deletePolicyGroupDescription": "现有数据将不会删除。", + "xpack.fleet.policyForm.deletePolicyGroupTitle": "删除策略", + "xpack.fleet.policyForm.generalSettingsGroupDescription": "为您的代理策略选择名称和描述。", + "xpack.fleet.policyForm.generalSettingsGroupTitle": "常规设置", + "xpack.fleet.policyForm.unableToDeleteDefaultPolicyText": "默认策略无法删除", + "xpack.fleet.securityRequiredErrorMessage": "必须在 Kibana 和 Elasticsearch 启用安全性,才能使用 Ingest Manager。", + "xpack.fleet.securityRequiredErrorTitle": "安全性未启用", + "xpack.fleet.settings.additionalYamlConfig": "Elasticsearch 输出配置", + "xpack.fleet.settings.autoUpgradeDisabledLabel": "手动管理代理二进制文件版本。需要黄金级订阅。", + "xpack.fleet.settings.autoUpgradeEnabledLabel": "自动更新代理二进制文件以使用最新的次要版本。", + "xpack.fleet.settings.autoUpgradeFieldLabel": "Elastic 代理二进制文件版本", + "xpack.fleet.settings.cancelButtonLabel": "取消", + "xpack.fleet.settings.elasticHostError": "URL 无效", + "xpack.fleet.settings.elasticsearchUrlLabel": "Elasticsearch URL", + "xpack.fleet.settings.flyoutTitle": "Ingest Manager 设置", + "xpack.fleet.settings.globalOutputDescription": "指定将数据发送到何处。这些设置将应用于所有的 Elastic 代理策略。", + "xpack.fleet.settings.globalOutputTitle": "全局输出", + "xpack.fleet.settings.integrationUpgradeDisabledFieldLabel": "自行手动管理集成版本。", + "xpack.fleet.settings.integrationUpgradeEnabledFieldLabel": "将集成自动更新到最新版本以获取最新资产。您可能需要更新代理策略以使用新功能。", + "xpack.fleet.settings.integrationUpgradeFieldLabel": "集成版本", + "xpack.fleet.settings.invalidYamlFormatErrorMessage": "YAML 无效:{reason}", + "xpack.fleet.settings.kibanaUrlDifferentPathOrProtocolError": "对于每个 URL,协议和路径必须相同", + "xpack.fleet.settings.kibanaUrlEmptyError": "至少需要一个 URL", + "xpack.fleet.settings.kibanaUrlError": "URL 无效", + "xpack.fleet.settings.kibanaUrlLabel": "Kibana URL", + "xpack.fleet.settings.saveButtonLabel": "保存设置", + "xpack.fleet.settings.success.message": "设置已保存", + "xpack.fleet.setupPage.apiKeyServiceLink": "API 密钥服务", + "xpack.fleet.setupPage.elasticsearchApiKeyFlagText": "{apiKeyLink}。将 {apiKeyFlag} 设置为 {true}。", + "xpack.fleet.setupPage.elasticsearchSecurityFlagText": "{esSecurityLink}。将 {securityFlag} 设置为 {true}。", + "xpack.fleet.setupPage.elasticsearchSecurityLink": "Elasticsearch 安全", + "xpack.fleet.setupPage.enableCentralManagement": "创建用户并启用集中管理", + "xpack.fleet.setupPage.enableText": "集中管理需要可以创建 API 密钥并写入到 logs-* 和 metrics-* 的 Elastic 用户。", + "xpack.fleet.setupPage.enableTitle": "对 Elastic 代理启用集中管理", + "xpack.fleet.setupPage.encryptionKeyFlagText": "{encryptionKeyLink}。将 {keyFlag} 设置为至少 32 个字符的字母数字值。", + "xpack.fleet.setupPage.gettingStartedLink": "入门", + "xpack.fleet.setupPage.gettingStartedText": "有关更多信息,请阅读我们的{link}指南。", + "xpack.fleet.setupPage.kibanaEncryptionLink": "Kibana 加密密钥", + "xpack.fleet.setupPage.kibanaSecurityLink": "Kibana 安全性", + "xpack.fleet.setupPage.missingRequirementsCalloutDescription": "要对 Elastic 代理使用集中管理,请启用下面的 Elasticsearch 和 Kibana 安全功能。", + "xpack.fleet.setupPage.missingRequirementsCalloutTitle": "缺失安全性要求", + "xpack.fleet.setupPage.missingRequirementsElasticsearchTitle": "在 Elasticsearch 策略中,启用:", + "xpack.fleet.setupPage.missingRequirementsKibanaTitle": "在 Kibana 策略中,启用:", + "xpack.fleet.setupPage.tlsFlagText": "{kibanaSecurityLink}。将 {securityFlag} 设置为 {true}。出于开发目的,作为非安全的备用方案可以通过将 {tlsFlag} 设置为 {true} 来禁用 {tlsLink}。", + "xpack.fleet.setupPage.tlsLink": "TLS", + "xpack.fleet.unenrollAgents.cancelButtonLabel": "取消", + "xpack.fleet.unenrollAgents.confirmMultipleButtonLabel": "取消注册 {count} 个代理", + "xpack.fleet.unenrollAgents.confirmSingleButtonLabel": "取消注册代理", + "xpack.fleet.unenrollAgents.deleteMultipleDescription": "此操作将从 Fleet 中移除多个代理,并防止采集新数据。将不会影响任何已由这些代理发送的数据。此操作无法撤消。", + "xpack.fleet.unenrollAgents.deleteSingleDescription": "此操作将从 Fleet 中移除“{hostName}”上运行的选定代理。由该代理发送的任何数据将不会被删除。此操作无法撤消。", + "xpack.fleet.unenrollAgents.deleteSingleTitle": "取消注册代理", + "xpack.fleet.unenrollAgents.fatalErrorNotificationTitle": "取消注册{count, plural, one {代理} other {代理}}时出错", + "xpack.fleet.unenrollAgents.forceDeleteMultipleTitle": "取消注册 {count} 个代理", + "xpack.fleet.unenrollAgents.forceUnenrollCheckboxLabel": "立即移除{count, plural, one {代理} other {代理}}。不用等待代理发送任何最终数据。", + "xpack.fleet.unenrollAgents.forceUnenrollLegendText": "强制取消注册{count, plural, one {代理} other {代理}}", + "xpack.fleet.unenrollAgents.successForceMultiNotificationTitle": "代理已取消注册", + "xpack.fleet.unenrollAgents.successForceSingleNotificationTitle": "代理已取消注册", + "xpack.fleet.unenrollAgents.successMultiNotificationTitle": "正在取消注册代理", + "xpack.fleet.unenrollAgents.successSingleNotificationTitle": "正在取消注册代理", + "xpack.fleet.upgradeAgents.cancelButtonLabel": "取消", + "xpack.fleet.upgradeAgents.confirmMultipleButtonLabel": "升级 {count} 个代理", + "xpack.fleet.upgradeAgents.confirmSingleButtonLabel": "升级代理", + "xpack.fleet.upgradeAgents.deleteMultipleTitle": "升级 {count} 个代理", + "xpack.fleet.upgradeAgents.deleteSingleTitle": "升级代理", + "xpack.fleet.upgradeAgents.fatalErrorNotificationTitle": "升级{count, plural, one {代理} other {代理}}时出错", + "xpack.fleet.upgradeAgents.successMultiNotificationTitle": "正在升级代理", + "xpack.fleet.upgradeAgents.successSingleNotificationTitle": "正在升级代理", + "xpack.fleet.upgradeAgents.upgradeMultipleDescription": "此操作会将多个代理升级到版本 {version}。此操作无法撤消。是否确定要继续?", + "xpack.fleet.upgradeAgents.upgradeSingleDescription": "此操作会将“{hostName}”上运行的选定代理升级到版本 {version}。此操作无法撤消。是否确定要继续?", "xpack.globalSearch.find.invalidLicenseError": "GlobalSearch API 已禁用,因为许可状态无效:{errorMessage}", "xpack.globalSearchBar.searchBar.mobileSearchButtonAriaLabel": "全站点搜索", "xpack.globalSearchBar.searchBar.noResults": "尝试搜索应用程序、仪表板和可视化等。", @@ -9642,580 +10215,6 @@ "xpack.infra.waffle.unableToSelectMetricErrorTitle": "无法选择指标选项或指标值。", "xpack.infra.waffleTime.autoRefreshButtonLabel": "自动刷新", "xpack.infra.waffleTime.stopRefreshingButtonLabel": "停止刷新", - "xpack.ingestManager.agentBulkActions.agentsSelected": "已选择 {count, plural, one {# 个代理} other {# 个代理}}", - "xpack.ingestManager.agentBulkActions.clearSelection": "清除所选内容", - "xpack.ingestManager.agentBulkActions.reassignPolicy": "分配到新策略", - "xpack.ingestManager.agentBulkActions.selectAll": "选择所有页面上的所有内容", - "xpack.ingestManager.agentBulkActions.totalAgents": "正在显示 {count, plural, one {# 个代理} other {# 个代理}}", - "xpack.ingestManager.agentBulkActions.totalAgentsWithLimit": "正在显示 {count} 个代理(共 {total} 个)", - "xpack.ingestManager.agentBulkActions.unenrollAgents": "取消注册代理", - "xpack.ingestManager.agentBulkActions.upgradeAgents": "升级代理", - "xpack.ingestManager.agentDetails.actionsButton": "操作", - "xpack.ingestManager.agentDetails.agentDetailsTitle": "代理“{id}”", - "xpack.ingestManager.agentDetails.agentNotFoundErrorDescription": "找不到代理 ID {agentId}", - "xpack.ingestManager.agentDetails.agentNotFoundErrorTitle": "未找到代理", - "xpack.ingestManager.agentDetails.agentPolicyLabel": "代理策略", - "xpack.ingestManager.agentDetails.agentVersionLabel": "代理版本", - "xpack.ingestManager.agentDetails.hostIdLabel": "代理 ID", - "xpack.ingestManager.agentDetails.hostNameLabel": "主机名", - "xpack.ingestManager.agentDetails.localMetadataSectionSubtitle": "本地元数据", - "xpack.ingestManager.agentDetails.metadataSectionTitle": "元数据", - "xpack.ingestManager.agentDetails.platformLabel": "平台", - "xpack.ingestManager.agentDetails.policyLabel": "策略", - "xpack.ingestManager.agentDetails.releaseLabel": "代理发行版", - "xpack.ingestManager.agentDetails.statusLabel": "状态", - "xpack.ingestManager.agentDetails.subTabs.activityLogTab": "活动日志", - "xpack.ingestManager.agentDetails.subTabs.detailsTab": "代理详情", - "xpack.ingestManager.agentDetails.unexceptedErrorTitle": "加载代理时出错", - "xpack.ingestManager.agentDetails.upgradeAvailableTooltip": "升级可用", - "xpack.ingestManager.agentDetails.userProvidedMetadataSectionSubtitle": "用户提供的元数据", - "xpack.ingestManager.agentDetails.versionLabel": "代理版本", - "xpack.ingestManager.agentDetails.viewAgentListTitle": "查看所有代理", - "xpack.ingestManager.agentEnrollment.agentDescription": "将 Elastic 代理添加到您的主机,以收集数据并将其发送到 Elastic Stack。", - "xpack.ingestManager.agentEnrollment.agentsNotInitializedText": "注册代理前,请{link}。", - "xpack.ingestManager.agentEnrollment.cancelButtonLabel": "取消", - "xpack.ingestManager.agentEnrollment.continueButtonLabel": "继续", - "xpack.ingestManager.agentEnrollment.copyPolicyButton": "复制到剪贴板", - "xpack.ingestManager.agentEnrollment.copyRunInstructionsButton": "复制到剪贴板", - "xpack.ingestManager.agentEnrollment.downloadDescription": "可从 Elastic 代理下载页面下载代理二进制文件及其验证签名。", - "xpack.ingestManager.agentEnrollment.downloadLink": "前往下载页面", - "xpack.ingestManager.agentEnrollment.downloadPolicyButton": "下载策略", - "xpack.ingestManager.agentEnrollment.enrollFleetTabLabel": "在 Fleet 中注册", - "xpack.ingestManager.agentEnrollment.enrollStandaloneTabLabel": "独立运行", - "xpack.ingestManager.agentEnrollment.flyoutTitle": "添加代理", - "xpack.ingestManager.agentEnrollment.goToDataStreamsLink": "数据流", - "xpack.ingestManager.agentEnrollment.managedDescription": "在 Fleet 中注册 Elastic 代理,以便自动部署更新并集中管理该代理。", - "xpack.ingestManager.agentEnrollment.setUpAgentsLink": "为 Elastic 代理设置集中管理", - "xpack.ingestManager.agentEnrollment.standaloneDescription": "独立运行 Elastic 代理,以在安装代理的主机上手动配置和更新代理。", - "xpack.ingestManager.agentEnrollment.stepCheckForDataDescription": "该代理应该开始发送数据。前往 {link} 以查看您的数据。", - "xpack.ingestManager.agentEnrollment.stepCheckForDataTitle": "检查数据", - "xpack.ingestManager.agentEnrollment.stepChooseAgentPolicyTitle": "选择代理策略", - "xpack.ingestManager.agentEnrollment.stepConfigureAgentDescription": "在安装 Elastic 代理的主机上将此策略复制到 {fileName}。在 {fileName} 的 {outputSection} 部分中修改 {ESUsernameVariable} 和 {ESPasswordVariable},以使用您的 Elasticsearch 凭据。", - "xpack.ingestManager.agentEnrollment.stepConfigureAgentTitle": "配置代理", - "xpack.ingestManager.agentEnrollment.stepDownloadAgentTitle": "将 Elastic 代理下载到您的主机", - "xpack.ingestManager.agentEnrollment.stepEnrollAndRunAgentTitle": "注册并启动 Elastic 代理", - "xpack.ingestManager.agentEnrollment.stepRunAgentDescription": "从代理目录运行此命令,以安装、注册并启动 Elastic 代理。您可以重复使用此命令在多个主机上设置代理。需要管理员权限。", - "xpack.ingestManager.agentEnrollment.stepRunAgentTitle": "启动代理", - "xpack.ingestManager.agentEventsList.collapseDetailsAriaLabel": "隐藏详情", - "xpack.ingestManager.agentEventsList.expandDetailsAriaLabel": "显示详情", - "xpack.ingestManager.agentEventsList.messageColumnTitle": "消息", - "xpack.ingestManager.agentEventsList.messageDetailsTitle": "消息", - "xpack.ingestManager.agentEventsList.payloadDetailsTitle": "负载", - "xpack.ingestManager.agentEventsList.refreshButton": "刷新", - "xpack.ingestManager.agentEventsList.searchPlaceholderText": "搜索活动日志", - "xpack.ingestManager.agentEventsList.subtypeColumnTitle": "子类型", - "xpack.ingestManager.agentEventsList.timestampColumnTitle": "时间戳", - "xpack.ingestManager.agentEventsList.typeColumnTitle": "类型", - "xpack.ingestManager.agentEventSubtype.acknowledgedLabel": "已确认", - "xpack.ingestManager.agentEventSubtype.dataDumpLabel": "数据转储", - "xpack.ingestManager.agentEventSubtype.degradedLabel": "已降级", - "xpack.ingestManager.agentEventSubtype.failedLabel": "失败", - "xpack.ingestManager.agentEventSubtype.inProgressLabel": "进行中", - "xpack.ingestManager.agentEventSubtype.policyLabel": "策略", - "xpack.ingestManager.agentEventSubtype.runningLabel": "正在运行", - "xpack.ingestManager.agentEventSubtype.startingLabel": "正在启动", - "xpack.ingestManager.agentEventSubtype.stoppedLabel": "已停止", - "xpack.ingestManager.agentEventSubtype.stoppingLabel": "正在停止", - "xpack.ingestManager.agentEventSubtype.unknownLabel": "未知", - "xpack.ingestManager.agentEventSubtype.updatingLabel": "正在更新", - "xpack.ingestManager.agentEventType.actionLabel": "操作", - "xpack.ingestManager.agentEventType.actionResultLabel": "操作结果", - "xpack.ingestManager.agentEventType.errorLabel": "错误", - "xpack.ingestManager.agentEventType.stateLabel": "状态", - "xpack.ingestManager.agentHealth.checkInTooltipText": "上次签入时间 {lastCheckIn}", - "xpack.ingestManager.agentHealth.degradedStatusText": "已降级", - "xpack.ingestManager.agentHealth.enrollingStatusText": "正在注册", - "xpack.ingestManager.agentHealth.errorStatusText": "错误", - "xpack.ingestManager.agentHealth.inactiveStatusText": "非活动", - "xpack.ingestManager.agentHealth.noCheckInTooltipText": "未签入", - "xpack.ingestManager.agentHealth.offlineStatusText": "脱机", - "xpack.ingestManager.agentHealth.onlineStatusText": "联机", - "xpack.ingestManager.agentHealth.unenrollingStatusText": "正在取消注册", - "xpack.ingestManager.agentHealth.updatingStatusText": "正在更新", - "xpack.ingestManager.agentHealth.warningStatusText": "错误", - "xpack.ingestManager.agentList.actionsColumnTitle": "操作", - "xpack.ingestManager.agentList.addButton": "添加代理", - "xpack.ingestManager.agentList.agentUpgradeLabel": "升级可用", - "xpack.ingestManager.agentList.clearFiltersLinkText": "清除筛选", - "xpack.ingestManager.agentList.enrollButton": "添加代理", - "xpack.ingestManager.agentList.forceUnenrollOneButton": "强制取消注册", - "xpack.ingestManager.agentList.hostColumnTitle": "主机", - "xpack.ingestManager.agentList.lastCheckinTitle": "上次活动", - "xpack.ingestManager.agentList.loadingAgentsMessage": "正在加载代理……", - "xpack.ingestManager.agentList.noAgentsPrompt": "未注册任何代理", - "xpack.ingestManager.agentList.noFilteredAgentsPrompt": "未找到任何代理。{clearFiltersLink}", - "xpack.ingestManager.agentList.outOfDateLabel": "过时", - "xpack.ingestManager.agentList.policyColumnTitle": "代理策略", - "xpack.ingestManager.agentList.policyFilterText": "代理策略", - "xpack.ingestManager.agentList.reassignActionText": "分配到新策略", - "xpack.ingestManager.agentList.revisionNumber": "修订 {revNumber}", - "xpack.ingestManager.agentList.showInactiveSwitchLabel": "非活动", - "xpack.ingestManager.agentList.showUpgradeableFilterLabel": "升级可用", - "xpack.ingestManager.agentList.statusColumnTitle": "状态", - "xpack.ingestManager.agentList.statusErrorFilterText": "错误", - "xpack.ingestManager.agentList.statusFilterText": "状态", - "xpack.ingestManager.agentList.statusOfflineFilterText": "脱机", - "xpack.ingestManager.agentList.statusOnlineFilterText": "联机", - "xpack.ingestManager.agentList.statusUpdatingFilterText": "正在更新", - "xpack.ingestManager.agentList.unenrollOneButton": "取消注册代理", - "xpack.ingestManager.agentList.upgradeOneButton": "升级代理", - "xpack.ingestManager.agentList.versionTitle": "版本", - "xpack.ingestManager.agentList.viewActionText": "查看代理", - "xpack.ingestManager.agentListStatus.errorLabel": "错误", - "xpack.ingestManager.agentListStatus.offlineLabel": "脱机", - "xpack.ingestManager.agentListStatus.onlineLabel": "联机", - "xpack.ingestManager.agentListStatus.totalLabel": "代理", - "xpack.ingestManager.agentPolicy.confirmModalCalloutDescription": "Fleet 检测到您的部分代理已在使用选定代理策略 {policyName}。由于此操作,Fleet 会将更新部署到使用此策略的所有代理。", - "xpack.ingestManager.agentPolicy.confirmModalCalloutTitle": "此操作将更新 {agentCount, plural, one {# 个代理} other {# 个代理}}", - "xpack.ingestManager.agentPolicy.confirmModalCancelButtonLabel": "取消", - "xpack.ingestManager.agentPolicy.confirmModalConfirmButtonLabel": "保存并部署更改", - "xpack.ingestManager.agentPolicy.confirmModalDescription": "此操作无法撤消。是否确定要继续?", - "xpack.ingestManager.agentPolicy.confirmModalTitle": "保存并部署更改", - "xpack.ingestManager.agentPolicy.linkedAgentCountText": "{count, plural, one {# 个代理} other {# 个代理}}", - "xpack.ingestManager.agentPolicyActionMenu.buttonText": "操作", - "xpack.ingestManager.agentPolicyActionMenu.copyPolicyActionText": "复制策略", - "xpack.ingestManager.agentPolicyActionMenu.enrollAgentActionText": "添加代理", - "xpack.ingestManager.agentPolicyActionMenu.viewPolicyText": "查看策略", - "xpack.ingestManager.agentPolicyForm.advancedOptionsToggleLabel": "高级选项", - "xpack.ingestManager.agentPolicyForm.descriptionFieldLabel": "描述", - "xpack.ingestManager.agentPolicyForm.descriptionFieldPlaceholder": "此策略将如何使用?", - "xpack.ingestManager.agentPolicyForm.monitoringDescription": "收集有关代理的数据,用于调试和跟踪性能。", - "xpack.ingestManager.agentPolicyForm.monitoringLabel": "代理监测", - "xpack.ingestManager.agentPolicyForm.monitoringLogsFieldLabel": "收集代理日志", - "xpack.ingestManager.agentPolicyForm.monitoringLogsTooltipText": "从使用此策略的 Elastic 代理收集日志。", - "xpack.ingestManager.agentPolicyForm.monitoringMetricsFieldLabel": "收集代理指标", - "xpack.ingestManager.agentPolicyForm.monitoringMetricsTooltipText": "从使用此策略的 Elastic 代理收集指标。", - "xpack.ingestManager.agentPolicyForm.nameFieldLabel": "名称", - "xpack.ingestManager.agentPolicyForm.nameFieldPlaceholder": "选择名称", - "xpack.ingestManager.agentPolicyForm.nameRequiredErrorMessage": "“代理策略名称”必填。", - "xpack.ingestManager.agentPolicyForm.namespaceFieldDescription": "将默认命名空间应用于使用此策略的集成。集成可以指定自己的命名空间。", - "xpack.ingestManager.agentPolicyForm.namespaceFieldLabel": "默认命名空间", - "xpack.ingestManager.agentPolicyForm.systemMonitoringFieldLabel": "系统监测", - "xpack.ingestManager.agentPolicyForm.systemMonitoringText": "收集系统指标", - "xpack.ingestManager.agentPolicyForm.systemMonitoringTooltipText": "启用此选项可使用收集系统指标和信息的集成启动您的策略。", - "xpack.ingestManager.agentPolicyList.actionsColumnTitle": "操作", - "xpack.ingestManager.agentPolicyList.addButton": "创建代理策略", - "xpack.ingestManager.agentPolicyList.agentsColumnTitle": "代理", - "xpack.ingestManager.agentPolicyList.clearFiltersLinkText": "清除筛选", - "xpack.ingestManager.agentPolicyList.descriptionColumnTitle": "描述", - "xpack.ingestManager.agentPolicyList.loadingAgentPoliciesMessage": "正在加载代理策略…...", - "xpack.ingestManager.agentPolicyList.nameColumnTitle": "名称", - "xpack.ingestManager.agentPolicyList.noAgentPoliciesPrompt": "无代理策略", - "xpack.ingestManager.agentPolicyList.noFilteredAgentPoliciesPrompt": "找不到任何代理策略。{clearFiltersLink}", - "xpack.ingestManager.agentPolicyList.packagePoliciesCountColumnTitle": "集成", - "xpack.ingestManager.agentPolicyList.pageSubtitle": "使用代理策略管理代理及其收集的数据。", - "xpack.ingestManager.agentPolicyList.pageTitle": "代理策略", - "xpack.ingestManager.agentPolicyList.reloadAgentPoliciesButtonText": "重新加载", - "xpack.ingestManager.agentPolicyList.revisionNumber": "修订版 {revNumber}", - "xpack.ingestManager.agentPolicyList.updatedOnColumnTitle": "上次更新时间", - "xpack.ingestManager.agentReassignPolicy.cancelButtonLabel": "取消", - "xpack.ingestManager.agentReassignPolicy.continueButtonLabel": "分配策略", - "xpack.ingestManager.agentReassignPolicy.flyoutDescription": "选择要将选定{count, plural, one {代理} other {代理}}分配到的新代理策略。", - "xpack.ingestManager.agentReassignPolicy.flyoutTitle": "分配新代理策略", - "xpack.ingestManager.agentReassignPolicy.policyDescription": "选定代理策略将收集 {count, plural, one {{countValue} 个集成} other {{countValue} 个集成}}的数据:", - "xpack.ingestManager.agentReassignPolicy.selectPolicyLabel": "代理策略", - "xpack.ingestManager.agentReassignPolicy.successSingleNotificationTitle": "代理策略已重新分配", - "xpack.ingestManager.agents.pageSubtitle": "管理策略更新并将其部署到一组任意大小的代理。", - "xpack.ingestManager.agents.pageTitle": "代理", - "xpack.ingestManager.alphaMessageDescription": "不推荐在生产环境中使用采集管理器。", - "xpack.ingestManager.alphaMessageLinkText": "查看更多详情。", - "xpack.ingestManager.alphaMessageTitle": "公测版", - "xpack.ingestManager.alphaMessaging.docsLink": "文档", - "xpack.ingestManager.alphaMessaging.feedbackText": "阅读我们的{docsLink}或前往我们的{forumLink},以了解问题或提供反馈。", - "xpack.ingestManager.alphaMessaging.flyoutTitle": "关于本版本", - "xpack.ingestManager.alphaMessaging.forumLink": "讨论论坛", - "xpack.ingestManager.alphaMessaging.introText": "采集管理器仍处于开发状态,不适用于生产环境。此公测版用于用户测试采集管理器和新 Elastic 代理并提供相关反馈。此插件不受支持 SLA 的约束。", - "xpack.ingestManager.alphaMessging.closeFlyoutLabel": "关闭", - "xpack.ingestManager.appNavigation.agentsLinkText": "代理", - "xpack.ingestManager.appNavigation.dataStreamsLinkText": "数据流", - "xpack.ingestManager.appNavigation.epmLinkText": "集成", - "xpack.ingestManager.appNavigation.overviewLinkText": "概览", - "xpack.ingestManager.appNavigation.policiesLinkText": "策略", - "xpack.ingestManager.appNavigation.sendFeedbackButton": "发送反馈", - "xpack.ingestManager.appNavigation.settingsButton": "设置", - "xpack.ingestManager.appTitle": "Fleet", - "xpack.ingestManager.betaBadge.labelText": "公测版", - "xpack.ingestManager.betaBadge.tooltipText": "不推荐在生产环境中使用此插件。请在我们讨论论坛中报告错误。", - "xpack.ingestManager.breadcrumbs.addPackagePolicyPageTitle": "添加集成", - "xpack.ingestManager.breadcrumbs.agentsPageTitle": "代理", - "xpack.ingestManager.breadcrumbs.allIntegrationsPageTitle": "全部", - "xpack.ingestManager.breadcrumbs.appTitle": "Fleet", - "xpack.ingestManager.breadcrumbs.datastreamsPageTitle": "数据流", - "xpack.ingestManager.breadcrumbs.editPackagePolicyPageTitle": "编辑集成", - "xpack.ingestManager.breadcrumbs.enrollmentTokensPageTitle": "注册令牌", - "xpack.ingestManager.breadcrumbs.installedIntegrationsPageTitle": "已安装", - "xpack.ingestManager.breadcrumbs.integrationsPageTitle": "集成", - "xpack.ingestManager.breadcrumbs.overviewPageTitle": "概览", - "xpack.ingestManager.breadcrumbs.policiesPageTitle": "策略", - "xpack.ingestManager.copyAgentPolicy.confirmModal.cancelButtonLabel": "取消", - "xpack.ingestManager.copyAgentPolicy.confirmModal.confirmButtonLabel": "复制策略", - "xpack.ingestManager.copyAgentPolicy.confirmModal.copyPolicyPrompt": "为您的新代理策略选择名称和描述。", - "xpack.ingestManager.copyAgentPolicy.confirmModal.copyPolicyTitle": "复制代理策略“{name}”", - "xpack.ingestManager.copyAgentPolicy.confirmModal.defaultNewPolicyName": "{name}(副本)", - "xpack.ingestManager.copyAgentPolicy.confirmModal.newDescriptionLabel": "描述", - "xpack.ingestManager.copyAgentPolicy.confirmModal.newNameLabel": "新策略名称", - "xpack.ingestManager.copyAgentPolicy.failureNotificationTitle": "复制代理策略“{id}”时出错", - "xpack.ingestManager.copyAgentPolicy.fatalErrorNotificationTitle": "复制代理策略时出错", - "xpack.ingestManager.copyAgentPolicy.successNotificationTitle": "代理策略已复制", - "xpack.ingestManager.createAgentPolicy.cancelButtonLabel": "取消", - "xpack.ingestManager.createAgentPolicy.errorNotificationTitle": "无法创建代理策略", - "xpack.ingestManager.createAgentPolicy.flyoutTitle": "创建代理策略", - "xpack.ingestManager.createAgentPolicy.flyoutTitleDescription": "代理策略用于管理一组代理的设置。您可以将集成添加到代理策略,以指定代理收集的数据。编辑代理策略时,可以使用 Fleet 将更新部署到一组指定代理。", - "xpack.ingestManager.createAgentPolicy.submitButtonLabel": "创建代理策略", - "xpack.ingestManager.createAgentPolicy.successNotificationTitle": "代理策略“{name}”已创建", - "xpack.ingestManager.createPackagePolicy.addedNotificationMessage": "Fleet 会将更新部署到所有使用策略“{agentPolicyName}”的代理。", - "xpack.ingestManager.createPackagePolicy.addedNotificationTitle": "“{packagePolicyName}”集成已添加。", - "xpack.ingestManager.createPackagePolicy.agentPolicyNameLabel": "代理策略", - "xpack.ingestManager.createPackagePolicy.cancelButton": "取消", - "xpack.ingestManager.createPackagePolicy.cancelLinkText": "取消", - "xpack.ingestManager.createPackagePolicy.errorOnSaveText": "您的集成策略有错误。请在保存前修复这些错误。", - "xpack.ingestManager.createPackagePolicy.pageDescriptionfromPackage": "按照以下说明将此集成添加到代理策略。", - "xpack.ingestManager.createPackagePolicy.pageDescriptionfromPolicy": "为选定代理策略配置集成。", - "xpack.ingestManager.createPackagePolicy.pageTitle": "添加集成", - "xpack.ingestManager.createPackagePolicy.pageTitleWithPackageName": "添加 {packageName} 集成", - "xpack.ingestManager.createPackagePolicy.saveButton": "保存集成", - "xpack.ingestManager.createPackagePolicy.stepConfigure.advancedOptionsToggleLinkText": "高级选项", - "xpack.ingestManager.createPackagePolicy.stepConfigure.errorCountText": "{count, plural, one {# 个错误} other {# 个错误}}", - "xpack.ingestManager.createPackagePolicy.stepConfigure.hideStreamsAriaLabel": "隐藏 {type} 输入", - "xpack.ingestManager.createPackagePolicy.stepConfigure.inputSettingsDescription": "以下设置适用于下面的所有输入。", - "xpack.ingestManager.createPackagePolicy.stepConfigure.inputSettingsTitle": "设置", - "xpack.ingestManager.createPackagePolicy.stepConfigure.inputVarFieldOptionalLabel": "可选", - "xpack.ingestManager.createPackagePolicy.stepConfigure.integrationSettingsSectionDescription": "选择有助于确定如何使用此集成的名称和描述。", - "xpack.ingestManager.createPackagePolicy.stepConfigure.integrationSettingsSectionTitle": "集成设置", - "xpack.ingestManager.createPackagePolicy.stepConfigure.noPolicyOptionsMessage": "没有可配置的内容", - "xpack.ingestManager.createPackagePolicy.stepConfigure.packagePolicyDescriptionInputLabel": "描述", - "xpack.ingestManager.createPackagePolicy.stepConfigure.packagePolicyNameInputLabel": "集成名称", - "xpack.ingestManager.createPackagePolicy.stepConfigure.packagePolicyNamespaceInputLabel": "命名空间", - "xpack.ingestManager.createPackagePolicy.stepConfigure.showStreamsAriaLabel": "显示 {type} 输入", - "xpack.ingestManager.createPackagePolicy.stepConfigure.toggleAdvancedOptionsButtonText": "高级选项", - "xpack.ingestManager.createPackagePolicy.stepConfigurePackagePolicyTitle": "配置集成", - "xpack.ingestManager.createPackagePolicy.stepSelectAgentPolicyTitle": "选择代理策略", - "xpack.ingestManager.createPackagePolicy.stepSelectPackage.errorLoadingPackagesTitle": "加载集成时出错", - "xpack.ingestManager.createPackagePolicy.stepSelectPackage.errorLoadingPolicyTitle": "加载代理策略信息时出错", - "xpack.ingestManager.createPackagePolicy.stepSelectPackage.errorLoadingSelectedPackageTitle": "加载选定集成时出错", - "xpack.ingestManager.createPackagePolicy.stepSelectPackage.filterPackagesInputPlaceholder": "搜索集成", - "xpack.ingestManager.createPackagePolicy.stepSelectPackageTitle": "选择集成", - "xpack.ingestManager.createPackagePolicy.StepSelectPolicy.addButton": "创建代理策略", - "xpack.ingestManager.createPackagePolicy.StepSelectPolicy.agentPolicyAgentsCountText": "{count, plural, one {# 个代理} other {# 个代理}}已注册", - "xpack.ingestManager.createPackagePolicy.StepSelectPolicy.agentPolicyAgentsDescriptionText": "{count, plural, one {# 个代理} other {# 个代理}}已注册到选定代理策略中。", - "xpack.ingestManager.createPackagePolicy.StepSelectPolicy.agentPolicyLabel": "代理策略", - "xpack.ingestManager.createPackagePolicy.StepSelectPolicy.agentPolicyPlaceholderText": "选择要将此集成添加到的代理策略", - "xpack.ingestManager.createPackagePolicy.StepSelectPolicy.errorLoadingAgentPoliciesTitle": "加载代理策略时出错", - "xpack.ingestManager.createPackagePolicy.StepSelectPolicy.errorLoadingPackageTitle": "加载软件包信息时出错", - "xpack.ingestManager.createPackagePolicy.StepSelectPolicy.errorLoadingSelectedAgentPolicyTitle": "加载选定代理策略时出错", - "xpack.ingestManager.dataStreamList.actionsColumnTitle": "操作", - "xpack.ingestManager.dataStreamList.datasetColumnTitle": "数据集", - "xpack.ingestManager.dataStreamList.integrationColumnTitle": "集成", - "xpack.ingestManager.dataStreamList.lastActivityColumnTitle": "上次活动", - "xpack.ingestManager.dataStreamList.loadingDataStreamsMessage": "正在加载数据流……", - "xpack.ingestManager.dataStreamList.namespaceColumnTitle": "命名空间", - "xpack.ingestManager.dataStreamList.noDataStreamsPrompt": "无数据流", - "xpack.ingestManager.dataStreamList.noFilteredDataStreamsMessage": "找不到匹配的数据流", - "xpack.ingestManager.dataStreamList.pageSubtitle": "管理您的代理创建的数据。", - "xpack.ingestManager.dataStreamList.pageTitle": "数据流", - "xpack.ingestManager.dataStreamList.reloadDataStreamsButtonText": "重新加载", - "xpack.ingestManager.dataStreamList.searchPlaceholderTitle": "筛选数据流", - "xpack.ingestManager.dataStreamList.sizeColumnTitle": "大小", - "xpack.ingestManager.dataStreamList.typeColumnTitle": "类型", - "xpack.ingestManager.dataStreamList.viewDashboardActionText": "查看仪表板", - "xpack.ingestManager.dataStreamList.viewDashboardsActionText": "查看仪表板", - "xpack.ingestManager.dataStreamList.viewDashboardsPanelTitle": "查看仪表板", - "xpack.ingestManager.defaultSearchPlaceholderText": "搜索", - "xpack.ingestManager.deleteAgentPolicy.confirmModal.affectedAgentsMessage": "{agentsCount, plural, one {# 个代理} other {# 个代理}}已分配到此代理策略。在删除此策略前取消分配这些代理。", - "xpack.ingestManager.deleteAgentPolicy.confirmModal.affectedAgentsTitle": "在用的策略", - "xpack.ingestManager.deleteAgentPolicy.confirmModal.cancelButtonLabel": "取消", - "xpack.ingestManager.deleteAgentPolicy.confirmModal.confirmButtonLabel": "删除策略", - "xpack.ingestManager.deleteAgentPolicy.confirmModal.deletePolicyTitle": "删除此代理策略?", - "xpack.ingestManager.deleteAgentPolicy.confirmModal.irreversibleMessage": "此操作无法撤消。", - "xpack.ingestManager.deleteAgentPolicy.confirmModal.loadingAgentsCountMessage": "正在检查受影响的代理数量……", - "xpack.ingestManager.deleteAgentPolicy.confirmModal.loadingButtonLabel": "正在加载……", - "xpack.ingestManager.deleteAgentPolicy.failureSingleNotificationTitle": "删除代理策略“{id}”时出错", - "xpack.ingestManager.deleteAgentPolicy.fatalErrorNotificationTitle": "删除代理策略时出错", - "xpack.ingestManager.deleteAgentPolicy.successSingleNotificationTitle": "已删除代理策略“{id}”", - "xpack.ingestManager.deletePackagePolicy.confirmModal.affectedAgentsMessage": "Fleet 检测到您的部分代理已在使用 {agentPolicyName}。", - "xpack.ingestManager.deletePackagePolicy.confirmModal.affectedAgentsTitle": "此操作将影响 {agentsCount} 个{agentsCount, plural, one {代理} other {代理}}。", - "xpack.ingestManager.deletePackagePolicy.confirmModal.cancelButtonLabel": "取消", - "xpack.ingestManager.deletePackagePolicy.confirmModal.confirmButtonLabel": "删除{agentPoliciesCount, plural, one {集成} other {集成}}", - "xpack.ingestManager.deletePackagePolicy.confirmModal.deleteMultipleTitle": "删除 {count, plural, one {集成} other {# 个集成}}?", - "xpack.ingestManager.deletePackagePolicy.confirmModal.generalMessage": "此操作无法撤消。是否确定要继续?", - "xpack.ingestManager.deletePackagePolicy.confirmModal.loadingAgentsCountMessage": "正在检查受影响的代理……", - "xpack.ingestManager.deletePackagePolicy.confirmModal.loadingButtonLabel": "正在加载……", - "xpack.ingestManager.deletePackagePolicy.failureMultipleNotificationTitle": "删除 {count} 个集成时出错", - "xpack.ingestManager.deletePackagePolicy.failureSingleNotificationTitle": "删除集成“{id}”时出错", - "xpack.ingestManager.deletePackagePolicy.fatalErrorNotificationTitle": "删除集成时出错", - "xpack.ingestManager.deletePackagePolicy.successMultipleNotificationTitle": "已删除 {count} 个集成", - "xpack.ingestManager.deletePackagePolicy.successSingleNotificationTitle": "已删除集成“{id}”", - "xpack.ingestManager.disabledSecurityDescription": "必须在 Kibana 和 Elasticsearch 启用安全性,才能使用 Elastic Fleet。", - "xpack.ingestManager.disabledSecurityTitle": "安全性未启用", - "xpack.ingestManager.editAgentPolicy.cancelButtonText": "取消", - "xpack.ingestManager.editAgentPolicy.errorNotificationTitle": "无法更新代理策略", - "xpack.ingestManager.editAgentPolicy.saveButtonText": "保存更改", - "xpack.ingestManager.editAgentPolicy.savingButtonText": "正在保存……", - "xpack.ingestManager.editAgentPolicy.successNotificationTitle": "已成功更新“{name}”设置", - "xpack.ingestManager.editAgentPolicy.unsavedChangesText": "您有未保存的更改", - "xpack.ingestManager.editPackagePolicy.cancelButton": "取消", - "xpack.ingestManager.editPackagePolicy.errorLoadingDataMessage": "加载此集成信息时出错", - "xpack.ingestManager.editPackagePolicy.errorLoadingDataTitle": "加载数据时出错", - "xpack.ingestManager.editPackagePolicy.failedConflictNotificationMessage": "数据已过时。刷新页面以获取最新策略。", - "xpack.ingestManager.editPackagePolicy.failedNotificationTitle": "更新“{packagePolicyName}”时出错", - "xpack.ingestManager.editPackagePolicy.pageDescription": "修改集成设置并将更改部署到选定代理策略。", - "xpack.ingestManager.editPackagePolicy.pageTitle": "编辑集成", - "xpack.ingestManager.editPackagePolicy.pageTitleWithPackageName": "编辑 {packageName} 集成", - "xpack.ingestManager.editPackagePolicy.saveButton": "保存集成", - "xpack.ingestManager.editPackagePolicy.updatedNotificationMessage": "Fleet 会将更新部署到所有使用策略“{agentPolicyName}”的代理", - "xpack.ingestManager.editPackagePolicy.updatedNotificationTitle": "已成功更新“{packagePolicyName}”", - "xpack.ingestManager.enrollemntAPIKeyList.emptyMessage": "未找到任何注册令牌。", - "xpack.ingestManager.enrollemntAPIKeyList.loadingTokensMessage": "正在加载注册令牌......", - "xpack.ingestManager.enrollmentInstructions.descriptionText": "从代理目录运行相应命令,以安装、注册并启动 Elastic 代理。您可以重复使用这些命令在多个主机上设置代理。需要管理员权限。", - "xpack.ingestManager.enrollmentInstructions.linuxMacOSTitle": "Linux、macOS", - "xpack.ingestManager.enrollmentInstructions.moreInstructionsLink": "Elastic 代理文档", - "xpack.ingestManager.enrollmentInstructions.moreInstructionsText": "有关更多说明和选项,请参见 {link}。", - "xpack.ingestManager.enrollmentInstructions.windowsTitle": "Windows", - "xpack.ingestManager.enrollmentStepAgentPolicy.enrollmentTokenSelectLabel": "注册令牌", - "xpack.ingestManager.enrollmentStepAgentPolicy.policySelectAriaLabel": "代理策略", - "xpack.ingestManager.enrollmentStepAgentPolicy.policySelectLabel": "代理策略", - "xpack.ingestManager.enrollmentStepAgentPolicy.showAuthenticationSettingsButton": "身份验证设置", - "xpack.ingestManager.enrollmentTokenDeleteModal.cancelButton": "取消", - "xpack.ingestManager.enrollmentTokenDeleteModal.deleteButton": "撤销注册令牌", - "xpack.ingestManager.enrollmentTokenDeleteModal.description": "确定要撤销 {keyName}?使用此令牌的代理将无法再访问策略或发送数据。 ", - "xpack.ingestManager.enrollmentTokenDeleteModal.title": "撤销注册令牌", - "xpack.ingestManager.enrollmentTokensList.actionsTitle": "操作", - "xpack.ingestManager.enrollmentTokensList.activeTitle": "活动", - "xpack.ingestManager.enrollmentTokensList.createdAtTitle": "创建日期", - "xpack.ingestManager.enrollmentTokensList.hideTokenButtonLabel": "隐藏令牌", - "xpack.ingestManager.enrollmentTokensList.nameTitle": "名称", - "xpack.ingestManager.enrollmentTokensList.newKeyButton": "创建注册令牌", - "xpack.ingestManager.enrollmentTokensList.pageDescription": "创建和撤销注册令牌。注册令牌允许一个或多个代理注册于 Fleet 中并发送数据。", - "xpack.ingestManager.enrollmentTokensList.policyTitle": "代理策略", - "xpack.ingestManager.enrollmentTokensList.revokeTokenButtonLabel": "撤销令牌", - "xpack.ingestManager.enrollmentTokensList.secretTitle": "密钥", - "xpack.ingestManager.enrollmentTokensList.showTokenButtonLabel": "显示令牌", - "xpack.ingestManager.epm.addPackagePolicyButtonText": "添加 {packageName}", - "xpack.ingestManager.epm.assetGroupTitle": "{assetType} 资产", - "xpack.ingestManager.epm.browseAllButtonText": "浏览所有集成", - "xpack.ingestManager.epm.illustrationAltText": "集成的图示", - "xpack.ingestManager.epm.loadingIntegrationErrorTitle": "加载集成详情时出错", - "xpack.ingestManager.epm.packageDetailsNav.overviewLinkText": "概览", - "xpack.ingestManager.epm.packageDetailsNav.packagePoliciesLinkText": "使用情况", - "xpack.ingestManager.epm.packageDetailsNav.settingsLinkText": "设置", - "xpack.ingestManager.epm.pageSubtitle": "浏览集成以了解热门应用和服务。", - "xpack.ingestManager.epm.pageTitle": "集成", - "xpack.ingestManager.epm.releaseBadge.betaDescription": "在生产环境中不推荐使用此集成。", - "xpack.ingestManager.epm.releaseBadge.betaLabel": "公测版", - "xpack.ingestManager.epm.releaseBadge.experimentalDescription": "此集成可能有重大更改或将在未来版本中移除。", - "xpack.ingestManager.epm.releaseBadge.experimentalLabel": "实验性", - "xpack.ingestManager.epm.screenshotsTitle": "屏幕截图", - "xpack.ingestManager.epm.updateAvailableTooltip": "有可用更新", - "xpack.ingestManager.epm.versionLabel": "版本", - "xpack.ingestManager.epmList.allFilterLinkText": "全部", - "xpack.ingestManager.epmList.allPackagesFilterLinkText": "全部", - "xpack.ingestManager.epmList.allTabText": "所有集成", - "xpack.ingestManager.epmList.allTitle": "按类别浏览", - "xpack.ingestManager.epmList.installedTabText": "已安装集成", - "xpack.ingestManager.epmList.installedTitle": "已安装集成", - "xpack.ingestManager.epmList.noPackagesFoundPlaceholder": "未找到任何软件包", - "xpack.ingestManager.epmList.searchPackagesPlaceholder": "搜索集成", - "xpack.ingestManager.epmList.updatesAvailableFilterLinkText": "有可用更新", - "xpack.ingestManager.featureCatalogueDescription": "添加并管理您所有的 Elastic 代理和集成。", - "xpack.ingestManager.featureCatalogueTitle": "添加 Elastic 代理", - "xpack.ingestManager.genericActionsMenuText": "打开", - "xpack.ingestManager.homeIntegration.tutorialDirectory.dismissNoticeButtonText": "关闭消息", - "xpack.ingestManager.homeIntegration.tutorialDirectory.noticeText": "通过 Elastic 代理,可以简单统一的方式将日志、指标和其他类型数据的监测添加到主机。不再需要安装多个 Beats 和其他代理,这样将策略部署到整个基础架构更容易也更快速。有关更多信息,请阅读我们的{blogPostLink}。", - "xpack.ingestManager.homeIntegration.tutorialDirectory.noticeText.blogPostLink": "公告博客", - "xpack.ingestManager.homeIntegration.tutorialDirectory.noticeTitle": "{newPrefix}Elastic 代理和采集管理器公测版", - "xpack.ingestManager.homeIntegration.tutorialDirectory.noticeTitle.newPrefix": "新通告:", - "xpack.ingestManager.homeIntegration.tutorialModule.noticeText": "{notePrefix}此模块的较新版本在采集管理器公测版中{availableAsIntegrationLink}。要详细了解代理策略和新的 Elastic 代理,请阅读我们的{blogPostLink}。", - "xpack.ingestManager.homeIntegration.tutorialModule.noticeText.blogPostLink": "公告博客", - "xpack.ingestManager.homeIntegration.tutorialModule.noticeText.integrationLink": "作为集成提供", - "xpack.ingestManager.homeIntegration.tutorialModule.noticeText.notePrefix": "注意:", - "xpack.ingestManager.initializationErrorMessageTitle": "无法初始化 Ingest Manager", - "xpack.ingestManager.integrations.installPackage.installingPackageButtonLabel": "正在安装 {title} 资产", - "xpack.ingestManager.integrations.installPackage.installPackageButtonLabel": "安装 {title} 资产", - "xpack.ingestManager.integrations.packageInstallErrorDescription": "尝试安装此软件包时出现问题。请稍后重试。", - "xpack.ingestManager.integrations.packageInstallErrorTitle": "无法安装 {title} 软件包", - "xpack.ingestManager.integrations.packageInstallSuccessDescription": "已成功安装 {title}", - "xpack.ingestManager.integrations.packageInstallSuccessTitle": "已安装 {title}", - "xpack.ingestManager.integrations.packageUninstallErrorDescription": "尝试卸载此软件包时出现问题。请稍后重试。", - "xpack.ingestManager.integrations.packageUninstallErrorTitle": "无法卸载 {title} 软件包", - "xpack.ingestManager.integrations.packageUninstallSuccessDescription": "已成功卸载 {title}", - "xpack.ingestManager.integrations.packageUninstallSuccessTitle": "已卸载 {title}", - "xpack.ingestManager.integrations.settings.confirmInstallModal.cancelButtonLabel": "取消", - "xpack.ingestManager.integrations.settings.confirmInstallModal.installButtonLabel": "安装 {packageName}", - "xpack.ingestManager.integrations.settings.confirmInstallModal.installCalloutTitle": "此操作将安装 {numOfAssets} 个资产", - "xpack.ingestManager.integrations.settings.confirmInstallModal.installDescription": "Kibana 资产将安装在当前工作区中(默认),仅有权查看此工作区的用户可访问。Elasticsearch 资产为全局安装,所有 Kibana 用户可访问。", - "xpack.ingestManager.integrations.settings.confirmInstallModal.installTitle": "安装 {packageName}", - "xpack.ingestManager.integrations.settings.confirmUninstallModal.cancelButtonLabel": "取消", - "xpack.ingestManager.integrations.settings.confirmUninstallModal.uninstallButtonLabel": "卸载 {packageName}", - "xpack.ingestManager.integrations.settings.confirmUninstallModal.uninstallCallout.description": "将会移除由此集成创建的 Kibana 和 Elasticsearch 资产。将不会影响代理策略以及您的代理发送的任何数据。", - "xpack.ingestManager.integrations.settings.confirmUninstallModal.uninstallCallout.title": "此操作将移除 {numOfAssets} 个资产", - "xpack.ingestManager.integrations.settings.confirmUninstallModal.uninstallDescription": "此操作无法撤消。是否确定要继续?", - "xpack.ingestManager.integrations.settings.confirmUninstallModal.uninstallTitle": "卸载 {packageName}", - "xpack.ingestManager.integrations.settings.packageInstallDescription": "安装此集成以设置专用于 {title} 数据的Kibana 和 Elasticsearch 资产。", - "xpack.ingestManager.integrations.settings.packageInstallTitle": "安装 {title}", - "xpack.ingestManager.integrations.settings.packageSettingsTitle": "设置", - "xpack.ingestManager.integrations.settings.packageUninstallDescription": "移除此集成安装的 Kibana 和 Elasticsearch 资产。", - "xpack.ingestManager.integrations.settings.packageUninstallNoteDescription.packageUninstallNoteDetail": "{strongNote}{title} 无法卸载,因为存在使用此集成的活动代理。要卸载,请从您的代理策略中移除所有 {title} 集成。", - "xpack.ingestManager.integrations.settings.packageUninstallNoteDescription.packageUninstallNoteLabel": "注意:", - "xpack.ingestManager.integrations.settings.packageUninstallNoteDescription.packageUninstallUninstallableNoteDetail": "{strongNote} {title} 集成默认安装,无法移除。", - "xpack.ingestManager.integrations.settings.packageUninstallTitle": "卸载 {title}", - "xpack.ingestManager.integrations.settings.packageVersionTitle": "{title} 版本", - "xpack.ingestManager.integrations.settings.versionInfo.installedVersion": "已安装版本", - "xpack.ingestManager.integrations.settings.versionInfo.latestVersion": "最新版本", - "xpack.ingestManager.integrations.settings.versionInfo.updatesAvailable": "更新可用", - "xpack.ingestManager.integrations.uninstallPackage.uninstallingPackageButtonLabel": "正在卸载 {title}", - "xpack.ingestManager.integrations.uninstallPackage.uninstallPackageButtonLabel": "卸载 {title}", - "xpack.ingestManager.integrations.updatePackage.updatePackageButtonLabel": "更新到最新版本", - "xpack.ingestManager.invalidLicenseDescription": "您当前的许可证已过期。已注册 Beats 代理将继续工作,但您需要有效的许可证,才能访问 Elastic Fleet 界面。", - "xpack.ingestManager.invalidLicenseTitle": "已过期许可证", - "xpack.ingestManager.listTabs.agentTitle": "代理", - "xpack.ingestManager.listTabs.enrollmentTokensTitle": "注册令牌", - "xpack.ingestManager.metadataForm.addButton": "+ 添加元数据", - "xpack.ingestManager.metadataForm.keyLabel": "键", - "xpack.ingestManager.metadataForm.submitButtonText": "添加", - "xpack.ingestManager.metadataForm.valueLabel": "值", - "xpack.ingestManager.namespaceValidation.invalidCharactersErrorMessage": "命名空间包含无效字符", - "xpack.ingestManager.namespaceValidation.lowercaseErrorMessage": "命名空间必须小写", - "xpack.ingestManager.namespaceValidation.requiredErrorMessage": "“命名空间”必填", - "xpack.ingestManager.namespaceValidation.tooLongErrorMessage": "命名空间不能超过 100 个字节", - "xpack.ingestManager.newEnrollmentKey.cancelButtonLabel": "取消", - "xpack.ingestManager.newEnrollmentKey.flyoutTitle": "创建注册令牌", - "xpack.ingestManager.newEnrollmentKey.keyCreatedToasts": "注册令牌已创建。", - "xpack.ingestManager.newEnrollmentKey.nameLabel": "名称", - "xpack.ingestManager.newEnrollmentKey.policyLabel": "策略", - "xpack.ingestManager.newEnrollmentKey.submitButton": "创建注册令牌", - "xpack.ingestManager.noAccess.accessDeniedDescription": "您无权访问 Elastic Fleet。要使用 Elastic Fleet,您需要包含此应用程序读取权限或所有权限的用户角色。", - "xpack.ingestManager.noAccess.accessDeniedTitle": "访问被拒绝", - "xpack.ingestManager.overviewAgentActiveTitle": "活动", - "xpack.ingestManager.overviewAgentErrorTitle": "错误", - "xpack.ingestManager.overviewAgentOfflineTitle": "脱机", - "xpack.ingestManager.overviewAgentTotalTitle": "代理总数", - "xpack.ingestManager.overviewDatastreamNamespacesTitle": "命名空间", - "xpack.ingestManager.overviewDatastreamSizeTitle": "总大小", - "xpack.ingestManager.overviewDatastreamTotalTitle": "数据流", - "xpack.ingestManager.overviewIntegrationsInstalledTitle": "安装时间", - "xpack.ingestManager.overviewIntegrationsTotalTitle": "可用总计", - "xpack.ingestManager.overviewIntegrationsUpdatesAvailableTitle": "可用更新", - "xpack.ingestManager.overviewPackagePolicyTitle": "已使用的集成", - "xpack.ingestManager.overviewPageAgentsPanelTitle": "代理", - "xpack.ingestManager.overviewPageDataStreamsPanelAction": "查看数据流", - "xpack.ingestManager.overviewPageDataStreamsPanelTitle": "数据流", - "xpack.ingestManager.overviewPageDataStreamsPanelTooltip": "您的代理收集的数据组织到各种数据流中。", - "xpack.ingestManager.overviewPageEnrollAgentButton": "添加代理", - "xpack.ingestManager.overviewPageFleetPanelAction": "查看代理", - "xpack.ingestManager.overviewPageFleetPanelTooltip": "使用 Fleet 注册代理并从中央位置管理其策略。", - "xpack.ingestManager.overviewPageIntegrationsPanelAction": "查看集成", - "xpack.ingestManager.overviewPageIntegrationsPanelTitle": "集成", - "xpack.ingestManager.overviewPageIntegrationsPanelTooltip": "浏览并安装适用于 Elastic Stack 的集成。将集成添加到您的代理策略,以开始发送数据。", - "xpack.ingestManager.overviewPagePoliciesPanelAction": "查看策略", - "xpack.ingestManager.overviewPagePoliciesPanelTitle": "代理策略", - "xpack.ingestManager.overviewPagePoliciesPanelTooltip": "使用代理策略控制您的代理收集的数据。", - "xpack.ingestManager.overviewPageSubtitle": "在集中位置管理 Elastic 代理及其策略。", - "xpack.ingestManager.overviewPageTitle": "Fleet", - "xpack.ingestManager.overviewPolicyTotalTitle": "可用总计", - "xpack.ingestManager.packagePolicyValidation.invalidArrayErrorMessage": "格式无效", - "xpack.ingestManager.packagePolicyValidation.invalidYamlFormatErrorMessage": "YAML 格式无效", - "xpack.ingestManager.packagePolicyValidation.nameRequiredErrorMessage": "“名称”必填", - "xpack.ingestManager.packagePolicyValidation.requiredErrorMessage": "“{fieldName}”必填", - "xpack.ingestManager.permissionDeniedErrorMessage": "您无权访问 Ingest Manager。Ingest Manager 需要{roleName}权限。", - "xpack.ingestManager.permissionDeniedErrorTitle": "权限被拒绝", - "xpack.ingestManager.permissionsRequestErrorMessageDescription": "检查 Ingest Manager 权限时出现问题", - "xpack.ingestManager.permissionsRequestErrorMessageTitle": "无法检查权限", - "xpack.ingestManager.policyDetails.addPackagePolicyButtonText": "添加集成", - "xpack.ingestManager.policyDetails.ErrorGettingFullAgentPolicy": "加载代理策略时出错", - "xpack.ingestManager.policyDetails.packagePoliciesTable.actionsColumnTitle": "操作", - "xpack.ingestManager.policyDetails.packagePoliciesTable.deleteActionTitle": "删除集成", - "xpack.ingestManager.policyDetails.packagePoliciesTable.descriptionColumnTitle": "描述", - "xpack.ingestManager.policyDetails.packagePoliciesTable.editActionTitle": "编辑集成", - "xpack.ingestManager.policyDetails.packagePoliciesTable.nameColumnTitle": "名称", - "xpack.ingestManager.policyDetails.packagePoliciesTable.namespaceColumnTitle": "命名空间", - "xpack.ingestManager.policyDetails.packagePoliciesTable.packageNameColumnTitle": "集成", - "xpack.ingestManager.policyDetails.policyDetailsTitle": "策略“{id}”", - "xpack.ingestManager.policyDetails.policyNotFoundErrorTitle": "找不到策略“{id}”", - "xpack.ingestManager.policyDetails.subTabs.packagePoliciesTabText": "集成", - "xpack.ingestManager.policyDetails.subTabs.settingsTabText": "设置", - "xpack.ingestManager.policyDetails.summary.integrations": "集成", - "xpack.ingestManager.policyDetails.summary.lastUpdated": "上次更新时间", - "xpack.ingestManager.policyDetails.summary.revision": "修订", - "xpack.ingestManager.policyDetails.summary.usedBy": "使用者", - "xpack.ingestManager.policyDetails.unexceptedErrorTitle": "加载代理策略时发生错误", - "xpack.ingestManager.policyDetails.viewAgentListTitle": "查看所有代理策略", - "xpack.ingestManager.policyDetails.yamlDownloadButtonLabel": "下载策略", - "xpack.ingestManager.policyDetails.yamlFlyoutCloseButtonLabel": "关闭", - "xpack.ingestManager.policyDetails.yamlflyoutTitleWithName": "代理策略“{name}”", - "xpack.ingestManager.policyDetails.yamlflyoutTitleWithoutName": "代理策略", - "xpack.ingestManager.policyDetailsPackagePolicies.createFirstButtonText": "添加集成", - "xpack.ingestManager.policyDetailsPackagePolicies.createFirstMessage": "此策略尚无任何集成。", - "xpack.ingestManager.policyDetailsPackagePolicies.createFirstTitle": "添加您的首个集成", - "xpack.ingestManager.policyForm.deletePolicyActionText": "删除策略", - "xpack.ingestManager.policyForm.deletePolicyGroupDescription": "现有数据将不会删除。", - "xpack.ingestManager.policyForm.deletePolicyGroupTitle": "删除策略", - "xpack.ingestManager.policyForm.generalSettingsGroupDescription": "为您的代理策略选择名称和描述。", - "xpack.ingestManager.policyForm.generalSettingsGroupTitle": "常规设置", - "xpack.ingestManager.policyForm.unableToDeleteDefaultPolicyText": "默认策略无法删除", - "xpack.ingestManager.securityRequiredErrorMessage": "必须在 Kibana 和 Elasticsearch 启用安全性,才能使用 Ingest Manager。", - "xpack.ingestManager.securityRequiredErrorTitle": "安全性未启用", - "xpack.ingestManager.settings.additionalYamlConfig": "Elasticsearch 输出配置", - "xpack.ingestManager.settings.autoUpgradeDisabledLabel": "手动管理代理二进制文件版本。需要黄金级订阅。", - "xpack.ingestManager.settings.autoUpgradeEnabledLabel": "自动更新代理二进制文件以使用最新的次要版本。", - "xpack.ingestManager.settings.autoUpgradeFieldLabel": "Elastic 代理二进制文件版本", - "xpack.ingestManager.settings.cancelButtonLabel": "取消", - "xpack.ingestManager.settings.elasticHostError": "URL 无效", - "xpack.ingestManager.settings.elasticsearchUrlLabel": "Elasticsearch URL", - "xpack.ingestManager.settings.flyoutTitle": "Ingest Manager 设置", - "xpack.ingestManager.settings.globalOutputDescription": "指定将数据发送到何处。这些设置将应用于所有的 Elastic 代理策略。", - "xpack.ingestManager.settings.globalOutputTitle": "全局输出", - "xpack.ingestManager.settings.integrationUpgradeDisabledFieldLabel": "自行手动管理集成版本。", - "xpack.ingestManager.settings.integrationUpgradeEnabledFieldLabel": "将集成自动更新到最新版本以获取最新资产。您可能需要更新代理策略以使用新功能。", - "xpack.ingestManager.settings.integrationUpgradeFieldLabel": "集成版本", - "xpack.ingestManager.settings.invalidYamlFormatErrorMessage": "YAML 无效:{reason}", - "xpack.ingestManager.settings.kibanaUrlDifferentPathOrProtocolError": "对于每个 URL,协议和路径必须相同", - "xpack.ingestManager.settings.kibanaUrlEmptyError": "至少需要一个 URL", - "xpack.ingestManager.settings.kibanaUrlError": "URL 无效", - "xpack.ingestManager.settings.kibanaUrlLabel": "Kibana URL", - "xpack.ingestManager.settings.saveButtonLabel": "保存设置", - "xpack.ingestManager.settings.success.message": "设置已保存", - "xpack.ingestManager.setupPage.apiKeyServiceLink": "API 密钥服务", - "xpack.ingestManager.setupPage.elasticsearchApiKeyFlagText": "{apiKeyLink}。将 {apiKeyFlag} 设置为 {true}。", - "xpack.ingestManager.setupPage.elasticsearchSecurityFlagText": "{esSecurityLink}。将 {securityFlag} 设置为 {true}。", - "xpack.ingestManager.setupPage.elasticsearchSecurityLink": "Elasticsearch 安全", - "xpack.ingestManager.setupPage.enableCentralManagement": "创建用户并启用集中管理", - "xpack.ingestManager.setupPage.enableText": "集中管理需要可以创建 API 密钥并写入到 logs-* 和 metrics-* 的 Elastic 用户。", - "xpack.ingestManager.setupPage.enableTitle": "对 Elastic 代理启用集中管理", - "xpack.ingestManager.setupPage.encryptionKeyFlagText": "{encryptionKeyLink}。将 {keyFlag} 设置为至少 32 个字符的字母数字值。", - "xpack.ingestManager.setupPage.gettingStartedLink": "入门", - "xpack.ingestManager.setupPage.gettingStartedText": "有关更多信息,请阅读我们的{link}指南。", - "xpack.ingestManager.setupPage.kibanaEncryptionLink": "Kibana 加密密钥", - "xpack.ingestManager.setupPage.kibanaSecurityLink": "Kibana 安全性", - "xpack.ingestManager.setupPage.missingRequirementsCalloutDescription": "要对 Elastic 代理使用集中管理,请启用下面的 Elasticsearch 和 Kibana 安全功能。", - "xpack.ingestManager.setupPage.missingRequirementsCalloutTitle": "缺失安全性要求", - "xpack.ingestManager.setupPage.missingRequirementsElasticsearchTitle": "在 Elasticsearch 策略中,启用:", - "xpack.ingestManager.setupPage.missingRequirementsKibanaTitle": "在 Kibana 策略中,启用:", - "xpack.ingestManager.setupPage.tlsFlagText": "{kibanaSecurityLink}。将 {securityFlag} 设置为 {true}。出于开发目的,作为非安全的备用方案可以通过将 {tlsFlag} 设置为 {true} 来禁用 {tlsLink}。", - "xpack.ingestManager.setupPage.tlsLink": "TLS", - "xpack.ingestManager.unenrollAgents.cancelButtonLabel": "取消", - "xpack.ingestManager.unenrollAgents.confirmMultipleButtonLabel": "取消注册 {count} 个代理", - "xpack.ingestManager.unenrollAgents.confirmSingleButtonLabel": "取消注册代理", - "xpack.ingestManager.unenrollAgents.deleteMultipleDescription": "此操作将从 Fleet 中移除多个代理,并防止采集新数据。将不会影响任何已由这些代理发送的数据。此操作无法撤消。", - "xpack.ingestManager.unenrollAgents.deleteSingleDescription": "此操作将从 Fleet 中移除“{hostName}”上运行的选定代理。由该代理发送的任何数据将不会被删除。此操作无法撤消。", - "xpack.ingestManager.unenrollAgents.deleteSingleTitle": "取消注册代理", - "xpack.ingestManager.unenrollAgents.fatalErrorNotificationTitle": "取消注册{count, plural, one {代理} other {代理}}时出错", - "xpack.ingestManager.unenrollAgents.forceDeleteMultipleTitle": "取消注册 {count} 个代理", - "xpack.ingestManager.unenrollAgents.forceUnenrollCheckboxLabel": "立即移除{count, plural, one {代理} other {代理}}。不用等待代理发送任何最终数据。", - "xpack.ingestManager.unenrollAgents.forceUnenrollLegendText": "强制取消注册{count, plural, one {代理} other {代理}}", - "xpack.ingestManager.unenrollAgents.successForceMultiNotificationTitle": "代理已取消注册", - "xpack.ingestManager.unenrollAgents.successForceSingleNotificationTitle": "代理已取消注册", - "xpack.ingestManager.unenrollAgents.successMultiNotificationTitle": "正在取消注册代理", - "xpack.ingestManager.unenrollAgents.successSingleNotificationTitle": "正在取消注册代理", - "xpack.ingestManager.upgradeAgents.cancelButtonLabel": "取消", - "xpack.ingestManager.upgradeAgents.confirmMultipleButtonLabel": "升级 {count} 个代理", - "xpack.ingestManager.upgradeAgents.confirmSingleButtonLabel": "升级代理", - "xpack.ingestManager.upgradeAgents.deleteMultipleTitle": "升级 {count} 个代理", - "xpack.ingestManager.upgradeAgents.deleteSingleTitle": "升级代理", - "xpack.ingestManager.upgradeAgents.fatalErrorNotificationTitle": "升级{count, plural, one {代理} other {代理}}时出错", - "xpack.ingestManager.upgradeAgents.successMultiNotificationTitle": "正在升级代理", - "xpack.ingestManager.upgradeAgents.successSingleNotificationTitle": "正在升级代理", - "xpack.ingestManager.upgradeAgents.upgradeMultipleDescription": "此操作会将多个代理升级到版本 {version}。此操作无法撤消。是否确定要继续?", - "xpack.ingestManager.upgradeAgents.upgradeSingleDescription": "此操作会将“{hostName}”上运行的选定代理升级到版本 {version}。此操作无法撤消。是否确定要继续?", "xpack.ingestPipelines.addProcesorFormOnFailureFlyout.cancelButtonLabel": "取消", "xpack.ingestPipelines.addProcessorFormOnFailureFlyout.addButtonLabel": "添加", "xpack.ingestPipelines.app.checkingPrivilegesDescription": "正在检查权限……", @@ -20277,7 +20276,6 @@ "xpack.triggersActionsUI.sections.actionsConnectorsList.unableToLoadActionTypesMessage": "无法加载操作类型", "xpack.triggersActionsUI.sections.addAction.webhookAction.error.requiredHeaderKeyText": "“键”必填。", "xpack.triggersActionsUI.sections.addAction.webhookAction.error.requiredHeaderValueText": "“值”必填。", - "xpack.triggersActionsUI.sections.addAction.webhookAction.error.requiredHostText": "“用户名”必填。", "xpack.triggersActionsUI.sections.addAction.webhookAction.error.requiredMethodText": "“方法”必填", "xpack.triggersActionsUI.sections.addAction.webhookAction.error.requiredPasswordText": "“密码”必填。", "xpack.triggersActionsUI.sections.addAlert.error.greaterThenThreshold0Text": "阈值 1 应 > 阈值 0。", diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/types.ts b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/types.ts index 958d77a11c883..e22cd268f9bc5 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/types.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/types.ts @@ -110,6 +110,7 @@ export interface WebhookConfig { method: string; url: string; headers: Record; + hasAuth: boolean; } export interface WebhookSecrets { diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/webhook/webhook.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/webhook/webhook.test.tsx index 337c1f0f18a93..e4d9d3f009c7e 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/webhook/webhook.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/webhook/webhook.test.tsx @@ -28,7 +28,7 @@ describe('actionTypeRegistry.get() works', () => { }); describe('webhook connector validation', () => { - test('connector validation succeeds when connector config is valid', () => { + test('connector validation succeeds when hasAuth is true and connector config is valid', () => { const actionConnector = { secrets: { user: 'user', @@ -42,6 +42,35 @@ describe('webhook connector validation', () => { method: 'PUT', url: 'http://test.com', headers: { 'content-type': 'text' }, + hasAuth: true, + }, + } as WebhookActionConnector; + + expect(actionTypeModel.validateConnector(actionConnector)).toEqual({ + errors: { + url: [], + method: [], + user: [], + password: [], + }, + }); + }); + + test('connector validation succeeds when hasAuth is false and connector config is valid', () => { + const actionConnector = { + secrets: { + user: '', + password: '', + }, + id: 'test', + actionTypeId: '.webhook', + name: 'webhook', + isPreconfigured: false, + config: { + method: 'PUT', + url: 'http://test.com', + headers: { 'content-type': 'text' }, + hasAuth: false, }, } as WebhookActionConnector; @@ -65,6 +94,7 @@ describe('webhook connector validation', () => { name: 'webhook', config: { method: 'PUT', + hasAuth: true, }, } as WebhookActionConnector; @@ -73,7 +103,7 @@ describe('webhook connector validation', () => { url: ['URL is required.'], method: [], user: [], - password: ['Password is required.'], + password: ['Password is required when username is used.'], }, }); }); @@ -90,6 +120,7 @@ describe('webhook connector validation', () => { config: { method: 'PUT', url: 'invalid.url', + hasAuth: true, }, } as WebhookActionConnector; diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/webhook/webhook.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/webhook/webhook.tsx index 04077738e6015..db3ba9b78cee6 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/webhook/webhook.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/webhook/webhook.tsx @@ -74,26 +74,46 @@ export function getActionType(): ActionTypeModel< ) ); } - if (!action.secrets.user && action.secrets.password) { + if (action.config.hasAuth && !action.secrets.user && !action.secrets.password) { errors.user.push( i18n.translate( - 'xpack.triggersActionsUI.sections.addAction.webhookAction.error.requiredHostText', + 'xpack.triggersActionsUI.sections.addAction.webhookAction.error.requiredAuthUserNameText', { defaultMessage: 'Username is required.', } ) ); } - if (!action.secrets.password && action.secrets.user) { + if (action.config.hasAuth && !action.secrets.user && !action.secrets.password) { errors.password.push( i18n.translate( - 'xpack.triggersActionsUI.sections.addAction.webhookAction.error.requiredPasswordText', + 'xpack.triggersActionsUI.sections.addAction.webhookAction.error.requiredAuthPasswordText', { defaultMessage: 'Password is required.', } ) ); } + if (action.secrets.user && !action.secrets.password) { + errors.password.push( + i18n.translate( + 'xpack.triggersActionsUI.sections.addAction.webhookAction.error.requiredPasswordText', + { + defaultMessage: 'Password is required when username is used.', + } + ) + ); + } + if (!action.secrets.user && action.secrets.password) { + errors.user.push( + i18n.translate( + 'xpack.triggersActionsUI.sections.addAction.webhookAction.error.requiredUserText', + { + defaultMessage: 'Username is required when password is used.', + } + ) + ); + } return validationResult; }, validateParams: (actionParams: WebhookActionParams): ValidationResult => { diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/webhook/webhook_connectors.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/webhook/webhook_connectors.test.tsx index 45e4c566f7a27..4c5e78670f0c4 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/webhook/webhook_connectors.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/webhook/webhook_connectors.test.tsx @@ -24,6 +24,7 @@ describe('WebhookActionConnectorFields renders', () => { method: 'PUT', url: 'http:\\test', headers: { 'content-type': 'text' }, + hasAuth: true, }, } as WebhookActionConnector; const wrapper = mountWithIntl( @@ -50,7 +51,9 @@ describe('WebhookActionConnectorFields renders', () => { secrets: {}, actionTypeId: '.webhook', isPreconfigured: false, - config: {}, + config: { + hasAuth: true, + }, } as WebhookActionConnector; const wrapper = mountWithIntl( { method: 'PUT', url: 'http:\\test', headers: { 'content-type': 'text' }, + hasAuth: true, }, } as WebhookActionConnector; const wrapper = mountWithIntl( diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/webhook/webhook_connectors.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/webhook/webhook_connectors.tsx index e4f5ef023a529..15d4c6c30450e 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/webhook/webhook_connectors.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/webhook/webhook_connectors.tsx @@ -3,7 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import React, { Fragment, useState } from 'react'; +import React, { Fragment, useEffect, useState } from 'react'; import { FormattedMessage } from '@kbn/i18n/react'; import { @@ -34,12 +34,19 @@ const WebhookActionConnectorFields: React.FunctionComponent> = ({ action, editActionConfig, editActionSecrets, errors, readOnly }) => { const { user, password } = action.secrets; - const { method, url, headers } = action.config; + const { method, url, headers, hasAuth } = action.config; const [httpHeaderKey, setHttpHeaderKey] = useState(''); const [httpHeaderValue, setHttpHeaderValue] = useState(''); const [hasHeaders, setHasHeaders] = useState(false); + useEffect(() => { + if (!action.id) { + editActionConfig('hasAuth', true); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + if (!method) { editActionConfig('method', 'post'); // set method to POST by default } @@ -268,9 +275,9 @@ const WebhookActionConnectorFields: React.FunctionComponent - +

    -
    -
    - - - - {getEncryptedFieldNotifyLabel(!action.id)} - - - - - - 0 && user !== undefined} + + - 0 && user !== undefined} - name="user" - readOnly={readOnly} - value={user || ''} - data-test-subj="webhookUserInput" - onChange={(e) => { - editActionSecrets('user', e.target.value); - }} - onBlur={() => { - if (!user) { - editActionSecrets('user', ''); - } - }} - /> - - - - 0 && password !== undefined} - label={i18n.translate( - 'xpack.triggersActionsUI.components.builtinActionTypes.webhookAction.passwordTextFieldLabel', - { - defaultMessage: 'Password', + disabled={readOnly} + checked={hasAuth} + onChange={(e) => { + editActionConfig('hasAuth', e.target.checked); + if (!e.target.checked) { + editActionSecrets('user', null); + editActionSecrets('password', null); } - )} - > - 0 && password !== undefined} - value={password || ''} - data-test-subj="webhookPasswordInput" - onChange={(e) => { - editActionSecrets('password', e.target.value); - }} - onBlur={() => { - if (!password) { - editActionSecrets('password', ''); - } - }} - /> - + }} + /> - + {hasAuth ? ( + <> + {getEncryptedFieldNotifyLabel(!action.id)} + + + 0 && user !== undefined} + label={i18n.translate( + 'xpack.triggersActionsUI.components.builtinActionTypes.webhookAction.userTextFieldLabel', + { + defaultMessage: 'Username', + } + )} + > + 0 && user !== undefined} + name="user" + readOnly={readOnly} + value={user || ''} + data-test-subj="webhookUserInput" + onChange={(e) => { + editActionSecrets('user', e.target.value); + }} + onBlur={() => { + if (!user) { + editActionSecrets('user', ''); + } + }} + /> + + + + 0 && password !== undefined} + label={i18n.translate( + 'xpack.triggersActionsUI.components.builtinActionTypes.webhookAction.passwordTextFieldLabel', + { + defaultMessage: 'Password', + } + )} + > + 0 && password !== undefined} + value={password || ''} + data-test-subj="webhookPasswordInput" + onChange={(e) => { + editActionSecrets('password', e.target.value); + }} + onBlur={() => { + if (!password) { + editActionSecrets('password', ''); + } + }} + /> + + + + + ) : null} - - + + + + + + + ); } return ( - + + + + + ); } diff --git a/x-pack/plugins/triggers_actions_ui/public/types.ts b/x-pack/plugins/triggers_actions_ui/public/types.ts index 148facdee248d..f24a9a2e3b658 100644 --- a/x-pack/plugins/triggers_actions_ui/public/types.ts +++ b/x-pack/plugins/triggers_actions_ui/public/types.ts @@ -3,7 +3,8 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import { HttpSetup, DocLinksStart, ToastsSetup } from 'kibana/public'; +import type { PublicMethodsOf } from '@kbn/utility-types'; +import type { HttpSetup, DocLinksStart, ToastsSetup } from 'kibana/public'; import { ComponentType } from 'react'; import { ActionGroup } from '../../alerts/common'; import { ActionType } from '../../actions/common'; diff --git a/x-pack/plugins/ui_actions_enhanced/public/drilldowns/components/connected_flyout_manage_drilldowns/test_data.ts b/x-pack/plugins/ui_actions_enhanced/public/drilldowns/components/connected_flyout_manage_drilldowns/test_data.ts index 78eec05eb2d0b..06f63949f6d63 100644 --- a/x-pack/plugins/ui_actions_enhanced/public/drilldowns/components/connected_flyout_manage_drilldowns/test_data.ts +++ b/x-pack/plugins/ui_actions_enhanced/public/drilldowns/components/connected_flyout_manage_drilldowns/test_data.ts @@ -5,6 +5,7 @@ */ import uuid from 'uuid'; +import type { PublicMethodsOf } from '@kbn/utility-types'; import { UiActionsEnhancedDynamicActionManager as DynamicActionManager, UiActionsEnhancedDynamicActionManagerState as DynamicActionManagerState, diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/webhook.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/webhook.ts index ef14dd9ec2eff..64d9711730c7b 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/webhook.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/webhook.ts @@ -20,6 +20,7 @@ import { const defaultValues: Record = { headers: null, method: 'post', + hasAuth: true, }; function parsePort(url: Record): Record { diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/actions/migrations.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/actions/migrations.ts index 5992bb54c81fd..d46d60905da1c 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/actions/migrations.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/actions/migrations.ts @@ -55,5 +55,22 @@ export default function createGetTests({ getService }: FtrProviderContext) { projectKey: 'CK', }); }); + + it('7.11.0 migrates webhook connector configurations to have `hasAuth` property', async () => { + const responseWithAuth = await supertest.get( + `${getUrlPrefix(``)}/api/actions/action/949f909b-20a0-46e3-aadb-6a4d117bb592` + ); + + expect(responseWithAuth.status).to.eql(200); + expect(responseWithAuth.body.config).key('hasAuth'); + expect(responseWithAuth.body.config.hasAuth).to.eql(true); + + const responseNoAuth = await supertest.get( + `${getUrlPrefix(``)}/api/actions/action/7434121e-045a-47d6-a0a6-0b6da752397a` + ); + expect(responseNoAuth.status).to.eql(200); + expect(responseNoAuth.body.config).key('hasAuth'); + expect(responseNoAuth.body.config.hasAuth).to.eql(false); + }); }); } diff --git a/x-pack/test/api_integration/apis/maps/proxy_api.js b/x-pack/test/api_integration/apis/maps/proxy_api.js index f85de9dc1670a..5dc6b372ced70 100644 --- a/x-pack/test/api_integration/apis/maps/proxy_api.js +++ b/x-pack/test/api_integration/apis/maps/proxy_api.js @@ -21,7 +21,7 @@ export default function ({ getService }) { //Check world-layer const worldLayer = resp.body.layers.find((layer) => layer.layer_id === 'world_countries'); expect(worldLayer.formats.length).to.be.greaterThan(0); - expect(worldLayer.formats[0].type).to.be('geojson'); + expect(worldLayer.formats[0].type).to.be('topojson'); expect(worldLayer.formats[0].url).to.be('file?id=world_countries'); }); }); diff --git a/x-pack/test/api_integration/apis/metrics_ui/log_item.ts b/x-pack/test/api_integration/apis/metrics_ui/log_item.ts index 6e0148f13277c..3bb7a9a76690d 100644 --- a/x-pack/test/api_integration/apis/metrics_ui/log_item.ts +++ b/x-pack/test/api_integration/apis/metrics_ui/log_item.ts @@ -44,107 +44,107 @@ export default function ({ getService }: FtrProviderContext) { expect(logItem.fields).to.eql([ { field: '@timestamp', - value: '2018-10-17T19:42:22.000Z', + value: ['2018-10-17T19:42:22.000Z'], }, { field: '_id', - value: 'yT2Mg2YBh-opCxJv8Vqj', + value: ['yT2Mg2YBh-opCxJv8Vqj'], }, { field: '_index', - value: 'filebeat-7.0.0-alpha1-2018.10.17', + value: ['filebeat-7.0.0-alpha1-2018.10.17'], }, { field: 'apache2.access.body_sent.bytes', - value: '1336', + value: ['1336'], }, { field: 'apache2.access.http_version', - value: '1.1', + value: ['1.1'], }, { field: 'apache2.access.method', - value: 'GET', + value: ['GET'], }, { field: 'apache2.access.referrer', - value: '-', + value: ['-'], }, { field: 'apache2.access.remote_ip', - value: '10.128.0.11', + value: ['10.128.0.11'], }, { field: 'apache2.access.response_code', - value: '200', + value: ['200'], }, { field: 'apache2.access.url', - value: '/a-fresh-start-will-put-you-on-your-way', + value: ['/a-fresh-start-will-put-you-on-your-way'], }, { field: 'apache2.access.user_agent.device', - value: 'Other', + value: ['Other'], }, { field: 'apache2.access.user_agent.name', - value: 'Other', + value: ['Other'], }, { field: 'apache2.access.user_agent.os', - value: 'Other', + value: ['Other'], }, { field: 'apache2.access.user_agent.os_name', - value: 'Other', + value: ['Other'], }, { field: 'apache2.access.user_name', - value: '-', + value: ['-'], }, { field: 'beat.hostname', - value: 'demo-stack-apache-01', + value: ['demo-stack-apache-01'], }, { field: 'beat.name', - value: 'demo-stack-apache-01', + value: ['demo-stack-apache-01'], }, { field: 'beat.version', - value: '7.0.0-alpha1', + value: ['7.0.0-alpha1'], }, { field: 'fileset.module', - value: 'apache2', + value: ['apache2'], }, { field: 'fileset.name', - value: 'access', + value: ['access'], }, { field: 'host.name', - value: 'demo-stack-apache-01', + value: ['demo-stack-apache-01'], }, { field: 'input.type', - value: 'log', + value: ['log'], }, { field: 'offset', - value: '5497614', + value: ['5497614'], }, { field: 'prospector.type', - value: 'log', + value: ['log'], }, { field: 'read_timestamp', - value: '2018-10-17T19:42:23.160Z', + value: ['2018-10-17T19:42:23.160Z'], }, { field: 'source', - value: '/var/log/apache2/access.log', + value: ['/var/log/apache2/access.log'], }, ]); }); diff --git a/x-pack/test/functional/apps/spaces/copy_saved_objects.ts b/x-pack/test/functional/apps/spaces/copy_saved_objects.ts index 2ee6b903cc3a9..8f29ae6a27c3a 100644 --- a/x-pack/test/functional/apps/spaces/copy_saved_objects.ts +++ b/x-pack/test/functional/apps/spaces/copy_saved_objects.ts @@ -115,5 +115,33 @@ export default function spaceSelectorFunctonalTests({ await PageObjects.copySavedObjectsToSpace.finishCopy(); }); + + it('allows a dashboard to be copied to the marketing space, with circular references', async () => { + const destinationSpaceId = 'marketing'; + + await PageObjects.copySavedObjectsToSpace.openCopyToSpaceFlyoutForObject('Dashboard Foo'); + + await PageObjects.copySavedObjectsToSpace.setupForm({ + overwrite: true, + destinationSpaceId, + }); + + await PageObjects.copySavedObjectsToSpace.startCopy(); + + // Wait for successful copy + await testSubjects.waitForDeleted(`cts-summary-indicator-loading-${destinationSpaceId}`); + await testSubjects.existOrFail(`cts-summary-indicator-success-${destinationSpaceId}`); + + const summaryCounts = await PageObjects.copySavedObjectsToSpace.getSummaryCounts(); + + expect(summaryCounts).to.eql({ + success: 2, + pending: 0, + skipped: 0, + errors: 0, + }); + + await PageObjects.copySavedObjectsToSpace.finishCopy(); + }); }); } diff --git a/x-pack/test/functional/es_archives/actions/data.json b/x-pack/test/functional/es_archives/actions/data.json index aeeca87deb9ff..18d67da1752bc 100644 --- a/x-pack/test/functional/es_archives/actions/data.json +++ b/x-pack/test/functional/es_archives/actions/data.json @@ -56,3 +56,57 @@ "type": "_doc" } } + +{ + "type": "doc", + "value": { + "id": "action:949f909b-20a0-46e3-aadb-6a4d117bb592", + "index": ".kibana_1", + "source": { + "action": { + "actionTypeId": ".webhook", + "config": { + "headers": null, + "method": "post", + "url": "http://localhost" + }, + "name": "A webhook with auth", + "secrets": "LUqlrITACjqPmcWGlbl+H4RsGGOlw8LM0Urq8r7y6jNT7Igv3J7FjKJ2NXfNTaghVBO7e9x3wZOtiycwyoAdviTyYm1pspni24vH+OT70xaSuXcDoxfGwiLEcaG04INDnUJX4dtmRerxqR9ChktC70LNtOU3sqjYI2tWt2vOqGeq" + }, + "migrationVersion": { + "action": "7.10.0" + }, + "references": [ + ], + "type": "action", + "updated_at": "2020-10-26T21:29:47.380Z" + } + } +} + +{ + "type": "doc", + "value": { + "id": "action:7434121e-045a-47d6-a0a6-0b6da752397a", + "index": ".kibana_1", + "source": { + "action": { + "actionTypeId": ".webhook", + "config": { + "headers": null, + "method": "post", + "url": "http://localhost" + }, + "name": "A webhook with no auth", + "secrets": "tOwFq20hbUrcp3FX7stKB5aJaQQdLNQwomSNym8BgnFaBBafPOASv5T0tGdGsTr/CA7VK+N/wYBHQPzt0apF8Z/UYl63ZXqck5tSoFDnQW77zv1VVQ5wEwN1qkAQQcfrXTXU2wYVAYZNSuHkbeRjcasfG0ty1K+J7A==" + }, + "migrationVersion": { + "action": "7.10.0" + }, + "references": [ + ], + "type": "action", + "updated_at": "2020-10-26T21:30:35.146Z" + } + } +} diff --git a/x-pack/test/functional/es_archives/spaces/copy_saved_objects/data.json b/x-pack/test/functional/es_archives/spaces/copy_saved_objects/data.json index 944b91e8be114..3434e1f80a7ce 100644 --- a/x-pack/test/functional/es_archives/spaces/copy_saved_objects/data.json +++ b/x-pack/test/functional/es_archives/spaces/copy_saved_objects/data.json @@ -109,3 +109,63 @@ } } } + +{ + "type": "doc", + "value": { + "index": ".kibana", + "type": "doc", + "id": "dashboard:dashboard-foo", + "source": { + "references": [{ + "id":"dashboard-bar", + "name":"dashboard-circular-ref", + "type":"dashboard" + }], + "dashboard": { + "title": "Dashboard Foo", + "hits": 0, + "description": "", + "panelsJSON": "[{}]", + "optionsJSON": "{}", + "version": 1, + "timeRestore": false, + "kibanaSavedObjectMeta": { + "searchSourceJSON": "{\"query\":{\"query\":\"\",\"language\":\"lucene\"},\"filter\":[]}" + } + }, + "type": "dashboard", + "updated_at": "2019-01-22T19:32:47.232Z" + } + } +} + +{ + "type": "doc", + "value": { + "index": ".kibana", + "type": "doc", + "id": "dashboard:dashboard-bar", + "source": { + "references": [{ + "id":"dashboard-foo", + "name":"dashboard-circular-ref", + "type":"dashboard" + }], + "dashboard": { + "title": "Dashboard Bar", + "hits": 0, + "description": "", + "panelsJSON": "[{}]", + "optionsJSON": "{}", + "version": 1, + "timeRestore": false, + "kibanaSavedObjectMeta": { + "searchSourceJSON": "{\"query\":{\"query\":\"\",\"language\":\"lucene\"},\"filter\":[]}" + } + }, + "type": "dashboard", + "updated_at": "2019-01-22T19:32:47.232Z" + } + } +} diff --git a/x-pack/test/ingest_manager_api_integration/apis/epm/data_stream.ts b/x-pack/test/ingest_manager_api_integration/apis/epm/data_stream.ts index d1d909f773a2b..3dbfdfb45008f 100644 --- a/x-pack/test/ingest_manager_api_integration/apis/epm/data_stream.ts +++ b/x-pack/test/ingest_manager_api_integration/apis/epm/data_stream.ts @@ -65,7 +65,7 @@ export default function (providerContext: FtrProviderContext) { }); }); afterEach(async () => { - if (!server) return; + if (!server.enabled) return; await es.transport.request({ method: 'DELETE', path: `/_data_stream/${logsTemplateName}-default`, diff --git a/x-pack/test/ingest_manager_api_integration/apis/epm/package_install_complete.ts b/x-pack/test/ingest_manager_api_integration/apis/epm/package_install_complete.ts index 6fd4b64f0ee5e..2e7ab199a7fbc 100644 --- a/x-pack/test/ingest_manager_api_integration/apis/epm/package_install_complete.ts +++ b/x-pack/test/ingest_manager_api_integration/apis/epm/package_install_complete.ts @@ -16,6 +16,8 @@ export default function (providerContext: FtrProviderContext) { const { getService } = providerContext; const supertest = getService('supertest'); const kibanaServer = getService('kibanaServer'); + const dockerServers = getService('dockerServers'); + const server = dockerServers.get('registry'); const pkgName = 'multiple_versions'; const pkgVersion = '0.1.0'; const pkgUpdateVersion = '0.2.0'; @@ -23,6 +25,7 @@ export default function (providerContext: FtrProviderContext) { skipIfNoDockerRegistry(providerContext); describe('package install', async () => { before(async () => { + if (!server.enabled) return; await supertest .post(`/api/fleet/epm/packages/${pkgName}-0.1.0`) .set('kbn-xsrf', 'xxxx') @@ -84,6 +87,7 @@ export default function (providerContext: FtrProviderContext) { expect(packageAfterSetup.attributes.install_status).equal('installing'); }); after(async () => { + if (!server.enabled) return; await supertest .delete(`/api/fleet/epm/packages/multiple_versions-0.1.0`) .set('kbn-xsrf', 'xxxx') @@ -92,6 +96,7 @@ export default function (providerContext: FtrProviderContext) { }); describe('package update', async () => { before(async () => { + if (!server.enabled) return; await supertest .post(`/api/fleet/epm/packages/${pkgName}-0.1.0`) .set('kbn-xsrf', 'xxxx') @@ -164,6 +169,7 @@ export default function (providerContext: FtrProviderContext) { expect(packageAfterSetup.attributes.version).equal(pkgVersion); }); after(async () => { + if (!server.enabled) return; await supertest .delete(`/api/fleet/epm/packages/multiple_versions-0.1.0`) .set('kbn-xsrf', 'xxxx') diff --git a/x-pack/test/plugin_api_integration/test_suites/task_manager/task_management.ts b/x-pack/test/plugin_api_integration/test_suites/task_manager/task_management.ts index 1fd313c1ac437..348ff35b2968f 100644 --- a/x-pack/test/plugin_api_integration/test_suites/task_manager/task_management.ts +++ b/x-pack/test/plugin_api_integration/test_suites/task_manager/task_management.ts @@ -57,7 +57,8 @@ export default function ({ getService }: FtrProviderContext) { const testHistoryIndex = '.kibana_task_manager_test_result'; const supertest = supertestAsPromised(url.format(config.get('servers.kibana'))); - describe('scheduling and running tasks', () => { + // Failing: See https://github.com/elastic/kibana/issues/81853 + describe.skip('scheduling and running tasks', () => { beforeEach( async () => await supertest.delete('/api/sample_tasks').set('kbn-xsrf', 'xxx').expect(200) ); diff --git a/x-pack/test/stack_functional_integration/test/functional/apps/ccs/ccs.js b/x-pack/test/stack_functional_integration/apps/ccs/ccs.js similarity index 100% rename from x-pack/test/stack_functional_integration/test/functional/apps/ccs/ccs.js rename to x-pack/test/stack_functional_integration/apps/ccs/ccs.js diff --git a/x-pack/test/stack_functional_integration/test/functional/apps/ccs/index.js b/x-pack/test/stack_functional_integration/apps/ccs/index.js similarity index 100% rename from x-pack/test/stack_functional_integration/test/functional/apps/ccs/index.js rename to x-pack/test/stack_functional_integration/apps/ccs/index.js diff --git a/x-pack/test/stack_functional_integration/test/functional/apps/filebeat/filebeat.js b/x-pack/test/stack_functional_integration/apps/filebeat/filebeat.js similarity index 100% rename from x-pack/test/stack_functional_integration/test/functional/apps/filebeat/filebeat.js rename to x-pack/test/stack_functional_integration/apps/filebeat/filebeat.js diff --git a/x-pack/test/stack_functional_integration/test/functional/apps/filebeat/index.js b/x-pack/test/stack_functional_integration/apps/filebeat/index.js similarity index 100% rename from x-pack/test/stack_functional_integration/test/functional/apps/filebeat/index.js rename to x-pack/test/stack_functional_integration/apps/filebeat/index.js diff --git a/x-pack/test/stack_functional_integration/test/functional/apps/heartbeat/_heartbeat.js b/x-pack/test/stack_functional_integration/apps/heartbeat/_heartbeat.js similarity index 100% rename from x-pack/test/stack_functional_integration/test/functional/apps/heartbeat/_heartbeat.js rename to x-pack/test/stack_functional_integration/apps/heartbeat/_heartbeat.js diff --git a/x-pack/test/stack_functional_integration/test/functional/apps/heartbeat/index.js b/x-pack/test/stack_functional_integration/apps/heartbeat/index.js similarity index 100% rename from x-pack/test/stack_functional_integration/test/functional/apps/heartbeat/index.js rename to x-pack/test/stack_functional_integration/apps/heartbeat/index.js diff --git a/x-pack/test/stack_functional_integration/test/functional/apps/management/_index_pattern_create.js b/x-pack/test/stack_functional_integration/apps/management/_index_pattern_create.js similarity index 100% rename from x-pack/test/stack_functional_integration/test/functional/apps/management/_index_pattern_create.js rename to x-pack/test/stack_functional_integration/apps/management/_index_pattern_create.js diff --git a/x-pack/test/stack_functional_integration/test/functional/apps/management/index.js b/x-pack/test/stack_functional_integration/apps/management/index.js similarity index 100% rename from x-pack/test/stack_functional_integration/test/functional/apps/management/index.js rename to x-pack/test/stack_functional_integration/apps/management/index.js diff --git a/x-pack/test/stack_functional_integration/test/functional/apps/metricbeat/_metricbeat.js b/x-pack/test/stack_functional_integration/apps/metricbeat/_metricbeat.js similarity index 100% rename from x-pack/test/stack_functional_integration/test/functional/apps/metricbeat/_metricbeat.js rename to x-pack/test/stack_functional_integration/apps/metricbeat/_metricbeat.js diff --git a/x-pack/test/stack_functional_integration/apps/metricbeat/_metricbeat_dashboard.js b/x-pack/test/stack_functional_integration/apps/metricbeat/_metricbeat_dashboard.js new file mode 100644 index 0000000000000..42f707fb77854 --- /dev/null +++ b/x-pack/test/stack_functional_integration/apps/metricbeat/_metricbeat_dashboard.js @@ -0,0 +1,59 @@ +/* + * 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 expect from '@kbn/expect'; +import { REPO_ROOT } from '@kbn/dev-utils'; + +export default function ({ getService, getPageObjects, updateBaselines }) { + const screenshot = getService('screenshots'); + const browser = getService('browser'); + const esArchiver = getService('esArchiver'); + const PageObjects = getPageObjects(['common', 'dashboard', 'timePicker']); + + describe('check metricbeat Dashboard', function () { + before(async function () { + await esArchiver.load(`${REPO_ROOT}/../integration-test/test/es_archives/metricbeat`); + + // this navigateToActualURL takes the place of navigating to the dashboard landing page, + // filtering on the dashboard name, selecting it, setting the timepicker, and going to full screen + await PageObjects.common.navigateToActualUrl( + 'dashboard', + 'view/Metricbeat-system-overview-ecs?_g=(filters:!(),refreshInterval:(pause:!t,value:0),' + + 'time:(from:%272020-09-29T19:02:37.902Z%27,to:%272020-09-29T19:06:43.218Z%27))&_a=' + + '(description:%27Overview%20of%20system%20metrics%27,filters:!(),fullScreenMode:!t,' + + 'options:(darkTheme:!f),query:(language:kuery,query:%27%27),timeRestore:!f,' + + 'title:%27%5BMetricbeat%20System%5D%20Overview%20ECS%27,viewMode:view)', + { + ensureCurrentUrl: false, + shouldLoginIfPrompted: true, + } + ); + // await PageObjects.common.navigateToApp('dashboard', { insertTimestamp: false }); + // await PageObjects.dashboard.loadSavedDashboard('[Metricbeat System] Overview ECS'); + // await PageObjects.timePicker.setAbsoluteRange( + // 'Sep 29, 2020 @ 14:02:37.902', + // 'Sep 29, 2020 @ 14:06:43.218' + // ); + // await PageObjects.dashboard.clickFullScreenMode(); + + await PageObjects.common.sleep(2000); + await PageObjects.dashboard.waitForRenderComplete(); + await browser.setScreenshotSize(1000, 1000); + }); + + it('[Metricbeat System] Overview ECS should match snapshot', async function () { + try { + const percentDifference = await screenshot.compareAgainstBaseline( + 'metricbeat_dashboard', + updateBaselines + ); + expect(percentDifference).to.be.lessThan(0.01); + } finally { + await PageObjects.dashboard.clickExitFullScreenLogoButton(); + } + }); + }); +} diff --git a/x-pack/test/stack_functional_integration/test/functional/apps/metricbeat/index.js b/x-pack/test/stack_functional_integration/apps/metricbeat/index.js similarity index 86% rename from x-pack/test/stack_functional_integration/test/functional/apps/metricbeat/index.js rename to x-pack/test/stack_functional_integration/apps/metricbeat/index.js index d45d6c835a315..148762c6a8b77 100644 --- a/x-pack/test/stack_functional_integration/test/functional/apps/metricbeat/index.js +++ b/x-pack/test/stack_functional_integration/apps/metricbeat/index.js @@ -7,5 +7,6 @@ export default function ({ loadTestFile }) { describe('metricbeat app', function () { loadTestFile(require.resolve('./_metricbeat')); + loadTestFile(require.resolve('./_metricbeat_dashboard')); }); } diff --git a/x-pack/test/stack_functional_integration/test/functional/apps/monitoring/_monitoring.js b/x-pack/test/stack_functional_integration/apps/monitoring/_monitoring.js similarity index 100% rename from x-pack/test/stack_functional_integration/test/functional/apps/monitoring/_monitoring.js rename to x-pack/test/stack_functional_integration/apps/monitoring/_monitoring.js diff --git a/x-pack/test/stack_functional_integration/test/functional/apps/monitoring/_monitoring_metricbeat.js b/x-pack/test/stack_functional_integration/apps/monitoring/_monitoring_metricbeat.js similarity index 100% rename from x-pack/test/stack_functional_integration/test/functional/apps/monitoring/_monitoring_metricbeat.js rename to x-pack/test/stack_functional_integration/apps/monitoring/_monitoring_metricbeat.js diff --git a/x-pack/test/stack_functional_integration/test/functional/apps/monitoring/index.js b/x-pack/test/stack_functional_integration/apps/monitoring/index.js similarity index 100% rename from x-pack/test/stack_functional_integration/test/functional/apps/monitoring/index.js rename to x-pack/test/stack_functional_integration/apps/monitoring/index.js diff --git a/x-pack/test/stack_functional_integration/test/functional/apps/packetbeat/_packetbeat.js b/x-pack/test/stack_functional_integration/apps/packetbeat/_packetbeat.js similarity index 100% rename from x-pack/test/stack_functional_integration/test/functional/apps/packetbeat/_packetbeat.js rename to x-pack/test/stack_functional_integration/apps/packetbeat/_packetbeat.js diff --git a/x-pack/test/stack_functional_integration/test/functional/apps/packetbeat/index.js b/x-pack/test/stack_functional_integration/apps/packetbeat/index.js similarity index 100% rename from x-pack/test/stack_functional_integration/test/functional/apps/packetbeat/index.js rename to x-pack/test/stack_functional_integration/apps/packetbeat/index.js diff --git a/x-pack/test/stack_functional_integration/test/functional/apps/reporting/index.js b/x-pack/test/stack_functional_integration/apps/reporting/index.js similarity index 100% rename from x-pack/test/stack_functional_integration/test/functional/apps/reporting/index.js rename to x-pack/test/stack_functional_integration/apps/reporting/index.js diff --git a/x-pack/test/stack_functional_integration/test/functional/apps/reporting/reporting_watcher.js b/x-pack/test/stack_functional_integration/apps/reporting/reporting_watcher.js similarity index 100% rename from x-pack/test/stack_functional_integration/test/functional/apps/reporting/reporting_watcher.js rename to x-pack/test/stack_functional_integration/apps/reporting/reporting_watcher.js diff --git a/x-pack/test/stack_functional_integration/test/functional/apps/reporting/reporting_watcher_png.js b/x-pack/test/stack_functional_integration/apps/reporting/reporting_watcher_png.js similarity index 100% rename from x-pack/test/stack_functional_integration/test/functional/apps/reporting/reporting_watcher_png.js rename to x-pack/test/stack_functional_integration/apps/reporting/reporting_watcher_png.js diff --git a/x-pack/test/stack_functional_integration/test/functional/apps/reporting/util.js b/x-pack/test/stack_functional_integration/apps/reporting/util.js similarity index 100% rename from x-pack/test/stack_functional_integration/test/functional/apps/reporting/util.js rename to x-pack/test/stack_functional_integration/apps/reporting/util.js diff --git a/x-pack/test/stack_functional_integration/test/functional/apps/sample_data/e_commerce.js b/x-pack/test/stack_functional_integration/apps/sample_data/e_commerce.js similarity index 100% rename from x-pack/test/stack_functional_integration/test/functional/apps/sample_data/e_commerce.js rename to x-pack/test/stack_functional_integration/apps/sample_data/e_commerce.js diff --git a/x-pack/test/stack_functional_integration/test/functional/apps/sample_data/index.js b/x-pack/test/stack_functional_integration/apps/sample_data/index.js similarity index 100% rename from x-pack/test/stack_functional_integration/test/functional/apps/sample_data/index.js rename to x-pack/test/stack_functional_integration/apps/sample_data/index.js diff --git a/x-pack/test/stack_functional_integration/test/functional/apps/telemetry/_telemetry.js b/x-pack/test/stack_functional_integration/apps/telemetry/_telemetry.js similarity index 100% rename from x-pack/test/stack_functional_integration/test/functional/apps/telemetry/_telemetry.js rename to x-pack/test/stack_functional_integration/apps/telemetry/_telemetry.js diff --git a/x-pack/test/stack_functional_integration/test/functional/apps/telemetry/index.js b/x-pack/test/stack_functional_integration/apps/telemetry/index.js similarity index 100% rename from x-pack/test/stack_functional_integration/test/functional/apps/telemetry/index.js rename to x-pack/test/stack_functional_integration/apps/telemetry/index.js diff --git a/x-pack/test/stack_functional_integration/test/functional/apps/winlogbeat/_winlogbeat.js b/x-pack/test/stack_functional_integration/apps/winlogbeat/_winlogbeat.js similarity index 100% rename from x-pack/test/stack_functional_integration/test/functional/apps/winlogbeat/_winlogbeat.js rename to x-pack/test/stack_functional_integration/apps/winlogbeat/_winlogbeat.js diff --git a/x-pack/test/stack_functional_integration/test/functional/apps/winlogbeat/index.js b/x-pack/test/stack_functional_integration/apps/winlogbeat/index.js similarity index 100% rename from x-pack/test/stack_functional_integration/test/functional/apps/winlogbeat/index.js rename to x-pack/test/stack_functional_integration/apps/winlogbeat/index.js diff --git a/x-pack/test/stack_functional_integration/configs/config.stack_functional_integration_base.js b/x-pack/test/stack_functional_integration/configs/config.stack_functional_integration_base.js index 96d338a04b01b..a838b129242a1 100644 --- a/x-pack/test/stack_functional_integration/configs/config.stack_functional_integration_base.js +++ b/x-pack/test/stack_functional_integration/configs/config.stack_functional_integration_base.js @@ -6,12 +6,12 @@ import { resolve } from 'path'; import buildState from './build_state'; -import { ToolingLog } from '@kbn/dev-utils'; +import { ToolingLog, REPO_ROOT } from '@kbn/dev-utils'; import chalk from 'chalk'; import { esTestConfig, kbnTestConfig } from '@kbn/test'; const reportName = 'Stack Functional Integration Tests'; -const testsFolder = '../test/functional/apps'; +const testsFolder = '../apps'; const log = new ToolingLog({ level: 'info', writeTo: process.stdout, @@ -19,13 +19,14 @@ const log = new ToolingLog({ log.info(`WORKSPACE in config file ${process.env.WORKSPACE}`); const stateFilePath = process.env.WORKSPACE ? `${process.env.WORKSPACE}/qa/envvars.sh` - : '../../../../../integration-test/qa/envvars.sh'; + : `${REPO_ROOT}/../integration-test/qa/envvars.sh`; const prepend = (testFile) => require.resolve(`${testsFolder}/${testFile}`); export default async ({ readConfigFile }) => { const defaultConfigs = await readConfigFile(require.resolve('../../functional/config')); const { tests, ...provisionedConfigs } = buildState(resolve(__dirname, stateFilePath)); + process.env.stack_functional_integration = true; const servers = { kibana: kbnTestConfig.getUrlParts(), @@ -43,6 +44,14 @@ export default async ({ readConfigFile }) => { // If we need to do things like disable animations, we can do it in configure_start_kibana.sh, in the provisioner...which lives in the integration-test private repo uiSettings: {}, security: { disableTestUser: true }, + // choose where screenshots should be saved + screenshots: { + directory: resolve(`${REPO_ROOT}/../integration-test`, 'test/screenshots'), + }, + // choose where esArchiver should load archives from + esArchiver: { + directory: resolve(`${REPO_ROOT}/../integration-test`, 'test/es_archives'), + }, }; return settings; }; @@ -55,7 +64,7 @@ function truncate(testPath) { return dropKibanaPath(testPath); } function highLight(testPath) { - const dropTestsPath = splitRight(/^.+test[\\/]functional[\\/]apps[\\/](.*)[\\/]/gm); + const dropTestsPath = splitRight(/^.+apps[\\/](.*)[\\/]/gm); const cleaned = dropTestsPath(testPath); const colored = chalk.greenBright.bold(cleaned); return testPath.replace(cleaned, colored); diff --git a/x-pack/test/stack_functional_integration/configs/tests_list.js b/x-pack/test/stack_functional_integration/configs/tests_list.js index 0d91a078b73fd..44b622a8bc9c5 100644 --- a/x-pack/test/stack_functional_integration/configs/tests_list.js +++ b/x-pack/test/stack_functional_integration/configs/tests_list.js @@ -20,7 +20,11 @@ export default (envObj) => { } if (envObj.BEATS.includes('metricbeat')) { - xs.push('metricbeat'); + xs.push('metricbeat/_metricbeat'); + if (envObj.XPACK === 'YES') { + // the esArchive and dashboard png are specific to the default distribution (with XPACK) + xs.push('metricbeat/_metricbeat_dashboard'); + } } if (envObj.BEATS.includes('filebeat')) { xs.push('filebeat'); diff --git a/x-pack/tsconfig.json b/x-pack/tsconfig.json index 382d4c073d41e..057441304f093 100644 --- a/x-pack/tsconfig.json +++ b/x-pack/tsconfig.json @@ -1,20 +1,14 @@ { "extends": "../tsconfig.base.json", - "include": [ - "mocks.ts", - "typings/**/*", - "plugins/**/*", - "test_utils/**/*", - "tasks/**/*" - ], + "include": ["mocks.ts", "typings/**/*", "plugins/**/*", "test_utils/**/*", "tasks/**/*"], "exclude": [ - "test/**/*", - "plugins/security_solution/cypress/**/*", "plugins/apm/e2e/cypress/**/*", "plugins/apm/scripts/**/*", - "plugins/licensing/**/*", "plugins/global_search/**/*", - "plugins/telemetry_collection_xpack/**/*" + "plugins/licensing/**/*", + "plugins/security_solution/cypress/**/*", + "plugins/telemetry_collection_xpack/**/*", + "test/**/*" ], "compilerOptions": { "paths": { @@ -28,15 +22,17 @@ }, "references": [ { "path": "../src/core/tsconfig.json" }, - { "path": "../src/plugins/kibana_utils/tsconfig.json" }, + { "path": "../src/plugins/kibana_legacy/tsconfig.json" }, { "path": "../src/plugins/kibana_react/tsconfig.json" }, - { "path": "./plugins/licensing/tsconfig.json" }, - { "path": "./plugins/global_search/tsconfig.json" }, - { "path": "../src/plugins/usage_collection/tsconfig.json" }, - { "path": "../src/plugins/telemetry_collection_manager/tsconfig.json" }, - { "path": "../src/plugins/telemetry/tsconfig.json" }, { "path": "../src/plugins/kibana_usage_collection/tsconfig.json" }, - { "path": "./plugins/telemetry_collection_xpack/tsconfig.json" }, + { "path": "../src/plugins/kibana_utils/tsconfig.json" }, { "path": "../src/plugins/newsfeed/tsconfig.json" }, + { "path": "../src/plugins/telemetry/tsconfig.json" }, + { "path": "../src/plugins/telemetry_collection_manager/tsconfig.json" }, + { "path": "../src/plugins/url_forwarding/tsconfig.json" }, + { "path": "../src/plugins/usage_collection/tsconfig.json" }, + { "path": "./plugins/global_search/tsconfig.json" }, + { "path": "./plugins/licensing/tsconfig.json" }, + { "path": "./plugins/telemetry_collection_xpack/tsconfig.json" } ] } diff --git a/x-pack/typings/hapi.d.ts b/x-pack/typings/hapi.d.ts deleted file mode 100644 index dd9e0239aeee7..0000000000000 --- a/x-pack/typings/hapi.d.ts +++ /dev/null @@ -1,23 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import 'hapi'; - -import { ActionsPlugin, ActionsClient } from '../plugins/actions/server'; -import { AlertingPlugin, AlertsClient } from '../plugins/alerts/server'; -import { TaskManager } from '../plugins/task_manager/server'; - -declare module 'hapi' { - interface Request { - getActionsClient?: () => ActionsClient; - getAlertsClient?: () => AlertsClient; - } - interface PluginProperties { - actions?: ActionsPlugin; - alerts?: AlertingPlugin; - task_manager?: TaskManager; - } -} diff --git a/x-pack/typings/index.d.ts b/x-pack/typings/index.d.ts index 90e2fa5868744..3168026a8679d 100644 --- a/x-pack/typings/index.d.ts +++ b/x-pack/typings/index.d.ts @@ -22,18 +22,8 @@ declare module '*.svg' { export default content; } -type MethodKeysOf = { - [K in keyof T]: T[K] extends (...args: any[]) => any ? K : never; -}[keyof T]; - -type PublicMethodsOf = Pick>; - declare module 'axios/lib/adapters/xhr'; -type Writable = { - -readonly [K in keyof T]: T[K]; -}; - // Storybook references this module. It's @ts-ignored in the codebase but when // built into its dist it strips that out. Add it here to avoid a type checking // error. diff --git a/x-pack/typings/jest.d.ts b/x-pack/typings/jest.d.ts deleted file mode 100644 index 488df5ad92373..0000000000000 --- a/x-pack/typings/jest.d.ts +++ /dev/null @@ -1,14 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -type MockedKeys = { [P in keyof T]: jest.Mocked> }; - -type DeeplyMockedKeys = { - [P in keyof T]: T[P] extends (...args: any[]) => any - ? jest.MockInstance, Parameters> - : DeeplyMockedKeys; -} & - T;