From bc66438ee207e115e09d7e74f98a34fb8eba253c Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Thu, 19 Aug 2021 15:31:43 -0400 Subject: [PATCH 01/76] Add `legacyId` field and set to current rule id (#108196) (#109291) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Initial commit * Rules client to set legacyId when creating a rule in < 8.0.0 * Set legacyId to null on export, change empty state of legacyId from undefined to null * Fix broken tests * Refactor create.test.ts to avoid increasing file size * Fix broken test Co-authored-by: Mike Côté --- .../server/rules_client/rules_client.ts | 32 +- .../server/rules_client/tests/create.test.ts | 288 ++++++++---------- .../tests/get_alert_instance_summary.test.ts | 1 + .../server/saved_objects/mappings.json | 3 + .../server/saved_objects/migrations.test.ts | 14 + .../server/saved_objects/migrations.ts | 20 ++ .../transform_rule_for_export.test.ts | 3 + .../transform_rule_for_export.ts | 1 + x-pack/plugins/alerting/server/types.ts | 1 + .../spaces_only/tests/alerting/migrations.ts | 21 ++ 10 files changed, 201 insertions(+), 183 deletions(-) diff --git a/x-pack/plugins/alerting/server/rules_client/rules_client.ts b/x-pack/plugins/alerting/server/rules_client/rules_client.ts index 4d191584592a2..486cf086b4a73 100644 --- a/x-pack/plugins/alerting/server/rules_client/rules_client.ts +++ b/x-pack/plugins/alerting/server/rules_client/rules_client.ts @@ -5,6 +5,7 @@ * 2.0. */ +import Semver from 'semver'; import Boom from '@hapi/boom'; import { omit, isEqual, map, uniq, pick, truncate, trim } from 'lodash'; import { i18n } from '@kbn/i18n'; @@ -297,11 +298,13 @@ export class RulesClient { ); const createTime = Date.now(); + const legacyId = Semver.lt(this.kibanaVersion, '8.0.0') ? id : null; const notifyWhen = getAlertNotifyWhenType(data.notifyWhen, data.throttle); const rawAlert: RawAlert = { ...data, ...this.apiKeyAsAlertAttributes(createdAPIKey, username), + legacyId, actions, createdBy: username, updatedBy: username, @@ -1539,36 +1542,29 @@ export class RulesClient { notifyWhen, scheduledTaskId, params, - ...rawAlert + legacyId, // exclude from result because it is an internal variable + executionStatus, + schedule, + actions, + ...partialRawAlert }: Partial, references: SavedObjectReference[] | undefined ): PartialAlert { - // Not the prettiest code here, but if we want to use most of the - // alert fields from the rawAlert using `...rawAlert` kind of access, we - // need to specifically delete the executionStatus as it's a different type - // in RawAlert and Alert. Probably next time we need to do something similar - // here, we should look at redesigning the implementation of this method. - const rawAlertWithoutExecutionStatus: Partial> = { - ...rawAlert, - }; - delete rawAlertWithoutExecutionStatus.executionStatus; - const executionStatus = alertExecutionStatusFromRaw(this.logger, id, rawAlert.executionStatus); - return { id, notifyWhen, - ...rawAlertWithoutExecutionStatus, + ...partialRawAlert, // we currently only support the Interval Schedule type // Once we support additional types, this type signature will likely change - schedule: rawAlert.schedule as IntervalSchedule, - actions: rawAlert.actions - ? this.injectReferencesIntoActions(id, rawAlert.actions, references || []) - : [], + schedule: schedule as IntervalSchedule, + actions: actions ? this.injectReferencesIntoActions(id, actions, references || []) : [], params: this.injectReferencesIntoParams(id, ruleType, params, references || []) as Params, ...(updatedAt ? { updatedAt: new Date(updatedAt) } : {}), ...(createdAt ? { createdAt: new Date(createdAt) } : {}), ...(scheduledTaskId ? { scheduledTaskId } : {}), - ...(executionStatus ? { executionStatus } : {}), + ...(executionStatus + ? { executionStatus: alertExecutionStatusFromRaw(this.logger, id, executionStatus) } + : {}), }; } diff --git a/x-pack/plugins/alerting/server/rules_client/tests/create.test.ts b/x-pack/plugins/alerting/server/rules_client/tests/create.test.ts index 944dcc29ff933..001604d68c46b 100644 --- a/x-pack/plugins/alerting/server/rules_client/tests/create.test.ts +++ b/x-pack/plugins/alerting/server/rules_client/tests/create.test.ts @@ -35,7 +35,7 @@ const authorization = alertingAuthorizationMock.create(); const actionsAuthorization = actionsAuthorizationMock.create(); const auditLogger = auditServiceMock.create().asScoped(httpServerMock.createKibanaRequest()); -const kibanaVersion = 'v7.10.0'; +const kibanaVersion = 'v8.0.0'; const rulesClientParams: jest.Mocked = { taskManager, ruleTypeRegistry, @@ -116,6 +116,19 @@ describe('create()', () => { isPreconfigured: false, }, ]); + taskManager.schedule.mockResolvedValue({ + id: 'task-123', + taskType: 'alerting:123', + scheduledAt: new Date(), + attempts: 1, + status: TaskStatus.Idle, + runAt: new Date(), + startedAt: null, + retryAt: null, + state: {}, + params: {}, + ownerId: null, + }); rulesClientParams.getActionsClient.mockResolvedValue(actionsClient); }); @@ -154,19 +167,6 @@ describe('create()', () => { }, ], }); - taskManager.schedule.mockResolvedValueOnce({ - id: 'task-123', - taskType: 'alerting:123', - scheduledAt: new Date(), - attempts: 1, - status: TaskStatus.Idle, - runAt: new Date(), - startedAt: null, - retryAt: null, - state: {}, - params: {}, - ownerId: null, - }); unsecuredSavedObjectsClient.create.mockResolvedValueOnce({ id: '1', type: 'alert', @@ -319,19 +319,6 @@ describe('create()', () => { }, ], }); - taskManager.schedule.mockResolvedValueOnce({ - id: 'task-123', - taskType: 'alerting:123', - scheduledAt: new Date(), - attempts: 1, - status: TaskStatus.Idle, - runAt: new Date(), - startedAt: null, - retryAt: null, - state: {}, - params: {}, - ownerId: null, - }); unsecuredSavedObjectsClient.create.mockResolvedValueOnce({ id: '1', type: 'alert', @@ -418,8 +405,9 @@ describe('create()', () => { "lastExecutionDate": "2019-02-12T21:01:22.479Z", "status": "pending", }, + "legacyId": null, "meta": Object { - "versionApiKeyLastmodified": "v7.10.0", + "versionApiKeyLastmodified": "v8.0.0", }, "muteAll": false, "mutedInstanceIds": Array [], @@ -524,19 +512,6 @@ describe('create()', () => { }, ], }); - taskManager.schedule.mockResolvedValueOnce({ - id: 'task-123', - taskType: 'alerting:123', - scheduledAt: new Date(), - attempts: 1, - status: TaskStatus.Idle, - runAt: new Date(), - startedAt: null, - retryAt: null, - state: {}, - params: {}, - ownerId: null, - }); const result = await rulesClient.create({ data, options: { id: '123' } }); expect(result.id).toEqual('123'); expect(unsecuredSavedObjectsClient.create.mock.calls[0][2]).toMatchInlineSnapshot(` @@ -553,6 +528,99 @@ describe('create()', () => { `); }); + test('sets legacyId when kibanaVersion is < 8.0.0', async () => { + const customrulesClient = new RulesClient({ + ...rulesClientParams, + kibanaVersion: 'v7.10.0', + }); + const data = getMockData(); + const createdAttributes = { + ...data, + legacyId: '123', + alertTypeId: '123', + schedule: { interval: '10s' }, + params: { + bar: true, + }, + createdAt: '2019-02-12T21:01:22.479Z', + createdBy: 'elastic', + updatedBy: 'elastic', + updatedAt: '2019-02-12T21:01:22.479Z', + muteAll: false, + mutedInstanceIds: [], + actions: [ + { + group: 'default', + actionRef: 'action_0', + actionTypeId: 'test', + params: { + foo: true, + }, + }, + ], + }; + unsecuredSavedObjectsClient.create.mockResolvedValueOnce({ + id: '123', + type: 'alert', + attributes: createdAttributes, + references: [ + { + name: 'action_0', + type: 'action', + id: '1', + }, + ], + }); + const result = await customrulesClient.create({ data, options: { id: '123' } }); + expect(result.id).toEqual('123'); + expect(unsecuredSavedObjectsClient.create.mock.calls[0][1]).toMatchInlineSnapshot(` + Object { + "actions": Array [ + Object { + "actionRef": "action_0", + "actionTypeId": "test", + "group": "default", + "params": Object { + "foo": true, + }, + }, + ], + "alertTypeId": "123", + "apiKey": null, + "apiKeyOwner": null, + "consumer": "bar", + "createdAt": "2019-02-12T21:01:22.479Z", + "createdBy": "elastic", + "enabled": true, + "executionStatus": Object { + "error": null, + "lastExecutionDate": "2019-02-12T21:01:22.479Z", + "status": "pending", + }, + "legacyId": "123", + "meta": Object { + "versionApiKeyLastmodified": "v7.10.0", + }, + "muteAll": false, + "mutedInstanceIds": Array [], + "name": "abc", + "notifyWhen": "onActiveAlert", + "params": Object { + "bar": true, + }, + "schedule": Object { + "interval": "10s", + }, + "tags": Array [ + "foo", + ], + "throttle": null, + "updatedAt": "2019-02-12T21:01:22.479Z", + "updatedBy": "elastic", + } + `); + }); + test('creates an alert with multiple actions', async () => { const data = getMockData({ actions: [ @@ -669,19 +737,6 @@ describe('create()', () => { }, ], }); - taskManager.schedule.mockResolvedValueOnce({ - id: 'task-123', - taskType: 'alerting:123', - scheduledAt: new Date(), - attempts: 1, - status: TaskStatus.Idle, - runAt: new Date(), - startedAt: null, - retryAt: null, - state: {}, - params: {}, - ownerId: null, - }); unsecuredSavedObjectsClient.create.mockResolvedValueOnce({ id: '1', type: 'alert', @@ -878,19 +933,6 @@ describe('create()', () => { }, ], }); - taskManager.schedule.mockResolvedValueOnce({ - id: 'task-123', - taskType: 'alerting:123', - scheduledAt: new Date(), - attempts: 1, - status: TaskStatus.Idle, - runAt: new Date(), - startedAt: null, - retryAt: null, - state: {}, - params: {}, - ownerId: null, - }); unsecuredSavedObjectsClient.create.mockResolvedValueOnce({ id: '1', type: 'alert', @@ -916,12 +958,13 @@ describe('create()', () => { createdAt: '2019-02-12T21:01:22.479Z', createdBy: 'elastic', enabled: true, + legacyId: null, executionStatus: { error: null, lastExecutionDate: '2019-02-12T21:01:22.479Z', status: 'pending', }, - meta: { versionApiKeyLastmodified: 'v7.10.0' }, + meta: { versionApiKeyLastmodified: kibanaVersion }, muteAll: false, mutedInstanceIds: [], name: 'abc', @@ -1055,19 +1098,6 @@ describe('create()', () => { }, ], }); - taskManager.schedule.mockResolvedValueOnce({ - id: 'task-123', - taskType: 'alerting:123', - scheduledAt: new Date(), - attempts: 1, - status: TaskStatus.Idle, - runAt: new Date(), - startedAt: null, - retryAt: null, - state: {}, - params: {}, - ownerId: null, - }); unsecuredSavedObjectsClient.create.mockResolvedValueOnce({ id: '1', type: 'alert', @@ -1089,6 +1119,7 @@ describe('create()', () => { alertTypeId: '123', apiKey: null, apiKeyOwner: null, + legacyId: null, consumer: 'bar', createdAt: '2019-02-12T21:01:22.479Z', createdBy: 'elastic', @@ -1098,7 +1129,7 @@ describe('create()', () => { lastExecutionDate: '2019-02-12T21:01:22.479Z', status: 'pending', }, - meta: { versionApiKeyLastmodified: 'v7.10.0' }, + meta: { versionApiKeyLastmodified: kibanaVersion }, muteAll: false, mutedInstanceIds: [], name: 'abc', @@ -1189,19 +1220,6 @@ describe('create()', () => { }, ], }); - taskManager.schedule.mockResolvedValueOnce({ - id: 'task-123', - taskType: 'alerting:123', - scheduledAt: new Date(), - attempts: 1, - status: TaskStatus.Idle, - runAt: new Date(), - startedAt: null, - retryAt: null, - state: {}, - params: {}, - ownerId: null, - }); await rulesClient.create({ data }); expect(rulesClientParams.createAPIKey).toHaveBeenCalledWith('Alerting: 123/my alert name'); @@ -1246,19 +1264,6 @@ describe('create()', () => { }, ], }); - taskManager.schedule.mockResolvedValueOnce({ - id: 'task-123', - taskType: 'alerting:123', - scheduledAt: new Date(), - attempts: 1, - status: TaskStatus.Idle, - runAt: new Date(), - startedAt: null, - retryAt: null, - state: {}, - params: {}, - ownerId: null, - }); const result = await rulesClient.create({ data }); expect(unsecuredSavedObjectsClient.create).toHaveBeenCalledWith( 'alert', @@ -1274,6 +1279,7 @@ describe('create()', () => { alertTypeId: '123', consumer: 'bar', name: 'abc', + legacyId: null, params: { bar: true }, apiKey: null, apiKeyOwner: null, @@ -1283,7 +1289,7 @@ describe('create()', () => { updatedAt: '2019-02-12T21:01:22.479Z', enabled: true, meta: { - versionApiKeyLastmodified: 'v7.10.0', + versionApiKeyLastmodified: kibanaVersion, }, schedule: { interval: '10s' }, throttle: '10m', @@ -1386,19 +1392,6 @@ describe('create()', () => { }, ], }); - taskManager.schedule.mockResolvedValueOnce({ - id: 'task-123', - taskType: 'alerting:123', - scheduledAt: new Date(), - attempts: 1, - status: TaskStatus.Idle, - runAt: new Date(), - startedAt: null, - retryAt: null, - state: {}, - params: {}, - ownerId: null, - }); const result = await rulesClient.create({ data }); expect(unsecuredSavedObjectsClient.create).toHaveBeenCalledWith( 'alert', @@ -1411,6 +1404,7 @@ describe('create()', () => { params: { foo: true }, }, ], + legacyId: null, alertTypeId: '123', consumer: 'bar', name: 'abc', @@ -1423,7 +1417,7 @@ describe('create()', () => { updatedAt: '2019-02-12T21:01:22.479Z', enabled: true, meta: { - versionApiKeyLastmodified: 'v7.10.0', + versionApiKeyLastmodified: kibanaVersion, }, schedule: { interval: '10s' }, throttle: '10m', @@ -1526,19 +1520,6 @@ describe('create()', () => { }, ], }); - taskManager.schedule.mockResolvedValueOnce({ - id: 'task-123', - taskType: 'alerting:123', - scheduledAt: new Date(), - attempts: 1, - status: TaskStatus.Idle, - runAt: new Date(), - startedAt: null, - retryAt: null, - state: {}, - params: {}, - ownerId: null, - }); const result = await rulesClient.create({ data }); expect(unsecuredSavedObjectsClient.create).toHaveBeenCalledWith( 'alert', @@ -1551,6 +1532,7 @@ describe('create()', () => { params: { foo: true }, }, ], + legacyId: null, alertTypeId: '123', consumer: 'bar', name: 'abc', @@ -1563,7 +1545,7 @@ describe('create()', () => { updatedAt: '2019-02-12T21:01:22.479Z', enabled: true, meta: { - versionApiKeyLastmodified: 'v7.10.0', + versionApiKeyLastmodified: kibanaVersion, }, schedule: { interval: '10s' }, throttle: null, @@ -1826,19 +1808,6 @@ describe('create()', () => { }, ], }); - taskManager.schedule.mockResolvedValueOnce({ - id: 'task-123', - taskType: 'alerting:123', - scheduledAt: new Date(), - attempts: 1, - status: TaskStatus.Idle, - runAt: new Date(), - startedAt: null, - retryAt: null, - state: {}, - params: {}, - ownerId: null, - }); unsecuredSavedObjectsClient.create.mockResolvedValueOnce({ id: '1', type: 'alert', @@ -1871,6 +1840,7 @@ describe('create()', () => { alertTypeId: '123', consumer: 'bar', name: 'abc', + legacyId: null, params: { bar: true }, apiKey: Buffer.from('123:abc').toString('base64'), apiKeyOwner: 'elastic', @@ -1880,7 +1850,7 @@ describe('create()', () => { updatedAt: '2019-02-12T21:01:22.479Z', enabled: true, meta: { - versionApiKeyLastmodified: 'v7.10.0', + versionApiKeyLastmodified: kibanaVersion, }, schedule: { interval: '10s' }, throttle: null, @@ -1937,19 +1907,6 @@ describe('create()', () => { }, ], }); - taskManager.schedule.mockResolvedValueOnce({ - id: 'task-123', - taskType: 'alerting:123', - scheduledAt: new Date(), - attempts: 1, - status: TaskStatus.Idle, - runAt: new Date(), - startedAt: null, - retryAt: null, - state: {}, - params: {}, - ownerId: null, - }); unsecuredSavedObjectsClient.create.mockResolvedValueOnce({ id: '1', type: 'alert', @@ -1979,6 +1936,7 @@ describe('create()', () => { params: { foo: true }, }, ], + legacyId: null, alertTypeId: '123', consumer: 'bar', name: 'abc', @@ -1991,7 +1949,7 @@ describe('create()', () => { updatedAt: '2019-02-12T21:01:22.479Z', enabled: false, meta: { - versionApiKeyLastmodified: 'v7.10.0', + versionApiKeyLastmodified: kibanaVersion, }, schedule: { interval: '10s' }, throttle: null, diff --git a/x-pack/plugins/alerting/server/rules_client/tests/get_alert_instance_summary.test.ts b/x-pack/plugins/alerting/server/rules_client/tests/get_alert_instance_summary.test.ts index d946c354872a7..f8414b08f191b 100644 --- a/x-pack/plugins/alerting/server/rules_client/tests/get_alert_instance_summary.test.ts +++ b/x-pack/plugins/alerting/server/rules_client/tests/get_alert_instance_summary.test.ts @@ -72,6 +72,7 @@ const BaseAlertInstanceSummarySavedObject: SavedObject = { tags: ['tag-1', 'tag-2'], alertTypeId: '123', consumer: 'alert-consumer', + legacyId: null, schedule: { interval: `${AlertInstanceSummaryIntervalSeconds}s` }, actions: [], params: {}, diff --git a/x-pack/plugins/alerting/server/saved_objects/mappings.json b/x-pack/plugins/alerting/server/saved_objects/mappings.json index 43292c6a54346..21d7a05f2a76d 100644 --- a/x-pack/plugins/alerting/server/saved_objects/mappings.json +++ b/x-pack/plugins/alerting/server/saved_objects/mappings.json @@ -28,6 +28,9 @@ "consumer": { "type": "keyword" }, + "legacyId": { + "type": "keyword" + }, "actions": { "type": "nested", "properties": { diff --git a/x-pack/plugins/alerting/server/saved_objects/migrations.test.ts b/x-pack/plugins/alerting/server/saved_objects/migrations.test.ts index b1460a5fe5cd8..c9a9d7c73a8a6 100644 --- a/x-pack/plugins/alerting/server/saved_objects/migrations.test.ts +++ b/x-pack/plugins/alerting/server/saved_objects/migrations.test.ts @@ -1416,6 +1416,20 @@ describe('successful migrations', () => { }); }); }); + + describe('7.16.0', () => { + test('add legacyId field to alert - set to SavedObject id attribute', () => { + const migration716 = getMigrations(encryptedSavedObjectsSetup)['7.16.0']; + const alert = getMockData({}, true); + expect(migration716(alert, migrationContext)).toEqual({ + ...alert, + attributes: { + ...alert.attributes, + legacyId: alert.id, + }, + }); + }); + }); }); describe('handles errors during migrations', () => { diff --git a/x-pack/plugins/alerting/server/saved_objects/migrations.ts b/x-pack/plugins/alerting/server/saved_objects/migrations.ts index 6823a9b9b20da..d53943991b215 100644 --- a/x-pack/plugins/alerting/server/saved_objects/migrations.ts +++ b/x-pack/plugins/alerting/server/saved_objects/migrations.ts @@ -99,6 +99,12 @@ export function getMigrations( pipeMigrations(addExceptionListsToReferences) ); + const migrateLegacyIds716 = createEsoMigration( + encryptedSavedObjects, + (doc): doc is SavedObjectUnsanitizedDoc => true, + pipeMigrations(setLegacyId) + ); + return { '7.10.0': executeMigrationWithErrorHandling(migrationWhenRBACWasIntroduced, '7.10.0'), '7.11.0': executeMigrationWithErrorHandling(migrationAlertUpdatedAtAndNotifyWhen, '7.11.0'), @@ -106,6 +112,7 @@ export function getMigrations( '7.13.0': executeMigrationWithErrorHandling(migrationSecurityRules713, '7.13.0'), '7.14.1': executeMigrationWithErrorHandling(migrationSecurityRules714, '7.14.1'), '7.15.0': executeMigrationWithErrorHandling(migrationSecurityRules715, '7.15.0'), + '7.16.0': executeMigrationWithErrorHandling(migrateLegacyIds716, '7.16.0'), }; } @@ -567,6 +574,19 @@ function removeMalformedExceptionsList( } } +function setLegacyId( + doc: SavedObjectUnsanitizedDoc +): SavedObjectUnsanitizedDoc { + const { id } = doc; + return { + ...doc, + attributes: { + ...doc.attributes, + legacyId: id, + }, + }; +} + function pipeMigrations(...migrations: AlertMigration[]): AlertMigration { return (doc: SavedObjectUnsanitizedDoc) => migrations.reduce((migratedDoc, nextMigration) => nextMigration(migratedDoc), doc); diff --git a/x-pack/plugins/alerting/server/saved_objects/transform_rule_for_export.test.ts b/x-pack/plugins/alerting/server/saved_objects/transform_rule_for_export.test.ts index 5997df2895761..8236c4455478c 100644 --- a/x-pack/plugins/alerting/server/saved_objects/transform_rule_for_export.test.ts +++ b/x-pack/plugins/alerting/server/saved_objects/transform_rule_for_export.test.ts @@ -35,6 +35,7 @@ describe('transform rule for export', () => { apiKey: '4tndskbuhewotw4klrhgjewrt9u', apiKeyOwner: 'me', throttle: null, + legacyId: '1', notifyWhen: 'onActionGroupChange', muteAll: false, mutedInstanceIds: [], @@ -66,6 +67,7 @@ describe('transform rule for export', () => { apiKey: null, apiKeyOwner: null, throttle: null, + legacyId: '2', notifyWhen: 'onActionGroupChange', muteAll: false, mutedInstanceIds: [], @@ -90,6 +92,7 @@ describe('transform rule for export', () => { apiKey: null, apiKeyOwner: null, scheduledTaskId: null, + legacyId: null, executionStatus: { status: 'pending', lastExecutionDate: '2020-08-20T19:23:38Z', diff --git a/x-pack/plugins/alerting/server/saved_objects/transform_rule_for_export.ts b/x-pack/plugins/alerting/server/saved_objects/transform_rule_for_export.ts index 707bd84e948bf..97fd226b49e8e 100644 --- a/x-pack/plugins/alerting/server/saved_objects/transform_rule_for_export.ts +++ b/x-pack/plugins/alerting/server/saved_objects/transform_rule_for_export.ts @@ -22,6 +22,7 @@ function transformRuleForExport( ...rule, attributes: { ...rule.attributes, + legacyId: null, enabled: false, apiKey: null, apiKeyOwner: null, diff --git a/x-pack/plugins/alerting/server/types.ts b/x-pack/plugins/alerting/server/types.ts index 8b8fce7a1bf62..67565271fedc8 100644 --- a/x-pack/plugins/alerting/server/types.ts +++ b/x-pack/plugins/alerting/server/types.ts @@ -198,6 +198,7 @@ export interface RawAlert extends SavedObjectAttributes { tags: string[]; alertTypeId: string; consumer: string; + legacyId: string | null; schedule: SavedObjectAttributes; actions: RawAlertAction[]; params: SavedObjectAttributes; diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/migrations.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/migrations.ts index 81b544ac97152..e5852d55e13c6 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/migrations.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/migrations.ts @@ -6,8 +6,10 @@ */ import expect from '@kbn/expect'; +import type { ApiResponse, estypes } from '@elastic/elasticsearch'; import { getUrlPrefix } from '../../../common/lib'; import { FtrProviderContext } from '../../../common/ftr_provider_context'; +import type { RawAlert } from '../../../../../plugins/alerting/server/types'; // eslint-disable-next-line import/no-default-export export default function createGetTests({ getService }: FtrProviderContext) { @@ -197,5 +199,24 @@ export default function createGetTests({ getService }: FtrProviderContext) { }, ]); }); + + it('7.16.0 migrates existing alerts to contain legacyId field', async () => { + const searchResult: ApiResponse> = await es.search({ + index: '.kibana', + body: { + query: { + term: { + _id: 'alert:74f3e6d7-b7bb-477d-ac28-92ee22728e6e', + }, + }, + }, + }); + expect(searchResult.statusCode).to.equal(200); + expect((searchResult.body.hits.total as estypes.SearchTotalHits).value).to.equal(1); + const hit = searchResult.body.hits.hits[0]; + expect((hit!._source!.alert! as RawAlert).legacyId).to.equal( + '74f3e6d7-b7bb-477d-ac28-92ee22728e6e' + ); + }); }); } From 50e484b0197fe8e3876e7f796b558d4d092db135 Mon Sep 17 00:00:00 2001 From: Sandra G Date: Thu, 19 Aug 2021 15:48:21 -0400 Subject: [PATCH 02/76] [Monitoring] document monitoring.ui.ccs.enabled (#109318) (#109331) * monitoring.ui.ccs.enabled doc * fix links --- docs/settings/monitoring-settings.asciidoc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/settings/monitoring-settings.asciidoc b/docs/settings/monitoring-settings.asciidoc index 6483442248cea..31148f0abf4e1 100644 --- a/docs/settings/monitoring-settings.asciidoc +++ b/docs/settings/monitoring-settings.asciidoc @@ -37,6 +37,10 @@ For more information, see monitoring back-end does not run and {kib} stats are not sent to the monitoring cluster. +| `monitoring.ui.ccs.enabled` + | Set to `true` (default) to enable {ref}/modules-cross-cluster-search.html[cross-cluster search] of your monitoring data. The {ref}/modules-remote-clusters.html#remote-cluster-settings[`remote_cluster_client`] role must exist on each node. + + | `monitoring.ui.elasticsearch.hosts` | Specifies the location of the {es} cluster where your monitoring data is stored. By default, this is the same as <>. This setting enables From 6c27febd247d167130be647f0c1f53fb58f2be05 Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Thu, 19 Aug 2021 22:02:15 +0100 Subject: [PATCH 03/76] skip flaky suite (#109329) --- x-pack/test/functional/apps/uptime/synthetics_integration.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/test/functional/apps/uptime/synthetics_integration.ts b/x-pack/test/functional/apps/uptime/synthetics_integration.ts index 6d468b32d7018..5a8ca33df791a 100644 --- a/x-pack/test/functional/apps/uptime/synthetics_integration.ts +++ b/x-pack/test/functional/apps/uptime/synthetics_integration.ts @@ -111,7 +111,8 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { }); }); - describe('create new policy', () => { + // FLAKY: https://github.com/elastic/kibana/issues/109329 + describe.skip('create new policy', () => { let version: string; before(async () => { await uptimeService.syntheticsPackage.deletePolicyByName('system-1'); From 4a630bb59f76865c3b3ce5db067f93c3fdcb8a74 Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Thu, 19 Aug 2021 19:33:03 -0400 Subject: [PATCH 04/76] chore(NA): moving @kbn/plugin-helpers to babel transpiler (#109085) (#109302) Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Tiago Costa --- packages/kbn-plugin-helpers/.babelrc | 3 +++ packages/kbn-plugin-helpers/BUILD.bazel | 25 +++++++++++++++++------ packages/kbn-plugin-helpers/package.json | 4 ++-- packages/kbn-plugin-helpers/tsconfig.json | 5 +++-- 4 files changed, 27 insertions(+), 10 deletions(-) create mode 100644 packages/kbn-plugin-helpers/.babelrc diff --git a/packages/kbn-plugin-helpers/.babelrc b/packages/kbn-plugin-helpers/.babelrc new file mode 100644 index 0000000000000..7da72d1779128 --- /dev/null +++ b/packages/kbn-plugin-helpers/.babelrc @@ -0,0 +1,3 @@ +{ + "presets": ["@kbn/babel-preset/node_preset"] +} diff --git a/packages/kbn-plugin-helpers/BUILD.bazel b/packages/kbn-plugin-helpers/BUILD.bazel index 9242701770a86..d7744aecac26e 100644 --- a/packages/kbn-plugin-helpers/BUILD.bazel +++ b/packages/kbn-plugin-helpers/BUILD.bazel @@ -1,6 +1,7 @@ load("@npm//@bazel/typescript:index.bzl", "ts_config", "ts_project") load("@build_bazel_rules_nodejs//:index.bzl", "js_library", "pkg_npm") +load("//src/dev/bazel:index.bzl", "jsts_transpiler") PKG_BASE_NAME = "kbn-plugin-helpers" PKG_REQUIRE_NAME = "@kbn/plugin-helpers" @@ -26,7 +27,7 @@ NPM_MODULE_EXTRA_FILES = [ "README.md" ] -SRC_DEPS = [ +RUNTIME_DEPS = [ "//packages/kbn-dev-utils", "//packages/kbn-optimizer", "//packages/kbn-utils", @@ -41,6 +42,13 @@ SRC_DEPS = [ ] TYPES_DEPS = [ + "//packages/kbn-dev-utils", + "//packages/kbn-optimizer", + "//packages/kbn-utils", + "@npm//del", + "@npm//execa", + "@npm//globby", + "@npm//load-json-file", "@npm//@types/extract-zip", "@npm//@types/gulp-zip", "@npm//@types/inquirer", @@ -49,7 +57,11 @@ TYPES_DEPS = [ "@npm//@types/vinyl-fs", ] -DEPS = SRC_DEPS + TYPES_DEPS +jsts_transpiler( + name = "target_node", + srcs = SRCS, + build_pkg_name = package_name(), +) ts_config( name = "tsconfig", @@ -61,13 +73,14 @@ ts_config( ) ts_project( - name = "tsc", + name = "tsc_types", args = ['--pretty'], srcs = SRCS, - deps = DEPS, + deps = TYPES_DEPS, declaration = True, declaration_map = True, - out_dir = "target", + emit_declaration_only = True, + out_dir = "target_types", source_map = True, root_dir = "src", tsconfig = ":tsconfig", @@ -76,7 +89,7 @@ ts_project( js_library( name = PKG_BASE_NAME, srcs = NPM_MODULE_EXTRA_FILES, - deps = DEPS + [":tsc"], + deps = RUNTIME_DEPS + [":target_node", ":tsc_types"], package_name = PKG_REQUIRE_NAME, visibility = ["//visibility:public"], ) diff --git a/packages/kbn-plugin-helpers/package.json b/packages/kbn-plugin-helpers/package.json index 1f4df52a03304..21ed8f46f52fa 100644 --- a/packages/kbn-plugin-helpers/package.json +++ b/packages/kbn-plugin-helpers/package.json @@ -7,8 +7,8 @@ "kibana": { "devOnly": true }, - "main": "target/index.js", - "types": "target/index.d.ts", + "main": "target_node/index.js", + "types": "target_types/index.d.ts", "bin": { "plugin-helpers": "bin/plugin-helpers.js" } diff --git a/packages/kbn-plugin-helpers/tsconfig.json b/packages/kbn-plugin-helpers/tsconfig.json index 22adf020187ba..34f3ec5e67503 100644 --- a/packages/kbn-plugin-helpers/tsconfig.json +++ b/packages/kbn-plugin-helpers/tsconfig.json @@ -1,12 +1,13 @@ { "extends": "../../tsconfig.bazel.json", "compilerOptions": { - "outDir": "target", - "target": "ES2018", "declaration": true, "declarationMap": true, + "emitDeclarationOnly": true, + "outDir": "target_types", "sourceMap": true, "sourceRoot": "../../../../packages/kbn-plugin-helpers/src", + "target": "ES2018", "types": [ "jest", "node" From 0be1a78785e0da6a1d796ac93cd5547ef81142b9 Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Thu, 19 Aug 2021 19:34:45 -0400 Subject: [PATCH 05/76] chore(NA): moving @kbn/optimizer to babel transpiler (#109231) (#109316) * chore(NA): adds 7.16 into backportrc * chore(NA): moving @kbn/optimizer to babel transpiler Co-authored-by: Tiago Costa --- packages/kbn-optimizer/.babelrc | 4 +++ packages/kbn-optimizer/BUILD.bazel | 34 +++++++++++++++---- packages/kbn-optimizer/babel.config.js | 12 ------- packages/kbn-optimizer/package.json | 4 +-- packages/kbn-optimizer/tsconfig.json | 3 +- .../kbn-test/src/jest/setup/babel_polyfill.js | 2 +- 6 files changed, 37 insertions(+), 22 deletions(-) create mode 100644 packages/kbn-optimizer/.babelrc delete mode 100644 packages/kbn-optimizer/babel.config.js diff --git a/packages/kbn-optimizer/.babelrc b/packages/kbn-optimizer/.babelrc new file mode 100644 index 0000000000000..1685d1644d94a --- /dev/null +++ b/packages/kbn-optimizer/.babelrc @@ -0,0 +1,4 @@ +{ + "presets": ["@kbn/babel-preset/node_preset"], + "ignore": ["**/*.test.js"] +} diff --git a/packages/kbn-optimizer/BUILD.bazel b/packages/kbn-optimizer/BUILD.bazel index ddf2a05519682..7f04aa4b262b0 100644 --- a/packages/kbn-optimizer/BUILD.bazel +++ b/packages/kbn-optimizer/BUILD.bazel @@ -1,5 +1,6 @@ load("@npm//@bazel/typescript:index.bzl", "ts_config", "ts_project") load("@build_bazel_rules_nodejs//:index.bzl", "js_library", "pkg_npm") +load("//src/dev/bazel:index.bzl", "jsts_transpiler") PKG_BASE_NAME = "kbn-optimizer" PKG_REQUIRE_NAME = "@kbn/optimizer" @@ -29,7 +30,7 @@ NPM_MODULE_EXTRA_FILES = [ "README.md" ] -SRC_DEPS = [ +RUNTIME_DEPS = [ "//packages/kbn-config", "//packages/kbn-dev-utils", "//packages/kbn-std", @@ -59,6 +60,22 @@ SRC_DEPS = [ ] TYPES_DEPS = [ + "//packages/kbn-config", + "//packages/kbn-dev-utils", + "//packages/kbn-std", + "//packages/kbn-ui-shared-deps", + "//packages/kbn-utils", + "@npm//chalk", + "@npm//clean-webpack-plugin", + "@npm//cpy", + "@npm//del", + "@npm//execa", + "@npm//jest-diff", + "@npm//lmdb-store", + "@npm//pirates", + "@npm//resize-observer-polyfill", + "@npm//rxjs", + "@npm//zlib", "@npm//@types/compression-webpack-plugin", "@npm//@types/jest", "@npm//@types/json-stable-stringify", @@ -72,7 +89,11 @@ TYPES_DEPS = [ "@npm//@types/webpack-sources", ] -DEPS = SRC_DEPS + TYPES_DEPS +jsts_transpiler( + name = "target_node", + srcs = SRCS, + build_pkg_name = package_name(), +) ts_config( name = "tsconfig", @@ -84,13 +105,14 @@ ts_config( ) ts_project( - name = "tsc", + name = "tsc_types", args = ['--pretty'], srcs = SRCS, - deps = DEPS, + deps = TYPES_DEPS, declaration = True, declaration_map = True, - out_dir = "target", + emit_declaration_only = True, + out_dir = "target_types", source_map = True, root_dir = "src", tsconfig = ":tsconfig", @@ -99,7 +121,7 @@ ts_project( js_library( name = PKG_BASE_NAME, srcs = NPM_MODULE_EXTRA_FILES, - deps = DEPS + [":tsc"], + deps = RUNTIME_DEPS + [":target_node", ":tsc_types"], package_name = PKG_REQUIRE_NAME, visibility = ["//visibility:public"], ) diff --git a/packages/kbn-optimizer/babel.config.js b/packages/kbn-optimizer/babel.config.js deleted file mode 100644 index e3a412717fb6e..0000000000000 --- a/packages/kbn-optimizer/babel.config.js +++ /dev/null @@ -1,12 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -module.exports = { - presets: ['@kbn/babel-preset/node_preset'], - ignore: ['**/*.test.js'], -}; diff --git a/packages/kbn-optimizer/package.json b/packages/kbn-optimizer/package.json index d23512f7c418d..488e1b5dbfde8 100644 --- a/packages/kbn-optimizer/package.json +++ b/packages/kbn-optimizer/package.json @@ -3,6 +3,6 @@ "version": "1.0.0", "private": true, "license": "SSPL-1.0 OR Elastic License 2.0", - "main": "./target/index.js", - "types": "./target/index.d.ts" + "main": "./target_node/index.js", + "types": "./target_types/index.d.ts" } \ No newline at end of file diff --git a/packages/kbn-optimizer/tsconfig.json b/packages/kbn-optimizer/tsconfig.json index 047c98db8a806..5fbd02106e777 100644 --- a/packages/kbn-optimizer/tsconfig.json +++ b/packages/kbn-optimizer/tsconfig.json @@ -1,9 +1,10 @@ { "extends": "../../tsconfig.bazel.json", "compilerOptions": { - "outDir": "./target/types", "declaration": true, "declarationMap": true, + "emitDeclarationOnly": true, + "outDir": "./target_types", "rootDir": "./src", "sourceMap": true, "sourceRoot": "../../../../packages/kbn-optimizer/src", diff --git a/packages/kbn-test/src/jest/setup/babel_polyfill.js b/packages/kbn-test/src/jest/setup/babel_polyfill.js index 7dda4cceec65c..7981eb668f38f 100644 --- a/packages/kbn-test/src/jest/setup/babel_polyfill.js +++ b/packages/kbn-test/src/jest/setup/babel_polyfill.js @@ -9,4 +9,4 @@ // Note: In theory importing the polyfill should not be needed, as Babel should // include the necessary polyfills when using `@babel/preset-env`, but for some // reason it did not work. See https://github.com/elastic/kibana/issues/14506 -import '@kbn/optimizer/target/node/polyfill'; +import '@kbn/optimizer/target_node/node/polyfill'; From fe2dc15dcc56ba5e84da7d74d928bb366fa8d606 Mon Sep 17 00:00:00 2001 From: Jonathan Budzenski Date: Thu, 19 Aug 2021 18:52:14 -0500 Subject: [PATCH 06/76] [7.x] [build] Remove jest.config.js (#108822) (#109266) --- src/dev/build/tasks/copy_source_task.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/dev/build/tasks/copy_source_task.ts b/src/dev/build/tasks/copy_source_task.ts index e0ec0340904dc..dd9f331ac263d 100644 --- a/src/dev/build/tasks/copy_source_task.ts +++ b/src/dev/build/tasks/copy_source_task.ts @@ -31,6 +31,7 @@ export const CopySource: Task = { '!src/dev/**', '!src/setup_node_env/babel_register/index.js', '!src/setup_node_env/babel_register/register.js', + '!**/jest.config.js', '!src/plugins/telemetry/schema/**', // Skip telemetry schemas '!**/public/**/*.{js,ts,tsx,json,scss}', 'typings/**', From 4b60f2e1121cc85cc4706cb7a52dc83212a0b139 Mon Sep 17 00:00:00 2001 From: Ignacio Rivas Date: Fri, 20 Aug 2021 02:04:57 +0200 Subject: [PATCH 07/76] [Upgrade Assistant] Overview page should reference nextMajor (#109222) (#109328) * Should use nextMajor instead of currentMajor * Fix small CR changes Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../helpers/overview.helpers.ts | 2 + .../overview/overview.test.tsx | 39 +++++++++++++++++++ .../components/overview/overview.tsx | 12 +++--- .../review_logs_step/review_logs_step.tsx | 6 +-- .../overview/upgrade_step/upgrade_step.tsx | 12 +++--- 5 files changed, 56 insertions(+), 15 deletions(-) create mode 100644 x-pack/plugins/upgrade_assistant/__jest__/client_integration/overview/overview.test.tsx diff --git a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/overview.helpers.ts b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/overview.helpers.ts index 93826497b8630..96e12d4806ee3 100644 --- a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/overview.helpers.ts +++ b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/overview.helpers.ts @@ -76,4 +76,6 @@ export type OverviewTestSubjects = | 'upgradeSetupDocsLink' | 'upgradeSetupCloudLink' | 'deprecationWarningCallout' + | 'whatsNewLink' + | 'documentationLink' | 'upgradeStatusError'; diff --git a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/overview/overview.test.tsx b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/overview/overview.test.tsx new file mode 100644 index 0000000000000..0acf5ae65c6cc --- /dev/null +++ b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/overview/overview.test.tsx @@ -0,0 +1,39 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { mockKibanaSemverVersion } from '../../../common/constants'; +import { OverviewTestBed, setupOverviewPage, setupEnvironment } from '../helpers'; + +describe('Overview Page', () => { + let testBed: OverviewTestBed; + const { server } = setupEnvironment(); + + beforeEach(async () => { + testBed = await setupOverviewPage(); + testBed.component.update(); + }); + + afterAll(() => { + server.restore(); + }); + + describe('Documentation links', () => { + test('Has a whatsNew link and it references nextMajor version', () => { + const { exists, find } = testBed; + const nextMajor = mockKibanaSemverVersion.major + 1; + + expect(exists('whatsNewLink')).toBe(true); + expect(find('whatsNewLink').text()).toContain(`${nextMajor}.0`); + }); + + test('Has a link for upgrade assistant in page header', () => { + const { exists } = testBed; + + expect(exists('documentationLink')).toBe(true); + }); + }); +}); diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/overview/overview.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/overview/overview.tsx index bd076dd600216..b7cac67ca5a96 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/overview/overview.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/overview/overview.tsx @@ -27,7 +27,7 @@ import { getUpgradeStep } from './upgrade_step'; export const Overview: FunctionComponent = () => { const { kibanaVersionInfo, breadcrumbs, docLinks, api } = useAppContext(); - const { currentMajor } = kibanaVersionInfo; + const { nextMajor } = kibanaVersionInfo; useEffect(() => { async function sendTelemetryData() { @@ -68,12 +68,12 @@ export const Overview: FunctionComponent = () => { , ]} > - + @@ -83,9 +83,9 @@ export const Overview: FunctionComponent = () => { diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/overview/review_logs_step/review_logs_step.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/overview/review_logs_step/review_logs_step.tsx index 2da31a3801dd0..4ebde8b5f847a 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/overview/review_logs_step/review_logs_step.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/overview/review_logs_step/review_logs_step.tsx @@ -20,7 +20,7 @@ const i18nTexts = { }), }; -export const getReviewLogsStep = ({ currentMajor }: { currentMajor: number }): EuiStepProps => { +export const getReviewLogsStep = ({ nextMajor }: { nextMajor: number }): EuiStepProps => { return { title: i18nTexts.reviewStepTitle, status: 'incomplete', @@ -30,8 +30,8 @@ export const getReviewLogsStep = ({ currentMajor }: { currentMajor: number }): E

diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/overview/upgrade_step/upgrade_step.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/overview/upgrade_step/upgrade_step.tsx index 9b66a28e81cd8..d66a408cfce77 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/overview/upgrade_step/upgrade_step.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/overview/upgrade_step/upgrade_step.tsx @@ -21,10 +21,10 @@ import type { DocLinksStart } from 'src/core/public'; import { useKibana } from '../../../../shared_imports'; const i18nTexts = { - upgradeStepTitle: (currentMajor: number) => + upgradeStepTitle: (nextMajor: number) => i18n.translate('xpack.upgradeAssistant.overview.upgradeStepTitle', { - defaultMessage: 'Install {currentMajor}.0', - values: { currentMajor }, + defaultMessage: 'Install {nextMajor}.0', + values: { nextMajor }, }), upgradeStepDescription: i18n.translate('xpack.upgradeAssistant.overview.upgradeStepDescription', { defaultMessage: @@ -117,12 +117,12 @@ const UpgradeStep = ({ docLinks }: { docLinks: DocLinksStart }) => { interface Props { docLinks: DocLinksStart; - currentMajor: number; + nextMajor: number; } -export const getUpgradeStep = ({ docLinks, currentMajor }: Props): EuiStepProps => { +export const getUpgradeStep = ({ docLinks, nextMajor }: Props): EuiStepProps => { return { - title: i18nTexts.upgradeStepTitle(currentMajor), + title: i18nTexts.upgradeStepTitle(nextMajor), status: 'incomplete', children: , }; From 4947a2809aea6971cd2a518f08a9568c3082cd92 Mon Sep 17 00:00:00 2001 From: CJ Cenizal Date: Thu, 19 Aug 2021 17:11:22 -0700 Subject: [PATCH 08/76] Migrate Stack Management apps to consume internal EuiCodeEditor (#108629) (#109327) * Migrate Index Management to use internal EuiCodeEditor. * Migrate Rollup to use internal EuiCodeEditor. * Migrate Snapshot and Restore to use internal EuiCodeEditor. * Migrate Watcher to use internal EuiCodeEditor. * Add default setOptions values to EuiCodeEditor. Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../components/authorization_provider.tsx | 2 +- .../components/code_editor/code_editor.tsx | 7 +++-- .../template_clone.test.tsx | 10 +------ .../template_create.test.tsx | 10 +------ .../template_edit.test.tsx | 10 +------ .../template_form.helpers.ts | 6 ++-- .../component_template_create.test.tsx | 10 +------ .../component_template_edit.test.tsx | 10 +------ .../component_template_form.helpers.ts | 6 ++-- .../components/wizard_steps/step_aliases.tsx | 3 +- .../components/wizard_steps/step_settings.tsx | 3 +- .../index_management/public/shared_imports.ts | 1 + .../index_management/test/global_mocks.tsx | 29 +++++++++++++++++++ .../components/job_details/tabs/tab_json.js | 2 +- .../plugins/rollup/public/shared_imports.ts | 1 + .../repository_edit.test.ts | 2 +- .../type_settings/hdfs_settings.tsx | 2 +- .../steps/step_review.tsx | 2 +- .../steps/step_settings.tsx | 2 +- .../policy_details/tabs/tab_history.tsx | 2 +- .../type_details/default_details.tsx | 3 +- .../snapshot_restore/public/shared_imports.ts | 1 + .../client_integration/watch_edit.test.ts | 2 +- .../json_watch_edit/json_watch_edit_form.tsx | 3 +- .../json_watch_edit_simulate.tsx | 3 +- .../action_fields/webhook_action_fields.tsx | 2 +- .../public/application/shared_imports.ts | 1 + 27 files changed, 66 insertions(+), 69 deletions(-) create mode 100644 x-pack/plugins/index_management/test/global_mocks.tsx diff --git a/src/plugins/es_ui_shared/__packages_do_not_import__/authorization/components/authorization_provider.tsx b/src/plugins/es_ui_shared/__packages_do_not_import__/authorization/components/authorization_provider.tsx index 1352081eaa30b..f29ab120013c6 100644 --- a/src/plugins/es_ui_shared/__packages_do_not_import__/authorization/components/authorization_provider.tsx +++ b/src/plugins/es_ui_shared/__packages_do_not_import__/authorization/components/authorization_provider.tsx @@ -9,7 +9,7 @@ import { HttpSetup } from 'kibana/public'; import React, { createContext, useContext } from 'react'; -import { useRequest } from '../../../public'; +import { useRequest } from '../../../public/request'; import { Privileges, Error as CustomError } from '../types'; diff --git a/src/plugins/es_ui_shared/public/components/code_editor/code_editor.tsx b/src/plugins/es_ui_shared/public/components/code_editor/code_editor.tsx index cae3210857543..6299b473f68df 100644 --- a/src/plugins/es_ui_shared/public/components/code_editor/code_editor.tsx +++ b/src/plugins/es_ui_shared/public/components/code_editor/code_editor.tsx @@ -46,7 +46,7 @@ export interface EuiCodeEditorProps extends SupportedAriaAttributes, Omit { static defaultProps = { - setOptions: {}, + setOptions: { + showLineNumbers: false, + tabSize: 2, + }, }; state: EuiCodeEditorState = { diff --git a/x-pack/plugins/index_management/__jest__/client_integration/index_template_wizard/template_clone.test.tsx b/x-pack/plugins/index_management/__jest__/client_integration/index_template_wizard/template_clone.test.tsx index 165a5b3dc8e31..31e65625cfdd0 100644 --- a/x-pack/plugins/index_management/__jest__/client_integration/index_template_wizard/template_clone.test.tsx +++ b/x-pack/plugins/index_management/__jest__/client_integration/index_template_wizard/template_clone.test.tsx @@ -8,6 +8,7 @@ import React from 'react'; import { act } from 'react-dom/test-utils'; +import '../../../test/global_mocks'; import { getComposableTemplate } from '../../../test/fixtures'; import { setupEnvironment } from '../helpers'; @@ -30,15 +31,6 @@ jest.mock('@elastic/eui', () => { }} /> ), - // Mocking EuiCodeEditor, which uses React Ace under the hood - EuiCodeEditor: (props: any) => ( - { - props.onChange(syntheticEvent.jsonString); - }} - /> - ), }; }); diff --git a/x-pack/plugins/index_management/__jest__/client_integration/index_template_wizard/template_create.test.tsx b/x-pack/plugins/index_management/__jest__/client_integration/index_template_wizard/template_create.test.tsx index 77ce172f3e0db..67c9ed067227d 100644 --- a/x-pack/plugins/index_management/__jest__/client_integration/index_template_wizard/template_create.test.tsx +++ b/x-pack/plugins/index_management/__jest__/client_integration/index_template_wizard/template_create.test.tsx @@ -8,6 +8,7 @@ import React from 'react'; import { act } from 'react-dom/test-utils'; +import '../../../test/global_mocks'; import { setupEnvironment } from '../helpers'; import { @@ -34,15 +35,6 @@ jest.mock('@elastic/eui', () => { }} /> ), - // Mocking EuiCodeEditor, which uses React Ace under the hood - EuiCodeEditor: (props: any) => ( - { - props.onChange(syntheticEvent.jsonString); - }} - /> - ), }; }); diff --git a/x-pack/plugins/index_management/__jest__/client_integration/index_template_wizard/template_edit.test.tsx b/x-pack/plugins/index_management/__jest__/client_integration/index_template_wizard/template_edit.test.tsx index 6d887dbb3305a..b55a2b9daa7f9 100644 --- a/x-pack/plugins/index_management/__jest__/client_integration/index_template_wizard/template_edit.test.tsx +++ b/x-pack/plugins/index_management/__jest__/client_integration/index_template_wizard/template_edit.test.tsx @@ -8,6 +8,7 @@ import React from 'react'; import { act } from 'react-dom/test-utils'; +import '../../../test/global_mocks'; import * as fixtures from '../../../test/fixtures'; import { setupEnvironment, BRANCH } from '../helpers'; @@ -41,15 +42,6 @@ jest.mock('@elastic/eui', () => { }} /> ), - // Mocking EuiCodeEditor, which uses React Ace under the hood - EuiCodeEditor: (props: any) => ( - { - props.onChange(syntheticEvent.jsonString); - }} - /> - ), }; }); diff --git a/x-pack/plugins/index_management/__jest__/client_integration/index_template_wizard/template_form.helpers.ts b/x-pack/plugins/index_management/__jest__/client_integration/index_template_wizard/template_form.helpers.ts index 01aeba31770db..3a8d34c341834 100644 --- a/x-pack/plugins/index_management/__jest__/client_integration/index_template_wizard/template_form.helpers.ts +++ b/x-pack/plugins/index_management/__jest__/client_integration/index_template_wizard/template_form.helpers.ts @@ -206,7 +206,7 @@ export const formSetup = async (initTestBed: SetupFunc) => { await act(async () => { if (settings) { - find('mockCodeEditor').simulate('change', { + find('settingsEditor').simulate('change', { jsonString: settings, }); // Using mocked EuiCodeEditor } @@ -241,7 +241,7 @@ export const formSetup = async (initTestBed: SetupFunc) => { if (aliases) { await act(async () => { - find('mockCodeEditor').simulate('change', { + find('aliasesEditor').simulate('change', { jsonString: aliases, }); // Using mocked EuiCodeEditor }); @@ -337,4 +337,6 @@ export type TestSubjects = | 'templateFormContainer' | 'testingEditor' | 'versionField' + | 'aliasesEditor' + | 'settingsEditor' | 'versionField.input'; diff --git a/x-pack/plugins/index_management/public/application/components/component_templates/__jest__/client_integration/component_template_create.test.tsx b/x-pack/plugins/index_management/public/application/components/component_templates/__jest__/client_integration/component_template_create.test.tsx index b07cd098e540d..f3957e0cc15c9 100644 --- a/x-pack/plugins/index_management/public/application/components/component_templates/__jest__/client_integration/component_template_create.test.tsx +++ b/x-pack/plugins/index_management/public/application/components/component_templates/__jest__/client_integration/component_template_create.test.tsx @@ -9,6 +9,7 @@ import React from 'react'; import { act } from 'react-dom/test-utils'; import '../../../../../../../../../src/plugins/es_ui_shared/public/components/code_editor/jest_mock'; +import '../../../../../../test/global_mocks'; import { setupEnvironment } from './helpers'; import { setup, ComponentTemplateCreateTestBed } from './helpers/component_template_create.helpers'; @@ -27,15 +28,6 @@ jest.mock('@elastic/eui', () => { }} /> ), - // Mocking EuiCodeEditor, which uses React Ace under the hood - EuiCodeEditor: (props: any) => ( - { - props.onChange(syntheticEvent.jsonString); - }} - /> - ), }; }); diff --git a/x-pack/plugins/index_management/public/application/components/component_templates/__jest__/client_integration/component_template_edit.test.tsx b/x-pack/plugins/index_management/public/application/components/component_templates/__jest__/client_integration/component_template_edit.test.tsx index 89dbbe14e6535..d15a115217269 100644 --- a/x-pack/plugins/index_management/public/application/components/component_templates/__jest__/client_integration/component_template_edit.test.tsx +++ b/x-pack/plugins/index_management/public/application/components/component_templates/__jest__/client_integration/component_template_edit.test.tsx @@ -8,6 +8,7 @@ import React from 'react'; import { act } from 'react-dom/test-utils'; +import '../../../../../../test/global_mocks'; import { setupEnvironment } from './helpers'; import { setup, ComponentTemplateEditTestBed } from './helpers/component_template_edit.helpers'; @@ -26,15 +27,6 @@ jest.mock('@elastic/eui', () => { }} /> ), - // Mocking EuiCodeEditor, which uses React Ace under the hood - EuiCodeEditor: (props: any) => ( - { - props.onChange(syntheticEvent.jsonString); - }} - /> - ), }; }); diff --git a/x-pack/plugins/index_management/public/application/components/component_templates/__jest__/client_integration/helpers/component_template_form.helpers.ts b/x-pack/plugins/index_management/public/application/components/component_templates/__jest__/client_integration/helpers/component_template_form.helpers.ts index f8ade2285016c..578a124125107 100644 --- a/x-pack/plugins/index_management/public/application/components/component_templates/__jest__/client_integration/helpers/component_template_form.helpers.ts +++ b/x-pack/plugins/index_management/public/application/components/component_templates/__jest__/client_integration/helpers/component_template_form.helpers.ts @@ -65,7 +65,7 @@ export const getFormActions = (testBed: TestBed) => { await act(async () => { if (settings) { - find('mockCodeEditor').simulate('change', { + find('settingsEditor').simulate('change', { jsonString: JSON.stringify(settings), }); // Using mocked EuiCodeEditor } @@ -118,7 +118,7 @@ export const getFormActions = (testBed: TestBed) => { await act(async () => { if (aliases) { - find('mockCodeEditor').simulate('change', { + find('aliasesEditor').simulate('change', { jsonString: JSON.stringify(aliases), }); // Using mocked EuiCodeEditor } @@ -161,4 +161,6 @@ export type ComponentTemplateFormTestSubjects = | 'stepReview.summaryTab' | 'stepReview.requestTab' | 'versionField' + | 'aliasesEditor' + | 'settingsEditor' | 'versionField.input'; diff --git a/x-pack/plugins/index_management/public/application/components/shared/components/wizard_steps/step_aliases.tsx b/x-pack/plugins/index_management/public/application/components/shared/components/wizard_steps/step_aliases.tsx index 1099ecaa7949f..2d7be72056e18 100644 --- a/x-pack/plugins/index_management/public/application/components/shared/components/wizard_steps/step_aliases.tsx +++ b/x-pack/plugins/index_management/public/application/components/shared/components/wizard_steps/step_aliases.tsx @@ -15,12 +15,11 @@ import { EuiSpacer, EuiFormRow, EuiText, - EuiCodeEditor, EuiCode, } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; -import { Forms } from '../../../../../shared_imports'; +import { EuiCodeEditor, Forms } from '../../../../../shared_imports'; import { useJsonStep } from './use_json_step'; interface Props { diff --git a/x-pack/plugins/index_management/public/application/components/shared/components/wizard_steps/step_settings.tsx b/x-pack/plugins/index_management/public/application/components/shared/components/wizard_steps/step_settings.tsx index e6bec46805169..359e1091c1303 100644 --- a/x-pack/plugins/index_management/public/application/components/shared/components/wizard_steps/step_settings.tsx +++ b/x-pack/plugins/index_management/public/application/components/shared/components/wizard_steps/step_settings.tsx @@ -15,12 +15,11 @@ import { EuiSpacer, EuiFormRow, EuiText, - EuiCodeEditor, EuiCode, } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; -import { Forms } from '../../../../../shared_imports'; +import { EuiCodeEditor, Forms } from '../../../../../shared_imports'; import { useJsonStep } from './use_json_step'; interface Props { diff --git a/x-pack/plugins/index_management/public/shared_imports.ts b/x-pack/plugins/index_management/public/shared_imports.ts index fa27b22e502fa..275f8af818caf 100644 --- a/x-pack/plugins/index_management/public/shared_imports.ts +++ b/x-pack/plugins/index_management/public/shared_imports.ts @@ -22,6 +22,7 @@ export { PageError, Error, SectionLoading, + EuiCodeEditor, } from '../../../../src/plugins/es_ui_shared/public'; export { diff --git a/x-pack/plugins/index_management/test/global_mocks.tsx b/x-pack/plugins/index_management/test/global_mocks.tsx new file mode 100644 index 0000000000000..342d74bce853e --- /dev/null +++ b/x-pack/plugins/index_management/test/global_mocks.tsx @@ -0,0 +1,29 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; + +// NOTE: Import this file for its side-effects. You must import it before the code that it mocks +// is imported. Typically this means just importing above your other imports. +// See https://jestjs.io/docs/manual-mocks for more info. + +jest.mock('../../../../src/plugins/es_ui_shared/public', () => { + const original = jest.requireActual('../../../../src/plugins/es_ui_shared/public'); + + return { + ...original, + EuiCodeEditor: (props: any) => ( + { + props.onChange(syntheticEvent.jsonString); + }} + /> + ), + }; +}); diff --git a/x-pack/plugins/rollup/public/crud_app/sections/components/job_details/tabs/tab_json.js b/x-pack/plugins/rollup/public/crud_app/sections/components/job_details/tabs/tab_json.js index d57a7d8305d51..adfb9aafc444e 100644 --- a/x-pack/plugins/rollup/public/crud_app/sections/components/job_details/tabs/tab_json.js +++ b/x-pack/plugins/rollup/public/crud_app/sections/components/job_details/tabs/tab_json.js @@ -7,7 +7,7 @@ import React from 'react'; -import { EuiCodeEditor } from '@elastic/eui'; +import { EuiCodeEditor } from '../../../../../shared_imports'; export const TabJson = ({ json }) => { const jsonString = JSON.stringify(json, null, 2); diff --git a/x-pack/plugins/rollup/public/shared_imports.ts b/x-pack/plugins/rollup/public/shared_imports.ts index c8d7f1d9f13f3..3478198dd9b68 100644 --- a/x-pack/plugins/rollup/public/shared_imports.ts +++ b/x-pack/plugins/rollup/public/shared_imports.ts @@ -9,4 +9,5 @@ export { extractQueryParams, indices, SectionLoading, + EuiCodeEditor, } from '../../../../src/plugins/es_ui_shared/public'; diff --git a/x-pack/plugins/snapshot_restore/__jest__/client_integration/repository_edit.test.ts b/x-pack/plugins/snapshot_restore/__jest__/client_integration/repository_edit.test.ts index 2087325056649..8adf1e988ff1e 100644 --- a/x-pack/plugins/snapshot_restore/__jest__/client_integration/repository_edit.test.ts +++ b/x-pack/plugins/snapshot_restore/__jest__/client_integration/repository_edit.test.ts @@ -215,7 +215,7 @@ describe('', () => { ); expect(find('readOnlyToggle').props()['aria-checked']).toBe(settings.readonly); - const codeEditor = testBed.component.find('EuiCodeEditor'); + const codeEditor = testBed.component.find('EuiCodeEditor').at(1); expect(JSON.parse(codeEditor.props().value as string)).toEqual({ loadDefault: true, conf1: 'foo', diff --git a/x-pack/plugins/snapshot_restore/public/application/components/repository_form/type_settings/hdfs_settings.tsx b/x-pack/plugins/snapshot_restore/public/application/components/repository_form/type_settings/hdfs_settings.tsx index 5457e22d50b89..2cece7d6d396a 100644 --- a/x-pack/plugins/snapshot_restore/public/application/components/repository_form/type_settings/hdfs_settings.tsx +++ b/x-pack/plugins/snapshot_restore/public/application/components/repository_form/type_settings/hdfs_settings.tsx @@ -10,7 +10,6 @@ import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import { EuiCode, - EuiCodeEditor, EuiDescribedFormGroup, EuiFieldText, EuiFormRow, @@ -20,6 +19,7 @@ import { } from '@elastic/eui'; import { HDFSRepository, Repository, SourceRepository } from '../../../../../common/types'; +import { EuiCodeEditor } from '../../../../shared_imports'; import { RepositorySettingsValidation } from '../../../services/validation'; import { ChunkSizeField, MaxSnapshotsField, MaxRestoreField } from './common'; diff --git a/x-pack/plugins/snapshot_restore/public/application/components/restore_snapshot_form/steps/step_review.tsx b/x-pack/plugins/snapshot_restore/public/application/components/restore_snapshot_form/steps/step_review.tsx index 4210279363780..2974a7b686039 100644 --- a/x-pack/plugins/snapshot_restore/public/application/components/restore_snapshot_form/steps/step_review.tsx +++ b/x-pack/plugins/snapshot_restore/public/application/components/restore_snapshot_form/steps/step_review.tsx @@ -8,7 +8,6 @@ import React, { Fragment } from 'react'; import { FormattedMessage } from '@kbn/i18n/react'; import { - EuiCodeEditor, EuiFlexGrid, EuiFlexGroup, EuiFlexItem, @@ -24,6 +23,7 @@ import { EuiToolTip, } from '@elastic/eui'; import { serializeRestoreSettings } from '../../../../../common/lib'; +import { EuiCodeEditor } from '../../../../shared_imports'; import { useServices } from '../../../app_context'; import { StepProps } from './'; import { CollapsibleIndicesList } from '../../collapsible_lists/collapsible_indices_list'; diff --git a/x-pack/plugins/snapshot_restore/public/application/components/restore_snapshot_form/steps/step_settings.tsx b/x-pack/plugins/snapshot_restore/public/application/components/restore_snapshot_form/steps/step_settings.tsx index c37be0907a27a..446e3f4c3c4ab 100644 --- a/x-pack/plugins/snapshot_restore/public/application/components/restore_snapshot_form/steps/step_settings.tsx +++ b/x-pack/plugins/snapshot_restore/public/application/components/restore_snapshot_form/steps/step_settings.tsx @@ -10,7 +10,6 @@ import { FormattedMessage } from '@kbn/i18n/react'; import { EuiButtonEmpty, EuiCode, - EuiCodeEditor, EuiComboBox, EuiDescribedFormGroup, EuiFlexGroup, @@ -23,6 +22,7 @@ import { EuiCallOut, } from '@elastic/eui'; import { RestoreSettings } from '../../../../../common/types'; +import { EuiCodeEditor } from '../../../../shared_imports'; import { REMOVE_INDEX_SETTINGS_SUGGESTIONS } from '../../../constants'; import { useCore, useServices } from '../../../app_context'; import { StepProps } from './'; diff --git a/x-pack/plugins/snapshot_restore/public/application/sections/home/policy_list/policy_details/tabs/tab_history.tsx b/x-pack/plugins/snapshot_restore/public/application/sections/home/policy_list/policy_details/tabs/tab_history.tsx index 733fdc3d7b653..4944d9bde379a 100644 --- a/x-pack/plugins/snapshot_restore/public/application/sections/home/policy_list/policy_details/tabs/tab_history.tsx +++ b/x-pack/plugins/snapshot_restore/public/application/sections/home/policy_list/policy_details/tabs/tab_history.tsx @@ -9,7 +9,6 @@ import React, { Fragment } from 'react'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import { - EuiCodeEditor, EuiFlexGroup, EuiFlexItem, EuiLink, @@ -23,6 +22,7 @@ import { } from '@elastic/eui'; import { SlmPolicy } from '../../../../../../../common/types'; +import { EuiCodeEditor } from '../../../../../../shared_imports'; import { FormattedDateTime } from '../../../../../components'; import { linkToSnapshot } from '../../../../../services/navigation'; import { useServices } from '../../../../../app_context'; diff --git a/x-pack/plugins/snapshot_restore/public/application/sections/home/repository_list/repository_details/type_details/default_details.tsx b/x-pack/plugins/snapshot_restore/public/application/sections/home/repository_list/repository_details/type_details/default_details.tsx index a349853485e45..8cb86fd4952fa 100644 --- a/x-pack/plugins/snapshot_restore/public/application/sections/home/repository_list/repository_details/type_details/default_details.tsx +++ b/x-pack/plugins/snapshot_restore/public/application/sections/home/repository_list/repository_details/type_details/default_details.tsx @@ -9,9 +9,10 @@ import 'brace/theme/textmate'; import React, { Fragment } from 'react'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; -import { EuiCodeEditor, EuiSpacer, EuiTitle } from '@elastic/eui'; +import { EuiSpacer, EuiTitle } from '@elastic/eui'; import { Repository } from '../../../../../../../common/types'; +import { EuiCodeEditor } from '../../../../../../shared_imports'; interface Props { repository: Repository; diff --git a/x-pack/plugins/snapshot_restore/public/shared_imports.ts b/x-pack/plugins/snapshot_restore/public/shared_imports.ts index 84c195a51950b..d1b9f37703c0c 100644 --- a/x-pack/plugins/snapshot_restore/public/shared_imports.ts +++ b/x-pack/plugins/snapshot_restore/public/shared_imports.ts @@ -22,6 +22,7 @@ export { useRequest, UseRequestConfig, WithPrivileges, + EuiCodeEditor, } from '../../../../src/plugins/es_ui_shared/public'; export { APP_WRAPPER_CLASS } from '../../../../src/core/public'; diff --git a/x-pack/plugins/watcher/__jest__/client_integration/watch_edit.test.ts b/x-pack/plugins/watcher/__jest__/client_integration/watch_edit.test.ts index b40388376d8d5..e8782edc829a4 100644 --- a/x-pack/plugins/watcher/__jest__/client_integration/watch_edit.test.ts +++ b/x-pack/plugins/watcher/__jest__/client_integration/watch_edit.test.ts @@ -66,7 +66,7 @@ describe('', () => { test('should populate the correct values', () => { const { find, exists, component } = testBed; const { watch } = WATCH; - const codeEditor = component.find('EuiCodeEditor'); + const codeEditor = component.find('EuiCodeEditor').at(1); expect(exists('jsonWatchForm')).toBe(true); expect(find('nameInput').props().value).toBe(watch.name); diff --git a/x-pack/plugins/watcher/public/application/sections/watch_edit/components/json_watch_edit/json_watch_edit_form.tsx b/x-pack/plugins/watcher/public/application/sections/watch_edit/components/json_watch_edit/json_watch_edit_form.tsx index 0c1d643475566..b19d97f67d2e0 100644 --- a/x-pack/plugins/watcher/public/application/sections/watch_edit/components/json_watch_edit/json_watch_edit_form.tsx +++ b/x-pack/plugins/watcher/public/application/sections/watch_edit/components/json_watch_edit/json_watch_edit_form.tsx @@ -10,7 +10,6 @@ import React, { Fragment, useContext, useState } from 'react'; import { EuiButton, EuiButtonEmpty, - EuiCodeEditor, EuiFieldText, EuiFlexGroup, EuiFlexItem, @@ -25,7 +24,7 @@ import { XJsonMode } from '@kbn/ace'; import { serializeJsonWatch } from '../../../../../../common/lib/serialization'; import { ErrableFormRow, SectionError, Error as ServerError } from '../../../../components'; -import { XJson } from '../../../../shared_imports'; +import { XJson, EuiCodeEditor } from '../../../../shared_imports'; import { onWatchSave } from '../../watch_edit_actions'; import { WatchContext } from '../../watch_context'; import { goToWatchList } from '../../../../lib/navigation'; diff --git a/x-pack/plugins/watcher/public/application/sections/watch_edit/components/json_watch_edit/json_watch_edit_simulate.tsx b/x-pack/plugins/watcher/public/application/sections/watch_edit/components/json_watch_edit/json_watch_edit_simulate.tsx index fa5ae53b9c6fa..034c0080c852c 100644 --- a/x-pack/plugins/watcher/public/application/sections/watch_edit/components/json_watch_edit/json_watch_edit_simulate.tsx +++ b/x-pack/plugins/watcher/public/application/sections/watch_edit/components/json_watch_edit/json_watch_edit_simulate.tsx @@ -10,7 +10,6 @@ import React, { Fragment, useContext, useState } from 'react'; import { EuiBasicTable, EuiButton, - EuiCodeEditor, EuiDescribedFormGroup, EuiFieldNumber, EuiFlexGroup, @@ -44,7 +43,7 @@ import { JsonWatchEditSimulateResults } from './json_watch_edit_simulate_results import { getTimeUnitLabel } from '../../../../lib/get_time_unit_label'; import { useAppContext } from '../../../../app_context'; -import { XJson } from '../../../../shared_imports'; +import { XJson, EuiCodeEditor } from '../../../../shared_imports'; const { useXJsonMode } = XJson; diff --git a/x-pack/plugins/watcher/public/application/sections/watch_edit/components/threshold_watch_edit/action_fields/webhook_action_fields.tsx b/x-pack/plugins/watcher/public/application/sections/watch_edit/components/threshold_watch_edit/action_fields/webhook_action_fields.tsx index 0199fce195279..bbe5449fa8732 100644 --- a/x-pack/plugins/watcher/public/application/sections/watch_edit/components/threshold_watch_edit/action_fields/webhook_action_fields.tsx +++ b/x-pack/plugins/watcher/public/application/sections/watch_edit/components/threshold_watch_edit/action_fields/webhook_action_fields.tsx @@ -8,7 +8,6 @@ import React, { Fragment, useEffect } from 'react'; import { - EuiCodeEditor, EuiFieldNumber, EuiFieldPassword, EuiFieldText, @@ -19,6 +18,7 @@ import { EuiSpacer, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; +import { EuiCodeEditor } from '../../../../../shared_imports'; import { ErrableFormRow } from '../../../../../components/form_errors'; import { WebhookAction } from '../../../../../../../common/types/action_types'; diff --git a/x-pack/plugins/watcher/public/application/shared_imports.ts b/x-pack/plugins/watcher/public/application/shared_imports.ts index 44bef3b0c4f5f..977204c627e5c 100644 --- a/x-pack/plugins/watcher/public/application/shared_imports.ts +++ b/x-pack/plugins/watcher/public/application/shared_imports.ts @@ -13,4 +13,5 @@ export { useRequest, XJson, PageError, + EuiCodeEditor, } from '../../../../../src/plugins/es_ui_shared/public'; From a592574e07b96c4e709208f843e5157204dda595 Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Thu, 19 Aug 2021 22:10:11 -0400 Subject: [PATCH 09/76] [APM] Rum service details doesn't show any data (#109117) (#109359) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * removing existing filter * fixing unit test * replacing terms agg for should filter * fixing test Co-authored-by: Cauê Marcondes <55978943+cauemarcondes@users.noreply.github.com> --- .../__snapshots__/queries.test.ts.snap | 12 ++++----- .../server/lib/services/get_service_agent.ts | 26 +++++++++---------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/x-pack/plugins/apm/server/lib/services/__snapshots__/queries.test.ts.snap b/x-pack/plugins/apm/server/lib/services/__snapshots__/queries.test.ts.snap index 1b5df64dd8d00..ce8a8bcb8930d 100644 --- a/x-pack/plugins/apm/server/lib/services/__snapshots__/queries.test.ts.snap +++ b/x-pack/plugins/apm/server/lib/services/__snapshots__/queries.test.ts.snap @@ -64,8 +64,8 @@ Object { }, "body": Object { "_source": Array [ - "service.runtime.name", "agent.name", + "service.runtime.name", ], "query": Object { "bool": Object { @@ -84,17 +84,17 @@ Object { }, }, }, - Object { - "exists": Object { - "field": "service.runtime.name", - }, - }, Object { "exists": Object { "field": "agent.name", }, }, ], + "should": Object { + "exists": Object { + "field": "service.runtime.name", + }, + }, }, }, "size": 1, diff --git a/x-pack/plugins/apm/server/lib/services/get_service_agent.ts b/x-pack/plugins/apm/server/lib/services/get_service_agent.ts index 2a6ec74bc0d1a..e99fd6b9ff278 100644 --- a/x-pack/plugins/apm/server/lib/services/get_service_agent.ts +++ b/x-pack/plugins/apm/server/lib/services/get_service_agent.ts @@ -16,14 +16,14 @@ import { Setup, SetupTimeRange } from '../helpers/setup_request'; import { getProcessorEventForAggregatedTransactions } from '../helpers/aggregated_transactions'; interface ServiceAgent { - service?: { - runtime: { - name: string; - }; - }; agent?: { name: string; }; + service?: { + runtime?: { + name?: string; + }; + }; } export async function getServiceAgent({ @@ -50,23 +50,23 @@ export async function getServiceAgent({ }, body: { size: 1, - _source: [SERVICE_RUNTIME_NAME, AGENT_NAME], + _source: [AGENT_NAME, SERVICE_RUNTIME_NAME], query: { bool: { filter: [ { term: { [SERVICE_NAME]: serviceName } }, ...rangeQuery(start, end), - { - exists: { - field: SERVICE_RUNTIME_NAME, - }, - }, { exists: { field: AGENT_NAME, }, }, ], + should: { + exists: { + field: SERVICE_RUNTIME_NAME, + }, + }, }, }, }, @@ -80,6 +80,6 @@ export async function getServiceAgent({ return {}; } - const { service, agent } = response.hits.hits[0]._source as ServiceAgent; - return { agentName: agent?.name, runtimeName: service?.runtime.name }; + const { agent, service } = response.hits.hits[0]._source as ServiceAgent; + return { agentName: agent?.name, runtimeName: service?.runtime?.name }; } From 01f38a7f1ac4851f55650c13794837e97fa62d55 Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Fri, 20 Aug 2021 00:32:42 -0400 Subject: [PATCH 10/76] Fix height of editor when maximized (#109161) (#109362) Co-authored-by: Clint Andrew Hall --- .../canvas/public/components/expression/expression.scss | 9 +++++++++ .../canvas/public/components/expression/expression.tsx | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/canvas/public/components/expression/expression.scss b/x-pack/plugins/canvas/public/components/expression/expression.scss index da95eca2b4f61..c649742077f2b 100644 --- a/x-pack/plugins/canvas/public/components/expression/expression.scss +++ b/x-pack/plugins/canvas/public/components/expression/expression.scss @@ -31,6 +31,15 @@ flex-direction: column; } + .canvasExpressionInput__editor { + height: auto; + position: absolute; + top: 0; + left: 0; + bottom: $euiSizeS * 7 + 1; + right: 0; + } + .canvasExpressionInput__inner { flex-grow: 1; display: flex; diff --git a/x-pack/plugins/canvas/public/components/expression/expression.tsx b/x-pack/plugins/canvas/public/components/expression/expression.tsx index ff3fed32c0ac0..a3ba18d541d76 100644 --- a/x-pack/plugins/canvas/public/components/expression/expression.tsx +++ b/x-pack/plugins/canvas/public/components/expression/expression.tsx @@ -171,7 +171,7 @@ export const Expression: FC = ({ - + {isCompact ? strings.getMaximizeButtonLabel() : strings.getMinimizeButtonLabel()} From cc3ca059b0dd34ece6f0ee3a0bc1ccdd4ed75a55 Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Fri, 20 Aug 2021 06:11:22 -0400 Subject: [PATCH 11/76] fix dnd tests (#109271) (#109373) Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Marta Bondyra --- .../functional/apps/lens/drag_and_drop.ts | 7 ++----- .../test/functional/page_objects/lens_page.ts | 19 +++++++++++++++---- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/x-pack/test/functional/apps/lens/drag_and_drop.ts b/x-pack/test/functional/apps/lens/drag_and_drop.ts index c8a0e171d5a79..e7b7ba18d62fb 100644 --- a/x-pack/test/functional/apps/lens/drag_and_drop.ts +++ b/x-pack/test/functional/apps/lens/drag_and_drop.ts @@ -8,9 +8,8 @@ import expect from '@kbn/expect'; import { FtrProviderContext } from '../../ftr_provider_context'; -export default function ({ getService, getPageObjects }: FtrProviderContext) { +export default function ({ getPageObjects }: FtrProviderContext) { const PageObjects = getPageObjects(['visualize', 'lens', 'common', 'header']); - const retry = getService('retry'); describe('lens drag and drop tests', () => { describe('basic drag and drop', () => { @@ -19,9 +18,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await PageObjects.visualize.clickVisType('lens'); await PageObjects.lens.goToTimeRange(); await PageObjects.header.waitUntilLoadingHasFinished(); - await retry.try(async () => { - await PageObjects.lens.dragFieldToWorkspace('@timestamp'); - }); + await PageObjects.lens.dragFieldToWorkspace('@timestamp'); expect(await PageObjects.lens.getDimensionTriggerText('lnsXY_xDimensionPanel')).to.eql( '@timestamp' diff --git a/x-pack/test/functional/page_objects/lens_page.ts b/x-pack/test/functional/page_objects/lens_page.ts index 1acddd4641ff4..2e1151602f311 100644 --- a/x-pack/test/functional/page_objects/lens_page.ts +++ b/x-pack/test/functional/page_objects/lens_page.ts @@ -185,8 +185,10 @@ export function LensPageProvider({ getService, getPageObjects }: FtrProviderCont * @param field - the desired field for the dimension * */ async dragFieldToWorkspace(field: string) { + const from = `lnsFieldListPanelField-${field}`; + await find.existsByCssSelector(from); await browser.html5DragAndDrop( - testSubjects.getCssSelector(`lnsFieldListPanelField-${field}`), + testSubjects.getCssSelector(from), testSubjects.getCssSelector('lnsWorkspace') ); await this.waitForLensDragDropToFinish(); @@ -199,8 +201,10 @@ export function LensPageProvider({ getService, getPageObjects }: FtrProviderCont * @param field - the desired geo_point or geo_shape field * */ async dragFieldToGeoFieldWorkspace(field: string) { + const from = `lnsFieldListPanelField-${field}`; + await find.existsByCssSelector(from); await browser.html5DragAndDrop( - testSubjects.getCssSelector(`lnsFieldListPanelField-${field}`), + testSubjects.getCssSelector(from), testSubjects.getCssSelector('lnsGeoFieldWorkspace') ); await this.waitForLensDragDropToFinish(); @@ -262,7 +266,10 @@ export function LensPageProvider({ getService, getPageObjects }: FtrProviderCont `[data-test-subj="lnsDragDrop_draggable-${fieldName}"] [data-test-subj="lnsDragDrop-keyboardHandler"]` ); await field.focus(); - await browser.pressKeys(browser.keys.ENTER); + await retry.try(async () => { + await browser.pressKeys(browser.keys.ENTER); + await testSubjects.exists('.lnsDragDrop-isDropTarget'); // checks if we're in dnd mode and there's any drop target active + }); for (let i = 0; i < steps; i++) { await browser.pressKeys(reverse ? browser.keys.LEFT : browser.keys.RIGHT); } @@ -335,8 +342,10 @@ export function LensPageProvider({ getService, getPageObjects }: FtrProviderCont * @param dimension - the selector of the dimension being changed * */ async dragFieldToDimensionTrigger(field: string, dimension: string) { + const from = `lnsFieldListPanelField-${field}`; + await find.existsByCssSelector(from); await browser.html5DragAndDrop( - testSubjects.getCssSelector(`lnsFieldListPanelField-${field}`), + testSubjects.getCssSelector(from), testSubjects.getCssSelector(dimension) ); await this.waitForLensDragDropToFinish(); @@ -350,6 +359,7 @@ export function LensPageProvider({ getService, getPageObjects }: FtrProviderCont * @param to - the selector of the dimension being dropped to * */ async dragDimensionToDimension(from: string, to: string) { + await find.existsByCssSelector(from); await browser.html5DragAndDrop( testSubjects.getCssSelector(from), testSubjects.getCssSelector(to) @@ -367,6 +377,7 @@ export function LensPageProvider({ getService, getPageObjects }: FtrProviderCont async reorderDimensions(dimension: string, startIndex: number, endIndex: number) { const dragging = `[data-test-subj='${dimension}']:nth-of-type(${startIndex}) .lnsDragDrop`; const dropping = `[data-test-subj='${dimension}']:nth-of-type(${endIndex}) [data-test-subj='lnsDragDrop-reorderableDropLayer'`; + await find.existsByCssSelector(dragging); await browser.html5DragAndDrop(dragging, dropping); await this.waitForLensDragDropToFinish(); await PageObjects.header.waitUntilLoadingHasFinished(); From 7fe125afdd48276bdc5f27088aad7d6cb22ccd41 Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Fri, 20 Aug 2021 06:14:10 -0400 Subject: [PATCH 12/76] Fix black scroll bar on alert count table (#109096) (#109250) Co-authored-by: Pablo Machado --- .../alerts_kpis/alerts_count_panel/alerts_count.tsx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_count_panel/alerts_count.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_count_panel/alerts_count.tsx index 2c0be879966cc..7355c237fb680 100644 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_count_panel/alerts_count.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_count_panel/alerts_count.tsx @@ -24,8 +24,7 @@ interface AlertsCountProps { } const Wrapper = styled.div` - overflow: scroll; - margin-top: -8px; + margin-top: -${({ theme }) => theme.eui.euiSizeS}; `; const getAlertsCountTableColumns = ( @@ -70,7 +69,7 @@ export const AlertsCount = memo(({ loading, selectedStackByOpt <> {loading && } - + Date: Fri, 20 Aug 2021 11:44:11 +0100 Subject: [PATCH 13/76] skip flaky suite (#102282) --- x-pack/test/api_integration/apis/ml/modules/index.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/test/api_integration/apis/ml/modules/index.ts b/x-pack/test/api_integration/apis/ml/modules/index.ts index c6a75eccfa4c8..ffb1a14a18469 100644 --- a/x-pack/test/api_integration/apis/ml/modules/index.ts +++ b/x-pack/test/api_integration/apis/ml/modules/index.ts @@ -14,7 +14,8 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) { const fleetPackages = ['apache', 'nginx']; - describe('modules', function () { + // FLAKY: https://github.com/elastic/kibana/issues/102282 + describe.skip('modules', function () { before(async () => { // use empty_kibana to make sure the fleet setup is removed correctly after the tests await esArchiver.load('x-pack/test/functional/es_archives/empty_kibana'); From 786b6033022711e7f33f299eb7223e3e21b866f1 Mon Sep 17 00:00:00 2001 From: Gloria Hornero Date: Fri, 20 Aug 2021 13:11:05 +0200 Subject: [PATCH 14/76] Bringing cypress tests back (#109129) (#109305) * fixes threshold cypress tests * add ticket command * fixes threshold cypress tests * add ticket command * fixes 'Creates a new case with timeline and opens the timeline' test * unskips navigation tests * removes 'sets correct classes when the user starts dragging a host, but is not hovering over the data providers' test since we are not supporting drag and drop on timeline * removes drag and drop related tests from 'data_providers.spec.ts' * modifies todo on skipped exceptions tests to add more clarity * fixes 'attach' to case and local storage test Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../integration/cases/creation.spec.ts | 8 +-- .../detection_alerts/attach_to_case.spec.ts | 7 ++- .../detection_rules/threshold_rule.spec.ts | 3 +- .../integration/exceptions/from_alert.spec.ts | 2 +- .../integration/exceptions/from_rule.spec.ts | 2 +- .../integration/header/navigation.spec.ts | 4 +- .../timelines/data_providers.spec.ts | 50 +------------------ .../timelines/flyout_button.spec.ts | 13 +---- .../timelines/local_storage.spec.ts | 12 +++-- .../cypress/screens/hosts/all_hosts.ts | 2 - .../cypress/screens/hosts/external_events.ts | 8 --- .../cypress/screens/timeline.ts | 9 +--- .../cypress/tasks/create_new_rule.ts | 4 +- .../cypress/tasks/hosts/all_hosts.ts | 46 +---------------- .../cypress/tasks/timeline.ts | 17 ++++--- 15 files changed, 34 insertions(+), 153 deletions(-) delete mode 100644 x-pack/plugins/security_solution/cypress/screens/hosts/external_events.ts diff --git a/x-pack/plugins/security_solution/cypress/integration/cases/creation.spec.ts b/x-pack/plugins/security_solution/cypress/integration/cases/creation.spec.ts index 9e3b775156cab..028439ce6c3a4 100644 --- a/x-pack/plugins/security_solution/cypress/integration/cases/creation.spec.ts +++ b/x-pack/plugins/security_solution/cypress/integration/cases/creation.spec.ts @@ -11,7 +11,6 @@ import { ALL_CASES_CLOSED_CASES_STATS, ALL_CASES_COMMENTS_COUNT, ALL_CASES_IN_PROGRESS_CASES_STATS, - ALL_CASES_ITEM_ACTIONS_BTN, ALL_CASES_NAME, ALL_CASES_OPEN_CASES_COUNT, ALL_CASES_OPEN_CASES_STATS, @@ -26,7 +25,6 @@ import { import { CASE_DETAILS_DESCRIPTION, CASE_DETAILS_PAGE_TITLE, - // CASE_DETAILS_PUSH_TO_EXTERNAL_SERVICE_BTN, CASE_DETAILS_STATUS, CASE_DETAILS_TAGS, CASE_DETAILS_USER_ACTION_DESCRIPTION_USERNAME, @@ -67,8 +65,8 @@ describe('Cases', () => { .as('mycase') ); }); - // TODO: enable once attach timeline to cases is re-enabled - it.skip('Creates a new case with timeline and opens the timeline', function () { + + it('Creates a new case with timeline and opens the timeline', function () { loginAndWaitForPageWithoutDateRange(CASES_URL); goToCreateNewCase(); fillCasesMandatoryfields(this.mycase); @@ -92,7 +90,6 @@ describe('Cases', () => { cy.get(ALL_CASES_COMMENTS_COUNT).should('have.text', '0'); cy.get(ALL_CASES_OPENED_ON).should('include.text', 'ago'); cy.get(ALL_CASES_SERVICE_NOW_INCIDENT).should('have.text', 'Not pushed'); - cy.get(ALL_CASES_ITEM_ACTIONS_BTN).should('exist'); goToCaseDetails(); @@ -108,7 +105,6 @@ describe('Cases', () => { cy.get(CASE_DETAILS_USERNAMES).eq(REPORTER).should('have.text', this.mycase.reporter); cy.get(CASE_DETAILS_USERNAMES).eq(PARTICIPANTS).should('have.text', this.mycase.reporter); cy.get(CASE_DETAILS_TAGS).should('have.text', expectedTags); - // cy.get(CASE_DETAILS_PUSH_TO_EXTERNAL_SERVICE_BTN).should('have.attr', 'disabled'); openCaseTimeline(); diff --git a/x-pack/plugins/security_solution/cypress/integration/detection_alerts/attach_to_case.spec.ts b/x-pack/plugins/security_solution/cypress/integration/detection_alerts/attach_to_case.spec.ts index 9ffade9abbb02..348b03b7f6399 100644 --- a/x-pack/plugins/security_solution/cypress/integration/detection_alerts/attach_to_case.spec.ts +++ b/x-pack/plugins/security_solution/cypress/integration/detection_alerts/attach_to_case.spec.ts @@ -23,8 +23,7 @@ const loadDetectionsPage = (role: ROLES) => { waitForAlertsToPopulate(); }; -// TODO: This test may need changes in our UI based on RBAC -describe.skip('Alerts timeline', () => { +describe('Alerts timeline', () => { before(() => { // First we login as a privileged user to create alerts. cleanKibana(); @@ -45,7 +44,7 @@ describe.skip('Alerts timeline', () => { }); it('should not allow user with read only privileges to attach alerts to cases', () => { - cy.get(TIMELINE_CONTEXT_MENU_BTN).first().click(); + cy.get(TIMELINE_CONTEXT_MENU_BTN).first().click({ force: true }); cy.get(ATTACH_ALERT_TO_CASE_BUTTON).should('not.exist'); }); }); @@ -56,7 +55,7 @@ describe.skip('Alerts timeline', () => { }); it('should allow a user with crud privileges to attach alerts to cases', () => { - cy.get(TIMELINE_CONTEXT_MENU_BTN).first().click(); + cy.get(TIMELINE_CONTEXT_MENU_BTN).first().click({ force: true }); cy.get(ATTACH_ALERT_TO_CASE_BUTTON).first().should('not.be.disabled'); }); }); diff --git a/x-pack/plugins/security_solution/cypress/integration/detection_rules/threshold_rule.spec.ts b/x-pack/plugins/security_solution/cypress/integration/detection_rules/threshold_rule.spec.ts index 588642fb69d0e..7bfc9631f7269 100644 --- a/x-pack/plugins/security_solution/cypress/integration/detection_rules/threshold_rule.spec.ts +++ b/x-pack/plugins/security_solution/cypress/integration/detection_rules/threshold_rule.spec.ts @@ -81,8 +81,7 @@ import { loginAndWaitForPageWithoutDateRange } from '../../tasks/login'; import { ALERTS_URL } from '../../urls/navigation'; -// TODO: Alert counts and preview results not showing correct values. Need to fix this test -describe.skip('Detection rules, threshold', () => { +describe('Detection rules, threshold', () => { let rule = getNewThresholdRule(); const expectedUrls = getNewThresholdRule().referenceUrls.join(''); const expectedFalsePositives = getNewThresholdRule().falsePositivesExamples.join(''); diff --git a/x-pack/plugins/security_solution/cypress/integration/exceptions/from_alert.spec.ts b/x-pack/plugins/security_solution/cypress/integration/exceptions/from_alert.spec.ts index 369e65ebf1bdd..002aa0bbc2b1e 100644 --- a/x-pack/plugins/security_solution/cypress/integration/exceptions/from_alert.spec.ts +++ b/x-pack/plugins/security_solution/cypress/integration/exceptions/from_alert.spec.ts @@ -64,7 +64,7 @@ describe('From alert', () => { esArchiverUnload('auditbeat_for_exceptions2'); }); - // TODO: Looks like the signal is missing some fields. Need to update to make sure it shows up + // TODO: Unskip the test when `https://github.com/elastic/kibana/issues/108244` it is fixed it.skip('Creates an exception and deletes it', () => { addExceptionFromFirstAlert(); addsException(getException()); diff --git a/x-pack/plugins/security_solution/cypress/integration/exceptions/from_rule.spec.ts b/x-pack/plugins/security_solution/cypress/integration/exceptions/from_rule.spec.ts index 16863ab651353..c4e1d882d1853 100644 --- a/x-pack/plugins/security_solution/cypress/integration/exceptions/from_rule.spec.ts +++ b/x-pack/plugins/security_solution/cypress/integration/exceptions/from_rule.spec.ts @@ -62,7 +62,7 @@ describe('From rule', () => { esArchiverUnload('auditbeat_for_exceptions2'); }); - // TODO: Looks like the signal is missing some fields. Need to update to make sure it shows up + // TODO: Unskip the test when `https://github.com/elastic/kibana/issues/108244` it is fixed it.skip('Creates an exception and deletes it', () => { goToExceptionsTab(); addsExceptionFromRuleSettings(getException()); diff --git a/x-pack/plugins/security_solution/cypress/integration/header/navigation.spec.ts b/x-pack/plugins/security_solution/cypress/integration/header/navigation.spec.ts index 16278c919a046..15982f1674351 100644 --- a/x-pack/plugins/security_solution/cypress/integration/header/navigation.spec.ts +++ b/x-pack/plugins/security_solution/cypress/integration/header/navigation.spec.ts @@ -51,7 +51,7 @@ import { } from '../../screens/kibana_navigation'; import { cleanKibana } from '../../tasks/common'; -describe.skip('top-level navigation common to all pages in the Security app', () => { +describe('top-level navigation common to all pages in the Security app', () => { before(() => { cleanKibana(); loginAndWaitForPage(TIMELINES_URL); @@ -111,7 +111,7 @@ describe.skip('top-level navigation common to all pages in the Security app', () }); }); -describe.skip('Kibana navigation to all pages in the Security app ', () => { +describe('Kibana navigation to all pages in the Security app ', () => { before(() => { loginAndWaitForPage(KIBANA_HOME); }); diff --git a/x-pack/plugins/security_solution/cypress/integration/timelines/data_providers.spec.ts b/x-pack/plugins/security_solution/cypress/integration/timelines/data_providers.spec.ts index 5e851cecbd86b..de754f8602667 100644 --- a/x-pack/plugins/security_solution/cypress/integration/timelines/data_providers.spec.ts +++ b/x-pack/plugins/security_solution/cypress/integration/timelines/data_providers.spec.ts @@ -6,23 +6,12 @@ */ import { - TIMELINE_DATA_PROVIDERS, - TIMELINE_DATA_PROVIDERS_EMPTY, TIMELINE_DROPPED_DATA_PROVIDERS, TIMELINE_DATA_PROVIDERS_ACTION_MENU, - IS_DRAGGING_DATA_PROVIDERS, TIMELINE_FLYOUT_HEADER, - TIMELINE_FLYOUT, } from '../../screens/timeline'; -import { HOSTS_NAMES_DRAGGABLE } from '../../screens/hosts/all_hosts'; -import { - dragAndDropFirstHostToTimeline, - dragFirstHostToEmptyTimelineDataProviders, - unDragFirstHostToEmptyTimelineDataProviders, - dragFirstHostToTimeline, - waitForAllHostsToBeLoaded, -} from '../../tasks/hosts/all_hosts'; +import { waitForAllHostsToBeLoaded } from '../../tasks/hosts/all_hosts'; import { loginAndWaitForPage } from '../../tasks/login'; import { openTimelineUsingToggle } from '../../tasks/security_main'; @@ -44,22 +33,6 @@ describe('timeline data providers', () => { closeTimeline(); }); - it.skip('renders the data provider of a host dragged from the All Hosts widget on the hosts page', () => { - dragAndDropFirstHostToTimeline(); - openTimelineUsingToggle(); - cy.get(`${TIMELINE_FLYOUT} ${TIMELINE_DROPPED_DATA_PROVIDERS}`) - .first() - .invoke('text') - .then((dataProviderText) => { - cy.get(HOSTS_NAMES_DRAGGABLE) - .first() - .invoke('text') - .should((hostname) => { - expect(dataProviderText).to.eq(`host.name: "${hostname}"AND`); - }); - }); - }); - it('displays the data provider action menu when Enter is pressed', (done) => { openTimelineUsingToggle(); addDataProvider({ field: 'host.name', operator: 'exists' }).then(() => { @@ -77,25 +50,4 @@ describe('timeline data providers', () => { done(); }); }); - - it.skip('sets correct classes when the user starts dragging a host, but is not hovering over the data providers', () => { - dragFirstHostToTimeline(); - - cy.get(IS_DRAGGING_DATA_PROVIDERS) - .find(TIMELINE_DATA_PROVIDERS) - .filter(':visible') - .should('have.class', 'drop-target-data-providers'); - }); - - it.skip('render an extra highlighted area in dataProvider when the user starts dragging a host AND is hovering over the data providers', () => { - dragFirstHostToEmptyTimelineDataProviders(); - - cy.get(IS_DRAGGING_DATA_PROVIDERS) - .find(TIMELINE_DATA_PROVIDERS_EMPTY) - .children() - .should('exist'); - - // Release the dragging item so the cursor can peform other action - unDragFirstHostToEmptyTimelineDataProviders(); - }); }); diff --git a/x-pack/plugins/security_solution/cypress/integration/timelines/flyout_button.spec.ts b/x-pack/plugins/security_solution/cypress/integration/timelines/flyout_button.spec.ts index ac34d65f0fd0a..2ee658c666665 100644 --- a/x-pack/plugins/security_solution/cypress/integration/timelines/flyout_button.spec.ts +++ b/x-pack/plugins/security_solution/cypress/integration/timelines/flyout_button.spec.ts @@ -8,14 +8,12 @@ import { TIMELINE_BOTTOM_BAR_TOGGLE_BUTTON } from '../../screens/security_main'; import { CREATE_NEW_TIMELINE, - IS_DRAGGING_DATA_PROVIDERS, - TIMELINE_DATA_PROVIDERS, TIMELINE_FLYOUT_HEADER, TIMELINE_SETTINGS_ICON, } from '../../screens/timeline'; import { cleanKibana } from '../../tasks/common'; -import { dragFirstHostToTimeline, waitForAllHostsToBeLoaded } from '../../tasks/hosts/all_hosts'; +import { waitForAllHostsToBeLoaded } from '../../tasks/hosts/all_hosts'; import { loginAndWaitForPage } from '../../tasks/login'; import { closeTimelineUsingCloseButton, @@ -78,13 +76,4 @@ describe('timeline flyout button', () => { cy.get('[data-test-subj="nav-search-option"]').its('length').should('be.gte', 1); closeTimelineUsingCloseButton(); }); - - it.skip('sets correct classes when the user starts dragging a host, but is not hovering over the data providers', () => { - dragFirstHostToTimeline(); - - cy.get(IS_DRAGGING_DATA_PROVIDERS) - .find(TIMELINE_DATA_PROVIDERS) - .filter(':visible') - .should('have.class', 'drop-target-data-providers'); - }); }); diff --git a/x-pack/plugins/security_solution/cypress/integration/timelines/local_storage.spec.ts b/x-pack/plugins/security_solution/cypress/integration/timelines/local_storage.spec.ts index f6be213f59d7e..617f04697c951 100644 --- a/x-pack/plugins/security_solution/cypress/integration/timelines/local_storage.spec.ts +++ b/x-pack/plugins/security_solution/cypress/integration/timelines/local_storage.spec.ts @@ -10,12 +10,11 @@ import { loginAndWaitForPage } from '../../tasks/login'; import { HOSTS_URL } from '../../urls/navigation'; import { openEvents } from '../../tasks/hosts/main'; import { DATAGRID_HEADERS } from '../../screens/timeline'; -import { TABLE_COLUMN_EVENTS_MESSAGE } from '../../screens/hosts/external_events'; import { waitsForEventsToBeLoaded } from '../../tasks/hosts/events'; import { removeColumn } from '../../tasks/timeline'; // TODO: Fix bug in persisting the columns of timeline -describe.skip('persistent timeline', () => { +describe('persistent timeline', () => { beforeEach(() => { cleanKibana(); loginAndWaitForPage(HOSTS_URL); @@ -27,8 +26,11 @@ describe.skip('persistent timeline', () => { }); it('persist the deletion of a column', function () { - cy.get(DATAGRID_HEADERS).eq(TABLE_COLUMN_EVENTS_MESSAGE).should('have.text', 'message'); - removeColumn(TABLE_COLUMN_EVENTS_MESSAGE); + const MESSAGE_COLUMN = 'message'; + const MESSAGE_COLUMN_POSITION = 2; + + cy.get(DATAGRID_HEADERS).eq(MESSAGE_COLUMN_POSITION).should('have.text', MESSAGE_COLUMN); + removeColumn(MESSAGE_COLUMN); cy.get(DATAGRID_HEADERS).should('have.length', this.expectedNumberOfTimelineColumns); @@ -36,6 +38,6 @@ describe.skip('persistent timeline', () => { waitsForEventsToBeLoaded(); cy.get(DATAGRID_HEADERS).should('have.length', this.expectedNumberOfTimelineColumns); - cy.get(DATAGRID_HEADERS).each(($el) => expect($el.text()).not.equal('message')); + cy.get(DATAGRID_HEADERS).each(($el) => expect($el.text()).not.equal(MESSAGE_COLUMN)); }); }); diff --git a/x-pack/plugins/security_solution/cypress/screens/hosts/all_hosts.ts b/x-pack/plugins/security_solution/cypress/screens/hosts/all_hosts.ts index cf1bac421b447..b76add918beaf 100644 --- a/x-pack/plugins/security_solution/cypress/screens/hosts/all_hosts.ts +++ b/x-pack/plugins/security_solution/cypress/screens/hosts/all_hosts.ts @@ -8,5 +8,3 @@ export const ALL_HOSTS_TABLE = '[data-test-subj="table-allHosts-loading-false"]'; export const HOSTS_NAMES = '[data-test-subj="render-content-host.name"] a.euiLink'; - -export const HOSTS_NAMES_DRAGGABLE = '[data-test-subj="render-content-host.name"]'; diff --git a/x-pack/plugins/security_solution/cypress/screens/hosts/external_events.ts b/x-pack/plugins/security_solution/cypress/screens/hosts/external_events.ts deleted file mode 100644 index 01f82f8944432..0000000000000 --- a/x-pack/plugins/security_solution/cypress/screens/hosts/external_events.ts +++ /dev/null @@ -1,8 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -export const TABLE_COLUMN_EVENTS_MESSAGE = 2; diff --git a/x-pack/plugins/security_solution/cypress/screens/timeline.ts b/x-pack/plugins/security_solution/cypress/screens/timeline.ts index 0b9d39d6b0c21..4cf5d2f87f7a9 100644 --- a/x-pack/plugins/security_solution/cypress/screens/timeline.ts +++ b/x-pack/plugins/security_solution/cypress/screens/timeline.ts @@ -39,6 +39,8 @@ export const DATAGRID_HEADERS = export const FAVORITE_TIMELINE = '[data-test-subj="timeline-favorite-filled-star"]'; +export const FIELD_BROWSER = '[data-test-subj="show-field-browser"]'; + export const GRAPH_TAB_BUTTON = '[data-test-subj="timelineTabs-graph"]'; export const HEADER = '[data-test-subj="header"]'; @@ -143,12 +145,8 @@ export const TIMELINE_CORRELATION_INPUT = '[data-test-subj="eqlQueryBarTextInput export const TIMELINE_CORRELATION_TAB = '[data-test-subj="timelineTabs-eql"]'; -export const IS_DRAGGING_DATA_PROVIDERS = '.is-dragging'; - export const TIMELINE_BOTTOM_BAR_CONTAINER = '[data-test-subj="timeline-bottom-bar-container"]'; -export const TIMELINE_DATA_PROVIDERS = '[data-test-subj="dataProviders"]'; - export const TIMELINE_DATA_PROVIDERS_ACTION_MENU = '[data-test-subj="providerActions"]'; export const TIMELINE_ADD_FIELD_BUTTON = '[data-test-subj="addField"]'; @@ -161,9 +159,6 @@ export const TIMELINE_DATA_PROVIDER_VALUE = `[data-test-subj="value"]`; export const SAVE_DATA_PROVIDER_BTN = `[data-test-subj="save"]`; -export const TIMELINE_DATA_PROVIDERS_EMPTY = - '[data-test-subj="dataProviders"] [data-test-subj="empty"]'; - export const TIMELINE_DESCRIPTION = '[data-test-subj="timeline-description"]'; export const TIMELINE_DESCRIPTION_INPUT = '[data-test-subj="save-timeline-description"]'; diff --git a/x-pack/plugins/security_solution/cypress/tasks/create_new_rule.ts b/x-pack/plugins/security_solution/cypress/tasks/create_new_rule.ts index 9a500f81ec45f..63d1cbbc883b0 100644 --- a/x-pack/plugins/security_solution/cypress/tasks/create_new_rule.ts +++ b/x-pack/plugins/security_solution/cypress/tasks/create_new_rule.ts @@ -293,7 +293,8 @@ export const fillDefineThresholdRuleAndContinue = (rule: ThresholdRule) => { const thresholdField = 0; const threshold = 1; - const typeThresholdField = ($el: Cypress.ObjectLike) => cy.wrap($el).type(rule.thresholdField); + const typeThresholdField = ($el: Cypress.ObjectLike) => + cy.wrap($el).type(rule.thresholdField, { delay: 35 }); cy.get(IMPORT_QUERY_FROM_SAVED_TIMELINE_LINK).click(); cy.get(TIMELINE(rule.timeline.id!)).click(); @@ -301,6 +302,7 @@ export const fillDefineThresholdRuleAndContinue = (rule: ThresholdRule) => { cy.get(THRESHOLD_INPUT_AREA) .find(INPUT) .then((inputs) => { + cy.wrap(inputs[thresholdField]).click(); cy.wrap(inputs[thresholdField]).pipe(typeThresholdField); cy.get(THRESHOLD_FIELD_SELECTION).click({ force: true }); cy.wrap(inputs[threshold]).clear().type(rule.threshold); diff --git a/x-pack/plugins/security_solution/cypress/tasks/hosts/all_hosts.ts b/x-pack/plugins/security_solution/cypress/tasks/hosts/all_hosts.ts index 317a35708de57..cdae0437eb565 100644 --- a/x-pack/plugins/security_solution/cypress/tasks/hosts/all_hosts.ts +++ b/x-pack/plugins/security_solution/cypress/tasks/hosts/all_hosts.ts @@ -5,52 +5,8 @@ * 2.0. */ -import { ALL_HOSTS_TABLE, HOSTS_NAMES_DRAGGABLE, HOSTS_NAMES } from '../../screens/hosts/all_hosts'; -import { TIMELINE_DATA_PROVIDERS, TIMELINE_DATA_PROVIDERS_EMPTY } from '../../screens/timeline'; +import { ALL_HOSTS_TABLE, HOSTS_NAMES } from '../../screens/hosts/all_hosts'; -import { drag, dragWithoutDrop, drop } from '../../tasks/common'; - -export const dragAndDropFirstHostToTimeline = () => { - cy.get(HOSTS_NAMES_DRAGGABLE) - .first() - .then((firstHost) => drag(firstHost)); - cy.get(TIMELINE_DATA_PROVIDERS) - .filter(':visible') - .then((dataProvidersDropArea) => drop(dataProvidersDropArea)); -}; - -export const dragFirstHostToEmptyTimelineDataProviders = () => { - cy.get(HOSTS_NAMES_DRAGGABLE) - .first() - .then((host) => drag(host)); - - cy.get(TIMELINE_DATA_PROVIDERS_EMPTY) - .filter(':visible') - .then((dataProvidersDropArea) => dragWithoutDrop(dataProvidersDropArea)); -}; - -export const unDragFirstHostToEmptyTimelineDataProviders = () => { - cy.get(HOSTS_NAMES_DRAGGABLE) - .first() - .then((host) => { - cy.wrap(host) - .trigger('mousemove', { - button: 0, - clientX: host[0].getBoundingClientRect().left, - clientY: host[0].getBoundingClientRect().top, - force: true, - }) - .wait(300) - .trigger('mouseup', { force: true }) - .wait(300); - }); -}; - -export const dragFirstHostToTimeline = () => { - cy.get(HOSTS_NAMES_DRAGGABLE) - .first() - .then((host) => drag(host)); -}; export const openFirstHostDetails = () => { cy.get(HOSTS_NAMES).first().click({ force: true }); }; diff --git a/x-pack/plugins/security_solution/cypress/tasks/timeline.ts b/x-pack/plugins/security_solution/cypress/tasks/timeline.ts index 4a61a94e4acea..03ccb784bd259 100644 --- a/x-pack/plugins/security_solution/cypress/tasks/timeline.ts +++ b/x-pack/plugins/security_solution/cypress/tasks/timeline.ts @@ -8,6 +8,7 @@ import { Timeline, TimelineFilter } from '../objects/timeline'; import { ALL_CASES_CREATE_NEW_CASE_TABLE_BTN } from '../screens/all_cases'; +import { FIELDS_BROWSER_CHECKBOX } from '../screens/fields_browser'; import { LOADING_INDICATOR } from '../screens/security_header'; import { @@ -20,7 +21,7 @@ import { CLOSE_TIMELINE_BTN, COMBO_BOX, CREATE_NEW_TIMELINE, - DATAGRID_HEADERS, + FIELD_BROWSER, ID_FIELD, ID_HEADER_FIELD, ID_TOGGLE_FIELD, @@ -70,6 +71,8 @@ import { REFRESH_BUTTON, TIMELINE } from '../screens/timelines'; import { drag, drop } from '../tasks/common'; +import { closeFieldsBrowser, filterFieldsBrowser } from '../tasks/fields_browser'; + export const hostExistsQuery = 'host.name: *'; export const addDescriptionToTimeline = (description: string) => { @@ -327,13 +330,11 @@ export const dragAndDropIdToggleFieldToTimeline = () => { .then((headersDropArea) => drop(headersDropArea)); }; -export const removeColumn = (column: number) => { - cy.get(DATAGRID_HEADERS) - .eq(column) - .click() - .within(() => { - cy.get('button').eq(0).click({ force: true }); - }); +export const removeColumn = (columnName: string) => { + cy.get(FIELD_BROWSER).first().click(); + filterFieldsBrowser(columnName); + cy.get(FIELDS_BROWSER_CHECKBOX(columnName)).click(); + closeFieldsBrowser(); }; export const resetFields = () => { From 052b0b1768901923636bd7220d6e73306e9063a3 Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Fri, 20 Aug 2021 07:19:14 -0400 Subject: [PATCH 15/76] [Security Solution] TopN chart styling issue (#109007) (#109283) * fix topN style * add unit tests for topN * add unit tests * review Co-authored-by: Angela Chuang <6295984+angorayc@users.noreply.github.com> --- .../hover_actions/actions/show_top_n.test.tsx | 166 ++++++++++++++++++ .../hover_actions/actions/show_top_n.tsx | 93 +++++++--- .../use_hover_action_items.test.tsx | 115 ++++++++++++ .../hover_actions/use_hover_action_items.tsx | 15 +- .../lib/cell_actions/default_cell_actions.tsx | 1 + .../hover_actions/actions/overflow.tsx | 8 +- 6 files changed, 361 insertions(+), 37 deletions(-) create mode 100644 x-pack/plugins/security_solution/public/common/components/hover_actions/actions/show_top_n.test.tsx create mode 100644 x-pack/plugins/security_solution/public/common/components/hover_actions/use_hover_action_items.test.tsx diff --git a/x-pack/plugins/security_solution/public/common/components/hover_actions/actions/show_top_n.test.tsx b/x-pack/plugins/security_solution/public/common/components/hover_actions/actions/show_top_n.test.tsx new file mode 100644 index 0000000000000..06b90a129136b --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/hover_actions/actions/show_top_n.test.tsx @@ -0,0 +1,166 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { EuiButtonEmpty, EuiContextMenuItem } from '@elastic/eui'; +import { mount } from 'enzyme'; +import React from 'react'; +import { TestProviders } from '../../../mock'; +import { ShowTopNButton } from './show_top_n'; + +describe('show topN button', () => { + const defaultProps = { + field: 'signal.rule.name', + onClick: jest.fn(), + ownFocus: false, + showTopN: false, + timelineId: 'timeline-1', + value: ['rule_name'], + }; + + describe('button', () => { + test('should show EuiButtonIcon by default', () => { + const wrapper = mount( + + + + ); + expect(wrapper.find('EuiButtonIcon').exists()).toBeTruthy(); + expect(wrapper.find('[data-test-subj="show-top-field"]').first().prop('iconType')).toEqual( + 'visBarVertical' + ); + }); + + test('should support EuiButtonEmpty', () => { + const testProps = { + ...defaultProps, + Component: EuiButtonEmpty, + }; + const wrapper = mount( + + + + ); + expect(wrapper.find('EuiButtonIcon').exists()).toBeFalsy(); + expect(wrapper.find('EuiButtonEmpty').exists()).toBeTruthy(); + expect(wrapper.find('[data-test-subj="show-top-field"]').first().prop('iconType')).toEqual( + 'visBarVertical' + ); + }); + + test('should support EuiContextMenuItem', () => { + const testProps = { + ...defaultProps, + Component: EuiContextMenuItem, + }; + const wrapper = mount( + + + + ); + expect(wrapper.find('EuiButtonIcon').exists()).toBeFalsy(); + expect(wrapper.find('EuiContextMenuItem').exists()).toBeTruthy(); + expect(wrapper.find('[data-test-subj="show-top-field"]').first().prop('icon')).toEqual( + 'visBarVertical' + ); + }); + }); + + describe('tooltip', () => { + test('should show tooltip by default', () => { + const wrapper = mount( + + + + ); + expect(wrapper.find('EuiToolTip').exists()).toBeTruthy(); + }); + + test('should hide tooltip when topN is showed', () => { + const testProps = { + ...defaultProps, + showTopN: true, + }; + const wrapper = mount( + + + + ); + expect(wrapper.find('EuiToolTip').exists()).toBeFalsy(); + }); + + test('should hide tooltip by setting showTooltip to false', () => { + const testProps = { + ...defaultProps, + showTooltip: false, + }; + const wrapper = mount( + + + + ); + expect(wrapper.find('EuiToolTip').exists()).toBeFalsy(); + }); + }); + + describe('popover', () => { + test('should be able to show topN without a popover', () => { + const testProps = { + ...defaultProps, + enablePopOver: false, + showTopN: true, + }; + const wrapper = mount( + + + + ); + expect(wrapper.find('[data-test-subj="top-n"]').exists()).toBeTruthy(); + expect(wrapper.find('[data-test-subj="showTopNContainer"]').exists()).toBeFalsy(); + }); + test('should be able to show topN within a popover', () => { + const testProps = { + ...defaultProps, + enablePopOver: true, + showTopN: true, + }; + const wrapper = mount( + + + + ); + expect(wrapper.find('[data-test-subj="top-n"]').exists()).toBeTruthy(); + expect(wrapper.find('[data-test-subj="showTopNContainer"]').exists()).toBeTruthy(); + }); + }); + + describe('topN', () => { + test('should render with correct props', () => { + const onFilterAdded = jest.fn(); + const testProps = { + ...defaultProps, + enablePopOver: true, + showTopN: true, + onFilterAdded, + }; + const wrapper = mount( + + + + ); + expect(wrapper.find('[data-test-subj="top-n"]').prop('field')).toEqual(testProps.field); + expect(wrapper.find('[data-test-subj="top-n"]').prop('value')).toEqual(testProps.value); + expect(wrapper.find('[data-test-subj="top-n"]').prop('toggleTopN')).toEqual( + testProps.onClick + ); + expect(wrapper.find('[data-test-subj="top-n"]').prop('timelineId')).toEqual( + testProps.timelineId + ); + expect(wrapper.find('[data-test-subj="top-n"]').prop('onFilterAdded')).toEqual( + testProps.onFilterAdded + ); + }); + }); +}); diff --git a/x-pack/plugins/security_solution/public/common/components/hover_actions/actions/show_top_n.tsx b/x-pack/plugins/security_solution/public/common/components/hover_actions/actions/show_top_n.tsx index dbb00eb90e2af..0d6e59483fbc4 100644 --- a/x-pack/plugins/security_solution/public/common/components/hover_actions/actions/show_top_n.tsx +++ b/x-pack/plugins/security_solution/public/common/components/hover_actions/actions/show_top_n.tsx @@ -6,7 +6,13 @@ */ import React, { useMemo } from 'react'; -import { EuiButtonEmpty, EuiButtonIcon, EuiContextMenuItem, EuiToolTip } from '@elastic/eui'; +import { + EuiButtonEmpty, + EuiPopover, + EuiButtonIcon, + EuiContextMenuItem, + EuiToolTip, +} from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { StatefulTopN } from '../../top_n'; import { TimelineId } from '../../../../../common/types/timeline'; @@ -23,8 +29,11 @@ const SHOW_TOP = (fieldName: string) => }); interface Props { - /** `Component` is only used with `EuiDataGrid`; the grid keeps a reference to `Component` for show / hide functionality */ + /** When `Component` is used with `EuiDataGrid`; the grid keeps a reference to `Component` for show / hide functionality. + * When `Component` is used with `EuiContextMenu`, we pass EuiContextMenuItem to render the right style. + */ Component?: typeof EuiButtonEmpty | typeof EuiButtonIcon | typeof EuiContextMenuItem; + enablePopOver?: boolean; field: string; onClick: () => void; onFilterAdded?: () => void; @@ -38,6 +47,7 @@ interface Props { export const ShowTopNButton: React.FC = React.memo( ({ Component, + enablePopOver, field, onClick, onFilterAdded, @@ -58,7 +68,7 @@ export const ShowTopNButton: React.FC = React.memo( : SourcererScopeName.default; const { browserFields, indexPattern } = useSourcererScope(activeScope); - const button = useMemo( + const basicButton = useMemo( () => Component ? ( = React.memo( [Component, field, onClick] ); + const button = useMemo( + () => + showTooltip && !showTopN ? ( + + } + > + {basicButton} + + ) : ( + basicButton + ), + [basicButton, field, ownFocus, showTooltip, showTopN, value] + ); + + const topNPannel = useMemo( + () => ( + + ), + [browserFields, field, indexPattern, onClick, onFilterAdded, timelineId, value] + ); + return showTopN ? ( - - ) : showTooltip ? ( - - } - > - {button} - + enablePopOver ? ( + + {topNPannel} + + ) : ( + topNPannel + ) ) : ( button ); diff --git a/x-pack/plugins/security_solution/public/common/components/hover_actions/use_hover_action_items.test.tsx b/x-pack/plugins/security_solution/public/common/components/hover_actions/use_hover_action_items.test.tsx new file mode 100644 index 0000000000000..2ef72571cf307 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/hover_actions/use_hover_action_items.test.tsx @@ -0,0 +1,115 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { useRef } from 'react'; +import { renderHook, act } from '@testing-library/react-hooks'; +import { useHoverActionItems, UseHoverActionItemsProps } from './use_hover_action_items'; +import { useDeepEqualSelector } from '../../hooks/use_selector'; +import { DataProvider } from '../../../../common/types/timeline'; + +jest.mock('../../lib/kibana'); +jest.mock('../../hooks/use_selector'); +jest.mock('../../containers/sourcerer', () => ({ + useSourcererScope: jest.fn().mockReturnValue({ browserFields: {} }), +})); + +describe('useHoverActionItems', () => { + const defaultProps: UseHoverActionItemsProps = ({ + dataProvider: [{} as DataProvider], + defaultFocusedButtonRef: null, + field: 'signal.rule.name', + handleHoverActionClicked: jest.fn(), + isObjectArray: true, + ownFocus: false, + showTopN: false, + stKeyboardEvent: undefined, + toggleColumn: jest.fn(), + toggleTopN: jest.fn(), + values: ['rule name'], + } as unknown) as UseHoverActionItemsProps; + + beforeEach(() => { + (useDeepEqualSelector as jest.Mock).mockImplementation((cb) => { + return cb(); + }); + }); + afterEach(() => { + (useDeepEqualSelector as jest.Mock).mockClear(); + }); + + test('should return allActionItems', async () => { + await act(async () => { + const { result, waitForNextUpdate } = renderHook(() => { + const defaultFocusedButtonRef = useRef(null); + const testProps = { + ...defaultProps, + defaultFocusedButtonRef, + }; + return useHoverActionItems(testProps); + }); + await waitForNextUpdate(); + + expect(result.current.allActionItems).toHaveLength(6); + expect(result.current.allActionItems[0].props['data-test-subj']).toEqual( + 'hover-actions-filter-for' + ); + expect(result.current.allActionItems[1].props['data-test-subj']).toEqual( + 'hover-actions-filter-out' + ); + expect(result.current.allActionItems[2].props['data-test-subj']).toEqual( + 'hover-actions-toggle-column' + ); + expect(result.current.allActionItems[3].props['data-test-subj']).toEqual( + 'hover-actions-add-timeline' + ); + expect(result.current.allActionItems[4].props['data-test-subj']).toEqual( + 'hover-actions-show-top-n' + ); + expect(result.current.allActionItems[5].props['data-test-subj']).toEqual( + 'hover-actions-copy-button' + ); + }); + }); + + test('should return overflowActionItems', async () => { + await act(async () => { + const { result, waitForNextUpdate } = renderHook(() => { + const defaultFocusedButtonRef = useRef(null); + const testProps = { + ...defaultProps, + defaultFocusedButtonRef, + enableOverflowButton: true, + }; + return useHoverActionItems(testProps); + }); + await waitForNextUpdate(); + + expect(result.current.overflowActionItems).toHaveLength(3); + expect(result.current.overflowActionItems[0].props['data-test-subj']).toEqual( + 'hover-actions-filter-for' + ); + expect(result.current.overflowActionItems[1].props['data-test-subj']).toEqual( + 'hover-actions-filter-out' + ); + expect(result.current.overflowActionItems[2].props['data-test-subj']).toEqual( + 'more-actions-signal.rule.name' + ); + expect(result.current.overflowActionItems[2].props.items[0].props['data-test-subj']).toEqual( + 'hover-actions-toggle-column' + ); + + expect(result.current.overflowActionItems[2].props.items[1].props['data-test-subj']).toEqual( + 'hover-actions-add-timeline' + ); + expect(result.current.overflowActionItems[2].props.items[2].props['data-test-subj']).toEqual( + 'hover-actions-show-top-n' + ); + expect(result.current.overflowActionItems[2].props.items[3].props['data-test-subj']).toEqual( + 'hover-actions-copy-button' + ); + }); + }); +}); diff --git a/x-pack/plugins/security_solution/public/common/components/hover_actions/use_hover_action_items.tsx b/x-pack/plugins/security_solution/public/common/components/hover_actions/use_hover_action_items.tsx index c8dc7b59b8a7d..a7e4a528ca1b8 100644 --- a/x-pack/plugins/security_solution/public/common/components/hover_actions/use_hover_action_items.tsx +++ b/x-pack/plugins/security_solution/public/common/components/hover_actions/use_hover_action_items.tsx @@ -21,7 +21,7 @@ import { useSourcererScope } from '../../containers/sourcerer'; import { timelineSelectors } from '../../../timelines/store/timeline'; import { ShowTopNButton } from './actions/show_top_n'; -interface UseHoverActionItemsProps { +export interface UseHoverActionItemsProps { dataProvider?: DataProvider | DataProvider[]; dataType?: string; defaultFocusedButtonRef: React.MutableRefObject; @@ -43,7 +43,7 @@ interface UseHoverActionItemsProps { values?: string[] | string | null; } -interface UseHoverActionItems { +export interface UseHoverActionItems { overflowActionItems: JSX.Element[]; allActionItems: JSX.Element[]; } @@ -116,7 +116,6 @@ export const useHoverActionItems = ({ */ const showFilters = values != null && (enableOverflowButton || (!showTopN && !enableOverflowButton)); - const allItems = useMemo( () => [ @@ -243,7 +242,7 @@ export const useHoverActionItems = ({ ] ) as JSX.Element[]; - const overflowBtn = useMemo( + const showTopNBtn = useMemo( () => ( (showTopN ? [overflowBtn] : allItems), [ + const allActionItems = useMemo(() => (showTopN ? [showTopNBtn] : allItems), [ allItems, - overflowBtn, + showTopNBtn, showTopN, ]); diff --git a/x-pack/plugins/security_solution/public/common/lib/cell_actions/default_cell_actions.tsx b/x-pack/plugins/security_solution/public/common/lib/cell_actions/default_cell_actions.tsx index 951d921653c15..085b2098cde35 100644 --- a/x-pack/plugins/security_solution/public/common/lib/cell_actions/default_cell_actions.tsx +++ b/x-pack/plugins/security_solution/public/common/lib/cell_actions/default_cell_actions.tsx @@ -140,6 +140,7 @@ export const defaultCellActions: TGridCellAction[] = [ }) && ( = React.memo( ({ closePopOver, @@ -91,9 +96,10 @@ const OverflowButton: React.FC = React.memo( isOpen={isOverflowPopoverOpen} closePopover={closePopOver} panelPaddingSize="none" + panelClassName="withHoverActions__popover" anchorPosition="downLeft" > - + ), [ From f0f4b4c2d6ae34e2480d91ad2299ee783c6d9407 Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Fri, 20 Aug 2021 07:56:30 -0400 Subject: [PATCH 16/76] [RAC] Update alert status column in alerts table (#108695) (#109063) * Update alert status in alerts table Co-authored-by: Kerry Gallagher <471693+Kerry350@users.noreply.github.com> --- .../pages/alerts/alerts_table_t_grid.tsx | 4 +- .../public/pages/alerts/render_cell_value.tsx | 44 ++++++++++++------- 2 files changed, 29 insertions(+), 19 deletions(-) diff --git a/x-pack/plugins/observability/public/pages/alerts/alerts_table_t_grid.tsx b/x-pack/plugins/observability/public/pages/alerts/alerts_table_t_grid.tsx index d8ba7a96ad2c6..754e568e3befd 100644 --- a/x-pack/plugins/observability/public/pages/alerts/alerts_table_t_grid.tsx +++ b/x-pack/plugins/observability/public/pages/alerts/alerts_table_t_grid.tsx @@ -110,10 +110,10 @@ export const columns: Array< { columnHeaderType: 'not-filtered', displayAsText: i18n.translate('xpack.observability.alertsTGrid.statusColumnDescription', { - defaultMessage: 'Status', + defaultMessage: 'Alert Status', }), id: ALERT_STATUS, - initialWidth: 79, + initialWidth: 110, }, { columnHeaderType: 'not-filtered', diff --git a/x-pack/plugins/observability/public/pages/alerts/render_cell_value.tsx b/x-pack/plugins/observability/public/pages/alerts/render_cell_value.tsx index 03b79a77baadc..d96751b4eb33a 100644 --- a/x-pack/plugins/observability/public/pages/alerts/render_cell_value.tsx +++ b/x-pack/plugins/observability/public/pages/alerts/render_cell_value.tsx @@ -4,7 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { EuiIconTip, EuiLink } from '@elastic/eui'; +import { EuiLink, EuiHealth, EuiText } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import React, { useEffect } from 'react'; /** @@ -34,6 +34,7 @@ import { SeverityBadge } from './severity_badge'; import { TopAlert } from '.'; import { parseAlert } from './parse_alert'; import { usePluginContext } from '../../hooks/use_plugin_context'; +import { useTheme } from '../../hooks/use_theme'; const ALERT_DURATION: typeof ALERT_DURATION_TYPED = ALERT_DURATION_NON_TYPED; const ALERT_SEVERITY: typeof ALERT_SEVERITY_TYPED = ALERT_SEVERITY_NON_TYPED; @@ -86,24 +87,33 @@ export const getRenderCellValue = ({ } }, [columnId, setCellProps]); + const theme = useTheme(); + switch (columnId) { case ALERT_STATUS: - return value !== 'closed' ? ( - - ) : ( - - ); + switch (value) { + case 'open': + return ( + + {i18n.translate('xpack.observability.alertsTGrid.statusActiveDescription', { + defaultMessage: 'Active', + })} + + ); + case 'closed': + return ( + + + {i18n.translate('xpack.observability.alertsTGrid.statusRecoveredDescription', { + defaultMessage: 'Recovered', + })} + + + ); + default: + // NOTE: This fallback shouldn't be needed. Status should be either "active" or "recovered". + return null; + } case TIMESTAMP: return ; case ALERT_DURATION: From a7289d1da82deb0b89b75c2417c35c2889b1010a Mon Sep 17 00:00:00 2001 From: Stratoula Kalafateli Date: Fri, 20 Aug 2021 15:07:08 +0300 Subject: [PATCH 17/76] Move to vis types part 1 (#107535) (#109393) * Move to vis types part 1 * Fix types * fix more types * Fix paths * Update readme file Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> # Conflicts: # .github/CODEOWNERS --- .i18nrc.json | 6 ++--- docs/developer/plugin-list.asciidoc | 6 ++--- jest.config.js | 1 + src/dev/typescript/projects.ts | 1 + src/plugins/vis_type_pie/tsconfig.json | 24 ----------------- src/plugins/vis_type_vislib/tsconfig.json | 26 ------------------- src/plugins/vis_type_xy/tsconfig.json | 24 ----------------- src/plugins/vis_types/README.md | 19 ++++++++++++++ .../pie}/common/index.ts | 0 .../pie}/jest.config.js | 4 +-- .../pie}/kibana.json | 0 .../public/__snapshots__/pie_fn.test.ts.snap | 0 .../public/__snapshots__/to_ast.test.ts.snap | 0 .../pie}/public/chart.scss | 0 .../pie}/public/components/chart_split.tsx | 2 +- .../pie}/public/editor/collections.ts | 0 .../pie}/public/editor/components/index.tsx | 2 +- .../public/editor/components/pie.test.tsx | 2 +- .../pie}/public/editor/components/pie.tsx | 6 ++--- .../components/truncate_labels.test.tsx | 0 .../editor/components/truncate_labels.tsx | 0 .../pie}/public/editor/positions.ts | 0 .../public/expression_functions/pie_labels.ts | 2 +- .../pie}/public/index.ts | 0 .../pie}/public/mocks.ts | 2 +- .../pie}/public/pie_component.test.tsx | 4 +-- .../pie}/public/pie_component.tsx | 14 ++++++---- .../pie}/public/pie_fn.test.ts | 4 +-- .../pie}/public/pie_fn.ts | 4 +-- .../pie}/public/pie_renderer.tsx | 6 ++--- .../pie}/public/plugin.ts | 10 +++---- .../pie}/public/sample_vis.test.mocks.ts | 0 .../pie}/public/to_ast.test.ts | 2 +- .../pie}/public/to_ast.ts | 4 +-- .../pie}/public/to_ast_esaggs.ts | 6 ++--- .../pie}/public/types/index.ts | 0 .../pie}/public/types/types.ts | 6 ++--- .../pie}/public/utils/filter_helpers.test.ts | 2 +- .../pie}/public/utils/filter_helpers.ts | 10 +++---- .../public/utils/get_color_picker.test.tsx | 4 +-- .../pie}/public/utils/get_color_picker.tsx | 6 ++--- .../pie}/public/utils/get_columns.test.ts | 0 .../pie}/public/utils/get_columns.ts | 2 +- .../pie}/public/utils/get_config.ts | 0 .../public/utils/get_distinct_series.test.ts | 0 .../pie}/public/utils/get_distinct_series.ts | 2 +- .../pie}/public/utils/get_layers.test.ts | 6 ++--- .../pie}/public/utils/get_layers.ts | 6 ++--- .../pie}/public/utils/get_legend_actions.tsx | 4 +-- .../utils/get_split_dimension_accessor.ts | 4 +-- .../pie}/public/utils/index.ts | 0 .../pie}/public/vis_type/index.ts | 0 .../pie}/public/vis_type/pie.ts | 4 +-- .../pie}/server/index.ts | 0 .../pie}/server/plugin.ts | 0 src/plugins/vis_types/pie/tsconfig.json | 24 +++++++++++++++++ .../vislib}/common/index.ts | 0 .../vislib}/jest.config.js | 4 +-- .../vislib}/kibana.json | 0 .../public/__snapshots__/pie_fn.test.ts.snap | 0 .../public/__snapshots__/to_ast.test.ts.snap | 0 .../__snapshots__/to_ast_pie.test.ts.snap | 0 .../vislib}/public/area.ts | 4 +-- .../vislib}/public/editor/collections.ts | 4 +-- .../public/editor/components/gauge/index.tsx | 0 .../editor/components/gauge/labels_panel.tsx | 2 +- .../editor/components/gauge/ranges_panel.tsx | 4 +-- .../editor/components/gauge/style_panel.tsx | 4 +-- .../editor/components/heatmap/index.tsx | 4 +-- .../components/heatmap/labels_panel.tsx | 4 +-- .../public/editor/components/index.tsx | 0 .../vislib}/public/editor/index.ts | 0 .../dispatch_bar_chart_config_normal.json | 0 .../dispatch_bar_chart_config_percentage.json | 0 .../fixtures/dispatch_bar_chart_d3.json | 0 .../dispatch_bar_chart_data_point.json | 0 .../fixtures/dispatch_heatmap_config.json | 0 .../public/fixtures/dispatch_heatmap_d3.json | 0 .../fixtures/dispatch_heatmap_data_point.json | 0 .../mock_data/date_histogram/_columns.js | 0 .../mock_data/date_histogram/_rows.js | 0 .../date_histogram/_rows_series_with_holes.js | 0 .../mock_data/date_histogram/_series.js | 0 .../_series_monthly_interval.js | 0 .../mock_data/date_histogram/_series_neg.js | 0 .../date_histogram/_series_pos_neg.js | 0 .../date_histogram/_stacked_series.js | 0 .../fixtures/mock_data/filters/_columns.js | 0 .../fixtures/mock_data/filters/_rows.js | 0 .../fixtures/mock_data/filters/_series.js | 0 .../fixtures/mock_data/geohash/_columns.js | 0 .../fixtures/mock_data/geohash/_geo_json.js | 0 .../fixtures/mock_data/geohash/_rows.js | 0 .../fixtures/mock_data/histogram/_columns.js | 0 .../fixtures/mock_data/histogram/_rows.js | 0 .../fixtures/mock_data/histogram/_series.js | 0 .../fixtures/mock_data/histogram/_slices.js | 0 .../mock_data/not_enough_data/_one_point.js | 0 .../fixtures/mock_data/range/_columns.js | 0 .../public/fixtures/mock_data/range/_rows.js | 0 .../fixtures/mock_data/range/_series.js | 0 .../mock_data/significant_terms/_columns.js | 0 .../mock_data/significant_terms/_rows.js | 0 .../mock_data/significant_terms/_series.js | 0 .../fixtures/mock_data/stacked/_stacked.js | 0 .../fixtures/mock_data/terms/_columns.js | 0 .../public/fixtures/mock_data/terms/_rows.js | 0 .../fixtures/mock_data/terms/_series.js | 0 .../mock_data/terms/_series_multiple.js | 0 .../vislib}/public/fixtures/mocks.js | 0 .../vislib}/public/gauge.ts | 8 +++--- .../vislib}/public/goal.ts | 6 ++--- .../vislib}/public/heatmap.ts | 10 +++---- .../vislib}/public/histogram.ts | 4 +-- .../vislib}/public/horizontal_bar.ts | 4 +-- .../vislib}/public/index.scss | 0 .../vislib}/public/index.ts | 2 +- .../vislib}/public/line.ts | 4 +-- .../vislib}/public/pie.ts | 4 +-- .../vislib}/public/pie_fn.test.ts | 2 +- .../vislib}/public/pie_fn.ts | 2 +- .../vislib}/public/plugin.ts | 14 +++++----- .../vislib}/public/services.ts | 4 +-- .../vislib}/public/to_ast.test.ts | 10 +++---- .../vislib}/public/to_ast.ts | 10 +++---- .../vislib}/public/to_ast_esaggs.ts | 6 ++--- .../vislib}/public/to_ast_pie.test.ts | 10 +++---- .../vislib}/public/to_ast_pie.ts | 4 +-- .../vislib}/public/types.ts | 4 +-- .../vislib}/public/vis_controller.tsx | 8 +++--- .../vislib}/public/vis_renderer.tsx | 6 ++--- .../vislib}/public/vis_type_vislib_vis_fn.ts | 2 +- .../public/vis_type_vislib_vis_types.ts | 0 .../vislib}/public/vis_wrapper.tsx | 6 ++--- .../vislib}/public/vislib/VISLIB.md | 0 .../vislib}/public/vislib/_index.scss | 0 .../vislib}/public/vislib/_variables.scss | 0 .../public/vislib/_vislib_vis_type.scss | 0 .../vislib/components/labels/data_array.js | 0 .../components/labels/flatten_series.js | 0 .../public/vislib/components/labels/index.js | 0 .../public/vislib/components/labels/labels.js | 0 .../vislib/components/labels/labels.test.js | 0 .../components/labels/truncate_labels.js | 0 .../vislib/components/labels/uniq_labels.js | 0 .../legend/__snapshots__/legend.test.tsx.snap | 0 .../vislib/components/legend/_index.scss | 0 .../vislib/components/legend/_legend.scss | 0 .../public/vislib/components/legend/index.ts | 0 .../vislib/components/legend/legend.test.tsx | 0 .../vislib/components/legend/legend.tsx | 4 +-- .../vislib/components/legend/legend_item.tsx | 2 +- .../public/vislib/components/legend/models.ts | 0 .../vislib/components/legend/pie_utils.ts | 2 +- .../components/tooltip/_collect_branch.js | 0 .../tooltip/_collect_branch.test.js | 0 .../_hierarchical_tooltip_formatter.js | 0 .../vislib/components/tooltip/_index.scss | 0 .../tooltip/_pointseries_tooltip_formatter.js | 2 +- .../_pointseries_tooltip_formatter.test.js | 0 .../vislib/components/tooltip/_tooltip.scss | 0 .../public/vislib/components/tooltip/index.js | 0 .../components/tooltip/position_tooltip.js | 0 .../tooltip/position_tooltip.test.js | 0 .../vislib/components/tooltip/tooltip.js | 0 .../components/zero_injection/flatten_data.js | 0 .../components/zero_injection/inject_zeros.js | 0 .../zero_injection/ordered_x_keys.js | 0 .../components/zero_injection/uniq_keys.js | 0 .../zero_injection/zero_fill_data_array.js | 0 .../zero_injection/zero_filled_array.js | 0 .../zero_injection/zero_injection.test.js | 0 .../vislib}/public/vislib/errors.ts | 2 +- .../build_hierarchical_data.test.ts | 2 +- .../hierarchical/build_hierarchical_data.ts | 2 +- .../vislib}/public/vislib/helpers/index.ts | 0 .../helpers/point_series/_add_to_siri.test.ts | 2 +- .../helpers/point_series/_add_to_siri.ts | 4 +-- .../point_series/_fake_x_aspect.test.ts | 0 .../helpers/point_series/_fake_x_aspect.ts | 0 .../helpers/point_series/_get_aspects.test.ts | 2 +- .../helpers/point_series/_get_aspects.ts | 2 +- .../helpers/point_series/_get_point.test.ts | 2 +- .../vislib/helpers/point_series/_get_point.ts | 0 .../helpers/point_series/_get_series.test.ts | 0 .../helpers/point_series/_get_series.ts | 0 .../helpers/point_series/_init_x_axis.test.ts | 2 +- .../helpers/point_series/_init_x_axis.ts | 0 .../helpers/point_series/_init_y_axis.test.ts | 0 .../helpers/point_series/_init_y_axis.ts | 0 .../point_series/_ordered_date_axis.test.ts | 2 +- .../point_series/_ordered_date_axis.ts | 0 .../vislib/helpers/point_series/index.ts | 0 .../helpers/point_series/point_series.test.ts | 2 +- .../helpers/point_series/point_series.ts | 4 +-- .../dispatch_heatmap.test.js.snap | 0 .../vislib}/public/vislib/lib/_alerts.scss | 0 .../vislib}/public/vislib/lib/_data_label.js | 0 .../public/vislib/lib/_error_handler.js | 0 .../public/vislib/lib/_error_handler.test.js | 0 .../vislib}/public/vislib/lib/_index.scss | 0 .../vislib}/public/vislib/lib/alerts.js | 0 .../vislib}/public/vislib/lib/axis/axis.js | 0 .../public/vislib/lib/axis/axis.test.js | 0 .../public/vislib/lib/axis/axis_config.js | 0 .../public/vislib/lib/axis/axis_labels.js | 0 .../public/vislib/lib/axis/axis_scale.js | 0 .../public/vislib/lib/axis/axis_title.js | 0 .../public/vislib/lib/axis/axis_title.test.js | 0 .../vislib}/public/vislib/lib/axis/index.js | 0 .../public/vislib/lib/axis/scale_modes.js | 0 .../public/vislib/lib/axis/time_ticks.js | 0 .../public/vislib/lib/axis/time_ticks.test.js | 0 .../public/vislib/lib/axis/x_axis.test.js | 0 .../public/vislib/lib/axis/y_axis.test.js | 0 .../vislib}/public/vislib/lib/binder.ts | 0 .../vislib}/public/vislib/lib/chart_grid.js | 0 .../vislib}/public/vislib/lib/chart_title.js | 0 .../public/vislib/lib/chart_title.test.js | 0 .../vislib}/public/vislib/lib/data.js | 0 .../vislib}/public/vislib/lib/data.test.js | 0 .../vislib}/public/vislib/lib/dispatch.js | 0 .../public/vislib/lib/dispatch.test.js | 0 .../vislib/lib/dispatch_heatmap.test.js | 0 .../lib/dispatch_vertical_bar_chart.test.js | 0 .../vislib}/public/vislib/lib/handler.js | 2 +- .../vislib}/public/vislib/lib/handler.test.js | 0 .../public/vislib/lib/layout/_index.scss | 0 .../public/vislib/lib/layout/_layout.scss | 0 .../vislib}/public/vislib/lib/layout/index.js | 0 .../public/vislib/lib/layout/layout.js | 0 .../public/vislib/lib/layout/layout.test.js | 0 .../public/vislib/lib/layout/layout_types.js | 0 .../vislib/lib/layout/layout_types.test.js | 0 .../layout/splits/column_chart/chart_split.js | 0 .../splits/column_chart/chart_title_split.js | 0 .../layout/splits/column_chart/splits.test.js | 0 .../splits/column_chart/x_axis_split.js | 0 .../splits/column_chart/y_axis_split.js | 0 .../layout/splits/gauge_chart/chart_split.js | 0 .../splits/gauge_chart/chart_title_split.js | 0 .../layout/splits/gauge_chart/splits.test.js | 0 .../layout/splits/pie_chart/chart_split.js | 0 .../splits/pie_chart/chart_title_split.js | 0 .../vislib/lib/layout/types/column_layout.js | 0 .../lib/layout/types/column_layout.test.js | 0 .../vislib/lib/layout/types/gauge_layout.js | 0 .../vislib/lib/layout/types/pie_layout.js | 0 .../vislib}/public/vislib/lib/types/gauge.js | 0 .../vislib}/public/vislib/lib/types/index.js | 0 .../vislib}/public/vislib/lib/types/pie.js | 0 .../public/vislib/lib/types/point_series.js | 0 .../vislib/lib/types/point_series.test.js | 0 .../types/testdata_linechart_percentile.json | 0 ...data_linechart_percentile_float_value.json | 0 ...nechart_percentile_float_value_result.json | 0 .../testdata_linechart_percentile_result.json | 0 .../vislib}/public/vislib/lib/vis_config.js | 0 .../public/vislib/lib/vis_config.test.js | 0 .../vislib/partials/touchdown_template.tsx | 0 .../vislib/percentage_mode_transform.ts | 0 .../vislib}/public/vislib/response_handler.js | 0 .../public/vislib/response_handler.test.ts | 0 .../vislib}/public/vislib/types.ts | 0 .../vislib}/public/vislib/vis.js | 0 .../vislib}/public/vislib/vis.test.js | 0 .../public/vislib/visualizations/_chart.js | 0 .../vislib/visualizations/_vis_fixture.js | 4 +-- .../vislib/visualizations/chart.test.js | 0 .../vislib/visualizations/gauge_chart.js | 0 .../vislib/visualizations/gauge_chart.test.js | 0 .../vislib/visualizations/gauges/_index.scss | 0 .../vislib/visualizations/gauges/_meter.scss | 0 .../visualizations/gauges/gauge_types.js | 0 .../vislib/visualizations/gauges/meter.js | 4 +-- .../public/vislib/visualizations/pie_chart.js | 0 .../vislib/visualizations/pie_chart.test.js | 0 .../visualizations/pie_chart_mock_data.js | 0 .../vislib/visualizations/point_series.js | 0 .../visualizations/point_series/_index.scss | 0 .../visualizations/point_series/_labels.scss | 0 .../point_series/_point_series.js | 0 .../point_series/_point_series.test.js | 0 .../visualizations/point_series/area_chart.js | 0 .../point_series/area_chart.test.js | 0 .../point_series/column_chart.js | 0 .../point_series/column_chart.test.js | 0 .../point_series/heatmap_chart.js | 4 +-- .../point_series/heatmap_chart.test.js | 0 .../visualizations/point_series/line_chart.js | 0 .../point_series/line_chart.test.js | 0 .../point_series/series_types.js | 0 .../vislib/visualizations/time_marker.d.ts | 0 .../vislib/visualizations/time_marker.js | 0 .../vislib/visualizations/time_marker.test.js | 0 .../public/vislib/visualizations/vis_types.js | 0 .../vislib/visualizations/vis_types.test.js | 0 .../vislib}/server/index.ts | 0 .../vislib}/server/plugin.ts | 0 .../vislib}/server/ui_settings.ts | 0 src/plugins/vis_types/vislib/tsconfig.json | 26 +++++++++++++++++++ .../xy}/common/index.ts | 0 .../xy}/jest.config.js | 4 +-- .../{vis_type_xy => vis_types/xy}/kibana.json | 0 .../public/__snapshots__/to_ast.test.ts.snap | 0 .../xy}/public/_chart.scss | 0 .../xy}/public/chart_splitter.tsx | 0 .../public/components/_detailed_tooltip.scss | 0 .../components/detailed_tooltip.mock.ts | 0 .../components/detailed_tooltip.test.tsx | 0 .../public/components/detailed_tooltip.tsx | 0 .../xy}/public/components/index.ts | 0 .../xy}/public/components/xy_axis.tsx | 0 .../xy}/public/components/xy_current_time.tsx | 2 +- .../xy}/public/components/xy_endzones.tsx | 2 +- .../xy}/public/components/xy_settings.tsx | 2 +- .../public/components/xy_threshold_line.tsx | 0 .../xy}/public/config/get_agg_id.ts | 0 .../xy}/public/config/get_aspects.ts | 2 +- .../xy}/public/config/get_axis.ts | 4 +-- .../xy}/public/config/get_config.ts | 6 ++--- .../xy}/public/config/get_legend.ts | 0 .../xy}/public/config/get_rotation.ts | 0 .../xy}/public/config/get_threshold_line.ts | 0 .../xy}/public/config/get_tooltip.ts | 0 .../xy}/public/config/index.ts | 0 .../xy}/public/editor/collections.ts | 2 +- .../xy}/public/editor/common_config.tsx | 2 +- .../public/editor/components/common/index.ts | 0 .../common/truncate_labels.test.tsx | 0 .../components/common/truncate_labels.tsx | 0 .../components/common/validation_wrapper.tsx | 2 +- .../xy}/public/editor/components/index.ts | 0 .../editor/components/options/index.tsx | 0 .../category_axis_panel.test.tsx.snap | 0 .../__snapshots__/chart_options.test.tsx.snap | 0 .../custom_extents_options.test.tsx.snap | 0 .../__snapshots__/index.test.tsx.snap | 0 .../__snapshots__/label_options.test.tsx.snap | 0 .../__snapshots__/line_options.test.tsx.snap | 0 .../__snapshots__/point_options.test.tsx.snap | 0 .../value_axes_panel.test.tsx.snap | 0 .../value_axis_options.test.tsx.snap | 0 .../__snapshots__/y_extents.test.tsx.snap | 0 .../metrics_axes/category_axis_panel.test.tsx | 0 .../metrics_axes/category_axis_panel.tsx | 2 +- .../metrics_axes/chart_options.test.tsx | 0 .../options/metrics_axes/chart_options.tsx | 2 +- .../custom_extents_options.test.tsx | 0 .../metrics_axes/custom_extents_options.tsx | 2 +- .../options/metrics_axes/index.test.tsx | 0 .../components/options/metrics_axes/index.tsx | 2 +- .../metrics_axes/label_options.test.tsx | 0 .../options/metrics_axes/label_options.tsx | 4 +-- .../metrics_axes/line_options.test.tsx | 2 +- .../options/metrics_axes/line_options.tsx | 2 +- .../components/options/metrics_axes/mocks.ts | 4 +-- .../metrics_axes/point_options.test.tsx | 0 .../options/metrics_axes/point_options.tsx | 2 +- .../options/metrics_axes/series_panel.tsx | 2 +- .../components/options/metrics_axes/utils.ts | 0 .../metrics_axes/value_axes_panel.test.tsx | 0 .../options/metrics_axes/value_axes_panel.tsx | 0 .../metrics_axes/value_axis_options.test.tsx | 2 +- .../metrics_axes/value_axis_options.tsx | 2 +- .../options/metrics_axes/y_extents.test.tsx | 2 +- .../options/metrics_axes/y_extents.tsx | 2 +- .../point_series/elastic_charts_options.tsx | 4 +-- .../options/point_series/grid_panel.tsx | 2 +- .../components/options/point_series/index.ts | 0 .../point_series/point_series.mocks.ts | 0 .../point_series/point_series.test.tsx | 0 .../options/point_series/point_series.tsx | 4 +-- .../options/point_series/threshold_panel.tsx | 2 +- .../xy}/public/editor/index.ts | 0 .../xy}/public/editor/positions.ts | 0 .../xy}/public/editor/scale_types.ts | 0 .../expression_functions/category_axis.ts | 2 +- .../xy}/public/expression_functions/index.ts | 0 .../xy}/public/expression_functions/label.ts | 4 +-- .../expression_functions/series_param.ts | 2 +- .../expression_functions/threshold_line.ts | 2 +- .../expression_functions/time_marker.ts | 2 +- .../public/expression_functions/value_axis.ts | 2 +- .../public/expression_functions/vis_scale.ts | 2 +- .../public/expression_functions/xy_vis_fn.ts | 8 ++++-- .../xy}/public/index.ts | 0 .../xy}/public/plugin.ts | 12 ++++----- .../xy}/public/sample_vis.test.mocks.ts | 0 .../xy}/public/services.ts | 8 +++--- .../xy}/public/to_ast.test.ts | 8 +++--- .../xy}/public/to_ast.ts | 10 +++---- .../xy}/public/to_ast_esaggs.ts | 6 ++--- .../xy}/public/types/config.ts | 0 .../xy}/public/types/constants.ts | 0 .../xy}/public/types/index.ts | 0 .../xy}/public/types/param.ts | 4 +-- .../xy}/public/types/vis_type.ts | 2 +- .../xy}/public/utils/accessors.test.ts | 2 +- .../xy}/public/utils/accessors.tsx | 4 +-- .../xy}/public/utils/domain.ts | 6 ++--- .../xy}/public/utils/get_all_series.test.ts | 0 .../xy}/public/utils/get_all_series.ts | 2 +- .../public/utils/get_color_picker.test.tsx | 4 +-- .../xy}/public/utils/get_color_picker.tsx | 4 +-- .../xy}/public/utils/get_legend_actions.tsx | 2 +- .../public/utils/get_series_name_fn.test.ts | 0 .../xy}/public/utils/get_series_name_fn.ts | 0 .../xy}/public/utils/get_time_zone.tsx | 0 .../xy}/public/utils/index.tsx | 0 .../utils/render_all_series.test.mocks.ts | 0 .../public/utils/render_all_series.test.tsx | 2 +- .../xy}/public/utils/render_all_series.tsx | 4 +-- .../xy}/public/vis_component.tsx | 8 +++--- .../xy}/public/vis_renderer.tsx | 6 ++--- .../xy}/public/vis_types/area.ts | 6 ++--- .../xy}/public/vis_types/histogram.ts | 6 ++--- .../xy}/public/vis_types/horizontal_bar.ts | 6 ++--- .../xy}/public/vis_types/index.ts | 0 .../xy}/public/vis_types/line.ts | 6 ++--- .../xy}/server/index.ts | 0 .../xy}/server/plugin.ts | 0 src/plugins/vis_types/xy/tsconfig.json | 24 +++++++++++++++++ .../ml/public/application/util/chart_utils.js | 2 +- 424 files changed, 384 insertions(+), 355 deletions(-) delete mode 100644 src/plugins/vis_type_pie/tsconfig.json delete mode 100644 src/plugins/vis_type_vislib/tsconfig.json delete mode 100644 src/plugins/vis_type_xy/tsconfig.json create mode 100644 src/plugins/vis_types/README.md rename src/plugins/{vis_type_pie => vis_types/pie}/common/index.ts (100%) rename src/plugins/{vis_type_xy => vis_types/pie}/jest.config.js (84%) rename src/plugins/{vis_type_pie => vis_types/pie}/kibana.json (100%) rename src/plugins/{vis_type_pie => vis_types/pie}/public/__snapshots__/pie_fn.test.ts.snap (100%) rename src/plugins/{vis_type_pie => vis_types/pie}/public/__snapshots__/to_ast.test.ts.snap (100%) rename src/plugins/{vis_type_pie => vis_types/pie}/public/chart.scss (100%) rename src/plugins/{vis_type_pie => vis_types/pie}/public/components/chart_split.tsx (96%) rename src/plugins/{vis_type_pie => vis_types/pie}/public/editor/collections.ts (100%) rename src/plugins/{vis_type_pie => vis_types/pie}/public/editor/components/index.tsx (91%) rename src/plugins/{vis_type_pie => vis_types/pie}/public/editor/components/pie.test.tsx (98%) rename src/plugins/{vis_type_pie => vis_types/pie}/public/editor/components/pie.tsx (98%) rename src/plugins/{vis_type_pie => vis_types/pie}/public/editor/components/truncate_labels.test.tsx (100%) rename src/plugins/{vis_type_pie => vis_types/pie}/public/editor/components/truncate_labels.tsx (100%) rename src/plugins/{vis_type_pie => vis_types/pie}/public/editor/positions.ts (100%) rename src/plugins/{vis_type_pie => vis_types/pie}/public/expression_functions/pie_labels.ts (98%) rename src/plugins/{vis_type_pie => vis_types/pie}/public/index.ts (100%) rename src/plugins/{vis_type_pie => vis_types/pie}/public/mocks.ts (99%) rename src/plugins/{vis_type_pie => vis_types/pie}/public/pie_component.test.tsx (97%) rename src/plugins/{vis_type_pie => vis_types/pie}/public/pie_component.tsx (96%) rename src/plugins/{vis_type_pie => vis_types/pie}/public/pie_fn.test.ts (90%) rename src/plugins/{vis_type_pie => vis_types/pie}/public/pie_fn.ts (98%) rename src/plugins/{vis_type_pie => vis_types/pie}/public/pie_renderer.tsx (90%) rename src/plugins/{vis_type_pie => vis_types/pie}/public/plugin.ts (87%) rename src/plugins/{vis_type_pie => vis_types/pie}/public/sample_vis.test.mocks.ts (100%) rename src/plugins/{vis_type_pie => vis_types/pie}/public/to_ast.test.ts (94%) rename src/plugins/{vis_type_pie => vis_types/pie}/public/to_ast.ts (97%) rename src/plugins/{vis_type_pie => vis_types/pie}/public/to_ast_esaggs.ts (90%) rename src/plugins/{vis_type_pie => vis_types/pie}/public/types/index.ts (100%) rename src/plugins/{vis_type_pie => vis_types/pie}/public/types/types.ts (92%) rename src/plugins/{vis_type_pie => vis_types/pie}/public/utils/filter_helpers.test.ts (97%) rename src/plugins/{vis_type_pie => vis_types/pie}/public/utils/filter_helpers.ts (88%) rename src/plugins/{vis_type_pie => vis_types/pie}/public/utils/get_color_picker.test.tsx (96%) rename src/plugins/{vis_type_pie => vis_types/pie}/public/utils/get_color_picker.tsx (94%) rename src/plugins/{vis_type_pie => vis_types/pie}/public/utils/get_columns.test.ts (100%) rename src/plugins/{vis_type_pie => vis_types/pie}/public/utils/get_columns.ts (94%) rename src/plugins/{vis_type_pie => vis_types/pie}/public/utils/get_config.ts (100%) rename src/plugins/{vis_type_pie => vis_types/pie}/public/utils/get_distinct_series.test.ts (100%) rename src/plugins/{vis_type_pie => vis_types/pie}/public/utils/get_distinct_series.ts (94%) rename src/plugins/{vis_type_pie => vis_types/pie}/public/utils/get_layers.test.ts (95%) rename src/plugins/{vis_type_pie => vis_types/pie}/public/utils/get_layers.ts (97%) rename src/plugins/{vis_type_pie => vis_types/pie}/public/utils/get_legend_actions.tsx (96%) rename src/plugins/{vis_type_pie => vis_types/pie}/public/utils/get_split_dimension_accessor.ts (87%) rename src/plugins/{vis_type_pie => vis_types/pie}/public/utils/index.ts (100%) rename src/plugins/{vis_type_pie => vis_types/pie}/public/vis_type/index.ts (100%) rename src/plugins/{vis_type_pie => vis_types/pie}/public/vis_type/pie.ts (97%) rename src/plugins/{vis_type_pie => vis_types/pie}/server/index.ts (100%) rename src/plugins/{vis_type_pie => vis_types/pie}/server/plugin.ts (100%) create mode 100644 src/plugins/vis_types/pie/tsconfig.json rename src/plugins/{vis_type_vislib => vis_types/vislib}/common/index.ts (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/jest.config.js (83%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/kibana.json (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/__snapshots__/pie_fn.test.ts.snap (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/__snapshots__/to_ast.test.ts.snap (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/__snapshots__/to_ast_pie.test.ts.snap (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/area.ts (82%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/editor/collections.ts (92%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/editor/components/gauge/index.tsx (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/editor/components/gauge/labels_panel.tsx (96%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/editor/components/gauge/ranges_panel.tsx (97%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/editor/components/gauge/style_panel.tsx (93%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/editor/components/heatmap/index.tsx (98%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/editor/components/heatmap/labels_panel.tsx (96%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/editor/components/index.tsx (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/editor/index.ts (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/fixtures/dispatch_bar_chart_config_normal.json (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/fixtures/dispatch_bar_chart_config_percentage.json (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/fixtures/dispatch_bar_chart_d3.json (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/fixtures/dispatch_bar_chart_data_point.json (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/fixtures/dispatch_heatmap_config.json (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/fixtures/dispatch_heatmap_d3.json (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/fixtures/dispatch_heatmap_data_point.json (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/fixtures/mock_data/date_histogram/_columns.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/fixtures/mock_data/date_histogram/_rows.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/fixtures/mock_data/date_histogram/_rows_series_with_holes.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/fixtures/mock_data/date_histogram/_series.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/fixtures/mock_data/date_histogram/_series_monthly_interval.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/fixtures/mock_data/date_histogram/_series_neg.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/fixtures/mock_data/date_histogram/_series_pos_neg.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/fixtures/mock_data/date_histogram/_stacked_series.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/fixtures/mock_data/filters/_columns.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/fixtures/mock_data/filters/_rows.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/fixtures/mock_data/filters/_series.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/fixtures/mock_data/geohash/_columns.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/fixtures/mock_data/geohash/_geo_json.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/fixtures/mock_data/geohash/_rows.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/fixtures/mock_data/histogram/_columns.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/fixtures/mock_data/histogram/_rows.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/fixtures/mock_data/histogram/_series.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/fixtures/mock_data/histogram/_slices.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/fixtures/mock_data/not_enough_data/_one_point.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/fixtures/mock_data/range/_columns.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/fixtures/mock_data/range/_rows.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/fixtures/mock_data/range/_series.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/fixtures/mock_data/significant_terms/_columns.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/fixtures/mock_data/significant_terms/_rows.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/fixtures/mock_data/significant_terms/_series.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/fixtures/mock_data/stacked/_stacked.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/fixtures/mock_data/terms/_columns.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/fixtures/mock_data/terms/_rows.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/fixtures/mock_data/terms/_series.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/fixtures/mock_data/terms/_series_multiple.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/fixtures/mocks.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/gauge.ts (93%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/goal.ts (93%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/heatmap.ts (91%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/histogram.ts (82%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/horizontal_bar.ts (83%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/index.scss (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/index.ts (89%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/line.ts (82%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/pie.ts (86%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/pie_fn.test.ts (95%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/pie_fn.ts (98%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/plugin.ts (83%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/services.ts (82%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/to_ast.test.ts (78%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/to_ast.ts (94%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/to_ast_esaggs.ts (91%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/to_ast_pie.test.ts (78%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/to_ast_pie.ts (91%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/types.ts (95%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vis_controller.tsx (94%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vis_renderer.tsx (89%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vis_type_vislib_vis_fn.ts (98%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vis_type_vislib_vis_types.ts (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vis_wrapper.tsx (92%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/VISLIB.md (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/_index.scss (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/_variables.scss (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/_vislib_vis_type.scss (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/components/labels/data_array.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/components/labels/flatten_series.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/components/labels/index.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/components/labels/labels.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/components/labels/labels.test.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/components/labels/truncate_labels.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/components/labels/uniq_labels.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/components/legend/__snapshots__/legend.test.tsx.snap (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/components/legend/_index.scss (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/components/legend/_legend.scss (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/components/legend/index.ts (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/components/legend/legend.test.tsx (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/components/legend/legend.tsx (98%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/components/legend/legend_item.tsx (98%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/components/legend/models.ts (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/components/legend/pie_utils.ts (97%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/components/tooltip/_collect_branch.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/components/tooltip/_collect_branch.test.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/components/tooltip/_hierarchical_tooltip_formatter.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/components/tooltip/_index.scss (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/components/tooltip/_pointseries_tooltip_formatter.js (97%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/components/tooltip/_pointseries_tooltip_formatter.test.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/components/tooltip/_tooltip.scss (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/components/tooltip/index.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/components/tooltip/position_tooltip.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/components/tooltip/position_tooltip.test.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/components/tooltip/tooltip.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/components/zero_injection/flatten_data.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/components/zero_injection/inject_zeros.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/components/zero_injection/ordered_x_keys.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/components/zero_injection/uniq_keys.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/components/zero_injection/zero_fill_data_array.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/components/zero_injection/zero_filled_array.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/components/zero_injection/zero_injection.test.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/errors.ts (95%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/helpers/hierarchical/build_hierarchical_data.test.ts (99%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/helpers/hierarchical/build_hierarchical_data.ts (97%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/helpers/index.ts (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/helpers/point_series/_add_to_siri.test.ts (97%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/helpers/point_series/_add_to_siri.ts (89%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/helpers/point_series/_fake_x_aspect.test.ts (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/helpers/point_series/_fake_x_aspect.ts (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/helpers/point_series/_get_aspects.test.ts (96%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/helpers/point_series/_get_aspects.ts (95%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/helpers/point_series/_get_point.test.ts (97%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/helpers/point_series/_get_point.ts (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/helpers/point_series/_get_series.test.ts (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/helpers/point_series/_get_series.ts (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/helpers/point_series/_init_x_axis.test.ts (99%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/helpers/point_series/_init_x_axis.ts (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/helpers/point_series/_init_y_axis.test.ts (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/helpers/point_series/_init_y_axis.ts (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/helpers/point_series/_ordered_date_axis.test.ts (95%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/helpers/point_series/_ordered_date_axis.ts (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/helpers/point_series/index.ts (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/helpers/point_series/point_series.test.ts (98%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/helpers/point_series/point_series.ts (95%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/lib/__snapshots__/dispatch_heatmap.test.js.snap (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/lib/_alerts.scss (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/lib/_data_label.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/lib/_error_handler.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/lib/_error_handler.test.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/lib/_index.scss (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/lib/alerts.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/lib/axis/axis.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/lib/axis/axis.test.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/lib/axis/axis_config.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/lib/axis/axis_labels.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/lib/axis/axis_scale.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/lib/axis/axis_title.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/lib/axis/axis_title.test.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/lib/axis/index.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/lib/axis/scale_modes.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/lib/axis/time_ticks.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/lib/axis/time_ticks.test.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/lib/axis/x_axis.test.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/lib/axis/y_axis.test.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/lib/binder.ts (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/lib/chart_grid.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/lib/chart_title.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/lib/chart_title.test.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/lib/data.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/lib/data.test.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/lib/dispatch.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/lib/dispatch.test.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/lib/dispatch_heatmap.test.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/lib/dispatch_vertical_bar_chart.test.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/lib/handler.js (98%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/lib/handler.test.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/lib/layout/_index.scss (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/lib/layout/_layout.scss (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/lib/layout/index.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/lib/layout/layout.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/lib/layout/layout.test.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/lib/layout/layout_types.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/lib/layout/layout_types.test.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/lib/layout/splits/column_chart/chart_split.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/lib/layout/splits/column_chart/chart_title_split.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/lib/layout/splits/column_chart/splits.test.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/lib/layout/splits/column_chart/x_axis_split.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/lib/layout/splits/column_chart/y_axis_split.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/lib/layout/splits/gauge_chart/chart_split.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/lib/layout/splits/gauge_chart/chart_title_split.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/lib/layout/splits/gauge_chart/splits.test.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/lib/layout/splits/pie_chart/chart_split.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/lib/layout/splits/pie_chart/chart_title_split.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/lib/layout/types/column_layout.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/lib/layout/types/column_layout.test.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/lib/layout/types/gauge_layout.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/lib/layout/types/pie_layout.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/lib/types/gauge.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/lib/types/index.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/lib/types/pie.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/lib/types/point_series.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/lib/types/point_series.test.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/lib/types/testdata_linechart_percentile.json (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/lib/types/testdata_linechart_percentile_float_value.json (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/lib/types/testdata_linechart_percentile_float_value_result.json (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/lib/types/testdata_linechart_percentile_result.json (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/lib/vis_config.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/lib/vis_config.test.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/partials/touchdown_template.tsx (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/percentage_mode_transform.ts (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/response_handler.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/response_handler.test.ts (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/types.ts (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/vis.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/vis.test.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/visualizations/_chart.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/visualizations/_vis_fixture.js (91%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/visualizations/chart.test.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/visualizations/gauge_chart.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/visualizations/gauge_chart.test.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/visualizations/gauges/_index.scss (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/visualizations/gauges/_meter.scss (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/visualizations/gauges/gauge_types.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/visualizations/gauges/meter.js (98%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/visualizations/pie_chart.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/visualizations/pie_chart.test.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/visualizations/pie_chart_mock_data.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/visualizations/point_series.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/visualizations/point_series/_index.scss (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/visualizations/point_series/_labels.scss (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/visualizations/point_series/_point_series.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/visualizations/point_series/_point_series.test.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/visualizations/point_series/area_chart.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/visualizations/point_series/area_chart.test.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/visualizations/point_series/column_chart.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/visualizations/point_series/column_chart.test.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/visualizations/point_series/heatmap_chart.js (98%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/visualizations/point_series/heatmap_chart.test.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/visualizations/point_series/line_chart.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/visualizations/point_series/line_chart.test.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/visualizations/point_series/series_types.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/visualizations/time_marker.d.ts (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/visualizations/time_marker.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/visualizations/time_marker.test.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/visualizations/vis_types.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/public/vislib/visualizations/vis_types.test.js (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/server/index.ts (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/server/plugin.ts (100%) rename src/plugins/{vis_type_vislib => vis_types/vislib}/server/ui_settings.ts (100%) create mode 100644 src/plugins/vis_types/vislib/tsconfig.json rename src/plugins/{vis_type_xy => vis_types/xy}/common/index.ts (100%) rename src/plugins/{vis_type_pie => vis_types/xy}/jest.config.js (84%) rename src/plugins/{vis_type_xy => vis_types/xy}/kibana.json (100%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/__snapshots__/to_ast.test.ts.snap (100%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/_chart.scss (100%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/chart_splitter.tsx (100%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/components/_detailed_tooltip.scss (100%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/components/detailed_tooltip.mock.ts (100%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/components/detailed_tooltip.test.tsx (100%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/components/detailed_tooltip.tsx (100%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/components/index.ts (100%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/components/xy_axis.tsx (100%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/components/xy_current_time.tsx (93%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/components/xy_endzones.tsx (96%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/components/xy_settings.tsx (98%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/components/xy_threshold_line.tsx (100%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/config/get_agg_id.ts (100%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/config/get_aspects.ts (97%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/config/get_axis.ts (97%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/config/get_config.ts (94%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/config/get_legend.ts (100%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/config/get_rotation.ts (100%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/config/get_threshold_line.ts (100%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/config/get_tooltip.ts (100%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/config/index.ts (100%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/editor/collections.ts (98%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/editor/common_config.tsx (94%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/editor/components/common/index.ts (100%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/editor/components/common/truncate_labels.test.tsx (100%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/editor/components/common/truncate_labels.tsx (100%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/editor/components/common/validation_wrapper.tsx (94%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/editor/components/index.ts (100%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/editor/components/options/index.tsx (100%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/editor/components/options/metrics_axes/__snapshots__/category_axis_panel.test.tsx.snap (100%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/editor/components/options/metrics_axes/__snapshots__/chart_options.test.tsx.snap (100%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/editor/components/options/metrics_axes/__snapshots__/custom_extents_options.test.tsx.snap (100%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/editor/components/options/metrics_axes/__snapshots__/index.test.tsx.snap (100%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/editor/components/options/metrics_axes/__snapshots__/label_options.test.tsx.snap (100%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/editor/components/options/metrics_axes/__snapshots__/line_options.test.tsx.snap (100%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/editor/components/options/metrics_axes/__snapshots__/point_options.test.tsx.snap (100%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/editor/components/options/metrics_axes/__snapshots__/value_axes_panel.test.tsx.snap (100%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/editor/components/options/metrics_axes/__snapshots__/value_axis_options.test.tsx.snap (100%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/editor/components/options/metrics_axes/__snapshots__/y_extents.test.tsx.snap (100%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/editor/components/options/metrics_axes/category_axis_panel.test.tsx (100%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/editor/components/options/metrics_axes/category_axis_panel.tsx (96%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/editor/components/options/metrics_axes/chart_options.test.tsx (100%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/editor/components/options/metrics_axes/chart_options.tsx (98%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/editor/components/options/metrics_axes/custom_extents_options.test.tsx (100%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/editor/components/options/metrics_axes/custom_extents_options.tsx (99%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/editor/components/options/metrics_axes/index.test.tsx (100%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/editor/components/options/metrics_axes/index.tsx (99%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/editor/components/options/metrics_axes/label_options.test.tsx (100%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/editor/components/options/metrics_axes/label_options.tsx (94%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/editor/components/options/metrics_axes/line_options.test.tsx (95%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/editor/components/options/metrics_axes/line_options.tsx (97%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/editor/components/options/metrics_axes/mocks.ts (93%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/editor/components/options/metrics_axes/point_options.test.tsx (100%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/editor/components/options/metrics_axes/point_options.tsx (95%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/editor/components/options/metrics_axes/series_panel.tsx (96%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/editor/components/options/metrics_axes/utils.ts (100%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/editor/components/options/metrics_axes/value_axes_panel.test.tsx (100%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/editor/components/options/metrics_axes/value_axes_panel.tsx (100%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/editor/components/options/metrics_axes/value_axis_options.test.tsx (97%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/editor/components/options/metrics_axes/value_axis_options.tsx (99%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/editor/components/options/metrics_axes/y_extents.test.tsx (97%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/editor/components/options/metrics_axes/y_extents.tsx (97%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/editor/components/options/point_series/elastic_charts_options.tsx (97%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/editor/components/options/point_series/grid_panel.tsx (97%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/editor/components/options/point_series/index.ts (100%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/editor/components/options/point_series/point_series.mocks.ts (100%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/editor/components/options/point_series/point_series.test.tsx (100%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/editor/components/options/point_series/point_series.tsx (97%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/editor/components/options/point_series/threshold_panel.tsx (98%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/editor/index.ts (100%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/editor/positions.ts (100%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/editor/scale_types.ts (100%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/expression_functions/category_axis.ts (98%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/expression_functions/index.ts (100%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/expression_functions/label.ts (96%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/expression_functions/series_param.ts (98%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/expression_functions/threshold_line.ts (98%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/expression_functions/time_marker.ts (98%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/expression_functions/value_axis.ts (98%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/expression_functions/vis_scale.ts (98%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/expression_functions/xy_vis_fn.ts (98%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/index.ts (100%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/plugin.ts (89%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/sample_vis.test.mocks.ts (100%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/services.ts (83%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/to_ast.test.ts (83%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/to_ast.ts (97%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/to_ast_esaggs.ts (91%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/types/config.ts (100%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/types/constants.ts (100%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/types/index.ts (100%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/types/param.ts (97%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/types/vis_type.ts (88%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/utils/accessors.test.ts (98%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/utils/accessors.tsx (94%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/utils/domain.ts (90%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/utils/get_all_series.test.ts (100%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/utils/get_all_series.ts (95%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/utils/get_color_picker.test.tsx (96%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/utils/get_color_picker.tsx (95%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/utils/get_legend_actions.tsx (98%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/utils/get_series_name_fn.test.ts (100%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/utils/get_series_name_fn.ts (100%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/utils/get_time_zone.tsx (100%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/utils/index.tsx (100%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/utils/render_all_series.test.mocks.ts (100%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/utils/render_all_series.test.tsx (98%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/utils/render_all_series.tsx (98%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/vis_component.tsx (98%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/vis_renderer.tsx (89%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/vis_types/area.ts (95%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/vis_types/histogram.ts (96%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/vis_types/horizontal_bar.ts (96%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/vis_types/index.ts (100%) rename src/plugins/{vis_type_xy => vis_types/xy}/public/vis_types/line.ts (95%) rename src/plugins/{vis_type_xy => vis_types/xy}/server/index.ts (100%) rename src/plugins/{vis_type_xy => vis_types/xy}/server/plugin.ts (100%) create mode 100644 src/plugins/vis_types/xy/tsconfig.json diff --git a/.i18nrc.json b/.i18nrc.json index d85c24dce68af..6c0f8d75c84b3 100644 --- a/.i18nrc.json +++ b/.i18nrc.json @@ -65,9 +65,9 @@ "visTypeTagCloud": "src/plugins/vis_type_tagcloud", "visTypeTimeseries": "src/plugins/vis_type_timeseries", "visTypeVega": "src/plugins/vis_type_vega", - "visTypeVislib": "src/plugins/vis_type_vislib", - "visTypeXy": "src/plugins/vis_type_xy", - "visTypePie": "src/plugins/vis_type_pie", + "visTypeVislib": "src/plugins/vis_types/vislib", + "visTypeXy": "src/plugins/vis_types/xy", + "visTypePie": "src/plugins/vis_types/pie", "visualizations": "src/plugins/visualizations", "visualize": "src/plugins/visualize", "apmOss": "src/plugins/apm_oss", diff --git a/docs/developer/plugin-list.asciidoc b/docs/developer/plugin-list.asciidoc index b665206b75576..8199a5995d368 100644 --- a/docs/developer/plugin-list.asciidoc +++ b/docs/developer/plugin-list.asciidoc @@ -294,7 +294,7 @@ The plugin exposes the static DefaultEditorController class to consume. |WARNING: Missing README. -|{kib-repo}blob/{branch}/src/plugins/vis_type_pie[visTypePie] +|{kib-repo}blob/{branch}/src/plugins/vis_types/pie[visTypePie] |WARNING: Missing README. @@ -318,11 +318,11 @@ The plugin exposes the static DefaultEditorController class to consume. |WARNING: Missing README. -|{kib-repo}blob/{branch}/src/plugins/vis_type_vislib[visTypeVislib] +|{kib-repo}blob/{branch}/src/plugins/vis_types/vislib[visTypeVislib] |WARNING: Missing README. -|{kib-repo}blob/{branch}/src/plugins/vis_type_xy[visTypeXy] +|{kib-repo}blob/{branch}/src/plugins/vis_types/xy[visTypeXy] |WARNING: Missing README. diff --git a/jest.config.js b/jest.config.js index bd1e865a7e64a..6cb23b279925e 100644 --- a/jest.config.js +++ b/jest.config.js @@ -13,6 +13,7 @@ module.exports = { '/packages/*/jest.config.js', '/src/*/jest.config.js', '/src/plugins/*/jest.config.js', + '/src/plugins/vis_types/*/jest.config.js', '/test/*/jest.config.js', '/x-pack/plugins/*/jest.config.js', ], diff --git a/src/dev/typescript/projects.ts b/src/dev/typescript/projects.ts index 0244cb2cd9115..58234be1317a7 100644 --- a/src/dev/typescript/projects.ts +++ b/src/dev/typescript/projects.ts @@ -70,6 +70,7 @@ export const PROJECTS = [ ...findProjects('packages/*/tsconfig.json'), ...findProjects('src/plugins/*/tsconfig.json'), + ...findProjects('src/plugins/vis_types/*/tsconfig.json'), ...findProjects('x-pack/plugins/*/tsconfig.json'), ...findProjects('examples/*/tsconfig.json'), ...findProjects('x-pack/examples/*/tsconfig.json'), diff --git a/src/plugins/vis_type_pie/tsconfig.json b/src/plugins/vis_type_pie/tsconfig.json deleted file mode 100644 index 9640447b35d98..0000000000000 --- a/src/plugins/vis_type_pie/tsconfig.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "extends": "../../../tsconfig.base.json", - "compilerOptions": { - "outDir": "./target/types", - "emitDeclarationOnly": true, - "declaration": true, - "declarationMap": true - }, - "include": [ - "common/**/*", - "public/**/*", - "server/**/*" - ], - "references": [ - { "path": "../../core/tsconfig.json" }, - { "path": "../charts/tsconfig.json" }, - { "path": "../data/tsconfig.json" }, - { "path": "../expressions/tsconfig.json" }, - { "path": "../visualizations/tsconfig.json" }, - { "path": "../usage_collection/tsconfig.json" }, - { "path": "../vis_default_editor/tsconfig.json" }, - { "path": "../field_formats/tsconfig.json" } - ] -} diff --git a/src/plugins/vis_type_vislib/tsconfig.json b/src/plugins/vis_type_vislib/tsconfig.json deleted file mode 100644 index 0d2a4094f04be..0000000000000 --- a/src/plugins/vis_type_vislib/tsconfig.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "extends": "../../../tsconfig.base.json", - "compilerOptions": { - "outDir": "./target/types", - "emitDeclarationOnly": true, - "declaration": true, - "declarationMap": true - }, - "include": [ - "common/**/*", - "public/**/*", - "server/**/*" - ], - "references": [ - { "path": "../../core/tsconfig.json" }, - { "path": "../charts/tsconfig.json" }, - { "path": "../data/tsconfig.json" }, - { "path": "../expressions/tsconfig.json" }, - { "path": "../visualizations/tsconfig.json" }, - { "path": "../kibana_legacy/tsconfig.json" }, - { "path": "../kibana_utils/tsconfig.json" }, - { "path": "../vis_default_editor/tsconfig.json" }, - { "path": "../vis_type_xy/tsconfig.json" }, - { "path": "../vis_type_pie/tsconfig.json" }, - ] -} diff --git a/src/plugins/vis_type_xy/tsconfig.json b/src/plugins/vis_type_xy/tsconfig.json deleted file mode 100644 index 0e4e41c286bd2..0000000000000 --- a/src/plugins/vis_type_xy/tsconfig.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "extends": "../../../tsconfig.base.json", - "compilerOptions": { - "outDir": "./target/types", - "emitDeclarationOnly": true, - "declaration": true, - "declarationMap": true - }, - "include": [ - "common/**/*", - "public/**/*", - "server/**/*" - ], - "references": [ - { "path": "../../core/tsconfig.json" }, - { "path": "../charts/tsconfig.json" }, - { "path": "../data/tsconfig.json" }, - { "path": "../expressions/tsconfig.json" }, - { "path": "../visualizations/tsconfig.json" }, - { "path": "../usage_collection/tsconfig.json" }, - { "path": "../kibana_utils/tsconfig.json" }, - { "path": "../vis_default_editor/tsconfig.json" }, - ] -} diff --git a/src/plugins/vis_types/README.md b/src/plugins/vis_types/README.md new file mode 100644 index 0000000000000..db3d426d4bb48 --- /dev/null +++ b/src/plugins/vis_types/README.md @@ -0,0 +1,19 @@ +# Vis types + +This folder contains all the legacy visualizations plugins. The legacy visualizations are: +- TSVB +- Vega +- All the aggregation-based visualizations + +The structure is: +``` + └ vis_types (just a folder) + + └ pie (previous vis_type_pie) + + └ tagcloud (previous vis_type_tagcloud) + + └ ... +``` + + If their renderer/expression is not shared with any other plugin, it can be contained within the vis_types/* plugin in this folder. If it's sharing a renderer/expression with Lens or Canvas, the renderer must be extracted into the chart_expression folder. diff --git a/src/plugins/vis_type_pie/common/index.ts b/src/plugins/vis_types/pie/common/index.ts similarity index 100% rename from src/plugins/vis_type_pie/common/index.ts rename to src/plugins/vis_types/pie/common/index.ts diff --git a/src/plugins/vis_type_xy/jest.config.js b/src/plugins/vis_types/pie/jest.config.js similarity index 84% rename from src/plugins/vis_type_xy/jest.config.js rename to src/plugins/vis_types/pie/jest.config.js index a14203b7b757f..505ea97f489f7 100644 --- a/src/plugins/vis_type_xy/jest.config.js +++ b/src/plugins/vis_types/pie/jest.config.js @@ -8,6 +8,6 @@ module.exports = { preset: '@kbn/test', - rootDir: '../../..', - roots: ['/src/plugins/vis_type_xy'], + rootDir: '../../../..', + roots: ['/src/plugins/vis_types/pie'], }; diff --git a/src/plugins/vis_type_pie/kibana.json b/src/plugins/vis_types/pie/kibana.json similarity index 100% rename from src/plugins/vis_type_pie/kibana.json rename to src/plugins/vis_types/pie/kibana.json diff --git a/src/plugins/vis_type_pie/public/__snapshots__/pie_fn.test.ts.snap b/src/plugins/vis_types/pie/public/__snapshots__/pie_fn.test.ts.snap similarity index 100% rename from src/plugins/vis_type_pie/public/__snapshots__/pie_fn.test.ts.snap rename to src/plugins/vis_types/pie/public/__snapshots__/pie_fn.test.ts.snap diff --git a/src/plugins/vis_type_pie/public/__snapshots__/to_ast.test.ts.snap b/src/plugins/vis_types/pie/public/__snapshots__/to_ast.test.ts.snap similarity index 100% rename from src/plugins/vis_type_pie/public/__snapshots__/to_ast.test.ts.snap rename to src/plugins/vis_types/pie/public/__snapshots__/to_ast.test.ts.snap diff --git a/src/plugins/vis_type_pie/public/chart.scss b/src/plugins/vis_types/pie/public/chart.scss similarity index 100% rename from src/plugins/vis_type_pie/public/chart.scss rename to src/plugins/vis_types/pie/public/chart.scss diff --git a/src/plugins/vis_type_pie/public/components/chart_split.tsx b/src/plugins/vis_types/pie/public/components/chart_split.tsx similarity index 96% rename from src/plugins/vis_type_pie/public/components/chart_split.tsx rename to src/plugins/vis_types/pie/public/components/chart_split.tsx index 46f841113c03d..563d9e9234b66 100644 --- a/src/plugins/vis_type_pie/public/components/chart_split.tsx +++ b/src/plugins/vis_types/pie/public/components/chart_split.tsx @@ -8,7 +8,7 @@ import React from 'react'; import { Accessor, AccessorFn, GroupBy, GroupBySort, SmallMultiples } from '@elastic/charts'; -import { DatatableColumn } from '../../../expressions/public'; +import { DatatableColumn } from '../../../../expressions/public'; import { SplitDimensionParams } from '../types'; interface ChartSplitProps { diff --git a/src/plugins/vis_type_pie/public/editor/collections.ts b/src/plugins/vis_types/pie/public/editor/collections.ts similarity index 100% rename from src/plugins/vis_type_pie/public/editor/collections.ts rename to src/plugins/vis_types/pie/public/editor/collections.ts diff --git a/src/plugins/vis_type_pie/public/editor/components/index.tsx b/src/plugins/vis_types/pie/public/editor/components/index.tsx similarity index 91% rename from src/plugins/vis_type_pie/public/editor/components/index.tsx rename to src/plugins/vis_types/pie/public/editor/components/index.tsx index 6bc31208fbdb0..5f7c744db0716 100644 --- a/src/plugins/vis_type_pie/public/editor/components/index.tsx +++ b/src/plugins/vis_types/pie/public/editor/components/index.tsx @@ -7,7 +7,7 @@ */ import React, { lazy } from 'react'; -import { VisEditorOptionsProps } from '../../../../visualizations/public'; +import { VisEditorOptionsProps } from '../../../../../visualizations/public'; import { PieVisParams, PieTypeProps } from '../../types'; const PieOptionsLazy = lazy(() => import('./pie')); diff --git a/src/plugins/vis_type_pie/public/editor/components/pie.test.tsx b/src/plugins/vis_types/pie/public/editor/components/pie.test.tsx similarity index 98% rename from src/plugins/vis_type_pie/public/editor/components/pie.test.tsx rename to src/plugins/vis_types/pie/public/editor/components/pie.test.tsx index d37f4c10ea9ea..ee8d0bf19ecac 100644 --- a/src/plugins/vis_type_pie/public/editor/components/pie.test.tsx +++ b/src/plugins/vis_types/pie/public/editor/components/pie.test.tsx @@ -10,7 +10,7 @@ import React from 'react'; import { mountWithIntl } from '@kbn/test/jest'; import { ReactWrapper } from 'enzyme'; import PieOptions, { PieOptionsProps } from './pie'; -import { chartPluginMock } from '../../../../charts/public/mocks'; +import { chartPluginMock } from '../../../../../charts/public/mocks'; import { findTestSubject } from '@elastic/eui/lib/test'; import { act } from 'react-dom/test-utils'; diff --git a/src/plugins/vis_type_pie/public/editor/components/pie.tsx b/src/plugins/vis_types/pie/public/editor/components/pie.tsx similarity index 98% rename from src/plugins/vis_type_pie/public/editor/components/pie.tsx rename to src/plugins/vis_types/pie/public/editor/components/pie.tsx index 3bf28ba58d4eb..78ae9527da3f9 100644 --- a/src/plugins/vis_type_pie/public/editor/components/pie.tsx +++ b/src/plugins/vis_types/pie/public/editor/components/pie.tsx @@ -27,10 +27,10 @@ import { SelectOption, PalettePicker, LongLegendOptions, -} from '../../../../vis_default_editor/public'; -import { VisEditorOptionsProps } from '../../../../visualizations/public'; +} from '../../../../../vis_default_editor/public'; +import { VisEditorOptionsProps } from '../../../../../visualizations/public'; import { TruncateLabelsOption } from './truncate_labels'; -import { PaletteRegistry } from '../../../../charts/public'; +import { PaletteRegistry } from '../../../../../charts/public'; import { DEFAULT_PERCENT_DECIMALS } from '../../../common'; import { PieVisParams, LabelPositions, ValueFormats, PieTypeProps } from '../../types'; import { getLabelPositions, getValuesFormats } from '../collections'; diff --git a/src/plugins/vis_type_pie/public/editor/components/truncate_labels.test.tsx b/src/plugins/vis_types/pie/public/editor/components/truncate_labels.test.tsx similarity index 100% rename from src/plugins/vis_type_pie/public/editor/components/truncate_labels.test.tsx rename to src/plugins/vis_types/pie/public/editor/components/truncate_labels.test.tsx diff --git a/src/plugins/vis_type_pie/public/editor/components/truncate_labels.tsx b/src/plugins/vis_types/pie/public/editor/components/truncate_labels.tsx similarity index 100% rename from src/plugins/vis_type_pie/public/editor/components/truncate_labels.tsx rename to src/plugins/vis_types/pie/public/editor/components/truncate_labels.tsx diff --git a/src/plugins/vis_type_pie/public/editor/positions.ts b/src/plugins/vis_types/pie/public/editor/positions.ts similarity index 100% rename from src/plugins/vis_type_pie/public/editor/positions.ts rename to src/plugins/vis_types/pie/public/editor/positions.ts diff --git a/src/plugins/vis_type_pie/public/expression_functions/pie_labels.ts b/src/plugins/vis_types/pie/public/expression_functions/pie_labels.ts similarity index 98% rename from src/plugins/vis_type_pie/public/expression_functions/pie_labels.ts rename to src/plugins/vis_types/pie/public/expression_functions/pie_labels.ts index 269d5d5f779d6..eeda49bce4c4c 100644 --- a/src/plugins/vis_type_pie/public/expression_functions/pie_labels.ts +++ b/src/plugins/vis_types/pie/public/expression_functions/pie_labels.ts @@ -11,7 +11,7 @@ import { ExpressionFunctionDefinition, Datatable, ExpressionValueBoxed, -} from '../../../expressions/public'; +} from '../../../../expressions/public'; interface Arguments { show: boolean; diff --git a/src/plugins/vis_type_pie/public/index.ts b/src/plugins/vis_types/pie/public/index.ts similarity index 100% rename from src/plugins/vis_type_pie/public/index.ts rename to src/plugins/vis_types/pie/public/index.ts diff --git a/src/plugins/vis_type_pie/public/mocks.ts b/src/plugins/vis_types/pie/public/mocks.ts similarity index 99% rename from src/plugins/vis_type_pie/public/mocks.ts rename to src/plugins/vis_types/pie/public/mocks.ts index 6cf291b8bf370..f7ba4056c77e4 100644 --- a/src/plugins/vis_type_pie/public/mocks.ts +++ b/src/plugins/vis_types/pie/public/mocks.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { Datatable } from '../../expressions/public'; +import { Datatable } from '../../../expressions/public'; import { BucketColumns, PieVisParams, LabelPositions, ValueFormats } from './types'; export const createMockBucketColumns = (): BucketColumns[] => { diff --git a/src/plugins/vis_type_pie/public/pie_component.test.tsx b/src/plugins/vis_types/pie/public/pie_component.test.tsx similarity index 97% rename from src/plugins/vis_type_pie/public/pie_component.test.tsx rename to src/plugins/vis_types/pie/public/pie_component.test.tsx index 177396f25adb6..c70cad285f2ae 100644 --- a/src/plugins/vis_type_pie/public/pie_component.test.tsx +++ b/src/plugins/vis_types/pie/public/pie_component.test.tsx @@ -8,8 +8,8 @@ import React from 'react'; import { Settings, TooltipType, SeriesIdentifier } from '@elastic/charts'; -import { chartPluginMock } from '../../charts/public/mocks'; -import { dataPluginMock } from '../../data/public/mocks'; +import { chartPluginMock } from '../../../charts/public/mocks'; +import { dataPluginMock } from '../../../data/public/mocks'; import { shallow, mount } from 'enzyme'; import { findTestSubject } from '@elastic/eui/lib/test'; import { act } from 'react-dom/test-utils'; diff --git a/src/plugins/vis_type_pie/public/pie_component.tsx b/src/plugins/vis_types/pie/public/pie_component.tsx similarity index 96% rename from src/plugins/vis_type_pie/public/pie_component.tsx rename to src/plugins/vis_types/pie/public/pie_component.tsx index 9119f2f2ecd6c..a5475a76e27cd 100644 --- a/src/plugins/vis_type_pie/public/pie_component.tsx +++ b/src/plugins/vis_types/pie/public/pie_component.tsx @@ -25,11 +25,15 @@ import { ClickTriggerEvent, ChartsPluginSetup, PaletteRegistry, -} from '../../charts/public'; -import { DataPublicPluginStart } from '../../data/public'; -import type { FieldFormat } from '../../field_formats/common'; -import type { PersistedState } from '../../visualizations/public'; -import { Datatable, DatatableColumn, IInterpreterRenderHandlers } from '../../expressions/public'; +} from '../../../charts/public'; +import { DataPublicPluginStart } from '../../../data/public'; +import type { PersistedState } from '../../../visualizations/public'; +import { + Datatable, + DatatableColumn, + IInterpreterRenderHandlers, +} from '../../../expressions/public'; +import type { FieldFormat } from '../../../field_formats/common'; import { DEFAULT_PERCENT_DECIMALS } from '../common'; import { PieVisParams, BucketColumns, ValueFormats, PieContainerDimensions } from './types'; import { diff --git a/src/plugins/vis_type_pie/public/pie_fn.test.ts b/src/plugins/vis_types/pie/public/pie_fn.test.ts similarity index 90% rename from src/plugins/vis_type_pie/public/pie_fn.test.ts rename to src/plugins/vis_types/pie/public/pie_fn.test.ts index 33b5f38cbe630..d0e0af9807f34 100644 --- a/src/plugins/vis_type_pie/public/pie_fn.test.ts +++ b/src/plugins/vis_types/pie/public/pie_fn.test.ts @@ -6,9 +6,9 @@ * Side Public License, v 1. */ -import { functionWrapper } from '../../expressions/common/expression_functions/specs/tests/utils'; +import { functionWrapper } from '../../../expressions/common/expression_functions/specs/tests/utils'; import { createPieVisFn } from './pie_fn'; -import { Datatable } from '../../expressions/common/expression_types/specs'; +import { Datatable } from '../../../expressions/common/expression_types/specs'; describe('interpreter/functions#pie', () => { const fn = functionWrapper(createPieVisFn()); diff --git a/src/plugins/vis_type_pie/public/pie_fn.ts b/src/plugins/vis_types/pie/public/pie_fn.ts similarity index 98% rename from src/plugins/vis_type_pie/public/pie_fn.ts rename to src/plugins/vis_types/pie/public/pie_fn.ts index c5987001d4494..74e8127712399 100644 --- a/src/plugins/vis_type_pie/public/pie_fn.ts +++ b/src/plugins/vis_types/pie/public/pie_fn.ts @@ -7,9 +7,9 @@ */ import { i18n } from '@kbn/i18n'; -import { ExpressionFunctionDefinition, Datatable, Render } from '../../expressions/common'; +import { ExpressionFunctionDefinition, Datatable, Render } from '../../../expressions/common'; import { PieVisParams, PieVisConfig } from './types'; -import { prepareLogTable } from '../../visualizations/public'; +import { prepareLogTable } from '../../../visualizations/public'; export const vislibPieName = 'pie_vis'; diff --git a/src/plugins/vis_type_pie/public/pie_renderer.tsx b/src/plugins/vis_types/pie/public/pie_renderer.tsx similarity index 90% rename from src/plugins/vis_type_pie/public/pie_renderer.tsx rename to src/plugins/vis_types/pie/public/pie_renderer.tsx index bcd4cad4efa66..e8fb6311904a6 100644 --- a/src/plugins/vis_type_pie/public/pie_renderer.tsx +++ b/src/plugins/vis_types/pie/public/pie_renderer.tsx @@ -9,9 +9,9 @@ import React, { lazy } from 'react'; import { render, unmountComponentAtNode } from 'react-dom'; import { I18nProvider } from '@kbn/i18n/react'; -import { ExpressionRenderDefinition } from '../../expressions/public'; -import { VisualizationContainer } from '../../visualizations/public'; -import type { PersistedState } from '../../visualizations/public'; +import { ExpressionRenderDefinition } from '../../../expressions/public'; +import { VisualizationContainer } from '../../../visualizations/public'; +import type { PersistedState } from '../../../visualizations/public'; import { VisTypePieDependencies } from './plugin'; import { RenderValue, vislibPieName } from './pie_fn'; diff --git a/src/plugins/vis_type_pie/public/plugin.ts b/src/plugins/vis_types/pie/public/plugin.ts similarity index 87% rename from src/plugins/vis_type_pie/public/plugin.ts rename to src/plugins/vis_types/pie/public/plugin.ts index 787f49c19aca3..12be6dd5de10f 100644 --- a/src/plugins/vis_type_pie/public/plugin.ts +++ b/src/plugins/vis_types/pie/public/plugin.ts @@ -7,11 +7,11 @@ */ import { CoreSetup, DocLinksStart } from 'src/core/public'; -import { VisualizationsSetup } from '../../visualizations/public'; -import { Plugin as ExpressionsPublicPlugin } from '../../expressions/public'; -import { ChartsPluginSetup } from '../../charts/public'; -import { UsageCollectionSetup } from '../../usage_collection/public'; -import { DataPublicPluginStart } from '../../data/public'; +import { VisualizationsSetup } from '../../../visualizations/public'; +import { Plugin as ExpressionsPublicPlugin } from '../../../expressions/public'; +import { ChartsPluginSetup } from '../../../charts/public'; +import { UsageCollectionSetup } from '../../../usage_collection/public'; +import { DataPublicPluginStart } from '../../../data/public'; import { LEGACY_PIE_CHARTS_LIBRARY } from '../common'; import { pieLabels as pieLabelsExpressionFunction } from './expression_functions/pie_labels'; import { createPieVisFn } from './pie_fn'; diff --git a/src/plugins/vis_type_pie/public/sample_vis.test.mocks.ts b/src/plugins/vis_types/pie/public/sample_vis.test.mocks.ts similarity index 100% rename from src/plugins/vis_type_pie/public/sample_vis.test.mocks.ts rename to src/plugins/vis_types/pie/public/sample_vis.test.mocks.ts diff --git a/src/plugins/vis_type_pie/public/to_ast.test.ts b/src/plugins/vis_types/pie/public/to_ast.test.ts similarity index 94% rename from src/plugins/vis_type_pie/public/to_ast.test.ts rename to src/plugins/vis_types/pie/public/to_ast.test.ts index 019c6e2176710..9d1dba32f2623 100644 --- a/src/plugins/vis_type_pie/public/to_ast.test.ts +++ b/src/plugins/vis_types/pie/public/to_ast.test.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { Vis } from '../../visualizations/public'; +import { Vis } from '../../../visualizations/public'; import { PieVisParams } from './types'; import { samplePieVis } from './sample_vis.test.mocks'; diff --git a/src/plugins/vis_type_pie/public/to_ast.ts b/src/plugins/vis_types/pie/public/to_ast.ts similarity index 97% rename from src/plugins/vis_type_pie/public/to_ast.ts rename to src/plugins/vis_types/pie/public/to_ast.ts index b360e375bf40d..fbfffbb77d5fb 100644 --- a/src/plugins/vis_type_pie/public/to_ast.ts +++ b/src/plugins/vis_types/pie/public/to_ast.ts @@ -6,8 +6,8 @@ * Side Public License, v 1. */ -import { getVisSchemas, VisToExpressionAst, SchemaConfig } from '../../visualizations/public'; -import { buildExpression, buildExpressionFunction } from '../../expressions/public'; +import { getVisSchemas, VisToExpressionAst, SchemaConfig } from '../../../visualizations/public'; +import { buildExpression, buildExpressionFunction } from '../../../expressions/public'; import { PieVisParams, LabelsParams } from './types'; import { vislibPieName, VisTypePieExpressionFunctionDefinition } from './pie_fn'; import { getEsaggsFn } from './to_ast_esaggs'; diff --git a/src/plugins/vis_type_pie/public/to_ast_esaggs.ts b/src/plugins/vis_types/pie/public/to_ast_esaggs.ts similarity index 90% rename from src/plugins/vis_type_pie/public/to_ast_esaggs.ts rename to src/plugins/vis_types/pie/public/to_ast_esaggs.ts index 9b760bd4bebcc..48a7dc50de171 100644 --- a/src/plugins/vis_type_pie/public/to_ast_esaggs.ts +++ b/src/plugins/vis_types/pie/public/to_ast_esaggs.ts @@ -6,12 +6,12 @@ * Side Public License, v 1. */ -import { Vis } from '../../visualizations/public'; -import { buildExpression, buildExpressionFunction } from '../../expressions/public'; +import { Vis } from '../../../visualizations/public'; +import { buildExpression, buildExpressionFunction } from '../../../expressions/public'; import { EsaggsExpressionFunctionDefinition, IndexPatternLoadExpressionFunctionDefinition, -} from '../../data/public'; +} from '../../../data/public'; import { PieVisParams } from './types'; diff --git a/src/plugins/vis_type_pie/public/types/index.ts b/src/plugins/vis_types/pie/public/types/index.ts similarity index 100% rename from src/plugins/vis_type_pie/public/types/index.ts rename to src/plugins/vis_types/pie/public/types/index.ts diff --git a/src/plugins/vis_type_pie/public/types/types.ts b/src/plugins/vis_types/pie/public/types/types.ts similarity index 92% rename from src/plugins/vis_type_pie/public/types/types.ts rename to src/plugins/vis_types/pie/public/types/types.ts index 94eaeb55f7242..a1f41e80fae28 100644 --- a/src/plugins/vis_type_pie/public/types/types.ts +++ b/src/plugins/vis_types/pie/public/types/types.ts @@ -8,10 +8,10 @@ import { Position } from '@elastic/charts'; import { UiCounterMetricType } from '@kbn/analytics'; -import { DatatableColumn, SerializedFieldFormat } from '../../../expressions/public'; -import { ExpressionValueVisDimension } from '../../../visualizations/public'; +import { DatatableColumn, SerializedFieldFormat } from '../../../../expressions/public'; +import { ExpressionValueVisDimension } from '../../../../visualizations/public'; import { ExpressionValuePieLabels } from '../expression_functions/pie_labels'; -import { PaletteOutput, ChartsPluginSetup } from '../../../charts/public'; +import { PaletteOutput, ChartsPluginSetup } from '../../../../charts/public'; export interface Dimension { accessor: number; diff --git a/src/plugins/vis_type_pie/public/utils/filter_helpers.test.ts b/src/plugins/vis_types/pie/public/utils/filter_helpers.test.ts similarity index 97% rename from src/plugins/vis_type_pie/public/utils/filter_helpers.test.ts rename to src/plugins/vis_types/pie/public/utils/filter_helpers.test.ts index 3f532cf4c384f..f6e20104779fa 100644 --- a/src/plugins/vis_type_pie/public/utils/filter_helpers.test.ts +++ b/src/plugins/vis_types/pie/public/utils/filter_helpers.test.ts @@ -5,7 +5,7 @@ * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ -import { DatatableColumn } from '../../../expressions/public'; +import { DatatableColumn } from '../../../../expressions/public'; import { getFilterClickData, getFilterEventData } from './filter_helpers'; import { createMockBucketColumns, createMockVisData } from '../mocks'; diff --git a/src/plugins/vis_type_pie/public/utils/filter_helpers.ts b/src/plugins/vis_types/pie/public/utils/filter_helpers.ts similarity index 88% rename from src/plugins/vis_type_pie/public/utils/filter_helpers.ts rename to src/plugins/vis_types/pie/public/utils/filter_helpers.ts index f1a4791821c12..31fff7612faf3 100644 --- a/src/plugins/vis_type_pie/public/utils/filter_helpers.ts +++ b/src/plugins/vis_types/pie/public/utils/filter_helpers.ts @@ -7,11 +7,11 @@ */ import { LayerValue, SeriesIdentifier } from '@elastic/charts'; -import { Datatable, DatatableColumn } from '../../../expressions/public'; -import { DataPublicPluginStart } from '../../../data/public'; -import type { FieldFormat } from '../../../field_formats/common'; -import { ClickTriggerEvent } from '../../../charts/public'; -import { ValueClickContext } from '../../../embeddable/public'; +import { Datatable, DatatableColumn } from '../../../../expressions/public'; +import { DataPublicPluginStart } from '../../../../data/public'; +import { ClickTriggerEvent } from '../../../../charts/public'; +import { ValueClickContext } from '../../../../embeddable/public'; +import type { FieldFormat } from '../../../../field_formats/common'; import { BucketColumns } from '../types'; export const canFilter = async ( diff --git a/src/plugins/vis_type_pie/public/utils/get_color_picker.test.tsx b/src/plugins/vis_types/pie/public/utils/get_color_picker.test.tsx similarity index 96% rename from src/plugins/vis_type_pie/public/utils/get_color_picker.test.tsx rename to src/plugins/vis_types/pie/public/utils/get_color_picker.test.tsx index 5e9087947b95e..bb4cbd8c08ae2 100644 --- a/src/plugins/vis_type_pie/public/utils/get_color_picker.test.tsx +++ b/src/plugins/vis_types/pie/public/utils/get_color_picker.test.tsx @@ -12,8 +12,8 @@ import { EuiPopover } from '@elastic/eui'; import { mountWithIntl } from '@kbn/test/jest'; import { ComponentType, ReactWrapper } from 'enzyme'; import { getColorPicker } from './get_color_picker'; -import { ColorPicker } from '../../../charts/public'; -import type { PersistedState } from '../../../visualizations/public'; +import { ColorPicker } from '../../../../charts/public'; +import type { PersistedState } from '../../../../visualizations/public'; import { createMockBucketColumns, createMockVisData } from '../mocks'; const bucketColumns = createMockBucketColumns(); diff --git a/src/plugins/vis_type_pie/public/utils/get_color_picker.tsx b/src/plugins/vis_types/pie/public/utils/get_color_picker.tsx similarity index 94% rename from src/plugins/vis_type_pie/public/utils/get_color_picker.tsx rename to src/plugins/vis_types/pie/public/utils/get_color_picker.tsx index 628c2d74dc438..68daa7bb82df7 100644 --- a/src/plugins/vis_type_pie/public/utils/get_color_picker.tsx +++ b/src/plugins/vis_types/pie/public/utils/get_color_picker.tsx @@ -10,9 +10,9 @@ import React, { useCallback } from 'react'; import Color from 'color'; import { LegendColorPicker, Position } from '@elastic/charts'; import { PopoverAnchorPosition, EuiPopover, EuiOutsideClickDetector } from '@elastic/eui'; -import type { DatatableRow } from '../../../expressions/public'; -import type { PersistedState } from '../../../visualizations/public'; -import { ColorPicker } from '../../../charts/public'; +import type { DatatableRow } from '../../../../expressions/public'; +import type { PersistedState } from '../../../../visualizations/public'; +import { ColorPicker } from '../../../../charts/public'; import { BucketColumns } from '../types'; const KEY_CODE_ENTER = 13; diff --git a/src/plugins/vis_type_pie/public/utils/get_columns.test.ts b/src/plugins/vis_types/pie/public/utils/get_columns.test.ts similarity index 100% rename from src/plugins/vis_type_pie/public/utils/get_columns.test.ts rename to src/plugins/vis_types/pie/public/utils/get_columns.test.ts diff --git a/src/plugins/vis_type_pie/public/utils/get_columns.ts b/src/plugins/vis_types/pie/public/utils/get_columns.ts similarity index 94% rename from src/plugins/vis_type_pie/public/utils/get_columns.ts rename to src/plugins/vis_types/pie/public/utils/get_columns.ts index 4a32466d808da..c8b8399f0f786 100644 --- a/src/plugins/vis_type_pie/public/utils/get_columns.ts +++ b/src/plugins/vis_types/pie/public/utils/get_columns.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { DatatableColumn, Datatable } from '../../../expressions/public'; +import { DatatableColumn, Datatable } from '../../../../expressions/public'; import { BucketColumns, PieVisParams } from '../types'; export const getColumns = ( diff --git a/src/plugins/vis_type_pie/public/utils/get_config.ts b/src/plugins/vis_types/pie/public/utils/get_config.ts similarity index 100% rename from src/plugins/vis_type_pie/public/utils/get_config.ts rename to src/plugins/vis_types/pie/public/utils/get_config.ts diff --git a/src/plugins/vis_type_pie/public/utils/get_distinct_series.test.ts b/src/plugins/vis_types/pie/public/utils/get_distinct_series.test.ts similarity index 100% rename from src/plugins/vis_type_pie/public/utils/get_distinct_series.test.ts rename to src/plugins/vis_types/pie/public/utils/get_distinct_series.test.ts diff --git a/src/plugins/vis_type_pie/public/utils/get_distinct_series.ts b/src/plugins/vis_types/pie/public/utils/get_distinct_series.ts similarity index 94% rename from src/plugins/vis_type_pie/public/utils/get_distinct_series.ts rename to src/plugins/vis_types/pie/public/utils/get_distinct_series.ts index ba5042dfc210c..8e0111391ec0f 100644 --- a/src/plugins/vis_type_pie/public/utils/get_distinct_series.ts +++ b/src/plugins/vis_types/pie/public/utils/get_distinct_series.ts @@ -5,7 +5,7 @@ * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ -import { DatatableRow } from '../../../expressions/public'; +import { DatatableRow } from '../../../../expressions/public'; import { BucketColumns } from '../types'; export const getDistinctSeries = (rows: DatatableRow[], buckets: Array>) => { diff --git a/src/plugins/vis_type_pie/public/utils/get_layers.test.ts b/src/plugins/vis_types/pie/public/utils/get_layers.test.ts similarity index 95% rename from src/plugins/vis_type_pie/public/utils/get_layers.test.ts rename to src/plugins/vis_types/pie/public/utils/get_layers.test.ts index d6f80b3eb231d..859d0daf07a02 100644 --- a/src/plugins/vis_type_pie/public/utils/get_layers.test.ts +++ b/src/plugins/vis_types/pie/public/utils/get_layers.test.ts @@ -6,9 +6,9 @@ * Side Public License, v 1. */ import { ShapeTreeNode } from '@elastic/charts'; -import { PaletteDefinition, SeriesLayer } from '../../../charts/public'; -import { dataPluginMock } from '../../../data/public/mocks'; -import type { DataPublicPluginStart } from '../../../data/public'; +import { PaletteDefinition, SeriesLayer } from '../../../../charts/public'; +import { dataPluginMock } from '../../../../data/public/mocks'; +import type { DataPublicPluginStart } from '../../../../data/public'; import { computeColor } from './get_layers'; import { createMockVisData, createMockBucketColumns, createMockPieParams } from '../mocks'; diff --git a/src/plugins/vis_type_pie/public/utils/get_layers.ts b/src/plugins/vis_types/pie/public/utils/get_layers.ts similarity index 97% rename from src/plugins/vis_type_pie/public/utils/get_layers.ts rename to src/plugins/vis_types/pie/public/utils/get_layers.ts index 42c4650419c6b..6ecef858619b5 100644 --- a/src/plugins/vis_type_pie/public/utils/get_layers.ts +++ b/src/plugins/vis_types/pie/public/utils/get_layers.ts @@ -14,9 +14,9 @@ import { ArrayEntry, } from '@elastic/charts'; import { isEqual } from 'lodash'; -import { SeriesLayer, PaletteRegistry, lightenColor } from '../../../charts/public'; -import type { DataPublicPluginStart } from '../../../data/public'; -import type { DatatableRow } from '../../../expressions/public'; +import { SeriesLayer, PaletteRegistry, lightenColor } from '../../../../charts/public'; +import type { DataPublicPluginStart } from '../../../../data/public'; +import type { DatatableRow } from '../../../../expressions/public'; import type { BucketColumns, PieVisParams, SplitDimensionParams } from '../types'; import { getDistinctSeries } from './get_distinct_series'; diff --git a/src/plugins/vis_type_pie/public/utils/get_legend_actions.tsx b/src/plugins/vis_types/pie/public/utils/get_legend_actions.tsx similarity index 96% rename from src/plugins/vis_type_pie/public/utils/get_legend_actions.tsx rename to src/plugins/vis_types/pie/public/utils/get_legend_actions.tsx index 4ffc458bfd401..cd1d1d71aaa76 100644 --- a/src/plugins/vis_type_pie/public/utils/get_legend_actions.tsx +++ b/src/plugins/vis_types/pie/public/utils/get_legend_actions.tsx @@ -11,9 +11,9 @@ import React, { useState, useEffect, useMemo } from 'react'; import { i18n } from '@kbn/i18n'; import { EuiContextMenuPanelDescriptor, EuiIcon, EuiPopover, EuiContextMenu } from '@elastic/eui'; import { LegendAction, SeriesIdentifier } from '@elastic/charts'; -import { DataPublicPluginStart } from '../../../data/public'; +import { DataPublicPluginStart } from '../../../../data/public'; import { PieVisParams } from '../types'; -import { ClickTriggerEvent } from '../../../charts/public'; +import { ClickTriggerEvent } from '../../../../charts/public'; export const getLegendActions = ( canFilter: ( diff --git a/src/plugins/vis_type_pie/public/utils/get_split_dimension_accessor.ts b/src/plugins/vis_types/pie/public/utils/get_split_dimension_accessor.ts similarity index 87% rename from src/plugins/vis_type_pie/public/utils/get_split_dimension_accessor.ts rename to src/plugins/vis_types/pie/public/utils/get_split_dimension_accessor.ts index 5addae51dd011..4f30d4f8b3cc4 100644 --- a/src/plugins/vis_type_pie/public/utils/get_split_dimension_accessor.ts +++ b/src/plugins/vis_types/pie/public/utils/get_split_dimension_accessor.ts @@ -6,8 +6,8 @@ * Side Public License, v 1. */ import { AccessorFn } from '@elastic/charts'; -import type { FieldFormatsStart } from '../../../field_formats/public'; -import { DatatableColumn } from '../../../expressions/public'; +import { DatatableColumn } from '../../../../expressions/public'; +import type { FieldFormatsStart } from '../../../../field_formats/public'; import { Dimension } from '../types'; export const getSplitDimensionAccessor = ( diff --git a/src/plugins/vis_type_pie/public/utils/index.ts b/src/plugins/vis_types/pie/public/utils/index.ts similarity index 100% rename from src/plugins/vis_type_pie/public/utils/index.ts rename to src/plugins/vis_types/pie/public/utils/index.ts diff --git a/src/plugins/vis_type_pie/public/vis_type/index.ts b/src/plugins/vis_types/pie/public/vis_type/index.ts similarity index 100% rename from src/plugins/vis_type_pie/public/vis_type/index.ts rename to src/plugins/vis_types/pie/public/vis_type/index.ts diff --git a/src/plugins/vis_type_pie/public/vis_type/pie.ts b/src/plugins/vis_types/pie/public/vis_type/pie.ts similarity index 97% rename from src/plugins/vis_type_pie/public/vis_type/pie.ts rename to src/plugins/vis_types/pie/public/vis_type/pie.ts index 95a9d0d41481b..cfe38442a1548 100644 --- a/src/plugins/vis_type_pie/public/vis_type/pie.ts +++ b/src/plugins/vis_types/pie/public/vis_type/pie.ts @@ -8,8 +8,8 @@ import { i18n } from '@kbn/i18n'; import { Position } from '@elastic/charts'; -import { AggGroupNames } from '../../../data/public'; -import { VIS_EVENT_TO_TRIGGER, VisTypeDefinition } from '../../../visualizations/public'; +import { AggGroupNames } from '../../../../data/public'; +import { VIS_EVENT_TO_TRIGGER, VisTypeDefinition } from '../../../../visualizations/public'; import { DEFAULT_PERCENT_DECIMALS } from '../../common'; import { PieVisParams, LabelPositions, ValueFormats, PieTypeProps } from '../types'; import { toExpressionAst } from '../to_ast'; diff --git a/src/plugins/vis_type_pie/server/index.ts b/src/plugins/vis_types/pie/server/index.ts similarity index 100% rename from src/plugins/vis_type_pie/server/index.ts rename to src/plugins/vis_types/pie/server/index.ts diff --git a/src/plugins/vis_type_pie/server/plugin.ts b/src/plugins/vis_types/pie/server/plugin.ts similarity index 100% rename from src/plugins/vis_type_pie/server/plugin.ts rename to src/plugins/vis_types/pie/server/plugin.ts diff --git a/src/plugins/vis_types/pie/tsconfig.json b/src/plugins/vis_types/pie/tsconfig.json new file mode 100644 index 0000000000000..9a0a3418d72db --- /dev/null +++ b/src/plugins/vis_types/pie/tsconfig.json @@ -0,0 +1,24 @@ +{ + "extends": "../../../../tsconfig.base.json", + "compilerOptions": { + "outDir": "./target/types", + "emitDeclarationOnly": true, + "declaration": true, + "declarationMap": true + }, + "include": [ + "common/**/*", + "public/**/*", + "server/**/*" + ], + "references": [ + { "path": "../../../core/tsconfig.json" }, + { "path": "../../charts/tsconfig.json" }, + { "path": "../../data/tsconfig.json" }, + { "path": "../../expressions/tsconfig.json" }, + { "path": "../../visualizations/tsconfig.json" }, + { "path": "../../usage_collection/tsconfig.json" }, + { "path": "../../vis_default_editor/tsconfig.json" }, + { "path": "../../field_formats/tsconfig.json" } + ] + } \ No newline at end of file diff --git a/src/plugins/vis_type_vislib/common/index.ts b/src/plugins/vis_types/vislib/common/index.ts similarity index 100% rename from src/plugins/vis_type_vislib/common/index.ts rename to src/plugins/vis_types/vislib/common/index.ts diff --git a/src/plugins/vis_type_vislib/jest.config.js b/src/plugins/vis_types/vislib/jest.config.js similarity index 83% rename from src/plugins/vis_type_vislib/jest.config.js rename to src/plugins/vis_types/vislib/jest.config.js index 5e144dabd25e2..6b6d7c3361ecf 100644 --- a/src/plugins/vis_type_vislib/jest.config.js +++ b/src/plugins/vis_types/vislib/jest.config.js @@ -8,6 +8,6 @@ module.exports = { preset: '@kbn/test', - rootDir: '../../..', - roots: ['/src/plugins/vis_type_vislib'], + rootDir: '../../../..', + roots: ['/src/plugins/vis_types/vislib'], }; diff --git a/src/plugins/vis_type_vislib/kibana.json b/src/plugins/vis_types/vislib/kibana.json similarity index 100% rename from src/plugins/vis_type_vislib/kibana.json rename to src/plugins/vis_types/vislib/kibana.json diff --git a/src/plugins/vis_type_vislib/public/__snapshots__/pie_fn.test.ts.snap b/src/plugins/vis_types/vislib/public/__snapshots__/pie_fn.test.ts.snap similarity index 100% rename from src/plugins/vis_type_vislib/public/__snapshots__/pie_fn.test.ts.snap rename to src/plugins/vis_types/vislib/public/__snapshots__/pie_fn.test.ts.snap diff --git a/src/plugins/vis_type_vislib/public/__snapshots__/to_ast.test.ts.snap b/src/plugins/vis_types/vislib/public/__snapshots__/to_ast.test.ts.snap similarity index 100% rename from src/plugins/vis_type_vislib/public/__snapshots__/to_ast.test.ts.snap rename to src/plugins/vis_types/vislib/public/__snapshots__/to_ast.test.ts.snap diff --git a/src/plugins/vis_type_vislib/public/__snapshots__/to_ast_pie.test.ts.snap b/src/plugins/vis_types/vislib/public/__snapshots__/to_ast_pie.test.ts.snap similarity index 100% rename from src/plugins/vis_type_vislib/public/__snapshots__/to_ast_pie.test.ts.snap rename to src/plugins/vis_types/vislib/public/__snapshots__/to_ast_pie.test.ts.snap diff --git a/src/plugins/vis_type_vislib/public/area.ts b/src/plugins/vis_types/vislib/public/area.ts similarity index 82% rename from src/plugins/vis_type_vislib/public/area.ts rename to src/plugins/vis_types/vislib/public/area.ts index 3b132ae9be12c..f4ac79e12bbe2 100644 --- a/src/plugins/vis_type_vislib/public/area.ts +++ b/src/plugins/vis_types/vislib/public/area.ts @@ -6,8 +6,8 @@ * Side Public License, v 1. */ -import { xyVisTypes } from '../../vis_type_xy/public'; -import { VisTypeDefinition } from '../../visualizations/public'; +import { xyVisTypes } from '../../xy/public'; +import { VisTypeDefinition } from '../../../visualizations/public'; import { toExpressionAst } from './to_ast'; import { BasicVislibParams } from './types'; diff --git a/src/plugins/vis_type_vislib/public/editor/collections.ts b/src/plugins/vis_types/vislib/public/editor/collections.ts similarity index 92% rename from src/plugins/vis_type_vislib/public/editor/collections.ts rename to src/plugins/vis_types/vislib/public/editor/collections.ts index cee6901b611ae..e7905ccaf1c29 100644 --- a/src/plugins/vis_type_vislib/public/editor/collections.ts +++ b/src/plugins/vis_types/vislib/public/editor/collections.ts @@ -8,8 +8,8 @@ import { i18n } from '@kbn/i18n'; -import { colorSchemas } from '../../../charts/public'; -import { getPositions, getScaleTypes } from '../../../vis_type_xy/public'; +import { colorSchemas } from '../../../../charts/public'; +import { getPositions, getScaleTypes } from '../../../xy/public'; import { Alignment, GaugeType } from '../types'; diff --git a/src/plugins/vis_type_vislib/public/editor/components/gauge/index.tsx b/src/plugins/vis_types/vislib/public/editor/components/gauge/index.tsx similarity index 100% rename from src/plugins/vis_type_vislib/public/editor/components/gauge/index.tsx rename to src/plugins/vis_types/vislib/public/editor/components/gauge/index.tsx diff --git a/src/plugins/vis_type_vislib/public/editor/components/gauge/labels_panel.tsx b/src/plugins/vis_types/vislib/public/editor/components/gauge/labels_panel.tsx similarity index 96% rename from src/plugins/vis_type_vislib/public/editor/components/gauge/labels_panel.tsx rename to src/plugins/vis_types/vislib/public/editor/components/gauge/labels_panel.tsx index a5fb435da4550..ae200892cec57 100644 --- a/src/plugins/vis_type_vislib/public/editor/components/gauge/labels_panel.tsx +++ b/src/plugins/vis_types/vislib/public/editor/components/gauge/labels_panel.tsx @@ -10,7 +10,7 @@ import React from 'react'; import { EuiPanel, EuiSpacer, EuiTitle } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; -import { SwitchOption, TextInputOption } from '../../../../../vis_default_editor/public'; +import { SwitchOption, TextInputOption } from '../../../../../../vis_default_editor/public'; import { GaugeOptionsInternalProps } from '../gauge'; function LabelsPanel({ stateParams, setValue, setGaugeValue }: GaugeOptionsInternalProps) { diff --git a/src/plugins/vis_type_vislib/public/editor/components/gauge/ranges_panel.tsx b/src/plugins/vis_types/vislib/public/editor/components/gauge/ranges_panel.tsx similarity index 97% rename from src/plugins/vis_type_vislib/public/editor/components/gauge/ranges_panel.tsx rename to src/plugins/vis_types/vislib/public/editor/components/gauge/ranges_panel.tsx index 5091c29c28752..0cb6d7d5940fd 100644 --- a/src/plugins/vis_type_vislib/public/editor/components/gauge/ranges_panel.tsx +++ b/src/plugins/vis_types/vislib/public/editor/components/gauge/ranges_panel.tsx @@ -16,8 +16,8 @@ import { SwitchOption, ColorSchemaOptions, PercentageModeOption, -} from '../../../../../vis_default_editor/public'; -import { ColorSchemaParams, ColorSchemas, colorSchemas } from '../../../../../charts/public'; +} from '../../../../../../vis_default_editor/public'; +import { ColorSchemaParams, ColorSchemas, colorSchemas } from '../../../../../../charts/public'; import { GaugeOptionsInternalProps } from '../gauge'; import { Gauge } from '../../../gauge'; diff --git a/src/plugins/vis_type_vislib/public/editor/components/gauge/style_panel.tsx b/src/plugins/vis_types/vislib/public/editor/components/gauge/style_panel.tsx similarity index 93% rename from src/plugins/vis_type_vislib/public/editor/components/gauge/style_panel.tsx rename to src/plugins/vis_types/vislib/public/editor/components/gauge/style_panel.tsx index 79e4ed96cadec..30bdab93cdfa8 100644 --- a/src/plugins/vis_type_vislib/public/editor/components/gauge/style_panel.tsx +++ b/src/plugins/vis_types/vislib/public/editor/components/gauge/style_panel.tsx @@ -11,9 +11,9 @@ import { EuiPanel, EuiSpacer, EuiTitle } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; -import { SelectOption } from '../../../../../vis_default_editor/public'; +import { SelectOption } from '../../../../../../vis_default_editor/public'; import { GaugeOptionsInternalProps } from '../gauge'; -import { AggGroupNames } from '../../../../../data/public'; +import { AggGroupNames } from '../../../../../../data/public'; import { getGaugeCollections } from './../../collections'; const gaugeCollections = getGaugeCollections(); diff --git a/src/plugins/vis_type_vislib/public/editor/components/heatmap/index.tsx b/src/plugins/vis_types/vislib/public/editor/components/heatmap/index.tsx similarity index 98% rename from src/plugins/vis_type_vislib/public/editor/components/heatmap/index.tsx rename to src/plugins/vis_types/vislib/public/editor/components/heatmap/index.tsx index bdabded67a74a..c0d89f2f66958 100644 --- a/src/plugins/vis_type_vislib/public/editor/components/heatmap/index.tsx +++ b/src/plugins/vis_types/vislib/public/editor/components/heatmap/index.tsx @@ -13,7 +13,7 @@ import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import { VisEditorOptionsProps } from 'src/plugins/visualizations/public'; -import { ValueAxis } from '../../../../../vis_type_xy/public'; +import { ValueAxis } from '../../../../../xy/public'; import { BasicOptions, SelectOption, @@ -24,7 +24,7 @@ import { ColorSchemaOptions, NumberInputOption, PercentageModeOption, -} from '../../../../../vis_default_editor/public'; +} from '../../../../../../vis_default_editor/public'; import { HeatmapVisParams } from '../../../heatmap'; import { LabelsPanel } from './labels_panel'; diff --git a/src/plugins/vis_type_vislib/public/editor/components/heatmap/labels_panel.tsx b/src/plugins/vis_types/vislib/public/editor/components/heatmap/labels_panel.tsx similarity index 96% rename from src/plugins/vis_type_vislib/public/editor/components/heatmap/labels_panel.tsx rename to src/plugins/vis_types/vislib/public/editor/components/heatmap/labels_panel.tsx index 206900959a35b..05b8949901e79 100644 --- a/src/plugins/vis_type_vislib/public/editor/components/heatmap/labels_panel.tsx +++ b/src/plugins/vis_types/vislib/public/editor/components/heatmap/labels_panel.tsx @@ -13,8 +13,8 @@ import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import { VisEditorOptionsProps } from 'src/plugins/visualizations/public'; -import { SwitchOption } from '../../../../../vis_default_editor/public'; -import { ValueAxis } from '../../../../../vis_type_xy/public'; +import { SwitchOption } from '../../../../../../vis_default_editor/public'; +import { ValueAxis } from '../../../../../xy/public'; import { HeatmapVisParams } from '../../../heatmap'; diff --git a/src/plugins/vis_type_vislib/public/editor/components/index.tsx b/src/plugins/vis_types/vislib/public/editor/components/index.tsx similarity index 100% rename from src/plugins/vis_type_vislib/public/editor/components/index.tsx rename to src/plugins/vis_types/vislib/public/editor/components/index.tsx diff --git a/src/plugins/vis_type_vislib/public/editor/index.ts b/src/plugins/vis_types/vislib/public/editor/index.ts similarity index 100% rename from src/plugins/vis_type_vislib/public/editor/index.ts rename to src/plugins/vis_types/vislib/public/editor/index.ts diff --git a/src/plugins/vis_type_vislib/public/fixtures/dispatch_bar_chart_config_normal.json b/src/plugins/vis_types/vislib/public/fixtures/dispatch_bar_chart_config_normal.json similarity index 100% rename from src/plugins/vis_type_vislib/public/fixtures/dispatch_bar_chart_config_normal.json rename to src/plugins/vis_types/vislib/public/fixtures/dispatch_bar_chart_config_normal.json diff --git a/src/plugins/vis_type_vislib/public/fixtures/dispatch_bar_chart_config_percentage.json b/src/plugins/vis_types/vislib/public/fixtures/dispatch_bar_chart_config_percentage.json similarity index 100% rename from src/plugins/vis_type_vislib/public/fixtures/dispatch_bar_chart_config_percentage.json rename to src/plugins/vis_types/vislib/public/fixtures/dispatch_bar_chart_config_percentage.json diff --git a/src/plugins/vis_type_vislib/public/fixtures/dispatch_bar_chart_d3.json b/src/plugins/vis_types/vislib/public/fixtures/dispatch_bar_chart_d3.json similarity index 100% rename from src/plugins/vis_type_vislib/public/fixtures/dispatch_bar_chart_d3.json rename to src/plugins/vis_types/vislib/public/fixtures/dispatch_bar_chart_d3.json diff --git a/src/plugins/vis_type_vislib/public/fixtures/dispatch_bar_chart_data_point.json b/src/plugins/vis_types/vislib/public/fixtures/dispatch_bar_chart_data_point.json similarity index 100% rename from src/plugins/vis_type_vislib/public/fixtures/dispatch_bar_chart_data_point.json rename to src/plugins/vis_types/vislib/public/fixtures/dispatch_bar_chart_data_point.json diff --git a/src/plugins/vis_type_vislib/public/fixtures/dispatch_heatmap_config.json b/src/plugins/vis_types/vislib/public/fixtures/dispatch_heatmap_config.json similarity index 100% rename from src/plugins/vis_type_vislib/public/fixtures/dispatch_heatmap_config.json rename to src/plugins/vis_types/vislib/public/fixtures/dispatch_heatmap_config.json diff --git a/src/plugins/vis_type_vislib/public/fixtures/dispatch_heatmap_d3.json b/src/plugins/vis_types/vislib/public/fixtures/dispatch_heatmap_d3.json similarity index 100% rename from src/plugins/vis_type_vislib/public/fixtures/dispatch_heatmap_d3.json rename to src/plugins/vis_types/vislib/public/fixtures/dispatch_heatmap_d3.json diff --git a/src/plugins/vis_type_vislib/public/fixtures/dispatch_heatmap_data_point.json b/src/plugins/vis_types/vislib/public/fixtures/dispatch_heatmap_data_point.json similarity index 100% rename from src/plugins/vis_type_vislib/public/fixtures/dispatch_heatmap_data_point.json rename to src/plugins/vis_types/vislib/public/fixtures/dispatch_heatmap_data_point.json diff --git a/src/plugins/vis_type_vislib/public/fixtures/mock_data/date_histogram/_columns.js b/src/plugins/vis_types/vislib/public/fixtures/mock_data/date_histogram/_columns.js similarity index 100% rename from src/plugins/vis_type_vislib/public/fixtures/mock_data/date_histogram/_columns.js rename to src/plugins/vis_types/vislib/public/fixtures/mock_data/date_histogram/_columns.js diff --git a/src/plugins/vis_type_vislib/public/fixtures/mock_data/date_histogram/_rows.js b/src/plugins/vis_types/vislib/public/fixtures/mock_data/date_histogram/_rows.js similarity index 100% rename from src/plugins/vis_type_vislib/public/fixtures/mock_data/date_histogram/_rows.js rename to src/plugins/vis_types/vislib/public/fixtures/mock_data/date_histogram/_rows.js diff --git a/src/plugins/vis_type_vislib/public/fixtures/mock_data/date_histogram/_rows_series_with_holes.js b/src/plugins/vis_types/vislib/public/fixtures/mock_data/date_histogram/_rows_series_with_holes.js similarity index 100% rename from src/plugins/vis_type_vislib/public/fixtures/mock_data/date_histogram/_rows_series_with_holes.js rename to src/plugins/vis_types/vislib/public/fixtures/mock_data/date_histogram/_rows_series_with_holes.js diff --git a/src/plugins/vis_type_vislib/public/fixtures/mock_data/date_histogram/_series.js b/src/plugins/vis_types/vislib/public/fixtures/mock_data/date_histogram/_series.js similarity index 100% rename from src/plugins/vis_type_vislib/public/fixtures/mock_data/date_histogram/_series.js rename to src/plugins/vis_types/vislib/public/fixtures/mock_data/date_histogram/_series.js diff --git a/src/plugins/vis_type_vislib/public/fixtures/mock_data/date_histogram/_series_monthly_interval.js b/src/plugins/vis_types/vislib/public/fixtures/mock_data/date_histogram/_series_monthly_interval.js similarity index 100% rename from src/plugins/vis_type_vislib/public/fixtures/mock_data/date_histogram/_series_monthly_interval.js rename to src/plugins/vis_types/vislib/public/fixtures/mock_data/date_histogram/_series_monthly_interval.js diff --git a/src/plugins/vis_type_vislib/public/fixtures/mock_data/date_histogram/_series_neg.js b/src/plugins/vis_types/vislib/public/fixtures/mock_data/date_histogram/_series_neg.js similarity index 100% rename from src/plugins/vis_type_vislib/public/fixtures/mock_data/date_histogram/_series_neg.js rename to src/plugins/vis_types/vislib/public/fixtures/mock_data/date_histogram/_series_neg.js diff --git a/src/plugins/vis_type_vislib/public/fixtures/mock_data/date_histogram/_series_pos_neg.js b/src/plugins/vis_types/vislib/public/fixtures/mock_data/date_histogram/_series_pos_neg.js similarity index 100% rename from src/plugins/vis_type_vislib/public/fixtures/mock_data/date_histogram/_series_pos_neg.js rename to src/plugins/vis_types/vislib/public/fixtures/mock_data/date_histogram/_series_pos_neg.js diff --git a/src/plugins/vis_type_vislib/public/fixtures/mock_data/date_histogram/_stacked_series.js b/src/plugins/vis_types/vislib/public/fixtures/mock_data/date_histogram/_stacked_series.js similarity index 100% rename from src/plugins/vis_type_vislib/public/fixtures/mock_data/date_histogram/_stacked_series.js rename to src/plugins/vis_types/vislib/public/fixtures/mock_data/date_histogram/_stacked_series.js diff --git a/src/plugins/vis_type_vislib/public/fixtures/mock_data/filters/_columns.js b/src/plugins/vis_types/vislib/public/fixtures/mock_data/filters/_columns.js similarity index 100% rename from src/plugins/vis_type_vislib/public/fixtures/mock_data/filters/_columns.js rename to src/plugins/vis_types/vislib/public/fixtures/mock_data/filters/_columns.js diff --git a/src/plugins/vis_type_vislib/public/fixtures/mock_data/filters/_rows.js b/src/plugins/vis_types/vislib/public/fixtures/mock_data/filters/_rows.js similarity index 100% rename from src/plugins/vis_type_vislib/public/fixtures/mock_data/filters/_rows.js rename to src/plugins/vis_types/vislib/public/fixtures/mock_data/filters/_rows.js diff --git a/src/plugins/vis_type_vislib/public/fixtures/mock_data/filters/_series.js b/src/plugins/vis_types/vislib/public/fixtures/mock_data/filters/_series.js similarity index 100% rename from src/plugins/vis_type_vislib/public/fixtures/mock_data/filters/_series.js rename to src/plugins/vis_types/vislib/public/fixtures/mock_data/filters/_series.js diff --git a/src/plugins/vis_type_vislib/public/fixtures/mock_data/geohash/_columns.js b/src/plugins/vis_types/vislib/public/fixtures/mock_data/geohash/_columns.js similarity index 100% rename from src/plugins/vis_type_vislib/public/fixtures/mock_data/geohash/_columns.js rename to src/plugins/vis_types/vislib/public/fixtures/mock_data/geohash/_columns.js diff --git a/src/plugins/vis_type_vislib/public/fixtures/mock_data/geohash/_geo_json.js b/src/plugins/vis_types/vislib/public/fixtures/mock_data/geohash/_geo_json.js similarity index 100% rename from src/plugins/vis_type_vislib/public/fixtures/mock_data/geohash/_geo_json.js rename to src/plugins/vis_types/vislib/public/fixtures/mock_data/geohash/_geo_json.js diff --git a/src/plugins/vis_type_vislib/public/fixtures/mock_data/geohash/_rows.js b/src/plugins/vis_types/vislib/public/fixtures/mock_data/geohash/_rows.js similarity index 100% rename from src/plugins/vis_type_vislib/public/fixtures/mock_data/geohash/_rows.js rename to src/plugins/vis_types/vislib/public/fixtures/mock_data/geohash/_rows.js diff --git a/src/plugins/vis_type_vislib/public/fixtures/mock_data/histogram/_columns.js b/src/plugins/vis_types/vislib/public/fixtures/mock_data/histogram/_columns.js similarity index 100% rename from src/plugins/vis_type_vislib/public/fixtures/mock_data/histogram/_columns.js rename to src/plugins/vis_types/vislib/public/fixtures/mock_data/histogram/_columns.js diff --git a/src/plugins/vis_type_vislib/public/fixtures/mock_data/histogram/_rows.js b/src/plugins/vis_types/vislib/public/fixtures/mock_data/histogram/_rows.js similarity index 100% rename from src/plugins/vis_type_vislib/public/fixtures/mock_data/histogram/_rows.js rename to src/plugins/vis_types/vislib/public/fixtures/mock_data/histogram/_rows.js diff --git a/src/plugins/vis_type_vislib/public/fixtures/mock_data/histogram/_series.js b/src/plugins/vis_types/vislib/public/fixtures/mock_data/histogram/_series.js similarity index 100% rename from src/plugins/vis_type_vislib/public/fixtures/mock_data/histogram/_series.js rename to src/plugins/vis_types/vislib/public/fixtures/mock_data/histogram/_series.js diff --git a/src/plugins/vis_type_vislib/public/fixtures/mock_data/histogram/_slices.js b/src/plugins/vis_types/vislib/public/fixtures/mock_data/histogram/_slices.js similarity index 100% rename from src/plugins/vis_type_vislib/public/fixtures/mock_data/histogram/_slices.js rename to src/plugins/vis_types/vislib/public/fixtures/mock_data/histogram/_slices.js diff --git a/src/plugins/vis_type_vislib/public/fixtures/mock_data/not_enough_data/_one_point.js b/src/plugins/vis_types/vislib/public/fixtures/mock_data/not_enough_data/_one_point.js similarity index 100% rename from src/plugins/vis_type_vislib/public/fixtures/mock_data/not_enough_data/_one_point.js rename to src/plugins/vis_types/vislib/public/fixtures/mock_data/not_enough_data/_one_point.js diff --git a/src/plugins/vis_type_vislib/public/fixtures/mock_data/range/_columns.js b/src/plugins/vis_types/vislib/public/fixtures/mock_data/range/_columns.js similarity index 100% rename from src/plugins/vis_type_vislib/public/fixtures/mock_data/range/_columns.js rename to src/plugins/vis_types/vislib/public/fixtures/mock_data/range/_columns.js diff --git a/src/plugins/vis_type_vislib/public/fixtures/mock_data/range/_rows.js b/src/plugins/vis_types/vislib/public/fixtures/mock_data/range/_rows.js similarity index 100% rename from src/plugins/vis_type_vislib/public/fixtures/mock_data/range/_rows.js rename to src/plugins/vis_types/vislib/public/fixtures/mock_data/range/_rows.js diff --git a/src/plugins/vis_type_vislib/public/fixtures/mock_data/range/_series.js b/src/plugins/vis_types/vislib/public/fixtures/mock_data/range/_series.js similarity index 100% rename from src/plugins/vis_type_vislib/public/fixtures/mock_data/range/_series.js rename to src/plugins/vis_types/vislib/public/fixtures/mock_data/range/_series.js diff --git a/src/plugins/vis_type_vislib/public/fixtures/mock_data/significant_terms/_columns.js b/src/plugins/vis_types/vislib/public/fixtures/mock_data/significant_terms/_columns.js similarity index 100% rename from src/plugins/vis_type_vislib/public/fixtures/mock_data/significant_terms/_columns.js rename to src/plugins/vis_types/vislib/public/fixtures/mock_data/significant_terms/_columns.js diff --git a/src/plugins/vis_type_vislib/public/fixtures/mock_data/significant_terms/_rows.js b/src/plugins/vis_types/vislib/public/fixtures/mock_data/significant_terms/_rows.js similarity index 100% rename from src/plugins/vis_type_vislib/public/fixtures/mock_data/significant_terms/_rows.js rename to src/plugins/vis_types/vislib/public/fixtures/mock_data/significant_terms/_rows.js diff --git a/src/plugins/vis_type_vislib/public/fixtures/mock_data/significant_terms/_series.js b/src/plugins/vis_types/vislib/public/fixtures/mock_data/significant_terms/_series.js similarity index 100% rename from src/plugins/vis_type_vislib/public/fixtures/mock_data/significant_terms/_series.js rename to src/plugins/vis_types/vislib/public/fixtures/mock_data/significant_terms/_series.js diff --git a/src/plugins/vis_type_vislib/public/fixtures/mock_data/stacked/_stacked.js b/src/plugins/vis_types/vislib/public/fixtures/mock_data/stacked/_stacked.js similarity index 100% rename from src/plugins/vis_type_vislib/public/fixtures/mock_data/stacked/_stacked.js rename to src/plugins/vis_types/vislib/public/fixtures/mock_data/stacked/_stacked.js diff --git a/src/plugins/vis_type_vislib/public/fixtures/mock_data/terms/_columns.js b/src/plugins/vis_types/vislib/public/fixtures/mock_data/terms/_columns.js similarity index 100% rename from src/plugins/vis_type_vislib/public/fixtures/mock_data/terms/_columns.js rename to src/plugins/vis_types/vislib/public/fixtures/mock_data/terms/_columns.js diff --git a/src/plugins/vis_type_vislib/public/fixtures/mock_data/terms/_rows.js b/src/plugins/vis_types/vislib/public/fixtures/mock_data/terms/_rows.js similarity index 100% rename from src/plugins/vis_type_vislib/public/fixtures/mock_data/terms/_rows.js rename to src/plugins/vis_types/vislib/public/fixtures/mock_data/terms/_rows.js diff --git a/src/plugins/vis_type_vislib/public/fixtures/mock_data/terms/_series.js b/src/plugins/vis_types/vislib/public/fixtures/mock_data/terms/_series.js similarity index 100% rename from src/plugins/vis_type_vislib/public/fixtures/mock_data/terms/_series.js rename to src/plugins/vis_types/vislib/public/fixtures/mock_data/terms/_series.js diff --git a/src/plugins/vis_type_vislib/public/fixtures/mock_data/terms/_series_multiple.js b/src/plugins/vis_types/vislib/public/fixtures/mock_data/terms/_series_multiple.js similarity index 100% rename from src/plugins/vis_type_vislib/public/fixtures/mock_data/terms/_series_multiple.js rename to src/plugins/vis_types/vislib/public/fixtures/mock_data/terms/_series_multiple.js diff --git a/src/plugins/vis_type_vislib/public/fixtures/mocks.js b/src/plugins/vis_types/vislib/public/fixtures/mocks.js similarity index 100% rename from src/plugins/vis_type_vislib/public/fixtures/mocks.js rename to src/plugins/vis_types/vislib/public/fixtures/mocks.js diff --git a/src/plugins/vis_type_vislib/public/gauge.ts b/src/plugins/vis_types/vislib/public/gauge.ts similarity index 93% rename from src/plugins/vis_type_vislib/public/gauge.ts rename to src/plugins/vis_types/vislib/public/gauge.ts index fa463bea6f27f..e03abf5d90cbe 100644 --- a/src/plugins/vis_type_vislib/public/gauge.ts +++ b/src/plugins/vis_types/vislib/public/gauge.ts @@ -8,10 +8,10 @@ import { i18n } from '@kbn/i18n'; -import { ColorMode, ColorSchemas, ColorSchemaParams, Labels, Style } from '../../charts/public'; -import { RangeValues } from '../../vis_default_editor/public'; -import { AggGroupNames } from '../../data/public'; -import { VisTypeDefinition, VIS_EVENT_TO_TRIGGER } from '../../visualizations/public'; +import { ColorMode, ColorSchemas, ColorSchemaParams, Labels, Style } from '../../../charts/public'; +import { RangeValues } from '../../../vis_default_editor/public'; +import { AggGroupNames } from '../../../data/public'; +import { VisTypeDefinition, VIS_EVENT_TO_TRIGGER } from '../../../visualizations/public'; import { Alignment, GaugeType, VislibChartType } from './types'; import { toExpressionAst } from './to_ast'; diff --git a/src/plugins/vis_type_vislib/public/goal.ts b/src/plugins/vis_types/vislib/public/goal.ts similarity index 93% rename from src/plugins/vis_type_vislib/public/goal.ts rename to src/plugins/vis_types/vislib/public/goal.ts index e594122871fe7..5e6074b12ce47 100644 --- a/src/plugins/vis_type_vislib/public/goal.ts +++ b/src/plugins/vis_types/vislib/public/goal.ts @@ -8,9 +8,9 @@ import { i18n } from '@kbn/i18n'; -import { AggGroupNames } from '../../data/public'; -import { ColorMode, ColorSchemas } from '../../charts/public'; -import { VisTypeDefinition } from '../../visualizations/public'; +import { AggGroupNames } from '../../../data/public'; +import { ColorMode, ColorSchemas } from '../../../charts/public'; +import { VisTypeDefinition } from '../../../visualizations/public'; import { GaugeOptions } from './editor'; import { toExpressionAst } from './to_ast'; diff --git a/src/plugins/vis_type_vislib/public/heatmap.ts b/src/plugins/vis_types/vislib/public/heatmap.ts similarity index 91% rename from src/plugins/vis_type_vislib/public/heatmap.ts rename to src/plugins/vis_types/vislib/public/heatmap.ts index f3f320b3658a0..3ea3a4b1e4a06 100644 --- a/src/plugins/vis_type_vislib/public/heatmap.ts +++ b/src/plugins/vis_types/vislib/public/heatmap.ts @@ -9,11 +9,11 @@ import { i18n } from '@kbn/i18n'; import { Position } from '@elastic/charts'; -import { RangeValues } from '../../vis_default_editor/public'; -import { AggGroupNames } from '../../data/public'; -import { ColorSchemas, ColorSchemaParams } from '../../charts/public'; -import { VIS_EVENT_TO_TRIGGER, VisTypeDefinition } from '../../visualizations/public'; -import { ValueAxis, ScaleType, AxisType } from '../../vis_type_xy/public'; +import { RangeValues } from '../../../vis_default_editor/public'; +import { AggGroupNames } from '../../../data/public'; +import { ColorSchemas, ColorSchemaParams } from '../../../charts/public'; +import { VIS_EVENT_TO_TRIGGER, VisTypeDefinition } from '../../../visualizations/public'; +import { ValueAxis, ScaleType, AxisType } from '../../xy/public'; import { HeatmapOptions } from './editor'; import { TimeMarker } from './vislib/visualizations/time_marker'; diff --git a/src/plugins/vis_type_vislib/public/histogram.ts b/src/plugins/vis_types/vislib/public/histogram.ts similarity index 82% rename from src/plugins/vis_type_vislib/public/histogram.ts rename to src/plugins/vis_types/vislib/public/histogram.ts index e7200a9ff30aa..bb4f570c6a2d8 100644 --- a/src/plugins/vis_type_vislib/public/histogram.ts +++ b/src/plugins/vis_types/vislib/public/histogram.ts @@ -6,8 +6,8 @@ * Side Public License, v 1. */ -import { xyVisTypes } from '../../vis_type_xy/public'; -import { VisTypeDefinition } from '../../visualizations/public'; +import { xyVisTypes } from '../../xy/public'; +import { VisTypeDefinition } from '../../../visualizations/public'; import { toExpressionAst } from './to_ast'; import { BasicVislibParams } from './types'; diff --git a/src/plugins/vis_type_vislib/public/horizontal_bar.ts b/src/plugins/vis_types/vislib/public/horizontal_bar.ts similarity index 83% rename from src/plugins/vis_type_vislib/public/horizontal_bar.ts rename to src/plugins/vis_types/vislib/public/horizontal_bar.ts index 70f0372025e3e..37aa79a0b1aee 100644 --- a/src/plugins/vis_type_vislib/public/horizontal_bar.ts +++ b/src/plugins/vis_types/vislib/public/horizontal_bar.ts @@ -6,8 +6,8 @@ * Side Public License, v 1. */ -import { xyVisTypes } from '../../vis_type_xy/public'; -import { VisTypeDefinition } from '../../visualizations/public'; +import { xyVisTypes } from '../../xy/public'; +import { VisTypeDefinition } from '../../../visualizations/public'; import { toExpressionAst } from './to_ast'; import { BasicVislibParams } from './types'; diff --git a/src/plugins/vis_type_vislib/public/index.scss b/src/plugins/vis_types/vislib/public/index.scss similarity index 100% rename from src/plugins/vis_type_vislib/public/index.scss rename to src/plugins/vis_types/vislib/public/index.scss diff --git a/src/plugins/vis_type_vislib/public/index.ts b/src/plugins/vis_types/vislib/public/index.ts similarity index 89% rename from src/plugins/vis_type_vislib/public/index.ts rename to src/plugins/vis_types/vislib/public/index.ts index 2a063e4d8a7f4..232e0494a9ebf 100644 --- a/src/plugins/vis_type_vislib/public/index.ts +++ b/src/plugins/vis_types/vislib/public/index.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { PluginInitializerContext } from '../../../core/public'; +import { PluginInitializerContext } from '../../../../core/public'; import { VisTypeVislibPlugin as Plugin } from './plugin'; export function plugin(initializerContext: PluginInitializerContext) { diff --git a/src/plugins/vis_type_vislib/public/line.ts b/src/plugins/vis_types/vislib/public/line.ts similarity index 82% rename from src/plugins/vis_type_vislib/public/line.ts rename to src/plugins/vis_types/vislib/public/line.ts index d91bb5d0384b6..0f33c393e0643 100644 --- a/src/plugins/vis_type_vislib/public/line.ts +++ b/src/plugins/vis_types/vislib/public/line.ts @@ -6,8 +6,8 @@ * Side Public License, v 1. */ -import { xyVisTypes } from '../../vis_type_xy/public'; -import { VisTypeDefinition } from '../../visualizations/public'; +import { xyVisTypes } from '../../xy/public'; +import { VisTypeDefinition } from '../../../visualizations/public'; import { toExpressionAst } from './to_ast'; import { BasicVislibParams } from './types'; diff --git a/src/plugins/vis_type_vislib/public/pie.ts b/src/plugins/vis_types/vislib/public/pie.ts similarity index 86% rename from src/plugins/vis_type_vislib/public/pie.ts rename to src/plugins/vis_types/vislib/public/pie.ts index 4f6eb7e536509..45794776bc998 100644 --- a/src/plugins/vis_type_vislib/public/pie.ts +++ b/src/plugins/vis_types/vislib/public/pie.ts @@ -6,8 +6,8 @@ * Side Public License, v 1. */ -import { pieVisType } from '../../vis_type_pie/public'; -import { VisTypeDefinition } from '../../visualizations/public'; +import { pieVisType } from '../../pie/public'; +import { VisTypeDefinition } from '../../../visualizations/public'; import { CommonVislibParams } from './types'; import { toExpressionAst } from './to_ast_pie'; diff --git a/src/plugins/vis_type_vislib/public/pie_fn.test.ts b/src/plugins/vis_types/vislib/public/pie_fn.test.ts similarity index 95% rename from src/plugins/vis_type_vislib/public/pie_fn.test.ts rename to src/plugins/vis_types/vislib/public/pie_fn.test.ts index 4291b5c05fc39..0df7bf1365bea 100644 --- a/src/plugins/vis_type_vislib/public/pie_fn.test.ts +++ b/src/plugins/vis_types/vislib/public/pie_fn.test.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { functionWrapper } from '../../expressions/common/expression_functions/specs/tests/utils'; +import { functionWrapper } from '../../../expressions/common/expression_functions/specs/tests/utils'; import { createPieVisFn } from './pie_fn'; // @ts-ignore import { vislibSlicesResponseHandler } from './vislib/response_handler'; diff --git a/src/plugins/vis_type_vislib/public/pie_fn.ts b/src/plugins/vis_types/vislib/public/pie_fn.ts similarity index 98% rename from src/plugins/vis_type_vislib/public/pie_fn.ts rename to src/plugins/vis_types/vislib/public/pie_fn.ts index 8776a6bc2d18a..dd5d2689af74d 100644 --- a/src/plugins/vis_type_vislib/public/pie_fn.ts +++ b/src/plugins/vis_types/vislib/public/pie_fn.ts @@ -8,7 +8,7 @@ import { i18n } from '@kbn/i18n'; -import { ExpressionFunctionDefinition, Datatable, Render } from '../../expressions/public'; +import { ExpressionFunctionDefinition, Datatable, Render } from '../../../expressions/public'; // @ts-ignore import { vislibSlicesResponseHandler } from './vislib/response_handler'; diff --git a/src/plugins/vis_type_vislib/public/plugin.ts b/src/plugins/vis_types/vislib/public/plugin.ts similarity index 83% rename from src/plugins/vis_type_vislib/public/plugin.ts rename to src/plugins/vis_types/vislib/public/plugin.ts index cdc02aacafa3b..24ba7741cab91 100644 --- a/src/plugins/vis_type_vislib/public/plugin.ts +++ b/src/plugins/vis_types/vislib/public/plugin.ts @@ -8,13 +8,13 @@ import { CoreSetup, CoreStart, Plugin, PluginInitializerContext } from 'kibana/public'; -import { Plugin as ExpressionsPublicPlugin } from '../../expressions/public'; -import { VisualizationsSetup } from '../../visualizations/public'; -import { ChartsPluginSetup } from '../../charts/public'; -import { DataPublicPluginStart } from '../../data/public'; -import { KibanaLegacyStart } from '../../kibana_legacy/public'; -import { LEGACY_CHARTS_LIBRARY } from '../../vis_type_xy/common/index'; -import { LEGACY_PIE_CHARTS_LIBRARY } from '../../vis_type_pie/common/index'; +import { Plugin as ExpressionsPublicPlugin } from '../../../expressions/public'; +import { VisualizationsSetup } from '../../../visualizations/public'; +import { ChartsPluginSetup } from '../../../charts/public'; +import { DataPublicPluginStart } from '../../../data/public'; +import { KibanaLegacyStart } from '../../../kibana_legacy/public'; +import { LEGACY_CHARTS_LIBRARY } from '../../xy/common/index'; +import { LEGACY_PIE_CHARTS_LIBRARY } from '../../pie/common/index'; import { createVisTypeVislibVisFn } from './vis_type_vislib_vis_fn'; import { createPieVisFn } from './pie_fn'; diff --git a/src/plugins/vis_type_vislib/public/services.ts b/src/plugins/vis_types/vislib/public/services.ts similarity index 82% rename from src/plugins/vis_type_vislib/public/services.ts rename to src/plugins/vis_types/vislib/public/services.ts index 00e3ed0791e5d..d111007598b8b 100644 --- a/src/plugins/vis_type_vislib/public/services.ts +++ b/src/plugins/vis_types/vislib/public/services.ts @@ -6,8 +6,8 @@ * Side Public License, v 1. */ -import { createGetterSetter } from '../../kibana_utils/public'; -import { DataPublicPluginStart } from '../../data/public'; +import { createGetterSetter } from '../../../kibana_utils/public'; +import { DataPublicPluginStart } from '../../../data/public'; export const [getDataActions, setDataActions] = createGetterSetter< DataPublicPluginStart['actions'] diff --git a/src/plugins/vis_type_vislib/public/to_ast.test.ts b/src/plugins/vis_types/vislib/public/to_ast.test.ts similarity index 78% rename from src/plugins/vis_type_vislib/public/to_ast.test.ts rename to src/plugins/vis_types/vislib/public/to_ast.test.ts index d4e4d4fcdd1dd..70a1f938a8266 100644 --- a/src/plugins/vis_type_vislib/public/to_ast.test.ts +++ b/src/plugins/vis_types/vislib/public/to_ast.test.ts @@ -6,15 +6,15 @@ * Side Public License, v 1. */ -import { Vis } from '../../visualizations/public'; -import { buildExpression } from '../../expressions/public'; +import { Vis } from '../../../visualizations/public'; +import { buildExpression } from '../../../expressions/public'; import { BasicVislibParams } from './types'; import { toExpressionAst } from './to_ast'; -import { sampleAreaVis } from '../../vis_type_xy/public/sample_vis.test.mocks'; +import { sampleAreaVis } from '../../xy/public/sample_vis.test.mocks'; -jest.mock('../../expressions/public', () => ({ - ...(jest.requireActual('../../expressions/public') as any), +jest.mock('../../../expressions/public', () => ({ + ...(jest.requireActual('../../../expressions/public') as any), buildExpression: jest.fn().mockImplementation(() => ({ toAst: () => ({ type: 'expression', diff --git a/src/plugins/vis_type_vislib/public/to_ast.ts b/src/plugins/vis_types/vislib/public/to_ast.ts similarity index 94% rename from src/plugins/vis_type_vislib/public/to_ast.ts rename to src/plugins/vis_types/vislib/public/to_ast.ts index 1e33c589ff1fc..c1de94ba0f5f9 100644 --- a/src/plugins/vis_type_vislib/public/to_ast.ts +++ b/src/plugins/vis_types/vislib/public/to_ast.ts @@ -13,12 +13,12 @@ import { VisToExpressionAstParams, getVisSchemas, VisParams, -} from '../../visualizations/public'; -import { buildExpression, buildExpressionFunction } from '../../expressions/public'; -import type { Dimensions } from '../../vis_type_xy/public'; -import type { DateHistogramParams, HistogramParams } from '../../visualizations/public'; +} from '../../../visualizations/public'; +import { buildExpression, buildExpressionFunction } from '../../../expressions/public'; +import type { Dimensions } from '../../xy/public'; +import type { DateHistogramParams, HistogramParams } from '../../../visualizations/public'; -import { BUCKET_TYPES } from '../../data/public'; +import { BUCKET_TYPES } from '../../../data/public'; import { vislibVisName, VisTypeVislibExpressionFunctionDefinition } from './vis_type_vislib_vis_fn'; import { BasicVislibParams, VislibChartType } from './types'; diff --git a/src/plugins/vis_type_vislib/public/to_ast_esaggs.ts b/src/plugins/vis_types/vislib/public/to_ast_esaggs.ts similarity index 91% rename from src/plugins/vis_type_vislib/public/to_ast_esaggs.ts rename to src/plugins/vis_types/vislib/public/to_ast_esaggs.ts index c7e351ccc0429..d34989917e707 100644 --- a/src/plugins/vis_type_vislib/public/to_ast_esaggs.ts +++ b/src/plugins/vis_types/vislib/public/to_ast_esaggs.ts @@ -6,12 +6,12 @@ * Side Public License, v 1. */ -import { Vis } from '../../visualizations/public'; -import { buildExpression, buildExpressionFunction } from '../../expressions/public'; +import { Vis } from '../../../visualizations/public'; +import { buildExpression, buildExpressionFunction } from '../../../expressions/public'; import { EsaggsExpressionFunctionDefinition, IndexPatternLoadExpressionFunctionDefinition, -} from '../../data/public'; +} from '../../../data/public'; /** * Get esaggs expressions function diff --git a/src/plugins/vis_type_vislib/public/to_ast_pie.test.ts b/src/plugins/vis_types/vislib/public/to_ast_pie.test.ts similarity index 78% rename from src/plugins/vis_type_vislib/public/to_ast_pie.test.ts rename to src/plugins/vis_types/vislib/public/to_ast_pie.test.ts index 3178c23ee8fa0..6202df3f65094 100644 --- a/src/plugins/vis_type_vislib/public/to_ast_pie.test.ts +++ b/src/plugins/vis_types/vislib/public/to_ast_pie.test.ts @@ -6,15 +6,15 @@ * Side Public License, v 1. */ -import { Vis } from '../../visualizations/public'; -import { buildExpression } from '../../expressions/public'; +import { Vis } from '../../../visualizations/public'; +import { buildExpression } from '../../../expressions/public'; import { PieVisParams } from './pie'; -import { samplePieVis } from '../../vis_type_pie/public/sample_vis.test.mocks'; +import { samplePieVis } from '../../pie/public/sample_vis.test.mocks'; import { toExpressionAst } from './to_ast_pie'; -jest.mock('../../expressions/public', () => ({ - ...(jest.requireActual('../../expressions/public') as any), +jest.mock('../../../expressions/public', () => ({ + ...(jest.requireActual('../../../expressions/public') as any), buildExpression: jest.fn().mockImplementation(() => ({ toAst: () => ({ type: 'expression', diff --git a/src/plugins/vis_type_vislib/public/to_ast_pie.ts b/src/plugins/vis_types/vislib/public/to_ast_pie.ts similarity index 91% rename from src/plugins/vis_type_vislib/public/to_ast_pie.ts rename to src/plugins/vis_types/vislib/public/to_ast_pie.ts index 05a887b5513a3..90c181f8ac74e 100644 --- a/src/plugins/vis_type_vislib/public/to_ast_pie.ts +++ b/src/plugins/vis_types/vislib/public/to_ast_pie.ts @@ -6,8 +6,8 @@ * Side Public License, v 1. */ -import { getVisSchemas, VisToExpressionAst } from '../../visualizations/public'; -import { buildExpression, buildExpressionFunction } from '../../expressions/public'; +import { getVisSchemas, VisToExpressionAst } from '../../../visualizations/public'; +import { buildExpression, buildExpressionFunction } from '../../../expressions/public'; import { PieVisParams } from './pie'; import { vislibPieName, VisTypeVislibPieExpressionFunctionDefinition } from './pie_fn'; diff --git a/src/plugins/vis_type_vislib/public/types.ts b/src/plugins/vis_types/vislib/public/types.ts similarity index 95% rename from src/plugins/vis_type_vislib/public/types.ts rename to src/plugins/vis_types/vislib/public/types.ts index d5432a12624fb..5196f0e33f404 100644 --- a/src/plugins/vis_type_vislib/public/types.ts +++ b/src/plugins/vis_types/vislib/public/types.ts @@ -9,7 +9,7 @@ import { $Values } from '@kbn/utility-types'; import { Position } from '@elastic/charts'; -import { Labels } from '../../charts/public'; +import { Labels } from '../../../charts/public'; import { CategoryAxis, Dimensions, @@ -17,7 +17,7 @@ import { SeriesParam, ThresholdLine, ValueAxis, -} from '../../vis_type_xy/public'; +} from '../../../vis_types/xy/public'; import { TimeMarker } from './vislib/visualizations/time_marker'; /** diff --git a/src/plugins/vis_type_vislib/public/vis_controller.tsx b/src/plugins/vis_types/vislib/public/vis_controller.tsx similarity index 94% rename from src/plugins/vis_type_vislib/public/vis_controller.tsx rename to src/plugins/vis_types/vislib/public/vis_controller.tsx index 73d110e4d8d75..7bae32d031b46 100644 --- a/src/plugins/vis_type_vislib/public/vis_controller.tsx +++ b/src/plugins/vis_types/vislib/public/vis_controller.tsx @@ -9,10 +9,10 @@ import $ from 'jquery'; import React, { RefObject } from 'react'; -import { mountReactNode } from '../../../core/public/utils'; -import { ChartsPluginSetup } from '../../charts/public'; -import type { PersistedState } from '../../visualizations/public'; -import { IInterpreterRenderHandlers } from '../../expressions/public'; +import { mountReactNode } from '../../../../core/public/utils'; +import { ChartsPluginSetup } from '../../../charts/public'; +import type { PersistedState } from '../../../visualizations/public'; +import { IInterpreterRenderHandlers } from '../../../expressions/public'; import { VisTypeVislibCoreSetup } from './plugin'; import { VisLegend, CUSTOM_LEGEND_VIS_TYPES } from './vislib/components/legend'; diff --git a/src/plugins/vis_type_vislib/public/vis_renderer.tsx b/src/plugins/vis_types/vislib/public/vis_renderer.tsx similarity index 89% rename from src/plugins/vis_type_vislib/public/vis_renderer.tsx rename to src/plugins/vis_types/vislib/public/vis_renderer.tsx index 2e954b9a5b710..04c4c3cedc9d2 100644 --- a/src/plugins/vis_type_vislib/public/vis_renderer.tsx +++ b/src/plugins/vis_types/vislib/public/vis_renderer.tsx @@ -9,9 +9,9 @@ import React, { lazy } from 'react'; import { render, unmountComponentAtNode } from 'react-dom'; -import { ExpressionRenderDefinition } from '../../expressions/public'; -import { VisualizationContainer } from '../../visualizations/public'; -import { ChartsPluginSetup } from '../../charts/public'; +import { ExpressionRenderDefinition } from '../../../expressions/public'; +import { VisualizationContainer } from '../../../visualizations/public'; +import { ChartsPluginSetup } from '../../../charts/public'; import { VisTypeVislibCoreSetup } from './plugin'; import { VislibRenderValue, vislibVisName } from './vis_type_vislib_vis_fn'; diff --git a/src/plugins/vis_type_vislib/public/vis_type_vislib_vis_fn.ts b/src/plugins/vis_types/vislib/public/vis_type_vislib_vis_fn.ts similarity index 98% rename from src/plugins/vis_type_vislib/public/vis_type_vislib_vis_fn.ts rename to src/plugins/vis_types/vislib/public/vis_type_vislib_vis_fn.ts index 2a987b3691f5e..0658ed1b7c4b1 100644 --- a/src/plugins/vis_type_vislib/public/vis_type_vislib_vis_fn.ts +++ b/src/plugins/vis_types/vislib/public/vis_type_vislib_vis_fn.ts @@ -8,7 +8,7 @@ import { i18n } from '@kbn/i18n'; -import { ExpressionFunctionDefinition, Datatable, Render } from '../../expressions/public'; +import { ExpressionFunctionDefinition, Datatable, Render } from '../../../expressions/public'; // @ts-ignore import { vislibSeriesResponseHandler } from './vislib/response_handler'; diff --git a/src/plugins/vis_type_vislib/public/vis_type_vislib_vis_types.ts b/src/plugins/vis_types/vislib/public/vis_type_vislib_vis_types.ts similarity index 100% rename from src/plugins/vis_type_vislib/public/vis_type_vislib_vis_types.ts rename to src/plugins/vis_types/vislib/public/vis_type_vislib_vis_types.ts diff --git a/src/plugins/vis_type_vislib/public/vis_wrapper.tsx b/src/plugins/vis_types/vislib/public/vis_wrapper.tsx similarity index 92% rename from src/plugins/vis_type_vislib/public/vis_wrapper.tsx rename to src/plugins/vis_types/vislib/public/vis_wrapper.tsx index c9b978b3a2cee..e3948807005e6 100644 --- a/src/plugins/vis_type_vislib/public/vis_wrapper.tsx +++ b/src/plugins/vis_types/vislib/public/vis_wrapper.tsx @@ -10,9 +10,9 @@ import React, { useEffect, useMemo, useRef } from 'react'; import { EuiResizeObserver } from '@elastic/eui'; import { debounce } from 'lodash'; -import { IInterpreterRenderHandlers } from '../../expressions/public'; -import type { PersistedState } from '../../visualizations/public'; -import { ChartsPluginSetup } from '../../charts/public'; +import { IInterpreterRenderHandlers } from '../../../expressions/public'; +import type { PersistedState } from '../../../visualizations/public'; +import { ChartsPluginSetup } from '../../../charts/public'; import { VislibRenderValue } from './vis_type_vislib_vis_fn'; import { createVislibVisController, VislibVisController } from './vis_controller'; diff --git a/src/plugins/vis_type_vislib/public/vislib/VISLIB.md b/src/plugins/vis_types/vislib/public/vislib/VISLIB.md similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/VISLIB.md rename to src/plugins/vis_types/vislib/public/vislib/VISLIB.md diff --git a/src/plugins/vis_type_vislib/public/vislib/_index.scss b/src/plugins/vis_types/vislib/public/vislib/_index.scss similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/_index.scss rename to src/plugins/vis_types/vislib/public/vislib/_index.scss diff --git a/src/plugins/vis_type_vislib/public/vislib/_variables.scss b/src/plugins/vis_types/vislib/public/vislib/_variables.scss similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/_variables.scss rename to src/plugins/vis_types/vislib/public/vislib/_variables.scss diff --git a/src/plugins/vis_type_vislib/public/vislib/_vislib_vis_type.scss b/src/plugins/vis_types/vislib/public/vislib/_vislib_vis_type.scss similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/_vislib_vis_type.scss rename to src/plugins/vis_types/vislib/public/vislib/_vislib_vis_type.scss diff --git a/src/plugins/vis_type_vislib/public/vislib/components/labels/data_array.js b/src/plugins/vis_types/vislib/public/vislib/components/labels/data_array.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/components/labels/data_array.js rename to src/plugins/vis_types/vislib/public/vislib/components/labels/data_array.js diff --git a/src/plugins/vis_type_vislib/public/vislib/components/labels/flatten_series.js b/src/plugins/vis_types/vislib/public/vislib/components/labels/flatten_series.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/components/labels/flatten_series.js rename to src/plugins/vis_types/vislib/public/vislib/components/labels/flatten_series.js diff --git a/src/plugins/vis_type_vislib/public/vislib/components/labels/index.js b/src/plugins/vis_types/vislib/public/vislib/components/labels/index.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/components/labels/index.js rename to src/plugins/vis_types/vislib/public/vislib/components/labels/index.js diff --git a/src/plugins/vis_type_vislib/public/vislib/components/labels/labels.js b/src/plugins/vis_types/vislib/public/vislib/components/labels/labels.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/components/labels/labels.js rename to src/plugins/vis_types/vislib/public/vislib/components/labels/labels.js diff --git a/src/plugins/vis_type_vislib/public/vislib/components/labels/labels.test.js b/src/plugins/vis_types/vislib/public/vislib/components/labels/labels.test.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/components/labels/labels.test.js rename to src/plugins/vis_types/vislib/public/vislib/components/labels/labels.test.js diff --git a/src/plugins/vis_type_vislib/public/vislib/components/labels/truncate_labels.js b/src/plugins/vis_types/vislib/public/vislib/components/labels/truncate_labels.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/components/labels/truncate_labels.js rename to src/plugins/vis_types/vislib/public/vislib/components/labels/truncate_labels.js diff --git a/src/plugins/vis_type_vislib/public/vislib/components/labels/uniq_labels.js b/src/plugins/vis_types/vislib/public/vislib/components/labels/uniq_labels.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/components/labels/uniq_labels.js rename to src/plugins/vis_types/vislib/public/vislib/components/labels/uniq_labels.js diff --git a/src/plugins/vis_type_vislib/public/vislib/components/legend/__snapshots__/legend.test.tsx.snap b/src/plugins/vis_types/vislib/public/vislib/components/legend/__snapshots__/legend.test.tsx.snap similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/components/legend/__snapshots__/legend.test.tsx.snap rename to src/plugins/vis_types/vislib/public/vislib/components/legend/__snapshots__/legend.test.tsx.snap diff --git a/src/plugins/vis_type_vislib/public/vislib/components/legend/_index.scss b/src/plugins/vis_types/vislib/public/vislib/components/legend/_index.scss similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/components/legend/_index.scss rename to src/plugins/vis_types/vislib/public/vislib/components/legend/_index.scss diff --git a/src/plugins/vis_type_vislib/public/vislib/components/legend/_legend.scss b/src/plugins/vis_types/vislib/public/vislib/components/legend/_legend.scss similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/components/legend/_legend.scss rename to src/plugins/vis_types/vislib/public/vislib/components/legend/_legend.scss diff --git a/src/plugins/vis_type_vislib/public/vislib/components/legend/index.ts b/src/plugins/vis_types/vislib/public/vislib/components/legend/index.ts similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/components/legend/index.ts rename to src/plugins/vis_types/vislib/public/vislib/components/legend/index.ts diff --git a/src/plugins/vis_type_vislib/public/vislib/components/legend/legend.test.tsx b/src/plugins/vis_types/vislib/public/vislib/components/legend/legend.test.tsx similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/components/legend/legend.test.tsx rename to src/plugins/vis_types/vislib/public/vislib/components/legend/legend.test.tsx diff --git a/src/plugins/vis_type_vislib/public/vislib/components/legend/legend.tsx b/src/plugins/vis_types/vislib/public/vislib/components/legend/legend.tsx similarity index 98% rename from src/plugins/vis_type_vislib/public/vislib/components/legend/legend.tsx rename to src/plugins/vis_types/vislib/public/vislib/components/legend/legend.tsx index 9ce5a5339c04f..56f9025a6bd0b 100644 --- a/src/plugins/vis_type_vislib/public/vislib/components/legend/legend.tsx +++ b/src/plugins/vis_types/vislib/public/vislib/components/legend/legend.tsx @@ -13,8 +13,8 @@ import { compact, uniqBy, map, every, isUndefined } from 'lodash'; import { i18n } from '@kbn/i18n'; import { EuiPopoverProps, EuiIcon, keys, htmlIdGenerator } from '@elastic/eui'; -import { PersistedState } from '../../../../../visualizations/public'; -import { IInterpreterRenderHandlers } from '../../../../../expressions/public'; +import { PersistedState } from '../../../../../../visualizations/public'; +import { IInterpreterRenderHandlers } from '../../../../../../expressions/public'; import { getDataActions } from '../../../services'; import { CUSTOM_LEGEND_VIS_TYPES, LegendItem } from './models'; diff --git a/src/plugins/vis_type_vislib/public/vislib/components/legend/legend_item.tsx b/src/plugins/vis_types/vislib/public/vislib/components/legend/legend_item.tsx similarity index 98% rename from src/plugins/vis_type_vislib/public/vislib/components/legend/legend_item.tsx rename to src/plugins/vis_types/vislib/public/vislib/components/legend/legend_item.tsx index f4ca3eb5c40ae..5752a0ac09e8f 100644 --- a/src/plugins/vis_type_vislib/public/vislib/components/legend/legend_item.tsx +++ b/src/plugins/vis_types/vislib/public/vislib/components/legend/legend_item.tsx @@ -21,7 +21,7 @@ import { } from '@elastic/eui'; import { LegendItem } from './models'; -import { ColorPicker } from '../../../../../charts/public'; +import { ColorPicker } from '../../../../../../charts/public'; interface Props { item: LegendItem; diff --git a/src/plugins/vis_type_vislib/public/vislib/components/legend/models.ts b/src/plugins/vis_types/vislib/public/vislib/components/legend/models.ts similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/components/legend/models.ts rename to src/plugins/vis_types/vislib/public/vislib/components/legend/models.ts diff --git a/src/plugins/vis_type_vislib/public/vislib/components/legend/pie_utils.ts b/src/plugins/vis_types/vislib/public/vislib/components/legend/pie_utils.ts similarity index 97% rename from src/plugins/vis_type_vislib/public/vislib/components/legend/pie_utils.ts rename to src/plugins/vis_types/vislib/public/vislib/components/legend/pie_utils.ts index 61051eadf6b93..0912adaf9f548 100644 --- a/src/plugins/vis_type_vislib/public/vislib/components/legend/pie_utils.ts +++ b/src/plugins/vis_types/vislib/public/vislib/components/legend/pie_utils.ts @@ -14,7 +14,7 @@ import _ from 'lodash'; * * > Duplicated utilty method from vislib Data class to decouple `vislib_vis_legend` from `vislib` * - * @see src/plugins/vis_type_vislib/public/vislib/lib/data.js + * @see src/plugins/vis_types/vislib/public/vislib/lib/data.js * * @returns {Array} Array of unique names (strings) */ diff --git a/src/plugins/vis_type_vislib/public/vislib/components/tooltip/_collect_branch.js b/src/plugins/vis_types/vislib/public/vislib/components/tooltip/_collect_branch.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/components/tooltip/_collect_branch.js rename to src/plugins/vis_types/vislib/public/vislib/components/tooltip/_collect_branch.js diff --git a/src/plugins/vis_type_vislib/public/vislib/components/tooltip/_collect_branch.test.js b/src/plugins/vis_types/vislib/public/vislib/components/tooltip/_collect_branch.test.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/components/tooltip/_collect_branch.test.js rename to src/plugins/vis_types/vislib/public/vislib/components/tooltip/_collect_branch.test.js diff --git a/src/plugins/vis_type_vislib/public/vislib/components/tooltip/_hierarchical_tooltip_formatter.js b/src/plugins/vis_types/vislib/public/vislib/components/tooltip/_hierarchical_tooltip_formatter.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/components/tooltip/_hierarchical_tooltip_formatter.js rename to src/plugins/vis_types/vislib/public/vislib/components/tooltip/_hierarchical_tooltip_formatter.js diff --git a/src/plugins/vis_type_vislib/public/vislib/components/tooltip/_index.scss b/src/plugins/vis_types/vislib/public/vislib/components/tooltip/_index.scss similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/components/tooltip/_index.scss rename to src/plugins/vis_types/vislib/public/vislib/components/tooltip/_index.scss diff --git a/src/plugins/vis_type_vislib/public/vislib/components/tooltip/_pointseries_tooltip_formatter.js b/src/plugins/vis_types/vislib/public/vislib/components/tooltip/_pointseries_tooltip_formatter.js similarity index 97% rename from src/plugins/vis_type_vislib/public/vislib/components/tooltip/_pointseries_tooltip_formatter.js rename to src/plugins/vis_types/vislib/public/vislib/components/tooltip/_pointseries_tooltip_formatter.js index 04ab8db1cda8f..ecd741bc4d5d0 100644 --- a/src/plugins/vis_type_vislib/public/vislib/components/tooltip/_pointseries_tooltip_formatter.js +++ b/src/plugins/vis_types/vislib/public/vislib/components/tooltip/_pointseries_tooltip_formatter.js @@ -9,7 +9,7 @@ import { last } from 'lodash'; import React from 'react'; import { renderToStaticMarkup } from 'react-dom/server'; -import { FORMATS_UI_SETTINGS } from '../../../../../../plugins/field_formats/common'; +import { FORMATS_UI_SETTINGS } from '../../../../../../../plugins/field_formats/common'; import { getValueForPercentageMode } from '../../percentage_mode_transform'; function getMax(handler, config, isGauge) { diff --git a/src/plugins/vis_type_vislib/public/vislib/components/tooltip/_pointseries_tooltip_formatter.test.js b/src/plugins/vis_types/vislib/public/vislib/components/tooltip/_pointseries_tooltip_formatter.test.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/components/tooltip/_pointseries_tooltip_formatter.test.js rename to src/plugins/vis_types/vislib/public/vislib/components/tooltip/_pointseries_tooltip_formatter.test.js diff --git a/src/plugins/vis_type_vislib/public/vislib/components/tooltip/_tooltip.scss b/src/plugins/vis_types/vislib/public/vislib/components/tooltip/_tooltip.scss similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/components/tooltip/_tooltip.scss rename to src/plugins/vis_types/vislib/public/vislib/components/tooltip/_tooltip.scss diff --git a/src/plugins/vis_type_vislib/public/vislib/components/tooltip/index.js b/src/plugins/vis_types/vislib/public/vislib/components/tooltip/index.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/components/tooltip/index.js rename to src/plugins/vis_types/vislib/public/vislib/components/tooltip/index.js diff --git a/src/plugins/vis_type_vislib/public/vislib/components/tooltip/position_tooltip.js b/src/plugins/vis_types/vislib/public/vislib/components/tooltip/position_tooltip.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/components/tooltip/position_tooltip.js rename to src/plugins/vis_types/vislib/public/vislib/components/tooltip/position_tooltip.js diff --git a/src/plugins/vis_type_vislib/public/vislib/components/tooltip/position_tooltip.test.js b/src/plugins/vis_types/vislib/public/vislib/components/tooltip/position_tooltip.test.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/components/tooltip/position_tooltip.test.js rename to src/plugins/vis_types/vislib/public/vislib/components/tooltip/position_tooltip.test.js diff --git a/src/plugins/vis_type_vislib/public/vislib/components/tooltip/tooltip.js b/src/plugins/vis_types/vislib/public/vislib/components/tooltip/tooltip.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/components/tooltip/tooltip.js rename to src/plugins/vis_types/vislib/public/vislib/components/tooltip/tooltip.js diff --git a/src/plugins/vis_type_vislib/public/vislib/components/zero_injection/flatten_data.js b/src/plugins/vis_types/vislib/public/vislib/components/zero_injection/flatten_data.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/components/zero_injection/flatten_data.js rename to src/plugins/vis_types/vislib/public/vislib/components/zero_injection/flatten_data.js diff --git a/src/plugins/vis_type_vislib/public/vislib/components/zero_injection/inject_zeros.js b/src/plugins/vis_types/vislib/public/vislib/components/zero_injection/inject_zeros.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/components/zero_injection/inject_zeros.js rename to src/plugins/vis_types/vislib/public/vislib/components/zero_injection/inject_zeros.js diff --git a/src/plugins/vis_type_vislib/public/vislib/components/zero_injection/ordered_x_keys.js b/src/plugins/vis_types/vislib/public/vislib/components/zero_injection/ordered_x_keys.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/components/zero_injection/ordered_x_keys.js rename to src/plugins/vis_types/vislib/public/vislib/components/zero_injection/ordered_x_keys.js diff --git a/src/plugins/vis_type_vislib/public/vislib/components/zero_injection/uniq_keys.js b/src/plugins/vis_types/vislib/public/vislib/components/zero_injection/uniq_keys.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/components/zero_injection/uniq_keys.js rename to src/plugins/vis_types/vislib/public/vislib/components/zero_injection/uniq_keys.js diff --git a/src/plugins/vis_type_vislib/public/vislib/components/zero_injection/zero_fill_data_array.js b/src/plugins/vis_types/vislib/public/vislib/components/zero_injection/zero_fill_data_array.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/components/zero_injection/zero_fill_data_array.js rename to src/plugins/vis_types/vislib/public/vislib/components/zero_injection/zero_fill_data_array.js diff --git a/src/plugins/vis_type_vislib/public/vislib/components/zero_injection/zero_filled_array.js b/src/plugins/vis_types/vislib/public/vislib/components/zero_injection/zero_filled_array.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/components/zero_injection/zero_filled_array.js rename to src/plugins/vis_types/vislib/public/vislib/components/zero_injection/zero_filled_array.js diff --git a/src/plugins/vis_type_vislib/public/vislib/components/zero_injection/zero_injection.test.js b/src/plugins/vis_types/vislib/public/vislib/components/zero_injection/zero_injection.test.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/components/zero_injection/zero_injection.test.js rename to src/plugins/vis_types/vislib/public/vislib/components/zero_injection/zero_injection.test.js diff --git a/src/plugins/vis_type_vislib/public/vislib/errors.ts b/src/plugins/vis_types/vislib/public/vislib/errors.ts similarity index 95% rename from src/plugins/vis_type_vislib/public/vislib/errors.ts rename to src/plugins/vis_types/vislib/public/vislib/errors.ts index cde0f4b43d1cb..67a9d79363e73 100644 --- a/src/plugins/vis_type_vislib/public/vislib/errors.ts +++ b/src/plugins/vis_types/vislib/public/vislib/errors.ts @@ -9,7 +9,7 @@ /* eslint-disable max-classes-per-file */ import { i18n } from '@kbn/i18n'; -import { KbnError } from '../../../kibana_utils/public'; +import { KbnError } from '../../../../kibana_utils/public'; export class VislibError extends KbnError { constructor(message: string) { diff --git a/src/plugins/vis_type_vislib/public/vislib/helpers/hierarchical/build_hierarchical_data.test.ts b/src/plugins/vis_types/vislib/public/vislib/helpers/hierarchical/build_hierarchical_data.test.ts similarity index 99% rename from src/plugins/vis_type_vislib/public/vislib/helpers/hierarchical/build_hierarchical_data.test.ts rename to src/plugins/vis_types/vislib/public/vislib/helpers/hierarchical/build_hierarchical_data.test.ts index de91053b6dc4d..43fdb3c198474 100644 --- a/src/plugins/vis_type_vislib/public/vislib/helpers/hierarchical/build_hierarchical_data.test.ts +++ b/src/plugins/vis_types/vislib/public/vislib/helpers/hierarchical/build_hierarchical_data.test.ts @@ -5,7 +5,7 @@ * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ -import type { Dimensions, Dimension } from '../../../../../vis_type_pie/public'; +import type { Dimensions, Dimension } from '../../../../../pie/public'; import { buildHierarchicalData } from './build_hierarchical_data'; import { Table, TableParent } from '../../types'; diff --git a/src/plugins/vis_type_vislib/public/vislib/helpers/hierarchical/build_hierarchical_data.ts b/src/plugins/vis_types/vislib/public/vislib/helpers/hierarchical/build_hierarchical_data.ts similarity index 97% rename from src/plugins/vis_type_vislib/public/vislib/helpers/hierarchical/build_hierarchical_data.ts rename to src/plugins/vis_types/vislib/public/vislib/helpers/hierarchical/build_hierarchical_data.ts index da10edf9591fb..e5b11fcc0339c 100644 --- a/src/plugins/vis_type_vislib/public/vislib/helpers/hierarchical/build_hierarchical_data.ts +++ b/src/plugins/vis_types/vislib/public/vislib/helpers/hierarchical/build_hierarchical_data.ts @@ -9,7 +9,7 @@ import { toArray } from 'lodash'; import { getFormatService } from '../../../services'; import { Table } from '../../types'; -import type { Dimensions } from '../../../../../vis_type_pie/public'; +import type { Dimensions } from '../../../../../pie/public'; interface Slice { name: string; diff --git a/src/plugins/vis_type_vislib/public/vislib/helpers/index.ts b/src/plugins/vis_types/vislib/public/vislib/helpers/index.ts similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/helpers/index.ts rename to src/plugins/vis_types/vislib/public/vislib/helpers/index.ts diff --git a/src/plugins/vis_type_vislib/public/vislib/helpers/point_series/_add_to_siri.test.ts b/src/plugins/vis_types/vislib/public/vislib/helpers/point_series/_add_to_siri.test.ts similarity index 97% rename from src/plugins/vis_type_vislib/public/vislib/helpers/point_series/_add_to_siri.test.ts rename to src/plugins/vis_types/vislib/public/vislib/helpers/point_series/_add_to_siri.test.ts index a5897519901a1..9256276b1e9c7 100644 --- a/src/plugins/vis_type_vislib/public/vislib/helpers/point_series/_add_to_siri.test.ts +++ b/src/plugins/vis_types/vislib/public/vislib/helpers/point_series/_add_to_siri.test.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import type { Dimension } from '../../../../../vis_type_xy/public'; +import type { Dimension } from '../../../../../xy/public'; import { addToSiri, Serie } from './_add_to_siri'; import { Point } from './_get_point'; diff --git a/src/plugins/vis_type_vislib/public/vislib/helpers/point_series/_add_to_siri.ts b/src/plugins/vis_types/vislib/public/vislib/helpers/point_series/_add_to_siri.ts similarity index 89% rename from src/plugins/vis_type_vislib/public/vislib/helpers/point_series/_add_to_siri.ts rename to src/plugins/vis_types/vislib/public/vislib/helpers/point_series/_add_to_siri.ts index 187b569f28867..c334a83f3dd6a 100644 --- a/src/plugins/vis_type_vislib/public/vislib/helpers/point_series/_add_to_siri.ts +++ b/src/plugins/vis_types/vislib/public/vislib/helpers/point_series/_add_to_siri.ts @@ -6,8 +6,8 @@ * Side Public License, v 1. */ -import { getAggId } from '../../../../../vis_type_xy/public'; -import type { Dimension } from '../../../../../vis_type_xy/public'; +import { getAggId } from '../../../../../xy/public'; +import type { Dimension } from '../../../../../xy/public'; import { Point } from './_get_point'; diff --git a/src/plugins/vis_type_vislib/public/vislib/helpers/point_series/_fake_x_aspect.test.ts b/src/plugins/vis_types/vislib/public/vislib/helpers/point_series/_fake_x_aspect.test.ts similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/helpers/point_series/_fake_x_aspect.test.ts rename to src/plugins/vis_types/vislib/public/vislib/helpers/point_series/_fake_x_aspect.test.ts diff --git a/src/plugins/vis_type_vislib/public/vislib/helpers/point_series/_fake_x_aspect.ts b/src/plugins/vis_types/vislib/public/vislib/helpers/point_series/_fake_x_aspect.ts similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/helpers/point_series/_fake_x_aspect.ts rename to src/plugins/vis_types/vislib/public/vislib/helpers/point_series/_fake_x_aspect.ts diff --git a/src/plugins/vis_type_vislib/public/vislib/helpers/point_series/_get_aspects.test.ts b/src/plugins/vis_types/vislib/public/vislib/helpers/point_series/_get_aspects.test.ts similarity index 96% rename from src/plugins/vis_type_vislib/public/vislib/helpers/point_series/_get_aspects.test.ts rename to src/plugins/vis_types/vislib/public/vislib/helpers/point_series/_get_aspects.test.ts index 710857e08ccde..e4ebb1fa47929 100644 --- a/src/plugins/vis_type_vislib/public/vislib/helpers/point_series/_get_aspects.test.ts +++ b/src/plugins/vis_types/vislib/public/vislib/helpers/point_series/_get_aspects.test.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import type { Dimension, Dimensions } from '../../../../../vis_type_xy/public'; +import type { Dimension, Dimensions } from '../../../../../xy/public'; import { getAspects } from './_get_aspects'; import { Aspect } from './point_series'; diff --git a/src/plugins/vis_type_vislib/public/vislib/helpers/point_series/_get_aspects.ts b/src/plugins/vis_types/vislib/public/vislib/helpers/point_series/_get_aspects.ts similarity index 95% rename from src/plugins/vis_type_vislib/public/vislib/helpers/point_series/_get_aspects.ts rename to src/plugins/vis_types/vislib/public/vislib/helpers/point_series/_get_aspects.ts index 1f27d2af1942d..1fecf09f77380 100644 --- a/src/plugins/vis_type_vislib/public/vislib/helpers/point_series/_get_aspects.ts +++ b/src/plugins/vis_types/vislib/public/vislib/helpers/point_series/_get_aspects.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import type { Dimensions } from '../../../../../vis_type_xy/public'; +import type { Dimensions } from '../../../../../xy/public'; import { makeFakeXAspect } from './_fake_x_aspect'; import { Aspects } from './point_series'; diff --git a/src/plugins/vis_type_vislib/public/vislib/helpers/point_series/_get_point.test.ts b/src/plugins/vis_types/vislib/public/vislib/helpers/point_series/_get_point.test.ts similarity index 97% rename from src/plugins/vis_type_vislib/public/vislib/helpers/point_series/_get_point.test.ts rename to src/plugins/vis_types/vislib/public/vislib/helpers/point_series/_get_point.test.ts index 815d0e10aafb2..bf7ff40904130 100644 --- a/src/plugins/vis_type_vislib/public/vislib/helpers/point_series/_get_point.test.ts +++ b/src/plugins/vis_types/vislib/public/vislib/helpers/point_series/_get_point.test.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { IFieldFormatsRegistry } from '../../../../../field_formats/common'; +import { IFieldFormatsRegistry } from '../../../../../../field_formats/common'; import { getPoint } from './_get_point'; import { setFormatService } from '../../../services'; diff --git a/src/plugins/vis_type_vislib/public/vislib/helpers/point_series/_get_point.ts b/src/plugins/vis_types/vislib/public/vislib/helpers/point_series/_get_point.ts similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/helpers/point_series/_get_point.ts rename to src/plugins/vis_types/vislib/public/vislib/helpers/point_series/_get_point.ts diff --git a/src/plugins/vis_type_vislib/public/vislib/helpers/point_series/_get_series.test.ts b/src/plugins/vis_types/vislib/public/vislib/helpers/point_series/_get_series.test.ts similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/helpers/point_series/_get_series.test.ts rename to src/plugins/vis_types/vislib/public/vislib/helpers/point_series/_get_series.test.ts diff --git a/src/plugins/vis_type_vislib/public/vislib/helpers/point_series/_get_series.ts b/src/plugins/vis_types/vislib/public/vislib/helpers/point_series/_get_series.ts similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/helpers/point_series/_get_series.ts rename to src/plugins/vis_types/vislib/public/vislib/helpers/point_series/_get_series.ts diff --git a/src/plugins/vis_type_vislib/public/vislib/helpers/point_series/_init_x_axis.test.ts b/src/plugins/vis_types/vislib/public/vislib/helpers/point_series/_init_x_axis.test.ts similarity index 99% rename from src/plugins/vis_type_vislib/public/vislib/helpers/point_series/_init_x_axis.test.ts rename to src/plugins/vis_types/vislib/public/vislib/helpers/point_series/_init_x_axis.test.ts index cb0ebe563f54b..251888aa19498 100644 --- a/src/plugins/vis_type_vislib/public/vislib/helpers/point_series/_init_x_axis.test.ts +++ b/src/plugins/vis_types/vislib/public/vislib/helpers/point_series/_init_x_axis.test.ts @@ -8,7 +8,7 @@ import moment from 'moment'; -import type { DateHistogramParams, HistogramParams } from '../../../../../visualizations/public'; +import type { DateHistogramParams, HistogramParams } from '../../../../../../visualizations/public'; import { initXAxis } from './_init_x_axis'; import { makeFakeXAspect } from './_fake_x_aspect'; diff --git a/src/plugins/vis_type_vislib/public/vislib/helpers/point_series/_init_x_axis.ts b/src/plugins/vis_types/vislib/public/vislib/helpers/point_series/_init_x_axis.ts similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/helpers/point_series/_init_x_axis.ts rename to src/plugins/vis_types/vislib/public/vislib/helpers/point_series/_init_x_axis.ts diff --git a/src/plugins/vis_type_vislib/public/vislib/helpers/point_series/_init_y_axis.test.ts b/src/plugins/vis_types/vislib/public/vislib/helpers/point_series/_init_y_axis.test.ts similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/helpers/point_series/_init_y_axis.test.ts rename to src/plugins/vis_types/vislib/public/vislib/helpers/point_series/_init_y_axis.test.ts diff --git a/src/plugins/vis_type_vislib/public/vislib/helpers/point_series/_init_y_axis.ts b/src/plugins/vis_types/vislib/public/vislib/helpers/point_series/_init_y_axis.ts similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/helpers/point_series/_init_y_axis.ts rename to src/plugins/vis_types/vislib/public/vislib/helpers/point_series/_init_y_axis.ts diff --git a/src/plugins/vis_type_vislib/public/vislib/helpers/point_series/_ordered_date_axis.test.ts b/src/plugins/vis_types/vislib/public/vislib/helpers/point_series/_ordered_date_axis.test.ts similarity index 95% rename from src/plugins/vis_type_vislib/public/vislib/helpers/point_series/_ordered_date_axis.test.ts rename to src/plugins/vis_types/vislib/public/vislib/helpers/point_series/_ordered_date_axis.test.ts index 4dfa5035275fb..4d39147587169 100644 --- a/src/plugins/vis_type_vislib/public/vislib/helpers/point_series/_ordered_date_axis.test.ts +++ b/src/plugins/vis_types/vislib/public/vislib/helpers/point_series/_ordered_date_axis.test.ts @@ -9,7 +9,7 @@ import moment from 'moment'; import _ from 'lodash'; -import type { DateHistogramParams } from '../../../../../visualizations/public'; +import type { DateHistogramParams } from '../../../../../../visualizations/public'; import { orderedDateAxis } from './_ordered_date_axis'; import { OrderedChart } from './point_series'; diff --git a/src/plugins/vis_type_vislib/public/vislib/helpers/point_series/_ordered_date_axis.ts b/src/plugins/vis_types/vislib/public/vislib/helpers/point_series/_ordered_date_axis.ts similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/helpers/point_series/_ordered_date_axis.ts rename to src/plugins/vis_types/vislib/public/vislib/helpers/point_series/_ordered_date_axis.ts diff --git a/src/plugins/vis_type_vislib/public/vislib/helpers/point_series/index.ts b/src/plugins/vis_types/vislib/public/vislib/helpers/point_series/index.ts similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/helpers/point_series/index.ts rename to src/plugins/vis_types/vislib/public/vislib/helpers/point_series/index.ts diff --git a/src/plugins/vis_type_vislib/public/vislib/helpers/point_series/point_series.test.ts b/src/plugins/vis_types/vislib/public/vislib/helpers/point_series/point_series.test.ts similarity index 98% rename from src/plugins/vis_type_vislib/public/vislib/helpers/point_series/point_series.test.ts rename to src/plugins/vis_types/vislib/public/vislib/helpers/point_series/point_series.test.ts index 2ff4040e3a8aa..d6e6531866d4b 100644 --- a/src/plugins/vis_type_vislib/public/vislib/helpers/point_series/point_series.test.ts +++ b/src/plugins/vis_types/vislib/public/vislib/helpers/point_series/point_series.test.ts @@ -8,7 +8,7 @@ import _ from 'lodash'; -import type { Dimensions } from '../../../../../vis_type_xy/public'; +import type { Dimensions } from '../../../../../xy/public'; import { buildPointSeriesData } from './point_series'; import { Table, Column } from '../../types'; diff --git a/src/plugins/vis_type_vislib/public/vislib/helpers/point_series/point_series.ts b/src/plugins/vis_types/vislib/public/vislib/helpers/point_series/point_series.ts similarity index 95% rename from src/plugins/vis_type_vislib/public/vislib/helpers/point_series/point_series.ts rename to src/plugins/vis_types/vislib/public/vislib/helpers/point_series/point_series.ts index 62be39ffb8a73..ec9f0169a48fc 100644 --- a/src/plugins/vis_type_vislib/public/vislib/helpers/point_series/point_series.ts +++ b/src/plugins/vis_types/vislib/public/vislib/helpers/point_series/point_series.ts @@ -8,8 +8,8 @@ import { Duration } from 'moment'; -import type { Dimension, Dimensions } from '../../../../../vis_type_xy/public'; -import type { DateHistogramParams, HistogramParams } from '../../../../../visualizations/public'; +import type { Dimension, Dimensions } from '../../../../../xy/public'; +import type { DateHistogramParams, HistogramParams } from '../../../../../../visualizations/public'; import { getSeries } from './_get_series'; import { getAspects } from './_get_aspects'; diff --git a/src/plugins/vis_type_vislib/public/vislib/lib/__snapshots__/dispatch_heatmap.test.js.snap b/src/plugins/vis_types/vislib/public/vislib/lib/__snapshots__/dispatch_heatmap.test.js.snap similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/lib/__snapshots__/dispatch_heatmap.test.js.snap rename to src/plugins/vis_types/vislib/public/vislib/lib/__snapshots__/dispatch_heatmap.test.js.snap diff --git a/src/plugins/vis_type_vislib/public/vislib/lib/_alerts.scss b/src/plugins/vis_types/vislib/public/vislib/lib/_alerts.scss similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/lib/_alerts.scss rename to src/plugins/vis_types/vislib/public/vislib/lib/_alerts.scss diff --git a/src/plugins/vis_type_vislib/public/vislib/lib/_data_label.js b/src/plugins/vis_types/vislib/public/vislib/lib/_data_label.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/lib/_data_label.js rename to src/plugins/vis_types/vislib/public/vislib/lib/_data_label.js diff --git a/src/plugins/vis_type_vislib/public/vislib/lib/_error_handler.js b/src/plugins/vis_types/vislib/public/vislib/lib/_error_handler.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/lib/_error_handler.js rename to src/plugins/vis_types/vislib/public/vislib/lib/_error_handler.js diff --git a/src/plugins/vis_type_vislib/public/vislib/lib/_error_handler.test.js b/src/plugins/vis_types/vislib/public/vislib/lib/_error_handler.test.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/lib/_error_handler.test.js rename to src/plugins/vis_types/vislib/public/vislib/lib/_error_handler.test.js diff --git a/src/plugins/vis_type_vislib/public/vislib/lib/_index.scss b/src/plugins/vis_types/vislib/public/vislib/lib/_index.scss similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/lib/_index.scss rename to src/plugins/vis_types/vislib/public/vislib/lib/_index.scss diff --git a/src/plugins/vis_type_vislib/public/vislib/lib/alerts.js b/src/plugins/vis_types/vislib/public/vislib/lib/alerts.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/lib/alerts.js rename to src/plugins/vis_types/vislib/public/vislib/lib/alerts.js diff --git a/src/plugins/vis_type_vislib/public/vislib/lib/axis/axis.js b/src/plugins/vis_types/vislib/public/vislib/lib/axis/axis.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/lib/axis/axis.js rename to src/plugins/vis_types/vislib/public/vislib/lib/axis/axis.js diff --git a/src/plugins/vis_type_vislib/public/vislib/lib/axis/axis.test.js b/src/plugins/vis_types/vislib/public/vislib/lib/axis/axis.test.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/lib/axis/axis.test.js rename to src/plugins/vis_types/vislib/public/vislib/lib/axis/axis.test.js diff --git a/src/plugins/vis_type_vislib/public/vislib/lib/axis/axis_config.js b/src/plugins/vis_types/vislib/public/vislib/lib/axis/axis_config.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/lib/axis/axis_config.js rename to src/plugins/vis_types/vislib/public/vislib/lib/axis/axis_config.js diff --git a/src/plugins/vis_type_vislib/public/vislib/lib/axis/axis_labels.js b/src/plugins/vis_types/vislib/public/vislib/lib/axis/axis_labels.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/lib/axis/axis_labels.js rename to src/plugins/vis_types/vislib/public/vislib/lib/axis/axis_labels.js diff --git a/src/plugins/vis_type_vislib/public/vislib/lib/axis/axis_scale.js b/src/plugins/vis_types/vislib/public/vislib/lib/axis/axis_scale.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/lib/axis/axis_scale.js rename to src/plugins/vis_types/vislib/public/vislib/lib/axis/axis_scale.js diff --git a/src/plugins/vis_type_vislib/public/vislib/lib/axis/axis_title.js b/src/plugins/vis_types/vislib/public/vislib/lib/axis/axis_title.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/lib/axis/axis_title.js rename to src/plugins/vis_types/vislib/public/vislib/lib/axis/axis_title.js diff --git a/src/plugins/vis_type_vislib/public/vislib/lib/axis/axis_title.test.js b/src/plugins/vis_types/vislib/public/vislib/lib/axis/axis_title.test.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/lib/axis/axis_title.test.js rename to src/plugins/vis_types/vislib/public/vislib/lib/axis/axis_title.test.js diff --git a/src/plugins/vis_type_vislib/public/vislib/lib/axis/index.js b/src/plugins/vis_types/vislib/public/vislib/lib/axis/index.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/lib/axis/index.js rename to src/plugins/vis_types/vislib/public/vislib/lib/axis/index.js diff --git a/src/plugins/vis_type_vislib/public/vislib/lib/axis/scale_modes.js b/src/plugins/vis_types/vislib/public/vislib/lib/axis/scale_modes.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/lib/axis/scale_modes.js rename to src/plugins/vis_types/vislib/public/vislib/lib/axis/scale_modes.js diff --git a/src/plugins/vis_type_vislib/public/vislib/lib/axis/time_ticks.js b/src/plugins/vis_types/vislib/public/vislib/lib/axis/time_ticks.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/lib/axis/time_ticks.js rename to src/plugins/vis_types/vislib/public/vislib/lib/axis/time_ticks.js diff --git a/src/plugins/vis_type_vislib/public/vislib/lib/axis/time_ticks.test.js b/src/plugins/vis_types/vislib/public/vislib/lib/axis/time_ticks.test.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/lib/axis/time_ticks.test.js rename to src/plugins/vis_types/vislib/public/vislib/lib/axis/time_ticks.test.js diff --git a/src/plugins/vis_type_vislib/public/vislib/lib/axis/x_axis.test.js b/src/plugins/vis_types/vislib/public/vislib/lib/axis/x_axis.test.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/lib/axis/x_axis.test.js rename to src/plugins/vis_types/vislib/public/vislib/lib/axis/x_axis.test.js diff --git a/src/plugins/vis_type_vislib/public/vislib/lib/axis/y_axis.test.js b/src/plugins/vis_types/vislib/public/vislib/lib/axis/y_axis.test.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/lib/axis/y_axis.test.js rename to src/plugins/vis_types/vislib/public/vislib/lib/axis/y_axis.test.js diff --git a/src/plugins/vis_type_vislib/public/vislib/lib/binder.ts b/src/plugins/vis_types/vislib/public/vislib/lib/binder.ts similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/lib/binder.ts rename to src/plugins/vis_types/vislib/public/vislib/lib/binder.ts diff --git a/src/plugins/vis_type_vislib/public/vislib/lib/chart_grid.js b/src/plugins/vis_types/vislib/public/vislib/lib/chart_grid.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/lib/chart_grid.js rename to src/plugins/vis_types/vislib/public/vislib/lib/chart_grid.js diff --git a/src/plugins/vis_type_vislib/public/vislib/lib/chart_title.js b/src/plugins/vis_types/vislib/public/vislib/lib/chart_title.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/lib/chart_title.js rename to src/plugins/vis_types/vislib/public/vislib/lib/chart_title.js diff --git a/src/plugins/vis_type_vislib/public/vislib/lib/chart_title.test.js b/src/plugins/vis_types/vislib/public/vislib/lib/chart_title.test.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/lib/chart_title.test.js rename to src/plugins/vis_types/vislib/public/vislib/lib/chart_title.test.js diff --git a/src/plugins/vis_type_vislib/public/vislib/lib/data.js b/src/plugins/vis_types/vislib/public/vislib/lib/data.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/lib/data.js rename to src/plugins/vis_types/vislib/public/vislib/lib/data.js diff --git a/src/plugins/vis_type_vislib/public/vislib/lib/data.test.js b/src/plugins/vis_types/vislib/public/vislib/lib/data.test.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/lib/data.test.js rename to src/plugins/vis_types/vislib/public/vislib/lib/data.test.js diff --git a/src/plugins/vis_type_vislib/public/vislib/lib/dispatch.js b/src/plugins/vis_types/vislib/public/vislib/lib/dispatch.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/lib/dispatch.js rename to src/plugins/vis_types/vislib/public/vislib/lib/dispatch.js diff --git a/src/plugins/vis_type_vislib/public/vislib/lib/dispatch.test.js b/src/plugins/vis_types/vislib/public/vislib/lib/dispatch.test.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/lib/dispatch.test.js rename to src/plugins/vis_types/vislib/public/vislib/lib/dispatch.test.js diff --git a/src/plugins/vis_type_vislib/public/vislib/lib/dispatch_heatmap.test.js b/src/plugins/vis_types/vislib/public/vislib/lib/dispatch_heatmap.test.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/lib/dispatch_heatmap.test.js rename to src/plugins/vis_types/vislib/public/vislib/lib/dispatch_heatmap.test.js diff --git a/src/plugins/vis_type_vislib/public/vislib/lib/dispatch_vertical_bar_chart.test.js b/src/plugins/vis_types/vislib/public/vislib/lib/dispatch_vertical_bar_chart.test.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/lib/dispatch_vertical_bar_chart.test.js rename to src/plugins/vis_types/vislib/public/vislib/lib/dispatch_vertical_bar_chart.test.js diff --git a/src/plugins/vis_type_vislib/public/vislib/lib/handler.js b/src/plugins/vis_types/vislib/public/vislib/lib/handler.js similarity index 98% rename from src/plugins/vis_type_vislib/public/vislib/lib/handler.js rename to src/plugins/vis_types/vislib/public/vislib/lib/handler.js index 1be6271382b10..a2b747f4d5d9c 100644 --- a/src/plugins/vis_type_vislib/public/vislib/lib/handler.js +++ b/src/plugins/vis_types/vislib/public/vislib/lib/handler.js @@ -11,7 +11,7 @@ import _ from 'lodash'; import MarkdownIt from 'markdown-it'; import moment from 'moment'; -import { dispatchRenderComplete } from '../../../../kibana_utils/public'; +import { dispatchRenderComplete } from '../../../../../kibana_utils/public'; import { visTypes as chartTypes } from '../visualizations/vis_types'; import { NoResults } from '../errors'; diff --git a/src/plugins/vis_type_vislib/public/vislib/lib/handler.test.js b/src/plugins/vis_types/vislib/public/vislib/lib/handler.test.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/lib/handler.test.js rename to src/plugins/vis_types/vislib/public/vislib/lib/handler.test.js diff --git a/src/plugins/vis_type_vislib/public/vislib/lib/layout/_index.scss b/src/plugins/vis_types/vislib/public/vislib/lib/layout/_index.scss similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/lib/layout/_index.scss rename to src/plugins/vis_types/vislib/public/vislib/lib/layout/_index.scss diff --git a/src/plugins/vis_type_vislib/public/vislib/lib/layout/_layout.scss b/src/plugins/vis_types/vislib/public/vislib/lib/layout/_layout.scss similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/lib/layout/_layout.scss rename to src/plugins/vis_types/vislib/public/vislib/lib/layout/_layout.scss diff --git a/src/plugins/vis_type_vislib/public/vislib/lib/layout/index.js b/src/plugins/vis_types/vislib/public/vislib/lib/layout/index.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/lib/layout/index.js rename to src/plugins/vis_types/vislib/public/vislib/lib/layout/index.js diff --git a/src/plugins/vis_type_vislib/public/vislib/lib/layout/layout.js b/src/plugins/vis_types/vislib/public/vislib/lib/layout/layout.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/lib/layout/layout.js rename to src/plugins/vis_types/vislib/public/vislib/lib/layout/layout.js diff --git a/src/plugins/vis_type_vislib/public/vislib/lib/layout/layout.test.js b/src/plugins/vis_types/vislib/public/vislib/lib/layout/layout.test.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/lib/layout/layout.test.js rename to src/plugins/vis_types/vislib/public/vislib/lib/layout/layout.test.js diff --git a/src/plugins/vis_type_vislib/public/vislib/lib/layout/layout_types.js b/src/plugins/vis_types/vislib/public/vislib/lib/layout/layout_types.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/lib/layout/layout_types.js rename to src/plugins/vis_types/vislib/public/vislib/lib/layout/layout_types.js diff --git a/src/plugins/vis_type_vislib/public/vislib/lib/layout/layout_types.test.js b/src/plugins/vis_types/vislib/public/vislib/lib/layout/layout_types.test.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/lib/layout/layout_types.test.js rename to src/plugins/vis_types/vislib/public/vislib/lib/layout/layout_types.test.js diff --git a/src/plugins/vis_type_vislib/public/vislib/lib/layout/splits/column_chart/chart_split.js b/src/plugins/vis_types/vislib/public/vislib/lib/layout/splits/column_chart/chart_split.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/lib/layout/splits/column_chart/chart_split.js rename to src/plugins/vis_types/vislib/public/vislib/lib/layout/splits/column_chart/chart_split.js diff --git a/src/plugins/vis_type_vislib/public/vislib/lib/layout/splits/column_chart/chart_title_split.js b/src/plugins/vis_types/vislib/public/vislib/lib/layout/splits/column_chart/chart_title_split.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/lib/layout/splits/column_chart/chart_title_split.js rename to src/plugins/vis_types/vislib/public/vislib/lib/layout/splits/column_chart/chart_title_split.js diff --git a/src/plugins/vis_type_vislib/public/vislib/lib/layout/splits/column_chart/splits.test.js b/src/plugins/vis_types/vislib/public/vislib/lib/layout/splits/column_chart/splits.test.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/lib/layout/splits/column_chart/splits.test.js rename to src/plugins/vis_types/vislib/public/vislib/lib/layout/splits/column_chart/splits.test.js diff --git a/src/plugins/vis_type_vislib/public/vislib/lib/layout/splits/column_chart/x_axis_split.js b/src/plugins/vis_types/vislib/public/vislib/lib/layout/splits/column_chart/x_axis_split.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/lib/layout/splits/column_chart/x_axis_split.js rename to src/plugins/vis_types/vislib/public/vislib/lib/layout/splits/column_chart/x_axis_split.js diff --git a/src/plugins/vis_type_vislib/public/vislib/lib/layout/splits/column_chart/y_axis_split.js b/src/plugins/vis_types/vislib/public/vislib/lib/layout/splits/column_chart/y_axis_split.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/lib/layout/splits/column_chart/y_axis_split.js rename to src/plugins/vis_types/vislib/public/vislib/lib/layout/splits/column_chart/y_axis_split.js diff --git a/src/plugins/vis_type_vislib/public/vislib/lib/layout/splits/gauge_chart/chart_split.js b/src/plugins/vis_types/vislib/public/vislib/lib/layout/splits/gauge_chart/chart_split.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/lib/layout/splits/gauge_chart/chart_split.js rename to src/plugins/vis_types/vislib/public/vislib/lib/layout/splits/gauge_chart/chart_split.js diff --git a/src/plugins/vis_type_vislib/public/vislib/lib/layout/splits/gauge_chart/chart_title_split.js b/src/plugins/vis_types/vislib/public/vislib/lib/layout/splits/gauge_chart/chart_title_split.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/lib/layout/splits/gauge_chart/chart_title_split.js rename to src/plugins/vis_types/vislib/public/vislib/lib/layout/splits/gauge_chart/chart_title_split.js diff --git a/src/plugins/vis_type_vislib/public/vislib/lib/layout/splits/gauge_chart/splits.test.js b/src/plugins/vis_types/vislib/public/vislib/lib/layout/splits/gauge_chart/splits.test.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/lib/layout/splits/gauge_chart/splits.test.js rename to src/plugins/vis_types/vislib/public/vislib/lib/layout/splits/gauge_chart/splits.test.js diff --git a/src/plugins/vis_type_vislib/public/vislib/lib/layout/splits/pie_chart/chart_split.js b/src/plugins/vis_types/vislib/public/vislib/lib/layout/splits/pie_chart/chart_split.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/lib/layout/splits/pie_chart/chart_split.js rename to src/plugins/vis_types/vislib/public/vislib/lib/layout/splits/pie_chart/chart_split.js diff --git a/src/plugins/vis_type_vislib/public/vislib/lib/layout/splits/pie_chart/chart_title_split.js b/src/plugins/vis_types/vislib/public/vislib/lib/layout/splits/pie_chart/chart_title_split.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/lib/layout/splits/pie_chart/chart_title_split.js rename to src/plugins/vis_types/vislib/public/vislib/lib/layout/splits/pie_chart/chart_title_split.js diff --git a/src/plugins/vis_type_vislib/public/vislib/lib/layout/types/column_layout.js b/src/plugins/vis_types/vislib/public/vislib/lib/layout/types/column_layout.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/lib/layout/types/column_layout.js rename to src/plugins/vis_types/vislib/public/vislib/lib/layout/types/column_layout.js diff --git a/src/plugins/vis_type_vislib/public/vislib/lib/layout/types/column_layout.test.js b/src/plugins/vis_types/vislib/public/vislib/lib/layout/types/column_layout.test.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/lib/layout/types/column_layout.test.js rename to src/plugins/vis_types/vislib/public/vislib/lib/layout/types/column_layout.test.js diff --git a/src/plugins/vis_type_vislib/public/vislib/lib/layout/types/gauge_layout.js b/src/plugins/vis_types/vislib/public/vislib/lib/layout/types/gauge_layout.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/lib/layout/types/gauge_layout.js rename to src/plugins/vis_types/vislib/public/vislib/lib/layout/types/gauge_layout.js diff --git a/src/plugins/vis_type_vislib/public/vislib/lib/layout/types/pie_layout.js b/src/plugins/vis_types/vislib/public/vislib/lib/layout/types/pie_layout.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/lib/layout/types/pie_layout.js rename to src/plugins/vis_types/vislib/public/vislib/lib/layout/types/pie_layout.js diff --git a/src/plugins/vis_type_vislib/public/vislib/lib/types/gauge.js b/src/plugins/vis_types/vislib/public/vislib/lib/types/gauge.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/lib/types/gauge.js rename to src/plugins/vis_types/vislib/public/vislib/lib/types/gauge.js diff --git a/src/plugins/vis_type_vislib/public/vislib/lib/types/index.js b/src/plugins/vis_types/vislib/public/vislib/lib/types/index.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/lib/types/index.js rename to src/plugins/vis_types/vislib/public/vislib/lib/types/index.js diff --git a/src/plugins/vis_type_vislib/public/vislib/lib/types/pie.js b/src/plugins/vis_types/vislib/public/vislib/lib/types/pie.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/lib/types/pie.js rename to src/plugins/vis_types/vislib/public/vislib/lib/types/pie.js diff --git a/src/plugins/vis_type_vislib/public/vislib/lib/types/point_series.js b/src/plugins/vis_types/vislib/public/vislib/lib/types/point_series.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/lib/types/point_series.js rename to src/plugins/vis_types/vislib/public/vislib/lib/types/point_series.js diff --git a/src/plugins/vis_type_vislib/public/vislib/lib/types/point_series.test.js b/src/plugins/vis_types/vislib/public/vislib/lib/types/point_series.test.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/lib/types/point_series.test.js rename to src/plugins/vis_types/vislib/public/vislib/lib/types/point_series.test.js diff --git a/src/plugins/vis_type_vislib/public/vislib/lib/types/testdata_linechart_percentile.json b/src/plugins/vis_types/vislib/public/vislib/lib/types/testdata_linechart_percentile.json similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/lib/types/testdata_linechart_percentile.json rename to src/plugins/vis_types/vislib/public/vislib/lib/types/testdata_linechart_percentile.json diff --git a/src/plugins/vis_type_vislib/public/vislib/lib/types/testdata_linechart_percentile_float_value.json b/src/plugins/vis_types/vislib/public/vislib/lib/types/testdata_linechart_percentile_float_value.json similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/lib/types/testdata_linechart_percentile_float_value.json rename to src/plugins/vis_types/vislib/public/vislib/lib/types/testdata_linechart_percentile_float_value.json diff --git a/src/plugins/vis_type_vislib/public/vislib/lib/types/testdata_linechart_percentile_float_value_result.json b/src/plugins/vis_types/vislib/public/vislib/lib/types/testdata_linechart_percentile_float_value_result.json similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/lib/types/testdata_linechart_percentile_float_value_result.json rename to src/plugins/vis_types/vislib/public/vislib/lib/types/testdata_linechart_percentile_float_value_result.json diff --git a/src/plugins/vis_type_vislib/public/vislib/lib/types/testdata_linechart_percentile_result.json b/src/plugins/vis_types/vislib/public/vislib/lib/types/testdata_linechart_percentile_result.json similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/lib/types/testdata_linechart_percentile_result.json rename to src/plugins/vis_types/vislib/public/vislib/lib/types/testdata_linechart_percentile_result.json diff --git a/src/plugins/vis_type_vislib/public/vislib/lib/vis_config.js b/src/plugins/vis_types/vislib/public/vislib/lib/vis_config.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/lib/vis_config.js rename to src/plugins/vis_types/vislib/public/vislib/lib/vis_config.js diff --git a/src/plugins/vis_type_vislib/public/vislib/lib/vis_config.test.js b/src/plugins/vis_types/vislib/public/vislib/lib/vis_config.test.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/lib/vis_config.test.js rename to src/plugins/vis_types/vislib/public/vislib/lib/vis_config.test.js diff --git a/src/plugins/vis_type_vislib/public/vislib/partials/touchdown_template.tsx b/src/plugins/vis_types/vislib/public/vislib/partials/touchdown_template.tsx similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/partials/touchdown_template.tsx rename to src/plugins/vis_types/vislib/public/vislib/partials/touchdown_template.tsx diff --git a/src/plugins/vis_type_vislib/public/vislib/percentage_mode_transform.ts b/src/plugins/vis_types/vislib/public/vislib/percentage_mode_transform.ts similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/percentage_mode_transform.ts rename to src/plugins/vis_types/vislib/public/vislib/percentage_mode_transform.ts diff --git a/src/plugins/vis_type_vislib/public/vislib/response_handler.js b/src/plugins/vis_types/vislib/public/vislib/response_handler.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/response_handler.js rename to src/plugins/vis_types/vislib/public/vislib/response_handler.js diff --git a/src/plugins/vis_type_vislib/public/vislib/response_handler.test.ts b/src/plugins/vis_types/vislib/public/vislib/response_handler.test.ts similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/response_handler.test.ts rename to src/plugins/vis_types/vislib/public/vislib/response_handler.test.ts diff --git a/src/plugins/vis_type_vislib/public/vislib/types.ts b/src/plugins/vis_types/vislib/public/vislib/types.ts similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/types.ts rename to src/plugins/vis_types/vislib/public/vislib/types.ts diff --git a/src/plugins/vis_type_vislib/public/vislib/vis.js b/src/plugins/vis_types/vislib/public/vislib/vis.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/vis.js rename to src/plugins/vis_types/vislib/public/vislib/vis.js diff --git a/src/plugins/vis_type_vislib/public/vislib/vis.test.js b/src/plugins/vis_types/vislib/public/vislib/vis.test.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/vis.test.js rename to src/plugins/vis_types/vislib/public/vislib/vis.test.js diff --git a/src/plugins/vis_type_vislib/public/vislib/visualizations/_chart.js b/src/plugins/vis_types/vislib/public/vislib/visualizations/_chart.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/visualizations/_chart.js rename to src/plugins/vis_types/vislib/public/vislib/visualizations/_chart.js diff --git a/src/plugins/vis_type_vislib/public/vislib/visualizations/_vis_fixture.js b/src/plugins/vis_types/vislib/public/vislib/visualizations/_vis_fixture.js similarity index 91% rename from src/plugins/vis_type_vislib/public/vislib/visualizations/_vis_fixture.js rename to src/plugins/vis_types/vislib/public/vislib/visualizations/_vis_fixture.js index aa05eb57f354a..f4e2e4b977b8f 100644 --- a/src/plugins/vis_type_vislib/public/vislib/visualizations/_vis_fixture.js +++ b/src/plugins/vis_types/vislib/public/vislib/visualizations/_vis_fixture.js @@ -8,8 +8,8 @@ import _ from 'lodash'; import $ from 'jquery'; -import { coreMock } from '../../../../../core/public/mocks'; -import { chartPluginMock } from '../../../../charts/public/mocks'; +import { coreMock } from '../../../../../../core/public/mocks'; +import { chartPluginMock } from '../../../../../charts/public/mocks'; import { Vis } from '../vis'; diff --git a/src/plugins/vis_type_vislib/public/vislib/visualizations/chart.test.js b/src/plugins/vis_types/vislib/public/vislib/visualizations/chart.test.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/visualizations/chart.test.js rename to src/plugins/vis_types/vislib/public/vislib/visualizations/chart.test.js diff --git a/src/plugins/vis_type_vislib/public/vislib/visualizations/gauge_chart.js b/src/plugins/vis_types/vislib/public/vislib/visualizations/gauge_chart.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/visualizations/gauge_chart.js rename to src/plugins/vis_types/vislib/public/vislib/visualizations/gauge_chart.js diff --git a/src/plugins/vis_type_vislib/public/vislib/visualizations/gauge_chart.test.js b/src/plugins/vis_types/vislib/public/vislib/visualizations/gauge_chart.test.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/visualizations/gauge_chart.test.js rename to src/plugins/vis_types/vislib/public/vislib/visualizations/gauge_chart.test.js diff --git a/src/plugins/vis_type_vislib/public/vislib/visualizations/gauges/_index.scss b/src/plugins/vis_types/vislib/public/vislib/visualizations/gauges/_index.scss similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/visualizations/gauges/_index.scss rename to src/plugins/vis_types/vislib/public/vislib/visualizations/gauges/_index.scss diff --git a/src/plugins/vis_type_vislib/public/vislib/visualizations/gauges/_meter.scss b/src/plugins/vis_types/vislib/public/vislib/visualizations/gauges/_meter.scss similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/visualizations/gauges/_meter.scss rename to src/plugins/vis_types/vislib/public/vislib/visualizations/gauges/_meter.scss diff --git a/src/plugins/vis_type_vislib/public/vislib/visualizations/gauges/gauge_types.js b/src/plugins/vis_types/vislib/public/vislib/visualizations/gauges/gauge_types.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/visualizations/gauges/gauge_types.js rename to src/plugins/vis_types/vislib/public/vislib/visualizations/gauges/gauge_types.js diff --git a/src/plugins/vis_type_vislib/public/vislib/visualizations/gauges/meter.js b/src/plugins/vis_types/vislib/public/vislib/visualizations/gauges/meter.js similarity index 98% rename from src/plugins/vis_type_vislib/public/vislib/visualizations/gauges/meter.js rename to src/plugins/vis_types/vislib/public/vislib/visualizations/gauges/meter.js index 65f7df6459bfe..ad278847b0780 100644 --- a/src/plugins/vis_type_vislib/public/vislib/visualizations/gauges/meter.js +++ b/src/plugins/vis_types/vislib/public/vislib/visualizations/gauges/meter.js @@ -9,8 +9,8 @@ import d3 from 'd3'; import _ from 'lodash'; -import { getHeatmapColors } from '../../../../../charts/public'; -import { FORMATS_UI_SETTINGS } from '../../../../../field_formats/common'; +import { getHeatmapColors } from '../../../../../../charts/public'; +import { FORMATS_UI_SETTINGS } from '../../../../../../field_formats/common'; import { getValueForPercentageMode } from '../../percentage_mode_transform'; const arcAngles = { diff --git a/src/plugins/vis_type_vislib/public/vislib/visualizations/pie_chart.js b/src/plugins/vis_types/vislib/public/vislib/visualizations/pie_chart.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/visualizations/pie_chart.js rename to src/plugins/vis_types/vislib/public/vislib/visualizations/pie_chart.js diff --git a/src/plugins/vis_type_vislib/public/vislib/visualizations/pie_chart.test.js b/src/plugins/vis_types/vislib/public/vislib/visualizations/pie_chart.test.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/visualizations/pie_chart.test.js rename to src/plugins/vis_types/vislib/public/vislib/visualizations/pie_chart.test.js diff --git a/src/plugins/vis_type_vislib/public/vislib/visualizations/pie_chart_mock_data.js b/src/plugins/vis_types/vislib/public/vislib/visualizations/pie_chart_mock_data.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/visualizations/pie_chart_mock_data.js rename to src/plugins/vis_types/vislib/public/vislib/visualizations/pie_chart_mock_data.js diff --git a/src/plugins/vis_type_vislib/public/vislib/visualizations/point_series.js b/src/plugins/vis_types/vislib/public/vislib/visualizations/point_series.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/visualizations/point_series.js rename to src/plugins/vis_types/vislib/public/vislib/visualizations/point_series.js diff --git a/src/plugins/vis_type_vislib/public/vislib/visualizations/point_series/_index.scss b/src/plugins/vis_types/vislib/public/vislib/visualizations/point_series/_index.scss similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/visualizations/point_series/_index.scss rename to src/plugins/vis_types/vislib/public/vislib/visualizations/point_series/_index.scss diff --git a/src/plugins/vis_type_vislib/public/vislib/visualizations/point_series/_labels.scss b/src/plugins/vis_types/vislib/public/vislib/visualizations/point_series/_labels.scss similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/visualizations/point_series/_labels.scss rename to src/plugins/vis_types/vislib/public/vislib/visualizations/point_series/_labels.scss diff --git a/src/plugins/vis_type_vislib/public/vislib/visualizations/point_series/_point_series.js b/src/plugins/vis_types/vislib/public/vislib/visualizations/point_series/_point_series.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/visualizations/point_series/_point_series.js rename to src/plugins/vis_types/vislib/public/vislib/visualizations/point_series/_point_series.js diff --git a/src/plugins/vis_type_vislib/public/vislib/visualizations/point_series/_point_series.test.js b/src/plugins/vis_types/vislib/public/vislib/visualizations/point_series/_point_series.test.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/visualizations/point_series/_point_series.test.js rename to src/plugins/vis_types/vislib/public/vislib/visualizations/point_series/_point_series.test.js diff --git a/src/plugins/vis_type_vislib/public/vislib/visualizations/point_series/area_chart.js b/src/plugins/vis_types/vislib/public/vislib/visualizations/point_series/area_chart.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/visualizations/point_series/area_chart.js rename to src/plugins/vis_types/vislib/public/vislib/visualizations/point_series/area_chart.js diff --git a/src/plugins/vis_type_vislib/public/vislib/visualizations/point_series/area_chart.test.js b/src/plugins/vis_types/vislib/public/vislib/visualizations/point_series/area_chart.test.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/visualizations/point_series/area_chart.test.js rename to src/plugins/vis_types/vislib/public/vislib/visualizations/point_series/area_chart.test.js diff --git a/src/plugins/vis_type_vislib/public/vislib/visualizations/point_series/column_chart.js b/src/plugins/vis_types/vislib/public/vislib/visualizations/point_series/column_chart.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/visualizations/point_series/column_chart.js rename to src/plugins/vis_types/vislib/public/vislib/visualizations/point_series/column_chart.js diff --git a/src/plugins/vis_type_vislib/public/vislib/visualizations/point_series/column_chart.test.js b/src/plugins/vis_types/vislib/public/vislib/visualizations/point_series/column_chart.test.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/visualizations/point_series/column_chart.test.js rename to src/plugins/vis_types/vislib/public/vislib/visualizations/point_series/column_chart.test.js diff --git a/src/plugins/vis_type_vislib/public/vislib/visualizations/point_series/heatmap_chart.js b/src/plugins/vis_types/vislib/public/vislib/visualizations/point_series/heatmap_chart.js similarity index 98% rename from src/plugins/vis_type_vislib/public/vislib/visualizations/point_series/heatmap_chart.js rename to src/plugins/vis_types/vislib/public/vislib/visualizations/point_series/heatmap_chart.js index a25d408769273..bef6c939f864a 100644 --- a/src/plugins/vis_type_vislib/public/vislib/visualizations/point_series/heatmap_chart.js +++ b/src/plugins/vis_types/vislib/public/vislib/visualizations/point_series/heatmap_chart.js @@ -12,8 +12,8 @@ import moment from 'moment'; import { isColorDark } from '@elastic/eui'; import { PointSeries } from './_point_series'; -import { getHeatmapColors } from '../../../../../../plugins/charts/public'; -import { FORMATS_UI_SETTINGS } from '../../../../../../plugins/field_formats/common'; +import { getHeatmapColors } from '../../../../../../../plugins/charts/public'; +import { FORMATS_UI_SETTINGS } from '../../../../../../../plugins/field_formats/common'; import { getValueForPercentageMode } from '../../percentage_mode_transform'; const defaults = { diff --git a/src/plugins/vis_type_vislib/public/vislib/visualizations/point_series/heatmap_chart.test.js b/src/plugins/vis_types/vislib/public/vislib/visualizations/point_series/heatmap_chart.test.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/visualizations/point_series/heatmap_chart.test.js rename to src/plugins/vis_types/vislib/public/vislib/visualizations/point_series/heatmap_chart.test.js diff --git a/src/plugins/vis_type_vislib/public/vislib/visualizations/point_series/line_chart.js b/src/plugins/vis_types/vislib/public/vislib/visualizations/point_series/line_chart.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/visualizations/point_series/line_chart.js rename to src/plugins/vis_types/vislib/public/vislib/visualizations/point_series/line_chart.js diff --git a/src/plugins/vis_type_vislib/public/vislib/visualizations/point_series/line_chart.test.js b/src/plugins/vis_types/vislib/public/vislib/visualizations/point_series/line_chart.test.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/visualizations/point_series/line_chart.test.js rename to src/plugins/vis_types/vislib/public/vislib/visualizations/point_series/line_chart.test.js diff --git a/src/plugins/vis_type_vislib/public/vislib/visualizations/point_series/series_types.js b/src/plugins/vis_types/vislib/public/vislib/visualizations/point_series/series_types.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/visualizations/point_series/series_types.js rename to src/plugins/vis_types/vislib/public/vislib/visualizations/point_series/series_types.js diff --git a/src/plugins/vis_type_vislib/public/vislib/visualizations/time_marker.d.ts b/src/plugins/vis_types/vislib/public/vislib/visualizations/time_marker.d.ts similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/visualizations/time_marker.d.ts rename to src/plugins/vis_types/vislib/public/vislib/visualizations/time_marker.d.ts diff --git a/src/plugins/vis_type_vislib/public/vislib/visualizations/time_marker.js b/src/plugins/vis_types/vislib/public/vislib/visualizations/time_marker.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/visualizations/time_marker.js rename to src/plugins/vis_types/vislib/public/vislib/visualizations/time_marker.js diff --git a/src/plugins/vis_type_vislib/public/vislib/visualizations/time_marker.test.js b/src/plugins/vis_types/vislib/public/vislib/visualizations/time_marker.test.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/visualizations/time_marker.test.js rename to src/plugins/vis_types/vislib/public/vislib/visualizations/time_marker.test.js diff --git a/src/plugins/vis_type_vislib/public/vislib/visualizations/vis_types.js b/src/plugins/vis_types/vislib/public/vislib/visualizations/vis_types.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/visualizations/vis_types.js rename to src/plugins/vis_types/vislib/public/vislib/visualizations/vis_types.js diff --git a/src/plugins/vis_type_vislib/public/vislib/visualizations/vis_types.test.js b/src/plugins/vis_types/vislib/public/vislib/visualizations/vis_types.test.js similarity index 100% rename from src/plugins/vis_type_vislib/public/vislib/visualizations/vis_types.test.js rename to src/plugins/vis_types/vislib/public/vislib/visualizations/vis_types.test.js diff --git a/src/plugins/vis_type_vislib/server/index.ts b/src/plugins/vis_types/vislib/server/index.ts similarity index 100% rename from src/plugins/vis_type_vislib/server/index.ts rename to src/plugins/vis_types/vislib/server/index.ts diff --git a/src/plugins/vis_type_vislib/server/plugin.ts b/src/plugins/vis_types/vislib/server/plugin.ts similarity index 100% rename from src/plugins/vis_type_vislib/server/plugin.ts rename to src/plugins/vis_types/vislib/server/plugin.ts diff --git a/src/plugins/vis_type_vislib/server/ui_settings.ts b/src/plugins/vis_types/vislib/server/ui_settings.ts similarity index 100% rename from src/plugins/vis_type_vislib/server/ui_settings.ts rename to src/plugins/vis_types/vislib/server/ui_settings.ts diff --git a/src/plugins/vis_types/vislib/tsconfig.json b/src/plugins/vis_types/vislib/tsconfig.json new file mode 100644 index 0000000000000..8246b3f30646b --- /dev/null +++ b/src/plugins/vis_types/vislib/tsconfig.json @@ -0,0 +1,26 @@ +{ + "extends": "../../../../tsconfig.base.json", + "compilerOptions": { + "outDir": "./target/types", + "emitDeclarationOnly": true, + "declaration": true, + "declarationMap": true + }, + "include": [ + "common/**/*", + "public/**/*", + "server/**/*" + ], + "references": [ + { "path": "../../../core/tsconfig.json" }, + { "path": "../../charts/tsconfig.json" }, + { "path": "../../data/tsconfig.json" }, + { "path": "../../expressions/tsconfig.json" }, + { "path": "../../visualizations/tsconfig.json" }, + { "path": "../../kibana_legacy/tsconfig.json" }, + { "path": "../../kibana_utils/tsconfig.json" }, + { "path": "../../vis_default_editor/tsconfig.json" }, + { "path": "../../vis_types/xy/tsconfig.json" }, + { "path": "../../vis_types/pie/tsconfig.json" }, + ] +} diff --git a/src/plugins/vis_type_xy/common/index.ts b/src/plugins/vis_types/xy/common/index.ts similarity index 100% rename from src/plugins/vis_type_xy/common/index.ts rename to src/plugins/vis_types/xy/common/index.ts diff --git a/src/plugins/vis_type_pie/jest.config.js b/src/plugins/vis_types/xy/jest.config.js similarity index 84% rename from src/plugins/vis_type_pie/jest.config.js rename to src/plugins/vis_types/xy/jest.config.js index e4900ef4a35c8..57b041b575e3f 100644 --- a/src/plugins/vis_type_pie/jest.config.js +++ b/src/plugins/vis_types/xy/jest.config.js @@ -8,6 +8,6 @@ module.exports = { preset: '@kbn/test', - rootDir: '../../..', - roots: ['/src/plugins/vis_type_pie'], + rootDir: '../../../..', + roots: ['/src/plugins/vis_types/xy'], }; diff --git a/src/plugins/vis_type_xy/kibana.json b/src/plugins/vis_types/xy/kibana.json similarity index 100% rename from src/plugins/vis_type_xy/kibana.json rename to src/plugins/vis_types/xy/kibana.json diff --git a/src/plugins/vis_type_xy/public/__snapshots__/to_ast.test.ts.snap b/src/plugins/vis_types/xy/public/__snapshots__/to_ast.test.ts.snap similarity index 100% rename from src/plugins/vis_type_xy/public/__snapshots__/to_ast.test.ts.snap rename to src/plugins/vis_types/xy/public/__snapshots__/to_ast.test.ts.snap diff --git a/src/plugins/vis_type_xy/public/_chart.scss b/src/plugins/vis_types/xy/public/_chart.scss similarity index 100% rename from src/plugins/vis_type_xy/public/_chart.scss rename to src/plugins/vis_types/xy/public/_chart.scss diff --git a/src/plugins/vis_type_xy/public/chart_splitter.tsx b/src/plugins/vis_types/xy/public/chart_splitter.tsx similarity index 100% rename from src/plugins/vis_type_xy/public/chart_splitter.tsx rename to src/plugins/vis_types/xy/public/chart_splitter.tsx diff --git a/src/plugins/vis_type_xy/public/components/_detailed_tooltip.scss b/src/plugins/vis_types/xy/public/components/_detailed_tooltip.scss similarity index 100% rename from src/plugins/vis_type_xy/public/components/_detailed_tooltip.scss rename to src/plugins/vis_types/xy/public/components/_detailed_tooltip.scss diff --git a/src/plugins/vis_type_xy/public/components/detailed_tooltip.mock.ts b/src/plugins/vis_types/xy/public/components/detailed_tooltip.mock.ts similarity index 100% rename from src/plugins/vis_type_xy/public/components/detailed_tooltip.mock.ts rename to src/plugins/vis_types/xy/public/components/detailed_tooltip.mock.ts diff --git a/src/plugins/vis_type_xy/public/components/detailed_tooltip.test.tsx b/src/plugins/vis_types/xy/public/components/detailed_tooltip.test.tsx similarity index 100% rename from src/plugins/vis_type_xy/public/components/detailed_tooltip.test.tsx rename to src/plugins/vis_types/xy/public/components/detailed_tooltip.test.tsx diff --git a/src/plugins/vis_type_xy/public/components/detailed_tooltip.tsx b/src/plugins/vis_types/xy/public/components/detailed_tooltip.tsx similarity index 100% rename from src/plugins/vis_type_xy/public/components/detailed_tooltip.tsx rename to src/plugins/vis_types/xy/public/components/detailed_tooltip.tsx diff --git a/src/plugins/vis_type_xy/public/components/index.ts b/src/plugins/vis_types/xy/public/components/index.ts similarity index 100% rename from src/plugins/vis_type_xy/public/components/index.ts rename to src/plugins/vis_types/xy/public/components/index.ts diff --git a/src/plugins/vis_type_xy/public/components/xy_axis.tsx b/src/plugins/vis_types/xy/public/components/xy_axis.tsx similarity index 100% rename from src/plugins/vis_type_xy/public/components/xy_axis.tsx rename to src/plugins/vis_types/xy/public/components/xy_axis.tsx diff --git a/src/plugins/vis_type_xy/public/components/xy_current_time.tsx b/src/plugins/vis_types/xy/public/components/xy_current_time.tsx similarity index 93% rename from src/plugins/vis_type_xy/public/components/xy_current_time.tsx rename to src/plugins/vis_types/xy/public/components/xy_current_time.tsx index 1294302d0becd..1ecf661355868 100644 --- a/src/plugins/vis_type_xy/public/components/xy_current_time.tsx +++ b/src/plugins/vis_types/xy/public/components/xy_current_time.tsx @@ -8,7 +8,7 @@ import React, { FC } from 'react'; import { DomainRange } from '@elastic/charts'; -import { CurrentTime } from '../../../charts/public'; +import { CurrentTime } from '../../../../charts/public'; interface XYCurrentTime { enabled: boolean; diff --git a/src/plugins/vis_type_xy/public/components/xy_endzones.tsx b/src/plugins/vis_types/xy/public/components/xy_endzones.tsx similarity index 96% rename from src/plugins/vis_type_xy/public/components/xy_endzones.tsx rename to src/plugins/vis_types/xy/public/components/xy_endzones.tsx index 1510ec1bcb89a..fbf398b886ffa 100644 --- a/src/plugins/vis_type_xy/public/components/xy_endzones.tsx +++ b/src/plugins/vis_types/xy/public/components/xy_endzones.tsx @@ -10,7 +10,7 @@ import React, { FC } from 'react'; import { DomainRange } from '@elastic/charts'; -import { Endzones } from '../../../charts/public'; +import { Endzones } from '../../../../charts/public'; interface XYEndzones { enabled: boolean; diff --git a/src/plugins/vis_type_xy/public/components/xy_settings.tsx b/src/plugins/vis_types/xy/public/components/xy_settings.tsx similarity index 98% rename from src/plugins/vis_type_xy/public/components/xy_settings.tsx rename to src/plugins/vis_types/xy/public/components/xy_settings.tsx index 2dd7d7e0a91f9..92b47edccfd92 100644 --- a/src/plugins/vis_type_xy/public/components/xy_settings.tsx +++ b/src/plugins/vis_types/xy/public/components/xy_settings.tsx @@ -26,7 +26,7 @@ import { HorizontalAlignment, } from '@elastic/charts'; -import { renderEndzoneTooltip } from '../../../charts/public'; +import { renderEndzoneTooltip } from '../../../../charts/public'; import { getThemeService, getUISettings } from '../services'; import { VisConfig } from '../types'; diff --git a/src/plugins/vis_type_xy/public/components/xy_threshold_line.tsx b/src/plugins/vis_types/xy/public/components/xy_threshold_line.tsx similarity index 100% rename from src/plugins/vis_type_xy/public/components/xy_threshold_line.tsx rename to src/plugins/vis_types/xy/public/components/xy_threshold_line.tsx diff --git a/src/plugins/vis_type_xy/public/config/get_agg_id.ts b/src/plugins/vis_types/xy/public/config/get_agg_id.ts similarity index 100% rename from src/plugins/vis_type_xy/public/config/get_agg_id.ts rename to src/plugins/vis_types/xy/public/config/get_agg_id.ts diff --git a/src/plugins/vis_type_xy/public/config/get_aspects.ts b/src/plugins/vis_types/xy/public/config/get_aspects.ts similarity index 97% rename from src/plugins/vis_type_xy/public/config/get_aspects.ts rename to src/plugins/vis_types/xy/public/config/get_aspects.ts index 1485131da83bc..666a913e48402 100644 --- a/src/plugins/vis_type_xy/public/config/get_aspects.ts +++ b/src/plugins/vis_types/xy/public/config/get_aspects.ts @@ -10,7 +10,7 @@ import { compact } from 'lodash'; import { i18n } from '@kbn/i18n'; -import { DatatableColumn } from '../../../expressions/public'; +import { DatatableColumn } from '../../../../expressions/public'; import { Aspect, Dimension, Aspects, Dimensions } from '../types'; import { getFormatService } from '../services'; diff --git a/src/plugins/vis_type_xy/public/config/get_axis.ts b/src/plugins/vis_types/xy/public/config/get_axis.ts similarity index 97% rename from src/plugins/vis_type_xy/public/config/get_axis.ts rename to src/plugins/vis_types/xy/public/config/get_axis.ts index 71d33cc20d057..4750724ca3d42 100644 --- a/src/plugins/vis_type_xy/public/config/get_axis.ts +++ b/src/plugins/vis_types/xy/public/config/get_axis.ts @@ -10,8 +10,8 @@ import { identity, isNil } from 'lodash'; import { AxisSpec, TickFormatter, YDomainRange, ScaleType as ECScaleType } from '@elastic/charts'; -import { LabelRotation } from '../../../charts/public'; -import { BUCKET_TYPES } from '../../../data/public'; +import { LabelRotation } from '../../../../charts/public'; +import { BUCKET_TYPES } from '../../../../data/public'; import { Aspect, diff --git a/src/plugins/vis_type_xy/public/config/get_config.ts b/src/plugins/vis_types/xy/public/config/get_config.ts similarity index 94% rename from src/plugins/vis_type_xy/public/config/get_config.ts rename to src/plugins/vis_types/xy/public/config/get_config.ts index 0c687aa918056..13c9a6c275f8e 100644 --- a/src/plugins/vis_type_xy/public/config/get_config.ts +++ b/src/plugins/vis_types/xy/public/config/get_config.ts @@ -8,9 +8,9 @@ import { ScaleContinuousType } from '@elastic/charts'; -import { Datatable } from '../../../expressions/public'; -import { BUCKET_TYPES } from '../../../data/public'; -import { DateHistogramParams } from '../../../visualizations/public'; +import { Datatable } from '../../../../expressions/public'; +import { BUCKET_TYPES } from '../../../../data/public'; +import { DateHistogramParams } from '../../../../visualizations/public'; import { Aspect, diff --git a/src/plugins/vis_type_xy/public/config/get_legend.ts b/src/plugins/vis_types/xy/public/config/get_legend.ts similarity index 100% rename from src/plugins/vis_type_xy/public/config/get_legend.ts rename to src/plugins/vis_types/xy/public/config/get_legend.ts diff --git a/src/plugins/vis_type_xy/public/config/get_rotation.ts b/src/plugins/vis_types/xy/public/config/get_rotation.ts similarity index 100% rename from src/plugins/vis_type_xy/public/config/get_rotation.ts rename to src/plugins/vis_types/xy/public/config/get_rotation.ts diff --git a/src/plugins/vis_type_xy/public/config/get_threshold_line.ts b/src/plugins/vis_types/xy/public/config/get_threshold_line.ts similarity index 100% rename from src/plugins/vis_type_xy/public/config/get_threshold_line.ts rename to src/plugins/vis_types/xy/public/config/get_threshold_line.ts diff --git a/src/plugins/vis_type_xy/public/config/get_tooltip.ts b/src/plugins/vis_types/xy/public/config/get_tooltip.ts similarity index 100% rename from src/plugins/vis_type_xy/public/config/get_tooltip.ts rename to src/plugins/vis_types/xy/public/config/get_tooltip.ts diff --git a/src/plugins/vis_type_xy/public/config/index.ts b/src/plugins/vis_types/xy/public/config/index.ts similarity index 100% rename from src/plugins/vis_type_xy/public/config/index.ts rename to src/plugins/vis_types/xy/public/config/index.ts diff --git a/src/plugins/vis_type_xy/public/editor/collections.ts b/src/plugins/vis_types/xy/public/editor/collections.ts similarity index 98% rename from src/plugins/vis_type_xy/public/editor/collections.ts rename to src/plugins/vis_types/xy/public/editor/collections.ts index 7053f7de0d328..71f7a639379e0 100644 --- a/src/plugins/vis_type_xy/public/editor/collections.ts +++ b/src/plugins/vis_types/xy/public/editor/collections.ts @@ -11,7 +11,7 @@ import { Fit } from '@elastic/charts'; import { AxisMode, ChartMode, InterpolationMode, ThresholdLineStyle } from '../types'; import { ChartType } from '../../common'; -import { LabelRotation } from '../../../charts/public'; +import { LabelRotation } from '../../../../charts/public'; import { getScaleTypes } from './scale_types'; import { getPositions } from './positions'; diff --git a/src/plugins/vis_type_xy/public/editor/common_config.tsx b/src/plugins/vis_types/xy/public/editor/common_config.tsx similarity index 94% rename from src/plugins/vis_type_xy/public/editor/common_config.tsx rename to src/plugins/vis_types/xy/public/editor/common_config.tsx index 5cafbdd0a569c..bd9882a15c124 100644 --- a/src/plugins/vis_type_xy/public/editor/common_config.tsx +++ b/src/plugins/vis_types/xy/public/editor/common_config.tsx @@ -9,7 +9,7 @@ import React from 'react'; import { i18n } from '@kbn/i18n'; -import type { VisEditorOptionsProps } from '../../../visualizations/public'; +import type { VisEditorOptionsProps } from '../../../../visualizations/public'; import type { VisParams } from '../types'; import { MetricsAxisOptions, PointSeriesOptions } from './components/options'; diff --git a/src/plugins/vis_type_xy/public/editor/components/common/index.ts b/src/plugins/vis_types/xy/public/editor/components/common/index.ts similarity index 100% rename from src/plugins/vis_type_xy/public/editor/components/common/index.ts rename to src/plugins/vis_types/xy/public/editor/components/common/index.ts diff --git a/src/plugins/vis_type_xy/public/editor/components/common/truncate_labels.test.tsx b/src/plugins/vis_types/xy/public/editor/components/common/truncate_labels.test.tsx similarity index 100% rename from src/plugins/vis_type_xy/public/editor/components/common/truncate_labels.test.tsx rename to src/plugins/vis_types/xy/public/editor/components/common/truncate_labels.test.tsx diff --git a/src/plugins/vis_type_xy/public/editor/components/common/truncate_labels.tsx b/src/plugins/vis_types/xy/public/editor/components/common/truncate_labels.tsx similarity index 100% rename from src/plugins/vis_type_xy/public/editor/components/common/truncate_labels.tsx rename to src/plugins/vis_types/xy/public/editor/components/common/truncate_labels.tsx diff --git a/src/plugins/vis_type_xy/public/editor/components/common/validation_wrapper.tsx b/src/plugins/vis_types/xy/public/editor/components/common/validation_wrapper.tsx similarity index 94% rename from src/plugins/vis_type_xy/public/editor/components/common/validation_wrapper.tsx rename to src/plugins/vis_types/xy/public/editor/components/common/validation_wrapper.tsx index 63df3f7eead43..2088878f963ae 100644 --- a/src/plugins/vis_type_xy/public/editor/components/common/validation_wrapper.tsx +++ b/src/plugins/vis_types/xy/public/editor/components/common/validation_wrapper.tsx @@ -8,7 +8,7 @@ import React, { useEffect, useState, useCallback } from 'react'; -import { VisEditorOptionsProps } from '../../../../../visualizations/public'; +import { VisEditorOptionsProps } from '../../../../../../visualizations/public'; export interface ValidationVisOptionsProps extends VisEditorOptionsProps { setMultipleValidity(paramName: string, isValid: boolean): void; diff --git a/src/plugins/vis_type_xy/public/editor/components/index.ts b/src/plugins/vis_types/xy/public/editor/components/index.ts similarity index 100% rename from src/plugins/vis_type_xy/public/editor/components/index.ts rename to src/plugins/vis_types/xy/public/editor/components/index.ts diff --git a/src/plugins/vis_type_xy/public/editor/components/options/index.tsx b/src/plugins/vis_types/xy/public/editor/components/options/index.tsx similarity index 100% rename from src/plugins/vis_type_xy/public/editor/components/options/index.tsx rename to src/plugins/vis_types/xy/public/editor/components/options/index.tsx diff --git a/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/__snapshots__/category_axis_panel.test.tsx.snap b/src/plugins/vis_types/xy/public/editor/components/options/metrics_axes/__snapshots__/category_axis_panel.test.tsx.snap similarity index 100% rename from src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/__snapshots__/category_axis_panel.test.tsx.snap rename to src/plugins/vis_types/xy/public/editor/components/options/metrics_axes/__snapshots__/category_axis_panel.test.tsx.snap diff --git a/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/__snapshots__/chart_options.test.tsx.snap b/src/plugins/vis_types/xy/public/editor/components/options/metrics_axes/__snapshots__/chart_options.test.tsx.snap similarity index 100% rename from src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/__snapshots__/chart_options.test.tsx.snap rename to src/plugins/vis_types/xy/public/editor/components/options/metrics_axes/__snapshots__/chart_options.test.tsx.snap diff --git a/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/__snapshots__/custom_extents_options.test.tsx.snap b/src/plugins/vis_types/xy/public/editor/components/options/metrics_axes/__snapshots__/custom_extents_options.test.tsx.snap similarity index 100% rename from src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/__snapshots__/custom_extents_options.test.tsx.snap rename to src/plugins/vis_types/xy/public/editor/components/options/metrics_axes/__snapshots__/custom_extents_options.test.tsx.snap diff --git a/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/__snapshots__/index.test.tsx.snap b/src/plugins/vis_types/xy/public/editor/components/options/metrics_axes/__snapshots__/index.test.tsx.snap similarity index 100% rename from src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/__snapshots__/index.test.tsx.snap rename to src/plugins/vis_types/xy/public/editor/components/options/metrics_axes/__snapshots__/index.test.tsx.snap diff --git a/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/__snapshots__/label_options.test.tsx.snap b/src/plugins/vis_types/xy/public/editor/components/options/metrics_axes/__snapshots__/label_options.test.tsx.snap similarity index 100% rename from src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/__snapshots__/label_options.test.tsx.snap rename to src/plugins/vis_types/xy/public/editor/components/options/metrics_axes/__snapshots__/label_options.test.tsx.snap diff --git a/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/__snapshots__/line_options.test.tsx.snap b/src/plugins/vis_types/xy/public/editor/components/options/metrics_axes/__snapshots__/line_options.test.tsx.snap similarity index 100% rename from src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/__snapshots__/line_options.test.tsx.snap rename to src/plugins/vis_types/xy/public/editor/components/options/metrics_axes/__snapshots__/line_options.test.tsx.snap diff --git a/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/__snapshots__/point_options.test.tsx.snap b/src/plugins/vis_types/xy/public/editor/components/options/metrics_axes/__snapshots__/point_options.test.tsx.snap similarity index 100% rename from src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/__snapshots__/point_options.test.tsx.snap rename to src/plugins/vis_types/xy/public/editor/components/options/metrics_axes/__snapshots__/point_options.test.tsx.snap diff --git a/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/__snapshots__/value_axes_panel.test.tsx.snap b/src/plugins/vis_types/xy/public/editor/components/options/metrics_axes/__snapshots__/value_axes_panel.test.tsx.snap similarity index 100% rename from src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/__snapshots__/value_axes_panel.test.tsx.snap rename to src/plugins/vis_types/xy/public/editor/components/options/metrics_axes/__snapshots__/value_axes_panel.test.tsx.snap diff --git a/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/__snapshots__/value_axis_options.test.tsx.snap b/src/plugins/vis_types/xy/public/editor/components/options/metrics_axes/__snapshots__/value_axis_options.test.tsx.snap similarity index 100% rename from src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/__snapshots__/value_axis_options.test.tsx.snap rename to src/plugins/vis_types/xy/public/editor/components/options/metrics_axes/__snapshots__/value_axis_options.test.tsx.snap diff --git a/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/__snapshots__/y_extents.test.tsx.snap b/src/plugins/vis_types/xy/public/editor/components/options/metrics_axes/__snapshots__/y_extents.test.tsx.snap similarity index 100% rename from src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/__snapshots__/y_extents.test.tsx.snap rename to src/plugins/vis_types/xy/public/editor/components/options/metrics_axes/__snapshots__/y_extents.test.tsx.snap diff --git a/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/category_axis_panel.test.tsx b/src/plugins/vis_types/xy/public/editor/components/options/metrics_axes/category_axis_panel.test.tsx similarity index 100% rename from src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/category_axis_panel.test.tsx rename to src/plugins/vis_types/xy/public/editor/components/options/metrics_axes/category_axis_panel.test.tsx diff --git a/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/category_axis_panel.tsx b/src/plugins/vis_types/xy/public/editor/components/options/metrics_axes/category_axis_panel.tsx similarity index 96% rename from src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/category_axis_panel.tsx rename to src/plugins/vis_types/xy/public/editor/components/options/metrics_axes/category_axis_panel.tsx index 5ba35717e46f3..ee5cc950ff66b 100644 --- a/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/category_axis_panel.tsx +++ b/src/plugins/vis_types/xy/public/editor/components/options/metrics_axes/category_axis_panel.tsx @@ -13,7 +13,7 @@ import { FormattedMessage } from '@kbn/i18n/react'; import { EuiPanel, EuiTitle, EuiSpacer } from '@elastic/eui'; import { Position } from '@elastic/charts'; -import { SelectOption, SwitchOption } from '../../../../../../vis_default_editor/public'; +import { SelectOption, SwitchOption } from '../../../../../../../vis_default_editor/public'; import { LabelOptions, SetAxisLabel } from './label_options'; import { CategoryAxis } from '../../../../types'; diff --git a/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/chart_options.test.tsx b/src/plugins/vis_types/xy/public/editor/components/options/metrics_axes/chart_options.test.tsx similarity index 100% rename from src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/chart_options.test.tsx rename to src/plugins/vis_types/xy/public/editor/components/options/metrics_axes/chart_options.test.tsx diff --git a/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/chart_options.tsx b/src/plugins/vis_types/xy/public/editor/components/options/metrics_axes/chart_options.tsx similarity index 98% rename from src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/chart_options.tsx rename to src/plugins/vis_types/xy/public/editor/components/options/metrics_axes/chart_options.tsx index 34ee33781f269..04013969fb4fa 100644 --- a/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/chart_options.tsx +++ b/src/plugins/vis_types/xy/public/editor/components/options/metrics_axes/chart_options.tsx @@ -11,7 +11,7 @@ import React, { useMemo, useCallback, useEffect, useState } from 'react'; import { i18n } from '@kbn/i18n'; import { EuiFlexGroup, EuiFlexItem, EuiSpacer } from '@elastic/eui'; -import { SelectOption } from '../../../../../../vis_default_editor/public'; +import { SelectOption } from '../../../../../../../vis_default_editor/public'; import { SeriesParam, ValueAxis, ChartMode, AxisMode } from '../../../../types'; import { LineOptions } from './line_options'; diff --git a/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/custom_extents_options.test.tsx b/src/plugins/vis_types/xy/public/editor/components/options/metrics_axes/custom_extents_options.test.tsx similarity index 100% rename from src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/custom_extents_options.test.tsx rename to src/plugins/vis_types/xy/public/editor/components/options/metrics_axes/custom_extents_options.test.tsx diff --git a/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/custom_extents_options.tsx b/src/plugins/vis_types/xy/public/editor/components/options/metrics_axes/custom_extents_options.tsx similarity index 99% rename from src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/custom_extents_options.tsx rename to src/plugins/vis_types/xy/public/editor/components/options/metrics_axes/custom_extents_options.tsx index 2d3e819e96024..2152849983513 100644 --- a/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/custom_extents_options.tsx +++ b/src/plugins/vis_types/xy/public/editor/components/options/metrics_axes/custom_extents_options.tsx @@ -10,7 +10,7 @@ import React, { useCallback, useEffect } from 'react'; import { i18n } from '@kbn/i18n'; -import { NumberInputOption, SwitchOption } from '../../../../../../vis_default_editor/public'; +import { NumberInputOption, SwitchOption } from '../../../../../../../vis_default_editor/public'; import { ValueAxis } from '../../../../types'; import { YExtents } from './y_extents'; diff --git a/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/index.test.tsx b/src/plugins/vis_types/xy/public/editor/components/options/metrics_axes/index.test.tsx similarity index 100% rename from src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/index.test.tsx rename to src/plugins/vis_types/xy/public/editor/components/options/metrics_axes/index.test.tsx diff --git a/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/index.tsx b/src/plugins/vis_types/xy/public/editor/components/options/metrics_axes/index.tsx similarity index 99% rename from src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/index.tsx rename to src/plugins/vis_types/xy/public/editor/components/options/metrics_axes/index.tsx index 5454df3a165cd..9b4e1c61a201f 100644 --- a/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/index.tsx +++ b/src/plugins/vis_types/xy/public/editor/components/options/metrics_axes/index.tsx @@ -11,7 +11,7 @@ import { cloneDeep, get } from 'lodash'; import { EuiSpacer } from '@elastic/eui'; -import { IAggConfig } from '../../../../../../data/public'; +import { IAggConfig } from '../../../../../../../data/public'; import { VisParams, ValueAxis, SeriesParam, CategoryAxis } from '../../../../types'; import { ValidationVisOptionsProps } from '../../common'; diff --git a/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/label_options.test.tsx b/src/plugins/vis_types/xy/public/editor/components/options/metrics_axes/label_options.test.tsx similarity index 100% rename from src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/label_options.test.tsx rename to src/plugins/vis_types/xy/public/editor/components/options/metrics_axes/label_options.test.tsx diff --git a/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/label_options.tsx b/src/plugins/vis_types/xy/public/editor/components/options/metrics_axes/label_options.tsx similarity index 94% rename from src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/label_options.tsx rename to src/plugins/vis_types/xy/public/editor/components/options/metrics_axes/label_options.tsx index bcf4beaa78945..ef48d8b6d7880 100644 --- a/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/label_options.tsx +++ b/src/plugins/vis_types/xy/public/editor/components/options/metrics_axes/label_options.tsx @@ -12,8 +12,8 @@ import { EuiTitle, EuiFlexGroup, EuiFlexItem, EuiSpacer } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; -import { SelectOption, SwitchOption } from '../../../../../../vis_default_editor/public'; -import { Labels } from '../../../../../../charts/public'; +import { SelectOption, SwitchOption } from '../../../../../../../vis_default_editor/public'; +import { Labels } from '../../../../../../../charts/public'; import { TruncateLabelsOption } from '../../common'; import { getRotateOptions } from '../../../collections'; diff --git a/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/line_options.test.tsx b/src/plugins/vis_types/xy/public/editor/components/options/metrics_axes/line_options.test.tsx similarity index 95% rename from src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/line_options.test.tsx rename to src/plugins/vis_types/xy/public/editor/components/options/metrics_axes/line_options.test.tsx index 5497c46c1dd34..41bbfec7ee939 100644 --- a/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/line_options.test.tsx +++ b/src/plugins/vis_types/xy/public/editor/components/options/metrics_axes/line_options.test.tsx @@ -9,7 +9,7 @@ import React from 'react'; import { shallow } from 'enzyme'; -import { NumberInputOption } from '../../../../../../vis_default_editor/public'; +import { NumberInputOption } from '../../../../../../../vis_default_editor/public'; import { LineOptions, LineOptionsParams } from './line_options'; import { seriesParam } from './mocks'; diff --git a/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/line_options.tsx b/src/plugins/vis_types/xy/public/editor/components/options/metrics_axes/line_options.tsx similarity index 97% rename from src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/line_options.tsx rename to src/plugins/vis_types/xy/public/editor/components/options/metrics_axes/line_options.tsx index 75dfe8627d73e..355b04f07d00d 100644 --- a/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/line_options.tsx +++ b/src/plugins/vis_types/xy/public/editor/components/options/metrics_axes/line_options.tsx @@ -15,7 +15,7 @@ import { NumberInputOption, SelectOption, SwitchOption, -} from '../../../../../../vis_default_editor/public'; +} from '../../../../../../../vis_default_editor/public'; import { SeriesParam } from '../../../../types'; import { SetChart } from './chart_options'; diff --git a/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/mocks.ts b/src/plugins/vis_types/xy/public/editor/components/options/metrics_axes/mocks.ts similarity index 93% rename from src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/mocks.ts rename to src/plugins/vis_types/xy/public/editor/components/options/metrics_axes/mocks.ts index eed224cf2a514..cbc970c7ed7d8 100644 --- a/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/mocks.ts +++ b/src/plugins/vis_types/xy/public/editor/components/options/metrics_axes/mocks.ts @@ -8,8 +8,8 @@ import { Position } from '@elastic/charts'; -import { Vis } from '../../../../../../visualizations/public'; -import { Style } from '../../../../../../charts/public'; +import { Vis } from '../../../../../../../visualizations/public'; +import { Style } from '../../../../../../../charts/public'; import { ValueAxis, diff --git a/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/point_options.test.tsx b/src/plugins/vis_types/xy/public/editor/components/options/metrics_axes/point_options.test.tsx similarity index 100% rename from src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/point_options.test.tsx rename to src/plugins/vis_types/xy/public/editor/components/options/metrics_axes/point_options.test.tsx diff --git a/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/point_options.tsx b/src/plugins/vis_types/xy/public/editor/components/options/metrics_axes/point_options.tsx similarity index 95% rename from src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/point_options.tsx rename to src/plugins/vis_types/xy/public/editor/components/options/metrics_axes/point_options.tsx index d35a5a2374ca3..41d5f7c2c9794 100644 --- a/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/point_options.tsx +++ b/src/plugins/vis_types/xy/public/editor/components/options/metrics_axes/point_options.tsx @@ -11,7 +11,7 @@ import React from 'react'; import { i18n } from '@kbn/i18n'; import { EuiRange, EuiFormRow, EuiSpacer } from '@elastic/eui'; -import { SwitchOption } from '../../../../../../vis_default_editor/public'; +import { SwitchOption } from '../../../../../../../vis_default_editor/public'; import { SeriesParam } from '../../../../types'; import { SetChart } from './chart_options'; diff --git a/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/series_panel.tsx b/src/plugins/vis_types/xy/public/editor/components/options/metrics_axes/series_panel.tsx similarity index 96% rename from src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/series_panel.tsx rename to src/plugins/vis_types/xy/public/editor/components/options/metrics_axes/series_panel.tsx index 3adfe3277c969..69fbbcf80e28b 100644 --- a/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/series_panel.tsx +++ b/src/plugins/vis_types/xy/public/editor/components/options/metrics_axes/series_panel.tsx @@ -12,7 +12,7 @@ import { EuiPanel, EuiTitle, EuiSpacer, EuiAccordion } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; -import { Vis } from '../../../../../../visualizations/public'; +import { Vis } from '../../../../../../../visualizations/public'; import { ValueAxis, SeriesParam } from '../../../../types'; import { ChartOptions } from './chart_options'; diff --git a/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/utils.ts b/src/plugins/vis_types/xy/public/editor/components/options/metrics_axes/utils.ts similarity index 100% rename from src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/utils.ts rename to src/plugins/vis_types/xy/public/editor/components/options/metrics_axes/utils.ts diff --git a/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/value_axes_panel.test.tsx b/src/plugins/vis_types/xy/public/editor/components/options/metrics_axes/value_axes_panel.test.tsx similarity index 100% rename from src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/value_axes_panel.test.tsx rename to src/plugins/vis_types/xy/public/editor/components/options/metrics_axes/value_axes_panel.test.tsx diff --git a/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/value_axes_panel.tsx b/src/plugins/vis_types/xy/public/editor/components/options/metrics_axes/value_axes_panel.tsx similarity index 100% rename from src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/value_axes_panel.tsx rename to src/plugins/vis_types/xy/public/editor/components/options/metrics_axes/value_axes_panel.tsx diff --git a/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/value_axis_options.test.tsx b/src/plugins/vis_types/xy/public/editor/components/options/metrics_axes/value_axis_options.test.tsx similarity index 97% rename from src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/value_axis_options.test.tsx rename to src/plugins/vis_types/xy/public/editor/components/options/metrics_axes/value_axis_options.test.tsx index f2d689126166f..ceb655fa47107 100644 --- a/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/value_axis_options.test.tsx +++ b/src/plugins/vis_types/xy/public/editor/components/options/metrics_axes/value_axis_options.test.tsx @@ -11,7 +11,7 @@ import { shallow } from 'enzyme'; import { Position } from '@elastic/charts'; -import { TextInputOption } from '../../../../../../vis_default_editor/public'; +import { TextInputOption } from '../../../../../../../vis_default_editor/public'; import { ValueAxis, ScaleType } from '../../../../types'; import { LabelOptions } from './label_options'; diff --git a/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/value_axis_options.tsx b/src/plugins/vis_types/xy/public/editor/components/options/metrics_axes/value_axis_options.tsx similarity index 99% rename from src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/value_axis_options.tsx rename to src/plugins/vis_types/xy/public/editor/components/options/metrics_axes/value_axis_options.tsx index d39bbf5bfa532..751c61f3b1531 100644 --- a/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/value_axis_options.tsx +++ b/src/plugins/vis_types/xy/public/editor/components/options/metrics_axes/value_axis_options.tsx @@ -14,7 +14,7 @@ import { SelectOption, SwitchOption, TextInputOption, -} from '../../../../../../vis_default_editor/public'; +} from '../../../../../../../vis_default_editor/public'; import { ValueAxis } from '../../../../types'; import { LabelOptions, SetAxisLabel } from './label_options'; diff --git a/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/y_extents.test.tsx b/src/plugins/vis_types/xy/public/editor/components/options/metrics_axes/y_extents.test.tsx similarity index 97% rename from src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/y_extents.test.tsx rename to src/plugins/vis_types/xy/public/editor/components/options/metrics_axes/y_extents.test.tsx index e5ed34d03099d..da7005210865d 100644 --- a/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/y_extents.test.tsx +++ b/src/plugins/vis_types/xy/public/editor/components/options/metrics_axes/y_extents.test.tsx @@ -11,7 +11,7 @@ import { mount, shallow } from 'enzyme'; import { ScaleType } from '../../../../types'; import { YExtents, YExtentsProps } from './y_extents'; -import { NumberInputOption } from '../../../../../../vis_default_editor/public'; +import { NumberInputOption } from '../../../../../../../vis_default_editor/public'; describe('YExtents component', () => { let setMultipleValidity: jest.Mock; diff --git a/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/y_extents.tsx b/src/plugins/vis_types/xy/public/editor/components/options/metrics_axes/y_extents.tsx similarity index 97% rename from src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/y_extents.tsx rename to src/plugins/vis_types/xy/public/editor/components/options/metrics_axes/y_extents.tsx index e81f0fff96f49..ce546339a9912 100644 --- a/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/y_extents.tsx +++ b/src/plugins/vis_types/xy/public/editor/components/options/metrics_axes/y_extents.tsx @@ -10,7 +10,7 @@ import React, { useEffect, useCallback } from 'react'; import { EuiFlexGroup, EuiFlexItem, EuiFormRow } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { NumberInputOption } from '../../../../../../vis_default_editor/public'; +import { NumberInputOption } from '../../../../../../../vis_default_editor/public'; import { Scale, ScaleType } from '../../../../types'; import { SetScale } from './value_axis_options'; diff --git a/src/plugins/vis_type_xy/public/editor/components/options/point_series/elastic_charts_options.tsx b/src/plugins/vis_types/xy/public/editor/components/options/point_series/elastic_charts_options.tsx similarity index 97% rename from src/plugins/vis_type_xy/public/editor/components/options/point_series/elastic_charts_options.tsx rename to src/plugins/vis_types/xy/public/editor/components/options/point_series/elastic_charts_options.tsx index 271c5445a9580..105cd66799041 100644 --- a/src/plugins/vis_type_xy/public/editor/components/options/point_series/elastic_charts_options.tsx +++ b/src/plugins/vis_types/xy/public/editor/components/options/point_series/elastic_charts_options.tsx @@ -15,8 +15,8 @@ import { SelectOption, SwitchOption, PalettePicker, -} from '../../../../../../vis_default_editor/public'; -import { PaletteRegistry } from '../../../../../../charts/public'; +} from '../../../../../../../vis_default_editor/public'; +import { PaletteRegistry } from '../../../../../../../charts/public'; import { ChartType } from '../../../../../common'; import { VisParams } from '../../../../types'; diff --git a/src/plugins/vis_type_xy/public/editor/components/options/point_series/grid_panel.tsx b/src/plugins/vis_types/xy/public/editor/components/options/point_series/grid_panel.tsx similarity index 97% rename from src/plugins/vis_type_xy/public/editor/components/options/point_series/grid_panel.tsx rename to src/plugins/vis_types/xy/public/editor/components/options/point_series/grid_panel.tsx index 69f6a08946fce..0bf5344ac7f26 100644 --- a/src/plugins/vis_type_xy/public/editor/components/options/point_series/grid_panel.tsx +++ b/src/plugins/vis_types/xy/public/editor/components/options/point_series/grid_panel.tsx @@ -12,7 +12,7 @@ import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import { EuiPanel, EuiTitle, EuiSpacer } from '@elastic/eui'; -import { SelectOption, SwitchOption } from '../../../../../../vis_default_editor/public'; +import { SelectOption, SwitchOption } from '../../../../../../../vis_default_editor/public'; import { VisParams, ValueAxis } from '../../../../types'; import { ValidationVisOptionsProps } from '../../common'; diff --git a/src/plugins/vis_type_xy/public/editor/components/options/point_series/index.ts b/src/plugins/vis_types/xy/public/editor/components/options/point_series/index.ts similarity index 100% rename from src/plugins/vis_type_xy/public/editor/components/options/point_series/index.ts rename to src/plugins/vis_types/xy/public/editor/components/options/point_series/index.ts diff --git a/src/plugins/vis_type_xy/public/editor/components/options/point_series/point_series.mocks.ts b/src/plugins/vis_types/xy/public/editor/components/options/point_series/point_series.mocks.ts similarity index 100% rename from src/plugins/vis_type_xy/public/editor/components/options/point_series/point_series.mocks.ts rename to src/plugins/vis_types/xy/public/editor/components/options/point_series/point_series.mocks.ts diff --git a/src/plugins/vis_type_xy/public/editor/components/options/point_series/point_series.test.tsx b/src/plugins/vis_types/xy/public/editor/components/options/point_series/point_series.test.tsx similarity index 100% rename from src/plugins/vis_type_xy/public/editor/components/options/point_series/point_series.test.tsx rename to src/plugins/vis_types/xy/public/editor/components/options/point_series/point_series.test.tsx diff --git a/src/plugins/vis_type_xy/public/editor/components/options/point_series/point_series.tsx b/src/plugins/vis_types/xy/public/editor/components/options/point_series/point_series.tsx similarity index 97% rename from src/plugins/vis_type_xy/public/editor/components/options/point_series/point_series.tsx rename to src/plugins/vis_types/xy/public/editor/components/options/point_series/point_series.tsx index 1fd9b043e87f5..da7bdfb0d7986 100644 --- a/src/plugins/vis_type_xy/public/editor/components/options/point_series/point_series.tsx +++ b/src/plugins/vis_types/xy/public/editor/components/options/point_series/point_series.tsx @@ -15,8 +15,8 @@ import { BasicOptions, SwitchOption, LongLegendOptions, -} from '../../../../../../vis_default_editor/public'; -import { BUCKET_TYPES } from '../../../../../../data/public'; +} from '../../../../../../../vis_default_editor/public'; +import { BUCKET_TYPES } from '../../../../../../../data/public'; import { VisParams } from '../../../../types'; import { GridPanel } from './grid_panel'; diff --git a/src/plugins/vis_type_xy/public/editor/components/options/point_series/threshold_panel.tsx b/src/plugins/vis_types/xy/public/editor/components/options/point_series/threshold_panel.tsx similarity index 98% rename from src/plugins/vis_type_xy/public/editor/components/options/point_series/threshold_panel.tsx rename to src/plugins/vis_types/xy/public/editor/components/options/point_series/threshold_panel.tsx index 00429c6702eeb..347354ac9d4f2 100644 --- a/src/plugins/vis_type_xy/public/editor/components/options/point_series/threshold_panel.tsx +++ b/src/plugins/vis_types/xy/public/editor/components/options/point_series/threshold_panel.tsx @@ -16,7 +16,7 @@ import { SelectOption, SwitchOption, RequiredNumberInputOption, -} from '../../../../../../vis_default_editor/public'; +} from '../../../../../../../vis_default_editor/public'; import { ValidationVisOptionsProps } from '../../common'; import { VisParams } from '../../../../types'; import { getThresholdLineStyles } from '../../../collections'; diff --git a/src/plugins/vis_type_xy/public/editor/index.ts b/src/plugins/vis_types/xy/public/editor/index.ts similarity index 100% rename from src/plugins/vis_type_xy/public/editor/index.ts rename to src/plugins/vis_types/xy/public/editor/index.ts diff --git a/src/plugins/vis_type_xy/public/editor/positions.ts b/src/plugins/vis_types/xy/public/editor/positions.ts similarity index 100% rename from src/plugins/vis_type_xy/public/editor/positions.ts rename to src/plugins/vis_types/xy/public/editor/positions.ts diff --git a/src/plugins/vis_type_xy/public/editor/scale_types.ts b/src/plugins/vis_types/xy/public/editor/scale_types.ts similarity index 100% rename from src/plugins/vis_type_xy/public/editor/scale_types.ts rename to src/plugins/vis_types/xy/public/editor/scale_types.ts diff --git a/src/plugins/vis_type_xy/public/expression_functions/category_axis.ts b/src/plugins/vis_types/xy/public/expression_functions/category_axis.ts similarity index 98% rename from src/plugins/vis_type_xy/public/expression_functions/category_axis.ts rename to src/plugins/vis_types/xy/public/expression_functions/category_axis.ts index 30215d8feb8a3..08958915da4a4 100644 --- a/src/plugins/vis_type_xy/public/expression_functions/category_axis.ts +++ b/src/plugins/vis_types/xy/public/expression_functions/category_axis.ts @@ -11,7 +11,7 @@ import type { ExpressionFunctionDefinition, Datatable, ExpressionValueBoxed, -} from '../../../expressions/public'; +} from '../../../../expressions/public'; import type { CategoryAxis } from '../types'; import type { ExpressionValueScale } from './vis_scale'; import type { ExpressionValueLabel } from './label'; diff --git a/src/plugins/vis_type_xy/public/expression_functions/index.ts b/src/plugins/vis_types/xy/public/expression_functions/index.ts similarity index 100% rename from src/plugins/vis_type_xy/public/expression_functions/index.ts rename to src/plugins/vis_types/xy/public/expression_functions/index.ts diff --git a/src/plugins/vis_type_xy/public/expression_functions/label.ts b/src/plugins/vis_types/xy/public/expression_functions/label.ts similarity index 96% rename from src/plugins/vis_type_xy/public/expression_functions/label.ts rename to src/plugins/vis_types/xy/public/expression_functions/label.ts index 934278d13cff0..e733aebaa627c 100644 --- a/src/plugins/vis_type_xy/public/expression_functions/label.ts +++ b/src/plugins/vis_types/xy/public/expression_functions/label.ts @@ -7,12 +7,12 @@ */ import { i18n } from '@kbn/i18n'; -import type { Labels } from '../../../charts/public'; +import type { Labels } from '../../../../charts/public'; import type { ExpressionFunctionDefinition, Datatable, ExpressionValueBoxed, -} from '../../../expressions/public'; +} from '../../../../expressions/public'; export type ExpressionValueLabel = ExpressionValueBoxed< 'label', diff --git a/src/plugins/vis_type_xy/public/expression_functions/series_param.ts b/src/plugins/vis_types/xy/public/expression_functions/series_param.ts similarity index 98% rename from src/plugins/vis_type_xy/public/expression_functions/series_param.ts rename to src/plugins/vis_types/xy/public/expression_functions/series_param.ts index 3fd62e33e257f..174ed4c057974 100644 --- a/src/plugins/vis_type_xy/public/expression_functions/series_param.ts +++ b/src/plugins/vis_types/xy/public/expression_functions/series_param.ts @@ -11,7 +11,7 @@ import type { ExpressionFunctionDefinition, Datatable, ExpressionValueBoxed, -} from '../../../expressions/public'; +} from '../../../../expressions/public'; import type { SeriesParam } from '../types'; export interface Arguments extends Omit { diff --git a/src/plugins/vis_type_xy/public/expression_functions/threshold_line.ts b/src/plugins/vis_types/xy/public/expression_functions/threshold_line.ts similarity index 98% rename from src/plugins/vis_type_xy/public/expression_functions/threshold_line.ts rename to src/plugins/vis_types/xy/public/expression_functions/threshold_line.ts index 8c01e37503985..a4f5cf98fb968 100644 --- a/src/plugins/vis_type_xy/public/expression_functions/threshold_line.ts +++ b/src/plugins/vis_types/xy/public/expression_functions/threshold_line.ts @@ -11,7 +11,7 @@ import type { ExpressionFunctionDefinition, Datatable, ExpressionValueBoxed, -} from '../../../expressions/public'; +} from '../../../../expressions/public'; import type { ThresholdLine } from '../types'; export type ExpressionValueThresholdLine = ExpressionValueBoxed< diff --git a/src/plugins/vis_type_xy/public/expression_functions/time_marker.ts b/src/plugins/vis_types/xy/public/expression_functions/time_marker.ts similarity index 98% rename from src/plugins/vis_type_xy/public/expression_functions/time_marker.ts rename to src/plugins/vis_types/xy/public/expression_functions/time_marker.ts index 3d9f609292c00..3b673394463f0 100644 --- a/src/plugins/vis_type_xy/public/expression_functions/time_marker.ts +++ b/src/plugins/vis_types/xy/public/expression_functions/time_marker.ts @@ -11,7 +11,7 @@ import type { ExpressionFunctionDefinition, Datatable, ExpressionValueBoxed, -} from '../../../expressions/public'; +} from '../../../../expressions/public'; import type { TimeMarker } from '../types'; export type ExpressionValueTimeMarker = ExpressionValueBoxed< diff --git a/src/plugins/vis_type_xy/public/expression_functions/value_axis.ts b/src/plugins/vis_types/xy/public/expression_functions/value_axis.ts similarity index 98% rename from src/plugins/vis_type_xy/public/expression_functions/value_axis.ts rename to src/plugins/vis_types/xy/public/expression_functions/value_axis.ts index 510ec9bc605d2..a92d35dc9fefd 100644 --- a/src/plugins/vis_type_xy/public/expression_functions/value_axis.ts +++ b/src/plugins/vis_types/xy/public/expression_functions/value_axis.ts @@ -13,7 +13,7 @@ import type { ExpressionFunctionDefinition, Datatable, ExpressionValueBoxed, -} from '../../../expressions/public'; +} from '../../../../expressions/public'; interface Arguments { name: string; diff --git a/src/plugins/vis_type_xy/public/expression_functions/vis_scale.ts b/src/plugins/vis_types/xy/public/expression_functions/vis_scale.ts similarity index 98% rename from src/plugins/vis_type_xy/public/expression_functions/vis_scale.ts rename to src/plugins/vis_types/xy/public/expression_functions/vis_scale.ts index fadf3d80a6e81..ddf14ead20a25 100644 --- a/src/plugins/vis_type_xy/public/expression_functions/vis_scale.ts +++ b/src/plugins/vis_types/xy/public/expression_functions/vis_scale.ts @@ -11,7 +11,7 @@ import type { ExpressionFunctionDefinition, Datatable, ExpressionValueBoxed, -} from '../../../expressions/public'; +} from '../../../../expressions/public'; import type { Scale } from '../types'; export type ExpressionValueScale = ExpressionValueBoxed< diff --git a/src/plugins/vis_type_xy/public/expression_functions/xy_vis_fn.ts b/src/plugins/vis_types/xy/public/expression_functions/xy_vis_fn.ts similarity index 98% rename from src/plugins/vis_type_xy/public/expression_functions/xy_vis_fn.ts rename to src/plugins/vis_types/xy/public/expression_functions/xy_vis_fn.ts index 6d2b860066b07..ccad0c520f8ea 100644 --- a/src/plugins/vis_type_xy/public/expression_functions/xy_vis_fn.ts +++ b/src/plugins/vis_types/xy/public/expression_functions/xy_vis_fn.ts @@ -8,8 +8,12 @@ import { i18n } from '@kbn/i18n'; -import type { ExpressionFunctionDefinition, Datatable, Render } from '../../../expressions/common'; -import { prepareLogTable, Dimension } from '../../../visualizations/public'; +import type { + ExpressionFunctionDefinition, + Datatable, + Render, +} from '../../../../expressions/common'; +import { prepareLogTable, Dimension } from '../../../../visualizations/public'; import type { ChartType } from '../../common'; import type { VisParams, XYVisConfig } from '../types'; diff --git a/src/plugins/vis_type_xy/public/index.ts b/src/plugins/vis_types/xy/public/index.ts similarity index 100% rename from src/plugins/vis_type_xy/public/index.ts rename to src/plugins/vis_types/xy/public/index.ts diff --git a/src/plugins/vis_type_xy/public/plugin.ts b/src/plugins/vis_types/xy/public/plugin.ts similarity index 89% rename from src/plugins/vis_type_xy/public/plugin.ts rename to src/plugins/vis_types/xy/public/plugin.ts index 488e6fd84b4da..57736444f49fe 100644 --- a/src/plugins/vis_type_xy/public/plugin.ts +++ b/src/plugins/vis_types/xy/public/plugin.ts @@ -6,12 +6,12 @@ * Side Public License, v 1. */ -import { CoreSetup, CoreStart, Plugin } from '../../../core/public'; -import { Plugin as ExpressionsPublicPlugin } from '../../expressions/public'; -import { VisualizationsSetup, VisualizationsStart } from '../../visualizations/public'; -import { ChartsPluginSetup, ChartsPluginStart } from '../../charts/public'; -import { DataPublicPluginStart } from '../../data/public'; -import { UsageCollectionSetup } from '../../usage_collection/public'; +import { CoreSetup, CoreStart, Plugin } from '../../../../core/public'; +import { Plugin as ExpressionsPublicPlugin } from '../../../expressions/public'; +import { VisualizationsSetup, VisualizationsStart } from '../../../visualizations/public'; +import { ChartsPluginSetup, ChartsPluginStart } from '../../../charts/public'; +import { DataPublicPluginStart } from '../../../data/public'; +import { UsageCollectionSetup } from '../../../usage_collection/public'; import { setDataActions, setFormatService, diff --git a/src/plugins/vis_type_xy/public/sample_vis.test.mocks.ts b/src/plugins/vis_types/xy/public/sample_vis.test.mocks.ts similarity index 100% rename from src/plugins/vis_type_xy/public/sample_vis.test.mocks.ts rename to src/plugins/vis_types/xy/public/sample_vis.test.mocks.ts diff --git a/src/plugins/vis_type_xy/public/services.ts b/src/plugins/vis_types/xy/public/services.ts similarity index 83% rename from src/plugins/vis_type_xy/public/services.ts rename to src/plugins/vis_types/xy/public/services.ts index 63bc55b288ae3..7f1f7e8728151 100644 --- a/src/plugins/vis_type_xy/public/services.ts +++ b/src/plugins/vis_types/xy/public/services.ts @@ -7,10 +7,10 @@ */ import { UiCounterMetricType } from '@kbn/analytics'; -import { CoreSetup, DocLinksStart } from '../../../core/public'; -import { createGetterSetter } from '../../kibana_utils/public'; -import { DataPublicPluginStart } from '../../data/public'; -import { ChartsPluginSetup, ChartsPluginStart } from '../../charts/public'; +import { CoreSetup, DocLinksStart } from '../../../../core/public'; +import { createGetterSetter } from '../../../kibana_utils/public'; +import { DataPublicPluginStart } from '../../../data/public'; +import { ChartsPluginSetup, ChartsPluginStart } from '../../../charts/public'; export const [getUISettings, setUISettings] = createGetterSetter( 'xy core.uiSettings' diff --git a/src/plugins/vis_type_xy/public/to_ast.test.ts b/src/plugins/vis_types/xy/public/to_ast.test.ts similarity index 83% rename from src/plugins/vis_type_xy/public/to_ast.test.ts rename to src/plugins/vis_types/xy/public/to_ast.test.ts index 4437986eff5f7..cbe25bc1fef6f 100644 --- a/src/plugins/vis_type_xy/public/to_ast.test.ts +++ b/src/plugins/vis_types/xy/public/to_ast.test.ts @@ -6,15 +6,15 @@ * Side Public License, v 1. */ -import { Vis } from '../../visualizations/public'; -import { buildExpression } from '../../expressions/public'; +import { Vis } from '../../../visualizations/public'; +import { buildExpression } from '../../../expressions/public'; import { sampleAreaVis } from './sample_vis.test.mocks'; import { toExpressionAst } from './to_ast'; import { VisParams } from './types'; -jest.mock('../../expressions/public', () => ({ - ...(jest.requireActual('../../expressions/public') as any), +jest.mock('../../../expressions/public', () => ({ + ...(jest.requireActual('../../../expressions/public') as any), buildExpression: jest.fn().mockImplementation(() => ({ toAst: () => ({ type: 'expression', diff --git a/src/plugins/vis_type_xy/public/to_ast.ts b/src/plugins/vis_types/xy/public/to_ast.ts similarity index 97% rename from src/plugins/vis_type_xy/public/to_ast.ts rename to src/plugins/vis_types/xy/public/to_ast.ts index 0b1eb5262d71a..5fc130a08ed27 100644 --- a/src/plugins/vis_type_xy/public/to_ast.ts +++ b/src/plugins/vis_types/xy/public/to_ast.ts @@ -13,10 +13,10 @@ import { getVisSchemas, DateHistogramParams, HistogramParams, -} from '../../visualizations/public'; -import { buildExpression, buildExpressionFunction } from '../../expressions/public'; -import { BUCKET_TYPES } from '../../data/public'; -import { Labels } from '../../charts/public'; +} from '../../../visualizations/public'; +import { buildExpression, buildExpressionFunction } from '../../../expressions/public'; +import { BUCKET_TYPES } from '../../../data/public'; +import { Labels } from '../../../charts/public'; import { Dimensions, @@ -32,7 +32,7 @@ import { import { visName, VisTypeXyExpressionFunctionDefinition } from './expression_functions/xy_vis_fn'; import { XyVisType } from '../common'; import { getEsaggsFn } from './to_ast_esaggs'; -import { TimeRangeBounds } from '../../data/common'; +import { TimeRangeBounds } from '../../../data/common'; const prepareLabel = (data: Labels) => { const label = buildExpressionFunction('label', { diff --git a/src/plugins/vis_type_xy/public/to_ast_esaggs.ts b/src/plugins/vis_types/xy/public/to_ast_esaggs.ts similarity index 91% rename from src/plugins/vis_type_xy/public/to_ast_esaggs.ts rename to src/plugins/vis_types/xy/public/to_ast_esaggs.ts index 71ef78b19e076..ff9dbd9ca7664 100644 --- a/src/plugins/vis_type_xy/public/to_ast_esaggs.ts +++ b/src/plugins/vis_types/xy/public/to_ast_esaggs.ts @@ -6,12 +6,12 @@ * Side Public License, v 1. */ -import { Vis } from '../../visualizations/public'; -import { buildExpression, buildExpressionFunction } from '../../expressions/public'; +import { Vis } from '../../../visualizations/public'; +import { buildExpression, buildExpressionFunction } from '../../../expressions/public'; import { EsaggsExpressionFunctionDefinition, IndexPatternLoadExpressionFunctionDefinition, -} from '../../data/public'; +} from '../../../data/public'; import { VisParams } from './types'; diff --git a/src/plugins/vis_type_xy/public/types/config.ts b/src/plugins/vis_types/xy/public/types/config.ts similarity index 100% rename from src/plugins/vis_type_xy/public/types/config.ts rename to src/plugins/vis_types/xy/public/types/config.ts diff --git a/src/plugins/vis_type_xy/public/types/constants.ts b/src/plugins/vis_types/xy/public/types/constants.ts similarity index 100% rename from src/plugins/vis_type_xy/public/types/constants.ts rename to src/plugins/vis_types/xy/public/types/constants.ts diff --git a/src/plugins/vis_type_xy/public/types/index.ts b/src/plugins/vis_types/xy/public/types/index.ts similarity index 100% rename from src/plugins/vis_type_xy/public/types/index.ts rename to src/plugins/vis_types/xy/public/types/index.ts diff --git a/src/plugins/vis_type_xy/public/types/param.ts b/src/plugins/vis_types/xy/public/types/param.ts similarity index 97% rename from src/plugins/vis_type_xy/public/types/param.ts rename to src/plugins/vis_types/xy/public/types/param.ts index 0687bd2af2cd1..81eeca55108ca 100644 --- a/src/plugins/vis_type_xy/public/types/param.ts +++ b/src/plugins/vis_types/xy/public/types/param.ts @@ -7,14 +7,14 @@ */ import type { Fit, Position } from '@elastic/charts'; -import type { Style, Labels, PaletteOutput } from '../../../charts/public'; +import type { Style, Labels, PaletteOutput } from '../../../../charts/public'; import type { SchemaConfig, ExpressionValueXYDimension, FakeParams, HistogramParams, DateHistogramParams, -} from '../../../visualizations/public'; +} from '../../../../visualizations/public'; import type { ChartType, XyVisType } from '../../common'; import type { ExpressionValueCategoryAxis, diff --git a/src/plugins/vis_type_xy/public/types/vis_type.ts b/src/plugins/vis_types/xy/public/types/vis_type.ts similarity index 88% rename from src/plugins/vis_type_xy/public/types/vis_type.ts rename to src/plugins/vis_types/xy/public/types/vis_type.ts index 849a646cca814..311714ed3587d 100644 --- a/src/plugins/vis_type_xy/public/types/vis_type.ts +++ b/src/plugins/vis_types/xy/public/types/vis_type.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { VisTypeDefinition } from '../../../visualizations/public'; +import { VisTypeDefinition } from '../../../../visualizations/public'; import { ChartType } from '../../common'; import { VisParams } from './param'; diff --git a/src/plugins/vis_type_xy/public/utils/accessors.test.ts b/src/plugins/vis_types/xy/public/utils/accessors.test.ts similarity index 98% rename from src/plugins/vis_type_xy/public/utils/accessors.test.ts rename to src/plugins/vis_types/xy/public/utils/accessors.test.ts index d074263e5bb25..61d175fa8ff7d 100644 --- a/src/plugins/vis_type_xy/public/utils/accessors.test.ts +++ b/src/plugins/vis_types/xy/public/utils/accessors.test.ts @@ -7,7 +7,7 @@ */ import { COMPLEX_SPLIT_ACCESSOR, getComplexAccessor } from './accessors'; -import { BUCKET_TYPES } from '../../../data/common'; +import { BUCKET_TYPES } from '../../../../data/common'; import { AccessorFn, Datum } from '@elastic/charts'; describe('XY chart datum accessors', () => { diff --git a/src/plugins/vis_type_xy/public/utils/accessors.tsx b/src/plugins/vis_types/xy/public/utils/accessors.tsx similarity index 94% rename from src/plugins/vis_type_xy/public/utils/accessors.tsx rename to src/plugins/vis_types/xy/public/utils/accessors.tsx index 4920885f51a07..0356e921a9d5c 100644 --- a/src/plugins/vis_type_xy/public/utils/accessors.tsx +++ b/src/plugins/vis_types/xy/public/utils/accessors.tsx @@ -7,8 +7,8 @@ */ import { AccessorFn, Accessor } from '@elastic/charts'; -import { BUCKET_TYPES } from '../../../data/public'; -import { FakeParams } from '../../../visualizations/public'; +import { BUCKET_TYPES } from '../../../../data/public'; +import { FakeParams } from '../../../../visualizations/public'; import { Aspect } from '../types'; export const COMPLEX_X_ACCESSOR = '__customXAccessor__'; diff --git a/src/plugins/vis_type_xy/public/utils/domain.ts b/src/plugins/vis_types/xy/public/utils/domain.ts similarity index 90% rename from src/plugins/vis_type_xy/public/utils/domain.ts rename to src/plugins/vis_types/xy/public/utils/domain.ts index 48527ec9333ed..fa8dd74e3942a 100644 --- a/src/plugins/vis_type_xy/public/utils/domain.ts +++ b/src/plugins/vis_types/xy/public/utils/domain.ts @@ -11,9 +11,9 @@ import { unitOfTime } from 'moment'; import { DomainRange } from '@elastic/charts'; -import { getAdjustedInterval } from '../../../charts/public'; -import { Datatable } from '../../../expressions/public'; -import { DateHistogramParams, HistogramParams } from '../../../visualizations/public'; +import { getAdjustedInterval } from '../../../../charts/public'; +import { Datatable } from '../../../../expressions/public'; +import { DateHistogramParams, HistogramParams } from '../../../../visualizations/public'; import { Aspect } from '../types'; diff --git a/src/plugins/vis_type_xy/public/utils/get_all_series.test.ts b/src/plugins/vis_types/xy/public/utils/get_all_series.test.ts similarity index 100% rename from src/plugins/vis_type_xy/public/utils/get_all_series.test.ts rename to src/plugins/vis_types/xy/public/utils/get_all_series.test.ts diff --git a/src/plugins/vis_type_xy/public/utils/get_all_series.ts b/src/plugins/vis_types/xy/public/utils/get_all_series.ts similarity index 95% rename from src/plugins/vis_type_xy/public/utils/get_all_series.ts rename to src/plugins/vis_types/xy/public/utils/get_all_series.ts index c9b956f7cd3b5..cdb8f816d7e4f 100644 --- a/src/plugins/vis_type_xy/public/utils/get_all_series.ts +++ b/src/plugins/vis_types/xy/public/utils/get_all_series.ts @@ -7,7 +7,7 @@ */ import { TickFormatter } from '@elastic/charts'; -import { DatatableRow } from '../../../expressions/public'; +import { DatatableRow } from '../../../../expressions/public'; import { Column, Aspect } from '../types'; interface SplitAccessors { diff --git a/src/plugins/vis_type_xy/public/utils/get_color_picker.test.tsx b/src/plugins/vis_types/xy/public/utils/get_color_picker.test.tsx similarity index 96% rename from src/plugins/vis_type_xy/public/utils/get_color_picker.test.tsx rename to src/plugins/vis_types/xy/public/utils/get_color_picker.test.tsx index c2377b42bb1c2..e015521f7436e 100644 --- a/src/plugins/vis_type_xy/public/utils/get_color_picker.test.tsx +++ b/src/plugins/vis_types/xy/public/utils/get_color_picker.test.tsx @@ -12,8 +12,8 @@ import { EuiPopover } from '@elastic/eui'; import { mountWithIntl } from '@kbn/test/jest'; import { ComponentType, ReactWrapper } from 'enzyme'; import { getColorPicker } from './get_color_picker'; -import { ColorPicker } from '../../../charts/public'; -import type { PersistedState } from '../../../visualizations/public'; +import { ColorPicker } from '../../../../charts/public'; +import type { PersistedState } from '../../../../visualizations/public'; jest.mock('@elastic/charts', () => { const original = jest.requireActual('@elastic/charts'); diff --git a/src/plugins/vis_type_xy/public/utils/get_color_picker.tsx b/src/plugins/vis_types/xy/public/utils/get_color_picker.tsx similarity index 95% rename from src/plugins/vis_type_xy/public/utils/get_color_picker.tsx rename to src/plugins/vis_types/xy/public/utils/get_color_picker.tsx index 4805d89068e86..1b5a16a8894aa 100644 --- a/src/plugins/vis_type_xy/public/utils/get_color_picker.tsx +++ b/src/plugins/vis_types/xy/public/utils/get_color_picker.tsx @@ -10,8 +10,8 @@ import React, { useCallback } from 'react'; import { LegendColorPicker, Position, XYChartSeriesIdentifier, SeriesName } from '@elastic/charts'; import { PopoverAnchorPosition, EuiWrappingPopover, EuiOutsideClickDetector } from '@elastic/eui'; -import type { PersistedState } from '../../../visualizations/public'; -import { ColorPicker } from '../../../charts/public'; +import type { PersistedState } from '../../../../visualizations/public'; +import { ColorPicker } from '../../../../charts/public'; function getAnchorPosition(legendPosition: Position): PopoverAnchorPosition { switch (legendPosition) { diff --git a/src/plugins/vis_type_xy/public/utils/get_legend_actions.tsx b/src/plugins/vis_types/xy/public/utils/get_legend_actions.tsx similarity index 98% rename from src/plugins/vis_type_xy/public/utils/get_legend_actions.tsx rename to src/plugins/vis_types/xy/public/utils/get_legend_actions.tsx index c125d8dd075ed..98ace7dd57a39 100644 --- a/src/plugins/vis_type_xy/public/utils/get_legend_actions.tsx +++ b/src/plugins/vis_types/xy/public/utils/get_legend_actions.tsx @@ -12,7 +12,7 @@ import { i18n } from '@kbn/i18n'; import { EuiContextMenuPanelDescriptor, EuiIcon, EuiPopover, EuiContextMenu } from '@elastic/eui'; import { LegendAction, XYChartSeriesIdentifier, SeriesName } from '@elastic/charts'; -import { ClickTriggerEvent } from '../../../charts/public'; +import { ClickTriggerEvent } from '../../../../charts/public'; export const getLegendActions = ( canFilter: (data: ClickTriggerEvent | null) => Promise, diff --git a/src/plugins/vis_type_xy/public/utils/get_series_name_fn.test.ts b/src/plugins/vis_types/xy/public/utils/get_series_name_fn.test.ts similarity index 100% rename from src/plugins/vis_type_xy/public/utils/get_series_name_fn.test.ts rename to src/plugins/vis_types/xy/public/utils/get_series_name_fn.test.ts diff --git a/src/plugins/vis_type_xy/public/utils/get_series_name_fn.ts b/src/plugins/vis_types/xy/public/utils/get_series_name_fn.ts similarity index 100% rename from src/plugins/vis_type_xy/public/utils/get_series_name_fn.ts rename to src/plugins/vis_types/xy/public/utils/get_series_name_fn.ts diff --git a/src/plugins/vis_type_xy/public/utils/get_time_zone.tsx b/src/plugins/vis_types/xy/public/utils/get_time_zone.tsx similarity index 100% rename from src/plugins/vis_type_xy/public/utils/get_time_zone.tsx rename to src/plugins/vis_types/xy/public/utils/get_time_zone.tsx diff --git a/src/plugins/vis_type_xy/public/utils/index.tsx b/src/plugins/vis_types/xy/public/utils/index.tsx similarity index 100% rename from src/plugins/vis_type_xy/public/utils/index.tsx rename to src/plugins/vis_types/xy/public/utils/index.tsx diff --git a/src/plugins/vis_type_xy/public/utils/render_all_series.test.mocks.ts b/src/plugins/vis_types/xy/public/utils/render_all_series.test.mocks.ts similarity index 100% rename from src/plugins/vis_type_xy/public/utils/render_all_series.test.mocks.ts rename to src/plugins/vis_types/xy/public/utils/render_all_series.test.mocks.ts diff --git a/src/plugins/vis_type_xy/public/utils/render_all_series.test.tsx b/src/plugins/vis_types/xy/public/utils/render_all_series.test.tsx similarity index 98% rename from src/plugins/vis_type_xy/public/utils/render_all_series.test.tsx rename to src/plugins/vis_types/xy/public/utils/render_all_series.test.tsx index 23dabef662d55..47b103003b3ed 100644 --- a/src/plugins/vis_type_xy/public/utils/render_all_series.test.tsx +++ b/src/plugins/vis_types/xy/public/utils/render_all_series.test.tsx @@ -9,7 +9,7 @@ import React from 'react'; import { shallow } from 'enzyme'; import { AreaSeries, BarSeries, CurveType } from '@elastic/charts'; -import { DatatableRow } from '../../../expressions/public'; +import { DatatableRow } from '../../../../expressions/public'; import { renderAllSeries } from './render_all_series'; import { getVisConfig, diff --git a/src/plugins/vis_type_xy/public/utils/render_all_series.tsx b/src/plugins/vis_types/xy/public/utils/render_all_series.tsx similarity index 98% rename from src/plugins/vis_type_xy/public/utils/render_all_series.tsx rename to src/plugins/vis_types/xy/public/utils/render_all_series.tsx index d186617fef2ae..f8ca1d059ae4f 100644 --- a/src/plugins/vis_type_xy/public/utils/render_all_series.tsx +++ b/src/plugins/vis_types/xy/public/utils/render_all_series.tsx @@ -21,8 +21,8 @@ import { LabelOverflowConstraint, } from '@elastic/charts'; -import { DatatableRow } from '../../../expressions/public'; -import { METRIC_TYPES } from '../../../data/public'; +import { DatatableRow } from '../../../../expressions/public'; +import { METRIC_TYPES } from '../../../../data/public'; import { ChartType } from '../../common'; import { SeriesParam, VisConfig } from '../types'; diff --git a/src/plugins/vis_type_xy/public/vis_component.tsx b/src/plugins/vis_types/xy/public/vis_component.tsx similarity index 98% rename from src/plugins/vis_type_xy/public/vis_component.tsx rename to src/plugins/vis_types/xy/public/vis_component.tsx index 346f6cc74a1ac..141174194f1bc 100644 --- a/src/plugins/vis_type_xy/public/vis_component.tsx +++ b/src/plugins/vis_types/xy/public/vis_component.tsx @@ -29,10 +29,10 @@ import { getBrushFromChartBrushEventFn, ClickTriggerEvent, PaletteRegistry, -} from '../../charts/public'; -import { Datatable, IInterpreterRenderHandlers } from '../../expressions/public'; -import type { PersistedState } from '../../visualizations/public'; -import { useActiveCursor } from '../../charts/public'; + useActiveCursor, +} from '../../../charts/public'; +import { Datatable, IInterpreterRenderHandlers } from '../../../expressions/public'; +import type { PersistedState } from '../../../visualizations/public'; import { VisParams } from './types'; import { getAdjustedDomain, diff --git a/src/plugins/vis_type_xy/public/vis_renderer.tsx b/src/plugins/vis_types/xy/public/vis_renderer.tsx similarity index 89% rename from src/plugins/vis_type_xy/public/vis_renderer.tsx rename to src/plugins/vis_types/xy/public/vis_renderer.tsx index df3bee9b3f446..093671307d538 100644 --- a/src/plugins/vis_type_xy/public/vis_renderer.tsx +++ b/src/plugins/vis_types/xy/public/vis_renderer.tsx @@ -10,9 +10,9 @@ import React, { lazy } from 'react'; import { render, unmountComponentAtNode } from 'react-dom'; import { I18nProvider } from '@kbn/i18n/react'; -import { VisualizationContainer } from '../../visualizations/public'; -import type { PersistedState } from '../../visualizations/public'; -import type { ExpressionRenderDefinition } from '../../expressions/public'; +import { VisualizationContainer } from '../../../visualizations/public'; +import type { PersistedState } from '../../../visualizations/public'; +import type { ExpressionRenderDefinition } from '../../../expressions/public'; import type { XyVisType } from '../common'; import type { VisComponentType } from './vis_component'; diff --git a/src/plugins/vis_type_xy/public/vis_types/area.ts b/src/plugins/vis_types/xy/public/vis_types/area.ts similarity index 95% rename from src/plugins/vis_type_xy/public/vis_types/area.ts rename to src/plugins/vis_types/xy/public/vis_types/area.ts index 4d886c0dcb884..b377fd54753da 100644 --- a/src/plugins/vis_type_xy/public/vis_types/area.ts +++ b/src/plugins/vis_types/xy/public/vis_types/area.ts @@ -11,9 +11,9 @@ import { i18n } from '@kbn/i18n'; import { euiPaletteColorBlind } from '@elastic/eui/lib/services'; import { Fit, Position } from '@elastic/charts'; -import { AggGroupNames } from '../../../data/public'; -import { VIS_EVENT_TO_TRIGGER } from '../../../visualizations/public'; -import { defaultCountLabel, LabelRotation } from '../../../charts/public'; +import { AggGroupNames } from '../../../../data/public'; +import { VIS_EVENT_TO_TRIGGER } from '../../../../visualizations/public'; +import { defaultCountLabel, LabelRotation } from '../../../../charts/public'; import { ChartMode, diff --git a/src/plugins/vis_type_xy/public/vis_types/histogram.ts b/src/plugins/vis_types/xy/public/vis_types/histogram.ts similarity index 96% rename from src/plugins/vis_type_xy/public/vis_types/histogram.ts rename to src/plugins/vis_types/xy/public/vis_types/histogram.ts index 9a0a3b43329fd..2d22b7566175c 100644 --- a/src/plugins/vis_type_xy/public/vis_types/histogram.ts +++ b/src/plugins/vis_types/xy/public/vis_types/histogram.ts @@ -11,8 +11,8 @@ import { i18n } from '@kbn/i18n'; import { euiPaletteColorBlind } from '@elastic/eui/lib/services'; import { Position } from '@elastic/charts'; -import { AggGroupNames } from '../../../data/public'; -import { VIS_EVENT_TO_TRIGGER } from '../../../visualizations/public'; +import { AggGroupNames } from '../../../../data/public'; +import { VIS_EVENT_TO_TRIGGER } from '../../../../visualizations/public'; import { ChartMode, @@ -26,7 +26,7 @@ import { import { toExpressionAst } from '../to_ast'; import { ChartType } from '../../common'; import { getOptionTabs } from '../editor/common_config'; -import { defaultCountLabel, LabelRotation } from '../../../charts/public'; +import { defaultCountLabel, LabelRotation } from '../../../../charts/public'; export const getHistogramVisTypeDefinition = ( showElasticChartsOptions = false diff --git a/src/plugins/vis_type_xy/public/vis_types/horizontal_bar.ts b/src/plugins/vis_types/xy/public/vis_types/horizontal_bar.ts similarity index 96% rename from src/plugins/vis_type_xy/public/vis_types/horizontal_bar.ts rename to src/plugins/vis_types/xy/public/vis_types/horizontal_bar.ts index 5238258fcf080..8916f3f94f6ff 100644 --- a/src/plugins/vis_type_xy/public/vis_types/horizontal_bar.ts +++ b/src/plugins/vis_types/xy/public/vis_types/horizontal_bar.ts @@ -11,8 +11,8 @@ import { i18n } from '@kbn/i18n'; import { euiPaletteColorBlind } from '@elastic/eui/lib/services'; import { Position } from '@elastic/charts'; -import { AggGroupNames } from '../../../data/public'; -import { VIS_EVENT_TO_TRIGGER } from '../../../visualizations/public'; +import { AggGroupNames } from '../../../../data/public'; +import { VIS_EVENT_TO_TRIGGER } from '../../../../visualizations/public'; import { ChartMode, @@ -26,7 +26,7 @@ import { import { toExpressionAst } from '../to_ast'; import { ChartType } from '../../common'; import { getOptionTabs } from '../editor/common_config'; -import { defaultCountLabel, LabelRotation } from '../../../charts/public'; +import { defaultCountLabel, LabelRotation } from '../../../../charts/public'; export const getHorizontalBarVisTypeDefinition = ( showElasticChartsOptions = false diff --git a/src/plugins/vis_type_xy/public/vis_types/index.ts b/src/plugins/vis_types/xy/public/vis_types/index.ts similarity index 100% rename from src/plugins/vis_type_xy/public/vis_types/index.ts rename to src/plugins/vis_types/xy/public/vis_types/index.ts diff --git a/src/plugins/vis_type_xy/public/vis_types/line.ts b/src/plugins/vis_types/xy/public/vis_types/line.ts similarity index 95% rename from src/plugins/vis_type_xy/public/vis_types/line.ts rename to src/plugins/vis_types/xy/public/vis_types/line.ts index 239eae83057d4..af75c38d627df 100644 --- a/src/plugins/vis_type_xy/public/vis_types/line.ts +++ b/src/plugins/vis_types/xy/public/vis_types/line.ts @@ -11,9 +11,9 @@ import { i18n } from '@kbn/i18n'; import { euiPaletteColorBlind } from '@elastic/eui/lib/services'; import { Position, Fit } from '@elastic/charts'; -import { AggGroupNames } from '../../../data/public'; -import { VIS_EVENT_TO_TRIGGER } from '../../../visualizations/public'; -import { defaultCountLabel, LabelRotation } from '../../../charts/public'; +import { AggGroupNames } from '../../../../data/public'; +import { VIS_EVENT_TO_TRIGGER } from '../../../../visualizations/public'; +import { defaultCountLabel, LabelRotation } from '../../../../charts/public'; import { ChartMode, diff --git a/src/plugins/vis_type_xy/server/index.ts b/src/plugins/vis_types/xy/server/index.ts similarity index 100% rename from src/plugins/vis_type_xy/server/index.ts rename to src/plugins/vis_types/xy/server/index.ts diff --git a/src/plugins/vis_type_xy/server/plugin.ts b/src/plugins/vis_types/xy/server/plugin.ts similarity index 100% rename from src/plugins/vis_type_xy/server/plugin.ts rename to src/plugins/vis_types/xy/server/plugin.ts diff --git a/src/plugins/vis_types/xy/tsconfig.json b/src/plugins/vis_types/xy/tsconfig.json new file mode 100644 index 0000000000000..f1f65b6218e82 --- /dev/null +++ b/src/plugins/vis_types/xy/tsconfig.json @@ -0,0 +1,24 @@ +{ + "extends": "../../../../tsconfig.base.json", + "compilerOptions": { + "outDir": "./target/types", + "emitDeclarationOnly": true, + "declaration": true, + "declarationMap": true + }, + "include": [ + "common/**/*", + "public/**/*", + "server/**/*" + ], + "references": [ + { "path": "../../../core/tsconfig.json" }, + { "path": "../../charts/tsconfig.json" }, + { "path": "../../data/tsconfig.json" }, + { "path": "../../expressions/tsconfig.json" }, + { "path": "../../visualizations/tsconfig.json" }, + { "path": "../../usage_collection/tsconfig.json" }, + { "path": "../../kibana_utils/tsconfig.json" }, + { "path": "../../vis_default_editor/tsconfig.json" }, + ] +} diff --git a/x-pack/plugins/ml/public/application/util/chart_utils.js b/x-pack/plugins/ml/public/application/util/chart_utils.js index c8e7285d8a34d..dacdb5e5d5d10 100644 --- a/x-pack/plugins/ml/public/application/util/chart_utils.js +++ b/x-pack/plugins/ml/public/application/util/chart_utils.js @@ -144,7 +144,7 @@ export function drawLineChartDots(data, lineChartGroup, lineChartValuesLine, rad } // this replicates Kibana's filterAxisLabels() behavior -// which can be found in src/plugins/vis_type_vislib/public/vislib/lib/axis/axis_labels.js +// which can be found in src/plugins/vis_types/vislib/public/vislib/lib/axis/axis_labels.js // axis labels which overflow the chart's boundaries will be removed export function filterAxisLabels(selection, chartWidth) { if (selection === undefined || selection.selectAll === undefined) { From b42c86932a2b6c53f02b51884a3c1bbd105c6a06 Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Fri, 20 Aug 2021 09:23:22 -0400 Subject: [PATCH 18/76] [ML] APM Latency Correlations: Fix formatting of duration values for log x axis and selection badge. (#109214) (#109416) - Fix, clean up and unit tests for the log log charts x axis duration based ticks. This extends existing duration utilities to support a custom threshold to be able to fine tune the formatting for either single values with more detail or chart axis ticks where less detail is required. This is useful for log axis that cover a wider range of units. As can be seen in the screenshot, axis ticks will be formatted as full seconds from 1s onwards instead of 1,000 ms already up to 10 seconds. Because the threshold parameter is optional and defaults to 10, other uses of getDurationFormatter don't need to be changed. - Fixes the formatting of the selection badge. Co-authored-by: Walter Rafelsberger --- .../common/utils/formatters/duration.test.ts | 51 ++++++++++++++++++- .../apm/common/utils/formatters/duration.ts | 45 +++++++++------- .../utils/formatters/formatters.test.ts | 47 ++++++++++++----- .../apm/common/utils/formatters/formatters.ts | 6 +-- .../distribution/index.test.ts | 22 ++++++++ .../distribution/index.tsx | 22 ++++++-- .../transaction_distribution_chart/index.tsx | 49 +++++++----------- 7 files changed, 172 insertions(+), 70 deletions(-) create mode 100644 x-pack/plugins/apm/public/components/app/transaction_details/distribution/index.test.ts diff --git a/x-pack/plugins/apm/common/utils/formatters/duration.test.ts b/x-pack/plugins/apm/common/utils/formatters/duration.test.ts index 42ae4d54bced3..a45582f42b5b2 100644 --- a/x-pack/plugins/apm/common/utils/formatters/duration.test.ts +++ b/x-pack/plugins/apm/common/utils/formatters/duration.test.ts @@ -5,7 +5,12 @@ * 2.0. */ -import { asDuration, toMicroseconds, asMillisecondDuration } from './duration'; +import { + asDuration, + getDurationFormatter, + toMicroseconds, + asMillisecondDuration, +} from './duration'; describe('duration formatters', () => { describe('asDuration', () => { @@ -35,6 +40,50 @@ describe('duration formatters', () => { }); }); + describe('getDurationFormatter', () => { + // Formatting with a default threshold of 10 for more detail for single values + it('formats correctly with defaults', () => { + expect(getDurationFormatter(987654)(987654).formatted).toEqual('988 ms'); + expect(getDurationFormatter(1000000)(1000000).formatted).toEqual( + '1,000 ms' + ); + expect(getDurationFormatter(1234567)(1234567).formatted).toEqual( + '1,235 ms' + ); + expect(getDurationFormatter(9876543)(9876543).formatted).toEqual( + '9,877 ms' + ); + expect(getDurationFormatter(10000000)(10000000).formatted).toEqual( + '10,000 ms' + ); + expect(getDurationFormatter(12345678)(12345678).formatted).toEqual( + '12 s' + ); + }); + + // Formatting useful for axis ticks with a lower threshold where less detail is sufficient + it('formats correctly with a threshold of 0.9999', () => { + expect(getDurationFormatter(987654, 0.9999)(987654).formatted).toEqual( + '988 ms' + ); + expect(getDurationFormatter(1000000, 0.9999)(1000000).formatted).toEqual( + '1 s' + ); + expect(getDurationFormatter(1234567, 0.9999)(1234567).formatted).toEqual( + '1 s' + ); + expect(getDurationFormatter(9876543, 0.9999)(9876543).formatted).toEqual( + '10 s' + ); + expect( + getDurationFormatter(10000000, 0.9999)(10000000).formatted + ).toEqual('10 s'); + expect( + getDurationFormatter(12345678, 0.9999)(12345678).formatted + ).toEqual('12 s'); + }); + }); + describe('toMicroseconds', () => { it('transformes to microseconds', () => { expect(toMicroseconds(1, 'hours')).toEqual(3600000000); diff --git a/x-pack/plugins/apm/common/utils/formatters/duration.ts b/x-pack/plugins/apm/common/utils/formatters/duration.ts index 917521117af4e..bc4d58831ff35 100644 --- a/x-pack/plugins/apm/common/utils/formatters/duration.ts +++ b/x-pack/plugins/apm/common/utils/formatters/duration.ts @@ -33,12 +33,16 @@ export type TimeFormatter = ( options?: FormatterOptions ) => ConvertedDuration; -type TimeFormatterBuilder = (max: number) => TimeFormatter; +type TimeFormatterBuilder = (max: number, threshold?: number) => TimeFormatter; -export function getUnitLabelAndConvertedValue( +// threshold defines the value from which upwards there should be no decimal places. +function getUnitLabelAndConvertedValue( unitKey: DurationTimeUnit, - value: number + value: number, + threshold: number = 10 ) { + const ms = value / 1000; + switch (unitKey) { case 'hours': { return { @@ -46,7 +50,8 @@ export function getUnitLabelAndConvertedValue( defaultMessage: 'h', }), convertedValue: asDecimalOrInteger( - moment.duration(value / 1000).asHours() + moment.duration(ms).asHours(), + threshold ), }; } @@ -56,7 +61,8 @@ export function getUnitLabelAndConvertedValue( defaultMessage: 'min', }), convertedValue: asDecimalOrInteger( - moment.duration(value / 1000).asMinutes() + moment.duration(ms).asMinutes(), + threshold ), }; } @@ -66,7 +72,8 @@ export function getUnitLabelAndConvertedValue( defaultMessage: 's', }), convertedValue: asDecimalOrInteger( - moment.duration(value / 1000).asSeconds() + moment.duration(ms).asSeconds(), + threshold ), }; } @@ -76,7 +83,8 @@ export function getUnitLabelAndConvertedValue( defaultMessage: 'ms', }), convertedValue: asDecimalOrInteger( - moment.duration(value / 1000).asMilliseconds() + moment.duration(ms).asMilliseconds(), + threshold ), }; } @@ -98,10 +106,12 @@ function convertTo({ unit, microseconds, defaultValue = NOT_AVAILABLE_LABEL, + threshold = 10, }: { unit: DurationTimeUnit; microseconds: Maybe; defaultValue?: string; + threshold?: number; }): ConvertedDuration { if (!isFiniteNumber(microseconds)) { return { value: defaultValue, formatted: defaultValue }; @@ -109,7 +119,8 @@ function convertTo({ const { convertedValue, unitLabel } = getUnitLabelAndConvertedValue( unit, - microseconds + microseconds, + threshold ); return { @@ -122,10 +133,7 @@ function convertTo({ export const toMicroseconds = (value: number, timeUnit: TimeUnit) => moment.duration(value, timeUnit).asMilliseconds() * 1000; -export function getDurationUnitKey( - max: number, - threshold = 10 -): DurationTimeUnit { +function getDurationUnitKey(max: number, threshold = 10): DurationTimeUnit { if (max > toMicroseconds(threshold, 'hours')) { return 'hours'; } @@ -141,13 +149,16 @@ export function getDurationUnitKey( return 'microseconds'; } +// memoizer with a custom resolver to consider both arguments max/threshold. +// by default lodash's memoize only considers the first argument. export const getDurationFormatter: TimeFormatterBuilder = memoize( - (max: number) => { - const unit = getDurationUnitKey(max); - return (value, { defaultValue }: FormatterOptions = {}) => { - return convertTo({ unit, microseconds: value, defaultValue }); + (max: number, threshold: number = 10) => { + const unit = getDurationUnitKey(max, threshold); + return (value: Maybe, { defaultValue }: FormatterOptions = {}) => { + return convertTo({ unit, microseconds: value, defaultValue, threshold }); }; - } + }, + (max, threshold) => `${max}_${threshold}` ); export function asTransactionRate(value: Maybe) { diff --git a/x-pack/plugins/apm/common/utils/formatters/formatters.test.ts b/x-pack/plugins/apm/common/utils/formatters/formatters.test.ts index 230912045077d..f876b639c923d 100644 --- a/x-pack/plugins/apm/common/utils/formatters/formatters.test.ts +++ b/x-pack/plugins/apm/common/utils/formatters/formatters.test.ts @@ -36,19 +36,40 @@ describe('formatters', () => { }); describe('asDecimalOrInteger', () => { - it('formats as integer when number equals to 0 ', () => { - expect(asDecimalOrInteger(0)).toEqual('0'); - }); - it('formats as integer when number is above or equals 10 ', () => { - expect(asDecimalOrInteger(10.123)).toEqual('10'); - expect(asDecimalOrInteger(15.123)).toEqual('15'); - }); - it('formats as decimal when number is below 10 ', () => { - expect(asDecimalOrInteger(0.25435632645)).toEqual('0.3'); - expect(asDecimalOrInteger(1)).toEqual('1.0'); - expect(asDecimalOrInteger(3.374329704990765)).toEqual('3.4'); - expect(asDecimalOrInteger(5)).toEqual('5.0'); - expect(asDecimalOrInteger(9)).toEqual('9.0'); + describe('with default threshold of 10', () => { + it('formats as integer when number equals to 0 ', () => { + expect(asDecimalOrInteger(0)).toEqual('0'); + }); + it('formats as integer when number is above or equals 10 ', () => { + expect(asDecimalOrInteger(10.123)).toEqual('10'); + expect(asDecimalOrInteger(15.123)).toEqual('15'); + }); + it('formats as decimal when number is below 10 ', () => { + expect(asDecimalOrInteger(0.25435632645)).toEqual('0.3'); + expect(asDecimalOrInteger(1)).toEqual('1.0'); + expect(asDecimalOrInteger(3.374329704990765)).toEqual('3.4'); + expect(asDecimalOrInteger(5)).toEqual('5.0'); + expect(asDecimalOrInteger(9)).toEqual('9.0'); + }); + }); + + describe('with custom threshold of 1', () => { + it('formats as integer when number equals to 0 ', () => { + expect(asDecimalOrInteger(0, 1)).toEqual('0'); + }); + it('formats as integer when number is above or equals 1 ', () => { + expect(asDecimalOrInteger(1, 1)).toEqual('1'); + expect(asDecimalOrInteger(1.123, 1)).toEqual('1'); + expect(asDecimalOrInteger(3.374329704990765, 1)).toEqual('3'); + expect(asDecimalOrInteger(5, 1)).toEqual('5'); + expect(asDecimalOrInteger(9, 1)).toEqual('9'); + expect(asDecimalOrInteger(10, 1)).toEqual('10'); + expect(asDecimalOrInteger(10.123, 1)).toEqual('10'); + expect(asDecimalOrInteger(15.123, 1)).toEqual('15'); + }); + it('formats as decimal when number is below 1 ', () => { + expect(asDecimalOrInteger(0.25435632645, 1)).toEqual('0.3'); + }); }); }); }); diff --git a/x-pack/plugins/apm/common/utils/formatters/formatters.ts b/x-pack/plugins/apm/common/utils/formatters/formatters.ts index 4da73a6d2c29a..67a259caa2534 100644 --- a/x-pack/plugins/apm/common/utils/formatters/formatters.ts +++ b/x-pack/plugins/apm/common/utils/formatters/formatters.ts @@ -55,9 +55,9 @@ export function asPercent( return numeral(decimal).format('0.0%'); } -export function asDecimalOrInteger(value: number) { - // exact 0 or above 10 should not have decimal - if (value === 0 || value >= 10) { +export function asDecimalOrInteger(value: number, threshold = 10) { + // exact 0 or above threshold should not have decimal + if (value === 0 || value >= threshold) { return asInteger(value); } return asDecimal(value); diff --git a/x-pack/plugins/apm/public/components/app/transaction_details/distribution/index.test.ts b/x-pack/plugins/apm/public/components/app/transaction_details/distribution/index.test.ts new file mode 100644 index 0000000000000..f541c16e655ab --- /dev/null +++ b/x-pack/plugins/apm/public/components/app/transaction_details/distribution/index.test.ts @@ -0,0 +1,22 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { getFormattedSelection } from './index'; + +describe('transaction_details/distribution', () => { + describe('getFormattedSelection', () => { + it('displays only one unit if from and to share the same unit', () => { + expect(getFormattedSelection([10000, 100000])).toEqual('10 - 100 ms'); + }); + + it('displays two units when from and to have different units', () => { + expect(getFormattedSelection([100000, 1000000000])).toEqual( + '100 ms - 17 min' + ); + }); + }); +}); diff --git a/x-pack/plugins/apm/public/components/app/transaction_details/distribution/index.tsx b/x-pack/plugins/apm/public/components/app/transaction_details/distribution/index.tsx index 49d28fec1a136..2506ac69f7aa2 100644 --- a/x-pack/plugins/apm/public/components/app/transaction_details/distribution/index.tsx +++ b/x-pack/plugins/apm/public/components/app/transaction_details/distribution/index.tsx @@ -17,6 +17,7 @@ import { EuiTitle, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; +import { getDurationFormatter } from '../../../../../common/utils/formatters'; import { useUrlParams } from '../../../../context/url_params_context/use_url_params'; import { useApmPluginContext } from '../../../../context/apm_plugin/use_apm_plugin_context'; import { useTransactionDistributionFetcher } from '../../../../hooks/use_transaction_distribution_fetcher'; @@ -28,11 +29,25 @@ import { isErrorMessage } from '../../correlations/utils/is_error_message'; const DEFAULT_PERCENTILE_THRESHOLD = 95; +type Selection = [number, number]; + +// Format the selected latency range for the "Clear selection" badge. +// If the two values share the same unit, it will only displayed once. +// For example: 12 - 23 ms / 12 ms - 3 s +export function getFormattedSelection(selection: Selection): string { + const from = getDurationFormatter(selection[0])(selection[0]); + const to = getDurationFormatter(selection[1])(selection[1]); + + return `${from.unit === to.unit ? from.value : from.formatted} - ${ + to.formatted + }`; +} + interface Props { markerCurrentTransaction?: number; onChartSelection: BrushEndListener; onClearSelection: () => void; - selection?: [number, number]; + selection?: Selection; } export function TransactionDistribution({ @@ -177,10 +192,9 @@ export function TransactionDistribution({ {i18n.translate( 'xpack.apm.transactionDetails.distribution.selectionText', { - defaultMessage: `Selection: {selectionFrom} - {selectionTo}ms`, + defaultMessage: `Selection: {formattedSelection}`, values: { - selectionFrom: Math.round(selection[0] / 1000), - selectionTo: Math.round(selection[1] / 1000), + formattedSelection: getFormattedSelection(selection), }, } )} diff --git a/x-pack/plugins/apm/public/components/shared/charts/transaction_distribution_chart/index.tsx b/x-pack/plugins/apm/public/components/shared/charts/transaction_distribution_chart/index.tsx index 3e8a8cc260a56..c511a708058d3 100644 --- a/x-pack/plugins/apm/public/components/shared/charts/transaction_distribution_chart/index.tsx +++ b/x-pack/plugins/apm/public/components/shared/charts/transaction_distribution_chart/index.tsx @@ -15,11 +15,12 @@ import { CurveType, LineAnnotation, LineAnnotationDatum, + LineAnnotationStyle, Position, RectAnnotation, ScaleType, Settings, - LineAnnotationStyle, + TickFormatter, } from '@elastic/charts'; import { euiPaletteColorBlind } from '@elastic/eui'; @@ -28,10 +29,7 @@ import { i18n } from '@kbn/i18n'; import { useChartTheme } from '../../../../../../observability/public'; -import { - getDurationUnitKey, - getUnitLabelAndConvertedValue, -} from '../../../../../common/utils/formatters'; +import { getDurationFormatter } from '../../../../../common/utils/formatters'; import { HistogramItem } from '../../../../../common/search_strategies/correlations/types'; import { FETCH_STATUS } from '../../../../hooks/use_fetcher'; @@ -39,7 +37,7 @@ import { useTheme } from '../../../../hooks/use_theme'; import { ChartContainer } from '../chart_container'; -interface CorrelationsChartProps { +interface TransactionDistributionChartProps { field?: string; value?: string; histogram?: HistogramItem[]; @@ -90,9 +88,15 @@ export const replaceHistogramDotsWithBars = ( } }; +// Create and call a duration formatter for every value since the durations for the +// x axis might have a wide range of values e.g. from low milliseconds to large seconds. +// This way we can get different suitable units across ticks. +const xAxisTickFormat: TickFormatter = (d) => + getDurationFormatter(d, 0.9999)(d).formatted; + export function TransactionDistributionChart({ - field, - value, + field: fieldName, + value: fieldValue, histogram: originalHistogram, markerCurrentTransaction, markerValue, @@ -100,7 +104,7 @@ export function TransactionDistributionChart({ overallHistogram, onChartSelection, selection, -}: CorrelationsChartProps) { +}: TransactionDistributionChartProps) { const chartTheme = useChartTheme(); const euiTheme = useTheme(); @@ -246,17 +250,7 @@ export function TransactionDistributionChart({ id="x-axis" title="" position={Position.Bottom} - tickFormat={(d) => { - const unit = getDurationUnitKey(d, 1); - const converted = getUnitLabelAndConvertedValue(unit, d); - const convertedValueParts = converted.convertedValue.split('.'); - const convertedValue = - convertedValueParts.length === 2 && - convertedValueParts[1] === '0' - ? convertedValueParts[0] - : converted.convertedValue; - return `${convertedValue}${converted.unitLabel}`; - }} + tickFormat={xAxisTickFormat} gridLine={{ visible: false }} /> {Array.isArray(histogram) && - field !== undefined && - value !== undefined && ( + fieldName !== undefined && + fieldValue !== undefined && ( Date: Fri, 20 Aug 2021 09:55:04 -0400 Subject: [PATCH 19/76] chore(NA): moving @kbn/interpreter to babel transpiler (#108512) (#109410) * chore(NA): moving @kbn/interpreter to babel transpiler * chore(NA): fix imports Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Tiago Costa --- packages/kbn-interpreter/.babelrc | 3 +++ packages/kbn-interpreter/BUILD.bazel | 18 ++++++++++++------ packages/kbn-interpreter/common/package.json | 4 ++-- .../src/common/lib/ast.from_expression.test.js | 2 +- packages/kbn-interpreter/tsconfig.json | 3 ++- .../public/embeddable/embeddable_factory.ts | 2 +- .../metric_visualization/visualization.tsx | 2 +- .../xy_visualization/to_expression.test.ts | 2 +- 8 files changed, 23 insertions(+), 13 deletions(-) create mode 100644 packages/kbn-interpreter/.babelrc diff --git a/packages/kbn-interpreter/.babelrc b/packages/kbn-interpreter/.babelrc new file mode 100644 index 0000000000000..7da72d1779128 --- /dev/null +++ b/packages/kbn-interpreter/.babelrc @@ -0,0 +1,3 @@ +{ + "presets": ["@kbn/babel-preset/node_preset"] +} diff --git a/packages/kbn-interpreter/BUILD.bazel b/packages/kbn-interpreter/BUILD.bazel index 903f892b64f3f..52df0f0aa8d85 100644 --- a/packages/kbn-interpreter/BUILD.bazel +++ b/packages/kbn-interpreter/BUILD.bazel @@ -1,6 +1,7 @@ load("@npm//@bazel/typescript:index.bzl", "ts_config", "ts_project") load("@npm//peggy:index.bzl", "peggy") load("@build_bazel_rules_nodejs//:index.bzl", "js_library", "pkg_npm") +load("//src/dev/bazel:index.bzl", "jsts_transpiler") PKG_BASE_NAME = "kbn-interpreter" PKG_REQUIRE_NAME = "@kbn/interpreter" @@ -25,7 +26,7 @@ NPM_MODULE_EXTRA_FILES = [ "package.json", ] -SRC_DEPS = [ +RUNTIME_DEPS = [ "@npm//lodash", ] @@ -35,7 +36,11 @@ TYPES_DEPS = [ "@npm//@types/node", ] -DEPS = SRC_DEPS + TYPES_DEPS +jsts_transpiler( + name = "target_node", + srcs = SRCS, + build_pkg_name = package_name(), +) peggy( name = "grammar", @@ -62,14 +67,15 @@ ts_config( ) ts_project( - name = "tsc", + name = "tsc_types", args = ['--pretty'], srcs = SRCS, - deps = DEPS, + deps = TYPES_DEPS, allow_js = True, declaration = True, declaration_map = True, - out_dir = "target", + emit_declaration_only = True, + out_dir = "target_types", source_map = True, root_dir = "src", tsconfig = ":tsconfig", @@ -78,7 +84,7 @@ ts_project( js_library( name = PKG_BASE_NAME, srcs = NPM_MODULE_EXTRA_FILES + [":grammar"], - deps = DEPS + [":tsc"], + deps = RUNTIME_DEPS + [":target_node", ":tsc_types"], package_name = PKG_REQUIRE_NAME, visibility = ["//visibility:public"], ) diff --git a/packages/kbn-interpreter/common/package.json b/packages/kbn-interpreter/common/package.json index 2f5277a8e8652..6d03f2e1c6236 100644 --- a/packages/kbn-interpreter/common/package.json +++ b/packages/kbn-interpreter/common/package.json @@ -1,5 +1,5 @@ { "private": true, - "main": "../target/common/index.js", - "types": "../target/common/index.d.ts" + "main": "../target_node/common/index.js", + "types": "../target_types/common/index.d.ts" } \ No newline at end of file diff --git a/packages/kbn-interpreter/src/common/lib/ast.from_expression.test.js b/packages/kbn-interpreter/src/common/lib/ast.from_expression.test.js index 608fe63b0b825..ae35a14482324 100644 --- a/packages/kbn-interpreter/src/common/lib/ast.from_expression.test.js +++ b/packages/kbn-interpreter/src/common/lib/ast.from_expression.test.js @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { fromExpression } from '@kbn/interpreter/target/common/lib/ast'; +import { fromExpression } from '@kbn/interpreter/common'; import { getType } from './get_type'; describe('ast fromExpression', () => { diff --git a/packages/kbn-interpreter/tsconfig.json b/packages/kbn-interpreter/tsconfig.json index 74ec484ea63e9..60f8c76cf8809 100644 --- a/packages/kbn-interpreter/tsconfig.json +++ b/packages/kbn-interpreter/tsconfig.json @@ -2,9 +2,10 @@ "extends": "../../tsconfig.bazel.json", "compilerOptions": { "allowJs": true, - "outDir": "./target/types", "declaration": true, "declarationMap": true, + "emitDeclarationOnly": true, + "outDir": "./target_types", "rootDir": "src", "sourceMap": true, "sourceRoot": "../../../../packages/kbn-interpreter/src", diff --git a/x-pack/plugins/lens/public/embeddable/embeddable_factory.ts b/x-pack/plugins/lens/public/embeddable/embeddable_factory.ts index dcb72455e0ee9..ca9d830816dbc 100644 --- a/x-pack/plugins/lens/public/embeddable/embeddable_factory.ts +++ b/x-pack/plugins/lens/public/embeddable/embeddable_factory.ts @@ -8,7 +8,7 @@ import type { Capabilities, HttpSetup } from 'kibana/public'; import { i18n } from '@kbn/i18n'; import { RecursiveReadonly } from '@kbn/utility-types'; -import { Ast } from '@kbn/interpreter/target/common'; +import { Ast } from '@kbn/interpreter/common'; import { UsageCollectionSetup } from 'src/plugins/usage_collection/public'; import { IndexPatternsContract, TimefilterContract } from '../../../../../src/plugins/data/public'; import { ReactExpressionRendererType } from '../../../../../src/plugins/expressions/public'; diff --git a/x-pack/plugins/lens/public/metric_visualization/visualization.tsx b/x-pack/plugins/lens/public/metric_visualization/visualization.tsx index 72aa3550e30dd..d832848db06f6 100644 --- a/x-pack/plugins/lens/public/metric_visualization/visualization.tsx +++ b/x-pack/plugins/lens/public/metric_visualization/visualization.tsx @@ -6,7 +6,7 @@ */ import { i18n } from '@kbn/i18n'; -import { Ast } from '@kbn/interpreter/target/common'; +import { Ast } from '@kbn/interpreter/common'; import { getSuggestions } from './metric_suggestions'; import { LensIconChartMetric } from '../assets/chart_metric'; import { Visualization, OperationMetadata, DatasourcePublicAPI } from '../types'; diff --git a/x-pack/plugins/lens/public/xy_visualization/to_expression.test.ts b/x-pack/plugins/lens/public/xy_visualization/to_expression.test.ts index 5ce44db1c4db5..80808a4055f26 100644 --- a/x-pack/plugins/lens/public/xy_visualization/to_expression.test.ts +++ b/x-pack/plugins/lens/public/xy_visualization/to_expression.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { Ast } from '@kbn/interpreter/target/common'; +import { Ast } from '@kbn/interpreter/common'; import { Position } from '@elastic/charts'; import { chartPluginMock } from '../../../../../src/plugins/charts/public/mocks'; import { getXyVisualization } from './xy_visualization'; From 878d6e8978fb6dccbfb1f0618d0fa4ce8b35c6df Mon Sep 17 00:00:00 2001 From: Mikhail Shustov Date: Fri, 20 Aug 2021 17:27:33 +0300 Subject: [PATCH 20/76] exclude tsx test and mock files from test coverage (#109203) (#109264) # Conflicts: # packages/kbn-test/jest-preset.js Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- packages/kbn-test/jest-preset.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/kbn-test/jest-preset.js b/packages/kbn-test/jest-preset.js index a52de37fb2008..0199aa6e311b6 100644 --- a/packages/kbn-test/jest-preset.js +++ b/packages/kbn-test/jest-preset.js @@ -103,11 +103,11 @@ module.exports = { // An array of regexp pattern strings that are matched against all source file paths, matched files to include/exclude for code coverage collectCoverageFrom: [ '**/*.{js,mjs,jsx,ts,tsx}', - '!**/{__test__,__snapshots__,__examples__,mocks,tests,test_helpers,integration_tests,types}/**/*', - '!**/*mock*.ts', - '!**/*.test.ts', + '!**/{__test__,__snapshots__,__examples__,*mock*,tests,test_helpers,integration_tests,types}/**/*', + '!**/*mock*.{ts,tsx}', + '!**/*.test.{ts,tsx}', '!**/*.d.ts', - '!**/index.{js,ts}', + '!**/index.{js,ts,tsx}', ], // A custom resolver to preserve symlinks by default From f797bd08ebc92cfaa8ea8dc86519a4a63322961c Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Fri, 20 Aug 2021 10:33:58 -0400 Subject: [PATCH 21/76] [Maps] fix edit layer settings action showing when readonly (#109321) (#109434) * [Maps] fix edit layer settings action showing when readonly * remove unneeded file Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Nathan Reese --- .../toc_entry_actions_popover.test.tsx.snap | 11 ---------- .../toc_entry_actions_popover.tsx | 22 +++++++++---------- 2 files changed, 11 insertions(+), 22 deletions(-) diff --git a/x-pack/plugins/maps/public/connected_components/right_side_controls/layer_control/layer_toc/toc_entry/toc_entry_actions_popover/__snapshots__/toc_entry_actions_popover.test.tsx.snap b/x-pack/plugins/maps/public/connected_components/right_side_controls/layer_control/layer_toc/toc_entry/toc_entry_actions_popover/__snapshots__/toc_entry_actions_popover.test.tsx.snap index 6531b8a2f2501..1fdae3b596e00 100644 --- a/x-pack/plugins/maps/public/connected_components/right_side_controls/layer_control/layer_toc/toc_entry/toc_entry_actions_popover/__snapshots__/toc_entry_actions_popover.test.tsx.snap +++ b/x-pack/plugins/maps/public/connected_components/right_side_controls/layer_control/layer_toc/toc_entry/toc_entry_actions_popover/__snapshots__/toc_entry_actions_popover.test.tsx.snap @@ -535,17 +535,6 @@ exports[`TOCEntryActionsPopover should not show edit actions in read only mode 1 "onClick": [Function], "toolTipContent": null, }, - Object { - "data-test-subj": "layerSettingsButton", - "disabled": false, - "icon": , - "name": "Edit layer settings", - "onClick": [Function], - "toolTipContent": null, - }, ], "title": "Layer actions", }, diff --git a/x-pack/plugins/maps/public/connected_components/right_side_controls/layer_control/layer_toc/toc_entry/toc_entry_actions_popover/toc_entry_actions_popover.tsx b/x-pack/plugins/maps/public/connected_components/right_side_controls/layer_control/layer_toc/toc_entry/toc_entry_actions_popover/toc_entry_actions_popover.tsx index ed0946e526c80..322c0540528d7 100644 --- a/x-pack/plugins/maps/public/connected_components/right_side_controls/layer_control/layer_toc/toc_entry/toc_entry_actions_popover/toc_entry_actions_popover.tsx +++ b/x-pack/plugins/maps/public/connected_components/right_side_controls/layer_control/layer_toc/toc_entry/toc_entry_actions_popover/toc_entry_actions_popover.tsx @@ -174,19 +174,19 @@ export class TOCEntryActionsPopover extends Component { }, }); } - actionItems.push({ - disabled: this.props.isEditButtonDisabled, - name: EDIT_LAYER_SETTINGS_LABEL, - icon: , - 'data-test-subj': 'layerSettingsButton', - toolTipContent: null, - onClick: () => { - this._closePopover(); - this.props.openLayerSettings(); - }, - }); if (!this.props.isReadOnly) { + actionItems.push({ + disabled: this.props.isEditButtonDisabled, + name: EDIT_LAYER_SETTINGS_LABEL, + icon: , + 'data-test-subj': 'layerSettingsButton', + toolTipContent: null, + onClick: () => { + this._closePopover(); + this.props.openLayerSettings(); + }, + }); if (this.state.supportsFeatureEditing) { actionItems.push({ name: EDIT_FEATURES_LABEL, From 80127a748711ec30804aeefba3710d8a9c8f5190 Mon Sep 17 00:00:00 2001 From: Rudolf Meijering Date: Fri, 20 Aug 2021 16:37:44 +0200 Subject: [PATCH 22/76] v2 migration algorithm docs for rewriting saved object id's (#93002) (#109472) * Document v2 migration algorithm using control state names from source code * v2 migrations support for rewriting document _id's * Minor edits and clarifications * Fix markdown formatting * Review comments: improve algorithm description * add WAIT_FOR_YELLOW_SOURCE step Co-authored-by: restrry # Conflicts: # rfcs/text/0013_saved_object_migrations.md --- rfcs/text/0013_saved_object_migrations.md | 824 ++++++++++++++++++ .../saved_objects/migrationsv2/README.md | 382 +++++++- 2 files changed, 1185 insertions(+), 21 deletions(-) create mode 100644 rfcs/text/0013_saved_object_migrations.md diff --git a/rfcs/text/0013_saved_object_migrations.md b/rfcs/text/0013_saved_object_migrations.md new file mode 100644 index 0000000000000..2f7ed796bf0e6 --- /dev/null +++ b/rfcs/text/0013_saved_object_migrations.md @@ -0,0 +1,824 @@ +- Start Date: 2020-05-11 +- RFC PR: (leave this empty) +- Kibana Issue: (leave this empty) + +--- +- [1. Summary](#1-summary) +- [2. Motivation](#2-motivation) +- [3. Saved Object Migration Errors](#3-saved-object-migration-errors) +- [4. Design](#4-design) + - [4.0 Assumptions and tradeoffs](#40-assumptions-and-tradeoffs) + - [4.1 Discover and remedy potential failures before any downtime](#41-discover-and-remedy-potential-failures-before-any-downtime) + - [4.2 Automatically retry failed migrations until they succeed](#42-automatically-retry-failed-migrations-until-they-succeed) + - [4.2.1 Idempotent migrations performed without coordination](#421-idempotent-migrations-performed-without-coordination) + - [4.2.1.1 Restrictions](#4211-restrictions) + - [4.2.1.2 Migration algorithm: Cloned index per version](#4212-migration-algorithm-cloned-index-per-version) + - [Known weaknesses:](#known-weaknesses) + - [4.2.1.3 Upgrade and rollback procedure](#4213-upgrade-and-rollback-procedure) + - [4.2.1.4 Handling documents that belong to a disabled plugin](#4214-handling-documents-that-belong-to-a-disabled-plugin) +- [5. Alternatives](#5-alternatives) + - [5.1 Rolling upgrades](#51-rolling-upgrades) + - [5.2 Single node migrations coordinated through a lease/lock](#52-single-node-migrations-coordinated-through-a-leaselock) + - [5.2.1 Migration algorithm](#521-migration-algorithm) + - [5.2.2 Document lock algorithm](#522-document-lock-algorithm) + - [5.2.3 Checking for "weak lease" expiry](#523-checking-for-weak-lease-expiry) + - [5.3 Minimize data loss with mixed Kibana versions during 7.x](#53-minimize-data-loss-with-mixed-kibana-versions-during-7x) + - [5.4 In-place migrations that re-use the same index (8.0)](#54-in-place-migrations-that-re-use-the-same-index-80) + - [5.4.1 Migration algorithm (8.0):](#541-migration-algorithm-80) + - [5.4.2 Minimizing data loss with unsupported upgrade configurations (8.0)](#542-minimizing-data-loss-with-unsupported-upgrade-configurations-80) + - [5.5 Tag objects as “invalid” if their transformation fails](#55-tag-objects-as-invalid-if-their-transformation-fails) +- [6. How we teach this](#6-how-we-teach-this) +- [7. Unresolved questions](#7-unresolved-questions) + +# 1. Summary + +Improve the Saved Object migration algorithm to ensure a smooth Kibana upgrade +procedure. + +# 2. Motivation + +Kibana version upgrades should have a minimal operational impact. To achieve +this, users should be able to rely on: + +1. A predictable downtime window. +2. A small downtime window. + 1. (future) provide a small downtime window on indices with 10k or even + a 100k documents. +3. The ability to discover and remedy potential failures before initiating the + downtime window. +4. Quick roll-back in case of failure. +5. Detailed documentation about the impact of downtime on the features they + are using (e.g. actions, task manager, fleet, reporting). +6. Mixed Kibana versions shouldn’t cause data loss. +7. (stretch goal) Maintain read-only functionality during the downtime window. + +The biggest hurdle to achieving the above is Kibana’s Saved Object migrations. +Migrations aren’t resilient and require manual intervention anytime an error +occurs (see [3. Saved Object Migration +Errors](#3-saved-object-migration-errors)). + +It is impossible to discover these failures before initiating downtime. Errors +often force users to roll-back to a previous version of Kibana or cause hours +of downtime. To retry the migration, users are asked to manually delete a +`.kibana_x` index. If done incorrectly this can lead to data loss, making it a +terrifying experience (restoring from a pre-upgrade snapshot is a safer +alternative but not mentioned in the docs or logs). + +Cloud users don’t have access to Kibana logs to be able to identify and remedy +the cause of the migration failure. Apart from blindly retrying migrations by +restoring a previous snapshot, cloud users are unable to remedy a failed +migration and have to escalate to support which can further delay resolution. + +Taken together, version upgrades are a major operational risk and discourage +users from adopting the latest features. + +# 3. Saved Object Migration Errors + +Any of the following classes of errors could result in a Saved Object +migration failure which requires manual intervention to resolve: + +1. A bug in a plugin’s registered document transformation function causes it + to throw an exception on _valid_ data. +2. _Invalid_ data stored in Elasticsearch causes a plugin’s registered + document transformation function to throw an exception . +3. Failures resulting from an unhealthy Elasticsearch cluster: + 1. Maximum shards open + 2. Too many scroll contexts + 3. `circuit_breaking_exception` (insufficient heap memory) + 4. `process_cluster_event_timeout_exception` for index-aliases, create-index, put-mappings + 5. Read-only indices due to low disk space (hitting the flood_stage watermark) + 6. Re-index failed: search rejected due to missing shards + 7. `TooManyRequests` while doing a `count` of documents requiring a migration + 8. Bulk write failed: primary shard is not active +4. The Kibana process is killed while migrations are in progress. + +# 4. Design +## 4.0 Assumptions and tradeoffs +The proposed design makes several important assumptions and tradeoffs. + +**Background:** + +The 7.x upgrade documentation lists taking an Elasticsearch snapshot as a +required step, but we instruct users to retry migrations and perform rollbacks +by deleting the failed `.kibana_n` index and pointing the `.kibana` alias to +`.kibana_n-1`: + - [Handling errors during saved object +migrations.](https://github.com/elastic/kibana/blob/75444a9f1879c5702f9f2b8ad4a70a3a0e75871d/docs/setup/upgrade/upgrade-migrations.asciidoc#handling-errors-during-saved-object-migrations) + - [Rolling back to a previous version of Kibana.](https://github.com/elastic/kibana/blob/75444a9f1879c5702f9f2b8ad4a70a3a0e75871d/docs/setup/upgrade/upgrade-migrations.asciidoc#rolling-back-to-a-previous-version-of-kib) + - Server logs from failed migrations. + +**Assumptions and tradeoffs:** +1. It is critical to maintain a backup index during 7.x to ensure that anyone + following the existing upgrade / rollback procedures don't end up in a + position where they no longer can recover their data. + 1. This excludes us from introducing in-place migrations to support huge + indices during 7.x. +2. The simplicity of idempotent, coordination-free migrations outweighs the + restrictions this will impose on the kinds of migrations we're able to + support in the future. See (4.2.1) +3. A saved object type (and it's associated migrations) will only ever be + owned by one plugin. If pluginA registers saved object type `plugin_a_type` + then pluginB must never register that same type, even if pluginA is + disabled. Although we cannot enforce it on third-party plugins, breaking + this assumption may lead to data loss. + +## 4.1 Discover and remedy potential failures before any downtime + +> Achieves goals: (2.3) +> Mitigates errors: (3.1), (3.2) + +1. Introduce a CLI option to perform a dry run migration to allow + administrators to locate and fix potential migration failures without + taking their existing Kibana node(s) offline. +2. To have the highest chance of surfacing potential failures such as low disk + space, dry run migrations should not be mere simulations. A dry run should + perform a real migration in a way that doesn’t impact the existing Kibana + cluster. +3. The CLI should generate a migration report to make it easy to create a + support request from a failed migration dry run. + 1. The report would be an NDJSON export of all failed objects. + 2. If support receives such a report, we could modify all the objects to + ensure the migration would pass and send this back to the client. + 3. The client can then import the updated objects using the standard Saved + Objects NDJSON import and run another dry run to verify all problems + have been fixed. +4. Make running dry run migrations a required step in the upgrade procedure + documentation. +5. (Optional) Add dry run migrations to the standard cloud upgrade procedure? + +## 4.2 Automatically retry failed migrations until they succeed + +> Achieves goals: (2.2), (2.6) +> Mitigates errors (3.3) and (3.4) + +External conditions such as failures from an unhealthy Elasticsearch cluster +(3.3) can cause the migration to fail. The Kibana cluster should be able to +recover automatically once these external conditions are resolved. There are +two broad approaches to solving this problem based on whether or not +migrations are idempotent: + +| Idempotent migrations |Description | +| --------------------- | --------------------------------------------------------- | +| Yes | Idempotent migrations performed without coordination | +| No | Single node migrations coordinated through a lease / lock | + +Idempotent migrations don't require coordination making the algorithm +significantly less complex and will never require manual intervention to +retry. We, therefore, prefer this solution, even though it introduces +restrictions on migrations (4.2.1.1). For other alternatives that were +considered see section [(5)](#5-alternatives). + +## 4.2.1 Idempotent migrations performed without coordination + +The migration system can be said to be idempotent if the same results are +produced whether the migration was run once or multiple times. This property +should hold even if new (up to date) writes occur in between migration runs +which introduces the following restrictions: + +### 4.2.1.1 Restrictions + +1. All document transforms need to be deterministic, that is a document + transform will always return the same result for the same set of inputs. +2. It should always be possible to construct the exact set of inputs required + for (1) at any point during the migration process (before, during, after). + +Although these restrictions require significant changes, it does not prevent +known upcoming migrations such as [sharing saved-objects in multiple spaces](https://github.com/elastic/kibana/issues/27004) or [splitting a saved +object into multiple child +documents](https://github.com/elastic/kibana/issues/26602). To ensure that +these migrations are idempotent, they will have to generate new saved object +id's deterministically with e.g. UUIDv5. + + +### 4.2.1.2 Migration algorithm: Cloned index per version +Note: +- The description below assumes the migration algorithm is released in 7.10.0. + So >= 7.10.0 will use the new algorithm. +- We refer to the alias and index that outdated nodes use as the source alias + and source index. +- Every version performs a migration even if mappings or documents aren't outdated. + +1. Locate the source index by fetching kibana indices: + + ``` + GET '/_indices/.kibana,.kibana_7.10.0' + ``` + + The source index is: + 1. the index the `.kibana` alias points to, or if it doesn't exist, + 2. the v6.x `.kibana` index + + If none of the aliases exists, this is a new Elasticsearch cluster and no + migrations are necessary. Create the `.kibana_7.10.0_001` index with the + following aliases: `.kibana` and `.kibana_7.10.0`. +2. If the source is a < v6.5 `.kibana` index or < 7.4 `.kibana_task_manager` + index prepare the legacy index for a migration: + 1. Mark the legacy index as read-only and wait for all in-flight operations to drain (requires https://github.com/elastic/elasticsearch/pull/58094). This prevents any further writes from outdated nodes. Assuming this API is similar to the existing `//_close` API, we expect to receive `"acknowledged" : true` and `"shards_acknowledged" : true`. If all shards don’t acknowledge within the timeout, retry the operation until it succeeds. + 2. Create a new index which will become the source index after the legacy + pre-migration is complete. This index should have the same mappings as + the legacy index. Use a fixed index name i.e `.kibana_pre6.5.0_001` or + `.kibana_task_manager_pre7.4.0_001`. Ignore index already exists errors. + 3. Reindex the legacy index into the new source index with the + `convertToAlias` script if specified. Use `wait_for_completion: false` + to run this as a task. Ignore errors if the legacy source doesn't exist. + 4. Wait for the reindex task to complete. If the task doesn’t complete + within the 60s timeout, log a warning for visibility and poll again. + Ignore errors if the legacy source doesn't exist. + 5. Delete the legacy index and replace it with an alias of the same name + ``` + POST /_aliases + { + "actions" : [ + { "remove_index": { "index": ".kibana" } } + { "add": { "index": ".kibana_pre6.5.0_001", "alias": ".kibana" } }, + ] + } + ```. + Unlike the delete index API, the `remove_index` action will fail if + provided with an _alias_. Therefore, if another instance completed this + step, the `.kibana` alias won't be added to `.kibana_pre6.5.0_001` a + second time. This avoids a situation where `.kibana` could point to both + `.kibana_pre6.5.0_001` and `.kibana_7.10.0_001`. These actions are + applied atomically so that other Kibana instances will always see either + a `.kibana` index or an alias, but never neither. + + Ignore "The provided expression [.kibana] matches an alias, specify the + corresponding concrete indices instead." or "index_not_found_exception" + errors as this means another instance has already completed this step. + 6. Use the reindexed legacy `.kibana_pre6.5.0_001` as the source for the rest of the migration algorithm. +3. If `.kibana` and `.kibana_7.10.0` both exists and are pointing to the same index this version's migration has already been completed. + 1. Because the same version can have plugins enabled at any point in time, + migrate outdated documents with step (9) and perform the mappings update in step (10). + 2. Skip to step (12) to start serving traffic. +4. Fail the migration if: + 1. `.kibana` is pointing to an index that belongs to a later version of Kibana .e.g. `.kibana_7.12.0_001` + 2. (Only in 8.x) The source index contains documents that belong to an unknown Saved Object type (from a disabled plugin). Log an error explaining that the plugin that created these documents needs to be enabled again or that these objects should be deleted. See section (4.2.1.4). +5. Set a write block on the source index. This prevents any further writes from outdated nodes. +6. Create a new temporary index `.kibana_7.10.0_reindex_temp` with `dynamic: false` on the top-level mappings so that any kind of document can be written to the index. This allows us to write untransformed documents to the index which might have fields which have been removed from the latest mappings defined by the plugin. Define minimal mappings for the `migrationVersion` and `type` fields so that we're still able to search for outdated documents that need to be transformed. + 1. Ignore errors if the target index already exists. +7. Reindex the source index into the new temporary index. + 1. Use `op_type=create` `conflicts=proceed` and `wait_for_completion=false` so that multiple instances can perform the reindex in parallel but only one write per document will succeed. + 2. Wait for the reindex task to complete. If reindexing doesn’t complete within the 60s timeout, log a warning for visibility and poll again. +8. Clone the temporary index into the target index `.kibana_7.10.0_001`. Since any further writes will only happen against the cloned target index this prevents a lost delete from occuring where one instance finishes the migration and deletes a document and another instance's reindex operation re-creates the deleted document. + 1. Set a write block on the temporary index + 2. Clone the temporary index into the target index while specifying that the target index should have writes enabled. + 3. If the clone operation fails because the target index already exist, ignore the error and wait for the target index to become green before proceeding. + 4. (The `001` postfix in the target index name isn't used by Kibana, but allows for re-indexing an index should this be required by an Elasticsearch upgrade. E.g. re-index `.kibana_7.10.0_001` into `.kibana_7.10.0_002` and point the `.kibana_7.10.0` alias to `.kibana_7.10.0_002`.) +9. Transform documents by reading batches of outdated documents from the target index then transforming and updating them with optimistic concurrency control. + 1. Ignore any version conflict errors. + 2. If a document transform throws an exception, add the document to a failure list and continue trying to transform all other documents. If any failures occured, log the complete list of documents that failed to transform. Fail the migration. +10. Update the mappings of the target index + 1. Retrieve the existing mappings including the `migrationMappingPropertyHashes` metadata. + 2. Update the mappings with `PUT /.kibana_7.10.0_001/_mapping`. The API deeply merges any updates so this won't remove the mappings of any plugins that are disabled on this instance but have been enabled on another instance that also migrated this index. + 3. Ensure that fields are correctly indexed using the target index's latest mappings `POST /.kibana_7.10.0_001/_update_by_query?conflicts=proceed`. In the future we could optimize this query by only targeting documents: + 1. That belong to a known saved object type. +11. Mark the migration as complete. This is done as a single atomic + operation (requires https://github.com/elastic/elasticsearch/pull/58100) + to guarantee that when multiple versions of Kibana are performing the + migration in parallel, only one version will win. E.g. if 7.11 and 7.12 + are started in parallel and migrate from a 7.9 index, either 7.11 or 7.12 + should succeed and accept writes, but not both. + 1. Check that `.kibana` alias is still pointing to the source index + 2. Point the `.kibana_7.10.0` and `.kibana` aliases to the target index. + 3. Remove the temporary index `.kibana_7.10.0_reindex_temp` + 4. If this fails with a "required alias [.kibana] does not exist" error or "index_not_found_exception" for the temporary index, fetch `.kibana` again: + 1. If `.kibana` is _not_ pointing to our target index fail the migration. + 2. If `.kibana` is pointing to our target index the migration has succeeded and we can proceed to step (12). +12. Start serving traffic. All saved object reads/writes happen through the + version-specific alias `.kibana_7.10.0`. + +Together with the limitations, this algorithm ensures that migrations are +idempotent. If two nodes are started simultaneously, both of them will start +transforming documents in that version's target index, but because migrations +are idempotent, it doesn’t matter which node’s writes win. +#### Known weaknesses: +(Also present in our existing migration algorithm since v7.4) +When the task manager index gets reindexed a reindex script is applied. +Because we delete the original task manager index there is no way to rollback +a failed task manager migration without a snapshot. Although losing the task +manager data has a fairly low impact. + +(Also present in our existing migration algorithm since v6.5) +If the outdated instance isn't shutdown before starting the migration, the +following data-loss scenario is possible: +1. Upgrade a 7.9 index without shutting down the 7.9 nodes +2. Kibana v7.10 performs a migration and after completing points `.kibana` + alias to `.kibana_7.11.0_001` +3. Kibana v7.9 writes unmigrated documents into `.kibana`. +4. Kibana v7.10 performs a query based on the updated mappings of documents so + results potentially don't match the acknowledged write from step (3). + +Note: + - Data loss won't occur if both nodes have the updated migration algorithm + proposed in this RFC. It is only when one of the nodes use the existing + algorithm that data loss is possible. + - Once v7.10 is restarted it will transform any outdated documents making + these visible to queries again. + +It is possible to work around this weakness by introducing a new alias such as +`.kibana_current` so that after a migration the `.kibana` alias will continue +to point to the outdated index. However, we decided to keep using the +`.kibana` alias despite this weakness for the following reasons: + - Users might rely on `.kibana` alias for snapshots, so if this alias no + longer points to the latest index their snapshots would no longer backup + kibana's latest data. + - Introducing another alias introduces complexity for users and support. + The steps to diagnose, fix or rollback a failed migration will deviate + depending on the 7.x version of Kibana you are using. + - The existing Kibana documentation clearly states that outdated nodes should + be shutdown, this scenario has never been supported by Kibana. + +
+ In the future, this algorithm could enable (2.6) "read-only functionality during the downtime window" but this is outside of the scope of this RFC. + + Although the migration algorithm guarantees there's no data loss while providing read-only access to outdated nodes, this could cause plugins to behave in unexpected ways. If we wish to persue it in the future, enabling read-only functionality during the downtime window will be it's own project and must include an audit of all plugins' behaviours. +
+ +### 4.2.1.3 Upgrade and rollback procedure +When a newer Kibana starts an upgrade, it blocks all writes to the outdated index to prevent data loss. Since Kibana is not designed to gracefully handle a read-only index this could have unintended consequences such as a task executing multiple times but never being able to write that the task was completed successfully. To prevent unintended consequences, the following procedure should be followed when upgrading Kibana: + +1. Gracefully shutdown outdated nodes by sending a `SIGTERM` signal + 1. Node starts returning `503` from it's healthcheck endpoint to signal to + the load balancer that it's no longer accepting new traffic (requires https://github.com/elastic/kibana/issues/46984). + 2. Allows ungoing HTTP requests to complete with a configurable timeout + before forcefully terminating any open connections. + 3. Closes any keep-alive sockets by sending a `connection: close` header. + 4. Shutdown all plugins and Core services. +2. (recommended) Take a snapshot of all Kibana's Saved Objects indices. This simplifies doing a rollback to a simple snapshot restore, but is not required in order to do a rollback if a migration fails. +3. Start the upgraded Kibana nodes. All running Kibana nodes should be on the same version, have the same plugins enabled and use the same configuration. + +To rollback to a previous version of Kibana with a snapshot +1. Shutdown all Kibana nodes. +2. Restore the Saved Object indices and aliases from the snapshot +3. Start the rollback Kibana nodes. All running Kibana nodes should be on the same rollback version, have the same plugins enabled and use the same configuration. + +To rollback to a previous version of Kibana without a snapshot: +(Assumes the migration to 7.11.0 failed) +1. Shutdown all Kibana nodes. +2. Remove the index created by the failed Kibana migration by using the version-specific alias e.g. `DELETE /.kibana_7.11.0` +3. Remove the write block from the rollback index using the `.kibana` alias + `PUT /.kibana/_settings {"index.blocks.write": false}` +4. Start the rollback Kibana nodes. All running Kibana nodes should be on the same rollback version, have the same plugins enabled and use the same configuration. + +### 4.2.1.4 Handling documents that belong to a disabled plugin +It is possible for a plugin to create documents in one version of Kibana, but then when upgrading Kibana to a newer version, that plugin is disabled. Because the plugin is disabled it cannot register it's Saved Objects type including the mappings or any migration transformation functions. These "orphan" documents could cause future problems: + - A major version introduces breaking mapping changes that cannot be applied to the data in these documents. + - Two majors later migrations will no longer be able to migrate this old schema and could fail unexpectadly when the plugin is suddenly enabled. + +As a concrete example of the above, consider a user taking the following steps: +1. Installs Kibana 7.6.0 with spaces=enabled. The spaces plugin creates a default space saved object. +2. User upgrades to 7.10.0 but uses the OSS download which has spaces=disabled. Although the 7.10.0 spaces plugin includes a migration for space documents, the OSS release cannot migrate the documents or update it's mappings. +3. User realizes they made a mistake and use Kibana 7.10.0 with x-pack and the spaces plugin enabled. At this point we have a completed migration for 7.10.0 but there's outdated spaces documents with migrationVersion=7.6.0 instead of 7.10.0. + +There are several approaches we could take to dealing with these orphan documents: + +1. Start up but refuse to query on types with outdated documents until a user manually triggers a re-migration + + Advantages: + - The impact is limited to a single plugin + + Disadvantages: + - It might be less obvious that a plugin is in a degraded state unless you read the logs (not possible on Cloud) or view the `/status` endpoint. + - If a user doesn't care that the plugin is degraded, orphan documents are carried forward indefinitely. + - Since Kibana has started receiving traffic, users can no longer + downgrade without losing data. They have to re-migrate, but if that + fails they're stuck. + - Introduces a breaking change in the upgrade behaviour + + To perform a re-migration: + - Remove the `.kibana_7.10.0` alias + - Take a snapshot OR set the configuration option `migrations.target_index_postfix: '002'` to create a new target index `.kibana_7.10.0_002` and keep the `.kibana_7.10.0_001` index to be able to perform a rollback. + - Start up Kibana + +2. Refuse to start Kibana until the plugin is enabled or it's data deleted + + Advantages: + - Admin’s are forced to deal with the problem as soon as they disable a plugin + + Disadvantages: + - Cannot temporarily disable a plugin to aid in debugging or to reduce the load a Kibana plugin places on an ES cluster. + - Introduces a breaking change + +3. Refuse to start a migration until the plugin is enabled or it's data deleted + + Advantages: + - We force users to enable a plugin or delete the documents which prevents these documents from creating future problems like a mapping update not being compatible because there are fields which are assumed to have been migrated. + - We keep the index “clean”. + + Disadvantages: + - Since users have to take down outdated nodes before they can start the upgrade, they have to enter the downtime window before they know about this problem. This prolongs the downtime window and in many cases might cause an operations team to have to reschedule their downtime window to give them time to investigate the documents that need to be deleted. Logging an error on every startup could warn users ahead of time to mitigate this. + - We don’t expose Kibana logs on Cloud so this will have to be escalated to support and could take 48hrs to resolve (users can safely rollback, but without visibility into the logs they might not know this). Exposing Kibana logs is on the cloud team’s roadmap. + - It might not be obvious just from the saved object type, which plugin created these objects. + - Introduces a breaking change in the upgrade behaviour + +4. Use a hash of enabled plugins as part of the target index name + Using a migration target index name like + `.kibana_7.10.0_${hash(enabled_plugins)}_001` we can migrate all documents + every time a plugin is enabled / disabled. + + Advantages: + - Outdated documents belonging to disabled plugins will be upgraded as soon + as the plugin is enabled again. + + Disadvantages: + - Disabling / enabling a plugin will cause downtime (breaking change). + - When a plugin is enabled, disabled and enabled again our target index + will be an existing outdated index which needs to be deleted and + re-cloned. Without a way to check if the index is outdated, we cannot + deterministically perform the delete and re-clone operation without + coordination. + +5. Transform outdated documents (step 8) on every startup + Advantages: + - Outdated documents belonging to disabled plugins will be upgraded as soon + as the plugin is enabled again. + + Disadvantages: + - Orphan documents are retained indefinitely so there's still a potential + for future problems. + - Slightly slower startup time since we have to query for outdated + documents every time. + +We prefer option (3) since it provides flexibility for disabling plugins in +the same version while also protecting users' data in all cases during an +upgrade migration. However, because this is a breaking change we will +implement (5) during 7.x and only implement (3) during 8.x. + +# 5. Alternatives +## 5.1 Rolling upgrades +We considered implementing rolling upgrades to provide zero downtime +migrations. However, this would introduce significant complexity for plugins: +they will need to maintain up and down migration transformations and ensure +that queries match both current and outdated documents across all +versions. Although we can afford the once-off complexity of implementing +rolling upgrades, the complexity burden of maintaining plugins that support +rolling-upgrades will slow down all development in Kibana. Since a predictable +downtime window is sufficient for our users, we decided against trying to +achieve zero downtime with rolling upgrades. See "Rolling upgrades" in +https://github.com/elastic/kibana/issues/52202 for more information. + +## 5.2 Single node migrations coordinated through a lease/lock +This alternative is a proposed algorithm for coordinating migrations so that +these only happen on a single node and therefore don't have the restrictions +found in [(4.2.1.1)](#4311-restrictions). We decided against this algorithm +primarily because it is a lot more complex, but also because it could still +require manual intervention to retry from certain unlikely edge cases. + +
+ It's impossible to guarantee that a single node performs the + migration and automatically retry failed migrations. + +Coordination should ensure that only one Kibana node performs the migration at +a given time which can be achived with a distributed lock built on top of +Elasticsearch. For the Kibana cluster to be able to retry a failed migration, +requires a specialized lock which expires after a given amount of inactivity. +We will refer to such expiring locks as a "lease". + +If a Kibana process stalls, it is possible that the process' lease has expired +but the process doesn't yet recognize this and continues the migration. To +prevent this from causing data loss each lease should be accompanied by a +"guard" that prevents all writes after the lease has expired. See +[how to do distributed +locking](https://martin.kleppmann.com/2016/02/08/how-to-do-distributed-locking.html) +for an in-depth discussion. + +Elasticsearch doesn't provide any building blocks for constructing such a guard. +
+ +However, we can implement a lock (that never expires) with strong +data-consistency guarantees. Because there’s no expiration, a failure between +obtaining the lock and releasing it will require manual intervention. Instead +of trying to accomplish the entire migration after obtaining a lock, we can +only perform the last step of the migration process, moving the aliases, with +a lock. A permanent failure in only this last step is not impossible, but very +unlikely. + +### 5.2.1 Migration algorithm +1. Obtain a document lock (see [5.2.2 Document lock + algorithm](#522-document-lock-algorithm)). Convert the lock into a "weak + lease" by expiring locks for nodes which aren't active (see [4.2.2.4 + Checking for lease expiry](#4324-checking-for-lease-expiry)). This "weak + lease" doesn't require strict guarantees since it's only used to prevent + multiple Kibana nodes from performing a migration in parallel to reduce the + load on Elasticsearch. +2. Migrate data into a new process specific index (we could use the process + UUID that’s used in the lease document like + `.kibana_3ef25ff1-090a-4335-83a0-307a47712b4e`). +3. Obtain a document lock (see [5.2.2 Document lock + algorithm](#522-document-lock-algorithm)). +4. Finish the migration by pointing `.kibana` → + `.kibana_3ef25ff1-090a-4335-83a0-307a47712b4e`. This automatically releases + the document lock (and any leases) because the new index will contain an + empty `kibana_cluster_state`. + +If a process crashes or is stopped after (3) but before (4) the lock will have +to be manually removed by deleting the `kibana_cluster_state` document from +`.kibana` or restoring from a snapshot. + +### 5.2.2 Document lock algorithm +To improve on the existing Saved Objects migrations lock, a locking algorithm +needs to satisfy the following requirements: +- Must guarantee that only a single node can obtain the lock. Since we can + only provide strong data-consistency guarantees on the document level in + Elasticsearch our locking mechanism needs to be based on a document. +- Manually removing the lock + - shouldn't have any risk of accidentally causing data loss. + - can be done with a single command that's always the same (shouldn’t + require trying to find `n` for removing the correct `.kibana_n` index). +- Must be easy to retrieve the lock/cluster state to aid in debugging or to + provide visibility. + +Algorithm: +1. Node reads `kibana_cluster_state` lease document from `.kibana` +2. It sends a heartbeat every `heartbeat_interval` seconds by sending an + update operation that adds it’s UUID to the `nodes` array and sets the + `lastSeen` value to the current local node time. If the update fails due to + a version conflict the update operation is retried after a random delay by + fetching the document again and attempting the update operation once more. +3. To obtain a lease, a node: + 1. Fetches the `kibana_cluster_state` document + 2. If all the nodes’ `hasLock === false` it sets it’s own `hasLock` to + true and attempts to write the document. If the update fails + (presumably because of another node’s heartbeat update) it restarts the + process to obtain a lease from step (3). + 3. If another nodes’ `hasLock === true` the node failed to acquire a + lock and waits until the active lock has expired before attempting to + obtain a lock again. +4. Once a node is done with its lock, it releases it by fetching and then + updating `hasLock = false`. The fetch + update operations are retried until + this node’s `hasLock === false`. + +Each machine writes a `UUID` to a file, so a single machine may have multiple +processes with the same Kibana `UUID`, so we should rather generate a new UUID +just for the lifetime of this process. + +`KibanaClusterState` document format: +```js + nodes: { + "852bd94e-5121-47f3-a321-e09d9db8d16e": { + version: "7.6.0", + lastSeen: [ 1114793, 555149266 ], // hrtime() big int timestamp + hasLease: true, + hasLock: false, + }, + "8d975c5b-cbf6-4418-9afb-7aa3ea34ac90": { + version: "7.6.0", + lastSeen: [ 1114862, 841295591 ], + hasLease: false, + hasLock: false, + }, + "3ef25ff1-090a-4335-83a0-307a47712b4e": { + version: "7.6.0", + lastSeen: [ 1114877, 611368546 ], + hasLease: false, + hasLock: false, + }, + }, + oplog: [ + {op: 'ACQUIRE_LOCK', node: '852bd94e...', timestamp: '2020-04-20T11:58:56.176Z'} + ] +} +``` + +### 5.2.3 Checking for "weak lease" expiry +The simplest way to check for lease expiry is to inspect the `lastSeen` value. +If `lastSeen + expiry_timeout > now` the lock is considered expired. If there +are clock drift or daylight savings time adjustments, there’s a risk that a +node loses it’s lease before `expiry_timeout` has occurred. Since losing a +lock prematurely will not lead to data loss it’s not critical that the +expiry time is observed under all conditions. + +A slightly safer approach is to use a monotonically increasing clock +(`process.hrtime()`) and relative time to determine expiry. Using a +monotonically increasing clock guarantees that the clock will always increase +even if the system time changes due to daylight savings time, NTP clock syncs, +or manually setting the time. To check for expiry, other nodes poll the +cluster state document. Once they see that the `lastSeen` value has increased, +they capture the current hr time `current_hr_time` and starts waiting until +`process.hrtime() - current_hr_time > expiry_timeout` if at that point +`lastSeen` hasn’t been updated the lease is considered to have expired. This +means other nodes can take up to `2*expiry_timeout` to recognize an expired +lease, but a lease will never expire prematurely. + +Any node that detects an expired lease can release that lease by setting the +expired node’s `hasLease = false`. It can then attempt to acquire its lease. + +## 5.3 Minimize data loss with mixed Kibana versions during 7.x +When multiple versions of Kibana are running at the same time, writes from the +outdated node can end up either in the outdated Kibana index, the newly +migrated index, or both. New documents added (and some updates) into the old +index while a migration is in-progress will be lost. Writes that end up in the +new index will be in an outdated format. This could cause queries on the data +to only return a subset of the results which leads to incorrect results or +silent data loss. + +Minimizing data loss from mixed 7.x versions, introduces two additional steps +to rollback to a previous version without a snapshot: +1. (existing) Point the `.kibana` alias to the previous Kibana index `.kibana_n-1` +2. (existing) Delete `.kibana_n` +3. (new) Enable writes on `.kibana_n-1` +4. (new) Delete the dummy "version lock" document from `.kibana_n-1` + +Since our documentation and server logs have implicitly encouraged users to +rollback without using snapshots, many users might have to rely on these +additional migration steps to perform a rollback. Since even the existing +steps are error prone, introducing more steps will likely introduce more +problems than what it solves. + +1. All future versions of Kibana 7.x will use the `.kibana_saved_objects` + alias to locate the current index. If `.kibana_saved_objects` doesn't + exist, newer versions will fallback to reading `.kibana`. +2. All future versions of Kibana will locate the index that + `.kibana_saved_objects` points to and then read and write directly from + the _index_ instead of the alias. +3. Before starting a migration: + 1. Write a new dummy "version lock" document to the `.kibana` index with a + `migrationVersion` set to the current version of Kibana. If an outdated + node is started up after a migration was started it will detect that + newer documents are present in the index and refuse to start up. + 2. Set the outdated index to read-only. Since `.kibana` is never advanced, + it will be pointing to a read-only index which prevent writes from + 6.8+ releases which are already online. + +## 5.4 In-place migrations that re-use the same index (8.0) +> We considered an algorithm that re-uses the same index for migrations and an approach to minimize data-loss if our upgrade procedures aren't followed. This is no longer our preferred approach because of several downsides: +> - It requires taking snapshots to prevent data loss so we can only release this in 8.x +> - Minimizing data loss with unsupported upgrade configurations adds significant complexity and still doesn't guarantee that data isn't lost. + +### 5.4.1 Migration algorithm (8.0): +1. Exit Kibana with a fatal error if a newer node has started a migration by + checking for: + 1. Documents with a newer `migrationVersion` numbers. +2. If the mappings are out of date, update the mappings to the combination of + the index's current mappings and the expected mappings. +3. If there are outdated documents, migrate these in batches: + 1. Read a batch of outdated documents from the index. + 2. Transform documents by applying the migration transformation functions. + 3. Update the document batch in the same index using optimistic concurrency + control. If a batch fails due to an update version mismatch continue + migrating the other batches. + 4. If a batch fails due other reasons repeat the entire migration process. +4. If any of the batches in step (3.3) failed, repeat the entire migration + process. This ensures that in-progress bulk update operations from an + outdated node won't lead to unmigrated documents still being present after + the migration. +5. Once all documents are up to date, the migration is complete and Kibana can + start serving traffic. + +Advantages: +- Not duplicating all documents into a new index will speed up migrations and + reduce the downtime window. This will be especially important for the future + requirement to support > 10k or > 100k documents. +- We can check the health of an existing index before starting the migration, + but we cannot detect what kind of failures might occur while creating a new + index. Whereas retrying migrations will eventually recover from the errors + in (3.3), re-using an index allows us to detect these problems before trying + and avoid errors like (3.3.1) altogether. +- Single index to backup instead of “index pattern” that matches any + `.kibana_n`. +- Simplifies Kibana system index Elasticsearch plugin since it needs to work + on one index per "tenant". +- By leveraging optimistic concurrency control we can further minimize data + loss for unsupported upgrade configurations in the future. + +Drawbacks: +- Cannot make breaking mapping changes (even though it was possible, we have not + introduced a breaking mapping change during 7.x). +- Rollback is only possible by restoring a snapshot which requires educating + users to ensure that they don't rely on `.kibana_n` indices as backups. + (Apart from the need to educate users, snapshot restores provide many + benefits). +- It narrows the second restriction under (4.2.1) even further: migrations + cannot rely on any state that could change as part of a migration because we + can no longer use the previous index as a snapshot of unmigrated state. +- We can’t automatically perform a rollback from a half-way done migration. +- It’s impossible to provide read-only functionality for outdated nodes which + means we can't achieve goal (2.7). + +### 5.4.2 Minimizing data loss with unsupported upgrade configurations (8.0) +> This alternative can reduce some data loss when our upgrade procedure isn't +> followed with the algorithm in (5.4.1). + +Even if (4.5.2) is the only supported upgrade procedure, we should try to +prevent data loss when these instructions aren't followed. + +To prevent data loss we need to prevent any writes from older nodes. We use +a version-specific alias for this purpose. Each time a migration is started, +all other aliases are removed. However, aliases are stored inside +Elasticsearch's ClusterState and this state could remain inconsistent between +nodes for an unbounded amount of time. In addition, bulk operations that were +accepted before the alias was removed will continue to run even after removing +the alias. + +As a result, Kibana cannot guarantee that there would be no data loss but +instead, aims to minimize it as much as possible by adding the bold sections +to the migration algorithm from (5.4.1) + +1. **Disable `action.auto_create_index` for the Kibana system indices.** +2. Exit Kibana with a fatal error if a newer node has started a migration by + checking for: + 1. **Version-specific aliases on the `.kibana` index with a newer version.** + 2. Documents with newer `migrationVersion` numbers. +3. **Remove all other aliases and create a new version-specific alias for + reading and writing to the `.kibana` index .e.g `.kibana_8.0.1`. During and + after the migration, all saved object reads and writes use this alias + instead of reading or writing directly to the index. By using the atomic + `POST /_aliases` API we minimize the chance that an outdated node creating + new outdated documents can cause data loss.** +4. **Wait for the default bulk operation timeout of 30s. This ensures that any + bulk operations accepted before the removal of the alias have either + completed or returned a timeout error to it's initiator.** +5. If the mappings are out of date, update the mappings **through the alias** + to the combination of the index's current mappings and the expected + mappings. **If this operation fails due to an index missing exception (most + likely because another node removed our version-specific alias) repeat the + entire migration process.** +6. If there are outdated documents, migrate these in batches: + 1. Read a batch of outdated documents from `.kibana_n`. + 2. Transform documents by applying the migration functions. + 3. Update the document batch in the same index using optimistic concurrency + control. If a batch fails due to an update version mismatch continue + migrating the other batches. + 4. If a batch fails due other reasons repeat the entire migration process. +7. If any of the batches in step (6.3) failed, repeat the entire migration + process. This ensures that in-progress bulk update operations from an + outdated node won't lead to unmigrated documents still being present after + the migration. +8. Once all documents are up to date, the migration is complete and Kibana can + start serving traffic. + +Steps (2) and (3) from the migration algorithm in minimize the chances of the +following scenarios occuring but cannot guarantee it. It is therefore useful +to enumarate some scenarios and their worst case impact: +1. An outdated node issued a bulk create to it's version-specific alias. + Because a user doesn't wait for all traffic to drain a newer node starts + it's migration before the bulk create was complete. Since this bulk create + was accepted before the newer node deleted the previous version-specific + aliases, it is possible that the index now contains some outdated documents + that the new node is unaware of and doesn't migrate. Although these outdated + documents can lead to inconsistent query results and data loss, step (4) + ensures that an error will be returned to the node that created these + objects. +2. A 8.1.0 node and a 8.2.0 node starts migrating a 8.0.0 index in parallel. + Even though the 8.2.0 node will remove the 8.1.0 version-specific aliases, + the 8.1.0 node could have sent an bulk update operation that got accepted + before its alias was removed. When the 8.2.0 node tries to migrate these + 8.1.0 documents it gets a version conflict but cannot be sure if this was + because another node of the same version migrated this document (which can + safely be ignored) or interference from a different Kibana version. The + 8.1.0 node will hit the error in step (6.3) and restart the migration but + then ultimately fail at step (2). The 8.2.0 node will repeat the entire + migration process from step (7) thus ensuring that all documents are up to + date. +3. A race condition with another Kibana node on the same version, but with + different enabled plugins caused this node's required mappings to be + overwritten. If this causes a mapper parsing exception in step (6.3) we can + restart the migration. Because updating the mappings is additive and saved + object types are unique to a plugin, restarting the migration will allow + the node to update the mappings to be compatible with node's plugins. Both + nodes will be able to successfully complete the migration of their plugins' + registered saved object types. However, if the migration doesn't trigger a + mapper parsing exception the incompatible mappings would go undetected + which can cause future problems like write failures or inconsistent query + results. + +## 5.5 Tag objects as “invalid” if their transformation fails +> This alternative prevents a failed migration when there's a migration transform function bug or a document with invalid data. Although it seems preferable to not fail the entire migration because of a single saved object type's migration transform bug or a single invalid document this has several pitfalls: +> 1. When an object fails to migrate the data for that saved object type becomes inconsistent. This could load to a critical feature being unavailable to a user leaving them with no choice but to downgrade. +> 2. Because Kibana starts accepting traffic after encountering invalid objects a rollback will lead to data loss leaving users with no clean way to recover. +> As a result we prefer to let an upgrade fail and making it easy for users to rollback until they can resolve the root cause. + +> Achieves goals: (2.2) +> Mitigates Errors (3.1), (3.2) + +1. Tag objects as “invalid” if they cause an exception when being transformed, + but don’t fail the entire migration. +2. Log an error message informing administrators that there are invalid + objects which require inspection. For each invalid object, provide an error + stack trace to aid in debugging. +3. Administrators should be able to generate a migration report (similar to + the one dry run migrations create) which is an NDJSON export of all objects + tagged as “invalid”. + 1. Expose this as an HTTP API first + 2. (later) Notify administrators and allow them to export invalid objects + from the Kibana UI. +4. When an invalid object is read, the Saved Objects repository will throw an + invalid object exception which should include a link to the documentation + to help administrators resolve migration bugs. +5. Educate Kibana developers to no longer simply write back an unmigrated + document if an exception occurred. A migration function should either + successfully transform the object or throw. + +# 6. How we teach this +1. Update documentation and server logs to start educating users to depend on + snapshots for Kibana rollbacks. +2. Update developer documentation and educate developers with best practices + for writing migration functions. + +# 7. Unresolved questions +1. When cloning an index we can only ever add new fields to the mappings. When + a saved object type or specific field is removed, the mappings will remain + until we re-index. Is it sufficient to only re-index every major? How do we + track the field count as it grows over every upgrade? +2. More generally, how do we deal with the growing field count approaching the + default limit of 1000? \ No newline at end of file diff --git a/src/core/server/saved_objects/migrationsv2/README.md b/src/core/server/saved_objects/migrationsv2/README.md index fcfff14ec98be..c92a5245e6c91 100644 --- a/src/core/server/saved_objects/migrationsv2/README.md +++ b/src/core/server/saved_objects/migrationsv2/README.md @@ -1,17 +1,358 @@ -## TODO - - [ ] Should we adopt the naming convention of event log `.kibana-event-log-8.0.0-000001`? - - [ ] Can we detect and throw if there's an auto-created `.kibana` index - with inferred mappings? If we detect this we cannot assume that `.kibana` - contains all the latest documents. Our algorithm might also fail because we - clone the `.kibana` index with it's faulty mappings which can prevent us - from updating the mappings to the correct ones. We can ask users to verify - their indices to identify where the most up to date documents are located - (e.g. in `.kibana`, `.kibana_N` or perhaps a combination of both). We can - prepare a `.kibana_7.11.0_001` index and ask users to manually reindex - documents into this index. - -## Manual QA Test Plan -### 1. Legacy pre-migration +- [Introduction](#introduction) +- [Algorithm steps](#algorithm-steps) + - [INIT](#init) + - [CREATE_NEW_TARGET](#create_new_target) + - [LEGACY_SET_WRITE_BLOCK](#legacy_set_write_block) + - [LEGACY_CREATE_REINDEX_TARGET](#legacy_create_reindex_target) + - [LEGACY_REINDEX](#legacy_reindex) + - [LEGACY_REINDEX_WAIT_FOR_TASK](#legacy_reindex_wait_for_task) + - [LEGACY_DELETE](#legacy_delete) + - [WAIT_FOR_YELLOW_SOURCE](#wait_for_yellow_source) + - [SET_SOURCE_WRITE_BLOCK](#set_source_write_block) + - [CREATE_REINDEX_TEMP](#create_reindex_temp) + - [REINDEX_SOURCE_TO_TEMP_OPEN_PIT](#reindex_source_to_temp_open_pit) + - [REINDEX_SOURCE_TO_TEMP_READ](#reindex_source_to_temp_read) + - [REINDEX_SOURCE_TO_TEMP_INDEX](#reindex_source_to_temp_index) + - [REINDEX_SOURCE_TO_TEMP_CLOSE_PIT](#reindex_source_to_temp_close_pit) + - [SET_TEMP_WRITE_BLOCK](#set_temp_write_block) + - [CLONE_TEMP_TO_TARGET](#clone_temp_to_target) + - [OUTDATED_DOCUMENTS_SEARCH](#outdated_documents_search) + - [OUTDATED_DOCUMENTS_TRANSFORM](#outdated_documents_transform) + - [UPDATE_TARGET_MAPPINGS](#update_target_mappings) + - [UPDATE_TARGET_MAPPINGS_WAIT_FOR_TASK](#update_target_mappings_wait_for_task) + - [MARK_VERSION_INDEX_READY_CONFLICT](#mark_version_index_ready_conflict) +- [Manual QA Test Plan](#manual-qa-test-plan) + - [1. Legacy pre-migration](#1-legacy-pre-migration) + - [2. Plugins enabled/disabled](#2-plugins-enableddisabled) + - [Test scenario 1 (enable a plugin after migration):](#test-scenario-1-enable-a-plugin-after-migration) + - [Test scenario 2 (disable a plugin after migration):](#test-scenario-2-disable-a-plugin-after-migration) + - [Test scenario 3 (multiple instances, enable a plugin after migration):](#test-scenario-3-multiple-instances-enable-a-plugin-after-migration) + - [Test scenario 4 (multiple instances, mixed plugin enabled configs):](#test-scenario-4-multiple-instances-mixed-plugin-enabled-configs) + +# Introduction +In the past, the risk of downtime caused by Kibana's saved object upgrade +migrations have discouraged users from adopting the latest features. v2 +migrations aims to solve this problem by minimizing the operational impact on +our users. + +To achieve this it uses a new migration algorithm where every step of the +algorithm is idempotent. No matter at which step a Kibana instance gets +interrupted, it can always restart the migration from the beginning and repeat +all the steps without requiring any user intervention. This doesn't mean +migrations will never fail, but when they fail for intermittent reasons like +an Elasticsearch cluster running out of heap, Kibana will automatically be +able to successfully complete the migration once the cluster has enough heap. + +For more background information on the problem see the [saved object +migrations +RFC](https://github.com/elastic/kibana/blob/master/rfcs/text/0013_saved_object_migrations.md). + +# Algorithm steps +The design goals for the algorithm was to keep downtime below 10 minutes for +100k saved objects while guaranteeing no data loss and keeping steps as simple +and explicit as possible. + +The algorithm is implemented as a state-action machine based on https://www.microsoft.com/en-us/research/uploads/prod/2016/12/Computation-and-State-Machines.pdf + +The state-action machine defines it's behaviour in steps. Each step is a +transition from a control state s_i to the contral state s_i+1 caused by an +action a_i. + +``` +s_i -> a_i -> s_i+1 +s_i+1 -> a_i+1 -> s_i+2 +``` + +Given a control state s1, `next(s1)` returns the next action to execute. +Actions are asynchronous, once the action resolves, we can use the action +response to determine the next state to transition to as defined by the +function `model(state, response)`. + +We can then loosely define a step as: +``` +s_i+1 = model(s_i, await next(s_i)()) +``` + +When there are no more actions returned by `next` the state-action machine +terminates such as in the DONE and FATAL control states. + +What follows is a list of all control states. For each control state the +following is described: + - _next action_: the next action triggered by the current control state + - _new control state_: based on the action response, the possible new control states that the machine will transition to + +Since the algorithm runs once for each saved object index the steps below +always reference a single saved object index `.kibana`. When Kibana starts up, +all the steps are also repeated for the `.kibana_task_manager` index but this +is left out of the description for brevity. + +## INIT +### Next action +`fetchIndices` + +Fetch the saved object indices, mappings and aliases to find the source index +and determine whether we’re migrating from a legacy index or a v1 migrations +index. + +### New control state +1. If `.kibana` and the version specific aliases both exists and are pointing +to the same index. This version's migration has already been completed. Since +the same version could have plugins enabled at any time that would introduce +new transforms or mappings. + → `OUTDATED_DOCUMENTS_SEARCH` + +2. If `.kibana` is pointing to an index that belongs to a later version of +Kibana .e.g. a 7.11.0 instance found the `.kibana` alias pointing to +`.kibana_7.12.0_001` fail the migration + → `FATAL` + +3. If the `.kibana` alias exists we’re migrating from either a v1 or v2 index +and the migration source index is the index the `.kibana` alias points to. + → `WAIT_FOR_YELLOW_SOURCE` + +4. If `.kibana` is a concrete index, we’re migrating from a legacy index + → `LEGACY_SET_WRITE_BLOCK` + +5. If there are no `.kibana` indices, this is a fresh deployment. Initialize a + new saved objects index + → `CREATE_NEW_TARGET` + +## CREATE_NEW_TARGET +### Next action +`createIndex` + +Create the target index. This operation is idempotent, if the index already exist, we wait until its status turns yellow + +### New control state + → `MARK_VERSION_INDEX_READY` + +## LEGACY_SET_WRITE_BLOCK +### Next action +`setWriteBlock` + +Set a write block on the legacy index to prevent any older Kibana instances +from writing to the index while the migration is in progress which could cause +lost acknowledged writes. + +This is the first of a series of `LEGACY_*` control states that will: + - reindex the concrete legacy `.kibana` index into a `.kibana_pre6.5.0_001` index + - delete the concrete `.kibana` _index_ so that we're able to create a `.kibana` _alias_ + +### New control state +1. If the write block was successfully added + → `LEGACY_CREATE_REINDEX_TARGET` +2. If the write block failed because the index doesn't exist, it means another instance already completed the legacy pre-migration. Proceed to the next step. + → `LEGACY_CREATE_REINDEX_TARGET` + +## LEGACY_CREATE_REINDEX_TARGET +### Next action +`createIndex` + +Create a new `.kibana_pre6.5.0_001` index into which we can reindex the legacy +index. (Since the task manager index was converted from a data index into a +saved objects index in 7.4 it will be reindexed into `.kibana_pre7.4.0_001`) +### New control state + → `LEGACY_REINDEX` + +## LEGACY_REINDEX +### Next action +`reindex` + +Let Elasticsearch reindex the legacy index into `.kibana_pre6.5.0_001`. (For +the task manager index we specify a `preMigrationScript` to convert the +original task manager documents into valid saved objects) +### New control state + → `LEGACY_REINDEX_WAIT_FOR_TASK` + + +## LEGACY_REINDEX_WAIT_FOR_TASK +### Next action +`waitForReindexTask` + +Wait for up to 60s for the reindex task to complete. +### New control state +1. If the reindex task completed + → `LEGACY_DELETE` +2. If the reindex task failed with a `target_index_had_write_block` or + `index_not_found_exception` another instance already completed this step + → `LEGACY_DELETE` +3. If the reindex task is still in progress + → `LEGACY_REINDEX_WAIT_FOR_TASK` + +## LEGACY_DELETE +### Next action +`updateAliases` + +Use the updateAliases API to atomically remove the legacy index and create a +new `.kibana` alias that points to `.kibana_pre6.5.0_001`. +### New control state +1. If the action succeeds + → `SET_SOURCE_WRITE_BLOCK` +2. If the action fails with `remove_index_not_a_concrete_index` or + `index_not_found_exception` another instance has already completed this step. + → `SET_SOURCE_WRITE_BLOCK` + +## WAIT_FOR_YELLOW_SOURCE +### Next action +`waitForIndexStatusYellow` + +Wait for the Elasticsearch cluster to be in "yellow" state. It means the index's primary shard is allocated and the index is ready for searching/indexing documents, but ES wasn't able to allocate the replicas. +We don't have as much data redundancy as we could have, but it's enough to start the migration. + +### New control state + → `SET_SOURCE_WRITE_BLOCK` + +## SET_SOURCE_WRITE_BLOCK +### Next action +`setWriteBlock` + +Set a write block on the source index to prevent any older Kibana instances from writing to the index while the migration is in progress which could cause lost acknowledged writes. + +### New control state + → `CREATE_REINDEX_TEMP` + +## CREATE_REINDEX_TEMP +### Next action +`createIndex` + +This operation is idempotent, if the index already exist, we wait until its status turns yellow. + +- Because we will be transforming documents before writing them into this index, we can already set the mappings to the target mappings for this version. The source index might contain documents belonging to a disabled plugin. So set `dynamic: false` mappings for any unknown saved object types. +- (Since we never query the temporary index we can potentially disable refresh to speed up indexing performance. Profile to see if gains justify complexity) + +### New control state + → `REINDEX_SOURCE_TO_TEMP_OPEN_PIT` + +## REINDEX_SOURCE_TO_TEMP_OPEN_PIT +### Next action +`openPIT` + +Open a PIT. Since there is a write block on the source index there is basically no overhead to keeping the PIT so we can lean towards a larger `keep_alive` value like 10 minutes. +### New control state + → `REINDEX_SOURCE_TO_TEMP_READ` + +## REINDEX_SOURCE_TO_TEMP_READ +### Next action +`readNextBatchOfSourceDocuments` + +Read the next batch of outdated documents from the source index by using search after with our PIT. + +### New control state +1. If the batch contained > 0 documents + → `REINDEX_SOURCE_TO_TEMP_INDEX` +2. If there are no more documents returned + → `REINDEX_SOURCE_TO_TEMP_CLOSE_PIT` + +## REINDEX_SOURCE_TO_TEMP_INDEX +### Next action +`transformRawDocs` + `bulkIndexTransformedDocuments` + +1. Transform the current batch of documents +2. Use the bulk API create action to write a batch of up-to-date documents. The create action ensures that there will be only one write per reindexed document even if multiple Kibana instances are performing this step. Ignore any create errors because of documents that already exist in the temporary index. Use `refresh=false` to speed up the create actions, the `UPDATE_TARGET_MAPPINGS` step will ensure that the index is refreshed before we start serving traffic. + +In order to support sharing saved objects to multiple spaces in 8.0, the +transforms will also regenerate document `_id`'s. To ensure that this step +remains idempotent, the new `_id` is deterministically generated using UUIDv5 +ensuring that each Kibana instance generates the same new `_id` for the same document. +### New control state + → `REINDEX_SOURCE_TO_TEMP_READ` + +## REINDEX_SOURCE_TO_TEMP_CLOSE_PIT +### Next action +`closePIT` + +### New control state + → `SET_TEMP_WRITE_BLOCK` + +## SET_TEMP_WRITE_BLOCK +### Next action +`setWriteBlock` + +Set a write block on the temporary index so that we can clone it. +### New control state + → `CLONE_TEMP_TO_TARGET` + +## CLONE_TEMP_TO_TARGET +### Next action +`cloneIndex` + +Ask elasticsearch to clone the temporary index into the target index. If the target index already exists (because another node already started the clone operation), wait until the clone is complete by waiting for a yellow index status. + +We can’t use the temporary index as our target index because one instance can complete the migration, delete a document, and then a second instance starts the reindex operation and re-creates the deleted document. By cloning the temporary index and only accepting writes/deletes from the cloned target index, we prevent lost acknowledged deletes. + +### New control state + → `OUTDATED_DOCUMENTS_SEARCH` + +## OUTDATED_DOCUMENTS_SEARCH +### Next action +`searchForOutdatedDocuments` + +Search for outdated saved object documents. Will return one batch of +documents. + +If another instance has a disabled plugin it will reindex that plugin's +documents without transforming them. Because this instance doesn't know which +plugins were disabled by the instance that performed the +`REINDEX_SOURCE_TO_TEMP_INDEX` step, we need to search for outdated documents +and transform them to ensure that everything is up to date. + +### New control state +1. Found outdated documents? + → `OUTDATED_DOCUMENTS_TRANSFORM` +2. All documents up to date + → `UPDATE_TARGET_MAPPINGS` + +## OUTDATED_DOCUMENTS_TRANSFORM +### Next action +`transformRawDocs` + `bulkOverwriteTransformedDocuments` + +Once transformed we use an index operation to overwrite the outdated document with the up-to-date version. Optimistic concurrency control ensures that we only overwrite the document once so that any updates/writes by another instance which already completed the migration aren’t overwritten and lost. + +### New control state + → `OUTDATED_DOCUMENTS_SEARCH` + +## UPDATE_TARGET_MAPPINGS +### Next action +`updateAndPickupMappings` + +If another instance has some plugins disabled it will disable the mappings of that plugin's types when creating the temporary index. This action will +update the mappings and then use an update_by_query to ensure that all fields are “picked-up” and ready to be searched over. + +### New control state + → `UPDATE_TARGET_MAPPINGS_WAIT_FOR_TASK` + +## UPDATE_TARGET_MAPPINGS_WAIT_FOR_TASK +### Next action +`updateAliases` + +Atomically apply the `versionIndexReadyActions` using the _alias actions API. By performing the following actions we guarantee that if multiple versions of Kibana started the upgrade in parallel, only one version will succeed. + +1. verify that the current alias is still pointing to the source index +2. Point the version alias and the current alias to the target index. +3. Remove the temporary index + +### New control state +1. If all the actions succeed we’re ready to serve traffic + → `DONE` +2. If action (1) fails with alias_not_found_exception or action (3) fails with index_not_found_exception another instance already completed the migration + → `MARK_VERSION_INDEX_READY_CONFLICT` + +## MARK_VERSION_INDEX_READY_CONFLICT +### Next action +`fetchIndices` + +Fetch the saved object indices + +### New control state +If another instance completed a migration from the same source we need to verify that it is running the same version. + +1. If the current and version aliases are pointing to the same index the instance that completed the migration was on the same version and it’s safe to start serving traffic. + → `DONE` +2. If the other instance was running a different version we fail the migration. Once we restart one of two things can happen: the other instance is an older version and we will restart the migration, or, it’s a newer version and we will refuse to start up. + → `FATAL` + +# Manual QA Test Plan +## 1. Legacy pre-migration When upgrading from a legacy index additional steps are required before the regular migration process can start. @@ -45,7 +386,7 @@ Test plan: get restarted. Given enough time, it should always be able to successfully complete the migration. -For a successful migration the following behaviour should be observed: +For a successful migration the following behaviour should be observed: 1. The `.kibana` index should be reindexed into a `.kibana_pre6.5.0` index 2. The `.kibana` index should be deleted 3. The `.kibana_index_template` should be deleted @@ -54,12 +395,12 @@ For a successful migration the following behaviour should be observed: 6. Once migration has completed, the `.kibana_current` and `.kibana_7.11.0` aliases should point to the `.kibana_7.11.0_001` index. -### 2. Plugins enabled/disabled +## 2. Plugins enabled/disabled Kibana plugins can be disabled/enabled at any point in time. We need to ensure that Saved Object documents are migrated for all the possible sequences of enabling, disabling, before or after a version upgrade. -#### Test scenario 1 (enable a plugin after migration): +### Test scenario 1 (enable a plugin after migration): 1. Start an old version of Kibana (< 7.11) 2. Create a document that we know will be migrated in a later version (i.e. create a `dashboard`) @@ -70,7 +411,7 @@ enabling, disabling, before or after a version upgrade. 7. Ensure that the document from step (2) has been migrated (`migrationVersion` contains 7.11.0) -#### Test scenario 2 (disable a plugin after migration): +### Test scenario 2 (disable a plugin after migration): 1. Start an old version of Kibana (< 7.11) 2. Create a document that we know will be migrated in a later version (i.e. create a `dashboard`) @@ -80,11 +421,11 @@ enabling, disabling, before or after a version upgrade. 7. Ensure that Kibana logs a warning, but continues to start even though there are saved object documents which don't belong to an enable plugin -#### Test scenario 2 (multiple instances, enable a plugin after migration): +### Test scenario 3 (multiple instances, enable a plugin after migration): Follow the steps from 'Test scenario 1', but perform the migration with multiple instances of Kibana -#### Test scenario 3 (multiple instances, mixed plugin enabled configs): +### Test scenario 4 (multiple instances, mixed plugin enabled configs): We don't support this upgrade scenario, but it's worth making sure we don't have data loss when there's a user error. 1. Start an old version of Kibana (< 7.11) @@ -97,4 +438,3 @@ have data loss when there's a user error. 5. Ensure that the document from step (2) has been migrated (`migrationVersion` contains 7.11.0) -### \ No newline at end of file From b542cb6b772e524f5d6eada7633e26233c55d862 Mon Sep 17 00:00:00 2001 From: Kaarina Tungseth Date: Fri, 20 Aug 2021 10:15:19 -0500 Subject: [PATCH 23/76] [DOCS] Reformats the Graph settings tables into definition lists (#108065) (#109484) --- docs/settings/graph-settings.asciidoc | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/docs/settings/graph-settings.asciidoc b/docs/settings/graph-settings.asciidoc index 876e3dc936ccf..093edb0d08547 100644 --- a/docs/settings/graph-settings.asciidoc +++ b/docs/settings/graph-settings.asciidoc @@ -7,13 +7,5 @@ You do not need to configure any settings to use the {graph-features}. -[float] -[[general-graph-settings]] -==== General graph settings - -[cols="2*<"] -|=== -| `xpack.graph.enabled` {ess-icon} - | Set to `false` to disable the {graph-features}. - -|=== +`xpack.graph.enabled` {ess-icon}:: +Set to `false` to disable the {graph-features}. From 144b960666d246432bfbe2db49ea92790bc35239 Mon Sep 17 00:00:00 2001 From: Kaarina Tungseth Date: Fri, 20 Aug 2021 10:24:33 -0500 Subject: [PATCH 24/76] [DOCS] Reformats the Development tools settings tables into definition lists (#107967) (#109490) Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- docs/settings/dev-settings.asciidoc | 23 ++++++----------------- 1 file changed, 6 insertions(+), 17 deletions(-) diff --git a/docs/settings/dev-settings.asciidoc b/docs/settings/dev-settings.asciidoc index 810694f46b317..b7edf36851d91 100644 --- a/docs/settings/dev-settings.asciidoc +++ b/docs/settings/dev-settings.asciidoc @@ -12,31 +12,20 @@ They are enabled by default. [[grok-settings]] ==== Grok Debugger settings -[cols="2*<"] -|=== -| `xpack.grokdebugger.enabled` {ess-icon} - | Set to `true` to enable the <>. Defaults to `true`. +`xpack.grokdebugger.enabled` {ess-icon}:: +Set to `true` to enable the <>. Defaults to `true`. -|=== [float] [[profiler-settings]] ==== {searchprofiler} settings -[cols="2*<"] -|=== -| `xpack.searchprofiler.enabled` - | Set to `true` to enable the <>. Defaults to `true`. - -|=== +`xpack.searchprofiler.enabled`:: +Set to `true` to enable the <>. Defaults to `true`. [float] [[painless_lab-settings]] ==== Painless Lab settings -[cols="2*<"] -|=== -| `xpack.painless_lab.enabled` - | When set to `true`, enables the <>. Defaults to `true`. - -|=== +`xpack.painless_lab.enabled`:: +When set to `true`, enables the <>. Defaults to `true`. From c5b766eeed225a17d1501d71525f708300dc5f6e Mon Sep 17 00:00:00 2001 From: Kaarina Tungseth Date: Fri, 20 Aug 2021 10:26:03 -0500 Subject: [PATCH 25/76] [DOCS] Reformats the AleBanner settings tables into definition lists (#107966) (#109494) Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- docs/settings/banners-settings.asciidoc | 28 +++++++++---------------- 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/docs/settings/banners-settings.asciidoc b/docs/settings/banners-settings.asciidoc index ce56d4dbe7a4d..43f1724403595 100644 --- a/docs/settings/banners-settings.asciidoc +++ b/docs/settings/banners-settings.asciidoc @@ -14,25 +14,17 @@ You can configure the `xpack.banners` settings in your `kibana.yml` file. Banners are a https://www.elastic.co/subscriptions[subscription feature]. ==== -[[general-banners-settings-kb]] -==== General banner settings +`xpack.banners.placement`:: +Set to `top` to display a banner above the Elastic header. Defaults to `disabled`. -[cols="2*<"] -|=== +`xpack.banners.textContent`:: +The text to display inside the banner, either plain text or Markdown. -| `xpack.banners.placement` -| Set to `top` to display a banner above the Elastic header. Defaults to `disabled`. +`xpack.banners.textColor`:: +The color for the banner text. Defaults to `#8A6A0A`. -| `xpack.banners.textContent` -| The text to display inside the banner, either plain text or Markdown. +`xpack.banners.backgroundColor`:: +The color of the banner background. Defaults to `#FFF9E8`. -| `xpack.banners.textColor` -| The color for the banner text. Defaults to `#8A6A0A`. - -| `xpack.banners.backgroundColor` -| The color of the banner background. Defaults to `#FFF9E8`. - -| `xpack.banners.disableSpaceBanners` -| If true, per-space banner overrides will be disabled. Defaults to `false`. - -|=== +`xpack.banners.disableSpaceBanners`:: +If true, per-space banner overrides will be disabled. Defaults to `false`. From d0e8e0700f46da8c560576c00527734a54aa249c Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Fri, 20 Aug 2021 11:31:08 -0400 Subject: [PATCH 26/76] Exception List Telemetry (#107765) (#109446) Co-authored-by: Pete Hampton --- .../server/lib/telemetry/constants.ts | 14 ++ .../server/lib/telemetry/endpoint_task.ts | 3 +- .../server/lib/telemetry/helpers.test.ts | 69 +++++++++ .../server/lib/telemetry/helpers.ts | 79 +++++++++- .../server/lib/telemetry/mocks.ts | 6 +- ...sk.test.ts => security_lists_task.test.ts} | 41 +++--- .../lib/telemetry/security_lists_task.ts | 138 ++++++++++++++++++ .../server/lib/telemetry/sender.ts | 39 ++++- .../server/lib/telemetry/trusted_apps_task.ts | 122 ---------------- .../server/lib/telemetry/types.ts | 43 ++++++ 10 files changed, 402 insertions(+), 152 deletions(-) create mode 100644 x-pack/plugins/security_solution/server/lib/telemetry/constants.ts rename x-pack/plugins/security_solution/server/lib/telemetry/{trusted_apps_task.test.ts => security_lists_task.test.ts} (66%) create mode 100644 x-pack/plugins/security_solution/server/lib/telemetry/security_lists_task.ts delete mode 100644 x-pack/plugins/security_solution/server/lib/telemetry/trusted_apps_task.ts diff --git a/x-pack/plugins/security_solution/server/lib/telemetry/constants.ts b/x-pack/plugins/security_solution/server/lib/telemetry/constants.ts new file mode 100644 index 0000000000000..3ef45a554e7a5 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/telemetry/constants.ts @@ -0,0 +1,14 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export const TELEMETRY_CHANNEL_LISTS = 'security-lists'; + +export const TELEMETRY_CHANNEL_ENDPOINT_META = 'endpoint-metadata'; + +export const LIST_ENDPOINT_EXCEPTION = 'endpoint_exception'; + +export const LIST_ENDPOINT_EVENT_FILTER = 'endpoint_event_filter'; diff --git a/x-pack/plugins/security_solution/server/lib/telemetry/endpoint_task.ts b/x-pack/plugins/security_solution/server/lib/telemetry/endpoint_task.ts index 13b4ebf0b3efb..668696f0dce1d 100644 --- a/x-pack/plugins/security_solution/server/lib/telemetry/endpoint_task.ts +++ b/x-pack/plugins/security_solution/server/lib/telemetry/endpoint_task.ts @@ -25,6 +25,7 @@ import { EndpointPolicyResponseAggregation, EndpointPolicyResponseDocument, } from './types'; +import { TELEMETRY_CHANNEL_ENDPOINT_META } from './constants'; export const TelemetryEndpointTaskConstants = { TIMEOUT: '5m', @@ -326,7 +327,7 @@ export class TelemetryEndpointTask { * Send the documents in a batches of 100 */ batchTelemetryRecords(telemetryPayloads, 100).forEach((telemetryBatch) => - this.sender.sendOnDemand('endpoint-metadata', telemetryBatch) + this.sender.sendOnDemand(TELEMETRY_CHANNEL_ENDPOINT_META, telemetryBatch) ); return telemetryPayloads.length; } catch (err) { diff --git a/x-pack/plugins/security_solution/server/lib/telemetry/helpers.test.ts b/x-pack/plugins/security_solution/server/lib/telemetry/helpers.test.ts index bee673fc8725f..a4d11b71f2a8e 100644 --- a/x-pack/plugins/security_solution/server/lib/telemetry/helpers.test.ts +++ b/x-pack/plugins/security_solution/server/lib/telemetry/helpers.test.ts @@ -7,12 +7,17 @@ import moment from 'moment'; import { createMockPackagePolicy } from './mocks'; +import { TrustedApp } from '../../../common/endpoint/types'; +import { LIST_ENDPOINT_EXCEPTION, LIST_ENDPOINT_EVENT_FILTER } from './constants'; import { getPreviousDiagTaskTimestamp, getPreviousEpMetaTaskTimestamp, batchTelemetryRecords, isPackagePolicyList, + templateTrustedApps, + templateEndpointExceptions, } from './helpers'; +import { EndpointExceptionListItem } from './types'; describe('test diagnostic telemetry scheduled task timing helper', () => { test('test -5 mins is returned when there is no previous task run', async () => { @@ -125,3 +130,67 @@ describe('test package policy type guard', () => { expect(result).toEqual(true); }); }); + +describe('list telemetry schema', () => { + test('trusted apps document is correctly formed', () => { + const data = [{ id: 'test_1' }] as TrustedApp[]; + const templatedItems = templateTrustedApps(data); + + expect(templatedItems[0]?.trusted_application.length).toEqual(1); + expect(templatedItems[0]?.endpoint_exception.length).toEqual(0); + expect(templatedItems[0]?.endpoint_event_filter.length).toEqual(0); + }); + + test('trusted apps document is correctly formed with multiple entries', () => { + const data = [{ id: 'test_2' }, { id: 'test_2' }] as TrustedApp[]; + const templatedItems = templateTrustedApps(data); + + expect(templatedItems[0]?.trusted_application.length).toEqual(1); + expect(templatedItems[1]?.trusted_application.length).toEqual(1); + expect(templatedItems[0]?.endpoint_exception.length).toEqual(0); + expect(templatedItems[0]?.endpoint_event_filter.length).toEqual(0); + }); + + test('endpoint exception document is correctly formed', () => { + const data = [{ id: 'test_3' }] as EndpointExceptionListItem[]; + const templatedItems = templateEndpointExceptions(data, LIST_ENDPOINT_EXCEPTION); + + expect(templatedItems[0]?.trusted_application.length).toEqual(0); + expect(templatedItems[0]?.endpoint_exception.length).toEqual(1); + expect(templatedItems[0]?.endpoint_event_filter.length).toEqual(0); + }); + + test('endpoint exception document is correctly formed with multiple entries', () => { + const data = [ + { id: 'test_4' }, + { id: 'test_4' }, + { id: 'test_4' }, + ] as EndpointExceptionListItem[]; + const templatedItems = templateEndpointExceptions(data, LIST_ENDPOINT_EXCEPTION); + + expect(templatedItems[0]?.trusted_application.length).toEqual(0); + expect(templatedItems[0]?.endpoint_exception.length).toEqual(1); + expect(templatedItems[1]?.endpoint_exception.length).toEqual(1); + expect(templatedItems[2]?.endpoint_exception.length).toEqual(1); + expect(templatedItems[0]?.endpoint_event_filter.length).toEqual(0); + }); + + test('endpoint event filters document is correctly formed', () => { + const data = [{ id: 'test_5' }] as EndpointExceptionListItem[]; + const templatedItems = templateEndpointExceptions(data, LIST_ENDPOINT_EVENT_FILTER); + + expect(templatedItems[0]?.trusted_application.length).toEqual(0); + expect(templatedItems[0]?.endpoint_exception.length).toEqual(0); + expect(templatedItems[0]?.endpoint_event_filter.length).toEqual(1); + }); + + test('endpoint event filters document is correctly formed with multiple entries', () => { + const data = [{ id: 'test_6' }, { id: 'test_6' }] as EndpointExceptionListItem[]; + const templatedItems = templateEndpointExceptions(data, LIST_ENDPOINT_EVENT_FILTER); + + expect(templatedItems[0]?.trusted_application.length).toEqual(0); + expect(templatedItems[0]?.endpoint_exception.length).toEqual(0); + expect(templatedItems[0]?.endpoint_event_filter.length).toEqual(1); + expect(templatedItems[1]?.endpoint_event_filter.length).toEqual(1); + }); +}); diff --git a/x-pack/plugins/security_solution/server/lib/telemetry/helpers.ts b/x-pack/plugins/security_solution/server/lib/telemetry/helpers.ts index 6af258a4cbe64..bb2cc4f42ca90 100644 --- a/x-pack/plugins/security_solution/server/lib/telemetry/helpers.ts +++ b/x-pack/plugins/security_solution/server/lib/telemetry/helpers.ts @@ -6,7 +6,11 @@ */ import moment from 'moment'; +import type { ExceptionListItemSchema } from '@kbn/securitysolution-io-ts-list-types'; +import { TrustedApp } from '../../../common/endpoint/types'; import { PackagePolicy } from '../../../../fleet/common/types/models/package_policy'; +import { EndpointExceptionListItem, ListTemplate } from './types'; +import { LIST_ENDPOINT_EXCEPTION, LIST_ENDPOINT_EVENT_FILTER } from './constants'; /** * Determines the when the last run was in order to execute to. @@ -84,9 +88,82 @@ export function isPackagePolicyList( return (data as PackagePolicy[])[0].inputs !== undefined; } +/** + * Maps Exception list item to parsable object + * + * @param exceptionListItem + * @returns collection of endpoint exceptions + */ +export const exceptionListItemToEndpointEntry = (exceptionListItem: ExceptionListItemSchema) => { + return { + id: exceptionListItem.id, + version: exceptionListItem._version || '', + name: exceptionListItem.name, + description: exceptionListItem.description, + created_at: exceptionListItem.created_at, + created_by: exceptionListItem.created_by, + updated_at: exceptionListItem.updated_at, + updated_by: exceptionListItem.updated_by, + entries: exceptionListItem.entries, + os_types: exceptionListItem.os_types, + } as EndpointExceptionListItem; +}; + +/** + * Constructs the lists telemetry schema from a collection of Trusted Apps + * + * @param listData + * @returns lists telemetry schema + */ +export const templateTrustedApps = (listData: TrustedApp[]) => { + return listData.map((item) => { + const template: ListTemplate = { + trusted_application: [], + endpoint_exception: [], + endpoint_event_filter: [], + }; + + template.trusted_application.push(item); + return template; + }); +}; + +/** + * Consructs the list telemetry schema from a collection of endpoint exceptions + * + * @param listData + * @param listType + * @returns lists telemetry schema + */ +export const templateEndpointExceptions = ( + listData: EndpointExceptionListItem[], + listType: string +) => { + return listData.map((item) => { + const template: ListTemplate = { + trusted_application: [], + endpoint_exception: [], + endpoint_event_filter: [], + }; + + if (listType === LIST_ENDPOINT_EXCEPTION) { + template.endpoint_exception.push(item); + return template; + } + + if (listType === LIST_ENDPOINT_EVENT_FILTER) { + template.endpoint_event_filter.push(item); + return template; + } + + return null; + }); +}; + /** * Convert counter label list to kebab case - * @params label_list the list of labels to create standardized UsageCounter from + * + * @param label_list the list of labels to create standardized UsageCounter from * @returns a string label for usage in the UsageCounter */ export function createUsageCounterLabel(labelList: string[]): string { diff --git a/x-pack/plugins/security_solution/server/lib/telemetry/mocks.ts b/x-pack/plugins/security_solution/server/lib/telemetry/mocks.ts index 642be5fc737f7..a38042e214ceb 100644 --- a/x-pack/plugins/security_solution/server/lib/telemetry/mocks.ts +++ b/x-pack/plugins/security_solution/server/lib/telemetry/mocks.ts @@ -9,7 +9,7 @@ import { TelemetryEventsSender } from './sender'; import { TelemetryDiagTask } from './diagnostic_task'; import { TelemetryEndpointTask } from './endpoint_task'; -import { TelemetryTrustedAppsTask } from './trusted_apps_task'; +import { TelemetryExceptionListsTask } from './security_lists_task'; import { PackagePolicy } from '../../../../fleet/common/types/models/package_policy'; /** @@ -69,8 +69,8 @@ export class MockTelemetryEndpointTask extends TelemetryEndpointTask { } /** - * Creates a mocked Telemetry trusted app Task + * Creates a mocked Telemetry exception lists Task */ -export class MockTelemetryTrustedAppTask extends TelemetryTrustedAppsTask { +export class MockExceptionListsTask extends TelemetryExceptionListsTask { public runTask = jest.fn(); } diff --git a/x-pack/plugins/security_solution/server/lib/telemetry/trusted_apps_task.test.ts b/x-pack/plugins/security_solution/server/lib/telemetry/security_lists_task.test.ts similarity index 66% rename from x-pack/plugins/security_solution/server/lib/telemetry/trusted_apps_task.test.ts rename to x-pack/plugins/security_solution/server/lib/telemetry/security_lists_task.test.ts index 5cd67a9c9c215..20d89c9721b27 100644 --- a/x-pack/plugins/security_solution/server/lib/telemetry/trusted_apps_task.test.ts +++ b/x-pack/plugins/security_solution/server/lib/telemetry/security_lists_task.test.ts @@ -9,10 +9,13 @@ import { loggingSystemMock } from 'src/core/server/mocks'; import { TaskStatus } from '../../../../task_manager/server'; import { taskManagerMock } from '../../../../task_manager/server/mocks'; -import { TelemetryTrustedAppsTask, TelemetryTrustedAppsTaskConstants } from './trusted_apps_task'; -import { createMockTelemetryEventsSender, MockTelemetryTrustedAppTask } from './mocks'; +import { + TelemetryExceptionListsTask, + TelemetrySecuityListsTaskConstants, +} from './security_lists_task'; +import { createMockTelemetryEventsSender, MockExceptionListsTask } from './mocks'; -describe('test trusted apps telemetry task functionality', () => { +describe('test exception list telemetry task functionality', () => { let logger: ReturnType; beforeEach(() => { @@ -20,25 +23,25 @@ describe('test trusted apps telemetry task functionality', () => { }); test('the trusted apps task can register', () => { - const telemetryTrustedAppsTask = new TelemetryTrustedAppsTask( + const telemetryTrustedAppsTask = new TelemetryExceptionListsTask( logger, taskManagerMock.createSetup(), createMockTelemetryEventsSender(true) ); - expect(telemetryTrustedAppsTask).toBeInstanceOf(TelemetryTrustedAppsTask); + expect(telemetryTrustedAppsTask).toBeInstanceOf(TelemetryExceptionListsTask); }); - test('the trusted apps task should be registered', () => { + test('the exception list task should be registered', () => { const mockTaskManager = taskManagerMock.createSetup(); - new TelemetryTrustedAppsTask(logger, mockTaskManager, createMockTelemetryEventsSender(true)); + new TelemetryExceptionListsTask(logger, mockTaskManager, createMockTelemetryEventsSender(true)); expect(mockTaskManager.registerTaskDefinitions).toHaveBeenCalled(); }); - test('the trusted apps task should be scheduled', async () => { + test('the exception list task should be scheduled', async () => { const mockTaskManagerSetup = taskManagerMock.createSetup(); - const telemetryTrustedAppsTask = new TelemetryTrustedAppsTask( + const telemetryTrustedAppsTask = new TelemetryExceptionListsTask( logger, mockTaskManagerSetup, createMockTelemetryEventsSender(true) @@ -49,13 +52,13 @@ describe('test trusted apps telemetry task functionality', () => { expect(mockTaskManagerStart.ensureScheduled).toHaveBeenCalled(); }); - test('the trusted apps task should not query elastic if telemetry is not opted in', async () => { + test('the exception list task should not query elastic if telemetry is not opted in', async () => { const mockSender = createMockTelemetryEventsSender(false); const mockTaskManager = taskManagerMock.createSetup(); - new MockTelemetryTrustedAppTask(logger, mockTaskManager, mockSender); + new MockExceptionListsTask(logger, mockTaskManager, mockSender); const mockTaskInstance = { - id: TelemetryTrustedAppsTaskConstants.TYPE, + id: TelemetrySecuityListsTaskConstants.TYPE, runAt: new Date(), attempts: 0, ownerId: '', @@ -65,28 +68,28 @@ describe('test trusted apps telemetry task functionality', () => { retryAt: new Date(), params: {}, state: {}, - taskType: TelemetryTrustedAppsTaskConstants.TYPE, + taskType: TelemetrySecuityListsTaskConstants.TYPE, }; const createTaskRunner = mockTaskManager.registerTaskDefinitions.mock.calls[0][0][ - TelemetryTrustedAppsTaskConstants.TYPE + TelemetrySecuityListsTaskConstants.TYPE ].createTaskRunner; const taskRunner = createTaskRunner({ taskInstance: mockTaskInstance }); await taskRunner.run(); expect(mockSender.fetchTrustedApplications).not.toHaveBeenCalled(); }); - test('the trusted apps task should query elastic if telemetry opted in', async () => { + test('the exception list task should query elastic if telemetry opted in', async () => { const mockSender = createMockTelemetryEventsSender(true); const mockTaskManager = taskManagerMock.createSetup(); - const telemetryTrustedAppsTask = new MockTelemetryTrustedAppTask( + const telemetryTrustedAppsTask = new MockExceptionListsTask( logger, mockTaskManager, mockSender ); const mockTaskInstance = { - id: TelemetryTrustedAppsTaskConstants.TYPE, + id: TelemetrySecuityListsTaskConstants.TYPE, runAt: new Date(), attempts: 0, ownerId: '', @@ -96,11 +99,11 @@ describe('test trusted apps telemetry task functionality', () => { retryAt: new Date(), params: {}, state: {}, - taskType: TelemetryTrustedAppsTaskConstants.TYPE, + taskType: TelemetrySecuityListsTaskConstants.TYPE, }; const createTaskRunner = mockTaskManager.registerTaskDefinitions.mock.calls[0][0][ - TelemetryTrustedAppsTaskConstants.TYPE + TelemetrySecuityListsTaskConstants.TYPE ].createTaskRunner; const taskRunner = createTaskRunner({ taskInstance: mockTaskInstance }); await taskRunner.run(); diff --git a/x-pack/plugins/security_solution/server/lib/telemetry/security_lists_task.ts b/x-pack/plugins/security_solution/server/lib/telemetry/security_lists_task.ts new file mode 100644 index 0000000000000..1c4dc28f1c5a5 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/telemetry/security_lists_task.ts @@ -0,0 +1,138 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import moment from 'moment'; +import { Logger } from 'src/core/server'; +import { + ENDPOINT_LIST_ID, + ENDPOINT_EVENT_FILTERS_LIST_ID, +} from '@kbn/securitysolution-list-constants'; +import { + ConcreteTaskInstance, + TaskManagerSetupContract, + TaskManagerStartContract, +} from '../../../../task_manager/server'; +import { + LIST_ENDPOINT_EXCEPTION, + LIST_ENDPOINT_EVENT_FILTER, + TELEMETRY_CHANNEL_LISTS, +} from './constants'; +import { batchTelemetryRecords, templateEndpointExceptions, templateTrustedApps } from './helpers'; +import { TelemetryEventsSender } from './sender'; + +export const TelemetrySecuityListsTaskConstants = { + TIMEOUT: '3m', + TYPE: 'security:telemetry-lists', + INTERVAL: '24h', + VERSION: '1.0.0', +}; + +const MAX_TELEMETRY_BATCH = 1_000; + +export class TelemetryExceptionListsTask { + private readonly logger: Logger; + private readonly sender: TelemetryEventsSender; + + constructor( + logger: Logger, + taskManager: TaskManagerSetupContract, + sender: TelemetryEventsSender + ) { + this.logger = logger; + this.sender = sender; + + taskManager.registerTaskDefinitions({ + [TelemetrySecuityListsTaskConstants.TYPE]: { + title: 'Security Solution Lists Telemetry', + timeout: TelemetrySecuityListsTaskConstants.TIMEOUT, + createTaskRunner: ({ taskInstance }: { taskInstance: ConcreteTaskInstance }) => { + const { state } = taskInstance; + + return { + run: async () => { + const taskExecutionTime = moment().utc().toISOString(); + const hits = await this.runTask(taskInstance.id); + + return { + state: { + lastExecutionTimestamp: taskExecutionTime, + runs: (state.runs || 0) + 1, + hits, + }, + }; + }, + cancel: async () => {}, + }; + }, + }, + }); + } + + public start = async (taskManager: TaskManagerStartContract) => { + try { + await taskManager.ensureScheduled({ + id: this.getTaskId(), + taskType: TelemetrySecuityListsTaskConstants.TYPE, + scope: ['securitySolution'], + schedule: { + interval: TelemetrySecuityListsTaskConstants.INTERVAL, + }, + state: { runs: 0 }, + params: { version: TelemetrySecuityListsTaskConstants.VERSION }, + }); + } catch (e) { + this.logger.error(`Error scheduling task, received ${e.message}`); + } + }; + + private getTaskId = (): string => { + return `${TelemetrySecuityListsTaskConstants.TYPE}:${TelemetrySecuityListsTaskConstants.VERSION}`; + }; + + public runTask = async (taskId: string) => { + if (taskId !== this.getTaskId()) { + return 0; + } + + const isOptedIn = await this.sender.isTelemetryOptedIn(); + if (!isOptedIn) { + return 0; + } + + // Lists Telemetry: Trusted Applications + + const trustedApps = await this.sender.fetchTrustedApplications(); + const trustedAppsJson = templateTrustedApps(trustedApps.data); + this.logger.debug(`Trusted Apps: ${trustedAppsJson}`); + + batchTelemetryRecords(trustedAppsJson, MAX_TELEMETRY_BATCH).forEach((batch) => + this.sender.sendOnDemand(TELEMETRY_CHANNEL_LISTS, batch) + ); + + // Lists Telemetry: Endpoint Exceptions + + const epExceptions = await this.sender.fetchEndpointList(ENDPOINT_LIST_ID); + const epExceptionsJson = templateEndpointExceptions(epExceptions.data, LIST_ENDPOINT_EXCEPTION); + this.logger.debug(`EP Exceptions: ${epExceptionsJson}`); + + batchTelemetryRecords(epExceptionsJson, MAX_TELEMETRY_BATCH).forEach((batch) => + this.sender.sendOnDemand(TELEMETRY_CHANNEL_LISTS, batch) + ); + + // Lists Telemetry: Endpoint Event Filters + + const epFilters = await this.sender.fetchEndpointList(ENDPOINT_EVENT_FILTERS_LIST_ID); + const epFiltersJson = templateEndpointExceptions(epFilters.data, LIST_ENDPOINT_EVENT_FILTER); + this.logger.debug(`EP Event Filters: ${epFiltersJson}`); + + batchTelemetryRecords(epFiltersJson, MAX_TELEMETRY_BATCH).forEach((batch) => + this.sender.sendOnDemand(TELEMETRY_CHANNEL_LISTS, batch) + ); + + return trustedAppsJson.length + epExceptionsJson.length + epFiltersJson.length; + }; +} diff --git a/x-pack/plugins/security_solution/server/lib/telemetry/sender.ts b/x-pack/plugins/security_solution/server/lib/telemetry/sender.ts index 5724c61bfcee7..c7bb58dd2251b 100644 --- a/x-pack/plugins/security_solution/server/lib/telemetry/sender.ts +++ b/x-pack/plugins/security_solution/server/lib/telemetry/sender.ts @@ -18,14 +18,15 @@ import { TaskManagerSetupContract, TaskManagerStartContract, } from '../../../../task_manager/server'; -import { createUsageCounterLabel } from './helpers'; import { TelemetryDiagTask } from './diagnostic_task'; import { TelemetryEndpointTask } from './endpoint_task'; -import { TelemetryTrustedAppsTask } from './trusted_apps_task'; +import { TelemetryExceptionListsTask } from './security_lists_task'; import { EndpointAppContextService } from '../../endpoint/endpoint_app_context_services'; import { AgentService, AgentPolicyServiceInterface } from '../../../../fleet/server'; -import { ExceptionListClient } from '../../../../lists/server'; import { getTrustedAppsList } from '../../endpoint/routes/trusted_apps/service'; +import { ExceptionListClient } from '../../../../lists/server'; +import { GetEndpointListResponse } from './types'; +import { createUsageCounterLabel, exceptionListItemToEndpointEntry } from './helpers'; type BaseSearchTypes = string | number | boolean | object; export type SearchTypes = BaseSearchTypes | BaseSearchTypes[] | undefined; @@ -63,7 +64,7 @@ export class TelemetryEventsSender { private isOptedIn?: boolean = true; // Assume true until the first check private diagTask?: TelemetryDiagTask; private epMetricsTask?: TelemetryEndpointTask; - private trustedAppsTask?: TelemetryTrustedAppsTask; + private exceptionListTask?: TelemetryExceptionListsTask; private agentService?: AgentService; private agentPolicyService?: AgentPolicyServiceInterface; private esClient?: ElasticsearchClient; @@ -86,7 +87,7 @@ export class TelemetryEventsSender { if (taskManager) { this.diagTask = new TelemetryDiagTask(this.logger, taskManager, this); this.epMetricsTask = new TelemetryEndpointTask(this.logger, taskManager, this); - this.trustedAppsTask = new TelemetryTrustedAppsTask(this.logger, taskManager, this); + this.exceptionListTask = new TelemetryExceptionListsTask(this.logger, taskManager, this); } } @@ -108,7 +109,7 @@ export class TelemetryEventsSender { this.logger.debug(`Starting diagnostic and endpoint telemetry tasks`); this.diagTask.start(taskManager); this.epMetricsTask.start(taskManager); - this.trustedAppsTask?.start(taskManager); + this.exceptionListTask?.start(taskManager); } this.logger.debug(`Starting local task`); @@ -279,6 +280,32 @@ export class TelemetryEventsSender { return getTrustedAppsList(this.exceptionListClient, { page: 1, per_page: 10_000 }); } + public async fetchEndpointList(listId: string): Promise { + if (this?.exceptionListClient === undefined || this?.exceptionListClient === null) { + throw Error('could not fetch trusted applications. exception list client not available.'); + } + + // Ensure list is created if it does not exist + await this.exceptionListClient.createTrustedAppsList(); + + const results = await this.exceptionListClient.findExceptionListItem({ + listId, + page: 1, + perPage: this.max_records, + filter: undefined, + namespaceType: 'agnostic', + sortField: 'name', + sortOrder: 'asc', + }); + + return { + data: results?.data.map(exceptionListItemToEndpointEntry) ?? [], + total: results?.total ?? 0, + page: results?.page ?? 1, + per_page: results?.per_page ?? this.max_records, + }; + } + public queueTelemetryEvents(events: TelemetryEvent[]) { const qlength = this.queue.length; diff --git a/x-pack/plugins/security_solution/server/lib/telemetry/trusted_apps_task.ts b/x-pack/plugins/security_solution/server/lib/telemetry/trusted_apps_task.ts deleted file mode 100644 index f91f3e8428d04..0000000000000 --- a/x-pack/plugins/security_solution/server/lib/telemetry/trusted_apps_task.ts +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import moment from 'moment'; -import { Logger } from 'src/core/server'; -import { - ConcreteTaskInstance, - TaskManagerSetupContract, - TaskManagerStartContract, -} from '../../../../task_manager/server'; - -import { getPreviousEpMetaTaskTimestamp, batchTelemetryRecords } from './helpers'; -import { TelemetryEventsSender } from './sender'; - -export const TelemetryTrustedAppsTaskConstants = { - TIMEOUT: '1m', - TYPE: 'security:trusted-apps-telemetry', - INTERVAL: '24h', - VERSION: '1.0.0', -}; - -/** Telemetry Trusted Apps Task - * - * The Trusted Apps task is a daily batch job that collects and transmits non-sensitive - * trusted apps hashes + file paths for supported operating systems. This helps test - * efficacy of our protections. - */ -export class TelemetryTrustedAppsTask { - private readonly logger: Logger; - private readonly sender: TelemetryEventsSender; - - constructor( - logger: Logger, - taskManager: TaskManagerSetupContract, - sender: TelemetryEventsSender - ) { - this.logger = logger; - this.sender = sender; - - taskManager.registerTaskDefinitions({ - [TelemetryTrustedAppsTaskConstants.TYPE]: { - title: 'Security Solution Telemetry Endpoint Metrics and Info task', - timeout: TelemetryTrustedAppsTaskConstants.TIMEOUT, - createTaskRunner: ({ taskInstance }: { taskInstance: ConcreteTaskInstance }) => { - const { state } = taskInstance; - - return { - run: async () => { - const taskExecutionTime = moment().utc().toISOString(); - const lastExecutionTimestamp = getPreviousEpMetaTaskTimestamp( - taskExecutionTime, - taskInstance.state?.lastExecutionTimestamp - ); - - const hits = await this.runTask( - taskInstance.id, - lastExecutionTimestamp, - taskExecutionTime - ); - - return { - state: { - lastExecutionTimestamp: taskExecutionTime, - runs: (state.runs || 0) + 1, - hits, - }, - }; - }, - cancel: async () => {}, - }; - }, - }, - }); - } - - public start = async (taskManager: TaskManagerStartContract) => { - try { - await taskManager.ensureScheduled({ - id: this.getTaskId(), - taskType: TelemetryTrustedAppsTaskConstants.TYPE, - scope: ['securitySolution'], - schedule: { - interval: TelemetryTrustedAppsTaskConstants.INTERVAL, - }, - state: { runs: 0 }, - params: { version: TelemetryTrustedAppsTaskConstants.VERSION }, - }); - } catch (e) { - this.logger.error(`Error scheduling task, received ${e.message}`); - } - }; - - private getTaskId = (): string => { - return `${TelemetryTrustedAppsTaskConstants.TYPE}:${TelemetryTrustedAppsTaskConstants.VERSION}`; - }; - - public runTask = async (taskId: string, executeFrom: string, executeTo: string) => { - if (taskId !== this.getTaskId()) { - this.logger.debug(`Outdated task running: ${taskId}`); - return 0; - } - - const isOptedIn = await this.sender.isTelemetryOptedIn(); - if (!isOptedIn) { - this.logger.debug(`Telemetry is not opted-in.`); - return 0; - } - - const response = await this.sender.fetchTrustedApplications(); - this.logger.debug(`Trusted Apps: ${response}`); - - batchTelemetryRecords(response.data, 1_000).forEach((telemetryBatch) => - this.sender.sendOnDemand('lists-trustedapps', telemetryBatch) - ); - - return response.data.length; - }; -} diff --git a/x-pack/plugins/security_solution/server/lib/telemetry/types.ts b/x-pack/plugins/security_solution/server/lib/telemetry/types.ts index 355393145fa0b..d1d7740071e1f 100644 --- a/x-pack/plugins/security_solution/server/lib/telemetry/types.ts +++ b/x-pack/plugins/security_solution/server/lib/telemetry/types.ts @@ -5,6 +5,9 @@ * 2.0. */ +import { schema, TypeOf } from '@kbn/config-schema'; +import { TrustedApp } from '../../../common/endpoint/types'; + // EP Policy Response export interface EndpointPolicyResponseAggregation { @@ -138,3 +141,43 @@ interface EndpointMetricOS { platform: string; full: string; } + +// List HTTP Types + +export const GetTrustedAppsRequestSchema = { + query: schema.object({ + page: schema.maybe(schema.number({ defaultValue: 1, min: 1 })), + per_page: schema.maybe(schema.number({ defaultValue: 20, min: 1 })), + kuery: schema.maybe(schema.string()), + }), +}; + +export type GetEndpointListRequest = TypeOf; + +export interface GetEndpointListResponse { + per_page: number; + page: number; + total: number; + data: EndpointExceptionListItem[]; +} + +// Telemetry List types + +export interface EndpointExceptionListItem { + id: string; + version: string; + name: string; + description: string; + created_at: string; + created_by: string; + updated_at: string; + updated_by: string; + entries: object; + os_types: object; +} + +export interface ListTemplate { + trusted_application: TrustedApp[]; + endpoint_exception: EndpointExceptionListItem[]; + endpoint_event_filter: EndpointExceptionListItem[]; +} From ffad23b11c75095ee2e2e3474a3b9ffc20b82f7d Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Fri, 20 Aug 2021 11:38:19 -0400 Subject: [PATCH 27/76] Remove unused chrome APIs (#109204) (#109254) * remove unused chrome APIs * update generated doc * fix tests * fix tests bis Co-authored-by: Pierre Gayvallet --- ...ana-plugin-core-public.chromebrand.logo.md | 11 -- .../kibana-plugin-core-public.chromebrand.md | 20 ---- ...lugin-core-public.chromebrand.smalllogo.md | 11 -- ...-public.chromestart.addapplicationclass.md | 24 ----- ...blic.chromestart.getapplicationclasses_.md | 17 --- ...lugin-core-public.chromestart.getbrand_.md | 17 --- .../kibana-plugin-core-public.chromestart.md | 6 -- ...blic.chromestart.removeapplicationclass.md | 24 ----- ...gin-core-public.chromestart.setapptitle.md | 24 ----- ...plugin-core-public.chromestart.setbrand.md | 39 ------- .../core/public/kibana-plugin-core-public.md | 1 - src/core/public/chrome/chrome_service.mock.ts | 10 +- src/core/public/chrome/chrome_service.test.ts | 100 ++---------------- src/core/public/chrome/chrome_service.tsx | 36 ------- src/core/public/chrome/index.ts | 1 - src/core/public/chrome/types.ts | 56 +--------- .../header/__snapshots__/header.test.tsx.snap | 89 +--------------- .../header_breadcrumbs.test.tsx.snap | 18 +++- src/core/public/chrome/ui/header/header.tsx | 5 +- .../ui/header/header_breadcrumbs.test.tsx | 4 +- .../chrome/ui/header/header_breadcrumbs.tsx | 8 +- src/core/public/index.ts | 2 - src/core/public/public.api.md | 14 --- .../public/rendering/app_containers.test.tsx | 56 +--------- src/core/public/rendering/app_containers.tsx | 12 +-- .../rendering/rendering_service.test.tsx | 23 +--- .../public/rendering/rendering_service.tsx | 5 +- 27 files changed, 42 insertions(+), 591 deletions(-) delete mode 100644 docs/development/core/public/kibana-plugin-core-public.chromebrand.logo.md delete mode 100644 docs/development/core/public/kibana-plugin-core-public.chromebrand.md delete mode 100644 docs/development/core/public/kibana-plugin-core-public.chromebrand.smalllogo.md delete mode 100644 docs/development/core/public/kibana-plugin-core-public.chromestart.addapplicationclass.md delete mode 100644 docs/development/core/public/kibana-plugin-core-public.chromestart.getapplicationclasses_.md delete mode 100644 docs/development/core/public/kibana-plugin-core-public.chromestart.getbrand_.md delete mode 100644 docs/development/core/public/kibana-plugin-core-public.chromestart.removeapplicationclass.md delete mode 100644 docs/development/core/public/kibana-plugin-core-public.chromestart.setapptitle.md delete mode 100644 docs/development/core/public/kibana-plugin-core-public.chromestart.setbrand.md diff --git a/docs/development/core/public/kibana-plugin-core-public.chromebrand.logo.md b/docs/development/core/public/kibana-plugin-core-public.chromebrand.logo.md deleted file mode 100644 index 561d9c50008b8..0000000000000 --- a/docs/development/core/public/kibana-plugin-core-public.chromebrand.logo.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-core-public](./kibana-plugin-core-public.md) > [ChromeBrand](./kibana-plugin-core-public.chromebrand.md) > [logo](./kibana-plugin-core-public.chromebrand.logo.md) - -## ChromeBrand.logo property - -Signature: - -```typescript -logo?: string; -``` diff --git a/docs/development/core/public/kibana-plugin-core-public.chromebrand.md b/docs/development/core/public/kibana-plugin-core-public.chromebrand.md deleted file mode 100644 index 21cdf6c3dee9b..0000000000000 --- a/docs/development/core/public/kibana-plugin-core-public.chromebrand.md +++ /dev/null @@ -1,20 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-core-public](./kibana-plugin-core-public.md) > [ChromeBrand](./kibana-plugin-core-public.chromebrand.md) - -## ChromeBrand interface - - -Signature: - -```typescript -export interface ChromeBrand -``` - -## Properties - -| Property | Type | Description | -| --- | --- | --- | -| [logo](./kibana-plugin-core-public.chromebrand.logo.md) | string | | -| [smallLogo](./kibana-plugin-core-public.chromebrand.smalllogo.md) | string | | - diff --git a/docs/development/core/public/kibana-plugin-core-public.chromebrand.smalllogo.md b/docs/development/core/public/kibana-plugin-core-public.chromebrand.smalllogo.md deleted file mode 100644 index 5b21e806540be..0000000000000 --- a/docs/development/core/public/kibana-plugin-core-public.chromebrand.smalllogo.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-core-public](./kibana-plugin-core-public.md) > [ChromeBrand](./kibana-plugin-core-public.chromebrand.md) > [smallLogo](./kibana-plugin-core-public.chromebrand.smalllogo.md) - -## ChromeBrand.smallLogo property - -Signature: - -```typescript -smallLogo?: string; -``` diff --git a/docs/development/core/public/kibana-plugin-core-public.chromestart.addapplicationclass.md b/docs/development/core/public/kibana-plugin-core-public.chromestart.addapplicationclass.md deleted file mode 100644 index 67e86863ad3c8..0000000000000 --- a/docs/development/core/public/kibana-plugin-core-public.chromestart.addapplicationclass.md +++ /dev/null @@ -1,24 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-core-public](./kibana-plugin-core-public.md) > [ChromeStart](./kibana-plugin-core-public.chromestart.md) > [addApplicationClass](./kibana-plugin-core-public.chromestart.addapplicationclass.md) - -## ChromeStart.addApplicationClass() method - -Add a className that should be set on the application container. - -Signature: - -```typescript -addApplicationClass(className: string): void; -``` - -## Parameters - -| Parameter | Type | Description | -| --- | --- | --- | -| className | string | | - -Returns: - -`void` - diff --git a/docs/development/core/public/kibana-plugin-core-public.chromestart.getapplicationclasses_.md b/docs/development/core/public/kibana-plugin-core-public.chromestart.getapplicationclasses_.md deleted file mode 100644 index c932d8b7f0a40..0000000000000 --- a/docs/development/core/public/kibana-plugin-core-public.chromestart.getapplicationclasses_.md +++ /dev/null @@ -1,17 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-core-public](./kibana-plugin-core-public.md) > [ChromeStart](./kibana-plugin-core-public.chromestart.md) > [getApplicationClasses$](./kibana-plugin-core-public.chromestart.getapplicationclasses_.md) - -## ChromeStart.getApplicationClasses$() method - -Get the current set of classNames that will be set on the application container. - -Signature: - -```typescript -getApplicationClasses$(): Observable; -``` -Returns: - -`Observable` - diff --git a/docs/development/core/public/kibana-plugin-core-public.chromestart.getbrand_.md b/docs/development/core/public/kibana-plugin-core-public.chromestart.getbrand_.md deleted file mode 100644 index fa42defd6339a..0000000000000 --- a/docs/development/core/public/kibana-plugin-core-public.chromestart.getbrand_.md +++ /dev/null @@ -1,17 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-core-public](./kibana-plugin-core-public.md) > [ChromeStart](./kibana-plugin-core-public.chromestart.md) > [getBrand$](./kibana-plugin-core-public.chromestart.getbrand_.md) - -## ChromeStart.getBrand$() method - -Get an observable of the current brand information. - -Signature: - -```typescript -getBrand$(): Observable; -``` -Returns: - -`Observable` - diff --git a/docs/development/core/public/kibana-plugin-core-public.chromestart.md b/docs/development/core/public/kibana-plugin-core-public.chromestart.md index 2d465745c436b..7285b4a00a0ec 100644 --- a/docs/development/core/public/kibana-plugin-core-public.chromestart.md +++ b/docs/development/core/public/kibana-plugin-core-public.chromestart.md @@ -50,20 +50,14 @@ core.chrome.setHelpExtension(elem => { | Method | Description | | --- | --- | -| [addApplicationClass(className)](./kibana-plugin-core-public.chromestart.addapplicationclass.md) | Add a className that should be set on the application container. | -| [getApplicationClasses$()](./kibana-plugin-core-public.chromestart.getapplicationclasses_.md) | Get the current set of classNames that will be set on the application container. | | [getBadge$()](./kibana-plugin-core-public.chromestart.getbadge_.md) | Get an observable of the current badge | -| [getBrand$()](./kibana-plugin-core-public.chromestart.getbrand_.md) | Get an observable of the current brand information. | | [getBreadcrumbs$()](./kibana-plugin-core-public.chromestart.getbreadcrumbs_.md) | Get an observable of the current list of breadcrumbs | | [getBreadcrumbsAppendExtension$()](./kibana-plugin-core-public.chromestart.getbreadcrumbsappendextension_.md) | Get an observable of the current extension appended to breadcrumbs | | [getCustomNavLink$()](./kibana-plugin-core-public.chromestart.getcustomnavlink_.md) | Get an observable of the current custom nav link | | [getHelpExtension$()](./kibana-plugin-core-public.chromestart.gethelpextension_.md) | Get an observable of the current custom help conttent | | [getIsNavDrawerLocked$()](./kibana-plugin-core-public.chromestart.getisnavdrawerlocked_.md) | Get an observable of the current locked state of the nav drawer. | | [getIsVisible$()](./kibana-plugin-core-public.chromestart.getisvisible_.md) | Get an observable of the current visibility state of the chrome. | -| [removeApplicationClass(className)](./kibana-plugin-core-public.chromestart.removeapplicationclass.md) | Remove a className added with addApplicationClass(). If className is unknown it is ignored. | -| [setAppTitle(appTitle)](./kibana-plugin-core-public.chromestart.setapptitle.md) | Sets the current app's title | | [setBadge(badge)](./kibana-plugin-core-public.chromestart.setbadge.md) | Override the current badge | -| [setBrand(brand)](./kibana-plugin-core-public.chromestart.setbrand.md) | Set the brand configuration. | | [setBreadcrumbs(newBreadcrumbs)](./kibana-plugin-core-public.chromestart.setbreadcrumbs.md) | Override the current set of breadcrumbs | | [setBreadcrumbsAppendExtension(breadcrumbsAppendExtension)](./kibana-plugin-core-public.chromestart.setbreadcrumbsappendextension.md) | Mount an element next to the last breadcrumb | | [setCustomNavLink(newCustomNavLink)](./kibana-plugin-core-public.chromestart.setcustomnavlink.md) | Override the current set of custom nav link | diff --git a/docs/development/core/public/kibana-plugin-core-public.chromestart.removeapplicationclass.md b/docs/development/core/public/kibana-plugin-core-public.chromestart.removeapplicationclass.md deleted file mode 100644 index 5bdeec635ed44..0000000000000 --- a/docs/development/core/public/kibana-plugin-core-public.chromestart.removeapplicationclass.md +++ /dev/null @@ -1,24 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-core-public](./kibana-plugin-core-public.md) > [ChromeStart](./kibana-plugin-core-public.chromestart.md) > [removeApplicationClass](./kibana-plugin-core-public.chromestart.removeapplicationclass.md) - -## ChromeStart.removeApplicationClass() method - -Remove a className added with `addApplicationClass()`. If className is unknown it is ignored. - -Signature: - -```typescript -removeApplicationClass(className: string): void; -``` - -## Parameters - -| Parameter | Type | Description | -| --- | --- | --- | -| className | string | | - -Returns: - -`void` - diff --git a/docs/development/core/public/kibana-plugin-core-public.chromestart.setapptitle.md b/docs/development/core/public/kibana-plugin-core-public.chromestart.setapptitle.md deleted file mode 100644 index f0e2db30f1891..0000000000000 --- a/docs/development/core/public/kibana-plugin-core-public.chromestart.setapptitle.md +++ /dev/null @@ -1,24 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-core-public](./kibana-plugin-core-public.md) > [ChromeStart](./kibana-plugin-core-public.chromestart.md) > [setAppTitle](./kibana-plugin-core-public.chromestart.setapptitle.md) - -## ChromeStart.setAppTitle() method - -Sets the current app's title - -Signature: - -```typescript -setAppTitle(appTitle: string): void; -``` - -## Parameters - -| Parameter | Type | Description | -| --- | --- | --- | -| appTitle | string | | - -Returns: - -`void` - diff --git a/docs/development/core/public/kibana-plugin-core-public.chromestart.setbrand.md b/docs/development/core/public/kibana-plugin-core-public.chromestart.setbrand.md deleted file mode 100644 index daaa510483ae7..0000000000000 --- a/docs/development/core/public/kibana-plugin-core-public.chromestart.setbrand.md +++ /dev/null @@ -1,39 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-core-public](./kibana-plugin-core-public.md) > [ChromeStart](./kibana-plugin-core-public.chromestart.md) > [setBrand](./kibana-plugin-core-public.chromestart.setbrand.md) - -## ChromeStart.setBrand() method - -Set the brand configuration. - -Signature: - -```typescript -setBrand(brand: ChromeBrand): void; -``` - -## Parameters - -| Parameter | Type | Description | -| --- | --- | --- | -| brand | ChromeBrand | | - -Returns: - -`void` - -## Remarks - -Normally the `logo` property will be rendered as the CSS background for the home link in the chrome navigation, but when the page is rendered in a small window the `smallLogo` will be used and rendered at about 45px wide. - -## Example - - -```js -chrome.setBrand({ - logo: 'url(/plugins/app/logo.png) center no-repeat' - smallLogo: 'url(/plugins/app/logo-small.png) center no-repeat' -}) - -``` - diff --git a/docs/development/core/public/kibana-plugin-core-public.md b/docs/development/core/public/kibana-plugin-core-public.md index e984fbb675e6d..59735b053adbc 100644 --- a/docs/development/core/public/kibana-plugin-core-public.md +++ b/docs/development/core/public/kibana-plugin-core-public.md @@ -42,7 +42,6 @@ The plugin integrates with the core system via lifecycle events: `setup` | [AsyncPlugin](./kibana-plugin-core-public.asyncplugin.md) | A plugin with asynchronous lifecycle methods. | | [Capabilities](./kibana-plugin-core-public.capabilities.md) | The read-only set of capabilities available for the current UI session. Capabilities are simple key-value pairs of (string, boolean), where the string denotes the capability ID, and the boolean is a flag indicating if the capability is enabled or disabled. | | [ChromeBadge](./kibana-plugin-core-public.chromebadge.md) | | -| [ChromeBrand](./kibana-plugin-core-public.chromebrand.md) | | | [ChromeDocTitle](./kibana-plugin-core-public.chromedoctitle.md) | APIs for accessing and updating the document title. | | [ChromeHelpExtension](./kibana-plugin-core-public.chromehelpextension.md) | | | [ChromeHelpExtensionMenuCustomLink](./kibana-plugin-core-public.chromehelpextensionmenucustomlink.md) | | diff --git a/src/core/public/chrome/chrome_service.mock.ts b/src/core/public/chrome/chrome_service.mock.ts index b624084258817..5e29218250fb9 100644 --- a/src/core/public/chrome/chrome_service.mock.ts +++ b/src/core/public/chrome/chrome_service.mock.ts @@ -9,7 +9,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 './'; +import { ChromeBadge, ChromeBreadcrumb, ChromeService, InternalChromeStart } from './'; const createStartContractMock = () => { const startContract: DeeplyMockedKeys = { @@ -40,14 +40,8 @@ const createStartContractMock = () => { getCenter$: jest.fn(), getRight$: jest.fn(), }, - setAppTitle: jest.fn(), - setBrand: jest.fn(), - getBrand$: jest.fn(), setIsVisible: jest.fn(), getIsVisible$: jest.fn(), - addApplicationClass: jest.fn(), - removeApplicationClass: jest.fn(), - getApplicationClasses$: jest.fn(), getBadge$: jest.fn(), setBadge: jest.fn(), getBreadcrumbs$: jest.fn(), @@ -64,9 +58,7 @@ const createStartContractMock = () => { getBodyClasses$: jest.fn(), }; startContract.navLinks.getAll.mockReturnValue([]); - startContract.getBrand$.mockReturnValue(new BehaviorSubject({} as ChromeBrand)); startContract.getIsVisible$.mockReturnValue(new BehaviorSubject(false)); - startContract.getApplicationClasses$.mockReturnValue(new BehaviorSubject(['class-name'])); startContract.getBadge$.mockReturnValue(new BehaviorSubject({} as ChromeBadge)); startContract.getBreadcrumbs$.mockReturnValue(new BehaviorSubject([{} as ChromeBreadcrumb])); startContract.getBreadcrumbsAppendExtension$.mockReturnValue(new BehaviorSubject(undefined)); diff --git a/src/core/public/chrome/chrome_service.test.ts b/src/core/public/chrome/chrome_service.test.ts index 92f5a854f6b00..8df8d76a13c46 100644 --- a/src/core/public/chrome/chrome_service.test.ts +++ b/src/core/public/chrome/chrome_service.test.ts @@ -23,8 +23,10 @@ import { getAppInfo } from '../application/utils'; class FakeApp implements App { public title = `${this.id} App`; public mount = () => () => {}; + constructor(public id: string, public chromeless?: boolean) {} } + const store = new Map(); const originalLocalStorage = window.localStorage; @@ -170,36 +172,6 @@ describe('start', () => { }); }); - describe('brand', () => { - it('updates/emits the brand as it changes', async () => { - const { chrome, service } = await start(); - const promise = chrome.getBrand$().pipe(toArray()).toPromise(); - - chrome.setBrand({ - logo: 'big logo', - smallLogo: 'not so big logo', - }); - chrome.setBrand({ - logo: 'big logo without small logo', - }); - service.stop(); - - await expect(promise).resolves.toMatchInlineSnapshot(` - Array [ - Object {}, - Object { - "logo": "big logo", - "smallLogo": "not so big logo", - }, - Object { - "logo": "big logo without small logo", - "smallLogo": undefined, - }, - ] - `); - }); - }); - describe('visibility', () => { it('emits false when no application is mounted', async () => { const { chrome, service } = await start(); @@ -289,54 +261,6 @@ describe('start', () => { }); }); - describe('application classes', () => { - it('updates/emits the application classes', async () => { - const { chrome, service } = await start(); - const promise = chrome.getApplicationClasses$().pipe(toArray()).toPromise(); - - chrome.addApplicationClass('foo'); - chrome.addApplicationClass('foo'); - chrome.addApplicationClass('bar'); - chrome.addApplicationClass('bar'); - chrome.addApplicationClass('baz'); - chrome.removeApplicationClass('bar'); - chrome.removeApplicationClass('foo'); - service.stop(); - - await expect(promise).resolves.toMatchInlineSnapshot(` - Array [ - Array [], - Array [ - "foo", - ], - Array [ - "foo", - ], - Array [ - "foo", - "bar", - ], - Array [ - "foo", - "bar", - ], - Array [ - "foo", - "bar", - "baz", - ], - Array [ - "foo", - "baz", - ], - Array [ - "baz", - ], - ] - `); - }); - }); - describe('badge', () => { it('updates/emits the current badge', async () => { const { chrome, service } = await start(); @@ -407,7 +331,9 @@ describe('start', () => { const { chrome, service } = await start(); const promise = chrome.getBreadcrumbsAppendExtension$().pipe(toArray()).toPromise(); - chrome.setBreadcrumbsAppendExtension({ content: (element) => () => {} }); + chrome.setBreadcrumbsAppendExtension({ + content: (element) => () => {}, + }); service.stop(); await expect(promise).resolves.toMatchInlineSnapshot(` @@ -521,14 +447,12 @@ describe('start', () => { describe('stop', () => { it('completes applicationClass$, getIsNavDrawerLocked, breadcrumbs$, isVisible$, and brand$ observables', async () => { const { chrome, service } = await start(); - const promise = Rx.combineLatest( - chrome.getBrand$(), - chrome.getApplicationClasses$(), + const promise = Rx.combineLatest([ chrome.getIsNavDrawerLocked$(), chrome.getBreadcrumbs$(), chrome.getIsVisible$(), - chrome.getHelpExtension$() - ).toPromise(); + chrome.getHelpExtension$(), + ]).toPromise(); service.stop(); await promise; @@ -539,14 +463,12 @@ describe('stop', () => { service.stop(); await expect( - Rx.combineLatest( - chrome.getBrand$(), - chrome.getApplicationClasses$(), + Rx.combineLatest([ chrome.getIsNavDrawerLocked$(), chrome.getBreadcrumbs$(), chrome.getIsVisible$(), - chrome.getHelpExtension$() - ).toPromise() + chrome.getHelpExtension$(), + ]).toPromise() ).resolves.toBe(undefined); }); }); diff --git a/src/core/public/chrome/chrome_service.tsx b/src/core/public/chrome/chrome_service.tsx index f1381c52ce779..5740e1739280a 100644 --- a/src/core/public/chrome/chrome_service.tsx +++ b/src/core/public/chrome/chrome_service.tsx @@ -26,7 +26,6 @@ import { ChromeRecentlyAccessed, RecentlyAccessedService } from './recently_acce import { Header } from './ui'; import { ChromeBadge, - ChromeBrand, ChromeBreadcrumb, ChromeBreadcrumbsAppendExtension, ChromeHelpExtension, @@ -105,9 +104,6 @@ export class ChromeService { }: StartDeps): Promise { this.initVisibility(application); - const appTitle$ = new BehaviorSubject('Kibana'); - const brand$ = new BehaviorSubject({}); - const applicationClasses$ = new BehaviorSubject>(new Set()); const helpExtension$ = new BehaviorSubject(undefined); const breadcrumbs$ = new BehaviorSubject([]); const breadcrumbsAppendExtension$ = new BehaviorSubject< @@ -210,7 +206,6 @@ export class ChromeService {
), - setAppTitle: (appTitle: string) => appTitle$.next(appTitle), - - getBrand$: () => brand$.pipe(takeUntil(this.stop$)), - - setBrand: (brand: ChromeBrand) => { - brand$.next( - Object.freeze({ - logo: brand.logo, - smallLogo: brand.smallLogo, - }) - ); - }, - getIsVisible$: () => this.isVisible$, setIsVisible: (isVisible: boolean) => this.isForceHidden$.next(!isVisible), - getApplicationClasses$: () => - applicationClasses$.pipe( - map((set) => [...set]), - takeUntil(this.stop$) - ), - - addApplicationClass: (className: string) => { - const update = new Set([...applicationClasses$.getValue()]); - update.add(className); - applicationClasses$.next(update); - }, - - removeApplicationClass: (className: string) => { - const update = new Set([...applicationClasses$.getValue()]); - update.delete(className); - applicationClasses$.next(update); - }, - getBadge$: () => badge$.pipe(takeUntil(this.stop$)), setBadge: (badge: ChromeBadge) => { diff --git a/src/core/public/chrome/index.ts b/src/core/public/chrome/index.ts index dd7affcdbf7cd..b1a70c1dc2b04 100644 --- a/src/core/public/chrome/index.ts +++ b/src/core/public/chrome/index.ts @@ -29,7 +29,6 @@ export type { ChromeHelpExtension, ChromeBreadcrumbsAppendExtension, ChromeBreadcrumb, - ChromeBrand, ChromeBadge, ChromeUserBanner, } from './types'; diff --git a/src/core/public/chrome/types.ts b/src/core/public/chrome/types.ts index 732236f1ba4a1..813f385fc94d2 100644 --- a/src/core/public/chrome/types.ts +++ b/src/core/public/chrome/types.ts @@ -22,12 +22,6 @@ export interface ChromeBadge { iconType?: IconType; } -/** @public */ -export interface ChromeBrand { - logo?: string; - smallLogo?: string; -} - /** @public */ export type ChromeBreadcrumb = EuiBreadcrumb; @@ -93,40 +87,6 @@ export interface ChromeStart { /** {@inheritdoc ChromeDocTitle} */ docTitle: ChromeDocTitle; - /** - * Sets the current app's title - * - * @internalRemarks - * This should be handled by the application service once it is in charge - * of mounting applications. - */ - setAppTitle(appTitle: string): void; - - /** - * Get an observable of the current brand information. - */ - getBrand$(): Observable; - - /** - * Set the brand configuration. - * - * @remarks - * Normally the `logo` property will be rendered as the - * CSS background for the home link in the chrome navigation, but when the page is - * rendered in a small window the `smallLogo` will be used and rendered at about - * 45px wide. - * - * @example - * ```js - * chrome.setBrand({ - * logo: 'url(/plugins/app/logo.png) center no-repeat' - * smallLogo: 'url(/plugins/app/logo-small.png) center no-repeat' - * }) - * ``` - * - */ - setBrand(brand: ChromeBrand): void; - /** * Get an observable of the current visibility state of the chrome. */ @@ -139,21 +99,6 @@ export interface ChromeStart { */ setIsVisible(isVisible: boolean): void; - /** - * Get the current set of classNames that will be set on the application container. - */ - getApplicationClasses$(): Observable; - - /** - * Add a className that should be set on the application container. - */ - addApplicationClass(className: string): void; - - /** - * Remove a className added with `addApplicationClass()`. If className is unknown it is ignored. - */ - removeApplicationClass(className: string): void; - /** * Get an observable of the current badge */ @@ -232,6 +177,7 @@ export interface InternalChromeStart extends ChromeStart { * @internal */ getHeaderComponent(): JSX.Element; + /** * Used only by the rendering service to retrieve the set of classNames * that will be set on the body element. diff --git a/src/core/public/chrome/ui/header/__snapshots__/header.test.tsx.snap b/src/core/public/chrome/ui/header/__snapshots__/header.test.tsx.snap index d2bc11f4db877..4450533090c7f 100644 --- a/src/core/public/chrome/ui/header/__snapshots__/header.test.tsx.snap +++ b/src/core/public/chrome/ui/header/__snapshots__/header.test.tsx.snap @@ -9,45 +9,7 @@ exports[`Header renders 1`] = ` "closed": false, "hasError": false, "isStopped": false, - "observers": Array [ - Subscriber { - "_parentOrParents": null, - "_subscriptions": Array [ - SubjectSubscription { - "_parentOrParents": [Circular], - "_subscriptions": null, - "closed": false, - "subject": [Circular], - "subscriber": [Circular], - }, - ], - "closed": false, - "destination": SafeSubscriber { - "_complete": undefined, - "_context": [Circular], - "_error": undefined, - "_next": [Function], - "_parentOrParents": null, - "_parentSubscriber": [Circular], - "_subscriptions": null, - "closed": false, - "destination": Object { - "closed": true, - "complete": [Function], - "error": [Function], - "next": [Function], - }, - "isStopped": false, - "syncErrorThrowable": false, - "syncErrorThrown": false, - "syncErrorValue": null, - }, - "isStopped": false, - "syncErrorThrowable": true, - "syncErrorThrown": false, - "syncErrorValue": null, - }, - ], + "observers": Array [], "thrownError": null, } } @@ -4713,55 +4675,6 @@ exports[`Header renders 1`] = ` + + + Kibana + + + +`; diff --git a/src/core/public/chrome/ui/header/header.tsx b/src/core/public/chrome/ui/header/header.tsx index a401195b38942..578c87411e543 100644 --- a/src/core/public/chrome/ui/header/header.tsx +++ b/src/core/public/chrome/ui/header/header.tsx @@ -52,7 +52,6 @@ export interface HeaderProps { kibanaVersion: string; application: InternalApplicationStart; headerBanner$: Observable; - appTitle$: Observable; badge$: Observable; breadcrumbs$: Observable; breadcrumbsAppendExtension$: Observable; @@ -102,9 +101,7 @@ export function Header({ const toggleCollapsibleNavRef = createRef void }>(); const className = classnames('hide-for-sharing', 'headerGlobalNav'); - const Breadcrumbs = ( - - ); + const Breadcrumbs = ; return ( <> diff --git a/src/core/public/chrome/ui/header/header_breadcrumbs.test.tsx b/src/core/public/chrome/ui/header/header_breadcrumbs.test.tsx index 26b397229d7e9..7d40bd77e2548 100644 --- a/src/core/public/chrome/ui/header/header_breadcrumbs.test.tsx +++ b/src/core/public/chrome/ui/header/header_breadcrumbs.test.tsx @@ -15,9 +15,7 @@ import { HeaderBreadcrumbs } from './header_breadcrumbs'; describe('HeaderBreadcrumbs', () => { it('renders updates to the breadcrumbs$ observable', () => { const breadcrumbs$ = new BehaviorSubject([{ text: 'First' }]); - const wrapper = mount( - - ); + const wrapper = mount(); expect(wrapper.find('.euiBreadcrumb')).toMatchSnapshot(); act(() => breadcrumbs$.next([{ text: 'First' }, { text: 'Second' }])); diff --git a/src/core/public/chrome/ui/header/header_breadcrumbs.tsx b/src/core/public/chrome/ui/header/header_breadcrumbs.tsx index 0e2bae82a3ad3..a90ceed32dcce 100644 --- a/src/core/public/chrome/ui/header/header_breadcrumbs.tsx +++ b/src/core/public/chrome/ui/header/header_breadcrumbs.tsx @@ -14,17 +14,15 @@ import { Observable } from 'rxjs'; import { ChromeBreadcrumb } from '../../types'; interface Props { - appTitle$: Observable; breadcrumbs$: Observable; } -export function HeaderBreadcrumbs({ appTitle$, breadcrumbs$ }: Props) { - const appTitle = useObservable(appTitle$, 'Kibana'); +export function HeaderBreadcrumbs({ breadcrumbs$ }: Props) { const breadcrumbs = useObservable(breadcrumbs$, []); let crumbs = breadcrumbs; - if (breadcrumbs.length === 0 && appTitle) { - crumbs = [{ text: appTitle }]; + if (breadcrumbs.length === 0) { + crumbs = [{ text: 'Kibana' }]; } crumbs = crumbs.map((breadcrumb, i) => ({ diff --git a/src/core/public/index.ts b/src/core/public/index.ts index e6e6433291873..d343a0b081fa1 100644 --- a/src/core/public/index.ts +++ b/src/core/public/index.ts @@ -28,7 +28,6 @@ import './index.scss'; import { ChromeBadge, - ChromeBrand, ChromeBreadcrumb, ChromeHelpExtension, ChromeHelpExtensionMenuLink, @@ -287,7 +286,6 @@ export interface CoreStart { export type { Capabilities, ChromeBadge, - ChromeBrand, ChromeBreadcrumb, ChromeHelpExtension, ChromeHelpExtensionMenuLink, diff --git a/src/core/public/public.api.md b/src/core/public/public.api.md index d3f9ce71379b7..2217b71d2f1a3 100644 --- a/src/core/public/public.api.md +++ b/src/core/public/public.api.md @@ -231,14 +231,6 @@ export interface ChromeBadge { tooltip: string; } -// @public (undocumented) -export interface ChromeBrand { - // (undocumented) - logo?: string; - // (undocumented) - smallLogo?: string; -} - // @public (undocumented) export type ChromeBreadcrumb = EuiBreadcrumb; @@ -355,11 +347,8 @@ export interface ChromeRecentlyAccessedHistoryItem { // @public export interface ChromeStart { - addApplicationClass(className: string): void; docTitle: ChromeDocTitle; - getApplicationClasses$(): Observable; getBadge$(): Observable; - getBrand$(): Observable; getBreadcrumbs$(): Observable; // Warning: (ae-forgotten-export) The symbol "ChromeBreadcrumbsAppendExtension" needs to be exported by the entry point index.d.ts getBreadcrumbsAppendExtension$(): Observable; @@ -370,10 +359,7 @@ export interface ChromeStart { navControls: ChromeNavControls; navLinks: ChromeNavLinks; recentlyAccessed: ChromeRecentlyAccessed; - removeApplicationClass(className: string): void; - setAppTitle(appTitle: string): void; setBadge(badge?: ChromeBadge): void; - setBrand(brand: ChromeBrand): void; setBreadcrumbs(newBreadcrumbs: ChromeBreadcrumb[]): void; setBreadcrumbsAppendExtension(breadcrumbsAppendExtension?: ChromeBreadcrumbsAppendExtension): void; setCustomNavLink(newCustomNavLink?: Partial): void; diff --git a/src/core/public/rendering/app_containers.test.tsx b/src/core/public/rendering/app_containers.test.tsx index 193e393f268f0..10f5f3f1c138f 100644 --- a/src/core/public/rendering/app_containers.test.tsx +++ b/src/core/public/rendering/app_containers.test.tsx @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { BehaviorSubject, of } from 'rxjs'; +import { BehaviorSubject } from 'rxjs'; import { act } from 'react-dom/test-utils'; import { mount } from 'enzyme'; import React from 'react'; @@ -17,11 +17,7 @@ describe('AppWrapper', () => { it('toggles the `hidden-chrome` class depending on the chrome visibility state', () => { const chromeVisible$ = new BehaviorSubject(true); - const component = mount( - - app-content - - ); + const component = mount(app-content); expect(component.getDOMNode()).toMatchInlineSnapshot(`
{
`); }); - - it('adds classes supplied by chrome', () => { - const chromeVisible$ = new BehaviorSubject(true); - const appClasses$ = new BehaviorSubject([]); - - const component = mount( - - app-content - - ); - expect(component.getDOMNode()).toMatchInlineSnapshot(` -
- app-content -
- `); - - act(() => appClasses$.next(['classA', 'classB'])); - component.update(); - expect(component.getDOMNode()).toMatchInlineSnapshot(` -
- app-content -
- `); - - act(() => appClasses$.next(['classC'])); - component.update(); - expect(component.getDOMNode()).toMatchInlineSnapshot(` -
- app-content -
- `); - - act(() => appClasses$.next([])); - component.update(); - expect(component.getDOMNode()).toMatchInlineSnapshot(` -
- app-content -
- `); - }); }); diff --git a/src/core/public/rendering/app_containers.tsx b/src/core/public/rendering/app_containers.tsx index 64d64d2caad75..2a8e944205910 100644 --- a/src/core/public/rendering/app_containers.tsx +++ b/src/core/public/rendering/app_containers.tsx @@ -14,18 +14,10 @@ import { APP_WRAPPER_CLASS } from '../../utils'; export const AppWrapper: React.FunctionComponent<{ chromeVisible$: Observable; - classes$: Observable; -}> = ({ chromeVisible$, classes$, children }) => { +}> = ({ chromeVisible$, children }) => { const visible = useObservable(chromeVisible$); - const classes = useObservable(classes$, ['']); return ( -
+
{children}
); diff --git a/src/core/public/rendering/rendering_service.test.tsx b/src/core/public/rendering/rendering_service.test.tsx index d9eb764fc9f0d..bdca628b295c6 100644 --- a/src/core/public/rendering/rendering_service.test.tsx +++ b/src/core/public/rendering/rendering_service.test.tsx @@ -13,7 +13,7 @@ import { RenderingService } from './rendering_service'; import { applicationServiceMock } from '../application/application_service.mock'; import { chromeServiceMock } from '../chrome/chrome_service.mock'; import { overlayServiceMock } from '../overlays/overlay_service.mock'; -import { BehaviorSubject, of } from 'rxjs'; +import { BehaviorSubject } from 'rxjs'; describe('RenderingService#start', () => { let application: ReturnType; @@ -28,7 +28,6 @@ describe('RenderingService#start', () => { chrome = chromeServiceMock.createStartContract(); chrome.getHeaderComponent.mockReturnValue(
Hello chrome!
); - chrome.getApplicationClasses$.mockReturnValue(of([])); overlays = overlayServiceMock.createStartContract(); overlays.banners.getComponent.mockReturnValue(
I'm a banner!
); @@ -78,26 +77,6 @@ describe('RenderingService#start', () => { expect(appWrapper.className).toEqual('kbnAppWrapper'); }); - it('adds the application classes to the AppWrapper', () => { - const applicationClasses$ = new BehaviorSubject([]); - const isVisible$ = new BehaviorSubject(true); - chrome.getIsVisible$.mockReturnValue(isVisible$); - chrome.getApplicationClasses$.mockReturnValue(applicationClasses$); - startService(); - - const appContainer = targetDomElement.querySelector('div.kbnAppWrapper')!; - expect(appContainer.className).toEqual('kbnAppWrapper'); - - act(() => applicationClasses$.next(['classA', 'classB'])); - expect(appContainer.className).toEqual('kbnAppWrapper classA classB'); - - act(() => applicationClasses$.next(['classC'])); - expect(appContainer.className).toEqual('kbnAppWrapper classC'); - - act(() => applicationClasses$.next([])); - expect(appContainer.className).toEqual('kbnAppWrapper'); - }); - it('contains wrapper divs', () => { startService(); expect(targetDomElement.querySelector('div.kbnAppWrapper')).toBeDefined(); diff --git a/src/core/public/rendering/rendering_service.tsx b/src/core/public/rendering/rendering_service.tsx index 1dfb4259d7d70..d3f91851370d5 100644 --- a/src/core/public/rendering/rendering_service.tsx +++ b/src/core/public/rendering/rendering_service.tsx @@ -56,10 +56,7 @@ export class RenderingService {
{bannerComponent}
{/* The App Wrapper outside of the fixed headers that accepts custom class names from apps */} - + {/* Affixes a div to restrict the position of charts tooltip to the visible viewport minus the header */}
From b1e531e3d585926234bade15b678eda09767e387 Mon Sep 17 00:00:00 2001 From: Kaarina Tungseth Date: Fri, 20 Aug 2021 10:39:34 -0500 Subject: [PATCH 28/76] [DOCS] Reformats the Alerting and action settings tables into definition lists (#107964) (#109498) Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- docs/settings/alert-action-settings.asciidoc | 289 ++++++++----------- 1 file changed, 126 insertions(+), 163 deletions(-) diff --git a/docs/settings/alert-action-settings.asciidoc b/docs/settings/alert-action-settings.asciidoc index 0f7ad56fe5e7a..2086a0490d052 100644 --- a/docs/settings/alert-action-settings.asciidoc +++ b/docs/settings/alert-action-settings.asciidoc @@ -13,59 +13,48 @@ Alerts and actions are enabled by default in {kib}, but require you configure th You can configure the following settings in the `kibana.yml` file. - [float] [[general-alert-action-settings]] ==== General settings -[cols="2*<"] -|=== - -| `xpack.encryptedSavedObjects` -`.encryptionKey` - | A string of 32 or more characters used to encrypt sensitive properties on alerting rules and actions before they're stored in {es}. Third party credentials — such as the username and password used to connect to an SMTP service — are an example of encrypted properties. + - + - {kib} offers a <> to help generate this encryption key. + - + - If not set, {kib} will generate a random key on startup, but all alerting and action functions will be blocked. Generated keys are not allowed for alerting and actions because when a new key is generated on restart, existing encrypted data becomes inaccessible. For the same reason, alerting and actions in high-availability deployments of {kib} will behave unexpectedly if the key isn't the same on all instances of {kib}. + - + - Although the key can be specified in clear text in `kibana.yml`, it's recommended to store this key securely in the <>. - Be sure to back up the encryption key value somewhere safe, as your alerting rules and actions will cease to function due to decryption failures should you lose it. If you want to rotate the encryption key, be sure to follow the instructions on <>. - -|=== +`xpack.encryptedSavedObjects.encryptionKey`:: +A string of 32 or more characters used to encrypt sensitive properties on alerting rules and actions before they're stored in {es}. Third party credentials — such as the username and password used to connect to an SMTP service — are an example of encrypted properties. ++ +{kib} offers a <> to help generate this encryption key. ++ +If not set, {kib} will generate a random key on startup, but all alerting and action functions will be blocked. Generated keys are not allowed for alerting and actions because when a new key is generated on restart, existing encrypted data becomes inaccessible. For the same reason, alerting and actions in high-availability deployments of {kib} will behave unexpectedly if the key isn't the same on all instances of {kib}. ++ +Although the key can be specified in clear text in `kibana.yml`, it's recommended to store this key securely in the <>. +Be sure to back up the encryption key value somewhere safe, as your alerting rules and actions will cease to function due to decryption failures should you lose it. If you want to rotate the encryption key, be sure to follow the instructions on <>. [float] [[action-settings]] ==== Action settings -[cols="2*<"] -|=== -| `xpack.actions.enabled` - | Deprecated. This will be removed in 8.0. Feature toggle that enables Actions in {kib}. - If `false`, all features dependent on Actions are disabled, including the *Observability* and *Security* apps. Default: `true`. - -| `xpack.actions.allowedHosts` {ess-icon} - | A list of hostnames that {kib} is allowed to connect to when built-in actions are triggered. It defaults to `[*]`, allowing any host, but keep in mind the potential for SSRF attacks when hosts are not explicitly added to the allowed hosts. An empty list `[]` can be used to block built-in actions from making any external connections. + - + - Note that hosts associated with built-in actions, such as Slack and PagerDuty, are not automatically added to allowed hosts. If you are not using the default `[*]` setting, you must ensure that the corresponding endpoints are added to the allowed hosts as well. - -| `xpack.actions.customHostSettings` {ess-icon} - | A list of custom host settings to override existing global settings. - Default: an empty list. + - + - Each entry in the list must have a `url` property, to associate a connection - type (mail or https), hostname and port with the remaining options in the - entry. - + - In the following example, two custom host settings - are defined. The first provides a custom host setting for mail server - `mail.example.com` using port 465 that supplies server certificate authorization - data from both a file and inline, and requires TLS for the - connection. The second provides a custom host setting for https server - `webhook.example.com` which turns off server certificate authorization. - -|=== - +`xpack.actions.enabled`:: +Feature toggle that enables Actions in {kib}. +If `false`, all features dependent on Actions are disabled, including the *Observability* and *Security* apps. Default: `true`. + +`xpack.actions.allowedHosts` {ess-icon}:: +A list of hostnames that {kib} is allowed to connect to when built-in actions are triggered. It defaults to `[*]`, allowing any host, but keep in mind the potential for SSRF attacks when hosts are not explicitly added to the allowed hosts. An empty list `[]` can be used to block built-in actions from making any external connections. ++ +Note that hosts associated with built-in actions, such as Slack and PagerDuty, are not automatically added to allowed hosts. If you are not using the default `[*]` setting, you must ensure that the corresponding endpoints are added to the allowed hosts as well. + +`xpack.actions.customHostSettings` {ess-icon}:: +A list of custom host settings to override existing global settings. +Default: an empty list. ++ +Each entry in the list must have a `url` property, to associate a connection +type (mail or https), hostname and port with the remaining options in the +entry. ++ +In the following example, two custom host settings +are defined. The first provides a custom host setting for mail server +`mail.example.com` using port 465 that supplies server certificate authorization +data from both a file and inline, and requires TLS for the +connection. The second provides a custom host setting for https server +`webhook.example.com` which turns off server certificate authorization. ++ [source,yaml] -- xpack.actions.customHostSettings: @@ -86,132 +75,106 @@ xpack.actions.customHostSettings: verificationMode: 'none' -- -[cols="2*<"] -|=== - -| `xpack.actions.customHostSettings[n]` -`.url` {ess-icon} - | A URL associated with this custom host setting. Should be in the form of - `protocol://hostname:port`, where `protocol` is `https` or `smtp`. If the - port is not provided, 443 is used for `https` and 25 is used for - `smtp`. The `smtp` URLs are used for the Email actions that use this - server, and the `https` URLs are used for actions which use `https` to - connect to services. + - + - Entries with `https` URLs can use the `ssl` options, and entries with `smtp` - URLs can use both the `ssl` and `smtp` options. + - + - No other URL values should be part of this URL, including paths, - query strings, and authentication information. When an http or smtp request - is made as part of executing an action, only the protocol, hostname, and - port of the URL for that request are used to look up these configuration - values. - -| `xpack.actions.customHostSettings[n]` -`.smtp.ignoreTLS` {ess-icon} - | A boolean value indicating that TLS must not be used for this connection. - The options `smtp.ignoreTLS` and `smtp.requireTLS` can not both be set to true. - -| `xpack.actions.customHostSettings[n]` -`.smtp.requireTLS` {ess-icon} - | A boolean value indicating that TLS must be used for this connection. - The options `smtp.ignoreTLS` and `smtp.requireTLS` can not both be set to true. - -| `xpack.actions.customHostSettings[n]` -`.ssl.rejectUnauthorized` - | Deprecated. Use <> instead. A boolean value indicating whether to bypass server certificate validation. - Overrides the general `xpack.actions.rejectUnauthorized` configuration - for requests made for this hostname/port. - -|[[action-config-custom-host-verification-mode]] `xpack.actions.customHostSettings[n]` -`.ssl.verificationMode` {ess-icon} - | Controls the verification of the server certificate that {hosted-ems} receives when making an outbound SSL/TLS connection to the host server. Valid values are `full`, `certificate`, and `none`. - Use `full` to perform hostname verification, `certificate` to skip hostname verification, and `none` to skip verification. Default: `full`. <>. Overrides the general `xpack.actions.ssl.verificationMode` configuration - for requests made for this hostname/port. - -| `xpack.actions.customHostSettings[n]` -`.ssl.certificateAuthoritiesFiles` - | A file name or list of file names of PEM-encoded certificate files to use - to validate the server. - -| `xpack.actions.customHostSettings[n]` -`.ssl.certificateAuthoritiesData` {ess-icon} - | The contents of a PEM-encoded certificate file, or multiple files appended - into a single string. This configuration can be used for environments where - the files cannot be made available. - -| `xpack.actions.enabledActionTypes` {ess-icon} - | A list of action types that are enabled. It defaults to `[*]`, enabling all types. The names for built-in {kib} action types are prefixed with a `.` and include: `.server-log`, `.slack`, `.email`, `.index`, `.pagerduty`, and `.webhook`. An empty list `[]` will disable all action types. + - + - Disabled action types will not appear as an option when creating new connectors, but existing connectors and actions of that type will remain in {kib} and will not function. - -| `xpack.actions` -`.preconfiguredAlertHistoryEsIndex` {ess-icon} - | Enables a preconfigured alert history {es} <> connector. Default: `false`. - -| `xpack.actions.preconfigured` - | Specifies preconfigured connector IDs and configs. Default: {}. - -| `xpack.actions.proxyUrl` {ess-icon} - | Specifies the proxy URL to use, if using a proxy for actions. By default, no proxy is used. - -| `xpack.actions.proxyBypassHosts` {ess-icon} - | Specifies hostnames which should not use the proxy, if using a proxy for actions. The value is an array of hostnames as strings. By default, all hosts will use the proxy, but if an action's hostname is in this list, the proxy will not be used. The settings `xpack.actions.proxyBypassHosts` and `xpack.actions.proxyOnlyHosts` cannot be used at the same time. - -| `xpack.actions.proxyOnlyHosts` {ess-icon} - | Specifies hostnames which should only use the proxy, if using a proxy for actions. The value is an array of hostnames as strings. By default, no hosts will use the proxy, but if an action's hostname is in this list, the proxy will be used. The settings `xpack.actions.proxyBypassHosts` and `xpack.actions.proxyOnlyHosts` cannot be used at the same time. - -| `xpack.actions.proxyHeaders` {ess-icon} - | Specifies HTTP headers for the proxy, if using a proxy for actions. Default: {}. - -a|`xpack.actions.` -`proxyRejectUnauthorizedCertificates` {ess-icon} - | Deprecated. Use <> instead. Set to `false` to bypass certificate validation for the proxy, if using a proxy for actions. Default: `true`. - -|[[action-config-proxy-verification-mode]] -`xpack.actions[n]` -`.ssl.proxyVerificationMode` {ess-icon} -| Controls the verification for the proxy server certificate that {hosted-ems} receives when making an outbound SSL/TLS connection to the proxy server. Valid values are `full`, `certificate`, and `none`. +`xpack.actions.customHostSettings[n].url` {ess-icon}:: +A URL associated with this custom host setting. Should be in the form of +`protocol://hostname:port`, where `protocol` is `https` or `smtp`. If the +port is not provided, 443 is used for `https` and 25 is used for +`smtp`. The `smtp` URLs are used for the Email actions that use this +server, and the `https` URLs are used for actions which use `https` to +connect to services. ++ +Entries with `https` URLs can use the `ssl` options, and entries with `smtp` +URLs can use both the `ssl` and `smtp` options. ++ +No other URL values should be part of this URL, including paths, +query strings, and authentication information. When an http or smtp request +is made as part of executing an action, only the protocol, hostname, and +port of the URL for that request are used to look up these configuration +values. + +`xpack.actions.customHostSettings[n].smtp.ignoreTLS` {ess-icon}:: +A boolean value indicating that TLS must not be used for this connection. +The options `smtp.ignoreTLS` and `smtp.requireTLS` can not both be set to true. + +`xpack.actions.customHostSettings[n].smtp.requireTLS` {ess-icon}:: +A boolean value indicating that TLS must be used for this connection. +The options `smtp.ignoreTLS` and `smtp.requireTLS` can not both be set to true. + +`xpack.actions.customHostSettings[n].ssl.rejectUnauthorized`:: +Deprecated. Use <> instead. A boolean value indicating whether to bypass server certificate validation. +Overrides the general `xpack.actions.rejectUnauthorized` configuration +for requests made for this hostname/port. + +[[action-config-custom-host-verification-mode]] `xpack.actions.customHostSettings[n].ssl.verificationMode` {ess-icon}:: +Controls the verification of the server certificate that {hosted-ems} receives when making an outbound SSL/TLS connection to the host server. Valid values are `full`, `certificate`, and `none`. +Use `full` to perform hostname verification, `certificate` to skip hostname verification, and `none` to skip verification. Default: `full`. <>. Overrides the general `xpack.actions.ssl.verificationMode` configuration +for requests made for this hostname/port. + +`xpack.actions.customHostSettings[n].ssl.certificateAuthoritiesFiles`:: +A file name or list of file names of PEM-encoded certificate files to use +to validate the server. + +`xpack.actions.customHostSettings[n].ssl.certificateAuthoritiesData` {ess-icon}:: +The contents of a PEM-encoded certificate file, or multiple files appended +into a single string. This configuration can be used for environments where +the files cannot be made available. + +`xpack.actions.enabledActionTypes` {ess-icon}:: +A list of action types that are enabled. It defaults to `[*]`, enabling all types. The names for built-in {kib} action types are prefixed with a `.` and include: `.server-log`, `.slack`, `.email`, `.index`, `.pagerduty`, and `.webhook`. An empty list `[]` will disable all action types. ++ +Disabled action types will not appear as an option when creating new connectors, but existing connectors and actions of that type will remain in {kib} and will not function. + +`xpack.actions.preconfiguredAlertHistoryEsIndex` {ess-icon}:: +Enables a preconfigured alert history {es} <> connector. Default: `false`. + +`xpack.actions.preconfigured`:: +Specifies preconfigured connector IDs and configs. Default: {}. + +`xpack.actions.proxyUrl` {ess-icon}:: +Specifies the proxy URL to use, if using a proxy for actions. By default, no proxy is used. + +`xpack.actions.proxyBypassHosts` {ess-icon}:: +Specifies hostnames which should not use the proxy, if using a proxy for actions. The value is an array of hostnames as strings. By default, all hosts will use the proxy, but if an action's hostname is in this list, the proxy will not be used. The settings `xpack.actions.proxyBypassHosts` and `xpack.actions.proxyOnlyHosts` cannot be used at the same time. + +`xpack.actions.proxyOnlyHosts` {ess-icon}:: +Specifies hostnames which should only use the proxy, if using a proxy for actions. The value is an array of hostnames as strings. By default, no hosts will use the proxy, but if an action's hostname is in this list, the proxy will be used. The settings `xpack.actions.proxyBypassHosts` and `xpack.actions.proxyOnlyHosts` cannot be used at the same time. + +`xpack.actions.proxyHeaders` {ess-icon}:: +Specifies HTTP headers for the proxy, if using a proxy for actions. Default: {}. + +`xpack.actions.proxyRejectUnauthorizedCertificates` {ess-icon}:: +Deprecated. Use <> instead. Set to `false` to bypass certificate validation for the proxy, if using a proxy for actions. Default: `true`. + +[[action-config-proxy-verification-mode]]`xpack.actions[n].ssl.proxyVerificationMode` {ess-icon}:: +Controls the verification for the proxy server certificate that {hosted-ems} receives when making an outbound SSL/TLS connection to the proxy server. Valid values are `full`, `certificate`, and `none`. Use `full` to perform hostname verification, `certificate` to skip hostname verification, and `none` to skip verification. Default: `full`. <>. -| `xpack.actions.rejectUnauthorized` {ess-icon} - | Deprecated. Use <> instead. Set to `false` to bypass certificate validation for actions. Default: `true`. + - + - As an alternative to setting `xpack.actions.rejectUnauthorized`, you can use the setting - `xpack.actions.customHostSettings` to set SSL options for specific servers. - -|[[action-config-verification-mode]] -`xpack.actions[n]` -`.ssl.verificationMode` {ess-icon} -| Controls the verification for the server certificate that {hosted-ems} receives when making an outbound SSL/TLS connection for actions. Valid values are `full`, `certificate`, and `none`. - Use `full` to perform hostname verification, `certificate` to skip hostname verification, and `none` to skip verification. Default: `full`. <>. + - + - As an alternative to setting `xpack.actions.ssl.verificationMode`, you can use the setting - `xpack.actions.customHostSettings` to set SSL options for specific servers. - +`xpack.actions.rejectUnauthorized` {ess-icon}:: +Deprecated. Use <> instead. Set to `false` to bypass certificate validation for actions. Default: `true`. ++ +As an alternative to setting `xpack.actions.rejectUnauthorized`, you can use the setting +`xpack.actions.customHostSettings` to set SSL options for specific servers. +[[action-config-verification-mode]] `xpack.actions[n].ssl.verificationMode` {ess-icon}:: +Controls the verification for the server certificate that {hosted-ems} receives when making an outbound SSL/TLS connection for actions. Valid values are `full`, `certificate`, and `none`. +Use `full` to perform hostname verification, `certificate` to skip hostname verification, and `none` to skip verification. Default: `full`. <>. ++ +As an alternative to setting `xpack.actions.ssl.verificationMode`, you can use the setting +`xpack.actions.customHostSettings` to set SSL options for specific servers. -| `xpack.actions.maxResponseContentLength` {ess-icon} - | Specifies the max number of bytes of the http response for requests to external resources. Default: 1000000 (1MB). - -| `xpack.actions.responseTimeout` {ess-icon} - | Specifies the time allowed for requests to external resources. Requests that take longer are aborted. The time is formatted as: + - + - `[ms,s,m,h,d,w,M,Y]` + - + - For example, `20m`, `24h`, `7d`, `1w`. Default: `60s`. - +`xpack.actions.maxResponseContentLength` {ess-icon}:: +Specifies the max number of bytes of the http response for requests to external resources. Default: 1000000 (1MB). -|=== +`xpack.actions.responseTimeout` {ess-icon}:: +Specifies the time allowed for requests to external resources. Requests that take longer are aborted. The time is formatted as: ++ +`[ms,s,m,h,d,w,M,Y]` ++ +For example, `20m`, `24h`, `7d`, `1w`. Default: `60s`. [float] [[alert-settings]] ==== Alerting settings -[cols="2*<"] -|=== - -| `xpack.alerting.maxEphemeralActionsPerAlert` - | Sets the number of actions that will be executed ephemerally. To use this, enable ephemeral tasks in task manager first with <> - -|=== +`xpack.alerting.maxEphemeralActionsPerAlert`:: +Sets the number of actions that will be executed ephemerally. To use this, enable ephemeral tasks in task manager first with <> From 402d1243944e2afa5c86fea8dce2a042bc9129bd Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Fri, 20 Aug 2021 11:51:59 -0400 Subject: [PATCH 29/76] [Cases] Include rule registry client for updating alert statuses (#108588) (#109335) * Trying to get import to work * Plumbed alerts client through and logging errors * No longer need the ES cluster client * Fixing types * Fixing imports * Fixing integration tests and refactoring * Throwing an error when rule registry is disabled * Reworking alert update and get to catch errors * Adding tests and fixing errors Co-authored-by: Jonathan Buttner <56361221+jonathan-buttner@users.noreply.github.com> --- x-pack/plugins/cases/kibana.json | 1 + .../plugins/cases/server/client/alerts/get.ts | 14 +- .../cases/server/client/alerts/types.ts | 12 +- .../server/client/alerts/update_status.ts | 4 +- .../cases/server/client/attachments/add.ts | 34 +- .../plugins/cases/server/client/cases/push.ts | 65 +- .../cases/server/client/cases/update.ts | 27 +- x-pack/plugins/cases/server/client/factory.ts | 19 +- .../cases/server/client/sub_cases/update.ts | 21 +- x-pack/plugins/cases/server/client/types.ts | 3 +- .../server/common/models/commentable_case.ts | 34 +- .../connectors/servicenow/sir_format.test.ts | 159 +- .../connectors/servicenow/sir_format.ts | 36 +- x-pack/plugins/cases/server/plugin.ts | 7 +- .../server/services/alerts/index.test.ts | 81 +- .../cases/server/services/alerts/index.ts | 137 +- .../cases/server/services/alerts/types.ts | 13 + x-pack/plugins/cases/tsconfig.json | 1 + x-pack/plugins/rule_registry/server/index.ts | 1 + x-pack/plugins/rule_registry/server/mocks.ts | 2 + .../tests/common/cases/patch_cases.ts | 10 +- .../common/client/update_alert_status.ts | 6 +- .../tests/common/comments/post_comment.ts | 2 +- .../tests/common/sub_cases/patch_sub_cases.ts | 8 +- .../cases/signals/default/data.json.gz | Bin 5586 -> 3945 bytes .../cases/signals/default/mappings.json | 1926 ++++++++- .../cases/signals/duplicate_ids/data.json.gz | Bin 5513 -> 3876 bytes .../cases/signals/duplicate_ids/mappings.json | 3713 ++++++++++++++++- 28 files changed, 5794 insertions(+), 542 deletions(-) create mode 100644 x-pack/plugins/cases/server/services/alerts/types.ts diff --git a/x-pack/plugins/cases/kibana.json b/x-pack/plugins/cases/kibana.json index ebac6295166df..3889c559238b3 100644 --- a/x-pack/plugins/cases/kibana.json +++ b/x-pack/plugins/cases/kibana.json @@ -10,6 +10,7 @@ "id":"cases", "kibanaVersion":"kibana", "optionalPlugins":[ + "ruleRegistry", "security", "spaces" ], diff --git a/x-pack/plugins/cases/server/client/alerts/get.ts b/x-pack/plugins/cases/server/client/alerts/get.ts index 2048ccae4fa60..391279aab5a83 100644 --- a/x-pack/plugins/cases/server/client/alerts/get.ts +++ b/x-pack/plugins/cases/server/client/alerts/get.ts @@ -12,19 +12,11 @@ export const get = async ( { alertsInfo }: AlertGet, clientArgs: CasesClientArgs ): Promise => { - const { alertsService, scopedClusterClient, logger } = clientArgs; + const { alertsService, logger } = clientArgs; if (alertsInfo.length === 0) { return []; } - const alerts = await alertsService.getAlerts({ alertsInfo, scopedClusterClient, logger }); - if (!alerts) { - return []; - } - - return alerts.docs.map((alert) => ({ - id: alert._id, - index: alert._index, - ...alert._source, - })); + const alerts = await alertsService.getAlerts({ alertsInfo, logger }); + return alerts ?? []; }; diff --git a/x-pack/plugins/cases/server/client/alerts/types.ts b/x-pack/plugins/cases/server/client/alerts/types.ts index 95cd9ae33bff9..6b3a49f20d1e5 100644 --- a/x-pack/plugins/cases/server/client/alerts/types.ts +++ b/x-pack/plugins/cases/server/client/alerts/types.ts @@ -7,17 +7,7 @@ import { CaseStatuses } from '../../../common/api'; import { AlertInfo } from '../../common'; - -interface Alert { - id: string; - index: string; - destination?: { - ip: string; - }; - source?: { - ip: string; - }; -} +import { Alert } from '../../services/alerts/types'; export type CasesClientGetAlertsResponse = Alert[]; diff --git a/x-pack/plugins/cases/server/client/alerts/update_status.ts b/x-pack/plugins/cases/server/client/alerts/update_status.ts index a0684b59241b0..9c8cc33264413 100644 --- a/x-pack/plugins/cases/server/client/alerts/update_status.ts +++ b/x-pack/plugins/cases/server/client/alerts/update_status.ts @@ -16,6 +16,6 @@ export const updateStatus = async ( { alerts }: UpdateAlertsStatusArgs, clientArgs: CasesClientArgs ): Promise => { - const { alertsService, scopedClusterClient, logger } = clientArgs; - await alertsService.updateAlertsStatus({ alerts, scopedClusterClient, logger }); + const { alertsService, logger } = clientArgs; + await alertsService.updateAlertsStatus({ alerts, logger }); }; diff --git a/x-pack/plugins/cases/server/client/attachments/add.ts b/x-pack/plugins/cases/server/client/attachments/add.ts index 166ae2ae65012..5393a108d6af2 100644 --- a/x-pack/plugins/cases/server/client/attachments/add.ts +++ b/x-pack/plugins/cases/server/client/attachments/add.ts @@ -40,12 +40,7 @@ import { } from '../../services/user_actions/helpers'; import { AttachmentService, CasesService, CaseUserActionService } from '../../services'; -import { - createCaseError, - CommentableCase, - createAlertUpdateRequest, - isCommentRequestTypeGenAlert, -} from '../../common'; +import { createCaseError, CommentableCase, isCommentRequestTypeGenAlert } from '../../common'; import { CasesClientArgs, CasesClientInternal } from '..'; import { decodeCommentRequest } from '../utils'; @@ -195,22 +190,9 @@ const addGeneratedAlerts = async ( user: userDetails, commentReq: query, id: savedObjectID, + casesClientInternal, }); - if ( - (newComment.attributes.type === CommentType.alert || - newComment.attributes.type === CommentType.generatedAlert) && - caseInfo.attributes.settings.syncAlerts - ) { - const alertsToUpdate = createAlertUpdateRequest({ - comment: query, - status: subCase.attributes.status, - }); - await casesClientInternal.alerts.updateStatus({ - alerts: alertsToUpdate, - }); - } - await userActionService.bulkCreate({ unsecuredSavedObjectsClient, actions: [ @@ -386,19 +368,9 @@ export const addComment = async ( user: userInfo, commentReq: query, id: savedObjectID, + casesClientInternal, }); - if (newComment.attributes.type === CommentType.alert && updatedCase.settings.syncAlerts) { - const alertsToUpdate = createAlertUpdateRequest({ - comment: query, - status: updatedCase.status, - }); - - await casesClientInternal.alerts.updateStatus({ - alerts: alertsToUpdate, - }); - } - await userActionService.bulkCreate({ unsecuredSavedObjectsClient, actions: [ diff --git a/x-pack/plugins/cases/server/client/cases/push.ts b/x-pack/plugins/cases/server/client/cases/push.ts index 3048cf01bb3ba..80e69d53e9e8b 100644 --- a/x-pack/plugins/cases/server/client/cases/push.ts +++ b/x-pack/plugins/cases/server/client/cases/push.ts @@ -6,7 +6,7 @@ */ import Boom from '@hapi/boom'; -import { SavedObjectsFindResponse, SavedObject } from 'kibana/server'; +import { SavedObjectsFindResponse, SavedObject, Logger } from 'kibana/server'; import { ActionConnector, @@ -22,26 +22,16 @@ import { import { buildCaseUserActionItem } from '../../services/user_actions/helpers'; import { createIncident, getCommentContextFromAttributes } from './utils'; -import { createCaseError, flattenCaseSavedObject, getAlertInfoFromComments } from '../../common'; +import { + AlertInfo, + createCaseError, + flattenCaseSavedObject, + getAlertInfoFromComments, +} from '../../common'; import { CasesClient, CasesClientArgs, CasesClientInternal } from '..'; import { Operations } from '../../authorization'; import { casesConnectors } from '../../connectors'; - -/** - * Returns true if the case should be closed based on the configuration settings and whether the case - * is a collection. Collections are not closable because we aren't allowing their status to be changed. - * In the future we could allow push to close all the sub cases of a collection but that's not currently supported. - */ -function shouldCloseByPush( - configureSettings: SavedObjectsFindResponse, - caseInfo: SavedObject -): boolean { - return ( - configureSettings.total > 0 && - configureSettings.saved_objects[0].attributes.closure_type === 'close-by-pushing' && - caseInfo.attributes.type !== CaseType.collection - ); -} +import { CasesClientGetAlertsResponse } from '../alerts/types'; /** * Parameters for pushing a case to an external system @@ -106,9 +96,7 @@ export const push = async ( const alertsInfo = getAlertInfoFromComments(theCase?.comments); - const alerts = await casesClientInternal.alerts.get({ - alertsInfo, - }); + const alerts = await getAlertsCatchErrors({ casesClientInternal, alertsInfo, logger }); const getMappingsResponse = await casesClientInternal.configuration.getMappings({ connector: theCase.connector, @@ -278,3 +266,38 @@ export const push = async ( throw createCaseError({ message: `Failed to push case: ${error}`, error, logger }); } }; + +async function getAlertsCatchErrors({ + casesClientInternal, + alertsInfo, + logger, +}: { + casesClientInternal: CasesClientInternal; + alertsInfo: AlertInfo[]; + logger: Logger; +}): Promise { + try { + return await casesClientInternal.alerts.get({ + alertsInfo, + }); + } catch (error) { + logger.error(`Failed to retrieve alerts during push: ${error}`); + return []; + } +} + +/** + * Returns true if the case should be closed based on the configuration settings and whether the case + * is a collection. Collections are not closable because we aren't allowing their status to be changed. + * In the future we could allow push to close all the sub cases of a collection but that's not currently supported. + */ +function shouldCloseByPush( + configureSettings: SavedObjectsFindResponse, + caseInfo: SavedObject +): boolean { + return ( + configureSettings.total > 0 && + configureSettings.saved_objects[0].attributes.closure_type === 'close-by-pushing' && + caseInfo.attributes.type !== CaseType.collection + ); +} diff --git a/x-pack/plugins/cases/server/client/cases/update.ts b/x-pack/plugins/cases/server/client/cases/update.ts index ed19444414d57..611c9e09fa76e 100644 --- a/x-pack/plugins/cases/server/client/cases/update.ts +++ b/x-pack/plugins/cases/server/client/cases/update.ts @@ -12,6 +12,7 @@ import { fold } from 'fp-ts/lib/Either'; import { identity } from 'fp-ts/lib/function'; import { + Logger, SavedObject, SavedObjectsClientContract, SavedObjectsFindResponse, @@ -307,12 +308,14 @@ async function updateAlerts({ caseService, unsecuredSavedObjectsClient, casesClientInternal, + logger, }: { casesWithSyncSettingChangedToOn: UpdateRequestWithOriginalCase[]; casesWithStatusChangedAndSynced: UpdateRequestWithOriginalCase[]; caseService: CasesService; unsecuredSavedObjectsClient: SavedObjectsClientContract; casesClientInternal: CasesClientInternal; + logger: Logger; }) { /** * It's possible that a case ID can appear multiple times in each array. I'm intentionally placing the status changes @@ -361,7 +364,9 @@ async function updateAlerts({ [] ); - await casesClientInternal.alerts.updateStatus({ alerts: alertsToUpdate }); + await casesClientInternal.alerts.updateStatus({ + alerts: alertsToUpdate, + }); } function partitionPatchRequest( @@ -562,15 +567,6 @@ export const update = async ( ); }); - // Update the alert's status to match any case status or sync settings changes - await updateAlerts({ - casesWithStatusChangedAndSynced, - casesWithSyncSettingChangedToOn, - caseService, - unsecuredSavedObjectsClient, - casesClientInternal, - }); - const returnUpdatedCase = myCases.saved_objects .filter((myCase) => updatedCases.saved_objects.some((updatedCase) => updatedCase.id === myCase.id) @@ -598,6 +594,17 @@ export const update = async ( }), }); + // Update the alert's status to match any case status or sync settings changes + // Attempt to do this after creating/changing the other entities just in case it fails + await updateAlerts({ + casesWithStatusChangedAndSynced, + casesWithSyncSettingChangedToOn, + caseService, + unsecuredSavedObjectsClient, + casesClientInternal, + logger, + }); + return CasesResponseRt.encode(returnUpdatedCase); } catch (error) { const idVersions = cases.cases.map((caseInfo) => ({ diff --git a/x-pack/plugins/cases/server/client/factory.ts b/x-pack/plugins/cases/server/client/factory.ts index 2fae6996f4aa2..a1a3ccdd3bc52 100644 --- a/x-pack/plugins/cases/server/client/factory.ts +++ b/x-pack/plugins/cases/server/client/factory.ts @@ -5,12 +5,7 @@ * 2.0. */ -import { - KibanaRequest, - SavedObjectsServiceStart, - Logger, - ElasticsearchClient, -} from 'kibana/server'; +import { KibanaRequest, SavedObjectsServiceStart, Logger } from 'kibana/server'; import { SecurityPluginSetup, SecurityPluginStart } from '../../../security/server'; import { SAVED_OBJECT_TYPES } from '../../common'; import { Authorization } from '../authorization/authorization'; @@ -25,8 +20,8 @@ import { } from '../services'; import { PluginStartContract as FeaturesPluginStart } from '../../../features/server'; import { PluginStartContract as ActionsPluginStart } from '../../../actions/server'; +import { RuleRegistryPluginStartContract } from '../../../rule_registry/server'; import { LensServerPluginSetup } from '../../../lens/server'; - import { AuthorizationAuditLogger } from '../authorization'; import { CasesClient, createCasesClient } from '.'; @@ -36,6 +31,7 @@ interface CasesClientFactoryArgs { getSpace: GetSpaceFn; featuresPluginStart: FeaturesPluginStart; actionsPluginStart: ActionsPluginStart; + ruleRegistryPluginStart?: RuleRegistryPluginStartContract; lensEmbeddableFactory: LensServerPluginSetup['lensEmbeddableFactory']; } @@ -69,12 +65,10 @@ export class CasesClientFactory { */ public async create({ request, - scopedClusterClient, savedObjectsService, }: { request: KibanaRequest; savedObjectsService: SavedObjectsServiceStart; - scopedClusterClient: ElasticsearchClient; }): Promise { if (!this.isInitialized || !this.options) { throw new Error('CasesClientFactory must be initialized before calling create'); @@ -94,9 +88,12 @@ export class CasesClientFactory { const caseService = new CasesService(this.logger, this.options?.securityPluginStart?.authc); const userInfo = caseService.getUser({ request }); + const alertsClient = await this.options.ruleRegistryPluginStart?.getRacClientWithRequest( + request + ); + return createCasesClient({ - alertsService: new AlertService(), - scopedClusterClient, + alertsService: new AlertService(alertsClient), unsecuredSavedObjectsClient: savedObjectsService.getScopedClient(request, { includedHiddenTypes: SAVED_OBJECT_TYPES, // this tells the security plugin to not perform SO authorization and audit logging since we are handling diff --git a/x-pack/plugins/cases/server/client/sub_cases/update.ts b/x-pack/plugins/cases/server/client/sub_cases/update.ts index c8cb96cbb6b8c..56610ea6858e3 100644 --- a/x-pack/plugins/cases/server/client/sub_cases/update.ts +++ b/x-pack/plugins/cases/server/client/sub_cases/update.ts @@ -246,7 +246,9 @@ async function updateAlerts({ [] ); - await casesClientInternal.alerts.updateStatus({ alerts: alertsToUpdate }); + await casesClientInternal.alerts.updateStatus({ + alerts: alertsToUpdate, + }); } catch (error) { throw createCaseError({ message: `Failed to update alert status while updating sub cases: ${JSON.stringify( @@ -355,14 +357,6 @@ export async function update({ ); }); - await updateAlerts({ - caseService, - unsecuredSavedObjectsClient, - casesClientInternal, - subCasesToSync: subCasesToSyncAlertsFor, - logger: clientArgs.logger, - }); - const returnUpdatedSubCases = updatedCases.saved_objects.reduce( (acc, updatedSO) => { const originalSubCase = subCasesMap.get(updatedSO.id); @@ -394,6 +388,15 @@ export async function update({ }), }); + // attempt to update the status of the alerts after creating all the user actions just in case it fails + await updateAlerts({ + caseService, + unsecuredSavedObjectsClient, + casesClientInternal, + subCasesToSync: subCasesToSyncAlertsFor, + logger: clientArgs.logger, + }); + return SubCasesResponseRt.encode(returnUpdatedSubCases); } catch (error) { const idVersions = query.subCases.map((subCase) => ({ diff --git a/x-pack/plugins/cases/server/client/types.ts b/x-pack/plugins/cases/server/client/types.ts index 27829d2539c7d..3979c19949d9a 100644 --- a/x-pack/plugins/cases/server/client/types.ts +++ b/x-pack/plugins/cases/server/client/types.ts @@ -6,7 +6,7 @@ */ import type { PublicMethodsOf } from '@kbn/utility-types'; -import { ElasticsearchClient, SavedObjectsClientContract, Logger } from 'kibana/server'; +import { SavedObjectsClientContract, Logger } from 'kibana/server'; import { User } from '../../common'; import { Authorization } from '../authorization/authorization'; import { @@ -24,7 +24,6 @@ import { LensServerPluginSetup } from '../../../lens/server'; * Parameters for initializing a cases client */ export interface CasesClientArgs { - readonly scopedClusterClient: ElasticsearchClient; readonly caseConfigureService: CaseConfigureService; readonly caseService: CasesService; readonly connectorMappingsService: ConnectorMappingsService; diff --git a/x-pack/plugins/cases/server/common/models/commentable_case.ts b/x-pack/plugins/cases/server/common/models/commentable_case.ts index 856d6378d5900..e540332b1ff84 100644 --- a/x-pack/plugins/cases/server/common/models/commentable_case.ts +++ b/x-pack/plugins/cases/server/common/models/commentable_case.ts @@ -34,10 +34,16 @@ import { CommentRequestUserType, CaseAttributes, } from '../../../common'; -import { flattenCommentSavedObjects, flattenSubCaseSavedObject, transformNewComment } from '..'; +import { + createAlertUpdateRequest, + flattenCommentSavedObjects, + flattenSubCaseSavedObject, + transformNewComment, +} from '..'; import { AttachmentService, CasesService } from '../../services'; import { createCaseError } from '../error'; import { countAlertsForID } from '../index'; +import { CasesClientInternal } from '../../client'; import { getOrUpdateLensReferences } from '../utils'; interface UpdateCommentResp { @@ -273,11 +279,13 @@ export class CommentableCase { user, commentReq, id, + casesClientInternal, }: { createdDate: string; user: User; commentReq: CommentRequest; id: string; + casesClientInternal: CasesClientInternal; }): Promise { try { if (commentReq.type === CommentType.alert) { @@ -294,6 +302,10 @@ export class CommentableCase { throw Boom.badRequest('The owner field of the comment must match the case'); } + // Let's try to sync the alert's status before creating the attachment, that way if the alert doesn't exist + // we'll throw an error early before creating the attachment + await this.syncAlertStatus(commentReq, casesClientInternal); + let references = this.buildRefsToCase(); if (commentReq.type === CommentType.user && commentReq?.comment) { @@ -331,6 +343,26 @@ export class CommentableCase { } } + private async syncAlertStatus( + commentRequest: CommentRequest, + casesClientInternal: CasesClientInternal + ) { + if ( + (commentRequest.type === CommentType.alert || + commentRequest.type === CommentType.generatedAlert) && + this.settings.syncAlerts + ) { + const alertsToUpdate = createAlertUpdateRequest({ + comment: commentRequest, + status: this.status, + }); + + await casesClientInternal.alerts.updateStatus({ + alerts: alertsToUpdate, + }); + } + } + private formatCollectionForEncoding(totalComment: number) { return { id: this.collection.id, diff --git a/x-pack/plugins/cases/server/connectors/servicenow/sir_format.test.ts b/x-pack/plugins/cases/server/connectors/servicenow/sir_format.test.ts index fa103d4c1142d..7a1efe8b366d0 100644 --- a/x-pack/plugins/cases/server/connectors/servicenow/sir_format.test.ts +++ b/x-pack/plugins/cases/server/connectors/servicenow/sir_format.test.ts @@ -24,7 +24,7 @@ describe('ITSM formatter', () => { } as CaseResponse; it('it formats correctly without alerts', async () => { - const res = await format(theCase, []); + const res = format(theCase, []); expect(res).toEqual({ dest_ip: null, source_ip: null, @@ -38,7 +38,7 @@ describe('ITSM formatter', () => { it('it formats correctly when fields do not exist ', async () => { const invalidFields = { connector: { fields: null } } as CaseResponse; - const res = await format(invalidFields, []); + const res = format(invalidFields, []); expect(res).toEqual({ dest_ip: null, source_ip: null, @@ -55,25 +55,31 @@ describe('ITSM formatter', () => { { id: 'alert-1', index: 'index-1', - destination: { ip: '192.168.1.1' }, - source: { ip: '192.168.1.2' }, - file: { - hash: { sha256: '9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08' }, + source: { + destination: { ip: '192.168.1.1' }, + source: { ip: '192.168.1.2' }, + file: { + hash: { sha256: '9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08' }, + }, + url: { full: 'https://attack.com' }, }, - url: { full: 'https://attack.com' }, }, { id: 'alert-2', index: 'index-2', - destination: { ip: '192.168.1.4' }, - source: { ip: '192.168.1.3' }, - file: { - hash: { sha256: '60303ae22b998861bce3b28f33eec1be758a213c86c93c076dbe9f558c11c752' }, + source: { + source: { + ip: '192.168.1.3', + }, + destination: { ip: '192.168.1.4' }, + file: { + hash: { sha256: '60303ae22b998861bce3b28f33eec1be758a213c86c93c076dbe9f558c11c752' }, + }, + url: { full: 'https://attack.com/api' }, }, - url: { full: 'https://attack.com/api' }, }, ]; - const res = await format(theCase, alerts); + const res = format(theCase, alerts); expect(res).toEqual({ dest_ip: '192.168.1.1,192.168.1.4', source_ip: '192.168.1.2,192.168.1.3', @@ -86,30 +92,109 @@ describe('ITSM formatter', () => { }); }); + it('it ignores alerts with an error', async () => { + const alerts = [ + { + id: 'alert-1', + index: 'index-1', + error: new Error('an error'), + source: { + destination: { ip: '192.168.1.1' }, + source: { ip: '192.168.1.2' }, + file: { + hash: { sha256: '9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08' }, + }, + url: { full: 'https://attack.com' }, + }, + }, + { + id: 'alert-2', + index: 'index-2', + source: { + source: { + ip: '192.168.1.3', + }, + destination: { ip: '192.168.1.4' }, + file: { + hash: { sha256: '60303ae22b998861bce3b28f33eec1be758a213c86c93c076dbe9f558c11c752' }, + }, + url: { full: 'https://attack.com/api' }, + }, + }, + ]; + const res = format(theCase, alerts); + expect(res).toEqual({ + dest_ip: '192.168.1.4', + source_ip: '192.168.1.3', + category: 'Denial of Service', + subcategory: 'Inbound DDos', + malware_hash: '60303ae22b998861bce3b28f33eec1be758a213c86c93c076dbe9f558c11c752', + malware_url: 'https://attack.com/api', + priority: '2 - High', + }); + }); + + it('it ignores alerts without a source field', async () => { + const alerts = [ + { + id: 'alert-1', + index: 'index-1', + }, + { + id: 'alert-2', + index: 'index-2', + source: { + source: { + ip: '192.168.1.3', + }, + destination: { ip: '192.168.1.4' }, + file: { + hash: { sha256: '60303ae22b998861bce3b28f33eec1be758a213c86c93c076dbe9f558c11c752' }, + }, + url: { full: 'https://attack.com/api' }, + }, + }, + ]; + const res = format(theCase, alerts); + expect(res).toEqual({ + dest_ip: '192.168.1.4', + source_ip: '192.168.1.3', + category: 'Denial of Service', + subcategory: 'Inbound DDos', + malware_hash: '60303ae22b998861bce3b28f33eec1be758a213c86c93c076dbe9f558c11c752', + malware_url: 'https://attack.com/api', + priority: '2 - High', + }); + }); + it('it handles duplicates correctly', async () => { const alerts = [ { id: 'alert-1', index: 'index-1', - destination: { ip: '192.168.1.1' }, - source: { ip: '192.168.1.2' }, - file: { - hash: { sha256: '9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08' }, + source: { + destination: { ip: '192.168.1.1' }, + source: { ip: '192.168.1.2' }, + file: { + hash: { sha256: '9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08' }, + }, + url: { full: 'https://attack.com' }, }, - url: { full: 'https://attack.com' }, }, { id: 'alert-2', index: 'index-2', - destination: { ip: '192.168.1.1' }, - source: { ip: '192.168.1.3' }, - file: { - hash: { sha256: '9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08' }, + source: { + destination: { ip: '192.168.1.1' }, + source: { ip: '192.168.1.3' }, + file: { + hash: { sha256: '9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08' }, + }, + url: { full: 'https://attack.com/api' }, }, - url: { full: 'https://attack.com/api' }, }, ]; - const res = await format(theCase, alerts); + const res = format(theCase, alerts); expect(res).toEqual({ dest_ip: '192.168.1.1', source_ip: '192.168.1.2,192.168.1.3', @@ -126,22 +211,26 @@ describe('ITSM formatter', () => { { id: 'alert-1', index: 'index-1', - destination: { ip: '192.168.1.1' }, - source: { ip: '192.168.1.2' }, - file: { - hash: { sha256: '9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08' }, + source: { + destination: { ip: '192.168.1.1' }, + source: { ip: '192.168.1.2' }, + file: { + hash: { sha256: '9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08' }, + }, + url: { full: 'https://attack.com' }, }, - url: { full: 'https://attack.com' }, }, { id: 'alert-2', index: 'index-2', - destination: { ip: '192.168.1.1' }, - source: { ip: '192.168.1.3' }, - file: { - hash: { sha256: '9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08' }, + source: { + destination: { ip: '192.168.1.1' }, + source: { ip: '192.168.1.3' }, + file: { + hash: { sha256: '9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08' }, + }, + url: { full: 'https://attack.com/api' }, }, - url: { full: 'https://attack.com/api' }, }, ]; @@ -150,7 +239,7 @@ describe('ITSM formatter', () => { connector: { fields: { ...theCase.connector.fields, destIp: false, malwareHash: false } }, } as CaseResponse; - const res = await format(newCase, alerts); + const res = format(newCase, alerts); expect(res).toEqual({ dest_ip: null, source_ip: '192.168.1.2,192.168.1.3', diff --git a/x-pack/plugins/cases/server/connectors/servicenow/sir_format.ts b/x-pack/plugins/cases/server/connectors/servicenow/sir_format.ts index b48a1b7f734c8..88b8f79d3ba5b 100644 --- a/x-pack/plugins/cases/server/connectors/servicenow/sir_format.ts +++ b/x-pack/plugins/cases/server/connectors/servicenow/sir_format.ts @@ -44,23 +44,25 @@ export const format: ServiceNowSIRFormat = (theCase, alerts) => { ); if (fieldsToAdd.length > 0) { - sirFields = alerts.reduce>((acc, alert) => { - fieldsToAdd.forEach((alertField) => { - const field = get(alertFieldMapping[alertField].alertPath, alert); - if (field && !manageDuplicate[alertFieldMapping[alertField].sirFieldKey].has(field)) { - manageDuplicate[alertFieldMapping[alertField].sirFieldKey].add(field); - acc = { - ...acc, - [alertFieldMapping[alertField].sirFieldKey]: `${ - acc[alertFieldMapping[alertField].sirFieldKey] != null - ? `${acc[alertFieldMapping[alertField].sirFieldKey]},${field}` - : field - }`, - }; - } - }); - return acc; - }, sirFields); + sirFields = alerts + .filter((alert) => !alert.error && alert.source != null) + .reduce>((acc, alert) => { + fieldsToAdd.forEach((alertField) => { + const field = get(alertFieldMapping[alertField].alertPath, alert.source); + if (field && !manageDuplicate[alertFieldMapping[alertField].sirFieldKey].has(field)) { + manageDuplicate[alertFieldMapping[alertField].sirFieldKey].add(field); + acc = { + ...acc, + [alertFieldMapping[alertField].sirFieldKey]: `${ + acc[alertFieldMapping[alertField].sirFieldKey] != null + ? `${acc[alertFieldMapping[alertField].sirFieldKey]},${field}` + : field + }`, + }; + } + }); + return acc; + }, sirFields); } return { diff --git a/x-pack/plugins/cases/server/plugin.ts b/x-pack/plugins/cases/server/plugin.ts index bb1be163585a8..49220fc716034 100644 --- a/x-pack/plugins/cases/server/plugin.ts +++ b/x-pack/plugins/cases/server/plugin.ts @@ -32,6 +32,7 @@ import type { CasesRequestHandlerContext } from './types'; import { CasesClientFactory } from './client/factory'; import { SpacesPluginStart } from '../../spaces/server'; import { PluginStartContract as FeaturesPluginStart } from '../../features/server'; +import { RuleRegistryPluginStartContract } from '../../rule_registry/server'; import { LensServerPluginSetup } from '../../lens/server'; function createConfig(context: PluginInitializerContext) { @@ -49,6 +50,7 @@ export interface PluginsStart { features: FeaturesPluginStart; spaces?: SpacesPluginStart; actions: ActionsPluginStart; + ruleRegistry?: RuleRegistryPluginStartContract; } /** @@ -137,15 +139,13 @@ export class CasePlugin { }, featuresPluginStart: plugins.features, actionsPluginStart: plugins.actions, + ruleRegistryPluginStart: plugins.ruleRegistry, lensEmbeddableFactory: this.lensEmbeddableFactory!, }); - const client = core.elasticsearch.client; - const getCasesClientWithRequest = async (request: KibanaRequest): Promise => { return this.clientFactory.create({ request, - scopedClusterClient: client.asScoped(request).asCurrentUser, savedObjectsService: core.savedObjects, }); }; @@ -171,7 +171,6 @@ export class CasePlugin { return this.clientFactory.create({ request, - scopedClusterClient: context.core.elasticsearch.client.asCurrentUser, savedObjectsService: savedObjects, }); }, diff --git a/x-pack/plugins/cases/server/services/alerts/index.test.ts b/x-pack/plugins/cases/server/services/alerts/index.test.ts index 28c3a6278d544..0e1ad03a32af2 100644 --- a/x-pack/plugins/cases/server/services/alerts/index.test.ts +++ b/x-pack/plugins/cases/server/services/alerts/index.test.ts @@ -5,56 +5,75 @@ * 2.0. */ -import { KibanaRequest } from 'kibana/server'; import { CaseStatuses } from '../../../common'; import { AlertService, AlertServiceContract } from '.'; -import { elasticsearchServiceMock, loggingSystemMock } from 'src/core/server/mocks'; +import { loggingSystemMock } from 'src/core/server/mocks'; +import { ruleRegistryMocks } from '../../../../rule_registry/server/mocks'; +import { AlertsClient } from '../../../../rule_registry/server'; +import { PublicMethodsOf } from '@kbn/utility-types'; describe('updateAlertsStatus', () => { - const esClient = elasticsearchServiceMock.createElasticsearchClient(); const logger = loggingSystemMock.create().get('case'); + let alertsClient: jest.Mocked>; + let alertService: AlertServiceContract; + + beforeEach(async () => { + alertsClient = ruleRegistryMocks.createAlertsClientMock.create(); + alertService = new AlertService(alertsClient); + jest.restoreAllMocks(); + }); describe('happy path', () => { - let alertService: AlertServiceContract; const args = { alerts: [{ id: 'alert-id-1', index: '.siem-signals', status: CaseStatuses.closed }], - request: {} as KibanaRequest, - scopedClusterClient: esClient, logger, }; - beforeEach(async () => { - alertService = new AlertService(); - jest.restoreAllMocks(); + it('updates the status of the alert correctly', async () => { + await alertService.updateAlertsStatus(args); + + expect(alertsClient.update).toHaveBeenCalledWith({ + id: 'alert-id-1', + index: '.siem-signals', + status: CaseStatuses.closed, + }); }); - test('it update the status of the alert correctly', async () => { - await alertService.updateAlertsStatus(args); + it('translates the in-progress status to acknowledged', async () => { + await alertService.updateAlertsStatus({ + alerts: [{ id: 'alert-id-1', index: '.siem-signals', status: CaseStatuses['in-progress'] }], + logger, + }); - expect(esClient.bulk).toHaveBeenCalledWith({ - body: [ - { update: { _id: 'alert-id-1', _index: '.siem-signals' } }, - { - doc: { - signal: { - status: CaseStatuses.closed, - }, - }, - }, - ], + expect(alertsClient.update).toHaveBeenCalledWith({ + id: 'alert-id-1', + index: '.siem-signals', + status: 'acknowledged', }); }); - describe('unhappy path', () => { - it('ignores empty indices', async () => { - expect( - await alertService.updateAlertsStatus({ - alerts: [{ id: 'alert-id-1', index: '', status: CaseStatuses.closed }], - scopedClusterClient: esClient, - logger, - }) - ).toBeUndefined(); + it('defaults an unknown status to open', async () => { + await alertService.updateAlertsStatus({ + alerts: [{ id: 'alert-id-1', index: '.siem-signals', status: 'bananas' as CaseStatuses }], + logger, + }); + + expect(alertsClient.update).toHaveBeenCalledWith({ + id: 'alert-id-1', + index: '.siem-signals', + status: 'open', }); }); }); + + describe('unhappy path', () => { + it('ignores empty indices', async () => { + expect( + await alertService.updateAlertsStatus({ + alerts: [{ id: 'alert-id-1', index: '', status: CaseStatuses.closed }], + logger, + }) + ).toBeUndefined(); + }); + }); }); diff --git a/x-pack/plugins/cases/server/services/alerts/index.ts b/x-pack/plugins/cases/server/services/alerts/index.ts index e33b0385bc123..ccb0fca4f995f 100644 --- a/x-pack/plugins/cases/server/services/alerts/index.ts +++ b/x-pack/plugins/cases/server/services/alerts/index.ts @@ -9,56 +9,67 @@ import { isEmpty } from 'lodash'; import type { PublicMethodsOf } from '@kbn/utility-types'; -import { ElasticsearchClient, Logger } from 'kibana/server'; -import { MAX_ALERTS_PER_SUB_CASE } from '../../../common'; +import { Logger } from 'kibana/server'; +import { CaseStatuses, MAX_ALERTS_PER_SUB_CASE } from '../../../common'; import { AlertInfo, createCaseError } from '../../common'; import { UpdateAlertRequest } from '../../client/alerts/types'; +import { AlertsClient } from '../../../../rule_registry/server'; +import { Alert } from './types'; +import { STATUS_VALUES } from '../../../../rule_registry/common/technical_rule_data_field_names'; export type AlertServiceContract = PublicMethodsOf; interface UpdateAlertsStatusArgs { alerts: UpdateAlertRequest[]; - scopedClusterClient: ElasticsearchClient; logger: Logger; } interface GetAlertsArgs { alertsInfo: AlertInfo[]; - scopedClusterClient: ElasticsearchClient; logger: Logger; } -interface Alert { - _id: string; - _index: string; - _source: Record; -} - -interface AlertsResponse { - docs: Alert[]; -} - function isEmptyAlert(alert: AlertInfo): boolean { return isEmpty(alert.id) || isEmpty(alert.index); } export class AlertService { - constructor() {} + constructor(private readonly alertsClient?: PublicMethodsOf) {} - public async updateAlertsStatus({ alerts, scopedClusterClient, logger }: UpdateAlertsStatusArgs) { + public async updateAlertsStatus({ alerts, logger }: UpdateAlertsStatusArgs) { try { - const body = alerts - .filter((alert) => !isEmptyAlert(alert)) - .flatMap((alert) => [ - { update: { _id: alert.id, _index: alert.index } }, - { doc: { signal: { status: alert.status } } }, - ]); - - if (body.length <= 0) { + if (!this.alertsClient) { + throw new Error( + 'Alert client is undefined, the rule registry plugin must be enabled to updated the status of alerts' + ); + } + + const alertsToUpdate = alerts.filter((alert) => !isEmptyAlert(alert)); + + if (alertsToUpdate.length <= 0) { return; } - return scopedClusterClient.bulk({ body }); + const updatedAlerts = await Promise.allSettled( + alertsToUpdate.map((alert) => + this.alertsClient?.update({ + id: alert.id, + index: alert.index, + status: translateStatus({ alert, logger }), + _version: undefined, + }) + ) + ); + + updatedAlerts.forEach((updatedAlert, index) => { + if (updatedAlert.status === 'rejected') { + logger.error( + `Failed to update status for alert: ${JSON.stringify(alertsToUpdate[index])}: ${ + updatedAlert.reason + }` + ); + } + }); } catch (error) { throw createCaseError({ message: `Failed to update alert status ids: ${JSON.stringify(alerts)}: ${error}`, @@ -68,25 +79,51 @@ export class AlertService { } } - public async getAlerts({ - scopedClusterClient, - alertsInfo, - logger, - }: GetAlertsArgs): Promise { + public async getAlerts({ alertsInfo, logger }: GetAlertsArgs): Promise { try { - const docs = alertsInfo - .filter((alert) => !isEmptyAlert(alert)) - .slice(0, MAX_ALERTS_PER_SUB_CASE) - .map((alert) => ({ _id: alert.id, _index: alert.index })); + if (!this.alertsClient) { + throw new Error( + 'Alert client is undefined, the rule registry plugin must be enabled to retrieve alerts' + ); + } - if (docs.length <= 0) { + const alertsToGet = alertsInfo + .filter((alert) => !isEmpty(alert)) + .slice(0, MAX_ALERTS_PER_SUB_CASE); + + if (alertsToGet.length <= 0) { return; } - const results = await scopedClusterClient.mget({ body: { docs } }); + const retrievedAlerts = await Promise.allSettled( + alertsToGet.map(({ id, index }) => this.alertsClient?.get({ id, index })) + ); + + retrievedAlerts.forEach((alert, index) => { + if (alert.status === 'rejected') { + logger.error( + `Failed to retrieve alert: ${JSON.stringify(alertsToGet[index])}: ${alert.reason}` + ); + } + }); - // @ts-expect-error @elastic/elasticsearch _source is optional - return results.body; + return retrievedAlerts.map((alert, index) => { + let source: unknown | undefined; + let error: Error | undefined; + + if (alert.status === 'fulfilled') { + source = alert.value; + } else { + error = alert.reason; + } + + return { + id: alertsToGet[index].id, + index: alertsToGet[index].index, + source, + error, + }; + }); } catch (error) { throw createCaseError({ message: `Failed to retrieve alerts ids: ${JSON.stringify(alertsInfo)}: ${error}`, @@ -96,3 +133,27 @@ export class AlertService { } } } + +function translateStatus({ + alert, + logger, +}: { + alert: UpdateAlertRequest; + logger: Logger; +}): STATUS_VALUES { + const translatedStatuses: Record = { + [CaseStatuses.open]: 'open', + [CaseStatuses['in-progress']]: 'acknowledged', + [CaseStatuses.closed]: 'closed', + }; + + const translatedStatus = translatedStatuses[alert.status]; + if (!translatedStatus) { + logger.error( + `Unable to translate case status ${alert.status} during alert update: ${JSON.stringify( + alert + )}` + ); + } + return translatedStatus ?? 'open'; +} diff --git a/x-pack/plugins/cases/server/services/alerts/types.ts b/x-pack/plugins/cases/server/services/alerts/types.ts new file mode 100644 index 0000000000000..5ddc57fa5861c --- /dev/null +++ b/x-pack/plugins/cases/server/services/alerts/types.ts @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export interface Alert { + id: string; + index: string; + error?: Error; + source?: unknown; +} diff --git a/x-pack/plugins/cases/tsconfig.json b/x-pack/plugins/cases/tsconfig.json index 1c9373e023366..d7c123ce3970b 100644 --- a/x-pack/plugins/cases/tsconfig.json +++ b/x-pack/plugins/cases/tsconfig.json @@ -22,6 +22,7 @@ // Required from './kibana.json' { "path": "../actions/tsconfig.json" }, + { "path": "../rule_registry/tsconfig.json" }, { "path": "../triggers_actions_ui/tsconfig.json"}, { "path": "../../../src/plugins/es_ui_shared/tsconfig.json" }, { "path": "../../../src/plugins/kibana_react/tsconfig.json" }, diff --git a/x-pack/plugins/rule_registry/server/index.ts b/x-pack/plugins/rule_registry/server/index.ts index 19257845fabe4..2a609aa3bef7e 100644 --- a/x-pack/plugins/rule_registry/server/index.ts +++ b/x-pack/plugins/rule_registry/server/index.ts @@ -29,6 +29,7 @@ export { } from './utils/create_lifecycle_executor'; export { createPersistenceRuleTypeFactory } from './utils/create_persistence_rule_type_factory'; export * from './utils/persistence_types'; +export type { AlertsClient } from './alert_data_client/alerts_client'; export const plugin = (initContext: PluginInitializerContext) => new RuleRegistryPlugin(initContext); diff --git a/x-pack/plugins/rule_registry/server/mocks.ts b/x-pack/plugins/rule_registry/server/mocks.ts index 395b53e229d64..269eff182633f 100644 --- a/x-pack/plugins/rule_registry/server/mocks.ts +++ b/x-pack/plugins/rule_registry/server/mocks.ts @@ -5,10 +5,12 @@ * 2.0. */ +import { alertsClientMock } from './alert_data_client/alerts_client.mock'; import { ruleDataPluginServiceMock } from './rule_data_plugin_service/rule_data_plugin_service.mock'; import { createLifecycleAlertServicesMock } from './utils/lifecycle_alert_services_mock'; export const ruleRegistryMocks = { createLifecycleAlertServices: createLifecycleAlertServicesMock, createRuleDataPluginService: ruleDataPluginServiceMock.create, + createAlertsClientMock: alertsClientMock, }; diff --git a/x-pack/test/case_api_integration/security_and_spaces/tests/common/cases/patch_cases.ts b/x-pack/test/case_api_integration/security_and_spaces/tests/common/cases/patch_cases.ts index e2a7512940250..63b2f2e9b90ed 100644 --- a/x-pack/test/case_api_integration/security_and_spaces/tests/common/cases/patch_cases.ts +++ b/x-pack/test/case_api_integration/security_and_spaces/tests/common/cases/patch_cases.ts @@ -535,8 +535,8 @@ export default ({ getService }: FtrProviderContext): void => { }); it('should update the status of multiple alerts attached to multiple cases', async () => { - const signalID = '5f2b9ec41f8febb1c06b5d1045aeabb9874733b7617e88a370510f2fb3a41a5d'; - const signalID2 = '4d0f4b1533e46b66b43bdd0330d23f39f2cf42a7253153270e38d30cce9ff0c6'; + const signalID = '4679431ee0ba3209b6fcd60a255a696886fe0a7d18f5375de510ff5b68fa6b78'; + const signalID2 = '1023bcfea939643c5e51fd8df53797e0ea693cee547db579ab56d96402365c1e'; // does NOT updates alert status when adding comments and syncAlerts=false const individualCase1 = await createCase(supertest, { @@ -653,7 +653,7 @@ export default ({ getService }: FtrProviderContext): void => { CaseStatuses.closed ); expect(signals.get(defaultSignalsIndex)?.get(signalID2)?._source?.signal.status).to.be( - CaseStatuses['in-progress'] + 'acknowledged' ); }); }); @@ -846,7 +846,7 @@ export default ({ getService }: FtrProviderContext): void => { .send(getQuerySignalIds([alert._id])) .expect(200); - expect(updatedAlert.hits.hits[0]._source?.signal.status).eql('in-progress'); + expect(updatedAlert.hits.hits[0]._source?.signal.status).eql('acknowledged'); }); it('does NOT updates alert status when the status is updated and syncAlerts=false', async () => { @@ -970,7 +970,7 @@ export default ({ getService }: FtrProviderContext): void => { .send(getQuerySignalIds([alert._id])) .expect(200); - expect(updatedAlert.hits.hits[0]._source?.signal.status).eql('in-progress'); + expect(updatedAlert.hits.hits[0]._source?.signal.status).eql('acknowledged'); }); it('it does NOT updates alert status when syncAlerts is turned off', async () => { diff --git a/x-pack/test/case_api_integration/security_and_spaces/tests/common/client/update_alert_status.ts b/x-pack/test/case_api_integration/security_and_spaces/tests/common/client/update_alert_status.ts index 15df0f0b40d0f..d2949c9728989 100644 --- a/x-pack/test/case_api_integration/security_and_spaces/tests/common/client/update_alert_status.ts +++ b/x-pack/test/case_api_integration/security_and_spaces/tests/common/client/update_alert_status.ts @@ -35,8 +35,8 @@ export default ({ getService }: FtrProviderContext): void => { }); it('should update the status of multiple alerts attached to multiple cases using the cases client', async () => { - const signalID = '5f2b9ec41f8febb1c06b5d1045aeabb9874733b7617e88a370510f2fb3a41a5d'; - const signalID2 = '4d0f4b1533e46b66b43bdd0330d23f39f2cf42a7253153270e38d30cce9ff0c6'; + const signalID = '4679431ee0ba3209b6fcd60a255a696886fe0a7d18f5375de510ff5b68fa6b78'; + const signalID2 = '1023bcfea939643c5e51fd8df53797e0ea693cee547db579ab56d96402365c1e'; // does NOT updates alert status when adding comments and syncAlerts=false const individualCase1 = await createCase(supertest, { @@ -160,7 +160,7 @@ export default ({ getService }: FtrProviderContext): void => { CaseStatuses.closed ); expect(signals.get(defaultSignalsIndex)?.get(signalID2)?._source?.signal.status).to.be( - CaseStatuses['in-progress'] + 'acknowledged' ); }); }); diff --git a/x-pack/test/case_api_integration/security_and_spaces/tests/common/comments/post_comment.ts b/x-pack/test/case_api_integration/security_and_spaces/tests/common/comments/post_comment.ts index ecd05a2717e08..f4c31c052cddd 100644 --- a/x-pack/test/case_api_integration/security_and_spaces/tests/common/comments/post_comment.ts +++ b/x-pack/test/case_api_integration/security_and_spaces/tests/common/comments/post_comment.ts @@ -394,7 +394,7 @@ export default ({ getService }: FtrProviderContext): void => { .send(getQuerySignalIds([alert._id])) .expect(200); - expect(updatedAlert.hits.hits[0]._source.signal.status).eql('in-progress'); + expect(updatedAlert.hits.hits[0]._source.signal.status).eql('acknowledged'); }); it('should NOT change the status of the alert if sync alert is off', async () => { diff --git a/x-pack/test/case_api_integration/security_and_spaces/tests/common/sub_cases/patch_sub_cases.ts b/x-pack/test/case_api_integration/security_and_spaces/tests/common/sub_cases/patch_sub_cases.ts index 45fada30ab567..340fdfbf77de1 100644 --- a/x-pack/test/case_api_integration/security_and_spaces/tests/common/sub_cases/patch_sub_cases.ts +++ b/x-pack/test/case_api_integration/security_and_spaces/tests/common/sub_cases/patch_sub_cases.ts @@ -129,7 +129,7 @@ export default function ({ getService }: FtrProviderContext) { signals = await getSignalsWithES({ es, indices: defaultSignalsIndex, ids: signalID }); expect(signals.get(defaultSignalsIndex)?.get(signalID)?._source?.signal.status).to.be( - CaseStatuses['in-progress'] + 'acknowledged' ); }); @@ -200,7 +200,7 @@ export default function ({ getService }: FtrProviderContext) { CaseStatuses['in-progress'] ); expect(signals.get(defaultSignalsIndex)?.get(signalID2)?._source?.signal.status).to.be( - CaseStatuses['in-progress'] + 'acknowledged' ); }); @@ -321,7 +321,7 @@ export default function ({ getService }: FtrProviderContext) { CaseStatuses.closed ); expect(signals.get(defaultSignalsIndex)?.get(signalID2)?._source?.signal.status).to.be( - CaseStatuses['in-progress'] + 'acknowledged' ); }); @@ -470,7 +470,7 @@ export default function ({ getService }: FtrProviderContext) { // alerts should be updated now that the expect(signals.get(defaultSignalsIndex)?.get(signalID)?._source?.signal.status).to.be( - CaseStatuses['in-progress'] + 'acknowledged' ); expect(signals.get(defaultSignalsIndex)?.get(signalID2)?._source?.signal.status).to.be( CaseStatuses.closed diff --git a/x-pack/test/functional/es_archives/cases/signals/default/data.json.gz b/x-pack/test/functional/es_archives/cases/signals/default/data.json.gz index 6caae322450e44b439e17bc8b6cf6445a4a9940c..51a1c96980e77311c8506a5f5311f88b6d0f1177 100644 GIT binary patch literal 3945 zcmV-v50>yBiwFq9d>UZ@17u-zVJ>QOZ*BnXomr3EwjIFV{V9ZfEW$BK@sgkFwkaAE zX@h!;An67Jp0l#0kyg^|RrtG?(pxJGQ~yHb=}+2*z3B(SsB|Dl<{IIlM)!~u~S6e5&n)uGlBT8oA$oGT-asR>R`7X5lUo3@yn6b zs_yYbuB!8SYAe|+GmXnKUM|}6(z3FPthn)&|Fe7QpKq7Ad-mIR{ez+~Bt$X?up=4} z!~8)}&OpdGw~RALjcyO+NA?0@&8U2YYcQw4#ap5uUqz+fQ4Uak^(Rqs(_ z^@>j>j;H%_FNd~dA!>iXNh>+jmayl9NT*~y>Zot@e1 zJjn`M%err`w^MO-GvC;e1;lA=)XKG|<7cT?l~hU7Uw;7|ZItDCf4Zrmjrv9sI)WWg5{H0z z^8{q*6mU}Gh&@ zh;<`_U6(tz-1w=srjDA6?HW+qJ{0jH_FFk0`ntz?yTkr&%;R+?_*k#^Fu&LGeCsuL zm2A}YjXS@g`#WSMcDq~$aN~2NGeU94Kj*R-Ig(L9yssEOyAU1{!Ow$rd;|LBdYP*fydUjbmu39|2x3t}&Yi*kj%6Squ;pgF1 zIG=#od7hPV6<^xpo8sc6vI9@it5al6w6e^uKm>cy%0`+wb;v~!I4dDQ$SM$V1AP=I zt&utkC8WJ}X}a^%&4fplx@VhYo`OGss*uZaed2!@$amqBsS@~#gCe;yai#oWfkBa1 ztA+R6!veoOcDzZWj)SK@mHT854B}%--)K{I*j+6Bd0aMuz)9HO>_jdXEAPST!cQyf z{ZY3#)^=GorQL#5Ue7m~c@utgE$v8<(K>aM_80OgR&wdHU!U*KWuDJhMKjy;s>n2q#!aW=ijl3VeC56NQP$9Ha?xy$uj_sNyY5+d ztLAJ`yTs#iUz@3UW2SsHj1H8|Q@_MIU^v>9U(zOSWz-OAu>z3u2oU8YPzE7DozLpH zq<(Is@4(l#a}5Hn#tZK?jY=+#FS$Cet=U~wvZ`wIcIgwMZdtam6XPEBVkok!+#I#I z(To%E>v)?Z7Iz;bqfrOG5B{>;E{B+8RobG*b+S~(jrp!FR;W?i6jPs_%oLh%8*#4Vbq0B&&}u%o*>->>4M&& zt{3=?LAs!Wy4r4e)U$QzU7lU}iJsde+3`CTtzHDbyP&98R9C7C$cFr`yM%iZJQ-5M z4fUxAWj@H#*a9JHiM9wb^Q`@n@t8I_^*c*nqmRjK!#oz99+B#c=2lB z-~-+5!yImKUpUzIx#M1U=y#t$2iY^w!8_&fwbH@Ypv{~5foa^h~=Dy#t=Iyef_nv%zJ!!%CgPqMn*QA2vux$XLD z)Ub4nii^@~&~a+mUcfz>q4SCqhCbFZ%F8%GUc^--EZ|T`LJ)Nk5yzR~p+WCK3=bUQ z011u(Lr$WBSiLY{`0-Wnj8_8;ALxM}=7WR#0>ic&9(Tk;SNsHE$e#fi-YJK#6&St_ z1$zQ8L=OXoA6;YxUzDqA0)`VXoPgm33|qw$Fr0wlu+3KjhH;fkMjSdX#(?48k3Ah2 zDq>vZe72w=VVp6;9CKl0Et6acV+3ji#$z;KkIH6<+y)pppU zKCcT5lTw!DjuxiHrx!sBbHWo{!Lh3Tu{7_SBtKG5?%%=ZTO1%++*JMMso zF8B$cP&@-Dyi*QeD=2&&3ibq0h#v+D&%^U`c3z|ePM~lCg%c>8Kw+zR0)-PO9JcvN zpzuZ;d=V+)+KRE0;JqJvhBphPw8EmuNMn(ch&ZFD)uB=@GR#PYkucIS7&(MP9)^k< z=%@%aq!DyG_V)!qVJjd#`F_jwIvc2EE>)a(pVU*kcD$jprHdDc-EEh=;E zja(VKSdS^jX4h*z;o`<_o%~!Q(K=8Z2v2>k8k|AV5W|eS}RhT#liQ~SpPCDT;NRt;%_w!nA9Q7{uWXh{ZU9NQFRKD82QT6hulJ zfJ6ud(JYj#W4)i}rYOzKI=3I4Sqo$lK4P1jM7-YX!Lc-3a2KZ^SeI_@IWV|=YonwI z>gKi>THL*@>3Z8{ng=88dm8_q>ECW$K6njzYxhy#61J`WjImyE&+LccVcT)Bl0G-D z;-$}uywTres!o2g!M-Ti79DEpXH&c15eib-G;aiYzPD0u>xXaaG3J{MYb?=dL?d-g z%bJ5g3`Yo4%pjrdUvjd+IY(+7dv&>9X+6K7e$dU+Hl}}HrFqh?voY_TTJ^Kh<)qv2 z;lNC{qB+={HpjhMuI1*#FCR|7|FKJJcYA!ShmGG32_62vgz36=x~~0ZuWOG7uV3B0 zRM{sx;!XCT;~%HN`+uMQ?Vtbp;q;f`)r1d28t#<%peJdJP$&i|bGO!RG3AY)?|>`j zMSST^-eQ2|#x^JzVD*1lFE82#GT5AT&cYgk@x5#pBvpxXiEd&z%J=g{_)n zX9}<8JD>;p--mhN;J)7hwVm*|8y-61$A1Sz&@-UBJLT}Teh2hA6zmJ3JarS?=GQ4H zE|#};0(%qKo50=#_FBag*qgxKu+3Nc4hY={A;>unJH%uw!FxY8iVOb-oKjw%B7^_{ D7lFVE literal 5586 zcmV;@6)ox?iwFqo`7>Yu17u-zVJ>QOZ*BnXomr3LNOFMR`&S5hTuj#Fee{!IV+_Bn z_rdloJnlsyPZe8diBw&S`R`7uN)jnjrK{AEs&g0UnNg6*JR&k8zRu&HUpk#`@jUU} zubr+N+wL#r4-a}UD}VWC{EzsbnJc9%V57XHD9GTAK^Ahu9DYsP(g?h90@O_ zCIT`90}h60iZpZcqRY}o&Oem}-sG7df;{Vu^dJY$2R$1U0G9tli-+^^Y-(3kiNE|y zkqv!b=;5R+14E1e!~miHM)E6RUn#o56#en`etcf{{HUlDuxt;8l4#@!K!H&}sR$r8 z0RnAet))jIAh9f_(o25iCgUuYS&=>XX`YQorI_Eu|99U+e=e)xbfItaV(RsGl@HVf1yi#v;LvLWqD-VtC zv%2uT@$@1xCssp(X+ zL%KRDaGXZgjqe|;qJOFCWUnl-`>p$LU%!1DX2YzniubG{W^KqzHQMG1qQpt+v+gClmr}vh= zyi5o8)#}7r+F7B^U|!yO18PR4^Skxx4jr3YArqW%A%N$C#|g(p6QU@pu+<(b4FkoY zy@rd1Z2IVAUU!9YV<_Kdp4v#>4t=55>$uVmMBB%2KG@@FzBbxxCgS|0xU0`<^WR^4 zSApMse`NpFd-$CFFM1psLc8lvE`74gLFqfd24A#v)8%Y@196;I>K=Pp6H=0(D)b5j-UTKrnFT1Ub zl*%sUh(InWf^nX&YOtQRbZe_J?W#&2u1K5I=+8zwegYer&IXNXS=%B`A?uB=tGk{R zcjM{1kC<6Da8bQ)&0uW%w{I02MNe6K%*OaN>i?}ST7z%GZy4ok`oDO`%ssLn=)A~m z{SoJLJIyA=o2z{5$IiUHwFmvE^atgTMJMFzq9^O;CFHk*Y#y9#Zf%GOhrgYS^Q_1o z{QI33vO(b+Gw|9o)A2k87>yqR;czVocvUg)1?DzDz^xLo%e(;!N(O}RnlsLEOrqA_ z8xEKLZ(ie8OIw>G^kfMB0*a{~<*%yomvyDnGnW-6jtOXpqC)qg+iMD9C;0YP=7!Mt zHD)M%zu_Y>nu;&I$u>{XquA>Yb2r*W!+OUI^r$zBd0i>%&wO+Nb#Z3>D4$E~f}wu8 zeM>jXX%W_^xE2px8Co`6Z%02fdK7cIn8e=d$>er6omcj*C?;Qj{WY4A9+c7kSH>aw zH9qib9^;v5jCwW)u8WxCw{kw{EF4^CvptN)MXQ~TXT@Yz+`gY`*NeKJcjRI+x>$inD#*nf8#?%KtE#24q#xc$E{%vl@^N-tDYn{5I>g`|SIsZO$g{ zT?Zm!E-L?Mf9D+sQi-HnLxffGGM@NRlXA>*KV8Ezl}URj22rsm?-i zKjYJ}87xcvviS4QFModdQkJ?$Puj=o@4&F$ucwjr#A?w|WzH}y5Lh2#E+izvlD*I0Hh;FAUu-9fohH0n0}68~k%TsM=)&0EZw+oC zE|6QCf$i<-1`l$Con6^p)fcvV!=^vn8}6ZF;oeqVx>mS%9Y&JiUV?ioX@Yy*1osl$ zOK>m2y_3Q{H!a+~nBB1&LRgq;zyI{2?p_%DemvZ>+6xJ}@SHJ;H8EHSi?pNMXkrak zkWx%>@X%puOd!EJFPI3<5#-RKPZHeg{=9I{a{{A|XyAoVfJ!fcGLXh0Kqig=G5ao` zlaN8QKinf}{ak{3pAGJ{a95c6KFx zI1#@@{5~1+YlUEQ$thUi zAlG@m1c5TEZFW5y2;_9abJ%BO{5}X=)_z9{h@qw|kT?N(1EaIh3`l7Rzy=ep0u9k& zyiWmJzqkVe+%T$5#@B`bDZ;X$X_tlouVOvZSvK_U~Vqm=NGe5#R{RXL$D=<7#rcG*x$}@=45Brto+KsF2l2 zS!s-=&SMreTr-J1=TW06w#)_sy=DYEOcB%85RMQf0vbu9#wP@r5TNDS2`mWUnsGoe zCBQiEfY2-`LL7CFSDUjvry-OaaAqD)i~bS<{A>uY6@R_H^F!fa8TL)ITjIgNeT~PR z4G#w5(DRHu=TGnB!Akvi1ccFHAxV)3ia-=y3HRk5;b*H&^y3VOa8GA?kUQ<{iU|3SSS3i0MTA>*=~@xtbr?xPgb5L@ zqzMsr6CzBAFd@Q(2v3R#sl+Oikf|CgSePnCA%A$8-P_`LLZ!9aWMfyGoo z=B=i(%CUCIX&5F4AVSpavxEp+hAkn&N+}nP2wM@@TyiP!u(8YdWq27Ed$1zT_<^F{ zmZJp^*kw!+SBOFexDo=;=pLgDa|8&X+`IB`*t|X2F5?X<(FBBT{16c-8ftoB{O~{j zb`5Cc4E%6UPkWHB?d;4C>v`2__#r!%A8ys9YvqU6VI+wkCVse*CVtpW{4nvu#19ic zJSjh9oG5wMpW;@2C=F*hLY#iU5e_nowbxfxvERXDp9Zy-gDnikcMQO%Spvuu&io8Qk!;w6I zAEsT#i64G8e%K1ZUK@PzWO032;zO@?YR37NCAyr+q499bjlugbOY{apOdJJ{a1E$8 z2uPw3(3U%{q=JOt_qpQX%Mv$eN|PJ5?pzk|^0DGooXd6wthlEGKF9@kcE*Z7V&^hH z8Y_O*!wav&ND@{|SaBsySh1V1V#10ED<-UXQmi=OgNISy+xyzF?F&u z`epIwzF1KPVq(}CoRgddVS=MHCO?p4X_;3}m06PDhFR~iM?5M#j}KBE<2oKNOjt2t zMGu|S0xH0@i@CIA3TVU~2ts3KC<$8CcHr-j(+G9Q&SjdgV#11_3@f%Gu({-#fn)Q+ z6jn`s&qo}4cX8ezJ{RBLCys|)m_iKJL@I!FoE)je7$`3YaOE^nK5~CC( zj%uZ$ncwQ7peD*|0gXY6W5g4U?EbtoGU^Go)COP$E3+DdfD+1rAcBheBIw#3L_6d( zOdUca(+bE$BR?CBY=vNR$sL!tT{~{^Y><-nSa!*HokSp)( zj3Ov2^Od%K}bO$4%i|eBtt|{;Uu+0#&E@wA9=NO z!jl(@CzW?fJ4}HS&HyT{1&Rp+0t;9Xp`1o_O1C|y;X)jMCt0)45}s@swuC1urCd0k zY{g%5NdlJ}w|i&P+TZJ)ja}ZGjPm?JkuCRLAF|y$x;AbJ12_;5s306D>=-aSx@_#7 zAWolbyY~jAY$D25f(iM>-+cZ1>>A+A83^W{zWyL@-`Sa9vYO;11T$9oSc17tm#&sz zUWJh)f|&^BN}32}HxbN4FcZN{1oNZ>^Z5zdyQyRMHQKf?RguT^EBm88zb{|wR*#(hkJq>mv94Tw=@k(3NV#f;}iEgapfou}apF+}4~%QHl2_mu@|7vt18DQisw2oiG?{k?Y42e#Jm1K{Qc zb$z3kn8|kT_$H>TVL=zhHtkjHi#-F|+%pO|C=TfC$~J4EKzlII3eUKl_a>C;O0u2;AS_$%>*|S+)Qxuq;T`4=Qw?MneWxRgo!JIYGDNw|;d?xEp=F(Q~_f)K}$mfCQec8@2x*;VE8U2int!fH@n ztps$O5`m%0BMSq!dOx_Skl+Vg%Z*q%%re2v&jvSJDcD?+u;+&!n%RG;>G9dH=aVL; z(D1om&CNdM&`i#u*UqZw7NpvETIIe=p;{eXyyh*UT{q!aO;=f#ELG$ ztc&HI->-t`oMTPregVQkAwp+o?#X_@shKfaJ(7EFRi#!d3vP)`yyYOy4c|N(dP?3NLoE*Klo!uD`&V(u;2D_bp25LE z;X!A2=J_Mmda`4g=T>F9R_1vfR+5-!VxB8$VxHZ^JQMRw%ri01lQPfZX(S2r`@-iJWBZM{O(K8q%9g1P74_0`?Jt9;_r6&YMsX@?b=Mh6xMIl6z z^R(78G0(1Iar*NF0!0l16e$g~gBnnyk$@Hj681ZaQ&Ef$VV)8-J1sHKmT^nWvr@{1 zGtWdek0G1>X;NR&nd{pAiL;?ioYN_x-VAG}Z8y*5n#YV!atJ7Q7#NM? zd`wMXgm|f_d!KD?`smRc+21>&lk&afP;d7&dy|0)-%4-kWGFp z+1#p3*Ge|8!%7m_Ok{H|JsR<*fb`IV4q=r+)_9vSdszf#u+5BW=vlW5OC5d@{=q~oB z@73t-jE8qlNbgP$?0u~|AF_*G#{`6y?hrZZqy6IO9Zj6GF^+R5f(9aQPqvGFgCf6i zO+w{+yVwO;0LzQTp3heSbk1?L`hM}jK@mb{SL|5}657LrW}vV)_7ulr&#lUIt=RKA ztR!L2ggsZ%ggv_ndnW9euxG-aC&ixk&Y;2L#1~l`_7wKf_UQOZ*BnXo!O4uxVeDu{S-o724BJywD&I*Bc%I`}l2BVWad-RcD!pI&R8yptRv- zQ~+50huX?{Qf6}ByM6LMMHuV6;Bi{@fgwf!`T(&rMBWqcJqeaR@_uXD+xmR1H$|s| z-4uP7BkdvsC@};OBR$|lE&w#x*T^%-qwcPo&cgLZrAcV}?37*UEDw`SRqQPhUgAYl z_GLE@#S6a5i%j#lKbxu`*G0GMrM|M0&X;MHNS){1kv80}KIL+I2HQQGnq`!%^YJ9K z%=?3PCXSY52`8FdjrOnJ(p9MJa(GczJuY}zT&!YU@OqhXnCIbU-JMq@3+p7iwUz&W z_tZXbm$-ZO``h6`QRouFnE}`k35a6$ps2@y%REmrk3p(rcPKlu6%ef^<-;Yvb?bh% z(pc5oN@2Go*O#T<)cXv_``cTC-G;2_tYEZ<7fC+c!c1O-g_cE`)yIX2MzOjs?!4|C zs&>_ZS2g}-|7{m9?#i`_F4bbRO`aAML6-tbeGG^cJ_wY+fNBqE0|U;f=(S3R>p*ac zJh=4Xl69xilu&nxp|`|@O&?aw<*-Ae00l|_t5sM5Kj?QVAh6Rj9-uBz82Ij>*azGI zM1ki6+mY{05Bq@qN%}%>pZsuB3?9{nEDL!p>x*BkSR~iE^HFD3Ll&KSUwU&iJPxBu zrWe=S7X2ldGK$9CIT#|=uh=f)m#JRTh!-Zw;)4~sN(}cpY$rRC#8%yU!Z_ZI1-FuK zjnzi&ic z=xHO*FNV{N6|L1b;Ls3kfZ*5##F{6-T_b?u5(iXp*VA-*hV4QQ4Vu<-w|ec3&a$yt zy`!vc@NklQ`JiL%Wr$v9EiY zw>#|braWG6f=~5&kMnyS&$nH3U&$t2-?Z}^yT3zLVz1VNK%j zK>CVUsd_$9r3&f2db=eF0(K#8n4csqTR-RJ-w+M zS0x_STk3w%jns7q`6>$Q@bmC0j7`AwDoygR2(R?^@JytdSIJ)8iPN9BIBEUd*Xi@ z$#-UxsT|mfqat3aun_jJz^KTo)!KUQae>_)J>8^M$I(-p%6--c2C*@vZPb(vP~{9J15kNU--)SJ96?H9!SX4Pcob@5A`%MuZ}pN1r-KA@c++x7aU{rk(CFK^ydeSRJ6hM$GqFr2a59|*ezSbLff0X#x9 zAOXj~C-%%ahukGvNEq~a(o17EglFzHb2n#jsM`g8XWY%{(W|bfope@xAeScBcA^(L zigrkj1?8(ia+efk>*8AUnb#P}^_TEKD92r@JVkAGL79!4B-X(9D~Z+!GGS=-=Qxx* zJnS@=xF0t<6GU%73hH7XvXKnEGTyg72_A7Wyzi0j_Hho^c_{De`rK)+JNCQJ0DkNR zfZx4xc&fnfG!*RVz|ZCjj{<(4SYO{{B9`S0{AS=c1HT#gb&6-;Hv_+Mn{NdC%+2L> z_zBCnn|bdfc<;xa5Bwz8p3N0J%_{o9U4cDMBCZG%+?4_ckPu9;(NJL`gmH~j+M}LP z%0&vbd-4@t%EM@;gMT18h=lMx*QP6&3t?@P!axMB21v-j^9czE@4aU8;&c#`nGVi$ z&>0-+c7fj?9h?Mdb;;AYVI0QcXI|Xxs3E=WU0{7PYM2{F{ma~H&~a+mUBCmGp|OhO zx;EBQ!pb;7R>Vc%Yv4hj6N0D-h<}_J9vbuk#PGl&j*#FKF!V?;6027R3_qO&&o~)i z_(%`@I3Mgh6c~2h@U$ZyyW(d6L+=HE;k|Nrs=)9x6zmzm5IqhUelmgfy>(s|GccTi z;S3CCVAv_1f#D1c$8Ek5Fbs>7Gh)z1HU$j#e(d?cP!MGTW3vSb3G*0J%rN5yS~Knm zUn!p%$*DEH(32$KzNZ3$l#j6t5O?|R4Z*Jf4Dk#M|3JV{A`~!g^Aqhu3<%^3a6&1t zzEE3zRFy#fSAn6+W?(o2LuYWP+Xa4qz;KeG)g>JY)pgjDKCcf9qnzjYjuyt*=T|`s zQ{qLkNUupZTbQ7QyV*Yw6-ok`vYr%3s1zU+W5BtgHvED%45J89eb4KKlOsNW6COCb z5eb~)gcuVt5~o)N3geUD7$*Y?AL)4?=X;%pg2Jx*op!)u7yJxR=)V9cyjKoS6%?L^ zf;|Hi;>Ur)3-{uJU1TwVGbo%v;S36AP}nJ+LE#Jv$8Ek5D7=*lUj~Ahu43#Yc<;xa z4+;a$wXad2xYEdQM2r$tOIHXJD5ki;$X8r57#M_I&vgY=&`{r%kOt7~*xy$Gg`I$O z@k7h?dK)Nt%0(DipEOXrZoDCrjS1If#v5PRbMj%HL~TLsGNxm*#G1j|QGk%9QCPdy zfthO~s@1mLYA-otVD`3WLOkUKR)+!et1sF-Us&}GBrpOhEQA}-zzhv$D;s~+6{m83 z;?cDYAf10~qT6BByw zc5CrVg+!}BaU?v|xi&5hj!G)?pI;=Ank?-cgAIhcbgZ`>yQ!yXW!RODPsZ} zNe!0R^*Kd8RKg>4lzrtF9Mw30`xFyvrnzC9*>e|)a~m!(pGu0fHrBce2}g==+uOlv z_2P;^89>euQZCcNH-Q$I7!HZ?Y-8>rR|(g5jiHo7mvd-bAL{@^hB!VPilw~HT5BHn zbC#?#9y|YQWi>xP?`-G?S>+bCT)<-4h&?%KgNWou6Sgd_SuND63n-QnLPda zr?n14#M=~wGEB;RRi!Z98WRR_d;_8}4j>XPkQ#Dpy*UMekP0B*g+7tY<*aADU*@JL zPSiHHpPX3-WD#$|HrI)Gwb!F#skh)hPCv3P{oHe8aEI1LaOG6ZbvCxRdt1}@w)Hd* zM%oWF{sYtBZe2Qh4Y{@ZXlMz$R)5LZpm<>RUH7oqdt_;6sRt!R!mr^|7#H(R;+ z`0K~BAAai7+T9)>>!I=6E}`S!moQ(~&eyfy?RD+(;Psokmm>MBC%nlXbo~9y`S7o^ zzy0H%Kc4+MzM8OMNX?xh8}vlA5pw-e%G|HDTTFgy=R4wxX%=2tleZpWxv33uMp*ry z+RBU64tJWfcIrW$?K+2>=5%rU2tYSA+WCIeAM$GRf6l^~XSZink3YAwT@2cN>HYls zV3GOOW_<+6S_tGHx}PbUA*$hqbs9L;TI_>5dZ^wruj$_%@B{bx#p5pVUT=8J5$-nKn+l&2wMvD*y?3)(zzrvb?6N|HGNs({izU zv$2QdWA|ocPtD05mz8z$vijf#_eaMPv%{&`k>u>LFB1^>0xuKXE730|&tK^!g4eC0 z&v_}M#23m?NRh_`@jOTs z_XB1G^@YUHgC6rG^swjoh7yF0O(wX|5*x!LXI@LQzV^lbNnZBOUjTIvs>&UxV1R00 z0|Frf0VW98=hn&)>0|ca{r~t8f4sr-7eJ%anvwE%fs`kKTV2wDQC-(M>7Dvt0Bw>& zr(Es60ZQZRp7Hor-vHfRMsE2@lCozS#@_&S=KnytsGyYAuK7R)*oH_*XdonofN*1# zl~Ka{1NVXLIu4Ba0BCsN1Y2l`j{UwMmwE0;s9qTaOi$u7g_HRX=#l>SaUR%t=yyO} zCp_(j$By{v-vJTy0_g5uIXu(LQOZ*BnXomq3^IDWw2`%|d&xHa(LKKdz@)THvV z*@q;vl}T^8aLR0*7Aap_^W6i=mPCq_by+RRjhQNUH~%DvdAnic{8M?)O`iGTn>+{3 z2R$1U0G9uu#m)J6HnpqLkD@8Y$qCeiAkN4}I z9~G4XmQ}=15{*0oC@=~r6#+;=A+`(&qLGe`pJ@9!1g~AzR>{G* zmp3cnZC-zQrQYa<-oTbe9vaJA^ z)Bqy`2G)DbAfZ(AP;E{&>cz44u4SmnSFCQZ5E!vPs*m)eewDYs>Qz;e`}>(6&ASdZ zyR6ofs9)2f(vU{C+>P_KUeQx~mlfU?v*~;UET$d}-DB}mtwZ@-IfmsO{}KNVs539K zo*Ue|Zlkx16y7id0bz^*im{Eog&Z)Ld4YU@O6%HFll68Wc!LSLK~UWwq$>Bm%8(Q{ zNa1KPtbNpm+O8Mr3NnK<0$$bl&xS%RjHjkk%?|16sKC*UtQ+4yRz?3()yZC2V)tA3-@bnPHq3@uUl%Vo z{>gvqcD{YnPrf=JcI^D^+-%--xc1^`62)v@S}~o?ZL-$Vd}h8!<-c9@*zPwBa_tomeTH0Bm&0t>MdIM@krSrS>>JA;7TOkvia3O%_ zf=7qrq6twHRoH5em4<=h&|bquLpHs1GOxSBxG|J(o~JgFw?kj(^*XM!1JU;Jn-BJQ zny-!anu$0+DemfCZGQc=cNO^E_eb_$y@$`)|DwmSA+)=G=Q1X{9F(yGY=}k6FkO1% z8;GM@sYmQ(k;`y746 zH=5Rn)E<+XQE8LaFT1VGl*%sUh(InWg3-@cHCRtuy0ulAc2%VhSENm9^k<_TKY@)* zXM=`Y*0zW)WWDiqb=R}vZajVW7BkBRE~@vf8H{cJ_N`*07%6MF*_gjZ{lC>kYw}I_ z4WoQb{}<1gc|`UDofny{-{O33r`e=<3zcvE*qOJtcB3Da@t_>C7=(OX^kn_Kg#31p z&6BgutqpO);cqA7JS(yX|9 zOuqj5YcwN0D6{>qj6?Kmyy4e8<}=fn^=wXD7dgjor9bE_0$gXaJ&eXhtDTN##bj38 zzCYEj7j-}H$b~byS-kw~w}m;zl(GKA)CWH;!`J)9G0pP+ZEnZ&loF#2vfE+oqUeC$ zFDiDxTh3^?hr!2?O|%PuDkXs?fdFZ-vWPKb{95pyKV0_k?Kmc0)6BK@T&^FYubRK3 zDT`e*AHewp`*A&%zY2G1NTGZ0cUo~*dd+ROjEiE>+KMvr53-Tp(2%7#CgGb4m_wF# zJF6JKdA;_Sec!ar*~GmYKt!C2%0Jqlc_)BWGU?V7VKsRfPyDD!IcB+^u3?$+P-pXK zBpz80;$h~h?s;jdvryd6_;hRr%Tm8Ae*XF8&o5ufGJgy-TTD(9H2Yl8O!zonLIq&0 zgMbF2fR>a3Oem2~5Gi=A&$rG}B*aSW56!Sl)GSf6&qU2SHTG1Ew5?I3j?*UN$5_uh zKNu{5+C7?H1W<$QCC+Q^d!zpQK&{?{9g!NOkaFZXke=aaUmOBM7zEabIK2@PVaeV{ zYMWo%jwH6j!cLRNtucbRlt@AwI&@*U?zaYt5EqCd&VcLo41)&+!p^R^t{My5qhT{1 z?#=7avAk}pE?q0HyAC5sye{#&l{E3XZsK)`*Ck$;c-={PotqZ!Ud--T4IwN{wcmew zQFkv4em|bqS?z^{TzJly#F`i^ghkp>ZZxq5D@ZA(IC$tVH71Z?ofk|5=Lm9W(I;s| zT=(aNd!7>*bwmR%gaTB036y~}4goT81c=#pMVy2TqW$3>NlW4q-1}^Bua$$%C5L0b z#wxmTUemawheD1y zb=)YfxMhkn98K3rD5H*BVG#2SIuCu2NSd?!2Gl7741^9S9Va`% z7zSx=rRffH8Ug76#1ALpmx$jdBYv$AY%Vzk3moJ+&zB%jX0`pRX9IzpPIwOcjEvt0 zfy>(ONC7d_lm!wUkT);}3(bI(h5&3Z;VRG&1IGIlu=R~QAixcy+GKof2#_Ky8=7`$ z2=FS_Go59R?q0$2pm5pQ83E#&!QEwFp`7-69QaG69Vie1eg$DLVyVY zo)iI&uzZGh-!ZOEPM4XB^OY$)9sw$3HBwd@W2y6)MGe-t?Rf64N~|&onX0jZ zg{fi`@`sn%y)BMMgb)YltcMm#>Ah4^2IZ-9%o0XbkTiHBkO)pO6SQJfazmi;C_du_ zTT;J-2!CEgXcW`|N0%r}>~6{k2HI;6ET#%FZ#9)wjug+Jjv`pI4oRAF^Zl z;Z|L`R(^OLMw0kp;)g3~;)mVD4--F3{4nvulk!8xiIR8yDQ@M5(r}g|#OVhtF@#Zd zop6N3yp%d2DG>rIgN-zlK`aE+2ueewB1Q-kLxwX%V@{E>6q`lHlK5fw=jDf3$LX|$ z<&j;n<0&gwMJQUbD9tzuR5@CkBJVJ#;Yc3957RE=#1B6kKWv3yuMNIu`epHRU#uttF){57&PmRKFu_q8CqIy5 zX_;3}m9r$l4YS^3k9bsg9&e;N=5;(^n6P5PiXJ+t1yq1*7w6KJDWDN|AP9|_p(JQk z+kwBsoJOcab}rL|6%$tcWLU8kfz2h?3>=#uOkvf@@A-&h?=Jcc;&bu+ed2h?2UCc_ znn(q(j?R%QYC^@oAhU920X~NfUGICgzx!V`7epIi8d`epk4dKnVx6na{#h z!%#|Ho@B_5XO0XzZ9Q{PIbpQ)!VqJf3|?r-q*didRG`9)Q)igu&<7%z#X)-xm9h&s z@*|idPR#K#nIrXzdm4vKieLdHm;e>k6IjAgunLhliQkVoa*7Z5V2Vmh8548-Y|OD0 zg1t8QQ_{%HKMi7THeDUdIA9k+BQyR;XZ`3VYrj8f(#UE9cBGLG`+&IefO%CefQ()= zMqmhJ^b*E9rKs4lv3k=>cc76Q6s(CGTUS65c=6wE`Jbx*Eob?5%U*H&pvc|Xl}4%` zu>w*aOCz`H(zVja>oAf;BNL5WNfV9iCK{P&WTKIYMxK;LPWU~?GnU&?D~&AJU0(=F z(eX5r1P!gxk{A+00;3|PY$BFzg@e*MPKi+p5=XVt(9FN;qM#VH(b?I91%itn#r0bDJ(*Ey27BBS{1^5zLh|5zKBPn2BH}f|&^B zNeSlj6SQ|z$L?#iZDFb+kJFPUZlaG`l=@}yb6p7AV`R_n&=HF^b9B-Jm7=`%ZRZ` z){)%SIgO$c?@urhPAe=E!u)Iqvz3C)B?)dW{aOUaiiDz)fAA z{fv14$PgFv)aaD8rU3+rIg0UKyBGsoYxn_hbA!6R(M!x^J9m5&Q`WGc3uBx1D)z;m zfo<-Y1ss$IbarK%wN#)z8EB>hd&5m~EZp3xOxFrGufs|b+)QwDB~5U%o8V@Gn+a|v zxOq~z`O4eFgg=ICI2uonhntEDV=WEX28prVaGQ3IC%D;Fx`G~mK&P<~no=;#uGp~@o*1GjoVxT%of2Yi+r zv2>Vaf}5WWZnjdexg=rF4?Q%q|5DTAvtiFCO-!NTbH6$_`tQ!{0mc_L$!4BQ*T6vN7Mgf%3HaApO^1)N~h>e?VIfk=R{~f8Pf^ptwqPIcV3P5#qyM_n^thUNq>7~S5 z4&vPK&ZD8H@yxS-6^9I-fqCwk92}G$barQ+KVq#XJC=EFRi?#)BpC=F~Y7n4EX`mg{ zfEtYiv?!3U-%*^3Vtfeml&INhiFvk+TVkG-QZAf%CbD@9+4N77`ijn6*Y;1G4Q=9_ zP6_p9SUYXIi8iYZ*pY2QAqCPr&iEvUfO3a{(Kz~JY62s~OGVxLY;)5~kKV}s-VvRg zUp(2I{_Pr=%{f+c?w0}_lmv8kCY!Q8<2w!6C7Yxd?85_p8nlv4S!g!Ndb8k;C!0bsp`rDRLE)6}SYpL#kT8hgtPTiL zMBXlT8d&BAbb9eloJziooWQ#5_NA7yHxqYW8-)^Hl(yb9`ET zzx?2!4570t_N*ld?P)?YQP>-Mies_oR%Np525!6ZTBlGhxq@ zV$XYL(BN_6i>wWM3j1h#cas?(f55lZS)2-$JJUHKo_Q@rRB{f9i|HuzI3P{5V$y4i z4fBX<$FL2=5`wh#L?-N+uqRap8%rdhERGv>h61I^9czwq=ahF?@41Ox3Ut7NPE2^h zo(X#w)zN{p diff --git a/x-pack/test/functional/es_archives/cases/signals/duplicate_ids/mappings.json b/x-pack/test/functional/es_archives/cases/signals/duplicate_ids/mappings.json index 97b2897150212..6ec0622bfce71 100644 --- a/x-pack/test/functional/es_archives/cases/signals/duplicate_ids/mappings.json +++ b/x-pack/test/functional/es_archives/cases/signals/duplicate_ids/mappings.json @@ -2,6 +2,9 @@ "type": "index", "value": { "aliases": { + ".alerts-security.alerts-default": { + "is_write_index": false + }, ".siem-signals-default": { "is_write_index": true } @@ -9,7 +12,8 @@ "index": ".siem-signals-default-000001", "mappings": { "_meta": { - "version": 14 + "aliases_version": 1, + "version": 55 }, "dynamic": "false", "properties": { @@ -18,6 +22,14 @@ }, "agent": { "properties": { + "build": { + "properties": { + "original": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, "ephemeral_id": { "ignore_above": 1024, "type": "keyword" @@ -101,6 +113,10 @@ "ignore_above": 1024, "type": "keyword" }, + "continent_code": { + "ignore_above": 1024, + "type": "keyword" + }, "continent_name": { "ignore_above": 1024, "type": "keyword" @@ -120,6 +136,10 @@ "ignore_above": 1024, "type": "keyword" }, + "postal_code": { + "ignore_above": 1024, + "type": "keyword" + }, "region_iso_code": { "ignore_above": 1024, "type": "keyword" @@ -127,6 +147,10 @@ "region_name": { "ignore_above": 1024, "type": "keyword" + }, + "timezone": { + "ignore_above": 1024, + "type": "keyword" } } }, @@ -157,6 +181,10 @@ "ignore_above": 1024, "type": "keyword" }, + "subdomain": { + "ignore_above": 1024, + "type": "keyword" + }, "top_level_domain": { "ignore_above": 1024, "type": "keyword" @@ -214,6 +242,10 @@ }, "ignore_above": 1024, "type": "keyword" + }, + "roles": { + "ignore_above": 1024, + "type": "keyword" } } } @@ -226,6 +258,10 @@ "id": { "ignore_above": 1024, "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" } } }, @@ -253,6 +289,18 @@ } } }, + "project": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, "provider": { "ignore_above": 1024, "type": "keyword" @@ -260,6 +308,14 @@ "region": { "ignore_above": 1024, "type": "keyword" + }, + "service": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } } } }, @@ -315,6 +371,19 @@ } } }, + "data_stream": { + "properties": { + "dataset": { + "type": "keyword" + }, + "namespace": { + "type": "keyword" + }, + "type": { + "type": "keyword" + } + } + }, "destination": { "properties": { "address": { @@ -355,6 +424,10 @@ "ignore_above": 1024, "type": "keyword" }, + "continent_code": { + "ignore_above": 1024, + "type": "keyword" + }, "continent_name": { "ignore_above": 1024, "type": "keyword" @@ -374,6 +447,10 @@ "ignore_above": 1024, "type": "keyword" }, + "postal_code": { + "ignore_above": 1024, + "type": "keyword" + }, "region_iso_code": { "ignore_above": 1024, "type": "keyword" @@ -381,6 +458,10 @@ "region_name": { "ignore_above": 1024, "type": "keyword" + }, + "timezone": { + "ignore_above": 1024, + "type": "keyword" } } }, @@ -411,6 +492,10 @@ "ignore_above": 1024, "type": "keyword" }, + "subdomain": { + "ignore_above": 1024, + "type": "keyword" + }, "top_level_domain": { "ignore_above": 1024, "type": "keyword" @@ -468,6 +553,10 @@ }, "ignore_above": 1024, "type": "keyword" + }, + "roles": { + "ignore_above": 1024, + "type": "keyword" } } } @@ -480,6 +569,10 @@ "exists": { "type": "boolean" }, + "signing_id": { + "ignore_above": 1024, + "type": "keyword" + }, "status": { "ignore_above": 1024, "type": "keyword" @@ -488,6 +581,10 @@ "ignore_above": 1024, "type": "keyword" }, + "team_id": { + "ignore_above": 1024, + "type": "keyword" + }, "trusted": { "type": "boolean" }, @@ -513,6 +610,10 @@ "sha512": { "ignore_above": 1024, "type": "keyword" + }, + "ssdeep": { + "ignore_above": 1024, + "type": "keyword" } } }, @@ -526,6 +627,10 @@ }, "pe": { "properties": { + "architecture": { + "ignore_above": 1024, + "type": "keyword" + }, "company": { "ignore_above": 1024, "type": "keyword" @@ -538,6 +643,10 @@ "ignore_above": 1024, "type": "keyword" }, + "imphash": { + "ignore_above": 1024, + "type": "keyword" + }, "original_file_name": { "ignore_above": 1024, "type": "keyword" @@ -728,6 +837,10 @@ "ignore_above": 1024, "type": "keyword" }, + "reason": { + "ignore_above": 1024, + "type": "keyword" + }, "reference": { "ignore_above": 1024, "type": "keyword" @@ -775,6 +888,10 @@ "exists": { "type": "boolean" }, + "signing_id": { + "ignore_above": 1024, + "type": "keyword" + }, "status": { "ignore_above": 1024, "type": "keyword" @@ -783,6 +900,10 @@ "ignore_above": 1024, "type": "keyword" }, + "team_id": { + "ignore_above": 1024, + "type": "keyword" + }, "trusted": { "type": "boolean" }, @@ -838,6 +959,10 @@ "sha512": { "ignore_above": 1024, "type": "keyword" + }, + "ssdeep": { + "ignore_above": 1024, + "type": "keyword" } } }, @@ -876,6 +1001,10 @@ }, "pe": { "properties": { + "architecture": { + "ignore_above": 1024, + "type": "keyword" + }, "company": { "ignore_above": 1024, "type": "keyword" @@ -888,6 +1017,10 @@ "ignore_above": 1024, "type": "keyword" }, + "imphash": { + "ignore_above": 1024, + "type": "keyword" + }, "original_file_name": { "ignore_above": 1024, "type": "keyword" @@ -918,6 +1051,112 @@ "uid": { "ignore_above": 1024, "type": "keyword" + }, + "x509": { + "properties": { + "alternative_names": { + "ignore_above": 1024, + "type": "keyword" + }, + "issuer": { + "properties": { + "common_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country": { + "ignore_above": 1024, + "type": "keyword" + }, + "distinguished_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "locality": { + "ignore_above": 1024, + "type": "keyword" + }, + "organization": { + "ignore_above": 1024, + "type": "keyword" + }, + "organizational_unit": { + "ignore_above": 1024, + "type": "keyword" + }, + "state_or_province": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "not_after": { + "type": "date" + }, + "not_before": { + "type": "date" + }, + "public_key_algorithm": { + "ignore_above": 1024, + "type": "keyword" + }, + "public_key_curve": { + "ignore_above": 1024, + "type": "keyword" + }, + "public_key_exponent": { + "doc_values": false, + "index": false, + "type": "long" + }, + "public_key_size": { + "type": "long" + }, + "serial_number": { + "ignore_above": 1024, + "type": "keyword" + }, + "signature_algorithm": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject": { + "properties": { + "common_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country": { + "ignore_above": 1024, + "type": "keyword" + }, + "distinguished_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "locality": { + "ignore_above": 1024, + "type": "keyword" + }, + "organization": { + "ignore_above": 1024, + "type": "keyword" + }, + "organizational_unit": { + "ignore_above": 1024, + "type": "keyword" + }, + "state_or_province": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "version_number": { + "ignore_above": 1024, + "type": "keyword" + } + } } } }, @@ -998,6 +1237,32 @@ "ignore_above": 1024, "type": "keyword" }, + "cpu": { + "properties": { + "usage": { + "scaling_factor": 1000, + "type": "scaled_float" + } + } + }, + "disk": { + "properties": { + "read": { + "properties": { + "bytes": { + "type": "long" + } + } + }, + "write": { + "properties": { + "bytes": { + "type": "long" + } + } + } + } + }, "domain": { "ignore_above": 1024, "type": "keyword" @@ -1008,6 +1273,10 @@ "ignore_above": 1024, "type": "keyword" }, + "continent_code": { + "ignore_above": 1024, + "type": "keyword" + }, "continent_name": { "ignore_above": 1024, "type": "keyword" @@ -1027,6 +1296,10 @@ "ignore_above": 1024, "type": "keyword" }, + "postal_code": { + "ignore_above": 1024, + "type": "keyword" + }, "region_iso_code": { "ignore_above": 1024, "type": "keyword" @@ -1034,6 +1307,10 @@ "region_name": { "ignore_above": 1024, "type": "keyword" + }, + "timezone": { + "ignore_above": 1024, + "type": "keyword" } } }, @@ -1056,6 +1333,30 @@ "ignore_above": 1024, "type": "keyword" }, + "network": { + "properties": { + "egress": { + "properties": { + "bytes": { + "type": "long" + }, + "packets": { + "type": "long" + } + } + }, + "ingress": { + "properties": { + "bytes": { + "type": "long" + }, + "packets": { + "type": "long" + } + } + } + } + }, "os": { "properties": { "family": { @@ -1090,6 +1391,10 @@ "ignore_above": 1024, "type": "keyword" }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, "version": { "ignore_above": 1024, "type": "keyword" @@ -1156,6 +1461,10 @@ }, "ignore_above": 1024, "type": "keyword" + }, + "roles": { + "ignore_above": 1024, + "type": "keyword" } } } @@ -1185,10 +1494,18 @@ "bytes": { "type": "long" }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, "method": { "ignore_above": 1024, "type": "keyword" }, + "mime_type": { + "ignore_above": 1024, + "type": "keyword" + }, "referrer": { "ignore_above": 1024, "type": "keyword" @@ -1217,6 +1534,10 @@ "bytes": { "type": "long" }, + "mime_type": { + "ignore_above": 1024, + "type": "keyword" + }, "status_code": { "type": "long" } @@ -1244,11 +1565,475 @@ } } }, - "labels": { - "type": "object" + "kibana": { + "properties": { + "alert": { + "properties": { + "ancestors": { + "properties": { + "depth": { + "path": "signal.ancestors.depth", + "type": "alias" + }, + "id": { + "path": "signal.ancestors.id", + "type": "alias" + }, + "index": { + "path": "signal.ancestors.index", + "type": "alias" + }, + "type": { + "path": "signal.ancestors.type", + "type": "alias" + } + } + }, + "depth": { + "path": "signal.depth", + "type": "alias" + }, + "original_event": { + "properties": { + "action": { + "path": "signal.original_event.action", + "type": "alias" + }, + "category": { + "path": "signal.original_event.category", + "type": "alias" + }, + "code": { + "path": "signal.original_event.code", + "type": "alias" + }, + "created": { + "path": "signal.original_event.created", + "type": "alias" + }, + "dataset": { + "path": "signal.original_event.dataset", + "type": "alias" + }, + "duration": { + "path": "signal.original_event.duration", + "type": "alias" + }, + "end": { + "path": "signal.original_event.end", + "type": "alias" + }, + "hash": { + "path": "signal.original_event.hash", + "type": "alias" + }, + "id": { + "path": "signal.original_event.id", + "type": "alias" + }, + "kind": { + "path": "signal.original_event.kind", + "type": "alias" + }, + "module": { + "path": "signal.original_event.module", + "type": "alias" + }, + "outcome": { + "path": "signal.original_event.outcome", + "type": "alias" + }, + "provider": { + "path": "signal.original_event.provider", + "type": "alias" + }, + "reason": { + "path": "signal.original_event.reason", + "type": "alias" + }, + "risk_score": { + "path": "signal.original_event.risk_score", + "type": "alias" + }, + "risk_score_norm": { + "path": "signal.original_event.risk_score_norm", + "type": "alias" + }, + "sequence": { + "path": "signal.original_event.sequence", + "type": "alias" + }, + "severity": { + "path": "signal.original_event.severity", + "type": "alias" + }, + "start": { + "path": "signal.original_event.start", + "type": "alias" + }, + "timezone": { + "path": "signal.original_event.timezone", + "type": "alias" + }, + "type": { + "path": "signal.original_event.type", + "type": "alias" + } + } + }, + "original_time": { + "path": "signal.original_time", + "type": "alias" + }, + "reason": { + "path": "signal.reason", + "type": "alias" + }, + "risk_score": { + "path": "signal.rule.risk_score", + "type": "alias" + }, + "rule": { + "properties": { + "author": { + "path": "signal.rule.author", + "type": "alias" + }, + "building_block_type": { + "path": "signal.rule.building_block_type", + "type": "alias" + }, + "consumer": { + "type": "constant_keyword", + "value": "siem" + }, + "created_at": { + "path": "signal.rule.created_at", + "type": "alias" + }, + "created_by": { + "path": "signal.rule.created_by", + "type": "alias" + }, + "description": { + "path": "signal.rule.description", + "type": "alias" + }, + "enabled": { + "path": "signal.rule.enabled", + "type": "alias" + }, + "false_positives": { + "path": "signal.rule.false_positives", + "type": "alias" + }, + "from": { + "path": "signal.rule.from", + "type": "alias" + }, + "id": { + "path": "signal.rule.id", + "type": "alias" + }, + "immutable": { + "path": "signal.rule.immutable", + "type": "alias" + }, + "index": { + "path": "signal.rule.index", + "type": "alias" + }, + "interval": { + "path": "signal.rule.interval", + "type": "alias" + }, + "language": { + "path": "signal.rule.language", + "type": "alias" + }, + "license": { + "path": "signal.rule.license", + "type": "alias" + }, + "max_signals": { + "path": "signal.rule.max_signals", + "type": "alias" + }, + "name": { + "path": "signal.rule.name", + "type": "alias" + }, + "note": { + "path": "signal.rule.note", + "type": "alias" + }, + "producer": { + "type": "constant_keyword", + "value": "siem" + }, + "query": { + "path": "signal.rule.query", + "type": "alias" + }, + "references": { + "path": "signal.rule.references", + "type": "alias" + }, + "risk_score_mapping": { + "properties": { + "field": { + "path": "signal.rule.risk_score_mapping.field", + "type": "alias" + }, + "operator": { + "path": "signal.rule.risk_score_mapping.operator", + "type": "alias" + }, + "value": { + "path": "signal.rule.risk_score_mapping.value", + "type": "alias" + } + } + }, + "rule_id": { + "path": "signal.rule.rule_id", + "type": "alias" + }, + "rule_name_override": { + "path": "signal.rule.rule_name_override", + "type": "alias" + }, + "rule_type_id": { + "type": "constant_keyword", + "value": "siem.signals" + }, + "saved_id": { + "path": "signal.rule.saved_id", + "type": "alias" + }, + "severity_mapping": { + "properties": { + "field": { + "path": "signal.rule.severity_mapping.field", + "type": "alias" + }, + "operator": { + "path": "signal.rule.severity_mapping.operator", + "type": "alias" + }, + "severity": { + "path": "signal.rule.severity_mapping.severity", + "type": "alias" + }, + "value": { + "path": "signal.rule.severity_mapping.value", + "type": "alias" + } + } + }, + "tags": { + "path": "signal.rule.tags", + "type": "alias" + }, + "threat": { + "properties": { + "framework": { + "path": "signal.rule.threat.framework", + "type": "alias" + }, + "tactic": { + "properties": { + "id": { + "path": "signal.rule.threat.tactic.id", + "type": "alias" + }, + "name": { + "path": "signal.rule.threat.tactic.name", + "type": "alias" + }, + "reference": { + "path": "signal.rule.threat.tactic.reference", + "type": "alias" + } + } + }, + "technique": { + "properties": { + "id": { + "path": "signal.rule.threat.technique.id", + "type": "alias" + }, + "name": { + "path": "signal.rule.threat.technique.name", + "type": "alias" + }, + "reference": { + "path": "signal.rule.threat.technique.reference", + "type": "alias" + }, + "subtechnique": { + "properties": { + "id": { + "path": "signal.rule.threat.technique.subtechnique.id", + "type": "alias" + }, + "name": { + "path": "signal.rule.threat.technique.subtechnique.name", + "type": "alias" + }, + "reference": { + "path": "signal.rule.threat.technique.subtechnique.reference", + "type": "alias" + } + } + } + } + } + } + }, + "threat_index": { + "path": "signal.rule.threat_index", + "type": "alias" + }, + "threat_indicator_path": { + "path": "signal.rule.threat_indicator_path", + "type": "alias" + }, + "threat_language": { + "path": "signal.rule.threat_language", + "type": "alias" + }, + "threat_mapping": { + "properties": { + "entries": { + "properties": { + "field": { + "path": "signal.rule.threat_mapping.entries.field", + "type": "alias" + }, + "type": { + "path": "signal.rule.threat_mapping.entries.type", + "type": "alias" + }, + "value": { + "path": "signal.rule.threat_mapping.entries.value", + "type": "alias" + } + } + } + } + }, + "threat_query": { + "path": "signal.rule.threat_query", + "type": "alias" + }, + "threshold": { + "properties": { + "field": { + "path": "signal.rule.threshold.field", + "type": "alias" + }, + "value": { + "path": "signal.rule.threshold.value", + "type": "alias" + } + } + }, + "timeline_id": { + "path": "signal.rule.timeline_id", + "type": "alias" + }, + "timeline_title": { + "path": "signal.rule.timeline_title", + "type": "alias" + }, + "to": { + "path": "signal.rule.to", + "type": "alias" + }, + "type": { + "path": "signal.rule.type", + "type": "alias" + }, + "updated_at": { + "path": "signal.rule.updated_at", + "type": "alias" + }, + "updated_by": { + "path": "signal.rule.updated_by", + "type": "alias" + }, + "version": { + "path": "signal.rule.version", + "type": "alias" + } + } + }, + "severity": { + "path": "signal.rule.severity", + "type": "alias" + }, + "threshold_result": { + "properties": { + "cardinality": { + "properties": { + "field": { + "path": "signal.threshold_result.cardinality.field", + "type": "alias" + }, + "value": { + "path": "signal.threshold_result.cardinality.value", + "type": "alias" + } + } + }, + "count": { + "path": "signal.threshold_result.count", + "type": "alias" + }, + "from": { + "path": "signal.threshold_result.from", + "type": "alias" + }, + "terms": { + "properties": { + "field": { + "path": "signal.threshold_result.terms.field", + "type": "alias" + }, + "value": { + "path": "signal.threshold_result.terms.value", + "type": "alias" + } + } + } + } + }, + "workflow_status": { + "path": "signal.status", + "type": "alias" + } + } + }, + "space_ids": { + "type": "constant_keyword", + "value": "default" + } + } + }, + "labels": { + "type": "object" }, "log": { "properties": { + "file": { + "properties": { + "path": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, "level": { "ignore_above": 1024, "type": "keyword" @@ -1434,6 +2219,10 @@ "ignore_above": 1024, "type": "keyword" }, + "continent_code": { + "ignore_above": 1024, + "type": "keyword" + }, "continent_name": { "ignore_above": 1024, "type": "keyword" @@ -1453,6 +2242,10 @@ "ignore_above": 1024, "type": "keyword" }, + "postal_code": { + "ignore_above": 1024, + "type": "keyword" + }, "region_iso_code": { "ignore_above": 1024, "type": "keyword" @@ -1460,6 +2253,10 @@ "region_name": { "ignore_above": 1024, "type": "keyword" + }, + "timezone": { + "ignore_above": 1024, + "type": "keyword" } } }, @@ -1548,6 +2345,10 @@ "ignore_above": 1024, "type": "keyword" }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, "version": { "ignore_above": 1024, "type": "keyword" @@ -1576,6 +2377,54 @@ } } }, + "orchestrator": { + "properties": { + "api_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "cluster": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "url": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "namespace": { + "ignore_above": 1024, + "type": "keyword" + }, + "organization": { + "ignore_above": 1024, + "type": "keyword" + }, + "resource": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, "organization": { "properties": { "id": { @@ -1726,6 +2575,10 @@ "exists": { "type": "boolean" }, + "signing_id": { + "ignore_above": 1024, + "type": "keyword" + }, "status": { "ignore_above": 1024, "type": "keyword" @@ -1734,6 +2587,10 @@ "ignore_above": 1024, "type": "keyword" }, + "team_id": { + "ignore_above": 1024, + "type": "keyword" + }, "trusted": { "type": "boolean" }, @@ -1786,6 +2643,10 @@ "sha512": { "ignore_above": 1024, "type": "keyword" + }, + "ssdeep": { + "ignore_above": 1024, + "type": "keyword" } } }, @@ -1813,6 +2674,10 @@ "exists": { "type": "boolean" }, + "signing_id": { + "ignore_above": 1024, + "type": "keyword" + }, "status": { "ignore_above": 1024, "type": "keyword" @@ -1821,6 +2686,10 @@ "ignore_above": 1024, "type": "keyword" }, + "team_id": { + "ignore_above": 1024, + "type": "keyword" + }, "trusted": { "type": "boolean" }, @@ -1873,6 +2742,10 @@ "sha512": { "ignore_above": 1024, "type": "keyword" + }, + "ssdeep": { + "ignore_above": 1024, + "type": "keyword" } } }, @@ -1886,22 +2759,54 @@ "ignore_above": 1024, "type": "keyword" }, - "pgid": { - "type": "long" - }, - "pid": { - "type": "long" - }, - "ppid": { - "type": "long" - }, - "start": { - "type": "date" - }, - "thread": { + "pe": { "properties": { - "id": { - "type": "long" + "architecture": { + "ignore_above": 1024, + "type": "keyword" + }, + "company": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "file_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "imphash": { + "ignore_above": 1024, + "type": "keyword" + }, + "original_file_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "product": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "pgid": { + "type": "long" + }, + "pid": { + "type": "long" + }, + "ppid": { + "type": "long" + }, + "start": { + "type": "date" + }, + "thread": { + "properties": { + "id": { + "type": "long" }, "name": { "ignore_above": 1024, @@ -1936,6 +2841,10 @@ }, "pe": { "properties": { + "architecture": { + "ignore_above": 1024, + "type": "keyword" + }, "company": { "ignore_above": 1024, "type": "keyword" @@ -1948,6 +2857,10 @@ "ignore_above": 1024, "type": "keyword" }, + "imphash": { + "ignore_above": 1024, + "type": "keyword" + }, "original_file_name": { "ignore_above": 1024, "type": "keyword" @@ -2048,6 +2961,10 @@ "ignore_above": 1024, "type": "keyword" }, + "hosts": { + "ignore_above": 1024, + "type": "keyword" + }, "ip": { "type": "ip" }, @@ -2141,6 +3058,10 @@ "ignore_above": 1024, "type": "keyword" }, + "continent_code": { + "ignore_above": 1024, + "type": "keyword" + }, "continent_name": { "ignore_above": 1024, "type": "keyword" @@ -2160,6 +3081,10 @@ "ignore_above": 1024, "type": "keyword" }, + "postal_code": { + "ignore_above": 1024, + "type": "keyword" + }, "region_iso_code": { "ignore_above": 1024, "type": "keyword" @@ -2167,6 +3092,10 @@ "region_name": { "ignore_above": 1024, "type": "keyword" + }, + "timezone": { + "ignore_above": 1024, + "type": "keyword" } } }, @@ -2197,6 +3126,10 @@ "ignore_above": 1024, "type": "keyword" }, + "subdomain": { + "ignore_above": 1024, + "type": "keyword" + }, "top_level_domain": { "ignore_above": 1024, "type": "keyword" @@ -2254,6 +3187,10 @@ }, "ignore_above": 1024, "type": "keyword" + }, + "roles": { + "ignore_above": 1024, + "type": "keyword" } } } @@ -2382,6 +3319,9 @@ "provider": { "type": "keyword" }, + "reason": { + "type": "keyword" + }, "risk_score": { "type": "float" }, @@ -2451,6 +3391,9 @@ } } }, + "reason": { + "type": "keyword" + }, "rule": { "properties": { "author": { @@ -2612,6 +3555,38 @@ } } }, + "threat_filters": { + "type": "object" + }, + "threat_index": { + "type": "keyword" + }, + "threat_indicator_path": { + "type": "keyword" + }, + "threat_language": { + "type": "keyword" + }, + "threat_mapping": { + "properties": { + "entries": { + "properties": { + "field": { + "type": "keyword" + }, + "type": { + "type": "keyword" + }, + "value": { + "type": "keyword" + } + } + } + } + }, + "threat_query": { + "type": "keyword" + }, "threshold": { "properties": { "field": { @@ -2656,11 +3631,31 @@ }, "threshold_result": { "properties": { + "cardinality": { + "properties": { + "field": { + "type": "keyword" + }, + "value": { + "type": "long" + } + } + }, "count": { "type": "long" }, - "value": { - "type": "keyword" + "from": { + "type": "date" + }, + "terms": { + "properties": { + "field": { + "type": "keyword" + }, + "value": { + "type": "keyword" + } + } } } } @@ -2706,6 +3701,10 @@ "ignore_above": 1024, "type": "keyword" }, + "continent_code": { + "ignore_above": 1024, + "type": "keyword" + }, "continent_name": { "ignore_above": 1024, "type": "keyword" @@ -2725,6 +3724,10 @@ "ignore_above": 1024, "type": "keyword" }, + "postal_code": { + "ignore_above": 1024, + "type": "keyword" + }, "region_iso_code": { "ignore_above": 1024, "type": "keyword" @@ -2732,6 +3735,10 @@ "region_name": { "ignore_above": 1024, "type": "keyword" + }, + "timezone": { + "ignore_above": 1024, + "type": "keyword" } } }, @@ -2762,6 +3769,10 @@ "ignore_above": 1024, "type": "keyword" }, + "subdomain": { + "ignore_above": 1024, + "type": "keyword" + }, "top_level_domain": { "ignore_above": 1024, "type": "keyword" @@ -2819,11 +3830,23 @@ }, "ignore_above": 1024, "type": "keyword" + }, + "roles": { + "ignore_above": 1024, + "type": "keyword" } } } } }, + "span": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, "tags": { "ignore_above": 1024, "type": "keyword" @@ -2834,129 +3857,492 @@ "ignore_above": 1024, "type": "keyword" }, - "tactic": { + "indicator": { "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" + "as": { + "properties": { + "number": { + "type": "long" + }, + "organization": { + "properties": { + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } }, - "name": { + "confidence": { "ignore_above": 1024, "type": "keyword" }, - "reference": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "technique": { - "properties": { - "id": { + "dataset": { "ignore_above": 1024, "type": "keyword" }, - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" + "description": { + "type": "wildcard" }, - "reference": { - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "tls": { - "properties": { - "cipher": { - "ignore_above": 1024, - "type": "keyword" - }, - "client": { - "properties": { - "certificate": { + "domain": { "ignore_above": 1024, "type": "keyword" }, - "certificate_chain": { - "ignore_above": 1024, - "type": "keyword" + "email": { + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + } + } }, - "hash": { + "event": { "properties": { - "md5": { + "action": { "ignore_above": 1024, "type": "keyword" }, - "sha1": { + "category": { "ignore_above": 1024, "type": "keyword" }, - "sha256": { + "code": { "ignore_above": 1024, "type": "keyword" - } - } - }, - "issuer": { - "ignore_above": 1024, - "type": "keyword" - }, - "ja3": { - "ignore_above": 1024, - "type": "keyword" - }, - "not_after": { - "type": "date" - }, - "not_before": { - "type": "date" - }, - "server_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "subject": { - "ignore_above": 1024, - "type": "keyword" - }, - "supported_ciphers": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "curve": { - "ignore_above": 1024, - "type": "keyword" - }, - "established": { - "type": "boolean" - }, - "next_protocol": { - "ignore_above": 1024, - "type": "keyword" - }, - "resumed": { - "type": "boolean" - }, - "server": { - "properties": { - "certificate": { - "ignore_above": 1024, - "type": "keyword" - }, - "certificate_chain": { - "ignore_above": 1024, - "type": "keyword" + }, + "created": { + "type": "date" + }, + "dataset": { + "ignore_above": 1024, + "type": "keyword" + }, + "duration": { + "type": "long" + }, + "end": { + "type": "date" + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "ingested": { + "type": "date" + }, + "kind": { + "ignore_above": 1024, + "type": "keyword" + }, + "module": { + "ignore_above": 1024, + "type": "keyword" + }, + "original": { + "doc_values": false, + "ignore_above": 1024, + "index": false, + "type": "keyword" + }, + "outcome": { + "ignore_above": 1024, + "type": "keyword" + }, + "provider": { + "ignore_above": 1024, + "type": "keyword" + }, + "reason": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + }, + "risk_score": { + "type": "float" + }, + "risk_score_norm": { + "type": "float" + }, + "sequence": { + "type": "long" + }, + "severity": { + "type": "long" + }, + "start": { + "type": "date" + }, + "timezone": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "url": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "first_seen": { + "type": "date" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "last_seen": { + "type": "date" + }, + "marking": { + "properties": { + "tlp": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "matched": { + "properties": { + "atomic": { + "ignore_above": 1024, + "type": "keyword" + }, + "field": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "module": { + "ignore_above": 1024, + "type": "keyword" + }, + "port": { + "type": "long" + }, + "provider": { + "ignore_above": 1024, + "type": "keyword" + }, + "scanner_stats": { + "type": "long" + }, + "sightings": { + "type": "long" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + }, + "type": "nested" + }, + "tactic": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "technique": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + }, + "subtechnique": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + } + } + }, + "tls": { + "properties": { + "cipher": { + "ignore_above": 1024, + "type": "keyword" + }, + "client": { + "properties": { + "certificate": { + "ignore_above": 1024, + "type": "keyword" + }, + "certificate_chain": { + "ignore_above": 1024, + "type": "keyword" + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "issuer": { + "ignore_above": 1024, + "type": "keyword" + }, + "ja3": { + "ignore_above": 1024, + "type": "keyword" + }, + "not_after": { + "type": "date" + }, + "not_before": { + "type": "date" + }, + "server_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject": { + "ignore_above": 1024, + "type": "keyword" + }, + "supported_ciphers": { + "ignore_above": 1024, + "type": "keyword" + }, + "x509": { + "properties": { + "alternative_names": { + "ignore_above": 1024, + "type": "keyword" + }, + "issuer": { + "properties": { + "common_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country": { + "ignore_above": 1024, + "type": "keyword" + }, + "distinguished_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "locality": { + "ignore_above": 1024, + "type": "keyword" + }, + "organization": { + "ignore_above": 1024, + "type": "keyword" + }, + "organizational_unit": { + "ignore_above": 1024, + "type": "keyword" + }, + "state_or_province": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "not_after": { + "type": "date" + }, + "not_before": { + "type": "date" + }, + "public_key_algorithm": { + "ignore_above": 1024, + "type": "keyword" + }, + "public_key_curve": { + "ignore_above": 1024, + "type": "keyword" + }, + "public_key_exponent": { + "doc_values": false, + "index": false, + "type": "long" + }, + "public_key_size": { + "type": "long" + }, + "serial_number": { + "ignore_above": 1024, + "type": "keyword" + }, + "signature_algorithm": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject": { + "properties": { + "common_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country": { + "ignore_above": 1024, + "type": "keyword" + }, + "distinguished_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "locality": { + "ignore_above": 1024, + "type": "keyword" + }, + "organization": { + "ignore_above": 1024, + "type": "keyword" + }, + "organizational_unit": { + "ignore_above": 1024, + "type": "keyword" + }, + "state_or_province": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "version_number": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "curve": { + "ignore_above": 1024, + "type": "keyword" + }, + "established": { + "type": "boolean" + }, + "next_protocol": { + "ignore_above": 1024, + "type": "keyword" + }, + "resumed": { + "type": "boolean" + }, + "server": { + "properties": { + "certificate": { + "ignore_above": 1024, + "type": "keyword" + }, + "certificate_chain": { + "ignore_above": 1024, + "type": "keyword" }, "hash": { "properties": { @@ -2991,6 +4377,112 @@ "subject": { "ignore_above": 1024, "type": "keyword" + }, + "x509": { + "properties": { + "alternative_names": { + "ignore_above": 1024, + "type": "keyword" + }, + "issuer": { + "properties": { + "common_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country": { + "ignore_above": 1024, + "type": "keyword" + }, + "distinguished_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "locality": { + "ignore_above": 1024, + "type": "keyword" + }, + "organization": { + "ignore_above": 1024, + "type": "keyword" + }, + "organizational_unit": { + "ignore_above": 1024, + "type": "keyword" + }, + "state_or_province": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "not_after": { + "type": "date" + }, + "not_before": { + "type": "date" + }, + "public_key_algorithm": { + "ignore_above": 1024, + "type": "keyword" + }, + "public_key_curve": { + "ignore_above": 1024, + "type": "keyword" + }, + "public_key_exponent": { + "doc_values": false, + "index": false, + "type": "long" + }, + "public_key_size": { + "type": "long" + }, + "serial_number": { + "ignore_above": 1024, + "type": "keyword" + }, + "signature_algorithm": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject": { + "properties": { + "common_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country": { + "ignore_above": 1024, + "type": "keyword" + }, + "distinguished_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "locality": { + "ignore_above": 1024, + "type": "keyword" + }, + "organization": { + "ignore_above": 1024, + "type": "keyword" + }, + "organizational_unit": { + "ignore_above": 1024, + "type": "keyword" + }, + "state_or_province": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "version_number": { + "ignore_above": 1024, + "type": "keyword" + } + } } } }, @@ -3077,6 +4569,10 @@ "ignore_above": 1024, "type": "keyword" }, + "subdomain": { + "ignore_above": 1024, + "type": "keyword" + }, "top_level_domain": { "ignore_above": 1024, "type": "keyword" @@ -3089,10 +4585,130 @@ }, "user": { "properties": { + "changes": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "roles": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, "domain": { "ignore_above": 1024, "type": "keyword" }, + "effective": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "roles": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, "email": { "ignore_above": 1024, "type": "keyword" @@ -3140,6 +4756,70 @@ }, "ignore_above": 1024, "type": "keyword" + }, + "roles": { + "ignore_above": 1024, + "type": "keyword" + }, + "target": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "roles": { + "ignore_above": 1024, + "type": "keyword" + } + } } } }, @@ -3201,6 +4881,10 @@ "ignore_above": 1024, "type": "keyword" }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, "version": { "ignore_above": 1024, "type": "keyword" @@ -3320,7 +5004,8 @@ "index": ".siem-signals-default-000002", "mappings": { "_meta": { - "version": 14 + "aliases_version": 1, + "version": 55 }, "dynamic": "false", "properties": { @@ -3329,6 +5014,14 @@ }, "agent": { "properties": { + "build": { + "properties": { + "original": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, "ephemeral_id": { "ignore_above": 1024, "type": "keyword" @@ -3412,6 +5105,10 @@ "ignore_above": 1024, "type": "keyword" }, + "continent_code": { + "ignore_above": 1024, + "type": "keyword" + }, "continent_name": { "ignore_above": 1024, "type": "keyword" @@ -3431,6 +5128,10 @@ "ignore_above": 1024, "type": "keyword" }, + "postal_code": { + "ignore_above": 1024, + "type": "keyword" + }, "region_iso_code": { "ignore_above": 1024, "type": "keyword" @@ -3438,6 +5139,10 @@ "region_name": { "ignore_above": 1024, "type": "keyword" + }, + "timezone": { + "ignore_above": 1024, + "type": "keyword" } } }, @@ -3468,6 +5173,10 @@ "ignore_above": 1024, "type": "keyword" }, + "subdomain": { + "ignore_above": 1024, + "type": "keyword" + }, "top_level_domain": { "ignore_above": 1024, "type": "keyword" @@ -3525,6 +5234,10 @@ }, "ignore_above": 1024, "type": "keyword" + }, + "roles": { + "ignore_above": 1024, + "type": "keyword" } } } @@ -3537,6 +5250,10 @@ "id": { "ignore_above": 1024, "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" } } }, @@ -3564,6 +5281,18 @@ } } }, + "project": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, "provider": { "ignore_above": 1024, "type": "keyword" @@ -3571,6 +5300,14 @@ "region": { "ignore_above": 1024, "type": "keyword" + }, + "service": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } } } }, @@ -3626,6 +5363,19 @@ } } }, + "data_stream": { + "properties": { + "dataset": { + "type": "keyword" + }, + "namespace": { + "type": "keyword" + }, + "type": { + "type": "keyword" + } + } + }, "destination": { "properties": { "address": { @@ -3666,6 +5416,10 @@ "ignore_above": 1024, "type": "keyword" }, + "continent_code": { + "ignore_above": 1024, + "type": "keyword" + }, "continent_name": { "ignore_above": 1024, "type": "keyword" @@ -3685,6 +5439,10 @@ "ignore_above": 1024, "type": "keyword" }, + "postal_code": { + "ignore_above": 1024, + "type": "keyword" + }, "region_iso_code": { "ignore_above": 1024, "type": "keyword" @@ -3692,6 +5450,10 @@ "region_name": { "ignore_above": 1024, "type": "keyword" + }, + "timezone": { + "ignore_above": 1024, + "type": "keyword" } } }, @@ -3722,6 +5484,10 @@ "ignore_above": 1024, "type": "keyword" }, + "subdomain": { + "ignore_above": 1024, + "type": "keyword" + }, "top_level_domain": { "ignore_above": 1024, "type": "keyword" @@ -3779,6 +5545,10 @@ }, "ignore_above": 1024, "type": "keyword" + }, + "roles": { + "ignore_above": 1024, + "type": "keyword" } } } @@ -3791,6 +5561,10 @@ "exists": { "type": "boolean" }, + "signing_id": { + "ignore_above": 1024, + "type": "keyword" + }, "status": { "ignore_above": 1024, "type": "keyword" @@ -3799,6 +5573,10 @@ "ignore_above": 1024, "type": "keyword" }, + "team_id": { + "ignore_above": 1024, + "type": "keyword" + }, "trusted": { "type": "boolean" }, @@ -3824,6 +5602,10 @@ "sha512": { "ignore_above": 1024, "type": "keyword" + }, + "ssdeep": { + "ignore_above": 1024, + "type": "keyword" } } }, @@ -3837,6 +5619,10 @@ }, "pe": { "properties": { + "architecture": { + "ignore_above": 1024, + "type": "keyword" + }, "company": { "ignore_above": 1024, "type": "keyword" @@ -3849,6 +5635,10 @@ "ignore_above": 1024, "type": "keyword" }, + "imphash": { + "ignore_above": 1024, + "type": "keyword" + }, "original_file_name": { "ignore_above": 1024, "type": "keyword" @@ -4039,6 +5829,10 @@ "ignore_above": 1024, "type": "keyword" }, + "reason": { + "ignore_above": 1024, + "type": "keyword" + }, "reference": { "ignore_above": 1024, "type": "keyword" @@ -4086,6 +5880,10 @@ "exists": { "type": "boolean" }, + "signing_id": { + "ignore_above": 1024, + "type": "keyword" + }, "status": { "ignore_above": 1024, "type": "keyword" @@ -4094,6 +5892,10 @@ "ignore_above": 1024, "type": "keyword" }, + "team_id": { + "ignore_above": 1024, + "type": "keyword" + }, "trusted": { "type": "boolean" }, @@ -4149,6 +5951,10 @@ "sha512": { "ignore_above": 1024, "type": "keyword" + }, + "ssdeep": { + "ignore_above": 1024, + "type": "keyword" } } }, @@ -4187,6 +5993,10 @@ }, "pe": { "properties": { + "architecture": { + "ignore_above": 1024, + "type": "keyword" + }, "company": { "ignore_above": 1024, "type": "keyword" @@ -4199,6 +6009,10 @@ "ignore_above": 1024, "type": "keyword" }, + "imphash": { + "ignore_above": 1024, + "type": "keyword" + }, "original_file_name": { "ignore_above": 1024, "type": "keyword" @@ -4229,6 +6043,112 @@ "uid": { "ignore_above": 1024, "type": "keyword" + }, + "x509": { + "properties": { + "alternative_names": { + "ignore_above": 1024, + "type": "keyword" + }, + "issuer": { + "properties": { + "common_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country": { + "ignore_above": 1024, + "type": "keyword" + }, + "distinguished_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "locality": { + "ignore_above": 1024, + "type": "keyword" + }, + "organization": { + "ignore_above": 1024, + "type": "keyword" + }, + "organizational_unit": { + "ignore_above": 1024, + "type": "keyword" + }, + "state_or_province": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "not_after": { + "type": "date" + }, + "not_before": { + "type": "date" + }, + "public_key_algorithm": { + "ignore_above": 1024, + "type": "keyword" + }, + "public_key_curve": { + "ignore_above": 1024, + "type": "keyword" + }, + "public_key_exponent": { + "doc_values": false, + "index": false, + "type": "long" + }, + "public_key_size": { + "type": "long" + }, + "serial_number": { + "ignore_above": 1024, + "type": "keyword" + }, + "signature_algorithm": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject": { + "properties": { + "common_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country": { + "ignore_above": 1024, + "type": "keyword" + }, + "distinguished_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "locality": { + "ignore_above": 1024, + "type": "keyword" + }, + "organization": { + "ignore_above": 1024, + "type": "keyword" + }, + "organizational_unit": { + "ignore_above": 1024, + "type": "keyword" + }, + "state_or_province": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "version_number": { + "ignore_above": 1024, + "type": "keyword" + } + } } } }, @@ -4309,6 +6229,32 @@ "ignore_above": 1024, "type": "keyword" }, + "cpu": { + "properties": { + "usage": { + "scaling_factor": 1000, + "type": "scaled_float" + } + } + }, + "disk": { + "properties": { + "read": { + "properties": { + "bytes": { + "type": "long" + } + } + }, + "write": { + "properties": { + "bytes": { + "type": "long" + } + } + } + } + }, "domain": { "ignore_above": 1024, "type": "keyword" @@ -4319,6 +6265,10 @@ "ignore_above": 1024, "type": "keyword" }, + "continent_code": { + "ignore_above": 1024, + "type": "keyword" + }, "continent_name": { "ignore_above": 1024, "type": "keyword" @@ -4338,6 +6288,10 @@ "ignore_above": 1024, "type": "keyword" }, + "postal_code": { + "ignore_above": 1024, + "type": "keyword" + }, "region_iso_code": { "ignore_above": 1024, "type": "keyword" @@ -4345,6 +6299,10 @@ "region_name": { "ignore_above": 1024, "type": "keyword" + }, + "timezone": { + "ignore_above": 1024, + "type": "keyword" } } }, @@ -4367,6 +6325,30 @@ "ignore_above": 1024, "type": "keyword" }, + "network": { + "properties": { + "egress": { + "properties": { + "bytes": { + "type": "long" + }, + "packets": { + "type": "long" + } + } + }, + "ingress": { + "properties": { + "bytes": { + "type": "long" + }, + "packets": { + "type": "long" + } + } + } + } + }, "os": { "properties": { "family": { @@ -4401,6 +6383,10 @@ "ignore_above": 1024, "type": "keyword" }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, "version": { "ignore_above": 1024, "type": "keyword" @@ -4467,6 +6453,10 @@ }, "ignore_above": 1024, "type": "keyword" + }, + "roles": { + "ignore_above": 1024, + "type": "keyword" } } } @@ -4493,65 +6483,533 @@ } } }, - "bytes": { - "type": "long" - }, - "method": { - "ignore_above": 1024, - "type": "keyword" + "bytes": { + "type": "long" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "method": { + "ignore_above": 1024, + "type": "keyword" + }, + "mime_type": { + "ignore_above": 1024, + "type": "keyword" + }, + "referrer": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "response": { + "properties": { + "body": { + "properties": { + "bytes": { + "type": "long" + }, + "content": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "bytes": { + "type": "long" + }, + "mime_type": { + "ignore_above": 1024, + "type": "keyword" + }, + "status_code": { + "type": "long" + } + } + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "interface": { + "properties": { + "alias": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "kibana": { + "properties": { + "alert": { + "properties": { + "ancestors": { + "properties": { + "depth": { + "path": "signal.ancestors.depth", + "type": "alias" + }, + "id": { + "path": "signal.ancestors.id", + "type": "alias" + }, + "index": { + "path": "signal.ancestors.index", + "type": "alias" + }, + "type": { + "path": "signal.ancestors.type", + "type": "alias" + } + } + }, + "depth": { + "path": "signal.depth", + "type": "alias" + }, + "original_event": { + "properties": { + "action": { + "path": "signal.original_event.action", + "type": "alias" + }, + "category": { + "path": "signal.original_event.category", + "type": "alias" + }, + "code": { + "path": "signal.original_event.code", + "type": "alias" + }, + "created": { + "path": "signal.original_event.created", + "type": "alias" + }, + "dataset": { + "path": "signal.original_event.dataset", + "type": "alias" + }, + "duration": { + "path": "signal.original_event.duration", + "type": "alias" + }, + "end": { + "path": "signal.original_event.end", + "type": "alias" + }, + "hash": { + "path": "signal.original_event.hash", + "type": "alias" + }, + "id": { + "path": "signal.original_event.id", + "type": "alias" + }, + "kind": { + "path": "signal.original_event.kind", + "type": "alias" + }, + "module": { + "path": "signal.original_event.module", + "type": "alias" + }, + "outcome": { + "path": "signal.original_event.outcome", + "type": "alias" + }, + "provider": { + "path": "signal.original_event.provider", + "type": "alias" + }, + "reason": { + "path": "signal.original_event.reason", + "type": "alias" + }, + "risk_score": { + "path": "signal.original_event.risk_score", + "type": "alias" + }, + "risk_score_norm": { + "path": "signal.original_event.risk_score_norm", + "type": "alias" + }, + "sequence": { + "path": "signal.original_event.sequence", + "type": "alias" + }, + "severity": { + "path": "signal.original_event.severity", + "type": "alias" + }, + "start": { + "path": "signal.original_event.start", + "type": "alias" + }, + "timezone": { + "path": "signal.original_event.timezone", + "type": "alias" + }, + "type": { + "path": "signal.original_event.type", + "type": "alias" + } + } + }, + "original_time": { + "path": "signal.original_time", + "type": "alias" + }, + "reason": { + "path": "signal.reason", + "type": "alias" + }, + "risk_score": { + "path": "signal.rule.risk_score", + "type": "alias" + }, + "rule": { + "properties": { + "author": { + "path": "signal.rule.author", + "type": "alias" + }, + "building_block_type": { + "path": "signal.rule.building_block_type", + "type": "alias" + }, + "consumer": { + "type": "constant_keyword", + "value": "siem" + }, + "created_at": { + "path": "signal.rule.created_at", + "type": "alias" + }, + "created_by": { + "path": "signal.rule.created_by", + "type": "alias" + }, + "description": { + "path": "signal.rule.description", + "type": "alias" + }, + "enabled": { + "path": "signal.rule.enabled", + "type": "alias" + }, + "false_positives": { + "path": "signal.rule.false_positives", + "type": "alias" + }, + "from": { + "path": "signal.rule.from", + "type": "alias" + }, + "id": { + "path": "signal.rule.id", + "type": "alias" + }, + "immutable": { + "path": "signal.rule.immutable", + "type": "alias" + }, + "index": { + "path": "signal.rule.index", + "type": "alias" + }, + "interval": { + "path": "signal.rule.interval", + "type": "alias" + }, + "language": { + "path": "signal.rule.language", + "type": "alias" + }, + "license": { + "path": "signal.rule.license", + "type": "alias" + }, + "max_signals": { + "path": "signal.rule.max_signals", + "type": "alias" + }, + "name": { + "path": "signal.rule.name", + "type": "alias" + }, + "note": { + "path": "signal.rule.note", + "type": "alias" + }, + "producer": { + "type": "constant_keyword", + "value": "siem" + }, + "query": { + "path": "signal.rule.query", + "type": "alias" + }, + "references": { + "path": "signal.rule.references", + "type": "alias" + }, + "risk_score_mapping": { + "properties": { + "field": { + "path": "signal.rule.risk_score_mapping.field", + "type": "alias" + }, + "operator": { + "path": "signal.rule.risk_score_mapping.operator", + "type": "alias" + }, + "value": { + "path": "signal.rule.risk_score_mapping.value", + "type": "alias" + } + } + }, + "rule_id": { + "path": "signal.rule.rule_id", + "type": "alias" + }, + "rule_name_override": { + "path": "signal.rule.rule_name_override", + "type": "alias" + }, + "rule_type_id": { + "type": "constant_keyword", + "value": "siem.signals" + }, + "saved_id": { + "path": "signal.rule.saved_id", + "type": "alias" + }, + "severity_mapping": { + "properties": { + "field": { + "path": "signal.rule.severity_mapping.field", + "type": "alias" + }, + "operator": { + "path": "signal.rule.severity_mapping.operator", + "type": "alias" + }, + "severity": { + "path": "signal.rule.severity_mapping.severity", + "type": "alias" + }, + "value": { + "path": "signal.rule.severity_mapping.value", + "type": "alias" + } + } + }, + "tags": { + "path": "signal.rule.tags", + "type": "alias" + }, + "threat": { + "properties": { + "framework": { + "path": "signal.rule.threat.framework", + "type": "alias" + }, + "tactic": { + "properties": { + "id": { + "path": "signal.rule.threat.tactic.id", + "type": "alias" + }, + "name": { + "path": "signal.rule.threat.tactic.name", + "type": "alias" + }, + "reference": { + "path": "signal.rule.threat.tactic.reference", + "type": "alias" + } + } + }, + "technique": { + "properties": { + "id": { + "path": "signal.rule.threat.technique.id", + "type": "alias" + }, + "name": { + "path": "signal.rule.threat.technique.name", + "type": "alias" + }, + "reference": { + "path": "signal.rule.threat.technique.reference", + "type": "alias" + }, + "subtechnique": { + "properties": { + "id": { + "path": "signal.rule.threat.technique.subtechnique.id", + "type": "alias" + }, + "name": { + "path": "signal.rule.threat.technique.subtechnique.name", + "type": "alias" + }, + "reference": { + "path": "signal.rule.threat.technique.subtechnique.reference", + "type": "alias" + } + } + } + } + } + } + }, + "threat_index": { + "path": "signal.rule.threat_index", + "type": "alias" + }, + "threat_indicator_path": { + "path": "signal.rule.threat_indicator_path", + "type": "alias" + }, + "threat_language": { + "path": "signal.rule.threat_language", + "type": "alias" + }, + "threat_mapping": { + "properties": { + "entries": { + "properties": { + "field": { + "path": "signal.rule.threat_mapping.entries.field", + "type": "alias" + }, + "type": { + "path": "signal.rule.threat_mapping.entries.type", + "type": "alias" + }, + "value": { + "path": "signal.rule.threat_mapping.entries.value", + "type": "alias" + } + } + } + } + }, + "threat_query": { + "path": "signal.rule.threat_query", + "type": "alias" + }, + "threshold": { + "properties": { + "field": { + "path": "signal.rule.threshold.field", + "type": "alias" + }, + "value": { + "path": "signal.rule.threshold.value", + "type": "alias" + } + } + }, + "timeline_id": { + "path": "signal.rule.timeline_id", + "type": "alias" + }, + "timeline_title": { + "path": "signal.rule.timeline_title", + "type": "alias" + }, + "to": { + "path": "signal.rule.to", + "type": "alias" + }, + "type": { + "path": "signal.rule.type", + "type": "alias" + }, + "updated_at": { + "path": "signal.rule.updated_at", + "type": "alias" + }, + "updated_by": { + "path": "signal.rule.updated_by", + "type": "alias" + }, + "version": { + "path": "signal.rule.version", + "type": "alias" + } + } + }, + "severity": { + "path": "signal.rule.severity", + "type": "alias" }, - "referrer": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "response": { - "properties": { - "body": { + "threshold_result": { "properties": { - "bytes": { - "type": "long" + "cardinality": { + "properties": { + "field": { + "path": "signal.threshold_result.cardinality.field", + "type": "alias" + }, + "value": { + "path": "signal.threshold_result.cardinality.value", + "type": "alias" + } + } }, - "content": { - "fields": { - "text": { - "norms": false, - "type": "text" + "count": { + "path": "signal.threshold_result.count", + "type": "alias" + }, + "from": { + "path": "signal.threshold_result.from", + "type": "alias" + }, + "terms": { + "properties": { + "field": { + "path": "signal.threshold_result.terms.field", + "type": "alias" + }, + "value": { + "path": "signal.threshold_result.terms.value", + "type": "alias" } - }, - "ignore_above": 1024, - "type": "keyword" + } } } }, - "bytes": { - "type": "long" - }, - "status_code": { - "type": "long" + "workflow_status": { + "path": "signal.status", + "type": "alias" } } }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "interface": { - "properties": { - "alias": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" + "space_ids": { + "type": "constant_keyword", + "value": "default" } } }, @@ -4560,6 +7018,14 @@ }, "log": { "properties": { + "file": { + "properties": { + "path": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, "level": { "ignore_above": 1024, "type": "keyword" @@ -4745,6 +7211,10 @@ "ignore_above": 1024, "type": "keyword" }, + "continent_code": { + "ignore_above": 1024, + "type": "keyword" + }, "continent_name": { "ignore_above": 1024, "type": "keyword" @@ -4764,6 +7234,10 @@ "ignore_above": 1024, "type": "keyword" }, + "postal_code": { + "ignore_above": 1024, + "type": "keyword" + }, "region_iso_code": { "ignore_above": 1024, "type": "keyword" @@ -4771,6 +7245,10 @@ "region_name": { "ignore_above": 1024, "type": "keyword" + }, + "timezone": { + "ignore_above": 1024, + "type": "keyword" } } }, @@ -4859,6 +7337,10 @@ "ignore_above": 1024, "type": "keyword" }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, "version": { "ignore_above": 1024, "type": "keyword" @@ -4887,6 +7369,54 @@ } } }, + "orchestrator": { + "properties": { + "api_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "cluster": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "url": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "namespace": { + "ignore_above": 1024, + "type": "keyword" + }, + "organization": { + "ignore_above": 1024, + "type": "keyword" + }, + "resource": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, "organization": { "properties": { "id": { @@ -5037,6 +7567,10 @@ "exists": { "type": "boolean" }, + "signing_id": { + "ignore_above": 1024, + "type": "keyword" + }, "status": { "ignore_above": 1024, "type": "keyword" @@ -5045,6 +7579,10 @@ "ignore_above": 1024, "type": "keyword" }, + "team_id": { + "ignore_above": 1024, + "type": "keyword" + }, "trusted": { "type": "boolean" }, @@ -5097,6 +7635,10 @@ "sha512": { "ignore_above": 1024, "type": "keyword" + }, + "ssdeep": { + "ignore_above": 1024, + "type": "keyword" } } }, @@ -5124,6 +7666,10 @@ "exists": { "type": "boolean" }, + "signing_id": { + "ignore_above": 1024, + "type": "keyword" + }, "status": { "ignore_above": 1024, "type": "keyword" @@ -5132,6 +7678,10 @@ "ignore_above": 1024, "type": "keyword" }, + "team_id": { + "ignore_above": 1024, + "type": "keyword" + }, "trusted": { "type": "boolean" }, @@ -5184,6 +7734,10 @@ "sha512": { "ignore_above": 1024, "type": "keyword" + }, + "ssdeep": { + "ignore_above": 1024, + "type": "keyword" } } }, @@ -5197,6 +7751,38 @@ "ignore_above": 1024, "type": "keyword" }, + "pe": { + "properties": { + "architecture": { + "ignore_above": 1024, + "type": "keyword" + }, + "company": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "file_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "imphash": { + "ignore_above": 1024, + "type": "keyword" + }, + "original_file_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "product": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, "pgid": { "type": "long" }, @@ -5247,6 +7833,10 @@ }, "pe": { "properties": { + "architecture": { + "ignore_above": 1024, + "type": "keyword" + }, "company": { "ignore_above": 1024, "type": "keyword" @@ -5259,6 +7849,10 @@ "ignore_above": 1024, "type": "keyword" }, + "imphash": { + "ignore_above": 1024, + "type": "keyword" + }, "original_file_name": { "ignore_above": 1024, "type": "keyword" @@ -5359,6 +7953,10 @@ "ignore_above": 1024, "type": "keyword" }, + "hosts": { + "ignore_above": 1024, + "type": "keyword" + }, "ip": { "type": "ip" }, @@ -5452,6 +8050,10 @@ "ignore_above": 1024, "type": "keyword" }, + "continent_code": { + "ignore_above": 1024, + "type": "keyword" + }, "continent_name": { "ignore_above": 1024, "type": "keyword" @@ -5471,6 +8073,10 @@ "ignore_above": 1024, "type": "keyword" }, + "postal_code": { + "ignore_above": 1024, + "type": "keyword" + }, "region_iso_code": { "ignore_above": 1024, "type": "keyword" @@ -5478,6 +8084,10 @@ "region_name": { "ignore_above": 1024, "type": "keyword" + }, + "timezone": { + "ignore_above": 1024, + "type": "keyword" } } }, @@ -5508,6 +8118,10 @@ "ignore_above": 1024, "type": "keyword" }, + "subdomain": { + "ignore_above": 1024, + "type": "keyword" + }, "top_level_domain": { "ignore_above": 1024, "type": "keyword" @@ -5565,6 +8179,10 @@ }, "ignore_above": 1024, "type": "keyword" + }, + "roles": { + "ignore_above": 1024, + "type": "keyword" } } } @@ -5693,6 +8311,9 @@ "provider": { "type": "keyword" }, + "reason": { + "type": "keyword" + }, "risk_score": { "type": "float" }, @@ -5762,6 +8383,9 @@ } } }, + "reason": { + "type": "keyword" + }, "rule": { "properties": { "author": { @@ -5923,6 +8547,38 @@ } } }, + "threat_filters": { + "type": "object" + }, + "threat_index": { + "type": "keyword" + }, + "threat_indicator_path": { + "type": "keyword" + }, + "threat_language": { + "type": "keyword" + }, + "threat_mapping": { + "properties": { + "entries": { + "properties": { + "field": { + "type": "keyword" + }, + "type": { + "type": "keyword" + }, + "value": { + "type": "keyword" + } + } + } + } + }, + "threat_query": { + "type": "keyword" + }, "threshold": { "properties": { "field": { @@ -5967,11 +8623,31 @@ }, "threshold_result": { "properties": { + "cardinality": { + "properties": { + "field": { + "type": "keyword" + }, + "value": { + "type": "long" + } + } + }, "count": { "type": "long" }, - "value": { - "type": "keyword" + "from": { + "type": "date" + }, + "terms": { + "properties": { + "field": { + "type": "keyword" + }, + "value": { + "type": "keyword" + } + } } } } @@ -6017,6 +8693,10 @@ "ignore_above": 1024, "type": "keyword" }, + "continent_code": { + "ignore_above": 1024, + "type": "keyword" + }, "continent_name": { "ignore_above": 1024, "type": "keyword" @@ -6036,6 +8716,10 @@ "ignore_above": 1024, "type": "keyword" }, + "postal_code": { + "ignore_above": 1024, + "type": "keyword" + }, "region_iso_code": { "ignore_above": 1024, "type": "keyword" @@ -6043,6 +8727,10 @@ "region_name": { "ignore_above": 1024, "type": "keyword" + }, + "timezone": { + "ignore_above": 1024, + "type": "keyword" } } }, @@ -6069,7 +8757,11 @@ "port": { "type": "long" }, - "registered_domain": { + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "subdomain": { "ignore_above": 1024, "type": "keyword" }, @@ -6130,11 +8822,23 @@ }, "ignore_above": 1024, "type": "keyword" + }, + "roles": { + "ignore_above": 1024, + "type": "keyword" } } } } }, + "span": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, "tags": { "ignore_above": 1024, "type": "keyword" @@ -6145,6 +8849,241 @@ "ignore_above": 1024, "type": "keyword" }, + "indicator": { + "properties": { + "as": { + "properties": { + "number": { + "type": "long" + }, + "organization": { + "properties": { + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "confidence": { + "ignore_above": 1024, + "type": "keyword" + }, + "dataset": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "type": "wildcard" + }, + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "event": { + "properties": { + "action": { + "ignore_above": 1024, + "type": "keyword" + }, + "category": { + "ignore_above": 1024, + "type": "keyword" + }, + "code": { + "ignore_above": 1024, + "type": "keyword" + }, + "created": { + "type": "date" + }, + "dataset": { + "ignore_above": 1024, + "type": "keyword" + }, + "duration": { + "type": "long" + }, + "end": { + "type": "date" + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "ingested": { + "type": "date" + }, + "kind": { + "ignore_above": 1024, + "type": "keyword" + }, + "module": { + "ignore_above": 1024, + "type": "keyword" + }, + "original": { + "doc_values": false, + "ignore_above": 1024, + "index": false, + "type": "keyword" + }, + "outcome": { + "ignore_above": 1024, + "type": "keyword" + }, + "provider": { + "ignore_above": 1024, + "type": "keyword" + }, + "reason": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + }, + "risk_score": { + "type": "float" + }, + "risk_score_norm": { + "type": "float" + }, + "sequence": { + "type": "long" + }, + "severity": { + "type": "long" + }, + "start": { + "type": "date" + }, + "timezone": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "url": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "first_seen": { + "type": "date" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "last_seen": { + "type": "date" + }, + "marking": { + "properties": { + "tlp": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "matched": { + "properties": { + "atomic": { + "ignore_above": 1024, + "type": "keyword" + }, + "field": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "module": { + "ignore_above": 1024, + "type": "keyword" + }, + "port": { + "type": "long" + }, + "provider": { + "ignore_above": 1024, + "type": "keyword" + }, + "scanner_stats": { + "type": "long" + }, + "sightings": { + "type": "long" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + }, + "type": "nested" + }, "tactic": { "properties": { "id": { @@ -6180,6 +9119,28 @@ "reference": { "ignore_above": 1024, "type": "keyword" + }, + "subtechnique": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + } + } } } } @@ -6242,6 +9203,112 @@ "supported_ciphers": { "ignore_above": 1024, "type": "keyword" + }, + "x509": { + "properties": { + "alternative_names": { + "ignore_above": 1024, + "type": "keyword" + }, + "issuer": { + "properties": { + "common_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country": { + "ignore_above": 1024, + "type": "keyword" + }, + "distinguished_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "locality": { + "ignore_above": 1024, + "type": "keyword" + }, + "organization": { + "ignore_above": 1024, + "type": "keyword" + }, + "organizational_unit": { + "ignore_above": 1024, + "type": "keyword" + }, + "state_or_province": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "not_after": { + "type": "date" + }, + "not_before": { + "type": "date" + }, + "public_key_algorithm": { + "ignore_above": 1024, + "type": "keyword" + }, + "public_key_curve": { + "ignore_above": 1024, + "type": "keyword" + }, + "public_key_exponent": { + "doc_values": false, + "index": false, + "type": "long" + }, + "public_key_size": { + "type": "long" + }, + "serial_number": { + "ignore_above": 1024, + "type": "keyword" + }, + "signature_algorithm": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject": { + "properties": { + "common_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country": { + "ignore_above": 1024, + "type": "keyword" + }, + "distinguished_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "locality": { + "ignore_above": 1024, + "type": "keyword" + }, + "organization": { + "ignore_above": 1024, + "type": "keyword" + }, + "organizational_unit": { + "ignore_above": 1024, + "type": "keyword" + }, + "state_or_province": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "version_number": { + "ignore_above": 1024, + "type": "keyword" + } + } } } }, @@ -6302,6 +9369,112 @@ "subject": { "ignore_above": 1024, "type": "keyword" + }, + "x509": { + "properties": { + "alternative_names": { + "ignore_above": 1024, + "type": "keyword" + }, + "issuer": { + "properties": { + "common_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country": { + "ignore_above": 1024, + "type": "keyword" + }, + "distinguished_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "locality": { + "ignore_above": 1024, + "type": "keyword" + }, + "organization": { + "ignore_above": 1024, + "type": "keyword" + }, + "organizational_unit": { + "ignore_above": 1024, + "type": "keyword" + }, + "state_or_province": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "not_after": { + "type": "date" + }, + "not_before": { + "type": "date" + }, + "public_key_algorithm": { + "ignore_above": 1024, + "type": "keyword" + }, + "public_key_curve": { + "ignore_above": 1024, + "type": "keyword" + }, + "public_key_exponent": { + "doc_values": false, + "index": false, + "type": "long" + }, + "public_key_size": { + "type": "long" + }, + "serial_number": { + "ignore_above": 1024, + "type": "keyword" + }, + "signature_algorithm": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject": { + "properties": { + "common_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country": { + "ignore_above": 1024, + "type": "keyword" + }, + "distinguished_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "locality": { + "ignore_above": 1024, + "type": "keyword" + }, + "organization": { + "ignore_above": 1024, + "type": "keyword" + }, + "organizational_unit": { + "ignore_above": 1024, + "type": "keyword" + }, + "state_or_province": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "version_number": { + "ignore_above": 1024, + "type": "keyword" + } + } } } }, @@ -6388,6 +9561,10 @@ "ignore_above": 1024, "type": "keyword" }, + "subdomain": { + "ignore_above": 1024, + "type": "keyword" + }, "top_level_domain": { "ignore_above": 1024, "type": "keyword" @@ -6400,10 +9577,130 @@ }, "user": { "properties": { + "changes": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "roles": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, "domain": { "ignore_above": 1024, "type": "keyword" }, + "effective": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "roles": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, "email": { "ignore_above": 1024, "type": "keyword" @@ -6451,6 +9748,70 @@ }, "ignore_above": 1024, "type": "keyword" + }, + "roles": { + "ignore_above": 1024, + "type": "keyword" + }, + "target": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "roles": { + "ignore_above": 1024, + "type": "keyword" + } + } } } }, @@ -6512,6 +9873,10 @@ "ignore_above": 1024, "type": "keyword" }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, "version": { "ignore_above": 1024, "type": "keyword" From 4df76f046d15aa58859e2193c4d6bad653fbde6a Mon Sep 17 00:00:00 2001 From: Alison Goryachev Date: Fri, 20 Aug 2021 11:56:57 -0400 Subject: [PATCH 30/76] [7.x] [Upgrade Assistant] New ES deprecations page (#107053) (#109443) * [Upgrade Assistant] New ES deprecations page (#107053) # Conflicts: # x-pack/plugins/translations/translations/ja-JP.json # x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/button.tsx # x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/flyout/container.tsx * fix linting --- .../schema/xpack_plugins.json | 10 +- .../translations/translations/ja-JP.json | 62 -- .../translations/translations/zh-CN.json | 30 - .../client_integration/cluster.test.ts | 363 -------- .../default_deprecation_flyout.test.ts | 52 ++ .../es_deprecations/deprecations_list.test.ts | 267 ++++++ .../es_deprecations/error_handling.test.ts | 115 +++ .../index_settings_deprecation_flyout.test.ts | 117 +++ .../ml_snapshots_deprecation_flyout.test.ts | 196 ++++ .../es_deprecations/mocked_responses.ts | 119 +++ .../reindex_deprecation_flyout.test.ts | 50 + .../helpers/cluster.helpers.ts | 67 -- .../helpers/elasticsearch.helpers.ts | 171 ++++ .../helpers/http_requests.ts | 20 +- .../client_integration/helpers/index.ts | 3 +- .../helpers/indices.helpers.ts | 75 -- .../helpers/setup_environment.tsx | 7 +- .../client_integration/indices.test.ts | 245 ----- .../client_integration/kibana.test.ts | 6 +- .../review_logs_step/mocked_responses.ts | 15 +- .../review_logs_step.test.tsx | 2 +- .../plugins/upgrade_assistant/common/types.ts | 31 +- .../public/application/app.tsx | 12 +- .../application/components/constants.tsx | 23 + .../__fixtures__/checkup_api_response.json | 870 ------------------ .../components/es_deprecations/_index.scss | 2 +- .../deprecation_tab_content.tsx | 228 ----- .../_index.scss | 1 - .../deprecation_types/default/flyout.tsx | 96 ++ .../default/index.ts} | 2 +- .../deprecation_types/default/table_row.tsx | 73 ++ .../index.tsx | 5 +- .../index_settings/flyout.tsx | 204 ++++ .../index_settings}/index.ts | 2 +- .../index_settings/resolution_table_cell.tsx | 130 +++ .../index_settings/table_row.tsx | 103 +++ .../ml_snapshots/context.tsx | 65 ++ .../ml_snapshots/flyout.tsx} | 129 +-- .../ml_snapshots}/index.ts | 2 +- .../ml_snapshots/resolution_table_cell.tsx | 140 +++ .../ml_snapshots/table_row.tsx | 92 ++ .../ml_snapshots/use_snapshot_state.tsx | 9 +- .../reindex/_index.scss | 1 - .../deprecation_types/reindex/context.tsx | 61 ++ .../checklist_step.test.tsx.snap | 0 .../__snapshots__/warning_step.test.tsx.snap | 0 .../reindex/flyout/_index.scss | 0 .../reindex/flyout/_step_progress.scss | 0 .../reindex/flyout/checklist_step.test.tsx | 2 +- .../reindex/flyout/checklist_step.tsx | 8 +- .../reindex/flyout/container.tsx | 142 +++ .../reindex/flyout/index.tsx | 8 + .../reindex/flyout/progress.test.tsx | 2 +- .../reindex/flyout/progress.tsx | 2 +- .../reindex/flyout/step_progress.tsx | 0 .../reindex/flyout/warning_step.test.tsx | 0 .../reindex/flyout/warning_step_checkbox.tsx | 0 .../reindex/flyout/warnings_step.tsx | 0 .../reindex/index.tsx | 2 +- .../reindex/resolution_table_cell.tsx | 158 ++++ .../deprecation_types/reindex/table_row.tsx | 104 +++ .../reindex/use_reindex_state.tsx | 187 ++++ .../es_deprecations/deprecations/_cell.scss | 4 - .../es_deprecations/deprecations/cell.tsx | 146 --- .../deprecations/deprecation_group_item.tsx | 75 -- .../deprecations/index_settings/button.tsx | 54 -- .../remove_settings_provider.tsx | 131 --- .../deprecations/index_table.test.tsx | 99 -- .../deprecations/index_table.tsx | 200 ---- .../deprecations/list.test.tsx | 129 --- .../es_deprecations/deprecations/list.tsx | 120 --- .../deprecations/ml_snapshots/button.tsx | 125 --- .../deprecations/reindex/_button.scss | 5 - .../deprecations/reindex/button.tsx | 245 ----- .../deprecations/reindex/flyout/container.tsx | 176 ---- .../reindex/polling_service.test.ts | 87 -- .../deprecations/reindex/polling_service.ts | 169 ---- .../es_deprecations/es_deprecation_errors.tsx | 2 +- .../es_deprecations/es_deprecations.tsx | 240 ++--- .../es_deprecations/es_deprecations_table.tsx | 316 +++++++ .../es_deprecations_table_cells.tsx | 74 ++ .../components/es_deprecations/index.ts | 2 +- .../kibana_deprecations.tsx | 2 +- .../components/overview/overview.tsx | 2 +- .../review_logs_step/es_stats/es_stats.tsx | 29 +- .../es_stats/es_stats_error.tsx | 2 +- .../components/shared/no_deprecations.tsx | 19 +- .../public/application/components/types.ts | 32 +- .../public/application/lib/api.ts | 35 +- .../public/application/lib/breadcrumbs.ts | 2 +- ..._errors.ts => get_es_deprecation_error.ts} | 3 +- .../public/shared_imports.ts | 1 + .../lib/__fixtures__/fake_deprecations.json | 42 +- .../es_deprecations_status.test.ts.snap | 60 +- .../server/lib/es_deprecations_status.test.ts | 5 +- .../server/lib/es_deprecations_status.ts | 100 +- .../lib/telemetry/es_ui_open_apis.test.ts | 12 +- .../server/lib/telemetry/es_ui_open_apis.ts | 14 +- .../lib/telemetry/usage_collector.test.ts | 6 +- .../server/lib/telemetry/usage_collector.ts | 18 +- .../server/routes/es_deprecations.test.ts | 16 +- .../server/routes/es_deprecations.ts | 9 +- .../server/routes/telemetry.test.ts | 12 +- .../server/routes/telemetry.ts | 8 +- .../telemetry_saved_object_type.ts | 6 +- 105 files changed, 3519 insertions(+), 4203 deletions(-) delete mode 100644 x-pack/plugins/upgrade_assistant/__jest__/client_integration/cluster.test.ts create mode 100644 x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecations/default_deprecation_flyout.test.ts create mode 100644 x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecations/deprecations_list.test.ts create mode 100644 x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecations/error_handling.test.ts create mode 100644 x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecations/index_settings_deprecation_flyout.test.ts create mode 100644 x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecations/ml_snapshots_deprecation_flyout.test.ts create mode 100644 x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecations/mocked_responses.ts create mode 100644 x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecations/reindex_deprecation_flyout.test.ts delete mode 100644 x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/cluster.helpers.ts create mode 100644 x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/elasticsearch.helpers.ts delete mode 100644 x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/indices.helpers.ts delete mode 100644 x-pack/plugins/upgrade_assistant/__jest__/client_integration/indices.test.ts delete mode 100644 x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/__fixtures__/checkup_api_response.json delete mode 100644 x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_tab_content.tsx rename x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/{deprecations => deprecation_types}/_index.scss (60%) create mode 100644 x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/default/flyout.tsx rename x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/{deprecations/reindex/flyout/index.tsx => deprecation_types/default/index.ts} (84%) create mode 100644 x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/default/table_row.tsx rename x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/{deprecations => deprecation_types}/index.tsx (55%) create mode 100644 x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/index_settings/flyout.tsx rename x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/{deprecations/ml_snapshots => deprecation_types/index_settings}/index.ts (82%) create mode 100644 x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/index_settings/resolution_table_cell.tsx create mode 100644 x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/index_settings/table_row.tsx create mode 100644 x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/ml_snapshots/context.tsx rename x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/{deprecations/ml_snapshots/fix_snapshots_flyout.tsx => deprecation_types/ml_snapshots/flyout.tsx} (61%) rename x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/{deprecations/index_settings => deprecation_types/ml_snapshots}/index.ts (83%) create mode 100644 x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/ml_snapshots/resolution_table_cell.tsx create mode 100644 x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/ml_snapshots/table_row.tsx rename x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/{deprecations => deprecation_types}/ml_snapshots/use_snapshot_state.tsx (94%) rename x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/{deprecations => deprecation_types}/reindex/_index.scss (57%) create mode 100644 x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/context.tsx rename x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/{deprecations => deprecation_types}/reindex/flyout/__snapshots__/checklist_step.test.tsx.snap (100%) rename x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/{deprecations => deprecation_types}/reindex/flyout/__snapshots__/warning_step.test.tsx.snap (100%) rename x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/{deprecations => deprecation_types}/reindex/flyout/_index.scss (100%) rename x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/{deprecations => deprecation_types}/reindex/flyout/_step_progress.scss (100%) rename x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/{deprecations => deprecation_types}/reindex/flyout/checklist_step.test.tsx (97%) rename x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/{deprecations => deprecation_types}/reindex/flyout/checklist_step.tsx (96%) create mode 100644 x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/flyout/container.tsx create mode 100644 x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/flyout/index.tsx rename x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/{deprecations => deprecation_types}/reindex/flyout/progress.test.tsx (99%) rename x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/{deprecations => deprecation_types}/reindex/flyout/progress.tsx (99%) rename x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/{deprecations => deprecation_types}/reindex/flyout/step_progress.tsx (100%) rename x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/{deprecations => deprecation_types}/reindex/flyout/warning_step.test.tsx (100%) rename x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/{deprecations => deprecation_types}/reindex/flyout/warning_step_checkbox.tsx (100%) rename x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/{deprecations => deprecation_types}/reindex/flyout/warnings_step.tsx (100%) rename x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/{deprecations => deprecation_types}/reindex/index.tsx (84%) create mode 100644 x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/resolution_table_cell.tsx create mode 100644 x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/table_row.tsx create mode 100644 x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/use_reindex_state.tsx delete mode 100644 x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/_cell.scss delete mode 100644 x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/cell.tsx delete mode 100644 x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/deprecation_group_item.tsx delete mode 100644 x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/index_settings/button.tsx delete mode 100644 x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/index_settings/remove_settings_provider.tsx delete mode 100644 x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/index_table.test.tsx delete mode 100644 x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/index_table.tsx delete mode 100644 x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/list.test.tsx delete mode 100644 x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/list.tsx delete mode 100644 x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/ml_snapshots/button.tsx delete mode 100644 x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/_button.scss delete mode 100644 x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/button.tsx delete mode 100644 x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/flyout/container.tsx delete mode 100644 x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/polling_service.test.ts delete mode 100644 x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/polling_service.ts create mode 100644 x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/es_deprecations_table.tsx create mode 100644 x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/es_deprecations_table_cells.tsx rename x-pack/plugins/upgrade_assistant/public/application/lib/{es_deprecation_errors.ts => get_es_deprecation_error.ts} (93%) diff --git a/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json b/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json index bbe0ad8014ae7..3c9dce63f2cb9 100644 --- a/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json +++ b/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json @@ -5921,16 +5921,10 @@ }, "ui_open": { "properties": { - "cluster": { + "elasticsearch": { "type": "long", "_meta": { - "description": "Number of times a user viewed the list of Elasticsearch cluster deprecations." - } - }, - "indices": { - "type": "long", - "_meta": { - "description": "Number of times a user viewed the list of Elasticsearch index deprecations." + "description": "Number of times a user viewed the list of Elasticsearch deprecations." } }, "overview": { diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 47dec9c051154..90c2913f3cd98 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -7265,39 +7265,6 @@ "xpack.canvas.workpadTemplates.table.descriptionColumnTitle": "説明", "xpack.canvas.workpadTemplates.table.nameColumnTitle": "テンプレート名", "xpack.canvas.workpadTemplates.table.tagsColumnTitle": "タグ", - "expressionError.renderer.error.displayName": "エラー情報", - "expressionError.renderer.error.helpDescription": "エラーデータをユーザーにわかるようにレンダリングします", - "expressionError.errorComponent.description": "表現が失敗し次のメッセージが返されました:", - "expressionError.errorComponent.title": "おっと!表現が失敗しました", - "expressionError.renderer.debug.displayName": "デバッグ", - "expressionError.renderer.debug.helpDescription": "デバッグアウトプットをフォーマットされた {JSON} としてレンダリングします", - "expressionImage.renderer.image.displayName": "画像", - "expressionImage.renderer.image.helpDescription": "画像をレンダリングします", - "expressionImage.functions.image.args.dataurlHelpText": "画像の {https} {URL} または {BASE64} データ {URL} です。", - "expressionImage.functions.image.args.modeHelpText": "{contain} はサイズに合わせて拡大・縮小して画像全体を表示し、{cover} はコンテナーを画像で埋め、必要に応じて両端や下をクロップします。{stretch} は画像の高さと幅をコンテナーの 100% になるよう変更します。", - "expressionImage.functions.image.invalidImageModeErrorMessage": "「mode」は「{contain}」、「{cover}」、または「{stretch}」でなければなりません", - "expressionImage.functions.imageHelpText": "画像を表示します。画像アセットは{BASE64}データ{URL}として提供するか、部分式で渡します。", - "expressionShape.functions.progress.args.barColorHelpText": "背景バーの色です。", - "expressionShape.functions.progress.args.barWeightHelpText": "背景バーの太さです。", - "expressionShape.functions.progress.args.fontHelpText": "ラベルの {CSS} フォントプロパティです。例:{FONT_FAMILY} または {FONT_WEIGHT}。", - "expressionShape.functions.progress.args.labelHelpText": "ラベルの表示・非表示を切り替えるには、{BOOLEAN_TRUE}または{BOOLEAN_FALSE}を使用します。また、ラベルとして表示する文字列を入力することもできます。", - "expressionShape.functions.progress.args.maxHelpText": "進捗エレメントの最高値です。", - "expressionShape.functions.progress.args.shapeHelpText": "{list} または {end} を選択します。", - "expressionShape.functions.progress.args.valueColorHelpText": "進捗バーの色です。", - "expressionShape.functions.progress.args.valueWeightHelpText": "進捗バーの太さです。", - "expressionShape.functions.progress.invalidMaxValueErrorMessage": "無効な {arg} 値:「{max, number}」。「{arg}」は 0 より大きい必要があります", - "expressionShape.functions.progress.invalidValueErrorMessage": "無効な値:「{value, number}」。値は 0 と {max, number} の間でなければなりません", - "expressionShape.functions.progressHelpText": "進捗エレメントを構成します。", - "expressionShape.renderer.progress.displayName": "進捗インジケーター", - "expressionShape.renderer.progress.helpDescription": "エレメントのパーセンテージを示す進捗インジケーターをレンダリングします", - "expressionShape.renderer.shape.displayName": "形状", - "expressionShape.renderer.shape.helpDescription": "基本的な図形をレンダリングします", - "expressionShape.functions.shape.args.borderHelpText": "図形の外郭の {SVG} カラーです。", - "expressionShape.functions.shape.args.borderWidthHelpText": "境界の太さです。", - "expressionShape.functions.shape.args.fillHelpText": "図形を塗りつぶす {SVG} カラーです。", - "expressionShape.functions.shape.args.maintainAspectHelpText": "図形の元の横縦比を維持しますか?", - "expressionShape.functions.shape.args.shapeHelpText": "図形を選択します。", - "expressionShape.functions.shapeHelpText": "図形を作成します。", "expressionRepeatImage.error.repeatImage.missingMaxArgument": "{emptyImageArgument} を指定する場合は、{maxArgument} を設定する必要があります", "expressionRepeatImage.functions.repeatImage.args.emptyImageHelpText": "この画像のエレメントについて、{CONTEXT}および{maxArg}パラメーターの差異を解消します。画像アセットは{BASE64}データ{URL}として提供するか、部分式で渡します。", "expressionRepeatImage.functions.repeatImage.args.imageHelpText": "繰り返す画像です。画像アセットは{BASE64}データ{URL}として提供するか、部分式で渡します。", @@ -24916,24 +24883,13 @@ "xpack.upgradeAssistant.breadcrumb.kibanaDeprecationsLabel": "Kibanaの廃止予定", "xpack.upgradeAssistant.breadcrumb.overviewLabel": "アップグレードアシスタント", "xpack.upgradeAssistant.checkupTab.changeFiltersShowMoreLabel": "より多く表示させるにはフィルターを変更します。", - "xpack.upgradeAssistant.checkupTab.confirmationModal.removeButtonLabel": "削除", "xpack.upgradeAssistant.checkupTab.controls.filterBar.criticalButtonLabel": "重大", "xpack.upgradeAssistant.checkupTab.controls.groupByBar.byIndexLabel": "インデックス別", "xpack.upgradeAssistant.checkupTab.controls.groupByBar.byIssueLabel": "問題別", "xpack.upgradeAssistant.checkupTab.deprecations.criticalActionTooltip": "アップグレード前にこの問題を解決してください。", "xpack.upgradeAssistant.checkupTab.deprecations.criticalLabel": "重大", - "xpack.upgradeAssistant.checkupTab.deprecations.documentationButtonLabel": "ドキュメント", - "xpack.upgradeAssistant.checkupTab.deprecations.indexTable.detailsColumnLabel": "詳細", - "xpack.upgradeAssistant.checkupTab.deprecations.indexTable.indexColumnLabel": "インデックス", "xpack.upgradeAssistant.checkupTab.deprecations.warningActionTooltip": "アップグレード前にこの問題を解決することをお勧めしますが、必須ではありません。", "xpack.upgradeAssistant.checkupTab.deprecations.warningLabel": "警告", - "xpack.upgradeAssistant.checkupTab.indexSettings.confirmationModal.cancelButtonLabel": "キャンセル", - "xpack.upgradeAssistant.checkupTab.indexSettings.confirmationModal.description": "次の廃止予定のインデックス設定が検出されました。これらは削除される予定です。", - "xpack.upgradeAssistant.checkupTab.indexSettings.confirmationModal.errorNotificationText": "インデックス設定の削除エラー", - "xpack.upgradeAssistant.checkupTab.indexSettings.confirmationModal.successNotificationText": "インデックス設定が削除されました", - "xpack.upgradeAssistant.checkupTab.indexSettings.confirmationModal.title": "廃止予定の設定を'{indexName}'から削除しますか?", - "xpack.upgradeAssistant.checkupTab.indexSettings.doneButtonLabel": "完了", - "xpack.upgradeAssistant.checkupTab.indexSettings.fixButtonLabel": "修正", "xpack.upgradeAssistant.checkupTab.noDeprecationsLabel": "説明がありません", "xpack.upgradeAssistant.checkupTab.numDeprecationsShownLabel": "{total} 件中 {numShown} 件を表示中", "xpack.upgradeAssistant.checkupTab.reindexing.flyout.checklistStep.cancelButtonLabel": "キャンセル", @@ -24961,7 +24917,6 @@ "xpack.upgradeAssistant.checkupTab.reindexing.flyout.checklistStep.reindexingChecklist.resumeWatcherStepTitle": "Watcher を再開中", "xpack.upgradeAssistant.checkupTab.reindexing.flyout.checklistStep.reindexingChecklist.stopWatcherStepTitle": "Watcher を停止中", "xpack.upgradeAssistant.checkupTab.reindexing.flyout.checklistStep.reindexingChecklistTitle": "プロセスを再インデックス中", - "xpack.upgradeAssistant.checkupTab.reindexing.flyout.flyoutHeader": "{indexName} を再インデックス", "xpack.upgradeAssistant.checkupTab.reindexing.flyout.indexClosedCallout.calloutDetails": "このインデックスは現在閉じています。アップグレードアシスタントが開き、再インデックスを実行してからインデックスを閉じます。 {reindexingMayTakeLongerEmph}。詳細については {docs} をご覧ください。", "xpack.upgradeAssistant.checkupTab.reindexing.flyout.indexClosedCallout.calloutDetails.reindexingTakesLongerEmphasis": "再インデックスには通常よりも時間がかかることがあります", "xpack.upgradeAssistant.checkupTab.reindexing.flyout.indexClosedCallout.calloutTitle": "インデックスが閉じました", @@ -24973,13 +24928,6 @@ "xpack.upgradeAssistant.checkupTab.reindexing.flyout.warningsStep.destructiveCallout.calloutDetail": "続行する前に、インデックスをバックアップしてください。再インデックスを続行するには、各変更を承諾してください。", "xpack.upgradeAssistant.checkupTab.reindexing.flyout.warningsStep.destructiveCallout.calloutTitle": "このインデックスには元に戻すことのできない破壊的な変更が含まれています", "xpack.upgradeAssistant.checkupTab.reindexing.flyout.warningsStep.documentationLinkLabel": "ドキュメント", - "xpack.upgradeAssistant.checkupTab.reindexing.reindexButton.cancelledLabel": "キャンセル済み", - "xpack.upgradeAssistant.checkupTab.reindexing.reindexButton.doneLabel": "完了", - "xpack.upgradeAssistant.checkupTab.reindexing.reindexButton.failedLabel": "失敗", - "xpack.upgradeAssistant.checkupTab.reindexing.reindexButton.indexClosedToolTipDetails": "「{indexName}」は再インデックスが必要ですが現在閉じています。アップグレードアシスタントが開き、再インデックスを実行してからインデックスを閉じます。再インデックスには通常よりも時間がかかることがあります。", - "xpack.upgradeAssistant.checkupTab.reindexing.reindexButton.loadingLabel": "読み込み中…", - "xpack.upgradeAssistant.checkupTab.reindexing.reindexButton.pausedLabel": "一時停止中", - "xpack.upgradeAssistant.checkupTab.reindexing.reindexButton.reindexLabel": "再インデックス", "xpack.upgradeAssistant.deprecationGroupItem.docLinkText": "ドキュメンテーションを表示", "xpack.upgradeAssistant.deprecationGroupItem.fixButtonLabel": "修正する手順を表示", "xpack.upgradeAssistant.deprecationGroupItem.resolveButtonLabel": "クイック解決", @@ -24997,13 +24945,6 @@ "xpack.upgradeAssistant.esDeprecationErrors.partiallyUpgradedWarningMessage": "Kibanaをご使用のElasticsearchクラスターと同じバージョンにアップグレードしてください。クラスターの1つ以上のノードがKibanaとは異なるバージョンを実行しています。", "xpack.upgradeAssistant.esDeprecationErrors.permissionsErrorMessage": "Elasticsearchの廃止予定を表示する権限がありません。", "xpack.upgradeAssistant.esDeprecationErrors.upgradedWarningMessage": "構成は最新です。KibanaおよびすべてのElasticsearchノードは同じバージョンを実行しています。", - "xpack.upgradeAssistant.esDeprecations.backupDataButtonLabel": "データをバックアップ", - "xpack.upgradeAssistant.esDeprecations.backupDataTooltipText": "変更を行う前にスナップショットを作成します。", - "xpack.upgradeAssistant.esDeprecations.clusterLabel": "クラスター", - "xpack.upgradeAssistant.esDeprecations.clusterTabLabel": "クラスター", - "xpack.upgradeAssistant.esDeprecations.docLinkText": "ドキュメント", - "xpack.upgradeAssistant.esDeprecations.indexLabel": "インデックス", - "xpack.upgradeAssistant.esDeprecations.indicesTabLabel": "インデックス", "xpack.upgradeAssistant.esDeprecations.loadingText": "廃止予定を読み込んでいます...", "xpack.upgradeAssistant.esDeprecations.pageDescription": "廃止予定のクラスターとインデックス設定をレビューします。アップグレード前に重要な問題を解決する必要があります。", "xpack.upgradeAssistant.esDeprecations.pageTitle": "Elasticsearch", @@ -25011,7 +24952,6 @@ "xpack.upgradeAssistant.esDeprecationStats.criticalDeprecationsTitle": "重大", "xpack.upgradeAssistant.esDeprecationStats.loadingText": "Elasticsearchの廃止統計情報を読み込んでいます...", "xpack.upgradeAssistant.esDeprecationStats.statsTitle": "Elasticsearch", - "xpack.upgradeAssistant.esDeprecationStats.totalDeprecationsTooltip": "このクラスターは{clusterCount}個の廃止予定のクラスター設定と{indexCount}個の廃止予定のインデックス設定を使用しています。", "xpack.upgradeAssistant.kibanaDeprecationErrors.loadingErrorDescription": "エラーについては、Kibanaサーバーログを確認してください。", "xpack.upgradeAssistant.kibanaDeprecationErrors.loadingErrorTitle": "Kibana廃止予定を取得できませんでした", "xpack.upgradeAssistant.kibanaDeprecationErrors.pluginErrorDescription": "エラーについては、Kibanaサーバーログを確認してください。", @@ -25035,10 +24975,8 @@ "xpack.upgradeAssistant.kibanaDeprecationStats.loadingErrorMessage": "Kibana廃止予定の取得中にエラーが発生しました。", "xpack.upgradeAssistant.kibanaDeprecationStats.loadingText": "Kibana廃止予定統計情報を読み込んでいます…", "xpack.upgradeAssistant.kibanaDeprecationStats.statsTitle": "Kibana", - "xpack.upgradeAssistant.noDeprecationsPrompt.description": "構成は最新です。", "xpack.upgradeAssistant.noDeprecationsPrompt.nextStepsDescription": "他のスタック廃止予定については、{overviewButton}を確認してください。", "xpack.upgradeAssistant.noDeprecationsPrompt.overviewLinkText": "概要ページ", - "xpack.upgradeAssistant.noDeprecationsPrompt.title": "アップグレードする準備ができました。", "xpack.upgradeAssistant.overview.deprecationLogs.disabledToastMessage": "廃止予定のアクションをログに出力しません。", "xpack.upgradeAssistant.overview.deprecationLogs.enabledToastMessage": "廃止予定のアクションをログに出力します。", "xpack.upgradeAssistant.overview.deprecationLogs.fetchErrorMessage": "ログ情報を取得できませんでした。", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 39b3cdfc7b3db..fae942e60c39b 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -25294,25 +25294,13 @@ "xpack.upgradeAssistant.breadcrumb.kibanaDeprecationsLabel": "Kibana 弃用", "xpack.upgradeAssistant.breadcrumb.overviewLabel": "升级助手", "xpack.upgradeAssistant.checkupTab.changeFiltersShowMoreLabel": "更改筛选以显示更多内容。", - "xpack.upgradeAssistant.checkupTab.confirmationModal.removeButtonLabel": "移除", "xpack.upgradeAssistant.checkupTab.controls.filterBar.criticalButtonLabel": "紧急", "xpack.upgradeAssistant.checkupTab.controls.groupByBar.byIndexLabel": "按索引", "xpack.upgradeAssistant.checkupTab.controls.groupByBar.byIssueLabel": "按问题", "xpack.upgradeAssistant.checkupTab.deprecations.criticalActionTooltip": "请解决此问题后再升级。", "xpack.upgradeAssistant.checkupTab.deprecations.criticalLabel": "紧急", - "xpack.upgradeAssistant.checkupTab.deprecations.documentationButtonLabel": "文档", - "xpack.upgradeAssistant.checkupTab.deprecations.indexTable.detailsColumnLabel": "详情", - "xpack.upgradeAssistant.checkupTab.deprecations.indexTable.indexColumnLabel": "索引", "xpack.upgradeAssistant.checkupTab.deprecations.warningActionTooltip": "建议在升级之前先解决此问题,但这不是必需的。", "xpack.upgradeAssistant.checkupTab.deprecations.warningLabel": "警告", - "xpack.upgradeAssistant.checkupTab.indexSettings.confirmationModal.cancelButtonLabel": "取消", - "xpack.upgradeAssistant.checkupTab.indexSettings.confirmationModal.description": "检测到并将移除以下弃用的索引设置:", - "xpack.upgradeAssistant.checkupTab.indexSettings.confirmationModal.errorNotificationText": "移除索引设置时出错", - "xpack.upgradeAssistant.checkupTab.indexSettings.confirmationModal.successNotificationText": "索引设置已移除", - "xpack.upgradeAssistant.checkupTab.indexSettings.confirmationModal.title": "从“{indexName}”移除已弃用的设置?", - "xpack.upgradeAssistant.checkupTab.indexSettings.doneButtonLabel": "完成", - "xpack.upgradeAssistant.checkupTab.indexSettings.fixButtonLabel": "修复", - "xpack.upgradeAssistant.checkupTab.indicesBadgeLabel": "{numIndices, plural, other { 个索引}}", "xpack.upgradeAssistant.checkupTab.noDeprecationsLabel": "无弃用内容", "xpack.upgradeAssistant.checkupTab.numDeprecationsShownLabel": "显示 {numShown} 个,共 {total} 个", "xpack.upgradeAssistant.checkupTab.reindexing.flyout.checklistStep.cancelButtonLabel": "取消", @@ -25340,7 +25328,6 @@ "xpack.upgradeAssistant.checkupTab.reindexing.flyout.checklistStep.reindexingChecklist.resumeWatcherStepTitle": "正在恢复 Watcher", "xpack.upgradeAssistant.checkupTab.reindexing.flyout.checklistStep.reindexingChecklist.stopWatcherStepTitle": "正在停止 Watcher", "xpack.upgradeAssistant.checkupTab.reindexing.flyout.checklistStep.reindexingChecklistTitle": "重新索引过程", - "xpack.upgradeAssistant.checkupTab.reindexing.flyout.flyoutHeader": "重新索引 {indexName}", "xpack.upgradeAssistant.checkupTab.reindexing.flyout.indexClosedCallout.calloutDetails": "此索引当前已关闭。升级助手将打开索引,重新索引,然后关闭索引。{reindexingMayTakeLongerEmph}。请参阅文档{docs}以了解更多信息。", "xpack.upgradeAssistant.checkupTab.reindexing.flyout.indexClosedCallout.calloutDetails.reindexingTakesLongerEmphasis": "重新索引可能比通常花费更多的时间", "xpack.upgradeAssistant.checkupTab.reindexing.flyout.indexClosedCallout.calloutTitle": "索引已关闭", @@ -25352,13 +25339,6 @@ "xpack.upgradeAssistant.checkupTab.reindexing.flyout.warningsStep.destructiveCallout.calloutDetail": "继续前备份索引。要继续重新索引,请接受每个更改。", "xpack.upgradeAssistant.checkupTab.reindexing.flyout.warningsStep.destructiveCallout.calloutTitle": "此索引需要无法恢复的破坏性更改", "xpack.upgradeAssistant.checkupTab.reindexing.flyout.warningsStep.documentationLinkLabel": "文档", - "xpack.upgradeAssistant.checkupTab.reindexing.reindexButton.cancelledLabel": "已取消", - "xpack.upgradeAssistant.checkupTab.reindexing.reindexButton.doneLabel": "完成", - "xpack.upgradeAssistant.checkupTab.reindexing.reindexButton.failedLabel": "失败", - "xpack.upgradeAssistant.checkupTab.reindexing.reindexButton.indexClosedToolTipDetails": "“{indexName}”需要重新索引,但当前已关闭。升级助手将打开索引,重新索引,然后关闭索引。重新索引可能比通常花费更多的时间。", - "xpack.upgradeAssistant.checkupTab.reindexing.reindexButton.loadingLabel": "正在加载……", - "xpack.upgradeAssistant.checkupTab.reindexing.reindexButton.pausedLabel": "已暂停", - "xpack.upgradeAssistant.checkupTab.reindexing.reindexButton.reindexLabel": "重新索引", "xpack.upgradeAssistant.deprecationGroupItem.docLinkText": "查看文档", "xpack.upgradeAssistant.deprecationGroupItem.fixButtonLabel": "显示修复步骤", "xpack.upgradeAssistant.deprecationGroupItem.resolveButtonLabel": "快速解决", @@ -25376,13 +25356,6 @@ "xpack.upgradeAssistant.esDeprecationErrors.partiallyUpgradedWarningMessage": "将 Kibana 升级到与您的 Elasticsearch 集群相同的版本。集群中的一个或多个节点正在运行与 Kibana 不同的版本。", "xpack.upgradeAssistant.esDeprecationErrors.permissionsErrorMessage": "您无权查看 Elasticsearch 弃用。", "xpack.upgradeAssistant.esDeprecationErrors.upgradedWarningMessage": "您的配置是最新的。Kibana 和索引 Elasticsearch 节点正在运行相同的版本。", - "xpack.upgradeAssistant.esDeprecations.backupDataButtonLabel": "备份您的数据", - "xpack.upgradeAssistant.esDeprecations.backupDataTooltipText": "在进行任何更改之前拍取快照。", - "xpack.upgradeAssistant.esDeprecations.clusterLabel": "集群", - "xpack.upgradeAssistant.esDeprecations.clusterTabLabel": "集群", - "xpack.upgradeAssistant.esDeprecations.docLinkText": "文档", - "xpack.upgradeAssistant.esDeprecations.indexLabel": "索引", - "xpack.upgradeAssistant.esDeprecations.indicesTabLabel": "索引", "xpack.upgradeAssistant.esDeprecations.loadingText": "正在加载弃用……", "xpack.upgradeAssistant.esDeprecations.pageDescription": "查看已弃用的群集和索引设置。在升级之前必须解决任何紧急问题。", "xpack.upgradeAssistant.esDeprecations.pageTitle": "Elasticsearch", @@ -25390,7 +25363,6 @@ "xpack.upgradeAssistant.esDeprecationStats.criticalDeprecationsTitle": "紧急", "xpack.upgradeAssistant.esDeprecationStats.loadingText": "正在加载 Elasticsearch 弃用统计……", "xpack.upgradeAssistant.esDeprecationStats.statsTitle": "Elasticsearch", - "xpack.upgradeAssistant.esDeprecationStats.totalDeprecationsTooltip": "此集群正在使用 {clusterCount} 个已弃用集群设置和 {indexCount} 个已弃用的索引设置", "xpack.upgradeAssistant.kibanaDeprecationErrors.loadingErrorDescription": "请在 Kibana 服务器日志中查看错误。", "xpack.upgradeAssistant.kibanaDeprecationErrors.loadingErrorTitle": "无法检索 Kibana 弃用", "xpack.upgradeAssistant.kibanaDeprecationErrors.pluginErrorDescription": "请在 Kibana 服务器日志中查看错误。", @@ -25414,10 +25386,8 @@ "xpack.upgradeAssistant.kibanaDeprecationStats.loadingErrorMessage": "检索 Kibana 弃用时发生错误。", "xpack.upgradeAssistant.kibanaDeprecationStats.loadingText": "正在加载 Kibana 弃用统计……", "xpack.upgradeAssistant.kibanaDeprecationStats.statsTitle": "Kibana", - "xpack.upgradeAssistant.noDeprecationsPrompt.description": "您的配置是最新的。", "xpack.upgradeAssistant.noDeprecationsPrompt.nextStepsDescription": "查看{overviewButton}以了解其他 Stack 弃用。", "xpack.upgradeAssistant.noDeprecationsPrompt.overviewLinkText": "“概览”页面", - "xpack.upgradeAssistant.noDeprecationsPrompt.title": "准备好升级!", "xpack.upgradeAssistant.overview.deprecationLogs.disabledToastMessage": "不记录弃用的操作。", "xpack.upgradeAssistant.overview.deprecationLogs.enabledToastMessage": "记录弃用的操作。", "xpack.upgradeAssistant.overview.deprecationLogs.fetchErrorMessage": "无法检索日志记录信息。", diff --git a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/cluster.test.ts b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/cluster.test.ts deleted file mode 100644 index 533a74842216a..0000000000000 --- a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/cluster.test.ts +++ /dev/null @@ -1,363 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { act } from 'react-dom/test-utils'; -import { MlAction, ESUpgradeStatus } from '../../common/types'; - -import { ClusterTestBed, setupClusterPage, setupEnvironment } from './helpers'; - -describe('Cluster tab', () => { - let testBed: ClusterTestBed; - const { server, httpRequestsMockHelpers } = setupEnvironment(); - - afterAll(() => { - server.restore(); - }); - - describe('with deprecations', () => { - const snapshotId = '1'; - const jobId = 'deprecation_check_job'; - const esDeprecationsMockResponse: ESUpgradeStatus = { - totalCriticalDeprecations: 1, - cluster: [ - { - level: 'critical', - message: - 'model snapshot [1] for job [deprecation_check_job] needs to be deleted or upgraded', - details: - 'model snapshot [%s] for job [%s] supports minimum version [%s] and needs to be at least [%s]', - url: 'doc_url', - correctiveAction: { - type: 'mlSnapshot', - snapshotId, - jobId, - }, - }, - ], - indices: [], - }; - - beforeEach(async () => { - httpRequestsMockHelpers.setLoadEsDeprecationsResponse(esDeprecationsMockResponse); - httpRequestsMockHelpers.setLoadDeprecationLoggingResponse({ - isDeprecationLogIndexingEnabled: true, - isDeprecationLoggingEnabled: true, - }); - - await act(async () => { - testBed = await setupClusterPage({ isReadOnlyMode: false }); - }); - - const { actions, component } = testBed; - - component.update(); - - // Navigate to the cluster tab - await act(async () => { - actions.clickTab('cluster'); - }); - - component.update(); - }); - - test('renders deprecations', () => { - const { exists } = testBed; - expect(exists('clusterTabContent')).toBe(true); - expect(exists('deprecationsContainer')).toBe(true); - }); - - describe('fix ml snapshots button', () => { - let flyout: Element | null; - - beforeEach(async () => { - const { component, actions, exists, find } = testBed; - - expect(exists('deprecationsContainer')).toBe(true); - - // Open all deprecations - actions.clickExpandAll(); - - // The data-test-subj is derived from the deprecation message - const accordionTestSubj = `depgroup_${esDeprecationsMockResponse.cluster[0].message - .split(' ') - .join('_')}`; - - await act(async () => { - find(`${accordionTestSubj}.fixMlSnapshotsButton`).simulate('click'); - }); - - component.update(); - - // We need to read the document "body" as the flyout is added there and not inside - // the component DOM tree. - flyout = document.body.querySelector('[data-test-subj="fixSnapshotsFlyout"]'); - - expect(flyout).not.toBe(null); - expect(flyout!.textContent).toContain('Upgrade or delete model snapshot'); - }); - - test('upgrades snapshots', async () => { - const { component } = testBed; - - const upgradeButton: HTMLButtonElement | null = flyout!.querySelector( - '[data-test-subj="upgradeSnapshotButton"]' - ); - - httpRequestsMockHelpers.setUpgradeMlSnapshotResponse({ - nodeId: 'my_node', - snapshotId, - jobId, - status: 'in_progress', - }); - - await act(async () => { - upgradeButton!.click(); - }); - - component.update(); - - // First, we expect a POST request to upgrade the snapshot - const upgradeRequest = server.requests[server.requests.length - 2]; - expect(upgradeRequest.method).toBe('POST'); - expect(upgradeRequest.url).toBe('/api/upgrade_assistant/ml_snapshots'); - - // Next, we expect a GET request to check the status of the upgrade - const statusRequest = server.requests[server.requests.length - 1]; - expect(statusRequest.method).toBe('GET'); - expect(statusRequest.url).toBe( - `/api/upgrade_assistant/ml_snapshots/${jobId}/${snapshotId}` - ); - }); - - test('handles upgrade failure', async () => { - const { component, find } = testBed; - - const upgradeButton: HTMLButtonElement | null = flyout!.querySelector( - '[data-test-subj="upgradeSnapshotButton"]' - ); - - const error = { - statusCode: 500, - error: 'Upgrade snapshot error', - message: 'Upgrade snapshot error', - }; - - httpRequestsMockHelpers.setUpgradeMlSnapshotResponse(undefined, error); - - await act(async () => { - upgradeButton!.click(); - }); - - component.update(); - - const upgradeRequest = server.requests[server.requests.length - 1]; - expect(upgradeRequest.method).toBe('POST'); - expect(upgradeRequest.url).toBe('/api/upgrade_assistant/ml_snapshots'); - - const accordionTestSubj = `depgroup_${esDeprecationsMockResponse.cluster[0].message - .split(' ') - .join('_')}`; - - expect(find(`${accordionTestSubj}.fixMlSnapshotsButton`).text()).toEqual('Failed'); - }); - - test('deletes snapshots', async () => { - const { component } = testBed; - - const deleteButton: HTMLButtonElement | null = flyout!.querySelector( - '[data-test-subj="deleteSnapshotButton"]' - ); - - httpRequestsMockHelpers.setDeleteMlSnapshotResponse({ - acknowledged: true, - }); - - await act(async () => { - deleteButton!.click(); - }); - - component.update(); - - const request = server.requests[server.requests.length - 1]; - const mlDeprecation = esDeprecationsMockResponse.cluster[0]; - - expect(request.method).toBe('DELETE'); - expect(request.url).toBe( - `/api/upgrade_assistant/ml_snapshots/${ - (mlDeprecation.correctiveAction! as MlAction).jobId - }/${(mlDeprecation.correctiveAction! as MlAction).snapshotId}` - ); - }); - - test('handles delete failure', async () => { - const { component, find } = testBed; - - const deleteButton: HTMLButtonElement | null = flyout!.querySelector( - '[data-test-subj="deleteSnapshotButton"]' - ); - - const error = { - statusCode: 500, - error: 'Upgrade snapshot error', - message: 'Upgrade snapshot error', - }; - - httpRequestsMockHelpers.setDeleteMlSnapshotResponse(undefined, error); - - await act(async () => { - deleteButton!.click(); - }); - - component.update(); - - const request = server.requests[server.requests.length - 1]; - const mlDeprecation = esDeprecationsMockResponse.cluster[0]; - - expect(request.method).toBe('DELETE'); - expect(request.url).toBe( - `/api/upgrade_assistant/ml_snapshots/${ - (mlDeprecation.correctiveAction! as MlAction).jobId - }/${(mlDeprecation.correctiveAction! as MlAction).snapshotId}` - ); - - const accordionTestSubj = `depgroup_${esDeprecationsMockResponse.cluster[0].message - .split(' ') - .join('_')}`; - - expect(find(`${accordionTestSubj}.fixMlSnapshotsButton`).text()).toEqual('Failed'); - }); - }); - }); - - describe('no deprecations', () => { - beforeEach(async () => { - const noDeprecationsResponse = { - totalCriticalDeprecations: 0, - cluster: [], - indices: [], - }; - - httpRequestsMockHelpers.setLoadEsDeprecationsResponse(noDeprecationsResponse); - - await act(async () => { - testBed = await setupClusterPage({ isReadOnlyMode: false }); - }); - - const { component } = testBed; - - component.update(); - }); - - test('renders prompt', () => { - const { exists, find } = testBed; - expect(exists('noDeprecationsPrompt')).toBe(true); - expect(find('noDeprecationsPrompt').text()).toContain('Ready to upgrade!'); - }); - }); - - describe('error handling', () => { - test('handles 403', async () => { - const error = { - statusCode: 403, - error: 'Forbidden', - message: 'Forbidden', - }; - - httpRequestsMockHelpers.setLoadEsDeprecationsResponse(undefined, error); - - await act(async () => { - testBed = await setupClusterPage({ isReadOnlyMode: false }); - }); - - const { component, exists, find } = testBed; - - component.update(); - - expect(exists('permissionsError')).toBe(true); - expect(find('permissionsError').text()).toContain( - 'You are not authorized to view Elasticsearch deprecations.' - ); - }); - - test('shows upgraded message when all nodes have been upgraded', async () => { - const error = { - statusCode: 426, - error: 'Upgrade required', - message: 'There are some nodes running a different version of Elasticsearch', - attributes: { - // This is marked true in the scenario where none of the nodes have the same major version of Kibana, - // and therefore we assume all have been upgraded - allNodesUpgraded: true, - }, - }; - - httpRequestsMockHelpers.setLoadEsDeprecationsResponse(undefined, error); - - await act(async () => { - testBed = await setupClusterPage({ isReadOnlyMode: false }); - }); - - const { component, exists, find } = testBed; - - component.update(); - - expect(exists('upgradedCallout')).toBe(true); - expect(find('upgradedCallout').text()).toContain( - 'Your configuration is up to date. Kibana and all Elasticsearch nodes are running the same version.' - ); - }); - - test('shows partially upgrade error when nodes are running different versions', async () => { - const error = { - statusCode: 426, - error: 'Upgrade required', - message: 'There are some nodes running a different version of Elasticsearch', - attributes: { - allNodesUpgraded: false, - }, - }; - - httpRequestsMockHelpers.setLoadEsDeprecationsResponse(undefined, error); - - await act(async () => { - testBed = await setupClusterPage({ isReadOnlyMode: false }); - }); - - const { component, exists, find } = testBed; - - component.update(); - - expect(exists('partiallyUpgradedWarning')).toBe(true); - expect(find('partiallyUpgradedWarning').text()).toContain( - 'Upgrade Kibana to the same version as your Elasticsearch cluster. One or more nodes in the cluster is running a different version than Kibana.' - ); - }); - - test('handles generic error', async () => { - const error = { - statusCode: 500, - error: 'Internal server error', - message: 'Internal server error', - }; - - httpRequestsMockHelpers.setLoadEsDeprecationsResponse(undefined, error); - - await act(async () => { - testBed = await setupClusterPage({ isReadOnlyMode: false }); - }); - - const { component, exists, find } = testBed; - - component.update(); - - expect(exists('requestError')).toBe(true); - expect(find('requestError').text()).toContain( - 'Could not retrieve Elasticsearch deprecations.' - ); - }); - }); -}); diff --git a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecations/default_deprecation_flyout.test.ts b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecations/default_deprecation_flyout.test.ts new file mode 100644 index 0000000000000..917fac8ef666a --- /dev/null +++ b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecations/default_deprecation_flyout.test.ts @@ -0,0 +1,52 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { act } from 'react-dom/test-utils'; + +import { ElasticsearchTestBed, setupElasticsearchPage, setupEnvironment } from '../helpers'; + +import { esDeprecationsMockResponse, MOCK_SNAPSHOT_ID, MOCK_JOB_ID } from './mocked_responses'; + +describe('Default deprecation flyout', () => { + let testBed: ElasticsearchTestBed; + const { server, httpRequestsMockHelpers } = setupEnvironment(); + + afterAll(() => { + server.restore(); + }); + + beforeEach(async () => { + httpRequestsMockHelpers.setLoadEsDeprecationsResponse(esDeprecationsMockResponse); + httpRequestsMockHelpers.setUpgradeMlSnapshotStatusResponse({ + nodeId: 'my_node', + snapshotId: MOCK_SNAPSHOT_ID, + jobId: MOCK_JOB_ID, + status: 'idle', + }); + + await act(async () => { + testBed = await setupElasticsearchPage({ isReadOnlyMode: false }); + }); + + testBed.component.update(); + }); + + it('renders a flyout with deprecation details', async () => { + const multiFieldsDeprecation = esDeprecationsMockResponse.deprecations[2]; + const { actions, find, exists } = testBed; + + await actions.clickDefaultDeprecationAt(0); + + expect(exists('defaultDeprecationDetails')).toBe(true); + expect(find('defaultDeprecationDetails.flyoutTitle').text()).toContain( + multiFieldsDeprecation.message + ); + expect(find('defaultDeprecationDetails.flyoutDescription').text()).toContain( + multiFieldsDeprecation.index + ); + }); +}); diff --git a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecations/deprecations_list.test.ts b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecations/deprecations_list.test.ts new file mode 100644 index 0000000000000..ceebc528f0bc4 --- /dev/null +++ b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecations/deprecations_list.test.ts @@ -0,0 +1,267 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { act } from 'react-dom/test-utils'; + +import { API_BASE_PATH } from '../../../common/constants'; +import type { MlAction } from '../../../common/types'; +import { ElasticsearchTestBed, setupElasticsearchPage, setupEnvironment } from '../helpers'; +import { + esDeprecationsMockResponse, + MOCK_SNAPSHOT_ID, + MOCK_JOB_ID, + createEsDeprecationsMockResponse, +} from './mocked_responses'; + +describe('Deprecations table', () => { + let testBed: ElasticsearchTestBed; + const { server, httpRequestsMockHelpers } = setupEnvironment(); + + afterAll(() => { + server.restore(); + }); + + beforeEach(async () => { + httpRequestsMockHelpers.setLoadEsDeprecationsResponse(esDeprecationsMockResponse); + httpRequestsMockHelpers.setUpgradeMlSnapshotStatusResponse({ + nodeId: 'my_node', + snapshotId: MOCK_SNAPSHOT_ID, + jobId: MOCK_JOB_ID, + status: 'idle', + }); + + await act(async () => { + testBed = await setupElasticsearchPage({ isReadOnlyMode: false }); + }); + + testBed.component.update(); + }); + + it('renders deprecations', () => { + const { exists, find } = testBed; + // Verify container exists + expect(exists('esDeprecationsContent')).toBe(true); + + // Verify all deprecations appear in the table + expect(find('deprecationTableRow').length).toEqual( + esDeprecationsMockResponse.deprecations.length + ); + }); + + it('refreshes deprecation data', async () => { + const { actions } = testBed; + const totalRequests = server.requests.length; + + await actions.clickRefreshButton(); + + const mlDeprecation = esDeprecationsMockResponse.deprecations[0]; + const reindexDeprecation = esDeprecationsMockResponse.deprecations[3]; + + // Since upgradeStatusMockResponse includes ML and reindex actions (which require fetching status), there will be 3 requests made + expect(server.requests.length).toBe(totalRequests + 3); + expect(server.requests[server.requests.length - 3].url).toBe( + `${API_BASE_PATH}/es_deprecations` + ); + expect(server.requests[server.requests.length - 2].url).toBe( + `${API_BASE_PATH}/ml_snapshots/${(mlDeprecation.correctiveAction as MlAction).jobId}/${ + (mlDeprecation.correctiveAction as MlAction).snapshotId + }` + ); + expect(server.requests[server.requests.length - 1].url).toBe( + `${API_BASE_PATH}/reindex/${reindexDeprecation.index}` + ); + }); + + describe('search bar', () => { + it('filters results by "critical" status', async () => { + const { find, actions } = testBed; + + await actions.clickCriticalFilterButton(); + + const criticalDeprecations = esDeprecationsMockResponse.deprecations.filter( + (deprecation) => deprecation.isCritical + ); + + expect(find('deprecationTableRow').length).toEqual(criticalDeprecations.length); + + await actions.clickCriticalFilterButton(); + + expect(find('deprecationTableRow').length).toEqual( + esDeprecationsMockResponse.deprecations.length + ); + }); + + it('filters results by type', async () => { + const { component, find, actions } = testBed; + + await actions.clickTypeFilterDropdownAt(0); + + // We need to read the document "body" as the filter dropdown options are added there and not inside + // the component DOM tree. + const clusterTypeFilterButton: HTMLButtonElement | null = document.body.querySelector( + '.euiFilterSelect__items .euiFilterSelectItem' + ); + + expect(clusterTypeFilterButton).not.toBeNull(); + + await act(async () => { + clusterTypeFilterButton!.click(); + }); + + component.update(); + + const clusterDeprecations = esDeprecationsMockResponse.deprecations.filter( + (deprecation) => deprecation.type === 'cluster_settings' + ); + + expect(find('deprecationTableRow').length).toEqual(clusterDeprecations.length); + }); + + it('filters results by query string', async () => { + const { find, actions } = testBed; + const multiFieldsDeprecation = esDeprecationsMockResponse.deprecations[2]; + + await actions.setSearchInputValue(multiFieldsDeprecation.message); + + expect(find('deprecationTableRow').length).toEqual(1); + expect(find('deprecationTableRow').at(0).text()).toContain(multiFieldsDeprecation.message); + }); + + it('shows error for invalid search queries', async () => { + const { find, exists, actions } = testBed; + + await actions.setSearchInputValue('%'); + + expect(exists('invalidSearchQueryMessage')).toBe(true); + expect(find('invalidSearchQueryMessage').text()).toContain('Invalid search'); + }); + + it('shows message when search query does not return results', async () => { + const { find, actions, exists } = testBed; + + await actions.setSearchInputValue('foobarbaz'); + + expect(exists('noDeprecationsRow')).toBe(true); + expect(find('noDeprecationsRow').text()).toContain( + 'No Elasticsearch deprecation issues found' + ); + }); + }); + + describe('pagination', () => { + const esDeprecationsMockResponseWithManyDeprecations = createEsDeprecationsMockResponse(20); + const { deprecations } = esDeprecationsMockResponseWithManyDeprecations; + + beforeEach(async () => { + httpRequestsMockHelpers.setLoadEsDeprecationsResponse( + esDeprecationsMockResponseWithManyDeprecations + ); + httpRequestsMockHelpers.setUpgradeMlSnapshotStatusResponse({ + nodeId: 'my_node', + snapshotId: MOCK_SNAPSHOT_ID, + jobId: MOCK_JOB_ID, + status: 'idle', + }); + + await act(async () => { + testBed = await setupElasticsearchPage({ isReadOnlyMode: false }); + }); + + testBed.component.update(); + }); + + it('shows the correct number of pages and deprecations per page', async () => { + const { find, actions } = testBed; + + expect(find('esDeprecationsPagination').find('.euiPagination__item').length).toEqual( + Math.round(deprecations.length / 50) // Default rows per page is 50 + ); + expect(find('deprecationTableRow').length).toEqual(50); + + // Navigate to the next page + await actions.clickPaginationAt(1); + + // On the second (last) page, we expect to see the remaining deprecations + expect(find('deprecationTableRow').length).toEqual(deprecations.length - 50); + }); + + it('allows the number of viewable rows to change', async () => { + const { find, actions, component } = testBed; + + await actions.clickRowsPerPageDropdown(); + + // We need to read the document "body" as the rows-per-page dropdown options are added there and not inside + // the component DOM tree. + const rowsPerPageButton: HTMLButtonElement | null = document.body.querySelector( + '[data-test-subj="tablePagination-100-rows"]' + ); + + expect(rowsPerPageButton).not.toBeNull(); + + await act(async () => { + rowsPerPageButton!.click(); + }); + + component.update(); + + expect(find('esDeprecationsPagination').find('.euiPagination__item').length).toEqual( + Math.round(deprecations.length / 100) // Rows per page is now 100 + ); + expect(find('deprecationTableRow').length).toEqual(deprecations.length); + }); + + it('updates pagination when filters change', async () => { + const { actions, find } = testBed; + + const criticalDeprecations = deprecations.filter((deprecation) => deprecation.isCritical); + + await actions.clickCriticalFilterButton(); + + // Only 40 critical deprecations, so only one page should show + expect(find('esDeprecationsPagination').find('.euiPagination__item').length).toEqual(1); + expect(find('deprecationTableRow').length).toEqual(criticalDeprecations.length); + }); + + it('updates pagination on search', async () => { + const { actions, find } = testBed; + const reindexDeprecations = deprecations.filter( + (deprecation) => deprecation.correctiveAction?.type === 'reindex' + ); + + await actions.setSearchInputValue('Index created before 7.0'); + + // Only 20 deprecations that match, so only one page should show + expect(find('esDeprecationsPagination').find('.euiPagination__item').length).toEqual(1); + expect(find('deprecationTableRow').length).toEqual(reindexDeprecations.length); + }); + }); + + describe('no deprecations', () => { + beforeEach(async () => { + const noDeprecationsResponse = { + totalCriticalDeprecations: 0, + deprecations: [], + }; + + httpRequestsMockHelpers.setLoadEsDeprecationsResponse(noDeprecationsResponse); + + await act(async () => { + testBed = await setupElasticsearchPage({ isReadOnlyMode: false }); + }); + + testBed.component.update(); + }); + + test('renders prompt', () => { + const { exists, find } = testBed; + expect(exists('noDeprecationsPrompt')).toBe(true); + expect(find('noDeprecationsPrompt').text()).toContain( + 'Your Elasticsearch configuration is up to date' + ); + }); + }); +}); diff --git a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecations/error_handling.test.ts b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecations/error_handling.test.ts new file mode 100644 index 0000000000000..8d3616a1b9d6b --- /dev/null +++ b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecations/error_handling.test.ts @@ -0,0 +1,115 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { act } from 'react-dom/test-utils'; + +import { ElasticsearchTestBed, setupElasticsearchPage, setupEnvironment } from '../helpers'; + +describe('Error handling', () => { + let testBed: ElasticsearchTestBed; + const { server, httpRequestsMockHelpers } = setupEnvironment(); + + afterAll(() => { + server.restore(); + }); + + it('handles 403', async () => { + const error = { + statusCode: 403, + error: 'Forbidden', + message: 'Forbidden', + }; + + httpRequestsMockHelpers.setLoadEsDeprecationsResponse(undefined, error); + + await act(async () => { + testBed = await setupElasticsearchPage({ isReadOnlyMode: false }); + }); + + const { component, exists, find } = testBed; + + component.update(); + + expect(exists('permissionsError')).toBe(true); + expect(find('permissionsError').text()).toContain( + 'You are not authorized to view Elasticsearch deprecations.' + ); + }); + + it('shows upgraded message when all nodes have been upgraded', async () => { + const error = { + statusCode: 426, + error: 'Upgrade required', + message: 'There are some nodes running a different version of Elasticsearch', + attributes: { + // This is marked true in the scenario where none of the nodes have the same major version of Kibana, + // and therefore we assume all have been upgraded + allNodesUpgraded: true, + }, + }; + + httpRequestsMockHelpers.setLoadEsDeprecationsResponse(undefined, error); + + await act(async () => { + testBed = await setupElasticsearchPage({ isReadOnlyMode: false }); + }); + + const { component, exists, find } = testBed; + + component.update(); + + expect(exists('upgradedCallout')).toBe(true); + expect(find('upgradedCallout').text()).toContain('All Elasticsearch nodes have been upgraded.'); + }); + + it('shows partially upgrade error when nodes are running different versions', async () => { + const error = { + statusCode: 426, + error: 'Upgrade required', + message: 'There are some nodes running a different version of Elasticsearch', + attributes: { + allNodesUpgraded: false, + }, + }; + + httpRequestsMockHelpers.setLoadEsDeprecationsResponse(undefined, error); + + await act(async () => { + testBed = await setupElasticsearchPage({ isReadOnlyMode: false }); + }); + + const { component, exists, find } = testBed; + + component.update(); + + expect(exists('partiallyUpgradedWarning')).toBe(true); + expect(find('partiallyUpgradedWarning').text()).toContain( + 'Upgrade Kibana to the same version as your Elasticsearch cluster. One or more nodes in the cluster is running a different version than Kibana.' + ); + }); + + it('handles generic error', async () => { + const error = { + statusCode: 500, + error: 'Internal server error', + message: 'Internal server error', + }; + + httpRequestsMockHelpers.setLoadEsDeprecationsResponse(undefined, error); + + await act(async () => { + testBed = await setupElasticsearchPage({ isReadOnlyMode: false }); + }); + + const { component, exists, find } = testBed; + + component.update(); + + expect(exists('requestError')).toBe(true); + expect(find('requestError').text()).toContain('Could not retrieve Elasticsearch deprecations.'); + }); +}); diff --git a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecations/index_settings_deprecation_flyout.test.ts b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecations/index_settings_deprecation_flyout.test.ts new file mode 100644 index 0000000000000..efeb78a507160 --- /dev/null +++ b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecations/index_settings_deprecation_flyout.test.ts @@ -0,0 +1,117 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { act } from 'react-dom/test-utils'; + +import { ElasticsearchTestBed, setupElasticsearchPage, setupEnvironment } from '../helpers'; + +import { esDeprecationsMockResponse, MOCK_SNAPSHOT_ID, MOCK_JOB_ID } from './mocked_responses'; + +describe('Index settings deprecation flyout', () => { + let testBed: ElasticsearchTestBed; + const { server, httpRequestsMockHelpers } = setupEnvironment(); + const indexSettingDeprecation = esDeprecationsMockResponse.deprecations[1]; + + afterAll(() => { + server.restore(); + }); + + beforeEach(async () => { + httpRequestsMockHelpers.setLoadEsDeprecationsResponse(esDeprecationsMockResponse); + httpRequestsMockHelpers.setUpgradeMlSnapshotStatusResponse({ + nodeId: 'my_node', + snapshotId: MOCK_SNAPSHOT_ID, + jobId: MOCK_JOB_ID, + status: 'idle', + }); + + await act(async () => { + testBed = await setupElasticsearchPage({ isReadOnlyMode: false }); + }); + + const { find, exists, actions, component } = testBed; + + component.update(); + + await actions.clickIndexSettingsDeprecationAt(0); + + expect(exists('indexSettingsDetails')).toBe(true); + expect(find('indexSettingsDetails.flyoutTitle').text()).toContain( + indexSettingDeprecation.message + ); + expect(exists('removeSettingsPrompt')).toBe(true); + }); + + it('removes deprecated index settings', async () => { + const { find, actions } = testBed; + + httpRequestsMockHelpers.setUpdateIndexSettingsResponse({ + acknowledged: true, + }); + + await actions.clickDeleteSettingsButton(); + + const request = server.requests[server.requests.length - 1]; + + expect(request.method).toBe('POST'); + expect(request.url).toBe( + `/api/upgrade_assistant/${indexSettingDeprecation.index!}/index_settings` + ); + expect(request.status).toEqual(200); + + // Verify the "Resolution" column of the table is updated + expect(find('indexSettingsResolutionStatusCell').at(0).text()).toEqual( + 'Deprecated settings removed' + ); + + // Reopen the flyout + await actions.clickIndexSettingsDeprecationAt(0); + + // Verify prompt to remove setting no longer displays + expect(find('removeSettingsPrompt').length).toEqual(0); + // Verify the action button no longer displays + expect(find('indexSettingsDetails.deleteSettingsButton').length).toEqual(0); + }); + + it('handles failure', async () => { + const { find, actions } = testBed; + const error = { + statusCode: 500, + error: 'Remove index settings error', + message: 'Remove index settings error', + }; + + httpRequestsMockHelpers.setUpdateIndexSettingsResponse(undefined, error); + + await actions.clickDeleteSettingsButton(); + + const request = server.requests[server.requests.length - 1]; + + expect(request.method).toBe('POST'); + expect(request.url).toBe( + `/api/upgrade_assistant/${indexSettingDeprecation.index!}/index_settings` + ); + expect(request.status).toEqual(500); + + // Verify the "Resolution" column of the table is updated + expect(find('indexSettingsResolutionStatusCell').at(0).text()).toEqual( + 'Settings removal failed' + ); + + // Reopen the flyout + await actions.clickIndexSettingsDeprecationAt(0); + + // Verify the flyout shows an error message + expect(find('indexSettingsDetails.deleteSettingsError').text()).toContain( + 'Error deleting index settings' + ); + // Verify the remove settings button text changes + expect(find('indexSettingsDetails.deleteSettingsButton').text()).toEqual( + 'Retry removing deprecated settings' + ); + }); +}); diff --git a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecations/ml_snapshots_deprecation_flyout.test.ts b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecations/ml_snapshots_deprecation_flyout.test.ts new file mode 100644 index 0000000000000..909976355cd31 --- /dev/null +++ b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecations/ml_snapshots_deprecation_flyout.test.ts @@ -0,0 +1,196 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { act } from 'react-dom/test-utils'; + +import type { MlAction } from '../../../common/types'; +import { ElasticsearchTestBed, setupElasticsearchPage, setupEnvironment } from '../helpers'; +import { esDeprecationsMockResponse, MOCK_SNAPSHOT_ID, MOCK_JOB_ID } from './mocked_responses'; + +describe('Machine learning deprecation flyout', () => { + let testBed: ElasticsearchTestBed; + const { server, httpRequestsMockHelpers } = setupEnvironment(); + const mlDeprecation = esDeprecationsMockResponse.deprecations[0]; + + afterAll(() => { + server.restore(); + }); + + beforeEach(async () => { + httpRequestsMockHelpers.setLoadEsDeprecationsResponse(esDeprecationsMockResponse); + httpRequestsMockHelpers.setUpgradeMlSnapshotStatusResponse({ + nodeId: 'my_node', + snapshotId: MOCK_SNAPSHOT_ID, + jobId: MOCK_JOB_ID, + status: 'idle', + }); + + await act(async () => { + testBed = await setupElasticsearchPage({ isReadOnlyMode: false }); + }); + + const { find, exists, actions, component } = testBed; + + component.update(); + + await actions.clickMlDeprecationAt(0); + + expect(exists('mlSnapshotDetails')).toBe(true); + expect(find('mlSnapshotDetails.flyoutTitle').text()).toContain( + 'Upgrade or delete model snapshot' + ); + }); + + describe('upgrade snapshots', () => { + it('successfully upgrades snapshots', async () => { + const { find, actions, exists } = testBed; + + httpRequestsMockHelpers.setUpgradeMlSnapshotResponse({ + nodeId: 'my_node', + snapshotId: MOCK_SNAPSHOT_ID, + jobId: MOCK_JOB_ID, + status: 'in_progress', + }); + + httpRequestsMockHelpers.setUpgradeMlSnapshotStatusResponse({ + nodeId: 'my_node', + snapshotId: MOCK_SNAPSHOT_ID, + jobId: MOCK_JOB_ID, + status: 'complete', + }); + + expect(find('mlSnapshotDetails.upgradeSnapshotButton').text()).toEqual('Upgrade'); + + await actions.clickUpgradeMlSnapshot(); + + // First, we expect a POST request to upgrade the snapshot + const upgradeRequest = server.requests[server.requests.length - 2]; + expect(upgradeRequest.method).toBe('POST'); + expect(upgradeRequest.url).toBe('/api/upgrade_assistant/ml_snapshots'); + + // Next, we expect a GET request to check the status of the upgrade + const statusRequest = server.requests[server.requests.length - 1]; + expect(statusRequest.method).toBe('GET'); + expect(statusRequest.url).toBe( + `/api/upgrade_assistant/ml_snapshots/${MOCK_JOB_ID}/${MOCK_SNAPSHOT_ID}` + ); + + // Verify the "Resolution" column of the table is updated + expect(find('mlActionResolutionCell').text()).toContain('Upgrade complete'); + + // Reopen the flyout + await actions.clickMlDeprecationAt(0); + + // Flyout actions should not be visible if deprecation was resolved + expect(exists('mlSnapshotDetails.upgradeSnapshotButton')).toBe(false); + expect(exists('mlSnapshotDetails.deleteSnapshotButton')).toBe(false); + }); + + it('handles upgrade failure', async () => { + const { find, actions } = testBed; + + const error = { + statusCode: 500, + error: 'Upgrade snapshot error', + message: 'Upgrade snapshot error', + }; + + httpRequestsMockHelpers.setUpgradeMlSnapshotResponse(undefined, error); + httpRequestsMockHelpers.setUpgradeMlSnapshotStatusResponse({ + nodeId: 'my_node', + snapshotId: MOCK_SNAPSHOT_ID, + jobId: MOCK_JOB_ID, + status: 'error', + error, + }); + + await actions.clickUpgradeMlSnapshot(); + + const upgradeRequest = server.requests[server.requests.length - 1]; + expect(upgradeRequest.method).toBe('POST'); + expect(upgradeRequest.url).toBe('/api/upgrade_assistant/ml_snapshots'); + + // Verify the "Resolution" column of the table is updated + expect(find('mlActionResolutionCell').text()).toContain('Upgrade failed'); + + // Reopen the flyout + await actions.clickMlDeprecationAt(0); + + // Verify the flyout shows an error message + expect(find('mlSnapshotDetails.resolveSnapshotError').text()).toContain( + 'Error upgrading snapshot' + ); + // Verify the upgrade button text changes + expect(find('mlSnapshotDetails.upgradeSnapshotButton').text()).toEqual('Retry upgrade'); + }); + }); + + describe('delete snapshots', () => { + it('successfully deletes snapshots', async () => { + const { find, actions } = testBed; + + httpRequestsMockHelpers.setDeleteMlSnapshotResponse({ + acknowledged: true, + }); + + expect(find('mlSnapshotDetails.deleteSnapshotButton').text()).toEqual('Delete'); + + await actions.clickDeleteMlSnapshot(); + + const request = server.requests[server.requests.length - 1]; + + expect(request.method).toBe('DELETE'); + expect(request.url).toBe( + `/api/upgrade_assistant/ml_snapshots/${ + (mlDeprecation.correctiveAction! as MlAction).jobId + }/${(mlDeprecation.correctiveAction! as MlAction).snapshotId}` + ); + + // Verify the "Resolution" column of the table is updated + expect(find('mlActionResolutionCell').at(0).text()).toEqual('Deletion complete'); + + // Reopen the flyout + await actions.clickMlDeprecationAt(0); + }); + + it('handles delete failure', async () => { + const { find, actions } = testBed; + + const error = { + statusCode: 500, + error: 'Upgrade snapshot error', + message: 'Upgrade snapshot error', + }; + + httpRequestsMockHelpers.setDeleteMlSnapshotResponse(undefined, error); + + await actions.clickDeleteMlSnapshot(); + + const request = server.requests[server.requests.length - 1]; + + expect(request.method).toBe('DELETE'); + expect(request.url).toBe( + `/api/upgrade_assistant/ml_snapshots/${ + (mlDeprecation.correctiveAction! as MlAction).jobId + }/${(mlDeprecation.correctiveAction! as MlAction).snapshotId}` + ); + + // Verify the "Resolution" column of the table is updated + expect(find('mlActionResolutionCell').at(0).text()).toEqual('Deletion failed'); + + // Reopen the flyout + await actions.clickMlDeprecationAt(0); + + // Verify the flyout shows an error message + expect(find('mlSnapshotDetails.resolveSnapshotError').text()).toContain( + 'Error deleting snapshot' + ); + // Verify the upgrade button text changes + expect(find('mlSnapshotDetails.deleteSnapshotButton').text()).toEqual('Retry delete'); + }); + }); +}); diff --git a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecations/mocked_responses.ts b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecations/mocked_responses.ts new file mode 100644 index 0000000000000..ddf477195063c --- /dev/null +++ b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecations/mocked_responses.ts @@ -0,0 +1,119 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { ESUpgradeStatus, EnrichedDeprecationInfo } from '../../../common/types'; +import { indexSettingDeprecations } from '../../../common/constants'; + +export const MOCK_SNAPSHOT_ID = '1'; +export const MOCK_JOB_ID = 'deprecation_check_job'; + +export const MOCK_ML_DEPRECATION: EnrichedDeprecationInfo = { + isCritical: true, + resolveDuringUpgrade: false, + type: 'ml_settings', + message: 'model snapshot [1] for job [deprecation_check_job] needs to be deleted or upgraded', + details: + 'model snapshot [%s] for job [%s] supports minimum version [%s] and needs to be at least [%s]', + url: 'doc_url', + correctiveAction: { + type: 'mlSnapshot', + snapshotId: MOCK_SNAPSHOT_ID, + jobId: MOCK_JOB_ID, + }, +}; + +const MOCK_REINDEX_DEPRECATION: EnrichedDeprecationInfo = { + isCritical: true, + resolveDuringUpgrade: false, + type: 'index_settings', + message: 'Index created before 7.0', + details: 'deprecation details', + url: 'doc_url', + index: 'reindex_index', + correctiveAction: { + type: 'reindex', + }, +}; + +const MOCK_INDEX_SETTING_DEPRECATION: EnrichedDeprecationInfo = { + isCritical: false, + resolveDuringUpgrade: false, + type: 'index_settings', + message: indexSettingDeprecations.translog.deprecationMessage, + details: 'deprecation details', + url: 'doc_url', + index: 'my_index', + correctiveAction: { + type: 'indexSetting', + deprecatedSettings: indexSettingDeprecations.translog.settings, + }, +}; + +const MOCK_DEFAULT_DEPRECATION: EnrichedDeprecationInfo = { + isCritical: false, + resolveDuringUpgrade: false, + type: 'index_settings', + message: 'multi-fields within multi-fields', + details: 'deprecation details', + url: 'doc_url', + index: 'nested_multi-fields', +}; + +export const esDeprecationsMockResponse: ESUpgradeStatus = { + totalCriticalDeprecations: 2, + deprecations: [ + MOCK_ML_DEPRECATION, + MOCK_INDEX_SETTING_DEPRECATION, + MOCK_DEFAULT_DEPRECATION, + MOCK_REINDEX_DEPRECATION, + ], +}; + +// Useful for testing pagination where a large number of deprecations are needed +export const createEsDeprecationsMockResponse = ( + numDeprecationsPerType: number +): ESUpgradeStatus => { + const mlDeprecations: EnrichedDeprecationInfo[] = Array.from( + { + length: numDeprecationsPerType, + }, + () => MOCK_ML_DEPRECATION + ); + + const indexSettingsDeprecations: EnrichedDeprecationInfo[] = Array.from( + { + length: numDeprecationsPerType, + }, + () => MOCK_INDEX_SETTING_DEPRECATION + ); + + const reindexDeprecations: EnrichedDeprecationInfo[] = Array.from( + { + length: numDeprecationsPerType, + }, + () => MOCK_REINDEX_DEPRECATION + ); + + const defaultDeprecations: EnrichedDeprecationInfo[] = Array.from( + { + length: numDeprecationsPerType, + }, + () => MOCK_DEFAULT_DEPRECATION + ); + + const deprecations: EnrichedDeprecationInfo[] = [ + ...defaultDeprecations, + ...reindexDeprecations, + ...indexSettingsDeprecations, + ...mlDeprecations, + ]; + + return { + totalCriticalDeprecations: mlDeprecations.length + reindexDeprecations.length, + deprecations, + }; +}; diff --git a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecations/reindex_deprecation_flyout.test.ts b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecations/reindex_deprecation_flyout.test.ts new file mode 100644 index 0000000000000..c93cdcb1f4d97 --- /dev/null +++ b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecations/reindex_deprecation_flyout.test.ts @@ -0,0 +1,50 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { act } from 'react-dom/test-utils'; + +import { ElasticsearchTestBed, setupElasticsearchPage, setupEnvironment } from '../helpers'; + +import { esDeprecationsMockResponse, MOCK_SNAPSHOT_ID, MOCK_JOB_ID } from './mocked_responses'; + +// Note: The reindexing flyout UX is subject to change; more tests should be added here once functionality is built out +describe('Reindex deprecation flyout', () => { + let testBed: ElasticsearchTestBed; + const { server, httpRequestsMockHelpers } = setupEnvironment(); + + afterAll(() => { + server.restore(); + }); + + beforeEach(async () => { + httpRequestsMockHelpers.setLoadEsDeprecationsResponse(esDeprecationsMockResponse); + httpRequestsMockHelpers.setUpgradeMlSnapshotStatusResponse({ + nodeId: 'my_node', + snapshotId: MOCK_SNAPSHOT_ID, + jobId: MOCK_JOB_ID, + status: 'idle', + }); + + await act(async () => { + testBed = await setupElasticsearchPage({ isReadOnlyMode: false }); + }); + + testBed.component.update(); + }); + + it('renders a flyout with reindexing details', async () => { + const reindexDeprecation = esDeprecationsMockResponse.deprecations[3]; + const { actions, find, exists } = testBed; + + await actions.clickReindexDeprecationAt(0); + + expect(exists('reindexDetails')).toBe(true); + expect(find('reindexDetails.flyoutTitle').text()).toContain( + `Reindex ${reindexDeprecation.index}` + ); + }); +}); diff --git a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/cluster.helpers.ts b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/cluster.helpers.ts deleted file mode 100644 index 2aedface1e32b..0000000000000 --- a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/cluster.helpers.ts +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { registerTestBed, TestBed, TestBedConfig } from '@kbn/test/jest'; -import { EsDeprecationsContent } from '../../../public/application/components/es_deprecations'; -import { WithAppDependencies } from './setup_environment'; - -const testBedConfig: TestBedConfig = { - memoryRouter: { - initialEntries: ['/es_deprecations/cluster'], - componentRoutePath: '/es_deprecations/:tabName', - }, - doMountAsync: true, -}; - -export type ClusterTestBed = TestBed & { - actions: ReturnType; -}; - -const createActions = (testBed: TestBed) => { - /** - * User Actions - */ - const clickTab = (tabName: string) => { - const { find } = testBed; - const camelcaseTabName = tabName.charAt(0).toUpperCase() + tabName.slice(1); - - find(`upgradeAssistant${camelcaseTabName}Tab`).simulate('click'); - }; - - const clickExpandAll = () => { - const { find } = testBed; - find('expandAll').simulate('click'); - }; - - return { - clickTab, - clickExpandAll, - }; -}; - -export const setup = async (overrides?: Record): Promise => { - const initTestBed = registerTestBed( - WithAppDependencies(EsDeprecationsContent, overrides), - testBedConfig - ); - const testBed = await initTestBed(); - - return { - ...testBed, - actions: createActions(testBed), - }; -}; - -export type ClusterTestSubjects = - | 'expandAll' - | 'deprecationsContainer' - | 'permissionsError' - | 'requestError' - | 'upgradedCallout' - | 'partiallyUpgradedWarning' - | 'noDeprecationsPrompt' - | string; diff --git a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/elasticsearch.helpers.ts b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/elasticsearch.helpers.ts new file mode 100644 index 0000000000000..86737d4925927 --- /dev/null +++ b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/elasticsearch.helpers.ts @@ -0,0 +1,171 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { act } from 'react-dom/test-utils'; + +import { registerTestBed, TestBed, TestBedConfig } from '@kbn/test/jest'; +import { EsDeprecations } from '../../../public/application/components/es_deprecations'; +import { WithAppDependencies } from './setup_environment'; + +const testBedConfig: TestBedConfig = { + memoryRouter: { + initialEntries: ['/es_deprecations'], + componentRoutePath: '/es_deprecations', + }, + doMountAsync: true, +}; + +export type ElasticsearchTestBed = TestBed & { + actions: ReturnType; +}; + +const createActions = (testBed: TestBed) => { + const { component, find } = testBed; + + /** + * User Actions + */ + const clickRefreshButton = async () => { + await act(async () => { + find('refreshButton').simulate('click'); + }); + + component.update(); + }; + + const clickMlDeprecationAt = async (index: number) => { + await act(async () => { + find('deprecation-mlSnapshot').at(index).simulate('click'); + }); + + component.update(); + }; + + const clickUpgradeMlSnapshot = async () => { + await act(async () => { + find('mlSnapshotDetails.upgradeSnapshotButton').simulate('click'); + }); + + component.update(); + }; + + const clickDeleteMlSnapshot = async () => { + await act(async () => { + find('mlSnapshotDetails.deleteSnapshotButton').simulate('click'); + }); + + component.update(); + }; + + const clickIndexSettingsDeprecationAt = async (index: number) => { + await act(async () => { + find('deprecation-indexSetting').at(index).simulate('click'); + }); + + component.update(); + }; + + const clickDeleteSettingsButton = async () => { + await act(async () => { + find('deleteSettingsButton').simulate('click'); + }); + + component.update(); + }; + + const clickReindexDeprecationAt = async (index: number) => { + await act(async () => { + find('deprecation-reindex').at(index).simulate('click'); + }); + + component.update(); + }; + + const clickDefaultDeprecationAt = async (index: number) => { + await act(async () => { + find('deprecation-default').at(index).simulate('click'); + }); + + component.update(); + }; + + const clickCriticalFilterButton = async () => { + await act(async () => { + // EUI doesn't support data-test-subj's on the filter buttons, so we must access via CSS selector + find('searchBarContainer').find('.euiFilterButton').at(0).simulate('click'); + }); + + component.update(); + }; + + const clickTypeFilterDropdownAt = async (index: number) => { + await act(async () => { + // EUI doesn't support data-test-subj's on the filter buttons, so we must access via CSS selector + find('searchBarContainer') + .find('.euiPopover') + .find('.euiFilterButton') + .at(index) + .simulate('click'); + }); + + component.update(); + }; + + const setSearchInputValue = async (searchValue: string) => { + await act(async () => { + find('searchBarContainer') + .find('input') + .simulate('keyup', { target: { value: searchValue } }); + }); + + component.update(); + }; + + const clickPaginationAt = async (index: number) => { + await act(async () => { + find(`pagination-button-${index}`).simulate('click'); + }); + + component.update(); + }; + + const clickRowsPerPageDropdown = async () => { + await act(async () => { + find('tablePaginationPopoverButton').simulate('click'); + }); + + component.update(); + }; + + return { + clickRefreshButton, + clickMlDeprecationAt, + clickUpgradeMlSnapshot, + clickDeleteMlSnapshot, + clickIndexSettingsDeprecationAt, + clickDeleteSettingsButton, + clickReindexDeprecationAt, + clickDefaultDeprecationAt, + clickCriticalFilterButton, + clickTypeFilterDropdownAt, + setSearchInputValue, + clickPaginationAt, + clickRowsPerPageDropdown, + }; +}; + +export const setup = async (overrides?: Record): Promise => { + const initTestBed = registerTestBed( + WithAppDependencies(EsDeprecations, overrides), + testBedConfig + ); + const testBed = await initTestBed(); + + return { + ...testBed, + actions: createActions(testBed), + }; +}; diff --git a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/http_requests.ts b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/http_requests.ts index 74fcf14fdf597..d0c93d74f31f4 100644 --- a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/http_requests.ts +++ b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/http_requests.ts @@ -51,11 +51,13 @@ const registerHttpRequestMockHelpers = (server: SinonFakeServer) => { ]); }; - const setUpdateIndexSettingsResponse = (response?: object) => { + const setUpdateIndexSettingsResponse = (response?: object, error?: ResponseError) => { + const status = error ? error.statusCode || 400 : 200; + const body = error ? error : response; server.respondWith('POST', `${API_BASE_PATH}/:indexName/index_settings`, [ - 200, + status, { 'Content-Type': 'application/json' }, - JSON.stringify(response), + JSON.stringify(body), ]); }; @@ -70,6 +72,17 @@ const registerHttpRequestMockHelpers = (server: SinonFakeServer) => { ]); }; + const setUpgradeMlSnapshotStatusResponse = (response?: object, error?: ResponseError) => { + const status = error ? error.statusCode || 400 : 200; + const body = error ? error : response; + + server.respondWith('GET', `${API_BASE_PATH}/ml_snapshots/:jobId/:snapshotId`, [ + status, + { 'Content-Type': 'application/json' }, + JSON.stringify(body), + ]); + }; + const setDeleteMlSnapshotResponse = (response?: object, error?: ResponseError) => { const status = error ? error.statusCode || 400 : 200; const body = error ? error : response; @@ -88,6 +101,7 @@ const registerHttpRequestMockHelpers = (server: SinonFakeServer) => { setUpdateIndexSettingsResponse, setUpgradeMlSnapshotResponse, setDeleteMlSnapshotResponse, + setUpgradeMlSnapshotStatusResponse, }; }; diff --git a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/index.ts b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/index.ts index 8e256680253be..b19c8b3d0f082 100644 --- a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/index.ts +++ b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/index.ts @@ -6,8 +6,7 @@ */ export { setup as setupOverviewPage, OverviewTestBed } from './overview.helpers'; -export { setup as setupIndicesPage, IndicesTestBed } from './indices.helpers'; -export { setup as setupClusterPage, ClusterTestBed } from './cluster.helpers'; +export { setup as setupElasticsearchPage, ElasticsearchTestBed } from './elasticsearch.helpers'; export { setup as setupKibanaPage, KibanaTestBed } from './kibana.helpers'; export { setupEnvironment } from './setup_environment'; diff --git a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/indices.helpers.ts b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/indices.helpers.ts deleted file mode 100644 index 5189ddc420b08..0000000000000 --- a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/indices.helpers.ts +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { registerTestBed, TestBed, TestBedConfig } from '@kbn/test/jest'; -import { EsDeprecationsContent } from '../../../public/application/components/es_deprecations'; -import { WithAppDependencies } from './setup_environment'; - -const testBedConfig: TestBedConfig = { - memoryRouter: { - initialEntries: ['/es_deprecations/indices'], - componentRoutePath: '/es_deprecations/:tabName', - }, - doMountAsync: true, -}; - -export type IndicesTestBed = TestBed & { - actions: ReturnType; -}; - -const createActions = (testBed: TestBed) => { - /** - * User Actions - */ - const clickTab = (tabName: string) => { - const { find } = testBed; - const camelcaseTabName = tabName.charAt(0).toUpperCase() + tabName.slice(1); - - find(`upgradeAssistant${camelcaseTabName}Tab`).simulate('click'); - }; - - const clickFixButton = () => { - const { find } = testBed; - find('removeIndexSettingsButton').simulate('click'); - }; - - const clickExpandAll = () => { - const { find } = testBed; - find('expandAll').simulate('click'); - }; - - return { - clickTab, - clickFixButton, - clickExpandAll, - }; -}; - -export const setup = async (overrides?: Record): Promise => { - const initTestBed = registerTestBed( - WithAppDependencies(EsDeprecationsContent, overrides), - testBedConfig - ); - const testBed = await initTestBed(); - - return { - ...testBed, - actions: createActions(testBed), - }; -}; - -export type IndicesTestSubjects = - | 'expandAll' - | 'removeIndexSettingsButton' - | 'deprecationsContainer' - | 'permissionsError' - | 'requestError' - | 'indexCount' - | 'upgradedCallout' - | 'partiallyUpgradedWarning' - | 'noDeprecationsPrompt' - | string; diff --git a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/setup_environment.tsx b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/setup_environment.tsx index 53b4b5d75931b..c5de02bebd512 100644 --- a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/setup_environment.tsx +++ b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/setup_environment.tsx @@ -23,9 +23,12 @@ import { mockKibanaSemverVersion } from '../../../common/constants'; import { AppContextProvider } from '../../../public/application/app_context'; import { apiService } from '../../../public/application/lib/api'; import { breadcrumbService } from '../../../public/application/lib/breadcrumbs'; +import { GlobalFlyout } from '../../../public/shared_imports'; import { servicesMock } from './services_mock'; import { init as initHttpRequests } from './http_requests'; +const { GlobalFlyoutProvider } = GlobalFlyout; + const mockHttpClient = axios.create({ adapter: axiosXhrAdapter }); export const WithAppDependencies = (Comp: any, overrides: Record = {}) => ( @@ -55,7 +58,9 @@ export const WithAppDependencies = (Comp: any, overrides: Record - + + + ); diff --git a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/indices.test.ts b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/indices.test.ts deleted file mode 100644 index 89f648c98437e..0000000000000 --- a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/indices.test.ts +++ /dev/null @@ -1,245 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { act } from 'react-dom/test-utils'; -import { indexSettingDeprecations } from '../../common/constants'; -import { ESUpgradeStatus } from '../../common/types'; - -import { IndicesTestBed, setupIndicesPage, setupEnvironment } from './helpers'; - -describe('Indices tab', () => { - let testBed: IndicesTestBed; - const { server, httpRequestsMockHelpers } = setupEnvironment(); - - afterAll(() => { - server.restore(); - }); - - describe('with deprecations', () => { - const esDeprecationsMockResponse: ESUpgradeStatus = { - totalCriticalDeprecations: 0, - cluster: [], - indices: [ - { - level: 'warning', - message: indexSettingDeprecations.translog.deprecationMessage, - url: 'doc_url', - index: 'my_index', - correctiveAction: { - type: 'indexSetting', - deprecatedSettings: indexSettingDeprecations.translog.settings, - }, - }, - ], - }; - - beforeEach(async () => { - httpRequestsMockHelpers.setLoadEsDeprecationsResponse(esDeprecationsMockResponse); - httpRequestsMockHelpers.setLoadDeprecationLoggingResponse({ - isDeprecationLogIndexingEnabled: true, - isDeprecationLoggingEnabled: true, - }); - - await act(async () => { - testBed = await setupIndicesPage({ isReadOnlyMode: false }); - }); - - const { actions, component } = testBed; - - component.update(); - - // Navigate to the indices tab - await act(async () => { - actions.clickTab('indices'); - }); - - component.update(); - }); - - test('renders deprecations', () => { - const { exists, find } = testBed; - expect(exists('indexTabContent')).toBe(true); - expect(exists('deprecationsContainer')).toBe(true); - expect(find('indexCount').text()).toEqual('1'); - }); - - describe('fix indices button', () => { - test('removes deprecated index settings', async () => { - const { component, actions, exists, find } = testBed; - - expect(exists('deprecationsContainer')).toBe(true); - - // Open all deprecations - actions.clickExpandAll(); - - const accordionTestSubj = `depgroup_${indexSettingDeprecations.translog.deprecationMessage - .split(' ') - .join('_')}`; - - await act(async () => { - find(`${accordionTestSubj}.removeIndexSettingsButton`).simulate('click'); - }); - - // We need to read the document "body" as the modal is added there and not inside - // the component DOM tree. - const modal = document.body.querySelector( - '[data-test-subj="indexSettingsDeleteConfirmModal"]' - ); - const confirmButton: HTMLButtonElement | null = modal!.querySelector( - '[data-test-subj="confirmModalConfirmButton"]' - ); - - expect(modal).not.toBe(null); - expect(modal!.textContent).toContain('Remove deprecated settings'); - - const indexName = esDeprecationsMockResponse.indices[0].index; - - httpRequestsMockHelpers.setUpdateIndexSettingsResponse({ - acknowledged: true, - }); - - await act(async () => { - confirmButton!.click(); - }); - - component.update(); - - const request = server.requests[server.requests.length - 1]; - - expect(request.method).toBe('POST'); - expect(request.url).toBe(`/api/upgrade_assistant/${indexName}/index_settings`); - expect(request.status).toEqual(200); - }); - }); - }); - - describe('no deprecations', () => { - beforeEach(async () => { - const noDeprecationsResponse = { - totalCriticalDeprecations: 0, - cluster: [], - indices: [], - }; - - httpRequestsMockHelpers.setLoadEsDeprecationsResponse(noDeprecationsResponse); - - await act(async () => { - testBed = await setupIndicesPage({ isReadOnlyMode: false }); - }); - - const { component } = testBed; - - component.update(); - }); - - test('renders prompt', () => { - const { exists, find } = testBed; - expect(exists('noDeprecationsPrompt')).toBe(true); - expect(find('noDeprecationsPrompt').text()).toContain('Ready to upgrade!'); - }); - }); - - describe('error handling', () => { - test('handles 403', async () => { - const error = { - statusCode: 403, - error: 'Forbidden', - message: 'Forbidden', - }; - - httpRequestsMockHelpers.setLoadEsDeprecationsResponse(undefined, error); - - await act(async () => { - testBed = await setupIndicesPage({ isReadOnlyMode: false }); - }); - - const { component, exists, find } = testBed; - - component.update(); - - expect(exists('permissionsError')).toBe(true); - expect(find('permissionsError').text()).toContain( - 'You are not authorized to view Elasticsearch deprecations.' - ); - }); - - test('handles upgrade error', async () => { - const error = { - statusCode: 426, - error: 'Upgrade required', - message: 'There are some nodes running a different version of Elasticsearch', - attributes: { - allNodesUpgraded: true, - }, - }; - - httpRequestsMockHelpers.setLoadEsDeprecationsResponse(undefined, error); - - await act(async () => { - testBed = await setupIndicesPage({ isReadOnlyMode: false }); - }); - - const { component, exists, find } = testBed; - - component.update(); - - expect(exists('upgradedCallout')).toBe(true); - expect(find('upgradedCallout').text()).toContain( - 'Your configuration is up to date. Kibana and all Elasticsearch nodes are running the same version.' - ); - }); - - test('handles partially upgrade error', async () => { - const error = { - statusCode: 426, - error: 'Upgrade required', - message: 'There are some nodes running a different version of Elasticsearch', - attributes: { - allNodesUpgraded: false, - }, - }; - - httpRequestsMockHelpers.setLoadEsDeprecationsResponse(undefined, error); - - await act(async () => { - testBed = await setupIndicesPage({ isReadOnlyMode: false }); - }); - - const { component, exists, find } = testBed; - - component.update(); - - expect(exists('partiallyUpgradedWarning')).toBe(true); - expect(find('partiallyUpgradedWarning').text()).toContain( - 'Upgrade Kibana to the same version as your Elasticsearch cluster. One or more nodes in the cluster is running a different version than Kibana.' - ); - }); - - test('handles generic error', async () => { - const error = { - statusCode: 500, - error: 'Internal server error', - message: 'Internal server error', - }; - - httpRequestsMockHelpers.setLoadEsDeprecationsResponse(undefined, error); - - await act(async () => { - testBed = await setupIndicesPage({ isReadOnlyMode: false }); - }); - - const { component, exists, find } = testBed; - - component.update(); - - expect(exists('requestError')).toBe(true); - expect(find('requestError').text()).toContain( - 'Could not retrieve Elasticsearch deprecations.' - ); - }); - }); -}); diff --git a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/kibana.test.ts b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/kibana.test.ts index b14ec26e5c8af..5de290e325fe4 100644 --- a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/kibana.test.ts +++ b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/kibana.test.ts @@ -78,7 +78,7 @@ describe('Kibana deprecations', () => { // the component DOM tree. let modal = document.body.querySelector('[data-test-subj="stepsModal"]'); - expect(modal).not.toBe(null); + expect(modal).not.toBeNull(); expect(modal!.textContent).toContain(`Resolve deprecation in '${deprecation.domainId}'`); const steps: NodeListOf | null = modal!.querySelectorAll( @@ -160,7 +160,9 @@ describe('Kibana deprecations', () => { test('renders prompt', () => { const { exists, find } = testBed; expect(exists('noDeprecationsPrompt')).toBe(true); - expect(find('noDeprecationsPrompt').text()).toContain('Ready to upgrade!'); + expect(find('noDeprecationsPrompt').text()).toContain( + 'Your Kibana configuration is up to date' + ); }); }); diff --git a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/overview/review_logs_step/mocked_responses.ts b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/overview/review_logs_step/mocked_responses.ts index ba8f9f8b67d0c..0bf9f9932b8a1 100644 --- a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/overview/review_logs_step/mocked_responses.ts +++ b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/overview/review_logs_step/mocked_responses.ts @@ -10,19 +10,21 @@ import { ESUpgradeStatus } from '../../../../common/types'; export const esDeprecations: ESUpgradeStatus = { totalCriticalDeprecations: 1, - cluster: [ + deprecations: [ { - level: 'critical', + isCritical: true, + type: 'cluster_settings', + resolveDuringUpgrade: false, message: 'Index Lifecycle Management poll interval is set too low', url: 'https://www.elastic.co/guide/en/elasticsearch/reference/master/breaking-changes-8.0.html#ilm-poll-interval-limit', details: 'The Index Lifecycle Management poll interval setting [indices.lifecycle.poll_interval] is currently set to [500ms], but must be 1s or greater', }, - ], - indices: [ { - level: 'warning', + isCritical: false, + type: 'index_settings', + resolveDuringUpgrade: false, message: 'translog retention settings are ignored', url: 'https://www.elastic.co/guide/en/elasticsearch/reference/current/index-modules-translog.html', @@ -35,8 +37,7 @@ export const esDeprecations: ESUpgradeStatus = { export const esDeprecationsEmpty: ESUpgradeStatus = { totalCriticalDeprecations: 0, - cluster: [], - indices: [], + deprecations: [], }; export const kibanaDeprecations: DomainDeprecationDetails[] = [ diff --git a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/overview/review_logs_step/review_logs_step.test.tsx b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/overview/review_logs_step/review_logs_step.test.tsx index 254242ab338a0..2afffe989ed1b 100644 --- a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/overview/review_logs_step/review_logs_step.test.tsx +++ b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/overview/review_logs_step/review_logs_step.test.tsx @@ -84,7 +84,7 @@ describe('Overview - Fix deprecated settings step', () => { component.update(); expect(exists('esStatsPanel')).toBe(true); - expect(find('esStatsPanel').find('a').props().href).toBe('/es_deprecations/cluster'); + expect(find('esStatsPanel').find('a').props().href).toBe('/es_deprecations'); }); describe('Renders ES errors', () => { diff --git a/x-pack/plugins/upgrade_assistant/common/types.ts b/x-pack/plugins/upgrade_assistant/common/types.ts index 35c514a0a95bb..a390dd26a0747 100644 --- a/x-pack/plugins/upgrade_assistant/common/types.ts +++ b/x-pack/plugins/upgrade_assistant/common/types.ts @@ -5,6 +5,10 @@ * 2.0. */ +import { + MigrationDeprecationInfoDeprecation, + MigrationDeprecationInfoResponse, +} from '@elastic/elasticsearch/api/types'; import { SavedObject, SavedObjectAttributes } from 'src/core/public'; export enum ReindexStep { @@ -116,13 +120,12 @@ export enum IndexGroup { // Telemetry types export const UPGRADE_ASSISTANT_TYPE = 'upgrade-assistant-telemetry'; export const UPGRADE_ASSISTANT_DOC_ID = 'upgrade-assistant-telemetry'; -export type UIOpenOption = 'overview' | 'cluster' | 'indices' | 'kibana'; +export type UIOpenOption = 'overview' | 'elasticsearch' | 'kibana'; export type UIReindexOption = 'close' | 'open' | 'start' | 'stop'; export interface UIOpen { overview: boolean; - cluster: boolean; - indices: boolean; + elasticsearch: boolean; kibana: boolean; } @@ -136,8 +139,7 @@ export interface UIReindex { export interface UpgradeAssistantTelemetrySavedObject { ui_open: { overview: number; - cluster: number; - indices: number; + elasticsearch: number; kibana: number; }; ui_reindex: { @@ -151,8 +153,7 @@ export interface UpgradeAssistantTelemetrySavedObject { export interface UpgradeAssistantTelemetry { ui_open: { overview: number; - cluster: number; - indices: number; + elasticsearch: number; kibana: number; }; ui_reindex: { @@ -186,13 +187,6 @@ export interface DeprecationInfo { export interface IndexSettingsDeprecationInfo { [indexName: string]: DeprecationInfo[]; } -export interface DeprecationAPIResponse { - cluster_settings: DeprecationInfo[]; - ml_settings: DeprecationInfo[]; - node_settings: DeprecationInfo[]; - index_settings: IndexSettingsDeprecationInfo; -} - export interface ReindexAction { type: 'reindex'; /** @@ -215,15 +209,18 @@ export interface IndexSettingAction { type: 'indexSetting'; deprecatedSettings: string[]; } -export interface EnrichedDeprecationInfo extends DeprecationInfo { +export interface EnrichedDeprecationInfo + extends Omit { + type: keyof MigrationDeprecationInfoResponse; + isCritical: boolean; index?: string; correctiveAction?: ReindexAction | MlAction | IndexSettingAction; + resolveDuringUpgrade: boolean; } export interface ESUpgradeStatus { totalCriticalDeprecations: number; - cluster: EnrichedDeprecationInfo[]; - indices: EnrichedDeprecationInfo[]; + deprecations: EnrichedDeprecationInfo[]; } export interface ResolveIndexResponseFromES { diff --git a/x-pack/plugins/upgrade_assistant/public/application/app.tsx b/x-pack/plugins/upgrade_assistant/public/application/app.tsx index b1571b9e45461..864be6e5d996d 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/app.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/app.tsx @@ -8,17 +8,19 @@ import React from 'react'; import { Router, Switch, Route, Redirect } from 'react-router-dom'; import { I18nStart, ScopedHistory } from 'src/core/public'; - import { ApplicationStart } from 'kibana/public'; +import { GlobalFlyout } from '../shared_imports'; + import { KibanaContextProvider } from '../shared_imports'; import { AppServicesContext } from '../types'; import { AppContextProvider, ContextValue, useAppContext } from './app_context'; import { ComingSoonPrompt } from './components/coming_soon_prompt'; -import { EsDeprecationsContent } from './components/es_deprecations'; +import { EsDeprecations } from './components/es_deprecations'; import { KibanaDeprecationsContent } from './components/kibana_deprecations'; import { Overview } from './components/overview'; import { RedirectAppLinks } from '../../../../../src/plugins/kibana_react/public'; +const { GlobalFlyoutProvider } = GlobalFlyout; export interface AppDependencies extends ContextValue { i18n: I18nStart; history: ScopedHistory; @@ -37,7 +39,7 @@ const App: React.FunctionComponent = () => { return ( - + @@ -64,7 +66,9 @@ export const RootComponent = ({ - + + + diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/constants.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/constants.tsx index 7b4bee75bc757..c7f974fab6a89 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/constants.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/constants.tsx @@ -7,6 +7,8 @@ import { IconColor } from '@elastic/eui'; import { invert } from 'lodash'; +import { i18n } from '@kbn/i18n'; + import { DeprecationInfo } from '../../../common/types'; export const LEVEL_MAP: { [level: string]: number } = { @@ -26,3 +28,24 @@ export const COLOR_MAP: { [level: string]: IconColor } = { }; export const DEPRECATIONS_PER_PAGE = 25; + +export const DEPRECATION_TYPE_MAP = { + cluster_settings: i18n.translate( + 'xpack.upgradeAssistant.esDeprecations.clusterDeprecationTypeLabel', + { + defaultMessage: 'Cluster', + } + ), + index_settings: i18n.translate( + 'xpack.upgradeAssistant.esDeprecations.indexDeprecationTypeLabel', + { + defaultMessage: 'Index', + } + ), + node_settings: i18n.translate('xpack.upgradeAssistant.esDeprecations.nodeDeprecationTypeLabel', { + defaultMessage: 'Node', + }), + ml_settings: i18n.translate('xpack.upgradeAssistant.esDeprecations.mlDeprecationTypeLabel', { + defaultMessage: 'Machine Learning', + }), +}; diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/__fixtures__/checkup_api_response.json b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/__fixtures__/checkup_api_response.json deleted file mode 100644 index 531bc229b39ea..0000000000000 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/__fixtures__/checkup_api_response.json +++ /dev/null @@ -1,870 +0,0 @@ -{ - "cluster": [ - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 0", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 0", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 1", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 1", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 0 1", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 0 1", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 2", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 2", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 0 2", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 0 2", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 1 2", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 1 2", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 0 1 2", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 0 1 2", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 3", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 3", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 0 3", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 0 3", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 1 3", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 1 3", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 0 1 3", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 0 1 3", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 2 3", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 2 3", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 0 2 3", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 0 2 3", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 1 2 3", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 1 2 3", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 0 1 2 3", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 0 1 2 3", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 4", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 4", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 0 4", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 0 4", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 1 4", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 1 4", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 0 1 4", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 0 1 4", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 2 4", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 2 4", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 0 2 4", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 0 2 4", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 1 2 4", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 1 2 4", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 0 1 2 4", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 0 1 2 4", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 3 4", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 3 4", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 0 3 4", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 0 3 4", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 1 3 4", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 1 3 4", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 0 1 3 4", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 0 1 3 4", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 2 3 4", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 2 3 4", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 0 2 3 4", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 0 2 3 4", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 1 2 3 4", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 1 2 3 4", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 0 1 2 3 4", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 0 1 2 3 4", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 0 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 0 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 1 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 1 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 0 1 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 0 1 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 2 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 2 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 0 2 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 0 2 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 1 2 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 1 2 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 0 1 2 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 0 1 2 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 3 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 3 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 0 3 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 0 3 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 1 3 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 1 3 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 0 1 3 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 0 1 3 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 2 3 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 2 3 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 0 2 3 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 0 2 3 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 1 2 3 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 1 2 3 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 0 1 2 3 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 0 1 2 3 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 4 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 4 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 0 4 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 0 4 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 1 4 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 1 4 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 0 1 4 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 0 1 4 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 2 4 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 2 4 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 0 2 4 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 0 2 4 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 1 2 4 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 1 2 4 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 0 1 2 4 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 0 1 2 4 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 3 4 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 3 4 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 0 3 4 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 0 3 4 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 1 3 4 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 1 3 4 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 0 1 3 4 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 0 1 3 4 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 2 3 4 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 2 3 4 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 0 2 3 4 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 0 2 3 4 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 1 2 3 4 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 1 2 3 4 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 0 1 2 3 4 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 0 1 2 3 4 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - } - ], - "nodes": [], - "indices": [ - { - "level": "warning", - "message": "Coercion of boolean fields", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_mappings_changes.html#_coercion_of_boolean_fields", - "details": "[[type: doc, field: spins], [type: doc, field: mlockall], [type: doc, field: node_master], [type: doc, field: primary]]", - "index": ".monitoring-es-6-2018.11.07" - }, - { - "level": "warning", - "message": "Coercion of boolean fields", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_mappings_changes.html#_coercion_of_boolean_fields", - "details": "[[type: tweet, field: liked]]", - "index": "twitter" - }, - { - "level": "warning", - "message": "Coercion of boolean fields", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_mappings_changes.html#_coercion_of_boolean_fields", - "details": "[[type: index-pattern, field: notExpandable], [type: config, field: xPackMonitoring:allowReport], [type: config, field: xPackMonitoring:showBanner], [type: dashboard, field: pause], [type: dashboard, field: timeRestore]]", - "index": ".kibana" - }, - { - "level": "warning", - "message": "Coercion of boolean fields", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_mappings_changes.html#_coercion_of_boolean_fields", - "details": "[[type: doc, field: notify], [type: doc, field: created], [type: doc, field: attach_payload], [type: doc, field: met]]", - "index": ".watcher-history-6-2018.11.07" - }, - { - "level": "warning", - "message": "Coercion of boolean fields", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_mappings_changes.html#_coercion_of_boolean_fields", - "details": "[[type: doc, field: snapshot]]", - "index": ".monitoring-kibana-6-2018.11.07" - }, - { - "level": "warning", - "message": "Coercion of boolean fields", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_mappings_changes.html#_coercion_of_boolean_fields", - "details": "[[type: tweet, field: liked]]", - "index": "twitter2" - }, - { - "index": "twitter", - "level": "critical", - "message": "This index must be reindexed in order to upgrade the Elastic Stack.", - "details": "Reindexing is irreversible, so always back up your index before proceeding.", - "actions": [ - { - "label": "Reindex in Console", - "url": "/app/dev_tools#/console?load_from=%2Fapi%2Fupgrade_assistant%2Freindex%2Fconsole_template%2Ftwitter.json" - } - ], - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/current/reindex-upgrade.html" - }, - { - "index": ".triggered_watches", - "level": "critical", - "message": "This index must be upgraded in order to upgrade the Elastic Stack.", - "details": "Upgrading is irreversible, so always back up your index before proceeding.", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/current/migration-api-upgrade.html" - }, - { - "index": ".reindex-status", - "level": "critical", - "message": "This index must be reindexed in order to upgrade the Elastic Stack.", - "details": "Reindexing is irreversible, so always back up your index before proceeding.", - "actions": [ - { - "label": "Reindex in Console", - "url": "/app/dev_tools#/console?load_from=%2Fapi%2Fupgrade_assistant%2Freindex%2Fconsole_template%2F.reindex-status.json" - } - ], - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/current/reindex-upgrade.html" - }, - { - "index": "twitter2", - "level": "critical", - "message": "This index must be reindexed in order to upgrade the Elastic Stack.", - "details": "Reindexing is irreversible, so always back up your index before proceeding.", - "actions": [ - { - "label": "Reindex in Console", - "url": "/app/dev_tools#/console?load_from=%2Fapi%2Fupgrade_assistant%2Freindex%2Fconsole_template%2Ftwitter2.json" - } - ], - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/current/reindex-upgrade.html" - }, - { - "index": ".watches", - "level": "critical", - "message": "This index must be upgraded in order to upgrade the Elastic Stack.", - "details": "Upgrading is irreversible, so always back up your index before proceeding.", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/current/migration-api-upgrade.html" - } - ] -} diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/_index.scss b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/_index.scss index d64400a8abdcf..4865e977f5261 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/_index.scss +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/_index.scss @@ -1 +1 @@ -@import 'deprecations/index'; +@import 'deprecation_types/index'; diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_tab_content.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_tab_content.tsx deleted file mode 100644 index 8be407371f038..0000000000000 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_tab_content.tsx +++ /dev/null @@ -1,228 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { find, groupBy } from 'lodash'; -import React, { FunctionComponent, useState, useEffect } from 'react'; -import { i18n } from '@kbn/i18n'; - -import { EuiSpacer, EuiHorizontalRule } from '@elastic/eui'; - -import { EnrichedDeprecationInfo } from '../../../../common/types'; -import { SectionLoading } from '../../../shared_imports'; -import { GroupByOption, LevelFilterOption, UpgradeAssistantTabProps } from '../types'; -import { - NoDeprecationsPrompt, - SearchBar, - DeprecationPagination, - DeprecationListBar, -} from '../shared'; -import { DEPRECATIONS_PER_PAGE } from '../constants'; -import { EsDeprecationErrors } from './es_deprecation_errors'; -import { EsDeprecationAccordion } from './deprecations'; - -const i18nTexts = { - isLoading: i18n.translate('xpack.upgradeAssistant.esDeprecations.loadingText', { - defaultMessage: 'Loading deprecations…', - }), -}; - -export interface CheckupTabProps extends UpgradeAssistantTabProps { - checkupLabel: string; -} - -export const createDependenciesFilter = (level: LevelFilterOption, search: string = '') => { - const conditions: Array<(dep: EnrichedDeprecationInfo) => boolean> = []; - - if (level !== 'all') { - conditions.push((dep: EnrichedDeprecationInfo) => dep.level === level); - } - - if (search.length > 0) { - conditions.push((dep) => { - try { - // 'i' is used for case-insensitive matching - const searchReg = new RegExp(search, 'i'); - return searchReg.test(dep.message); - } catch (e) { - // ignore any regexp errors. - return true; - } - }); - } - - // Return true if every condition function returns true (boolean AND) - return (dep: EnrichedDeprecationInfo) => conditions.map((c) => c(dep)).every((t) => t); -}; - -const filterDeprecations = ( - deprecations: EnrichedDeprecationInfo[] = [], - currentFilter: LevelFilterOption, - search: string -) => deprecations.filter(createDependenciesFilter(currentFilter, search)); - -const groupDeprecations = ( - deprecations: EnrichedDeprecationInfo[], - currentFilter: LevelFilterOption, - search: string, - currentGroupBy: GroupByOption -) => groupBy(filterDeprecations(deprecations, currentFilter, search), currentGroupBy); - -const getPageCount = ( - deprecations: EnrichedDeprecationInfo[], - currentFilter: LevelFilterOption, - search: string, - currentGroupBy: GroupByOption -) => - Math.ceil( - Object.keys(groupDeprecations(deprecations, currentFilter, search, currentGroupBy)).length / - DEPRECATIONS_PER_PAGE - ); - -/** - * Displays a list of deprecations that are filterable and groupable. Can be used for cluster, - * nodes, or indices deprecations. - */ -export const DeprecationTabContent: FunctionComponent = ({ - checkupLabel, - deprecations, - error, - isLoading, - refreshCheckupData, - navigateToOverviewPage, -}) => { - const [currentFilter, setCurrentFilter] = useState('all'); - const [search, setSearch] = useState(''); - const [currentGroupBy, setCurrentGroupBy] = useState(GroupByOption.message); - const [expandState, setExpandState] = useState({ - forceExpand: false, - expandNumber: 0, - }); - const [currentPage, setCurrentPage] = useState(0); - - const getAvailableGroupByOptions = () => { - if (!deprecations) { - return []; - } - - return Object.keys(GroupByOption).filter((opt) => find(deprecations, opt)) as GroupByOption[]; - }; - - const setExpandAll = (expandAll: boolean) => { - setExpandState({ forceExpand: expandAll, expandNumber: expandState.expandNumber + 1 }); - }; - - useEffect(() => { - if (deprecations) { - const pageCount = getPageCount(deprecations, currentFilter, search, currentGroupBy); - - if (currentPage >= pageCount) { - setCurrentPage(0); - } - } - }, [currentPage, deprecations, currentFilter, search, currentGroupBy]); - - if (deprecations && deprecations.length === 0) { - return ( -
- -
- ); - } - - let content: React.ReactNode; - - if (isLoading) { - content = {i18nTexts.isLoading}; - } else if (deprecations?.length) { - const levelGroups = groupBy(deprecations, 'level'); - const levelToDeprecationCountMap = Object.keys(levelGroups).reduce((counts, level) => { - counts[level] = levelGroups[level].length; - return counts; - }, {} as Record); - - const filteredDeprecations = filterDeprecations(deprecations, currentFilter, search); - - const groups = groupDeprecations(deprecations, currentFilter, search, currentGroupBy); - - content = ( -
- - - - - - - <> - {Object.keys(groups) - .sort() - // Apply pagination - .slice(currentPage * DEPRECATIONS_PER_PAGE, (currentPage + 1) * DEPRECATIONS_PER_PAGE) - .map((groupName, index) => [ -
- - -
, - ])} - - {/* Only show pagination if we have more than DEPRECATIONS_PER_PAGE. */} - {Object.keys(groups).length > DEPRECATIONS_PER_PAGE && ( - <> - - - - - )} - -
- ); - } else if (error) { - content = ; - } - - return ( -
- - - {content} -
- ); -}; diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/_index.scss b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/_index.scss similarity index 60% rename from x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/_index.scss rename to x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/_index.scss index 1f4f0352e7939..c3e842941a250 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/_index.scss +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/_index.scss @@ -1,2 +1 @@ -@import 'cell'; @import 'reindex/index'; diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/default/flyout.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/default/flyout.tsx new file mode 100644 index 0000000000000..439062e027650 --- /dev/null +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/default/flyout.tsx @@ -0,0 +1,96 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { i18n } from '@kbn/i18n'; +import { + EuiButtonEmpty, + EuiFlyoutBody, + EuiFlyoutFooter, + EuiFlyoutHeader, + EuiFlexGroup, + EuiFlexItem, + EuiTitle, + EuiText, + EuiTextColor, + EuiLink, +} from '@elastic/eui'; + +import { EnrichedDeprecationInfo } from '../../../../../../common/types'; + +export interface DefaultDeprecationFlyoutProps { + deprecation: EnrichedDeprecationInfo; + closeFlyout: () => void; +} + +const i18nTexts = { + getFlyoutDescription: (indexName: string) => + i18n.translate( + 'xpack.upgradeAssistant.esDeprecations.deprecationDetailsFlyout.secondaryDescription', + { + defaultMessage: 'Index: {indexName}', + values: { + indexName, + }, + } + ), + learnMoreLinkLabel: i18n.translate( + 'xpack.upgradeAssistant.esDeprecations.deprecationDetailsFlyout.learnMoreLinkLabel', + { + defaultMessage: 'Learn more about this deprecation', + } + ), + closeButtonLabel: i18n.translate( + 'xpack.upgradeAssistant.esDeprecations.deprecationDetailsFlyout.closeButtonLabel', + { + defaultMessage: 'Close', + } + ), +}; + +export const DefaultDeprecationFlyout = ({ + deprecation, + closeFlyout, +}: DefaultDeprecationFlyoutProps) => { + const { message, url, details, index } = deprecation; + + return ( + <> + + +

{message}

+
+ {index && ( + +

+ {i18nTexts.getFlyoutDescription(index)} +

+
+ )} +
+ + +

{details}

+

+ + {i18nTexts.learnMoreLinkLabel} + +

+
+
+ + + + + {i18nTexts.closeButtonLabel} + + + + + + ); +}; diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/flyout/index.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/default/index.ts similarity index 84% rename from x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/flyout/index.tsx rename to x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/default/index.ts index facc830234667..ea537b642d8e4 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/flyout/index.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/default/index.ts @@ -5,4 +5,4 @@ * 2.0. */ -export { ReindexFlyout } from './container'; +export { DefaultTableRow } from './table_row'; diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/default/table_row.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/default/table_row.tsx new file mode 100644 index 0000000000000..7f4b2e3be3479 --- /dev/null +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/default/table_row.tsx @@ -0,0 +1,73 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useState, useEffect, useCallback } from 'react'; +import { EuiTableRowCell } from '@elastic/eui'; +import { GlobalFlyout } from '../../../../../shared_imports'; +import { EnrichedDeprecationInfo } from '../../../../../../common/types'; +import { DeprecationTableColumns } from '../../../types'; +import { EsDeprecationsTableCells } from '../../es_deprecations_table_cells'; +import { DefaultDeprecationFlyout, DefaultDeprecationFlyoutProps } from './flyout'; + +const { useGlobalFlyout } = GlobalFlyout; + +interface Props { + rowFieldNames: DeprecationTableColumns[]; + deprecation: EnrichedDeprecationInfo; +} + +export const DefaultTableRow: React.FunctionComponent = ({ rowFieldNames, deprecation }) => { + const [showFlyout, setShowFlyout] = useState(false); + + const { + addContent: addContentToGlobalFlyout, + removeContent: removeContentFromGlobalFlyout, + } = useGlobalFlyout(); + + const closeFlyout = useCallback(() => { + setShowFlyout(false); + removeContentFromGlobalFlyout('deprecationDetails'); + }, [removeContentFromGlobalFlyout]); + + useEffect(() => { + if (showFlyout) { + addContentToGlobalFlyout({ + id: 'deprecationDetails', + Component: DefaultDeprecationFlyout, + props: { + deprecation, + closeFlyout, + }, + flyoutProps: { + onClose: closeFlyout, + 'data-test-subj': 'defaultDeprecationDetails', + 'aria-labelledby': 'defaultDeprecationDetailsFlyoutTitle', + }, + }); + } + }, [addContentToGlobalFlyout, closeFlyout, deprecation, showFlyout]); + + return ( + <> + {rowFieldNames.map((field) => { + return ( + + setShowFlyout(true)} + deprecation={deprecation} + /> + + ); + })} + + ); +}; diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/index.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/index.tsx similarity index 55% rename from x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/index.tsx rename to x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/index.tsx index a4152e52a35b7..eb0221a722a30 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/index.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/index.tsx @@ -5,4 +5,7 @@ * 2.0. */ -export { EsDeprecationAccordion } from './deprecation_group_item'; +export { MlSnapshotsTableRow } from './ml_snapshots'; +export { IndexSettingsTableRow } from './index_settings'; +export { DefaultTableRow } from './default'; +export { ReindexTableRow } from './reindex'; diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/index_settings/flyout.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/index_settings/flyout.tsx new file mode 100644 index 0000000000000..1567562db53ee --- /dev/null +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/index_settings/flyout.tsx @@ -0,0 +1,204 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { i18n } from '@kbn/i18n'; +import { + EuiButton, + EuiButtonEmpty, + EuiCode, + EuiFlyoutBody, + EuiFlyoutFooter, + EuiFlyoutHeader, + EuiFlexGroup, + EuiFlexItem, + EuiTitle, + EuiText, + EuiTextColor, + EuiLink, + EuiSpacer, + EuiCallOut, +} from '@elastic/eui'; +import { EnrichedDeprecationInfo, IndexSettingAction } from '../../../../../../common/types'; +import type { ResponseError } from '../../../../lib/api'; +import type { Status } from '../../../types'; + +export interface RemoveIndexSettingsFlyoutProps { + deprecation: EnrichedDeprecationInfo; + closeFlyout: () => void; + removeIndexSettings: (index: string, settings: string[]) => Promise; + status: { + statusType: Status; + details?: ResponseError; + }; +} + +const i18nTexts = { + getFlyoutDescription: (indexName: string) => + i18n.translate( + 'xpack.upgradeAssistant.esDeprecations.removeSettingsFlyout.secondaryDescription', + { + defaultMessage: 'Index: {indexName}', + values: { + indexName, + }, + } + ), + learnMoreLinkLabel: i18n.translate( + 'xpack.upgradeAssistant.esDeprecations.removeSettingsFlyout.learnMoreLinkLabel', + { + defaultMessage: 'Learn more about this deprecation', + } + ), + removeButtonLabel: i18n.translate( + 'xpack.upgradeAssistant.esDeprecations.removeSettingsFlyout.removeButtonLabel', + { + defaultMessage: 'Remove deprecated settings', + } + ), + retryRemoveButtonLabel: i18n.translate( + 'xpack.upgradeAssistant.esDeprecations.removeSettingsFlyout.retryRemoveButtonLabel', + { + defaultMessage: 'Retry removing deprecated settings', + } + ), + resolvedButtonLabel: i18n.translate( + 'xpack.upgradeAssistant.esDeprecations.removeSettingsFlyout.resolvedButtonLabel', + { + defaultMessage: 'Resolved', + } + ), + closeButtonLabel: i18n.translate( + 'xpack.upgradeAssistant.esDeprecations.removeSettingsFlyout.closeButtonLabel', + { + defaultMessage: 'Close', + } + ), + getConfirmationText: (indexSettingsCount: number) => + i18n.translate('xpack.upgradeAssistant.esDeprecations.removeSettingsFlyout.description', { + defaultMessage: + 'Remove the following deprecated index {indexSettingsCount, plural, one {setting} other {settings}}?', + values: { + indexSettingsCount, + }, + }), + errorTitle: i18n.translate( + 'xpack.upgradeAssistant.esDeprecations.removeSettingsFlyout.deleteErrorTitle', + { + defaultMessage: 'Error deleting index settings', + } + ), +}; + +export const RemoveIndexSettingsFlyout = ({ + deprecation, + closeFlyout, + removeIndexSettings, + status, +}: RemoveIndexSettingsFlyoutProps) => { + const { index, message, details, url, correctiveAction } = deprecation; + const { statusType, details: statusDetails } = status; + + // Flag used to hide certain parts of the UI if the deprecation has been resolved or is in progress + const isResolvable = ['idle', 'error'].includes(statusType); + + return ( + <> + + +

{message}

+
+ +

+ {i18nTexts.getFlyoutDescription(index!)} +

+
+
+ + {statusType === 'error' && ( + <> + + {statusDetails!.message} + + + + )} + + +

{details}

+

+ + {i18nTexts.learnMoreLinkLabel} + +

+
+ + {isResolvable && ( +
+ + + +

+ {i18nTexts.getConfirmationText( + (correctiveAction as IndexSettingAction).deprecatedSettings.length + )} +

+
+ + + + +
    + {(correctiveAction as IndexSettingAction).deprecatedSettings.map( + (setting, settingIndex) => ( +
  • + {setting} +
  • + ) + )} +
+
+
+ )} +
+ + + + + {i18nTexts.closeButtonLabel} + + + + {isResolvable && ( + + + removeIndexSettings( + index!, + (correctiveAction as IndexSettingAction).deprecatedSettings + ) + } + > + {statusType === 'error' + ? i18nTexts.retryRemoveButtonLabel + : i18nTexts.removeButtonLabel} + + + )} + + + + ); +}; diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/ml_snapshots/index.ts b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/index_settings/index.ts similarity index 82% rename from x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/ml_snapshots/index.ts rename to x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/index_settings/index.ts index d537c94cf67ae..282b8308f403f 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/ml_snapshots/index.ts +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/index_settings/index.ts @@ -5,4 +5,4 @@ * 2.0. */ -export { FixMlSnapshotsButton } from './button'; +export { IndexSettingsTableRow } from './table_row'; diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/index_settings/resolution_table_cell.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/index_settings/resolution_table_cell.tsx new file mode 100644 index 0000000000000..a5a586927c811 --- /dev/null +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/index_settings/resolution_table_cell.tsx @@ -0,0 +1,130 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; + +import { + EuiFlexItem, + EuiText, + EuiFlexGroup, + EuiIcon, + EuiLoadingSpinner, + EuiToolTip, +} from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { Status } from '../../../types'; + +const i18nTexts = { + deleteInProgressText: i18n.translate( + 'xpack.upgradeAssistant.esDeprecations.indexSettings.deletingButtonLabel', + { + defaultMessage: 'Settings removal in progress…', + } + ), + deleteCompleteText: i18n.translate( + 'xpack.upgradeAssistant.esDeprecations.indexSettings.deleteCompleteText', + { + defaultMessage: 'Deprecated settings removed', + } + ), + deleteFailedText: i18n.translate( + 'xpack.upgradeAssistant.esDeprecations.indexSettings.deleteFailedText', + { + defaultMessage: 'Settings removal failed', + } + ), + resolutionText: i18n.translate( + 'xpack.upgradeAssistant.esDeprecations.indexSettings.resolutionText', + { + defaultMessage: 'Remove settings', + } + ), + resolutionTooltipLabel: i18n.translate( + 'xpack.upgradeAssistant.esDeprecations.indexSettings.resolutionTooltipLabel', + { + defaultMessage: + 'Resolve this deprecation by removing settings from this index. This is an automated resolution.', + } + ), +}; + +interface Props { + status: { + statusType: Status; + }; +} + +export const IndexSettingsResolutionCell: React.FunctionComponent = ({ status }) => { + const { statusType } = status; + if (statusType === 'in_progress') { + return ( + + + + + + {i18nTexts.deleteInProgressText} + + + ); + } + + if (statusType === 'complete') { + return ( + + + + + + {i18nTexts.deleteCompleteText} + + + ); + } + + if (statusType === 'error') { + return ( + + + + + + {i18nTexts.deleteFailedText} + + + ); + } + + return ( + + + + + + + {i18nTexts.resolutionText} + + + + ); +}; diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/index_settings/table_row.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/index_settings/table_row.tsx new file mode 100644 index 0000000000000..3a1706b08c0ee --- /dev/null +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/index_settings/table_row.tsx @@ -0,0 +1,103 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useState, useEffect, useCallback } from 'react'; +import { EuiTableRowCell } from '@elastic/eui'; +import { EnrichedDeprecationInfo } from '../../../../../../common/types'; +import { GlobalFlyout } from '../../../../../shared_imports'; +import { useAppContext } from '../../../../app_context'; +import type { ResponseError } from '../../../../lib/api'; +import { EsDeprecationsTableCells } from '../../es_deprecations_table_cells'; +import { DeprecationTableColumns, Status } from '../../../types'; +import { IndexSettingsResolutionCell } from './resolution_table_cell'; +import { RemoveIndexSettingsFlyout, RemoveIndexSettingsFlyoutProps } from './flyout'; + +const { useGlobalFlyout } = GlobalFlyout; + +interface Props { + deprecation: EnrichedDeprecationInfo; + rowFieldNames: DeprecationTableColumns[]; +} + +export const IndexSettingsTableRow: React.FunctionComponent = ({ + rowFieldNames, + deprecation, +}) => { + const [showFlyout, setShowFlyout] = useState(false); + const [status, setStatus] = useState<{ + statusType: Status; + details?: ResponseError; + }>({ statusType: 'idle' }); + + const { api } = useAppContext(); + + const { + addContent: addContentToGlobalFlyout, + removeContent: removeContentFromGlobalFlyout, + } = useGlobalFlyout(); + + const closeFlyout = useCallback(() => { + setShowFlyout(false); + removeContentFromGlobalFlyout('indexSettingsFlyout'); + }, [removeContentFromGlobalFlyout]); + + const removeIndexSettings = useCallback( + async (index: string, settings: string[]) => { + setStatus({ statusType: 'in_progress' }); + + const { error } = await api.updateIndexSettings(index, settings); + + setStatus({ + statusType: error ? 'error' : 'complete', + details: error ?? undefined, + }); + closeFlyout(); + }, + [api, closeFlyout] + ); + + useEffect(() => { + if (showFlyout) { + addContentToGlobalFlyout({ + id: 'indexSettingsFlyout', + Component: RemoveIndexSettingsFlyout, + props: { + closeFlyout, + deprecation, + removeIndexSettings, + status, + }, + flyoutProps: { + onClose: closeFlyout, + 'data-test-subj': 'indexSettingsDetails', + 'aria-labelledby': 'indexSettingsDetailsFlyoutTitle', + }, + }); + } + }, [addContentToGlobalFlyout, deprecation, removeIndexSettings, showFlyout, closeFlyout, status]); + + return ( + <> + {rowFieldNames.map((field: DeprecationTableColumns) => { + return ( + + setShowFlyout(true)} + deprecation={deprecation} + resolutionTableCell={} + /> + + ); + })} + + ); +}; diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/ml_snapshots/context.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/ml_snapshots/context.tsx new file mode 100644 index 0000000000000..972d640d18c5a --- /dev/null +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/ml_snapshots/context.tsx @@ -0,0 +1,65 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useEffect, createContext, useContext } from 'react'; +import { ApiService } from '../../../../lib/api'; + +import { useSnapshotState, SnapshotState } from './use_snapshot_state'; + +export interface MlSnapshotContext { + snapshotState: SnapshotState; + upgradeSnapshot: () => Promise; + deleteSnapshot: () => Promise; +} + +const MlSnapshotsContext = createContext(undefined); + +export const useMlSnapshotContext = () => { + const context = useContext(MlSnapshotsContext); + if (context === undefined) { + throw new Error('useMlSnapshotContext must be used within a '); + } + return context; +}; + +interface Props { + api: ApiService; + children: React.ReactNode; + snapshotId: string; + jobId: string; +} + +export const MlSnapshotsStatusProvider: React.FunctionComponent = ({ + api, + snapshotId, + jobId, + children, +}) => { + const { updateSnapshotStatus, snapshotState, upgradeSnapshot, deleteSnapshot } = useSnapshotState( + { + jobId, + snapshotId, + api, + } + ); + + useEffect(() => { + updateSnapshotStatus(); + }, [updateSnapshotStatus]); + + return ( + + {children} + + ); +}; diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/ml_snapshots/fix_snapshots_flyout.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/ml_snapshots/flyout.tsx similarity index 61% rename from x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/ml_snapshots/fix_snapshots_flyout.tsx rename to x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/ml_snapshots/flyout.tsx index 7dafab011a69a..ba72faf2f8c3f 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/ml_snapshots/fix_snapshots_flyout.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/ml_snapshots/flyout.tsx @@ -13,28 +13,22 @@ import { EuiButtonEmpty, EuiFlexGroup, EuiFlexItem, - EuiFlyout, EuiFlyoutBody, EuiFlyoutFooter, EuiFlyoutHeader, - EuiPortal, EuiTitle, EuiText, EuiCallOut, EuiSpacer, + EuiLink, } from '@elastic/eui'; -import { SnapshotStatus } from './use_snapshot_state'; -import { ResponseError } from '../../../../lib/api'; -interface SnapshotState extends SnapshotStatus { - error?: ResponseError; -} -interface Props { - upgradeSnapshot: () => Promise; - deleteSnapshot: () => Promise; - description: string; +import { EnrichedDeprecationInfo } from '../../../../../../common/types'; +import { MlSnapshotContext } from './context'; + +export interface FixSnapshotsFlyoutProps extends MlSnapshotContext { + deprecation: EnrichedDeprecationInfo; closeFlyout: () => void; - snapshotState: SnapshotState; } const i18nTexts = { @@ -51,7 +45,7 @@ const i18nTexts = { } ), closeButtonLabel: i18n.translate( - 'xpack.upgradeAssistant.esDeprecations.mlSnapshots.flyout.cancelButtonLabel', + 'xpack.upgradeAssistant.esDeprecations.mlSnapshots.flyout.closeButtonLabel', { defaultMessage: 'Close', } @@ -83,15 +77,24 @@ const i18nTexts = { defaultMessage: 'Error upgrading snapshot', } ), + learnMoreLinkLabel: i18n.translate( + 'xpack.upgradeAssistant.esDeprecations.mlSnapshots.learnMoreLinkLabel', + { + defaultMessage: 'Learn more about this deprecation', + } + ), }; export const FixSnapshotsFlyout = ({ - upgradeSnapshot, - deleteSnapshot, - description, + deprecation, closeFlyout, snapshotState, -}: Props) => { + upgradeSnapshot, + deleteSnapshot, +}: FixSnapshotsFlyoutProps) => { + // Flag used to hide certain parts of the UI if the deprecation has been resolved or is in progress + const isResolvable = ['idle', 'error'].includes(snapshotState.status); + const onUpgradeSnapshot = () => { upgradeSnapshot(); closeFlyout(); @@ -103,48 +106,48 @@ export const FixSnapshotsFlyout = ({ }; return ( - - - - -

{i18nTexts.flyoutTitle}

-
-
- - {snapshotState.error && ( - <> - - {snapshotState.error.message} - - - - )} - -

{description}

-
-
- - - - - {i18nTexts.closeButtonLabel} - - + <> + + +

{i18nTexts.flyoutTitle}

+
+
+ + {snapshotState.error && ( + <> + + {snapshotState.error.message} + + + + )} + +

{deprecation.details}

+

+ + {i18nTexts.learnMoreLinkLabel} + +

+
+
+ + + + + {i18nTexts.closeButtonLabel} + + + + {isResolvable && ( @@ -173,9 +176,9 @@ export const FixSnapshotsFlyout = ({ - - -
-
+ )} + + + ); }; diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/index_settings/index.ts b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/ml_snapshots/index.ts similarity index 83% rename from x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/index_settings/index.ts rename to x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/ml_snapshots/index.ts index e8a83790ee2a6..d523184454533 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/index_settings/index.ts +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/ml_snapshots/index.ts @@ -5,4 +5,4 @@ * 2.0. */ -export { FixIndexSettingsButton } from './button'; +export { MlSnapshotsTableRow } from './table_row'; diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/ml_snapshots/resolution_table_cell.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/ml_snapshots/resolution_table_cell.tsx new file mode 100644 index 0000000000000..7963701b5c543 --- /dev/null +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/ml_snapshots/resolution_table_cell.tsx @@ -0,0 +1,140 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; + +import { + EuiToolTip, + EuiFlexItem, + EuiText, + EuiFlexGroup, + EuiIcon, + EuiLoadingSpinner, +} from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; + +import { useMlSnapshotContext } from './context'; + +const i18nTexts = { + upgradeInProgressText: i18n.translate( + 'xpack.upgradeAssistant.esDeprecations.mlSnapshots.upgradeInProgressText', + { + defaultMessage: 'Upgrade in progress…', + } + ), + deleteInProgressText: i18n.translate( + 'xpack.upgradeAssistant.esDeprecations.mlSnapshots.deletingButtonLabel', + { + defaultMessage: 'Deletion in progress…', + } + ), + upgradeCompleteText: i18n.translate( + 'xpack.upgradeAssistant.esDeprecations.mlSnapshots.upgradeCompleteText', + { + defaultMessage: 'Upgrade complete', + } + ), + deleteCompleteText: i18n.translate( + 'xpack.upgradeAssistant.esDeprecations.mlSnapshots.deleteCompleteText', + { + defaultMessage: 'Deletion complete', + } + ), + upgradeFailedText: i18n.translate( + 'xpack.upgradeAssistant.esDeprecations.mlSnapshots.upgradeFailedText', + { + defaultMessage: 'Upgrade failed', + } + ), + deleteFailedText: i18n.translate( + 'xpack.upgradeAssistant.esDeprecations.mlSnapshots.deleteFailedText', + { + defaultMessage: 'Deletion failed', + } + ), + resolutionText: i18n.translate( + 'xpack.upgradeAssistant.esDeprecations.mlSnapshots.resolutionText', + { + defaultMessage: 'Upgrade or delete snapshots', + } + ), + resolutionTooltipLabel: i18n.translate( + 'xpack.upgradeAssistant.esDeprecations.mlSnapshots.resolutionTooltipLabel', + { + defaultMessage: + 'Resolve this deprecation by upgrading or deleting a job model snapshot. This is an automated resolution.', + } + ), +}; + +export const MlSnapshotsResolutionCell: React.FunctionComponent = () => { + const { snapshotState } = useMlSnapshotContext(); + + if (snapshotState.status === 'in_progress') { + return ( + + + + + + + {snapshotState.action === 'delete' + ? i18nTexts.deleteInProgressText + : i18nTexts.upgradeInProgressText} + + + + ); + } + + if (snapshotState.status === 'complete') { + return ( + + + + + + + {snapshotState.action === 'delete' + ? i18nTexts.deleteCompleteText + : i18nTexts.upgradeCompleteText} + + + + ); + } + + if (snapshotState.status === 'error') { + return ( + + + + + + + {snapshotState.action === 'delete' + ? i18nTexts.deleteFailedText + : i18nTexts.upgradeFailedText} + + + + ); + } + + return ( + + + + + + + {i18nTexts.resolutionText} + + + + ); +}; diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/ml_snapshots/table_row.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/ml_snapshots/table_row.tsx new file mode 100644 index 0000000000000..73921b235d88c --- /dev/null +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/ml_snapshots/table_row.tsx @@ -0,0 +1,92 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useState, useEffect, useCallback } from 'react'; +import { EuiTableRowCell } from '@elastic/eui'; +import { EnrichedDeprecationInfo, MlAction } from '../../../../../../common/types'; +import { GlobalFlyout } from '../../../../../shared_imports'; +import { useAppContext } from '../../../../app_context'; +import { DeprecationTableColumns } from '../../../types'; +import { EsDeprecationsTableCells } from '../../es_deprecations_table_cells'; +import { MlSnapshotsResolutionCell } from './resolution_table_cell'; +import { FixSnapshotsFlyout, FixSnapshotsFlyoutProps } from './flyout'; +import { MlSnapshotsStatusProvider, useMlSnapshotContext } from './context'; + +const { useGlobalFlyout } = GlobalFlyout; + +interface TableRowProps { + deprecation: EnrichedDeprecationInfo; + rowFieldNames: DeprecationTableColumns[]; +} + +export const MlSnapshotsTableRowCells: React.FunctionComponent = ({ + rowFieldNames, + deprecation, +}) => { + const [showFlyout, setShowFlyout] = useState(false); + const snapshotState = useMlSnapshotContext(); + + const { + addContent: addContentToGlobalFlyout, + removeContent: removeContentFromGlobalFlyout, + } = useGlobalFlyout(); + + const closeFlyout = useCallback(() => { + setShowFlyout(false); + removeContentFromGlobalFlyout('mlFlyout'); + }, [removeContentFromGlobalFlyout]); + + useEffect(() => { + if (showFlyout) { + addContentToGlobalFlyout({ + id: 'mlFlyout', + Component: FixSnapshotsFlyout, + props: { + deprecation, + closeFlyout, + ...snapshotState, + }, + flyoutProps: { + onClose: closeFlyout, + 'data-test-subj': 'mlSnapshotDetails', + 'aria-labelledby': 'mlSnapshotDetailsFlyoutTitle', + }, + }); + } + }, [snapshotState, addContentToGlobalFlyout, showFlyout, deprecation, closeFlyout]); + + return ( + <> + {rowFieldNames.map((field: DeprecationTableColumns) => { + return ( + + setShowFlyout(true)} + deprecation={deprecation} + resolutionTableCell={} + /> + + ); + })} + + ); +}; + +export const MlSnapshotsTableRow: React.FunctionComponent = (props) => { + const { api } = useAppContext(); + + return ( + + + + ); +}; diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/ml_snapshots/use_snapshot_state.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/ml_snapshots/use_snapshot_state.tsx similarity index 94% rename from x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/ml_snapshots/use_snapshot_state.tsx rename to x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/ml_snapshots/use_snapshot_state.tsx index 2dd4638c772b3..a724922563e05 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/ml_snapshots/use_snapshot_state.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/ml_snapshots/use_snapshot_state.tsx @@ -8,16 +8,21 @@ import { useRef, useCallback, useState, useEffect } from 'react'; import { ApiService, ResponseError } from '../../../../lib/api'; +import { Status } from '../../../types'; const POLL_INTERVAL_MS = 1000; -export interface SnapshotStatus { +interface SnapshotStatus { snapshotId: string; jobId: string; - status: 'complete' | 'in_progress' | 'error' | 'idle'; + status: Status; action?: 'upgrade' | 'delete'; } +export interface SnapshotState extends SnapshotStatus { + error: ResponseError | undefined; +} + export const useSnapshotState = ({ jobId, snapshotId, diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/_index.scss b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/_index.scss similarity index 57% rename from x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/_index.scss rename to x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/_index.scss index 014edc96b0565..4cd55614ab4e6 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/_index.scss +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/_index.scss @@ -1,2 +1 @@ -@import 'button'; @import 'flyout/index'; diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/context.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/context.tsx new file mode 100644 index 0000000000000..2d34253d2c426 --- /dev/null +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/context.tsx @@ -0,0 +1,61 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useEffect, createContext, useContext } from 'react'; + +import { ApiService } from '../../../../lib/api'; +import { useReindexStatus, ReindexState } from './use_reindex_state'; + +export interface ReindexStateContext { + reindexState: ReindexState; + startReindex: () => Promise; + cancelReindex: () => Promise; +} + +const ReindexContext = createContext(undefined); + +export const useReindexContext = () => { + const context = useContext(ReindexContext); + if (context === undefined) { + throw new Error('useReindexContext must be used within a '); + } + return context; +}; + +interface Props { + api: ApiService; + children: React.ReactNode; + indexName: string; +} + +export const ReindexStatusProvider: React.FunctionComponent = ({ + api, + indexName, + children, +}) => { + const { reindexState, startReindex, cancelReindex, updateStatus } = useReindexStatus({ + indexName, + api, + }); + + useEffect(() => { + updateStatus(); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + return ( + + {children} + + ); +}; diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/flyout/__snapshots__/checklist_step.test.tsx.snap b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/flyout/__snapshots__/checklist_step.test.tsx.snap similarity index 100% rename from x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/flyout/__snapshots__/checklist_step.test.tsx.snap rename to x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/flyout/__snapshots__/checklist_step.test.tsx.snap diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/flyout/__snapshots__/warning_step.test.tsx.snap b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/flyout/__snapshots__/warning_step.test.tsx.snap similarity index 100% rename from x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/flyout/__snapshots__/warning_step.test.tsx.snap rename to x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/flyout/__snapshots__/warning_step.test.tsx.snap diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/flyout/_index.scss b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/flyout/_index.scss similarity index 100% rename from x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/flyout/_index.scss rename to x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/flyout/_index.scss diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/flyout/_step_progress.scss b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/flyout/_step_progress.scss similarity index 100% rename from x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/flyout/_step_progress.scss rename to x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/flyout/_step_progress.scss diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/flyout/checklist_step.test.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/flyout/checklist_step.test.tsx similarity index 97% rename from x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/flyout/checklist_step.test.tsx rename to x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/flyout/checklist_step.test.tsx index d2fb3ec342135..e84623b6f3612 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/flyout/checklist_step.test.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/flyout/checklist_step.test.tsx @@ -11,7 +11,7 @@ import React from 'react'; import { ReindexStatus } from '../../../../../../../common/types'; import { LoadingState } from '../../../../types'; -import { ReindexState } from '../polling_service'; +import type { ReindexState } from '../use_reindex_state'; import { ChecklistFlyoutStep } from './checklist_step'; describe('ChecklistFlyout', () => { diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/flyout/checklist_step.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/flyout/checklist_step.tsx similarity index 96% rename from x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/flyout/checklist_step.tsx rename to x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/flyout/checklist_step.tsx index 9d42055506ac4..856e2a57649df 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/flyout/checklist_step.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/flyout/checklist_step.tsx @@ -7,7 +7,6 @@ import React, { Fragment } from 'react'; -import { HttpSetup } from 'src/core/public'; import { EuiButton, EuiButtonEmpty, @@ -23,7 +22,7 @@ import { FormattedMessage } from '@kbn/i18n/react'; import { ReindexStatus } from '../../../../../../../common/types'; import { LoadingState } from '../../../../types'; -import { ReindexState } from '../polling_service'; +import type { ReindexState } from '../use_reindex_state'; import { ReindexProgress } from './progress'; const buttonLabel = (status?: ReindexStatus) => { @@ -46,7 +45,7 @@ const buttonLabel = (status?: ReindexStatus) => { return ( ); case ReindexStatus.paused: @@ -75,8 +74,7 @@ export const ChecklistFlyoutStep: React.FunctionComponent<{ reindexState: ReindexState; startReindex: () => void; cancelReindex: () => void; - http: HttpSetup; -}> = ({ closeFlyout, reindexState, startReindex, cancelReindex, http, renderGlobalCallouts }) => { +}> = ({ closeFlyout, reindexState, startReindex, cancelReindex, renderGlobalCallouts }) => { const { loadingState, status, hasRequiredPrivileges } = reindexState; const loading = loadingState === LoadingState.Loading || status === ReindexStatus.inProgress; diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/flyout/container.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/flyout/container.tsx new file mode 100644 index 0000000000000..f10e7b4cc687e --- /dev/null +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/flyout/container.tsx @@ -0,0 +1,142 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useState } from 'react'; +import { DocLinksStart } from 'kibana/public'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { EuiCallOut, EuiFlyoutHeader, EuiLink, EuiSpacer, EuiTitle } from '@elastic/eui'; + +import { + EnrichedDeprecationInfo, + ReindexAction, + ReindexStatus, +} from '../../../../../../../common/types'; +import { useAppContext } from '../../../../../app_context'; + +import type { ReindexStateContext } from '../context'; +import { ChecklistFlyoutStep } from './checklist_step'; +import { WarningsFlyoutStep } from './warnings_step'; + +enum ReindexFlyoutStep { + reindexWarnings, + checklist, +} + +export interface ReindexFlyoutProps extends ReindexStateContext { + deprecation: EnrichedDeprecationInfo; + closeFlyout: () => void; +} + +const getOpenAndCloseIndexDocLink = (docLinks: DocLinksStart) => ( + + {i18n.translate( + 'xpack.upgradeAssistant.checkupTab.reindexing.flyout.openAndCloseDocumentation', + { defaultMessage: 'documentation' } + )} + +); + +const getIndexClosedCallout = (docLinks: DocLinksStart) => ( + <> + +

+ + {i18n.translate( + 'xpack.upgradeAssistant.checkupTab.reindexing.flyout.indexClosedCallout.calloutDetails.reindexingTakesLongerEmphasis', + { defaultMessage: 'Reindexing may take longer than usual' } + )} + + ), + }} + /> +

+
+ + +); + +export const ReindexFlyout: React.FunctionComponent = ({ + reindexState, + startReindex, + cancelReindex, + closeFlyout, + deprecation, +}) => { + const { status, reindexWarnings } = reindexState; + const { index, correctiveAction } = deprecation; + const { docLinks } = useAppContext(); + // If there are any warnings and we haven't started reindexing, show the warnings step first. + const [currentFlyoutStep, setCurrentFlyoutStep] = useState( + reindexWarnings && reindexWarnings.length > 0 && status === undefined + ? ReindexFlyoutStep.reindexWarnings + : ReindexFlyoutStep.checklist + ); + + let flyoutContents: React.ReactNode; + + const globalCallout = + (correctiveAction as ReindexAction).blockerForReindexing === 'index-closed' && + reindexState.status !== ReindexStatus.completed + ? getIndexClosedCallout(docLinks) + : undefined; + switch (currentFlyoutStep) { + case ReindexFlyoutStep.reindexWarnings: + flyoutContents = ( + globalCallout} + closeFlyout={closeFlyout} + warnings={reindexState.reindexWarnings!} + advanceNextStep={() => setCurrentFlyoutStep(ReindexFlyoutStep.checklist)} + /> + ); + break; + case ReindexFlyoutStep.checklist: + flyoutContents = ( + globalCallout} + closeFlyout={closeFlyout} + reindexState={reindexState} + startReindex={startReindex} + cancelReindex={cancelReindex} + /> + ); + break; + default: + throw new Error(`Invalid flyout step: ${currentFlyoutStep}`); + } + + return ( + <> + + +

+ +

+
+
+ {flyoutContents} + + ); +}; diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/flyout/index.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/flyout/index.tsx new file mode 100644 index 0000000000000..6b9eee80acb57 --- /dev/null +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/flyout/index.tsx @@ -0,0 +1,8 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export { ReindexFlyout, ReindexFlyoutProps } from './container'; diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/flyout/progress.test.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/flyout/progress.test.tsx similarity index 99% rename from x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/flyout/progress.test.tsx rename to x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/flyout/progress.test.tsx index 24a00af7a9fee..b49d816302213 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/flyout/progress.test.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/flyout/progress.test.tsx @@ -9,7 +9,7 @@ import { shallow } from 'enzyme'; import React from 'react'; import { IndexGroup, ReindexStatus, ReindexStep } from '../../../../../../../common/types'; -import { ReindexState } from '../polling_service'; +import type { ReindexState } from '../use_reindex_state'; import { ReindexProgress } from './progress'; describe('ReindexProgress', () => { diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/flyout/progress.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/flyout/progress.tsx similarity index 99% rename from x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/flyout/progress.tsx rename to x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/flyout/progress.tsx index 088266f3a4840..65a790fe96691 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/flyout/progress.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/flyout/progress.tsx @@ -19,7 +19,7 @@ import { FormattedMessage } from '@kbn/i18n/react'; import { IndexGroup, ReindexStatus, ReindexStep } from '../../../../../../../common/types'; import { LoadingState } from '../../../../types'; -import { ReindexState } from '../polling_service'; +import type { ReindexState } from '../use_reindex_state'; import { StepProgress, StepProgressStep } from './step_progress'; const ErrorCallout: React.FunctionComponent<{ errorMessage: string | null }> = ({ diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/flyout/step_progress.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/flyout/step_progress.tsx similarity index 100% rename from x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/flyout/step_progress.tsx rename to x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/flyout/step_progress.tsx diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/flyout/warning_step.test.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/flyout/warning_step.test.tsx similarity index 100% rename from x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/flyout/warning_step.test.tsx rename to x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/flyout/warning_step.test.tsx diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/flyout/warning_step_checkbox.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/flyout/warning_step_checkbox.tsx similarity index 100% rename from x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/flyout/warning_step_checkbox.tsx rename to x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/flyout/warning_step_checkbox.tsx diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/flyout/warnings_step.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/flyout/warnings_step.tsx similarity index 100% rename from x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/flyout/warnings_step.tsx rename to x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/flyout/warnings_step.tsx diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/index.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/index.tsx similarity index 84% rename from x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/index.tsx rename to x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/index.tsx index 6fbb38b04bbd6..bbb1493f15bcc 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/index.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/index.tsx @@ -5,4 +5,4 @@ * 2.0. */ -export { ReindexButton } from './button'; +export { ReindexTableRow } from './table_row'; diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/resolution_table_cell.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/resolution_table_cell.tsx new file mode 100644 index 0000000000000..6ea9a0277059a --- /dev/null +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/resolution_table_cell.tsx @@ -0,0 +1,158 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { i18n } from '@kbn/i18n'; + +import { + EuiIcon, + EuiLoadingSpinner, + EuiText, + EuiFlexGroup, + EuiFlexItem, + EuiToolTip, +} from '@elastic/eui'; +import { ReindexStatus } from '../../../../../../common/types'; +import { LoadingState } from '../../../types'; +import { useReindexContext } from './context'; + +const i18nTexts = { + reindexLoadingStatusText: i18n.translate( + 'xpack.upgradeAssistant.esDeprecations.reindex.reindexLoadingStatusText', + { + defaultMessage: 'Loading status…', + } + ), + reindexInProgressText: i18n.translate( + 'xpack.upgradeAssistant.esDeprecations.reindex.reindexInProgressText', + { + defaultMessage: 'Reindexing in progress…', + } + ), + reindexCompleteText: i18n.translate( + 'xpack.upgradeAssistant.esDeprecations.reindex.reindexCompleteText', + { + defaultMessage: 'Reindex complete', + } + ), + reindexFailedText: i18n.translate( + 'xpack.upgradeAssistant.esDeprecations.reindex.reindexFailedText', + { + defaultMessage: 'Reindex failed', + } + ), + reindexCanceledText: i18n.translate( + 'xpack.upgradeAssistant.esDeprecations.reindex.reindexCanceledText', + { + defaultMessage: 'Reindex canceled', + } + ), + reindexPausedText: i18n.translate( + 'xpack.upgradeAssistant.esDeprecations.reindex.reindexPausedText', + { + defaultMessage: 'Reindex paused', + } + ), + resolutionText: i18n.translate('xpack.upgradeAssistant.esDeprecations.reindex.resolutionLabel', { + defaultMessage: 'Reindex', + }), + resolutionTooltipLabel: i18n.translate( + 'xpack.upgradeAssistant.esDeprecations.reindex.resolutionTooltipLabel', + { + defaultMessage: + 'Resolve this deprecation by reindexing this index. This is an automated resolution.', + } + ), +}; + +export const ReindexResolutionCell: React.FunctionComponent = () => { + const { reindexState } = useReindexContext(); + + if (reindexState.loadingState === LoadingState.Loading) { + return ( + + + + + + {i18nTexts.reindexLoadingStatusText} + + + ); + } + + switch (reindexState.status) { + case ReindexStatus.inProgress: + return ( + + + + + + {i18nTexts.reindexInProgressText} + + + ); + case ReindexStatus.completed: + return ( + + + + + + {i18nTexts.reindexCompleteText} + + + ); + case ReindexStatus.failed: + return ( + + + + + + {i18nTexts.reindexFailedText} + + + ); + case ReindexStatus.paused: + return ( + + + + + + {i18nTexts.reindexPausedText} + + + ); + case ReindexStatus.cancelled: + return ( + + + + + + {i18nTexts.reindexCanceledText} + + + ); + } + + return ( + + + + + + + {i18nTexts.resolutionText} + + + + ); +}; diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/table_row.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/table_row.tsx new file mode 100644 index 0000000000000..95d65f1e77771 --- /dev/null +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/table_row.tsx @@ -0,0 +1,104 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useState, useEffect, useCallback } from 'react'; +import { EuiTableRowCell } from '@elastic/eui'; +import { EnrichedDeprecationInfo } from '../../../../../../common/types'; +import { GlobalFlyout } from '../../../../../shared_imports'; +import { useAppContext } from '../../../../app_context'; +import { DeprecationTableColumns } from '../../../types'; +import { EsDeprecationsTableCells } from '../../es_deprecations_table_cells'; +import { ReindexResolutionCell } from './resolution_table_cell'; +import { ReindexFlyout, ReindexFlyoutProps } from './flyout'; +import { ReindexStatusProvider, useReindexContext } from './context'; + +const { useGlobalFlyout } = GlobalFlyout; + +interface TableRowProps { + deprecation: EnrichedDeprecationInfo; + rowFieldNames: DeprecationTableColumns[]; +} + +const ReindexTableRowCells: React.FunctionComponent = ({ + rowFieldNames, + deprecation, +}) => { + const [showFlyout, setShowFlyout] = useState(false); + const reindexState = useReindexContext(); + const { api } = useAppContext(); + + const { + addContent: addContentToGlobalFlyout, + removeContent: removeContentFromGlobalFlyout, + } = useGlobalFlyout(); + + const closeFlyout = useCallback(async () => { + removeContentFromGlobalFlyout('reindexFlyout'); + setShowFlyout(false); + await api.sendReindexTelemetryData({ close: true }); + }, [api, removeContentFromGlobalFlyout]); + + useEffect(() => { + if (showFlyout) { + addContentToGlobalFlyout({ + id: 'reindexFlyout', + Component: ReindexFlyout, + props: { + deprecation, + closeFlyout, + ...reindexState, + }, + flyoutProps: { + onClose: closeFlyout, + 'data-test-subj': 'reindexDetails', + 'aria-labelledby': 'reindexDetailsFlyoutTitle', + }, + }); + } + }, [addContentToGlobalFlyout, deprecation, showFlyout, reindexState, closeFlyout]); + + useEffect(() => { + if (showFlyout) { + async function sendTelemetry() { + await api.sendReindexTelemetryData({ open: true }); + } + + sendTelemetry(); + } + }, [showFlyout, api]); + + return ( + <> + {rowFieldNames.map((field: DeprecationTableColumns) => { + return ( + + setShowFlyout(true)} + deprecation={deprecation} + resolutionTableCell={} + /> + + ); + })} + + ); +}; + +export const ReindexTableRow: React.FunctionComponent = (props) => { + const { api } = useAppContext(); + + return ( + + + + ); +}; diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/use_reindex_state.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/use_reindex_state.tsx new file mode 100644 index 0000000000000..b87a509d25a55 --- /dev/null +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/use_reindex_state.tsx @@ -0,0 +1,187 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { useRef, useCallback, useState, useEffect } from 'react'; + +import { + IndexGroup, + ReindexOperation, + ReindexStatus, + ReindexStep, + ReindexWarning, +} from '../../../../../../common/types'; +import { LoadingState } from '../../../types'; +import { ApiService } from '../../../../lib/api'; + +const POLL_INTERVAL = 1000; + +export interface ReindexState { + loadingState: LoadingState; + cancelLoadingState?: LoadingState; + lastCompletedStep?: ReindexStep; + status?: ReindexStatus; + reindexTaskPercComplete: number | null; + errorMessage: string | null; + reindexWarnings?: ReindexWarning[]; + hasRequiredPrivileges?: boolean; + indexGroup?: IndexGroup; +} + +interface StatusResponse { + warnings?: ReindexWarning[]; + reindexOp?: ReindexOperation; + hasRequiredPrivileges?: boolean; + indexGroup?: IndexGroup; +} + +const getReindexState = ( + reindexState: ReindexState, + { reindexOp, warnings, hasRequiredPrivileges, indexGroup }: StatusResponse +) => { + const newReindexState = { + ...reindexState, + loadingState: LoadingState.Success, + }; + + if (warnings) { + newReindexState.reindexWarnings = warnings; + } + + if (hasRequiredPrivileges !== undefined) { + newReindexState.hasRequiredPrivileges = hasRequiredPrivileges; + } + + if (indexGroup) { + newReindexState.indexGroup = indexGroup; + } + + if (reindexOp) { + // Prevent the UI flickering back to inProgress after cancelling + newReindexState.lastCompletedStep = reindexOp.lastCompletedStep; + newReindexState.status = reindexOp.status; + newReindexState.reindexTaskPercComplete = reindexOp.reindexTaskPercComplete; + newReindexState.errorMessage = reindexOp.errorMessage; + + if (reindexOp.status === ReindexStatus.cancelled) { + newReindexState.cancelLoadingState = LoadingState.Success; + } + } + + return newReindexState; +}; + +export const useReindexStatus = ({ indexName, api }: { indexName: string; api: ApiService }) => { + const [reindexState, setReindexState] = useState({ + loadingState: LoadingState.Loading, + errorMessage: null, + reindexTaskPercComplete: null, + }); + + const pollIntervalIdRef = useRef | null>(null); + const isMounted = useRef(false); + + const clearPollInterval = useCallback(() => { + if (pollIntervalIdRef.current) { + clearTimeout(pollIntervalIdRef.current); + pollIntervalIdRef.current = null; + } + }, []); + + const updateStatus = useCallback(async () => { + clearPollInterval(); + + const { data, error } = await api.getReindexStatus(indexName); + + if (error) { + setReindexState({ + ...reindexState, + loadingState: LoadingState.Error, + status: ReindexStatus.failed, + }); + return; + } + + setReindexState(getReindexState(reindexState, data)); + + // Only keep polling if it exists and is in progress. + if (data.reindexOp && data.reindexOp.status === ReindexStatus.inProgress) { + pollIntervalIdRef.current = setTimeout(updateStatus, POLL_INTERVAL); + } + }, [clearPollInterval, api, indexName, reindexState]); + + const startReindex = useCallback(async () => { + const currentReindexState = { + ...reindexState, + }; + + setReindexState({ + ...currentReindexState, + // Only reset last completed step if we aren't currently paused + lastCompletedStep: + currentReindexState.status === ReindexStatus.paused + ? currentReindexState.lastCompletedStep + : undefined, + status: ReindexStatus.inProgress, + reindexTaskPercComplete: null, + errorMessage: null, + cancelLoadingState: undefined, + }); + + api.sendReindexTelemetryData({ start: true }); + + const { data, error } = await api.startReindexTask(indexName); + + if (error) { + setReindexState({ + ...reindexState, + loadingState: LoadingState.Error, + status: ReindexStatus.failed, + }); + return; + } + + setReindexState(getReindexState(reindexState, data)); + updateStatus(); + }, [api, indexName, reindexState, updateStatus]); + + const cancelReindex = useCallback(async () => { + api.sendReindexTelemetryData({ stop: true }); + + const { error } = await api.cancelReindexTask(indexName); + + setReindexState({ + ...reindexState, + cancelLoadingState: LoadingState.Loading, + }); + + if (error) { + setReindexState({ + ...reindexState, + cancelLoadingState: LoadingState.Error, + }); + return; + } + }, [api, indexName, reindexState]); + + useEffect(() => { + isMounted.current = true; + + return () => { + isMounted.current = false; + + // Clean up on unmount. + clearPollInterval(); + }; + }, [clearPollInterval]); + + return { + reindexState, + startReindex, + cancelReindex, + updateStatus, + }; +}; diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/_cell.scss b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/_cell.scss deleted file mode 100644 index e53fd9b254cf0..0000000000000 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/_cell.scss +++ /dev/null @@ -1,4 +0,0 @@ -.upgDeprecationCell { - overflow: hidden; - padding: $euiSize 0 0 $euiSizeL; -} diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/cell.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/cell.tsx deleted file mode 100644 index 4324379f456ea..0000000000000 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/cell.tsx +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React, { ReactNode, FunctionComponent } from 'react'; - -import { - EuiFlexGroup, - EuiFlexItem, - EuiIcon, - EuiLink, - EuiSpacer, - EuiText, - EuiTitle, -} from '@elastic/eui'; -import { FormattedMessage } from '@kbn/i18n/react'; -import { - EnrichedDeprecationInfo, - MlAction, - ReindexAction, - IndexSettingAction, -} from '../../../../../common/types'; -import { AppContext } from '../../../app_context'; -import { ReindexButton } from './reindex'; -import { FixIndexSettingsButton } from './index_settings'; -import { FixMlSnapshotsButton } from './ml_snapshots'; - -interface DeprecationCellProps { - items?: Array<{ title?: string; body: string }>; - docUrl?: string; - headline?: string; - healthColor?: string; - children?: ReactNode; - correctiveAction?: EnrichedDeprecationInfo['correctiveAction']; - indexName?: string; -} - -interface CellActionProps { - correctiveAction: EnrichedDeprecationInfo['correctiveAction']; - indexName?: string; - items: Array<{ title?: string; body: string }>; -} - -const CellAction: FunctionComponent = ({ correctiveAction, indexName, items }) => { - const { type: correctiveActionType } = correctiveAction!; - switch (correctiveActionType) { - case 'mlSnapshot': - const { jobId, snapshotId } = correctiveAction as MlAction; - return ( - - ); - - case 'reindex': - const { blockerForReindexing } = correctiveAction as ReindexAction; - - return ( - - {({ http, docLinks }) => ( - - )} - - ); - - case 'indexSetting': - const { deprecatedSettings } = correctiveAction as IndexSettingAction; - - return ; - - default: - throw new Error(`No UI defined for corrective action: ${correctiveActionType}`); - } -}; - -/** - * Used to display a deprecation with links to docs, a health indicator, and other descriptive information. - */ -export const DeprecationCell: FunctionComponent = ({ - headline, - healthColor, - correctiveAction, - indexName, - docUrl, - items = [], - children, -}) => ( -
- - {healthColor && ( - - - - )} - - - {headline && ( - -

{headline}

-
- )} - - {items.map((item, index) => ( - - {item.title &&
{item.title}
} -

{item.body}

-
- ))} - - {docUrl && ( - <> - - - - - - - )} -
- - {correctiveAction && ( - - - - )} -
- - - - {children} -
-); diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/deprecation_group_item.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/deprecation_group_item.tsx deleted file mode 100644 index 66e2a5d25998b..0000000000000 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/deprecation_group_item.tsx +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ -import React, { FunctionComponent } from 'react'; -import { EuiAccordion, EuiBadge } from '@elastic/eui'; -import { FormattedMessage } from '@kbn/i18n/react'; - -import { EnrichedDeprecationInfo } from '../../../../../common/types'; -import { DeprecationHealth } from '../../shared'; -import { GroupByOption } from '../../types'; -import { EsDeprecationList } from './list'; -import { LEVEL_MAP } from '../../constants'; - -export interface Props { - id: string; - deprecations: EnrichedDeprecationInfo[]; - title: string; - currentGroupBy: GroupByOption; - forceExpand: boolean; - dataTestSubj: string; -} - -/** - * A single accordion item for a grouped deprecation item. - */ -export const EsDeprecationAccordion: FunctionComponent = ({ - id, - deprecations, - title, - currentGroupBy, - forceExpand, - dataTestSubj, -}) => { - const hasIndices = Boolean( - currentGroupBy === GroupByOption.message && - (deprecations as EnrichedDeprecationInfo[]).filter((d) => d.index).length - ); - const numIndices = hasIndices ? deprecations.length : null; - - return ( - - {hasIndices && ( - <> - - {numIndices}{' '} - - -   - - )} - LEVEL_MAP[d.level])} - /> -
- } - > - - - ); -}; diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/index_settings/button.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/index_settings/button.tsx deleted file mode 100644 index e63e26f3ecc61..0000000000000 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/index_settings/button.tsx +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; - -import { EuiButton } from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; - -import { RemoveIndexSettingsProvider } from './remove_settings_provider'; - -const i18nTexts = { - fixButtonLabel: i18n.translate('xpack.upgradeAssistant.checkupTab.indexSettings.fixButtonLabel', { - defaultMessage: 'Fix', - }), - doneButtonLabel: i18n.translate( - 'xpack.upgradeAssistant.checkupTab.indexSettings.doneButtonLabel', - { - defaultMessage: 'Done', - } - ), -}; - -interface Props { - settings: string[]; - index: string; -} - -/** - * Renders a button if the given index contains deprecated index settings - */ -export const FixIndexSettingsButton: React.FunctionComponent = ({ settings, index }) => { - return ( - - {(removeIndexSettingsPrompt, successfulRequests) => { - const isSuccessfulRequest = successfulRequests[index] === true; - return ( - removeIndexSettingsPrompt(index, settings)} - isDisabled={isSuccessfulRequest} - iconType={isSuccessfulRequest ? 'check' : undefined} - > - {isSuccessfulRequest ? i18nTexts.doneButtonLabel : i18nTexts.fixButtonLabel} - - ); - }} - - ); -}; diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/index_settings/remove_settings_provider.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/index_settings/remove_settings_provider.tsx deleted file mode 100644 index 1fd0c79dbbef3..0000000000000 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/index_settings/remove_settings_provider.tsx +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React, { useState, useRef } from 'react'; -import { i18n } from '@kbn/i18n'; -import { EuiCode, EuiConfirmModal } from '@elastic/eui'; -import { useAppContext } from '../../../../app_context'; - -interface Props { - children: ( - removeSettingsPrompt: (index: string, settings: string[]) => void, - successfulRequests: { [key: string]: boolean } - ) => React.ReactNode; -} - -const i18nTexts = { - removeButtonLabel: i18n.translate( - 'xpack.upgradeAssistant.checkupTab.confirmationModal.removeButtonLabel', - { - defaultMessage: 'Remove', - } - ), - cancelButtonLabel: i18n.translate( - 'xpack.upgradeAssistant.checkupTab.indexSettings.confirmationModal.cancelButtonLabel', - { - defaultMessage: 'Cancel', - } - ), - modalDescription: i18n.translate( - 'xpack.upgradeAssistant.checkupTab.indexSettings.confirmationModal.description', - { - defaultMessage: 'The following deprecated index settings were detected and will be removed:', - } - ), - successNotificationText: i18n.translate( - 'xpack.upgradeAssistant.checkupTab.indexSettings.confirmationModal.successNotificationText', - { - defaultMessage: 'Index settings removed', - } - ), - errorNotificationText: i18n.translate( - 'xpack.upgradeAssistant.checkupTab.indexSettings.confirmationModal.errorNotificationText', - { - defaultMessage: 'Error removing index settings', - } - ), -}; - -export const RemoveIndexSettingsProvider = ({ children }: Props) => { - const [isModalOpen, setIsModalOpen] = useState(false); - const [successfulRequests, setSuccessfulRequests] = useState<{ [key: string]: boolean }>({}); - const [isLoading, setIsLoading] = useState(false); - - const deprecatedSettings = useRef([]); - const indexName = useRef(undefined); - - const { api, notifications } = useAppContext(); - - const removeIndexSettings = async () => { - setIsLoading(true); - - const { error } = await api.updateIndexSettings(indexName.current!, deprecatedSettings.current); - - setIsLoading(false); - closeModal(); - - if (error) { - notifications.toasts.addDanger(i18nTexts.errorNotificationText); - } else { - setSuccessfulRequests({ - [indexName.current!]: true, - }); - notifications.toasts.addSuccess(i18nTexts.successNotificationText); - } - }; - - const closeModal = () => { - setIsModalOpen(false); - }; - - const removeSettingsPrompt = (index: string, settings: string[]) => { - setIsModalOpen(true); - setSuccessfulRequests({ - [index]: false, - }); - indexName.current = index; - deprecatedSettings.current = settings; - }; - - return ( - <> - {children(removeSettingsPrompt, successfulRequests)} - - {isModalOpen && ( - - <> -

{i18nTexts.modalDescription}

-
    - {deprecatedSettings.current.map((setting, index) => ( -
  • - {setting} -
  • - ))} -
- -
- )} - - ); -}; diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/index_table.test.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/index_table.test.tsx deleted file mode 100644 index f4ac573d86b11..0000000000000 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/index_table.test.tsx +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; -import { shallow } from 'enzyme'; - -import { IndexDeprecationTableProps, IndexDeprecationTable } from './index_table'; - -describe('IndexDeprecationTable', () => { - const defaultProps = { - indices: [ - { index: 'index1', details: 'Index 1 deets', correctiveAction: { type: 'reindex' } }, - { index: 'index2', details: 'Index 2 deets', correctiveAction: { type: 'reindex' } }, - { index: 'index3', details: 'Index 3 deets', correctiveAction: { type: 'reindex' } }, - ], - } as IndexDeprecationTableProps; - - // Relying pretty heavily on EUI to implement the table functionality correctly. - // This test simply verifies that the props passed to EuiBaseTable are the ones - // expected. - test('render', () => { - expect(shallow()).toMatchInlineSnapshot(` - - `); - }); -}); diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/index_table.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/index_table.tsx deleted file mode 100644 index 6b0f94ea24bc7..0000000000000 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/index_table.tsx +++ /dev/null @@ -1,200 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { sortBy } from 'lodash'; -import React from 'react'; - -import { EuiBasicTable } from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; -import { - EnrichedDeprecationInfo, - IndexSettingAction, - ReindexAction, -} from '../../../../../common/types'; -import { AppContext } from '../../../app_context'; -import { ReindexButton } from './reindex'; -import { FixIndexSettingsButton } from './index_settings'; - -const PAGE_SIZES = [10, 25, 50, 100, 250, 500, 1000]; - -export interface IndexDeprecationDetails { - index: string; - correctiveAction?: EnrichedDeprecationInfo['correctiveAction']; - details?: string; -} - -export interface IndexDeprecationTableProps { - indices: IndexDeprecationDetails[]; -} - -interface IndexDeprecationTableState { - sortField: string; - sortDirection: 'asc' | 'desc'; - pageIndex: number; - pageSize: number; -} - -export class IndexDeprecationTable extends React.Component< - IndexDeprecationTableProps, - IndexDeprecationTableState -> { - constructor(props: IndexDeprecationTableProps) { - super(props); - - this.state = { - sortField: 'index', - sortDirection: 'asc', - pageIndex: 0, - pageSize: 10, - }; - } - - public render() { - const { pageIndex, pageSize, sortField, sortDirection } = this.state; - - const columns = [ - { - field: 'index', - name: i18n.translate( - 'xpack.upgradeAssistant.checkupTab.deprecations.indexTable.indexColumnLabel', - { - defaultMessage: 'Index', - } - ), - sortable: true, - }, - { - field: 'details', - name: i18n.translate( - 'xpack.upgradeAssistant.checkupTab.deprecations.indexTable.detailsColumnLabel', - { - defaultMessage: 'Details', - } - ), - }, - ]; - - const actionsColumn = this.generateActionsColumn(); - - if (actionsColumn) { - columns.push(actionsColumn as any); - } - - const sorting = { - sort: { field: sortField as keyof IndexDeprecationDetails, direction: sortDirection }, - }; - const pagination = { - pageIndex, - pageSize, - ...this.pageSizeOptions(), - }; - - return ( - { - return { - 'data-test-subj': `indexTableRow-${indexDetails.index}`, - }; - }} - /> - ); - } - - private getRows() { - const { sortField, sortDirection, pageIndex, pageSize } = this.state; - const { indices } = this.props; - - let sorted = sortBy(indices, sortField); - if (sortDirection === 'desc') { - sorted = sorted.reverse(); - } - - const start = pageIndex * pageSize; - return sorted.slice(start, start + pageSize); - } - - private onTableChange = (tableProps: any) => { - this.setState({ - sortField: tableProps.sort.field, - sortDirection: tableProps.sort.direction, - pageIndex: tableProps.page.index, - pageSize: tableProps.page.size, - }); - }; - - private pageSizeOptions() { - const { indices } = this.props; - const totalItemCount = indices.length; - - // If we only have that smallest page size, don't show any page size options. - if (totalItemCount <= PAGE_SIZES[0]) { - return { totalItemCount, pageSizeOptions: [], hidePerPageOptions: true }; - } - - // Keep a size option if the # of items is larger than the previous option. - // This avoids having a long list of useless page sizes. - const pageSizeOptions = PAGE_SIZES.filter((perPage, idx) => { - return idx === 0 || totalItemCount > PAGE_SIZES[idx - 1]; - }); - - return { totalItemCount, pageSizeOptions, hidePerPageOptions: false }; - } - - private generateActionsColumn() { - // NOTE: this naive implementation assumes all indices in the table - // should show the reindex button or fix indices button. This should work for known use cases. - const { indices } = this.props; - const showReindexButton = Boolean(indices.find((i) => i.correctiveAction?.type === 'reindex')); - const showFixSettingsButton = Boolean( - indices.find((i) => i.correctiveAction?.type === 'indexSetting') - ); - - if (showReindexButton === false && showFixSettingsButton === false) { - return null; - } - - return { - actions: [ - { - render(indexDep: IndexDeprecationDetails) { - if (showReindexButton) { - return ( - - {({ http, docLinks }) => { - return ( - - ); - }} - - ); - } - - return ( - - ); - }, - }, - ], - }; - } -} diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/list.test.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/list.test.tsx deleted file mode 100644 index 2bfa8119e41bc..0000000000000 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/list.test.tsx +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { shallow } from 'enzyme'; -import React from 'react'; - -import { EnrichedDeprecationInfo } from '../../../../../common/types'; -import { GroupByOption } from '../../types'; -import { EsDeprecationList } from './list'; - -describe('EsDeprecationList', () => { - describe('group by message', () => { - const defaultProps = { - deprecations: [ - { message: 'Issue 1', url: '', level: 'warning' }, - { message: 'Issue 1', url: '', level: 'warning' }, - ] as EnrichedDeprecationInfo[], - currentGroupBy: GroupByOption.message, - }; - - test('shows simple messages when index field is not present', () => { - expect(shallow()).toMatchInlineSnapshot(` -
- - -
- `); - }); - - test('shows index deprecation when index field is present', () => { - // Add index fields to deprecation items - const props = { - ...defaultProps, - deprecations: defaultProps.deprecations.map((d, index) => ({ - ...d, - index: index.toString(), - })), - }; - const wrapper = shallow(); - expect(wrapper).toMatchInlineSnapshot(` - - `); - }); - }); - - describe('group by index', () => { - const defaultProps = { - deprecations: [ - { message: 'Issue 1', index: 'index1', url: '', level: 'warning' }, - { message: 'Issue 2', index: 'index1', url: '', level: 'warning' }, - ] as EnrichedDeprecationInfo[], - currentGroupBy: GroupByOption.index, - }; - - test('shows detailed messages', () => { - expect(shallow()).toMatchInlineSnapshot(` -
- - -
- `); - }); - }); -}); diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/list.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/list.tsx deleted file mode 100644 index 7b543a7e94b33..0000000000000 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/list.tsx +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React, { FunctionComponent } from 'react'; - -import { DeprecationInfo, EnrichedDeprecationInfo } from '../../../../../common/types'; -import { GroupByOption } from '../../types'; - -import { COLOR_MAP, LEVEL_MAP } from '../../constants'; -import { DeprecationCell } from './cell'; -import { IndexDeprecationDetails, IndexDeprecationTable } from './index_table'; - -const sortByLevelDesc = (a: DeprecationInfo, b: DeprecationInfo) => { - return -1 * (LEVEL_MAP[a.level] - LEVEL_MAP[b.level]); -}; - -/** - * Used to show a single deprecation message with any detailed information. - */ -const MessageDeprecation: FunctionComponent<{ - deprecation: EnrichedDeprecationInfo; -}> = ({ deprecation }) => { - const items = []; - - if (deprecation.details) { - items.push({ body: deprecation.details }); - } - - return ( - - ); -}; - -/** - * Used to show a single (simple) deprecation message with any detailed information. - */ -const SimpleMessageDeprecation: FunctionComponent<{ deprecation: EnrichedDeprecationInfo }> = ({ - deprecation, -}) => { - const items = []; - - if (deprecation.details) { - items.push({ body: deprecation.details }); - } - - return ( - - ); -}; - -interface IndexDeprecationProps { - deprecation: EnrichedDeprecationInfo; - indices: IndexDeprecationDetails[]; -} - -/** - * Shows a single deprecation and table of affected indices with details for each index. - */ -const IndexDeprecation: FunctionComponent = ({ deprecation, indices }) => { - return ( - - - - ); -}; - -/** - * A list of deprecations that is either shown as individual deprecation cells or as a - * deprecation summary for a list of indices. - */ -export const EsDeprecationList: FunctionComponent<{ - deprecations: EnrichedDeprecationInfo[]; - currentGroupBy: GroupByOption; -}> = ({ deprecations, currentGroupBy }) => { - // If we're grouping by message and the first deprecation has an index field, show an index - // group deprecation. Otherwise, show each message. - if (currentGroupBy === GroupByOption.message && deprecations[0].index !== undefined) { - // We assume that every deprecation message is the same issue (since they have the same - // message) and that each deprecation will have an index associated with it. - - const indices = deprecations.map((dep) => ({ - index: dep.index!, - details: dep.details, - correctiveAction: dep.correctiveAction, - })); - return ; - } else if (currentGroupBy === GroupByOption.index) { - return ( -
- {deprecations.sort(sortByLevelDesc).map((dep, index) => ( - - ))} -
- ); - } else { - return ( -
- {deprecations.sort(sortByLevelDesc).map((dep, index) => ( - - ))} -
- ); - } -}; diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/ml_snapshots/button.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/ml_snapshots/button.tsx deleted file mode 100644 index 13b7dacc3b598..0000000000000 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/ml_snapshots/button.tsx +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React, { useEffect, useState } from 'react'; - -import { ButtonSize, EuiButton } from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; - -import { FixSnapshotsFlyout } from './fix_snapshots_flyout'; -import { useAppContext } from '../../../../app_context'; -import { useSnapshotState } from './use_snapshot_state'; - -const i18nTexts = { - fixButtonLabel: i18n.translate( - 'xpack.upgradeAssistant.esDeprecations.mlSnapshots.fixButtonLabel', - { - defaultMessage: 'Fix', - } - ), - upgradingButtonLabel: i18n.translate( - 'xpack.upgradeAssistant.esDeprecations.mlSnapshots.upgradingButtonLabel', - { - defaultMessage: 'Upgrading…', - } - ), - deletingButtonLabel: i18n.translate( - 'xpack.upgradeAssistant.esDeprecations.mlSnapshots.deletingButtonLabel', - { - defaultMessage: 'Deleting…', - } - ), - doneButtonLabel: i18n.translate( - 'xpack.upgradeAssistant.esDeprecations.mlSnapshots.doneButtonLabel', - { - defaultMessage: 'Done', - } - ), - failedButtonLabel: i18n.translate( - 'xpack.upgradeAssistant.esDeprecations.mlSnapshots.failedButtonLabel', - { - defaultMessage: 'Failed', - } - ), -}; - -interface Props { - snapshotId: string; - jobId: string; - description: string; -} - -export const FixMlSnapshotsButton: React.FunctionComponent = ({ - snapshotId, - jobId, - description, -}) => { - const { api } = useAppContext(); - const { snapshotState, upgradeSnapshot, deleteSnapshot, updateSnapshotStatus } = useSnapshotState( - { - jobId, - snapshotId, - api, - } - ); - - const [showFlyout, setShowFlyout] = useState(false); - - useEffect(() => { - updateSnapshotStatus(); - }, [updateSnapshotStatus]); - - const commonButtonProps = { - size: 's' as ButtonSize, - onClick: () => setShowFlyout(true), - 'data-test-subj': 'fixMlSnapshotsButton', - }; - - let button = {i18nTexts.fixButtonLabel}; - - switch (snapshotState.status) { - case 'in_progress': - button = ( - - {snapshotState.action === 'delete' - ? i18nTexts.deletingButtonLabel - : i18nTexts.upgradingButtonLabel} - - ); - break; - case 'complete': - button = ( - - {i18nTexts.doneButtonLabel} - - ); - break; - case 'error': - button = ( - - {i18nTexts.failedButtonLabel} - - ); - break; - } - - return ( - <> - {button} - - {showFlyout && ( - setShowFlyout(false)} - /> - )} - - ); -}; diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/_button.scss b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/_button.scss deleted file mode 100644 index f12149f9e88cb..0000000000000 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/_button.scss +++ /dev/null @@ -1,5 +0,0 @@ -.upgReindexButton__spinner { - position: relative; - top: $euiSizeXS / 2; - margin-right: $euiSizeXS; -} diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/button.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/button.tsx deleted file mode 100644 index fafdf504ee602..0000000000000 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/button.tsx +++ /dev/null @@ -1,245 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { set } from '@elastic/safer-lodash-set'; -import React, { Fragment, ReactNode } from 'react'; -import { i18n } from '@kbn/i18n'; -import { Subscription } from 'rxjs'; - -import { EuiButton, EuiLoadingSpinner, EuiText, EuiToolTip } from '@elastic/eui'; -import { FormattedMessage } from '@kbn/i18n/react'; -import { DocLinksStart, HttpSetup } from 'src/core/public'; -import { API_BASE_PATH } from '../../../../../../common/constants'; -import { ReindexAction, ReindexStatus, UIReindexOption } from '../../../../../../common/types'; -import { LoadingState } from '../../../types'; -import { ReindexFlyout } from './flyout'; -import { ReindexPollingService, ReindexState } from './polling_service'; - -interface ReindexButtonProps { - indexName: string; - http: HttpSetup; - docLinks: DocLinksStart; - reindexBlocker?: ReindexAction['blockerForReindexing']; -} - -interface ReindexButtonState { - flyoutVisible: boolean; - reindexState: ReindexState; -} - -/** - * Displays a button that will display a flyout when clicked with the reindexing status for - * the given `indexName`. - */ -export class ReindexButton extends React.Component { - private service: ReindexPollingService; - private subscription?: Subscription; - - constructor(props: ReindexButtonProps) { - super(props); - - this.service = this.newService(); - this.state = { - flyoutVisible: false, - reindexState: this.service.status$.value, - }; - } - - public async componentDidMount() { - this.subscribeToUpdates(); - } - - public async componentWillUnmount() { - this.unsubscribeToUpdates(); - } - - public componentDidUpdate(prevProps: ReindexButtonProps) { - if (prevProps.indexName !== this.props.indexName) { - this.unsubscribeToUpdates(); - this.service = this.newService(); - this.subscribeToUpdates(); - } - } - - public render() { - const { indexName, reindexBlocker, docLinks } = this.props; - const { flyoutVisible, reindexState } = this.state; - - const buttonProps: any = { size: 's', onClick: this.showFlyout }; - let buttonContent: ReactNode = ( - - ); - - if (reindexState.loadingState === LoadingState.Loading) { - buttonProps.disabled = true; - buttonContent = ( - - ); - } else { - switch (reindexState.status) { - case ReindexStatus.inProgress: - buttonContent = ( - - Reindexing… - - ); - break; - case ReindexStatus.completed: - buttonProps.color = 'secondary'; - buttonProps.iconSide = 'left'; - buttonProps.iconType = 'check'; - buttonContent = ( - - ); - break; - case ReindexStatus.failed: - buttonProps.color = 'danger'; - buttonProps.iconSide = 'left'; - buttonProps.iconType = 'cross'; - buttonContent = ( - - ); - break; - case ReindexStatus.paused: - buttonProps.color = 'warning'; - buttonProps.iconSide = 'left'; - buttonProps.iconType = 'pause'; - buttonContent = ( - - ); - case ReindexStatus.cancelled: - buttonProps.color = 'danger'; - buttonProps.iconSide = 'left'; - buttonProps.iconType = 'cross'; - buttonContent = ( - - ); - break; - } - } - - const showIndexedClosedWarning = - reindexBlocker === 'index-closed' && reindexState.status !== ReindexStatus.completed; - - if (showIndexedClosedWarning) { - buttonProps.color = 'warning'; - buttonProps.iconType = 'alert'; - } - - const button = {buttonContent}; - - return ( - - {showIndexedClosedWarning ? ( - - {i18n.translate( - 'xpack.upgradeAssistant.checkupTab.reindexing.reindexButton.indexClosedToolTipDetails', - { - defaultMessage: - '"{indexName}" needs to be reindexed, but it is currently closed. The Upgrade Assistant will open, reindex and then close the index. Reindexing may take longer than usual.', - values: { indexName }, - } - )} - - } - > - {button} - - ) : ( - button - )} - - {flyoutVisible && ( - - )} - - ); - } - - private newService() { - const { indexName, http } = this.props; - return new ReindexPollingService(indexName, http); - } - - private subscribeToUpdates() { - this.service.updateStatus(); - this.subscription = this.service!.status$.subscribe((reindexState) => - this.setState({ reindexState }) - ); - } - - private unsubscribeToUpdates() { - if (this.subscription) { - this.subscription.unsubscribe(); - delete this.subscription; - } - - if (this.service) { - this.service.stopPolling(); - } - } - - private startReindex = async () => { - if (!this.state.reindexState.status) { - // if status didn't exist we are starting a reindex action - this.sendUIReindexTelemetryInfo('start'); - } - - await this.service.startReindex(); - }; - - private cancelReindex = async () => { - this.sendUIReindexTelemetryInfo('stop'); - await this.service.cancelReindex(); - }; - - private showFlyout = () => { - this.sendUIReindexTelemetryInfo('open'); - this.setState({ flyoutVisible: true }); - }; - - private closeFlyout = () => { - this.sendUIReindexTelemetryInfo('close'); - this.setState({ flyoutVisible: false }); - }; - - private async sendUIReindexTelemetryInfo(uiReindexAction: UIReindexOption) { - await this.props.http.put(`${API_BASE_PATH}/stats/ui_reindex`, { - body: JSON.stringify(set({}, uiReindexAction, true)), - }); - } -} diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/flyout/container.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/flyout/container.tsx deleted file mode 100644 index 1205a6e4147c2..0000000000000 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/flyout/container.tsx +++ /dev/null @@ -1,176 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; - -import { HttpSetup } from 'src/core/public'; -import { DocLinksStart } from 'kibana/public'; -import { i18n } from '@kbn/i18n'; -import { FormattedMessage } from '@kbn/i18n/react'; -import { - EuiCallOut, - EuiFlyout, - EuiFlyoutHeader, - EuiLink, - EuiPortal, - EuiSpacer, - EuiTitle, -} from '@elastic/eui'; - -import { ReindexAction, ReindexStatus } from '../../../../../../../common/types'; - -import { ReindexState } from '../polling_service'; -import { ChecklistFlyoutStep } from './checklist_step'; -import { WarningsFlyoutStep } from './warnings_step'; - -enum ReindexFlyoutStep { - reindexWarnings, - checklist, -} - -interface ReindexFlyoutProps { - indexName: string; - http: HttpSetup; - closeFlyout: () => void; - reindexState: ReindexState; - startReindex: () => void; - cancelReindex: () => void; - docLinks: DocLinksStart; - reindexBlocker?: ReindexAction['blockerForReindexing']; -} - -interface ReindexFlyoutState { - currentFlyoutStep: ReindexFlyoutStep; -} - -const getOpenAndCloseIndexDocLink = (docLinks: DocLinksStart) => ( - - {i18n.translate( - 'xpack.upgradeAssistant.checkupTab.reindexing.flyout.openAndCloseDocumentation', - { defaultMessage: 'documentation' } - )} - -); - -const getIndexClosedCallout = (docLinks: DocLinksStart) => ( - <> - -

- - {i18n.translate( - 'xpack.upgradeAssistant.checkupTab.reindexing.flyout.indexClosedCallout.calloutDetails.reindexingTakesLongerEmphasis', - { defaultMessage: 'Reindexing may take longer than usual' } - )} - - ), - }} - /> -

-
- - -); - -/** - * Wrapper for the contents of the flyout that manages which step of the flyout to show. - */ -export class ReindexFlyout extends React.Component { - constructor(props: ReindexFlyoutProps) { - super(props); - const { status, reindexWarnings } = props.reindexState; - - this.state = { - // If there are any warnings and we haven't started reindexing, show the warnings step first. - currentFlyoutStep: - reindexWarnings && reindexWarnings.length > 0 && status === undefined - ? ReindexFlyoutStep.reindexWarnings - : ReindexFlyoutStep.checklist, - }; - } - - public render() { - const { - closeFlyout, - indexName, - reindexState, - startReindex, - cancelReindex, - reindexBlocker, - docLinks, - } = this.props; - const { currentFlyoutStep } = this.state; - - let flyoutContents: React.ReactNode; - - const globalCallout = - reindexBlocker === 'index-closed' && reindexState.status !== ReindexStatus.completed - ? getIndexClosedCallout(docLinks) - : undefined; - switch (currentFlyoutStep) { - case ReindexFlyoutStep.reindexWarnings: - flyoutContents = ( - globalCallout} - closeFlyout={closeFlyout} - warnings={reindexState.reindexWarnings!} - advanceNextStep={this.advanceNextStep} - /> - ); - break; - case ReindexFlyoutStep.checklist: - flyoutContents = ( - globalCallout} - closeFlyout={closeFlyout} - reindexState={reindexState} - startReindex={startReindex} - cancelReindex={cancelReindex} - /> - ); - break; - default: - throw new Error(`Invalid flyout step: ${currentFlyoutStep}`); - } - - return ( - - - - -

- -

-
-
- {flyoutContents} -
-
- ); - } - - public advanceNextStep = () => { - this.setState({ currentFlyoutStep: ReindexFlyoutStep.checklist }); - }; -} diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/polling_service.test.ts b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/polling_service.test.ts deleted file mode 100644 index 13818e864783e..0000000000000 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/polling_service.test.ts +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { ReindexStatus, ReindexStep } from '../../../../../../common/types'; -import { ReindexPollingService } from './polling_service'; -import { httpServiceMock } from 'src/core/public/mocks'; - -const mockClient = httpServiceMock.createSetupContract(); - -describe('ReindexPollingService', () => { - beforeEach(() => { - mockClient.post.mockReset(); - mockClient.get.mockReset(); - }); - - it('does not poll when reindexOp is null', async () => { - mockClient.get.mockResolvedValueOnce({ - warnings: [], - reindexOp: null, - }); - - const service = new ReindexPollingService('myIndex', mockClient); - service.updateStatus(); - await new Promise((resolve) => setTimeout(resolve, 1200)); // wait for poll interval - - expect(mockClient.get).toHaveBeenCalledTimes(1); - service.stopPolling(); - }); - - it('does not poll when first check is a 200 and status is failed', async () => { - mockClient.get.mockResolvedValue({ - warnings: [], - reindexOp: { - lastCompletedStep: ReindexStep.created, - status: ReindexStatus.failed, - errorMessage: `Oh no!`, - }, - }); - - const service = new ReindexPollingService('myIndex', mockClient); - service.updateStatus(); - await new Promise((resolve) => setTimeout(resolve, 1200)); // wait for poll interval - - expect(mockClient.get).toHaveBeenCalledTimes(1); - expect(service.status$.value.errorMessage).toEqual(`Oh no!`); - service.stopPolling(); - }); - - it('begins to poll when first check is a 200 and status is inProgress', async () => { - mockClient.get.mockResolvedValue({ - warnings: [], - reindexOp: { - lastCompletedStep: ReindexStep.created, - status: ReindexStatus.inProgress, - }, - }); - - const service = new ReindexPollingService('myIndex', mockClient); - service.updateStatus(); - await new Promise((resolve) => setTimeout(resolve, 1200)); // wait for poll interval - - expect(mockClient.get).toHaveBeenCalledTimes(2); - service.stopPolling(); - }); - - describe('startReindex', () => { - it('posts to endpoint', async () => { - const service = new ReindexPollingService('myIndex', mockClient); - await service.startReindex(); - - expect(mockClient.post).toHaveBeenCalledWith('/api/upgrade_assistant/reindex/myIndex'); - }); - }); - - describe('cancelReindex', () => { - it('posts to cancel endpoint', async () => { - const service = new ReindexPollingService('myIndex', mockClient); - await service.cancelReindex(); - - expect(mockClient.post).toHaveBeenCalledWith('/api/upgrade_assistant/reindex/myIndex/cancel'); - }); - }); -}); diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/polling_service.ts b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/polling_service.ts deleted file mode 100644 index 239bd56bd2fa5..0000000000000 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/polling_service.ts +++ /dev/null @@ -1,169 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { BehaviorSubject } from 'rxjs'; - -import { HttpSetup } from 'src/core/public'; -import { API_BASE_PATH } from '../../../../../../common/constants'; -import { - IndexGroup, - ReindexOperation, - ReindexStatus, - ReindexStep, - ReindexWarning, -} from '../../../../../../common/types'; -import { LoadingState } from '../../../types'; - -const POLL_INTERVAL = 1000; - -export interface ReindexState { - loadingState: LoadingState; - cancelLoadingState?: LoadingState; - lastCompletedStep?: ReindexStep; - status?: ReindexStatus; - reindexTaskPercComplete: number | null; - errorMessage: string | null; - reindexWarnings?: ReindexWarning[]; - hasRequiredPrivileges?: boolean; - indexGroup?: IndexGroup; -} - -interface StatusResponse { - warnings?: ReindexWarning[]; - reindexOp?: ReindexOperation; - hasRequiredPrivileges?: boolean; - indexGroup?: IndexGroup; -} - -/** - * Service used by the frontend to start reindexing and get updates on the state of a reindex - * operation. Exposes an Observable that can be used to subscribe to state updates. - */ -export class ReindexPollingService { - public status$: BehaviorSubject; - private pollTimeout?: NodeJS.Timeout; - - constructor(private indexName: string, private http: HttpSetup) { - this.status$ = new BehaviorSubject({ - loadingState: LoadingState.Loading, - errorMessage: null, - reindexTaskPercComplete: null, - }); - } - - public updateStatus = async () => { - // Prevent two loops from being started. - this.stopPolling(); - - try { - const data = await this.http.get( - `${API_BASE_PATH}/reindex/${this.indexName}` - ); - this.updateWithResponse(data); - - // Only keep polling if it exists and is in progress. - if (data.reindexOp && data.reindexOp.status === ReindexStatus.inProgress) { - this.pollTimeout = setTimeout(this.updateStatus, POLL_INTERVAL); - } - } catch (e) { - this.status$.next({ - ...this.status$.value, - status: ReindexStatus.failed, - }); - } - }; - - public stopPolling = () => { - if (this.pollTimeout) { - clearTimeout(this.pollTimeout); - } - }; - - public startReindex = async () => { - try { - // Optimistically assume it will start, reset other state. - const currentValue = this.status$.value; - this.status$.next({ - ...currentValue, - // Only reset last completed step if we aren't currently paused - lastCompletedStep: - currentValue.status === ReindexStatus.paused ? currentValue.lastCompletedStep : undefined, - status: ReindexStatus.inProgress, - reindexTaskPercComplete: null, - errorMessage: null, - cancelLoadingState: undefined, - }); - - const data = await this.http.post( - `${API_BASE_PATH}/reindex/${this.indexName}` - ); - - this.updateWithResponse({ reindexOp: data }); - this.updateStatus(); - } catch (e) { - this.status$.next({ ...this.status$.value, status: ReindexStatus.failed }); - } - }; - - public cancelReindex = async () => { - try { - this.status$.next({ - ...this.status$.value, - cancelLoadingState: LoadingState.Loading, - }); - - await this.http.post(`${API_BASE_PATH}/reindex/${this.indexName}/cancel`); - } catch (e) { - this.status$.next({ - ...this.status$.value, - cancelLoadingState: LoadingState.Error, - }); - } - }; - - private updateWithResponse = ({ - reindexOp, - warnings, - hasRequiredPrivileges, - indexGroup, - }: StatusResponse) => { - const currentValue = this.status$.value; - // Next value should always include the entire state, not just what changes. - // We make a shallow copy as a starting new state. - const nextValue = { - ...currentValue, - // If we're getting any updates, set to success. - loadingState: LoadingState.Success, - }; - - if (warnings) { - nextValue.reindexWarnings = warnings; - } - - if (hasRequiredPrivileges !== undefined) { - nextValue.hasRequiredPrivileges = hasRequiredPrivileges; - } - - if (indexGroup) { - nextValue.indexGroup = indexGroup; - } - - if (reindexOp) { - // Prevent the UI flickering back to inProgres after cancelling. - nextValue.lastCompletedStep = reindexOp.lastCompletedStep; - nextValue.status = reindexOp.status; - nextValue.reindexTaskPercComplete = reindexOp.reindexTaskPercComplete; - nextValue.errorMessage = reindexOp.errorMessage; - - if (reindexOp.status === ReindexStatus.cancelled) { - nextValue.cancelLoadingState = LoadingState.Success; - } - } - - this.status$.next(nextValue); - }; -} diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/es_deprecation_errors.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/es_deprecation_errors.tsx index 239433808c5af..5e3c7a5fe6cef 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/es_deprecation_errors.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/es_deprecation_errors.tsx @@ -10,7 +10,7 @@ import React from 'react'; import { EuiCallOut } from '@elastic/eui'; import { ResponseError } from '../../lib/api'; -import { getEsDeprecationError } from '../../lib/es_deprecation_errors'; +import { getEsDeprecationError } from '../../lib/get_es_deprecation_error'; interface Props { error: ResponseError; } diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/es_deprecations.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/es_deprecations.tsx index 4fc4d691c4038..38367bd3cfaff 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/es_deprecations.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/es_deprecations.tsx @@ -5,204 +5,88 @@ * 2.0. */ -import React, { useMemo, useEffect, useState } from 'react'; +import React, { useEffect } from 'react'; import { withRouter, RouteComponentProps } from 'react-router-dom'; -import { - EuiButton, - EuiButtonEmpty, - EuiPageHeader, - EuiTabbedContent, - EuiTabbedContentTab, - EuiToolTip, - EuiNotificationBadge, - EuiSpacer, -} from '@elastic/eui'; +import { EuiPageHeader, EuiSpacer, EuiPageContent } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; +import { SectionLoading } from '../../../shared_imports'; import { useAppContext } from '../../app_context'; -import { UpgradeAssistantTabProps, EsTabs, TelemetryState } from '../types'; -import { DeprecationTabContent } from './deprecation_tab_content'; +import { EsDeprecationsTable } from './es_deprecations_table'; +import { EsDeprecationErrors } from './es_deprecation_errors'; +import { NoDeprecationsPrompt } from '../shared'; const i18nTexts = { pageTitle: i18n.translate('xpack.upgradeAssistant.esDeprecations.pageTitle', { - defaultMessage: 'Elasticsearch', + defaultMessage: 'Elasticsearch deprecation warnings', }), pageDescription: i18n.translate('xpack.upgradeAssistant.esDeprecations.pageDescription', { defaultMessage: - 'Review the deprecated cluster and index settings. You must resolve any critical issues before upgrading.', + 'You must resolve all critical issues before upgrading. Back up recommended. Make sure you have a current snapshot before modifying your configuration or reindexing.', }), - docLinkText: i18n.translate('xpack.upgradeAssistant.esDeprecations.docLinkText', { - defaultMessage: 'Documentation', + isLoading: i18n.translate('xpack.upgradeAssistant.esDeprecations.loadingText', { + defaultMessage: 'Loading deprecations…', }), - backupDataButton: { - label: i18n.translate('xpack.upgradeAssistant.esDeprecations.backupDataButtonLabel', { - defaultMessage: 'Back up your data', - }), - tooltipText: i18n.translate('xpack.upgradeAssistant.esDeprecations.backupDataTooltipText', { - defaultMessage: 'Take a snapshot before you make any changes.', - }), - }, - clusterTab: { - tabName: i18n.translate('xpack.upgradeAssistant.esDeprecations.clusterTabLabel', { - defaultMessage: 'Cluster', - }), - deprecationType: i18n.translate('xpack.upgradeAssistant.esDeprecations.clusterLabel', { - defaultMessage: 'cluster', - }), - }, - indicesTab: { - tabName: i18n.translate('xpack.upgradeAssistant.esDeprecations.indicesTabLabel', { - defaultMessage: 'Indices', - }), - deprecationType: i18n.translate('xpack.upgradeAssistant.esDeprecations.indexLabel', { - defaultMessage: 'index', - }), - }, }; -interface MatchParams { - tabName: EsTabs; -} - -export const EsDeprecationsContent = withRouter( - ({ - match: { - params: { tabName }, - }, - history, - }: RouteComponentProps) => { - const [telemetryState, setTelemetryState] = useState(TelemetryState.Complete); - - const { api, breadcrumbs, getUrlForApp, docLinks } = useAppContext(); - - const { data: checkupData, isLoading, error, resendRequest } = api.useLoadUpgradeStatus(); - - const onTabClick = (selectedTab: EuiTabbedContentTab) => { - history.push(`/es_deprecations/${selectedTab.id}`); - }; - - const tabs = useMemo(() => { - const commonTabProps: UpgradeAssistantTabProps = { - error, - isLoading, - refreshCheckupData: resendRequest, - navigateToOverviewPage: () => history.push('/overview'), - }; - - return [ - { - id: 'cluster', - 'data-test-subj': 'upgradeAssistantClusterTab', - name: ( - - {i18nTexts.clusterTab.tabName} - {checkupData && checkupData.cluster.length > 0 && ( - <> - {' '} - {checkupData.cluster.length} - - )} - - ), - content: ( - - ), - }, - { - id: 'indices', - 'data-test-subj': 'upgradeAssistantIndicesTab', - name: ( - - {i18nTexts.indicesTab.tabName} - {checkupData && checkupData.indices.length > 0 && ( - <> - {' '} - {checkupData.indices.length} - - )} - - ), - content: ( - - ), - }, - ]; - }, [checkupData, error, history, isLoading, resendRequest]); - - useEffect(() => { - breadcrumbs.setBreadcrumbs('esDeprecations'); - }, [breadcrumbs]); - - useEffect(() => { - if (isLoading === false) { - setTelemetryState(TelemetryState.Running); +export const EsDeprecations = withRouter(({ history }: RouteComponentProps) => { + const { api, breadcrumbs } = useAppContext(); + + const { + data: esDeprecations, + isLoading, + error, + resendRequest, + isInitialRequest, + } = api.useLoadEsDeprecations(); + + useEffect(() => { + breadcrumbs.setBreadcrumbs('esDeprecations'); + }, [breadcrumbs]); + + useEffect(() => { + if (isLoading === false && isInitialRequest) { + async function sendTelemetryData() { + await api.sendPageTelemetryData({ + elasticsearch: true, + }); + } - async function sendTelemetryData() { - await api.sendTelemetryData({ - [tabName]: true, - }); - setTelemetryState(TelemetryState.Complete); - } + sendTelemetryData(); + } + }, [api, isLoading, isInitialRequest]); - sendTelemetryData(); - } - }, [api, tabName, isLoading]); + if (error) { + return ; + } + if (isLoading) { return ( - <> - - {i18nTexts.docLinkText} - , - ]} - > - - - {i18nTexts.backupDataButton.label} - - - - - + + {i18nTexts.isLoading} + + ); + } - tab.id === tabName)} + if (esDeprecations?.deprecations?.length === 0) { + return ( + + history.push('/overview')} /> - + ); } -); + + return ( +
+ + + + + +
+ ); +}); diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/es_deprecations_table.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/es_deprecations_table.tsx new file mode 100644 index 0000000000000..5f742a3c63ae6 --- /dev/null +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/es_deprecations_table.tsx @@ -0,0 +1,316 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useState, useEffect, useCallback, useMemo } from 'react'; +import { i18n } from '@kbn/i18n'; +import { sortBy } from 'lodash'; +import { + EuiButton, + EuiFlexGroup, + EuiTable, + EuiTableRow, + EuiTableHeaderCell, + EuiTableHeader, + EuiSearchBar, + EuiSpacer, + EuiFlexItem, + EuiTableBody, + EuiTablePagination, + EuiCallOut, + EuiTableRowCell, + Pager, + Query, +} from '@elastic/eui'; +import { EnrichedDeprecationInfo } from '../../../../common/types'; +import { + MlSnapshotsTableRow, + DefaultTableRow, + IndexSettingsTableRow, + ReindexTableRow, +} from './deprecation_types'; +import { DeprecationTableColumns } from '../types'; +import { DEPRECATION_TYPE_MAP } from '../constants'; + +const i18nTexts = { + refreshButtonLabel: i18n.translate( + 'xpack.upgradeAssistant.esDeprecations.table.refreshButtonLabel', + { + defaultMessage: 'Refresh', + } + ), + noDeprecationsMessage: i18n.translate( + 'xpack.upgradeAssistant.esDeprecations.table.noDeprecationsMessage', + { + defaultMessage: 'No Elasticsearch deprecation issues found', + } + ), + typeFilterLabel: i18n.translate('xpack.upgradeAssistant.esDeprecations.table.typeFilterLabel', { + defaultMessage: 'Type', + }), + criticalFilterLabel: i18n.translate( + 'xpack.upgradeAssistant.esDeprecations.table.criticalFilterLabel', + { + defaultMessage: 'Critical', + } + ), + searchPlaceholderLabel: i18n.translate( + 'xpack.upgradeAssistant.esDeprecations.table.searchPlaceholderLabel', + { + defaultMessage: 'Filter', + } + ), +}; + +const cellToLabelMap = { + isCritical: { + label: i18n.translate('xpack.upgradeAssistant.esDeprecations.table.statusColumnTitle', { + defaultMessage: 'Status', + }), + width: '8px', + }, + message: { + label: i18n.translate('xpack.upgradeAssistant.esDeprecations.table.issueColumnTitle', { + defaultMessage: 'Issue', + }), + width: '36px', + }, + type: { + label: i18n.translate('xpack.upgradeAssistant.esDeprecations.table.typeColumnTitle', { + defaultMessage: 'Type', + }), + width: '10px', + }, + index: { + label: i18n.translate('xpack.upgradeAssistant.esDeprecations.table.nameColumnTitle', { + defaultMessage: 'Name', + }), + width: '24px', + }, + correctiveAction: { + label: i18n.translate('xpack.upgradeAssistant.esDeprecations.table.resolutionColumnTitle', { + defaultMessage: 'Resolution', + }), + width: '24px', + }, +}; + +const cellTypes = Object.keys(cellToLabelMap) as DeprecationTableColumns[]; +const pageSizeOptions = [50, 100, 200]; + +const renderTableRowCells = (deprecation: EnrichedDeprecationInfo) => { + switch (deprecation.correctiveAction?.type) { + case 'mlSnapshot': + return ; + + case 'indexSetting': + return ; + + case 'reindex': + return ; + + default: + return ; + } +}; + +interface Props { + deprecations?: EnrichedDeprecationInfo[]; + reload: () => void; +} + +interface SortConfig { + isSortAscending: boolean; + sortField: DeprecationTableColumns; +} + +const getSortedItems = (deprecations: EnrichedDeprecationInfo[], sortConfig: SortConfig) => { + const { isSortAscending, sortField } = sortConfig; + const sorted = sortBy(deprecations, [ + (deprecation) => { + if (sortField === 'isCritical') { + // Critical deprecations should take precendence in ascending order + return deprecation.isCritical !== true; + } + return deprecation[sortField]; + }, + ]); + + return isSortAscending ? sorted : sorted.reverse(); +}; + +export const EsDeprecationsTable: React.FunctionComponent = ({ + deprecations = [], + reload, +}) => { + const [sortConfig, setSortConfig] = useState({ + isSortAscending: true, + sortField: 'isCritical', + }); + + const [itemsPerPage, setItemsPerPage] = useState(pageSizeOptions[0]); + const [currentPageIndex, setCurrentPageIndex] = useState(0); + const [searchQuery, setSearchQuery] = useState(EuiSearchBar.Query.MATCH_ALL); + const [searchError, setSearchError] = useState<{ message: string } | undefined>(undefined); + + const [filteredDeprecations, setFilteredDeprecations] = useState( + getSortedItems(deprecations, sortConfig) + ); + + const pager = useMemo(() => new Pager(deprecations.length, itemsPerPage, currentPageIndex), [ + currentPageIndex, + deprecations, + itemsPerPage, + ]); + + const visibleDeprecations = useMemo( + () => filteredDeprecations.slice(pager.firstItemIndex, pager.lastItemIndex + 1), + [filteredDeprecations, pager] + ); + + const handleSort = useCallback( + (fieldName: DeprecationTableColumns) => { + const newSortConfig = { + isSortAscending: sortConfig.sortField === fieldName ? !sortConfig.isSortAscending : true, + sortField: fieldName, + }; + setSortConfig(newSortConfig); + }, + [sortConfig] + ); + + const handleSearch = useCallback(({ query, error }) => { + if (error) { + setSearchError(error); + } else { + setSearchError(undefined); + setSearchQuery(query); + } + }, []); + + useEffect(() => { + const { setTotalItems, goToPageIndex } = pager; + const deprecationsFilteredByQuery = EuiSearchBar.Query.execute(searchQuery, deprecations); + const deprecationsSortedByFieldType = getSortedItems(deprecationsFilteredByQuery, sortConfig); + + setTotalItems(deprecationsSortedByFieldType.length); + setFilteredDeprecations(deprecationsSortedByFieldType); + + // Reset pagination if the filtered results return a different length + if (deprecationsSortedByFieldType.length !== filteredDeprecations.length) { + goToPageIndex(0); + } + }, [deprecations, sortConfig, pager, searchQuery, filteredDeprecations.length]); + + return ( + <> + + + ).map((type) => ({ + value: type, + name: DEPRECATION_TYPE_MAP[type], + })), + }, + ]} + onChange={handleSearch} + /> + + + + {i18nTexts.refreshButtonLabel} + + + + + {searchError && ( +
+ + + +
+ )} + + + + + + {Object.entries(cellToLabelMap).map(([fieldName, cell]) => { + return ( + handleSort(fieldName as DeprecationTableColumns)} + isSorted={sortConfig.sortField === fieldName} + isSortAscending={sortConfig.isSortAscending} + > + {cell.label} + + ); + })} + + + {filteredDeprecations.length === 0 ? ( + + + + {i18nTexts.noDeprecationsMessage} + + + + ) : ( + + {visibleDeprecations.map((deprecation, index) => { + return ( + + {renderTableRowCells(deprecation)} + + ); + })} + + )} + + + + + + + ); +}; diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/es_deprecations_table_cells.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/es_deprecations_table_cells.tsx new file mode 100644 index 0000000000000..dd187f19d5e96 --- /dev/null +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/es_deprecations_table_cells.tsx @@ -0,0 +1,74 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { i18n } from '@kbn/i18n'; +import { EuiBadge, EuiLink } from '@elastic/eui'; +import { EnrichedDeprecationInfo } from '../../../../common/types'; +import { DEPRECATION_TYPE_MAP } from '../constants'; +import { DeprecationTableColumns } from '../types'; + +interface Props { + resolutionTableCell?: React.ReactNode; + fieldName: DeprecationTableColumns; + deprecation: EnrichedDeprecationInfo; + openFlyout: () => void; +} + +const i18nTexts = { + criticalBadgeLabel: i18n.translate( + 'xpack.upgradeAssistant.esDeprecations.defaultDeprecation.criticalBadgeLabel', + { + defaultMessage: 'Critical', + } + ), +}; + +export const EsDeprecationsTableCells: React.FunctionComponent = ({ + resolutionTableCell, + fieldName, + deprecation, + openFlyout, +}) => { + // "Status column" + if (fieldName === 'isCritical') { + if (deprecation.isCritical === true) { + return {i18nTexts.criticalBadgeLabel}; + } + + return <>{''}; + } + + // "Issue" column + if (fieldName === 'message') { + return ( + + {deprecation.message} + + ); + } + + // "Type" column + if (fieldName === 'type') { + return <>{DEPRECATION_TYPE_MAP[deprecation.type as EnrichedDeprecationInfo['type']]}; + } + + // "Resolution column" + if (fieldName === 'correctiveAction') { + if (resolutionTableCell) { + return <>{resolutionTableCell}; + } + + return <>{''}; + } + + // Default behavior: render value or empty string if undefined + return <>{deprecation[fieldName] ?? ''}; +}; diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/index.ts b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/index.ts index 0e69259adc609..1783745843070 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/index.ts +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/index.ts @@ -5,4 +5,4 @@ * 2.0. */ -export { EsDeprecationsContent } from './es_deprecations'; +export { EsDeprecations } from './es_deprecations'; diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/kibana_deprecations/kibana_deprecations.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/kibana_deprecations/kibana_deprecations.tsx index 31b5c80d5b377..56d6e23d9d4f3 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/kibana_deprecations/kibana_deprecations.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/kibana_deprecations/kibana_deprecations.tsx @@ -112,7 +112,7 @@ export const KibanaDeprecationsContent = withRouter(({ history }: RouteComponent useEffect(() => { async function sendTelemetryData() { - await api.sendTelemetryData({ + await api.sendPageTelemetryData({ kibana: true, }); } diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/overview/overview.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/overview/overview.tsx index b7cac67ca5a96..f900416873b83 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/overview/overview.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/overview/overview.tsx @@ -31,7 +31,7 @@ export const Overview: FunctionComponent = () => { useEffect(() => { async function sendTelemetryData() { - await api.sendTelemetryData({ + await api.sendPageTelemetryData({ overview: true, }); } diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/overview/review_logs_step/es_stats/es_stats.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/overview/review_logs_step/es_stats/es_stats.tsx index 97306dac287ba..ef0b3f438da03 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/overview/review_logs_step/es_stats/es_stats.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/overview/review_logs_step/es_stats/es_stats.tsx @@ -50,13 +50,12 @@ const i18nTexts = { criticalDeprecations, }, }), - getWarningDeprecationMessage: (clusterCount: number, indexCount: number) => - i18n.translate('xpack.upgradeAssistant.esDeprecationStats.totalDeprecationsTooltip', { + getWarningDeprecationMessage: (warningDeprecations: number) => + i18n.translate('xpack.upgradeAssistant.esDeprecationStats.warningDeprecationsTooltip', { defaultMessage: - 'This cluster is using {clusterCount} deprecated cluster settings and {indexCount} deprecated index settings', + 'This cluster has {warningDeprecations} non-critical {warningDeprecations, plural, one {deprecation} other {deprecations}}', values: { - clusterCount, - indexCount, + warningDeprecations, }, }), }; @@ -65,15 +64,12 @@ export const ESDeprecationStats: FunctionComponent = () => { const history = useHistory(); const { api } = useAppContext(); - const { data: esDeprecations, isLoading, error } = api.useLoadUpgradeStatus(); + const { data: esDeprecations, isLoading, error } = api.useLoadEsDeprecations(); - const allDeprecations = esDeprecations?.cluster?.concat(esDeprecations?.indices) ?? []; - const warningDeprecations = allDeprecations.filter( - (deprecation) => deprecation.level === 'warning' - ); - const criticalDeprecations = allDeprecations.filter( - (deprecation) => deprecation.level === 'critical' - ); + const warningDeprecations = + esDeprecations?.deprecations?.filter((deprecation) => deprecation.isCritical === false) || []; + const criticalDeprecations = + esDeprecations?.deprecations?.filter((deprecation) => deprecation.isCritical) || []; const hasWarnings = warningDeprecations.length > 0; const hasCritical = criticalDeprecations.length > 0; @@ -90,7 +86,7 @@ export const ESDeprecationStats: FunctionComponent = () => { {error && } } - {...(!hasNoDeprecations && reactRouterNavigate(history, '/es_deprecations/cluster'))} + {...(!hasNoDeprecations && reactRouterNavigate(history, '/es_deprecations'))} > @@ -137,10 +133,7 @@ export const ESDeprecationStats: FunctionComponent = () => {

{isLoading ? i18nTexts.loadingText - : i18nTexts.getWarningDeprecationMessage( - esDeprecations?.cluster.length ?? 0, - esDeprecations?.indices.length ?? 0 - )} + : i18nTexts.getWarningDeprecationMessage(warningDeprecations.length)}

)} diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/overview/review_logs_step/es_stats/es_stats_error.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/overview/review_logs_step/es_stats/es_stats_error.tsx index 5db5b80cc42eb..c717a8a2e12e8 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/overview/review_logs_step/es_stats/es_stats_error.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/overview/review_logs_step/es_stats/es_stats_error.tsx @@ -9,7 +9,7 @@ import React from 'react'; import { EuiIconTip } from '@elastic/eui'; import { ResponseError } from '../../../../lib/api'; -import { getEsDeprecationError } from '../../../../lib/es_deprecation_errors'; +import { getEsDeprecationError } from '../../../../lib/get_es_deprecation_error'; interface Props { error: ResponseError; diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/shared/no_deprecations.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/shared/no_deprecations.tsx index 3626151b63bbf..7763450c6cfcf 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/shared/no_deprecations.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/shared/no_deprecations.tsx @@ -12,14 +12,14 @@ import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; const i18nTexts = { - emptyPromptTitle: i18n.translate('xpack.upgradeAssistant.noDeprecationsPrompt.title', { - defaultMessage: 'Ready to upgrade!', - }), - getEmptyPromptDescription: (deprecationType: string) => + getEmptyPromptTitle: (deprecationType: string) => i18n.translate('xpack.upgradeAssistant.noDeprecationsPrompt.description', { - defaultMessage: 'Your configuration is up to date.', + defaultMessage: 'Your {deprecationType} configuration is up to date', + values: { + deprecationType, + }, }), - getEmptyPromptNextStepsDescription: (navigateToOverviewPage: () => void) => ( + getEmptyPromptDescription: (navigateToOverviewPage: () => void) => ( = ({ }) => { return ( {i18nTexts.emptyPromptTitle}} + title={

{i18nTexts.getEmptyPromptTitle(deprecationType)}

} body={ <>

- {i18nTexts.getEmptyPromptDescription(deprecationType)} + {i18nTexts.getEmptyPromptDescription(navigateToOverviewPage)}

-

{i18nTexts.getEmptyPromptNextStepsDescription(navigateToOverviewPage)}

} /> diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/types.ts b/x-pack/plugins/upgrade_assistant/public/application/components/types.ts index b4fd78252b2ff..b46bb583244f0 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/types.ts +++ b/x-pack/plugins/upgrade_assistant/public/application/components/types.ts @@ -5,27 +5,8 @@ * 2.0. */ -import React from 'react'; - -import { EnrichedDeprecationInfo, ESUpgradeStatus } from '../../../common/types'; import { ResponseError } from '../lib/api'; -export interface UpgradeAssistantTabProps { - alertBanner?: React.ReactNode; - checkupData?: ESUpgradeStatus | null; - deprecations?: EnrichedDeprecationInfo[]; - refreshCheckupData: () => void; - error: ResponseError | null; - isLoading: boolean; - navigateToOverviewPage: () => void; -} - -// eslint-disable-next-line react/prefer-stateless-function -export class UpgradeAssistantTabComponent< - T extends UpgradeAssistantTabProps = UpgradeAssistantTabProps, - S = {} -> extends React.Component {} - export enum LoadingState { Loading, Success, @@ -40,13 +21,14 @@ export enum GroupByOption { node = 'node', } -export enum TelemetryState { - Running, - Complete, -} - -export type EsTabs = 'cluster' | 'indices'; +export type DeprecationTableColumns = + | 'type' + | 'index' + | 'message' + | 'correctiveAction' + | 'isCritical'; +export type Status = 'in_progress' | 'complete' | 'idle' | 'error'; export interface DeprecationLoggingPreviewProps { isDeprecationLogIndexingEnabled: boolean; onlyDeprecationLogWritingEnabled: boolean; diff --git a/x-pack/plugins/upgrade_assistant/public/application/lib/api.ts b/x-pack/plugins/upgrade_assistant/public/application/lib/api.ts index 1b22d26ea7218..78070c5717496 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/lib/api.ts +++ b/x-pack/plugins/upgrade_assistant/public/application/lib/api.ts @@ -45,14 +45,14 @@ export class ApiService { this.client = httpClient; } - public useLoadUpgradeStatus() { + public useLoadEsDeprecations() { return this.useRequest({ path: `${API_BASE_PATH}/es_deprecations`, method: 'get', }); } - public async sendTelemetryData(telemetryData: { [tabName: string]: boolean }) { + public async sendPageTelemetryData(telemetryData: { [tabName: string]: boolean }) { const result = await this.sendRequest({ path: `${API_BASE_PATH}/stats/ui_open`, method: 'put', @@ -125,6 +125,37 @@ export class ApiService { method: 'get', }); } + + public async sendReindexTelemetryData(telemetryData: { [key: string]: boolean }) { + const result = await this.sendRequest({ + path: `${API_BASE_PATH}/stats/ui_reindex`, + method: 'put', + body: JSON.stringify(telemetryData), + }); + + return result; + } + + public async getReindexStatus(indexName: string) { + return await this.sendRequest({ + path: `${API_BASE_PATH}/reindex/${indexName}`, + method: 'get', + }); + } + + public async startReindexTask(indexName: string) { + return await this.sendRequest({ + path: `${API_BASE_PATH}/reindex/${indexName}`, + method: 'post', + }); + } + + public async cancelReindexTask(indexName: string) { + return await this.sendRequest({ + path: `${API_BASE_PATH}/reindex/${indexName}/cancel`, + method: 'post', + }); + } } export const apiService = new ApiService(); diff --git a/x-pack/plugins/upgrade_assistant/public/application/lib/breadcrumbs.ts b/x-pack/plugins/upgrade_assistant/public/application/lib/breadcrumbs.ts index 00359988d5e2a..f36dc2096ddc7 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/lib/breadcrumbs.ts +++ b/x-pack/plugins/upgrade_assistant/public/application/lib/breadcrumbs.ts @@ -16,7 +16,7 @@ const i18nTexts = { defaultMessage: 'Upgrade Assistant', }), esDeprecations: i18n.translate('xpack.upgradeAssistant.breadcrumb.esDeprecationsLabel', { - defaultMessage: 'Elasticsearch deprecations', + defaultMessage: 'Elasticsearch deprecation warnings', }), kibanaDeprecations: i18n.translate( 'xpack.upgradeAssistant.breadcrumb.kibanaDeprecationsLabel', diff --git a/x-pack/plugins/upgrade_assistant/public/application/lib/es_deprecation_errors.ts b/x-pack/plugins/upgrade_assistant/public/application/lib/get_es_deprecation_error.ts similarity index 93% rename from x-pack/plugins/upgrade_assistant/public/application/lib/es_deprecation_errors.ts rename to x-pack/plugins/upgrade_assistant/public/application/lib/get_es_deprecation_error.ts index 4220f0eef8d42..85cfd2a3fd16c 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/lib/es_deprecation_errors.ts +++ b/x-pack/plugins/upgrade_assistant/public/application/lib/get_es_deprecation_error.ts @@ -25,8 +25,7 @@ const i18nTexts = { upgradedMessage: i18n.translate( 'xpack.upgradeAssistant.esDeprecationErrors.upgradedWarningMessage', { - defaultMessage: - 'Your configuration is up to date. Kibana and all Elasticsearch nodes are running the same version.', + defaultMessage: 'All Elasticsearch nodes have been upgraded.', } ), loadingError: i18n.translate('xpack.upgradeAssistant.esDeprecationErrors.loadingErrorMessage', { diff --git a/x-pack/plugins/upgrade_assistant/public/shared_imports.ts b/x-pack/plugins/upgrade_assistant/public/shared_imports.ts index c3ffd44662ec2..64b52065f63e6 100644 --- a/x-pack/plugins/upgrade_assistant/public/shared_imports.ts +++ b/x-pack/plugins/upgrade_assistant/public/shared_imports.ts @@ -15,6 +15,7 @@ export { useRequest, UseRequestConfig, SectionLoading, + GlobalFlyout, } from '../../../../src/plugins/es_ui_shared/public/'; export { KibanaContextProvider } from '../../../../src/plugins/kibana_react/public'; diff --git a/x-pack/plugins/upgrade_assistant/server/lib/__fixtures__/fake_deprecations.json b/x-pack/plugins/upgrade_assistant/server/lib/__fixtures__/fake_deprecations.json index ef724e3bf892e..617bb02ff9dfc 100644 --- a/x-pack/plugins/upgrade_assistant/server/lib/__fixtures__/fake_deprecations.json +++ b/x-pack/plugins/upgrade_assistant/server/lib/__fixtures__/fake_deprecations.json @@ -4,13 +4,15 @@ "level": "warning", "message": "Template patterns are no longer using `template` field, but `index_patterns` instead", "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" + "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template", + "resolve_during_rolling_upgrade": false }, { "level": "warning", "message": "one or more templates use deprecated mapping settings", "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" + "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}", + "resolve_during_rolling_upgrade": false } ], "ml_settings": [ @@ -18,7 +20,8 @@ "level": "warning", "message": "Datafeed [deprecation-datafeed] uses deprecated query options", "url": "https://www.elastic.co/guide/en/elasticsearch/reference/master/breaking-changes-7.0.html#breaking_70_search_changes", - "details": "[Deprecated field [use_dis_max] used, replaced by [Set [tie_breaker] to 1 instead]]" + "details": "[Deprecated field [use_dis_max] used, replaced by [Set [tie_breaker] to 1 instead]]", + "resolve_during_rolling_upgrade": false }, { "level": "critical", @@ -28,7 +31,8 @@ "_meta": { "snapshot_id": "1", "job_id": "deprecation_check_job" - } + }, + "resolve_during_rolling_upgrade": false } ], "node_settings": [ @@ -36,7 +40,8 @@ "level": "critical", "message": "A node-level issue", "url": "http://nodeissue.com", - "details": "This node thing is wrong" + "details": "This node thing is wrong", + "resolve_during_rolling_upgrade": true } ], "index_settings": { @@ -45,7 +50,8 @@ "level": "warning", "message": "Coercion of boolean fields", "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_mappings_changes.html#_coercion_of_boolean_fields", - "details": "[[type: doc, field: spins], [type: doc, field: mlockall], [type: doc, field: node_master], [type: doc, field: primary]]" + "details": "[[type: doc, field: spins], [type: doc, field: mlockall], [type: doc, field: node_master], [type: doc, field: primary]]", + "resolve_during_rolling_upgrade": false } ], "twitter": [ @@ -53,7 +59,8 @@ "level": "warning", "message": "Coercion of boolean fields", "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_mappings_changes.html#_coercion_of_boolean_fields", - "details": "[[type: tweet, field: liked]]" + "details": "[[type: tweet, field: liked]]", + "resolve_during_rolling_upgrade": false } ], "old_index": [ @@ -62,7 +69,8 @@ "message": "Index created before 7.0", "url": "https: //www.elastic.co/guide/en/elasticsearch/reference/master/breaking-changes-8.0.html", - "details": "This index was created using version: 6.8.13" + "details": "This index was created using version: 6.8.13", + "resolve_during_rolling_upgrade": false } ], "closed_index": [ @@ -70,7 +78,8 @@ "level": "critical", "message": "Index created before 7.0", "url": "https: //www.elastic.co/guide/en/elasticsearch/reference/master/breaking-changes-8.0.html", - "details": "This index was created using version: 6.8.13" + "details": "This index was created using version: 6.8.13", + "resolve_during_rolling_upgrade": false } ], "deprecated_settings": [ @@ -80,7 +89,8 @@ "url": "https://www.elastic.co/guide/en/elasticsearch/reference/current/index-modules-translog.html", "details": - "translog retention settings [index.translog.retention.size] and [index.translog.retention.age] are ignored because translog is no longer used in peer recoveries with soft-deletes enabled (default in 7.0 or later)" + "translog retention settings [index.translog.retention.size] and [index.translog.retention.age] are ignored because translog is no longer used in peer recoveries with soft-deletes enabled (default in 7.0 or later)", + "resolve_during_rolling_upgrade": false } ], ".kibana": [ @@ -88,7 +98,8 @@ "level": "warning", "message": "Coercion of boolean fields", "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_mappings_changes.html#_coercion_of_boolean_fields", - "details": "[[type: index-pattern, field: notExpandable], [type: config, field: xPackMonitoring:allowReport], [type: config, field: xPackMonitoring:showBanner], [type: dashboard, field: pause], [type: dashboard, field: timeRestore]]" + "details": "[[type: index-pattern, field: notExpandable], [type: config, field: xPackMonitoring:allowReport], [type: config, field: xPackMonitoring:showBanner], [type: dashboard, field: pause], [type: dashboard, field: timeRestore]]", + "resolve_during_rolling_upgrade": false } ], ".watcher-history-6-2018.11.07": [ @@ -96,7 +107,8 @@ "level": "warning", "message": "Coercion of boolean fields", "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_mappings_changes.html#_coercion_of_boolean_fields", - "details": "[[type: doc, field: notify], [type: doc, field: created], [type: doc, field: attach_payload], [type: doc, field: met]]" + "details": "[[type: doc, field: notify], [type: doc, field: created], [type: doc, field: attach_payload], [type: doc, field: met]]", + "resolve_during_rolling_upgrade": false } ], ".monitoring-kibana-6-2018.11.07": [ @@ -104,7 +116,8 @@ "level": "warning", "message": "Coercion of boolean fields", "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_mappings_changes.html#_coercion_of_boolean_fields", - "details": "[[type: doc, field: snapshot]]" + "details": "[[type: doc, field: snapshot]]", + "resolve_during_rolling_upgrade": false } ], "twitter2": [ @@ -112,7 +125,8 @@ "level": "warning", "message": "Coercion of boolean fields", "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_mappings_changes.html#_coercion_of_boolean_fields", - "details": "[[type: tweet, field: liked]]" + "details": "[[type: tweet, field: liked]]", + "resolve_during_rolling_upgrade": false } ] } diff --git a/x-pack/plugins/upgrade_assistant/server/lib/__snapshots__/es_deprecations_status.test.ts.snap b/x-pack/plugins/upgrade_assistant/server/lib/__snapshots__/es_deprecations_status.test.ts.snap index 3e847eef18f07..be9ea11a4886e 100644 --- a/x-pack/plugins/upgrade_assistant/server/lib/__snapshots__/es_deprecations_status.test.ts.snap +++ b/x-pack/plugins/upgrade_assistant/server/lib/__snapshots__/es_deprecations_status.test.ts.snap @@ -2,26 +2,32 @@ exports[`getESUpgradeStatus returns the correct shape of data 1`] = ` Object { - "cluster": Array [ + "deprecations": Array [ Object { "correctiveAction": undefined, "details": "templates using \`template\` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template", - "level": "warning", + "isCritical": false, "message": "Template patterns are no longer using \`template\` field, but \`index_patterns\` instead", + "resolveDuringUpgrade": false, + "type": "cluster_settings", "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", }, Object { "correctiveAction": undefined, "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}", - "level": "warning", + "isCritical": false, "message": "one or more templates use deprecated mapping settings", + "resolveDuringUpgrade": false, + "type": "cluster_settings", "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", }, Object { "correctiveAction": undefined, "details": "[Deprecated field [use_dis_max] used, replaced by [Set [tie_breaker] to 1 instead]]", - "level": "warning", + "isCritical": false, "message": "Datafeed [deprecation-datafeed] uses deprecated query options", + "resolveDuringUpgrade": false, + "type": "ml_settings", "url": "https://www.elastic.co/guide/en/elasticsearch/reference/master/breaking-changes-7.0.html#breaking_70_search_changes", }, Object { @@ -31,33 +37,39 @@ Object { "type": "mlSnapshot", }, "details": "details", - "level": "critical", + "isCritical": true, "message": "model snapshot [1] for job [deprecation_check_job] needs to be deleted or upgraded", + "resolveDuringUpgrade": false, + "type": "ml_settings", "url": "", }, Object { "correctiveAction": undefined, "details": "This node thing is wrong", - "level": "critical", + "isCritical": true, "message": "A node-level issue", + "resolveDuringUpgrade": true, + "type": "node_settings", "url": "http://nodeissue.com", }, - ], - "indices": Array [ Object { "correctiveAction": undefined, "details": "[[type: doc, field: spins], [type: doc, field: mlockall], [type: doc, field: node_master], [type: doc, field: primary]]", "index": ".monitoring-es-6-2018.11.07", - "level": "warning", + "isCritical": false, "message": "Coercion of boolean fields", + "resolveDuringUpgrade": false, + "type": "index_settings", "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_mappings_changes.html#_coercion_of_boolean_fields", }, Object { "correctiveAction": undefined, "details": "[[type: tweet, field: liked]]", "index": "twitter", - "level": "warning", + "isCritical": false, "message": "Coercion of boolean fields", + "resolveDuringUpgrade": false, + "type": "index_settings", "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_mappings_changes.html#_coercion_of_boolean_fields", }, Object { @@ -67,8 +79,10 @@ Object { }, "details": "This index was created using version: 6.8.13", "index": "old_index", - "level": "critical", + "isCritical": true, "message": "Index created before 7.0", + "resolveDuringUpgrade": false, + "type": "index_settings", "url": "https: //www.elastic.co/guide/en/elasticsearch/reference/master/breaking-changes-8.0.html", }, Object { @@ -78,8 +92,10 @@ Object { }, "details": "This index was created using version: 6.8.13", "index": "closed_index", - "level": "critical", + "isCritical": true, "message": "Index created before 7.0", + "resolveDuringUpgrade": false, + "type": "index_settings", "url": "https: //www.elastic.co/guide/en/elasticsearch/reference/master/breaking-changes-8.0.html", }, Object { @@ -92,40 +108,50 @@ Object { }, "details": "translog retention settings [index.translog.retention.size] and [index.translog.retention.age] are ignored because translog is no longer used in peer recoveries with soft-deletes enabled (default in 7.0 or later)", "index": "deprecated_settings", - "level": "warning", + "isCritical": false, "message": "translog retention settings are ignored", + "resolveDuringUpgrade": false, + "type": "index_settings", "url": "https://www.elastic.co/guide/en/elasticsearch/reference/current/index-modules-translog.html", }, Object { "correctiveAction": undefined, "details": "[[type: index-pattern, field: notExpandable], [type: config, field: xPackMonitoring:allowReport], [type: config, field: xPackMonitoring:showBanner], [type: dashboard, field: pause], [type: dashboard, field: timeRestore]]", "index": ".kibana", - "level": "warning", + "isCritical": false, "message": "Coercion of boolean fields", + "resolveDuringUpgrade": false, + "type": "index_settings", "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_mappings_changes.html#_coercion_of_boolean_fields", }, Object { "correctiveAction": undefined, "details": "[[type: doc, field: notify], [type: doc, field: created], [type: doc, field: attach_payload], [type: doc, field: met]]", "index": ".watcher-history-6-2018.11.07", - "level": "warning", + "isCritical": false, "message": "Coercion of boolean fields", + "resolveDuringUpgrade": false, + "type": "index_settings", "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_mappings_changes.html#_coercion_of_boolean_fields", }, Object { "correctiveAction": undefined, "details": "[[type: doc, field: snapshot]]", "index": ".monitoring-kibana-6-2018.11.07", - "level": "warning", + "isCritical": false, "message": "Coercion of boolean fields", + "resolveDuringUpgrade": false, + "type": "index_settings", "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_mappings_changes.html#_coercion_of_boolean_fields", }, Object { "correctiveAction": undefined, "details": "[[type: tweet, field: liked]]", "index": "twitter2", - "level": "warning", + "isCritical": false, "message": "Coercion of boolean fields", + "resolveDuringUpgrade": false, + "type": "index_settings", "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_mappings_changes.html#_coercion_of_boolean_fields", }, ], diff --git a/x-pack/plugins/upgrade_assistant/server/lib/es_deprecations_status.test.ts b/x-pack/plugins/upgrade_assistant/server/lib/es_deprecations_status.test.ts index f87a8916e1a52..e1a348f8ed8ee 100644 --- a/x-pack/plugins/upgrade_assistant/server/lib/es_deprecations_status.test.ts +++ b/x-pack/plugins/upgrade_assistant/server/lib/es_deprecations_status.test.ts @@ -8,7 +8,7 @@ import _ from 'lodash'; import { RequestEvent } from '@elastic/elasticsearch/lib/Transport'; import { elasticsearchServiceMock } from 'src/core/server/mocks'; -import { DeprecationAPIResponse } from '../../common/types'; +import { MigrationDeprecationInfoResponse } from '@elastic/elasticsearch/api/types'; import { getESUpgradeStatus } from './es_deprecations_status'; import fakeDeprecations from './__fixtures__/fake_deprecations.json'; @@ -32,12 +32,11 @@ describe('getESUpgradeStatus', () => { }; // @ts-expect-error mock data is too loosely typed - const deprecationsResponse: DeprecationAPIResponse = _.cloneDeep(fakeDeprecations); + const deprecationsResponse: MigrationDeprecationInfoResponse = _.cloneDeep(fakeDeprecations); const esClient = elasticsearchServiceMock.createScopedClusterClient(); esClient.asCurrentUser.migration.deprecations.mockResolvedValue( - // @ts-expect-error not full interface asApiResponse(deprecationsResponse) ); diff --git a/x-pack/plugins/upgrade_assistant/server/lib/es_deprecations_status.ts b/x-pack/plugins/upgrade_assistant/server/lib/es_deprecations_status.ts index b87d63ae36ec1..cd719cc0f32b5 100644 --- a/x-pack/plugins/upgrade_assistant/server/lib/es_deprecations_status.ts +++ b/x-pack/plugins/upgrade_assistant/server/lib/es_deprecations_status.ts @@ -5,13 +5,13 @@ * 2.0. */ +import { + MigrationDeprecationInfoDeprecation, + MigrationDeprecationInfoResponse, +} from '@elastic/elasticsearch/api/types'; import { IScopedClusterClient } from 'src/core/server'; import { indexSettingDeprecations } from '../../common/constants'; -import { - DeprecationAPIResponse, - EnrichedDeprecationInfo, - ESUpgradeStatus, -} from '../../common/types'; +import { EnrichedDeprecationInfo, ESUpgradeStatus } from '../../common/types'; import { esIndicesStateCheck } from './es_indices_state_check'; @@ -20,33 +20,82 @@ export async function getESUpgradeStatus( ): Promise { const { body: deprecations } = await dataClient.asCurrentUser.migration.deprecations(); - const cluster = getClusterDeprecations(deprecations); - const indices = await getCombinedIndexInfos(deprecations, dataClient); + const getCombinedDeprecations = async () => { + const indices = await getCombinedIndexInfos(deprecations, dataClient); + + return Object.keys(deprecations).reduce((combinedDeprecations, deprecationType) => { + if (deprecationType === 'index_settings') { + combinedDeprecations = combinedDeprecations.concat(indices); + } else { + const deprecationsByType = deprecations[ + deprecationType as keyof MigrationDeprecationInfoResponse + ] as MigrationDeprecationInfoDeprecation[]; + + const enrichedDeprecationInfo = deprecationsByType.map( + ({ + details, + level, + message, + url, + // @ts-expect-error @elastic/elasticsearch _meta not available yet in MigrationDeprecationInfoResponse + _meta: metadata, + // @ts-expect-error @elastic/elasticsearch resolve_during_rolling_upgrade not available yet in MigrationDeprecationInfoResponse + resolve_during_rolling_upgrade: resolveDuringUpgrade, + }) => { + return { + details, + message, + url, + type: deprecationType as keyof MigrationDeprecationInfoResponse, + isCritical: level === 'critical', + resolveDuringUpgrade, + correctiveAction: getCorrectiveAction(message, metadata), + }; + } + ); + + combinedDeprecations = combinedDeprecations.concat(enrichedDeprecationInfo); + } + + return combinedDeprecations; + }, [] as EnrichedDeprecationInfo[]); + }; - const totalCriticalDeprecations = cluster.concat(indices).filter((d) => d.level === 'critical') - .length; + const combinedDeprecations = await getCombinedDeprecations(); + const criticalWarnings = combinedDeprecations.filter(({ isCritical }) => isCritical === true); return { - totalCriticalDeprecations, - cluster, - indices, + totalCriticalDeprecations: criticalWarnings.length, + deprecations: combinedDeprecations, }; } // Reformats the index deprecations to an array of deprecation warnings extended with an index field. const getCombinedIndexInfos = async ( - deprecations: DeprecationAPIResponse, + deprecations: MigrationDeprecationInfoResponse, dataClient: IScopedClusterClient ) => { const indices = Object.keys(deprecations.index_settings).reduce( (indexDeprecations, indexName) => { return indexDeprecations.concat( deprecations.index_settings[indexName].map( - (d) => + ({ + details, + message, + url, + level, + // @ts-expect-error @elastic/elasticsearch resolve_during_rolling_upgrade not available yet in MigrationDeprecationInfoResponse + resolve_during_rolling_upgrade: resolveDuringUpgrade, + }) => ({ - ...d, + details, + message, + url, index: indexName, - correctiveAction: getCorrectiveAction(d.message), + type: 'index_settings', + isCritical: level === 'critical', + correctiveAction: getCorrectiveAction(message), + resolveDuringUpgrade, } as EnrichedDeprecationInfo) ) ); @@ -71,21 +120,10 @@ const getCombinedIndexInfos = async ( return indices as EnrichedDeprecationInfo[]; }; -const getClusterDeprecations = (deprecations: DeprecationAPIResponse) => { - const combinedDeprecations = deprecations.cluster_settings - .concat(deprecations.ml_settings) - .concat(deprecations.node_settings); - - return combinedDeprecations.map((deprecation) => { - const { _meta: metadata, ...deprecationInfo } = deprecation; - return { - ...deprecationInfo, - correctiveAction: getCorrectiveAction(deprecation.message, metadata), - }; - }) as EnrichedDeprecationInfo[]; -}; - -const getCorrectiveAction = (message: string, metadata?: { [key: string]: string }) => { +const getCorrectiveAction = ( + message: string, + metadata?: { [key: string]: string } +): EnrichedDeprecationInfo['correctiveAction'] => { const indexSettingDeprecation = Object.values(indexSettingDeprecations).find( ({ deprecationMessage }) => deprecationMessage === message ); diff --git a/x-pack/plugins/upgrade_assistant/server/lib/telemetry/es_ui_open_apis.test.ts b/x-pack/plugins/upgrade_assistant/server/lib/telemetry/es_ui_open_apis.test.ts index a911c5810dd0a..caff78390b9d1 100644 --- a/x-pack/plugins/upgrade_assistant/server/lib/telemetry/es_ui_open_apis.test.ts +++ b/x-pack/plugins/upgrade_assistant/server/lib/telemetry/es_ui_open_apis.test.ts @@ -22,13 +22,12 @@ describe('Upgrade Assistant Telemetry SavedObject UIOpen', () => { await upsertUIOpenOption({ overview: true, - cluster: true, - indices: true, + elasticsearch: true, kibana: true, savedObjects: { createInternalRepository: () => internalRepo } as any, }); - expect(internalRepo.incrementCounter).toHaveBeenCalledTimes(4); + expect(internalRepo.incrementCounter).toHaveBeenCalledTimes(3); expect(internalRepo.incrementCounter).toHaveBeenCalledWith( UPGRADE_ASSISTANT_TYPE, UPGRADE_ASSISTANT_DOC_ID, @@ -37,12 +36,7 @@ describe('Upgrade Assistant Telemetry SavedObject UIOpen', () => { expect(internalRepo.incrementCounter).toHaveBeenCalledWith( UPGRADE_ASSISTANT_TYPE, UPGRADE_ASSISTANT_DOC_ID, - ['ui_open.cluster'] - ); - expect(internalRepo.incrementCounter).toHaveBeenCalledWith( - UPGRADE_ASSISTANT_TYPE, - UPGRADE_ASSISTANT_DOC_ID, - ['ui_open.indices'] + ['ui_open.elasticsearch'] ); expect(internalRepo.incrementCounter).toHaveBeenCalledWith( UPGRADE_ASSISTANT_TYPE, diff --git a/x-pack/plugins/upgrade_assistant/server/lib/telemetry/es_ui_open_apis.ts b/x-pack/plugins/upgrade_assistant/server/lib/telemetry/es_ui_open_apis.ts index ab876828a343c..3d463fe4b03ed 100644 --- a/x-pack/plugins/upgrade_assistant/server/lib/telemetry/es_ui_open_apis.ts +++ b/x-pack/plugins/upgrade_assistant/server/lib/telemetry/es_ui_open_apis.ts @@ -33,8 +33,7 @@ type UpsertUIOpenOptionDependencies = UIOpen & { savedObjects: SavedObjectsServi export async function upsertUIOpenOption({ overview, - cluster, - indices, + elasticsearch, savedObjects, kibana, }: UpsertUIOpenOptionDependencies): Promise { @@ -42,12 +41,8 @@ export async function upsertUIOpenOption({ await incrementUIOpenOptionCounter({ savedObjects, uiOpenOptionCounter: 'overview' }); } - if (cluster) { - await incrementUIOpenOptionCounter({ savedObjects, uiOpenOptionCounter: 'cluster' }); - } - - if (indices) { - await incrementUIOpenOptionCounter({ savedObjects, uiOpenOptionCounter: 'indices' }); + if (elasticsearch) { + await incrementUIOpenOptionCounter({ savedObjects, uiOpenOptionCounter: 'elasticsearch' }); } if (kibana) { @@ -56,8 +51,7 @@ export async function upsertUIOpenOption({ return { overview, - cluster, - indices, + elasticsearch, kibana, }; } diff --git a/x-pack/plugins/upgrade_assistant/server/lib/telemetry/usage_collector.test.ts b/x-pack/plugins/upgrade_assistant/server/lib/telemetry/usage_collector.test.ts index 2227139c53cda..50c5b358aa5cb 100644 --- a/x-pack/plugins/upgrade_assistant/server/lib/telemetry/usage_collector.test.ts +++ b/x-pack/plugins/upgrade_assistant/server/lib/telemetry/usage_collector.test.ts @@ -54,8 +54,7 @@ describe('Upgrade Assistant Usage Collector', () => { return { attributes: { 'ui_open.overview': 10, - 'ui_open.cluster': 20, - 'ui_open.indices': 30, + 'ui_open.elasticsearch': 20, 'ui_open.kibana': 15, 'ui_reindex.close': 1, 'ui_reindex.open': 4, @@ -94,8 +93,7 @@ describe('Upgrade Assistant Usage Collector', () => { expect(upgradeAssistantStats).toEqual({ ui_open: { overview: 10, - cluster: 20, - indices: 30, + elasticsearch: 20, kibana: 15, }, ui_reindex: { diff --git a/x-pack/plugins/upgrade_assistant/server/lib/telemetry/usage_collector.ts b/x-pack/plugins/upgrade_assistant/server/lib/telemetry/usage_collector.ts index a6253ab1091da..ee997f5da7ab7 100644 --- a/x-pack/plugins/upgrade_assistant/server/lib/telemetry/usage_collector.ts +++ b/x-pack/plugins/upgrade_assistant/server/lib/telemetry/usage_collector.ts @@ -77,8 +77,7 @@ export async function fetchUpgradeAssistantMetrics( const defaultTelemetrySavedObject = { ui_open: { overview: 0, - cluster: 0, - indices: 0, + elasticsearch: 0, kibana: 0, }, ui_reindex: { @@ -96,8 +95,7 @@ export async function fetchUpgradeAssistantMetrics( return { ui_open: { overview: get(upgradeAssistantTelemetrySavedObjectAttrs, 'ui_open.overview', 0), - cluster: get(upgradeAssistantTelemetrySavedObjectAttrs, 'ui_open.cluster', 0), - indices: get(upgradeAssistantTelemetrySavedObjectAttrs, 'ui_open.indices', 0), + elasticsearch: get(upgradeAssistantTelemetrySavedObjectAttrs, 'ui_open.elasticsearch', 0), kibana: get(upgradeAssistantTelemetrySavedObjectAttrs, 'ui_open.kibana', 0), }, ui_reindex: { @@ -146,18 +144,10 @@ export function registerUpgradeAssistantUsageCollector({ }, }, ui_open: { - cluster: { + elasticsearch: { type: 'long', _meta: { - description: - 'Number of times a user viewed the list of Elasticsearch cluster deprecations.', - }, - }, - indices: { - type: 'long', - _meta: { - description: - 'Number of times a user viewed the list of Elasticsearch index deprecations.', + description: 'Number of times a user viewed the list of Elasticsearch deprecations.', }, }, overview: { diff --git a/x-pack/plugins/upgrade_assistant/server/routes/es_deprecations.test.ts b/x-pack/plugins/upgrade_assistant/server/routes/es_deprecations.test.ts index 9603eae18d9c1..bea74f116e0e2 100644 --- a/x-pack/plugins/upgrade_assistant/server/routes/es_deprecations.test.ts +++ b/x-pack/plugins/upgrade_assistant/server/routes/es_deprecations.test.ts @@ -44,9 +44,8 @@ describe('ES deprecations API', () => { describe('GET /api/upgrade_assistant/es_deprecations', () => { it('returns state', async () => { ESUpgradeStatusApis.getESUpgradeStatus.mockResolvedValue({ - cluster: [], - indices: [], - nodes: [], + deprecations: [], + totalCriticalDeprecations: 0, }); const resp = await routeDependencies.router.getHandler({ method: 'get', @@ -55,15 +54,18 @@ describe('ES deprecations API', () => { expect(resp.status).toEqual(200); expect(JSON.stringify(resp.payload)).toMatchInlineSnapshot( - `"{\\"cluster\\":[],\\"indices\\":[],\\"nodes\\":[]}"` + `"{\\"deprecations\\":[],\\"totalCriticalDeprecations\\":0}"` ); }); it('returns an 403 error if it throws forbidden', async () => { - const e: any = new Error(`you can't go here!`); - e.statusCode = 403; + const error = { + name: 'ResponseError', + message: `you can't go here!`, + statusCode: 403, + }; - ESUpgradeStatusApis.getESUpgradeStatus.mockRejectedValue(e); + ESUpgradeStatusApis.getESUpgradeStatus.mockRejectedValue(error); const resp = await routeDependencies.router.getHandler({ method: 'get', pathPattern: '/api/upgrade_assistant/es_deprecations', diff --git a/x-pack/plugins/upgrade_assistant/server/routes/es_deprecations.ts b/x-pack/plugins/upgrade_assistant/server/routes/es_deprecations.ts index 395fa04af9173..eb0ade26de766 100644 --- a/x-pack/plugins/upgrade_assistant/server/routes/es_deprecations.ts +++ b/x-pack/plugins/upgrade_assistant/server/routes/es_deprecations.ts @@ -11,6 +11,7 @@ import { versionCheckHandlerWrapper } from '../lib/es_version_precheck'; import { RouteDependencies } from '../types'; import { reindexActionsFactory } from '../lib/reindexing/reindex_actions'; import { reindexServiceFactory } from '../lib/reindexing'; +import { handleEsError } from '../shared_imports'; export function registerESDeprecationRoutes({ router, licensing, log }: RouteDependencies) { router.get( @@ -40,7 +41,7 @@ export function registerESDeprecationRoutes({ router, licensing, log }: RouteDep log, licensing ); - const indexNames = status.indices + const indexNames = status.deprecations .filter(({ index }) => typeof index !== 'undefined') .map(({ index }) => index as string); @@ -50,11 +51,7 @@ export function registerESDeprecationRoutes({ router, licensing, log }: RouteDep body: status, }); } catch (e) { - if (e.statusCode === 403) { - return response.forbidden(e.message); - } - - throw e; + return handleEsError({ error: e, response }); } } ) diff --git a/x-pack/plugins/upgrade_assistant/server/routes/telemetry.test.ts b/x-pack/plugins/upgrade_assistant/server/routes/telemetry.test.ts index 05ad542ec9c00..578cceb702751 100644 --- a/x-pack/plugins/upgrade_assistant/server/routes/telemetry.test.ts +++ b/x-pack/plugins/upgrade_assistant/server/routes/telemetry.test.ts @@ -44,8 +44,8 @@ describe('Upgrade Assistant Telemetry API', () => { it('returns correct payload with single option', async () => { const returnPayload = { overview: true, - cluster: false, - indices: false, + elasticsearch: false, + kibana: false, }; (upsertUIOpenOption as jest.Mock).mockResolvedValue(returnPayload); @@ -65,8 +65,8 @@ describe('Upgrade Assistant Telemetry API', () => { it('returns correct payload with multiple option', async () => { const returnPayload = { overview: true, - cluster: true, - indices: true, + elasticsearch: true, + kibana: true, }; (upsertUIOpenOption as jest.Mock).mockResolvedValue(returnPayload); @@ -79,8 +79,8 @@ describe('Upgrade Assistant Telemetry API', () => { createRequestMock({ body: { overview: true, - cluster: true, - indices: true, + elasticsearch: true, + kibana: true, }, }), kibanaResponseFactory diff --git a/x-pack/plugins/upgrade_assistant/server/routes/telemetry.ts b/x-pack/plugins/upgrade_assistant/server/routes/telemetry.ts index 4e9b4b9a472a9..d083b38c7c240 100644 --- a/x-pack/plugins/upgrade_assistant/server/routes/telemetry.ts +++ b/x-pack/plugins/upgrade_assistant/server/routes/telemetry.ts @@ -18,19 +18,17 @@ export function registerTelemetryRoutes({ router, getSavedObjectsService }: Rout validate: { body: schema.object({ overview: schema.boolean({ defaultValue: false }), - cluster: schema.boolean({ defaultValue: false }), - indices: schema.boolean({ defaultValue: false }), + elasticsearch: schema.boolean({ defaultValue: false }), kibana: schema.boolean({ defaultValue: false }), }), }, }, async (ctx, request, response) => { - const { cluster, indices, overview, kibana } = request.body; + const { elasticsearch, overview, kibana } = request.body; return response.ok({ body: await upsertUIOpenOption({ savedObjects: getSavedObjectsService(), - cluster, - indices, + elasticsearch, overview, kibana, }), diff --git a/x-pack/plugins/upgrade_assistant/server/saved_object_types/telemetry_saved_object_type.ts b/x-pack/plugins/upgrade_assistant/server/saved_object_types/telemetry_saved_object_type.ts index f76c07da678da..42d5d339dd050 100644 --- a/x-pack/plugins/upgrade_assistant/server/saved_object_types/telemetry_saved_object_type.ts +++ b/x-pack/plugins/upgrade_assistant/server/saved_object_types/telemetry_saved_object_type.ts @@ -21,11 +21,7 @@ export const telemetrySavedObjectType: SavedObjectsType = { type: 'long', null_value: 0, }, - cluster: { - type: 'long', - null_value: 0, - }, - indices: { + elasticsearch: { type: 'long', null_value: 0, }, From d91368292825e4777980a0a4f479cf250a5bd155 Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Fri, 20 Aug 2021 12:22:52 -0400 Subject: [PATCH 31/76] [Security solution] [Endpoint] Remove linked policy from trusted apps when removing endpoint integration (#108347) (#109296) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Remove policy from trusted app when this is removed from fleet * Fleet: run package delete external callbacks when the Agent Policy is deleted Co-authored-by: David Sánchez --- .../fleet/register_fleet_policy_callbacks.ts | 9 ++- x-pack/plugins/fleet/common/mocks.ts | 13 +++- x-pack/plugins/fleet/server/mocks/index.ts | 5 +- .../server/routes/package_policy/handlers.ts | 1 + .../server/services/agent_policy.test.ts | 35 +++++++++ .../fleet/server/services/agent_policy.ts | 10 ++- .../server/services/package_policy.test.ts | 78 +++++++++++++++++++ .../fleet/server/services/package_policy.ts | 45 ++++++++--- .../plugins/fleet/server/types/extensions.ts | 6 +- .../endpoint/endpoint_app_context_services.ts | 6 ++ .../fleet_integration.test.ts | 72 ++++++++++++++++- .../fleet_integration/fleet_integration.ts | 23 ++++++ .../remove_policy_from_trusted_apps.ts | 61 +++++++++++++++ 13 files changed, 340 insertions(+), 24 deletions(-) create mode 100644 x-pack/plugins/security_solution/server/fleet_integration/handlers/remove_policy_from_trusted_apps.ts diff --git a/x-pack/plugins/apm/server/lib/fleet/register_fleet_policy_callbacks.ts b/x-pack/plugins/apm/server/lib/fleet/register_fleet_policy_callbacks.ts index 428378178afc8..6fcd0433e2e83 100644 --- a/x-pack/plugins/apm/server/lib/fleet/register_fleet_policy_callbacks.ts +++ b/x-pack/plugins/apm/server/lib/fleet/register_fleet_policy_callbacks.ts @@ -7,8 +7,7 @@ import { APMPlugin, APMRouteHandlerResources } from '../..'; import { - ExternalCallback, - PostPackagePolicyDeleteCallback, + PostPackagePolicyCreateCallback, PutPackagePolicyUpdateCallback, } from '../../../../fleet/server'; import { @@ -60,7 +59,9 @@ export async function registerFleetPolicyCallbacks({ }); } -type ExternalCallbackParams = Parameters; +type ExternalCallbackParams = + | Parameters + | Parameters; export type PackagePolicy = NewPackagePolicy | UpdatePackagePolicy; type Context = ExternalCallbackParams[1]; type Request = ExternalCallbackParams[2]; @@ -81,7 +82,7 @@ function registerPackagePolicyExternalCallback({ logger: NonNullable; }) { const callbackFn: - | PostPackagePolicyDeleteCallback + | PostPackagePolicyCreateCallback | PutPackagePolicyUpdateCallback = async ( packagePolicy: PackagePolicy, context: Context, diff --git a/x-pack/plugins/fleet/common/mocks.ts b/x-pack/plugins/fleet/common/mocks.ts index 7ea4be0ee35c6..eb81ea2d6a0ac 100644 --- a/x-pack/plugins/fleet/common/mocks.ts +++ b/x-pack/plugins/fleet/common/mocks.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { NewPackagePolicy, PackagePolicy } from './types'; +import type { NewPackagePolicy, PackagePolicy, DeletePackagePoliciesResponse } from './types'; export const createNewPackagePolicyMock = (): NewPackagePolicy => { return { @@ -45,3 +45,14 @@ export const createPackagePolicyMock = (): PackagePolicy => { ], }; }; + +export const deletePackagePolicyMock = (): DeletePackagePoliciesResponse => { + const newPackagePolicy = createNewPackagePolicyMock(); + return [ + { + id: 'c6d16e42-c32d-4dce-8a88-113cfe276ad1', + success: true, + package: newPackagePolicy.package, + }, + ]; +}; diff --git a/x-pack/plugins/fleet/server/mocks/index.ts b/x-pack/plugins/fleet/server/mocks/index.ts index 9f07dfac9670b..43b455045e72b 100644 --- a/x-pack/plugins/fleet/server/mocks/index.ts +++ b/x-pack/plugins/fleet/server/mocks/index.ts @@ -62,7 +62,7 @@ export const xpackMocks = { createRequestHandlerContext: createCoreRequestHandlerContextMock, }; -export const createPackagePolicyServiceMock = () => { +export const createPackagePolicyServiceMock = (): jest.Mocked => { return { compilePackagePolicyInputs: jest.fn(), buildPackagePolicyFromPackage: jest.fn(), @@ -75,10 +75,11 @@ export const createPackagePolicyServiceMock = () => { listIds: jest.fn(), update: jest.fn(), runExternalCallbacks: jest.fn(), + runDeleteExternalCallbacks: jest.fn(), upgrade: jest.fn(), getUpgradeDryRunDiff: jest.fn(), getUpgradePackagePolicyInfo: jest.fn(), - } as jest.Mocked; + }; }; /** diff --git a/x-pack/plugins/fleet/server/routes/package_policy/handlers.ts b/x-pack/plugins/fleet/server/routes/package_policy/handlers.ts index b9f0f6c69d4e7..77e7a2c4ede1a 100644 --- a/x-pack/plugins/fleet/server/routes/package_policy/handlers.ts +++ b/x-pack/plugins/fleet/server/routes/package_policy/handlers.ts @@ -181,6 +181,7 @@ export const deletePackagePolicyHandler: RequestHandler< } catch (error) { const logger = appContextService.getLogger(); logger.error(`An error occurred executing external callback: ${error}`); + logger.error(error); } return response.ok({ body, diff --git a/x-pack/plugins/fleet/server/services/agent_policy.test.ts b/x-pack/plugins/fleet/server/services/agent_policy.test.ts index a020b95ca3302..3267b2b7e2665 100644 --- a/x-pack/plugins/fleet/server/services/agent_policy.test.ts +++ b/x-pack/plugins/fleet/server/services/agent_policy.test.ts @@ -12,6 +12,9 @@ import type { AgentPolicy, NewAgentPolicy, Output } from '../types'; import { agentPolicyService } from './agent_policy'; import { agentPolicyUpdateEventHandler } from './agent_policy_update'; +import { getAgentsByKuery } from './agents'; +import { packagePolicyService } from './package_policy'; + function getSavedObjectMock(agentPolicyAttributes: any) { const mock = savedObjectsClientMock.create(); mock.get.mockImplementation(async (type: string, id: string) => { @@ -63,6 +66,8 @@ jest.mock('./output', () => { }); jest.mock('./agent_policy_update'); +jest.mock('./agents'); +jest.mock('./package_policy'); function getAgentPolicyUpdateMock() { return (agentPolicyUpdateEventHandler as unknown) as jest.Mock< @@ -123,6 +128,36 @@ describe('agent policy', () => { }); }); + describe('delete', () => { + let soClient: ReturnType; + let esClient: ReturnType['asInternalUser']; + + beforeEach(() => { + soClient = getSavedObjectMock({ revision: 1, package_policies: ['package-1'] }); + esClient = elasticsearchServiceMock.createClusterClient().asInternalUser; + + (getAgentsByKuery as jest.Mock).mockResolvedValue({ + agents: [], + total: 0, + page: 1, + perPage: 10, + }); + + (packagePolicyService.delete as jest.Mock).mockResolvedValue([ + { + id: 'package-1', + }, + ]); + }); + + it('should run package policy delete external callbacks', async () => { + await agentPolicyService.delete(soClient, esClient, 'mocked'); + expect(packagePolicyService.runDeleteExternalCallbacks).toHaveBeenCalledWith([ + { id: 'package-1' }, + ]); + }); + }); + describe('bumpRevision', () => { it('should call agentPolicyUpdateEventHandler with updated event once', async () => { const soClient = getSavedObjectMock({ diff --git a/x-pack/plugins/fleet/server/services/agent_policy.ts b/x-pack/plugins/fleet/server/services/agent_policy.ts index d3cccd4c07f3c..8539db05ffb54 100644 --- a/x-pack/plugins/fleet/server/services/agent_policy.ts +++ b/x-pack/plugins/fleet/server/services/agent_policy.ts @@ -45,6 +45,7 @@ import type { FleetServerPolicy, Installation, Output, + DeletePackagePoliciesResponse, } from '../../common'; import { AgentPolicyNameExistsError, HostedAgentPolicyRestrictionRelatedError } from '../errors'; import { @@ -616,7 +617,7 @@ class AgentPolicyService { } if (agentPolicy.package_policies && agentPolicy.package_policies.length) { - await packagePolicyService.delete( + const deletedPackagePolicies: DeletePackagePoliciesResponse = await packagePolicyService.delete( soClient, esClient, agentPolicy.package_policies as string[], @@ -624,6 +625,13 @@ class AgentPolicyService { skipUnassignFromAgentPolicies: true, } ); + try { + await packagePolicyService.runDeleteExternalCallbacks(deletedPackagePolicies); + } catch (error) { + const logger = appContextService.getLogger(); + logger.error(`An error occurred executing external callback: ${error}`); + logger.error(error); + } } if (agentPolicy.is_preconfigured) { diff --git a/x-pack/plugins/fleet/server/services/package_policy.test.ts b/x-pack/plugins/fleet/server/services/package_policy.test.ts index 66128c7e6c3e2..204650574e92a 100644 --- a/x-pack/plugins/fleet/server/services/package_policy.test.ts +++ b/x-pack/plugins/fleet/server/services/package_policy.test.ts @@ -20,6 +20,12 @@ import type { PutPackagePolicyUpdateCallback, PostPackagePolicyCreateCallback } import { createAppContextStartContractMock, xpackMocks } from '../mocks'; +import type { PostPackagePolicyDeleteCallback } from '../types'; + +import type { DeletePackagePoliciesResponse } from '../../common'; + +import { IngestManagerError } from '../errors'; + import { packagePolicyService } from './package_policy'; import { appContextService } from './app_context'; @@ -815,6 +821,78 @@ describe('Package policy service', () => { }); }); + describe('runDeleteExternalCallbacks', () => { + let callbackOne: jest.MockedFunction; + let callbackTwo: jest.MockedFunction; + let callingOrder: string[]; + let deletedPackagePolicies: DeletePackagePoliciesResponse; + + beforeEach(() => { + appContextService.start(createAppContextStartContractMock()); + callingOrder = []; + deletedPackagePolicies = [ + { id: 'a', success: true }, + { id: 'a', success: true }, + ]; + callbackOne = jest.fn(async (deletedPolicies) => { + callingOrder.push('one'); + }); + callbackTwo = jest.fn(async (deletedPolicies) => { + callingOrder.push('two'); + }); + appContextService.addExternalCallback('postPackagePolicyDelete', callbackOne); + appContextService.addExternalCallback('postPackagePolicyDelete', callbackTwo); + }); + + afterEach(() => { + appContextService.stop(); + }); + + it('should execute external callbacks', async () => { + await packagePolicyService.runDeleteExternalCallbacks(deletedPackagePolicies); + + expect(callbackOne).toHaveBeenCalledWith(deletedPackagePolicies); + expect(callbackTwo).toHaveBeenCalledWith(deletedPackagePolicies); + expect(callingOrder).toEqual(['one', 'two']); + }); + + it("should execute all external callbacks even if one throw's", async () => { + callbackOne.mockImplementation(async (deletedPolicies) => { + callingOrder.push('one'); + throw new Error('foo'); + }); + await expect( + packagePolicyService.runDeleteExternalCallbacks(deletedPackagePolicies) + ).rejects.toThrow(IngestManagerError); + expect(callingOrder).toEqual(['one', 'two']); + }); + + it('should provide an array of errors encountered by running external callbacks', async () => { + let error: IngestManagerError; + const callbackOneError = new Error('foo 1'); + const callbackTwoError = new Error('foo 2'); + + callbackOne.mockImplementation(async (deletedPolicies) => { + callingOrder.push('one'); + throw callbackOneError; + }); + callbackTwo.mockImplementation(async (deletedPolicies) => { + callingOrder.push('two'); + throw callbackTwoError; + }); + + await packagePolicyService.runDeleteExternalCallbacks(deletedPackagePolicies).catch((e) => { + error = e; + }); + + expect(error!.message).toEqual( + '2 encountered while executing package delete external callbacks' + ); + expect(error!.meta).toEqual([callbackOneError, callbackTwoError]); + expect(callingOrder).toEqual(['one', 'two']); + }); + }); + describe('runExternalCallbacks', () => { let context: ReturnType; let request: KibanaRequest; diff --git a/x-pack/plugins/fleet/server/services/package_policy.ts b/x-pack/plugins/fleet/server/services/package_policy.ts index 561cbef952f8d..61152b07f793b 100644 --- a/x-pack/plugins/fleet/server/services/package_policy.ts +++ b/x-pack/plugins/fleet/server/services/package_policy.ts @@ -428,9 +428,9 @@ class PackagePolicyService { name: packagePolicy.name, success: true, package: { - name: packagePolicy.name, - title: '', - version: packagePolicy.version || '', + name: packagePolicy.package?.name || '', + title: packagePolicy.package?.title || '', + version: packagePolicy.package?.version || '', }, }); } catch (error) { @@ -642,7 +642,9 @@ class PackagePolicyService { public async runExternalCallbacks( externalCallbackType: A, - packagePolicy: NewPackagePolicy | DeletePackagePoliciesResponse, + packagePolicy: A extends 'postPackagePolicyDelete' + ? DeletePackagePoliciesResponse + : NewPackagePolicy, context: RequestHandlerContext, request: KibanaRequest ): Promise; @@ -653,14 +655,7 @@ class PackagePolicyService { request: KibanaRequest ): Promise { if (externalCallbackType === 'postPackagePolicyDelete') { - const externalCallbacks = appContextService.getExternalCallbacks(externalCallbackType); - if (externalCallbacks && externalCallbacks.size > 0) { - for (const callback of externalCallbacks) { - if (Array.isArray(packagePolicy)) { - await callback(packagePolicy, context, request); - } - } - } + return await this.runDeleteExternalCallbacks(packagePolicy as DeletePackagePoliciesResponse); } else { if (!Array.isArray(packagePolicy)) { let newData = packagePolicy; @@ -682,6 +677,32 @@ class PackagePolicyService { } } } + + public async runDeleteExternalCallbacks( + deletedPackagePolicies: DeletePackagePoliciesResponse + ): Promise { + const externalCallbacks = appContextService.getExternalCallbacks('postPackagePolicyDelete'); + const errorsThrown: Error[] = []; + + if (externalCallbacks && externalCallbacks.size > 0) { + for (const callback of externalCallbacks) { + // Failures from an external callback should not prevent other external callbacks from being + // executed. Errors (if any) will be collected and `throw`n after processing the entire set + try { + await callback(deletedPackagePolicies); + } catch (error) { + errorsThrown.push(error); + } + } + + if (errorsThrown.length > 0) { + throw new IngestManagerError( + `${errorsThrown.length} encountered while executing package delete external callbacks`, + errorsThrown + ); + } + } + } } function assignStreamIdToInput(packagePolicyId: string, input: NewPackagePolicyInput) { diff --git a/x-pack/plugins/fleet/server/types/extensions.ts b/x-pack/plugins/fleet/server/types/extensions.ts index bca9cc016f828..a7f4a422cc2ae 100644 --- a/x-pack/plugins/fleet/server/types/extensions.ts +++ b/x-pack/plugins/fleet/server/types/extensions.ts @@ -7,6 +7,8 @@ import type { KibanaRequest, RequestHandlerContext } from 'kibana/server'; +import type { DeepReadonly } from 'utility-types'; + import type { DeletePackagePoliciesResponse, NewPackagePolicy, @@ -14,9 +16,7 @@ import type { } from '../../common'; export type PostPackagePolicyDeleteCallback = ( - deletedPackagePolicies: DeletePackagePoliciesResponse, - context: RequestHandlerContext, - request: KibanaRequest + deletedPackagePolicies: DeepReadonly ) => Promise; export type PostPackagePolicyCreateCallback = ( diff --git a/x-pack/plugins/security_solution/server/endpoint/endpoint_app_context_services.ts b/x-pack/plugins/security_solution/server/endpoint/endpoint_app_context_services.ts index 9a46aacf247c9..9df371be24d9e 100644 --- a/x-pack/plugins/security_solution/server/endpoint/endpoint_app_context_services.ts +++ b/x-pack/plugins/security_solution/server/endpoint/endpoint_app_context_services.ts @@ -18,6 +18,7 @@ import { PluginStartContract as AlertsPluginStartContract } from '../../../alert import { getPackagePolicyCreateCallback, getPackagePolicyUpdateCallback, + getPackagePolicyDeleteCallback, } from '../fleet_integration/fleet_integration'; import { ManifestManager } from './services/artifacts'; import { AppClientFactory } from '../client'; @@ -102,6 +103,11 @@ export class EndpointAppContextService { 'packagePolicyUpdate', getPackagePolicyUpdateCallback(dependencies.logger, dependencies.licenseService) ); + + dependencies.registerIngestCallback( + 'postPackagePolicyDelete', + getPackagePolicyDeleteCallback(dependencies.exceptionListsClient, this.experimentalFeatures) + ); } } diff --git a/x-pack/plugins/security_solution/server/fleet_integration/fleet_integration.test.ts b/x-pack/plugins/security_solution/server/fleet_integration/fleet_integration.test.ts index 56c462de54c52..d0bbb3b346ea8 100644 --- a/x-pack/plugins/security_solution/server/fleet_integration/fleet_integration.test.ts +++ b/x-pack/plugins/security_solution/server/fleet_integration/fleet_integration.test.ts @@ -6,7 +6,7 @@ */ import { httpServerMock, loggingSystemMock } from 'src/core/server/mocks'; -import { createNewPackagePolicyMock } from '../../../fleet/common/mocks'; +import { createNewPackagePolicyMock, deletePackagePolicyMock } from '../../../fleet/common/mocks'; import { policyFactory, policyFactoryWithoutPaidFeatures, @@ -14,6 +14,7 @@ import { import { buildManifestManagerMock } from '../endpoint/services/artifacts/manifest_manager/manifest_manager.mock'; import { getPackagePolicyCreateCallback, + getPackagePolicyDeleteCallback, getPackagePolicyUpdateCallback, } from './fleet_integration'; import { KibanaRequest } from 'kibana/server'; @@ -28,6 +29,7 @@ import { EndpointDocGenerator } from '../../common/endpoint/generate_data'; import { ProtectionModes } from '../../common/endpoint/types'; import type { SecuritySolutionRequestHandlerContext } from '../types'; import { getExceptionListClientMock } from '../../../lists/server/services/exception_lists/exception_list_client.mock'; +import { getExceptionListSchemaMock } from '../../../lists/common/schemas/response/exception_list_schema.mock'; import { ExceptionListClient } from '../../../lists/server'; import { InternalArtifactCompleteSchema } from '../endpoint/schemas/artifacts'; import { ManifestManager } from '../endpoint/services/artifacts/manifest_manager'; @@ -35,6 +37,12 @@ import { getMockArtifacts, toArtifactRecords } from '../endpoint/lib/artifacts/m import { Manifest } from '../endpoint/lib/artifacts'; import { NewPackagePolicy } from '../../../fleet/common/types/models'; import { ManifestSchema } from '../../common/endpoint/schema/manifest'; +import { + allowedExperimentalValues, + ExperimentalFeatures, +} from '../../common/experimental_features'; +import { DeletePackagePoliciesResponse } from '../../../fleet/common'; +import { ExceptionListSchema } from '@kbn/securitysolution-io-ts-list-types'; describe('ingest_integration tests ', () => { let endpointAppContextMock: EndpointAppContextServiceStartContract; @@ -282,4 +290,66 @@ describe('ingest_integration tests ', () => { expect(updatedPolicyConfig.inputs[0]!.config!.policy.value).toEqual(mockPolicy); }); }); + + describe('package policy delete callback with trusted apps by policy enabled', () => { + const invokeDeleteCallback = async ( + experimentalFeatures?: ExperimentalFeatures + ): Promise => { + const callback = getPackagePolicyDeleteCallback(exceptionListClient, experimentalFeatures); + await callback(deletePackagePolicyMock()); + }; + + let removedPolicies: DeletePackagePoliciesResponse; + let policyId: string; + let fakeTA: ExceptionListSchema; + + beforeEach(() => { + removedPolicies = deletePackagePolicyMock(); + policyId = removedPolicies[0].id; + fakeTA = { + ...getExceptionListSchemaMock(), + tags: [`policy:${policyId}`], + }; + + exceptionListClient.findExceptionListItem = jest + .fn() + .mockResolvedValueOnce({ data: [fakeTA], total: 1 }); + exceptionListClient.updateExceptionListItem = jest + .fn() + .mockResolvedValueOnce({ ...fakeTA, tags: [] }); + }); + + it('removes policy from trusted app FF enabled', async () => { + await invokeDeleteCallback({ + ...allowedExperimentalValues, + trustedAppsByPolicyEnabled: true, // Needs to be enabled, it needs also a test with this disabled. + }); + + expect(exceptionListClient.findExceptionListItem).toHaveBeenCalledWith({ + filter: `exception-list-agnostic.attributes.tags:"policy:${policyId}"`, + listId: 'endpoint_trusted_apps', + namespaceType: 'agnostic', + page: 1, + perPage: 50, + sortField: undefined, + sortOrder: undefined, + }); + + expect(exceptionListClient.updateExceptionListItem).toHaveBeenCalledWith({ + ...fakeTA, + namespaceType: fakeTA.namespace_type, + osTypes: fakeTA.os_types, + tags: [], + }); + }); + + it("doesn't remove policy from trusted app FF disabled", async () => { + await invokeDeleteCallback({ + ...allowedExperimentalValues, + }); + + expect(exceptionListClient.findExceptionListItem).toHaveBeenCalledTimes(0); + expect(exceptionListClient.updateExceptionListItem).toHaveBeenCalledTimes(0); + }); + }); }); diff --git a/x-pack/plugins/security_solution/server/fleet_integration/fleet_integration.ts b/x-pack/plugins/security_solution/server/fleet_integration/fleet_integration.ts index 62c7b3719d6a6..09810a6c88c3d 100644 --- a/x-pack/plugins/security_solution/server/fleet_integration/fleet_integration.ts +++ b/x-pack/plugins/security_solution/server/fleet_integration/fleet_integration.ts @@ -11,9 +11,12 @@ import { PluginStartContract as AlertsStartContract } from '../../../alerting/se import { SecurityPluginStart } from '../../../security/server'; import { PostPackagePolicyCreateCallback, + PostPackagePolicyDeleteCallback, PutPackagePolicyUpdateCallback, } from '../../../fleet/server'; + import { NewPackagePolicy, UpdatePackagePolicy } from '../../../fleet/common'; + import { NewPolicyData, PolicyConfig } from '../../common/endpoint/types'; import { ManifestManager } from '../endpoint/services'; import { AppClientFactory } from '../client'; @@ -22,6 +25,8 @@ import { installPrepackagedRules } from './handlers/install_prepackaged_rules'; import { createPolicyArtifactManifest } from './handlers/create_policy_artifact_manifest'; import { createDefaultPolicy } from './handlers/create_default_policy'; import { validatePolicyAgainstLicense } from './handlers/validate_policy_against_license'; +import { removePolicyFromTrustedApps } from './handlers/remove_policy_from_trusted_apps'; +import { ExperimentalFeatures } from '../../common/experimental_features'; const isEndpointPackagePolicy = ( packagePolicy: T @@ -126,3 +131,21 @@ export const getPackagePolicyUpdateCallback = ( return newPackagePolicy; }; }; + +export const getPackagePolicyDeleteCallback = ( + exceptionsClient: ExceptionListClient | undefined, + experimentalFeatures: ExperimentalFeatures | undefined +): PostPackagePolicyDeleteCallback => { + return async (deletePackagePolicy): Promise => { + if (!exceptionsClient) { + return; + } + const policiesToRemove: Array> = []; + for (const policy of deletePackagePolicy) { + if (isEndpointPackagePolicy(policy) && experimentalFeatures?.trustedAppsByPolicyEnabled) { + policiesToRemove.push(removePolicyFromTrustedApps(exceptionsClient, policy)); + } + } + await Promise.all(policiesToRemove); + }; +}; diff --git a/x-pack/plugins/security_solution/server/fleet_integration/handlers/remove_policy_from_trusted_apps.ts b/x-pack/plugins/security_solution/server/fleet_integration/handlers/remove_policy_from_trusted_apps.ts new file mode 100644 index 0000000000000..88af71508f33a --- /dev/null +++ b/x-pack/plugins/security_solution/server/fleet_integration/handlers/remove_policy_from_trusted_apps.ts @@ -0,0 +1,61 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { ENDPOINT_TRUSTED_APPS_LIST_ID } from '@kbn/securitysolution-list-constants'; +import { ExceptionListClient } from '../../../../lists/server'; +import { PostPackagePolicyDeleteCallback } from '../../../../fleet/server'; + +/** + * Removes policy from trusted apps + */ +export const removePolicyFromTrustedApps = async ( + exceptionsClient: ExceptionListClient, + policy: Parameters[0][0] +) => { + let page = 1; + + const findTrustedAppsByPolicy = async (currentPage: number) => { + return exceptionsClient.findExceptionListItem({ + listId: ENDPOINT_TRUSTED_APPS_LIST_ID, + filter: `exception-list-agnostic.attributes.tags:"policy:${policy.id}"`, + namespaceType: 'agnostic', + page: currentPage, + perPage: 50, + sortField: undefined, + sortOrder: undefined, + }); + }; + + let findResponse = await findTrustedAppsByPolicy(page); + if (!findResponse) { + return; + } + const trustedApps = findResponse.data; + + while (findResponse && (trustedApps.length < findResponse.total || findResponse.data.length)) { + page += 1; + findResponse = await findTrustedAppsByPolicy(page); + if (findResponse) { + trustedApps.push(...findResponse.data); + } + } + + const updates = []; + for (const trustedApp of trustedApps) { + updates.push( + exceptionsClient.updateExceptionListItem({ + ...trustedApp, + itemId: trustedApp.item_id, + namespaceType: trustedApp.namespace_type, + osTypes: trustedApp.os_types, + tags: trustedApp.tags.filter((currentPolicy) => currentPolicy !== `policy:${policy.id}`), + }) + ); + } + + await Promise.all(updates); +}; From 5b2da7e66baabf343e901e2b0566be0c788a933f Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Fri, 20 Aug 2021 12:31:32 -0400 Subject: [PATCH 32/76] [APM] Hash-based links into APM app don't work (#108777) (#109342) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fixing navigation issues * addressing PR comments Co-authored-by: Cauê Marcondes <55978943+cauemarcondes@users.noreply.github.com> --- .../components/routing/apm_route_config.tsx | 6 ++ .../public/components/routing/home/index.tsx | 4 +- .../public/components/routing/redirect_to.tsx | 63 ++++++++++++------- 3 files changed, 48 insertions(+), 25 deletions(-) diff --git a/x-pack/plugins/apm/public/components/routing/apm_route_config.tsx b/x-pack/plugins/apm/public/components/routing/apm_route_config.tsx index 922662e25ab20..b751ef3f71190 100644 --- a/x-pack/plugins/apm/public/components/routing/apm_route_config.tsx +++ b/x-pack/plugins/apm/public/components/routing/apm_route_config.tsx @@ -53,6 +53,12 @@ const apmRoutes = route([ }), }), ]), + defaults: { + query: { + rangeFrom: 'now-15m', + rangeTo: 'now', + }, + }, }, { path: '/', diff --git a/x-pack/plugins/apm/public/components/routing/home/index.tsx b/x-pack/plugins/apm/public/components/routing/home/index.tsx index ce74a48fd8c86..d1304e192ddce 100644 --- a/x-pack/plugins/apm/public/components/routing/home/index.tsx +++ b/x-pack/plugins/apm/public/components/routing/home/index.tsx @@ -8,7 +8,7 @@ import { i18n } from '@kbn/i18n'; import { Outlet } from '@kbn/typed-react-router-config'; import * as t from 'io-ts'; import React from 'react'; -import { Redirect } from 'react-router-dom'; +import { RedirectTo } from '../redirect_to'; import { ENVIRONMENT_ALL } from '../../../../common/environment_filter_values'; import { environmentRt } from '../../../../common/environment_rt'; import { BackendDetailOverview } from '../../app/backend_detail_overview'; @@ -121,7 +121,7 @@ export const home = { }, { path: '/', - element: , + element: , }, ], } as const; diff --git a/x-pack/plugins/apm/public/components/routing/redirect_to.tsx b/x-pack/plugins/apm/public/components/routing/redirect_to.tsx index 68ff2fce77f13..7e5e01cadbf3e 100644 --- a/x-pack/plugins/apm/public/components/routing/redirect_to.tsx +++ b/x-pack/plugins/apm/public/components/routing/redirect_to.tsx @@ -6,33 +6,50 @@ */ import React from 'react'; -import { Redirect, RouteComponentProps } from 'react-router-dom'; +import { Location } from 'history'; +import { Redirect, useLocation, RouteComponentProps } from 'react-router-dom'; /** - * Given a path, redirect to that location, preserving the search and maintaining - * backward-compatibilty with legacy (pre-7.9) hash-based URLs. + * Function that returns a react component to redirect to a given pathname removing hash-based URLs + * @param pathname */ -export function redirectTo(to: string) { +export function redirectTo(pathname: string) { return ({ location }: RouteComponentProps<{}>) => { - let resolvedUrl: URL | undefined; + return ; + }; +} - // Redirect root URLs with a hash to support backward compatibility with URLs - // from before we switched to the non-hash platform history. - if (location.pathname === '' && location.hash.length > 0) { - // We just want the search and pathname so the host doesn't matter - resolvedUrl = new URL(location.hash.slice(1), 'http://localhost'); - to = resolvedUrl.pathname; - } +/** + * React component to redirect to a given pathname removing hash-based URLs + * @param param0 + */ +export function RedirectTo({ pathname }: { pathname: string }) { + const location = useLocation(); + return ; +} - return ( - - ); - }; +interface Props { + location: Location; + pathname: string; +} + +/** + * Given a pathname, redirect to that location, preserving the search and maintaining + * backward-compatibilty with legacy (pre-7.9) hash-based URLs. + */ +function RenderRedirectTo(props: Props) { + const { location } = props; + let search = location.search; + let pathname = props.pathname; + + // Redirect root URLs with a hash to support backward compatibility with URLs + // from before we switched to the non-hash platform history. + if (location.pathname === '' && location.hash.length > 0) { + // We just want the search and pathname so the host doesn't matter + const resolvedUrl = new URL(location.hash.slice(1), 'http://localhost'); + search = resolvedUrl.search; + pathname = resolvedUrl.pathname; + } + + return ; } From 6910a2ead7e6ade11ef66562491d4834f5ea23d3 Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Fri, 20 Aug 2021 12:35:06 -0400 Subject: [PATCH 33/76] [Observability RAC] add filter for value action (#108648) (#109079) * filter for value * code clean up * fix i18n tests * fix type errors * revert changes to reason field to make reason field clickable again * [RAC Observability] fix reason field * fix type issues * filter my kibana.alert. status on load (will refactor) * refactor filter for alert status on load * remove rest params * fix eslint errors * hard code alert status for now, will be fixed in another PR * move filter_for button in a separate file * fix errors * comply with kibana i18n guideines * simpler implementation for default filtering * fix syntax error * fix type errors * fix eslint errors * fix eslint errors Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: mgiota --- .../pages/alerts/alerts_table_t_grid.tsx | 15 ++-- .../pages/alerts/default_cell_actions.tsx | 69 ++++++------------- .../public/pages/alerts/filter_for_value.tsx | 64 +++++++++++++++++ .../public/pages/alerts/index.tsx | 22 +++++- .../public/pages/alerts/render_cell_value.tsx | 8 +-- 5 files changed, 119 insertions(+), 59 deletions(-) create mode 100644 x-pack/plugins/observability/public/pages/alerts/filter_for_value.tsx diff --git a/x-pack/plugins/observability/public/pages/alerts/alerts_table_t_grid.tsx b/x-pack/plugins/observability/public/pages/alerts/alerts_table_t_grid.tsx index 754e568e3befd..bbbd81b4e49ea 100644 --- a/x-pack/plugins/observability/public/pages/alerts/alerts_table_t_grid.tsx +++ b/x-pack/plugins/observability/public/pages/alerts/alerts_table_t_grid.tsx @@ -14,13 +14,13 @@ import { AlertConsumers as AlertConsumersTyped, ALERT_DURATION as ALERT_DURATION_TYPED, ALERT_STATUS as ALERT_STATUS_TYPED, - ALERT_RULE_NAME as ALERT_RULE_NAME_TYPED, + ALERT_REASON as ALERT_REASON_TYPED, ALERT_RULE_CONSUMER, } from '@kbn/rule-data-utils'; import { ALERT_DURATION as ALERT_DURATION_NON_TYPED, ALERT_STATUS as ALERT_STATUS_NON_TYPED, - ALERT_RULE_NAME as ALERT_RULE_NAME_NON_TYPED, + ALERT_REASON as ALERT_REASON_NON_TYPED, TIMESTAMP, // @ts-expect-error importing from a place other than root because we want to limit what we import from this package } from '@kbn/rule-data-utils/target_node/technical_field_names'; @@ -39,7 +39,6 @@ import { import { i18n } from '@kbn/i18n'; import styled from 'styled-components'; import React, { Suspense, useMemo, useState, useCallback } from 'react'; - import { get } from 'lodash'; import { useGetUserAlertsPermissions } from '../../hooks/use_alert_permission'; import type { TimelinesUIStart, TGridType, SortDirection } from '../../../../timelines/public'; @@ -65,7 +64,7 @@ import { CoreStart } from '../../../../../../src/core/public'; const AlertConsumers: typeof AlertConsumersTyped = AlertConsumersNonTyped; const ALERT_DURATION: typeof ALERT_DURATION_TYPED = ALERT_DURATION_NON_TYPED; const ALERT_STATUS: typeof ALERT_STATUS_TYPED = ALERT_STATUS_NON_TYPED; -const ALERT_RULE_NAME: typeof ALERT_RULE_NAME_TYPED = ALERT_RULE_NAME_NON_TYPED; +const ALERT_REASON: typeof ALERT_REASON_TYPED = ALERT_REASON_NON_TYPED; interface AlertsTableTGridProps { indexName: string; @@ -74,6 +73,7 @@ interface AlertsTableTGridProps { kuery: string; status: string; setRefetch: (ref: () => void) => void; + addToQuery: (value: string) => void; } interface ObservabilityActionsProps extends ActionProps { @@ -136,8 +136,8 @@ export const columns: Array< displayAsText: i18n.translate('xpack.observability.alertsTGrid.reasonColumnDescription', { defaultMessage: 'Reason', }), + id: ALERT_REASON, linkField: '*', - id: ALERT_RULE_NAME, }, ]; @@ -288,7 +288,7 @@ function ObservabilityActions({ } export function AlertsTableTGrid(props: AlertsTableTGridProps) { - const { indexName, rangeFrom, rangeTo, kuery, status, setRefetch } = props; + const { indexName, rangeFrom, rangeTo, kuery, status, setRefetch, addToQuery } = props; const { timelines } = useKibana<{ timelines: TimelinesUIStart }>().services; const [flyoutAlert, setFlyoutAlert] = useState(undefined); @@ -332,7 +332,7 @@ export function AlertsTableTGrid(props: AlertsTableTGridProps) { type, columns, deletedEventIds: [], - defaultCellActions: getDefaultCellActions({ enableFilterActions: false }), + defaultCellActions: getDefaultCellActions({ addToQuery }), end: rangeTo, filters: [], indexNames: [indexName], @@ -377,6 +377,7 @@ export function AlertsTableTGrid(props: AlertsTableTGridProps) { rangeTo, setRefetch, status, + addToQuery, ]); const handleFlyoutClose = () => setFlyoutAlert(undefined); const { observabilityRuleTypeRegistry } = usePluginContext(); diff --git a/x-pack/plugins/observability/public/pages/alerts/default_cell_actions.tsx b/x-pack/plugins/observability/public/pages/alerts/default_cell_actions.tsx index 3056b026fc27a..7e166ac99c05f 100644 --- a/x-pack/plugins/observability/public/pages/alerts/default_cell_actions.tsx +++ b/x-pack/plugins/observability/public/pages/alerts/default_cell_actions.tsx @@ -6,16 +6,18 @@ */ import React from 'react'; - +import { i18n } from '@kbn/i18n'; import { ObservabilityPublicPluginsStart } from '../..'; import { getMappedNonEcsValue } from './render_cell_value'; +import FilterForValueButton from './filter_for_value'; import { useKibana } from '../../../../../../src/plugins/kibana_react/public'; import { TimelineNonEcsData } from '../../../../timelines/common/search_strategy'; import { TGridCellAction } from '../../../../timelines/common/types/timeline'; import { TimelinesUIStart } from '../../../../timelines/public'; -/** a noop required by the filter in / out buttons */ -const onFilterAdded = () => {}; +export const FILTER_FOR_VALUE = i18n.translate('xpack.observability.hoverActions.filterForValue', { + defaultMessage: 'Filter for value', +}); /** a hook to eliminate the verbose boilerplate required to use common services */ const useKibanaServices = () => { @@ -31,32 +33,10 @@ const useKibanaServices = () => { return { timelines, filterManager }; }; -/** actions for adding filters to the search bar */ -const filterCellActions: TGridCellAction[] = [ - ({ data }: { data: TimelineNonEcsData[][] }) => ({ rowIndex, columnId, Component }) => { - const { timelines, filterManager } = useKibanaServices(); - - const value = getMappedNonEcsValue({ - data: data[rowIndex], - fieldName: columnId, - }); - - return ( - <> - {timelines.getHoverActions().getFilterForValueButton({ - Component, - field: columnId, - filterManager, - onFilterAdded, - ownFocus: false, - showTooltip: false, - value, - })} - - ); - }, +/** actions common to all cells (e.g. copy to clipboard) */ +const commonCellActions: TGridCellAction[] = [ ({ data }: { data: TimelineNonEcsData[][] }) => ({ rowIndex, columnId, Component }) => { - const { timelines, filterManager } = useKibanaServices(); + const { timelines } = useKibanaServices(); const value = getMappedNonEcsValue({ data: data[rowIndex], @@ -65,11 +45,10 @@ const filterCellActions: TGridCellAction[] = [ return ( <> - {timelines.getHoverActions().getFilterOutValueButton({ + {timelines.getHoverActions().getCopyButton({ Component, field: columnId, - filterManager, - onFilterAdded, + isHoverAction: false, ownFocus: false, showTooltip: false, value, @@ -79,31 +58,27 @@ const filterCellActions: TGridCellAction[] = [ }, ]; -/** actions common to all cells (e.g. copy to clipboard) */ -const commonCellActions: TGridCellAction[] = [ +/** actions for adding filters to the search bar */ +const buildFilterCellActions = (addToQuery: (value: string) => void): TGridCellAction[] => [ ({ data }: { data: TimelineNonEcsData[][] }) => ({ rowIndex, columnId, Component }) => { - const { timelines } = useKibanaServices(); - const value = getMappedNonEcsValue({ data: data[rowIndex], fieldName: columnId, }); return ( - <> - {timelines.getHoverActions().getCopyButton({ - Component, - field: columnId, - isHoverAction: false, - ownFocus: false, - showTooltip: false, - value, - })} - + ); }, ]; /** returns the default actions shown in `EuiDataGrid` cells */ -export const getDefaultCellActions = ({ enableFilterActions }: { enableFilterActions: boolean }) => - enableFilterActions ? [...filterCellActions, ...commonCellActions] : [...commonCellActions]; +export const getDefaultCellActions = ({ addToQuery }: { addToQuery: (value: string) => void }) => [ + ...buildFilterCellActions(addToQuery), + ...commonCellActions, +]; diff --git a/x-pack/plugins/observability/public/pages/alerts/filter_for_value.tsx b/x-pack/plugins/observability/public/pages/alerts/filter_for_value.tsx new file mode 100644 index 0000000000000..77cac9d482a37 --- /dev/null +++ b/x-pack/plugins/observability/public/pages/alerts/filter_for_value.tsx @@ -0,0 +1,64 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useCallback, useMemo } from 'react'; +import { i18n } from '@kbn/i18n'; + +export const filterForValueButtonLabel = i18n.translate( + 'xpack.observability.hoverActions.filterForValueButtonLabel', + { + defaultMessage: 'Filter for value', + } +); + +import { EuiButtonIcon, EuiButtonEmpty } from '@elastic/eui'; + +interface FilterForValueProps { + Component?: typeof EuiButtonEmpty | typeof EuiButtonIcon; + field: string; + value: string[] | string | null | undefined; + addToQuery: (value: string) => void; +} + +const FilterForValueButton: React.FC = React.memo( + ({ Component, field, value, addToQuery }) => { + const text = useMemo(() => `${field}${value != null ? `: "${value}"` : ''}`, [field, value]); + const onClick = useCallback(() => { + addToQuery(text); + }, [text, addToQuery]); + const button = useMemo( + () => + Component ? ( + + {filterForValueButtonLabel} + + ) : ( + + ), + [Component, onClick] + ); + return button; + } +); + +FilterForValueButton.displayName = 'FilterForValueButton'; + +// eslint-disable-next-line import/no-default-export +export { FilterForValueButton as default }; diff --git a/x-pack/plugins/observability/public/pages/alerts/index.tsx b/x-pack/plugins/observability/public/pages/alerts/index.tsx index baed76d49aac8..b3ff3f94dc4db 100644 --- a/x-pack/plugins/observability/public/pages/alerts/index.tsx +++ b/x-pack/plugins/observability/public/pages/alerts/index.tsx @@ -40,7 +40,12 @@ export function AlertsPage({ routeParams }: AlertsPageProps) { const history = useHistory(); const refetch = useRef<() => void>(); const { - query: { rangeFrom = 'now-15m', rangeTo = 'now', kuery = '', status = 'open' }, + query: { + rangeFrom = 'now-15m', + rangeTo = 'now', + kuery = 'kibana.alert.status: "open"', // TODO change hardcoded values as part of another PR + status = 'open', + }, } = routeParams; useBreadcrumbs([ @@ -98,6 +103,20 @@ export function AlertsPage({ routeParams }: AlertsPageProps) { [history, rangeFrom, rangeTo, kuery] ); + const addToQuery = useCallback( + (value: string) => { + let output = value; + if (kuery !== '') { + output = `${kuery} and ${value}`; + } + onQueryChange({ + dateRange: { from: rangeFrom, to: rangeTo }, + query: output, + }); + }, + [kuery, onQueryChange, rangeFrom, rangeTo] + ); + const setRefetch = useCallback((ref) => { refetch.current = ref; }, []); @@ -170,6 +189,7 @@ export function AlertsPage({ routeParams }: AlertsPageProps) { kuery={kuery} status={status} setRefetch={setRefetch} + addToQuery={addToQuery} />
diff --git a/x-pack/plugins/observability/public/pages/alerts/render_cell_value.tsx b/x-pack/plugins/observability/public/pages/alerts/render_cell_value.tsx index d96751b4eb33a..c85ea0b1086fa 100644 --- a/x-pack/plugins/observability/public/pages/alerts/render_cell_value.tsx +++ b/x-pack/plugins/observability/public/pages/alerts/render_cell_value.tsx @@ -16,13 +16,13 @@ import type { ALERT_DURATION as ALERT_DURATION_TYPED, ALERT_SEVERITY as ALERT_SEVERITY_TYPED, ALERT_STATUS as ALERT_STATUS_TYPED, - ALERT_RULE_NAME as ALERT_RULE_NAME_TYPED, + ALERT_REASON as ALERT_REASON_TYPED, } from '@kbn/rule-data-utils'; import { ALERT_DURATION as ALERT_DURATION_NON_TYPED, ALERT_SEVERITY as ALERT_SEVERITY_NON_TYPED, ALERT_STATUS as ALERT_STATUS_NON_TYPED, - ALERT_RULE_NAME as ALERT_RULE_NAME_NON_TYPED, + ALERT_REASON as ALERT_REASON_NON_TYPED, TIMESTAMP, // @ts-expect-error importing from a place other than root because we want to limit what we import from this package } from '@kbn/rule-data-utils/target_node/technical_field_names'; @@ -39,7 +39,7 @@ import { useTheme } from '../../hooks/use_theme'; const ALERT_DURATION: typeof ALERT_DURATION_TYPED = ALERT_DURATION_NON_TYPED; const ALERT_SEVERITY: typeof ALERT_SEVERITY_TYPED = ALERT_SEVERITY_NON_TYPED; const ALERT_STATUS: typeof ALERT_STATUS_TYPED = ALERT_STATUS_NON_TYPED; -const ALERT_RULE_NAME: typeof ALERT_RULE_NAME_TYPED = ALERT_RULE_NAME_NON_TYPED; +const ALERT_REASON: typeof ALERT_REASON_TYPED = ALERT_REASON_NON_TYPED; export const getMappedNonEcsValue = ({ data, @@ -120,7 +120,7 @@ export const getRenderCellValue = ({ return asDuration(Number(value)); case ALERT_SEVERITY: return ; - case ALERT_RULE_NAME: + case ALERT_REASON: const dataFieldEs = data.reduce((acc, d) => ({ ...acc, [d.field]: d.value }), {}); const alert = parseAlert(observabilityRuleTypeRegistry)(dataFieldEs); From ef2bc97d2d834b302e19eef5ef2671fd2a80bcf8 Mon Sep 17 00:00:00 2001 From: Devon Thomson Date: Fri, 20 Aug 2021 12:56:33 -0400 Subject: [PATCH 34/76] [Input Controls] Options List Data Fetch In Embeddable (#108226) (#109474) Moved data fetching from react component into embeddable class. This cleans up the component, and allows for more accurate comparison before firing async requests --- .../options_list/options_list_component.tsx | 151 +++++------------ .../options_list/options_list_embeddable.tsx | 152 +++++++++++++++++- .../options_list_popover_component.tsx | 10 +- .../input_controls/use_state_observable.ts | 23 +++ 4 files changed, 214 insertions(+), 122 deletions(-) create mode 100644 src/plugins/presentation_util/public/components/input_controls/use_state_observable.ts diff --git a/src/plugins/presentation_util/public/components/input_controls/control_types/options_list/options_list_component.tsx b/src/plugins/presentation_util/public/components/input_controls/control_types/options_list/options_list_component.tsx index 2feb527ff9160..4aff1ff4eee96 100644 --- a/src/plugins/presentation_util/public/components/input_controls/control_types/options_list/options_list_component.tsx +++ b/src/plugins/presentation_util/public/components/input_controls/control_types/options_list/options_list_component.tsx @@ -6,133 +6,63 @@ * Side Public License, v 1. */ -import React, { useMemo, useEffect, useState, useCallback, useRef } from 'react'; -import { debounceTime, tap } from 'rxjs/operators'; -import useMount from 'react-use/lib/useMount'; +import React, { useState } from 'react'; import classNames from 'classnames'; -import { Subject } from 'rxjs'; -import { EuiFilterButton, EuiFilterGroup, EuiPopover, EuiSelectableOption } from '@elastic/eui'; -import { - OptionsListDataFetcher, - OptionsListEmbeddable, - OptionsListEmbeddableInput, -} from './options_list_embeddable'; +import { EuiFilterButton, EuiFilterGroup, EuiPopover, EuiSelectableOption } from '@elastic/eui'; +import { Subject } from 'rxjs'; import { OptionsListStrings } from './options_list_strings'; -import { InputControlOutput } from '../../embeddable/types'; import { OptionsListPopover } from './options_list_popover_component'; -import { withEmbeddableSubscription } from '../../../../../../embeddable/public'; import './options_list.scss'; - -const toggleAvailableOptions = ( - indices: number[], - availableOptions: EuiSelectableOption[], - enabled: boolean -) => { - const newAvailableOptions = [...availableOptions]; - indices.forEach((index) => (newAvailableOptions[index].checked = enabled ? 'on' : undefined)); - return newAvailableOptions; -}; - -interface OptionsListProps { - input: OptionsListEmbeddableInput; - fetchData: OptionsListDataFetcher; +import { useStateObservable } from '../../use_state_observable'; + +export interface OptionsListComponentState { + availableOptions?: EuiSelectableOption[]; + selectedOptionsString?: string; + selectedOptionsCount?: number; + twoLineLayout?: boolean; + searchString?: string; + loading: boolean; } -export const OptionsListInner = ({ input, fetchData }: OptionsListProps) => { - const [availableOptions, setAvailableOptions] = useState([]); - const selectedOptions = useRef>(new Set()); - - // raw search string is stored here so it is remembered when popover is closed. - const [searchString, setSearchString] = useState(''); - const [debouncedSearchString, setDebouncedSearchString] = useState(); - +export const OptionsListComponent = ({ + componentStateSubject, + typeaheadSubject, + updateOption, +}: { + componentStateSubject: Subject; + typeaheadSubject: Subject; + updateOption: (index: number) => void; +}) => { const [isPopoverOpen, setIsPopoverOpen] = useState(false); - const [loading, setIsLoading] = useState(false); - - const typeaheadSubject = useMemo(() => new Subject(), []); - - useMount(() => { - typeaheadSubject - .pipe( - tap((rawSearchText) => setSearchString(rawSearchText)), - debounceTime(100) - ) - .subscribe((search) => setDebouncedSearchString(search)); - // default selections can be applied here... + const optionsListState = useStateObservable(componentStateSubject, { + loading: true, }); - const { indexPattern, timeRange, filters, field, query } = input; - useEffect(() => { - let canceled = false; - setIsLoading(true); - fetchData({ - search: debouncedSearchString, - indexPattern, - timeRange, - filters, - field, - query, - }).then((newOptions) => { - if (canceled) return; - setIsLoading(false); - // We now have new 'availableOptions', we need to ensure the previously selected options are still selected. - const enabledIndices: number[] = []; - selectedOptions.current?.forEach((selectedOption) => { - const optionIndex = newOptions.findIndex( - (availableOption) => availableOption.label === selectedOption - ); - if (optionIndex >= 0) enabledIndices.push(optionIndex); - }); - newOptions = toggleAvailableOptions(enabledIndices, newOptions, true); - setAvailableOptions(newOptions); - }); - return () => { - canceled = true; - }; - }, [indexPattern, timeRange, filters, field, query, debouncedSearchString, fetchData]); - - const updateItem = useCallback( - (index: number) => { - const item = availableOptions?.[index]; - if (!item) return; - - const toggleOff = availableOptions[index].checked === 'on'; - - const newAvailableOptions = toggleAvailableOptions([index], availableOptions, !toggleOff); - setAvailableOptions(newAvailableOptions); - - if (toggleOff) { - selectedOptions.current.delete(item.label); - } else { - selectedOptions.current.add(item.label); - } - }, - [availableOptions] - ); - - const selectedOptionsString = Array.from(selectedOptions.current).join( - OptionsListStrings.summary.getSeparator() - ); - const selectedOptionsLength = Array.from(selectedOptions.current).length; - - const { twoLineLayout } = input; + const { + selectedOptionsString, + selectedOptionsCount, + availableOptions, + twoLineLayout, + searchString, + loading, + } = optionsListState; const button = ( setIsPopoverOpen((openState) => !openState)} isSelected={isPopoverOpen} - numFilters={availableOptions.length} - hasActiveFilters={selectedOptionsLength > 0} - numActiveFilters={selectedOptionsLength} + numFilters={availableOptions?.length ?? 0} + hasActiveFilters={(selectedOptionsCount ?? 0) > 0} + numActiveFilters={selectedOptionsCount} > - {!selectedOptionsLength ? OptionsListStrings.summary.getPlaceholder() : selectedOptionsString} + {!selectedOptionsCount ? OptionsListStrings.summary.getPlaceholder() : selectedOptionsString} ); @@ -155,7 +85,7 @@ export const OptionsListInner = ({ input, fetchData }: OptionsListProps) => { > { ); }; - -export const OptionsListComponent = withEmbeddableSubscription< - OptionsListEmbeddableInput, - InputControlOutput, - OptionsListEmbeddable, - { fetchData: OptionsListDataFetcher } ->(OptionsListInner); diff --git a/src/plugins/presentation_util/public/components/input_controls/control_types/options_list/options_list_embeddable.tsx b/src/plugins/presentation_util/public/components/input_controls/control_types/options_list/options_list_embeddable.tsx index 4dcc4a75dc1f0..bdd3660606b7e 100644 --- a/src/plugins/presentation_util/public/components/input_controls/control_types/options_list/options_list_embeddable.tsx +++ b/src/plugins/presentation_util/public/components/input_controls/control_types/options_list/options_list_embeddable.tsx @@ -8,12 +8,39 @@ import React from 'react'; import ReactDOM from 'react-dom'; +import { merge, Subject } from 'rxjs'; +import deepEqual from 'fast-deep-equal'; import { EuiSelectableOption } from '@elastic/eui'; +import { tap, debounceTime, map, distinctUntilChanged } from 'rxjs/operators'; -import { OptionsListComponent } from './options_list_component'; +import { esFilters } from '../../../../../../data/public'; +import { OptionsListStrings } from './options_list_strings'; +import { OptionsListComponent, OptionsListComponentState } from './options_list_component'; import { Embeddable } from '../../../../../../embeddable/public'; import { InputControlInput, InputControlOutput } from '../../embeddable/types'; +const toggleAvailableOptions = ( + indices: number[], + availableOptions: EuiSelectableOption[], + enabled?: boolean +) => { + const newAvailableOptions = [...availableOptions]; + indices.forEach((index) => (newAvailableOptions[index].checked = enabled ? 'on' : undefined)); + return newAvailableOptions; +}; + +const diffDataFetchProps = ( + current?: OptionsListDataFetchProps, + last?: OptionsListDataFetchProps +) => { + if (!current || !last) return false; + const { filters: currentFilters, ...currentWithoutFilters } = current; + const { filters: lastFilters, ...lastWithoutFilters } = last; + if (!deepEqual(currentWithoutFilters, lastWithoutFilters)) return false; + if (!esFilters.compareFilters(lastFilters ?? [], currentFilters ?? [])) return false; + return true; +}; + interface OptionsListDataFetchProps { field: string; search?: string; @@ -32,6 +59,7 @@ export interface OptionsListEmbeddableInput extends InputControlInput { field: string; indexPattern: string; multiSelect: boolean; + defaultSelections?: string[]; } export class OptionsListEmbeddable extends Embeddable< OptionsListEmbeddableInput, @@ -42,6 +70,21 @@ export class OptionsListEmbeddable extends Embeddable< private node?: HTMLElement; private fetchData: OptionsListDataFetcher; + // internal state for this input control. + private selectedOptions: Set; + private typeaheadSubject: Subject = new Subject(); + private searchString: string = ''; + + private componentState: OptionsListComponentState; + private componentStateSubject$ = new Subject(); + private updateComponentState(changes: Partial) { + this.componentState = { + ...this.componentState, + ...changes, + }; + this.componentStateSubject$.next(this.componentState); + } + constructor( input: OptionsListEmbeddableInput, output: InputControlOutput, @@ -49,15 +92,118 @@ export class OptionsListEmbeddable extends Embeddable< ) { super(input, output); this.fetchData = fetchData; + + // populate default selections from input + this.selectedOptions = new Set(input.defaultSelections ?? []); + const { selectedOptionsCount, selectedOptionsString } = this.buildSelectedOptionsString(); + + // fetch available options when input changes or when search string has changed + const typeaheadPipe = this.typeaheadSubject.pipe( + tap((newSearchString) => (this.searchString = newSearchString)), + debounceTime(100) + ); + const inputPipe = this.getInput$().pipe( + map( + (newInput) => ({ + field: newInput.field, + indexPattern: newInput.indexPattern, + query: newInput.query, + filters: newInput.filters, + timeRange: newInput.timeRange, + }), + distinctUntilChanged(diffDataFetchProps) + ) + ); + merge(typeaheadPipe, inputPipe).subscribe(this.fetchAvailableOptions); + + // push changes from input into component state + this.getInput$().subscribe((newInput) => { + if (newInput.twoLineLayout !== this.componentState.twoLineLayout) + this.updateComponentState({ twoLineLayout: newInput.twoLineLayout }); + }); + + this.componentState = { + loading: true, + selectedOptionsCount, + selectedOptionsString, + twoLineLayout: input.twoLineLayout, + }; + this.updateComponentState(this.componentState); + } + + private fetchAvailableOptions = async () => { + this.updateComponentState({ loading: true }); + + const { indexPattern, timeRange, filters, field, query } = this.getInput(); + let newOptions = await this.fetchData({ + search: this.searchString, + indexPattern, + timeRange, + filters, + field, + query, + }); + + // We now have new 'availableOptions', we need to ensure the selected options are still selected in the new list. + const enabledIndices: number[] = []; + this.selectedOptions?.forEach((selectedOption) => { + const optionIndex = newOptions.findIndex( + (availableOption) => availableOption.label === selectedOption + ); + if (optionIndex >= 0) enabledIndices.push(optionIndex); + }); + newOptions = toggleAvailableOptions(enabledIndices, newOptions, true); + this.updateComponentState({ loading: false, availableOptions: newOptions }); + }; + + private updateOption = (index: number) => { + const item = this.componentState.availableOptions?.[index]; + if (!item) return; + const toggleOff = item.checked === 'on'; + + // update availableOptions to show selection check marks + const newAvailableOptions = toggleAvailableOptions( + [index], + this.componentState.availableOptions ?? [], + !toggleOff + ); + this.componentState.availableOptions = newAvailableOptions; + + // update selectedOptions string + if (toggleOff) this.selectedOptions.delete(item.label); + else this.selectedOptions.add(item.label); + const { selectedOptionsString, selectedOptionsCount } = this.buildSelectedOptionsString(); + this.updateComponentState({ selectedOptionsString, selectedOptionsCount }); + }; + + private buildSelectedOptionsString(): { + selectedOptionsString: string; + selectedOptionsCount: number; + } { + const selectedOptionsArray = Array.from(this.selectedOptions ?? []); + const selectedOptionsString = selectedOptionsArray.join( + OptionsListStrings.summary.getSeparator() + ); + const selectedOptionsCount = selectedOptionsArray.length; + return { selectedOptionsString, selectedOptionsCount }; } - reload = () => {}; + reload = () => { + this.fetchAvailableOptions(); + }; public render = (node: HTMLElement) => { if (this.node) { ReactDOM.unmountComponentAtNode(this.node); } this.node = node; - ReactDOM.render(, node); + ReactDOM.render( + , + node + ); }; } diff --git a/src/plugins/presentation_util/public/components/input_controls/control_types/options_list/options_list_popover_component.tsx b/src/plugins/presentation_util/public/components/input_controls/control_types/options_list/options_list_popover_component.tsx index cd558b99f9aa1..4bfce9eb377e9 100644 --- a/src/plugins/presentation_util/public/components/input_controls/control_types/options_list/options_list_popover_component.tsx +++ b/src/plugins/presentation_util/public/components/input_controls/control_types/options_list/options_list_popover_component.tsx @@ -23,14 +23,14 @@ import { OptionsListStrings } from './options_list_strings'; interface OptionsListPopoverProps { loading: boolean; typeaheadSubject: Subject; - searchString: string; - updateItem: (index: number) => void; - availableOptions: EuiSelectableOption[]; + searchString?: string; + updateOption: (index: number) => void; + availableOptions?: EuiSelectableOption[]; } export const OptionsListPopover = ({ loading, - updateItem, + updateOption, searchString, typeaheadSubject, availableOptions, @@ -53,7 +53,7 @@ export const OptionsListPopover = ({ updateItem(index)} + onClick={() => updateOption(index)} > {item.label} diff --git a/src/plugins/presentation_util/public/components/input_controls/use_state_observable.ts b/src/plugins/presentation_util/public/components/input_controls/use_state_observable.ts new file mode 100644 index 0000000000000..c317f11979f54 --- /dev/null +++ b/src/plugins/presentation_util/public/components/input_controls/use_state_observable.ts @@ -0,0 +1,23 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { useEffect, useState } from 'react'; +import { Observable } from 'rxjs'; + +export const useStateObservable = ( + stateObservable: Observable, + initialState: T +) => { + useEffect(() => { + const subscription = stateObservable.subscribe((newState) => setInnerState(newState)); + return () => subscription.unsubscribe(); + }, [stateObservable]); + const [innerState, setInnerState] = useState(initialState); + + return innerState; +}; From 095d113d9162a17667b451f66850c59307802d68 Mon Sep 17 00:00:00 2001 From: Rudolf Meijering Date: Fri, 20 Aug 2021 18:57:24 +0200 Subject: [PATCH 35/76] Handle index not found during bulk index action (#108544) (#109473) Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../saved_objects/migrationsv2/README.md | 69 +++++++++++++++++-- .../bulk_overwrite_transformed_documents.ts | 19 ++++- .../migrationsv2/actions/es_errors.ts | 4 ++ .../migrationsv2/model/model.test.ts | 40 ++++++++--- .../saved_objects/migrationsv2/model/model.ts | 20 ++++-- 5 files changed, 129 insertions(+), 23 deletions(-) diff --git a/src/core/server/saved_objects/migrationsv2/README.md b/src/core/server/saved_objects/migrationsv2/README.md index c92a5245e6c91..5bdc548987842 100644 --- a/src/core/server/saved_objects/migrationsv2/README.md +++ b/src/core/server/saved_objects/migrationsv2/README.md @@ -1,26 +1,71 @@ - [Introduction](#introduction) - [Algorithm steps](#algorithm-steps) - [INIT](#init) + - [Next action](#next-action) + - [New control state](#new-control-state) - [CREATE_NEW_TARGET](#create_new_target) + - [Next action](#next-action-1) + - [New control state](#new-control-state-1) - [LEGACY_SET_WRITE_BLOCK](#legacy_set_write_block) + - [Next action](#next-action-2) + - [New control state](#new-control-state-2) - [LEGACY_CREATE_REINDEX_TARGET](#legacy_create_reindex_target) + - [Next action](#next-action-3) + - [New control state](#new-control-state-3) - [LEGACY_REINDEX](#legacy_reindex) + - [Next action](#next-action-4) + - [New control state](#new-control-state-4) - [LEGACY_REINDEX_WAIT_FOR_TASK](#legacy_reindex_wait_for_task) + - [Next action](#next-action-5) + - [New control state](#new-control-state-5) - [LEGACY_DELETE](#legacy_delete) + - [Next action](#next-action-6) + - [New control state](#new-control-state-6) - [WAIT_FOR_YELLOW_SOURCE](#wait_for_yellow_source) + - [Next action](#next-action-7) + - [New control state](#new-control-state-7) - [SET_SOURCE_WRITE_BLOCK](#set_source_write_block) + - [Next action](#next-action-8) + - [New control state](#new-control-state-8) - [CREATE_REINDEX_TEMP](#create_reindex_temp) + - [Next action](#next-action-9) + - [New control state](#new-control-state-9) - [REINDEX_SOURCE_TO_TEMP_OPEN_PIT](#reindex_source_to_temp_open_pit) + - [Next action](#next-action-10) + - [New control state](#new-control-state-10) - [REINDEX_SOURCE_TO_TEMP_READ](#reindex_source_to_temp_read) + - [Next action](#next-action-11) + - [New control state](#new-control-state-11) - [REINDEX_SOURCE_TO_TEMP_INDEX](#reindex_source_to_temp_index) + - [Next action](#next-action-12) + - [New control state](#new-control-state-12) + - [REINDEX_SOURCE_TO_TEMP_INDEX_BULK](#reindex_source_to_temp_index_bulk) + - [Next action](#next-action-13) + - [New control state](#new-control-state-13) - [REINDEX_SOURCE_TO_TEMP_CLOSE_PIT](#reindex_source_to_temp_close_pit) + - [Next action](#next-action-14) + - [New control state](#new-control-state-14) - [SET_TEMP_WRITE_BLOCK](#set_temp_write_block) + - [Next action](#next-action-15) + - [New control state](#new-control-state-15) - [CLONE_TEMP_TO_TARGET](#clone_temp_to_target) + - [Next action](#next-action-16) + - [New control state](#new-control-state-16) - [OUTDATED_DOCUMENTS_SEARCH](#outdated_documents_search) + - [Next action](#next-action-17) + - [New control state](#new-control-state-17) - [OUTDATED_DOCUMENTS_TRANSFORM](#outdated_documents_transform) + - [Next action](#next-action-18) + - [New control state](#new-control-state-18) - [UPDATE_TARGET_MAPPINGS](#update_target_mappings) + - [Next action](#next-action-19) + - [New control state](#new-control-state-19) - [UPDATE_TARGET_MAPPINGS_WAIT_FOR_TASK](#update_target_mappings_wait_for_task) + - [Next action](#next-action-20) + - [New control state](#new-control-state-20) - [MARK_VERSION_INDEX_READY_CONFLICT](#mark_version_index_ready_conflict) + - [Next action](#next-action-21) + - [New control state](#new-control-state-21) - [Manual QA Test Plan](#manual-qa-test-plan) - [1. Legacy pre-migration](#1-legacy-pre-migration) - [2. Plugins enabled/disabled](#2-plugins-enableddisabled) @@ -245,15 +290,31 @@ Read the next batch of outdated documents from the source index by using search ## REINDEX_SOURCE_TO_TEMP_INDEX ### Next action -`transformRawDocs` + `bulkIndexTransformedDocuments` - -1. Transform the current batch of documents -2. Use the bulk API create action to write a batch of up-to-date documents. The create action ensures that there will be only one write per reindexed document even if multiple Kibana instances are performing this step. Ignore any create errors because of documents that already exist in the temporary index. Use `refresh=false` to speed up the create actions, the `UPDATE_TARGET_MAPPINGS` step will ensure that the index is refreshed before we start serving traffic. +`transformRawDocs` +Transform the current batch of documents + In order to support sharing saved objects to multiple spaces in 8.0, the transforms will also regenerate document `_id`'s. To ensure that this step remains idempotent, the new `_id` is deterministically generated using UUIDv5 ensuring that each Kibana instance generates the same new `_id` for the same document. +### New control state + → `REINDEX_SOURCE_TO_TEMP_INDEX_BULK` +## REINDEX_SOURCE_TO_TEMP_INDEX_BULK +### Next action +`bulkIndexTransformedDocuments` + +Use the bulk API create action to write a batch of up-to-date documents. The +create action ensures that there will be only one write per reindexed document +even if multiple Kibana instances are performing this step. Use +`refresh=false` to speed up the create actions, the `UPDATE_TARGET_MAPPINGS` +step will ensure that the index is refreshed before we start serving traffic. + +The following errors are ignored because it means another instance already +completed this step: + - documents already exist in the temp index + - temp index has a write block + - temp index is not found ### New control state → `REINDEX_SOURCE_TO_TEMP_READ` diff --git a/src/core/server/saved_objects/migrationsv2/actions/bulk_overwrite_transformed_documents.ts b/src/core/server/saved_objects/migrationsv2/actions/bulk_overwrite_transformed_documents.ts index d0259f8f21ca4..4217ca599297a 100644 --- a/src/core/server/saved_objects/migrationsv2/actions/bulk_overwrite_transformed_documents.ts +++ b/src/core/server/saved_objects/migrationsv2/actions/bulk_overwrite_transformed_documents.ts @@ -15,9 +15,13 @@ import { catchRetryableEsClientErrors, RetryableEsClientError, } from './catch_retryable_es_client_errors'; -import { isWriteBlockException } from './es_errors'; +import { isWriteBlockException, isIndexNotFoundException } from './es_errors'; import { WAIT_FOR_ALL_SHARDS_TO_BE_ACTIVE } from './constants'; -import type { TargetIndexHadWriteBlock, RequestEntityTooLargeException } from './index'; +import type { + TargetIndexHadWriteBlock, + RequestEntityTooLargeException, + IndexNotFound, +} from './index'; /** @internal */ export interface BulkOverwriteTransformedDocumentsParams { @@ -37,7 +41,10 @@ export const bulkOverwriteTransformedDocuments = ({ transformedDocs, refresh = false, }: BulkOverwriteTransformedDocumentsParams): TaskEither.TaskEither< - RetryableEsClientError | TargetIndexHadWriteBlock | RequestEntityTooLargeException, + | RetryableEsClientError + | TargetIndexHadWriteBlock + | IndexNotFound + | RequestEntityTooLargeException, 'bulk_index_succeeded' > => () => { return client @@ -87,6 +94,12 @@ export const bulkOverwriteTransformedDocuments = ({ type: 'target_index_had_write_block' as const, }); } + if (errors.every(isIndexNotFoundException)) { + return Either.left({ + type: 'index_not_found_exception' as const, + index, + }); + } throw new Error(JSON.stringify(errors)); } }) diff --git a/src/core/server/saved_objects/migrationsv2/actions/es_errors.ts b/src/core/server/saved_objects/migrationsv2/actions/es_errors.ts index 0d3c9fe3741aa..49b996bb118d8 100644 --- a/src/core/server/saved_objects/migrationsv2/actions/es_errors.ts +++ b/src/core/server/saved_objects/migrationsv2/actions/es_errors.ts @@ -21,3 +21,7 @@ export const isWriteBlockException = ({ type, reason }: EsErrorCause): boolean = export const isIncompatibleMappingException = ({ type }: EsErrorCause): boolean => { return type === 'strict_dynamic_mapping_exception' || type === 'mapper_parsing_exception'; }; + +export const isIndexNotFoundException = ({ type }: EsErrorCause): boolean => { + return type === 'index_not_found_exception'; +}; diff --git a/src/core/server/saved_objects/migrationsv2/model/model.test.ts b/src/core/server/saved_objects/migrationsv2/model/model.test.ts index 30612b82d58aa..f24d175f416a7 100644 --- a/src/core/server/saved_objects/migrationsv2/model/model.test.ts +++ b/src/core/server/saved_objects/migrationsv2/model/model.test.ts @@ -1154,6 +1154,16 @@ describe('migrations v2 model', () => { expect(newState.retryCount).toEqual(0); expect(newState.retryDelay).toEqual(0); }); + test('REINDEX_SOURCE_TO_TEMP_INDEX_BULK -> REINDEX_SOURCE_TO_TEMP_CLOSE_PIT if response is left index_not_found_exception', () => { + const res: ResponseType<'REINDEX_SOURCE_TO_TEMP_INDEX_BULK'> = Either.left({ + type: 'index_not_found_exception', + index: 'the_temp_index', + }); + const newState = model(reindexSourceToTempIndexBulkState, res); + expect(newState.controlState).toEqual('REINDEX_SOURCE_TO_TEMP_CLOSE_PIT'); + expect(newState.retryCount).toEqual(0); + expect(newState.retryDelay).toEqual(0); + }); test('REINDEX_SOURCE_TO_TEMP_INDEX_BULK -> FATAL if action returns left request_entity_too_large_exception', () => { const res: ResponseType<'REINDEX_SOURCE_TO_TEMP_INDEX_BULK'> = Either.left({ type: 'request_entity_too_large_exception', @@ -1529,18 +1539,28 @@ describe('migrations v2 model', () => { hasTransformedDocs: false, progress: createInitialProgress(), }; - test('TRANSFORMED_DOCUMENTS_BULK_INDEX should throw a throwBadResponse error if action failed', () => { + + test('TRANSFORMED_DOCUMENTS_BULK_INDEX throws if action returns left index_not_found_exception', () => { const res: ResponseType<'TRANSFORMED_DOCUMENTS_BULK_INDEX'> = Either.left({ - type: 'retryable_es_client_error', - message: 'random documents bulk index error', + type: 'index_not_found_exception', + index: 'the_target_index', }); - const newState = model( - transformedDocumentsBulkIndexState, - res - ) as TransformedDocumentsBulkIndex; - expect(newState.controlState).toEqual('TRANSFORMED_DOCUMENTS_BULK_INDEX'); - expect(newState.retryCount).toEqual(1); - expect(newState.retryDelay).toEqual(2000); + expect(() => + model(transformedDocumentsBulkIndexState, res) + ).toThrowErrorMatchingInlineSnapshot( + `"TRANSFORMED_DOCUMENTS_BULK_INDEX received unexpected action response: {\\"type\\":\\"index_not_found_exception\\",\\"index\\":\\"the_target_index\\"}"` + ); + }); + + test('TRANSFORMED_DOCUMENTS_BULK_INDEX throws if action returns left target_index_had_write_block', () => { + const res: ResponseType<'TRANSFORMED_DOCUMENTS_BULK_INDEX'> = Either.left({ + type: 'target_index_had_write_block', + }); + expect(() => + model(transformedDocumentsBulkIndexState, res) + ).toThrowErrorMatchingInlineSnapshot( + `"TRANSFORMED_DOCUMENTS_BULK_INDEX received unexpected action response: {\\"type\\":\\"target_index_had_write_block\\"}"` + ); }); test('TRANSFORMED_DOCUMENTS_BULK_INDEX -> FATAL if action returns left request_entity_too_large_exception', () => { diff --git a/src/core/server/saved_objects/migrationsv2/model/model.ts b/src/core/server/saved_objects/migrationsv2/model/model.ts index 01c1893154c6c..50be4a524f5c5 100644 --- a/src/core/server/saved_objects/migrationsv2/model/model.ts +++ b/src/core/server/saved_objects/migrationsv2/model/model.ts @@ -533,9 +533,13 @@ export const model = (currentState: State, resW: ResponseType): transformErrors: [], }; } else { - if (isLeftTypeof(res.left, 'target_index_had_write_block')) { - // the temp index has a write block, meaning that another instance already finished and moved forward. - // close the PIT search and carry on with the happy path. + if ( + isLeftTypeof(res.left, 'target_index_had_write_block') || + isLeftTypeof(res.left, 'index_not_found_exception') + ) { + // When the temp index has a write block or has been deleted another + // instance already completed this step. Close the PIT search and carry + // on with the happy path. return { ...stateP, controlState: 'REINDEX_SOURCE_TO_TEMP_CLOSE_PIT', @@ -721,9 +725,13 @@ export const model = (currentState: State, resW: ResponseType): controlState: 'FATAL', reason: `While indexing a batch of saved objects, Elasticsearch returned a 413 Request Entity Too Large exception. Try to use smaller batches by changing the Kibana 'migrations.batchSize' configuration option and restarting Kibana.`, }; - } else if (isLeftTypeof(res.left, 'target_index_had_write_block')) { - // we fail on this error since the target index will only have a write - // block if a newer version of Kibana started an upgrade + } else if ( + isLeftTypeof(res.left, 'target_index_had_write_block') || + isLeftTypeof(res.left, 'index_not_found_exception') + ) { + // we fail on these errors since the target index will never get + // deleted and should only have a write block if a newer version of + // Kibana started an upgrade throwBadResponse(stateP, res.left as never); } else { throwBadResponse(stateP, res.left); From 2c44f266560155a15c67befb23a518f2298610ef Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Fri, 20 Aug 2021 13:07:40 -0400 Subject: [PATCH 36/76] [Discover] Fix runtime fields editor test in cloud environment (#109367) (#109478) Co-authored-by: Matthias Wilhelm --- test/functional/apps/discover/_runtime_fields_editor.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/test/functional/apps/discover/_runtime_fields_editor.ts b/test/functional/apps/discover/_runtime_fields_editor.ts index 46fe5c34f4cf3..a77bc4c77568a 100644 --- a/test/functional/apps/discover/_runtime_fields_editor.ts +++ b/test/functional/apps/discover/_runtime_fields_editor.ts @@ -10,7 +10,6 @@ import expect from '@kbn/expect'; import { FtrProviderContext } from './ftr_provider_context'; export default function ({ getService, getPageObjects }: FtrProviderContext) { - const log = getService('log'); const retry = getService('retry'); const testSubjects = getService('testSubjects'); const kibanaServer = getService('kibanaServer'); @@ -33,12 +32,11 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { describe('discover integration with runtime fields editor', function describeIndexTests() { before(async function () { - await esArchiver.load('test/functional/fixtures/es_archiver/discover'); + await kibanaServer.importExport.load('test/functional/fixtures/kbn_archiver/discover.json'); await esArchiver.loadIfNeeded('test/functional/fixtures/es_archiver/logstash_functional'); await kibanaServer.uiSettings.replace(defaultSettings); - log.debug('discover'); + await PageObjects.timePicker.setDefaultAbsoluteRangeViaUiSettings(); await PageObjects.common.navigateToApp('discover'); - await PageObjects.timePicker.setDefaultAbsoluteRange(); }); it('allows adding custom label to existing fields', async function () { From e998e41b268e53b7b4cd165318d12afd2c991505 Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Fri, 20 Aug 2021 13:15:59 -0400 Subject: [PATCH 37/76] [APM] Change panel style for license prompt (#109386) (#109482) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Casper Hübertz --- .../public/components/app/Settings/anomaly_detection/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/apm/public/components/app/Settings/anomaly_detection/index.tsx b/x-pack/plugins/apm/public/components/app/Settings/anomaly_detection/index.tsx index 57d141d763909..7293fb81f3303 100644 --- a/x-pack/plugins/apm/public/components/app/Settings/anomaly_detection/index.tsx +++ b/x-pack/plugins/apm/public/components/app/Settings/anomaly_detection/index.tsx @@ -45,7 +45,7 @@ export function AnomalyDetection() { if (!hasValidLicense) { return ( - + ); From a930371708fac5f98512b06f2b9c9370848c30c2 Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Fri, 20 Aug 2021 13:19:02 -0400 Subject: [PATCH 38/76] [7.x] chore(NA): moving @kbn/logging to babel transpiler (#108702) (#109412) * chore(NA): moving @kbn/logging to babel transpiler (#108702) * chore(NA): moving @kbn/logging to babel transpiler * chore(NA): fix imports for @kbn/logging Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> * chore(NA): fix test failures Co-authored-by: Tiago Costa --- .../kbn-config/src/config_service.test.ts | 2 +- packages/kbn-logging/.babelrc | 3 +++ packages/kbn-logging/BUILD.bazel | 20 +++++++++++++------ packages/kbn-logging/mocks/package.json | 5 +++++ packages/kbn-logging/package.json | 4 ++-- packages/kbn-logging/tsconfig.json | 5 +++-- .../http/integration_tests/router.test.ts | 2 +- src/core/server/logging/logger.mock.ts | 4 ++-- .../server/metrics/collectors/cgroup.test.ts | 2 +- src/core/server/metrics/collectors/os.test.ts | 2 +- .../metrics/ops_metrics_collector.test.ts | 2 +- .../server/routes/create_rule.test.ts | 2 +- .../server/routes/legacy/create.test.ts | 2 +- .../saved_objects/is_rule_exportable.test.ts | 2 +- .../cases/server/services/cases/index.test.ts | 2 +- .../server/services/configure/index.test.ts | 2 +- .../utils/create_lifecycle_executor.test.ts | 2 +- .../utils/create_lifecycle_rule_type.test.ts | 2 +- 18 files changed, 41 insertions(+), 24 deletions(-) create mode 100644 packages/kbn-logging/.babelrc create mode 100644 packages/kbn-logging/mocks/package.json diff --git a/packages/kbn-config/src/config_service.test.ts b/packages/kbn-config/src/config_service.test.ts index d09c61a1c2110..aa520e7189e54 100644 --- a/packages/kbn-config/src/config_service.test.ts +++ b/packages/kbn-config/src/config_service.test.ts @@ -13,7 +13,7 @@ import { mockApplyDeprecations, mockedChangedPaths } from './config_service.test import { rawConfigServiceMock } from './raw/raw_config_service.mock'; import { schema } from '@kbn/config-schema'; -import { MockedLogger, loggerMock } from '@kbn/logging/target/mocks'; +import { MockedLogger, loggerMock } from '@kbn/logging/mocks'; import { ConfigService, Env, RawPackageInfo } from '.'; diff --git a/packages/kbn-logging/.babelrc b/packages/kbn-logging/.babelrc new file mode 100644 index 0000000000000..7da72d1779128 --- /dev/null +++ b/packages/kbn-logging/.babelrc @@ -0,0 +1,3 @@ +{ + "presets": ["@kbn/babel-preset/node_preset"] +} diff --git a/packages/kbn-logging/BUILD.bazel b/packages/kbn-logging/BUILD.bazel index 1a3fa851a3957..71a7ece15aa73 100644 --- a/packages/kbn-logging/BUILD.bazel +++ b/packages/kbn-logging/BUILD.bazel @@ -1,5 +1,6 @@ load("@npm//@bazel/typescript:index.bzl", "ts_config", "ts_project") load("@build_bazel_rules_nodejs//:index.bzl", "js_library", "pkg_npm") +load("//src/dev/bazel:index.bzl", "jsts_transpiler") PKG_BASE_NAME = "kbn-logging" PKG_REQUIRE_NAME = "@kbn/logging" @@ -21,20 +22,26 @@ filegroup( ) NPM_MODULE_EXTRA_FILES = [ + "mocks/package.json", "package.json", "README.md" ] -SRC_DEPS = [ +RUNTIME_DEPS = [ "//packages/kbn-std" ] TYPES_DEPS = [ + "//packages/kbn-std", "@npm//@types/jest", "@npm//@types/node", ] -DEPS = SRC_DEPS + TYPES_DEPS +jsts_transpiler( + name = "target_node", + srcs = SRCS, + build_pkg_name = package_name(), +) ts_config( name = "tsconfig", @@ -46,13 +53,14 @@ ts_config( ) ts_project( - name = "tsc", + name = "tsc_types", args = ['--pretty'], srcs = SRCS, - deps = DEPS, + deps = TYPES_DEPS, declaration = True, declaration_map = True, - out_dir = "target", + emit_declaration_only = True, + out_dir = "target_types", source_map = True, root_dir = "src", tsconfig = ":tsconfig", @@ -61,7 +69,7 @@ ts_project( js_library( name = PKG_BASE_NAME, srcs = NPM_MODULE_EXTRA_FILES, - deps = DEPS + [":tsc"], + deps = RUNTIME_DEPS + [":target_node", ":tsc_types"], package_name = PKG_REQUIRE_NAME, visibility = ["//visibility:public"], ) diff --git a/packages/kbn-logging/mocks/package.json b/packages/kbn-logging/mocks/package.json new file mode 100644 index 0000000000000..8410f557e9524 --- /dev/null +++ b/packages/kbn-logging/mocks/package.json @@ -0,0 +1,5 @@ +{ + "private": true, + "main": "../target_node/mocks/index.js", + "types": "../target_types/mocks/index.d.ts" +} \ No newline at end of file diff --git a/packages/kbn-logging/package.json b/packages/kbn-logging/package.json index d80cc1c40d7e1..c35c2f5d06095 100644 --- a/packages/kbn-logging/package.json +++ b/packages/kbn-logging/package.json @@ -3,6 +3,6 @@ "version": "1.0.0", "private": true, "license": "SSPL-1.0 OR Elastic License 2.0", - "main": "./target/index.js", - "types": "./target/index.d.ts" + "main": "./target_node/index.js", + "types": "./target_types/index.d.ts" } \ No newline at end of file diff --git a/packages/kbn-logging/tsconfig.json b/packages/kbn-logging/tsconfig.json index aaf79da229a86..a6fb0f2f73187 100644 --- a/packages/kbn-logging/tsconfig.json +++ b/packages/kbn-logging/tsconfig.json @@ -1,13 +1,14 @@ { "extends": "../../tsconfig.bazel.json", "compilerOptions": { - "outDir": "target", - "stripInternal": false, "declaration": true, "declarationMap": true, + "emitDeclarationOnly": true, + "outDir": "target_types", "rootDir": "src", "sourceMap": true, "sourceRoot": "../../../../packages/kbn-logging/src", + "stripInternal": false, "types": [ "jest", "node" diff --git a/src/core/server/http/integration_tests/router.test.ts b/src/core/server/http/integration_tests/router.test.ts index 5bea371d479ae..a3e872ee3ea87 100644 --- a/src/core/server/http/integration_tests/router.test.ts +++ b/src/core/server/http/integration_tests/router.test.ts @@ -17,7 +17,7 @@ import { loggingSystemMock } from '../../logging/logging_system.mock'; import { createHttpServer } from '../test_utils'; import { HttpService } from '../http_service'; import { Router } from '../router'; -import { loggerMock } from '@kbn/logging/target/mocks'; +import { loggerMock } from '@kbn/logging/mocks'; let server: HttpService; let logger: ReturnType; diff --git a/src/core/server/logging/logger.mock.ts b/src/core/server/logging/logger.mock.ts index efab15b7bf5f4..cfabaeb72adf7 100644 --- a/src/core/server/logging/logger.mock.ts +++ b/src/core/server/logging/logger.mock.ts @@ -6,5 +6,5 @@ * Side Public License, v 1. */ -export { loggerMock } from '@kbn/logging/target/mocks'; -export type { MockedLogger } from '@kbn/logging/target/mocks'; +export { loggerMock } from '@kbn/logging/mocks'; +export type { MockedLogger } from '@kbn/logging/mocks'; diff --git a/src/core/server/metrics/collectors/cgroup.test.ts b/src/core/server/metrics/collectors/cgroup.test.ts index 298a143717d84..269437f026f2f 100644 --- a/src/core/server/metrics/collectors/cgroup.test.ts +++ b/src/core/server/metrics/collectors/cgroup.test.ts @@ -7,7 +7,7 @@ */ import mockFs from 'mock-fs'; -import { loggerMock } from '@kbn/logging/target/mocks'; +import { loggerMock } from '@kbn/logging/mocks'; import { OsCgroupMetricsCollector } from './cgroup'; describe('OsCgroupMetricsCollector', () => { diff --git a/src/core/server/metrics/collectors/os.test.ts b/src/core/server/metrics/collectors/os.test.ts index 37373ea14c339..5592038f1416a 100644 --- a/src/core/server/metrics/collectors/os.test.ts +++ b/src/core/server/metrics/collectors/os.test.ts @@ -8,7 +8,7 @@ jest.mock('getos', () => (cb: Function) => cb(null, { dist: 'distrib', release: 'release' })); -import { loggerMock } from '@kbn/logging/target/mocks'; +import { loggerMock } from '@kbn/logging/mocks'; import os from 'os'; import { cgroupCollectorMock } from './os.test.mocks'; import { OsMetricsCollector } from './os'; diff --git a/src/core/server/metrics/ops_metrics_collector.test.ts b/src/core/server/metrics/ops_metrics_collector.test.ts index e966c7e0a8095..3faa771db1dae 100644 --- a/src/core/server/metrics/ops_metrics_collector.test.ts +++ b/src/core/server/metrics/ops_metrics_collector.test.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { loggerMock } from '@kbn/logging/target/mocks'; +import { loggerMock } from '@kbn/logging/mocks'; import { mockOsCollector, mockProcessCollector, diff --git a/x-pack/plugins/alerting/server/routes/create_rule.test.ts b/x-pack/plugins/alerting/server/routes/create_rule.test.ts index de301377ffaaf..6636d33872f59 100644 --- a/x-pack/plugins/alerting/server/routes/create_rule.test.ts +++ b/x-pack/plugins/alerting/server/routes/create_rule.test.ts @@ -6,7 +6,7 @@ */ import { pick } from 'lodash'; -import { MockedLogger, loggerMock } from '@kbn/logging/target/mocks'; +import { MockedLogger, loggerMock } from '@kbn/logging/mocks'; import { createRuleRoute } from './create_rule'; import { httpServiceMock } from 'src/core/server/mocks'; import { licenseStateMock } from '../lib/license_state.mock'; diff --git a/x-pack/plugins/alerting/server/routes/legacy/create.test.ts b/x-pack/plugins/alerting/server/routes/legacy/create.test.ts index bb076e709dcd2..921fe3a7e6fb6 100644 --- a/x-pack/plugins/alerting/server/routes/legacy/create.test.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/create.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { MockedLogger, loggerMock } from '@kbn/logging/target/mocks'; +import { MockedLogger, loggerMock } from '@kbn/logging/mocks'; import { createAlertRoute } from './create'; import { httpServiceMock } from 'src/core/server/mocks'; import { licenseStateMock } from '../../lib/license_state.mock'; diff --git a/x-pack/plugins/alerting/server/saved_objects/is_rule_exportable.test.ts b/x-pack/plugins/alerting/server/saved_objects/is_rule_exportable.test.ts index 8a22ded2886ff..8322e42b0743c 100644 --- a/x-pack/plugins/alerting/server/saved_objects/is_rule_exportable.test.ts +++ b/x-pack/plugins/alerting/server/saved_objects/is_rule_exportable.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { MockedLogger, loggerMock } from '@kbn/logging/target/mocks'; +import { MockedLogger, loggerMock } from '@kbn/logging/mocks'; import { TaskRunnerFactory } from '../task_runner'; import { RuleTypeRegistry, ConstructorOptions } from '../rule_type_registry'; import { taskManagerMock } from '../../../task_manager/server/mocks'; diff --git a/x-pack/plugins/cases/server/services/cases/index.test.ts b/x-pack/plugins/cases/server/services/cases/index.test.ts index bf7eeda7e0e2e..aec188037f095 100644 --- a/x-pack/plugins/cases/server/services/cases/index.test.ts +++ b/x-pack/plugins/cases/server/services/cases/index.test.ts @@ -29,7 +29,7 @@ import { SavedObjectsUpdateResponse, } from 'kibana/server'; import { ACTION_SAVED_OBJECT_TYPE } from '../../../../actions/server'; -import { loggerMock } from '@kbn/logging/target/mocks'; +import { loggerMock } from '@kbn/logging/mocks'; import { getNoneCaseConnector, CONNECTOR_ID_REFERENCE_NAME } from '../../common'; import { CasesService } from '.'; import { diff --git a/x-pack/plugins/cases/server/services/configure/index.test.ts b/x-pack/plugins/cases/server/services/configure/index.test.ts index 199b541d49f98..045142ea13e11 100644 --- a/x-pack/plugins/cases/server/services/configure/index.test.ts +++ b/x-pack/plugins/cases/server/services/configure/index.test.ts @@ -23,7 +23,7 @@ import { SavedObjectsUpdateResponse, } from 'kibana/server'; import { ACTION_SAVED_OBJECT_TYPE } from '../../../../actions/server'; -import { loggerMock } from '@kbn/logging/target/mocks'; +import { loggerMock } from '@kbn/logging/mocks'; import { CaseConfigureService } from '.'; import { ESCasesConfigureAttributes } from './types'; import { getNoneCaseConnector, CONNECTOR_ID_REFERENCE_NAME } from '../../common'; diff --git a/x-pack/plugins/rule_registry/server/utils/create_lifecycle_executor.test.ts b/x-pack/plugins/rule_registry/server/utils/create_lifecycle_executor.test.ts index 236f3b41d689d..2d0ca3e328a13 100644 --- a/x-pack/plugins/rule_registry/server/utils/create_lifecycle_executor.test.ts +++ b/x-pack/plugins/rule_registry/server/utils/create_lifecycle_executor.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { loggerMock } from '@kbn/logging/target/mocks'; +import { loggerMock } from '@kbn/logging/mocks'; import { elasticsearchServiceMock, savedObjectsClientMock, diff --git a/x-pack/plugins/rule_registry/server/utils/create_lifecycle_rule_type.test.ts b/x-pack/plugins/rule_registry/server/utils/create_lifecycle_rule_type.test.ts index 962a37a2991b0..79c2284db047d 100644 --- a/x-pack/plugins/rule_registry/server/utils/create_lifecycle_rule_type.test.ts +++ b/x-pack/plugins/rule_registry/server/utils/create_lifecycle_rule_type.test.ts @@ -7,7 +7,7 @@ import { schema } from '@kbn/config-schema'; import { ALERT_DURATION, ALERT_STATUS, ALERT_UUID } from '@kbn/rule-data-utils'; -import { loggerMock } from '@kbn/logging/target/mocks'; +import { loggerMock } from '@kbn/logging/mocks'; import { castArray, omit, mapValues } from 'lodash'; import { RuleDataClient } from '../rule_data_client'; import { createRuleDataClientMock } from '../rule_data_client/rule_data_client.mock'; From c9c53262f07bde15f09367743bd0bb8f07b3cf39 Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Fri, 20 Aug 2021 13:31:15 -0400 Subject: [PATCH 39/76] fix(heatmap): remove duplicate legend items (#109338) (#109489) Co-authored-by: Marco Vettorello --- package.json | 2 +- .../heatmap_visualization/chart_component.tsx | 18 +++++-- .../explorer/swimlane_container.tsx | 46 ++++++++++------ .../test/functional/apps/lens/chart_data.ts | 9 ++-- x-pack/test/functional/apps/lens/heatmap.ts | 54 +++++++++---------- yarn.lock | 27 ++-------- 6 files changed, 78 insertions(+), 78 deletions(-) diff --git a/package.json b/package.json index 7d6698a77a302..7184b199aecd7 100644 --- a/package.json +++ b/package.json @@ -92,7 +92,7 @@ "dependencies": { "@elastic/apm-rum": "^5.8.0", "@elastic/apm-rum-react": "^1.2.11", - "@elastic/charts": "34.0.0", + "@elastic/charts": "34.1.1", "@elastic/datemath": "link:bazel-bin/packages/elastic-datemath", "@elastic/elasticsearch": "npm:@elastic/elasticsearch-canary@^7.15.0-canary.3", "@elastic/ems-client": "7.15.0", diff --git a/x-pack/plugins/lens/public/heatmap_visualization/chart_component.tsx b/x-pack/plugins/lens/public/heatmap_visualization/chart_component.tsx index d38afc17b2b07..c666d27e780b5 100644 --- a/x-pack/plugins/lens/public/heatmap_visualization/chart_component.tsx +++ b/x-pack/plugins/lens/public/heatmap_visualization/chart_component.tsx @@ -174,6 +174,17 @@ export const HeatmapComponent: FC = ({ minMaxByColumnId[args.valueAccessor!] ); + const bands = ranges.map((start, index, array) => { + return { + // with the default continuity:above the every range is left-closed + start, + // with the default continuity:above the last range is right-open + end: index === array.length - 1 ? Infinity : array[index + 1], + // the current colors array contains a duplicated color at the beginning that we need to skip + color: colors[index + 1], + }; + }); + const onElementClick = ((e: HeatmapElementEvent[]) => { const cell = e[0][0]; const { x, y } = cell.datum; @@ -331,9 +342,10 @@ export const HeatmapComponent: FC = ({ = ({ Date: Fri, 20 Aug 2021 13:36:09 -0400 Subject: [PATCH 40/76] [ML] Anomaly detection: Adds functional test for delayed data chart flyout (#109026) (#109311) * wip add delayed data functional test * adds delayed data functional test * add menu check for stability and reorganize functions * ensure describe block is self contained Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../datafeed_chart_flyout.tsx | 245 +++++++++--------- .../apps/ml/anomaly_detection/annotations.ts | 23 ++ .../services/ml/job_annotations_table.ts | 46 ++++ 3 files changed, 193 insertions(+), 121 deletions(-) diff --git a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/datafeed_chart_flyout/datafeed_chart_flyout.tsx b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/datafeed_chart_flyout/datafeed_chart_flyout.tsx index 0879a657d7fa9..17ff5db2768d6 100644 --- a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/datafeed_chart_flyout/datafeed_chart_flyout.tsx +++ b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/datafeed_chart_flyout/datafeed_chart_flyout.tsx @@ -185,8 +185,9 @@ export const DatafeedChartFlyout: FC = ({ jobId, end, aria-label={i18n.translate('xpack.ml.jobsList.datafeedChart.datafeedChartFlyoutAriaLabel', { defaultMessage: 'Datafeed chart flyout', })} + data-test-subj="mlAnnotationsViewDatafeedFlyout" > - + @@ -308,143 +309,145 @@ export const DatafeedChartFlyout: FC = ({ jobId, end, - - - - - {showModelSnapshots ? ( - } - markerPosition={Position.Top} - style={{ - line: { - strokeWidth: 3, - stroke: euiTheme.euiColorVis1, - opacity: 0.5, +
+ + - ) : null} - {showAnnotations ? ( - <> - } - markerPosition={Position.Top} - style={{ - line: { - strokeWidth: 3, - stroke: euiTheme.euiColorDangerText, - opacity: 0.5, - }, - }} - /> - - - ) : null} - {messageData.length > 0 ? ( - <> + + + {showModelSnapshots ? ( } + dataValues={modelSnapshotData} + marker={} markerPosition={Position.Top} style={{ line: { strokeWidth: 3, - stroke: euiTheme.euiColorAccent, + stroke: euiTheme.euiColorVis1, opacity: 0.5, }, }} /> - - ) : null} - - - + ) : null} + {showAnnotations ? ( + <> + } + markerPosition={Position.Top} + style={{ + line: { + strokeWidth: 3, + stroke: euiTheme.euiColorDangerText, + opacity: 0.5, + }, + }} + /> + + + ) : null} + {messageData.length > 0 ? ( + <> + } + markerPosition={Position.Top} + style={{ + line: { + strokeWidth: 3, + stroke: euiTheme.euiColorAccent, + opacity: 0.5, + }, + }} + /> + + ) : null} + + + +
{ + await ml.api.indexAnnotation(annotation as Partial, annotationId); + }); + + it('displays delayed data chart for annotation', async () => { + await ml.testExecution.logTestStep( + 'should display delayed data action in annotations table' + ); + + await ml.navigation.navigateToMl(); + await ml.navigation.navigateToJobManagement(); + await ml.jobTable.waitForJobsToLoad(); + await ml.jobTable.filterWithSearchString(jobId, 1); + await ml.jobTable.openAnnotationsTab(jobId); + + await ml.jobAnnotations.openDatafeedChartFlyout(annotationId, jobId); + await ml.jobAnnotations.assertDelayedDataChartExists(); + }); + }); + describe('deleting', function () { const annotationId = `delete-annotation-id-${Date.now()}`; diff --git a/x-pack/test/functional/services/ml/job_annotations_table.ts b/x-pack/test/functional/services/ml/job_annotations_table.ts index 0acba253cb056..90b47e9f8b455 100644 --- a/x-pack/test/functional/services/ml/job_annotations_table.ts +++ b/x-pack/test/functional/services/ml/job_annotations_table.ts @@ -341,5 +341,51 @@ export function MachineLearningJobAnnotationsProvider({ getService }: FtrProvide await this.setAnnotationText(text); }); } + + public async assertAnnotationsDelayedDataChartActionExists() { + await retry.tryForTime(1000, async () => { + await testSubjects.existOrFail('mlAnnotationsActionViewDatafeed'); + }); + } + + public async ensureAllMenuPopoversClosed() { + await retry.tryForTime(5000, async () => { + await browser.pressKeys(browser.keys.ESCAPE); + const popoverExists = await find.existsByCssSelector('euiContextMenuPanel'); + expect(popoverExists).to.eql(false, 'All popovers should be closed'); + }); + } + + public async ensureAnnotationsActionsMenuOpen(annotationId: string) { + await retry.tryForTime(10 * 1000, async () => { + await this.ensureAllMenuPopoversClosed(); + await testSubjects.click( + `mlAnnotationsTableRow row-${annotationId} > euiCollapsedItemActionsButton`, + 30 * 1000 + ); + await find.existsByCssSelector('euiContextMenuPanel'); + }); + } + + public async openDatafeedChartFlyout(annotationId: string, jobId: string) { + await retry.tryForTime(10 * 1000, async () => { + await this.ensureAnnotationsActionsMenuOpen(annotationId); + await this.assertAnnotationsDelayedDataChartActionExists(); + + await testSubjects.clickWhenNotDisabled('mlAnnotationsActionViewDatafeed'); + await testSubjects.existOrFail('mlAnnotationsViewDatafeedFlyout'); + await testSubjects.existOrFail('mlAnnotationsViewDatafeedFlyoutTitle'); + + const title = await testSubjects.getVisibleText('mlAnnotationsViewDatafeedFlyoutTitle'); + expect(title).to.eql( + `Datafeed chart for ${jobId}`, + `Expected annotations flyout title to be 'Datafeed chart for ${jobId}' but got ${title}` + ); + }); + } + + public async assertDelayedDataChartExists() { + await testSubjects.existOrFail('mlAnnotationsViewDatafeedFlyoutChart'); + } })(); } From b120c04a8d1e07fffbe75f008b14fe628bf3a3c7 Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Fri, 20 Aug 2021 14:13:19 -0400 Subject: [PATCH 41/76] Fix maps upgrade test (#109088) (#109262) Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: liza-mae --- .../upgrade/apps/maps/maps_smoke_tests.ts | 54 ++++++++++++------- 1 file changed, 34 insertions(+), 20 deletions(-) diff --git a/x-pack/test/upgrade/apps/maps/maps_smoke_tests.ts b/x-pack/test/upgrade/apps/maps/maps_smoke_tests.ts index 0c43528ad8b84..5a98011386567 100644 --- a/x-pack/test/upgrade/apps/maps/maps_smoke_tests.ts +++ b/x-pack/test/upgrade/apps/maps/maps_smoke_tests.ts @@ -19,6 +19,7 @@ export default function ({ const screenshot = getService('screenshots'); const testSubjects = getService('testSubjects'); const kibanaServer = getService('kibanaServer'); + const browser = getService('browser'); const SAMPLE_DATA_RANGE = `[ { "from": "now-30d", @@ -87,20 +88,29 @@ export default function ({ ]; before(async () => { - await kibanaServer.uiSettings.update({ - [UI_SETTINGS.TIMEPICKER_QUICK_RANGES]: SAMPLE_DATA_RANGE, - }); + await kibanaServer.uiSettings.update( + { [UI_SETTINGS.TIMEPICKER_QUICK_RANGES]: SAMPLE_DATA_RANGE }, + { space: 'default' } + ); + await kibanaServer.uiSettings.update( + { [UI_SETTINGS.TIMEPICKER_QUICK_RANGES]: SAMPLE_DATA_RANGE }, + { space: 'automation' } + ); + await browser.refresh(); }); spaces.forEach(({ space, basePath }) => { describe('space ' + space + ' ecommerce', () => { before(async () => { - await PageObjects.common.navigateToActualUrl('home', '/tutorial_directory/sampleData', { - basePath, - }); + await PageObjects.common.navigateToActualUrl( + 'maps', + 'map/' + '2c9c1f60-1909-11e9-919b-ffe5949a18d2', + { + basePath, + } + ); await PageObjects.header.waitUntilLoadingHasFinished(); - await PageObjects.home.addSampleDataSet('ecommerce'); - await PageObjects.maps.loadSavedMap('[eCommerce] Orders by Country'); + await PageObjects.maps.waitForLayersToLoad(); await PageObjects.maps.toggleLayerVisibility('Road map'); await PageObjects.maps.toggleLayerVisibility('United Kingdom'); await PageObjects.maps.toggleLayerVisibility('France'); @@ -120,15 +130,17 @@ export default function ({ expect(percentDifference.toFixed(3)).to.be.lessThan(0.031); }); }); - describe('space ' + space + ' flights', () => { before(async () => { - await PageObjects.common.navigateToActualUrl('home', '/tutorial_directory/sampleData', { - basePath, - }); + await PageObjects.common.navigateToActualUrl( + 'maps', + 'map/' + '5dd88580-1906-11e9-919b-ffe5949a18d2', + { + basePath, + } + ); await PageObjects.header.waitUntilLoadingHasFinished(); - await PageObjects.home.addSampleDataSet('flights'); - await PageObjects.maps.loadSavedMap('[Flights] Origin Time Delayed'); + await PageObjects.maps.waitForLayersToLoad(); await PageObjects.maps.toggleLayerVisibility('Road map'); await PageObjects.timePicker.setCommonlyUsedTime('sample_data range'); await PageObjects.maps.enterFullScreen(); @@ -144,15 +156,17 @@ export default function ({ expect(percentDifference.toFixed(3)).to.be.lessThan(0.031); }); }); - describe('space ' + space + ' web logs', () => { before(async () => { - await PageObjects.common.navigateToActualUrl('home', '/tutorial_directory/sampleData', { - basePath, - }); + await PageObjects.common.navigateToActualUrl( + 'maps', + 'map/' + 'de71f4f0-1902-11e9-919b-ffe5949a18d2', + { + basePath, + } + ); await PageObjects.header.waitUntilLoadingHasFinished(); - await PageObjects.home.addSampleDataSet('logs'); - await PageObjects.maps.loadSavedMap('[Logs] Total Requests and Bytes'); + await PageObjects.maps.waitForLayersToLoad(); await PageObjects.maps.toggleLayerVisibility('Road map'); await PageObjects.maps.toggleLayerVisibility('Total Requests by Country'); await PageObjects.timePicker.setCommonlyUsedTime('sample_data range'); From 31bda372afa2e2d50f64f75cd32214cddefa6099 Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Fri, 20 Aug 2021 14:32:21 -0400 Subject: [PATCH 42/76] Remove references to deprecated IIndexPattern. (#109347) (#109506) Co-authored-by: Justin Kambic --- .../shared/exploratory_view/configurations/utils.ts | 10 +++++----- .../exploratory_view/hooks/use_app_index_pattern.tsx | 8 ++++---- .../public/components/shared/exploratory_view/types.ts | 4 ++-- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/utils.ts b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/utils.ts index f7df2939d9909..1af4e83ed1f54 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/utils.ts +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/utils.ts @@ -7,7 +7,7 @@ import rison, { RisonValue } from 'rison-node'; import type { SeriesUrl, UrlFilter } from '../types'; import type { AllSeries, AllShortSeries } from '../hooks/use_series_storage'; -import { IIndexPattern } from '../../../../../../../../src/plugins/data/common/index_patterns'; +import { IndexPattern } from '../../../../../../../../src/plugins/data/common/index_patterns'; import { esFilters, ExistsFilter } from '../../../../../../../../src/plugins/data/public'; import { URL_KEYS } from './constants/url_constants'; import { PersistableFilter } from '../../../../../../lens/common'; @@ -53,7 +53,7 @@ export function createExploratoryViewUrl(allSeries: AllSeries, baseHref = '') { ); } -export function buildPhraseFilter(field: string, value: string, indexPattern: IIndexPattern) { +export function buildPhraseFilter(field: string, value: string, indexPattern: IndexPattern) { const fieldMeta = indexPattern?.fields.find((fieldT) => fieldT.name === field); if (fieldMeta) { return [esFilters.buildPhraseFilter(fieldMeta, value, indexPattern)]; @@ -61,7 +61,7 @@ export function buildPhraseFilter(field: string, value: string, indexPattern: II return []; } -export function buildPhrasesFilter(field: string, value: string[], indexPattern: IIndexPattern) { +export function buildPhrasesFilter(field: string, value: string[], indexPattern: IndexPattern) { const fieldMeta = indexPattern?.fields.find((fieldT) => fieldT.name === field); if (fieldMeta) { return [esFilters.buildPhrasesFilter(fieldMeta, value, indexPattern)]; @@ -69,7 +69,7 @@ export function buildPhrasesFilter(field: string, value: string[], indexPattern: return []; } -export function buildExistsFilter(field: string, indexPattern: IIndexPattern) { +export function buildExistsFilter(field: string, indexPattern: IndexPattern) { const fieldMeta = indexPattern?.fields.find((fieldT) => fieldT.name === field); if (fieldMeta) { return [esFilters.buildExistsFilter(fieldMeta, indexPattern)]; @@ -86,7 +86,7 @@ export function urlFilterToPersistedFilter({ }: { urlFilters: UrlFilter[]; initFilters: FiltersType; - indexPattern: IIndexPattern; + indexPattern: IndexPattern; }) { const parsedFilters: FiltersType = initFilters ? [...initFilters] : []; diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_app_index_pattern.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_app_index_pattern.tsx index 7a5f12a72b1f0..e508990ea25a4 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_app_index_pattern.tsx +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_app_index_pattern.tsx @@ -13,14 +13,14 @@ import { ObservabilityPublicPluginsStart } from '../../../../plugin'; import { ObservabilityIndexPatterns } from '../utils/observability_index_patterns'; import { getDataHandler } from '../../../../data_handler'; -export interface IIndexPatternContext { +export interface IndexPatternContext { loading: boolean; indexPatterns: IndexPatternState; hasAppData: HasAppDataState; loadIndexPattern: (params: { dataType: AppDataType }) => void; } -export const IndexPatternContext = createContext>({}); +export const IndexPatternContext = createContext>({}); interface ProviderProps { children: JSX.Element; @@ -46,7 +46,7 @@ export function IndexPatternContextProvider({ children }: ProviderProps) { services: { data }, } = useKibana(); - const loadIndexPattern: IIndexPatternContext['loadIndexPattern'] = useCallback( + const loadIndexPattern: IndexPatternContext['loadIndexPattern'] = useCallback( async ({ dataType }) => { if (hasAppData[dataType] === null && !loading[dataType]) { setLoading((prevState) => ({ ...prevState, [dataType]: true })); @@ -101,7 +101,7 @@ export function IndexPatternContextProvider({ children }: ProviderProps) { export const useAppIndexPatternContext = (dataType?: AppDataType) => { const { loading, hasAppData, loadIndexPattern, indexPatterns } = useContext( - (IndexPatternContext as unknown) as Context + (IndexPatternContext as unknown) as Context ); if (dataType && !indexPatterns?.[dataType] && !loading) { diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/types.ts b/x-pack/plugins/observability/public/components/shared/exploratory_view/types.ts index fbda2f4ff62e2..9817899412ce3 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/types.ts +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/types.ts @@ -17,7 +17,7 @@ import { } from '../../../../../lens/public'; import { PersistableFilter } from '../../../../../lens/common'; -import { IIndexPattern } from '../../../../../../../src/plugins/data/public'; +import { IndexPattern } from '../../../../../../../src/plugins/data/public'; export const ReportViewTypes = { dist: 'data-distribution', @@ -91,7 +91,7 @@ export interface UrlFilter { } export interface ConfigProps { - indexPattern: IIndexPattern; + indexPattern: IndexPattern; series?: SeriesUrl; } From 61d3f2e9bdabccfcdfcb23da84aa70e08e89ae4e Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Fri, 20 Aug 2021 14:35:49 -0400 Subject: [PATCH 43/76] Fix bug with highlighting in field formatters (#109401) (#109505) Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Tim Roes --- .../field_formats/common/converters/string.test.ts | 14 ++++++++++++++ .../field_formats/common/converters/string.ts | 2 +- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/plugins/field_formats/common/converters/string.test.ts b/src/plugins/field_formats/common/converters/string.test.ts index d691712b674dd..e5e4023621d3d 100644 --- a/src/plugins/field_formats/common/converters/string.test.ts +++ b/src/plugins/field_formats/common/converters/string.test.ts @@ -111,4 +111,18 @@ describe('String Format', () => { '(empty)' ); }); + + test('does escape value while highlighting', () => { + const string = new StringFormat(); + expect( + stripSpan( + string.convert('', 'html', { + field: { name: 'foo' }, + hit: { + highlight: { foo: ['@kibana-highlighted-field@@/kibana-highlighted-field@'] }, + }, + }) + ) + ).toBe('<img />'); + }); }); diff --git a/src/plugins/field_formats/common/converters/string.ts b/src/plugins/field_formats/common/converters/string.ts index 96cd786147800..a3d571897ef61 100644 --- a/src/plugins/field_formats/common/converters/string.ts +++ b/src/plugins/field_formats/common/converters/string.ts @@ -137,7 +137,7 @@ export class StringFormat extends FieldFormat { } return hit?.highlight?.[field?.name] - ? getHighlightHtml(val, hit.highlight[field.name]) + ? getHighlightHtml(escape(val), hit.highlight[field.name]) : escape(this.textConvert(val)); }; } From fb8af4d7d3ffd95262ce20fa177e5e48db836c9a Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Fri, 20 Aug 2021 14:45:32 -0400 Subject: [PATCH 44/76] chore(NA): moving @kbn/ui-shared-deps to babel transpiler (#109323) (#109509) * chore(NA): moving @kbn/ui-shared-deps to babel transpiler * fix(NA): missing correct paths on package.json files * chore(NA): update jest integration snapshots Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Tiago Costa --- .../basic_optimization.test.ts | 6 +- packages/kbn-ui-shared-deps/.babelrc | 3 + packages/kbn-ui-shared-deps/BUILD.bazel | 61 ++++++++++++++++--- .../flot_charts/package.json | 4 +- packages/kbn-ui-shared-deps/package.json | 4 +- .../kbn-ui-shared-deps/theme/package.json | 4 +- packages/kbn-ui-shared-deps/tsconfig.json | 3 +- 7 files changed, 67 insertions(+), 18 deletions(-) create mode 100644 packages/kbn-ui-shared-deps/.babelrc diff --git a/packages/kbn-optimizer/src/integration_tests/basic_optimization.test.ts b/packages/kbn-optimizer/src/integration_tests/basic_optimization.test.ts index 646c279cd1346..c1fa2994bbe52 100644 --- a/packages/kbn-optimizer/src/integration_tests/basic_optimization.test.ts +++ b/packages/kbn-optimizer/src/integration_tests/basic_optimization.test.ts @@ -132,7 +132,7 @@ it('builds expected bundles, saves bundle counts to metadata', async () => { expect(foo.cache.getModuleCount()).toBe(6); expect(foo.cache.getReferencedFiles()).toMatchInlineSnapshot(` Array [ - /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/bazel-out/-fastbuild/bin/packages/kbn-ui-shared-deps/target/public_path_module_creator.js, + /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/bazel-out/-fastbuild/bin/packages/kbn-ui-shared-deps/target_node/public_path_module_creator.js, /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/foo/kibana.json, /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/foo/public/async_import.ts, /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/foo/public/ext.ts, @@ -155,7 +155,7 @@ it('builds expected bundles, saves bundle counts to metadata', async () => { /node_modules/@kbn/optimizer/postcss.config.js, /node_modules/css-loader/package.json, /node_modules/style-loader/package.json, - /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/bazel-out/-fastbuild/bin/packages/kbn-ui-shared-deps/target/public_path_module_creator.js, + /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/bazel-out/-fastbuild/bin/packages/kbn-ui-shared-deps/target_node/public_path_module_creator.js, /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/bar/kibana.json, /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/bar/public/index.scss, /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/bar/public/index.ts, @@ -175,7 +175,7 @@ it('builds expected bundles, saves bundle counts to metadata', async () => { expect(baz.cache.getReferencedFiles()).toMatchInlineSnapshot(` Array [ - /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/bazel-out/-fastbuild/bin/packages/kbn-ui-shared-deps/target/public_path_module_creator.js, + /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/bazel-out/-fastbuild/bin/packages/kbn-ui-shared-deps/target_node/public_path_module_creator.js, /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/x-pack/baz/kibana.json, /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/x-pack/baz/public/index.ts, /packages/kbn-optimizer/src/worker/entry_point_creator.ts, diff --git a/packages/kbn-ui-shared-deps/.babelrc b/packages/kbn-ui-shared-deps/.babelrc new file mode 100644 index 0000000000000..7da72d1779128 --- /dev/null +++ b/packages/kbn-ui-shared-deps/.babelrc @@ -0,0 +1,3 @@ +{ + "presets": ["@kbn/babel-preset/node_preset"] +} diff --git a/packages/kbn-ui-shared-deps/BUILD.bazel b/packages/kbn-ui-shared-deps/BUILD.bazel index 352fd48907345..8bc9555e640b5 100644 --- a/packages/kbn-ui-shared-deps/BUILD.bazel +++ b/packages/kbn-ui-shared-deps/BUILD.bazel @@ -1,6 +1,7 @@ load("@npm//@bazel/typescript:index.bzl", "ts_config", "ts_project") load("@build_bazel_rules_nodejs//:index.bzl", "js_library", "pkg_npm") load("@npm//webpack-cli:index.bzl", webpack = "webpack_cli") +load("//src/dev/bazel:index.bzl", "jsts_transpiler") PKG_BASE_NAME = "kbn-ui-shared-deps" PKG_REQUIRE_NAME = "@kbn/ui-shared-deps" @@ -28,7 +29,7 @@ NPM_MODULE_EXTRA_FILES = [ "README.md" ] -SRC_DEPS = [ +RUNTIME_DEPS = [ "//packages/elastic-datemath", "//packages/elastic-safer-lodash-set", "//packages/kbn-analytics", @@ -71,10 +72,53 @@ SRC_DEPS = [ ] TYPES_DEPS = [ + "//packages/elastic-datemath", + "//packages/elastic-safer-lodash-set", + "//packages/kbn-analytics", + "//packages/kbn-babel-preset", + "//packages/kbn-i18n", + "//packages/kbn-monaco", + "//packages/kbn-std", + "//packages/kbn-utils", + "@npm//@elastic/charts", + "@npm//@elastic/eui", + "@npm//@elastic/numeral", + "@npm//@emotion/react", + "@npm//abortcontroller-polyfill", + "@npm//angular", + "@npm//babel-loader", + "@npm//core-js", + "@npm//css-loader", + "@npm//fflate", + "@npm//jquery", + "@npm//loader-utils", + "@npm//mini-css-extract-plugin", + "@npm//moment", + "@npm//moment-timezone", + "@npm//raw-loader", + "@npm//react", + "@npm//react-dom", + "@npm//react-intl", + "@npm//react-is", + "@npm//react-router", + "@npm//react-router-dom", + "@npm//regenerator-runtime", + "@npm//resize-observer-polyfill", + "@npm//rison-node", + "@npm//rxjs", + "@npm//styled-components", + "@npm//symbol-observable", + "@npm//url-loader", + "@npm//val-loader", + "@npm//whatwg-fetch", "@npm//@types/node", ] -DEPS = SRC_DEPS + TYPES_DEPS +jsts_transpiler( + name = "target_node", + srcs = SRCS, + build_pkg_name = package_name(), +) ts_config( name = "tsconfig", @@ -86,22 +130,23 @@ ts_config( ) ts_project( - name = "tsc", + name = "tsc_types", args = ['--pretty'], srcs = SRCS, - deps = DEPS, + deps = TYPES_DEPS, allow_js = True, declaration = True, declaration_map = True, - out_dir = "target", - source_map = True, + emit_declaration_only = True, + out_dir = "target_types", root_dir = "src", + source_map = True, tsconfig = ":tsconfig", ) webpack( name = "shared_built_assets", - data = DEPS + [ + data = RUNTIME_DEPS + [ "//:package.json", ":srcs", ":tsconfig", @@ -120,7 +165,7 @@ webpack( js_library( name = PKG_BASE_NAME, srcs = NPM_MODULE_EXTRA_FILES, - deps = DEPS + [":tsc", ":shared_built_assets"], + deps = RUNTIME_DEPS + [":target_node", ":tsc_types", ":shared_built_assets"], package_name = PKG_REQUIRE_NAME, visibility = ["//visibility:public"], ) diff --git a/packages/kbn-ui-shared-deps/flot_charts/package.json b/packages/kbn-ui-shared-deps/flot_charts/package.json index 03d7ac348fcb9..6c2f62447daf5 100644 --- a/packages/kbn-ui-shared-deps/flot_charts/package.json +++ b/packages/kbn-ui-shared-deps/flot_charts/package.json @@ -1,4 +1,4 @@ { - "main": "../target/flot_charts/index.js", - "types": "../target/flot_charts/index.d.ts" + "main": "../target_node/flot_charts/index.js", + "types": "../target_types/flot_charts/index.d.ts" } \ No newline at end of file diff --git a/packages/kbn-ui-shared-deps/package.json b/packages/kbn-ui-shared-deps/package.json index 5ec32ca059aa1..f360d37db11c8 100644 --- a/packages/kbn-ui-shared-deps/package.json +++ b/packages/kbn-ui-shared-deps/package.json @@ -3,6 +3,6 @@ "version": "1.0.0", "private": true, "license": "SSPL-1.0 OR Elastic License 2.0", - "main": "target/index.js", - "types": "target/index.d.ts" + "main": "target_node/index.js", + "types": "target_types/index.d.ts" } \ No newline at end of file diff --git a/packages/kbn-ui-shared-deps/theme/package.json b/packages/kbn-ui-shared-deps/theme/package.json index 2d41937701a29..37d60f83b18e9 100644 --- a/packages/kbn-ui-shared-deps/theme/package.json +++ b/packages/kbn-ui-shared-deps/theme/package.json @@ -1,4 +1,4 @@ { - "main": "../target/theme.js", - "types": "../target/theme.d.ts" + "main": "../target_node/theme.js", + "types": "../target_types/theme.d.ts" } \ No newline at end of file diff --git a/packages/kbn-ui-shared-deps/tsconfig.json b/packages/kbn-ui-shared-deps/tsconfig.json index 90a89ac580a40..81a8a6b200ada 100644 --- a/packages/kbn-ui-shared-deps/tsconfig.json +++ b/packages/kbn-ui-shared-deps/tsconfig.json @@ -2,9 +2,10 @@ "extends": "../../tsconfig.bazel.json", "compilerOptions": { "allowJs": true, - "outDir": "./target/types", "declaration": true, "declarationMap": true, + "emitDeclarationOnly": true, + "outDir": "./target_types", "rootDir": "src", "sourceMap": true, "sourceRoot": "../../../../packages/kbn-ui-shared-deps/src", From f087c755d14fc53cfc030034d7ad267142e16d02 Mon Sep 17 00:00:00 2001 From: Lukas Olson Date: Fri, 20 Aug 2021 11:54:54 -0700 Subject: [PATCH 45/76] [data.search] Handle warnings inside of headers (#103744) (#109298) * [data.search] Handle warnings inside of headers * Update docs * Add tests * Remove isWarningResponse Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- ...ugins-data-public.ikibanasearchresponse.md | 1 + ...ta-public.ikibanasearchresponse.warning.md | 13 +++ .../search_examples/public/search/app.tsx | 98 +++++++++++++++++-- src/plugins/data/common/search/types.ts | 5 + src/plugins/data/public/public.api.md | 1 + .../public/search/fetch/handle_response.tsx | 13 ++- .../ese_search/ese_search_strategy.ts | 6 +- .../strategies/ese_search/response_utils.ts | 3 +- .../search_examples/search_example.ts | 21 ++++ 9 files changed, 151 insertions(+), 10 deletions(-) create mode 100644 docs/development/plugins/data/public/kibana-plugin-plugins-data-public.ikibanasearchresponse.warning.md diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.ikibanasearchresponse.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.ikibanasearchresponse.md index c7046902dac72..73261cd49d6d2 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.ikibanasearchresponse.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.ikibanasearchresponse.md @@ -21,4 +21,5 @@ export interface IKibanaSearchResponse | [loaded](./kibana-plugin-plugins-data-public.ikibanasearchresponse.loaded.md) | number | If relevant to the search strategy, return a loaded number that represents how progress is indicated. | | [rawResponse](./kibana-plugin-plugins-data-public.ikibanasearchresponse.rawresponse.md) | RawResponse | The raw response returned by the internal search method (usually the raw ES response) | | [total](./kibana-plugin-plugins-data-public.ikibanasearchresponse.total.md) | number | If relevant to the search strategy, return a total number that represents how progress is indicated. | +| [warning](./kibana-plugin-plugins-data-public.ikibanasearchresponse.warning.md) | string | Optional warnings that should be surfaced to the end user | diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.ikibanasearchresponse.warning.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.ikibanasearchresponse.warning.md new file mode 100644 index 0000000000000..cc0b8e2bea56e --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.ikibanasearchresponse.warning.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [IKibanaSearchResponse](./kibana-plugin-plugins-data-public.ikibanasearchresponse.md) > [warning](./kibana-plugin-plugins-data-public.ikibanasearchresponse.warning.md) + +## IKibanaSearchResponse.warning property + +Optional warnings that should be surfaced to the end user + +Signature: + +```typescript +warning?: string; +``` diff --git a/examples/search_examples/public/search/app.tsx b/examples/search_examples/public/search/app.tsx index 06f9426b4965c..bfb41160ae963 100644 --- a/examples/search_examples/public/search/app.tsx +++ b/examples/search_examples/public/search/app.tsx @@ -131,12 +131,46 @@ export const SearchExamplesApp = ({ setSelectedNumericField(fields?.length ? getNumeric(fields)[0] : null); }, [fields]); - const doAsyncSearch = async (strategy?: string, sessionId?: string) => { + const doAsyncSearch = async ( + strategy?: string, + sessionId?: string, + addWarning: boolean = false, + addError: boolean = false + ) => { if (!indexPattern || !selectedNumericField) return; // Construct the query portion of the search request const query = data.query.getEsQuery(indexPattern); + if (addWarning) { + query.bool.must.push({ + // @ts-ignore + error_query: { + indices: [ + { + name: indexPattern.title, + error_type: 'warning', + message: 'Watch out!', + }, + ], + }, + }); + } + if (addError) { + query.bool.must.push({ + // @ts-ignore + error_query: { + indices: [ + { + name: indexPattern.title, + error_type: 'exception', + message: 'Watch out!', + }, + ], + }, + }); + } + // Construct the aggregations portion of the search request by using the `data.search.aggs` service. const aggs = [{ type: 'avg', params: { field: selectedNumericField!.name } }]; const aggsDsl = data.search.aggs.createAggConfigs(indexPattern, aggs).toDsl(); @@ -193,14 +227,23 @@ export const SearchExamplesApp = ({ } ); searchSubscription$.unsubscribe(); + if (res.warning) { + notifications.toasts.addWarning({ + title: 'Warning', + text: mountReactNode(res.warning), + }); + } } else if (isErrorResponse(res)) { // TODO: Make response error status clearer - notifications.toasts.addWarning('An error has occurred'); + notifications.toasts.addDanger('An error has occurred'); searchSubscription$.unsubscribe(); } }, - error: () => { - notifications.toasts.addDanger('Failed to run search'); + error: (e) => { + notifications.toasts.addDanger({ + title: 'Failed to run search', + text: e.message, + }); }, }); }; @@ -270,6 +313,14 @@ export const SearchExamplesApp = ({ doAsyncSearch('myStrategy'); }; + const onWarningSearchClickHandler = () => { + doAsyncSearch(undefined, undefined, true); + }; + + const onErrorSearchClickHandler = () => { + doAsyncSearch(undefined, undefined, false, true); + }; + const onPartialResultsClickHandler = () => { setSelectedTab(1); const req = { @@ -299,8 +350,11 @@ export const SearchExamplesApp = ({ searchSubscription$.unsubscribe(); } }, - error: () => { - notifications.toasts.addDanger('Failed to run search'); + error: (e) => { + notifications.toasts.addDanger({ + title: 'Failed to run search', + text: e.message, + }); }, }); }; @@ -530,6 +584,38 @@ export const SearchExamplesApp = ({ + +

Handling errors & warnings

+
+ + When fetching data from Elasticsearch, there are several different ways warnings and + errors may be returned. In general, it is recommended to surface these in the UX. + + + + + + + + + +

Handling partial results

diff --git a/src/plugins/data/common/search/types.ts b/src/plugins/data/common/search/types.ts index cffba6203dfe2..68a25d4c4d69d 100644 --- a/src/plugins/data/common/search/types.ts +++ b/src/plugins/data/common/search/types.ts @@ -70,6 +70,11 @@ export interface IKibanaSearchResponse { */ isRestored?: boolean; + /** + * Optional warnings that should be surfaced to the end user + */ + warning?: string; + /** * The raw response returned by the internal search method (usually the raw ES response) */ diff --git a/src/plugins/data/public/public.api.md b/src/plugins/data/public/public.api.md index 1fb78900f9e35..2f3df32cc6ff3 100644 --- a/src/plugins/data/public/public.api.md +++ b/src/plugins/data/public/public.api.md @@ -1149,6 +1149,7 @@ export interface IKibanaSearchResponse { loaded?: number; rawResponse: RawResponse; total?: number; + warning?: string; } // Warning: (ae-forgotten-export) The symbol "MetricAggType" needs to be exported by the entry point index.d.ts diff --git a/src/plugins/data/public/search/fetch/handle_response.tsx b/src/plugins/data/public/search/fetch/handle_response.tsx index 58e4da6b95fae..f4acebfb36060 100644 --- a/src/plugins/data/public/search/fetch/handle_response.tsx +++ b/src/plugins/data/public/search/fetch/handle_response.tsx @@ -16,7 +16,18 @@ import { getNotifications } from '../../services'; import { SearchRequest } from '..'; export function handleResponse(request: SearchRequest, response: IKibanaSearchResponse) { - const { rawResponse } = response; + const { rawResponse, warning } = response; + if (warning) { + getNotifications().toasts.addWarning({ + title: i18n.translate('data.search.searchSource.fetch.warningMessage', { + defaultMessage: 'Warning: {warning}', + values: { + warning, + }, + }), + }); + } + if (rawResponse.timed_out) { getNotifications().toasts.addWarning({ title: i18n.translate('data.search.searchSource.fetch.requestTimedOutNotificationMessage', { diff --git a/src/plugins/data/server/search/strategies/ese_search/ese_search_strategy.ts b/src/plugins/data/server/search/strategies/ese_search/ese_search_strategy.ts index eb39417ac535f..75a4ddf051418 100644 --- a/src/plugins/data/server/search/strategies/ese_search/ese_search_strategy.ts +++ b/src/plugins/data/server/search/strategies/ese_search/ese_search_strategy.ts @@ -71,12 +71,14 @@ export const enhancedEsSearchStrategyProvider = ( const promise = id ? client.asyncSearch.get({ ...params, id }) : client.asyncSearch.submit(params); - const { body } = await shimAbortSignal(promise, options.abortSignal); + const { body, headers } = await shimAbortSignal(promise, options.abortSignal); + const response = shimHitsTotal(body.response, options); return toAsyncKibanaSearchResponse( // @ts-expect-error @elastic/elasticsearch start_time_in_millis expected to be number - { ...body, response } + { ...body, response }, + headers?.warning ); }; diff --git a/src/plugins/data/server/search/strategies/ese_search/response_utils.ts b/src/plugins/data/server/search/strategies/ese_search/response_utils.ts index ae3d258e2205d..0a92c95dac615 100644 --- a/src/plugins/data/server/search/strategies/ese_search/response_utils.ts +++ b/src/plugins/data/server/search/strategies/ese_search/response_utils.ts @@ -12,12 +12,13 @@ import { getTotalLoaded } from '../es_search'; /** * Get the Kibana representation of an async search response (see `IKibanaSearchResponse`). */ -export function toAsyncKibanaSearchResponse(response: AsyncSearchResponse) { +export function toAsyncKibanaSearchResponse(response: AsyncSearchResponse, warning?: string) { return { id: response.id, rawResponse: response.response, isPartial: response.is_partial, isRunning: response.is_running, + ...(warning ? { warning } : {}), ...getTotalLoaded(response.response), }; } diff --git a/x-pack/test/examples/search_examples/search_example.ts b/x-pack/test/examples/search_examples/search_example.ts index c841b595ed119..fb3cef4055e33 100644 --- a/x-pack/test/examples/search_examples/search_example.ts +++ b/x-pack/test/examples/search_examples/search_example.ts @@ -5,6 +5,7 @@ * 2.0. */ +import expect from '@kbn/expect'; import { FtrProviderContext } from '../../functional/ftr_provider_context'; // eslint-disable-next-line import/no-default-export @@ -13,6 +14,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const PageObjects = getPageObjects(['common', 'timePicker']); const retry = getService('retry'); const comboBox = getService('comboBox'); + const toasts = getService('toasts'); describe('Search session example', () => { const appId = 'searchExamples'; @@ -28,6 +30,13 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { ); }); + beforeEach(async () => { + await toasts.dismissAllToasts(); + await retry.waitFor('toasts gone', async () => { + return (await toasts.getToastCount()) === 0; + }); + }); + it('should have an other bucket', async () => { await testSubjects.click('searchSourceWithOther'); await testSubjects.click('responseTab'); @@ -53,5 +62,17 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { return buckets.length === 2; }); }); + + it('should handle warnings', async () => { + await testSubjects.click('searchWithWarning'); + await retry.waitFor('', async () => { + const toastCount = await toasts.getToastCount(); + return toastCount > 1; + }); + const warningToast = await toasts.getToastElement(2); + const textEl = await warningToast.findByClassName('euiToastBody'); + const text: string = await textEl.getVisibleText(); + expect(text).to.contain('Watch out!'); + }); }); } From b9adda7564c5d2f333142a8f40de8715aa88bcb2 Mon Sep 17 00:00:00 2001 From: Chris Cowan Date: Fri, 20 Aug 2021 13:57:06 -0600 Subject: [PATCH 46/76] [Metrics UI] Re-enabled saved view tests (#108725) (#109530) * [Metrics UI] Re-enabled saved view tests * Adding ensureViewIsLoadable back in Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- x-pack/test/functional/apps/infra/home_page.ts | 3 +-- x-pack/test/functional/apps/infra/metrics_explorer.ts | 3 +-- x-pack/test/functional/page_objects/infra_saved_views.ts | 5 ++--- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/x-pack/test/functional/apps/infra/home_page.ts b/x-pack/test/functional/apps/infra/home_page.ts index 90b34702767e4..e344f86f89fe8 100644 --- a/x-pack/test/functional/apps/infra/home_page.ts +++ b/x-pack/test/functional/apps/infra/home_page.ts @@ -87,8 +87,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { }); }); - // FLAKY: https://github.com/elastic/kibana/issues/106660 - describe.skip('Saved Views', () => { + describe('Saved Views', () => { before(() => esArchiver.load('x-pack/test/functional/es_archives/infra/metrics_and_logs')); after(() => esArchiver.unload('x-pack/test/functional/es_archives/infra/metrics_and_logs')); it('should have save and load controls', async () => { diff --git a/x-pack/test/functional/apps/infra/metrics_explorer.ts b/x-pack/test/functional/apps/infra/metrics_explorer.ts index 5a8d7da628259..6b1873b7b5e39 100644 --- a/x-pack/test/functional/apps/infra/metrics_explorer.ts +++ b/x-pack/test/functional/apps/infra/metrics_explorer.ts @@ -87,8 +87,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { }); }); - // FLAKY: https://github.com/elastic/kibana/issues/106651 - describe.skip('Saved Views', () => { + describe('Saved Views', () => { before(() => esArchiver.load('x-pack/test/functional/es_archives/infra/metrics_and_logs')); after(() => esArchiver.unload('x-pack/test/functional/es_archives/infra/metrics_and_logs')); describe('save functionality', () => { diff --git a/x-pack/test/functional/page_objects/infra_saved_views.ts b/x-pack/test/functional/page_objects/infra_saved_views.ts index ef91b3b5fcb3c..9437dd05d644c 100644 --- a/x-pack/test/functional/page_objects/infra_saved_views.ts +++ b/x-pack/test/functional/page_objects/infra_saved_views.ts @@ -79,9 +79,8 @@ export function InfraSavedViewsProvider({ getService }: FtrProviderContext) { }, async ensureViewIsLoadable(name: string) { - const subjects = await testSubjects.getVisibleTextAll('savedViews-loadList'); - const includesName = subjects.some((s) => s.includes(name)); - expect(includesName).to.be(true); + const subject = await testSubjects.find('savedViews-loadList'); + await subject.findByCssSelector(`li[title="${name}"]`); }, async closeSavedViewsLoadModal() { From a02b258fbf76f8bb2d96289cc8f21d5525a97035 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Fern=C3=A1ndez=20Haro?= Date: Fri, 20 Aug 2021 21:42:25 +0100 Subject: [PATCH 47/76] [7.x] Update dependency @elastic/elasticsearch to ^7.16.0-canary.1 (#109535) --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 7184b199aecd7..cadd067299554 100644 --- a/package.json +++ b/package.json @@ -94,7 +94,7 @@ "@elastic/apm-rum-react": "^1.2.11", "@elastic/charts": "34.1.1", "@elastic/datemath": "link:bazel-bin/packages/elastic-datemath", - "@elastic/elasticsearch": "npm:@elastic/elasticsearch-canary@^7.15.0-canary.3", + "@elastic/elasticsearch": "npm:@elastic/elasticsearch-canary@^7.16.0-canary.1", "@elastic/ems-client": "7.15.0", "@elastic/eui": "37.1.1", "@elastic/filesaver": "1.1.2", diff --git a/yarn.lock b/yarn.lock index 4357f2d0f2672..951ed8da48d4c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1432,10 +1432,10 @@ dependencies: "@elastic/ecs-helpers" "^1.1.0" -"@elastic/elasticsearch@npm:@elastic/elasticsearch-canary@^7.15.0-canary.3": - version "7.15.0-canary.3" - resolved "https://registry.yarnpkg.com/@elastic/elasticsearch-canary/-/elasticsearch-canary-7.15.0-canary.3.tgz#0f0f21641d4eab0eaa98e6f9f5c18f28a968c4ad" - integrity sha512-9T3/RNW0b6R1D7ZrdMZ7aujEjs4IoiKvhkTqrH6fDNzTaMmTCTf6BLnIbWWwGdFLYOyIjnpDg+pSfYF+JYjKFA== +"@elastic/elasticsearch@npm:@elastic/elasticsearch-canary@^7.16.0-canary.1": + version "7.16.0-canary.1" + resolved "https://registry.yarnpkg.com/@elastic/elasticsearch-canary/-/elasticsearch-canary-7.16.0-canary.1.tgz#c5490e28a503fe2c32a03413d23da237aec3eb70" + integrity sha512-bM7edHcILn29l8j53sxsZ0w0/m6P2nAOjehq4XFXQNBz7/d5mva7O0Wf9EqG22ZNqdU0rozIEnUSY0lwWzxJYw== dependencies: debug "^4.3.1" hpagent "^0.1.1" From ec3c28f29590d2d916826fb066fad059f3eb3152 Mon Sep 17 00:00:00 2001 From: CJ Cenizal Date: Fri, 20 Aug 2021 15:08:08 -0700 Subject: [PATCH 48/76] Fix link to Cloud deployment URL in upgrade step. (#109528) --- .../overview/upgrade_step/upgrade_step.test.tsx | 8 +++++--- .../components/overview/upgrade_step/upgrade_step.tsx | 5 +---- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/overview/upgrade_step/upgrade_step.test.tsx b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/overview/upgrade_step/upgrade_step.test.tsx index 21daed29acaca..bfcd88b91b94a 100644 --- a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/overview/upgrade_step/upgrade_step.test.tsx +++ b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/overview/upgrade_step/upgrade_step.test.tsx @@ -36,8 +36,8 @@ describe('Overview - Upgrade Step', () => { servicesOverrides: { cloud: { isCloudEnabled: true, - baseUrl: 'https://test.com', - cloudId: '1234', + deploymentUrl: + 'https://cloud.elastic.co./deployments/bfdad4ef99a24212a06d387593686d63', }, }, }); @@ -49,7 +49,9 @@ describe('Overview - Upgrade Step', () => { expect(exists('upgradeSetupCloudLink')).toBe(true); expect(exists('upgradeSetupDocsLink')).toBe(true); - expect(find('upgradeSetupCloudLink').props().href).toBe('https://test.com/deployments/1234'); + expect(find('upgradeSetupCloudLink').props().href).toBe( + 'https://cloud.elastic.co./deployments/bfdad4ef99a24212a06d387593686d63' + ); }); }); }); diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/overview/upgrade_step/upgrade_step.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/overview/upgrade_step/upgrade_step.tsx index d66a408cfce77..2ea6777404316 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/overview/upgrade_step/upgrade_step.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/overview/upgrade_step/upgrade_step.tsx @@ -50,10 +50,7 @@ const i18nTexts = { const UpgradeStep = ({ docLinks }: { docLinks: DocLinksStart }) => { const { cloud } = useKibana().services; - const isCloudEnabled: boolean = Boolean(cloud?.isCloudEnabled); - const cloudDeploymentUrl: string = `${cloud?.baseUrl ?? ''}/deployments/${cloud?.cloudId ?? ''}`; - let callToAction; if (isCloudEnabled) { @@ -61,7 +58,7 @@ const UpgradeStep = ({ docLinks }: { docLinks: DocLinksStart }) => { Date: Fri, 20 Aug 2021 18:10:12 -0400 Subject: [PATCH 49/76] [Upgrade Assistant] Refactor CITs (#109536) --- .../default_deprecation_flyout.test.ts | 6 +- .../es_deprecations/deprecations_list.test.ts | 25 +-- .../es_deprecations/error_handling.test.ts | 3 +- .../es_deprecations.helpers.ts | 150 +++++++++++++++ .../index_settings_deprecation_flyout.test.ts | 14 +- .../ml_snapshots_deprecation_flyout.test.ts | 21 ++- .../reindex_deprecation_flyout.test.ts | 6 +- .../helpers/app_context.mock.ts | 34 ++++ .../helpers/elasticsearch.helpers.ts | 171 ------------------ .../client_integration/helpers/index.ts | 6 +- ...ervices_mock.ts => kibana_context.mock.ts} | 2 +- .../helpers/setup_environment.tsx | 32 +--- .../kibana_deprecations.helpers.ts} | 17 +- .../kibana_deprecations.test.ts} | 3 +- .../fix_deprecation_logs_step.test.tsx | 3 +- .../{helpers => overview}/overview.helpers.ts | 36 +--- .../overview/overview.test.tsx | 3 +- .../review_logs_step.test.tsx | 75 +++----- .../upgrade_step/upgrade_step.test.tsx | 5 +- 19 files changed, 279 insertions(+), 333 deletions(-) create mode 100644 x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecations/es_deprecations.helpers.ts create mode 100644 x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/app_context.mock.ts delete mode 100644 x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/elasticsearch.helpers.ts rename x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/{services_mock.ts => kibana_context.mock.ts} (96%) rename x-pack/plugins/upgrade_assistant/__jest__/client_integration/{helpers/kibana.helpers.ts => kibana_deprecations/kibana_deprecations.helpers.ts} (73%) rename x-pack/plugins/upgrade_assistant/__jest__/client_integration/{kibana.test.ts => kibana_deprecations/kibana_deprecations.test.ts} (98%) rename x-pack/plugins/upgrade_assistant/__jest__/client_integration/{helpers => overview}/overview.helpers.ts (54%) diff --git a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecations/default_deprecation_flyout.test.ts b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecations/default_deprecation_flyout.test.ts index 917fac8ef666a..1975d0abaf11d 100644 --- a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecations/default_deprecation_flyout.test.ts +++ b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecations/default_deprecation_flyout.test.ts @@ -7,8 +7,8 @@ import { act } from 'react-dom/test-utils'; -import { ElasticsearchTestBed, setupElasticsearchPage, setupEnvironment } from '../helpers'; - +import { setupEnvironment } from '../helpers'; +import { ElasticsearchTestBed, setupElasticsearchPage } from './es_deprecations.helpers'; import { esDeprecationsMockResponse, MOCK_SNAPSHOT_ID, MOCK_JOB_ID } from './mocked_responses'; describe('Default deprecation flyout', () => { @@ -39,7 +39,7 @@ describe('Default deprecation flyout', () => { const multiFieldsDeprecation = esDeprecationsMockResponse.deprecations[2]; const { actions, find, exists } = testBed; - await actions.clickDefaultDeprecationAt(0); + await actions.table.clickDeprecationRowAt('default', 0); expect(exists('defaultDeprecationDetails')).toBe(true); expect(find('defaultDeprecationDetails.flyoutTitle').text()).toContain( diff --git a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecations/deprecations_list.test.ts b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecations/deprecations_list.test.ts index ceebc528f0bc4..f040de1c318fd 100644 --- a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecations/deprecations_list.test.ts +++ b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecations/deprecations_list.test.ts @@ -9,7 +9,8 @@ import { act } from 'react-dom/test-utils'; import { API_BASE_PATH } from '../../../common/constants'; import type { MlAction } from '../../../common/types'; -import { ElasticsearchTestBed, setupElasticsearchPage, setupEnvironment } from '../helpers'; +import { setupEnvironment } from '../helpers'; +import { ElasticsearchTestBed, setupElasticsearchPage } from './es_deprecations.helpers'; import { esDeprecationsMockResponse, MOCK_SNAPSHOT_ID, @@ -56,7 +57,7 @@ describe('Deprecations table', () => { const { actions } = testBed; const totalRequests = server.requests.length; - await actions.clickRefreshButton(); + await actions.table.clickRefreshButton(); const mlDeprecation = esDeprecationsMockResponse.deprecations[0]; const reindexDeprecation = esDeprecationsMockResponse.deprecations[3]; @@ -80,7 +81,7 @@ describe('Deprecations table', () => { it('filters results by "critical" status', async () => { const { find, actions } = testBed; - await actions.clickCriticalFilterButton(); + await actions.searchBar.clickCriticalFilterButton(); const criticalDeprecations = esDeprecationsMockResponse.deprecations.filter( (deprecation) => deprecation.isCritical @@ -88,7 +89,7 @@ describe('Deprecations table', () => { expect(find('deprecationTableRow').length).toEqual(criticalDeprecations.length); - await actions.clickCriticalFilterButton(); + await actions.searchBar.clickCriticalFilterButton(); expect(find('deprecationTableRow').length).toEqual( esDeprecationsMockResponse.deprecations.length @@ -98,7 +99,7 @@ describe('Deprecations table', () => { it('filters results by type', async () => { const { component, find, actions } = testBed; - await actions.clickTypeFilterDropdownAt(0); + await actions.searchBar.clickTypeFilterDropdownAt(0); // We need to read the document "body" as the filter dropdown options are added there and not inside // the component DOM tree. @@ -125,7 +126,7 @@ describe('Deprecations table', () => { const { find, actions } = testBed; const multiFieldsDeprecation = esDeprecationsMockResponse.deprecations[2]; - await actions.setSearchInputValue(multiFieldsDeprecation.message); + await actions.searchBar.setSearchInputValue(multiFieldsDeprecation.message); expect(find('deprecationTableRow').length).toEqual(1); expect(find('deprecationTableRow').at(0).text()).toContain(multiFieldsDeprecation.message); @@ -134,7 +135,7 @@ describe('Deprecations table', () => { it('shows error for invalid search queries', async () => { const { find, exists, actions } = testBed; - await actions.setSearchInputValue('%'); + await actions.searchBar.setSearchInputValue('%'); expect(exists('invalidSearchQueryMessage')).toBe(true); expect(find('invalidSearchQueryMessage').text()).toContain('Invalid search'); @@ -143,7 +144,7 @@ describe('Deprecations table', () => { it('shows message when search query does not return results', async () => { const { find, actions, exists } = testBed; - await actions.setSearchInputValue('foobarbaz'); + await actions.searchBar.setSearchInputValue('foobarbaz'); expect(exists('noDeprecationsRow')).toBe(true); expect(find('noDeprecationsRow').text()).toContain( @@ -183,7 +184,7 @@ describe('Deprecations table', () => { expect(find('deprecationTableRow').length).toEqual(50); // Navigate to the next page - await actions.clickPaginationAt(1); + await actions.pagination.clickPaginationAt(1); // On the second (last) page, we expect to see the remaining deprecations expect(find('deprecationTableRow').length).toEqual(deprecations.length - 50); @@ -192,7 +193,7 @@ describe('Deprecations table', () => { it('allows the number of viewable rows to change', async () => { const { find, actions, component } = testBed; - await actions.clickRowsPerPageDropdown(); + await actions.pagination.clickRowsPerPageDropdown(); // We need to read the document "body" as the rows-per-page dropdown options are added there and not inside // the component DOM tree. @@ -219,7 +220,7 @@ describe('Deprecations table', () => { const criticalDeprecations = deprecations.filter((deprecation) => deprecation.isCritical); - await actions.clickCriticalFilterButton(); + await actions.searchBar.clickCriticalFilterButton(); // Only 40 critical deprecations, so only one page should show expect(find('esDeprecationsPagination').find('.euiPagination__item').length).toEqual(1); @@ -232,7 +233,7 @@ describe('Deprecations table', () => { (deprecation) => deprecation.correctiveAction?.type === 'reindex' ); - await actions.setSearchInputValue('Index created before 7.0'); + await actions.searchBar.setSearchInputValue('Index created before 7.0'); // Only 20 deprecations that match, so only one page should show expect(find('esDeprecationsPagination').find('.euiPagination__item').length).toEqual(1); diff --git a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecations/error_handling.test.ts b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecations/error_handling.test.ts index 8d3616a1b9d6b..6314b4630f850 100644 --- a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecations/error_handling.test.ts +++ b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecations/error_handling.test.ts @@ -7,7 +7,8 @@ import { act } from 'react-dom/test-utils'; -import { ElasticsearchTestBed, setupElasticsearchPage, setupEnvironment } from '../helpers'; +import { setupEnvironment } from '../helpers'; +import { ElasticsearchTestBed, setupElasticsearchPage } from './es_deprecations.helpers'; describe('Error handling', () => { let testBed: ElasticsearchTestBed; diff --git a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecations/es_deprecations.helpers.ts b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecations/es_deprecations.helpers.ts new file mode 100644 index 0000000000000..96474f66dc629 --- /dev/null +++ b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecations/es_deprecations.helpers.ts @@ -0,0 +1,150 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { act } from 'react-dom/test-utils'; + +import { registerTestBed, TestBed, TestBedConfig } from '@kbn/test/jest'; +import { EsDeprecations } from '../../../public/application/components/es_deprecations'; +import { WithAppDependencies } from '../helpers'; + +const testBedConfig: TestBedConfig = { + memoryRouter: { + initialEntries: ['/es_deprecations'], + componentRoutePath: '/es_deprecations', + }, + doMountAsync: true, +}; + +export type ElasticsearchTestBed = TestBed & { + actions: ReturnType; +}; + +const createActions = (testBed: TestBed) => { + const { component, find } = testBed; + + /** + * User Actions + */ + + const table = { + clickRefreshButton: async () => { + await act(async () => { + find('refreshButton').simulate('click'); + }); + + component.update(); + }, + clickDeprecationRowAt: async ( + deprecationType: 'mlSnapshot' | 'indexSetting' | 'reindex' | 'default', + index: number + ) => { + await act(async () => { + find(`deprecation-${deprecationType}`).at(index).simulate('click'); + }); + + component.update(); + }, + }; + + const searchBar = { + clickTypeFilterDropdownAt: async (index: number) => { + await act(async () => { + // EUI doesn't support data-test-subj's on the filter buttons, so we must access via CSS selector + find('searchBarContainer') + .find('.euiPopover') + .find('.euiFilterButton') + .at(index) + .simulate('click'); + }); + + component.update(); + }, + setSearchInputValue: async (searchValue: string) => { + await act(async () => { + find('searchBarContainer') + .find('input') + .simulate('keyup', { target: { value: searchValue } }); + }); + + component.update(); + }, + clickCriticalFilterButton: async () => { + await act(async () => { + // EUI doesn't support data-test-subj's on the filter buttons, so we must access via CSS selector + find('searchBarContainer').find('.euiFilterButton').at(0).simulate('click'); + }); + + component.update(); + }, + }; + + const pagination = { + clickPaginationAt: async (index: number) => { + await act(async () => { + find(`pagination-button-${index}`).simulate('click'); + }); + + component.update(); + }, + clickRowsPerPageDropdown: async () => { + await act(async () => { + find('tablePaginationPopoverButton').simulate('click'); + }); + + component.update(); + }, + }; + + const mlDeprecationFlyout = { + clickUpgradeSnapshot: async () => { + await act(async () => { + find('mlSnapshotDetails.upgradeSnapshotButton').simulate('click'); + }); + + component.update(); + }, + clickDeleteSnapshot: async () => { + await act(async () => { + find('mlSnapshotDetails.deleteSnapshotButton').simulate('click'); + }); + + component.update(); + }, + }; + + const indexSettingsDeprecationFlyout = { + clickDeleteSettingsButton: async () => { + await act(async () => { + find('deleteSettingsButton').simulate('click'); + }); + + component.update(); + }, + }; + + return { + table, + searchBar, + pagination, + mlDeprecationFlyout, + indexSettingsDeprecationFlyout, + }; +}; + +export const setupElasticsearchPage = async ( + overrides?: Record +): Promise => { + const initTestBed = registerTestBed( + WithAppDependencies(EsDeprecations, overrides), + testBedConfig + ); + const testBed = await initTestBed(); + + return { + ...testBed, + actions: createActions(testBed), + }; +}; diff --git a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecations/index_settings_deprecation_flyout.test.ts b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecations/index_settings_deprecation_flyout.test.ts index efeb78a507160..e3cefe313063a 100644 --- a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecations/index_settings_deprecation_flyout.test.ts +++ b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecations/index_settings_deprecation_flyout.test.ts @@ -7,8 +7,8 @@ import { act } from 'react-dom/test-utils'; -import { ElasticsearchTestBed, setupElasticsearchPage, setupEnvironment } from '../helpers'; - +import { setupEnvironment } from '../helpers'; +import { ElasticsearchTestBed, setupElasticsearchPage } from './es_deprecations.helpers'; import { esDeprecationsMockResponse, MOCK_SNAPSHOT_ID, MOCK_JOB_ID } from './mocked_responses'; describe('Index settings deprecation flyout', () => { @@ -37,7 +37,7 @@ describe('Index settings deprecation flyout', () => { component.update(); - await actions.clickIndexSettingsDeprecationAt(0); + await actions.table.clickDeprecationRowAt('indexSetting', 0); expect(exists('indexSettingsDetails')).toBe(true); expect(find('indexSettingsDetails.flyoutTitle').text()).toContain( @@ -53,7 +53,7 @@ describe('Index settings deprecation flyout', () => { acknowledged: true, }); - await actions.clickDeleteSettingsButton(); + await actions.indexSettingsDeprecationFlyout.clickDeleteSettingsButton(); const request = server.requests[server.requests.length - 1]; @@ -69,7 +69,7 @@ describe('Index settings deprecation flyout', () => { ); // Reopen the flyout - await actions.clickIndexSettingsDeprecationAt(0); + await actions.table.clickDeprecationRowAt('indexSetting', 0); // Verify prompt to remove setting no longer displays expect(find('removeSettingsPrompt').length).toEqual(0); @@ -87,7 +87,7 @@ describe('Index settings deprecation flyout', () => { httpRequestsMockHelpers.setUpdateIndexSettingsResponse(undefined, error); - await actions.clickDeleteSettingsButton(); + await actions.indexSettingsDeprecationFlyout.clickDeleteSettingsButton(); const request = server.requests[server.requests.length - 1]; @@ -103,7 +103,7 @@ describe('Index settings deprecation flyout', () => { ); // Reopen the flyout - await actions.clickIndexSettingsDeprecationAt(0); + await actions.table.clickDeprecationRowAt('indexSetting', 0); // Verify the flyout shows an error message expect(find('indexSettingsDetails.deleteSettingsError').text()).toContain( diff --git a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecations/ml_snapshots_deprecation_flyout.test.ts b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecations/ml_snapshots_deprecation_flyout.test.ts index 909976355cd31..6a97dd24286db 100644 --- a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecations/ml_snapshots_deprecation_flyout.test.ts +++ b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecations/ml_snapshots_deprecation_flyout.test.ts @@ -8,7 +8,8 @@ import { act } from 'react-dom/test-utils'; import type { MlAction } from '../../../common/types'; -import { ElasticsearchTestBed, setupElasticsearchPage, setupEnvironment } from '../helpers'; +import { setupEnvironment } from '../helpers'; +import { ElasticsearchTestBed, setupElasticsearchPage } from './es_deprecations.helpers'; import { esDeprecationsMockResponse, MOCK_SNAPSHOT_ID, MOCK_JOB_ID } from './mocked_responses'; describe('Machine learning deprecation flyout', () => { @@ -37,7 +38,7 @@ describe('Machine learning deprecation flyout', () => { component.update(); - await actions.clickMlDeprecationAt(0); + await actions.table.clickDeprecationRowAt('mlSnapshot', 0); expect(exists('mlSnapshotDetails')).toBe(true); expect(find('mlSnapshotDetails.flyoutTitle').text()).toContain( @@ -65,7 +66,7 @@ describe('Machine learning deprecation flyout', () => { expect(find('mlSnapshotDetails.upgradeSnapshotButton').text()).toEqual('Upgrade'); - await actions.clickUpgradeMlSnapshot(); + await actions.mlDeprecationFlyout.clickUpgradeSnapshot(); // First, we expect a POST request to upgrade the snapshot const upgradeRequest = server.requests[server.requests.length - 2]; @@ -83,7 +84,7 @@ describe('Machine learning deprecation flyout', () => { expect(find('mlActionResolutionCell').text()).toContain('Upgrade complete'); // Reopen the flyout - await actions.clickMlDeprecationAt(0); + await actions.table.clickDeprecationRowAt('mlSnapshot', 0); // Flyout actions should not be visible if deprecation was resolved expect(exists('mlSnapshotDetails.upgradeSnapshotButton')).toBe(false); @@ -108,7 +109,7 @@ describe('Machine learning deprecation flyout', () => { error, }); - await actions.clickUpgradeMlSnapshot(); + await actions.mlDeprecationFlyout.clickUpgradeSnapshot(); const upgradeRequest = server.requests[server.requests.length - 1]; expect(upgradeRequest.method).toBe('POST'); @@ -118,7 +119,7 @@ describe('Machine learning deprecation flyout', () => { expect(find('mlActionResolutionCell').text()).toContain('Upgrade failed'); // Reopen the flyout - await actions.clickMlDeprecationAt(0); + await actions.table.clickDeprecationRowAt('mlSnapshot', 0); // Verify the flyout shows an error message expect(find('mlSnapshotDetails.resolveSnapshotError').text()).toContain( @@ -139,7 +140,7 @@ describe('Machine learning deprecation flyout', () => { expect(find('mlSnapshotDetails.deleteSnapshotButton').text()).toEqual('Delete'); - await actions.clickDeleteMlSnapshot(); + await actions.mlDeprecationFlyout.clickDeleteSnapshot(); const request = server.requests[server.requests.length - 1]; @@ -154,7 +155,7 @@ describe('Machine learning deprecation flyout', () => { expect(find('mlActionResolutionCell').at(0).text()).toEqual('Deletion complete'); // Reopen the flyout - await actions.clickMlDeprecationAt(0); + await actions.table.clickDeprecationRowAt('mlSnapshot', 0); }); it('handles delete failure', async () => { @@ -168,7 +169,7 @@ describe('Machine learning deprecation flyout', () => { httpRequestsMockHelpers.setDeleteMlSnapshotResponse(undefined, error); - await actions.clickDeleteMlSnapshot(); + await actions.mlDeprecationFlyout.clickDeleteSnapshot(); const request = server.requests[server.requests.length - 1]; @@ -183,7 +184,7 @@ describe('Machine learning deprecation flyout', () => { expect(find('mlActionResolutionCell').at(0).text()).toEqual('Deletion failed'); // Reopen the flyout - await actions.clickMlDeprecationAt(0); + await actions.table.clickDeprecationRowAt('mlSnapshot', 0); // Verify the flyout shows an error message expect(find('mlSnapshotDetails.resolveSnapshotError').text()).toContain( diff --git a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecations/reindex_deprecation_flyout.test.ts b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecations/reindex_deprecation_flyout.test.ts index c93cdcb1f4d97..d7ca0101d2b74 100644 --- a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecations/reindex_deprecation_flyout.test.ts +++ b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecations/reindex_deprecation_flyout.test.ts @@ -7,8 +7,8 @@ import { act } from 'react-dom/test-utils'; -import { ElasticsearchTestBed, setupElasticsearchPage, setupEnvironment } from '../helpers'; - +import { setupEnvironment } from '../helpers'; +import { ElasticsearchTestBed, setupElasticsearchPage } from './es_deprecations.helpers'; import { esDeprecationsMockResponse, MOCK_SNAPSHOT_ID, MOCK_JOB_ID } from './mocked_responses'; // Note: The reindexing flyout UX is subject to change; more tests should be added here once functionality is built out @@ -40,7 +40,7 @@ describe('Reindex deprecation flyout', () => { const reindexDeprecation = esDeprecationsMockResponse.deprecations[3]; const { actions, find, exists } = testBed; - await actions.clickReindexDeprecationAt(0); + await actions.table.clickDeprecationRowAt('reindex', 0); expect(exists('reindexDetails')).toBe(true); expect(find('reindexDetails.flyoutTitle').text()).toContain( diff --git a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/app_context.mock.ts b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/app_context.mock.ts new file mode 100644 index 0000000000000..ce9a1fbf79197 --- /dev/null +++ b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/app_context.mock.ts @@ -0,0 +1,34 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { + deprecationsServiceMock, + docLinksServiceMock, + notificationServiceMock, + applicationServiceMock, +} from 'src/core/public/mocks'; +import { HttpSetup } from 'src/core/public'; + +import { mockKibanaSemverVersion } from '../../../common/constants'; +import { apiService } from '../../../public/application/lib/api'; +import { breadcrumbService } from '../../../public/application/lib/breadcrumbs'; + +export const getAppContextMock = (mockHttpClient: HttpSetup) => ({ + http: mockHttpClient, + docLinks: docLinksServiceMock.createStartContract(), + kibanaVersionInfo: { + currentMajor: mockKibanaSemverVersion.major, + prevMajor: mockKibanaSemverVersion.major - 1, + nextMajor: mockKibanaSemverVersion.major + 1, + }, + notifications: notificationServiceMock.createStartContract(), + isReadOnlyMode: false, + api: apiService, + breadcrumbs: breadcrumbService, + getUrlForApp: applicationServiceMock.createStartContract().getUrlForApp, + deprecations: deprecationsServiceMock.createStartContract(), +}); diff --git a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/elasticsearch.helpers.ts b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/elasticsearch.helpers.ts deleted file mode 100644 index 86737d4925927..0000000000000 --- a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/elasticsearch.helpers.ts +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ -import { act } from 'react-dom/test-utils'; - -import { registerTestBed, TestBed, TestBedConfig } from '@kbn/test/jest'; -import { EsDeprecations } from '../../../public/application/components/es_deprecations'; -import { WithAppDependencies } from './setup_environment'; - -const testBedConfig: TestBedConfig = { - memoryRouter: { - initialEntries: ['/es_deprecations'], - componentRoutePath: '/es_deprecations', - }, - doMountAsync: true, -}; - -export type ElasticsearchTestBed = TestBed & { - actions: ReturnType; -}; - -const createActions = (testBed: TestBed) => { - const { component, find } = testBed; - - /** - * User Actions - */ - const clickRefreshButton = async () => { - await act(async () => { - find('refreshButton').simulate('click'); - }); - - component.update(); - }; - - const clickMlDeprecationAt = async (index: number) => { - await act(async () => { - find('deprecation-mlSnapshot').at(index).simulate('click'); - }); - - component.update(); - }; - - const clickUpgradeMlSnapshot = async () => { - await act(async () => { - find('mlSnapshotDetails.upgradeSnapshotButton').simulate('click'); - }); - - component.update(); - }; - - const clickDeleteMlSnapshot = async () => { - await act(async () => { - find('mlSnapshotDetails.deleteSnapshotButton').simulate('click'); - }); - - component.update(); - }; - - const clickIndexSettingsDeprecationAt = async (index: number) => { - await act(async () => { - find('deprecation-indexSetting').at(index).simulate('click'); - }); - - component.update(); - }; - - const clickDeleteSettingsButton = async () => { - await act(async () => { - find('deleteSettingsButton').simulate('click'); - }); - - component.update(); - }; - - const clickReindexDeprecationAt = async (index: number) => { - await act(async () => { - find('deprecation-reindex').at(index).simulate('click'); - }); - - component.update(); - }; - - const clickDefaultDeprecationAt = async (index: number) => { - await act(async () => { - find('deprecation-default').at(index).simulate('click'); - }); - - component.update(); - }; - - const clickCriticalFilterButton = async () => { - await act(async () => { - // EUI doesn't support data-test-subj's on the filter buttons, so we must access via CSS selector - find('searchBarContainer').find('.euiFilterButton').at(0).simulate('click'); - }); - - component.update(); - }; - - const clickTypeFilterDropdownAt = async (index: number) => { - await act(async () => { - // EUI doesn't support data-test-subj's on the filter buttons, so we must access via CSS selector - find('searchBarContainer') - .find('.euiPopover') - .find('.euiFilterButton') - .at(index) - .simulate('click'); - }); - - component.update(); - }; - - const setSearchInputValue = async (searchValue: string) => { - await act(async () => { - find('searchBarContainer') - .find('input') - .simulate('keyup', { target: { value: searchValue } }); - }); - - component.update(); - }; - - const clickPaginationAt = async (index: number) => { - await act(async () => { - find(`pagination-button-${index}`).simulate('click'); - }); - - component.update(); - }; - - const clickRowsPerPageDropdown = async () => { - await act(async () => { - find('tablePaginationPopoverButton').simulate('click'); - }); - - component.update(); - }; - - return { - clickRefreshButton, - clickMlDeprecationAt, - clickUpgradeMlSnapshot, - clickDeleteMlSnapshot, - clickIndexSettingsDeprecationAt, - clickDeleteSettingsButton, - clickReindexDeprecationAt, - clickDefaultDeprecationAt, - clickCriticalFilterButton, - clickTypeFilterDropdownAt, - setSearchInputValue, - clickPaginationAt, - clickRowsPerPageDropdown, - }; -}; - -export const setup = async (overrides?: Record): Promise => { - const initTestBed = registerTestBed( - WithAppDependencies(EsDeprecations, overrides), - testBedConfig - ); - const testBed = await initTestBed(); - - return { - ...testBed, - actions: createActions(testBed), - }; -}; diff --git a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/index.ts b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/index.ts index b19c8b3d0f082..1f7264336190c 100644 --- a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/index.ts +++ b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/index.ts @@ -5,8 +5,4 @@ * 2.0. */ -export { setup as setupOverviewPage, OverviewTestBed } from './overview.helpers'; -export { setup as setupElasticsearchPage, ElasticsearchTestBed } from './elasticsearch.helpers'; -export { setup as setupKibanaPage, KibanaTestBed } from './kibana.helpers'; - -export { setupEnvironment } from './setup_environment'; +export { setupEnvironment, WithAppDependencies } from './setup_environment'; diff --git a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/services_mock.ts b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/kibana_context.mock.ts similarity index 96% rename from x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/services_mock.ts rename to x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/kibana_context.mock.ts index 893b97c5a0ca6..785c8dc49a76c 100644 --- a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/services_mock.ts +++ b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/kibana_context.mock.ts @@ -11,7 +11,7 @@ import { applicationServiceMock } from '../../../../../../src/core/public/applic const discoverMock = discoverPluginMock.createStartContract(); -export const servicesMock = { +export const kibanaContextMock = { data: dataPluginMock.createStartContract(), application: applicationServiceMock.createStartContract(), discover: { diff --git a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/setup_environment.tsx b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/setup_environment.tsx index c5de02bebd512..cbc21697651fb 100644 --- a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/setup_environment.tsx +++ b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/setup_environment.tsx @@ -10,21 +10,15 @@ import axios from 'axios'; // @ts-ignore import axiosXhrAdapter from 'axios/lib/adapters/xhr'; -import { - deprecationsServiceMock, - docLinksServiceMock, - notificationServiceMock, - applicationServiceMock, -} from 'src/core/public/mocks'; import { HttpSetup } from 'src/core/public'; import { KibanaContextProvider } from '../../../public/shared_imports'; -import { mockKibanaSemverVersion } from '../../../common/constants'; import { AppContextProvider } from '../../../public/application/app_context'; import { apiService } from '../../../public/application/lib/api'; import { breadcrumbService } from '../../../public/application/lib/breadcrumbs'; import { GlobalFlyout } from '../../../public/shared_imports'; -import { servicesMock } from './services_mock'; +import { kibanaContextMock } from './kibana_context.mock'; +import { getAppContextMock } from './app_context.mock'; import { init as initHttpRequests } from './http_requests'; const { GlobalFlyoutProvider } = GlobalFlyout; @@ -37,27 +31,13 @@ export const WithAppDependencies = (Comp: any, overrides: Record ''); - const contextValue = { - http: (mockHttpClient as unknown) as HttpSetup, - docLinks: docLinksServiceMock.createStartContract(), - kibanaVersionInfo: { - currentMajor: mockKibanaSemverVersion.major, - prevMajor: mockKibanaSemverVersion.major - 1, - nextMajor: mockKibanaSemverVersion.major + 1, - }, - notifications: notificationServiceMock.createStartContract(), - isReadOnlyMode: false, - api: apiService, - breadcrumbs: breadcrumbService, - getUrlForApp: applicationServiceMock.createStartContract().getUrlForApp, - deprecations: deprecationsServiceMock.createStartContract(), - }; + const appContextMock = getAppContextMock((mockHttpClient as unknown) as HttpSetup); - const { servicesOverrides, ...contextOverrides } = overrides; + const { kibanaContextOverrides, ...appContextOverrides } = overrides; return ( - - + + diff --git a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/kibana.helpers.ts b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/kibana_deprecations/kibana_deprecations.helpers.ts similarity index 73% rename from x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/kibana.helpers.ts rename to x-pack/plugins/upgrade_assistant/__jest__/client_integration/kibana_deprecations/kibana_deprecations.helpers.ts index 370679d7d1a71..860c9249b266a 100644 --- a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/kibana.helpers.ts +++ b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/kibana_deprecations/kibana_deprecations.helpers.ts @@ -7,7 +7,7 @@ import { registerTestBed, TestBed, TestBedConfig } from '@kbn/test/jest'; import { KibanaDeprecationsContent } from '../../../public/application/components/kibana_deprecations'; -import { WithAppDependencies } from './setup_environment'; +import { WithAppDependencies } from '../helpers'; const testBedConfig: TestBedConfig = { memoryRouter: { @@ -17,7 +17,7 @@ const testBedConfig: TestBedConfig = { doMountAsync: true, }; -export type KibanaTestBed = TestBed & { +export type KibanaTestBed = TestBed & { actions: ReturnType; }; @@ -36,7 +36,9 @@ const createActions = (testBed: TestBed) => { }; }; -export const setup = async (overrides?: Record): Promise => { +export const setupKibanaPage = async ( + overrides?: Record +): Promise => { const initTestBed = registerTestBed( WithAppDependencies(KibanaDeprecationsContent, overrides), testBedConfig @@ -48,12 +50,3 @@ export const setup = async (overrides?: Record): Promise { let testBed: KibanaTestBed; diff --git a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/overview/fix_deprecation_logs_step/fix_deprecation_logs_step.test.tsx b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/overview/fix_deprecation_logs_step/fix_deprecation_logs_step.test.tsx index 3db75ba0a342d..67d18a5a2e8f7 100644 --- a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/overview/fix_deprecation_logs_step/fix_deprecation_logs_step.test.tsx +++ b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/overview/fix_deprecation_logs_step/fix_deprecation_logs_step.test.tsx @@ -7,9 +7,10 @@ import { act } from 'react-dom/test-utils'; -import { OverviewTestBed, setupOverviewPage, setupEnvironment } from '../../helpers'; import { DeprecationLoggingStatus } from '../../../../common/types'; import { DEPRECATION_LOGS_SOURCE_ID } from '../../../../common/constants'; +import { setupEnvironment } from '../../helpers'; +import { OverviewTestBed, setupOverviewPage } from '../overview.helpers'; const getLoggingResponse = (toggle: boolean): DeprecationLoggingStatus => ({ isDeprecationLogIndexingEnabled: toggle, diff --git a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/overview.helpers.ts b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/overview/overview.helpers.ts similarity index 54% rename from x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/overview.helpers.ts rename to x-pack/plugins/upgrade_assistant/__jest__/client_integration/overview/overview.helpers.ts index 96e12d4806ee3..3ab7f18bbefb8 100644 --- a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/overview.helpers.ts +++ b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/overview/overview.helpers.ts @@ -8,7 +8,7 @@ import { act } from 'react-dom/test-utils'; import { registerTestBed, TestBed, TestBedConfig } from '@kbn/test/jest'; import { Overview } from '../../../public/application/components/overview'; -import { WithAppDependencies } from './setup_environment'; +import { WithAppDependencies } from '../helpers'; const testBedConfig: TestBedConfig = { memoryRouter: { @@ -18,7 +18,7 @@ const testBedConfig: TestBedConfig = { doMountAsync: true, }; -export type OverviewTestBed = TestBed & { +export type OverviewTestBed = TestBed & { actions: ReturnType; }; @@ -42,7 +42,9 @@ const createActions = (testBed: TestBed) => { }; }; -export const setup = async (overrides?: Record): Promise => { +export const setupOverviewPage = async ( + overrides?: Record +): Promise => { const initTestBed = registerTestBed(WithAppDependencies(Overview, overrides), testBedConfig); const testBed = await initTestBed(); @@ -51,31 +53,3 @@ export const setup = async (overrides?: Record): Promise { let testBed: OverviewTestBed; diff --git a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/overview/review_logs_step/review_logs_step.test.tsx b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/overview/review_logs_step/review_logs_step.test.tsx index 2afffe989ed1b..b8646540171e5 100644 --- a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/overview/review_logs_step/review_logs_step.test.tsx +++ b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/overview/review_logs_step/review_logs_step.test.tsx @@ -9,7 +9,8 @@ import { act } from 'react-dom/test-utils'; import { deprecationsServiceMock } from 'src/core/public/mocks'; import * as mockedResponses from './mocked_responses'; -import { OverviewTestBed, setupOverviewPage, setupEnvironment } from '../../helpers'; +import { setupEnvironment } from '../../helpers'; +import { OverviewTestBed, setupOverviewPage } from '../overview.helpers'; describe('Overview - Fix deprecated settings step', () => { let testBed: OverviewTestBed; @@ -46,27 +47,7 @@ describe('Overview - Fix deprecated settings step', () => { expect(find('esStatsPanel.criticalDeprecations').text()).toContain('1'); }); - test('Handles network failure', async () => { - const error = { - statusCode: 500, - error: 'Cant retrieve deprecations error', - message: 'Cant retrieve deprecations error', - }; - - httpRequestsMockHelpers.setLoadEsDeprecationsResponse(undefined, error); - - await act(async () => { - testBed = await setupOverviewPage(); - }); - - const { component, exists } = testBed; - - component.update(); - - expect(exists('esRequestErrorIconTip')).toBe(true); - }); - - test('Hides deprecation counts if it doesnt have any', async () => { + test(`Hides deprecation counts if it doesn't have any`, async () => { httpRequestsMockHelpers.setLoadEsDeprecationsResponse(mockedResponses.esDeprecationsEmpty); await act(async () => { @@ -78,7 +59,7 @@ describe('Overview - Fix deprecated settings step', () => { expect(exists('noDeprecationsLabel')).toBe(true); }); - test('Stats panel navigates to deprecations list if clicked', () => { + test('Stats panel contains link to ES deprecations page', () => { const { component, exists, find } = testBed; component.update(); @@ -87,7 +68,7 @@ describe('Overview - Fix deprecated settings step', () => { expect(find('esStatsPanel').find('a').props().href).toBe('/es_deprecations'); }); - describe('Renders ES errors', () => { + describe('Renders errors', () => { test('handles network failure', async () => { const error = { statusCode: 500, @@ -177,7 +158,7 @@ describe('Overview - Fix deprecated settings step', () => { }); describe('Kibana deprecations', () => { - test('Show deprecation warning and critical counts', () => { + test('Shows deprecation warning and critical counts', () => { const { exists, find } = testBed; expect(exists('kibanaStatsPanel')).toBe(true); @@ -185,26 +166,7 @@ describe('Overview - Fix deprecated settings step', () => { expect(find('kibanaStatsPanel.criticalDeprecations').text()).toContain('1'); }); - test('Handles network failure', async () => { - await act(async () => { - const deprecationService = deprecationsServiceMock.createStartContract(); - deprecationService.getAllDeprecations = jest - .fn() - .mockRejectedValue(new Error('Internal Server Error')); - - testBed = await setupOverviewPage({ - deprecations: deprecationService, - }); - }); - - const { component, exists } = testBed; - - component.update(); - - expect(exists('kibanaRequestErrorIconTip')).toBe(true); - }); - - test('Hides deprecation count if it doesnt have any', async () => { + test(`Hides deprecation count if it doesn't have any`, async () => { await act(async () => { const deprecationService = deprecationsServiceMock.createStartContract(); deprecationService.getAllDeprecations = jest.fn().mockRejectedValue([]); @@ -221,7 +183,7 @@ describe('Overview - Fix deprecated settings step', () => { expect(exists('kibanaStatsPanel.criticalDeprecations')).toBe(false); }); - test('Stats panel navigates to deprecations list if clicked', () => { + test('Stats panel contains link to Kibana deprecations page', () => { const { component, exists, find } = testBed; component.update(); @@ -229,5 +191,26 @@ describe('Overview - Fix deprecated settings step', () => { expect(exists('kibanaStatsPanel')).toBe(true); expect(find('kibanaStatsPanel').find('a').props().href).toBe('/kibana_deprecations'); }); + + describe('Renders errors', () => { + test('Handles network failure', async () => { + await act(async () => { + const deprecationService = deprecationsServiceMock.createStartContract(); + deprecationService.getAllDeprecations = jest + .fn() + .mockRejectedValue(new Error('Internal Server Error')); + + testBed = await setupOverviewPage({ + deprecations: deprecationService, + }); + }); + + const { component, exists } = testBed; + + component.update(); + + expect(exists('kibanaRequestErrorIconTip')).toBe(true); + }); + }); }); }); diff --git a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/overview/upgrade_step/upgrade_step.test.tsx b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/overview/upgrade_step/upgrade_step.test.tsx index bfcd88b91b94a..617aea19a129d 100644 --- a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/overview/upgrade_step/upgrade_step.test.tsx +++ b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/overview/upgrade_step/upgrade_step.test.tsx @@ -7,7 +7,8 @@ import { act } from 'react-dom/test-utils'; -import { OverviewTestBed, setupOverviewPage, setupEnvironment } from '../../helpers'; +import { setupEnvironment } from '../../helpers'; +import { OverviewTestBed, setupOverviewPage } from '../overview.helpers'; describe('Overview - Upgrade Step', () => { let testBed: OverviewTestBed; @@ -33,7 +34,7 @@ describe('Overview - Upgrade Step', () => { test('Shows upgrade cta and link to docs for cloud installations', async () => { await act(async () => { testBed = await setupOverviewPage({ - servicesOverrides: { + kibanaContextOverrides: { cloud: { isCloudEnabled: true, deploymentUrl: From 7114cf69bb4f02c6bc1c094e68e6afb0218aa9a6 Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Fri, 20 Aug 2021 19:25:22 -0400 Subject: [PATCH 50/76] chore(NA): moving @kbn/securitysolution-utils to babel transpiler (#109439) (#109550) * chore(NA): moving @kbn/securitysolution-utils to babel transpiler * chore(NA): update packages/kbn-securitysolution-utils/.babelrc Co-authored-by: Frank Hassanabad Co-authored-by: Frank Hassanabad Co-authored-by: Tiago Costa Co-authored-by: Frank Hassanabad --- packages/kbn-securitysolution-utils/.babelrc | 4 ++++ .../kbn-securitysolution-utils/BUILD.bazel | 23 ++++++++++++------- .../kbn-securitysolution-utils/package.json | 4 ++-- .../kbn-securitysolution-utils/tsconfig.json | 3 ++- 4 files changed, 23 insertions(+), 11 deletions(-) create mode 100644 packages/kbn-securitysolution-utils/.babelrc diff --git a/packages/kbn-securitysolution-utils/.babelrc b/packages/kbn-securitysolution-utils/.babelrc new file mode 100644 index 0000000000000..40a198521b903 --- /dev/null +++ b/packages/kbn-securitysolution-utils/.babelrc @@ -0,0 +1,4 @@ +{ + "presets": ["@kbn/babel-preset/node_preset"], + "ignore": ["**/*.test.ts", "**/*.test.tsx"] +} diff --git a/packages/kbn-securitysolution-utils/BUILD.bazel b/packages/kbn-securitysolution-utils/BUILD.bazel index 41fb97bc6079e..c3d6b92044ef6 100644 --- a/packages/kbn-securitysolution-utils/BUILD.bazel +++ b/packages/kbn-securitysolution-utils/BUILD.bazel @@ -1,5 +1,6 @@ load("@npm//@bazel/typescript:index.bzl", "ts_config", "ts_project") load("@build_bazel_rules_nodejs//:index.bzl", "js_library", "pkg_npm") +load("//src/dev/bazel:index.bzl", "jsts_transpiler") PKG_BASE_NAME = "kbn-securitysolution-utils" @@ -27,18 +28,23 @@ NPM_MODULE_EXTRA_FILES = [ "README.md", ] -SRC_DEPS = [ +RUNTIME_DEPS = [ "@npm//tslib", "@npm//uuid", ] TYPES_DEPS = [ + "@npm//tslib", "@npm//@types/jest", "@npm//@types/node", "@npm//@types/uuid" ] -DEPS = SRC_DEPS + TYPES_DEPS +jsts_transpiler( + name = "target_node", + srcs = SRCS, + build_pkg_name = package_name(), +) ts_config( name = "tsconfig", @@ -50,24 +56,25 @@ ts_config( ) ts_project( - name = "tsc", - srcs = SRCS, + name = "tsc_types", args = ["--pretty"], + srcs = SRCS, + deps = TYPES_DEPS, declaration = True, declaration_map = True, - out_dir = "target", + emit_declaration_only = True, + out_dir = "target_types", root_dir = "src", source_map = True, tsconfig = ":tsconfig", - deps = DEPS, ) js_library( name = PKG_BASE_NAME, - package_name = PKG_REQUIRE_NAME, srcs = NPM_MODULE_EXTRA_FILES, + deps = RUNTIME_DEPS + [":target_node", ":tsc_types"], + package_name = PKG_REQUIRE_NAME, visibility = ["//visibility:public"], - deps = DEPS + [":tsc"], ) pkg_npm( diff --git a/packages/kbn-securitysolution-utils/package.json b/packages/kbn-securitysolution-utils/package.json index d4b46ed07bfdd..98f19e33d379b 100644 --- a/packages/kbn-securitysolution-utils/package.json +++ b/packages/kbn-securitysolution-utils/package.json @@ -3,7 +3,7 @@ "version": "1.0.0", "description": "security solution utilities to use across plugins such lists, security_solution, cases, etc...", "license": "SSPL-1.0 OR Elastic License 2.0", - "main": "./target/index.js", - "types": "./target/index.d.ts", + "main": "./target_node/index.js", + "types": "./target_types/index.d.ts", "private": true } diff --git a/packages/kbn-securitysolution-utils/tsconfig.json b/packages/kbn-securitysolution-utils/tsconfig.json index 3894b53d6cff3..23fdf3178e174 100644 --- a/packages/kbn-securitysolution-utils/tsconfig.json +++ b/packages/kbn-securitysolution-utils/tsconfig.json @@ -3,7 +3,8 @@ "compilerOptions": { "declaration": true, "declarationMap": true, - "outDir": "target", + "emitDeclarationOnly": true, + "outDir": "target_types", "rootDir": "src", "sourceMap": true, "sourceRoot": "../../../../packages/kbn-securitysolution-utils/src", From 9374b7b7421b0107a1f8b5baef1505b84952806d Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Fri, 20 Aug 2021 21:15:09 -0400 Subject: [PATCH 51/76] chore(NA): moving @kbn/alerts to babel transpiler (#109320) (#109563) * chore(NA): moving @kbn/alerts to babel transpiler * chore(NA): finetune package * chore(NA): miss dep Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Tiago Costa --- packages/kbn-alerts/.babelrc | 4 ++ packages/kbn-alerts/.babelrc.browser | 4 ++ packages/kbn-alerts/BUILD.bazel | 70 +++++++++-------------- packages/kbn-alerts/babel.config.js | 19 ------ packages/kbn-alerts/react/package.json | 5 -- packages/kbn-alerts/tsconfig.browser.json | 22 ------- packages/kbn-alerts/tsconfig.json | 11 ++-- 7 files changed, 40 insertions(+), 95 deletions(-) create mode 100644 packages/kbn-alerts/.babelrc create mode 100644 packages/kbn-alerts/.babelrc.browser delete mode 100644 packages/kbn-alerts/babel.config.js delete mode 100644 packages/kbn-alerts/react/package.json delete mode 100644 packages/kbn-alerts/tsconfig.browser.json diff --git a/packages/kbn-alerts/.babelrc b/packages/kbn-alerts/.babelrc new file mode 100644 index 0000000000000..40a198521b903 --- /dev/null +++ b/packages/kbn-alerts/.babelrc @@ -0,0 +1,4 @@ +{ + "presets": ["@kbn/babel-preset/node_preset"], + "ignore": ["**/*.test.ts", "**/*.test.tsx"] +} diff --git a/packages/kbn-alerts/.babelrc.browser b/packages/kbn-alerts/.babelrc.browser new file mode 100644 index 0000000000000..71bbfbcd6eb2f --- /dev/null +++ b/packages/kbn-alerts/.babelrc.browser @@ -0,0 +1,4 @@ +{ + "presets": ["@kbn/babel-preset/webpack_preset"], + "ignore": ["**/*.test.ts", "**/*.test.tsx"] +} diff --git a/packages/kbn-alerts/BUILD.bazel b/packages/kbn-alerts/BUILD.bazel index c585b4430bfcb..a571380202cd6 100644 --- a/packages/kbn-alerts/BUILD.bazel +++ b/packages/kbn-alerts/BUILD.bazel @@ -1,5 +1,6 @@ load("@npm//@bazel/typescript:index.bzl", "ts_config", "ts_project") load("@build_bazel_rules_nodejs//:index.bzl", "js_library", "pkg_npm") +load("//src/dev/bazel:index.bzl", "jsts_transpiler") PKG_BASE_NAME = "kbn-alerts" @@ -12,8 +13,7 @@ SOURCE_FILES = glob( ], exclude = [ "**/*.test.*", - "**/*.mock.*", - "**/*.mocks.*", + "**/__snapshots__" ], ) @@ -25,32 +25,40 @@ filegroup( ) NPM_MODULE_EXTRA_FILES = [ - "react/package.json", "package.json", "README.md", ] -SRC_DEPS = [ - "//packages/kbn-babel-preset", - "//packages/kbn-dev-utils", +RUNTIME_DEPS = [ "//packages/kbn-i18n", - "@npm//@babel/core", - "@npm//babel-loader", "@npm//@elastic/eui", + "@npm//enzyme", "@npm//react", "@npm//resize-observer-polyfill", - "@npm//rxjs", - "@npm//tslib", ] TYPES_DEPS = [ - "@npm//typescript", + "//packages/kbn-i18n", + "@npm//@elastic/eui", + "@npm//resize-observer-polyfill", + "@npm//@types/enzyme", "@npm//@types/jest", "@npm//@types/node", "@npm//@types/react", ] -DEPS = SRC_DEPS + TYPES_DEPS +jsts_transpiler( + name = "target_node", + srcs = SRCS, + build_pkg_name = package_name(), +) + +jsts_transpiler( + name = "target_web", + srcs = SRCS, + build_pkg_name = package_name(), + config_file = ".babelrc.browser" +) ts_config( name = "tsconfig", @@ -61,50 +69,26 @@ ts_config( ], ) -ts_config( - name = "tsconfig_browser", - src = "tsconfig.browser.json", - deps = [ - "//:tsconfig.base.json", - "//:tsconfig.browser.json", - "//:tsconfig.browser_bazel.json", - ], -) - ts_project( - name = "tsc", + name = "tsc_types", args = ["--pretty"], srcs = SRCS, - deps = DEPS, - allow_js = True, + deps = TYPES_DEPS, declaration = True, - declaration_dir = "target_types", declaration_map = True, - out_dir = "target_node", + emit_declaration_only = True, + out_dir = "target_types", root_dir = "src", source_map = True, tsconfig = ":tsconfig", ) -ts_project( - name = "tsc_browser", - args = ['--pretty'], - srcs = SRCS, - deps = DEPS, - allow_js = True, - declaration = False, - out_dir = "target_web", - source_map = True, - root_dir = "src", - tsconfig = ":tsconfig_browser", -) - js_library( name = PKG_BASE_NAME, - package_name = PKG_REQUIRE_NAME, srcs = NPM_MODULE_EXTRA_FILES, + deps = RUNTIME_DEPS + [":target_node", ":target_web", ":tsc_types"], + package_name = PKG_REQUIRE_NAME, visibility = ["//visibility:public"], - deps = [":tsc", ":tsc_browser"] + DEPS, ) pkg_npm( @@ -120,4 +104,4 @@ filegroup( ":npm_module", ], visibility = ["//visibility:public"], -) \ No newline at end of file +) diff --git a/packages/kbn-alerts/babel.config.js b/packages/kbn-alerts/babel.config.js deleted file mode 100644 index b4a118df51af5..0000000000000 --- a/packages/kbn-alerts/babel.config.js +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -module.exports = { - env: { - web: { - presets: ['@kbn/babel-preset/webpack_preset'], - }, - node: { - presets: ['@kbn/babel-preset/node_preset'], - }, - }, - ignore: ['**/*.test.ts', '**/*.test.tsx'], -}; diff --git a/packages/kbn-alerts/react/package.json b/packages/kbn-alerts/react/package.json deleted file mode 100644 index c5f222b5843ac..0000000000000 --- a/packages/kbn-alerts/react/package.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "browser": "../target_web/react", - "main": "../target_node/react", - "types": "../target_types/react/index.d.ts" -} diff --git a/packages/kbn-alerts/tsconfig.browser.json b/packages/kbn-alerts/tsconfig.browser.json deleted file mode 100644 index bb58f529eb0bb..0000000000000 --- a/packages/kbn-alerts/tsconfig.browser.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "extends": "../../tsconfig.browser_bazel.json", - "compilerOptions": { - "allowJs": true, - "outDir": "./target_web", - "declaration": false, - "isolatedModules": true, - "sourceMap": true, - "sourceRoot": "../../../../../packages/kbn-alerts/src", - "types": [ - "jest", - "node" - ], - }, - "include": [ - "src/**/*.ts", - "src/**/*.tsx", - ], - "exclude": [ - "**/__fixtures__/**/*" - ] -} \ No newline at end of file diff --git a/packages/kbn-alerts/tsconfig.json b/packages/kbn-alerts/tsconfig.json index 6a791ca2e5844..fa18a40744354 100644 --- a/packages/kbn-alerts/tsconfig.json +++ b/packages/kbn-alerts/tsconfig.json @@ -1,15 +1,14 @@ { "extends": "../../tsconfig.bazel.json", "compilerOptions": { - "allowJs": true, - "declarationDir": "./target_types", - "outDir": "target_node", "declaration": true, "declarationMap": true, + "emitDeclarationOnly": true, + "outDir": "target_types", + "rootDir": "src", "sourceMap": true, "sourceRoot": "../../../../packages/kbn-alerts/src", - "rootDir": "src", "types": ["jest", "node", "resize-observer-polyfill"] }, - "include": ["src/**/*"] -} \ No newline at end of file + "include": ["src/**/*"], +} From 03e3baad4d95bdb35269261b55006ecb5e978b8c Mon Sep 17 00:00:00 2001 From: CJ Cenizal Date: Fri, 20 Aug 2021 18:37:45 -0700 Subject: [PATCH 52/76] Rename UA steps to fix_issues_step and fix_logs_step. (#109526) * Rename tests accordingly. --- .../fix_issues_step.test.tsx} | 2 +- .../mocked_responses.ts | 0 .../fix_logs_step.test.tsx} | 0 .../public/application/components/overview/_index.scss | 4 ++-- .../{review_logs_step => fix_issues_step}/_index.scss | 0 .../_stats_panel.scss | 0 .../es_stats/es_stats.tsx | 0 .../es_stats/es_stats_error.tsx | 0 .../es_stats/index.ts | 0 .../fix_issues_step.tsx} | 6 +++--- .../{review_logs_step => fix_issues_step}/index.ts | 2 +- .../kibana_stats/index.ts | 0 .../kibana_stats/kibana_stats.tsx | 0 .../no_deprecations/_no_deprecations.scss | 0 .../no_deprecations/index.ts | 0 .../no_deprecations/no_deprecations.tsx | 0 .../_index.scss | 0 .../_deprecation_logging_toggle.scss | 0 .../deprecation_logging_toggle.tsx | 0 .../deprecation_logging_toggle/index.ts | 0 .../external_links.tsx | 0 .../fix_logs_step.tsx} | 6 +++--- .../{fix_deprecation_logs_step => fix_logs_step}/index.ts | 2 +- .../use_deprecation_logging.ts | 0 .../public/application/components/overview/overview.tsx | 8 ++++---- 25 files changed, 15 insertions(+), 15 deletions(-) rename x-pack/plugins/upgrade_assistant/__jest__/client_integration/overview/{review_logs_step/review_logs_step.test.tsx => fix_issues_step/fix_issues_step.test.tsx} (99%) rename x-pack/plugins/upgrade_assistant/__jest__/client_integration/overview/{review_logs_step => fix_issues_step}/mocked_responses.ts (100%) rename x-pack/plugins/upgrade_assistant/__jest__/client_integration/overview/{fix_deprecation_logs_step/fix_deprecation_logs_step.test.tsx => fix_logs_step/fix_logs_step.test.tsx} (100%) rename x-pack/plugins/upgrade_assistant/public/application/components/overview/{review_logs_step => fix_issues_step}/_index.scss (100%) rename x-pack/plugins/upgrade_assistant/public/application/components/overview/{review_logs_step => fix_issues_step}/_stats_panel.scss (100%) rename x-pack/plugins/upgrade_assistant/public/application/components/overview/{review_logs_step => fix_issues_step}/es_stats/es_stats.tsx (100%) rename x-pack/plugins/upgrade_assistant/public/application/components/overview/{review_logs_step => fix_issues_step}/es_stats/es_stats_error.tsx (100%) rename x-pack/plugins/upgrade_assistant/public/application/components/overview/{review_logs_step => fix_issues_step}/es_stats/index.ts (100%) rename x-pack/plugins/upgrade_assistant/public/application/components/overview/{review_logs_step/review_logs_step.tsx => fix_issues_step/fix_issues_step.tsx} (88%) rename x-pack/plugins/upgrade_assistant/public/application/components/overview/{review_logs_step => fix_issues_step}/index.ts (81%) rename x-pack/plugins/upgrade_assistant/public/application/components/overview/{review_logs_step => fix_issues_step}/kibana_stats/index.ts (100%) rename x-pack/plugins/upgrade_assistant/public/application/components/overview/{review_logs_step => fix_issues_step}/kibana_stats/kibana_stats.tsx (100%) rename x-pack/plugins/upgrade_assistant/public/application/components/overview/{review_logs_step => fix_issues_step}/no_deprecations/_no_deprecations.scss (100%) rename x-pack/plugins/upgrade_assistant/public/application/components/overview/{review_logs_step => fix_issues_step}/no_deprecations/index.ts (100%) rename x-pack/plugins/upgrade_assistant/public/application/components/overview/{review_logs_step => fix_issues_step}/no_deprecations/no_deprecations.tsx (100%) rename x-pack/plugins/upgrade_assistant/public/application/components/overview/{fix_deprecation_logs_step => fix_logs_step}/_index.scss (100%) rename x-pack/plugins/upgrade_assistant/public/application/components/overview/{fix_deprecation_logs_step => fix_logs_step}/deprecation_logging_toggle/_deprecation_logging_toggle.scss (100%) rename x-pack/plugins/upgrade_assistant/public/application/components/overview/{fix_deprecation_logs_step => fix_logs_step}/deprecation_logging_toggle/deprecation_logging_toggle.tsx (100%) rename x-pack/plugins/upgrade_assistant/public/application/components/overview/{fix_deprecation_logs_step => fix_logs_step}/deprecation_logging_toggle/index.ts (100%) rename x-pack/plugins/upgrade_assistant/public/application/components/overview/{fix_deprecation_logs_step => fix_logs_step}/external_links.tsx (100%) rename x-pack/plugins/upgrade_assistant/public/application/components/overview/{fix_deprecation_logs_step/fix_deprecation_logs_step.tsx => fix_logs_step/fix_logs_step.tsx} (94%) rename x-pack/plugins/upgrade_assistant/public/application/components/overview/{fix_deprecation_logs_step => fix_logs_step}/index.ts (77%) rename x-pack/plugins/upgrade_assistant/public/application/components/overview/{fix_deprecation_logs_step => fix_logs_step}/use_deprecation_logging.ts (100%) diff --git a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/overview/review_logs_step/review_logs_step.test.tsx b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/overview/fix_issues_step/fix_issues_step.test.tsx similarity index 99% rename from x-pack/plugins/upgrade_assistant/__jest__/client_integration/overview/review_logs_step/review_logs_step.test.tsx rename to x-pack/plugins/upgrade_assistant/__jest__/client_integration/overview/fix_issues_step/fix_issues_step.test.tsx index b8646540171e5..581e80e7c290a 100644 --- a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/overview/review_logs_step/review_logs_step.test.tsx +++ b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/overview/fix_issues_step/fix_issues_step.test.tsx @@ -12,7 +12,7 @@ import * as mockedResponses from './mocked_responses'; import { setupEnvironment } from '../../helpers'; import { OverviewTestBed, setupOverviewPage } from '../overview.helpers'; -describe('Overview - Fix deprecated settings step', () => { +describe('Overview - Fix deprecation issues step', () => { let testBed: OverviewTestBed; const { server, httpRequestsMockHelpers } = setupEnvironment(); diff --git a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/overview/review_logs_step/mocked_responses.ts b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/overview/fix_issues_step/mocked_responses.ts similarity index 100% rename from x-pack/plugins/upgrade_assistant/__jest__/client_integration/overview/review_logs_step/mocked_responses.ts rename to x-pack/plugins/upgrade_assistant/__jest__/client_integration/overview/fix_issues_step/mocked_responses.ts diff --git a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/overview/fix_deprecation_logs_step/fix_deprecation_logs_step.test.tsx b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/overview/fix_logs_step/fix_logs_step.test.tsx similarity index 100% rename from x-pack/plugins/upgrade_assistant/__jest__/client_integration/overview/fix_deprecation_logs_step/fix_deprecation_logs_step.test.tsx rename to x-pack/plugins/upgrade_assistant/__jest__/client_integration/overview/fix_logs_step/fix_logs_step.test.tsx diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/overview/_index.scss b/x-pack/plugins/upgrade_assistant/public/application/components/overview/_index.scss index cbcfbff3bab68..3febfe77b3cf7 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/overview/_index.scss +++ b/x-pack/plugins/upgrade_assistant/public/application/components/overview/_index.scss @@ -1,2 +1,2 @@ -@import 'review_logs_step/index'; -@import 'fix_deprecation_logs_step/index'; +@import 'fix_issues_step/index'; +@import 'fix_logs_step/index'; diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/overview/review_logs_step/_index.scss b/x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_issues_step/_index.scss similarity index 100% rename from x-pack/plugins/upgrade_assistant/public/application/components/overview/review_logs_step/_index.scss rename to x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_issues_step/_index.scss diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/overview/review_logs_step/_stats_panel.scss b/x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_issues_step/_stats_panel.scss similarity index 100% rename from x-pack/plugins/upgrade_assistant/public/application/components/overview/review_logs_step/_stats_panel.scss rename to x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_issues_step/_stats_panel.scss diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/overview/review_logs_step/es_stats/es_stats.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_issues_step/es_stats/es_stats.tsx similarity index 100% rename from x-pack/plugins/upgrade_assistant/public/application/components/overview/review_logs_step/es_stats/es_stats.tsx rename to x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_issues_step/es_stats/es_stats.tsx diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/overview/review_logs_step/es_stats/es_stats_error.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_issues_step/es_stats/es_stats_error.tsx similarity index 100% rename from x-pack/plugins/upgrade_assistant/public/application/components/overview/review_logs_step/es_stats/es_stats_error.tsx rename to x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_issues_step/es_stats/es_stats_error.tsx diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/overview/review_logs_step/es_stats/index.ts b/x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_issues_step/es_stats/index.ts similarity index 100% rename from x-pack/plugins/upgrade_assistant/public/application/components/overview/review_logs_step/es_stats/index.ts rename to x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_issues_step/es_stats/index.ts diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/overview/review_logs_step/review_logs_step.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_issues_step/fix_issues_step.tsx similarity index 88% rename from x-pack/plugins/upgrade_assistant/public/application/components/overview/review_logs_step/review_logs_step.tsx rename to x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_issues_step/fix_issues_step.tsx index 4ebde8b5f847a..12f26a1ea3430 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/overview/review_logs_step/review_logs_step.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_issues_step/fix_issues_step.tsx @@ -15,12 +15,12 @@ import { ESDeprecationStats } from './es_stats'; import { KibanaDeprecationStats } from './kibana_stats'; const i18nTexts = { - reviewStepTitle: i18n.translate('xpack.upgradeAssistant.overview.reviewStepTitle', { + reviewStepTitle: i18n.translate('xpack.upgradeAssistant.overview.fixIssuesStepTitle', { defaultMessage: 'Review deprecated settings and resolve issues', }), }; -export const getReviewLogsStep = ({ nextMajor }: { nextMajor: number }): EuiStepProps => { +export const getFixIssuesStep = ({ nextMajor }: { nextMajor: number }): EuiStepProps => { return { title: i18nTexts.reviewStepTitle, status: 'incomplete', @@ -29,7 +29,7 @@ export const getReviewLogsStep = ({ nextMajor }: { nextMajor: number }): EuiStep

diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/overview/review_logs_step/index.ts b/x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_issues_step/index.ts similarity index 81% rename from x-pack/plugins/upgrade_assistant/public/application/components/overview/review_logs_step/index.ts rename to x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_issues_step/index.ts index 231b8ba2d7774..dde6996edfc74 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/overview/review_logs_step/index.ts +++ b/x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_issues_step/index.ts @@ -5,4 +5,4 @@ * 2.0. */ -export { getReviewLogsStep } from './review_logs_step'; +export { getFixIssuesStep } from './fix_issues_step'; diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/overview/review_logs_step/kibana_stats/index.ts b/x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_issues_step/kibana_stats/index.ts similarity index 100% rename from x-pack/plugins/upgrade_assistant/public/application/components/overview/review_logs_step/kibana_stats/index.ts rename to x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_issues_step/kibana_stats/index.ts diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/overview/review_logs_step/kibana_stats/kibana_stats.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_issues_step/kibana_stats/kibana_stats.tsx similarity index 100% rename from x-pack/plugins/upgrade_assistant/public/application/components/overview/review_logs_step/kibana_stats/kibana_stats.tsx rename to x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_issues_step/kibana_stats/kibana_stats.tsx diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/overview/review_logs_step/no_deprecations/_no_deprecations.scss b/x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_issues_step/no_deprecations/_no_deprecations.scss similarity index 100% rename from x-pack/plugins/upgrade_assistant/public/application/components/overview/review_logs_step/no_deprecations/_no_deprecations.scss rename to x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_issues_step/no_deprecations/_no_deprecations.scss diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/overview/review_logs_step/no_deprecations/index.ts b/x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_issues_step/no_deprecations/index.ts similarity index 100% rename from x-pack/plugins/upgrade_assistant/public/application/components/overview/review_logs_step/no_deprecations/index.ts rename to x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_issues_step/no_deprecations/index.ts diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/overview/review_logs_step/no_deprecations/no_deprecations.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_issues_step/no_deprecations/no_deprecations.tsx similarity index 100% rename from x-pack/plugins/upgrade_assistant/public/application/components/overview/review_logs_step/no_deprecations/no_deprecations.tsx rename to x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_issues_step/no_deprecations/no_deprecations.tsx diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_deprecation_logs_step/_index.scss b/x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_logs_step/_index.scss similarity index 100% rename from x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_deprecation_logs_step/_index.scss rename to x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_logs_step/_index.scss diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_deprecation_logs_step/deprecation_logging_toggle/_deprecation_logging_toggle.scss b/x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_logs_step/deprecation_logging_toggle/_deprecation_logging_toggle.scss similarity index 100% rename from x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_deprecation_logs_step/deprecation_logging_toggle/_deprecation_logging_toggle.scss rename to x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_logs_step/deprecation_logging_toggle/_deprecation_logging_toggle.scss diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_deprecation_logs_step/deprecation_logging_toggle/deprecation_logging_toggle.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_logs_step/deprecation_logging_toggle/deprecation_logging_toggle.tsx similarity index 100% rename from x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_deprecation_logs_step/deprecation_logging_toggle/deprecation_logging_toggle.tsx rename to x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_logs_step/deprecation_logging_toggle/deprecation_logging_toggle.tsx diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_deprecation_logs_step/deprecation_logging_toggle/index.ts b/x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_logs_step/deprecation_logging_toggle/index.ts similarity index 100% rename from x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_deprecation_logs_step/deprecation_logging_toggle/index.ts rename to x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_logs_step/deprecation_logging_toggle/index.ts diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_deprecation_logs_step/external_links.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_logs_step/external_links.tsx similarity index 100% rename from x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_deprecation_logs_step/external_links.tsx rename to x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_logs_step/external_links.tsx diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_deprecation_logs_step/fix_deprecation_logs_step.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_logs_step/fix_logs_step.tsx similarity index 94% rename from x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_deprecation_logs_step/fix_deprecation_logs_step.tsx rename to x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_logs_step/fix_logs_step.tsx index a2f1feae4979d..9c22a07ed771b 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_deprecation_logs_step/fix_deprecation_logs_step.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_logs_step/fix_logs_step.tsx @@ -40,7 +40,7 @@ const i18nTexts = { ), }; -const DeprecationLogsPreview: FunctionComponent = () => { +const FixLogsStep: FunctionComponent = () => { const state = useDeprecationLogging(); return ( @@ -81,10 +81,10 @@ const DeprecationLogsPreview: FunctionComponent = () => { ); }; -export const getFixDeprecationLogsStep = (): EuiStepProps => { +export const getFixLogsStep = (): EuiStepProps => { return { title: i18nTexts.identifyStepTitle, status: 'incomplete', - children: , + children: , }; }; diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_deprecation_logs_step/index.ts b/x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_logs_step/index.ts similarity index 77% rename from x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_deprecation_logs_step/index.ts rename to x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_logs_step/index.ts index d4794623d8a99..8a9a9faa6d098 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_deprecation_logs_step/index.ts +++ b/x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_logs_step/index.ts @@ -5,4 +5,4 @@ * 2.0. */ -export { getFixDeprecationLogsStep } from './fix_deprecation_logs_step'; +export { getFixLogsStep } from './fix_logs_step'; diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_deprecation_logs_step/use_deprecation_logging.ts b/x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_logs_step/use_deprecation_logging.ts similarity index 100% rename from x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_deprecation_logs_step/use_deprecation_logging.ts rename to x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_logs_step/use_deprecation_logging.ts diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/overview/overview.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/overview/overview.tsx index f900416873b83..3f6bf25e9abf0 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/overview/overview.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/overview/overview.tsx @@ -21,8 +21,8 @@ import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import { useAppContext } from '../../app_context'; -import { getReviewLogsStep } from './review_logs_step'; -import { getFixDeprecationLogsStep } from './fix_deprecation_logs_step'; +import { getFixIssuesStep } from './fix_issues_step'; +import { getFixLogsStep } from './fix_logs_step'; import { getUpgradeStep } from './upgrade_step'; export const Overview: FunctionComponent = () => { @@ -83,8 +83,8 @@ export const Overview: FunctionComponent = () => { From fce1ddbb7d909c09fcf474a49dc739defd2e22c0 Mon Sep 17 00:00:00 2001 From: Tim Sullivan Date: Fri, 20 Aug 2021 21:08:52 -0700 Subject: [PATCH 53/76] [Reporting/Telemetry] Include counts for each deprecated job type (#108614) (#109366) * add isDeprecated to report meta for telemetry * test clean up * update snapshots * Update x-pack/plugins/reporting/server/usage/decorate_range_stats.ts Co-authored-by: Michael Dokolin Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Michael Dokolin Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Michael Dokolin --- x-pack/plugins/reporting/common/constants.ts | 2 + x-pack/plugins/reporting/common/types.ts | 7 +- .../reporting/server/lib/enqueue_job.test.ts | 1 + .../reporting/server/lib/enqueue_job.ts | 2 + .../reporting/server/lib/store/mapping.ts | 3 + .../reporting_usage_collector.test.ts.snap | 771 ++++++++++++++++ .../server/usage/decorate_range_stats.test.ts | 142 +++ .../server/usage/decorate_range_stats.ts | 9 +- .../server/usage/get_reporting_usage.ts | 33 +- .../usage/reporting_usage_collector.test.ts | 866 +++--------------- .../plugins/reporting/server/usage/schema.ts | 14 +- .../plugins/reporting/server/usage/types.ts | 58 +- .../schema/xpack_plugins.json | 142 +-- .../job_apis_csv_deprecated.ts | 16 +- 14 files changed, 1153 insertions(+), 913 deletions(-) create mode 100644 x-pack/plugins/reporting/server/usage/decorate_range_stats.test.ts diff --git a/x-pack/plugins/reporting/common/constants.ts b/x-pack/plugins/reporting/common/constants.ts index 4ba406a14bafc..842d7d1eb4b8d 100644 --- a/x-pack/plugins/reporting/common/constants.ts +++ b/x-pack/plugins/reporting/common/constants.ts @@ -79,6 +79,8 @@ export const CSV_JOB_TYPE_DEPRECATED = 'csv'; export const USES_HEADLESS_JOB_TYPES = [PDF_JOB_TYPE, PNG_JOB_TYPE]; +export const DEPRECATED_JOB_TYPES = [CSV_JOB_TYPE_DEPRECATED]; + // Licenses export const LICENSE_TYPE_TRIAL = 'trial'; export const LICENSE_TYPE_BASIC = 'basic'; diff --git a/x-pack/plugins/reporting/common/types.ts b/x-pack/plugins/reporting/common/types.ts index 745bc11a8c855..c324cf363faa1 100644 --- a/x-pack/plugins/reporting/common/types.ts +++ b/x-pack/plugins/reporting/common/types.ts @@ -73,7 +73,12 @@ export interface ReportSource { jobtype: string; // refers to `ExportTypeDefinition.jobType` created_by: string | false; // username or `false` if security is disabled. Used for ensuring users can only access the reports they've created. payload: BasePayload; - meta: { objectType: string; layout?: string }; // for telemetry + meta: { + // for telemetry + objectType: string; + layout?: string; + isDeprecated?: boolean; + }; migration_version: string; // for reminding the user to update their POST URL attempts: number; // initially populated as 0 created_at: string; // timestamp in UTC diff --git a/x-pack/plugins/reporting/server/lib/enqueue_job.test.ts b/x-pack/plugins/reporting/server/lib/enqueue_job.test.ts index 8cfea1b010dfe..50103c8806fe0 100644 --- a/x-pack/plugins/reporting/server/lib/enqueue_job.test.ts +++ b/x-pack/plugins/reporting/server/lib/enqueue_job.test.ts @@ -97,6 +97,7 @@ describe('Enqueue Job', () => { "kibana_name": undefined, "max_attempts": undefined, "meta": Object { + "isDeprecated": undefined, "layout": undefined, "objectType": "cool_object_type", }, diff --git a/x-pack/plugins/reporting/server/lib/enqueue_job.ts b/x-pack/plugins/reporting/server/lib/enqueue_job.ts index 998e4edf26a38..129c474fd134a 100644 --- a/x-pack/plugins/reporting/server/lib/enqueue_job.ts +++ b/x-pack/plugins/reporting/server/lib/enqueue_job.ts @@ -47,8 +47,10 @@ export async function enqueueJob( created_by: user ? user.username : false, payload: job, meta: { + // telemetry fields objectType: jobParams.objectType, layout: jobParams.layout?.id, + isDeprecated: job.isDeprecated, }, }) ); diff --git a/x-pack/plugins/reporting/server/lib/store/mapping.ts b/x-pack/plugins/reporting/server/lib/store/mapping.ts index 7a7a16c7bc7ea..a43b4494fe913 100644 --- a/x-pack/plugins/reporting/server/lib/store/mapping.ts +++ b/x-pack/plugins/reporting/server/lib/store/mapping.ts @@ -29,6 +29,9 @@ export const mapping = { }, }, }, + isDeprecated: { + type: 'boolean', + }, }, }, browser_type: { type: 'keyword' }, diff --git a/x-pack/plugins/reporting/server/usage/__snapshots__/reporting_usage_collector.test.ts.snap b/x-pack/plugins/reporting/server/usage/__snapshots__/reporting_usage_collector.test.ts.snap index 150154fa996c5..12e89f19e6248 100644 --- a/x-pack/plugins/reporting/server/usage/__snapshots__/reporting_usage_collector.test.ts.snap +++ b/x-pack/plugins/reporting/server/usage/__snapshots__/reporting_usage_collector.test.ts.snap @@ -1,9 +1,757 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`Ready for collection observable converts observable to promise 1`] = ` +Object { + "fetch": [Function], + "isReady": [Function], + "schema": Object { + "PNG": Object { + "available": Object { + "type": "boolean", + }, + "deprecated": Object { + "type": "long", + }, + "total": Object { + "type": "long", + }, + }, + "_all": Object { + "type": "long", + }, + "available": Object { + "type": "boolean", + }, + "browser_type": Object { + "type": "keyword", + }, + "csv": Object { + "available": Object { + "type": "boolean", + }, + "deprecated": Object { + "type": "long", + }, + "total": Object { + "type": "long", + }, + }, + "csv_searchsource": Object { + "available": Object { + "type": "boolean", + }, + "deprecated": Object { + "type": "long", + }, + "total": Object { + "type": "long", + }, + }, + "enabled": Object { + "type": "boolean", + }, + "last7Days": Object { + "PNG": Object { + "available": Object { + "type": "boolean", + }, + "deprecated": Object { + "type": "long", + }, + "total": Object { + "type": "long", + }, + }, + "_all": Object { + "type": "long", + }, + "csv": Object { + "available": Object { + "type": "boolean", + }, + "deprecated": Object { + "type": "long", + }, + "total": Object { + "type": "long", + }, + }, + "csv_searchsource": Object { + "available": Object { + "type": "boolean", + }, + "deprecated": Object { + "type": "long", + }, + "total": Object { + "type": "long", + }, + }, + "printable_pdf": Object { + "app": Object { + "canvas workpad": Object { + "type": "long", + }, + "dashboard": Object { + "type": "long", + }, + "visualization": Object { + "type": "long", + }, + }, + "available": Object { + "type": "boolean", + }, + "deprecated": Object { + "type": "long", + }, + "layout": Object { + "preserve_layout": Object { + "type": "long", + }, + "print": Object { + "type": "long", + }, + }, + "total": Object { + "type": "long", + }, + }, + "status": Object { + "completed": Object { + "type": "long", + }, + "completed_with_warnings": Object { + "type": "long", + }, + "failed": Object { + "type": "long", + }, + "pending": Object { + "type": "long", + }, + "processing": Object { + "type": "long", + }, + }, + "statuses": Object { + "completed": Object { + "PNG": Object { + "canvas workpad": Object { + "type": "long", + }, + "dashboard": Object { + "type": "long", + }, + "visualization": Object { + "type": "long", + }, + }, + "csv": Object { + "canvas workpad": Object { + "type": "long", + }, + "dashboard": Object { + "type": "long", + }, + "visualization": Object { + "type": "long", + }, + }, + "csv_searchsource": Object { + "canvas workpad": Object { + "type": "long", + }, + "dashboard": Object { + "type": "long", + }, + "visualization": Object { + "type": "long", + }, + }, + "printable_pdf": Object { + "canvas workpad": Object { + "type": "long", + }, + "dashboard": Object { + "type": "long", + }, + "visualization": Object { + "type": "long", + }, + }, + }, + "completed_with_warnings": Object { + "PNG": Object { + "canvas workpad": Object { + "type": "long", + }, + "dashboard": Object { + "type": "long", + }, + "visualization": Object { + "type": "long", + }, + }, + "csv": Object { + "canvas workpad": Object { + "type": "long", + }, + "dashboard": Object { + "type": "long", + }, + "visualization": Object { + "type": "long", + }, + }, + "csv_searchsource": Object { + "canvas workpad": Object { + "type": "long", + }, + "dashboard": Object { + "type": "long", + }, + "visualization": Object { + "type": "long", + }, + }, + "printable_pdf": Object { + "canvas workpad": Object { + "type": "long", + }, + "dashboard": Object { + "type": "long", + }, + "visualization": Object { + "type": "long", + }, + }, + }, + "failed": Object { + "PNG": Object { + "canvas workpad": Object { + "type": "long", + }, + "dashboard": Object { + "type": "long", + }, + "visualization": Object { + "type": "long", + }, + }, + "csv": Object { + "canvas workpad": Object { + "type": "long", + }, + "dashboard": Object { + "type": "long", + }, + "visualization": Object { + "type": "long", + }, + }, + "csv_searchsource": Object { + "canvas workpad": Object { + "type": "long", + }, + "dashboard": Object { + "type": "long", + }, + "visualization": Object { + "type": "long", + }, + }, + "printable_pdf": Object { + "canvas workpad": Object { + "type": "long", + }, + "dashboard": Object { + "type": "long", + }, + "visualization": Object { + "type": "long", + }, + }, + }, + "pending": Object { + "PNG": Object { + "canvas workpad": Object { + "type": "long", + }, + "dashboard": Object { + "type": "long", + }, + "visualization": Object { + "type": "long", + }, + }, + "csv": Object { + "canvas workpad": Object { + "type": "long", + }, + "dashboard": Object { + "type": "long", + }, + "visualization": Object { + "type": "long", + }, + }, + "csv_searchsource": Object { + "canvas workpad": Object { + "type": "long", + }, + "dashboard": Object { + "type": "long", + }, + "visualization": Object { + "type": "long", + }, + }, + "printable_pdf": Object { + "canvas workpad": Object { + "type": "long", + }, + "dashboard": Object { + "type": "long", + }, + "visualization": Object { + "type": "long", + }, + }, + }, + "processing": Object { + "PNG": Object { + "canvas workpad": Object { + "type": "long", + }, + "dashboard": Object { + "type": "long", + }, + "visualization": Object { + "type": "long", + }, + }, + "csv": Object { + "canvas workpad": Object { + "type": "long", + }, + "dashboard": Object { + "type": "long", + }, + "visualization": Object { + "type": "long", + }, + }, + "csv_searchsource": Object { + "canvas workpad": Object { + "type": "long", + }, + "dashboard": Object { + "type": "long", + }, + "visualization": Object { + "type": "long", + }, + }, + "printable_pdf": Object { + "canvas workpad": Object { + "type": "long", + }, + "dashboard": Object { + "type": "long", + }, + "visualization": Object { + "type": "long", + }, + }, + }, + }, + }, + "printable_pdf": Object { + "app": Object { + "canvas workpad": Object { + "type": "long", + }, + "dashboard": Object { + "type": "long", + }, + "visualization": Object { + "type": "long", + }, + }, + "available": Object { + "type": "boolean", + }, + "deprecated": Object { + "type": "long", + }, + "layout": Object { + "preserve_layout": Object { + "type": "long", + }, + "print": Object { + "type": "long", + }, + }, + "total": Object { + "type": "long", + }, + }, + "status": Object { + "completed": Object { + "type": "long", + }, + "completed_with_warnings": Object { + "type": "long", + }, + "failed": Object { + "type": "long", + }, + "pending": Object { + "type": "long", + }, + "processing": Object { + "type": "long", + }, + }, + "statuses": Object { + "completed": Object { + "PNG": Object { + "canvas workpad": Object { + "type": "long", + }, + "dashboard": Object { + "type": "long", + }, + "visualization": Object { + "type": "long", + }, + }, + "csv": Object { + "canvas workpad": Object { + "type": "long", + }, + "dashboard": Object { + "type": "long", + }, + "visualization": Object { + "type": "long", + }, + }, + "csv_searchsource": Object { + "canvas workpad": Object { + "type": "long", + }, + "dashboard": Object { + "type": "long", + }, + "visualization": Object { + "type": "long", + }, + }, + "printable_pdf": Object { + "canvas workpad": Object { + "type": "long", + }, + "dashboard": Object { + "type": "long", + }, + "visualization": Object { + "type": "long", + }, + }, + }, + "completed_with_warnings": Object { + "PNG": Object { + "canvas workpad": Object { + "type": "long", + }, + "dashboard": Object { + "type": "long", + }, + "visualization": Object { + "type": "long", + }, + }, + "csv": Object { + "canvas workpad": Object { + "type": "long", + }, + "dashboard": Object { + "type": "long", + }, + "visualization": Object { + "type": "long", + }, + }, + "csv_searchsource": Object { + "canvas workpad": Object { + "type": "long", + }, + "dashboard": Object { + "type": "long", + }, + "visualization": Object { + "type": "long", + }, + }, + "printable_pdf": Object { + "canvas workpad": Object { + "type": "long", + }, + "dashboard": Object { + "type": "long", + }, + "visualization": Object { + "type": "long", + }, + }, + }, + "failed": Object { + "PNG": Object { + "canvas workpad": Object { + "type": "long", + }, + "dashboard": Object { + "type": "long", + }, + "visualization": Object { + "type": "long", + }, + }, + "csv": Object { + "canvas workpad": Object { + "type": "long", + }, + "dashboard": Object { + "type": "long", + }, + "visualization": Object { + "type": "long", + }, + }, + "csv_searchsource": Object { + "canvas workpad": Object { + "type": "long", + }, + "dashboard": Object { + "type": "long", + }, + "visualization": Object { + "type": "long", + }, + }, + "printable_pdf": Object { + "canvas workpad": Object { + "type": "long", + }, + "dashboard": Object { + "type": "long", + }, + "visualization": Object { + "type": "long", + }, + }, + }, + "pending": Object { + "PNG": Object { + "canvas workpad": Object { + "type": "long", + }, + "dashboard": Object { + "type": "long", + }, + "visualization": Object { + "type": "long", + }, + }, + "csv": Object { + "canvas workpad": Object { + "type": "long", + }, + "dashboard": Object { + "type": "long", + }, + "visualization": Object { + "type": "long", + }, + }, + "csv_searchsource": Object { + "canvas workpad": Object { + "type": "long", + }, + "dashboard": Object { + "type": "long", + }, + "visualization": Object { + "type": "long", + }, + }, + "printable_pdf": Object { + "canvas workpad": Object { + "type": "long", + }, + "dashboard": Object { + "type": "long", + }, + "visualization": Object { + "type": "long", + }, + }, + }, + "processing": Object { + "PNG": Object { + "canvas workpad": Object { + "type": "long", + }, + "dashboard": Object { + "type": "long", + }, + "visualization": Object { + "type": "long", + }, + }, + "csv": Object { + "canvas workpad": Object { + "type": "long", + }, + "dashboard": Object { + "type": "long", + }, + "visualization": Object { + "type": "long", + }, + }, + "csv_searchsource": Object { + "canvas workpad": Object { + "type": "long", + }, + "dashboard": Object { + "type": "long", + }, + "visualization": Object { + "type": "long", + }, + }, + "printable_pdf": Object { + "canvas workpad": Object { + "type": "long", + }, + "dashboard": Object { + "type": "long", + }, + "visualization": Object { + "type": "long", + }, + }, + }, + }, + }, + "type": "reporting", +} +`; + +exports[`data modeling usage data with meta.isDeprecated jobTypes 1`] = ` +Object { + "PNG": Object { + "available": true, + "deprecated": 0, + "total": 0, + }, + "_all": 9, + "available": true, + "browser_type": undefined, + "csv": Object { + "available": true, + "deprecated": 4, + "total": 4, + }, + "csv_searchsource": Object { + "available": true, + "deprecated": 0, + "total": 5, + }, + "enabled": true, + "last7Days": Object { + "PNG": Object { + "available": true, + "deprecated": 0, + "total": 0, + }, + "_all": 9, + "csv": Object { + "available": true, + "deprecated": 4, + "total": 4, + }, + "csv_searchsource": Object { + "available": true, + "deprecated": 0, + "total": 5, + }, + "printable_pdf": Object { + "app": Object { + "dashboard": 0, + "visualization": 0, + }, + "available": true, + "deprecated": 0, + "layout": Object { + "preserve_layout": 0, + "print": 0, + }, + "total": 0, + }, + "status": Object { + "completed": 9, + "failed": 0, + }, + "statuses": Object { + "completed": Object { + "csv": Object { + "search": 4, + }, + "csv_searchsource": Object { + "search": 5, + }, + }, + }, + }, + "printable_pdf": Object { + "app": Object { + "dashboard": 0, + "visualization": 0, + }, + "available": true, + "deprecated": 0, + "layout": Object { + "preserve_layout": 0, + "print": 0, + }, + "total": 0, + }, + "status": Object { + "completed": 9, + "failed": 0, + }, + "statuses": Object { + "completed": Object { + "csv": Object { + "search": 4, + }, + "csv_searchsource": Object { + "search": 5, + }, + }, + }, +} +`; + exports[`data modeling with empty data 1`] = ` Object { "PNG": Object { "available": true, + "deprecated": 0, "total": 0, }, "_all": 0, @@ -11,25 +759,30 @@ Object { "browser_type": undefined, "csv": Object { "available": true, + "deprecated": 0, "total": 0, }, "csv_searchsource": Object { "available": true, + "deprecated": 0, "total": 0, }, "enabled": true, "last7Days": Object { "PNG": Object { "available": true, + "deprecated": 0, "total": 0, }, "_all": 0, "csv": Object { "available": true, + "deprecated": 0, "total": 0, }, "csv_searchsource": Object { "available": true, + "deprecated": 0, "total": 0, }, "printable_pdf": Object { @@ -38,6 +791,7 @@ Object { "visualization": 0, }, "available": true, + "deprecated": 0, "layout": Object { "preserve_layout": 0, "print": 0, @@ -56,6 +810,7 @@ Object { "visualization": 0, }, "available": true, + "deprecated": 0, "layout": Object { "preserve_layout": 0, "print": 0, @@ -74,6 +829,7 @@ exports[`data modeling with normal looking usage data 1`] = ` Object { "PNG": Object { "available": true, + "deprecated": 0, "total": 3, }, "_all": 12, @@ -81,25 +837,30 @@ Object { "browser_type": undefined, "csv": Object { "available": true, + "deprecated": 0, "total": 0, }, "csv_searchsource": Object { "available": true, + "deprecated": 0, "total": 0, }, "enabled": true, "last7Days": Object { "PNG": Object { "available": true, + "deprecated": 0, "total": 1, }, "_all": 1, "csv": Object { "available": true, + "deprecated": 0, "total": 0, }, "csv_searchsource": Object { "available": true, + "deprecated": 0, "total": 0, }, "printable_pdf": Object { @@ -108,6 +869,7 @@ Object { "visualization": 0, }, "available": true, + "deprecated": 0, "layout": Object { "preserve_layout": 0, "print": 0, @@ -134,6 +896,7 @@ Object { "visualization": 3, }, "available": true, + "deprecated": 0, "layout": Object { "preserve_layout": 9, "print": 0, @@ -173,6 +936,7 @@ exports[`data modeling with sparse data 1`] = ` Object { "PNG": Object { "available": true, + "deprecated": 0, "total": 1, }, "_all": 4, @@ -180,25 +944,30 @@ Object { "browser_type": undefined, "csv": Object { "available": true, + "deprecated": 1, "total": 1, }, "csv_searchsource": Object { "available": true, + "deprecated": 0, "total": 0, }, "enabled": true, "last7Days": Object { "PNG": Object { "available": true, + "deprecated": 0, "total": 1, }, "_all": 4, "csv": Object { "available": true, + "deprecated": 1, "total": 1, }, "csv_searchsource": Object { "available": true, + "deprecated": 0, "total": 0, }, "printable_pdf": Object { @@ -208,6 +977,7 @@ Object { "visualization": 0, }, "available": true, + "deprecated": 0, "layout": Object { "preserve_layout": 2, "print": 0, @@ -238,6 +1008,7 @@ Object { "visualization": 0, }, "available": true, + "deprecated": 0, "layout": Object { "preserve_layout": 2, "print": 0, diff --git a/x-pack/plugins/reporting/server/usage/decorate_range_stats.test.ts b/x-pack/plugins/reporting/server/usage/decorate_range_stats.test.ts new file mode 100644 index 0000000000000..ca1677c2379fc --- /dev/null +++ b/x-pack/plugins/reporting/server/usage/decorate_range_stats.test.ts @@ -0,0 +1,142 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { decorateRangeStats } from './decorate_range_stats'; +import { FeatureAvailabilityMap } from './types'; + +let featureMap: FeatureAvailabilityMap; + +beforeEach(() => { + featureMap = { PNG: true, csv: true, csv_searchsource: true, printable_pdf: true }; +}); + +test('Model of job status and status-by-pdf-app', () => { + const result = decorateRangeStats( + { + status: { completed: 0, processing: 1, pending: 2, failed: 3 }, + statuses: { + processing: { printable_pdf: { 'canvas workpad': 1 } }, + pending: { printable_pdf: { dashboard: 1, 'canvas workpad': 1 } }, + failed: { printable_pdf: { visualization: 2, dashboard: 2, 'canvas workpad': 1 } }, + }, + }, + featureMap + ); + + expect(result.status).toMatchInlineSnapshot(` + Object { + "completed": 0, + "failed": 3, + "pending": 2, + "processing": 1, + } + `); + expect(result.statuses).toMatchInlineSnapshot(` + Object { + "failed": Object { + "printable_pdf": Object { + "canvas workpad": 1, + "dashboard": 2, + "visualization": 2, + }, + }, + "pending": Object { + "printable_pdf": Object { + "canvas workpad": 1, + "dashboard": 1, + }, + }, + "processing": Object { + "printable_pdf": Object { + "canvas workpad": 1, + }, + }, + } + `); +}); + +test('Model of jobTypes', () => { + const result = decorateRangeStats( + { + PNG: { available: true, total: 3 }, + printable_pdf: { + available: true, + total: 3, + app: { dashboard: 0, visualization: 0, 'canvas workpad': 3 }, + layout: { preserve_layout: 3, print: 0 }, + }, + csv_searchsource: { available: true, total: 3 }, + }, + featureMap + ); + + expect(result.PNG).toMatchInlineSnapshot(` + Object { + "available": true, + "deprecated": 0, + "total": 3, + } + `); + expect(result.csv).toMatchInlineSnapshot(` + Object { + "available": true, + "deprecated": 0, + "total": 0, + } + `); + expect(result.csv_searchsource).toMatchInlineSnapshot(` + Object { + "available": true, + "deprecated": 0, + "total": 3, + } + `); + expect(result.printable_pdf).toMatchInlineSnapshot(` + Object { + "app": Object { + "canvas workpad": 3, + "dashboard": 0, + "visualization": 0, + }, + "available": true, + "deprecated": 0, + "layout": Object { + "preserve_layout": 3, + "print": 0, + }, + "total": 3, + } + `); +}); + +test('PNG counts, provided count of deprecated jobs explicitly', () => { + const result = decorateRangeStats( + { PNG: { available: true, total: 15, deprecated: 5 } }, + featureMap + ); + expect(result.PNG).toMatchInlineSnapshot(` + Object { + "available": true, + "deprecated": 5, + "total": 15, + } + `); +}); + +test('CSV counts, provides all jobs implicitly deprecated due to jobtype', () => { + const result = decorateRangeStats( + { csv: { available: true, total: 15, deprecated: 0 } }, + featureMap + ); + expect(result.csv).toMatchInlineSnapshot(` + Object { + "available": true, + "deprecated": 15, + "total": 15, + } + `); +}); diff --git a/x-pack/plugins/reporting/server/usage/decorate_range_stats.ts b/x-pack/plugins/reporting/server/usage/decorate_range_stats.ts index 9fc0141ab742e..99d4b7d934579 100644 --- a/x-pack/plugins/reporting/server/usage/decorate_range_stats.ts +++ b/x-pack/plugins/reporting/server/usage/decorate_range_stats.ts @@ -9,11 +9,14 @@ import { uniq } from 'lodash'; import { CSV_JOB_TYPE, CSV_JOB_TYPE_DEPRECATED, + DEPRECATED_JOB_TYPES, PDF_JOB_TYPE, PNG_JOB_TYPE, } from '../../common/constants'; import { AvailableTotal, ExportType, FeatureAvailabilityMap, RangeStats } from './types'; +const jobTypeIsDeprecated = (jobType: string) => DEPRECATED_JOB_TYPES.includes(jobType); + function getForFeature( range: Partial, typeKey: ExportType, @@ -21,7 +24,7 @@ function getForFeature( additional?: any ): AvailableTotal & typeof additional { const isAvailable = (feature: ExportType) => !!featureAvailability[feature]; - const jobType = range[typeKey] || { total: 0, ...additional }; + const jobType = range[typeKey] || { total: 0, ...additional, deprecated: 0 }; // merge the additional stats for the jobType type AdditionalType = { [K in keyof typeof additional]: K }; @@ -32,9 +35,13 @@ function getForFeature( }); } + // if the type itself is deprecated, all jobs are deprecated, otherwise only some of them might be + const deprecated = jobTypeIsDeprecated(typeKey) ? jobType.total : jobType.deprecated || 0; + return { available: isAvailable(typeKey), total: jobType.total, + deprecated, ...filledAdditional, }; } diff --git a/x-pack/plugins/reporting/server/usage/get_reporting_usage.ts b/x-pack/plugins/reporting/server/usage/get_reporting_usage.ts index f07da188f3e62..e5801b30caff6 100644 --- a/x-pack/plugins/reporting/server/usage/get_reporting_usage.ts +++ b/x-pack/plugins/reporting/server/usage/get_reporting_usage.ts @@ -5,21 +5,21 @@ * 2.0. */ import type { estypes } from '@elastic/elasticsearch'; +import type { ElasticsearchClient } from 'kibana/server'; import { get } from 'lodash'; -import { ElasticsearchClient } from 'kibana/server'; -import { ReportingConfig } from '../'; -import { ExportTypesRegistry } from '../lib/export_types_registry'; -import { GetLicense } from './'; +import type { ReportingConfig } from '../'; +import type { ExportTypesRegistry } from '../lib/export_types_registry'; +import type { GetLicense } from './'; import { decorateRangeStats } from './decorate_range_stats'; import { getExportTypesHandler } from './get_export_type_handler'; -import { +import type { AggregationResultBuckets, + AvailableTotal, FeatureAvailabilityMap, JobTypes, KeyCountBucket, RangeStats, ReportingUsageType, - // ReportingUsageSearchResponse, StatusByAppBucket, } from './types'; @@ -28,6 +28,7 @@ const JOB_TYPES_FIELD = 'jobtype'; const LAYOUT_TYPES_KEY = 'layoutTypes'; const LAYOUT_TYPES_FIELD = 'meta.layout.keyword'; const OBJECT_TYPES_KEY = 'objectTypes'; +const OBJECT_TYPE_DEPRECATED_KEY = 'meta.isDeprecated'; const OBJECT_TYPES_FIELD = 'meta.objectType.keyword'; const STATUS_TYPES_KEY = 'statusTypes'; const STATUS_BY_APP_KEY = 'statusByApp'; @@ -64,12 +65,15 @@ const getAppStatuses = (buckets: StatusByAppBucket[]) => function getAggStats(aggs: AggregationResultBuckets): Partial { const { buckets: jobBuckets } = aggs[JOB_TYPES_KEY]; - const jobTypes = jobBuckets.reduce( - (accum: JobTypes, { key, doc_count: count }: { key: string; doc_count: number }) => { - return { ...accum, [key]: { total: count } }; - }, - {} as JobTypes - ); + const jobTypes = jobBuckets.reduce((accum: JobTypes, bucket) => { + const { key, doc_count: count, isDeprecated } = bucket; + const deprecatedCount = isDeprecated?.doc_count; + const total: Omit = { + total: count, + deprecated: deprecatedCount, + }; + return { ...accum, [key]: total }; + }, {} as JobTypes); // merge pdf stats into pdf jobtype key const pdfJobs = jobTypes[PRINTABLE_PDF_JOBTYPE]; @@ -141,7 +145,10 @@ export async function getReportingUsage( }, }, aggs: { - [JOB_TYPES_KEY]: { terms: { field: JOB_TYPES_FIELD, size: DEFAULT_TERMS_SIZE } }, + [JOB_TYPES_KEY]: { + terms: { field: JOB_TYPES_FIELD, size: DEFAULT_TERMS_SIZE }, + aggs: { isDeprecated: { filter: { term: { [OBJECT_TYPE_DEPRECATED_KEY]: true } } } }, + }, [STATUS_TYPES_KEY]: { terms: { field: STATUS_TYPES_FIELD, size: DEFAULT_TERMS_SIZE } }, [STATUS_BY_APP_KEY]: { terms: { field: 'status', size: DEFAULT_TERMS_SIZE }, diff --git a/x-pack/plugins/reporting/server/usage/reporting_usage_collector.test.ts b/x-pack/plugins/reporting/server/usage/reporting_usage_collector.test.ts index 226704b255ab3..72824f6aeeb38 100644 --- a/x-pack/plugins/reporting/server/usage/reporting_usage_collector.test.ts +++ b/x-pack/plugins/reporting/server/usage/reporting_usage_collector.test.ts @@ -238,6 +238,147 @@ describe('data modeling', () => { expect(usageStats).toMatchSnapshot(); }); + test('usage data with meta.isDeprecated jobTypes', async () => { + const plugins = getPluginsMock(); + const collector = getReportingUsageCollector( + mockCore, + plugins.usageCollection, + getLicenseMock(), + exportTypesRegistry, + function isReady() { + return Promise.resolve(true); + } + ); + collectorFetchContext = getMockFetchClients( + getResponseMock({ + aggregations: { + ranges: { + buckets: { + all: { + doc_count: 9, + layoutTypes: { + doc_count: 0, + pdf: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [] }, + }, + statusByApp: { + doc_count_error_upper_bound: 0, + sum_other_doc_count: 0, + buckets: [ + { + key: 'completed', + doc_count: 9, + jobTypes: { + doc_count_error_upper_bound: 0, + sum_other_doc_count: 0, + buckets: [ + { + key: 'csv_searchsource', + doc_count: 5, + appNames: { + doc_count_error_upper_bound: 0, + sum_other_doc_count: 0, + buckets: [{ key: 'search', doc_count: 5 }], + }, + }, + { + key: 'csv', + doc_count: 4, + appNames: { + doc_count_error_upper_bound: 0, + sum_other_doc_count: 0, + buckets: [{ key: 'search', doc_count: 4 }], + }, + }, + ], + }, + }, + ], + }, + objectTypes: { + doc_count: 0, + pdf: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [] }, + }, + statusTypes: { + doc_count_error_upper_bound: 0, + sum_other_doc_count: 0, + buckets: [{ key: 'completed', doc_count: 9 }], + }, + jobTypes: { + doc_count_error_upper_bound: 0, + sum_other_doc_count: 0, + buckets: [ + { key: 'csv_searchsource', doc_count: 5, isDeprecated: { doc_count: 0 } }, + { key: 'csv', doc_count: 4, isDeprecated: { doc_count: 4 } }, + ], + }, + }, + last7Days: { + doc_count: 9, + layoutTypes: { + doc_count: 0, + pdf: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [] }, + }, + statusByApp: { + doc_count_error_upper_bound: 0, + sum_other_doc_count: 0, + buckets: [ + { + key: 'completed', + doc_count: 9, + jobTypes: { + doc_count_error_upper_bound: 0, + sum_other_doc_count: 0, + buckets: [ + { + key: 'csv_searchsource', + doc_count: 5, + appNames: { + doc_count_error_upper_bound: 0, + sum_other_doc_count: 0, + buckets: [{ key: 'search', doc_count: 5 }], + }, + }, + { + key: 'csv', + doc_count: 4, + appNames: { + doc_count_error_upper_bound: 0, + sum_other_doc_count: 0, + buckets: [{ key: 'search', doc_count: 4 }], + }, + }, + ], + }, + }, + ], + }, + objectTypes: { + doc_count: 0, + pdf: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [] }, + }, + statusTypes: { + doc_count_error_upper_bound: 0, + sum_other_doc_count: 0, + buckets: [{ key: 'completed', doc_count: 9 }], + }, + jobTypes: { + doc_count_error_upper_bound: 0, + sum_other_doc_count: 0, + buckets: [ + { key: 'csv_searchsource', doc_count: 5, isDeprecated: { doc_count: 0 } }, + { key: 'csv', doc_count: 4, isDeprecated: { doc_count: 4 } }, + ], + }, + }, + }, + }, + }, + }) + ); + const usageStats = await collector.fetch(collectorFetchContext); + expect(usageStats).toMatchSnapshot(); + }); + test('with sparse data', async () => { const plugins = getPluginsMock(); const collector = getReportingUsageCollector( @@ -462,730 +603,7 @@ describe('Ready for collection observable', () => { registerReportingUsageCollector(mockReporting, plugins); const [args] = makeCollectorSpy.firstCall.args; - expect(args).toMatchInlineSnapshot(` - Object { - "fetch": [Function], - "isReady": [Function], - "schema": Object { - "PNG": Object { - "available": Object { - "type": "boolean", - }, - "total": Object { - "type": "long", - }, - }, - "_all": Object { - "type": "long", - }, - "available": Object { - "type": "boolean", - }, - "browser_type": Object { - "type": "keyword", - }, - "csv": Object { - "available": Object { - "type": "boolean", - }, - "total": Object { - "type": "long", - }, - }, - "csv_searchsource": Object { - "available": Object { - "type": "boolean", - }, - "total": Object { - "type": "long", - }, - }, - "enabled": Object { - "type": "boolean", - }, - "last7Days": Object { - "PNG": Object { - "available": Object { - "type": "boolean", - }, - "total": Object { - "type": "long", - }, - }, - "_all": Object { - "type": "long", - }, - "csv": Object { - "available": Object { - "type": "boolean", - }, - "total": Object { - "type": "long", - }, - }, - "csv_searchsource": Object { - "available": Object { - "type": "boolean", - }, - "total": Object { - "type": "long", - }, - }, - "printable_pdf": Object { - "app": Object { - "canvas workpad": Object { - "type": "long", - }, - "dashboard": Object { - "type": "long", - }, - "visualization": Object { - "type": "long", - }, - }, - "available": Object { - "type": "boolean", - }, - "layout": Object { - "preserve_layout": Object { - "type": "long", - }, - "print": Object { - "type": "long", - }, - }, - "total": Object { - "type": "long", - }, - }, - "status": Object { - "cancelled": Object { - "type": "long", - }, - "completed": Object { - "type": "long", - }, - "completed_with_warnings": Object { - "type": "long", - }, - "failed": Object { - "type": "long", - }, - "pending": Object { - "type": "long", - }, - "processing": Object { - "type": "long", - }, - }, - "statuses": Object { - "cancelled": Object { - "PNG": Object { - "canvas workpad": Object { - "type": "long", - }, - "dashboard": Object { - "type": "long", - }, - "visualization": Object { - "type": "long", - }, - }, - "csv": Object { - "canvas workpad": Object { - "type": "long", - }, - "dashboard": Object { - "type": "long", - }, - "visualization": Object { - "type": "long", - }, - }, - "csv_searchsource": Object { - "canvas workpad": Object { - "type": "long", - }, - "dashboard": Object { - "type": "long", - }, - "visualization": Object { - "type": "long", - }, - }, - "printable_pdf": Object { - "canvas workpad": Object { - "type": "long", - }, - "dashboard": Object { - "type": "long", - }, - "visualization": Object { - "type": "long", - }, - }, - }, - "completed": Object { - "PNG": Object { - "canvas workpad": Object { - "type": "long", - }, - "dashboard": Object { - "type": "long", - }, - "visualization": Object { - "type": "long", - }, - }, - "csv": Object { - "canvas workpad": Object { - "type": "long", - }, - "dashboard": Object { - "type": "long", - }, - "visualization": Object { - "type": "long", - }, - }, - "csv_searchsource": Object { - "canvas workpad": Object { - "type": "long", - }, - "dashboard": Object { - "type": "long", - }, - "visualization": Object { - "type": "long", - }, - }, - "printable_pdf": Object { - "canvas workpad": Object { - "type": "long", - }, - "dashboard": Object { - "type": "long", - }, - "visualization": Object { - "type": "long", - }, - }, - }, - "completed_with_warnings": Object { - "PNG": Object { - "canvas workpad": Object { - "type": "long", - }, - "dashboard": Object { - "type": "long", - }, - "visualization": Object { - "type": "long", - }, - }, - "csv": Object { - "canvas workpad": Object { - "type": "long", - }, - "dashboard": Object { - "type": "long", - }, - "visualization": Object { - "type": "long", - }, - }, - "csv_searchsource": Object { - "canvas workpad": Object { - "type": "long", - }, - "dashboard": Object { - "type": "long", - }, - "visualization": Object { - "type": "long", - }, - }, - "printable_pdf": Object { - "canvas workpad": Object { - "type": "long", - }, - "dashboard": Object { - "type": "long", - }, - "visualization": Object { - "type": "long", - }, - }, - }, - "failed": Object { - "PNG": Object { - "canvas workpad": Object { - "type": "long", - }, - "dashboard": Object { - "type": "long", - }, - "visualization": Object { - "type": "long", - }, - }, - "csv": Object { - "canvas workpad": Object { - "type": "long", - }, - "dashboard": Object { - "type": "long", - }, - "visualization": Object { - "type": "long", - }, - }, - "csv_searchsource": Object { - "canvas workpad": Object { - "type": "long", - }, - "dashboard": Object { - "type": "long", - }, - "visualization": Object { - "type": "long", - }, - }, - "printable_pdf": Object { - "canvas workpad": Object { - "type": "long", - }, - "dashboard": Object { - "type": "long", - }, - "visualization": Object { - "type": "long", - }, - }, - }, - "pending": Object { - "PNG": Object { - "canvas workpad": Object { - "type": "long", - }, - "dashboard": Object { - "type": "long", - }, - "visualization": Object { - "type": "long", - }, - }, - "csv": Object { - "canvas workpad": Object { - "type": "long", - }, - "dashboard": Object { - "type": "long", - }, - "visualization": Object { - "type": "long", - }, - }, - "csv_searchsource": Object { - "canvas workpad": Object { - "type": "long", - }, - "dashboard": Object { - "type": "long", - }, - "visualization": Object { - "type": "long", - }, - }, - "printable_pdf": Object { - "canvas workpad": Object { - "type": "long", - }, - "dashboard": Object { - "type": "long", - }, - "visualization": Object { - "type": "long", - }, - }, - }, - "processing": Object { - "PNG": Object { - "canvas workpad": Object { - "type": "long", - }, - "dashboard": Object { - "type": "long", - }, - "visualization": Object { - "type": "long", - }, - }, - "csv": Object { - "canvas workpad": Object { - "type": "long", - }, - "dashboard": Object { - "type": "long", - }, - "visualization": Object { - "type": "long", - }, - }, - "csv_searchsource": Object { - "canvas workpad": Object { - "type": "long", - }, - "dashboard": Object { - "type": "long", - }, - "visualization": Object { - "type": "long", - }, - }, - "printable_pdf": Object { - "canvas workpad": Object { - "type": "long", - }, - "dashboard": Object { - "type": "long", - }, - "visualization": Object { - "type": "long", - }, - }, - }, - }, - }, - "printable_pdf": Object { - "app": Object { - "canvas workpad": Object { - "type": "long", - }, - "dashboard": Object { - "type": "long", - }, - "visualization": Object { - "type": "long", - }, - }, - "available": Object { - "type": "boolean", - }, - "layout": Object { - "preserve_layout": Object { - "type": "long", - }, - "print": Object { - "type": "long", - }, - }, - "total": Object { - "type": "long", - }, - }, - "status": Object { - "cancelled": Object { - "type": "long", - }, - "completed": Object { - "type": "long", - }, - "completed_with_warnings": Object { - "type": "long", - }, - "failed": Object { - "type": "long", - }, - "pending": Object { - "type": "long", - }, - "processing": Object { - "type": "long", - }, - }, - "statuses": Object { - "cancelled": Object { - "PNG": Object { - "canvas workpad": Object { - "type": "long", - }, - "dashboard": Object { - "type": "long", - }, - "visualization": Object { - "type": "long", - }, - }, - "csv": Object { - "canvas workpad": Object { - "type": "long", - }, - "dashboard": Object { - "type": "long", - }, - "visualization": Object { - "type": "long", - }, - }, - "csv_searchsource": Object { - "canvas workpad": Object { - "type": "long", - }, - "dashboard": Object { - "type": "long", - }, - "visualization": Object { - "type": "long", - }, - }, - "printable_pdf": Object { - "canvas workpad": Object { - "type": "long", - }, - "dashboard": Object { - "type": "long", - }, - "visualization": Object { - "type": "long", - }, - }, - }, - "completed": Object { - "PNG": Object { - "canvas workpad": Object { - "type": "long", - }, - "dashboard": Object { - "type": "long", - }, - "visualization": Object { - "type": "long", - }, - }, - "csv": Object { - "canvas workpad": Object { - "type": "long", - }, - "dashboard": Object { - "type": "long", - }, - "visualization": Object { - "type": "long", - }, - }, - "csv_searchsource": Object { - "canvas workpad": Object { - "type": "long", - }, - "dashboard": Object { - "type": "long", - }, - "visualization": Object { - "type": "long", - }, - }, - "printable_pdf": Object { - "canvas workpad": Object { - "type": "long", - }, - "dashboard": Object { - "type": "long", - }, - "visualization": Object { - "type": "long", - }, - }, - }, - "completed_with_warnings": Object { - "PNG": Object { - "canvas workpad": Object { - "type": "long", - }, - "dashboard": Object { - "type": "long", - }, - "visualization": Object { - "type": "long", - }, - }, - "csv": Object { - "canvas workpad": Object { - "type": "long", - }, - "dashboard": Object { - "type": "long", - }, - "visualization": Object { - "type": "long", - }, - }, - "csv_searchsource": Object { - "canvas workpad": Object { - "type": "long", - }, - "dashboard": Object { - "type": "long", - }, - "visualization": Object { - "type": "long", - }, - }, - "printable_pdf": Object { - "canvas workpad": Object { - "type": "long", - }, - "dashboard": Object { - "type": "long", - }, - "visualization": Object { - "type": "long", - }, - }, - }, - "failed": Object { - "PNG": Object { - "canvas workpad": Object { - "type": "long", - }, - "dashboard": Object { - "type": "long", - }, - "visualization": Object { - "type": "long", - }, - }, - "csv": Object { - "canvas workpad": Object { - "type": "long", - }, - "dashboard": Object { - "type": "long", - }, - "visualization": Object { - "type": "long", - }, - }, - "csv_searchsource": Object { - "canvas workpad": Object { - "type": "long", - }, - "dashboard": Object { - "type": "long", - }, - "visualization": Object { - "type": "long", - }, - }, - "printable_pdf": Object { - "canvas workpad": Object { - "type": "long", - }, - "dashboard": Object { - "type": "long", - }, - "visualization": Object { - "type": "long", - }, - }, - }, - "pending": Object { - "PNG": Object { - "canvas workpad": Object { - "type": "long", - }, - "dashboard": Object { - "type": "long", - }, - "visualization": Object { - "type": "long", - }, - }, - "csv": Object { - "canvas workpad": Object { - "type": "long", - }, - "dashboard": Object { - "type": "long", - }, - "visualization": Object { - "type": "long", - }, - }, - "csv_searchsource": Object { - "canvas workpad": Object { - "type": "long", - }, - "dashboard": Object { - "type": "long", - }, - "visualization": Object { - "type": "long", - }, - }, - "printable_pdf": Object { - "canvas workpad": Object { - "type": "long", - }, - "dashboard": Object { - "type": "long", - }, - "visualization": Object { - "type": "long", - }, - }, - }, - "processing": Object { - "PNG": Object { - "canvas workpad": Object { - "type": "long", - }, - "dashboard": Object { - "type": "long", - }, - "visualization": Object { - "type": "long", - }, - }, - "csv": Object { - "canvas workpad": Object { - "type": "long", - }, - "dashboard": Object { - "type": "long", - }, - "visualization": Object { - "type": "long", - }, - }, - "csv_searchsource": Object { - "canvas workpad": Object { - "type": "long", - }, - "dashboard": Object { - "type": "long", - }, - "visualization": Object { - "type": "long", - }, - }, - "printable_pdf": Object { - "canvas workpad": Object { - "type": "long", - }, - "dashboard": Object { - "type": "long", - }, - "visualization": Object { - "type": "long", - }, - }, - }, - }, - }, - "type": "reporting", - } - `); + expect(args).toMatchSnapshot(); await expect(args.isReady()).resolves.toBe(true); }); diff --git a/x-pack/plugins/reporting/server/usage/schema.ts b/x-pack/plugins/reporting/server/usage/schema.ts index 8528543b09e07..2060fdcb1f01e 100644 --- a/x-pack/plugins/reporting/server/usage/schema.ts +++ b/x-pack/plugins/reporting/server/usage/schema.ts @@ -6,7 +6,14 @@ */ import { MakeSchemaFrom } from 'src/plugins/usage_collection/server'; -import { AppCounts, AvailableTotal, JobTypes, RangeStats, ReportingUsageType } from './types'; +import { + AppCounts, + AvailableTotal, + ByAppCounts, + JobTypes, + RangeStats, + ReportingUsageType, +} from './types'; const appCountsSchema: MakeSchemaFrom = { 'canvas workpad': { type: 'long' }, @@ -14,7 +21,7 @@ const appCountsSchema: MakeSchemaFrom = { visualization: { type: 'long' }, }; -const byAppCountsSchema: MakeSchemaFrom = { +const byAppCountsSchema: MakeSchemaFrom = { csv: appCountsSchema, csv_searchsource: appCountsSchema, PNG: appCountsSchema, @@ -24,6 +31,7 @@ const byAppCountsSchema: MakeSchemaFrom = { const availableTotalSchema: MakeSchemaFrom = { available: { type: 'boolean' }, total: { type: 'long' }, + deprecated: { type: 'long' }, }; const jobTypesSchema: MakeSchemaFrom = { @@ -44,7 +52,6 @@ const rangeStatsSchema: MakeSchemaFrom = { ...jobTypesSchema, _all: { type: 'long' }, status: { - cancelled: { type: 'long' }, completed: { type: 'long' }, completed_with_warnings: { type: 'long' }, failed: { type: 'long' }, @@ -52,7 +59,6 @@ const rangeStatsSchema: MakeSchemaFrom = { processing: { type: 'long' }, }, statuses: { - cancelled: byAppCountsSchema, completed: byAppCountsSchema, completed_with_warnings: byAppCountsSchema, failed: byAppCountsSchema, diff --git a/x-pack/plugins/reporting/server/usage/types.ts b/x-pack/plugins/reporting/server/usage/types.ts index 58def60a24ccb..aae8c0ff42710 100644 --- a/x-pack/plugins/reporting/server/usage/types.ts +++ b/x-pack/plugins/reporting/server/usage/types.ts @@ -8,6 +8,9 @@ export interface KeyCountBucket { key: string; doc_count: number; + isDeprecated?: { + doc_count: number; + }; } export interface AggregationBuckets { @@ -57,9 +60,11 @@ export interface SearchResponse { export interface AvailableTotal { available: boolean; total: number; + deprecated?: number; } type BaseJobTypes = 'csv' | 'csv_searchsource' | 'PNG' | 'printable_pdf'; + export interface LayoutCounts { print: number; preserve_layout: number; @@ -77,20 +82,15 @@ export type JobTypes = { [K in BaseJobTypes]: AvailableTotal } & { }; }; -type Statuses = - | 'cancelled' - | 'completed' - | 'completed_with_warnings' - | 'failed' - | 'pending' - | 'processing'; +export type ByAppCounts = { [J in BaseJobTypes]?: AppCounts }; + +type Statuses = 'completed' | 'completed_with_warnings' | 'failed' | 'pending' | 'processing'; + type StatusCounts = { [S in Statuses]?: number; }; type StatusByAppCounts = { - [S in Statuses]?: { - [J in BaseJobTypes]?: AppCounts; - }; + [S in Statuses]?: ByAppCounts; }; export type RangeStats = JobTypes & { @@ -109,44 +109,6 @@ export type ReportingUsageType = RangeStats & { export type ExportType = 'csv' | 'csv_searchsource' | 'printable_pdf' | 'PNG'; export type FeatureAvailabilityMap = { [F in ExportType]: boolean }; -export interface KeyCountBucket { - key: string; - doc_count: number; -} - -export interface AggregationBuckets { - buckets: KeyCountBucket[]; -} - -export interface StatusByAppBucket { - key: string; - doc_count: number; - jobTypes: { - buckets: Array<{ - doc_count: number; - key: string; - appNames: AggregationBuckets; - }>; - }; -} - -export interface AggregationResultBuckets { - jobTypes: AggregationBuckets; - layoutTypes: { - doc_count: number; - pdf: AggregationBuckets; - }; - objectTypes: { - doc_count: number; - pdf: AggregationBuckets; - }; - statusTypes: AggregationBuckets; - statusByApp: { - buckets: StatusByAppBucket[]; - }; - doc_count: number; -} - export interface ReportingUsageSearchResponse { aggregations: { ranges: { diff --git a/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json b/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json index 3c9dce63f2cb9..54a5f22839bfd 100644 --- a/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json +++ b/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json @@ -4044,6 +4044,9 @@ }, "total": { "type": "long" + }, + "deprecated": { + "type": "long" } } }, @@ -4054,6 +4057,9 @@ }, "total": { "type": "long" + }, + "deprecated": { + "type": "long" } } }, @@ -4064,6 +4070,9 @@ }, "total": { "type": "long" + }, + "deprecated": { + "type": "long" } } }, @@ -4075,6 +4084,9 @@ "total": { "type": "long" }, + "deprecated": { + "type": "long" + }, "app": { "properties": { "canvas workpad": { @@ -4105,9 +4117,6 @@ }, "status": { "properties": { - "cancelled": { - "type": "long" - }, "completed": { "type": "long" }, @@ -4127,62 +4136,6 @@ }, "statuses": { "properties": { - "cancelled": { - "properties": { - "csv": { - "properties": { - "canvas workpad": { - "type": "long" - }, - "dashboard": { - "type": "long" - }, - "visualization": { - "type": "long" - } - } - }, - "csv_searchsource": { - "properties": { - "canvas workpad": { - "type": "long" - }, - "dashboard": { - "type": "long" - }, - "visualization": { - "type": "long" - } - } - }, - "PNG": { - "properties": { - "canvas workpad": { - "type": "long" - }, - "dashboard": { - "type": "long" - }, - "visualization": { - "type": "long" - } - } - }, - "printable_pdf": { - "properties": { - "canvas workpad": { - "type": "long" - }, - "dashboard": { - "type": "long" - }, - "visualization": { - "type": "long" - } - } - } - } - }, "completed": { "properties": { "csv": { @@ -4483,6 +4436,9 @@ }, "total": { "type": "long" + }, + "deprecated": { + "type": "long" } } }, @@ -4493,6 +4449,9 @@ }, "total": { "type": "long" + }, + "deprecated": { + "type": "long" } } }, @@ -4503,6 +4462,9 @@ }, "total": { "type": "long" + }, + "deprecated": { + "type": "long" } } }, @@ -4514,6 +4476,9 @@ "total": { "type": "long" }, + "deprecated": { + "type": "long" + }, "app": { "properties": { "canvas workpad": { @@ -4544,9 +4509,6 @@ }, "status": { "properties": { - "cancelled": { - "type": "long" - }, "completed": { "type": "long" }, @@ -4566,62 +4528,6 @@ }, "statuses": { "properties": { - "cancelled": { - "properties": { - "csv": { - "properties": { - "canvas workpad": { - "type": "long" - }, - "dashboard": { - "type": "long" - }, - "visualization": { - "type": "long" - } - } - }, - "csv_searchsource": { - "properties": { - "canvas workpad": { - "type": "long" - }, - "dashboard": { - "type": "long" - }, - "visualization": { - "type": "long" - } - } - }, - "PNG": { - "properties": { - "canvas workpad": { - "type": "long" - }, - "dashboard": { - "type": "long" - }, - "visualization": { - "type": "long" - } - } - }, - "printable_pdf": { - "properties": { - "canvas workpad": { - "type": "long" - }, - "dashboard": { - "type": "long" - }, - "visualization": { - "type": "long" - } - } - } - } - }, "completed": { "properties": { "csv": { diff --git a/x-pack/test/reporting_api_integration/reporting_without_security/job_apis_csv_deprecated.ts b/x-pack/test/reporting_api_integration/reporting_without_security/job_apis_csv_deprecated.ts index 2d62725e23989..6ff8946d48c5b 100644 --- a/x-pack/test/reporting_api_integration/reporting_without_security/job_apis_csv_deprecated.ts +++ b/x-pack/test/reporting_api_integration/reporting_without_security/job_apis_csv_deprecated.ts @@ -59,7 +59,9 @@ export default function ({ getService }: FtrProviderContext) { "attempts": 0, "created_by": false, "jobtype": "csv", - "meta": Object {}, + "meta": Object { + "isDeprecated": true, + }, "payload": Object { "isDeprecated": true, "title": "A Saved Search With a DATE FILTER", @@ -101,7 +103,9 @@ export default function ({ getService }: FtrProviderContext) { "attempts": 0, "created_by": false, "jobtype": "csv", - "meta": Object {}, + "meta": Object { + "isDeprecated": true, + }, "payload": Object { "isDeprecated": true, "title": "A Saved Search With a DATE FILTER", @@ -136,7 +140,9 @@ export default function ({ getService }: FtrProviderContext) { "attempts": 0, "created_by": false, "jobtype": "csv", - "meta": Object {}, + "meta": Object { + "isDeprecated": true, + }, "payload": Object { "isDeprecated": true, "title": "A Saved Search With a DATE FILTER", @@ -168,7 +174,9 @@ export default function ({ getService }: FtrProviderContext) { "attempts": 0, "created_by": false, "jobtype": "csv", - "meta": Object {}, + "meta": Object { + "isDeprecated": true, + }, "payload": Object { "isDeprecated": true, "title": "A Saved Search With a DATE FILTER", From b35cb348ba1896ab74f10a826b53235592807636 Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Sat, 21 Aug 2021 02:27:10 -0400 Subject: [PATCH 54/76] chore(NA): moving @kbn/securitysolution-autocomplete to babel transpiler (#109423) (#109570) * chore(NA): moving @kbn/securitysolution-autocomplete to babel transpiler * chore(NA): finetune package * chore(NA): update deps Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Tiago Costa --- .../.babelrc | 4 + .../.babelrc.browser | 4 + .../BUILD.bazel | 80 +++++++++---------- .../babel.config.js | 19 ----- .../react/package.json | 5 -- .../tsconfig.browser.json | 22 ----- .../tsconfig.json | 7 +- 7 files changed, 49 insertions(+), 92 deletions(-) create mode 100644 packages/kbn-securitysolution-autocomplete/.babelrc create mode 100644 packages/kbn-securitysolution-autocomplete/.babelrc.browser delete mode 100644 packages/kbn-securitysolution-autocomplete/babel.config.js delete mode 100644 packages/kbn-securitysolution-autocomplete/react/package.json delete mode 100644 packages/kbn-securitysolution-autocomplete/tsconfig.browser.json diff --git a/packages/kbn-securitysolution-autocomplete/.babelrc b/packages/kbn-securitysolution-autocomplete/.babelrc new file mode 100644 index 0000000000000..40a198521b903 --- /dev/null +++ b/packages/kbn-securitysolution-autocomplete/.babelrc @@ -0,0 +1,4 @@ +{ + "presets": ["@kbn/babel-preset/node_preset"], + "ignore": ["**/*.test.ts", "**/*.test.tsx"] +} diff --git a/packages/kbn-securitysolution-autocomplete/.babelrc.browser b/packages/kbn-securitysolution-autocomplete/.babelrc.browser new file mode 100644 index 0000000000000..71bbfbcd6eb2f --- /dev/null +++ b/packages/kbn-securitysolution-autocomplete/.babelrc.browser @@ -0,0 +1,4 @@ +{ + "presets": ["@kbn/babel-preset/webpack_preset"], + "ignore": ["**/*.test.ts", "**/*.test.tsx"] +} diff --git a/packages/kbn-securitysolution-autocomplete/BUILD.bazel b/packages/kbn-securitysolution-autocomplete/BUILD.bazel index 18c3b8f3ae3bb..53cd7b4f8d3e1 100644 --- a/packages/kbn-securitysolution-autocomplete/BUILD.bazel +++ b/packages/kbn-securitysolution-autocomplete/BUILD.bazel @@ -1,5 +1,6 @@ load("@npm//@bazel/typescript:index.bzl", "ts_config", "ts_project") load("@build_bazel_rules_nodejs//:index.bzl", "js_library", "pkg_npm") +load("//src/dev/bazel:index.bzl", "jsts_transpiler") PKG_BASE_NAME = "kbn-securitysolution-autocomplete" @@ -25,35 +26,54 @@ filegroup( ) NPM_MODULE_EXTRA_FILES = [ - "react/package.json", "package.json", "README.md", ] -SRC_DEPS = [ - "//packages/kbn-babel-preset", - "//packages/kbn-dev-utils", +RUNTIME_DEPS = [ + "//packages/kbn-es-query", "//packages/kbn-i18n", - "//packages/kbn-securitysolution-io-ts-list-types", "//packages/kbn-securitysolution-list-hooks", - "//packages/kbn-es-query", - "@npm//@babel/core", - "@npm//babel-loader", + "//packages/kbn-securitysolution-list-utils", + "//packages/kbn-securitysolution-io-ts-list-types", "@npm//@elastic/eui", + "@npm//@testing-library/react", + "@npm//@testing-library/react-hooks", + "@npm//enzyme", + "@npm//moment", "@npm//react", "@npm//resize-observer-polyfill", - "@npm//rxjs", - "@npm//tslib", ] TYPES_DEPS = [ - "@npm//typescript", + "//packages/kbn-es-query", + "//packages/kbn-i18n", + "//packages/kbn-securitysolution-list-hooks", + "//packages/kbn-securitysolution-list-utils", + "//packages/kbn-securitysolution-io-ts-list-types", + "@npm//@elastic/eui", + "@npm//@testing-library/react", + "@npm//@testing-library/react-hooks", + "@npm//moment", + "@npm//resize-observer-polyfill", + "@npm//@types/enzyme", "@npm//@types/jest", "@npm//@types/node", "@npm//@types/react", ] -DEPS = SRC_DEPS + TYPES_DEPS +jsts_transpiler( + name = "target_node", + srcs = SRCS, + build_pkg_name = package_name(), +) + +jsts_transpiler( + name = "target_web", + srcs = SRCS, + build_pkg_name = package_name(), + config_file = ".babelrc.browser" +) ts_config( name = "tsconfig", @@ -64,50 +84,26 @@ ts_config( ], ) -ts_config( - name = "tsconfig_browser", - src = "tsconfig.browser.json", - deps = [ - "//:tsconfig.base.json", - "//:tsconfig.browser.json", - "//:tsconfig.browser_bazel.json", - ], -) - ts_project( - name = "tsc", + name = "tsc_types", args = ["--pretty"], srcs = SRCS, - deps = DEPS, - allow_js = True, + deps = TYPES_DEPS, declaration = True, - declaration_dir = "target_types", declaration_map = True, - out_dir = "target_node", + emit_declaration_only = True, + out_dir = "target_types", root_dir = "src", source_map = True, tsconfig = ":tsconfig", ) -ts_project( - name = "tsc_browser", - args = ['--pretty'], - srcs = SRCS, - deps = DEPS, - allow_js = True, - declaration = False, - out_dir = "target_web", - source_map = True, - root_dir = "src", - tsconfig = ":tsconfig_browser", -) - js_library( name = PKG_BASE_NAME, - package_name = PKG_REQUIRE_NAME, srcs = NPM_MODULE_EXTRA_FILES, + deps = RUNTIME_DEPS + [":target_node", ":target_web", ":tsc_types"], + package_name = PKG_REQUIRE_NAME, visibility = ["//visibility:public"], - deps = [":tsc", ":tsc_browser"] + DEPS, ) pkg_npm( diff --git a/packages/kbn-securitysolution-autocomplete/babel.config.js b/packages/kbn-securitysolution-autocomplete/babel.config.js deleted file mode 100644 index b4a118df51af5..0000000000000 --- a/packages/kbn-securitysolution-autocomplete/babel.config.js +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -module.exports = { - env: { - web: { - presets: ['@kbn/babel-preset/webpack_preset'], - }, - node: { - presets: ['@kbn/babel-preset/node_preset'], - }, - }, - ignore: ['**/*.test.ts', '**/*.test.tsx'], -}; diff --git a/packages/kbn-securitysolution-autocomplete/react/package.json b/packages/kbn-securitysolution-autocomplete/react/package.json deleted file mode 100644 index c5f222b5843ac..0000000000000 --- a/packages/kbn-securitysolution-autocomplete/react/package.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "browser": "../target_web/react", - "main": "../target_node/react", - "types": "../target_types/react/index.d.ts" -} diff --git a/packages/kbn-securitysolution-autocomplete/tsconfig.browser.json b/packages/kbn-securitysolution-autocomplete/tsconfig.browser.json deleted file mode 100644 index 404043569aa92..0000000000000 --- a/packages/kbn-securitysolution-autocomplete/tsconfig.browser.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "extends": "../../tsconfig.browser_bazel.json", - "compilerOptions": { - "allowJs": true, - "outDir": "./target_web", - "declaration": false, - "isolatedModules": true, - "sourceMap": true, - "sourceRoot": "../../../../../packages/kbn-securitysolution-autocomplete/src", - "types": [ - "jest", - "node" - ], - }, - "include": [ - "src/**/*.ts", - "src/**/*.tsx", - ], - "exclude": [ - "**/__fixtures__/**/*" - ] -} diff --git a/packages/kbn-securitysolution-autocomplete/tsconfig.json b/packages/kbn-securitysolution-autocomplete/tsconfig.json index 484b639f94332..fa7eff8234011 100644 --- a/packages/kbn-securitysolution-autocomplete/tsconfig.json +++ b/packages/kbn-securitysolution-autocomplete/tsconfig.json @@ -1,15 +1,14 @@ { "extends": "../../tsconfig.bazel.json", "compilerOptions": { - "allowJs": true, - "declarationDir": "./target_types", - "outDir": "target_node", "declaration": true, "declarationMap": true, + "emitDeclarationOnly": true, + "outDir": "target_types", "sourceMap": true, "sourceRoot": "../../../../packages/kbn-securitysolution-autocomplete/src", "rootDir": "src", "types": ["jest", "node", "resize-observer-polyfill"] }, - "include": ["src/**/*"] + "include": ["src/**/*"], } From 9e00e1e3936a9acad1eccb51647eceb7af43bf6a Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Sat, 21 Aug 2021 11:10:53 +0200 Subject: [PATCH 55/76] [IndexPatterns] No data experience to handle default Fleet assets (#108887) (#109511) Co-authored-by: Josh Dover <1813008+joshdover@users.noreply.github.com> # Conflicts: # docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternsservice.md # docs/development/plugins/data/server/kibana-plugin-plugins-data-server.indexpatternsservice.md # src/plugins/data/public/public.api.md # src/plugins/data/server/server.api.md Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- ...ndexpatternsservice.hasuserindexpattern.md | 17 ++ ...lugins-data-public.indexpatternsservice.md | 1 + ...ndexpatternsservice.hasuserindexpattern.md | 17 ++ ...lugins-data-server.indexpatternsservice.md | 1 + .../data/common/index_patterns/constants.ts | 14 ++ .../ensure_default_index_pattern.ts | 5 +- .../index_patterns/index_patterns.ts | 7 + .../data/common/index_patterns/types.ts | 1 + .../index_patterns_api_client.ts | 7 +- src/plugins/data/public/public.api.md | 1 + .../has_user_index_pattern.test.ts | 174 ++++++++++++++++++ .../index_patterns/has_user_index_pattern.ts | 62 +++++++ .../index_patterns_api_client.ts | 15 +- .../index_patterns/index_patterns_service.ts | 2 +- .../data/server/index_patterns/routes.ts | 2 + .../routes/has_user_index_pattern.ts | 40 ++++ src/plugins/data/server/server.api.md | 1 + .../empty_prompts/empty_prompts.test.tsx | 98 ++++++++++ .../empty_prompts/empty_prompts.tsx | 34 ++-- .../index_pattern_editor_flyout_content.tsx | 7 +- .../index_pattern_table.tsx | 5 +- .../public/components/overview/overview.tsx | 4 +- .../has_user_index_pattern.ts | 139 ++++++++++++++ .../has_user_index_pattern/index.ts | 15 ++ .../apis/index_patterns/index.js | 1 + 25 files changed, 644 insertions(+), 26 deletions(-) create mode 100644 docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternsservice.hasuserindexpattern.md create mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.indexpatternsservice.hasuserindexpattern.md create mode 100644 src/plugins/data/server/index_patterns/has_user_index_pattern.test.ts create mode 100644 src/plugins/data/server/index_patterns/has_user_index_pattern.ts create mode 100644 src/plugins/data/server/index_patterns/routes/has_user_index_pattern.ts create mode 100644 src/plugins/index_pattern_editor/public/components/empty_prompts/empty_prompts.test.tsx create mode 100644 test/api_integration/apis/index_patterns/has_user_index_pattern/has_user_index_pattern.ts create mode 100644 test/api_integration/apis/index_patterns/has_user_index_pattern/index.ts diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternsservice.hasuserindexpattern.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternsservice.hasuserindexpattern.md new file mode 100644 index 0000000000000..31d1b9b9c16a9 --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternsservice.hasuserindexpattern.md @@ -0,0 +1,17 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [IndexPatternsService](./kibana-plugin-plugins-data-public.indexpatternsservice.md) > [hasUserIndexPattern](./kibana-plugin-plugins-data-public.indexpatternsservice.hasuserindexpattern.md) + +## IndexPatternsService.hasUserIndexPattern() method + +Checks if current user has a user created index pattern ignoring fleet's server default index patterns + +Signature: + +```typescript +hasUserIndexPattern(): Promise; +``` +Returns: + +`Promise` + diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternsservice.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternsservice.md index 30e7a6be143e9..1af365d96a254 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternsservice.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternsservice.md @@ -45,6 +45,7 @@ export declare class IndexPatternsService | [createAndSave(spec, override, skipFetchFields)](./kibana-plugin-plugins-data-public.indexpatternsservice.createandsave.md) | | Create a new index pattern and save it right away | | [createSavedObject(indexPattern, override)](./kibana-plugin-plugins-data-public.indexpatternsservice.createsavedobject.md) | | Save a new index pattern | | [delete(indexPatternId)](./kibana-plugin-plugins-data-public.indexpatternsservice.delete.md) | | Deletes an index pattern from .kibana index | +| [hasUserIndexPattern()](./kibana-plugin-plugins-data-public.indexpatternsservice.hasuserindexpattern.md) | | Checks if current user has a user created index pattern ignoring fleet's server default index patterns | | [migrate(indexPattern, newTitle)](./kibana-plugin-plugins-data-public.indexpatternsservice.migrate.md) | | | | [updateSavedObject(indexPattern, saveAttempts, ignoreErrors)](./kibana-plugin-plugins-data-public.indexpatternsservice.updatesavedobject.md) | | Save existing index pattern. Will attempt to merge differences if there are conflicts | diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.indexpatternsservice.hasuserindexpattern.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.indexpatternsservice.hasuserindexpattern.md new file mode 100644 index 0000000000000..49f365c106040 --- /dev/null +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.indexpatternsservice.hasuserindexpattern.md @@ -0,0 +1,17 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [IndexPatternsService](./kibana-plugin-plugins-data-server.indexpatternsservice.md) > [hasUserIndexPattern](./kibana-plugin-plugins-data-server.indexpatternsservice.hasuserindexpattern.md) + +## IndexPatternsService.hasUserIndexPattern() method + +Checks if current user has a user created index pattern ignoring fleet's server default index patterns + +Signature: + +```typescript +hasUserIndexPattern(): Promise; +``` +Returns: + +`Promise` + diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.indexpatternsservice.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.indexpatternsservice.md index b42325b578f6e..2e71c1f7c4f93 100644 --- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.indexpatternsservice.md +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.indexpatternsservice.md @@ -45,6 +45,7 @@ export declare class IndexPatternsService | [createAndSave(spec, override, skipFetchFields)](./kibana-plugin-plugins-data-server.indexpatternsservice.createandsave.md) | | Create a new index pattern and save it right away | | [createSavedObject(indexPattern, override)](./kibana-plugin-plugins-data-server.indexpatternsservice.createsavedobject.md) | | Save a new index pattern | | [delete(indexPatternId)](./kibana-plugin-plugins-data-server.indexpatternsservice.delete.md) | | Deletes an index pattern from .kibana index | +| [hasUserIndexPattern()](./kibana-plugin-plugins-data-server.indexpatternsservice.hasuserindexpattern.md) | | Checks if current user has a user created index pattern ignoring fleet's server default index patterns | | [migrate(indexPattern, newTitle)](./kibana-plugin-plugins-data-server.indexpatternsservice.migrate.md) | | | | [updateSavedObject(indexPattern, saveAttempts, ignoreErrors)](./kibana-plugin-plugins-data-server.indexpatternsservice.updatesavedobject.md) | | Save existing index pattern. Will attempt to merge differences if there are conflicts | diff --git a/src/plugins/data/common/index_patterns/constants.ts b/src/plugins/data/common/index_patterns/constants.ts index d508a62422fc7..67e266dbd84a2 100644 --- a/src/plugins/data/common/index_patterns/constants.ts +++ b/src/plugins/data/common/index_patterns/constants.ts @@ -15,3 +15,17 @@ export const RUNTIME_FIELD_TYPES = [ 'boolean', 'geo_point', ] as const; + +/** + * Used to determine if the instance has any user created index patterns by filtering index patterns + * that are created and backed only by Fleet server data + * Should be revised after https://github.com/elastic/kibana/issues/82851 is fixed + * For more background see: https://github.com/elastic/kibana/issues/107020 + */ +export const FLEET_ASSETS_TO_IGNORE = { + LOGS_INDEX_PATTERN: 'logs-*', + METRICS_INDEX_PATTERN: 'metrics-*', + LOGS_DATA_STREAM_TO_IGNORE: 'logs-elastic_agent', // ignore ds created by Fleet server itself + METRICS_DATA_STREAM_TO_IGNORE: 'metrics-elastic_agent', // ignore ds created by Fleet server itself + METRICS_ENDPOINT_INDEX_TO_IGNORE: 'metrics-endpoint.metadata_current_default', // ignore index created by Fleet endpoint package installed by default in Cloud +}; diff --git a/src/plugins/data/common/index_patterns/index_patterns/ensure_default_index_pattern.ts b/src/plugins/data/common/index_patterns/index_patterns/ensure_default_index_pattern.ts index 492c82a053c05..61ec1c5a4c090 100644 --- a/src/plugins/data/common/index_patterns/index_patterns/ensure_default_index_pattern.ts +++ b/src/plugins/data/common/index_patterns/index_patterns/ensure_default_index_pattern.ts @@ -35,8 +35,9 @@ export const createEnsureDefaultIndexPattern = ( return; } - // If there is any index pattern created, set the first as default - if (patterns.length >= 1) { + // If there is any user index pattern created, set the first as default + // if there is 0 patterns, then don't even call `hasUserIndexPattern()` + if (patterns.length >= 1 && (await this.hasUserIndexPattern().catch(() => true))) { defaultId = patterns[0]; await uiSettings.set('defaultIndex', defaultId); } else { 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 36dfb7fb9b021..19924caf5ed8e 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 @@ -236,6 +236,13 @@ export class IndexPatternsService { } }; + /** + * Checks if current user has a user created index pattern ignoring fleet's server default index patterns + */ + async hasUserIndexPattern(): Promise { + return this.apiClient.hasUserIndexPattern(); + } + /** * Get field list by providing { pattern } * @param options diff --git a/src/plugins/data/common/index_patterns/types.ts b/src/plugins/data/common/index_patterns/types.ts index 95cf294acedcd..5be2c5297adf9 100644 --- a/src/plugins/data/common/index_patterns/types.ts +++ b/src/plugins/data/common/index_patterns/types.ts @@ -147,6 +147,7 @@ export interface GetFieldsOptionsTimePattern { export interface IIndexPatternsApiClient { getFieldsForTimePattern: (options: GetFieldsOptionsTimePattern) => Promise; getFieldsForWildcard: (options: GetFieldsOptions) => Promise; + hasUserIndexPattern: () => Promise; } export type { SavedObject }; diff --git a/src/plugins/data/public/index_patterns/index_patterns/index_patterns_api_client.ts b/src/plugins/data/public/index_patterns/index_patterns/index_patterns_api_client.ts index 485f0079a0187..d4e8e06245114 100644 --- a/src/plugins/data/public/index_patterns/index_patterns/index_patterns_api_client.ts +++ b/src/plugins/data/public/index_patterns/index_patterns/index_patterns_api_client.ts @@ -23,7 +23,7 @@ export class IndexPatternsApiClient implements IIndexPatternsApiClient { this.http = http; } - private _request(url: string, query: any) { + private _request(url: string, query?: any) { return this.http .fetch(url, { query, @@ -62,4 +62,9 @@ export class IndexPatternsApiClient implements IIndexPatternsApiClient { allow_no_index: allowNoIndex, }).then((resp: any) => resp.fields || []); } + + async hasUserIndexPattern(): Promise { + const response = await this._request(this._getUrl(['has_user_index_pattern'])); + return response.result; + } } diff --git a/src/plugins/data/public/public.api.md b/src/plugins/data/public/public.api.md index 2f3df32cc6ff3..48264b300ad66 100644 --- a/src/plugins/data/public/public.api.md +++ b/src/plugins/data/public/public.api.md @@ -1485,6 +1485,7 @@ export class IndexPatternsService { getIds: (refresh?: boolean) => Promise; getIdsWithTitle: (refresh?: boolean) => Promise; getTitles: (refresh?: boolean) => Promise; + hasUserIndexPattern(): Promise; // (undocumented) migrate(indexPattern: IndexPattern, newTitle: string): Promise; refreshFields: (indexPattern: IndexPattern) => Promise; diff --git a/src/plugins/data/server/index_patterns/has_user_index_pattern.test.ts b/src/plugins/data/server/index_patterns/has_user_index_pattern.test.ts new file mode 100644 index 0000000000000..efc149b409375 --- /dev/null +++ b/src/plugins/data/server/index_patterns/has_user_index_pattern.test.ts @@ -0,0 +1,174 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { hasUserIndexPattern } from './has_user_index_pattern'; +import { elasticsearchServiceMock, savedObjectsClientMock } from '../../../../core/server/mocks'; + +describe('hasUserIndexPattern', () => { + const esClient = elasticsearchServiceMock.createScopedClusterClient().asCurrentUser; + const soClient = savedObjectsClientMock.create(); + + beforeEach(() => jest.resetAllMocks()); + + it('returns false when there are no index patterns', async () => { + soClient.find.mockResolvedValue({ + page: 1, + per_page: 100, + total: 0, + saved_objects: [], + }); + expect(await hasUserIndexPattern({ esClient, soClient })).toEqual(false); + }); + + it('returns true when there are any index patterns other than metrics-* or logs-*', async () => { + soClient.find.mockResolvedValue({ + page: 1, + per_page: 100, + total: 1, + saved_objects: [ + { + id: '1', + references: [], + type: 'index-pattern', + score: 99, + attributes: { title: 'my-pattern-*' }, + }, + ], + }); + expect(await hasUserIndexPattern({ esClient, soClient })).toEqual(true); + }); + + describe('when only metrics-* and logs-* index patterns exist', () => { + beforeEach(() => { + soClient.find.mockResolvedValue({ + page: 1, + per_page: 100, + total: 2, + saved_objects: [ + { + id: '1', + references: [], + type: 'index-pattern', + score: 99, + attributes: { title: 'metrics-*' }, + }, + { + id: '2', + references: [], + type: 'index-pattern', + score: 99, + attributes: { title: 'logs-*' }, + }, + ], + }); + }); + + it('calls indices.resolveIndex for the index patterns', async () => { + esClient.indices.resolveIndex.mockReturnValue( + elasticsearchServiceMock.createSuccessTransportRequestPromise({ + indices: [], + data_streams: [], + aliases: [], + }) + ); + await hasUserIndexPattern({ esClient, soClient }); + expect(esClient.indices.resolveIndex).toHaveBeenCalledWith({ + name: 'logs-*,metrics-*', + }); + }); + + it('returns false if no logs or metrics data_streams exist', async () => { + esClient.indices.resolveIndex.mockReturnValue( + elasticsearchServiceMock.createSuccessTransportRequestPromise({ + indices: [], + data_streams: [], + aliases: [], + }) + ); + expect(await hasUserIndexPattern({ esClient, soClient })).toEqual(false); + }); + + it('returns true if any index exists', async () => { + esClient.indices.resolveIndex.mockReturnValue( + elasticsearchServiceMock.createSuccessTransportRequestPromise({ + indices: [{ name: 'logs', attributes: [] }], + data_streams: [], + aliases: [], + }) + ); + expect(await hasUserIndexPattern({ esClient, soClient })).toEqual(true); + }); + + it('returns false if only metrics-elastic_agent data stream exists', async () => { + esClient.indices.resolveIndex.mockReturnValue( + elasticsearchServiceMock.createSuccessTransportRequestPromise({ + indices: [], + data_streams: [ + { + name: 'metrics-elastic_agent', + timestamp_field: '@timestamp', + backing_indices: ['.ds-metrics-elastic_agent'], + }, + ], + aliases: [], + }) + ); + expect(await hasUserIndexPattern({ esClient, soClient })).toEqual(false); + }); + + it('returns false if only logs-elastic_agent data stream exists', async () => { + esClient.indices.resolveIndex.mockReturnValue( + elasticsearchServiceMock.createSuccessTransportRequestPromise({ + indices: [], + data_streams: [ + { + name: 'logs-elastic_agent', + timestamp_field: '@timestamp', + backing_indices: ['.ds-logs-elastic_agent'], + }, + ], + aliases: [], + }) + ); + expect(await hasUserIndexPattern({ esClient, soClient })).toEqual(false); + }); + + it('returns false if only metrics-endpoint.metadata_current_default index exists', async () => { + esClient.indices.resolveIndex.mockReturnValue( + elasticsearchServiceMock.createSuccessTransportRequestPromise({ + indices: [ + { + name: 'metrics-endpoint.metadata_current_default', + attributes: ['open'], + }, + ], + aliases: [], + data_streams: [], + }) + ); + expect(await hasUserIndexPattern({ esClient, soClient })).toEqual(false); + }); + + it('returns true if any other data stream exists', async () => { + esClient.indices.resolveIndex.mockReturnValue( + elasticsearchServiceMock.createSuccessTransportRequestPromise({ + indices: [], + data_streams: [ + { + name: 'other', + timestamp_field: '@timestamp', + backing_indices: ['.ds-other'], + }, + ], + aliases: [], + }) + ); + expect(await hasUserIndexPattern({ esClient, soClient })).toEqual(true); + }); + }); +}); diff --git a/src/plugins/data/server/index_patterns/has_user_index_pattern.ts b/src/plugins/data/server/index_patterns/has_user_index_pattern.ts new file mode 100644 index 0000000000000..b65983a7fd5d4 --- /dev/null +++ b/src/plugins/data/server/index_patterns/has_user_index_pattern.ts @@ -0,0 +1,62 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { ElasticsearchClient, SavedObjectsClientContract } from '../../../../core/server'; +import { IndexPatternSavedObjectAttrs } from '../../common/index_patterns/index_patterns'; +import { FLEET_ASSETS_TO_IGNORE } from '../../common/index_patterns/constants'; + +interface Deps { + esClient: ElasticsearchClient; + soClient: SavedObjectsClientContract; +} + +export const hasUserIndexPattern = async ({ esClient, soClient }: Deps): Promise => { + const indexPatterns = await soClient.find({ + type: 'index-pattern', + fields: ['title'], + search: `*`, + searchFields: ['title'], + perPage: 100, + }); + + if (indexPatterns.total === 0) { + return false; + } + + // If there are any index patterns that are not the default metrics-* and logs-* ones created by Fleet, + // assume there are user created index patterns + if ( + indexPatterns.saved_objects.some( + (ip) => + ip.attributes.title !== FLEET_ASSETS_TO_IGNORE.METRICS_INDEX_PATTERN && + ip.attributes.title !== FLEET_ASSETS_TO_IGNORE.LOGS_INDEX_PATTERN + ) + ) { + return true; + } + + const resolveResponse = await esClient.indices.resolveIndex({ + name: `${FLEET_ASSETS_TO_IGNORE.LOGS_INDEX_PATTERN},${FLEET_ASSETS_TO_IGNORE.METRICS_INDEX_PATTERN}`, + }); + + const hasAnyNonDefaultFleetIndices = resolveResponse.body.indices.some( + (ds) => ds.name !== FLEET_ASSETS_TO_IGNORE.METRICS_ENDPOINT_INDEX_TO_IGNORE + ); + + if (hasAnyNonDefaultFleetIndices) return true; + + const hasAnyNonDefaultFleetDataStreams = resolveResponse.body.data_streams.some( + (ds) => + ds.name !== FLEET_ASSETS_TO_IGNORE.METRICS_DATA_STREAM_TO_IGNORE && + ds.name !== FLEET_ASSETS_TO_IGNORE.LOGS_DATA_STREAM_TO_IGNORE + ); + + if (hasAnyNonDefaultFleetDataStreams) return true; + + return false; +}; diff --git a/src/plugins/data/server/index_patterns/index_patterns_api_client.ts b/src/plugins/data/server/index_patterns/index_patterns_api_client.ts index 0ed84d4eee3b7..fb76647a945be 100644 --- a/src/plugins/data/server/index_patterns/index_patterns_api_client.ts +++ b/src/plugins/data/server/index_patterns/index_patterns_api_client.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { ElasticsearchClient } from 'kibana/server'; +import { ElasticsearchClient, SavedObjectsClientContract } from 'kibana/server'; import { GetFieldsOptions, IIndexPatternsApiClient, @@ -14,10 +14,14 @@ import { } from '../../common/index_patterns/types'; import { IndexPatternMissingIndices } from '../../common/index_patterns/lib'; import { IndexPatternsFetcher } from './fetcher'; +import { hasUserIndexPattern } from './has_user_index_pattern'; export class IndexPatternsApiServer implements IIndexPatternsApiClient { esClient: ElasticsearchClient; - constructor(elasticsearchClient: ElasticsearchClient) { + constructor( + elasticsearchClient: ElasticsearchClient, + private readonly savedObjectsClient: SavedObjectsClientContract + ) { this.esClient = elasticsearchClient; } async getFieldsForWildcard({ @@ -50,4 +54,11 @@ export class IndexPatternsApiServer implements IIndexPatternsApiClient { const indexPatterns = new IndexPatternsFetcher(this.esClient); return await indexPatterns.getFieldsForTimePattern(options); } + + async hasUserIndexPattern() { + return hasUserIndexPattern({ + esClient: this.esClient, + soClient: this.savedObjectsClient, + }); + } } diff --git a/src/plugins/data/server/index_patterns/index_patterns_service.ts b/src/plugins/data/server/index_patterns/index_patterns_service.ts index 89b5e130ec792..a6bed19a1e7e6 100644 --- a/src/plugins/data/server/index_patterns/index_patterns_service.ts +++ b/src/plugins/data/server/index_patterns/index_patterns_service.ts @@ -66,7 +66,7 @@ export const indexPatternsServiceFactory = ({ return new IndexPatternsCommonService({ uiSettings: new UiSettingsServerToCommon(uiSettingsClient), savedObjectsClient: new SavedObjectsClientServerToCommon(savedObjectsClient), - apiClient: new IndexPatternsApiServer(elasticsearchClient), + apiClient: new IndexPatternsApiServer(elasticsearchClient, savedObjectsClient), fieldFormats: formats, onError: (error) => { logger.error(error); diff --git a/src/plugins/data/server/index_patterns/routes.ts b/src/plugins/data/server/index_patterns/routes.ts index d2d8cb82cf646..32fa50940bca7 100644 --- a/src/plugins/data/server/index_patterns/routes.ts +++ b/src/plugins/data/server/index_patterns/routes.ts @@ -26,6 +26,7 @@ import { registerGetRuntimeFieldRoute } from './routes/runtime_fields/get_runtim import { registerDeleteRuntimeFieldRoute } from './routes/runtime_fields/delete_runtime_field'; import { registerPutRuntimeFieldRoute } from './routes/runtime_fields/put_runtime_field'; import { registerUpdateRuntimeFieldRoute } from './routes/runtime_fields/update_runtime_field'; +import { registerHasUserIndexPatternRoute } from './routes/has_user_index_pattern'; export function registerRoutes( http: HttpServiceSetup, @@ -49,6 +50,7 @@ export function registerRoutes( registerDeleteIndexPatternRoute(router, getStartServices); registerUpdateIndexPatternRoute(router, getStartServices); registerManageDefaultIndexPatternRoutes(router, getStartServices); + registerHasUserIndexPatternRoute(router, getStartServices); // Fields API registerUpdateFieldsRoute(router, getStartServices); diff --git a/src/plugins/data/server/index_patterns/routes/has_user_index_pattern.ts b/src/plugins/data/server/index_patterns/routes/has_user_index_pattern.ts new file mode 100644 index 0000000000000..6447f50f88f26 --- /dev/null +++ b/src/plugins/data/server/index_patterns/routes/has_user_index_pattern.ts @@ -0,0 +1,40 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { handleErrors } from './util/handle_errors'; +import { IRouter, StartServicesAccessor } from '../../../../../core/server'; +import type { DataPluginStart, DataPluginStartDependencies } from '../../plugin'; + +export const registerHasUserIndexPatternRoute = ( + router: IRouter, + getStartServices: StartServicesAccessor +) => { + router.get( + { + path: '/api/index_patterns/has_user_index_pattern', + validate: {}, + }, + router.handleLegacyErrors( + handleErrors(async (ctx, req, res) => { + const savedObjectsClient = ctx.core.savedObjects.client; + const elasticsearchClient = ctx.core.elasticsearch.client.asCurrentUser; + const [, , { indexPatterns }] = await getStartServices(); + const indexPatternsService = await indexPatterns.indexPatternsServiceFactory( + savedObjectsClient, + elasticsearchClient + ); + + return res.ok({ + body: { + result: await indexPatternsService.hasUserIndexPattern(), + }, + }); + }) + ) + ); +}; diff --git a/src/plugins/data/server/server.api.md b/src/plugins/data/server/server.api.md index aa3fd2ebf67a6..c2e9d9b16d87b 100644 --- a/src/plugins/data/server/server.api.md +++ b/src/plugins/data/server/server.api.md @@ -532,6 +532,7 @@ class IndexPatternsService { // Warning: (ae-forgotten-export) The symbol "IndexPatternListItem" needs to be exported by the entry point index.d.ts getIdsWithTitle: (refresh?: boolean) => Promise; getTitles: (refresh?: boolean) => Promise; + hasUserIndexPattern(): Promise; // (undocumented) migrate(indexPattern: IndexPattern, newTitle: string): Promise; refreshFields: (indexPattern: IndexPattern) => Promise; diff --git a/src/plugins/index_pattern_editor/public/components/empty_prompts/empty_prompts.test.tsx b/src/plugins/index_pattern_editor/public/components/empty_prompts/empty_prompts.test.tsx new file mode 100644 index 0000000000000..03902792371e7 --- /dev/null +++ b/src/plugins/index_pattern_editor/public/components/empty_prompts/empty_prompts.test.tsx @@ -0,0 +1,98 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { isUserDataIndex } from './empty_prompts'; +import { MatchedItem, ResolveIndexResponseItemIndexAttrs } from '../../types'; + +describe('isUserDataIndex', () => { + test('system index is not data index', () => { + const systemIndexes: MatchedItem[] = [ + { + name: '.apm-agent-configuration', + tags: [ + { + key: 'index', + name: 'Index', + color: 'default', + }, + ], + item: { + name: '.apm-agent-configuration', + attributes: [ResolveIndexResponseItemIndexAttrs.OPEN], + }, + }, + { + name: '.kibana', + tags: [ + { + key: 'alias', + name: 'Alias', + color: 'default', + }, + ], + item: { + name: '.kibana', + indices: ['.kibana_8.0.0_001'], + }, + }, + ]; + + expect(systemIndexes.some(isUserDataIndex)).toBe(false); + }); + + test('data index is data index', () => { + const dataIndex: MatchedItem = { + name: 'kibana_sample_data_ecommerce', + tags: [ + { + key: 'index', + name: 'Index', + color: 'default', + }, + ], + item: { + name: 'kibana_sample_data_ecommerce', + attributes: [ResolveIndexResponseItemIndexAttrs.OPEN], + }, + }; + + expect(isUserDataIndex(dataIndex)).toBe(true); + }); + + test('fleet asset is not data index', () => { + const fleetAssetIndex: MatchedItem = { + name: 'logs-elastic_agent', + tags: [ + { + key: 'data_stream', + name: 'Data stream', + color: 'primary', + }, + ], + item: { + name: 'logs-elastic_agent', + backing_indices: ['.ds-logs-elastic_agent-2021.08.18-000001'], + timestamp_field: '@timestamp', + }, + }; + + expect(isUserDataIndex(fleetAssetIndex)).toBe(false); + }); + + test('metrics-endpoint.metadata_current_default is not data index', () => { + const fleetAssetIndex: MatchedItem = { + name: 'metrics-endpoint.metadata_current_default', + tags: [{ key: 'index', name: 'Index', color: 'default' }], + item: { + name: 'metrics-endpoint.metadata_current_default', + attributes: [ResolveIndexResponseItemIndexAttrs.OPEN], + }, + }; + expect(isUserDataIndex(fleetAssetIndex)).toBe(false); + }); +}); diff --git a/src/plugins/index_pattern_editor/public/components/empty_prompts/empty_prompts.tsx b/src/plugins/index_pattern_editor/public/components/empty_prompts/empty_prompts.tsx index 80224dbfb673f..2f1631694e952 100644 --- a/src/plugins/index_pattern_editor/public/components/empty_prompts/empty_prompts.tsx +++ b/src/plugins/index_pattern_editor/public/components/empty_prompts/empty_prompts.tsx @@ -7,6 +7,7 @@ */ import React, { useState, useCallback, FC } from 'react'; +import useAsync from 'react-use/lib/useAsync'; import { useKibana } from '../../shared_imports'; @@ -17,6 +18,7 @@ import { getIndices } from '../../lib'; import { EmptyIndexListPrompt } from './empty_index_list_prompt'; import { EmptyIndexPatternPrompt } from './empty_index_pattern_prompt'; import { PromptFooter } from './prompt_footer'; +import { FLEET_ASSETS_TO_IGNORE } from '../../../../data/common'; const removeAliases = (item: MatchedItem) => !((item as unknown) as ResolveIndexResponseItemAlias).indices; @@ -24,25 +26,33 @@ const removeAliases = (item: MatchedItem) => interface Props { onCancel: () => void; allSources: MatchedItem[]; - hasExistingIndexPatterns: boolean; loadSources: () => void; } -export const EmptyPrompts: FC = ({ - hasExistingIndexPatterns, - allSources, - onCancel, - children, - loadSources, -}) => { +export function isUserDataIndex(source: MatchedItem) { + // filter out indices that start with `.` + if (source.name.startsWith('.')) return false; + + // filter out sources from FLEET_ASSETS_TO_IGNORE + if (source.name === FLEET_ASSETS_TO_IGNORE.LOGS_DATA_STREAM_TO_IGNORE) return false; + if (source.name === FLEET_ASSETS_TO_IGNORE.METRICS_DATA_STREAM_TO_IGNORE) return false; + if (source.name === FLEET_ASSETS_TO_IGNORE.METRICS_ENDPOINT_INDEX_TO_IGNORE) return false; + + return true; +} + +export const EmptyPrompts: FC = ({ allSources, onCancel, children, loadSources }) => { const { - services: { docLinks, application, http, searchClient }, + services: { docLinks, application, http, searchClient, indexPatternService }, } = useKibana(); const [remoteClustersExist, setRemoteClustersExist] = useState(false); const [goToForm, setGoToForm] = useState(false); - const hasDataIndices = allSources.some(({ name }: MatchedItem) => !name.startsWith('.')); + const hasDataIndices = allSources.some(isUserDataIndex); + const hasUserIndexPattern = useAsync(() => + indexPatternService.hasUserIndexPattern().catch(() => true) + ); useCallback(() => { let isMounted = true; @@ -63,7 +73,9 @@ export const EmptyPrompts: FC = ({ }; }, [http, hasDataIndices, searchClient]); - if (!hasExistingIndexPatterns && !goToForm) { + if (hasUserIndexPattern.loading) return null; // return null to prevent UI flickering while loading + + if (!hasUserIndexPattern.value && !goToForm) { if (!hasDataIndices && !remoteClustersExist) { // load data return ( diff --git a/src/plugins/index_pattern_editor/public/components/index_pattern_editor_flyout_content.tsx b/src/plugins/index_pattern_editor/public/components/index_pattern_editor_flyout_content.tsx index 4f6f7708d90c0..14e1da44c7a35 100644 --- a/src/plugins/index_pattern_editor/public/components/index_pattern_editor_flyout_content.tsx +++ b/src/plugins/index_pattern_editor/public/components/index_pattern_editor_flyout_content.tsx @@ -338,12 +338,7 @@ const IndexPatternEditorFlyoutContentComponent = ({ ); return ( - + diff --git a/src/plugins/index_pattern_management/public/components/index_pattern_table/index_pattern_table.tsx b/src/plugins/index_pattern_management/public/components/index_pattern_table/index_pattern_table.tsx index ef99be4df7cb8..0a436f1541613 100644 --- a/src/plugins/index_pattern_management/public/components/index_pattern_table/index_pattern_table.tsx +++ b/src/plugins/index_pattern_management/public/components/index_pattern_table/index_pattern_table.tsx @@ -81,7 +81,10 @@ export const IndexPatternTable = ({ ); setIndexPatterns(gettedIndexPatterns); setIsLoadingIndexPatterns(false); - if (gettedIndexPatterns.length === 0) { + if ( + gettedIndexPatterns.length === 0 || + !(await data.indexPatterns.hasUserIndexPattern().catch(() => false)) + ) { setShowCreateDialog(true); } })(); diff --git a/src/plugins/kibana_overview/public/components/overview/overview.tsx b/src/plugins/kibana_overview/public/components/overview/overview.tsx index b6d486a656860..68a469c753ce9 100644 --- a/src/plugins/kibana_overview/public/components/overview/overview.tsx +++ b/src/plugins/kibana_overview/public/components/overview/overview.tsx @@ -93,9 +93,9 @@ export const Overview: FC = ({ newsFetchResult, solutions, features }) => useEffect(() => { const fetchIsNewKibanaInstance = async () => { - const resp = await indexPatternService.getTitles(); + const hasUserIndexPattern = await indexPatternService.hasUserIndexPattern().catch(() => true); - setNewKibanaInstance(resp.length === 0); + setNewKibanaInstance(!hasUserIndexPattern); }; fetchIsNewKibanaInstance(); diff --git a/test/api_integration/apis/index_patterns/has_user_index_pattern/has_user_index_pattern.ts b/test/api_integration/apis/index_patterns/has_user_index_pattern/has_user_index_pattern.ts new file mode 100644 index 0000000000000..8dfb892acfd90 --- /dev/null +++ b/test/api_integration/apis/index_patterns/has_user_index_pattern/has_user_index_pattern.ts @@ -0,0 +1,139 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import expect from '@kbn/expect'; +import { FtrProviderContext } from '../../../ftr_provider_context'; + +export default function ({ getService }: FtrProviderContext) { + const supertest = getService('supertest'); + const esArchiver = getService('esArchiver'); + const es = getService('es'); + + describe('has user index pattern API', () => { + beforeEach(async () => { + await esArchiver.emptyKibanaIndex(); + if ((await es.indices.exists({ index: 'metrics-test' })).body) { + await es.indices.delete({ index: 'metrics-test' }); + } + + if ((await es.indices.exists({ index: 'logs-test' })).body) { + await es.indices.delete({ index: 'logs-test' }); + } + }); + + it('should return false if no index patterns', async () => { + const response = await supertest.get('/api/index_patterns/has_user_index_pattern'); + expect(response.status).to.be(200); + expect(response.body.result).to.be(false); + }); + + it('should return true if has index pattern with user data', async () => { + await esArchiver.load('test/api_integration/fixtures/es_archiver/index_patterns/basic_index'); + await supertest.post('/api/index_patterns/index_pattern').send({ + override: true, + index_pattern: { + title: 'basic_index', + }, + }); + + const response = await supertest.get('/api/index_patterns/has_user_index_pattern'); + expect(response.status).to.be(200); + expect(response.body.result).to.be(true); + + await esArchiver.unload( + 'test/api_integration/fixtures/es_archiver/index_patterns/basic_index' + ); + }); + + it('should return true if has user index pattern without data', async () => { + await supertest.post('/api/index_patterns/index_pattern').send({ + override: true, + index_pattern: { + title: 'basic_index', + allowNoIndex: true, + }, + }); + + const response = await supertest.get('/api/index_patterns/has_user_index_pattern'); + expect(response.status).to.be(200); + expect(response.body.result).to.be(true); + }); + + it('should return false if only metric-* index pattern without data', async () => { + await supertest.post('/api/index_patterns/index_pattern').send({ + override: true, + index_pattern: { + title: 'metrics-*', + allowNoIndex: true, + }, + }); + + const response = await supertest.get('/api/index_patterns/has_user_index_pattern'); + expect(response.status).to.be(200); + expect(response.body.result).to.be(false); + }); + + it('should return true if metric-* index pattern with user data', async () => { + await es.index({ + index: 'metrics-test', + body: { + foo: 'bar', + }, + }); + + await supertest.post('/api/index_patterns/index_pattern').send({ + override: true, + index_pattern: { + title: 'metrics-*', + }, + }); + + const response = await supertest.get('/api/index_patterns/has_user_index_pattern'); + expect(response.status).to.be(200); + expect(response.body.result).to.be(true); + }); + + it('should return false if only logs-* index pattern without data', async () => { + await supertest.post('/api/index_patterns/index_pattern').send({ + override: true, + index_pattern: { + title: 'logs-*', + }, + }); + + const response = await supertest.get('/api/index_patterns/has_user_index_pattern'); + expect(response.status).to.be(200); + expect(response.body.result).to.be(false); + }); + + it('should return true if logs-* index pattern with user data', async () => { + await es.index({ + index: 'logs-test', + body: { + foo: 'bar', + }, + }); + + await supertest.post('/api/index_patterns/index_pattern').send({ + override: true, + index_pattern: { + title: 'logs-*', + }, + }); + + const response = await supertest.get('/api/index_patterns/has_user_index_pattern'); + expect(response.status).to.be(200); + expect(response.body.result).to.be(true); + }); + + // TODO: should setup fleet first similar to x-pack/test/fleet_functional/apps/home/welcome.ts + // but it is skipped due to flakiness https://github.com/elastic/kibana/issues/109017 + it('should return false if logs-* with .ds-logs-elastic_agent only'); + it('should return false if metrics-* with .ds-metrics-elastic_agent only'); + }); +} diff --git a/test/api_integration/apis/index_patterns/has_user_index_pattern/index.ts b/test/api_integration/apis/index_patterns/has_user_index_pattern/index.ts new file mode 100644 index 0000000000000..5c05467d15c3f --- /dev/null +++ b/test/api_integration/apis/index_patterns/has_user_index_pattern/index.ts @@ -0,0 +1,15 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { FtrProviderContext } from '../../../ftr_provider_context'; + +export default function ({ loadTestFile }: FtrProviderContext) { + describe('has user index pattern', () => { + loadTestFile(require.resolve('./has_user_index_pattern')); + }); +} diff --git a/test/api_integration/apis/index_patterns/index.js b/test/api_integration/apis/index_patterns/index.js index 3dbe01206afa3..b34012e362cbf 100644 --- a/test/api_integration/apis/index_patterns/index.js +++ b/test/api_integration/apis/index_patterns/index.js @@ -18,5 +18,6 @@ export default function ({ loadTestFile }) { loadTestFile(require.resolve('./runtime_fields_crud')); loadTestFile(require.resolve('./integration')); loadTestFile(require.resolve('./deprecations')); + loadTestFile(require.resolve('./has_user_index_pattern')); }); } From 3b97a965ed2c036d4a8cc41ee2c1338b07bbe5c8 Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Sat, 21 Aug 2021 07:08:43 -0400 Subject: [PATCH 56/76] [ML] Functional tests - re-enable modules API test suite (#109471) (#109574) https://kibana-ci.elastic.co/job/kibana+flaky-test-suite-runner/1839/ Co-authored-by: Robert Oskamp --- x-pack/test/api_integration/apis/ml/modules/index.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/x-pack/test/api_integration/apis/ml/modules/index.ts b/x-pack/test/api_integration/apis/ml/modules/index.ts index ffb1a14a18469..c6a75eccfa4c8 100644 --- a/x-pack/test/api_integration/apis/ml/modules/index.ts +++ b/x-pack/test/api_integration/apis/ml/modules/index.ts @@ -14,8 +14,7 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) { const fleetPackages = ['apache', 'nginx']; - // FLAKY: https://github.com/elastic/kibana/issues/102282 - describe.skip('modules', function () { + describe('modules', function () { before(async () => { // use empty_kibana to make sure the fleet setup is removed correctly after the tests await esArchiver.load('x-pack/test/functional/es_archives/empty_kibana'); From dd45adeacc8534d73f824a3b8cc3a6a39740f5a9 Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Mon, 23 Aug 2021 00:08:19 +0100 Subject: [PATCH 57/76] skip flaky suite (#106650) --- x-pack/test/functional/apps/infra/home_page.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/test/functional/apps/infra/home_page.ts b/x-pack/test/functional/apps/infra/home_page.ts index e344f86f89fe8..255f2c49e5621 100644 --- a/x-pack/test/functional/apps/infra/home_page.ts +++ b/x-pack/test/functional/apps/infra/home_page.ts @@ -87,7 +87,8 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { }); }); - describe('Saved Views', () => { + // FLAKY: https://github.com/elastic/kibana/issues/106650 + describe.skip('Saved Views', () => { before(() => esArchiver.load('x-pack/test/functional/es_archives/infra/metrics_and_logs')); after(() => esArchiver.unload('x-pack/test/functional/es_archives/infra/metrics_and_logs')); it('should have save and load controls', async () => { From e31d32ae14ddf3b3fb9fc6f629d685ed18700135 Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Mon, 23 Aug 2021 00:21:24 +0100 Subject: [PATCH 58/76] skip failing es promotion suites (#109583) --- .../tests/correlations/latency_slow_transactions.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/test/apm_api_integration/tests/correlations/latency_slow_transactions.ts b/x-pack/test/apm_api_integration/tests/correlations/latency_slow_transactions.ts index fc56615b3b13a..dac9ed70bc483 100644 --- a/x-pack/test/apm_api_integration/tests/correlations/latency_slow_transactions.ts +++ b/x-pack/test/apm_api_integration/tests/correlations/latency_slow_transactions.ts @@ -43,7 +43,8 @@ export default function ApiTest({ getService }: FtrProviderContext) { } ); - registry.when( + // FAILING ES PROMOTION: https://github.com/elastic/kibana/issues/109583 + registry.when.skip( 'correlations latency slow transactions with data and default args', { config: 'trial', archives: ['apm_8.0.0'] }, () => { From f4b98a09dbf3d270ce360318f15047cf1bf0a30f Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Mon, 23 Aug 2021 02:24:55 -0400 Subject: [PATCH 59/76] Fix grammar on stack monitoring alerts modal (#109360) (#109585) Pretty sure the rules only get created in the current kibana space, but the message is plural. Switching to singular. Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Mat Schaffer --- docs/user/monitoring/kibana-alerts.asciidoc | 2 +- x-pack/plugins/monitoring/public/alerts/enable_alerts_modal.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/user/monitoring/kibana-alerts.asciidoc b/docs/user/monitoring/kibana-alerts.asciidoc index f00a3999ab277..64ba8bf044e4f 100644 --- a/docs/user/monitoring/kibana-alerts.asciidoc +++ b/docs/user/monitoring/kibana-alerts.asciidoc @@ -124,7 +124,7 @@ valid for 30 days. == Alerts and rules [discrete] === Create default rules -This option can be used to create default rules in this kibana spaces. This is +This option can be used to create default rules in this kibana space. This is useful for scenarios when you didn't choose to create these default rules initially or anytime later if the rules were accidentally deleted. diff --git a/x-pack/plugins/monitoring/public/alerts/enable_alerts_modal.tsx b/x-pack/plugins/monitoring/public/alerts/enable_alerts_modal.tsx index 827ce958deb11..780997ca98191 100644 --- a/x-pack/plugins/monitoring/public/alerts/enable_alerts_modal.tsx +++ b/x-pack/plugins/monitoring/public/alerts/enable_alerts_modal.tsx @@ -42,7 +42,7 @@ export const EnableAlertsModal: React.FC = ({ alerts }: Props) => { { id: 'create-alerts', label: i18n.translate('xpack.monitoring.alerts.modal.yesOption', { - defaultMessage: 'Yes (Recommended - create default rules in this kibana spaces)', + defaultMessage: 'Yes (Recommended - create default rules in this kibana space)', }), }, { From f4f5a7035af58ec7599fde88cdcf44438e05eef1 Mon Sep 17 00:00:00 2001 From: Matthias Wilhelm Date: Mon, 23 Aug 2021 11:41:49 +0200 Subject: [PATCH 60/76] [Discover] Unskip discover tab field data functional tests (#107305) (#109589) --- test/functional/apps/discover/_data_grid.ts | 4 +-- .../apps/discover/_data_grid_doc_table.ts | 2 +- test/functional/apps/discover/_discover.ts | 2 +- test/functional/apps/discover/_doc_table.ts | 2 +- test/functional/apps/discover/_field_data.ts | 3 +- .../discover/_field_data_with_fields_api.ts | 3 +- test/functional/page_objects/discover_page.ts | 30 ++++++++++++++++--- 7 files changed, 33 insertions(+), 13 deletions(-) diff --git a/test/functional/apps/discover/_data_grid.ts b/test/functional/apps/discover/_data_grid.ts index efd97fce3f7f5..4a343fb30384e 100644 --- a/test/functional/apps/discover/_data_grid.ts +++ b/test/functional/apps/discover/_data_grid.ts @@ -47,10 +47,10 @@ export default function ({ await PageObjects.discover.clickFieldListItemAdd('agent'); expect(await getTitles()).to.be('Time (@timestamp) bytes agent'); - await PageObjects.discover.clickFieldListItemAdd('bytes'); + await PageObjects.discover.clickFieldListItemRemove('bytes'); expect(await getTitles()).to.be('Time (@timestamp) agent'); - await PageObjects.discover.clickFieldListItemAdd('agent'); + await PageObjects.discover.clickFieldListItemRemove('agent'); expect(await getTitles()).to.be('Time (@timestamp) Document'); }); }); diff --git a/test/functional/apps/discover/_data_grid_doc_table.ts b/test/functional/apps/discover/_data_grid_doc_table.ts index ec5a51c55265b..9ae6a9086f819 100644 --- a/test/functional/apps/discover/_data_grid_doc_table.ts +++ b/test/functional/apps/discover/_data_grid_doc_table.ts @@ -162,7 +162,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await PageObjects.header.waitUntilLoadingHasFinished(); } // remove the second column - await PageObjects.discover.clickFieldListItemAdd(extraColumns[1]); + await PageObjects.discover.clickFieldListItemRemove(extraColumns[1]); await PageObjects.header.waitUntilLoadingHasFinished(); // test that the second column is no longer there const header = await dataGrid.getHeaderFields(); diff --git a/test/functional/apps/discover/_discover.ts b/test/functional/apps/discover/_discover.ts index 7c97220f36949..87960d1b6a966 100644 --- a/test/functional/apps/discover/_discover.ts +++ b/test/functional/apps/discover/_discover.ts @@ -336,7 +336,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await PageObjects.discover.clickFieldSort('_score', 'Sort Low-High'); const currentUrlWithScore = await browser.getCurrentUrl(); expect(currentUrlWithScore).to.contain('_score'); - await PageObjects.discover.clickFieldListItemAdd('_score'); + await PageObjects.discover.clickFieldListItemRemove('_score'); const currentUrlWithoutScore = await browser.getCurrentUrl(); expect(currentUrlWithoutScore).not.to.contain('_score'); }); diff --git a/test/functional/apps/discover/_doc_table.ts b/test/functional/apps/discover/_doc_table.ts index 09a162e051bf6..f01d6b18fbf01 100644 --- a/test/functional/apps/discover/_doc_table.ts +++ b/test/functional/apps/discover/_doc_table.ts @@ -218,7 +218,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await PageObjects.header.waitUntilLoadingHasFinished(); } // remove the second column - await PageObjects.discover.clickFieldListItemAdd(extraColumns[1]); + await PageObjects.discover.clickFieldListItemRemove(extraColumns[1]); await PageObjects.header.waitUntilLoadingHasFinished(); // test that the second column is no longer there const docHeader = await find.byCssSelector('thead > tr:nth-child(1)'); diff --git a/test/functional/apps/discover/_field_data.ts b/test/functional/apps/discover/_field_data.ts index fc0c0c6a48649..27407e9a0bc4d 100644 --- a/test/functional/apps/discover/_field_data.ts +++ b/test/functional/apps/discover/_field_data.ts @@ -34,8 +34,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await PageObjects.timePicker.setDefaultAbsoluteRangeViaUiSettings(); await PageObjects.common.navigateToApp('discover'); }); - // FLAKY: https://github.com/elastic/kibana/issues/100437 - describe.skip('field data', function () { + describe('field data', function () { it('search php should show the correct hit count', async function () { const expectedHitCount = '445'; await retry.try(async function () { diff --git a/test/functional/apps/discover/_field_data_with_fields_api.ts b/test/functional/apps/discover/_field_data_with_fields_api.ts index 97c1e678c4a9f..666377ae7f794 100644 --- a/test/functional/apps/discover/_field_data_with_fields_api.ts +++ b/test/functional/apps/discover/_field_data_with_fields_api.ts @@ -34,8 +34,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await PageObjects.timePicker.setDefaultAbsoluteRangeViaUiSettings(); await PageObjects.common.navigateToApp('discover'); }); - // FLAKY: https://github.com/elastic/kibana/issues/103389 - describe.skip('field data', function () { + describe('field data', function () { it('search php should show the correct hit count', async function () { const expectedHitCount = '445'; await retry.try(async function () { diff --git a/test/functional/page_objects/discover_page.ts b/test/functional/page_objects/discover_page.ts index 9ffb206760867..b964566b06927 100644 --- a/test/functional/page_objects/discover_page.ts +++ b/test/functional/page_objects/discover_page.ts @@ -360,17 +360,39 @@ export class DiscoverPageObject extends FtrService { public async clickFieldListItemAdd(field: string) { // a filter check may make sense here, but it should be properly handled to make // it work with the _score and _source fields as well + if (await this.isFieldSelected(field)) { + return; + } await this.clickFieldListItemToggle(field); + const isLegacyDefault = await this.useLegacyTable(); + if (isLegacyDefault) { + await this.retry.waitFor(`field ${field} to be added to classic table`, async () => { + return await this.testSubjects.exists(`docTableHeader-${field}`); + }); + } else { + await this.retry.waitFor(`field ${field} to be added to new table`, async () => { + return await this.testSubjects.exists(`dataGridHeaderCell-${field}`); + }); + } } - public async clickFieldListItemRemove(field: string) { + public async isFieldSelected(field: string) { if (!(await this.testSubjects.exists('fieldList-selected'))) { - return; + return false; } const selectedList = await this.testSubjects.find('fieldList-selected'); - if (await this.testSubjects.descendantExists(`field-${field}`, selectedList)) { - await this.clickFieldListItemToggle(field); + return await this.testSubjects.descendantExists(`field-${field}`, selectedList); + } + + public async clickFieldListItemRemove(field: string) { + if ( + !(await this.testSubjects.exists('fieldList-selected')) || + !(await this.isFieldSelected(field)) + ) { + return; } + + await this.clickFieldListItemToggle(field); } public async clickFieldListItemVisualize(fieldName: string) { From 171f6559a183183bee518e1939df25af88532b68 Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Mon, 23 Aug 2021 08:16:58 -0400 Subject: [PATCH 61/76] [Flaky test] Application Usage: Wait for chrome to visible (#109405) (#109600) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Alejandro Fernández Haro --- .../test_suites/application_usage/index.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/x-pack/test/usage_collection/test_suites/application_usage/index.ts b/x-pack/test/usage_collection/test_suites/application_usage/index.ts index 43d7714dfea1d..fc53c8ddf5ed3 100644 --- a/x-pack/test/usage_collection/test_suites/application_usage/index.ts +++ b/x-pack/test/usage_collection/test_suites/application_usage/index.ts @@ -16,8 +16,14 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const browser = getService('browser'); it('keys in the schema match the registered application IDs', async () => { - await common.navigateToApp('home'); // Navigate to Home to make sure all the appIds are loaded + await common.navigateToApp('home'); // Navigate to Home + await common.isChromeVisible(); // Make sure the page is fully loaded const appIds = await browser.execute(() => window.__applicationIds__); + if (!appIds || !Array.isArray(appIds)) { + throw new Error( + 'Failed to retrieve all the existing applications in Kibana. Did it fail to boot or to navigate to home?' + ); + } try { expect(Object.keys(applicationUsageSchema).sort()).to.eql(appIds.sort()); } catch (err) { From d17d2e7cea5c505d64ade4cdd6ee75bbc106e52c Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Mon, 23 Aug 2021 08:22:55 -0400 Subject: [PATCH 62/76] Add multiple namespaces support to PIT search and finder (#109062) (#109603) * initial modifications * change approach for openPointInTime and add tests for spaces wrapper changes * fix and add security wrapper tests * fix export security FTR tests * update generated doc * add tests for PIT finder * NIT * improve doc * nits Co-authored-by: Pierre Gayvallet --- ...rver.savedobjectsopenpointintimeoptions.md | 3 +- ...bjectsopenpointintimeoptions.namespaces.md | 15 ++ .../service/lib/point_in_time_finder.test.ts | 222 +++++++++--------- .../service/lib/point_in_time_finder.ts | 4 +- .../service/saved_objects_client.ts | 11 +- src/core/server/server.api.md | 3 +- ...ecure_saved_objects_client_wrapper.test.ts | 116 +++++++-- .../secure_saved_objects_client_wrapper.ts | 31 +-- .../spaces_saved_objects_client.test.ts | 85 ++++++- .../spaces_saved_objects_client.ts | 63 ++--- .../common/suites/export.ts | 12 +- .../security_and_spaces/apis/export.ts | 2 +- .../security_only/apis/export.ts | 2 +- 13 files changed, 384 insertions(+), 185 deletions(-) create mode 100644 docs/development/core/server/kibana-plugin-core-server.savedobjectsopenpointintimeoptions.namespaces.md diff --git a/docs/development/core/server/kibana-plugin-core-server.savedobjectsopenpointintimeoptions.md b/docs/development/core/server/kibana-plugin-core-server.savedobjectsopenpointintimeoptions.md index 46516be2329e9..fc825e3bf2937 100644 --- a/docs/development/core/server/kibana-plugin-core-server.savedobjectsopenpointintimeoptions.md +++ b/docs/development/core/server/kibana-plugin-core-server.savedobjectsopenpointintimeoptions.md @@ -8,7 +8,7 @@ Signature: ```typescript -export interface SavedObjectsOpenPointInTimeOptions extends SavedObjectsBaseOptions +export interface SavedObjectsOpenPointInTimeOptions ``` ## Properties @@ -16,5 +16,6 @@ export interface SavedObjectsOpenPointInTimeOptions extends SavedObjectsBaseOpti | Property | Type | Description | | --- | --- | --- | | [keepAlive](./kibana-plugin-core-server.savedobjectsopenpointintimeoptions.keepalive.md) | string | Optionally specify how long ES should keep the PIT alive until the next request. Defaults to 5m. | +| [namespaces](./kibana-plugin-core-server.savedobjectsopenpointintimeoptions.namespaces.md) | string[] | An optional list of namespaces to be used when opening the PIT.When the spaces plugin is enabled: - this will default to the user's current space (as determined by the URL) - if specified, the user's current space will be ignored - ['*'] will search across all available spaces | | [preference](./kibana-plugin-core-server.savedobjectsopenpointintimeoptions.preference.md) | string | An optional ES preference value to be used for the query. | diff --git a/docs/development/core/server/kibana-plugin-core-server.savedobjectsopenpointintimeoptions.namespaces.md b/docs/development/core/server/kibana-plugin-core-server.savedobjectsopenpointintimeoptions.namespaces.md new file mode 100644 index 0000000000000..06fb7519d52c2 --- /dev/null +++ b/docs/development/core/server/kibana-plugin-core-server.savedobjectsopenpointintimeoptions.namespaces.md @@ -0,0 +1,15 @@ + + +[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [SavedObjectsOpenPointInTimeOptions](./kibana-plugin-core-server.savedobjectsopenpointintimeoptions.md) > [namespaces](./kibana-plugin-core-server.savedobjectsopenpointintimeoptions.namespaces.md) + +## SavedObjectsOpenPointInTimeOptions.namespaces property + +An optional list of namespaces to be used when opening the PIT. + +When the spaces plugin is enabled: - this will default to the user's current space (as determined by the URL) - if specified, the user's current space will be ignored - `['*']` will search across all available spaces + +Signature: + +```typescript +namespaces?: string[]; +``` diff --git a/src/core/server/saved_objects/service/lib/point_in_time_finder.test.ts b/src/core/server/saved_objects/service/lib/point_in_time_finder.test.ts index 044bb45269538..160852f9160b7 100644 --- a/src/core/server/saved_objects/service/lib/point_in_time_finder.test.ts +++ b/src/core/server/saved_objects/service/lib/point_in_time_finder.test.ts @@ -7,7 +7,6 @@ */ import { loggerMock, MockedLogger } from '../../../logging/logger.mock'; -import type { SavedObjectsClientContract } from '../../types'; import type { SavedObjectsFindResult } from '../'; import { savedObjectsRepositoryMock } from './repository.mock'; @@ -43,37 +42,67 @@ const mockHits = [ describe('createPointInTimeFinder()', () => { let logger: MockedLogger; - let find: jest.Mocked['find']; - let openPointInTimeForType: jest.Mocked['openPointInTimeForType']; - let closePointInTime: jest.Mocked['closePointInTime']; + let repository: ReturnType; beforeEach(() => { logger = loggerMock.create(); - const mockRepository = savedObjectsRepositoryMock.create(); - find = mockRepository.find; - openPointInTimeForType = mockRepository.openPointInTimeForType; - closePointInTime = mockRepository.closePointInTime; + repository = savedObjectsRepositoryMock.create(); }); describe('#find', () => { - test('throws if a PIT is already open', async () => { - openPointInTimeForType.mockResolvedValueOnce({ + test('opens a PIT with the correct parameters', async () => { + repository.openPointInTimeForType.mockResolvedValueOnce({ id: 'abc123', }); - find.mockResolvedValueOnce({ + repository.find.mockResolvedValue({ total: 2, saved_objects: mockHits, pit_id: 'abc123', per_page: 1, page: 0, }); - find.mockResolvedValueOnce({ - total: 2, - saved_objects: mockHits, - pit_id: 'abc123', - per_page: 1, - page: 1, + + const findOptions: SavedObjectsCreatePointInTimeFinderOptions = { + type: ['visualization'], + search: 'foo*', + perPage: 1, + namespaces: ['ns1', 'ns2'], + }; + + const finder = new PointInTimeFinder(findOptions, { + logger, + client: repository, + }); + + expect(repository.openPointInTimeForType).not.toHaveBeenCalled(); + + await finder.find().next(); + + expect(repository.openPointInTimeForType).toHaveBeenCalledTimes(1); + expect(repository.openPointInTimeForType).toHaveBeenCalledWith(findOptions.type, { + namespaces: findOptions.namespaces, }); + }); + + test('throws if a PIT is already open', async () => { + repository.openPointInTimeForType.mockResolvedValueOnce({ + id: 'abc123', + }); + repository.find + .mockResolvedValueOnce({ + total: 2, + saved_objects: mockHits, + pit_id: 'abc123', + per_page: 1, + page: 0, + }) + .mockResolvedValueOnce({ + total: 2, + saved_objects: mockHits, + pit_id: 'abc123', + per_page: 1, + page: 1, + }); const findOptions: SavedObjectsCreatePointInTimeFinderOptions = { type: ['visualization'], @@ -83,30 +112,25 @@ describe('createPointInTimeFinder()', () => { const finder = new PointInTimeFinder(findOptions, { logger, - client: { - find, - openPointInTimeForType, - closePointInTime, - }, + client: repository, }); await finder.find().next(); - expect(find).toHaveBeenCalledTimes(1); - find.mockClear(); + expect(repository.find).toHaveBeenCalledTimes(1); expect(async () => { await finder.find().next(); }).rejects.toThrowErrorMatchingInlineSnapshot( `"Point In Time has already been opened for this finder instance. Please call \`close()\` before calling \`find()\` again."` ); - expect(find).toHaveBeenCalledTimes(0); + expect(repository.find).toHaveBeenCalledTimes(1); }); test('works with a single page of results', async () => { - openPointInTimeForType.mockResolvedValueOnce({ + repository.openPointInTimeForType.mockResolvedValueOnce({ id: 'abc123', }); - find.mockResolvedValueOnce({ + repository.find.mockResolvedValueOnce({ total: 2, saved_objects: mockHits, pit_id: 'abc123', @@ -121,11 +145,7 @@ describe('createPointInTimeFinder()', () => { const finder = new PointInTimeFinder(findOptions, { logger, - client: { - find, - openPointInTimeForType, - closePointInTime, - }, + client: repository, }); const hits: SavedObjectsFindResult[] = []; for await (const result of finder.find()) { @@ -133,10 +153,10 @@ describe('createPointInTimeFinder()', () => { } expect(hits.length).toBe(2); - expect(openPointInTimeForType).toHaveBeenCalledTimes(1); - expect(closePointInTime).toHaveBeenCalledTimes(1); - expect(find).toHaveBeenCalledTimes(1); - expect(find).toHaveBeenCalledWith( + expect(repository.openPointInTimeForType).toHaveBeenCalledTimes(1); + expect(repository.closePointInTime).toHaveBeenCalledTimes(1); + expect(repository.find).toHaveBeenCalledTimes(1); + expect(repository.find).toHaveBeenCalledWith( expect.objectContaining({ pit: expect.objectContaining({ id: 'abc123', keepAlive: '2m' }), sortField: 'updated_at', @@ -147,24 +167,25 @@ describe('createPointInTimeFinder()', () => { }); test('works with multiple pages of results', async () => { - openPointInTimeForType.mockResolvedValueOnce({ + repository.openPointInTimeForType.mockResolvedValueOnce({ id: 'abc123', }); - find.mockResolvedValueOnce({ - total: 2, - saved_objects: [mockHits[0]], - pit_id: 'abc123', - per_page: 1, - page: 0, - }); - find.mockResolvedValueOnce({ - total: 2, - saved_objects: [mockHits[1]], - pit_id: 'abc123', - per_page: 1, - page: 0, - }); - find.mockResolvedValueOnce({ + repository.find + .mockResolvedValueOnce({ + total: 2, + saved_objects: [mockHits[0]], + pit_id: 'abc123', + per_page: 1, + page: 0, + }) + .mockResolvedValueOnce({ + total: 2, + saved_objects: [mockHits[1]], + pit_id: 'abc123', + per_page: 1, + page: 0, + }); + repository.find.mockResolvedValueOnce({ total: 2, saved_objects: [], per_page: 1, @@ -180,11 +201,7 @@ describe('createPointInTimeFinder()', () => { const finder = new PointInTimeFinder(findOptions, { logger, - client: { - find, - openPointInTimeForType, - closePointInTime, - }, + client: repository, }); const hits: SavedObjectsFindResult[] = []; for await (const result of finder.find()) { @@ -192,12 +209,12 @@ describe('createPointInTimeFinder()', () => { } expect(hits.length).toBe(2); - expect(openPointInTimeForType).toHaveBeenCalledTimes(1); - expect(closePointInTime).toHaveBeenCalledTimes(1); + expect(repository.openPointInTimeForType).toHaveBeenCalledTimes(1); + expect(repository.closePointInTime).toHaveBeenCalledTimes(1); // called 3 times since we need a 3rd request to check if we // are done paginating through results. - expect(find).toHaveBeenCalledTimes(3); - expect(find).toHaveBeenCalledWith( + expect(repository.find).toHaveBeenCalledTimes(3); + expect(repository.find).toHaveBeenCalledWith( expect.objectContaining({ pit: expect.objectContaining({ id: 'abc123', keepAlive: '2m' }), sortField: 'updated_at', @@ -210,10 +227,10 @@ describe('createPointInTimeFinder()', () => { describe('#close', () => { test('calls closePointInTime with correct ID', async () => { - openPointInTimeForType.mockResolvedValueOnce({ + repository.openPointInTimeForType.mockResolvedValueOnce({ id: 'test', }); - find.mockResolvedValueOnce({ + repository.find.mockResolvedValueOnce({ total: 1, saved_objects: [mockHits[0]], pit_id: 'test', @@ -229,11 +246,7 @@ describe('createPointInTimeFinder()', () => { const finder = new PointInTimeFinder(findOptions, { logger, - client: { - find, - openPointInTimeForType, - closePointInTime, - }, + client: repository, }); const hits: SavedObjectsFindResult[] = []; for await (const result of finder.find()) { @@ -241,28 +254,28 @@ describe('createPointInTimeFinder()', () => { await finder.close(); } - expect(closePointInTime).toHaveBeenCalledWith('test'); + expect(repository.closePointInTime).toHaveBeenCalledWith('test'); }); test('causes generator to stop', async () => { - openPointInTimeForType.mockResolvedValueOnce({ + repository.openPointInTimeForType.mockResolvedValueOnce({ id: 'test', }); - find.mockResolvedValueOnce({ + repository.find.mockResolvedValueOnce({ total: 2, saved_objects: [mockHits[0]], pit_id: 'test', per_page: 1, page: 0, }); - find.mockResolvedValueOnce({ + repository.find.mockResolvedValueOnce({ total: 2, saved_objects: [mockHits[1]], pit_id: 'test', per_page: 1, page: 0, }); - find.mockResolvedValueOnce({ + repository.find.mockResolvedValueOnce({ total: 2, saved_objects: [], per_page: 1, @@ -278,11 +291,7 @@ describe('createPointInTimeFinder()', () => { const finder = new PointInTimeFinder(findOptions, { logger, - client: { - find, - openPointInTimeForType, - closePointInTime, - }, + client: repository, }); const hits: SavedObjectsFindResult[] = []; for await (const result of finder.find()) { @@ -290,15 +299,15 @@ describe('createPointInTimeFinder()', () => { await finder.close(); } - expect(closePointInTime).toHaveBeenCalledTimes(1); + expect(repository.closePointInTime).toHaveBeenCalledTimes(1); expect(hits.length).toBe(1); }); test('is called if `find` throws an error', async () => { - openPointInTimeForType.mockResolvedValueOnce({ + repository.openPointInTimeForType.mockResolvedValueOnce({ id: 'test', }); - find.mockRejectedValueOnce(new Error('oops')); + repository.find.mockRejectedValueOnce(new Error('oops')); const findOptions: SavedObjectsCreatePointInTimeFinderOptions = { type: ['visualization'], @@ -308,11 +317,7 @@ describe('createPointInTimeFinder()', () => { const finder = new PointInTimeFinder(findOptions, { logger, - client: { - find, - openPointInTimeForType, - closePointInTime, - }, + client: repository, }); const hits: SavedObjectsFindResult[] = []; try { @@ -323,27 +328,28 @@ describe('createPointInTimeFinder()', () => { // intentionally empty } - expect(closePointInTime).toHaveBeenCalledWith('test'); + expect(repository.closePointInTime).toHaveBeenCalledWith('test'); }); test('finder can be reused after closing', async () => { - openPointInTimeForType.mockResolvedValueOnce({ + repository.openPointInTimeForType.mockResolvedValueOnce({ id: 'abc123', }); - find.mockResolvedValueOnce({ - total: 2, - saved_objects: mockHits, - pit_id: 'abc123', - per_page: 1, - page: 0, - }); - find.mockResolvedValueOnce({ - total: 2, - saved_objects: mockHits, - pit_id: 'abc123', - per_page: 1, - page: 1, - }); + repository.find + .mockResolvedValueOnce({ + total: 2, + saved_objects: mockHits, + pit_id: 'abc123', + per_page: 1, + page: 0, + }) + .mockResolvedValueOnce({ + total: 2, + saved_objects: mockHits, + pit_id: 'abc123', + per_page: 1, + page: 1, + }); const findOptions: SavedObjectsCreatePointInTimeFinderOptions = { type: ['visualization'], @@ -353,11 +359,7 @@ describe('createPointInTimeFinder()', () => { const finder = new PointInTimeFinder(findOptions, { logger, - client: { - find, - openPointInTimeForType, - closePointInTime, - }, + client: repository, }); const findA = finder.find(); @@ -370,9 +372,9 @@ describe('createPointInTimeFinder()', () => { expect((await findA.next()).done).toBe(true); expect((await findB.next()).done).toBe(true); - expect(openPointInTimeForType).toHaveBeenCalledTimes(2); - expect(find).toHaveBeenCalledTimes(2); - expect(closePointInTime).toHaveBeenCalledTimes(2); + expect(repository.openPointInTimeForType).toHaveBeenCalledTimes(2); + expect(repository.find).toHaveBeenCalledTimes(2); + expect(repository.closePointInTime).toHaveBeenCalledTimes(2); }); }); }); diff --git a/src/core/server/saved_objects/service/lib/point_in_time_finder.ts b/src/core/server/saved_objects/service/lib/point_in_time_finder.ts index f0ed943c585e5..d11be250ad0a9 100644 --- a/src/core/server/saved_objects/service/lib/point_in_time_finder.ts +++ b/src/core/server/saved_objects/service/lib/point_in_time_finder.ts @@ -139,7 +139,9 @@ export class PointInTimeFinder private async open() { try { - const { id } = await this.#client.openPointInTimeForType(this.#findOptions.type); + const { id } = await this.#client.openPointInTimeForType(this.#findOptions.type, { + namespaces: this.#findOptions.namespaces, + }); this.#pitId = id; this.#open = true; } catch (e) { diff --git a/src/core/server/saved_objects/service/saved_objects_client.ts b/src/core/server/saved_objects/service/saved_objects_client.ts index 00d47d8d1fb03..1564df2969ecc 100644 --- a/src/core/server/saved_objects/service/saved_objects_client.ts +++ b/src/core/server/saved_objects/service/saved_objects_client.ts @@ -334,7 +334,7 @@ export interface SavedObjectsResolveResponse { /** * @public */ -export interface SavedObjectsOpenPointInTimeOptions extends SavedObjectsBaseOptions { +export interface SavedObjectsOpenPointInTimeOptions { /** * Optionally specify how long ES should keep the PIT alive until the next request. Defaults to `5m`. */ @@ -343,6 +343,15 @@ export interface SavedObjectsOpenPointInTimeOptions extends SavedObjectsBaseOpti * An optional ES preference value to be used for the query. */ preference?: string; + /** + * An optional list of namespaces to be used when opening the PIT. + * + * When the spaces plugin is enabled: + * - this will default to the user's current space (as determined by the URL) + * - if specified, the user's current space will be ignored + * - `['*']` will search across all available spaces + */ + namespaces?: string[]; } /** diff --git a/src/core/server/server.api.md b/src/core/server/server.api.md index 47455e0c14316..1bd59dfc7fdb1 100644 --- a/src/core/server/server.api.md +++ b/src/core/server/server.api.md @@ -2460,8 +2460,9 @@ export interface SavedObjectsMigrationVersion { export type SavedObjectsNamespaceType = 'single' | 'multiple' | 'multiple-isolated' | 'agnostic'; // @public (undocumented) -export interface SavedObjectsOpenPointInTimeOptions extends SavedObjectsBaseOptions { +export interface SavedObjectsOpenPointInTimeOptions { keepAlive?: string; + namespaces?: string[]; preference?: string; } diff --git a/x-pack/plugins/security/server/saved_objects/secure_saved_objects_client_wrapper.test.ts b/x-pack/plugins/security/server/saved_objects/secure_saved_objects_client_wrapper.test.ts index e5a2340aba3f0..2f622d9e8a0e1 100644 --- a/x-pack/plugins/security/server/saved_objects/secure_saved_objects_client_wrapper.test.ts +++ b/x-pack/plugins/security/server/saved_objects/secure_saved_objects_client_wrapper.test.ts @@ -779,17 +779,6 @@ describe('#find', () => { ); }); - test(`throws BadRequestError when searching across namespaces when pit is provided`, async () => { - const options = { - type: [type1, type2], - pit: { id: 'abc123' }, - namespaces: ['some-ns', 'another-ns'], - }; - await expect(client.find(options)).rejects.toThrowErrorMatchingInlineSnapshot( - `"_find across namespaces is not permitted when using the \`pit\` option."` - ); - }); - test(`checks privileges for user, actions, and namespaces`, async () => { const options = { type: [type1, type2], namespaces }; await expectPrivilegeCheck(client.find, { options }, namespaces); @@ -884,7 +873,7 @@ describe('#openPointInTimeForType', () => { const apiCallReturnValue = Symbol(); clientOpts.baseClient.openPointInTimeForType.mockReturnValue(apiCallReturnValue as any); - const options = { namespace }; + const options = { namespaces: [namespace] }; const result = await expectSuccess(client.openPointInTimeForType, { type, options }); expect(result).toBe(apiCallReturnValue); }); @@ -892,18 +881,113 @@ describe('#openPointInTimeForType', () => { test(`adds audit event when successful`, async () => { const apiCallReturnValue = Symbol(); clientOpts.baseClient.openPointInTimeForType.mockReturnValue(apiCallReturnValue as any); - const options = { namespace }; + const options = { namespaces: [namespace] }; await expectSuccess(client.openPointInTimeForType, { type, options }); expect(clientOpts.auditLogger.log).toHaveBeenCalledTimes(1); expectAuditEvent('saved_object_open_point_in_time', 'unknown'); }); - test(`adds audit event when not successful`, async () => { - clientOpts.checkSavedObjectsPrivilegesAsCurrentUser.mockRejectedValue(new Error()); - await expect(() => client.openPointInTimeForType(type, { namespace })).rejects.toThrow(); + test(`throws an error when unauthorized`, async () => { + clientOpts.checkSavedObjectsPrivilegesAsCurrentUser.mockImplementation( + getMockCheckPrivilegesFailure + ); + const options = { namespaces: [namespace] }; + await expect(() => client.openPointInTimeForType(type, options)).rejects.toThrowError( + 'unauthorized' + ); + }); + + test(`adds audit event when unauthorized`, async () => { + clientOpts.checkSavedObjectsPrivilegesAsCurrentUser.mockImplementation( + getMockCheckPrivilegesFailure + ); + const options = { namespaces: [namespace] }; + await expect(() => client.openPointInTimeForType(type, options)).rejects.toThrow(); expect(clientOpts.auditLogger.log).toHaveBeenCalledTimes(1); expectAuditEvent('saved_object_open_point_in_time', 'failure'); }); + + test(`filters types based on authorization`, async () => { + clientOpts.checkSavedObjectsPrivilegesAsCurrentUser.mockResolvedValue({ + hasAllRequested: false, + username: USERNAME, + privileges: { + kibana: [ + { + resource: 'some-ns', + privilege: 'mock-saved_object:foo/open_point_in_time', + authorized: true, + }, + { + resource: 'some-ns', + privilege: 'mock-saved_object:bar/open_point_in_time', + authorized: true, + }, + { + resource: 'some-ns', + privilege: 'mock-saved_object:baz/open_point_in_time', + authorized: false, + }, + { + resource: 'some-ns', + privilege: 'mock-saved_object:qux/open_point_in_time', + authorized: false, + }, + { + resource: 'another-ns', + privilege: 'mock-saved_object:foo/open_point_in_time', + authorized: true, + }, + { + resource: 'another-ns', + privilege: 'mock-saved_object:bar/open_point_in_time', + authorized: false, + }, + { + resource: 'another-ns', + privilege: 'mock-saved_object:baz/open_point_in_time', + authorized: true, + }, + { + resource: 'another-ns', + privilege: 'mock-saved_object:qux/open_point_in_time', + authorized: false, + }, + { + resource: 'forbidden-ns', + privilege: 'mock-saved_object:foo/open_point_in_time', + authorized: false, + }, + { + resource: 'forbidden-ns', + privilege: 'mock-saved_object:bar/open_point_in_time', + authorized: false, + }, + { + resource: 'forbidden-ns', + privilege: 'mock-saved_object:baz/open_point_in_time', + authorized: false, + }, + { + resource: 'forbidden-ns', + privilege: 'mock-saved_object:qux/open_point_in_time', + authorized: false, + }, + ], + }, + }); + + await client.openPointInTimeForType(['foo', 'bar', 'baz', 'qux'], { + namespaces: ['some-ns', 'another-ns', 'forbidden-ns'], + }); + + expect(clientOpts.baseClient.openPointInTimeForType).toHaveBeenCalledWith( + ['foo', 'bar', 'baz'], + { + namespaces: ['some-ns', 'another-ns', 'forbidden-ns'], + } + ); + }); }); describe('#closePointInTime', () => { 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 a3bd215211983..6f2b8d28a5601 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 @@ -29,7 +29,7 @@ import type { SavedObjectsUpdateOptions, } from 'src/core/server'; -import { SavedObjectsUtils } from '../../../../../src/core/server'; +import { SavedObjectsErrorHelpers, SavedObjectsUtils } from '../../../../../src/core/server'; import { ALL_SPACES_ID, UNKNOWN_SPACE } from '../../common/constants'; import type { AuditLogger, SecurityAuditLogger } from '../audit'; import { SavedObjectAction, savedObjectEvent } from '../audit'; @@ -75,10 +75,12 @@ interface LegacyEnsureAuthorizedResult { status: 'fully_authorized' | 'partially_authorized' | 'unauthorized'; typeMap: Map; } + interface LegacyEnsureAuthorizedTypeResult { authorizedSpaces: string[]; isGloballyAuthorized?: boolean; } + export class SecureSavedObjectsClientWrapper implements SavedObjectsClientContract { private readonly actions: Actions; private readonly legacyAuditLogger: PublicMethodsOf; @@ -236,11 +238,6 @@ export class SecureSavedObjectsClientWrapper implements SavedObjectsClientContra `_find across namespaces is not permitted when the Spaces plugin is disabled.` ); } - if (options.pit && Array.isArray(options.namespaces) && options.namespaces.length > 1) { - throw this.errors.createBadRequestError( - '_find across namespaces is not permitted when using the `pit` option.' - ); - } const args = { options }; const { status, typeMap } = await this.legacyEnsureAuthorized( @@ -508,22 +505,27 @@ export class SecureSavedObjectsClientWrapper implements SavedObjectsClientContra type: string | string[], options: SavedObjectsOpenPointInTimeOptions ) { - try { - const args = { type, options }; - await this.legacyEnsureAuthorized(type, 'open_point_in_time', options?.namespace, { + const args = { type, options }; + const { status, typeMap } = await this.legacyEnsureAuthorized( + type, + 'open_point_in_time', + options?.namespaces, + { args, // Partial authorization is acceptable in this case because this method is only designed // to be used with `find`, which already allows for partial authorization. requireFullAuthorization: false, - }); - } catch (error) { + } + ); + + if (status === 'unauthorized') { this.auditLogger.log( savedObjectEvent({ action: SavedObjectAction.OPEN_POINT_IN_TIME, - error, + error: new Error(status), }) ); - throw error; + throw SavedObjectsErrorHelpers.decorateForbiddenError(new Error(status)); } this.auditLogger.log( @@ -533,7 +535,8 @@ export class SecureSavedObjectsClientWrapper implements SavedObjectsClientContra }) ); - return await this.baseClient.openPointInTimeForType(type, options); + const allowedTypes = [...typeMap.keys()]; // only allow the user to open a PIT against indices for type(s) they are authorized to access + return await this.baseClient.openPointInTimeForType(allowedTypes, options); } public async closePointInTime(id: string, options?: SavedObjectsClosePointInTimeOptions) { diff --git a/x-pack/plugins/spaces/server/saved_objects/spaces_saved_objects_client.test.ts b/x-pack/plugins/spaces/server/saved_objects/spaces_saved_objects_client.test.ts index 56bfe71b581ed..b94113436d7ad 100644 --- a/x-pack/plugins/spaces/server/saved_objects/spaces_saved_objects_client.test.ts +++ b/x-pack/plugins/spaces/server/saved_objects/spaces_saved_objects_client.test.ts @@ -533,27 +533,94 @@ const ERROR_NAMESPACE_SPECIFIED = 'Spaces currently determines the namespaces'; }); describe('#openPointInTimeForType', () => { - test(`throws error if options.namespace is specified`, async () => { - const { client } = createSpacesSavedObjectsClient(); + test(`throws error if if user is unauthorized in this space`, async () => { + const { client, baseClient, spacesService } = createSpacesSavedObjectsClient(); + const spacesClient = spacesClientMock.create(); + spacesClient.getAll.mockResolvedValue([]); + spacesService.createSpacesClient.mockReturnValue(spacesClient); - await expect(client.openPointInTimeForType('foo', { namespace: 'bar' })).rejects.toThrow( - ERROR_NAMESPACE_SPECIFIED + await expect( + client.openPointInTimeForType('foo', { namespaces: ['bar'] }) + ).rejects.toThrowError('Bad Request'); + + expect(baseClient.openPointInTimeForType).not.toHaveBeenCalled(); + }); + + test(`throws error if if user is unauthorized in any space`, async () => { + const { client, baseClient, spacesService } = createSpacesSavedObjectsClient(); + const spacesClient = spacesClientMock.create(); + spacesClient.getAll.mockRejectedValue(Boom.unauthorized()); + spacesService.createSpacesClient.mockReturnValue(spacesClient); + + await expect( + client.openPointInTimeForType('foo', { namespaces: ['bar'] }) + ).rejects.toThrowError('Bad Request'); + + expect(baseClient.openPointInTimeForType).not.toHaveBeenCalled(); + }); + + test(`filters options.namespaces based on authorization`, async () => { + const { client, baseClient, spacesService } = createSpacesSavedObjectsClient(); + const expectedReturnValue = { id: 'abc123' }; + baseClient.openPointInTimeForType.mockReturnValue(Promise.resolve(expectedReturnValue)); + + const spacesClient = spacesService.createSpacesClient( + null as any + ) as jest.Mocked; + spacesClient.getAll.mockImplementation(() => + Promise.resolve([ + { id: 'ns-1', name: '', disabledFeatures: [] }, + { id: 'ns-2', name: '', disabledFeatures: [] }, + ]) ); + + const options = Object.freeze({ namespaces: ['ns-1', 'ns-3'] }); + const actualReturnValue = await client.openPointInTimeForType(['foo', 'bar'], options); + + expect(actualReturnValue).toBe(expectedReturnValue); + expect(baseClient.openPointInTimeForType).toHaveBeenCalledWith(['foo', 'bar'], { + namespaces: ['ns-1'], + }); + expect(spacesClient.getAll).toHaveBeenCalledWith({ purpose: 'findSavedObjects' }); }); - test(`supplements options with the current namespace`, async () => { + test(`translates options.namespaces: ['*']`, async () => { + const { client, baseClient, spacesService } = createSpacesSavedObjectsClient(); + const expectedReturnValue = { id: 'abc123' }; + baseClient.openPointInTimeForType.mockReturnValue(Promise.resolve(expectedReturnValue)); + + const spacesClient = spacesService.createSpacesClient( + null as any + ) as jest.Mocked; + spacesClient.getAll.mockImplementation(() => + Promise.resolve([ + { id: 'ns-1', name: '', disabledFeatures: [] }, + { id: 'ns-2', name: '', disabledFeatures: [] }, + ]) + ); + + const options = Object.freeze({ namespaces: ['*'] }); + const actualReturnValue = await client.openPointInTimeForType(['foo', 'bar'], options); + + expect(actualReturnValue).toBe(expectedReturnValue); + expect(baseClient.openPointInTimeForType).toHaveBeenCalledWith(['foo', 'bar'], { + namespaces: ['ns-1', 'ns-2'], + }); + expect(spacesClient.getAll).toHaveBeenCalledWith({ purpose: 'findSavedObjects' }); + }); + + test(`supplements options with the current namespace if unspecified`, async () => { const { client, baseClient } = createSpacesSavedObjectsClient(); const expectedReturnValue = { id: 'abc123' }; baseClient.openPointInTimeForType.mockReturnValue(Promise.resolve(expectedReturnValue)); - const options = Object.freeze({ foo: 'bar' }); - // @ts-expect-error + const options = Object.freeze({ keepAlive: '2m' }); const actualReturnValue = await client.openPointInTimeForType('foo', options); expect(actualReturnValue).toBe(expectedReturnValue); expect(baseClient.openPointInTimeForType).toHaveBeenCalledWith('foo', { - foo: 'bar', - namespace: currentSpace.expectedNamespace, + keepAlive: '2m', + namespaces: [currentSpace.expectedNamespace ?? DEFAULT_SPACE_ID], }); }); }); diff --git a/x-pack/plugins/spaces/server/saved_objects/spaces_saved_objects_client.ts b/x-pack/plugins/spaces/server/saved_objects/spaces_saved_objects_client.ts index e344aa8cecf07..9c51f22e280d8 100644 --- a/x-pack/plugins/spaces/server/saved_objects/spaces_saved_objects_client.ts +++ b/x-pack/plugins/spaces/server/saved_objects/spaces_saved_objects_client.ts @@ -30,7 +30,7 @@ import type { SavedObjectsUpdateOptions, } from 'src/core/server'; -import { SavedObjectsUtils } from '../../../../../src/core/server'; +import { SavedObjectsErrorHelpers, SavedObjectsUtils } from '../../../../../src/core/server'; import { ALL_SPACES_ID } from '../../common/constants'; import { spaceIdToNamespace } from '../lib/utils/namespace'; import type { ISpacesClient } from '../spaces_client'; @@ -175,32 +175,19 @@ export class SpacesSavedObjectsClient implements SavedObjectsClientContract { * @returns {promise} - { saved_objects: [{ id, type, version, attributes }], total, per_page, page } */ public async find(options: SavedObjectsFindOptions) { - throwErrorIfNamespaceSpecified(options); - - let namespaces = options.namespaces; - if (namespaces) { - try { - const availableSpaces = await this.spacesClient.getAll({ purpose: 'findSavedObjects' }); - if (namespaces.includes(ALL_SPACES_ID)) { - namespaces = availableSpaces.map((space) => space.id); - } else { - namespaces = namespaces.filter((namespace) => - availableSpaces.some((space) => space.id === namespace) - ); - } - if (namespaces.length === 0) { - // return empty response, since the user is unauthorized in this space (or these spaces), but we don't return forbidden errors for `find` operations - return SavedObjectsUtils.createEmptyFindResponse(options); - } - } catch (err) { - if (Boom.isBoom(err) && err.output.payload.statusCode === 403) { - // return empty response, since the user is unauthorized in any space, but we don't return forbidden errors for `find` operations - return SavedObjectsUtils.createEmptyFindResponse(options); - } - throw err; + let namespaces: string[]; + try { + namespaces = await this.getSearchableSpaces(options.namespaces); + } catch (err) { + if (Boom.isBoom(err) && err.output.payload.statusCode === 403) { + // return empty response, since the user is unauthorized in any space, but we don't return forbidden errors for `find` operations + return SavedObjectsUtils.createEmptyFindResponse(options); } - } else { - namespaces = [this.spaceId]; + throw err; + } + if (namespaces.length === 0) { + // return empty response, since the user is unauthorized in this space (or these spaces), but we don't return forbidden errors for `find` operations + return SavedObjectsUtils.createEmptyFindResponse(options); } return await this.client.find({ @@ -396,10 +383,15 @@ export class SpacesSavedObjectsClient implements SavedObjectsClientContract { type: string | string[], options: SavedObjectsOpenPointInTimeOptions = {} ) { - throwErrorIfNamespaceSpecified(options); + const namespaces = await this.getSearchableSpaces(options.namespaces); + if (namespaces.length === 0) { + // throw bad request if no valid spaces were found. + throw SavedObjectsErrorHelpers.createBadRequestError(); + } + return await this.client.openPointInTimeForType(type, { ...options, - namespace: spaceIdToNamespace(this.spaceId), + namespaces, }); } @@ -446,4 +438,19 @@ export class SpacesSavedObjectsClient implements SavedObjectsClientContract { ...dependencies, }); } + + private async getSearchableSpaces(namespaces?: string[]): Promise { + if (namespaces) { + const availableSpaces = await this.spacesClient.getAll({ purpose: 'findSavedObjects' }); + if (namespaces.includes(ALL_SPACES_ID)) { + return availableSpaces.map((space) => space.id); + } else { + return namespaces.filter((namespace) => + availableSpaces.some((space) => space.id === namespace) + ); + } + } else { + return [this.spaceId]; + } + } } diff --git a/x-pack/test/saved_object_api_integration/common/suites/export.ts b/x-pack/test/saved_object_api_integration/common/suites/export.ts index ea2f321458c22..77eb93a4107a5 100644 --- a/x-pack/test/saved_object_api_integration/common/suites/export.ts +++ b/x-pack/test/saved_object_api_integration/common/suites/export.ts @@ -155,8 +155,16 @@ export function exportTestSuiteFactory(esArchiver: any, supertest: SuperTest Date: Mon, 23 Aug 2021 15:21:50 +0200 Subject: [PATCH 63/76] [Saved Search Embeddable] Do not set source field when reading fields from source (#109069) (#109611) * [Saved Search Embeddable] Do not set source if reading fields from source enabled * Extract functionality to a helper function and added unit tests * Fix unit test Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../helpers/update_search_source.test.ts | 33 +++++++++++++++++++ .../helpers/update_search_source.ts | 33 +++++++++++++++++++ .../embeddable/saved_search_embeddable.tsx | 31 +++++++---------- 3 files changed, 77 insertions(+), 20 deletions(-) create mode 100644 src/plugins/discover/public/application/embeddable/helpers/update_search_source.test.ts create mode 100644 src/plugins/discover/public/application/embeddable/helpers/update_search_source.ts diff --git a/src/plugins/discover/public/application/embeddable/helpers/update_search_source.test.ts b/src/plugins/discover/public/application/embeddable/helpers/update_search_source.test.ts new file mode 100644 index 0000000000000..f3edc523f4464 --- /dev/null +++ b/src/plugins/discover/public/application/embeddable/helpers/update_search_source.test.ts @@ -0,0 +1,33 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ +import { createSearchSourceMock } from '../../../../../data/common/search/search_source/mocks'; +import { updateSearchSource } from './update_search_source'; +import { indexPatternMock } from '../../../__mocks__/index_pattern'; +import { SortOrder } from '../../../saved_searches/types'; + +describe('updateSearchSource', () => { + const defaults = { + sampleSize: 50, + defaultSort: 'asc', + }; + + it('updates a given search source', async () => { + const searchSource = createSearchSourceMock({}); + updateSearchSource(searchSource, indexPatternMock, [] as SortOrder[], false, defaults); + expect(searchSource.getField('fields')).toBe(undefined); + // does not explicitly request fieldsFromSource when not using fields API + expect(searchSource.getField('fieldsFromSource')).toBe(undefined); + }); + + it('updates a given search source with the usage of the new fields api', async () => { + const searchSource = createSearchSourceMock({}); + updateSearchSource(searchSource, indexPatternMock, [] as SortOrder[], true, defaults); + expect(searchSource.getField('fields')).toEqual([{ field: '*', include_unmapped: 'true' }]); + expect(searchSource.getField('fieldsFromSource')).toBe(undefined); + }); +}); diff --git a/src/plugins/discover/public/application/embeddable/helpers/update_search_source.ts b/src/plugins/discover/public/application/embeddable/helpers/update_search_source.ts new file mode 100644 index 0000000000000..1d6c29d65ca85 --- /dev/null +++ b/src/plugins/discover/public/application/embeddable/helpers/update_search_source.ts @@ -0,0 +1,33 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { IndexPattern, ISearchSource } from '../../../../../data/common'; +import { getSortForSearchSource } from '../../apps/main/components/doc_table'; +import { SortPairArr } from '../../apps/main/components/doc_table/lib/get_sort'; + +export const updateSearchSource = ( + searchSource: ISearchSource, + indexPattern: IndexPattern | undefined, + sort: (SortPairArr[] & string[][]) | undefined, + useNewFieldsApi: boolean, + defaults: { + sampleSize: number; + defaultSort: string; + } +) => { + const { sampleSize, defaultSort } = defaults; + searchSource.setField('size', sampleSize); + searchSource.setField('sort', getSortForSearchSource(sort, indexPattern, defaultSort)); + if (useNewFieldsApi) { + searchSource.removeField('fieldsFromSource'); + const fields: Record = { field: '*', include_unmapped: 'true' }; + searchSource.setField('fields', [fields]); + } else { + searchSource.removeField('fields'); + } +}; diff --git a/src/plugins/discover/public/application/embeddable/saved_search_embeddable.tsx b/src/plugins/discover/public/application/embeddable/saved_search_embeddable.tsx index 1981f0228d2c7..362f5b9276c65 100644 --- a/src/plugins/discover/public/application/embeddable/saved_search_embeddable.tsx +++ b/src/plugins/discover/public/application/embeddable/saved_search_embeddable.tsx @@ -42,8 +42,9 @@ import { handleSourceColumnState } from '../angular/helpers'; import { DiscoverGridProps } from '../components/discover_grid/discover_grid'; import { DiscoverGridSettings } from '../components/discover_grid/types'; import { DocTableProps } from '../apps/main/components/doc_table/doc_table_wrapper'; -import { getDefaultSort, getSortForSearchSource } from '../apps/main/components/doc_table'; +import { getDefaultSort } from '../apps/main/components/doc_table'; import { SortOrder } from '../apps/main/components/doc_table/components/table_header/helpers'; +import { updateSearchSource } from './helpers/update_search_source'; export type SearchProps = Partial & Partial & { @@ -143,26 +144,16 @@ export class SavedSearchEmbeddable if (this.abortController) this.abortController.abort(); this.abortController = new AbortController(); - searchSource.setField('size', this.services.uiSettings.get(SAMPLE_SIZE_SETTING)); - searchSource.setField( - 'sort', - getSortForSearchSource( - this.searchProps!.sort, - this.searchProps!.indexPattern, - this.services.uiSettings.get(SORT_DEFAULT_ORDER_SETTING) - ) - ); - if (useNewFieldsApi) { - searchSource.removeField('fieldsFromSource'); - const fields: Record = { field: '*', include_unmapped: 'true' }; - searchSource.setField('fields', [fields]); - } else { - searchSource.removeField('fields'); - if (this.searchProps.indexPattern) { - const fieldNames = this.searchProps.indexPattern.fields.map((field) => field.name); - searchSource.setField('fieldsFromSource', fieldNames); + updateSearchSource( + searchSource, + this.searchProps!.indexPattern, + this.searchProps!.sort, + useNewFieldsApi, + { + sampleSize: this.services.uiSettings.get(SAMPLE_SIZE_SETTING), + defaultSort: this.services.uiSettings.get(SORT_DEFAULT_ORDER_SETTING), } - } + ); // Log request to inspector this.inspectorAdapters.requests!.reset(); From b3120d9d3ca7bebc314092d5e393a5d19959a3eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yulia=20=C4=8Cech?= <6585477+yuliacech@users.noreply.github.com> Date: Mon, 23 Aug 2021 15:24:05 +0200 Subject: [PATCH 64/76] [ILM] Fixed _meta field failing server validation (#109295) (#109613) * [ILM] Fixed the bug with built-in policies not saving because of the _meta field * [ILM] Added PR review suggestions Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../features/request_flyout.test.ts | 40 ++++++++++++++++++ .../common/types/policies.ts | 1 + .../components/policy_json_flyout.tsx | 41 ++++++++++--------- .../api/policies/register_create_route.ts | 17 ++++---- .../index_lifecycle_management/policies.js | 32 +++++++++++++++ 5 files changed, 103 insertions(+), 28 deletions(-) diff --git a/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/features/request_flyout.test.ts b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/features/request_flyout.test.ts index 86bf36984b9fd..e49a1c5c94f90 100644 --- a/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/features/request_flyout.test.ts +++ b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/features/request_flyout.test.ts @@ -136,4 +136,44 @@ describe(' request flyout', () => { expect(json).toBe(expected); }); + + test('renders _meta field', async () => { + const defaultPolicy = getDefaultHotPhasePolicy(); + const policyWithMetaField = { + ...defaultPolicy, + policy: { + ...defaultPolicy.policy, + _meta: { + description: 'test meta description', + someObject: { + test: 'test', + }, + }, + }, + }; + httpRequestsMockHelpers.setLoadPolicies([policyWithMetaField]); + + await act(async () => { + testBed = await setupRequestFlyoutTestBed(); + }); + + const { component, actions } = testBed; + component.update(); + + await actions.openRequestFlyout(); + + const json = actions.getRequestJson(); + const expected = `PUT _ilm/policy/${policyWithMetaField.name}\n${JSON.stringify( + { + policy: { + phases: { ...policyWithMetaField.policy.phases }, + _meta: { ...policyWithMetaField.policy._meta }, + }, + }, + null, + 2 + )}`; + + expect(json).toBe(expected); + }); }); diff --git a/x-pack/plugins/index_lifecycle_management/common/types/policies.ts b/x-pack/plugins/index_lifecycle_management/common/types/policies.ts index 76b38eacba2d1..3a338c80fa56c 100644 --- a/x-pack/plugins/index_lifecycle_management/common/types/policies.ts +++ b/x-pack/plugins/index_lifecycle_management/common/types/policies.ts @@ -18,6 +18,7 @@ export type PhaseExceptDelete = keyof Omit; export interface SerializedPolicy { name: string; phases: Phases; + _meta?: Record; } export interface Phases { diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/policy_json_flyout.tsx b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/policy_json_flyout.tsx index f510090323e1f..ae7b1ebaffc02 100644 --- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/policy_json_flyout.tsx +++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/policy_json_flyout.tsx @@ -29,6 +29,7 @@ import { useFormContext, useFormData } from '../../../../shared_imports'; import { i18nTexts } from '../i18n_texts'; import { FormInternal } from '../types'; +type PolicyJson = Omit; interface Props { close: () => void; policyName: string; @@ -37,48 +38,50 @@ interface Props { /** * Ensure that the JSON we get from the from has phases in the correct order. */ -const prettifyFormJson = (policy: SerializedPolicy): SerializedPolicy => ({ - ...policy, - phases: { - hot: policy.phases.hot, - warm: policy.phases.warm, - cold: policy.phases.cold, - frozen: policy.phases.frozen, - delete: policy.phases.delete, - }, -}); +const prettifyFormJson = (policy: SerializedPolicy): PolicyJson => { + return { + phases: { + hot: policy.phases.hot, + warm: policy.phases.warm, + cold: policy.phases.cold, + frozen: policy.phases.frozen, + delete: policy.phases.delete, + }, + _meta: policy._meta, + }; +}; export const PolicyJsonFlyout: React.FunctionComponent = ({ policyName, close }) => { /** * policy === undefined: we are checking validity * policy === null: we have determined the policy is invalid - * policy === {@link SerializedPolicy} we have determined the policy is valid + * policy === {@link PolicyJson} we have determined the policy is valid */ - const [policy, setPolicy] = useState(undefined); + const [policyJson, setPolicyJson] = useState(undefined); const { validate: validateForm, getErrors } = useFormContext(); const [, getFormData] = useFormData(); const updatePolicy = useCallback(async () => { - setPolicy(undefined); + setPolicyJson(undefined); const isFormValid = await validateForm(); const errorMessages = getErrors(); const isOnlyMissingPolicyName = errorMessages.length === 1 && errorMessages[0] === i18nTexts.editPolicy.errors.policyNameRequiredMessage; if (isFormValid || isOnlyMissingPolicyName) { - setPolicy(prettifyFormJson(getFormData())); + setPolicyJson(prettifyFormJson(getFormData())); } else { - setPolicy(null); + setPolicyJson(null); } - }, [setPolicy, getFormData, validateForm, getErrors]); + }, [setPolicyJson, getFormData, validateForm, getErrors]); useEffect(() => { updatePolicy(); }, [updatePolicy]); let content: React.ReactNode; - switch (policy) { + switch (policyJson) { case undefined: content = ; break; @@ -100,12 +103,10 @@ export const PolicyJsonFlyout: React.FunctionComponent = ({ policyName, c ); break; default: - const { phases } = policy; - const json = JSON.stringify( { policy: { - phases, + ...policyJson, }, }, null, diff --git a/x-pack/plugins/index_lifecycle_management/server/routes/api/policies/register_create_route.ts b/x-pack/plugins/index_lifecycle_management/server/routes/api/policies/register_create_route.ts index 7a4795f8e370b..bc27a3b909c85 100644 --- a/x-pack/plugins/index_lifecycle_management/server/routes/api/policies/register_create_route.ts +++ b/x-pack/plugins/index_lifecycle_management/server/routes/api/policies/register_create_route.ts @@ -11,12 +11,12 @@ import { ElasticsearchClient } from 'kibana/server'; import { RouteDependencies } from '../../../types'; import { addBasePath } from '../../../services'; -async function createPolicy(client: ElasticsearchClient, name: string, phases: any): Promise { - const body = { - policy: { - phases, - }, - }; +async function createPolicy( + client: ElasticsearchClient, + name: string, + policy: Omit +): Promise { + const body = { policy }; const options = { ignore: [404], }; @@ -40,6 +40,7 @@ const bodySchema = schema.object({ frozen: schema.maybe(schema.any()), delete: schema.maybe(schema.any()), }), + _meta: schema.maybe(schema.any()), }); export function registerCreateRoute({ @@ -51,10 +52,10 @@ export function registerCreateRoute({ { path: addBasePath('/policies'), validate: { body: bodySchema } }, license.guardApiRoute(async (context, request, response) => { const body = request.body as typeof bodySchema.type; - const { name, phases } = body; + const { name, ...rest } = body; try { - await createPolicy(context.core.elasticsearch.client.asCurrentUser, name, phases); + await createPolicy(context.core.elasticsearch.client.asCurrentUser, name, rest); return response.ok(); } catch (error) { return handleEsError({ error, response }); diff --git a/x-pack/test/api_integration/apis/management/index_lifecycle_management/policies.js b/x-pack/test/api_integration/apis/management/index_lifecycle_management/policies.js index 1f5f28744dd98..8e29604a0bf62 100644 --- a/x-pack/test/api_integration/apis/management/index_lifecycle_management/policies.js +++ b/x-pack/test/api_integration/apis/management/index_lifecycle_management/policies.js @@ -119,6 +119,38 @@ export default function ({ getService }) { }); }); + describe('edit', () => { + it('keeps _meta field intact', async () => { + const policyName = 'edit-meta-test-policy'; + const policy = { + ...getPolicyPayload(policyName), + _meta: { description: 'test policy with _meta field' }, + }; + + // Update the policy (uses the same route as create) + await createPolicy(policy).expect(200); + + // only update warm phase timing, not deleting or changing _meta field + const editedPolicy = { + ...policy, + phases: { + ...policy.phases, + warm: { + ...policy.phases.warm, + min_age: '2d', + }, + }, + }; + + await createPolicy(editedPolicy).expect(200); + + const { body } = await loadPolicies(); + const loadedPolicy = body.find((p) => p.name === policyName); + // Make sure the edited policy still has _meta field + expect(loadedPolicy.policy._meta).to.eql(editedPolicy._meta); + }); + }); + describe('delete', () => { it('should delete the policy created', async () => { const policy = getPolicyPayload('delete-test-policy'); From 4a14a94942e798b8753639fb82d9cb06cbb0d8f4 Mon Sep 17 00:00:00 2001 From: Alison Goryachev Date: Mon, 23 Aug 2021 09:25:40 -0400 Subject: [PATCH 65/76] [Upgrade Assistant] Cleanup scss (#109524) --- .../public/application/_index.scss | 1 - .../public/application/components/_index.scss | 2 -- .../components/es_deprecations/_index.scss | 1 - .../deprecation_types/_index.scss | 1 - .../deprecation_types/reindex/_index.scss | 1 - .../reindex/flyout/_index.scss | 1 - .../reindex/flyout/step_progress.tsx | 2 ++ .../components/overview/_index.scss | 2 -- ...stats_panel.scss => _fix_issues_step.scss} | 0 .../overview/fix_issues_step/_index.scss | 2 -- .../fix_issues_step/fix_issues_step.tsx | 2 ++ .../no_deprecations/_no_deprecations.scss | 3 --- .../no_deprecations/no_deprecations.tsx | 25 +++++++++++-------- .../overview/fix_logs_step/_index.scss | 1 - .../deprecation_logging_toggle.tsx | 2 ++ .../upgrade_assistant/public/index.scss | 1 - .../plugins/upgrade_assistant/public/index.ts | 1 - 17 files changed, 20 insertions(+), 28 deletions(-) delete mode 100644 x-pack/plugins/upgrade_assistant/public/application/_index.scss delete mode 100644 x-pack/plugins/upgrade_assistant/public/application/components/_index.scss delete mode 100644 x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/_index.scss delete mode 100644 x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/_index.scss delete mode 100644 x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/_index.scss delete mode 100644 x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/flyout/_index.scss delete mode 100644 x-pack/plugins/upgrade_assistant/public/application/components/overview/_index.scss rename x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_issues_step/{_stats_panel.scss => _fix_issues_step.scss} (100%) delete mode 100644 x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_issues_step/_index.scss delete mode 100644 x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_issues_step/no_deprecations/_no_deprecations.scss delete mode 100644 x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_logs_step/_index.scss delete mode 100644 x-pack/plugins/upgrade_assistant/public/index.scss diff --git a/x-pack/plugins/upgrade_assistant/public/application/_index.scss b/x-pack/plugins/upgrade_assistant/public/application/_index.scss deleted file mode 100644 index 841415620d691..0000000000000 --- a/x-pack/plugins/upgrade_assistant/public/application/_index.scss +++ /dev/null @@ -1 +0,0 @@ -@import 'components/index'; diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/_index.scss b/x-pack/plugins/upgrade_assistant/public/application/components/_index.scss deleted file mode 100644 index 8f900ca8dc055..0000000000000 --- a/x-pack/plugins/upgrade_assistant/public/application/components/_index.scss +++ /dev/null @@ -1,2 +0,0 @@ -@import 'es_deprecations/index'; -@import 'overview/index'; diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/_index.scss b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/_index.scss deleted file mode 100644 index 4865e977f5261..0000000000000 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/_index.scss +++ /dev/null @@ -1 +0,0 @@ -@import 'deprecation_types/index'; diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/_index.scss b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/_index.scss deleted file mode 100644 index c3e842941a250..0000000000000 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/_index.scss +++ /dev/null @@ -1 +0,0 @@ -@import 'reindex/index'; diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/_index.scss b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/_index.scss deleted file mode 100644 index 4cd55614ab4e6..0000000000000 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/_index.scss +++ /dev/null @@ -1 +0,0 @@ -@import 'flyout/index'; diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/flyout/_index.scss b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/flyout/_index.scss deleted file mode 100644 index 1c9fd599b13a8..0000000000000 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/flyout/_index.scss +++ /dev/null @@ -1 +0,0 @@ -@import 'step_progress'; diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/flyout/step_progress.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/flyout/step_progress.tsx index 0973f721a5372..d5947426aee3d 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/flyout/step_progress.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/flyout/step_progress.tsx @@ -10,6 +10,8 @@ import React, { Fragment, ReactNode } from 'react'; import { EuiIcon, EuiLoadingSpinner } from '@elastic/eui'; +import './_step_progress.scss'; + type STATUS = 'incomplete' | 'inProgress' | 'complete' | 'failed' | 'paused' | 'cancelled'; const StepStatus: React.FunctionComponent<{ status: STATUS; idx: number }> = ({ status, idx }) => { diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/overview/_index.scss b/x-pack/plugins/upgrade_assistant/public/application/components/overview/_index.scss deleted file mode 100644 index 3febfe77b3cf7..0000000000000 --- a/x-pack/plugins/upgrade_assistant/public/application/components/overview/_index.scss +++ /dev/null @@ -1,2 +0,0 @@ -@import 'fix_issues_step/index'; -@import 'fix_logs_step/index'; diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_issues_step/_stats_panel.scss b/x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_issues_step/_fix_issues_step.scss similarity index 100% rename from x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_issues_step/_stats_panel.scss rename to x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_issues_step/_fix_issues_step.scss diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_issues_step/_index.scss b/x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_issues_step/_index.scss deleted file mode 100644 index 7eea518d5698e..0000000000000 --- a/x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_issues_step/_index.scss +++ /dev/null @@ -1,2 +0,0 @@ -@import 'stats_panel'; -@import 'no_deprecations/no_deprecations'; diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_issues_step/fix_issues_step.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_issues_step/fix_issues_step.tsx index 12f26a1ea3430..f235075350e66 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_issues_step/fix_issues_step.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_issues_step/fix_issues_step.tsx @@ -14,6 +14,8 @@ import type { EuiStepProps } from '@elastic/eui/src/components/steps/step'; import { ESDeprecationStats } from './es_stats'; import { KibanaDeprecationStats } from './kibana_stats'; +import './_fix_issues_step.scss'; + const i18nTexts = { reviewStepTitle: i18n.translate('xpack.upgradeAssistant.overview.fixIssuesStepTitle', { defaultMessage: 'Review deprecated settings and resolve issues', diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_issues_step/no_deprecations/_no_deprecations.scss b/x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_issues_step/no_deprecations/_no_deprecations.scss deleted file mode 100644 index 0697efbd6ee37..0000000000000 --- a/x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_issues_step/no_deprecations/_no_deprecations.scss +++ /dev/null @@ -1,3 +0,0 @@ -.upgRenderSuccessMessage { - margin-top: $euiSizeL; -} diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_issues_step/no_deprecations/no_deprecations.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_issues_step/no_deprecations/no_deprecations.tsx index 06fea677aa0a5..2f034d461a24f 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_issues_step/no_deprecations/no_deprecations.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_issues_step/no_deprecations/no_deprecations.tsx @@ -7,7 +7,7 @@ import React, { FunctionComponent } from 'react'; -import { EuiFlexGroup, EuiFlexItem, EuiText, EuiIcon } from '@elastic/eui'; +import { EuiFlexGroup, EuiFlexItem, EuiText, EuiIcon, EuiSpacer } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; const i18nTexts = { @@ -21,15 +21,18 @@ const i18nTexts = { export const NoDeprecations: FunctionComponent = () => { return ( - - - - - - - {i18nTexts.noDeprecationsText} - - - + <> + + + + + + + + {i18nTexts.noDeprecationsText} + + + + ); }; diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_logs_step/_index.scss b/x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_logs_step/_index.scss deleted file mode 100644 index 2299c08a4ac31..0000000000000 --- a/x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_logs_step/_index.scss +++ /dev/null @@ -1 +0,0 @@ -@import 'deprecation_logging_toggle/deprecation_logging_toggle'; diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_logs_step/deprecation_logging_toggle/deprecation_logging_toggle.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_logs_step/deprecation_logging_toggle/deprecation_logging_toggle.tsx index 42b9f073a52f1..6de099fe05ef5 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_logs_step/deprecation_logging_toggle/deprecation_logging_toggle.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_logs_step/deprecation_logging_toggle/deprecation_logging_toggle.tsx @@ -23,6 +23,8 @@ import { i18n } from '@kbn/i18n'; import { ResponseError } from '../../../../lib/api'; import { DeprecationLoggingPreviewProps } from '../../../types'; +import './_deprecation_logging_toggle.scss'; + const i18nTexts = { fetchErrorMessage: i18n.translate( 'xpack.upgradeAssistant.overview.deprecationLogs.fetchErrorMessage', diff --git a/x-pack/plugins/upgrade_assistant/public/index.scss b/x-pack/plugins/upgrade_assistant/public/index.scss deleted file mode 100644 index 9bd47b6473372..0000000000000 --- a/x-pack/plugins/upgrade_assistant/public/index.scss +++ /dev/null @@ -1 +0,0 @@ -@import './application/index'; diff --git a/x-pack/plugins/upgrade_assistant/public/index.ts b/x-pack/plugins/upgrade_assistant/public/index.ts index a4091bcb3e1ab..e338b9c044f68 100644 --- a/x-pack/plugins/upgrade_assistant/public/index.ts +++ b/x-pack/plugins/upgrade_assistant/public/index.ts @@ -5,7 +5,6 @@ * 2.0. */ -import './index.scss'; import { PluginInitializerContext } from 'src/core/public'; import { UpgradeAssistantUIPlugin } from './plugin'; From 418e449f3060f6274413b340d5118c4c28f599a3 Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Mon, 23 Aug 2021 09:52:41 -0400 Subject: [PATCH 66/76] [ML] Fix UI inconsistencies in APM Failed transaction correlations (#109187) (#109626) - Show the same empty state in the correlations table - Add "Correlations" title above the table - Add EuiSpacer between the sections before and after progress - Update the copy within the beta badge title=Failed transaction correlations description=Failed transaction correlations is not GA... - Remove s size from the beta badge - Move the help popover to the top of the panel (similar to the Latency correlations tab) - Move the Cancel/Refresh option to the right of the progress bar (similar to the Latency correlations tab) - When the correlation job is running the correlations tab should show a loading state similar to the latency correlations table - Indicate in the table headers Score is sorted by default - Add sortability to both Latency and failed transactions correlations table - Refactor to prevent duplicate code/components like Log, progress bar - Fix alignments of the tab content header (previously navigating from one Trace samples tab to Latency correlation tabs will cause a minor jump in the header, or the titles within the same tab were not the same size ) - Remove the event.outcome as a field candidate (because event.outcome: failure would always be significant in this case) - Shrink the column width for impact (previously it was at 116px) - Added badge for High, medium, low [APM] Correlations: Show impact levels (high, medium, low) as colored badges indicating their severity - Fix license prompt text - Functional tests for the new tab - Make the p value & error rate columns visible only when esInspect mode is enabled Co-authored-by: Quynh Nguyen <43350163+qn895@users.noreply.github.com> --- .../failure_correlations/types.ts | 3 + .../common/utils/formatters/datetime.test.ts | 28 ++ .../app/correlations/correlations_log.tsx | 38 ++ .../app/correlations/correlations_table.tsx | 26 +- .../cross_cluster_search_warning.tsx | 33 ++ .../app/correlations/empty_state_prompt.tsx | 49 ++ .../failed_transactions_correlations.tsx | 426 ++++++++++-------- ...transactions_correlations_help_popover.tsx | 18 +- .../app/correlations/latency_correlations.tsx | 239 ++++------ .../app/correlations/progress_controls.tsx | 77 ++++ ...nsactions_correlation_impact_label.test.ts | 42 +- ...d_transactions_correlation_impact_label.ts | 17 +- .../distribution/index.tsx | 5 +- .../failed_transactions_correlations_tab.tsx | 2 +- ...ailed_transactions_correlations_fetcher.ts | 6 +- .../async_search_service.ts | 10 +- .../queries/query_failure_correlation.ts | 19 +- .../translations/translations/ja-JP.json | 4 - .../translations/translations/zh-CN.json | 4 - .../common/utils/parse_b_fetch.ts | 15 + .../tests/correlations/failed_transactions.ts | 238 ++++++++++ .../{latency_ml.ts => latency.ts} | 10 +- .../test/apm_api_integration/tests/index.ts | 9 +- .../failed_transaction_correlations.ts | 155 +++++++ .../functional/apps/apm/correlations/index.ts | 3 +- .../apm/correlations/latency_correlations.ts | 6 +- 26 files changed, 1074 insertions(+), 408 deletions(-) create mode 100644 x-pack/plugins/apm/public/components/app/correlations/correlations_log.tsx create mode 100644 x-pack/plugins/apm/public/components/app/correlations/cross_cluster_search_warning.tsx create mode 100644 x-pack/plugins/apm/public/components/app/correlations/empty_state_prompt.tsx create mode 100644 x-pack/plugins/apm/public/components/app/correlations/progress_controls.tsx create mode 100644 x-pack/test/apm_api_integration/common/utils/parse_b_fetch.ts create mode 100644 x-pack/test/apm_api_integration/tests/correlations/failed_transactions.ts rename x-pack/test/apm_api_integration/tests/correlations/{latency_ml.ts => latency.ts} (97%) create mode 100644 x-pack/test/functional/apps/apm/correlations/failed_transaction_correlations.ts diff --git a/x-pack/plugins/apm/common/search_strategies/failure_correlations/types.ts b/x-pack/plugins/apm/common/search_strategies/failure_correlations/types.ts index 08e05d46ba013..2b0d2b5642e0c 100644 --- a/x-pack/plugins/apm/common/search_strategies/failure_correlations/types.ts +++ b/x-pack/plugins/apm/common/search_strategies/failure_correlations/types.ts @@ -15,6 +15,9 @@ export interface FailedTransactionsCorrelationValue { pValue: number | null; fieldName: string; fieldValue: string; + normalizedScore: number; + failurePercentage: number; + successPercentage: number; } export type FailureCorrelationImpactThreshold = typeof FAILED_TRANSACTIONS_IMPACT_THRESHOLD[keyof typeof FAILED_TRANSACTIONS_IMPACT_THRESHOLD]; diff --git a/x-pack/plugins/apm/common/utils/formatters/datetime.test.ts b/x-pack/plugins/apm/common/utils/formatters/datetime.test.ts index 9efb7184f3927..54e74330c0604 100644 --- a/x-pack/plugins/apm/common/utils/formatters/datetime.test.ts +++ b/x-pack/plugins/apm/common/utils/formatters/datetime.test.ts @@ -165,6 +165,34 @@ describe('date time formatters', () => { 'Dec 1, 2019, 13:00:00.000 (UTC+1)' ); }); + + it('milliseconds', () => { + moment.tz.setDefault('Europe/Copenhagen'); + expect(asAbsoluteDateTime(1559390400000, 'milliseconds')).toBe( + 'Jun 1, 2019, 14:00:00.000 (UTC+2)' + ); + }); + + it('seconds', () => { + moment.tz.setDefault('Europe/Copenhagen'); + expect(asAbsoluteDateTime(1559390400000, 'seconds')).toBe( + 'Jun 1, 2019, 14:00:00 (UTC+2)' + ); + }); + + it('minutes', () => { + moment.tz.setDefault('Europe/Copenhagen'); + expect(asAbsoluteDateTime(1559390400000, 'minutes')).toBe( + 'Jun 1, 2019, 14:00 (UTC+2)' + ); + }); + + it('hours', () => { + moment.tz.setDefault('Europe/Copenhagen'); + expect(asAbsoluteDateTime(1559390400000, 'hours')).toBe( + 'Jun 1, 2019, 14 (UTC+2)' + ); + }); }); describe('getDateDifference', () => { it('milliseconds', () => { diff --git a/x-pack/plugins/apm/public/components/app/correlations/correlations_log.tsx b/x-pack/plugins/apm/public/components/app/correlations/correlations_log.tsx new file mode 100644 index 0000000000000..2115918a71415 --- /dev/null +++ b/x-pack/plugins/apm/public/components/app/correlations/correlations_log.tsx @@ -0,0 +1,38 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { EuiAccordion, EuiCode, EuiPanel } from '@elastic/eui'; +import React from 'react'; +import { i18n } from '@kbn/i18n'; +import { asAbsoluteDateTime } from '../../../../common/utils/formatters'; + +interface Props { + logMessages: string[]; +} +export function CorrelationsLog({ logMessages }: Props) { + return ( + + + {logMessages.map((logMessage, i) => { + const [timestamp, message] = logMessage.split(': '); + return ( +

+ + {asAbsoluteDateTime(timestamp)} {message} + +

+ ); + })} +
+ + ); +} diff --git a/x-pack/plugins/apm/public/components/app/correlations/correlations_table.tsx b/x-pack/plugins/apm/public/components/app/correlations/correlations_table.tsx index 28f671183ed87..f7e62b76a61c0 100644 --- a/x-pack/plugins/apm/public/components/app/correlations/correlations_table.tsx +++ b/x-pack/plugins/apm/public/components/app/correlations/correlations_table.tsx @@ -9,10 +9,12 @@ import React, { useCallback, useMemo, useState } from 'react'; import { debounce } from 'lodash'; import { EuiBasicTable, EuiBasicTableColumn } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; +import type { EuiTableSortingType } from '@elastic/eui/src/components/basic_table/table_types'; +import type { Criteria } from '@elastic/eui/src/components/basic_table/basic_table'; import { FETCH_STATUS } from '../../../hooks/use_fetcher'; import { useUiTracker } from '../../../../../observability/public'; import { useTheme } from '../../../hooks/use_theme'; -import { CorrelationsTerm } from '../../../../common/search_strategies/failure_correlations/types'; +import type { CorrelationsTerm } from '../../../../common/search_strategies/failure_correlations/types'; const PAGINATION_SIZE_OPTIONS = [5, 10, 20, 50]; @@ -29,6 +31,8 @@ interface Props { selectedTerm?: { fieldName: string; fieldValue: string }; onFilter?: () => void; columns: Array>; + onTableChange: (c: Criteria) => void; + sorting?: EuiTableSortingType; } export function CorrelationsTable({ @@ -37,6 +41,8 @@ export function CorrelationsTable({ setSelectedSignificantTerm, columns, selectedTerm, + onTableChange, + sorting, }: Props) { const euiTheme = useTheme(); const trackApmEvent = useUiTracker({ app: 'apm' }); @@ -67,12 +73,17 @@ export function CorrelationsTable({ }; }, [pageIndex, pageSize, significantTerms]); - const onTableChange = useCallback(({ page }) => { - const { index, size } = page; + const onChange = useCallback( + (tableSettings) => { + const { index, size } = tableSettings.page; - setPageIndex(index); - setPageSize(size); - }, []); + setPageIndex(index); + setPageSize(size); + + onTableChange(tableSettings); + }, + [onTableChange] + ); return ( ({ }; }} pagination={pagination} - onChange={onTableChange} + onChange={onChange} + sorting={sorting} /> ); } diff --git a/x-pack/plugins/apm/public/components/app/correlations/cross_cluster_search_warning.tsx b/x-pack/plugins/apm/public/components/app/correlations/cross_cluster_search_warning.tsx new file mode 100644 index 0000000000000..9d5ca09ad3add --- /dev/null +++ b/x-pack/plugins/apm/public/components/app/correlations/cross_cluster_search_warning.tsx @@ -0,0 +1,33 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { EuiCallOut } from '@elastic/eui'; +import React from 'react'; +import { i18n } from '@kbn/i18n'; + +export function CrossClusterSearchCompatibilityWarning({ + version, +}: { + version: string; +}) { + return ( + +

+ {i18n.translate('xpack.apm.correlations.ccsWarningCalloutBody', { + defaultMessage: + 'Data for the correlation analysis could not be fully retrieved. This feature is supported only for {version} and later versions.', + values: { version }, + })} +

+
+ ); +} diff --git a/x-pack/plugins/apm/public/components/app/correlations/empty_state_prompt.tsx b/x-pack/plugins/apm/public/components/app/correlations/empty_state_prompt.tsx new file mode 100644 index 0000000000000..57e57a526baff --- /dev/null +++ b/x-pack/plugins/apm/public/components/app/correlations/empty_state_prompt.tsx @@ -0,0 +1,49 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { EuiEmptyPrompt, EuiSpacer, EuiText } from '@elastic/eui'; +import React from 'react'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; + +export function CorrelationsEmptyStatePrompt() { + return ( + <> + + +

+ {i18n.translate('xpack.apm.correlations.noCorrelationsTitle', { + defaultMessage: 'No significant correlations', + })} +

+ + } + body={ + <> + +

+ +

+

+ +

+
+ + } + /> + + ); +} diff --git a/x-pack/plugins/apm/public/components/app/correlations/failed_transactions_correlations.tsx b/x-pack/plugins/apm/public/components/app/correlations/failed_transactions_correlations.tsx index 4fdd908b6faf6..1cc115861a594 100644 --- a/x-pack/plugins/apm/public/components/app/correlations/failed_transactions_correlations.tsx +++ b/x-pack/plugins/apm/public/components/app/correlations/failed_transactions_correlations.tsx @@ -5,45 +5,46 @@ * 2.0. */ -import React, { useEffect, useMemo, useState } from 'react'; +import React, { useCallback, useEffect, useMemo, useState } from 'react'; import { - EuiCallOut, - EuiCode, - EuiAccordion, - EuiPanel, EuiBasicTableColumn, - EuiButton, EuiFlexGroup, EuiFlexItem, - EuiProgress, EuiSpacer, - EuiText, - EuiBadge, EuiIcon, EuiLink, EuiTitle, EuiBetaBadge, + EuiBadge, + EuiToolTip, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { FormattedMessage } from '@kbn/i18n/react'; import { useHistory } from 'react-router-dom'; +import { orderBy } from 'lodash'; +import type { EuiTableSortingType } from '@elastic/eui/src/components/basic_table/table_types'; +import type { Direction } from '@elastic/eui/src/services/sort/sort_direction'; import { useUrlParams } from '../../../context/url_params_context/use_url_params'; import { useApmPluginContext } from '../../../context/apm_plugin/use_apm_plugin_context'; import { CorrelationsTable } from './correlations_table'; import { enableInspectEsQueries } from '../../../../../observability/public'; import { useApmServiceContext } from '../../../context/apm_service/use_apm_service_context'; import { FailedTransactionsCorrelationsHelpPopover } from './failed_transactions_correlations_help_popover'; -import { FailedTransactionsCorrelationValue } from '../../../../common/search_strategies/failure_correlations/types'; import { ImpactBar } from '../../shared/ImpactBar'; import { isErrorMessage } from './utils/is_error_message'; -import { Summary } from '../../shared/Summary'; import { FETCH_STATUS } from '../../../hooks/use_fetcher'; import { getFailedTransactionsCorrelationImpactLabel } from './utils/get_failed_transactions_correlation_impact_label'; import { createHref, push } from '../../shared/Links/url_helpers'; import { useUiTracker } from '../../../../../observability/public'; import { useFailedTransactionsCorrelationsFetcher } from '../../../hooks/use_failed_transactions_correlations_fetcher'; -import { SearchServiceParams } from '../../../../common/search_strategies/correlations/types'; import { useApmParams } from '../../../hooks/use_apm_params'; +import { CorrelationsLog } from './correlations_log'; +import { CorrelationsEmptyStatePrompt } from './empty_state_prompt'; +import { CrossClusterSearchCompatibilityWarning } from './cross_cluster_search_warning'; +import { CorrelationsProgressControls } from './progress_controls'; +import type { SearchServiceParams } from '../../../../common/search_strategies/correlations/types'; +import type { FailedTransactionsCorrelationValue } from '../../../../common/search_strategies/failure_correlations/types'; +import { Summary } from '../../shared/Summary'; +import { asPercent } from '../../../../common/utils/formatters'; export function FailedTransactionsCorrelations({ onFilter, @@ -64,7 +65,7 @@ export function FailedTransactionsCorrelations({ const { urlParams } = useUrlParams(); const { transactionName, start, end } = urlParams; - const displayLog = uiSettings.get(enableInspectEsQueries); + const inspectEnabled = uiSettings.get(enableInspectEsQueries); const searchServicePrams: SearchServiceParams = { environment, @@ -76,7 +77,7 @@ export function FailedTransactionsCorrelations({ end, }; - const result = useFailedTransactionsCorrelationsFetcher(searchServicePrams); + const result = useFailedTransactionsCorrelationsFetcher(); const { ccsWarning, @@ -87,10 +88,20 @@ export function FailedTransactionsCorrelations({ startFetch, cancelFetch, } = result; + + const startFetchHandler = useCallback(() => { + startFetch(searchServicePrams); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [environment, serviceName, kuery, start, end]); + // start fetching on load // we want this effect to execute exactly once after the component mounts useEffect(() => { - startFetch(); + if (isRunning) { + cancelFetch(); + } + + startFetchHandler(); return () => { // cancel any running async partial request when unmounting the component @@ -98,7 +109,7 @@ export function FailedTransactionsCorrelations({ cancelFetch(); }; // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); + }, [startFetchHandler]); const [ selectedSignificantTerm, @@ -118,10 +129,83 @@ export function FailedTransactionsCorrelations({ const failedTransactionsCorrelationsColumns: Array< EuiBasicTableColumn - > = useMemo( - () => [ + > = useMemo(() => { + const percentageColumns: Array< + EuiBasicTableColumn + > = inspectEnabled + ? [ + { + width: '100px', + field: 'failurePercentage', + name: ( + + <> + {i18n.translate( + 'xpack.apm.correlations.failedTransactions.correlationsTable.failurePercentageLabel', + { + defaultMessage: 'Failure %', + } + )} + + + + ), + render: (failurePercentage: number) => + asPercent(failurePercentage, 1), + sortable: true, + }, + { + field: 'successPercentage', + width: '100px', + name: ( + + <> + {i18n.translate( + 'xpack.apm.correlations.failedTransactions.correlationsTable.successPercentageLabel', + { + defaultMessage: 'Success %', + } + )} + + + + ), + + render: (successPercentage: number) => + asPercent(successPercentage, 1), + sortable: true, + }, + ] + : []; + return [ { - width: '116px', + width: '80px', field: 'normalizedScore', name: ( <> @@ -140,6 +224,7 @@ export function FailedTransactionsCorrelations({ ); }, + sortable: true, }, { width: '116px', @@ -154,7 +239,13 @@ export function FailedTransactionsCorrelations({ )} ), - render: getFailedTransactionsCorrelationImpactLabel, + render: (pValue: number) => { + const label = getFailedTransactionsCorrelationImpactLabel(pValue); + return label ? ( + {label.impact} + ) : null; + }, + sortable: true, }, { field: 'fieldName', @@ -162,6 +253,7 @@ export function FailedTransactionsCorrelations({ 'xpack.apm.correlations.failedTransactions.correlationsTable.fieldNameLabel', { defaultMessage: 'Field name' } ), + sortable: true, }, { field: 'key', @@ -170,7 +262,9 @@ export function FailedTransactionsCorrelations({ { defaultMessage: 'Field value' } ), render: (fieldValue: string) => String(fieldValue).slice(0, 50), + sortable: true, }, + ...percentageColumns, { width: '100px', actions: [ @@ -188,9 +282,7 @@ export function FailedTransactionsCorrelations({ onClick: (term: FailedTransactionsCorrelationValue) => { push(history, { query: { - kuery: `${term.fieldName}:"${encodeURIComponent( - term.fieldValue - )}"`, + kuery: `${term.fieldName}:"${term.fieldValue}"`, }, }); onFilter(); @@ -211,9 +303,7 @@ export function FailedTransactionsCorrelations({ onClick: (term: FailedTransactionsCorrelationValue) => { push(history, { query: { - kuery: `not ${term.fieldName}:"${encodeURIComponent( - term.fieldValue - )}"`, + kuery: `not ${term.fieldName}:"${term.fieldValue}"`, }, }); onFilter(); @@ -231,9 +321,7 @@ export function FailedTransactionsCorrelations({ @@ -243,9 +331,7 @@ export function FailedTransactionsCorrelations({ @@ -255,9 +341,8 @@ export function FailedTransactionsCorrelations({ ); }, }, - ], - [history, onFilter, trackApmEvent] - ); + ] as Array>; + }, [history, onFilter, trackApmEvent, inspectEnabled]); useEffect(() => { if (isErrorMessage(error)) { @@ -273,100 +358,124 @@ export function FailedTransactionsCorrelations({ }); } }, [error, notifications.toasts]); + + const [sortField, setSortField] = useState< + keyof FailedTransactionsCorrelationValue + >('normalizedScore'); + const [sortDirection, setSortDirection] = useState('desc'); + + const onTableChange = useCallback(({ sort }) => { + const { field: currentSortField, direction: currentSortDirection } = sort; + + setSortField(currentSortField); + setSortDirection(currentSortDirection); + }, []); + + const { sorting, correlationTerms } = useMemo(() => { + if (!Array.isArray(result.values)) { + return { correlationTerms: [], sorting: undefined }; + } + const orderedTerms = orderBy( + result.values, + // The smaller the p value the higher the impact + // So we want to sort by the normalized score here + // which goes from 0 -> 1 + sortField === 'pValue' ? 'normalizedScore' : sortField, + sortDirection + ); + return { + correlationTerms: orderedTerms, + sorting: { + sort: { + field: sortField, + direction: sortDirection, + }, + } as EuiTableSortingType, + }; + }, [result?.values, sortField, sortDirection]); + return ( - <> - - - -
- {i18n.translate( - 'xpack.apm.correlations.failedTransactions.panelTitle', +
+ + + + +
+ {i18n.translate( + 'xpack.apm.correlations.failedTransactions.panelTitle', + { + defaultMessage: 'Failed transactions', + } + )} +
+
+
+ + + - - + title={i18n.translate( + 'xpack.apm.transactionDetails.tabs.failedTransactionsCorrelationsBetaTitle', + { + defaultMessage: 'Failed transaction correlations', + } + )} + tooltipContent={i18n.translate( + 'xpack.apm.transactionDetails.tabs.failedTransactionsCorrelationsBetaDescription', + { + defaultMessage: + 'Failed transaction correlations is not GA. Please help us by reporting any bugs.', + } + )} + /> +
+ - + - + - - - {!isRunning && ( - - - - )} - {isRunning && ( - - - + + + + + {i18n.translate( + 'xpack.apm.correlations.failedTransactions.tableTitle', + { + defaultMessage: 'Correlations', + } )} - - - - - - - - - - - - - - - - - - {selectedTerm?.pValue != null ? ( + + + + + + + + {ccsWarning && ( + <> + + + + )} + + {inspectEnabled && + selectedTerm?.pValue != null && + (isRunning || correlationTerms.length > 0) ? ( <> {`p-value: ${selectedTerm.pValue.toPrecision(3)}`}, ]} /> - ) : null} - - columns={failedTransactionsCorrelationsColumns} - significantTerms={result?.values} - status={FETCH_STATUS.SUCCESS} - setSelectedSignificantTerm={setSelectedSignificantTerm} - selectedTerm={selectedTerm} - /> - {ccsWarning && ( - <> - - -

- {i18n.translate( - 'xpack.apm.correlations.failedTransactions.ccsWarningCalloutBody', - { - defaultMessage: - 'Data for the correlation analysis could not be fully retrieved. This feature is supported only for 7.15 and later versions.', - } - )} -

-
- - )} - {log.length > 0 && displayLog && ( - - - {log.map((d, i) => { - const splitItem = d.split(': '); - return ( -

- - {splitItem[0]} {splitItem[1]} - -

- ); - })} -
-
- )} - +
+ {(isRunning || correlationTerms.length > 0) && ( + + columns={failedTransactionsCorrelationsColumns} + significantTerms={correlationTerms} + status={isRunning ? FETCH_STATUS.LOADING : FETCH_STATUS.SUCCESS} + setSelectedSignificantTerm={setSelectedSignificantTerm} + selectedTerm={selectedTerm} + onTableChange={onTableChange} + sorting={sorting} + /> + )} + {correlationTerms.length < 1 && (progress === 1 || !isRunning) && ( + + )} +
+ {inspectEnabled && } +
); } diff --git a/x-pack/plugins/apm/public/components/app/correlations/failed_transactions_correlations_help_popover.tsx b/x-pack/plugins/apm/public/components/app/correlations/failed_transactions_correlations_help_popover.tsx index bebc889cc4ed9..e66101d619224 100644 --- a/x-pack/plugins/apm/public/components/app/correlations/failed_transactions_correlations_help_popover.tsx +++ b/x-pack/plugins/apm/public/components/app/correlations/failed_transactions_correlations_help_popover.tsx @@ -18,6 +18,7 @@ export function FailedTransactionsCorrelationsHelpPopover() { anchorPosition="leftUp" button={ { setIsPopoverOpen((prevIsPopoverOpen) => !prevIsPopoverOpen); }} @@ -25,25 +26,28 @@ export function FailedTransactionsCorrelationsHelpPopover() { } closePopover={() => setIsPopoverOpen(false)} isOpen={isPopoverOpen} - title={i18n.translate('xpack.apm.correlations.failurePopoverTitle', { - defaultMessage: 'Failure correlations', - })} + title={i18n.translate( + 'xpack.apm.correlations.failedTransactions.helpPopover.title', + { + defaultMessage: 'Failed transaction correlations', + } + )} >

diff --git a/x-pack/plugins/apm/public/components/app/correlations/latency_correlations.tsx b/x-pack/plugins/apm/public/components/app/correlations/latency_correlations.tsx index 6d6e56184e254..ed47d49948fba 100644 --- a/x-pack/plugins/apm/public/components/app/correlations/latency_correlations.tsx +++ b/x-pack/plugins/apm/public/components/app/correlations/latency_correlations.tsx @@ -8,24 +8,18 @@ import React, { useCallback, useEffect, useMemo, useState } from 'react'; import { useHistory } from 'react-router-dom'; import { - EuiCallOut, - EuiCode, - EuiEmptyPrompt, - EuiAccordion, - EuiPanel, EuiIcon, EuiBasicTableColumn, - EuiButton, EuiFlexGroup, EuiFlexItem, - EuiProgress, EuiSpacer, - EuiText, EuiTitle, EuiToolTip, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { FormattedMessage } from '@kbn/i18n/react'; +import { Direction } from '@elastic/eui/src/services/sort/sort_direction'; +import { orderBy } from 'lodash'; +import { EuiTableSortingType } from '@elastic/eui/src/components/basic_table/table_types'; import { useUrlParams } from '../../../context/url_params_context/use_url_params'; import { useApmPluginContext } from '../../../context/apm_plugin/use_apm_plugin_context'; import { FETCH_STATUS } from '../../../hooks/use_fetcher'; @@ -42,6 +36,10 @@ import { useApmServiceContext } from '../../../context/apm_service/use_apm_servi import { LatencyCorrelationsHelpPopover } from './latency_correlations_help_popover'; import { useApmParams } from '../../../hooks/use_apm_params'; import { isErrorMessage } from './utils/is_error_message'; +import { CorrelationsLog } from './correlations_log'; +import { CorrelationsEmptyStatePrompt } from './empty_state_prompt'; +import { CrossClusterSearchCompatibilityWarning } from './cross_cluster_search_warning'; +import { CorrelationsProgressControls } from './progress_controls'; const DEFAULT_PERCENTILE_THRESHOLD = 95; @@ -133,15 +131,19 @@ export function LatencyCorrelations({ onFilter }: { onFilter: () => void }) { setSelectedSignificantTerm, ] = useState(null); - let selectedHistogram = histograms.length > 0 ? histograms[0] : undefined; + const selectedHistogram = useMemo(() => { + let selected = histograms.length > 0 ? histograms[0] : undefined; + + if (histograms.length > 0 && selectedSignificantTerm !== null) { + selected = histograms.find( + (h) => + h.field === selectedSignificantTerm.fieldName && + h.value === selectedSignificantTerm.fieldValue + ); + } + return selected; + }, [histograms, selectedSignificantTerm]); - if (histograms.length > 0 && selectedSignificantTerm !== null) { - selectedHistogram = histograms.find( - (h) => - h.field === selectedSignificantTerm.fieldName && - h.value === selectedSignificantTerm.fieldValue - ); - } const history = useHistory(); const trackApmEvent = useUiTracker({ app: 'apm' }); @@ -181,6 +183,7 @@ export function LatencyCorrelations({ onFilter }: { onFilter: () => void }) { render: (correlation: number) => { return
{asPreciseDecimal(correlation, 2)}
; }, + sortable: true, }, { field: 'fieldName', @@ -188,6 +191,7 @@ export function LatencyCorrelations({ onFilter }: { onFilter: () => void }) { 'xpack.apm.correlations.latencyCorrelations.correlationsTable.fieldNameLabel', { defaultMessage: 'Field name' } ), + sortable: true, }, { field: 'fieldValue', @@ -196,6 +200,7 @@ export function LatencyCorrelations({ onFilter }: { onFilter: () => void }) { { defaultMessage: 'Field value' } ), render: (fieldValue: string) => String(fieldValue).slice(0, 50), + sortable: true, }, { width: '100px', @@ -214,9 +219,7 @@ export function LatencyCorrelations({ onFilter }: { onFilter: () => void }) { onClick: (term: MlCorrelationsTerms) => { push(history, { query: { - kuery: `${term.fieldName}:"${encodeURIComponent( - term.fieldValue - )}"`, + kuery: `${term.fieldName}:"${term.fieldValue}"`, }, }); onFilter(); @@ -237,9 +240,7 @@ export function LatencyCorrelations({ onFilter }: { onFilter: () => void }) { onClick: (term: MlCorrelationsTerms) => { push(history, { query: { - kuery: `not ${term.fieldName}:"${encodeURIComponent( - term.fieldValue - )}"`, + kuery: `not ${term.fieldName}:"${term.fieldValue}"`, }, }); onFilter(); @@ -256,17 +257,46 @@ export function LatencyCorrelations({ onFilter }: { onFilter: () => void }) { [history, onFilter, trackApmEvent] ); - const histogramTerms: MlCorrelationsTerms[] = useMemo(() => { - return histograms.map((d) => { - return { - fieldName: d.field, - fieldValue: d.value, - ksTest: d.ksTest, - correlation: d.correlation, - duplicatedFields: d.duplicatedFields, - }; - }); - }, [histograms]); + const [sortField, setSortField] = useState( + 'correlation' + ); + const [sortDirection, setSortDirection] = useState('desc'); + + const onTableChange = useCallback(({ sort }) => { + const { field: currentSortField, direction: currentSortDirection } = sort; + + setSortField(currentSortField); + setSortDirection(currentSortDirection); + }, []); + + const { histogramTerms, sorting } = useMemo(() => { + if (!Array.isArray(histograms)) { + return { histogramTerms: [], sorting: undefined }; + } + const orderedTerms = orderBy( + histograms.map((d) => { + return { + fieldName: d.field, + fieldValue: d.value, + ksTest: d.ksTest, + correlation: d.correlation, + duplicatedFields: d.duplicatedFields, + }; + }), + sortField, + sortDirection + ); + + return { + histogramTerms: orderedTerms, + sorting: { + sort: { + field: sortField, + direction: sortDirection, + }, + } as EuiTableSortingType, + }; + }, [histograms, sortField, sortDirection]); return (
@@ -300,88 +330,34 @@ export function LatencyCorrelations({ onFilter }: { onFilter: () => void }) { - +
{i18n.translate( 'xpack.apm.correlations.latencyCorrelations.tableTitle', { defaultMessage: 'Correlations', } )} - +
- - - - - - - - - - - - - - - {!isRunning && ( - - - - )} - {isRunning && ( - - - - )} - - + + {ccsWarning && ( <> - -

- {i18n.translate( - 'xpack.apm.correlations.latencyCorrelations.ccsWarningCalloutBody', - { - defaultMessage: - 'Data for the correlation analysis could not be fully retrieved. This feature is supported only for 7.14 and later versions.', - } - )} -

-
+ )} + +
{(isRunning || histogramTerms.length > 0) && ( @@ -397,70 +373,15 @@ export function LatencyCorrelations({ onFilter }: { onFilter: () => void }) { } : undefined } + onTableChange={onTableChange} + sorting={sorting} /> )} {histogramTerms.length < 1 && (progress === 1 || !isRunning) && ( - <> - - -

- {i18n.translate( - 'xpack.apm.correlations.latencyCorrelations.noCorrelationsTitle', - { - defaultMessage: 'No significant correlations', - } - )} -

- - } - body={ - <> - - - - {/* Another EuiText element to enforce a line break */} - - - - - } - /> - + )}
- {log.length > 0 && displayLog && ( - - - {log.map((d, i) => { - const splitItem = d.split(': '); - return ( -

- - {splitItem[0]} {splitItem[1]} - -

- ); - })} -
-
- )} + {displayLog && }
); } diff --git a/x-pack/plugins/apm/public/components/app/correlations/progress_controls.tsx b/x-pack/plugins/apm/public/components/app/correlations/progress_controls.tsx new file mode 100644 index 0000000000000..a581313d6a5d5 --- /dev/null +++ b/x-pack/plugins/apm/public/components/app/correlations/progress_controls.tsx @@ -0,0 +1,77 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { + EuiButton, + EuiFlexGroup, + EuiFlexItem, + EuiProgress, + EuiText, +} from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; +import React from 'react'; + +export function CorrelationsProgressControls({ + progress, + onRefresh, + onCancel, + isRunning, +}: { + progress: number; + onRefresh: () => void; + onCancel: () => void; + isRunning: boolean; +}) { + return ( + + + + + + + + + + + + + + + {!isRunning && ( + + + + )} + {isRunning && ( + + + + )} + + + ); +} diff --git a/x-pack/plugins/apm/public/components/app/correlations/utils/get_failed_transactions_correlation_impact_label.test.ts b/x-pack/plugins/apm/public/components/app/correlations/utils/get_failed_transactions_correlation_impact_label.test.ts index d133ed1060ebe..edb7c8c16e267 100644 --- a/x-pack/plugins/apm/public/components/app/correlations/utils/get_failed_transactions_correlation_impact_label.test.ts +++ b/x-pack/plugins/apm/public/components/app/correlations/utils/get_failed_transactions_correlation_impact_label.test.ts @@ -8,6 +8,20 @@ import { getFailedTransactionsCorrelationImpactLabel } from './get_failed_transactions_correlation_impact_label'; import { FAILED_TRANSACTIONS_IMPACT_THRESHOLD } from '../../../../../common/search_strategies/failure_correlations/constants'; +const EXPECTED_RESULT = { + HIGH: { + impact: FAILED_TRANSACTIONS_IMPACT_THRESHOLD.HIGH, + color: 'danger', + }, + MEDIUM: { + impact: FAILED_TRANSACTIONS_IMPACT_THRESHOLD.MEDIUM, + color: 'warning', + }, + LOW: { + impact: FAILED_TRANSACTIONS_IMPACT_THRESHOLD.LOW, + color: 'default', + }, +}; describe('getFailedTransactionsCorrelationImpactLabel', () => { it('returns null if value is invalid ', () => { expect(getFailedTransactionsCorrelationImpactLabel(-0.03)).toBe(null); @@ -21,32 +35,32 @@ describe('getFailedTransactionsCorrelationImpactLabel', () => { }); it('returns High if value is within [0, 1e-6) ', () => { - expect(getFailedTransactionsCorrelationImpactLabel(0)).toBe( - FAILED_TRANSACTIONS_IMPACT_THRESHOLD.HIGH + expect(getFailedTransactionsCorrelationImpactLabel(0)).toStrictEqual( + EXPECTED_RESULT.HIGH ); - expect(getFailedTransactionsCorrelationImpactLabel(1e-7)).toBe( - FAILED_TRANSACTIONS_IMPACT_THRESHOLD.HIGH + expect(getFailedTransactionsCorrelationImpactLabel(1e-7)).toStrictEqual( + EXPECTED_RESULT.HIGH ); }); it('returns Medium if value is within [1e-6, 1e-3) ', () => { - expect(getFailedTransactionsCorrelationImpactLabel(1e-6)).toBe( - FAILED_TRANSACTIONS_IMPACT_THRESHOLD.MEDIUM + expect(getFailedTransactionsCorrelationImpactLabel(1e-6)).toStrictEqual( + EXPECTED_RESULT.MEDIUM ); - expect(getFailedTransactionsCorrelationImpactLabel(1e-5)).toBe( - FAILED_TRANSACTIONS_IMPACT_THRESHOLD.MEDIUM + expect(getFailedTransactionsCorrelationImpactLabel(1e-5)).toStrictEqual( + EXPECTED_RESULT.MEDIUM ); - expect(getFailedTransactionsCorrelationImpactLabel(1e-4)).toBe( - FAILED_TRANSACTIONS_IMPACT_THRESHOLD.MEDIUM + expect(getFailedTransactionsCorrelationImpactLabel(1e-4)).toStrictEqual( + EXPECTED_RESULT.MEDIUM ); }); it('returns Low if value is within [1e-3, 0.02) ', () => { - expect(getFailedTransactionsCorrelationImpactLabel(1e-3)).toBe( - FAILED_TRANSACTIONS_IMPACT_THRESHOLD.LOW + expect(getFailedTransactionsCorrelationImpactLabel(1e-3)).toStrictEqual( + EXPECTED_RESULT.LOW ); - expect(getFailedTransactionsCorrelationImpactLabel(0.009)).toBe( - FAILED_TRANSACTIONS_IMPACT_THRESHOLD.LOW + expect(getFailedTransactionsCorrelationImpactLabel(0.009)).toStrictEqual( + EXPECTED_RESULT.LOW ); }); }); diff --git a/x-pack/plugins/apm/public/components/app/correlations/utils/get_failed_transactions_correlation_impact_label.ts b/x-pack/plugins/apm/public/components/app/correlations/utils/get_failed_transactions_correlation_impact_label.ts index af64c50617019..5a806aba5371e 100644 --- a/x-pack/plugins/apm/public/components/app/correlations/utils/get_failed_transactions_correlation_impact_label.ts +++ b/x-pack/plugins/apm/public/components/app/correlations/utils/get_failed_transactions_correlation_impact_label.ts @@ -10,14 +10,23 @@ import { FAILED_TRANSACTIONS_IMPACT_THRESHOLD } from '../../../../../common/sear export function getFailedTransactionsCorrelationImpactLabel( pValue: number -): FailureCorrelationImpactThreshold | null { +): { impact: FailureCorrelationImpactThreshold; color: string } | null { // The lower the p value, the higher the impact if (pValue >= 0 && pValue < 1e-6) - return FAILED_TRANSACTIONS_IMPACT_THRESHOLD.HIGH; + return { + impact: FAILED_TRANSACTIONS_IMPACT_THRESHOLD.HIGH, + color: 'danger', + }; if (pValue >= 1e-6 && pValue < 0.001) - return FAILED_TRANSACTIONS_IMPACT_THRESHOLD.MEDIUM; + return { + impact: FAILED_TRANSACTIONS_IMPACT_THRESHOLD.MEDIUM, + color: 'warning', + }; if (pValue >= 0.001 && pValue < 0.02) - return FAILED_TRANSACTIONS_IMPACT_THRESHOLD.LOW; + return { + impact: FAILED_TRANSACTIONS_IMPACT_THRESHOLD.LOW, + color: 'default', + }; return null; } diff --git a/x-pack/plugins/apm/public/components/app/transaction_details/distribution/index.tsx b/x-pack/plugins/apm/public/components/app/transaction_details/distribution/index.tsx index 2506ac69f7aa2..86bef9917daf6 100644 --- a/x-pack/plugins/apm/public/components/app/transaction_details/distribution/index.tsx +++ b/x-pack/plugins/apm/public/components/app/transaction_details/distribution/index.tsx @@ -28,6 +28,9 @@ import { useApmParams } from '../../../../hooks/use_apm_params'; import { isErrorMessage } from '../../correlations/utils/is_error_message'; const DEFAULT_PERCENTILE_THRESHOLD = 95; +// Enforce min height so it's consistent across all tabs on the same level +// to prevent "flickering" behavior +const MIN_TAB_TITLE_HEIGHT = 56; type Selection = [number, number]; @@ -147,7 +150,7 @@ export function TransactionDistribution({ return (
- +
diff --git a/x-pack/plugins/apm/public/components/app/transaction_details/failed_transactions_correlations_tab.tsx b/x-pack/plugins/apm/public/components/app/transaction_details/failed_transactions_correlations_tab.tsx index 8743b8f3ea811..af66f818309a0 100644 --- a/x-pack/plugins/apm/public/components/app/transaction_details/failed_transactions_correlations_tab.tsx +++ b/x-pack/plugins/apm/public/components/app/transaction_details/failed_transactions_correlations_tab.tsx @@ -46,7 +46,7 @@ function FailedTransactionsCorrelationsTab({ onFilter }: TabContentProps) { text={i18n.translate( 'xpack.apm.failedTransactionsCorrelations.licenseCheckText', { - defaultMessage: `To use the failed transactions correlations feature, you must be subscribed to an Elastic Platinum license.`, + defaultMessage: `To use the failed transaction correlations feature, you must be subscribed to an Elastic Platinum license. With it, you'll be able to discover which attributes are contributing to failed transactions.`, } )} /> diff --git a/x-pack/plugins/apm/public/hooks/use_failed_transactions_correlations_fetcher.ts b/x-pack/plugins/apm/public/hooks/use_failed_transactions_correlations_fetcher.ts index 3841419e860fc..add00968f0444 100644 --- a/x-pack/plugins/apm/public/hooks/use_failed_transactions_correlations_fetcher.ts +++ b/x-pack/plugins/apm/public/hooks/use_failed_transactions_correlations_fetcher.ts @@ -38,9 +38,7 @@ interface FailedTransactionsCorrelationsFetcherState { total: number; } -export const useFailedTransactionsCorrelationsFetcher = ( - params: Omit -) => { +export const useFailedTransactionsCorrelationsFetcher = () => { const { services: { data }, } = useKibana(); @@ -74,7 +72,7 @@ export const useFailedTransactionsCorrelationsFetcher = ( })); } - const startFetch = () => { + const startFetch = (params: SearchServiceParams) => { setFetchState((prevState) => ({ ...prevState, error: undefined, diff --git a/x-pack/plugins/apm/server/lib/search_strategies/failed_transactions_correlations/async_search_service.ts b/x-pack/plugins/apm/server/lib/search_strategies/failed_transactions_correlations/async_search_service.ts index 9afe9d916b38e..89fcda926d547 100644 --- a/x-pack/plugins/apm/server/lib/search_strategies/failed_transactions_correlations/async_search_service.ts +++ b/x-pack/plugins/apm/server/lib/search_strategies/failed_transactions_correlations/async_search_service.ts @@ -15,6 +15,7 @@ import { fetchTransactionDurationFieldCandidates } from '../correlations/queries import type { SearchServiceFetchParams } from '../../../../common/search_strategies/correlations/types'; import { fetchFailedTransactionsCorrelationPValues } from './queries/query_failure_correlation'; import { ERROR_CORRELATION_THRESHOLD } from './constants'; +import { EVENT_OUTCOME } from '../../../../common/elasticsearch_fieldnames'; export const asyncErrorCorrelationSearchServiceProvider = ( esClient: ElasticsearchClient, @@ -35,10 +36,11 @@ export const asyncErrorCorrelationSearchServiceProvider = ( includeFrozen, }; - const { fieldCandidates } = await fetchTransactionDurationFieldCandidates( - esClient, - params - ); + const { + fieldCandidates: candidates, + } = await fetchTransactionDurationFieldCandidates(esClient, params); + + const fieldCandidates = candidates.filter((t) => !(t === EVENT_OUTCOME)); addLogMessage(`Identified ${fieldCandidates.length} fieldCandidates.`); diff --git a/x-pack/plugins/apm/server/lib/search_strategies/failed_transactions_correlations/queries/query_failure_correlation.ts b/x-pack/plugins/apm/server/lib/search_strategies/failed_transactions_correlations/queries/query_failure_correlation.ts index 22424d68f07ff..81fe6697d1fb1 100644 --- a/x-pack/plugins/apm/server/lib/search_strategies/failed_transactions_correlations/queries/query_failure_correlation.ts +++ b/x-pack/plugins/apm/server/lib/search_strategies/failed_transactions_correlations/queries/query_failure_correlation.ts @@ -75,14 +75,15 @@ export const fetchFailedTransactionsCorrelationPValues = async ( ); } - const result = (resp.body.aggregations - .failure_p_value as estypes.AggregationsMultiBucketAggregate<{ + const overallResult = resp.body.aggregations + .failure_p_value as estypes.AggregationsSignificantTermsAggregate<{ key: string; doc_count: number; bg_count: number; score: number; - }>).buckets.map((b) => { - const score = b.score; + }>; + const result = overallResult.buckets.map((bucket) => { + const score = bucket.score; // Scale the score into a value from 0 - 1 // using a concave piecewise linear function in -log(p-value) @@ -92,11 +93,17 @@ export const fetchFailedTransactionsCorrelationPValues = async ( 0.25 * Math.min(Math.max((score - 13.816) / 101.314, 0), 1); return { - ...b, + ...bucket, fieldName, - fieldValue: b.key, + fieldValue: bucket.key, pValue: Math.exp(-score), normalizedScore, + // Percentage of time the term appears in failed transactions + failurePercentage: bucket.doc_count / overallResult.doc_count, + // Percentage of time the term appears in successful transactions + successPercentage: + (bucket.bg_count - bucket.doc_count) / + (overallResult.bg_count - overallResult.doc_count), }; }); diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 90c2913f3cd98..b5b7e35c4a9b4 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -5518,7 +5518,6 @@ "xpack.apm.correlations.customize.fieldPlaceholder": "オプションを選択または作成", "xpack.apm.correlations.customize.thresholdLabel": "しきい値", "xpack.apm.correlations.customize.thresholdPercentile": "{percentile}パーセンタイル", - "xpack.apm.correlations.latencyCorrelations.cancelButtonTitle": "キャンセル", "xpack.apm.correlations.latencyCorrelations.correlationsTable.actionsLabel": "フィルター", "xpack.apm.correlations.latencyCorrelations.correlationsTable.correlationColumnDescription": "サービスの遅延に対するフィールドの影響。0~1の範囲。", "xpack.apm.correlations.latencyCorrelations.correlationsTable.correlationLabel": "相関関係", @@ -5529,9 +5528,6 @@ "xpack.apm.correlations.latencyCorrelations.correlationsTable.filterDescription": "値でフィルタリング", "xpack.apm.correlations.latencyCorrelations.correlationsTable.filterLabel": "フィルター", "xpack.apm.correlations.latencyCorrelations.errorTitle": "相関関係の取得中にエラーが発生しました", - "xpack.apm.correlations.latencyCorrelations.progressAriaLabel": "進捗", - "xpack.apm.correlations.latencyCorrelations.progressTitle": "進捗状況: {progress}%", - "xpack.apm.correlations.latencyCorrelations.refreshButtonTitle": "更新", "xpack.apm.csm.breakdownFilter.browser": "ブラウザー", "xpack.apm.csm.breakdownFilter.device": "デバイス", "xpack.apm.csm.breakdownFilter.location": "場所", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index fae942e60c39b..1a21d16c80f03 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -5543,7 +5543,6 @@ "xpack.apm.correlations.customize.fieldPlaceholder": "选择或创建选项", "xpack.apm.correlations.customize.thresholdLabel": "阈值", "xpack.apm.correlations.customize.thresholdPercentile": "第 {percentile} 个百分位数", - "xpack.apm.correlations.latencyCorrelations.cancelButtonTitle": "取消", "xpack.apm.correlations.latencyCorrelations.correlationsTable.actionsLabel": "筛选", "xpack.apm.correlations.latencyCorrelations.correlationsTable.correlationColumnDescription": "字段对服务延迟的影响,范围从 0 到 1。", "xpack.apm.correlations.latencyCorrelations.correlationsTable.correlationLabel": "相关性", @@ -5554,9 +5553,6 @@ "xpack.apm.correlations.latencyCorrelations.correlationsTable.filterDescription": "按值筛选", "xpack.apm.correlations.latencyCorrelations.correlationsTable.filterLabel": "筛选", "xpack.apm.correlations.latencyCorrelations.errorTitle": "提取关联性时发生错误", - "xpack.apm.correlations.latencyCorrelations.progressAriaLabel": "进度", - "xpack.apm.correlations.latencyCorrelations.progressTitle": "进度:{progress}%", - "xpack.apm.correlations.latencyCorrelations.refreshButtonTitle": "刷新", "xpack.apm.csm.breakdownFilter.browser": "浏览器", "xpack.apm.csm.breakdownFilter.device": "设备", "xpack.apm.csm.breakdownFilter.location": "位置", diff --git a/x-pack/test/apm_api_integration/common/utils/parse_b_fetch.ts b/x-pack/test/apm_api_integration/common/utils/parse_b_fetch.ts new file mode 100644 index 0000000000000..79ea70f7199f9 --- /dev/null +++ b/x-pack/test/apm_api_integration/common/utils/parse_b_fetch.ts @@ -0,0 +1,15 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import request from 'superagent'; + +export function parseBfetchResponse(resp: request.Response): Array> { + return resp.text + .trim() + .split('\n') + .map((item) => JSON.parse(item)); +} diff --git a/x-pack/test/apm_api_integration/tests/correlations/failed_transactions.ts b/x-pack/test/apm_api_integration/tests/correlations/failed_transactions.ts new file mode 100644 index 0000000000000..2d014b3ee1e6b --- /dev/null +++ b/x-pack/test/apm_api_integration/tests/correlations/failed_transactions.ts @@ -0,0 +1,238 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; +import { FtrProviderContext } from '../../common/ftr_provider_context'; +import { registry } from '../../common/registry'; +import { PartialSearchRequest } from '../../../../plugins/apm/server/lib/search_strategies/correlations/search_strategy'; +import { parseBfetchResponse } from '../../common/utils/parse_b_fetch'; + +export default function ApiTest({ getService }: FtrProviderContext) { + const retry = getService('retry'); + const supertest = getService('supertest'); + + const getRequestBody = () => { + const partialSearchRequest: PartialSearchRequest = { + params: { + environment: 'ENVIRONMENT_ALL', + start: '2020', + end: '2021', + kuery: '', + }, + }; + + return { + batch: [ + { + request: partialSearchRequest, + options: { strategy: 'apmFailedTransactionsCorrelationsSearchStrategy' }, + }, + ], + }; + }; + + registry.when('on trial license without data', { config: 'trial', archives: [] }, () => { + it('queries the search strategy and returns results', async () => { + const intialResponse = await supertest + .post(`/internal/bsearch`) + .set('kbn-xsrf', 'foo') + .send(getRequestBody()); + + expect(intialResponse.status).to.eql( + 200, + `Expected status to be '200', got '${intialResponse.status}'` + ); + expect(intialResponse.body).to.eql( + {}, + `Expected response body to be an empty object, actual response is in the text attribute. Got: '${JSON.stringify( + intialResponse.body + )}'` + ); + + const body = parseBfetchResponse(intialResponse)[0]; + + expect(typeof body.result).to.be('object'); + const { result } = body; + + expect(typeof result?.id).to.be('string'); + + // pass on id for follow up queries + const searchStrategyId = result.id; + + // follow up request body including search strategy ID + const reqBody = getRequestBody(); + reqBody.batch[0].request.id = searchStrategyId; + + let followUpResponse: Record = {}; + + // continues querying until the search strategy finishes + await retry.waitForWithTimeout( + 'search strategy eventually completes and returns full results', + 5000, + async () => { + const response = await supertest + .post(`/internal/bsearch`) + .set('kbn-xsrf', 'foo') + .send(reqBody); + + followUpResponse = parseBfetchResponse(response)[0]; + + return ( + followUpResponse?.result?.isRunning === false || followUpResponse?.error !== undefined + ); + } + ); + + expect(followUpResponse?.error).to.eql( + undefined, + `search strategy should not return an error, got: ${JSON.stringify( + followUpResponse?.error + )}` + ); + + const followUpResult = followUpResponse.result; + expect(followUpResult?.isRunning).to.eql(false, 'search strategy should not be running'); + expect(followUpResult?.isPartial).to.eql( + false, + 'search strategy result should not be partial' + ); + expect(followUpResult?.id).to.eql( + searchStrategyId, + 'search strategy id should match original id' + ); + expect(followUpResult?.isRestored).to.eql( + true, + 'search strategy response should be restored' + ); + expect(followUpResult?.loaded).to.eql(100, 'loaded state should be 100'); + expect(followUpResult?.total).to.eql(100, 'total state should be 100'); + + expect(typeof followUpResult?.rawResponse).to.be('object'); + + const { rawResponse: finalRawResponse } = followUpResult; + + expect(typeof finalRawResponse?.took).to.be('number'); + + expect(finalRawResponse?.values.length).to.eql( + 0, + `Expected 0 identified correlations, got ${finalRawResponse?.values.length}.` + ); + }); + }); + + registry.when('on trial license with data', { config: 'trial', archives: ['8.0.0'] }, () => { + it('queries the search strategy and returns results', async () => { + const intialResponse = await supertest + .post(`/internal/bsearch`) + .set('kbn-xsrf', 'foo') + .send(getRequestBody()); + + expect(intialResponse.status).to.eql( + 200, + `Expected status to be '200', got '${intialResponse.status}'` + ); + expect(intialResponse.body).to.eql( + {}, + `Expected response body to be an empty object, actual response is in the text attribute. Got: '${JSON.stringify( + intialResponse.body + )}'` + ); + + const body = parseBfetchResponse(intialResponse)[0]; + + expect(typeof body.result).to.be('object'); + const { result } = body; + + expect(typeof result?.id).to.be('string'); + + // pass on id for follow up queries + const searchStrategyId = result.id; + + // follow up request body including search strategy ID + const reqBody = getRequestBody(); + reqBody.batch[0].request.id = searchStrategyId; + + let followUpResponse: Record = {}; + + // continues querying until the search strategy finishes + await retry.waitForWithTimeout( + 'search strategy eventually completes and returns full results', + 5000, + async () => { + const response = await supertest + .post(`/internal/bsearch`) + .set('kbn-xsrf', 'foo') + .send(reqBody); + + followUpResponse = parseBfetchResponse(response)[0]; + + return ( + followUpResponse?.result?.isRunning === false || followUpResponse?.error !== undefined + ); + } + ); + + expect(followUpResponse?.error).to.eql( + undefined, + `search strategy should not return an error, got: ${JSON.stringify( + followUpResponse?.error + )}` + ); + + const followUpResult = followUpResponse.result; + expect(followUpResult?.isRunning).to.eql(false, 'search strategy should not be running'); + expect(followUpResult?.isPartial).to.eql( + false, + 'search strategy result should not be partial' + ); + expect(followUpResult?.id).to.eql( + searchStrategyId, + 'search strategy id should match original id' + ); + expect(followUpResult?.isRestored).to.eql( + true, + 'search strategy response should be restored' + ); + expect(followUpResult?.loaded).to.eql(100, 'loaded state should be 100'); + expect(followUpResult?.total).to.eql(100, 'total state should be 100'); + + expect(typeof followUpResult?.rawResponse).to.be('object'); + + const { rawResponse: finalRawResponse } = followUpResult; + + expect(typeof finalRawResponse?.took).to.be('number'); + expect(finalRawResponse?.percentileThresholdValue).to.be(undefined); + expect(finalRawResponse?.overallHistogram).to.be(undefined); + + expect(finalRawResponse?.values.length).to.eql( + 43, + `Expected 43 identified correlations, got ${finalRawResponse?.values.length}.` + ); + + expect(finalRawResponse?.log.map((d: string) => d.split(': ')[1])).to.eql([ + 'Identified 68 fieldCandidates.', + 'Identified correlations for 68 fields out of 68 candidates.', + 'Identified 43 significant correlations relating to failed transactions.', + ]); + + const sortedCorrelations = finalRawResponse?.values.sort(); + const correlation = sortedCorrelations[0]; + + expect(typeof correlation).to.be('object'); + expect(correlation?.key).to.be('HTTP 5xx'); + expect(correlation?.doc_count).to.be(31); + expect(correlation?.score).to.be(100.17736139032642); + expect(correlation?.bg_count).to.be(60); + expect(correlation?.fieldName).to.be('transaction.result'); + expect(correlation?.fieldValue).to.be('HTTP 5xx'); + expect(typeof correlation?.pValue).to.be('number'); + expect(typeof correlation?.normalizedScore).to.be('number'); + expect(typeof correlation?.failurePercentage).to.be('number'); + expect(typeof correlation?.successPercentage).to.be('number'); + }); + }); +} diff --git a/x-pack/test/apm_api_integration/tests/correlations/latency_ml.ts b/x-pack/test/apm_api_integration/tests/correlations/latency.ts similarity index 97% rename from x-pack/test/apm_api_integration/tests/correlations/latency_ml.ts rename to x-pack/test/apm_api_integration/tests/correlations/latency.ts index e41a830735a89..32ca71694626f 100644 --- a/x-pack/test/apm_api_integration/tests/correlations/latency_ml.ts +++ b/x-pack/test/apm_api_integration/tests/correlations/latency.ts @@ -6,18 +6,10 @@ */ import expect from '@kbn/expect'; -import request from 'superagent'; import { FtrProviderContext } from '../../common/ftr_provider_context'; import { registry } from '../../common/registry'; - import { PartialSearchRequest } from '../../../../plugins/apm/server/lib/search_strategies/correlations/search_strategy'; - -function parseBfetchResponse(resp: request.Response): Array> { - return resp.text - .trim() - .split('\n') - .map((item) => JSON.parse(item)); -} +import { parseBfetchResponse } from '../../common/utils/parse_b_fetch'; export default function ApiTest({ getService }: FtrProviderContext) { const retry = getService('retry'); diff --git a/x-pack/test/apm_api_integration/tests/index.ts b/x-pack/test/apm_api_integration/tests/index.ts index 0e76a4ed86688..c8a57bc613a92 100644 --- a/x-pack/test/apm_api_integration/tests/index.ts +++ b/x-pack/test/apm_api_integration/tests/index.ts @@ -28,12 +28,17 @@ export default function apmApiIntegrationTests(providerContext: FtrProviderConte loadTestFile(require.resolve('./alerts/rule_registry')); }); + // correlations describe('correlations/latency_slow_transactions', function () { loadTestFile(require.resolve('./correlations/latency_slow_transactions')); }); - describe('correlations/latency_ml', function () { - loadTestFile(require.resolve('./correlations/latency_ml')); + describe('correlations/failed_transactions', function () { + loadTestFile(require.resolve('./correlations/failed_transactions')); + }); + + describe('correlations/latency', function () { + loadTestFile(require.resolve('./correlations/latency')); }); describe('correlations/latency_overall', function () { diff --git a/x-pack/test/functional/apps/apm/correlations/failed_transaction_correlations.ts b/x-pack/test/functional/apps/apm/correlations/failed_transaction_correlations.ts new file mode 100644 index 0000000000000..969a543e5f97d --- /dev/null +++ b/x-pack/test/functional/apps/apm/correlations/failed_transaction_correlations.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 + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; +import { FtrProviderContext } from '../../../ftr_provider_context'; + +export default function ({ getPageObjects, getService }: FtrProviderContext) { + const esArchiver = getService('esArchiver'); + const find = getService('find'); + const retry = getService('retry'); + const spacesService = getService('spaces'); + const PageObjects = getPageObjects(['common', 'error', 'timePicker', 'security']); + const testSubjects = getService('testSubjects'); + const appsMenu = getService('appsMenu'); + + const testData = { + correlationsTab: 'Failed transaction correlations', + serviceName: 'opbeans-go', + transactionsTab: 'Transactions', + transaction: 'GET /api/stats', + }; + + describe('failed transactions correlations', () => { + describe('space with no features disabled', () => { + before(async () => { + await esArchiver.load('x-pack/test/functional/es_archives/infra/8.0.0/metrics_and_apm'); + await spacesService.create({ + id: 'custom_space', + name: 'custom_space', + disabledFeatures: [], + }); + }); + + after(async () => { + await spacesService.delete('custom_space'); + }); + + it('shows apm navlink', async () => { + await PageObjects.common.navigateToApp('home', { + basePath: '/s/custom_space', + }); + const navLinks = (await appsMenu.readLinks()).map((link) => link.text); + expect(navLinks).to.contain('APM'); + }); + + it('can navigate to APM app', async () => { + await PageObjects.common.navigateToApp('apm'); + + await retry.try(async () => { + await testSubjects.existOrFail('apmMainContainer', { + timeout: 10000, + }); + + const apmMainContainerText = await testSubjects.getVisibleTextAll('apmMainContainer'); + const apmMainContainerTextItems = apmMainContainerText[0].split('\n'); + expect(apmMainContainerTextItems).to.contain('No services found'); + }); + }); + + it('sets the timePicker to return data', async () => { + await PageObjects.timePicker.timePickerExists(); + + const fromTime = 'Jul 29, 2019 @ 00:00:00.000'; + const toTime = 'Jul 30, 2019 @ 00:00:00.000'; + await PageObjects.timePicker.setAbsoluteRange(fromTime, toTime); + + await retry.try(async () => { + const apmMainContainerText = await testSubjects.getVisibleTextAll('apmMainContainer'); + const apmMainContainerTextItems = apmMainContainerText[0].split('\n'); + + expect(apmMainContainerTextItems).to.not.contain('No services found'); + + expect(apmMainContainerTextItems).to.contain('opbeans-go'); + expect(apmMainContainerTextItems).to.contain('opbeans-node'); + expect(apmMainContainerTextItems).to.contain('opbeans-ruby'); + expect(apmMainContainerTextItems).to.contain('opbeans-python'); + expect(apmMainContainerTextItems).to.contain('opbeans-dotnet'); + expect(apmMainContainerTextItems).to.contain('opbeans-java'); + + expect(apmMainContainerTextItems).to.contain('development'); + + const items = await testSubjects.findAll('apmServiceListAppLink'); + expect(items.length).to.be(6); + }); + }); + + it(`navigates to the 'opbeans-go' service overview page`, async function () { + await find.clickByDisplayedLinkText(testData.serviceName); + + await retry.try(async () => { + const apmMainTemplateHeaderServiceName = await testSubjects.getVisibleTextAll( + 'apmMainTemplateHeaderServiceName' + ); + expect(apmMainTemplateHeaderServiceName).to.contain(testData.serviceName); + }); + }); + + it('navigates to the transactions tab', async function () { + await find.clickByDisplayedLinkText(testData.transactionsTab); + + await retry.try(async () => { + const apmMainContainerText = await testSubjects.getVisibleTextAll('apmMainContainer'); + const apmMainContainerTextItems = apmMainContainerText[0].split('\n'); + + expect(apmMainContainerTextItems).to.contain(testData.transaction); + }); + }); + + it(`navigates to the 'GET /api/stats' transactions`, async function () { + await find.clickByDisplayedLinkText(testData.transaction); + + await retry.try(async () => { + const apmMainContainerText = await testSubjects.getVisibleTextAll('apmMainContainer'); + const apmMainContainerTextItems = apmMainContainerText[0].split('\n'); + + expect(apmMainContainerTextItems).to.contain(testData.transaction); + expect(apmMainContainerTextItems).to.contain(testData.correlationsTab); + }); + }); + + it('shows the failed transactions correlations tab', async function () { + await testSubjects.click('apmFailedTransactionsCorrelationsTabButton'); + + await retry.try(async () => { + await testSubjects.existOrFail('apmFailedTransactionsCorrelationsTabContent'); + }); + }); + + it('loads the failed transactions correlations results', async function () { + await retry.try(async () => { + const apmFailedTransactionsCorrelationsTabTitle = await testSubjects.getVisibleText( + 'apmFailedTransactionsCorrelationsTabTitle' + ); + expect(apmFailedTransactionsCorrelationsTabTitle).to.be('Failed transactions'); + + // Assert that the data fully loaded to 100% + const apmFailedTransactionsCorrelationsProgressTitle = await testSubjects.getVisibleText( + 'apmCorrelationsProgressTitle' + ); + expect(apmFailedTransactionsCorrelationsProgressTitle).to.be('Progress: 100%'); + + // Assert that results for the given service didn't find any correlations + const apmCorrelationsTable = await testSubjects.getVisibleText('apmCorrelationsTable'); + expect(apmCorrelationsTable).to.be( + 'No significant correlations\nCorrelations will only be identified if they have significant impact.\nTry selecting another time range or remove any added filter.' + ); + }); + }); + }); + }); +} diff --git a/x-pack/test/functional/apps/apm/correlations/index.ts b/x-pack/test/functional/apps/apm/correlations/index.ts index ae5f594e54400..abf74910f4e8d 100644 --- a/x-pack/test/functional/apps/apm/correlations/index.ts +++ b/x-pack/test/functional/apps/apm/correlations/index.ts @@ -9,7 +9,8 @@ import { FtrProviderContext } from '../../../ftr_provider_context'; export default function ({ loadTestFile }: FtrProviderContext) { describe('correlations', function () { - this.tags('skipFirefox'); + this.tags(['skipFirefox', 'apm']); loadTestFile(require.resolve('./latency_correlations')); + loadTestFile(require.resolve('./failed_transaction_correlations')); }); } diff --git a/x-pack/test/functional/apps/apm/correlations/latency_correlations.ts b/x-pack/test/functional/apps/apm/correlations/latency_correlations.ts index 3f743c378b7c3..af3633798133b 100644 --- a/x-pack/test/functional/apps/apm/correlations/latency_correlations.ts +++ b/x-pack/test/functional/apps/apm/correlations/latency_correlations.ts @@ -144,10 +144,10 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { it('loads the correlation results', async function () { await retry.try(async () => { // Assert that the data fully loaded to 100% - const apmCorrelationsLatencyCorrelationsProgressTitle = await testSubjects.getVisibleText( - 'apmCorrelationsLatencyCorrelationsProgressTitle' + const apmLatencyCorrelationsProgressTitle = await testSubjects.getVisibleText( + 'apmCorrelationsProgressTitle' ); - expect(apmCorrelationsLatencyCorrelationsProgressTitle).to.be('Progress: 100%'); + expect(apmLatencyCorrelationsProgressTitle).to.be('Progress: 100%'); // Assert that the Correlations Chart and its header are present const apmCorrelationsLatencyCorrelationsChartTitle = await testSubjects.getVisibleText( From 94bdff6e8a167429ea79e8a85c59834094f429da Mon Sep 17 00:00:00 2001 From: Yaroslav Kuznietsov Date: Mon, 23 Aug 2021 16:58:32 +0300 Subject: [PATCH 67/76] [Canvas] Expression tagcloud (#108036) (#109627) * Added `expression_tagcloud` plugin. Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> # Conflicts: # .github/CODEOWNERS # packages/kbn-optimizer/limits.yml --- .i18nrc.json | 1 + docs/developer/plugin-list.asciidoc | 4 + jest.config.js | 1 + packages/kbn-optimizer/limits.yml | 2 +- src/dev/typescript/projects.ts | 1 + .../expression_tagcloud/.i18nrc.json | 6 + .../expression_tagcloud/README.md | 9 + .../expression_tagcloud/common/constants.ts} | 8 +- .../tagcloud_function.test.ts.snap} | 2 +- .../common/expression_functions/index.ts | 13 ++ .../tagcloud_function.test.ts} | 8 +- .../expression_functions/tagcloud_function.ts | 164 ++++++++++++++++++ .../expression_tagcloud/common/index.ts | 9 + .../common/types/expression_functions.ts | 61 +++++++ .../common/types/expression_renderers.ts | 13 ++ .../expression_tagcloud/common/types/index.ts | 9 + .../expression_tagcloud/jest.config.js | 13 ++ .../expression_tagcloud/kibana.json | 15 ++ .../public/components/index.ts | 9 + .../public/components/tag_cloud.scss | 0 .../components/tagcloud_component.test.tsx} | 8 +- .../public/components/tagcloud_component.tsx} | 13 +- .../public/expression_renderers/index.ts | 9 + .../tagcloud_renderer.tsx | 61 +++++++ .../expression_tagcloud/public/index.ts | 15 ++ .../expression_tagcloud/public/plugin.ts | 51 ++++++ .../expression_tagcloud/public/services.ts | 22 +++ .../expression_tagcloud/server/index.ts | 13 ++ .../expression_tagcloud/server/plugin.ts | 34 ++++ .../expression_tagcloud/tsconfig.json | 24 +++ src/plugins/vis_type_tagcloud/kibana.json | 2 +- .../vis_type_tagcloud/public/plugin.ts | 29 +--- .../vis_type_tagcloud/public/tag_cloud_fn.ts | 143 --------------- .../public/tag_cloud_vis_renderer.tsx | 47 ----- .../vis_type_tagcloud/public/to_ast.ts | 3 +- src/plugins/vis_type_tagcloud/public/types.ts | 6 - src/plugins/vis_type_tagcloud/tsconfig.json | 1 - .../snapshots/baseline/partial_test_1.json | 2 +- .../snapshots/baseline/tagcloud_all_data.json | 2 +- .../snapshots/baseline/tagcloud_fontsize.json | 2 +- .../baseline/tagcloud_invalid_data.json | 2 +- .../baseline/tagcloud_metric_data.json | 2 +- .../snapshots/baseline/tagcloud_options.json | 2 +- .../snapshots/session/partial_test_1.json | 2 +- .../snapshots/session/tagcloud_all_data.json | 2 +- .../snapshots/session/tagcloud_fontsize.json | 2 +- .../session/tagcloud_invalid_data.json | 2 +- .../session/tagcloud_metric_data.json | 2 +- .../snapshots/session/tagcloud_options.json | 2 +- .../translations/translations/ja-JP.json | 16 +- .../translations/translations/zh-CN.json | 16 +- 51 files changed, 610 insertions(+), 275 deletions(-) create mode 100755 src/plugins/chart_expressions/expression_tagcloud/.i18nrc.json create mode 100755 src/plugins/chart_expressions/expression_tagcloud/README.md rename src/plugins/{vis_type_tagcloud/public/services.ts => chart_expressions/expression_tagcloud/common/constants.ts} (57%) rename src/plugins/{vis_type_tagcloud/public/__snapshots__/tag_cloud_fn.test.ts.snap => chart_expressions/expression_tagcloud/common/expression_functions/__snapshots__/tagcloud_function.test.ts.snap} (98%) create mode 100644 src/plugins/chart_expressions/expression_tagcloud/common/expression_functions/index.ts rename src/plugins/{vis_type_tagcloud/public/tag_cloud_fn.test.ts => chart_expressions/expression_tagcloud/common/expression_functions/tagcloud_function.test.ts} (82%) create mode 100644 src/plugins/chart_expressions/expression_tagcloud/common/expression_functions/tagcloud_function.ts create mode 100755 src/plugins/chart_expressions/expression_tagcloud/common/index.ts create mode 100644 src/plugins/chart_expressions/expression_tagcloud/common/types/expression_functions.ts create mode 100644 src/plugins/chart_expressions/expression_tagcloud/common/types/expression_renderers.ts create mode 100644 src/plugins/chart_expressions/expression_tagcloud/common/types/index.ts create mode 100644 src/plugins/chart_expressions/expression_tagcloud/jest.config.js create mode 100755 src/plugins/chart_expressions/expression_tagcloud/kibana.json create mode 100644 src/plugins/chart_expressions/expression_tagcloud/public/components/index.ts rename src/plugins/{vis_type_tagcloud => chart_expressions/expression_tagcloud}/public/components/tag_cloud.scss (100%) rename src/plugins/{vis_type_tagcloud/public/components/tag_cloud_chart.test.tsx => chart_expressions/expression_tagcloud/public/components/tagcloud_component.test.tsx} (93%) rename src/plugins/{vis_type_tagcloud/public/components/tag_cloud_chart.tsx => chart_expressions/expression_tagcloud/public/components/tagcloud_component.tsx} (93%) create mode 100644 src/plugins/chart_expressions/expression_tagcloud/public/expression_renderers/index.ts create mode 100644 src/plugins/chart_expressions/expression_tagcloud/public/expression_renderers/tagcloud_renderer.tsx create mode 100644 src/plugins/chart_expressions/expression_tagcloud/public/index.ts create mode 100644 src/plugins/chart_expressions/expression_tagcloud/public/plugin.ts create mode 100644 src/plugins/chart_expressions/expression_tagcloud/public/services.ts create mode 100644 src/plugins/chart_expressions/expression_tagcloud/server/index.ts create mode 100644 src/plugins/chart_expressions/expression_tagcloud/server/plugin.ts create mode 100644 src/plugins/chart_expressions/expression_tagcloud/tsconfig.json delete mode 100644 src/plugins/vis_type_tagcloud/public/tag_cloud_fn.ts delete mode 100644 src/plugins/vis_type_tagcloud/public/tag_cloud_vis_renderer.tsx diff --git a/.i18nrc.json b/.i18nrc.json index 6c0f8d75c84b3..6369637479478 100644 --- a/.i18nrc.json +++ b/.i18nrc.json @@ -25,6 +25,7 @@ "expressionRepeatImage": "src/plugins/expression_repeat_image", "expressionRevealImage": "src/plugins/expression_reveal_image", "expressionShape": "src/plugins/expression_shape", + "expressionTagcloud": "src/plugins/chart_expressions/expression_tagcloud", "inputControl": "src/plugins/input_control_vis", "inspector": "src/plugins/inspector", "inspectorViews": "src/legacy/core_plugins/inspector_views", diff --git a/docs/developer/plugin-list.asciidoc b/docs/developer/plugin-list.asciidoc index 8199a5995d368..393e5efed4516 100644 --- a/docs/developer/plugin-list.asciidoc +++ b/docs/developer/plugin-list.asciidoc @@ -113,6 +113,10 @@ for use in their own application. |Expression Shape plugin adds a shape function to the expression plugin and an associated renderer. The renderer will display the given shape with selected decorations. +|{kib-repo}blob/{branch}/src/plugins/chart_expressions/expression_tagcloud/README.md[expressionTagcloud] +|Expression Tagcloud plugin adds a tagcloud renderer and function to the expression plugin. The renderer will display the Wordcloud chart. + + |{kib-repo}blob/{branch}/src/plugins/field_formats/README.md[fieldFormats] |Index pattern fields formatters diff --git a/jest.config.js b/jest.config.js index 6cb23b279925e..09532dc28bbb2 100644 --- a/jest.config.js +++ b/jest.config.js @@ -13,6 +13,7 @@ module.exports = { '/packages/*/jest.config.js', '/src/*/jest.config.js', '/src/plugins/*/jest.config.js', + '/src/plugins/chart_expressions/*/jest.config.js', '/src/plugins/vis_types/*/jest.config.js', '/test/*/jest.config.js', '/x-pack/plugins/*/jest.config.js', diff --git a/packages/kbn-optimizer/limits.yml b/packages/kbn-optimizer/limits.yml index b405fbbe8fafc..4dbb4ad51fa81 100644 --- a/packages/kbn-optimizer/limits.yml +++ b/packages/kbn-optimizer/limits.yml @@ -119,4 +119,4 @@ pageLoadAssetSize: expressionImage: 19288 expressionMetric: 22238 expressionShape: 34008 - + expressionTagcloud: 27505 diff --git a/src/dev/typescript/projects.ts b/src/dev/typescript/projects.ts index 58234be1317a7..e3d8185e73e55 100644 --- a/src/dev/typescript/projects.ts +++ b/src/dev/typescript/projects.ts @@ -70,6 +70,7 @@ export const PROJECTS = [ ...findProjects('packages/*/tsconfig.json'), ...findProjects('src/plugins/*/tsconfig.json'), + ...findProjects('src/plugins/chart_expressions/*/tsconfig.json'), ...findProjects('src/plugins/vis_types/*/tsconfig.json'), ...findProjects('x-pack/plugins/*/tsconfig.json'), ...findProjects('examples/*/tsconfig.json'), diff --git a/src/plugins/chart_expressions/expression_tagcloud/.i18nrc.json b/src/plugins/chart_expressions/expression_tagcloud/.i18nrc.json new file mode 100755 index 0000000000000..df4e39309f98e --- /dev/null +++ b/src/plugins/chart_expressions/expression_tagcloud/.i18nrc.json @@ -0,0 +1,6 @@ +{ + "prefix": "expressionTagcloud", + "paths": { + "expressionTagcloud": "." + } +} diff --git a/src/plugins/chart_expressions/expression_tagcloud/README.md b/src/plugins/chart_expressions/expression_tagcloud/README.md new file mode 100755 index 0000000000000..ae7635ffe0173 --- /dev/null +++ b/src/plugins/chart_expressions/expression_tagcloud/README.md @@ -0,0 +1,9 @@ +# expressionTagcloud + +Expression Tagcloud plugin adds a `tagcloud` renderer and function to the expression plugin. The renderer will display the `Wordcloud` chart. + +--- + +## Development + +See the [kibana contributing guide](https://github.com/elastic/kibana/blob/master/CONTRIBUTING.md) for instructions setting up your development environment. diff --git a/src/plugins/vis_type_tagcloud/public/services.ts b/src/plugins/chart_expressions/expression_tagcloud/common/constants.ts similarity index 57% rename from src/plugins/vis_type_tagcloud/public/services.ts rename to src/plugins/chart_expressions/expression_tagcloud/common/constants.ts index abec36c4aae7b..3d834448a94ef 100644 --- a/src/plugins/vis_type_tagcloud/public/services.ts +++ b/src/plugins/chart_expressions/expression_tagcloud/common/constants.ts @@ -6,9 +6,7 @@ * Side Public License, v 1. */ -import { createGetterSetter } from '../../kibana_utils/public'; -import { DataPublicPluginStart } from '../../data/public'; +export const PLUGIN_ID = 'expressionTagcloud'; +export const PLUGIN_NAME = 'expressionTagcloud'; -export const [getFormatService, setFormatService] = createGetterSetter< - DataPublicPluginStart['fieldFormats'] ->('data.fieldFormats'); +export const EXPRESSION_NAME = 'tagcloud'; diff --git a/src/plugins/vis_type_tagcloud/public/__snapshots__/tag_cloud_fn.test.ts.snap b/src/plugins/chart_expressions/expression_tagcloud/common/expression_functions/__snapshots__/tagcloud_function.test.ts.snap similarity index 98% rename from src/plugins/vis_type_tagcloud/public/__snapshots__/tag_cloud_fn.test.ts.snap rename to src/plugins/chart_expressions/expression_tagcloud/common/expression_functions/__snapshots__/tagcloud_function.test.ts.snap index 2888d7637546c..56b24f0ae004f 100644 --- a/src/plugins/vis_type_tagcloud/public/__snapshots__/tag_cloud_fn.test.ts.snap +++ b/src/plugins/chart_expressions/expression_tagcloud/common/expression_functions/__snapshots__/tagcloud_function.test.ts.snap @@ -22,7 +22,7 @@ Object { exports[`interpreter/functions#tagcloud returns an object with the correct structure 1`] = ` Object { - "as": "tagloud_vis", + "as": "tagcloud", "type": "render", "value": Object { "syncColors": false, diff --git a/src/plugins/chart_expressions/expression_tagcloud/common/expression_functions/index.ts b/src/plugins/chart_expressions/expression_tagcloud/common/expression_functions/index.ts new file mode 100644 index 0000000000000..5df32e3991edc --- /dev/null +++ b/src/plugins/chart_expressions/expression_tagcloud/common/expression_functions/index.ts @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { tagcloudFunction } from './tagcloud_function'; + +export const functions = [tagcloudFunction]; + +export { tagcloudFunction }; diff --git a/src/plugins/vis_type_tagcloud/public/tag_cloud_fn.test.ts b/src/plugins/chart_expressions/expression_tagcloud/common/expression_functions/tagcloud_function.test.ts similarity index 82% rename from src/plugins/vis_type_tagcloud/public/tag_cloud_fn.test.ts rename to src/plugins/chart_expressions/expression_tagcloud/common/expression_functions/tagcloud_function.test.ts index 1671c0b01a666..2c6e021b5107a 100644 --- a/src/plugins/vis_type_tagcloud/public/tag_cloud_fn.test.ts +++ b/src/plugins/chart_expressions/expression_tagcloud/common/expression_functions/tagcloud_function.test.ts @@ -6,13 +6,13 @@ * Side Public License, v 1. */ -import { createTagCloudFn } from './tag_cloud_fn'; +import { tagcloudFunction } from './tagcloud_function'; -import { functionWrapper } from '../../expressions/common/expression_functions/specs/tests/utils'; -import { Datatable } from '../../expressions/common/expression_types/specs'; +import { functionWrapper } from '../../../../expressions/common/expression_functions/specs/tests/utils'; +import { Datatable } from '../../../../expressions/common/expression_types/specs'; describe('interpreter/functions#tagcloud', () => { - const fn = functionWrapper(createTagCloudFn()); + const fn = functionWrapper(tagcloudFunction()); const context = { type: 'datatable', rows: [{ 'col-0-1': 0 }], diff --git a/src/plugins/chart_expressions/expression_tagcloud/common/expression_functions/tagcloud_function.ts b/src/plugins/chart_expressions/expression_tagcloud/common/expression_functions/tagcloud_function.ts new file mode 100644 index 0000000000000..c3553c4660ce9 --- /dev/null +++ b/src/plugins/chart_expressions/expression_tagcloud/common/expression_functions/tagcloud_function.ts @@ -0,0 +1,164 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ +import { i18n } from '@kbn/i18n'; + +import { prepareLogTable, Dimension } from '../../../../visualizations/common/prepare_log_table'; +import { TagCloudVisParams } from '../types'; +import { ExpressionTagcloudFunction } from '../types'; +import { EXPRESSION_NAME } from '../constants'; + +const strings = { + help: i18n.translate('expressionTagcloud.functions.tagcloudHelpText', { + defaultMessage: 'Tagcloud visualization.', + }), + args: { + scale: i18n.translate('expressionTagcloud.functions.tagcloud.args.scaleHelpText', { + defaultMessage: 'Scale to determine font size of a word', + }), + orientation: i18n.translate('expressionTagcloud.functions.tagcloud.args.orientationHelpText', { + defaultMessage: 'Orientation of words inside tagcloud', + }), + minFontSize: i18n.translate('expressionTagcloud.functions.tagcloud.args.minFontSizeHelpText', { + defaultMessage: 'Min font size', + }), + maxFontSize: i18n.translate('expressionTagcloud.functions.tagcloud.args.maxFontSizeHelpText', { + defaultMessage: 'Max font size', + }), + showLabel: i18n.translate('expressionTagcloud.functions.tagcloud.args.showLabelHelpText', { + defaultMessage: 'Show chart label', + }), + palette: i18n.translate('expressionTagcloud.functions.tagcloud.args.paletteHelpText', { + defaultMessage: 'Defines the chart palette name', + }), + metric: i18n.translate('expressionTagcloud.functions.tagcloud.args.metricHelpText', { + defaultMessage: 'metric dimension configuration', + }), + bucket: i18n.translate('expressionTagcloud.functions.tagcloud.args.bucketHelpText', { + defaultMessage: 'bucket dimension configuration', + }), + }, + dimension: { + tags: i18n.translate('expressionTagcloud.functions.tagcloud.dimension.tags', { + defaultMessage: 'Tags', + }), + tagSize: i18n.translate('expressionTagcloud.functions.tagcloud.dimension.tagSize', { + defaultMessage: 'Tag size', + }), + }, +}; + +export const errors = { + invalidPercent: (percent: number) => + new Error( + i18n.translate('expressionTagcloud.functions.tagcloud.invalidPercentErrorMessage', { + defaultMessage: "Invalid value: '{percent}'. Percentage must be between 0 and 1", + values: { + percent, + }, + }) + ), + invalidImageUrl: (imageUrl: string) => + new Error( + i18n.translate('expressionTagcloud.functions.tagcloud.invalidImageUrl', { + defaultMessage: "Invalid image url: '{imageUrl}'.", + values: { + imageUrl, + }, + }) + ), +}; + +export const tagcloudFunction: ExpressionTagcloudFunction = () => { + const { help, args: argHelp, dimension } = strings; + + return { + name: EXPRESSION_NAME, + type: 'render', + inputTypes: ['datatable'], + help, + args: { + scale: { + types: ['string'], + default: 'linear', + options: ['linear', 'log', 'square root'], + help: argHelp.scale, + }, + orientation: { + types: ['string'], + default: 'single', + options: ['single', 'right angled', 'multiple'], + help: argHelp.orientation, + }, + minFontSize: { + types: ['number'], + default: 18, + help: argHelp.minFontSize, + }, + maxFontSize: { + types: ['number'], + default: 72, + help: argHelp.maxFontSize, + }, + showLabel: { + types: ['boolean'], + default: true, + help: argHelp.showLabel, + }, + palette: { + types: ['string'], + help: argHelp.palette, + default: 'default', + }, + metric: { + types: ['vis_dimension'], + help: argHelp.metric, + required: true, + }, + bucket: { + types: ['vis_dimension'], + help: argHelp.bucket, + }, + }, + fn(input, args, handlers) { + const visParams = { + scale: args.scale, + orientation: args.orientation, + minFontSize: args.minFontSize, + maxFontSize: args.maxFontSize, + showLabel: args.showLabel, + metric: args.metric, + ...(args.bucket && { + bucket: args.bucket, + }), + palette: { + type: 'palette', + name: args.palette, + }, + } as TagCloudVisParams; + + if (handlers?.inspectorAdapters?.tables) { + const argsTable: Dimension[] = [[[args.metric], dimension.tagSize]]; + if (args.bucket) { + argsTable.push([[args.bucket], dimension.tags]); + } + const logTable = prepareLogTable(input, argsTable); + handlers.inspectorAdapters.tables.logDatatable('default', logTable); + } + return { + type: 'render', + as: EXPRESSION_NAME, + value: { + visData: input, + visType: EXPRESSION_NAME, + visParams, + syncColors: handlers?.isSyncColorsEnabled?.() ?? false, + }, + }; + }, + }; +}; diff --git a/src/plugins/chart_expressions/expression_tagcloud/common/index.ts b/src/plugins/chart_expressions/expression_tagcloud/common/index.ts new file mode 100755 index 0000000000000..d8989abcc3d6f --- /dev/null +++ b/src/plugins/chart_expressions/expression_tagcloud/common/index.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export * from './constants'; diff --git a/src/plugins/chart_expressions/expression_tagcloud/common/types/expression_functions.ts b/src/plugins/chart_expressions/expression_tagcloud/common/types/expression_functions.ts new file mode 100644 index 0000000000000..b1aba30380b59 --- /dev/null +++ b/src/plugins/chart_expressions/expression_tagcloud/common/types/expression_functions.ts @@ -0,0 +1,61 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ +import { PaletteOutput } from '../../../../charts/common'; +import { + Datatable, + ExpressionFunctionDefinition, + ExpressionValueRender, + SerializedFieldFormat, +} from '../../../../expressions'; +import { ExpressionValueVisDimension } from '../../../../visualizations/common'; +import { EXPRESSION_NAME } from '../constants'; + +interface Dimension { + accessor: number; + format: { + id?: string; + params?: SerializedFieldFormat; + }; +} + +interface TagCloudCommonParams { + scale: 'linear' | 'log' | 'square root'; + orientation: 'single' | 'right angled' | 'multiple'; + minFontSize: number; + maxFontSize: number; + showLabel: boolean; +} + +export interface TagCloudVisConfig extends TagCloudCommonParams { + metric: ExpressionValueVisDimension; + bucket?: ExpressionValueVisDimension; +} + +export interface TagCloudVisParams extends TagCloudCommonParams { + palette: PaletteOutput; + metric: Dimension; + bucket?: Dimension; +} + +export interface TagcloudRendererConfig { + visType: typeof EXPRESSION_NAME; + visData: Datatable; + visParams: TagCloudVisParams; + syncColors: boolean; +} + +interface Arguments extends TagCloudVisConfig { + palette: string; +} + +export type ExpressionTagcloudFunction = () => ExpressionFunctionDefinition< + 'tagcloud', + Datatable, + Arguments, + ExpressionValueRender +>; diff --git a/src/plugins/chart_expressions/expression_tagcloud/common/types/expression_renderers.ts b/src/plugins/chart_expressions/expression_tagcloud/common/types/expression_renderers.ts new file mode 100644 index 0000000000000..d426aa061a2ab --- /dev/null +++ b/src/plugins/chart_expressions/expression_tagcloud/common/types/expression_renderers.ts @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { ChartsPluginSetup } from '../../../../charts/public'; + +export interface TagCloudTypeProps { + palettes: ChartsPluginSetup['palettes']; +} diff --git a/src/plugins/chart_expressions/expression_tagcloud/common/types/index.ts b/src/plugins/chart_expressions/expression_tagcloud/common/types/index.ts new file mode 100644 index 0000000000000..ec934e7affe88 --- /dev/null +++ b/src/plugins/chart_expressions/expression_tagcloud/common/types/index.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ +export * from './expression_functions'; +export * from './expression_renderers'; diff --git a/src/plugins/chart_expressions/expression_tagcloud/jest.config.js b/src/plugins/chart_expressions/expression_tagcloud/jest.config.js new file mode 100644 index 0000000000000..c88c150d6f649 --- /dev/null +++ b/src/plugins/chart_expressions/expression_tagcloud/jest.config.js @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +module.exports = { + preset: '@kbn/test', + rootDir: '../../../../', + roots: ['/src/plugins/chart_expressions/expression_tagcloud'], +}; diff --git a/src/plugins/chart_expressions/expression_tagcloud/kibana.json b/src/plugins/chart_expressions/expression_tagcloud/kibana.json new file mode 100755 index 0000000000000..26d5ef9750e60 --- /dev/null +++ b/src/plugins/chart_expressions/expression_tagcloud/kibana.json @@ -0,0 +1,15 @@ +{ + "id": "expressionTagcloud", + "version": "1.0.0", + "kibanaVersion": "kibana", + "server": true, + "ui": true, + "requiredPlugins": ["expressions", "visualizations", "charts", "presentationUtil", "fieldFormats"], + "requiredBundles": ["kibanaUtils"], + "optionalPlugins": [], + "owner": { + "name": "Kibana App", + "githubTeam": "kibana-app" + }, + "description": "Expression Tagcloud plugin adds a `tagcloud` renderer and function to the expression plugin. The renderer will display the `Wordcloud` chart." +} diff --git a/src/plugins/chart_expressions/expression_tagcloud/public/components/index.ts b/src/plugins/chart_expressions/expression_tagcloud/public/components/index.ts new file mode 100644 index 0000000000000..2ebc3d586d903 --- /dev/null +++ b/src/plugins/chart_expressions/expression_tagcloud/public/components/index.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export * from './tagcloud_component'; diff --git a/src/plugins/vis_type_tagcloud/public/components/tag_cloud.scss b/src/plugins/chart_expressions/expression_tagcloud/public/components/tag_cloud.scss similarity index 100% rename from src/plugins/vis_type_tagcloud/public/components/tag_cloud.scss rename to src/plugins/chart_expressions/expression_tagcloud/public/components/tag_cloud.scss diff --git a/src/plugins/vis_type_tagcloud/public/components/tag_cloud_chart.test.tsx b/src/plugins/chart_expressions/expression_tagcloud/public/components/tagcloud_component.test.tsx similarity index 93% rename from src/plugins/vis_type_tagcloud/public/components/tag_cloud_chart.test.tsx rename to src/plugins/chart_expressions/expression_tagcloud/public/components/tagcloud_component.test.tsx index b4d4e70d5ffe3..542a9c1cd9bf7 100644 --- a/src/plugins/vis_type_tagcloud/public/components/tag_cloud_chart.test.tsx +++ b/src/plugins/chart_expressions/expression_tagcloud/public/components/tagcloud_component.test.tsx @@ -7,12 +7,12 @@ */ import React from 'react'; import { Wordcloud, Settings } from '@elastic/charts'; -import { chartPluginMock } from '../../../charts/public/mocks'; -import type { Datatable } from '../../../expressions/public'; +import { chartPluginMock } from '../../../../charts/public/mocks'; +import type { Datatable } from '../../../../expressions/public'; import { mount } from 'enzyme'; import { findTestSubject } from '@elastic/eui/lib/test'; -import TagCloudChart, { TagCloudChartProps } from './tag_cloud_chart'; -import { TagCloudVisParams } from '../types'; +import TagCloudChart, { TagCloudChartProps } from './tagcloud_component'; +import { TagCloudVisParams } from '../../common/types'; jest.mock('../services', () => ({ getFormatService: jest.fn(() => { diff --git a/src/plugins/vis_type_tagcloud/public/components/tag_cloud_chart.tsx b/src/plugins/chart_expressions/expression_tagcloud/public/components/tagcloud_component.tsx similarity index 93% rename from src/plugins/vis_type_tagcloud/public/components/tag_cloud_chart.tsx rename to src/plugins/chart_expressions/expression_tagcloud/public/components/tagcloud_component.tsx index b89fe2fa90ede..163a2e8ce38ac 100644 --- a/src/plugins/vis_type_tagcloud/public/components/tag_cloud_chart.tsx +++ b/src/plugins/chart_expressions/expression_tagcloud/public/components/tagcloud_component.tsx @@ -11,16 +11,16 @@ import { FormattedMessage } from '@kbn/i18n/react'; import { throttle } from 'lodash'; import { EuiIconTip, EuiResizeObserver } from '@elastic/eui'; import { Chart, Settings, Wordcloud, RenderChangeListener } from '@elastic/charts'; -import type { PaletteRegistry } from '../../../charts/public'; -import type { IInterpreterRenderHandlers } from '../../../expressions/public'; +import type { PaletteRegistry } from '../../../../charts/public'; +import type { IInterpreterRenderHandlers } from '../../../../expressions/public'; import { getFormatService } from '../services'; -import { TagCloudVisRenderValue } from '../tag_cloud_fn'; +import { TagcloudRendererConfig } from '../../common/types'; import './tag_cloud.scss'; const MAX_TAG_COUNT = 200; -export type TagCloudChartProps = TagCloudVisRenderValue & { +export type TagCloudChartProps = TagcloudRendererConfig & { fireEvent: IInterpreterRenderHandlers['event']; renderComplete: IInterpreterRenderHandlers['done']; palettesRegistry: PaletteRegistry; @@ -204,7 +204,7 @@ export const TagCloudChart = ({ color="warning" content={ } @@ -218,7 +218,7 @@ export const TagCloudChart = ({ color="warning" content={ } @@ -231,6 +231,5 @@ export const TagCloudChart = ({ ); }; -// default export required for React.Lazy // eslint-disable-next-line import/no-default-export export { TagCloudChart as default }; diff --git a/src/plugins/chart_expressions/expression_tagcloud/public/expression_renderers/index.ts b/src/plugins/chart_expressions/expression_tagcloud/public/expression_renderers/index.ts new file mode 100644 index 0000000000000..4819430cda791 --- /dev/null +++ b/src/plugins/chart_expressions/expression_tagcloud/public/expression_renderers/index.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export { tagcloudRenderer } from './tagcloud_renderer'; diff --git a/src/plugins/chart_expressions/expression_tagcloud/public/expression_renderers/tagcloud_renderer.tsx b/src/plugins/chart_expressions/expression_tagcloud/public/expression_renderers/tagcloud_renderer.tsx new file mode 100644 index 0000000000000..58e177dac6775 --- /dev/null +++ b/src/plugins/chart_expressions/expression_tagcloud/public/expression_renderers/tagcloud_renderer.tsx @@ -0,0 +1,61 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ +import React, { lazy } from 'react'; +import { render, unmountComponentAtNode } from 'react-dom'; +import { I18nProvider } from '@kbn/i18n/react'; +import { i18n } from '@kbn/i18n'; +import { ExpressionRenderDefinition } from '../../../../expressions/common'; +import { VisualizationContainer } from '../../../../visualizations/public'; +import { withSuspense } from '../../../../presentation_util/public'; +import { TagcloudRendererConfig } from '../../common/types'; +import { ExpressioTagcloudRendererDependencies } from '../plugin'; +import { EXPRESSION_NAME } from '../../common'; + +export const strings = { + getDisplayName: () => + i18n.translate('expressionTagcloud.renderer.tagcloud.displayName', { + defaultMessage: 'Tag Cloud visualization', + }), + getHelpDescription: () => + i18n.translate('expressionTagcloud.renderer.tagcloud.helpDescription', { + defaultMessage: 'Render a tag cloud', + }), +}; + +const LazyTagcloudComponent = lazy(() => import('../components/tagcloud_component')); +const TagcloudComponent = withSuspense(LazyTagcloudComponent); + +export const tagcloudRenderer: ( + deps: ExpressioTagcloudRendererDependencies +) => ExpressionRenderDefinition = ({ palettes }) => ({ + name: EXPRESSION_NAME, + displayName: strings.getDisplayName(), + help: strings.getHelpDescription(), + reuseDomNode: true, + render: async (domNode, config, handlers) => { + handlers.onDestroy(() => { + unmountComponentAtNode(domNode); + }); + const palettesRegistry = await palettes.getPalettes(); + + render( + + + + + , + domNode + ); + }, +}); diff --git a/src/plugins/chart_expressions/expression_tagcloud/public/index.ts b/src/plugins/chart_expressions/expression_tagcloud/public/index.ts new file mode 100644 index 0000000000000..8d170c49b6633 --- /dev/null +++ b/src/plugins/chart_expressions/expression_tagcloud/public/index.ts @@ -0,0 +1,15 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { ExpressionTagcloudPlugin } from './plugin'; + +export type { ExpressionTagcloudPluginSetup, ExpressionTagcloudPluginStart } from './plugin'; + +export function plugin() { + return new ExpressionTagcloudPlugin(); +} diff --git a/src/plugins/chart_expressions/expression_tagcloud/public/plugin.ts b/src/plugins/chart_expressions/expression_tagcloud/public/plugin.ts new file mode 100644 index 0000000000000..7cbc9ac7c6706 --- /dev/null +++ b/src/plugins/chart_expressions/expression_tagcloud/public/plugin.ts @@ -0,0 +1,51 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { CoreSetup, CoreStart, Plugin } from '../../../../core/public'; +import { ExpressionsStart, ExpressionsSetup } from '../../../expressions/public'; +import { ChartsPluginSetup } from '../../../charts/public'; +import { tagcloudRenderer } from './expression_renderers'; +import { tagcloudFunction } from '../common/expression_functions'; +import { FieldFormatsStart } from '../../../field_formats/public'; +import { setFormatService } from './services'; + +interface SetupDeps { + expressions: ExpressionsSetup; + charts: ChartsPluginSetup; +} + +/** @internal */ +export interface ExpressioTagcloudRendererDependencies { + palettes: ChartsPluginSetup['palettes']; +} + +interface StartDeps { + expression: ExpressionsStart; + fieldFormats: FieldFormatsStart; +} + +export type ExpressionTagcloudPluginSetup = void; +export type ExpressionTagcloudPluginStart = void; + +export class ExpressionTagcloudPlugin + implements + Plugin { + public setup(core: CoreSetup, { expressions, charts }: SetupDeps): ExpressionTagcloudPluginSetup { + const rendererDependencies: ExpressioTagcloudRendererDependencies = { + palettes: charts.palettes, + }; + expressions.registerFunction(tagcloudFunction); + expressions.registerRenderer(tagcloudRenderer(rendererDependencies)); + } + + public start(core: CoreStart, { fieldFormats }: StartDeps): ExpressionTagcloudPluginStart { + setFormatService(fieldFormats); + } + + public stop() {} +} diff --git a/src/plugins/chart_expressions/expression_tagcloud/public/services.ts b/src/plugins/chart_expressions/expression_tagcloud/public/services.ts new file mode 100644 index 0000000000000..541e46a847260 --- /dev/null +++ b/src/plugins/chart_expressions/expression_tagcloud/public/services.ts @@ -0,0 +1,22 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { createGetterSetter } from '../../../kibana_utils/public'; +import { FieldFormatsStart } from '../../../field_formats/public'; + +export const [getFormatService, setFormatService] = createGetterSetter( + 'fieldFormats' +); diff --git a/src/plugins/chart_expressions/expression_tagcloud/server/index.ts b/src/plugins/chart_expressions/expression_tagcloud/server/index.ts new file mode 100644 index 0000000000000..c944168271314 --- /dev/null +++ b/src/plugins/chart_expressions/expression_tagcloud/server/index.ts @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { ExpressionTagcloudPlugin } from './plugin'; + +export function plugin() { + return new ExpressionTagcloudPlugin(); +} diff --git a/src/plugins/chart_expressions/expression_tagcloud/server/plugin.ts b/src/plugins/chart_expressions/expression_tagcloud/server/plugin.ts new file mode 100644 index 0000000000000..03dd05db25fa7 --- /dev/null +++ b/src/plugins/chart_expressions/expression_tagcloud/server/plugin.ts @@ -0,0 +1,34 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { CoreSetup, CoreStart, Plugin } from '../../../../core/public'; +import { ExpressionsServerStart, ExpressionsServerSetup } from '../../../expressions/server'; +import { tagcloudFunction } from '../common/expression_functions'; + +interface SetupDeps { + expressions: ExpressionsServerSetup; +} + +interface StartDeps { + expression: ExpressionsServerStart; +} + +export type ExpressionTagcloudPluginSetup = void; +export type ExpressionTagcloudPluginStart = void; + +export class ExpressionTagcloudPlugin + implements + Plugin { + public setup(core: CoreSetup, { expressions }: SetupDeps): ExpressionTagcloudPluginSetup { + expressions.registerFunction(tagcloudFunction); + } + + public start(core: CoreStart): ExpressionTagcloudPluginStart {} + + public stop() {} +} diff --git a/src/plugins/chart_expressions/expression_tagcloud/tsconfig.json b/src/plugins/chart_expressions/expression_tagcloud/tsconfig.json new file mode 100644 index 0000000000000..c2d50e4cd4e13 --- /dev/null +++ b/src/plugins/chart_expressions/expression_tagcloud/tsconfig.json @@ -0,0 +1,24 @@ +{ + "extends": "../../../../tsconfig.base.json", + "compilerOptions": { + "outDir": "./target/types", + "emitDeclarationOnly": true, + "declaration": true, + "declarationMap": true, + "isolatedModules": true + }, + "include": [ + "common/**/*", + "public/**/*", + "server/**/*", + ], + "references": [ + { "path": "../../../core/tsconfig.json" }, + { "path": "../../presentation_util/tsconfig.json" }, + { "path": "../../expressions/tsconfig.json" }, + { "path": "../../visualizations/tsconfig.json" }, + { "path": "../../charts/tsconfig.json" }, + { "path": "../../field_formats/tsconfig.json" }, + { "path": "../../kibana_utils/tsconfig.json" }, + ] +} diff --git a/src/plugins/vis_type_tagcloud/kibana.json b/src/plugins/vis_type_tagcloud/kibana.json index 1c427600b5de6..b51d5d49cb7b2 100644 --- a/src/plugins/vis_type_tagcloud/kibana.json +++ b/src/plugins/vis_type_tagcloud/kibana.json @@ -4,7 +4,7 @@ "ui": true, "server": true, "requiredPlugins": ["data", "expressions", "visualizations", "charts"], - "requiredBundles": ["kibanaUtils", "kibanaReact", "visDefaultEditor"], + "requiredBundles": ["kibanaReact", "visDefaultEditor"], "owner": { "name": "Kibana App", "githubTeam": "kibana-app" diff --git a/src/plugins/vis_type_tagcloud/public/plugin.ts b/src/plugins/vis_type_tagcloud/public/plugin.ts index b2414762f6e47..06e1c516d9e61 100644 --- a/src/plugins/vis_type_tagcloud/public/plugin.ts +++ b/src/plugins/vis_type_tagcloud/public/plugin.ts @@ -7,20 +7,14 @@ */ import { PluginInitializerContext, CoreSetup, CoreStart, Plugin } from 'kibana/public'; -import { Plugin as ExpressionsPublicPlugin } from '../../expressions/public'; import { VisualizationsSetup } from '../../visualizations/public'; import { ChartsPluginSetup } from '../../charts/public'; -import { createTagCloudFn } from './tag_cloud_fn'; import { getTagCloudVisTypeDefinition } from './tag_cloud_type'; -import { DataPublicPluginStart } from '../../data/public'; -import { setFormatService } from './services'; import { ConfigSchema } from '../config'; -import { getTagCloudVisRenderer } from './tag_cloud_vis_renderer'; /** @internal */ export interface TagCloudPluginSetupDependencies { - expressions: ReturnType; visualizations: VisualizationsSetup; charts: ChartsPluginSetup; } @@ -30,11 +24,6 @@ export interface TagCloudVisDependencies { palettes: ChartsPluginSetup['palettes']; } -/** @internal */ -export interface TagCloudVisPluginStartDependencies { - data: DataPublicPluginStart; -} - /** @internal */ export class TagCloudPlugin implements Plugin { initializerContext: PluginInitializerContext; @@ -43,23 +32,13 @@ export class TagCloudPlugin implements Plugin { this.initializerContext = initializerContext; } - public setup( - core: CoreSetup, - { expressions, visualizations, charts }: TagCloudPluginSetupDependencies - ) { + public setup(core: CoreSetup, { visualizations, charts }: TagCloudPluginSetupDependencies) { const visualizationDependencies: TagCloudVisDependencies = { palettes: charts.palettes, }; - expressions.registerFunction(createTagCloudFn); - expressions.registerRenderer(getTagCloudVisRenderer(visualizationDependencies)); - visualizations.createBaseVisualization( - getTagCloudVisTypeDefinition({ - palettes: charts.palettes, - }) - ); - } - public start(core: CoreStart, { data }: TagCloudVisPluginStartDependencies) { - setFormatService(data.fieldFormats); + visualizations.createBaseVisualization(getTagCloudVisTypeDefinition(visualizationDependencies)); } + + public start(core: CoreStart) {} } diff --git a/src/plugins/vis_type_tagcloud/public/tag_cloud_fn.ts b/src/plugins/vis_type_tagcloud/public/tag_cloud_fn.ts deleted file mode 100644 index bfaf557c6baff..0000000000000 --- a/src/plugins/vis_type_tagcloud/public/tag_cloud_fn.ts +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import { i18n } from '@kbn/i18n'; - -import { ExpressionFunctionDefinition, Datatable, Render } from '../../expressions/public'; -import { prepareLogTable, Dimension } from '../../visualizations/public'; -import { TagCloudVisParams, TagCloudVisConfig } from './types'; - -const name = 'tagcloud'; - -interface Arguments extends TagCloudVisConfig { - palette: string; -} - -export interface TagCloudVisRenderValue { - visType: typeof name; - visData: Datatable; - visParams: TagCloudVisParams; - syncColors: boolean; -} - -export type TagcloudExpressionFunctionDefinition = ExpressionFunctionDefinition< - typeof name, - Datatable, - Arguments, - Render ->; - -export const createTagCloudFn = (): TagcloudExpressionFunctionDefinition => ({ - name, - type: 'render', - inputTypes: ['datatable'], - help: i18n.translate('visTypeTagCloud.function.help', { - defaultMessage: 'Tagcloud visualization', - }), - args: { - scale: { - types: ['string'], - default: 'linear', - options: ['linear', 'log', 'square root'], - help: i18n.translate('visTypeTagCloud.function.scale.help', { - defaultMessage: 'Scale to determine font size of a word', - }), - }, - orientation: { - types: ['string'], - default: 'single', - options: ['single', 'right angled', 'multiple'], - help: i18n.translate('visTypeTagCloud.function.orientation.help', { - defaultMessage: 'Orientation of words inside tagcloud', - }), - }, - minFontSize: { - types: ['number'], - default: 18, - help: '', - }, - maxFontSize: { - types: ['number'], - default: 72, - help: '', - }, - showLabel: { - types: ['boolean'], - default: true, - help: '', - }, - palette: { - types: ['string'], - help: i18n.translate('visTypeTagCloud.function.paletteHelpText', { - defaultMessage: 'Defines the chart palette name', - }), - default: 'default', - }, - metric: { - types: ['vis_dimension'], - help: i18n.translate('visTypeTagCloud.function.metric.help', { - defaultMessage: 'metric dimension configuration', - }), - required: true, - }, - bucket: { - types: ['vis_dimension'], - help: i18n.translate('visTypeTagCloud.function.bucket.help', { - defaultMessage: 'bucket dimension configuration', - }), - }, - }, - fn(input, args, handlers) { - const visParams = { - scale: args.scale, - orientation: args.orientation, - minFontSize: args.minFontSize, - maxFontSize: args.maxFontSize, - showLabel: args.showLabel, - metric: args.metric, - ...(args.bucket && { - bucket: args.bucket, - }), - palette: { - type: 'palette', - name: args.palette, - }, - } as TagCloudVisParams; - - if (handlers?.inspectorAdapters?.tables) { - const argsTable: Dimension[] = [ - [ - [args.metric], - i18n.translate('visTypeTagCloud.function.dimension.tagSize', { - defaultMessage: 'Tag size', - }), - ], - ]; - if (args.bucket) { - argsTable.push([ - [args.bucket], - i18n.translate('visTypeTagCloud.function.adimension.tags', { - defaultMessage: 'Tags', - }), - ]); - } - const logTable = prepareLogTable(input, argsTable); - handlers.inspectorAdapters.tables.logDatatable('default', logTable); - } - return { - type: 'render', - as: 'tagloud_vis', - value: { - visData: input, - visType: name, - visParams, - syncColors: handlers?.isSyncColorsEnabled?.() ?? false, - }, - }; - }, -}); diff --git a/src/plugins/vis_type_tagcloud/public/tag_cloud_vis_renderer.tsx b/src/plugins/vis_type_tagcloud/public/tag_cloud_vis_renderer.tsx deleted file mode 100644 index 279bfdfffee67..0000000000000 --- a/src/plugins/vis_type_tagcloud/public/tag_cloud_vis_renderer.tsx +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import React, { lazy } from 'react'; -import { render, unmountComponentAtNode } from 'react-dom'; -import { I18nProvider } from '@kbn/i18n/react'; - -import { VisualizationContainer } from '../../visualizations/public'; -import { ExpressionRenderDefinition } from '../../expressions/common/expression_renderers'; -import { TagCloudVisDependencies } from './plugin'; -import { TagCloudVisRenderValue } from './tag_cloud_fn'; - -const TagCloudChart = lazy(() => import('./components/tag_cloud_chart')); - -export const getTagCloudVisRenderer: ( - deps: TagCloudVisDependencies -) => ExpressionRenderDefinition = ({ palettes }) => ({ - name: 'tagloud_vis', - displayName: 'Tag Cloud visualization', - reuseDomNode: true, - render: async (domNode, config, handlers) => { - handlers.onDestroy(() => { - unmountComponentAtNode(domNode); - }); - const palettesRegistry = await palettes.getPalettes(); - - render( - - - - - , - domNode - ); - }, -}); diff --git a/src/plugins/vis_type_tagcloud/public/to_ast.ts b/src/plugins/vis_type_tagcloud/public/to_ast.ts index 8a2fb4e843973..c8810aa0397ee 100644 --- a/src/plugins/vis_type_tagcloud/public/to_ast.ts +++ b/src/plugins/vis_type_tagcloud/public/to_ast.ts @@ -12,7 +12,6 @@ import { } from '../../data/public'; import { buildExpression, buildExpressionFunction } from '../../expressions/public'; import { getVisSchemas, SchemaConfig, VisToExpressionAst } from '../../visualizations/public'; -import { TagcloudExpressionFunctionDefinition } from './tag_cloud_fn'; import { TagCloudVisParams } from './types'; const prepareDimension = (params: SchemaConfig) => { @@ -41,7 +40,7 @@ export const toExpressionAst: VisToExpressionAst = (vis, para const schemas = getVisSchemas(vis, params); const { scale, orientation, minFontSize, maxFontSize, showLabel, palette } = vis.params; - const tagcloud = buildExpressionFunction('tagcloud', { + const tagcloud = buildExpressionFunction('tagcloud', { scale, orientation, minFontSize, diff --git a/src/plugins/vis_type_tagcloud/public/types.ts b/src/plugins/vis_type_tagcloud/public/types.ts index 7105476670693..d855ae5ab65c6 100644 --- a/src/plugins/vis_type_tagcloud/public/types.ts +++ b/src/plugins/vis_type_tagcloud/public/types.ts @@ -7,7 +7,6 @@ */ import type { ChartsPluginSetup, PaletteOutput } from '../../charts/public'; import type { SerializedFieldFormat } from '../../expressions/public'; -import { ExpressionValueVisDimension } from '../../visualizations/public'; interface Dimension { accessor: number; @@ -25,11 +24,6 @@ interface TagCloudCommonParams { showLabel: boolean; } -export interface TagCloudVisConfig extends TagCloudCommonParams { - metric: ExpressionValueVisDimension; - bucket?: ExpressionValueVisDimension; -} - export interface TagCloudVisParams extends TagCloudCommonParams { palette: PaletteOutput; metric: Dimension; diff --git a/src/plugins/vis_type_tagcloud/tsconfig.json b/src/plugins/vis_type_tagcloud/tsconfig.json index 021237dd7ad5b..043eed06c6bcb 100644 --- a/src/plugins/vis_type_tagcloud/tsconfig.json +++ b/src/plugins/vis_type_tagcloud/tsconfig.json @@ -17,7 +17,6 @@ { "path": "../expressions/tsconfig.json" }, { "path": "../visualizations/tsconfig.json" }, { "path": "../charts/tsconfig.json" }, - { "path": "../kibana_utils/tsconfig.json" }, { "path": "../kibana_react/tsconfig.json" }, { "path": "../vis_default_editor/tsconfig.json" }, ] diff --git a/test/interpreter_functional/snapshots/baseline/partial_test_1.json b/test/interpreter_functional/snapshots/baseline/partial_test_1.json index e0b62688d0662..082c7b934c17c 100644 --- a/test/interpreter_functional/snapshots/baseline/partial_test_1.json +++ b/test/interpreter_functional/snapshots/baseline/partial_test_1.json @@ -1 +1 @@ -{"as":"tagloud_vis","type":"render","value":{"syncColors":false,"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visParams":{"bucket":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"maxFontSize":72,"metric":{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"single","palette":{"name":"default","type":"palette"},"scale":"linear","showLabel":true},"visType":"tagcloud"}} \ No newline at end of file +{"as":"tagcloud","type":"render","value":{"syncColors":false,"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visParams":{"bucket":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"maxFontSize":72,"metric":{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"single","palette":{"name":"default","type":"palette"},"scale":"linear","showLabel":true},"visType":"tagcloud"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/baseline/tagcloud_all_data.json b/test/interpreter_functional/snapshots/baseline/tagcloud_all_data.json index d85444f5d3b6b..9813a3ca036a1 100644 --- a/test/interpreter_functional/snapshots/baseline/tagcloud_all_data.json +++ b/test/interpreter_functional/snapshots/baseline/tagcloud_all_data.json @@ -1 +1 @@ -{"as":"tagloud_vis","type":"render","value":{"syncColors":false,"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visParams":{"bucket":{"accessor":1,"format":{"id":"string","params":{}},"type":"vis_dimension"},"maxFontSize":72,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"single","palette":{"name":"default","type":"palette"},"scale":"linear","showLabel":true},"visType":"tagcloud"}} \ No newline at end of file +{"as":"tagcloud","type":"render","value":{"syncColors":false,"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visParams":{"bucket":{"accessor":1,"format":{"id":"string","params":{}},"type":"vis_dimension"},"maxFontSize":72,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"single","palette":{"name":"default","type":"palette"},"scale":"linear","showLabel":true},"visType":"tagcloud"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/baseline/tagcloud_fontsize.json b/test/interpreter_functional/snapshots/baseline/tagcloud_fontsize.json index 2c81c9447b826..bef1b10120fe5 100644 --- a/test/interpreter_functional/snapshots/baseline/tagcloud_fontsize.json +++ b/test/interpreter_functional/snapshots/baseline/tagcloud_fontsize.json @@ -1 +1 @@ -{"as":"tagloud_vis","type":"render","value":{"syncColors":false,"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visParams":{"bucket":{"accessor":1,"format":{"id":"string","params":{}},"type":"vis_dimension"},"maxFontSize":40,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":20,"orientation":"single","palette":{"name":"default","type":"palette"},"scale":"linear","showLabel":true},"visType":"tagcloud"}} \ No newline at end of file +{"as":"tagcloud","type":"render","value":{"syncColors":false,"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visParams":{"bucket":{"accessor":1,"format":{"id":"string","params":{}},"type":"vis_dimension"},"maxFontSize":40,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":20,"orientation":"single","palette":{"name":"default","type":"palette"},"scale":"linear","showLabel":true},"visType":"tagcloud"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/baseline/tagcloud_invalid_data.json b/test/interpreter_functional/snapshots/baseline/tagcloud_invalid_data.json index 687b669b18e61..3e594380588dc 100644 --- a/test/interpreter_functional/snapshots/baseline/tagcloud_invalid_data.json +++ b/test/interpreter_functional/snapshots/baseline/tagcloud_invalid_data.json @@ -1 +1 @@ -{"as":"tagloud_vis","type":"render","value":{"syncColors":false,"visData":{"columns":[],"meta":{},"rows":[],"type":"datatable"},"visParams":{"maxFontSize":72,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"single","palette":{"name":"default","type":"palette"},"scale":"linear","showLabel":true},"visType":"tagcloud"}} \ No newline at end of file +{"as":"tagcloud","type":"render","value":{"syncColors":false,"visData":{"columns":[],"meta":{},"rows":[],"type":"datatable"},"visParams":{"maxFontSize":72,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"single","palette":{"name":"default","type":"palette"},"scale":"linear","showLabel":true},"visType":"tagcloud"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/baseline/tagcloud_metric_data.json b/test/interpreter_functional/snapshots/baseline/tagcloud_metric_data.json index b49953f9a023b..bea6dad294e01 100644 --- a/test/interpreter_functional/snapshots/baseline/tagcloud_metric_data.json +++ b/test/interpreter_functional/snapshots/baseline/tagcloud_metric_data.json @@ -1 +1 @@ -{"as":"tagloud_vis","type":"render","value":{"syncColors":false,"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visParams":{"maxFontSize":72,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"single","palette":{"name":"default","type":"palette"},"scale":"linear","showLabel":true},"visType":"tagcloud"}} \ No newline at end of file +{"as":"tagcloud","type":"render","value":{"syncColors":false,"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visParams":{"maxFontSize":72,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"single","palette":{"name":"default","type":"palette"},"scale":"linear","showLabel":true},"visType":"tagcloud"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/baseline/tagcloud_options.json b/test/interpreter_functional/snapshots/baseline/tagcloud_options.json index fc7e289dfbd3a..c45b063fdb542 100644 --- a/test/interpreter_functional/snapshots/baseline/tagcloud_options.json +++ b/test/interpreter_functional/snapshots/baseline/tagcloud_options.json @@ -1 +1 @@ -{"as":"tagloud_vis","type":"render","value":{"syncColors":false,"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visParams":{"bucket":{"accessor":1,"format":{"id":"string","params":{}},"type":"vis_dimension"},"maxFontSize":72,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"multiple","palette":{"name":"default","type":"palette"},"scale":"log","showLabel":true},"visType":"tagcloud"}} \ No newline at end of file +{"as":"tagcloud","type":"render","value":{"syncColors":false,"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visParams":{"bucket":{"accessor":1,"format":{"id":"string","params":{}},"type":"vis_dimension"},"maxFontSize":72,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"multiple","palette":{"name":"default","type":"palette"},"scale":"log","showLabel":true},"visType":"tagcloud"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/session/partial_test_1.json b/test/interpreter_functional/snapshots/session/partial_test_1.json index e0b62688d0662..082c7b934c17c 100644 --- a/test/interpreter_functional/snapshots/session/partial_test_1.json +++ b/test/interpreter_functional/snapshots/session/partial_test_1.json @@ -1 +1 @@ -{"as":"tagloud_vis","type":"render","value":{"syncColors":false,"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visParams":{"bucket":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"maxFontSize":72,"metric":{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"single","palette":{"name":"default","type":"palette"},"scale":"linear","showLabel":true},"visType":"tagcloud"}} \ No newline at end of file +{"as":"tagcloud","type":"render","value":{"syncColors":false,"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visParams":{"bucket":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"maxFontSize":72,"metric":{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"single","palette":{"name":"default","type":"palette"},"scale":"linear","showLabel":true},"visType":"tagcloud"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/session/tagcloud_all_data.json b/test/interpreter_functional/snapshots/session/tagcloud_all_data.json index d85444f5d3b6b..9813a3ca036a1 100644 --- a/test/interpreter_functional/snapshots/session/tagcloud_all_data.json +++ b/test/interpreter_functional/snapshots/session/tagcloud_all_data.json @@ -1 +1 @@ -{"as":"tagloud_vis","type":"render","value":{"syncColors":false,"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visParams":{"bucket":{"accessor":1,"format":{"id":"string","params":{}},"type":"vis_dimension"},"maxFontSize":72,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"single","palette":{"name":"default","type":"palette"},"scale":"linear","showLabel":true},"visType":"tagcloud"}} \ No newline at end of file +{"as":"tagcloud","type":"render","value":{"syncColors":false,"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visParams":{"bucket":{"accessor":1,"format":{"id":"string","params":{}},"type":"vis_dimension"},"maxFontSize":72,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"single","palette":{"name":"default","type":"palette"},"scale":"linear","showLabel":true},"visType":"tagcloud"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/session/tagcloud_fontsize.json b/test/interpreter_functional/snapshots/session/tagcloud_fontsize.json index 2c81c9447b826..bef1b10120fe5 100644 --- a/test/interpreter_functional/snapshots/session/tagcloud_fontsize.json +++ b/test/interpreter_functional/snapshots/session/tagcloud_fontsize.json @@ -1 +1 @@ -{"as":"tagloud_vis","type":"render","value":{"syncColors":false,"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visParams":{"bucket":{"accessor":1,"format":{"id":"string","params":{}},"type":"vis_dimension"},"maxFontSize":40,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":20,"orientation":"single","palette":{"name":"default","type":"palette"},"scale":"linear","showLabel":true},"visType":"tagcloud"}} \ No newline at end of file +{"as":"tagcloud","type":"render","value":{"syncColors":false,"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visParams":{"bucket":{"accessor":1,"format":{"id":"string","params":{}},"type":"vis_dimension"},"maxFontSize":40,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":20,"orientation":"single","palette":{"name":"default","type":"palette"},"scale":"linear","showLabel":true},"visType":"tagcloud"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/session/tagcloud_invalid_data.json b/test/interpreter_functional/snapshots/session/tagcloud_invalid_data.json index 687b669b18e61..3e594380588dc 100644 --- a/test/interpreter_functional/snapshots/session/tagcloud_invalid_data.json +++ b/test/interpreter_functional/snapshots/session/tagcloud_invalid_data.json @@ -1 +1 @@ -{"as":"tagloud_vis","type":"render","value":{"syncColors":false,"visData":{"columns":[],"meta":{},"rows":[],"type":"datatable"},"visParams":{"maxFontSize":72,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"single","palette":{"name":"default","type":"palette"},"scale":"linear","showLabel":true},"visType":"tagcloud"}} \ No newline at end of file +{"as":"tagcloud","type":"render","value":{"syncColors":false,"visData":{"columns":[],"meta":{},"rows":[],"type":"datatable"},"visParams":{"maxFontSize":72,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"single","palette":{"name":"default","type":"palette"},"scale":"linear","showLabel":true},"visType":"tagcloud"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/session/tagcloud_metric_data.json b/test/interpreter_functional/snapshots/session/tagcloud_metric_data.json index b49953f9a023b..bea6dad294e01 100644 --- a/test/interpreter_functional/snapshots/session/tagcloud_metric_data.json +++ b/test/interpreter_functional/snapshots/session/tagcloud_metric_data.json @@ -1 +1 @@ -{"as":"tagloud_vis","type":"render","value":{"syncColors":false,"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visParams":{"maxFontSize":72,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"single","palette":{"name":"default","type":"palette"},"scale":"linear","showLabel":true},"visType":"tagcloud"}} \ No newline at end of file +{"as":"tagcloud","type":"render","value":{"syncColors":false,"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visParams":{"maxFontSize":72,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"single","palette":{"name":"default","type":"palette"},"scale":"linear","showLabel":true},"visType":"tagcloud"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/session/tagcloud_options.json b/test/interpreter_functional/snapshots/session/tagcloud_options.json index fc7e289dfbd3a..c45b063fdb542 100644 --- a/test/interpreter_functional/snapshots/session/tagcloud_options.json +++ b/test/interpreter_functional/snapshots/session/tagcloud_options.json @@ -1 +1 @@ -{"as":"tagloud_vis","type":"render","value":{"syncColors":false,"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visParams":{"bucket":{"accessor":1,"format":{"id":"string","params":{}},"type":"vis_dimension"},"maxFontSize":72,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"multiple","palette":{"name":"default","type":"palette"},"scale":"log","showLabel":true},"visType":"tagcloud"}} \ No newline at end of file +{"as":"tagcloud","type":"render","value":{"syncColors":false,"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visParams":{"bucket":{"accessor":1,"format":{"id":"string","params":{}},"type":"vis_dimension"},"maxFontSize":72,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"multiple","palette":{"name":"default","type":"palette"},"scale":"log","showLabel":true},"visType":"tagcloud"}} \ No newline at end of file diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index b5b7e35c4a9b4..84806cd6acfec 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -4230,14 +4230,14 @@ "visTypeTable.vis.controls.formattedCSVButtonLabel": "フォーマット済み", "visTypeTable.vis.controls.rawCSVButtonLabel": "未加工", "visTypeTable.vis.noResultsFoundTitle": "結果が見つかりませんでした", - "visTypeTagCloud.feedbackMessage.tooSmallContainerDescription": "コンテナーが小さすぎてクラウド全体を表示できません。タグが切り取られたか省略されている可能性があります。", - "visTypeTagCloud.feedbackMessage.truncatedTagsDescription": "描写時間が長くなるのを防ぐため、タグの数が切り捨てられています。", - "visTypeTagCloud.function.bucket.help": "バケットディメンションの構成です。", - "visTypeTagCloud.function.help": "タグクラウドのビジュアライゼーションです。", - "visTypeTagCloud.function.metric.help": "メトリックディメンションの構成です。", - "visTypeTagCloud.function.orientation.help": "タグクラウド内の単語の方向です。", - "visTypeTagCloud.function.paletteHelpText": "グラフパレット名を定義します", - "visTypeTagCloud.function.scale.help": "単語のフォントサイズを決定するスケールです", + "expressionTagcloud.feedbackMessage.tooSmallContainerDescription": "コンテナーが小さすぎてクラウド全体を表示できません。タグが切り取られたか省略されている可能性があります。", + "expressionTagcloud.feedbackMessage.truncatedTagsDescription": "描写時間が長くなるのを防ぐため、タグの数が切り捨てられています。", + "expressionTagcloud.functions.tagcloud.args.bucketHelpText": "バケットディメンションの構成です。", + "expressionTagcloud.functions.tagcloudHelpText": "タグクラウドのビジュアライゼーションです。", + "expressionTagcloud.functions.tagcloud.args.metricHelpText": "メトリックディメンションの構成です。", + "expressionTagcloud.functions.tagcloud.args.orientationHelpText": "タグクラウド内の単語の方向です。", + "expressionTagcloud.functions.tagcloud.args.paletteHelpText": "グラフパレット名を定義します", + "expressionTagcloud.functions.tagcloud.args.scaleHelpText": "単語のフォントサイズを決定するスケールです", "visTypeTagCloud.orientations.multipleText": "複数", "visTypeTagCloud.orientations.rightAngledText": "直角", "visTypeTagCloud.orientations.singleText": "単一", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 1a21d16c80f03..8756484e8bf4f 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -4250,14 +4250,14 @@ "visTypeTable.vis.controls.formattedCSVButtonLabel": "格式化", "visTypeTable.vis.controls.rawCSVButtonLabel": "原始", "visTypeTable.vis.noResultsFoundTitle": "找不到结果", - "visTypeTagCloud.feedbackMessage.tooSmallContainerDescription": "容器太小,无法显示整个云。标签可能被裁剪或省略。", - "visTypeTagCloud.feedbackMessage.truncatedTagsDescription": "标签数量已截断,以避免绘制时间过长。", - "visTypeTagCloud.function.bucket.help": "存储桶维度配置", - "visTypeTagCloud.function.help": "标签云图可视化", - "visTypeTagCloud.function.metric.help": "指标维度配置", - "visTypeTagCloud.function.orientation.help": "标签云图内的字方向", - "visTypeTagCloud.function.paletteHelpText": "定义图表调色板名称", - "visTypeTagCloud.function.scale.help": "缩放以确定字体大小", + "expressionTagcloud.feedbackMessage.tooSmallContainerDescription": "容器太小,无法显示整个云。标签可能被裁剪或省略。", + "expressionTagcloud.feedbackMessage.truncatedTagsDescription": "标签数量已截断,以避免绘制时间过长。", + "expressionTagcloud.functions.tagcloud.args.bucketHelpText": "存储桶维度配置", + "expressionTagcloud.functions.tagcloudHelpText": "标签云图可视化", + "expressionTagcloud.functions.tagcloud.args.metricHelpText": "指标维度配置", + "expressionTagcloud.functions.tagcloud.args.orientationHelpText": "标签云图内的字方向", + "expressionTagcloud.functions.tagcloud.args.paletteHelpText": "定义图表调色板名称", + "expressionTagcloud.functions.tagcloud.args.scaleHelpText": "缩放以确定字体大小", "visTypeTagCloud.orientations.multipleText": "多个", "visTypeTagCloud.orientations.rightAngledText": "直角", "visTypeTagCloud.orientations.singleText": "单个", From d1a8bbd22624cb4ad08621ad20bb937a7388dfc0 Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Sun, 22 Aug 2021 23:56:13 +0100 Subject: [PATCH 68/76] skip flaky suite (#106492) --- .../security_and_spaces/tests/alerting/alerts.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/alerts.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/alerts.ts index 7e819fb15ea1f..93535826d14e7 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/alerts.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/alerts.ts @@ -39,7 +39,8 @@ export default function alertTests({ getService }: FtrProviderContext) { const esTestIndexTool = new ESTestIndexTool(es, retry); const taskManagerUtils = new TaskManagerUtils(es, retry); - describe('alerts', () => { + // FLAKY: https://github.com/elastic/kibana/issues/106492 + describe.skip('alerts', () => { const authorizationIndex = '.kibana-test-authorization'; const objectRemover = new ObjectRemover(supertest); From e8e26395fd212d41a4c4ac28b3652959a4679256 Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Mon, 23 Aug 2021 15:18:00 +0100 Subject: [PATCH 69/76] skip failing es promotion suite (#109660) --- .../tests/correlations/errors_failed_transactions.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/test/apm_api_integration/tests/correlations/errors_failed_transactions.ts b/x-pack/test/apm_api_integration/tests/correlations/errors_failed_transactions.ts index 12d71530ecce1..054ccbfb4996e 100644 --- a/x-pack/test/apm_api_integration/tests/correlations/errors_failed_transactions.ts +++ b/x-pack/test/apm_api_integration/tests/correlations/errors_failed_transactions.ts @@ -40,7 +40,8 @@ export default function ApiTest({ getService }: FtrProviderContext) { } ); - registry.when( + // FAILING ES PROMOTION: https://github.com/elastic/kibana/issues/109660 + registry.when.skip( 'correlations errors failed transactions with data and default args', { config: 'trial', archives: ['apm_8.0.0'] }, () => { From ff3bd1dcacd91647b18492b667b5e99064c77975 Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Mon, 23 Aug 2021 10:28:44 -0400 Subject: [PATCH 70/76] [RAC] Fix hover on alert status column (#109273) (#109632) * Fix alert status column hover Co-authored-by: Kerry Gallagher <471693+Kerry350@users.noreply.github.com> --- .../public/pages/alerts/render_cell_value.tsx | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/x-pack/plugins/observability/public/pages/alerts/render_cell_value.tsx b/x-pack/plugins/observability/public/pages/alerts/render_cell_value.tsx index c85ea0b1086fa..691bfc984b9cb 100644 --- a/x-pack/plugins/observability/public/pages/alerts/render_cell_value.tsx +++ b/x-pack/plugins/observability/public/pages/alerts/render_cell_value.tsx @@ -6,7 +6,7 @@ */ import { EuiLink, EuiHealth, EuiText } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import React, { useEffect } from 'react'; +import React from 'react'; /** * We need to produce types and code transpilation at different folders during the build of the package. * We have types and code at different imports because we don't want to import the whole package in the resulting webpack bundle for the plugin. @@ -77,16 +77,6 @@ export const getRenderCellValue = ({ fieldName: columnId, })?.reduce((x) => x[0]); - useEffect(() => { - if (columnId === ALERT_STATUS) { - setCellProps({ - style: { - textAlign: 'center', - }, - }); - } - }, [columnId, setCellProps]); - const theme = useTheme(); switch (columnId) { From e27007f81cc3275df53f7a6d2aedf074eea4b44a Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Mon, 23 Aug 2021 10:45:25 -0400 Subject: [PATCH 71/76] [Fleet] Fix Fleet settings and HostInput error handling (#109418) (#109636) * fix: HostInput error placement onChange * fix: check for duplicates in hosts * fix: validate all sections * fix: error swapping * fix: yaml placeholder position and styling * test: add unit tests for delete behaviour * tidy: use generic for reduce typing Co-authored-by: Mark Hopkin --- .../settings_flyout/hosts_input.test.tsx | 70 ++++++++++++++++++- .../settings_flyout/hosts_input.tsx | 47 +++++++------ .../components/settings_flyout/index.tsx | 48 +++++++++++-- 3 files changed, 135 insertions(+), 30 deletions(-) diff --git a/x-pack/plugins/fleet/public/components/settings_flyout/hosts_input.test.tsx b/x-pack/plugins/fleet/public/components/settings_flyout/hosts_input.test.tsx index bd475acbb4feb..01ec166b74afc 100644 --- a/x-pack/plugins/fleet/public/components/settings_flyout/hosts_input.test.tsx +++ b/x-pack/plugins/fleet/public/components/settings_flyout/hosts_input.test.tsx @@ -12,13 +12,17 @@ import { createFleetTestRendererMock } from '../../mock'; import { HostsInput } from './hosts_input'; -function renderInput(value = ['http://host1.com']) { +function renderInput( + value = ['http://host1.com'], + errors: Array<{ message: string; index?: number }> = [], + mockOnChange: (...args: any[]) => void = jest.fn() +) { const renderer = createFleetTestRendererMock(); - const mockOnChange = jest.fn(); const utils = renderer.render( { fireEvent.change(inputEl, { target: { value: 'http://newhost.com' } }); expect(mockOnChange).toHaveBeenCalledWith(['http://newhost.com']); }); + +test('Should display single indexed error message', async () => { + const { utils } = renderInput(['bad host'], [{ message: 'Invalid URL', index: 0 }]); + const inputEl = await utils.findByText('Invalid URL'); + expect(inputEl).toBeDefined(); +}); + +test('Should display errors in order', async () => { + const { utils } = renderInput( + ['bad host 1', 'bad host 2', 'bad host 3'], + [ + { message: 'Error 1', index: 0 }, + { message: 'Error 2', index: 1 }, + { message: 'Error 3', index: 2 }, + ] + ); + await act(async () => { + const errors = await utils.queryAllByText(/Error [1-3]/); + expect(errors[0]).toHaveTextContent('Error 1'); + expect(errors[1]).toHaveTextContent('Error 2'); + expect(errors[2]).toHaveTextContent('Error 3'); + }); +}); + +test('Should remove error when item deleted', async () => { + const mockOnChange = jest.fn(); + const errors = [ + { message: 'Error 1', index: 0 }, + { message: 'Error 2', index: 1 }, + { message: 'Error 3', index: 2 }, + ]; + + const { utils } = renderInput(['bad host 1', 'bad host 2', 'bad host 3'], errors, mockOnChange); + + mockOnChange.mockImplementation((newValue) => { + utils.rerender( + + ); + }); + + await act(async () => { + const deleteRowButtons = await utils.container.querySelectorAll('[aria-label="Delete host"]'); + if (deleteRowButtons.length !== 3) { + throw new Error('Delete host buttons not found'); + } + + fireEvent.click(deleteRowButtons[1]); + expect(mockOnChange).toHaveBeenCalled(); + + const renderedErrors = await utils.queryAllByText(/Error [1-3]/); + expect(renderedErrors).toHaveLength(2); + expect(renderedErrors[0]).toHaveTextContent('Error 1'); + expect(renderedErrors[1]).toHaveTextContent('Error 3'); + }); +}); diff --git a/x-pack/plugins/fleet/public/components/settings_flyout/hosts_input.tsx b/x-pack/plugins/fleet/public/components/settings_flyout/hosts_input.tsx index c99cad93b7ec6..49cff905d167f 100644 --- a/x-pack/plugins/fleet/public/components/settings_flyout/hosts_input.tsx +++ b/x-pack/plugins/fleet/public/components/settings_flyout/hosts_input.tsx @@ -158,11 +158,31 @@ export const HostsInput: FunctionComponent = ({ [value, onChange] ); + const indexedErrors = useMemo(() => { + if (!errors) { + return []; + } + return errors.reduce((acc, err) => { + if (err.index === undefined) { + return acc; + } + + if (!acc[err.index]) { + acc[err.index] = []; + } + + acc[err.index].push(err.message); + + return acc; + }, []); + }, [errors]); + const onDelete = useCallback( (idx: number) => { + indexedErrors.splice(idx, 1); onChange([...value.slice(0, idx), ...value.slice(idx + 1)]); }, - [value, onChange] + [value, onChange, indexedErrors] ); const addRowHandler = useCallback(() => { @@ -174,36 +194,19 @@ export const HostsInput: FunctionComponent = ({ ({ source, destination }) => { if (source && destination) { const items = euiDragDropReorder(value, source.index, destination.index); - + const sourceErrors = indexedErrors[source.index]; + indexedErrors.splice(source.index, 1); + indexedErrors.splice(destination.index, 0, sourceErrors); onChange(items); } }, - [value, onChange] + [value, onChange, indexedErrors] ); const globalErrors = useMemo(() => { return errors && errors.filter((err) => err.index === undefined).map(({ message }) => message); }, [errors]); - const indexedErrors = useMemo(() => { - if (!errors) { - return []; - } - return errors.reduce((acc, err) => { - if (err.index === undefined) { - return acc; - } - - if (!acc[err.index]) { - acc[err.index] = []; - } - - acc[err.index].push(err.message); - - return acc; - }, [] as string[][]); - }, [errors]); - const isSortable = rows.length > 1; return ( diff --git a/x-pack/plugins/fleet/public/components/settings_flyout/index.tsx b/x-pack/plugins/fleet/public/components/settings_flyout/index.tsx index 3d3a4dda60632..e42733bbd2da0 100644 --- a/x-pack/plugins/fleet/public/components/settings_flyout/index.tsx +++ b/x-pack/plugins/fleet/public/components/settings_flyout/index.tsx @@ -58,9 +58,11 @@ const CodeEditorPlaceholder = styled(EuiTextColor).attrs((props) => ({ }))` position: absolute; top: 0; - right: 0; + left: 0; // Matches monaco editor font-family: Menlo, Monaco, 'Courier New', monospace; + font-size: 12px; + line-height: 21px; pointer-events: none; `; @@ -102,6 +104,7 @@ function useSettingsForm(outputId: string | undefined, onSuccess: () => void) { } const res: Array<{ message: string; index: number }> = []; + const hostIndexes: { [key: string]: number[] } = {}; value.forEach((val, idx) => { if (!val.match(URL_REGEX)) { res.push({ @@ -111,7 +114,23 @@ function useSettingsForm(outputId: string | undefined, onSuccess: () => void) { index: idx, }); } + const curIndexes = hostIndexes[val] || []; + hostIndexes[val] = [...curIndexes, idx]; }); + + Object.values(hostIndexes) + .filter(({ length }) => length > 1) + .forEach((indexes) => { + indexes.forEach((index) => + res.push({ + message: i18n.translate('xpack.fleet.settings.fleetServerHostsDuplicateError', { + defaultMessage: 'Duplicate URL', + }), + index, + }) + ); + }); + if (res.length) { return res; } @@ -132,6 +151,7 @@ function useSettingsForm(outputId: string | undefined, onSuccess: () => void) { const elasticsearchUrlInput = useComboInput('esHostsComboxBox', [], (value) => { const res: Array<{ message: string; index: number }> = []; + const urlIndexes: { [key: string]: number[] } = {}; value.forEach((val, idx) => { if (!val.match(URL_REGEX)) { res.push({ @@ -141,7 +161,23 @@ function useSettingsForm(outputId: string | undefined, onSuccess: () => void) { index: idx, }); } + const curIndexes = urlIndexes[val] || []; + urlIndexes[val] = [...curIndexes, idx]; }); + + Object.values(urlIndexes) + .filter(({ length }) => length > 1) + .forEach((indexes) => { + indexes.forEach((index) => + res.push({ + message: i18n.translate('xpack.fleet.settings.elasticHostDuplicateError', { + defaultMessage: 'Duplicate URL', + }), + index, + }) + ); + }); + if (res.length) { return res; } @@ -162,11 +198,11 @@ function useSettingsForm(outputId: string | undefined, onSuccess: () => void) { }); const validate = useCallback(() => { - if ( - !fleetServerHostsInput.validate() || - !elasticsearchUrlInput.validate() || - !additionalYamlConfigInput.validate() - ) { + const fleetServerHostsValid = fleetServerHostsInput.validate(); + const elasticsearchUrlsValid = elasticsearchUrlInput.validate(); + const additionalYamlConfigValid = additionalYamlConfigInput.validate(); + + if (!fleetServerHostsValid || !elasticsearchUrlsValid || !additionalYamlConfigValid) { return false; } From 377760f0603dd9ec58f39073ffeb487fd55ed350 Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Mon, 23 Aug 2021 11:19:57 -0400 Subject: [PATCH 72/76] [Discover] Fix keeping error state after invalid KQL query (#109514) (#109643) Co-authored-by: Matthias Wilhelm --- .../use_saved_search_messages.test.ts | 79 +++++++++++++++++++ .../services/use_saved_search_messages.ts | 1 + 2 files changed, 80 insertions(+) create mode 100644 src/plugins/discover/public/application/apps/main/services/use_saved_search_messages.test.ts diff --git a/src/plugins/discover/public/application/apps/main/services/use_saved_search_messages.test.ts b/src/plugins/discover/public/application/apps/main/services/use_saved_search_messages.test.ts new file mode 100644 index 0000000000000..9810436aebd90 --- /dev/null +++ b/src/plugins/discover/public/application/apps/main/services/use_saved_search_messages.test.ts @@ -0,0 +1,79 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ +import { + sendCompleteMsg, + sendErrorMsg, + sendLoadingMsg, + sendPartialMsg, +} from './use_saved_search_messages'; +import { FetchStatus } from '../../../types'; +import { BehaviorSubject } from 'rxjs'; +import { DataMainMsg } from './use_saved_search'; + +describe('test useSavedSearch message generators', () => { + test('sendCompleteMsg', async (done) => { + const main$ = new BehaviorSubject({ fetchStatus: FetchStatus.LOADING }); + main$.subscribe((value) => { + if (value.fetchStatus !== FetchStatus.LOADING) { + expect(value.fetchStatus).toBe(FetchStatus.COMPLETE); + expect(value.foundDocuments).toBe(true); + expect(value.error).toBe(undefined); + done(); + } + }); + sendCompleteMsg(main$, true); + }); + test('sendPartialMessage', async (done) => { + const main$ = new BehaviorSubject({ fetchStatus: FetchStatus.LOADING }); + main$.subscribe((value) => { + if (value.fetchStatus !== FetchStatus.LOADING) { + expect(value.fetchStatus).toBe(FetchStatus.PARTIAL); + done(); + } + }); + sendPartialMsg(main$); + }); + test('sendLoadingMsg', async (done) => { + const main$ = new BehaviorSubject({ fetchStatus: FetchStatus.COMPLETE }); + main$.subscribe((value) => { + if (value.fetchStatus !== FetchStatus.COMPLETE) { + expect(value.fetchStatus).toBe(FetchStatus.LOADING); + done(); + } + }); + sendLoadingMsg(main$); + }); + test('sendErrorMsg', async (done) => { + const main$ = new BehaviorSubject({ fetchStatus: FetchStatus.PARTIAL }); + main$.subscribe((value) => { + if (value.fetchStatus === FetchStatus.ERROR) { + expect(value.fetchStatus).toBe(FetchStatus.ERROR); + expect(value.error).toBeInstanceOf(Error); + done(); + } + }); + sendErrorMsg(main$, new Error('Pls help!')); + }); + + test('sendCompleteMsg cleaning error state message', async (done) => { + const initialState = { + fetchStatus: FetchStatus.ERROR, + error: new Error('Oh noes!'), + }; + const main$ = new BehaviorSubject(initialState); + main$.subscribe((value) => { + if (value.fetchStatus === FetchStatus.COMPLETE) { + const newState = { ...initialState, ...value }; + expect(newState.fetchStatus).toBe(FetchStatus.COMPLETE); + expect(newState.error).toBeUndefined(); + done(); + } + }); + sendCompleteMsg(main$, false); + }); +}); diff --git a/src/plugins/discover/public/application/apps/main/services/use_saved_search_messages.ts b/src/plugins/discover/public/application/apps/main/services/use_saved_search_messages.ts index b42d699f344cc..ff72a69e65fa8 100644 --- a/src/plugins/discover/public/application/apps/main/services/use_saved_search_messages.ts +++ b/src/plugins/discover/public/application/apps/main/services/use_saved_search_messages.ts @@ -27,6 +27,7 @@ export function sendCompleteMsg(main$: DataMain$, foundDocuments = true) { main$.next({ fetchStatus: FetchStatus.COMPLETE, foundDocuments, + error: undefined, }); } From 6fe650d30370ff600558cf359d32fdfea2c47f23 Mon Sep 17 00:00:00 2001 From: Aleh Zasypkin Date: Mon, 23 Aug 2021 17:22:31 +0200 Subject: [PATCH 73/76] Cumulative set of the preboot stage adjustments (#108514) (#109646) # Conflicts: # src/plugins/interactive_setup/server/elasticsearch_service.test.ts # src/plugins/interactive_setup/server/elasticsearch_service.ts # src/plugins/interactive_setup/server/routes/enroll.test.ts # src/plugins/interactive_setup/server/routes/enroll.ts --- ...-plugin-core-server.elasticsearchclientconfig.md | 1 + ...-core-server.httpservicepreboot.getserverinfo.md | 13 +++++++++++++ .../kibana-plugin-core-server.httpservicepreboot.md | 1 + src/core/server/core_app/core_app.test.ts | 2 +- src/core/server/core_app/core_app.ts | 2 +- .../elasticsearch/client/client_config.test.ts | 6 ++++++ .../server/elasticsearch/client/client_config.ts | 5 +++++ src/core/server/http/http_service.mock.ts | 2 ++ src/core/server/http/http_service.test.ts | 2 ++ src/core/server/http/http_service.ts | 1 + src/core/server/http/types.ts | 6 ++++++ src/core/server/plugins/plugin_context.ts | 1 + src/core/server/server.api.md | 2 ++ 13 files changed, 42 insertions(+), 2 deletions(-) create mode 100644 docs/development/core/server/kibana-plugin-core-server.httpservicepreboot.getserverinfo.md diff --git a/docs/development/core/server/kibana-plugin-core-server.elasticsearchclientconfig.md b/docs/development/core/server/kibana-plugin-core-server.elasticsearchclientconfig.md index 208e0e0175d71..0084b0b50c869 100644 --- a/docs/development/core/server/kibana-plugin-core-server.elasticsearchclientconfig.md +++ b/docs/development/core/server/kibana-plugin-core-server.elasticsearchclientconfig.md @@ -14,5 +14,6 @@ export declare type ElasticsearchClientConfig = Pick; keepAlive?: boolean; + caFingerprint?: ClientOptions['caFingerprint']; }; ``` diff --git a/docs/development/core/server/kibana-plugin-core-server.httpservicepreboot.getserverinfo.md b/docs/development/core/server/kibana-plugin-core-server.httpservicepreboot.getserverinfo.md new file mode 100644 index 0000000000000..0c9636b8eb634 --- /dev/null +++ b/docs/development/core/server/kibana-plugin-core-server.httpservicepreboot.getserverinfo.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [HttpServicePreboot](./kibana-plugin-core-server.httpservicepreboot.md) > [getServerInfo](./kibana-plugin-core-server.httpservicepreboot.getserverinfo.md) + +## HttpServicePreboot.getServerInfo property + +Provides common [information](./kibana-plugin-core-server.httpserverinfo.md) about the running preboot http server. + +Signature: + +```typescript +getServerInfo: () => HttpServerInfo; +``` diff --git a/docs/development/core/server/kibana-plugin-core-server.httpservicepreboot.md b/docs/development/core/server/kibana-plugin-core-server.httpservicepreboot.md index b4adf454a480f..ab0fc365fc651 100644 --- a/docs/development/core/server/kibana-plugin-core-server.httpservicepreboot.md +++ b/docs/development/core/server/kibana-plugin-core-server.httpservicepreboot.md @@ -73,6 +73,7 @@ httpPreboot.registerRoutes('my-plugin', (router) => { | Property | Type | Description | | --- | --- | --- | | [basePath](./kibana-plugin-core-server.httpservicepreboot.basepath.md) | IBasePath | Access or manipulate the Kibana base path See [IBasePath](./kibana-plugin-core-server.ibasepath.md). | +| [getServerInfo](./kibana-plugin-core-server.httpservicepreboot.getserverinfo.md) | () => HttpServerInfo | Provides common [information](./kibana-plugin-core-server.httpserverinfo.md) about the running preboot http server. | ## Methods diff --git a/src/core/server/core_app/core_app.test.ts b/src/core/server/core_app/core_app.test.ts index f6a9b653ec034..e5c3a592a72c7 100644 --- a/src/core/server/core_app/core_app.test.ts +++ b/src/core/server/core_app/core_app.test.ts @@ -137,7 +137,7 @@ describe('CoreApp', () => { mockResponseFactory ); - expect(mockResponseFactory.renderAnonymousCoreApp).toHaveBeenCalled(); + expect(mockResponseFactory.renderCoreApp).toHaveBeenCalled(); }); }); diff --git a/src/core/server/core_app/core_app.ts b/src/core/server/core_app/core_app.ts index 35a7c57b67610..23ad78ca46d45 100644 --- a/src/core/server/core_app/core_app.ts +++ b/src/core/server/core_app/core_app.ts @@ -64,7 +64,7 @@ export class CoreApp { httpResources: corePreboot.httpResources.createRegistrar(router), router, uiPlugins, - onResourceNotFound: (res) => res.renderAnonymousCoreApp(), + onResourceNotFound: (res) => res.renderCoreApp(), }); }); } diff --git a/src/core/server/elasticsearch/client/client_config.test.ts b/src/core/server/elasticsearch/client/client_config.test.ts index 7e16339b40235..7956bcc64ea2f 100644 --- a/src/core/server/elasticsearch/client/client_config.test.ts +++ b/src/core/server/elasticsearch/client/client_config.test.ts @@ -163,6 +163,12 @@ describe('parseClientOptions', () => { ] `); }); + + it('`caFingerprint` option', () => { + const options = parseClientOptions(createConfig({ caFingerprint: 'ab:cd:ef' }), false); + + expect(options.caFingerprint).toBe('ab:cd:ef'); + }); }); describe('authorization', () => { diff --git a/src/core/server/elasticsearch/client/client_config.ts b/src/core/server/elasticsearch/client/client_config.ts index bbbb1ac247b3b..27d6f877a5572 100644 --- a/src/core/server/elasticsearch/client/client_config.ts +++ b/src/core/server/elasticsearch/client/client_config.ts @@ -35,6 +35,7 @@ export type ElasticsearchClientConfig = Pick< requestTimeout?: ElasticsearchConfig['requestTimeout'] | ClientOptions['requestTimeout']; ssl?: Partial; keepAlive?: boolean; + caFingerprint?: ClientOptions['caFingerprint']; }; /** @@ -96,6 +97,10 @@ export function parseClientOptions( ); } + if (config.caFingerprint != null) { + clientOptions.caFingerprint = config.caFingerprint; + } + return clientOptions; } diff --git a/src/core/server/http/http_service.mock.ts b/src/core/server/http/http_service.mock.ts index ef5e151083780..4cb1bc9867d2c 100644 --- a/src/core/server/http/http_service.mock.ts +++ b/src/core/server/http/http_service.mock.ts @@ -88,6 +88,7 @@ const createInternalPrebootContractMock = () => { csp: CspConfig.DEFAULT, externalUrl: ExternalUrlConfig.DEFAULT, auth: createAuthMock(), + getServerInfo: jest.fn(), }; return mock; }; @@ -98,6 +99,7 @@ const createPrebootContractMock = () => { const mock: HttpServicePrebootMock = { registerRoutes: internalMock.registerRoutes, basePath: createBasePathMock(), + getServerInfo: jest.fn(), }; return mock; diff --git a/src/core/server/http/http_service.test.ts b/src/core/server/http/http_service.test.ts index 8d29e3221a2ca..4955d19668580 100644 --- a/src/core/server/http/http_service.test.ts +++ b/src/core/server/http/http_service.test.ts @@ -379,6 +379,7 @@ test('returns `preboot` http server contract on preboot', async () => { auth: Symbol('auth'), basePath: Symbol('basePath'), csp: Symbol('csp'), + getServerInfo: jest.fn(), }; mockHttpServer.mockImplementation(() => ({ @@ -397,6 +398,7 @@ test('returns `preboot` http server contract on preboot', async () => { registerRouteHandlerContext: expect.any(Function), registerRoutes: expect.any(Function), registerStaticDir: expect.any(Function), + getServerInfo: expect.any(Function), }); }); diff --git a/src/core/server/http/http_service.ts b/src/core/server/http/http_service.ts index 4b9e45e271be2..538a4c065e997 100644 --- a/src/core/server/http/http_service.ts +++ b/src/core/server/http/http_service.ts @@ -128,6 +128,7 @@ export class HttpService prebootSetup.registerRouterAfterListening(router); }, + getServerInfo: prebootSetup.getServerInfo, }; return this.internalPreboot; diff --git a/src/core/server/http/types.ts b/src/core/server/http/types.ts index 7353f48b47194..89d0d72017082 100644 --- a/src/core/server/http/types.ts +++ b/src/core/server/http/types.ts @@ -142,6 +142,11 @@ export interface HttpServicePreboot { * See {@link IBasePath}. */ basePath: IBasePath; + + /** + * Provides common {@link HttpServerInfo | information} about the running preboot http server. + */ + getServerInfo: () => HttpServerInfo; } /** @internal */ @@ -155,6 +160,7 @@ export interface InternalHttpServicePreboot | 'registerStaticDir' | 'registerRouteHandlerContext' | 'server' + | 'getServerInfo' > { registerRoutes(path: string, callback: (router: IRouter) => void): void; } diff --git a/src/core/server/plugins/plugin_context.ts b/src/core/server/plugins/plugin_context.ts index b972c6078ca2b..cbefdae525180 100644 --- a/src/core/server/plugins/plugin_context.ts +++ b/src/core/server/plugins/plugin_context.ts @@ -115,6 +115,7 @@ export function createPluginPrebootSetupContext( http: { registerRoutes: deps.http.registerRoutes, basePath: deps.http.basePath, + getServerInfo: deps.http.getServerInfo, }, preboot: { isSetupOnHold: deps.preboot.isSetupOnHold, diff --git a/src/core/server/server.api.md b/src/core/server/server.api.md index 1bd59dfc7fdb1..67b08f4c0d9b7 100644 --- a/src/core/server/server.api.md +++ b/src/core/server/server.api.md @@ -807,6 +807,7 @@ export type ElasticsearchClientConfig = Pick; keepAlive?: boolean; + caFingerprint?: ClientOptions['caFingerprint']; }; // @public @@ -1003,6 +1004,7 @@ export interface HttpServerInfo { // @public export interface HttpServicePreboot { basePath: IBasePath; + getServerInfo: () => HttpServerInfo; registerRoutes(path: string, callback: (router: IRouter) => void): void; } From 4981a8bb5807bbc03b46c4654851f90f9a9c9260 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ester=20Mart=C3=AD=20Vilaseca?= Date: Mon, 23 Aug 2021 17:55:29 +0200 Subject: [PATCH 74/76] [Stack Monitoring] Add initial react app (#109218) (#109652) * Add feature toggle * Add basic react app with router and simple loading page * Add title hook * Add loading page with page template and clusters hook * fix types * fix tests Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../public/application/hooks/use_clusters.ts | 65 +++++++++++++++++++ .../public/application/hooks/use_title.ts | 24 +++++++ .../monitoring/public/application/index.tsx | 61 +++++++++++++++++ .../public/application/pages/loading_page.tsx | 41 ++++++++++++ .../application/pages/page_template.tsx | 20 ++++++ .../monitoring/public/components/index.d.ts | 8 +++ x-pack/plugins/monitoring/public/plugin.ts | 40 +++++++----- .../plugins/monitoring/server/config.test.ts | 1 + x-pack/plugins/monitoring/server/config.ts | 1 + 9 files changed, 245 insertions(+), 16 deletions(-) create mode 100644 x-pack/plugins/monitoring/public/application/hooks/use_clusters.ts create mode 100644 x-pack/plugins/monitoring/public/application/hooks/use_title.ts create mode 100644 x-pack/plugins/monitoring/public/application/index.tsx create mode 100644 x-pack/plugins/monitoring/public/application/pages/loading_page.tsx create mode 100644 x-pack/plugins/monitoring/public/application/pages/page_template.tsx create mode 100644 x-pack/plugins/monitoring/public/components/index.d.ts diff --git a/x-pack/plugins/monitoring/public/application/hooks/use_clusters.ts b/x-pack/plugins/monitoring/public/application/hooks/use_clusters.ts new file mode 100644 index 0000000000000..49f6464b2ce3e --- /dev/null +++ b/x-pack/plugins/monitoring/public/application/hooks/use_clusters.ts @@ -0,0 +1,65 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { useState, useEffect } from 'react'; +import { useKibana } from '../../../../../../src/plugins/kibana_react/public'; +import { STANDALONE_CLUSTER_CLUSTER_UUID } from '../../../common/constants'; + +export function useClusters(codePaths?: string[], fetchAllClusters?: boolean, ccs?: any) { + const clusterUuid = fetchAllClusters ? null : ''; + const { services } = useKibana<{ data: any }>(); + + const bounds = services.data?.query.timefilter.timefilter.getBounds(); + const [min] = useState(bounds.min.toISOString()); + const [max] = useState(bounds.max.toISOString()); + + const [clusters, setClusters] = useState([]); + const [loaded, setLoaded] = useState(false); + + let url = '../api/monitoring/v1/clusters'; + if (clusterUuid) { + url += `/${clusterUuid}`; + } + + useEffect(() => { + const fetchClusters = async () => { + try { + const response = await services.http?.fetch(url, { + method: 'POST', + body: JSON.stringify({ + ccs, + timeRange: { + min, + max, + }, + codePaths, + }), + }); + + setClusters(formatClusters(response)); + } catch (err) { + // TODO: handle errors + } finally { + setLoaded(null); + } + }; + + fetchClusters(); + }, [ccs, services.http, codePaths, url, min, max]); + + return { clusters, loaded }; +} + +function formatClusters(clusters: any) { + return clusters.map(formatCluster); +} + +function formatCluster(cluster: any) { + if (cluster.cluster_uuid === STANDALONE_CLUSTER_CLUSTER_UUID) { + cluster.cluster_name = 'Standalone Cluster'; + } + return cluster; +} diff --git a/x-pack/plugins/monitoring/public/application/hooks/use_title.ts b/x-pack/plugins/monitoring/public/application/hooks/use_title.ts new file mode 100644 index 0000000000000..25cc2c5b40dff --- /dev/null +++ b/x-pack/plugins/monitoring/public/application/hooks/use_title.ts @@ -0,0 +1,24 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { get } from 'lodash'; +import { i18n } from '@kbn/i18n'; +import { useKibana } from '../../../../../../src/plugins/kibana_react/public'; + +// TODO: verify that works for all pages +export function useTitle(cluster: string, suffix: string) { + const { services } = useKibana(); + let clusterName = get(cluster, 'cluster_name'); + clusterName = clusterName ? `- ${clusterName}` : ''; + suffix = suffix ? `- ${suffix}` : ''; + + services.chrome?.docTitle.change( + i18n.translate('xpack.monitoring.stackMonitoringDocTitle', { + defaultMessage: 'Stack Monitoring {clusterName} {suffix}', + values: { clusterName, suffix }, + }) + ); +} diff --git a/x-pack/plugins/monitoring/public/application/index.tsx b/x-pack/plugins/monitoring/public/application/index.tsx new file mode 100644 index 0000000000000..a0c9afd73f0ce --- /dev/null +++ b/x-pack/plugins/monitoring/public/application/index.tsx @@ -0,0 +1,61 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { CoreStart, AppMountParameters } from 'kibana/public'; +import React from 'react'; +import ReactDOM from 'react-dom'; +import { Route, Switch, Redirect, HashRouter } from 'react-router-dom'; +import { KibanaContextProvider } from '../../../../../src/plugins/kibana_react/public'; +import { LoadingPage } from './pages/loading_page'; +import { MonitoringStartPluginDependencies } from '../types'; + +export const renderApp = ( + core: CoreStart, + plugins: MonitoringStartPluginDependencies, + { element }: AppMountParameters +) => { + ReactDOM.render(, element); + + return () => { + ReactDOM.unmountComponentAtNode(element); + }; +}; + +const MonitoringApp: React.FC<{ + core: CoreStart; + plugins: MonitoringStartPluginDependencies; +}> = ({ core, plugins }) => { + return ( + + + + + + + + + + + + ); +}; + +const NoData: React.FC<{}> = () => { + return
No data page
; +}; + +const Home: React.FC<{}> = () => { + return
Home page (Cluster listing)
; +}; + +const ClusterOverview: React.FC<{}> = () => { + return
Cluster overview page
; +}; diff --git a/x-pack/plugins/monitoring/public/application/pages/loading_page.tsx b/x-pack/plugins/monitoring/public/application/pages/loading_page.tsx new file mode 100644 index 0000000000000..4bd09f73ac75a --- /dev/null +++ b/x-pack/plugins/monitoring/public/application/pages/loading_page.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 + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { Redirect } from 'react-router-dom'; +import { i18n } from '@kbn/i18n'; +import { PageTemplate } from './page_template'; +import { PageLoading } from '../../components'; +import { useClusters } from '../hooks/use_clusters'; +import { CODE_PATH_ELASTICSEARCH } from '../../../common/constants'; + +const CODE_PATHS = [CODE_PATH_ELASTICSEARCH]; + +export const LoadingPage = () => { + const { clusters, loaded } = useClusters(CODE_PATHS, true); + const title = i18n.translate('xpack.monitoring.loading.pageTitle', { + defaultMessage: 'Loading', + }); + + return ( + + {loaded === false ? : renderRedirections(clusters)} + + ); +}; + +const renderRedirections = (clusters: any) => { + if (!clusters || !clusters.length) { + return ; + } + if (clusters.length === 1) { + // Bypass the cluster listing if there is just 1 cluster + return ; + } + + return ; +}; diff --git a/x-pack/plugins/monitoring/public/application/pages/page_template.tsx b/x-pack/plugins/monitoring/public/application/pages/page_template.tsx new file mode 100644 index 0000000000000..fb766af6c8cbe --- /dev/null +++ b/x-pack/plugins/monitoring/public/application/pages/page_template.tsx @@ -0,0 +1,20 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { useTitle } from '../hooks/use_title'; + +interface PageTemplateProps { + title: string; + children: React.ReactNode; +} + +export const PageTemplate = ({ title, children }: PageTemplateProps) => { + useTitle('', title); + + return
{children}
; +}; diff --git a/x-pack/plugins/monitoring/public/components/index.d.ts b/x-pack/plugins/monitoring/public/components/index.d.ts new file mode 100644 index 0000000000000..d027298c81c4c --- /dev/null +++ b/x-pack/plugins/monitoring/public/components/index.d.ts @@ -0,0 +1,8 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export const PageLoading: FunctionComponent; diff --git a/x-pack/plugins/monitoring/public/plugin.ts b/x-pack/plugins/monitoring/public/plugin.ts index 710b453e7f21e..df0496d438013 100644 --- a/x-pack/plugins/monitoring/public/plugin.ts +++ b/x-pack/plugins/monitoring/public/plugin.ts @@ -94,6 +94,7 @@ export class MonitoringPlugin mount: async (params: AppMountParameters) => { const [coreStart, pluginsStart] = await core.getStartServices(); const { AngularApp } = await import('./angular'); + const externalConfig = this.getExternalConfig(); const deps: MonitoringStartPluginDependencies = { navigation: pluginsStart.navigation, kibanaLegacy: pluginsStart.kibanaLegacy, @@ -102,27 +103,33 @@ export class MonitoringPlugin data: pluginsStart.data, isCloud: Boolean(plugins.cloud?.isCloudEnabled), pluginInitializerContext: this.initializerContext, - externalConfig: this.getExternalConfig(), + externalConfig, triggersActionsUi: pluginsStart.triggersActionsUi, usageCollection: plugins.usageCollection, appMountParameters: params, }; - const monitoringApp = new AngularApp(deps); - const removeHistoryListener = params.history.listen((location) => { - if (location.pathname === '' && location.hash === '') { - monitoringApp.applyScope(); - } - }); - - const removeHashChange = this.setInitialTimefilter(deps); - return () => { - if (removeHashChange) { - removeHashChange(); - } - removeHistoryListener(); - monitoringApp.destroy(); - }; + const config = Object.fromEntries(externalConfig); + if (config.renderReactApp) { + const { renderApp } = await import('./application'); + return renderApp(coreStart, pluginsStart, params); + } else { + const monitoringApp = new AngularApp(deps); + const removeHistoryListener = params.history.listen((location) => { + if (location.pathname === '' && location.hash === '') { + monitoringApp.applyScope(); + } + }); + + const removeHashChange = this.setInitialTimefilter(deps); + return () => { + if (removeHashChange) { + removeHashChange(); + } + removeHistoryListener(); + monitoringApp.destroy(); + }; + } }, }; @@ -163,6 +170,7 @@ export class MonitoringPlugin ['showLicenseExpiration', monitoring.ui.show_license_expiration], ['showCgroupMetricsElasticsearch', monitoring.ui.container.elasticsearch.enabled], ['showCgroupMetricsLogstash', monitoring.ui.container.logstash.enabled], + ['renderReactApp', monitoring.ui.render_react_app], ]; } diff --git a/x-pack/plugins/monitoring/server/config.test.ts b/x-pack/plugins/monitoring/server/config.test.ts index f39e5a0703d22..90c6e68314b71 100644 --- a/x-pack/plugins/monitoring/server/config.test.ts +++ b/x-pack/plugins/monitoring/server/config.test.ts @@ -106,6 +106,7 @@ describe('config schema', () => { "index": "metricbeat-*", }, "min_interval_seconds": 10, + "render_react_app": false, "show_license_expiration": true, }, } diff --git a/x-pack/plugins/monitoring/server/config.ts b/x-pack/plugins/monitoring/server/config.ts index 98fd02b03539c..5c2bdc1424f93 100644 --- a/x-pack/plugins/monitoring/server/config.ts +++ b/x-pack/plugins/monitoring/server/config.ts @@ -51,6 +51,7 @@ export const configSchema = schema.object({ }), min_interval_seconds: schema.number({ defaultValue: 10 }), show_license_expiration: schema.boolean({ defaultValue: true }), + render_react_app: schema.boolean({ defaultValue: false }), }), kibana: schema.object({ collection: schema.object({ From bf9413dc42b4f2beebf2e316879ace26f254966f Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Mon, 23 Aug 2021 12:02:22 -0400 Subject: [PATCH 75/76] [APM] Support multiple route paths in useApmParams (#109370) (#109653) Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Dario Gieselaar --- .../src/create_router.test.tsx | 15 +++++++ .../src/create_router.ts | 44 ++++++++++++------- .../src/types/index.ts | 16 +++++++ .../src/use_params.ts | 18 +++++++- .../service_map/Popover/backend_contents.tsx | 6 ++- .../apm/public/hooks/use_apm_params.ts | 26 +++++++++-- x-pack/plugins/apm/typings/common.d.ts | 1 + 7 files changed, 104 insertions(+), 22 deletions(-) diff --git a/packages/kbn-typed-react-router-config/src/create_router.test.tsx b/packages/kbn-typed-react-router-config/src/create_router.test.tsx index d8f42c8714e8b..3fb37f813e2e1 100644 --- a/packages/kbn-typed-react-router-config/src/create_router.test.tsx +++ b/packages/kbn-typed-react-router-config/src/create_router.test.tsx @@ -201,6 +201,21 @@ describe('createRouter', () => { }, }); }); + + it('supports multiple paths', () => { + history.push('/service-map?rangeFrom=now-15m&rangeTo=now&maxNumNodes=3'); + + const params = router.getParams('/services', '/service-map', history.location); + + expect(params).toEqual({ + path: {}, + query: { + maxNumNodes: 3, + rangeFrom: 'now-15m', + rangeTo: 'now', + }, + }); + }); }); describe('matchRoutes', () => { diff --git a/packages/kbn-typed-react-router-config/src/create_router.ts b/packages/kbn-typed-react-router-config/src/create_router.ts index 28f9e2774eb74..370d8b48e53b4 100644 --- a/packages/kbn-typed-react-router-config/src/create_router.ts +++ b/packages/kbn-typed-react-router-config/src/create_router.ts @@ -9,6 +9,7 @@ import { isLeft } from 'fp-ts/lib/Either'; import { Location } from 'history'; import { PathReporter } from 'io-ts/lib/PathReporter'; import { + MatchedRoute, matchRoutes as matchRoutesConfig, RouteConfig as ReactRouterConfig, } from 'react-router-config'; @@ -49,33 +50,44 @@ export function createRouter(routes: TRoutes): Router { - let path: string = args[0]; - let location: Location = args[1]; - let optional: boolean = args[2]; - - if (args.length === 1) { - location = args[0] as Location; - path = location.pathname; - optional = args[1]; + let optional: boolean = false; + + if (typeof args[args.length - 1] === 'boolean') { + optional = args[args.length - 1]; + args.pop(); } - const greedy = path.endsWith('/*') || args.length === 1; + const location: Location = args[args.length - 1]; + args.pop(); + + let paths: string[] = args; - if (!path) { - path = '/'; + if (paths.length === 0) { + paths = [location.pathname || '/']; } - const matches = matchRoutesConfig(reactRouterConfigs, location.pathname); + let matches: Array> = []; + let matchIndex: number = -1; - const matchIndex = greedy - ? matches.length - 1 - : findLastIndex(matches, (match) => match.route.path === path); + for (const path of paths) { + const greedy = path.endsWith('/*') || args.length === 0; + matches = matchRoutesConfig(reactRouterConfigs, location.pathname); + + matchIndex = greedy + ? matches.length - 1 + : findLastIndex(matches, (match) => match.route.path === path); + + if (matchIndex !== -1) { + break; + } + matchIndex = -1; + } if (matchIndex === -1) { if (optional) { return []; } - throw new Error(`No matching route found for ${path}`); + throw new Error(`No matching route found for ${paths}`); } return matches.slice(0, matchIndex + 1).map((matchedRoute) => { diff --git a/packages/kbn-typed-react-router-config/src/types/index.ts b/packages/kbn-typed-react-router-config/src/types/index.ts index 0e02318c50aad..4d26d2879d5e7 100644 --- a/packages/kbn-typed-react-router-config/src/types/index.ts +++ b/packages/kbn-typed-react-router-config/src/types/index.ts @@ -134,6 +134,22 @@ export interface Router { location: Location, optional: TOptional ): TOptional extends true ? TypeOf | undefined : TypeOf; + getParams, T2 extends PathsOf>( + path1: T1, + path2: T2, + location: Location + ): TypeOf | TypeOf; + getParams, T2 extends PathsOf, T3 extends PathsOf>( + path1: T1, + path2: T2, + path3: T3, + location: Location + ): TypeOf | TypeOf | TypeOf; + getParams, TOptional extends boolean>( + path: TPath, + location: Location, + optional: TOptional + ): TOptional extends true ? TypeOf | undefined : TypeOf; link>( path: TPath, ...args: TypeAsArgs> diff --git a/packages/kbn-typed-react-router-config/src/use_params.ts b/packages/kbn-typed-react-router-config/src/use_params.ts index 94a5cf401c569..0468eb9566236 100644 --- a/packages/kbn-typed-react-router-config/src/use_params.ts +++ b/packages/kbn-typed-react-router-config/src/use_params.ts @@ -6,12 +6,26 @@ * Side Public License, v 1. */ +import { Location } from 'history'; import { useLocation } from 'react-router-dom'; import { useRouter } from './use_router'; -export function useParams(path: string, optional: boolean = false) { +export function useParams(...args: any[]) { const router = useRouter(); const location = useLocation(); - return router.getParams(path as never, location, optional); + let optional: boolean = false; + + const last: boolean | string | undefined = args[args.length - 1]; + + if (typeof last === 'boolean') { + optional = last; + args.pop(); + } + + const paths = args as string[]; + + const getParamsArgs = [...paths, location, optional] as [never, Location, boolean]; + + return router.getParams(...getParamsArgs); } diff --git a/x-pack/plugins/apm/public/components/app/service_map/Popover/backend_contents.tsx b/x-pack/plugins/apm/public/components/app/service_map/Popover/backend_contents.tsx index 5a55fd1979c91..0432cdb2dff5e 100644 --- a/x-pack/plugins/apm/public/components/app/service_map/Popover/backend_contents.tsx +++ b/x-pack/plugins/apm/public/components/app/service_map/Popover/backend_contents.tsx @@ -21,7 +21,11 @@ import { ApmRoutes } from '../../../routing/apm_route_config'; import { StatsList } from './stats_list'; export function BackendContents({ nodeData, environment }: ContentsProps) { - const { query } = useApmParams('/*'); + const { query } = useApmParams( + '/service-map', + '/services/:serviceName/service-map' + ); + const apmRouter = useApmRouter(); const { urlParams: { start, end }, diff --git a/x-pack/plugins/apm/public/hooks/use_apm_params.ts b/x-pack/plugins/apm/public/hooks/use_apm_params.ts index fd27e8446e3c4..12b79ec7c90ae 100644 --- a/x-pack/plugins/apm/public/hooks/use_apm_params.ts +++ b/x-pack/plugins/apm/public/hooks/use_apm_params.ts @@ -17,9 +17,29 @@ export function useApmParams>( path: TPath ): TypeOf; +export function useApmParams< + TPath1 extends PathsOf, + TPath2 extends PathsOf +>( + path1: TPath1, + path2: TPath2 +): TypeOf | TypeOf; + +export function useApmParams< + TPath1 extends PathsOf, + TPath2 extends PathsOf, + TPath3 extends PathsOf +>( + path1: TPath1, + path2: TPath2, + path3: TPath3 +): + | TypeOf + | TypeOf + | TypeOf; + export function useApmParams( - path: string, - optional?: true + ...args: any[] ): TypeOf> | undefined { - return useParams(path, optional); + return useParams(...args); } diff --git a/x-pack/plugins/apm/typings/common.d.ts b/x-pack/plugins/apm/typings/common.d.ts index ea4bafad84619..b94eb6cd97b06 100644 --- a/x-pack/plugins/apm/typings/common.d.ts +++ b/x-pack/plugins/apm/typings/common.d.ts @@ -10,6 +10,7 @@ import '../../../typings/rison_node'; import '../../infra/types/eui'; // EUIBasicTable import '../../reporting/public/components/report_listing'; +import '../../reporting/server/lib/puid'; import './apm_rum_react'; // Allow unknown properties in an object From a6eb15ae9348a96c92a44a35c8a3e38709ebfa7d Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Mon, 23 Aug 2021 12:44:29 -0400 Subject: [PATCH 76/76] fix TableListView empty view trapping users with no action to create new item (#109345) (#109663) Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Nathan Reese --- .../table_list_view.test.tsx.snap | 46 +++++++++++++++++++ .../table_list_view/table_list_view.test.tsx | 13 ++++++ .../table_list_view/table_list_view.tsx | 1 + 3 files changed, 60 insertions(+) diff --git a/src/plugins/kibana_react/public/table_list_view/__snapshots__/table_list_view.test.tsx.snap b/src/plugins/kibana_react/public/table_list_view/__snapshots__/table_list_view.test.tsx.snap index f56dc56073542..a0c34cfdfee07 100644 --- a/src/plugins/kibana_react/public/table_list_view/__snapshots__/table_list_view.test.tsx.snap +++ b/src/plugins/kibana_react/public/table_list_view/__snapshots__/table_list_view.test.tsx.snap @@ -42,6 +42,52 @@ exports[`TableListView render default empty prompt 1`] = ` `; +exports[`TableListView render default empty prompt with create action when createItem supplied 1`] = ` + + + + + } + title={ +

+ +

+ } + /> +
+`; + exports[`TableListView render list view 1`] = ` { expect(component).toMatchSnapshot(); }); + // avoid trapping users in empty prompt that can not create new items + test('render default empty prompt with create action when createItem supplied', async () => { + const component = shallowWithIntl( {}} />); + + // Using setState to check the final render while sidestepping the debounced promise management + component.setState({ + hasInitialFetchReturned: true, + isFetchingItems: false, + }); + + expect(component).toMatchSnapshot(); + }); + test('render custom empty prompt', () => { const component = shallowWithIntl( } /> diff --git a/src/plugins/kibana_react/public/table_list_view/table_list_view.tsx b/src/plugins/kibana_react/public/table_list_view/table_list_view.tsx index d3cbda7c2ab2e..30d09f4bf8657 100644 --- a/src/plugins/kibana_react/public/table_list_view/table_list_view.tsx +++ b/src/plugins/kibana_react/public/table_list_view/table_list_view.tsx @@ -362,6 +362,7 @@ class TableListView extends React.Component } + actions={this.renderCreateButton()} /> ); }