From 7ef4c9c0464ddb4ec22a26540618dfe72af80d68 Mon Sep 17 00:00:00 2001 From: Simeon Widdis Date: Mon, 27 Nov 2023 16:51:02 -0800 Subject: [PATCH 01/36] Add full statics scan method Signed-off-by: Simeon Widdis --- .../integrations/repository/integration.ts | 60 +++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/server/adaptors/integrations/repository/integration.ts b/server/adaptors/integrations/repository/integration.ts index 83e5779aca..96b3648bf5 100644 --- a/server/adaptors/integrations/repository/integration.ts +++ b/server/adaptors/integrations/repository/integration.ts @@ -254,4 +254,64 @@ export class IntegrationReader { async getStatic(staticPath: string): Promise> { return await this.reader.readFileRaw(staticPath, 'static'); } + + async getAllStatics(version?: string): Promise> { + const configResult = await this.getConfig(version); + if (!configResult.ok) { + return configResult; + } + const config: IntegrationConfig = configResult.value; + + const allStatics: StaticAsset[] = [ + config.statics?.logo ?? null, + config.statics?.darkModeLogo ?? null, + ...(config.statics?.gallery ?? [null]), + ...(config.statics?.darkModeGallery ?? [null]), + ].filter((s) => s !== null) as StaticAsset[]; + + const staticsData = await Promise.all( + allStatics.map(async (s: StaticAsset) => { + return { + path: s.path, + result: await this.getStatic(s.path), + }; + }) + ); + + for (const data of staticsData) { + if (!data.result.ok) { + return data.result; + } + } + + return { + ok: true, + value: Object.fromEntries( + staticsData.map((data) => [ + data.path, + (data.result as { value: Buffer }).value.toString('base64'), + ]) + ), + }; + } + + /** + * Serialize the referenced integration as a flat JSON object. + * Useful for normalizing the format for sending to other locations. + * + * @param version The version of the integration to serialize. + * @returns A large object which includes all of the integration's data. + */ + async serialize(version?: string): Promise> { + const configResult = await this.getConfig(version); + if (!configResult.ok) { + return configResult; + } + const config: IntegrationConfig = configResult.value; + const result = { config }; + + const staticsData = await this.getAllStatics(version); + + return { ok: true, value: result }; + } } From d28abcd1516ce1433cef28a46cfdaac29ae564f7 Mon Sep 17 00:00:00 2001 From: Simeon Widdis Date: Wed, 29 Nov 2023 11:13:43 -0800 Subject: [PATCH 02/36] Add sample data to serialization method Signed-off-by: Simeon Widdis --- .../integrations/repository/integration.ts | 29 ++++++++++++------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/server/adaptors/integrations/repository/integration.ts b/server/adaptors/integrations/repository/integration.ts index 96b3648bf5..4d3e71f487 100644 --- a/server/adaptors/integrations/repository/integration.ts +++ b/server/adaptors/integrations/repository/integration.ts @@ -255,13 +255,9 @@ export class IntegrationReader { return await this.reader.readFileRaw(staticPath, 'static'); } - async getAllStatics(version?: string): Promise> { - const configResult = await this.getConfig(version); - if (!configResult.ok) { - return configResult; - } - const config: IntegrationConfig = configResult.value; - + private async getAllStatics( + config: IntegrationConfig + ): Promise> { const allStatics: StaticAsset[] = [ config.statics?.logo ?? null, config.statics?.darkModeLogo ?? null, @@ -308,10 +304,23 @@ export class IntegrationReader { return configResult; } const config: IntegrationConfig = configResult.value; - const result = { config }; - const staticsData = await this.getAllStatics(version); + const staticsResult = await this.getAllStatics(config); + if (!staticsResult.ok) { + return staticsResult; + } + const statics = staticsResult.value; + + const components = null; // TODO + + const assets = null; // TODO + + const sampleDataResult = await this.getSampleData(version); + if (!sampleDataResult.ok) { + return sampleDataResult; + } + const sampleData = JSON.stringify(sampleDataResult.value.sampleData); - return { ok: true, value: result }; + return { ok: true, value: { config, statics, components, assets, sampleData } }; } } From ae1bedec9705251fcbc8c25e5faa7430881363ed Mon Sep 17 00:00:00 2001 From: Simeon Widdis Date: Wed, 29 Nov 2023 11:42:38 -0800 Subject: [PATCH 03/36] Finish integration serialization Signed-off-by: Simeon Widdis --- .../__test__/local_repository.test.ts | 32 +++++++++++++++++++ .../integrations/repository/integration.ts | 29 ++++++++++++++--- 2 files changed, 57 insertions(+), 4 deletions(-) diff --git a/server/adaptors/integrations/__test__/local_repository.test.ts b/server/adaptors/integrations/__test__/local_repository.test.ts index 622547f116..2c6804409d 100644 --- a/server/adaptors/integrations/__test__/local_repository.test.ts +++ b/server/adaptors/integrations/__test__/local_repository.test.ts @@ -3,6 +3,10 @@ * SPDX-License-Identifier: Apache-2.0 */ +/** + * This file is used as integration tests for Integrations Repository functionality. + */ + import { TemplateManager } from '../repository/repository'; import { IntegrationReader } from '../repository/integration'; import path from 'path'; @@ -42,3 +46,31 @@ describe('The local repository', () => { ); }); }); + +describe('Local Nginx Integration', () => { + it('Should serialize without errors', async () => { + const repository: TemplateManager = new TemplateManager( + path.join(__dirname, '../__data__/repository') + ); + const integration = await repository.getIntegration('nginx'); + + expect(integration?.serialize()).resolves.toHaveProperty('ok', true); + }); + + it('Should serialize to include the config', async () => { + const repository: TemplateManager = new TemplateManager( + path.join(__dirname, '../__data__/repository') + ); + const integration = await repository.getIntegration('nginx'); + const config = await integration!.getConfig(); + const serialized = await integration!.serialize(); + + expect(serialized).toHaveProperty('value'); + expect(config).toHaveProperty('value'); + // Manual if-statement check wrapping expects to satisfy TS check + if (!('value' in serialized) || !('value' in config)) { + return; + } + expect(serialized.value.config).toEqual(config.value); + }); +}); diff --git a/server/adaptors/integrations/repository/integration.ts b/server/adaptors/integrations/repository/integration.ts index 4d3e71f487..357492bbd3 100644 --- a/server/adaptors/integrations/repository/integration.ts +++ b/server/adaptors/integrations/repository/integration.ts @@ -298,7 +298,17 @@ export class IntegrationReader { * @param version The version of the integration to serialize. * @returns A large object which includes all of the integration's data. */ - async serialize(version?: string): Promise> { + async serialize( + version?: string + ): Promise< + Result<{ + config: IntegrationConfig; + statics: unknown; + components: unknown; + assets: unknown; + sampleData: unknown; + }> + > { const configResult = await this.getConfig(version); if (!configResult.ok) { return configResult; @@ -311,9 +321,17 @@ export class IntegrationReader { } const statics = staticsResult.value; - const components = null; // TODO + const componentsResult = await this.getSchemas(version); + if (!componentsResult.ok) { + return componentsResult; + } + const components = componentsResult.value; - const assets = null; // TODO + const assetsResult = await this.getAssets(version); // TODO + if (!assetsResult.ok) { + return assetsResult; + } + const assets = assetsResult.value; const sampleDataResult = await this.getSampleData(version); if (!sampleDataResult.ok) { @@ -321,6 +339,9 @@ export class IntegrationReader { } const sampleData = JSON.stringify(sampleDataResult.value.sampleData); - return { ok: true, value: { config, statics, components, assets, sampleData } }; + return { + ok: true, + value: { config, statics, components, assets, sampleData }, + }; } } From f97347b3fe48663d7cdca8be8c428bf8151640f9 Mon Sep 17 00:00:00 2001 From: Simeon Widdis Date: Tue, 5 Dec 2023 14:27:25 -0800 Subject: [PATCH 04/36] Rename integration reader and add stub json adaptor Signed-off-by: Simeon Widdis --- .../integrations/__test__/builder.test.ts | 2 +- .../__test__/local_repository.test.ts | 2 +- .../integrations/__test__/manager.test.ts | 2 +- .../integrations/integrations_builder.ts | 2 +- .../repository/__test__/integration.test.ts | 2 +- .../__test__/json_data_adaptor.test.ts | 26 ++++++++ .../repository/__test__/repository.test.ts | 2 +- .../repository/catalog_data_adaptor.ts | 26 ++++++++ .../repository/fs_data_adaptor.ts | 28 +-------- .../{integration.ts => integration_reader.ts} | 0 .../repository/json_data_adaptor.ts | 62 +++++++++++++++++++ .../integrations/repository/repository.ts | 2 +- 12 files changed, 122 insertions(+), 34 deletions(-) create mode 100644 server/adaptors/integrations/repository/__test__/json_data_adaptor.test.ts rename server/adaptors/integrations/repository/{integration.ts => integration_reader.ts} (100%) create mode 100644 server/adaptors/integrations/repository/json_data_adaptor.ts diff --git a/server/adaptors/integrations/__test__/builder.test.ts b/server/adaptors/integrations/__test__/builder.test.ts index 33aff3497f..36f65cb7a1 100644 --- a/server/adaptors/integrations/__test__/builder.test.ts +++ b/server/adaptors/integrations/__test__/builder.test.ts @@ -5,7 +5,7 @@ import { SavedObjectsClientContract } from '../../../../../../src/core/server'; import { IntegrationInstanceBuilder } from '../integrations_builder'; -import { IntegrationReader } from '../repository/integration'; +import { IntegrationReader } from '../repository/integration_reader'; const mockSavedObjectsClient: SavedObjectsClientContract = ({ bulkCreate: jest.fn(), diff --git a/server/adaptors/integrations/__test__/local_repository.test.ts b/server/adaptors/integrations/__test__/local_repository.test.ts index 2c6804409d..dd748df8b9 100644 --- a/server/adaptors/integrations/__test__/local_repository.test.ts +++ b/server/adaptors/integrations/__test__/local_repository.test.ts @@ -8,7 +8,7 @@ */ import { TemplateManager } from '../repository/repository'; -import { IntegrationReader } from '../repository/integration'; +import { IntegrationReader } from '../repository/integration_reader'; import path from 'path'; import * as fs from 'fs/promises'; diff --git a/server/adaptors/integrations/__test__/manager.test.ts b/server/adaptors/integrations/__test__/manager.test.ts index 3ee62470c4..417f566ede 100644 --- a/server/adaptors/integrations/__test__/manager.test.ts +++ b/server/adaptors/integrations/__test__/manager.test.ts @@ -7,7 +7,7 @@ import { IntegrationsManager } from '../integrations_manager'; import { SavedObject, SavedObjectsClientContract } from '../../../../../../src/core/server/types'; import { TemplateManager } from '../repository/repository'; import { IntegrationInstanceBuilder } from '../integrations_builder'; -import { IntegrationReader } from '../repository/integration'; +import { IntegrationReader } from '../repository/integration_reader'; import { SavedObjectsFindResponse } from '../../../../../../src/core/server'; describe('IntegrationsKibanaBackend', () => { diff --git a/server/adaptors/integrations/integrations_builder.ts b/server/adaptors/integrations/integrations_builder.ts index 7a8026ceac..946b6f20fc 100644 --- a/server/adaptors/integrations/integrations_builder.ts +++ b/server/adaptors/integrations/integrations_builder.ts @@ -6,7 +6,7 @@ import { v4 as uuidv4 } from 'uuid'; import { uuidRx } from 'public/components/custom_panels/redux/panel_slice'; import { SavedObjectsClientContract } from '../../../../../src/core/server'; -import { IntegrationReader } from './repository/integration'; +import { IntegrationReader } from './repository/integration_reader'; import { SavedObjectsBulkCreateObject } from '../../../../../src/core/public'; interface BuilderOptions { diff --git a/server/adaptors/integrations/repository/__test__/integration.test.ts b/server/adaptors/integrations/repository/__test__/integration.test.ts index ec77acac1a..80c092b216 100644 --- a/server/adaptors/integrations/repository/__test__/integration.test.ts +++ b/server/adaptors/integrations/repository/__test__/integration.test.ts @@ -4,7 +4,7 @@ */ import * as fs from 'fs/promises'; -import { IntegrationReader } from '../integration'; +import { IntegrationReader } from '../integration_reader'; import { Dirent, Stats } from 'fs'; import * as path from 'path'; import { TEST_INTEGRATION_CONFIG } from '../../../../../test/constants'; diff --git a/server/adaptors/integrations/repository/__test__/json_data_adaptor.test.ts b/server/adaptors/integrations/repository/__test__/json_data_adaptor.test.ts new file mode 100644 index 0000000000..03073f62d7 --- /dev/null +++ b/server/adaptors/integrations/repository/__test__/json_data_adaptor.test.ts @@ -0,0 +1,26 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import * as fs from 'fs/promises'; +import { TemplateManager } from '../repository'; +import { IntegrationReader } from '../integration_reader'; +import path from 'path'; +import { JsonCatalogDataAdaptor } from '../json_data_adaptor'; + +describe('JSON Data Adaptor', () => { + it('Should be able to deserialize a serialized integration', async () => { + const repository: TemplateManager = new TemplateManager( + path.join(__dirname, '../../__data__/repository') + ); + const fsIntegration: IntegrationReader = (await repository.getIntegration('nginx'))!; + const fsConfig = await fsIntegration.getConfig(); + const serialized = await fsIntegration.serialize(); + + const adaptor: JsonCatalogDataAdaptor = new JsonCatalogDataAdaptor([serialized]); + const jsonIntegration = new IntegrationReader('nginx', adaptor); + + expect(jsonIntegration.getConfig()).resolves.toEqual(fsConfig); + }); +}); diff --git a/server/adaptors/integrations/repository/__test__/repository.test.ts b/server/adaptors/integrations/repository/__test__/repository.test.ts index ea5c853c66..5ecd6630be 100644 --- a/server/adaptors/integrations/repository/__test__/repository.test.ts +++ b/server/adaptors/integrations/repository/__test__/repository.test.ts @@ -5,7 +5,7 @@ import * as fs from 'fs/promises'; import { TemplateManager } from '../repository'; -import { IntegrationReader } from '../integration'; +import { IntegrationReader } from '../integration_reader'; import { Dirent, Stats } from 'fs'; import path from 'path'; diff --git a/server/adaptors/integrations/repository/catalog_data_adaptor.ts b/server/adaptors/integrations/repository/catalog_data_adaptor.ts index 6373fee4d4..21fe27033d 100644 --- a/server/adaptors/integrations/repository/catalog_data_adaptor.ts +++ b/server/adaptors/integrations/repository/catalog_data_adaptor.ts @@ -5,6 +5,32 @@ type IntegrationPart = 'assets' | 'data' | 'schemas' | 'static'; +/** + * Helper function to compare version numbers. + * Assumes that the version numbers are valid, produces undefined behavior otherwise. + * + * @param a Left-hand number + * @param b Right-hand number + * @returns -1 if a > b, 1 if a < b, 0 otherwise. + */ +function compareVersions(a: string, b: string): number { + const aParts = a.split('.').map(Number.parseInt); + const bParts = b.split('.').map(Number.parseInt); + + for (let i = 0; i < Math.max(aParts.length, bParts.length); i++) { + const aValue = i < aParts.length ? aParts[i] : 0; + const bValue = i < bParts.length ? bParts[i] : 0; + + if (aValue > bValue) { + return -1; // a > b + } else if (aValue < bValue) { + return 1; // a < b + } + } + + return 0; // a == b +} + interface CatalogDataAdaptor { /** * Reads a Json or NDJson file from the data source. diff --git a/server/adaptors/integrations/repository/fs_data_adaptor.ts b/server/adaptors/integrations/repository/fs_data_adaptor.ts index d39a0de889..3db4af8ce6 100644 --- a/server/adaptors/integrations/repository/fs_data_adaptor.ts +++ b/server/adaptors/integrations/repository/fs_data_adaptor.ts @@ -6,32 +6,6 @@ import * as fs from 'fs/promises'; import path from 'path'; -/** - * Helper function to compare version numbers. - * Assumes that the version numbers are valid, produces undefined behavior otherwise. - * - * @param a Left-hand number - * @param b Right-hand number - * @returns -1 if a > b, 1 if a < b, 0 otherwise. - */ -function compareVersions(a: string, b: string): number { - const aParts = a.split('.').map(Number.parseInt); - const bParts = b.split('.').map(Number.parseInt); - - for (let i = 0; i < Math.max(aParts.length, bParts.length); i++) { - const aValue = i < aParts.length ? aParts[i] : 0; - const bValue = i < bParts.length ? bParts[i] : 0; - - if (aValue > bValue) { - return -1; // a > b - } else if (aValue < bValue) { - return 1; // a < b - } - } - - return 0; // a == b -} - function tryParseNDJson(content: string): object[] | null { try { const objects = []; @@ -59,7 +33,7 @@ const safeIsDirectory = async (maybeDirectory: string): Promise => { /** * A CatalogDataAdaptor that reads from the local filesystem. - * Used to read Integration information when the user uploads their own catalog. + * Used to read default Integrations shipped in the in-product catalog at `__data__`. */ export class FileSystemCatalogDataAdaptor implements CatalogDataAdaptor { directory: string; diff --git a/server/adaptors/integrations/repository/integration.ts b/server/adaptors/integrations/repository/integration_reader.ts similarity index 100% rename from server/adaptors/integrations/repository/integration.ts rename to server/adaptors/integrations/repository/integration_reader.ts diff --git a/server/adaptors/integrations/repository/json_data_adaptor.ts b/server/adaptors/integrations/repository/json_data_adaptor.ts new file mode 100644 index 0000000000..97ee8e66a3 --- /dev/null +++ b/server/adaptors/integrations/repository/json_data_adaptor.ts @@ -0,0 +1,62 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import * as fs from 'fs/promises'; +import path from 'path'; + +/** + * A CatalogDataAdaptor that reads from a provided list of JSON objects. + * Used to read Integration information when the user uploads their own catalog. + */ +export class JsonCatalogDataAdaptor implements CatalogDataAdaptor { + integrationsList: object[]; + + /** + * Creates a new FileSystemCatalogDataAdaptor instance. + * + * @param directory The base directory from which to read files. This is not sanitized. + */ + constructor(integrationsList: object[]) { + this.integrationsList = integrationsList; + } + + async findIntegrationVersions(dirname?: string | undefined): Promise> { + // TODO + return { ok: false, error: new Error('Not Implemented') }; + } + + async readFile(filename: string, type?: IntegrationPart): Promise> { + // TODO + return { ok: false, error: new Error('Not Implemented') }; + } + + async readFileRaw(filename: string, type?: IntegrationPart): Promise> { + // TODO + return { ok: false, error: new Error('Not Implemented') }; + } + + async findIntegrations(dirname: string = '.'): Promise> { + // TODO + return { ok: false, error: new Error('Not Implemented') }; + } + + private async collectIntegrationsRecursive( + dirname: string, + integrations: string[] + ): Promise { + // TODO + return; + } + + async getDirectoryType(dirname?: string): Promise<'integration' | 'repository' | 'unknown'> { + // TODO + return 'unknown'; + } + + join(filename: string): JsonCatalogDataAdaptor { + // Since the integration list is flat, joining is a no-op. + return this; + } +} diff --git a/server/adaptors/integrations/repository/repository.ts b/server/adaptors/integrations/repository/repository.ts index ca56767b0d..b1870c4dce 100644 --- a/server/adaptors/integrations/repository/repository.ts +++ b/server/adaptors/integrations/repository/repository.ts @@ -4,7 +4,7 @@ */ import * as path from 'path'; -import { IntegrationReader } from './integration'; +import { IntegrationReader } from './integration_reader'; import { FileSystemCatalogDataAdaptor } from './fs_data_adaptor'; export class TemplateManager { From f39729f62fc9f486e1f8bf09b583288dcb8fb1c9 Mon Sep 17 00:00:00 2001 From: Simeon Widdis Date: Tue, 5 Dec 2023 14:48:41 -0800 Subject: [PATCH 05/36] Add JsonCatalogDataAdaptor directory type checking Signed-off-by: Simeon Widdis --- .../__test__/json_data_adaptor.test.ts | 43 +++++++++++++++++-- .../repository/catalog_data_adaptor.ts | 6 +-- .../repository/fs_data_adaptor.ts | 1 + .../repository/integration_reader.ts | 13 +----- .../repository/json_data_adaptor.ts | 30 +++++++++---- .../integrations/repository/repository.ts | 1 + server/adaptors/integrations/types.ts | 8 ++++ 7 files changed, 77 insertions(+), 25 deletions(-) diff --git a/server/adaptors/integrations/repository/__test__/json_data_adaptor.test.ts b/server/adaptors/integrations/repository/__test__/json_data_adaptor.test.ts index 03073f62d7..fcd86e20a8 100644 --- a/server/adaptors/integrations/repository/__test__/json_data_adaptor.test.ts +++ b/server/adaptors/integrations/repository/__test__/json_data_adaptor.test.ts @@ -3,14 +3,29 @@ * SPDX-License-Identifier: Apache-2.0 */ -import * as fs from 'fs/promises'; import { TemplateManager } from '../repository'; import { IntegrationReader } from '../integration_reader'; import path from 'path'; import { JsonCatalogDataAdaptor } from '../json_data_adaptor'; +import { TEST_INTEGRATION_CONFIG } from '../../../../../test/constants'; + +const TEST_CATALOG: SerializedIntegration[] = [ + { + config: { + ...TEST_INTEGRATION_CONFIG, + name: 'sample1', + }, + }, + { + config: { + ...TEST_INTEGRATION_CONFIG, + name: 'sample2', + }, + }, +]; describe('JSON Data Adaptor', () => { - it('Should be able to deserialize a serialized integration', async () => { + it.skip('Should be able to deserialize a serialized integration', async () => { const repository: TemplateManager = new TemplateManager( path.join(__dirname, '../../__data__/repository') ); @@ -18,9 +33,31 @@ describe('JSON Data Adaptor', () => { const fsConfig = await fsIntegration.getConfig(); const serialized = await fsIntegration.serialize(); - const adaptor: JsonCatalogDataAdaptor = new JsonCatalogDataAdaptor([serialized]); + expect(serialized.ok).toBe(true); + if (!serialized.ok) { + return; // Trick type system into allowing access to value + } + + const adaptor: JsonCatalogDataAdaptor = new JsonCatalogDataAdaptor([serialized.value]); const jsonIntegration = new IntegrationReader('nginx', adaptor); expect(jsonIntegration.getConfig()).resolves.toEqual(fsConfig); }); + + it('Should filter its list on join', async () => { + const adaptor = new JsonCatalogDataAdaptor(TEST_CATALOG); + const joined = await adaptor.join('sample1'); + expect(joined.integrationsList).toHaveLength(1); + }); + + it('Should correctly identify repository type', async () => { + const adaptor = new JsonCatalogDataAdaptor(TEST_CATALOG); + expect(adaptor.getDirectoryType()).resolves.toBe('repository'); + }); + + it('Should correctly identify integration type after filtering', async () => { + const adaptor = new JsonCatalogDataAdaptor(TEST_CATALOG); + const joined = await adaptor.join('sample1'); + expect(joined.getDirectoryType()).resolves.toBe('integration'); + }); }); diff --git a/server/adaptors/integrations/repository/catalog_data_adaptor.ts b/server/adaptors/integrations/repository/catalog_data_adaptor.ts index 21fe27033d..d464afc36a 100644 --- a/server/adaptors/integrations/repository/catalog_data_adaptor.ts +++ b/server/adaptors/integrations/repository/catalog_data_adaptor.ts @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -type IntegrationPart = 'assets' | 'data' | 'schemas' | 'static'; +export type IntegrationPart = 'assets' | 'data' | 'schemas' | 'static'; /** * Helper function to compare version numbers. @@ -13,7 +13,7 @@ type IntegrationPart = 'assets' | 'data' | 'schemas' | 'static'; * @param b Right-hand number * @returns -1 if a > b, 1 if a < b, 0 otherwise. */ -function compareVersions(a: string, b: string): number { +export function compareVersions(a: string, b: string): number { const aParts = a.split('.').map(Number.parseInt); const bParts = b.split('.').map(Number.parseInt); @@ -31,7 +31,7 @@ function compareVersions(a: string, b: string): number { return 0; // a == b } -interface CatalogDataAdaptor { +export interface CatalogDataAdaptor { /** * Reads a Json or NDJson file from the data source. * diff --git a/server/adaptors/integrations/repository/fs_data_adaptor.ts b/server/adaptors/integrations/repository/fs_data_adaptor.ts index 3db4af8ce6..9b750f3671 100644 --- a/server/adaptors/integrations/repository/fs_data_adaptor.ts +++ b/server/adaptors/integrations/repository/fs_data_adaptor.ts @@ -5,6 +5,7 @@ import * as fs from 'fs/promises'; import path from 'path'; +import { compareVersions, CatalogDataAdaptor, IntegrationPart } from './catalog_data_adaptor'; function tryParseNDJson(content: string): object[] | null { try { diff --git a/server/adaptors/integrations/repository/integration_reader.ts b/server/adaptors/integrations/repository/integration_reader.ts index 357492bbd3..b4151ae076 100644 --- a/server/adaptors/integrations/repository/integration_reader.ts +++ b/server/adaptors/integrations/repository/integration_reader.ts @@ -6,6 +6,7 @@ import path from 'path'; import { validateTemplate } from '../validators'; import { FileSystemCatalogDataAdaptor } from './fs_data_adaptor'; +import { CatalogDataAdaptor } from './catalog_data_adaptor'; /** * The Integration class represents the data for Integration Templates. @@ -298,17 +299,7 @@ export class IntegrationReader { * @param version The version of the integration to serialize. * @returns A large object which includes all of the integration's data. */ - async serialize( - version?: string - ): Promise< - Result<{ - config: IntegrationConfig; - statics: unknown; - components: unknown; - assets: unknown; - sampleData: unknown; - }> - > { + async serialize(version?: string): Promise> { const configResult = await this.getConfig(version); if (!configResult.ok) { return configResult; diff --git a/server/adaptors/integrations/repository/json_data_adaptor.ts b/server/adaptors/integrations/repository/json_data_adaptor.ts index 97ee8e66a3..92c681d188 100644 --- a/server/adaptors/integrations/repository/json_data_adaptor.ts +++ b/server/adaptors/integrations/repository/json_data_adaptor.ts @@ -3,22 +3,21 @@ * SPDX-License-Identifier: Apache-2.0 */ -import * as fs from 'fs/promises'; -import path from 'path'; +import { CatalogDataAdaptor, IntegrationPart } from './catalog_data_adaptor'; /** * A CatalogDataAdaptor that reads from a provided list of JSON objects. * Used to read Integration information when the user uploads their own catalog. */ export class JsonCatalogDataAdaptor implements CatalogDataAdaptor { - integrationsList: object[]; + integrationsList: SerializedIntegration[]; /** * Creates a new FileSystemCatalogDataAdaptor instance. * * @param directory The base directory from which to read files. This is not sanitized. */ - constructor(integrationsList: object[]) { + constructor(integrationsList: SerializedIntegration[]) { this.integrationsList = integrationsList; } @@ -51,12 +50,27 @@ export class JsonCatalogDataAdaptor implements CatalogDataAdaptor { } async getDirectoryType(dirname?: string): Promise<'integration' | 'repository' | 'unknown'> { - // TODO - return 'unknown'; + // First, filter list by dirname if available + const integrationsList = dirname + ? this.integrationsList.filter((i) => i.config.name === dirname) + : this.integrationsList; + if (integrationsList.length === 0) { + return 'unknown'; + } + // The list is an integration iff all of its names match + for (let i = 0; i < integrationsList.length - 1; i++) { + if (integrationsList[i].config.name !== integrationsList[i + 1].config.name) { + return 'repository'; + } + } + return 'integration'; } join(filename: string): JsonCatalogDataAdaptor { - // Since the integration list is flat, joining is a no-op. - return this; + // In other adaptors, joining moves from directories to integrations. + // Since for JSON adapting we use a flat structure, we just filter. + return new JsonCatalogDataAdaptor( + this.integrationsList.filter((i) => i.config.name === filename) + ); } } diff --git a/server/adaptors/integrations/repository/repository.ts b/server/adaptors/integrations/repository/repository.ts index b1870c4dce..0337372049 100644 --- a/server/adaptors/integrations/repository/repository.ts +++ b/server/adaptors/integrations/repository/repository.ts @@ -6,6 +6,7 @@ import * as path from 'path'; import { IntegrationReader } from './integration_reader'; import { FileSystemCatalogDataAdaptor } from './fs_data_adaptor'; +import { CatalogDataAdaptor } from './catalog_data_adaptor'; export class TemplateManager { reader: CatalogDataAdaptor; diff --git a/server/adaptors/integrations/types.ts b/server/adaptors/integrations/types.ts index fd5729afcc..0cb18a8e02 100644 --- a/server/adaptors/integrations/types.ts +++ b/server/adaptors/integrations/types.ts @@ -90,3 +90,11 @@ interface IntegrationInstanceQuery { added?: boolean; id?: string; } + +interface SerializedIntegration { + config: IntegrationConfig; + statics?: unknown; + components?: unknown; + assets?: unknown; + sampleData?: unknown; +} From c8899e99b3aca8f94766e3506342f2e2216eff1e Mon Sep 17 00:00:00 2001 From: Simeon Widdis Date: Thu, 4 Jan 2024 11:16:37 -0800 Subject: [PATCH 06/36] Add integration version filtering to json_data_adaptor Signed-off-by: Simeon Widdis --- .../__test__/json_data_adaptor.test.ts | 21 +++++++++++++++---- .../repository/json_data_adaptor.ts | 20 +++++++++++------- 2 files changed, 30 insertions(+), 11 deletions(-) diff --git a/server/adaptors/integrations/repository/__test__/json_data_adaptor.test.ts b/server/adaptors/integrations/repository/__test__/json_data_adaptor.test.ts index fcd86e20a8..532e82ac94 100644 --- a/server/adaptors/integrations/repository/__test__/json_data_adaptor.test.ts +++ b/server/adaptors/integrations/repository/__test__/json_data_adaptor.test.ts @@ -22,6 +22,13 @@ const TEST_CATALOG: SerializedIntegration[] = [ name: 'sample2', }, }, + { + config: { + ...TEST_INTEGRATION_CONFIG, + name: 'sample2', + version: '2.1.0', + }, + }, ]; describe('JSON Data Adaptor', () => { @@ -35,13 +42,13 @@ describe('JSON Data Adaptor', () => { expect(serialized.ok).toBe(true); if (!serialized.ok) { - return; // Trick type system into allowing access to value + return; // Trick typescript into allowing access to serialized.value } const adaptor: JsonCatalogDataAdaptor = new JsonCatalogDataAdaptor([serialized.value]); const jsonIntegration = new IntegrationReader('nginx', adaptor); - expect(jsonIntegration.getConfig()).resolves.toEqual(fsConfig); + await expect(jsonIntegration.getConfig()).resolves.toEqual(fsConfig); }); it('Should filter its list on join', async () => { @@ -52,12 +59,18 @@ describe('JSON Data Adaptor', () => { it('Should correctly identify repository type', async () => { const adaptor = new JsonCatalogDataAdaptor(TEST_CATALOG); - expect(adaptor.getDirectoryType()).resolves.toBe('repository'); + await expect(adaptor.getDirectoryType()).resolves.toBe('repository'); }); it('Should correctly identify integration type after filtering', async () => { const adaptor = new JsonCatalogDataAdaptor(TEST_CATALOG); const joined = await adaptor.join('sample1'); - expect(joined.getDirectoryType()).resolves.toBe('integration'); + await expect(joined.getDirectoryType()).resolves.toBe('integration'); + }); + + it('Should correctly retrieve integration versions', async () => { + const adaptor = new JsonCatalogDataAdaptor(TEST_CATALOG); + const versions = await adaptor.findIntegrationVersions('sample2'); + expect((versions as { value: string[] }).value).toHaveLength(2); }); }); diff --git a/server/adaptors/integrations/repository/json_data_adaptor.ts b/server/adaptors/integrations/repository/json_data_adaptor.ts index 92c681d188..47b8fc2363 100644 --- a/server/adaptors/integrations/repository/json_data_adaptor.ts +++ b/server/adaptors/integrations/repository/json_data_adaptor.ts @@ -22,28 +22,34 @@ export class JsonCatalogDataAdaptor implements CatalogDataAdaptor { } async findIntegrationVersions(dirname?: string | undefined): Promise> { - // TODO - return { ok: false, error: new Error('Not Implemented') }; + const versions: string[] = []; + for (const integration of this.integrationsList) { + if (integration.config.name !== dirname) { + continue; + } + versions.push(integration.config.version); + } + return { ok: true, value: versions }; } - async readFile(filename: string, type?: IntegrationPart): Promise> { + async readFile(_filename: string, _type?: IntegrationPart): Promise> { // TODO return { ok: false, error: new Error('Not Implemented') }; } - async readFileRaw(filename: string, type?: IntegrationPart): Promise> { + async readFileRaw(_filename: string, _type?: IntegrationPart): Promise> { // TODO return { ok: false, error: new Error('Not Implemented') }; } - async findIntegrations(dirname: string = '.'): Promise> { + async findIntegrations(_dirname: string = '.'): Promise> { // TODO return { ok: false, error: new Error('Not Implemented') }; } private async collectIntegrationsRecursive( - dirname: string, - integrations: string[] + _dirname: string, + _integrations: string[] ): Promise { // TODO return; From 8056e8765a3b82ee5671710979120cbe2291036c Mon Sep 17 00:00:00 2001 From: Simeon Widdis Date: Thu, 4 Jan 2024 16:38:56 -0800 Subject: [PATCH 07/36] Remove unviable serialization implementation The existing serialization implementation was not able to recover all data, as mapping information associating file names with the content was lost in appending the file content at the end of the JSON object. In order to work around this, a new serialization method needs to add this association. The most viable solution I see is to add encoded file data right next to the file names within the config, which will make it slightly harder to read if word wrap is enabled, but otherwise solves the issue. Going to clear this method out entirely for now and restore old functionality with TDD. Alternative solution: We can make a loose association by making heavy assumptions about array ordering and with complicated parsing logic, but I'm not sure it's worth it. Better to just go back to the drawing board and make a serialization method that's more flexible. Signed-off-by: Simeon Widdis --- .../repository/integration_reader.ts | 41 ++----------------- 1 file changed, 4 insertions(+), 37 deletions(-) diff --git a/server/adaptors/integrations/repository/integration_reader.ts b/server/adaptors/integrations/repository/integration_reader.ts index b4151ae076..370a7ef29b 100644 --- a/server/adaptors/integrations/repository/integration_reader.ts +++ b/server/adaptors/integrations/repository/integration_reader.ts @@ -44,7 +44,7 @@ export class IntegrationReader { if (!assets.ok || Object.keys(assets).length === 0) { return { ok: false, error: new Error('An integration must have at least one asset') }; } - } catch (err: any) { + } catch (err) { return { ok: false, error: err }; } @@ -223,7 +223,7 @@ export class IntegrationReader { version?: string ): Promise< Result<{ - mappings: { [key: string]: any }; + mappings: { [key: string]: unknown }; }> > { const configResult = await this.getConfig(version); @@ -299,40 +299,7 @@ export class IntegrationReader { * @param version The version of the integration to serialize. * @returns A large object which includes all of the integration's data. */ - async serialize(version?: string): Promise> { - const configResult = await this.getConfig(version); - if (!configResult.ok) { - return configResult; - } - const config: IntegrationConfig = configResult.value; - - const staticsResult = await this.getAllStatics(config); - if (!staticsResult.ok) { - return staticsResult; - } - const statics = staticsResult.value; - - const componentsResult = await this.getSchemas(version); - if (!componentsResult.ok) { - return componentsResult; - } - const components = componentsResult.value; - - const assetsResult = await this.getAssets(version); // TODO - if (!assetsResult.ok) { - return assetsResult; - } - const assets = assetsResult.value; - - const sampleDataResult = await this.getSampleData(version); - if (!sampleDataResult.ok) { - return sampleDataResult; - } - const sampleData = JSON.stringify(sampleDataResult.value.sampleData); - - return { - ok: true, - value: { config, statics, components, assets, sampleData }, - }; + async serialize(_version?: string): Promise> { + return { ok: false, error: new Error('Not implemented') }; } } From 99834640ecad2a2f21ecb190d2911fe5dd88c8c4 Mon Sep 17 00:00:00 2001 From: Simeon Widdis Date: Mon, 8 Jan 2024 11:23:45 -0800 Subject: [PATCH 08/36] Add new static serialization Signed-off-by: Simeon Widdis --- .../repository/integration_reader.ts | 115 +++++++++++++----- server/adaptors/integrations/types.ts | 86 +++++++++---- 2 files changed, 147 insertions(+), 54 deletions(-) diff --git a/server/adaptors/integrations/repository/integration_reader.ts b/server/adaptors/integrations/repository/integration_reader.ts index 370a7ef29b..d850627368 100644 --- a/server/adaptors/integrations/repository/integration_reader.ts +++ b/server/adaptors/integrations/repository/integration_reader.ts @@ -256,39 +256,82 @@ export class IntegrationReader { return await this.reader.readFileRaw(staticPath, 'static'); } - private async getAllStatics( - config: IntegrationConfig - ): Promise> { - const allStatics: StaticAsset[] = [ - config.statics?.logo ?? null, - config.statics?.darkModeLogo ?? null, - ...(config.statics?.gallery ?? [null]), - ...(config.statics?.darkModeGallery ?? [null]), - ].filter((s) => s !== null) as StaticAsset[]; + private async serializeStaticAsset(asset: StaticAsset): Promise> { + const data = await this.getStatic(asset.path); + if (!data.ok) { + return data; + } + + return { + ok: true, + value: { + ...asset, + data: data.value.toString('base64'), + }, + }; + } - const staticsData = await Promise.all( - allStatics.map(async (s: StaticAsset) => { - return { - path: s.path, - result: await this.getStatic(s.path), - }; - }) - ); + private async serializeStatics( + statics: IntegrationStatics + ): Promise> { + const serialized: SerializedIntegrationStatics = {}; - for (const data of staticsData) { - if (!data.result.ok) { - return data.result; + if (statics.logo) { + const serializeResult = await this.serializeStaticAsset(statics.logo); + if (!serializeResult.ok) { + return serializeResult; } + serialized.logo = serializeResult.value; + } + + if (statics.darkModeLogo) { + const serializeResult = await this.serializeStaticAsset(statics.darkModeLogo); + if (!serializeResult.ok) { + return serializeResult; + } + serialized.darkModeLogo = serializeResult.value; + } + + const foldResults = (results: Array>) => + results.reduce( + (result, currentValue) => { + if (!result.ok) { + return result; + } + if (!currentValue.ok) { + return currentValue; + } + result.value.push(currentValue.value); + return result; + }, + { ok: true, value: [] } as Result + ); + + if (statics.gallery) { + const results = await Promise.all( + statics.gallery.map((asset) => this.serializeStaticAsset(asset)) + ); + const foldedResult = foldResults(results); + if (!foldedResult.ok) { + return foldedResult; + } + serialized.gallery = foldedResult.value; + } + + if (statics.darkModeGallery) { + const results = await Promise.all( + statics.darkModeGallery.map((asset) => this.serializeStaticAsset(asset)) + ); + const foldedResult = foldResults(results); + if (!foldedResult.ok) { + return foldedResult; + } + serialized.darkModeGallery = foldedResult.value; } return { ok: true, - value: Object.fromEntries( - staticsData.map((data) => [ - data.path, - (data.result as { value: Buffer }).value.toString('base64'), - ]) - ), + value: serialized, }; } @@ -299,7 +342,23 @@ export class IntegrationReader { * @param version The version of the integration to serialize. * @returns A large object which includes all of the integration's data. */ - async serialize(_version?: string): Promise> { - return { ok: false, error: new Error('Not implemented') }; + async serialize(version?: string): Promise> { + const configResult = await this.getConfig(version); + if (!configResult.ok) { + return configResult; + } + const config: IntegrationConfig = configResult.value; + + // For every type of asset, serialize the asset within the config. + if (config.statics) { + const staticsResult = await this.serializeStatics(config.statics); + if (!staticsResult.ok) { + return staticsResult; + } + config.statics = staticsResult.value; + } + + // Type cast safety: all serializable properties must have the 'data' field. + return { ok: true, value: config as SerializedIntegration }; } } diff --git a/server/adaptors/integrations/types.ts b/server/adaptors/integrations/types.ts index 0cb18a8e02..1a1ac1892a 100644 --- a/server/adaptors/integrations/types.ts +++ b/server/adaptors/integrations/types.ts @@ -5,18 +5,6 @@ type Result = { ok: true; value: T } | { ok: false; error: E }; -interface IntegrationAssets { - savedObjects?: { - name: string; - version: string; - }; - queries?: Array<{ - name: string; - version: string; - language: string; - }>; -} - interface IntegrationConfig { name: string; version: string; @@ -27,12 +15,7 @@ interface IntegrationConfig { author?: string; description?: string; sourceUrl?: string; - statics?: { - logo?: StaticAsset; - gallery?: StaticAsset[]; - darkModeLogo?: StaticAsset; - darkModeGallery?: StaticAsset[]; - }; + statics?: IntegrationStatics; components: IntegrationComponent[]; assets: IntegrationAssets; sampleData?: { @@ -40,16 +23,75 @@ interface IntegrationConfig { }; } +// IntegrationConfig extended with local copies of all data +interface SerializedIntegration extends IntegrationConfig { + statics?: SerializedIntegrationStatics; + components: SerializedIntegrationComponent[]; + assets: SerializedIntegrationAssets; + sampleData: { + path: string; + data: string; + }; +} + +interface IntegrationStatics { + logo?: StaticAsset; + gallery?: StaticAsset[]; + darkModeLogo?: StaticAsset; + darkModeGallery?: StaticAsset[]; +} + +interface SerializedIntegrationStatics { + logo?: SerializedStaticAsset; + gallery?: SerializedStaticAsset[]; + darkModeLogo?: SerializedStaticAsset; + darkModeGallery?: SerializedStaticAsset[]; +} + +interface IntegrationAssets { + savedObjects?: { + name: string; + version: string; + }; + queries?: Array<{ + name: string; + version: string; + language: string; + }>; +} + +interface SerializedIntegrationAssets extends IntegrationAssets { + savedObjects?: { + name: string; + version: string; + data: string; + }; + queries?: Array<{ + name: string; + version: string; + language: string; + data: string; + }>; +} + interface StaticAsset { annotation?: string; path: string; } +interface SerializedStaticAsset extends StaticAsset { + data: string; +} + interface IntegrationComponent { name: string; version: string; } +interface SerializedIntegrationComponent extends IntegrationComponent { + data: string; +} + interface DisplayAsset { body: string; } @@ -90,11 +132,3 @@ interface IntegrationInstanceQuery { added?: boolean; id?: string; } - -interface SerializedIntegration { - config: IntegrationConfig; - statics?: unknown; - components?: unknown; - assets?: unknown; - sampleData?: unknown; -} From 77c80869f33045c03968f22c663cb2180dc8d695 Mon Sep 17 00:00:00 2001 From: Simeon Widdis Date: Mon, 8 Jan 2024 12:55:55 -0800 Subject: [PATCH 09/36] Add component and sample data serialization Signed-off-by: Simeon Widdis --- .../repository/integration_reader.ts | 80 ++++++++++++++----- server/adaptors/integrations/types.ts | 2 +- 2 files changed, 62 insertions(+), 20 deletions(-) diff --git a/server/adaptors/integrations/repository/integration_reader.ts b/server/adaptors/integrations/repository/integration_reader.ts index d850627368..8c9e037074 100644 --- a/server/adaptors/integrations/repository/integration_reader.ts +++ b/server/adaptors/integrations/repository/integration_reader.ts @@ -8,6 +8,27 @@ import { validateTemplate } from '../validators'; import { FileSystemCatalogDataAdaptor } from './fs_data_adaptor'; import { CatalogDataAdaptor } from './catalog_data_adaptor'; +/** + * Helper method: Convert an Array> to Result>. + * + * @param results The list of results to fold. + * @returns A single result object with values in an array, or an error result. + */ +const foldResults = (results: Array>) => + results.reduce( + (result, currentValue) => { + if (!result.ok) { + return result; + } + if (!currentValue.ok) { + return currentValue; + } + result.value.push(currentValue.value); + return result; + }, + { ok: true, value: [] } as Result + ); + /** * The Integration class represents the data for Integration Templates. * It is backed by the repository file system. @@ -292,21 +313,6 @@ export class IntegrationReader { serialized.darkModeLogo = serializeResult.value; } - const foldResults = (results: Array>) => - results.reduce( - (result, currentValue) => { - if (!result.ok) { - return result; - } - if (!currentValue.ok) { - return currentValue; - } - result.value.push(currentValue.value); - return result; - }, - { ok: true, value: [] } as Result - ); - if (statics.gallery) { const results = await Promise.all( statics.gallery.map((asset) => this.serializeStaticAsset(asset)) @@ -347,9 +353,35 @@ export class IntegrationReader { if (!configResult.ok) { return configResult; } - const config: IntegrationConfig = configResult.value; - // For every type of asset, serialize the asset within the config. + // Type cast safety: all serializable properties must have the 'data' field. + // The remainder of the method is populating all such fields. + const config = configResult.value as SerializedIntegration; + + const componentResults = await Promise.all( + config.components.map((component) => + this.reader.readFile(`${component.name}-${component.version}.mapping.json`, 'schemas') + ) + ); + const componentsResult = foldResults(componentResults); + if (!componentsResult.ok) { + return componentsResult; + } + config.components = config.components.map((component, idx) => { + return { + ...component, + data: JSON.stringify(componentsResult.value[idx]), + }; + }); + + if (config.assets.savedObjects) { + // TODO + } + + if (config.assets.queries) { + // TODO + } + if (config.statics) { const staticsResult = await this.serializeStatics(config.statics); if (!staticsResult.ok) { @@ -358,7 +390,17 @@ export class IntegrationReader { config.statics = staticsResult.value; } - // Type cast safety: all serializable properties must have the 'data' field. - return { ok: true, value: config as SerializedIntegration }; + if (config.sampleData) { + const dataResult = await this.getSampleData(version); + if (!dataResult.ok) { + return dataResult; + } + config.sampleData = { + ...config.sampleData, + data: JSON.stringify(dataResult.value.sampleData), + }; + } + + return { ok: true, value: config }; } } diff --git a/server/adaptors/integrations/types.ts b/server/adaptors/integrations/types.ts index 1a1ac1892a..95f7d92c7f 100644 --- a/server/adaptors/integrations/types.ts +++ b/server/adaptors/integrations/types.ts @@ -28,7 +28,7 @@ interface SerializedIntegration extends IntegrationConfig { statics?: SerializedIntegrationStatics; components: SerializedIntegrationComponent[]; assets: SerializedIntegrationAssets; - sampleData: { + sampleData?: { path: string; data: string; }; From 39bcf3ec07389c8d80990617ae32f8418ed49688 Mon Sep 17 00:00:00 2001 From: Simeon Widdis Date: Mon, 8 Jan 2024 13:02:49 -0800 Subject: [PATCH 10/36] Fix serialization test for new serialization approach Signed-off-by: Simeon Widdis --- .../integrations/__test__/local_repository.test.ts | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/server/adaptors/integrations/__test__/local_repository.test.ts b/server/adaptors/integrations/__test__/local_repository.test.ts index dd748df8b9..411b256f1e 100644 --- a/server/adaptors/integrations/__test__/local_repository.test.ts +++ b/server/adaptors/integrations/__test__/local_repository.test.ts @@ -25,7 +25,7 @@ describe('The local repository', () => { } // Otherwise, all directories must be integrations const integ = new IntegrationReader(integPath); - expect(integ.getConfig()).resolves.toHaveProperty('ok', true); + await expect(integ.getConfig()).resolves.toHaveProperty('ok', true); }) ); }); @@ -54,7 +54,7 @@ describe('Local Nginx Integration', () => { ); const integration = await repository.getIntegration('nginx'); - expect(integration?.serialize()).resolves.toHaveProperty('ok', true); + await expect(integration?.serialize()).resolves.toHaveProperty('ok', true); }); it('Should serialize to include the config', async () => { @@ -65,12 +65,8 @@ describe('Local Nginx Integration', () => { const config = await integration!.getConfig(); const serialized = await integration!.serialize(); - expect(serialized).toHaveProperty('value'); - expect(config).toHaveProperty('value'); - // Manual if-statement check wrapping expects to satisfy TS check - if (!('value' in serialized) || !('value' in config)) { - return; - } - expect(serialized.value.config).toEqual(config.value); + expect((serialized as { value: object }).value).toMatchObject( + (config as { value: object }).value + ); }); }); From 2f8502829bea241cd498c3e5426902ceb415d43a Mon Sep 17 00:00:00 2001 From: Simeon Widdis Date: Mon, 8 Jan 2024 13:16:59 -0800 Subject: [PATCH 11/36] Add new asset serialization Signed-off-by: Simeon Widdis --- .../__test__/local_repository.test.ts | 1 + .../repository/integration_reader.ts | 27 +++++++++++++++++-- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/server/adaptors/integrations/__test__/local_repository.test.ts b/server/adaptors/integrations/__test__/local_repository.test.ts index 411b256f1e..c7919dddc1 100644 --- a/server/adaptors/integrations/__test__/local_repository.test.ts +++ b/server/adaptors/integrations/__test__/local_repository.test.ts @@ -65,6 +65,7 @@ describe('Local Nginx Integration', () => { const config = await integration!.getConfig(); const serialized = await integration!.serialize(); + expect(serialized).toHaveProperty('ok', true); expect((serialized as { value: object }).value).toMatchObject( (config as { value: object }).value ); diff --git a/server/adaptors/integrations/repository/integration_reader.ts b/server/adaptors/integrations/repository/integration_reader.ts index 8c9e037074..17824a96d6 100644 --- a/server/adaptors/integrations/repository/integration_reader.ts +++ b/server/adaptors/integrations/repository/integration_reader.ts @@ -344,6 +344,7 @@ export class IntegrationReader { /** * Serialize the referenced integration as a flat JSON object. * Useful for normalizing the format for sending to other locations. + * This method implements the serialization scheme expected by `JsonCatalogDataAdaptor`. * * @param version The version of the integration to serialize. * @returns A large object which includes all of the integration's data. @@ -375,11 +376,33 @@ export class IntegrationReader { }); if (config.assets.savedObjects) { - // TODO + const soMetadata = config.assets.savedObjects; + const soResult = await this.reader.readFile( + `${soMetadata.name}-${soMetadata.version}.ndjson`, + 'assets' + ); + if (!soResult.ok) { + return soResult; + } + config.assets.savedObjects = { ...soMetadata, data: JSON.stringify(soResult.value) }; } if (config.assets.queries) { - // TODO + const queryResults = await Promise.all( + config.assets.queries.map((query) => + this.reader.readFileRaw(`${query.name}-${query.version}.${query.language}`, 'assets') + ) + ); + const queriesResult = foldResults(queryResults); + if (!queriesResult.ok) { + return queriesResult; + } + config.assets.queries = config.assets.queries.map((query, idx) => { + return { + ...query, + data: JSON.stringify(queriesResult.value[idx].toString('utf8')), + }; + }); } if (config.statics) { From 2d595054179da520887242ad92ae60134958df07 Mon Sep 17 00:00:00 2001 From: Simeon Widdis Date: Mon, 8 Jan 2024 14:35:57 -0800 Subject: [PATCH 12/36] Fix broken compareVersions comparison and version sorting When I noticed that adaptors had to handle version sorting, I started writing a test to verify the versions were being sorted. While verifying the test, I noticed a weird result where 2.0.0 was being sorted after both 1.0.0 and 2.1.0. After moving the comparison function over to integration_reader where it should be and writing tests, I saw the method was falsely saying 2.0.0 and 2.1.0 were equal. Debugging the comparison, I found that the version '1.2.3' was being parsed as [1, NaN, NaN]. Several more minutes of banging my head against my desk, and I realized that the suspect was this line: `a.split('.').map(Number.parseInt)`. Because parseInt takes two arguments (number and radix), map was giving it the part *and the index*. The error went away after fixing the method to use only the part. Signed-off-by: Simeon Widdis --- .../__test__/compare_versions.test.ts | 30 ++++++++++++++ .../__test__/json_data_adaptor.test.ts | 39 ++++++++++--------- .../repository/catalog_data_adaptor.ts | 28 +------------ .../repository/fs_data_adaptor.ts | 15 ++++--- .../repository/integration_reader.ts | 37 +++++++++++++++++- .../repository/json_data_adaptor.ts | 22 +++-------- 6 files changed, 101 insertions(+), 70 deletions(-) create mode 100644 server/adaptors/integrations/repository/__test__/compare_versions.test.ts diff --git a/server/adaptors/integrations/repository/__test__/compare_versions.test.ts b/server/adaptors/integrations/repository/__test__/compare_versions.test.ts new file mode 100644 index 0000000000..03efce1e82 --- /dev/null +++ b/server/adaptors/integrations/repository/__test__/compare_versions.test.ts @@ -0,0 +1,30 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { compareVersions } from '../integration_reader'; + +describe('compareVersions', () => { + it('should return 0 for equal versions', () => { + expect(compareVersions('1.2.3', '1.2.3')).toBe(0); + }); + + it('should return -1 for a < b', () => { + expect(compareVersions('1.2.3', '1.2.4')).toBe(-1); + expect(compareVersions('1.2.3', '1.3.0')).toBe(-1); + expect(compareVersions('1.2.3', '2.0.0')).toBe(-1); + }); + + it('should return 1 for a > b', () => { + expect(compareVersions('1.2.4', '1.2.3')).toBe(1); + expect(compareVersions('1.3.0', '1.2.3')).toBe(1); + expect(compareVersions('2.0.0', '1.2.3')).toBe(1); + }); + + it('should handle versions with different numbers of parts', () => { + expect(compareVersions('1.2.3', '1.2')).toBe(1); + expect(compareVersions('1.2', '1.2.3')).toBe(-1); + expect(compareVersions('1.2.3', '1.2.3.4')).toBe(-1); + }); +}); diff --git a/server/adaptors/integrations/repository/__test__/json_data_adaptor.test.ts b/server/adaptors/integrations/repository/__test__/json_data_adaptor.test.ts index 532e82ac94..0bfa0d1c17 100644 --- a/server/adaptors/integrations/repository/__test__/json_data_adaptor.test.ts +++ b/server/adaptors/integrations/repository/__test__/json_data_adaptor.test.ts @@ -9,25 +9,20 @@ import path from 'path'; import { JsonCatalogDataAdaptor } from '../json_data_adaptor'; import { TEST_INTEGRATION_CONFIG } from '../../../../../test/constants'; -const TEST_CATALOG: SerializedIntegration[] = [ +// Simplified catalog for integration searching -- Do not use for full deserialization tests. +const TEST_CATALOG_NO_SERIALIZATION: SerializedIntegration[] = [ { - config: { - ...TEST_INTEGRATION_CONFIG, - name: 'sample1', - }, + ...(TEST_INTEGRATION_CONFIG as SerializedIntegration), + name: 'sample1', }, { - config: { - ...TEST_INTEGRATION_CONFIG, - name: 'sample2', - }, + ...(TEST_INTEGRATION_CONFIG as SerializedIntegration), + name: 'sample2', }, { - config: { - ...TEST_INTEGRATION_CONFIG, - name: 'sample2', - version: '2.1.0', - }, + ...(TEST_INTEGRATION_CONFIG as SerializedIntegration), + name: 'sample2', + version: '2.1.0', }, ]; @@ -52,25 +47,33 @@ describe('JSON Data Adaptor', () => { }); it('Should filter its list on join', async () => { - const adaptor = new JsonCatalogDataAdaptor(TEST_CATALOG); + const adaptor = new JsonCatalogDataAdaptor(TEST_CATALOG_NO_SERIALIZATION); const joined = await adaptor.join('sample1'); expect(joined.integrationsList).toHaveLength(1); }); it('Should correctly identify repository type', async () => { - const adaptor = new JsonCatalogDataAdaptor(TEST_CATALOG); + const adaptor = new JsonCatalogDataAdaptor(TEST_CATALOG_NO_SERIALIZATION); await expect(adaptor.getDirectoryType()).resolves.toBe('repository'); }); it('Should correctly identify integration type after filtering', async () => { - const adaptor = new JsonCatalogDataAdaptor(TEST_CATALOG); + const adaptor = new JsonCatalogDataAdaptor(TEST_CATALOG_NO_SERIALIZATION); const joined = await adaptor.join('sample1'); await expect(joined.getDirectoryType()).resolves.toBe('integration'); }); it('Should correctly retrieve integration versions', async () => { - const adaptor = new JsonCatalogDataAdaptor(TEST_CATALOG); + const adaptor = new JsonCatalogDataAdaptor(TEST_CATALOG_NO_SERIALIZATION); const versions = await adaptor.findIntegrationVersions('sample2'); expect((versions as { value: string[] }).value).toHaveLength(2); }); + + it('Should correctly supply latest integration version for IntegrationReader', async () => { + const adaptor = new JsonCatalogDataAdaptor(TEST_CATALOG_NO_SERIALIZATION); + const reader = new IntegrationReader('sample2', adaptor.join('sample2')); + const version = await reader.getLatestVersion(); + console.log(await adaptor.join('sample2').findIntegrationVersions()); + expect(version).toBe('2.1.0'); + }); }); diff --git a/server/adaptors/integrations/repository/catalog_data_adaptor.ts b/server/adaptors/integrations/repository/catalog_data_adaptor.ts index d464afc36a..2fb0ea412f 100644 --- a/server/adaptors/integrations/repository/catalog_data_adaptor.ts +++ b/server/adaptors/integrations/repository/catalog_data_adaptor.ts @@ -5,32 +5,6 @@ export type IntegrationPart = 'assets' | 'data' | 'schemas' | 'static'; -/** - * Helper function to compare version numbers. - * Assumes that the version numbers are valid, produces undefined behavior otherwise. - * - * @param a Left-hand number - * @param b Right-hand number - * @returns -1 if a > b, 1 if a < b, 0 otherwise. - */ -export function compareVersions(a: string, b: string): number { - const aParts = a.split('.').map(Number.parseInt); - const bParts = b.split('.').map(Number.parseInt); - - for (let i = 0; i < Math.max(aParts.length, bParts.length); i++) { - const aValue = i < aParts.length ? aParts[i] : 0; - const bValue = i < bParts.length ? bParts[i] : 0; - - if (aValue > bValue) { - return -1; // a > b - } else if (aValue < bValue) { - return 1; // a < b - } - } - - return 0; // a == b -} - export interface CatalogDataAdaptor { /** * Reads a Json or NDJson file from the data source. @@ -59,7 +33,7 @@ export interface CatalogDataAdaptor { findIntegrations: (dirname?: string) => Promise>; /** - * Reads the contents of an integration version to find available versions. + * Reads the contents of an integration directory to find available versions. * * @param dirname The name of the directory to read. * @returns A Promise that resolves with an array of filenames within the directory. diff --git a/server/adaptors/integrations/repository/fs_data_adaptor.ts b/server/adaptors/integrations/repository/fs_data_adaptor.ts index 9b750f3671..4c5eb34067 100644 --- a/server/adaptors/integrations/repository/fs_data_adaptor.ts +++ b/server/adaptors/integrations/repository/fs_data_adaptor.ts @@ -5,7 +5,7 @@ import * as fs from 'fs/promises'; import path from 'path'; -import { compareVersions, CatalogDataAdaptor, IntegrationPart } from './catalog_data_adaptor'; +import { CatalogDataAdaptor, IntegrationPart } from './catalog_data_adaptor'; function tryParseNDJson(content: string): object[] | null { try { @@ -18,7 +18,7 @@ function tryParseNDJson(content: string): object[] | null { objects.push(JSON.parse(line)); } return objects; - } catch (err: any) { + } catch (err) { return null; } } @@ -54,14 +54,14 @@ export class FileSystemCatalogDataAdaptor implements CatalogDataAdaptor { content = await fs.readFile(path.join(this.directory, type ?? '.', filename), { encoding: 'utf-8', }); - } catch (err: any) { + } catch (err) { return { ok: false, error: err }; } // First try to parse as JSON, then NDJSON, then fail. try { const parsed = JSON.parse(content); return { ok: true, value: parsed }; - } catch (err: any) { + } catch (err) { const parsed = tryParseNDJson(content); if (parsed) { return { ok: true, value: parsed }; @@ -77,7 +77,7 @@ export class FileSystemCatalogDataAdaptor implements CatalogDataAdaptor { try { const buffer = await fs.readFile(path.join(this.directory, type ?? '.', filename)); return { ok: true, value: buffer }; - } catch (err: any) { + } catch (err) { return { ok: false, error: err }; } } @@ -87,7 +87,7 @@ export class FileSystemCatalogDataAdaptor implements CatalogDataAdaptor { const integrations: string[] = []; await this.collectIntegrationsRecursive(dirname, integrations); return { ok: true, value: integrations }; - } catch (err: any) { + } catch (err) { return { ok: false, error: err }; } } @@ -115,7 +115,7 @@ export class FileSystemCatalogDataAdaptor implements CatalogDataAdaptor { const integPath = path.join(this.directory, dirname); try { files = await fs.readdir(integPath); - } catch (err: any) { + } catch (err) { return { ok: false, error: err }; } const versions: string[] = []; @@ -131,7 +131,6 @@ export class FileSystemCatalogDataAdaptor implements CatalogDataAdaptor { } } - versions.sort((a, b) => compareVersions(a, b)); return { ok: true, value: versions }; } diff --git a/server/adaptors/integrations/repository/integration_reader.ts b/server/adaptors/integrations/repository/integration_reader.ts index 17824a96d6..21697c45d2 100644 --- a/server/adaptors/integrations/repository/integration_reader.ts +++ b/server/adaptors/integrations/repository/integration_reader.ts @@ -29,6 +29,36 @@ const foldResults = (results: Array>) => { ok: true, value: [] } as Result ); +/** + * Helper function to compare version numbers. + * Assumes that the version numbers are valid, produces undefined behavior otherwise. + * + * @param a Left-hand number + * @param b Right-hand number + * @returns -1 if a < b, 1 if a > b, 0 otherwise. + */ +export function compareVersions(a: string, b: string): number { + console.log(a.split('.'), b.split('.')); + const aParts = a.split('.').map((part) => Number.parseInt(part, 10)); + const bParts = b.split('.').map((part) => Number.parseInt(part, 10)); + + console.log(aParts, bParts); + + for (let i = 0; i < Math.max(aParts.length, bParts.length); i++) { + const aValue = i < aParts.length ? aParts[i] : 0; + const bValue = i < bParts.length ? bParts[i] : 0; + + if (aValue > bValue) { + return 1; + } + if (aValue < bValue) { + return -1; + } + } + + return 0; +} + /** * The Integration class represents the data for Integration Templates. * It is backed by the repository file system. @@ -85,7 +115,12 @@ export class IntegrationReader { console.error(versions.error); return null; } - return versions.value.length > 0 ? versions.value[0] : null; + if (versions.value.length === 0) { + return null; + } + // Sort descending + versions.value.sort((a, b) => -compareVersions(a, b)); + return versions.value[0]; } /** diff --git a/server/adaptors/integrations/repository/json_data_adaptor.ts b/server/adaptors/integrations/repository/json_data_adaptor.ts index 47b8fc2363..c99b812ccd 100644 --- a/server/adaptors/integrations/repository/json_data_adaptor.ts +++ b/server/adaptors/integrations/repository/json_data_adaptor.ts @@ -24,10 +24,10 @@ export class JsonCatalogDataAdaptor implements CatalogDataAdaptor { async findIntegrationVersions(dirname?: string | undefined): Promise> { const versions: string[] = []; for (const integration of this.integrationsList) { - if (integration.config.name !== dirname) { + if (dirname && integration.name !== dirname) { continue; } - versions.push(integration.config.version); + versions.push(integration.version); } return { ok: true, value: versions }; } @@ -47,25 +47,17 @@ export class JsonCatalogDataAdaptor implements CatalogDataAdaptor { return { ok: false, error: new Error('Not Implemented') }; } - private async collectIntegrationsRecursive( - _dirname: string, - _integrations: string[] - ): Promise { - // TODO - return; - } - async getDirectoryType(dirname?: string): Promise<'integration' | 'repository' | 'unknown'> { // First, filter list by dirname if available const integrationsList = dirname - ? this.integrationsList.filter((i) => i.config.name === dirname) + ? this.integrationsList.filter((i) => i.name === dirname) : this.integrationsList; if (integrationsList.length === 0) { return 'unknown'; } // The list is an integration iff all of its names match for (let i = 0; i < integrationsList.length - 1; i++) { - if (integrationsList[i].config.name !== integrationsList[i + 1].config.name) { + if (integrationsList[i].name !== integrationsList[i + 1].name) { return 'repository'; } } @@ -74,9 +66,7 @@ export class JsonCatalogDataAdaptor implements CatalogDataAdaptor { join(filename: string): JsonCatalogDataAdaptor { // In other adaptors, joining moves from directories to integrations. - // Since for JSON adapting we use a flat structure, we just filter. - return new JsonCatalogDataAdaptor( - this.integrationsList.filter((i) => i.config.name === filename) - ); + // Since for JSON catalogs we use a flat structure, we just filter. + return new JsonCatalogDataAdaptor(this.integrationsList.filter((i) => i.name === filename)); } } From ac52b80eee982631336c5639b63c0b7b47db7269 Mon Sep 17 00:00:00 2001 From: Simeon Widdis Date: Mon, 8 Jan 2024 15:49:39 -0800 Subject: [PATCH 13/36] Add ability to read config file from json integration Signed-off-by: Simeon Widdis --- .../__test__/json_data_adaptor.test.ts | 5 +- .../repository/integration_reader.ts | 3 -- .../repository/json_data_adaptor.ts | 51 +++++++++++++++++-- 3 files changed, 50 insertions(+), 9 deletions(-) diff --git a/server/adaptors/integrations/repository/__test__/json_data_adaptor.test.ts b/server/adaptors/integrations/repository/__test__/json_data_adaptor.test.ts index 0bfa0d1c17..f90a3da3f4 100644 --- a/server/adaptors/integrations/repository/__test__/json_data_adaptor.test.ts +++ b/server/adaptors/integrations/repository/__test__/json_data_adaptor.test.ts @@ -27,7 +27,7 @@ const TEST_CATALOG_NO_SERIALIZATION: SerializedIntegration[] = [ ]; describe('JSON Data Adaptor', () => { - it.skip('Should be able to deserialize a serialized integration', async () => { + it('Should be able to deserialize a serialized integration', async () => { const repository: TemplateManager = new TemplateManager( path.join(__dirname, '../../__data__/repository') ); @@ -43,7 +43,7 @@ describe('JSON Data Adaptor', () => { const adaptor: JsonCatalogDataAdaptor = new JsonCatalogDataAdaptor([serialized.value]); const jsonIntegration = new IntegrationReader('nginx', adaptor); - await expect(jsonIntegration.getConfig()).resolves.toEqual(fsConfig); + await expect(jsonIntegration.getConfig()).resolves.toMatchObject(fsConfig); }); it('Should filter its list on join', async () => { @@ -73,7 +73,6 @@ describe('JSON Data Adaptor', () => { const adaptor = new JsonCatalogDataAdaptor(TEST_CATALOG_NO_SERIALIZATION); const reader = new IntegrationReader('sample2', adaptor.join('sample2')); const version = await reader.getLatestVersion(); - console.log(await adaptor.join('sample2').findIntegrationVersions()); expect(version).toBe('2.1.0'); }); }); diff --git a/server/adaptors/integrations/repository/integration_reader.ts b/server/adaptors/integrations/repository/integration_reader.ts index 21697c45d2..3f9d967576 100644 --- a/server/adaptors/integrations/repository/integration_reader.ts +++ b/server/adaptors/integrations/repository/integration_reader.ts @@ -38,12 +38,9 @@ const foldResults = (results: Array>) => * @returns -1 if a < b, 1 if a > b, 0 otherwise. */ export function compareVersions(a: string, b: string): number { - console.log(a.split('.'), b.split('.')); const aParts = a.split('.').map((part) => Number.parseInt(part, 10)); const bParts = b.split('.').map((part) => Number.parseInt(part, 10)); - console.log(aParts, bParts); - for (let i = 0; i < Math.max(aParts.length, bParts.length); i++) { const aValue = i < aParts.length ? aParts[i] : 0; const bValue = i < bParts.length ? bParts[i] : 0; diff --git a/server/adaptors/integrations/repository/json_data_adaptor.ts b/server/adaptors/integrations/repository/json_data_adaptor.ts index c99b812ccd..ab5cb76248 100644 --- a/server/adaptors/integrations/repository/json_data_adaptor.ts +++ b/server/adaptors/integrations/repository/json_data_adaptor.ts @@ -5,6 +5,40 @@ import { CatalogDataAdaptor, IntegrationPart } from './catalog_data_adaptor'; +/** + * Remove all fields from SerializedIntegration not present in IntegrationConfig + * + * @param rawConfig The raw config to prune + * @returns A config with all data fields removed + */ +const pruneConfig = (rawConfig: SerializedIntegration): IntegrationConfig => { + // Hacky workaround: we currently only need to prune 'data' fields, so just remove every 'data'. + // Lots of risky conversion in this method, so scope it to here and rewrite if more granular + // pruning is needed. + const prunePart = (part: T): T => { + const result = {} as { [key: string]: unknown }; + for (const [key, value] of Object.entries(part as { [key: string]: unknown })) { + if (key === 'data') { + continue; + } else if (Array.isArray(value)) { + result[key] = value.map((item) => { + if (item instanceof Object && item !== null) { + return prunePart(item); + } + return item; + }); + } else if (value instanceof Object && value !== null) { + result[key] = prunePart(value as { [key: string]: unknown }); + } else { + result[key] = value; + } + } + return (result as unknown) as T; + }; + + return prunePart(rawConfig); +}; + /** * A CatalogDataAdaptor that reads from a provided list of JSON objects. * Used to read Integration information when the user uploads their own catalog. @@ -32,9 +66,20 @@ export class JsonCatalogDataAdaptor implements CatalogDataAdaptor { return { ok: true, value: versions }; } - async readFile(_filename: string, _type?: IntegrationPart): Promise> { - // TODO - return { ok: false, error: new Error('Not Implemented') }; + async readFile(filename: string, type?: IntegrationPart): Promise> { + switch (type) { + case undefined: + const name = filename.split('-')[0]; + const version = filename.match(/\d+(\.\d+)*/); + for (const integ of this.integrationsList) { + if (integ.name === name && integ.version === version?.[0]) { + return { ok: true, value: pruneConfig(integ) }; + } + } + return { ok: false, error: new Error('Config file not found: ' + filename) }; + default: + return { ok: false, error: new Error('Unsupported type: ' + type) }; + } } async readFileRaw(_filename: string, _type?: IntegrationPart): Promise> { From bd1651d776cb2d8453cf5917145908f88eeb9751 Mon Sep 17 00:00:00 2001 From: Simeon Widdis Date: Mon, 8 Jan 2024 16:15:29 -0800 Subject: [PATCH 14/36] Add rudimentary integration search to JSONAdaptor Signed-off-by: Simeon Widdis --- .../__test__/json_data_adaptor.test.ts | 9 +++++++++ .../repository/json_data_adaptor.ts | 17 +++++++++++++---- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/server/adaptors/integrations/repository/__test__/json_data_adaptor.test.ts b/server/adaptors/integrations/repository/__test__/json_data_adaptor.test.ts index f90a3da3f4..328b957562 100644 --- a/server/adaptors/integrations/repository/__test__/json_data_adaptor.test.ts +++ b/server/adaptors/integrations/repository/__test__/json_data_adaptor.test.ts @@ -75,4 +75,13 @@ describe('JSON Data Adaptor', () => { const version = await reader.getLatestVersion(); expect(version).toBe('2.1.0'); }); + + it('Should find integration names', async () => { + const adaptor = new JsonCatalogDataAdaptor(TEST_CATALOG_NO_SERIALIZATION); + const integResult = await adaptor.findIntegrations(); + const integs = (integResult as { value: string[] }).value; + integs.sort(); + + expect(integs).toEqual(['sample1', 'sample2']); + }); }); diff --git a/server/adaptors/integrations/repository/json_data_adaptor.ts b/server/adaptors/integrations/repository/json_data_adaptor.ts index ab5cb76248..4c67c43fe6 100644 --- a/server/adaptors/integrations/repository/json_data_adaptor.ts +++ b/server/adaptors/integrations/repository/json_data_adaptor.ts @@ -78,7 +78,7 @@ export class JsonCatalogDataAdaptor implements CatalogDataAdaptor { } return { ok: false, error: new Error('Config file not found: ' + filename) }; default: - return { ok: false, error: new Error('Unsupported type: ' + type) }; + return { ok: false, error: new Error('Unsupported type for json read: ' + type) }; } } @@ -87,9 +87,18 @@ export class JsonCatalogDataAdaptor implements CatalogDataAdaptor { return { ok: false, error: new Error('Not Implemented') }; } - async findIntegrations(_dirname: string = '.'): Promise> { - // TODO - return { ok: false, error: new Error('Not Implemented') }; + async findIntegrations(dirname: string = '.'): Promise> { + if (dirname !== '.') { + return { + ok: false, + error: new Error('Finding integrations for custom dirs not supported for JSONreader'), + }; + } + const result: Set = new Set([]); + for (const integration of this.integrationsList) { + result.add(integration.name); + } + return { ok: true, value: [...result] }; } async getDirectoryType(dirname?: string): Promise<'integration' | 'repository' | 'unknown'> { From a24dc0a9fff98ddc898214a1bd499ab9de8cdf0e Mon Sep 17 00:00:00 2001 From: Simeon Widdis Date: Tue, 9 Jan 2024 14:38:47 -0800 Subject: [PATCH 15/36] Create readRawConfig method to avoid data pruning Signed-off-by: Simeon Widdis --- .../__test__/json_data_adaptor.test.ts | 7 +- .../repository/catalog_data_adaptor.ts | 4 ++ .../repository/fs_data_adaptor.ts | 1 + .../repository/integration_reader.ts | 59 ++++++++++++++-- .../repository/json_data_adaptor.ts | 67 ++++++------------- server/adaptors/integrations/validators.ts | 9 ++- 6 files changed, 85 insertions(+), 62 deletions(-) diff --git a/server/adaptors/integrations/repository/__test__/json_data_adaptor.test.ts b/server/adaptors/integrations/repository/__test__/json_data_adaptor.test.ts index 328b957562..c154ce5794 100644 --- a/server/adaptors/integrations/repository/__test__/json_data_adaptor.test.ts +++ b/server/adaptors/integrations/repository/__test__/json_data_adaptor.test.ts @@ -36,11 +36,10 @@ describe('JSON Data Adaptor', () => { const serialized = await fsIntegration.serialize(); expect(serialized.ok).toBe(true); - if (!serialized.ok) { - return; // Trick typescript into allowing access to serialized.value - } - const adaptor: JsonCatalogDataAdaptor = new JsonCatalogDataAdaptor([serialized.value]); + const adaptor: JsonCatalogDataAdaptor = new JsonCatalogDataAdaptor([ + (serialized as { value: SerializedIntegration }).value, + ]); const jsonIntegration = new IntegrationReader('nginx', adaptor); await expect(jsonIntegration.getConfig()).resolves.toMatchObject(fsConfig); diff --git a/server/adaptors/integrations/repository/catalog_data_adaptor.ts b/server/adaptors/integrations/repository/catalog_data_adaptor.ts index 2fb0ea412f..a8c076231c 100644 --- a/server/adaptors/integrations/repository/catalog_data_adaptor.ts +++ b/server/adaptors/integrations/repository/catalog_data_adaptor.ts @@ -6,6 +6,10 @@ export type IntegrationPart = 'assets' | 'data' | 'schemas' | 'static'; export interface CatalogDataAdaptor { + // Indicates whether the config for this type of adaptor should be localized. + // If true, the catalog supports reading serialized integrations. + isConfigLocalized: boolean; + /** * Reads a Json or NDJson file from the data source. * diff --git a/server/adaptors/integrations/repository/fs_data_adaptor.ts b/server/adaptors/integrations/repository/fs_data_adaptor.ts index 4c5eb34067..59ac3e9cdb 100644 --- a/server/adaptors/integrations/repository/fs_data_adaptor.ts +++ b/server/adaptors/integrations/repository/fs_data_adaptor.ts @@ -37,6 +37,7 @@ const safeIsDirectory = async (maybeDirectory: string): Promise => { * Used to read default Integrations shipped in the in-product catalog at `__data__`. */ export class FileSystemCatalogDataAdaptor implements CatalogDataAdaptor { + isConfigLocalized = false; directory: string; /** diff --git a/server/adaptors/integrations/repository/integration_reader.ts b/server/adaptors/integrations/repository/integration_reader.ts index 3f9d967576..9d71eb7c7c 100644 --- a/server/adaptors/integrations/repository/integration_reader.ts +++ b/server/adaptors/integrations/repository/integration_reader.ts @@ -29,6 +29,40 @@ const foldResults = (results: Array>) => { ok: true, value: [] } as Result ); +/** + * Remove all fields from SerializedIntegration not present in IntegrationConfig. + * + * @param rawConfig The raw config to prune + * @returns A config with all data fields removed + */ +const pruneConfig = (rawConfig: IntegrationConfig | SerializedIntegration): IntegrationConfig => { + // Hacky workaround: we currently only need to prune 'data' fields, so just remove every 'data'. + // Lots of risky conversion in this method, so scope it to here and rewrite if more granular + // pruning is needed. + const prunePart = (part: T): T => { + const result = {} as { [key: string]: unknown }; + for (const [key, value] of Object.entries(part as { [key: string]: unknown })) { + if (key === 'data') { + continue; + } else if (Array.isArray(value)) { + result[key] = value.map((item) => { + if (item instanceof Object && item !== null) { + return prunePart(item); + } + return item; + }); + } else if (value instanceof Object && value !== null) { + result[key] = prunePart(value as { [key: string]: unknown }); + } else { + result[key] = value; + } + } + return (result as unknown) as T; + }; + + return prunePart(rawConfig); +}; + /** * Helper function to compare version numbers. * Assumes that the version numbers are valid, produces undefined behavior otherwise. @@ -120,13 +154,10 @@ export class IntegrationReader { return versions.value[0]; } - /** - * Get the configuration of the current integration. - * - * @param version The version of the config to retrieve. - * @returns The config if a valid config matching the version is present, otherwise null. - */ - async getConfig(version?: string): Promise> { + // Get config without pruning or validation. + private async getRawConfig( + version?: string + ): Promise> { if ((await this.reader.getDirectoryType()) !== 'integration') { return { ok: false, error: new Error(`${this.directory} is not a valid integration`) }; } @@ -149,6 +180,20 @@ export class IntegrationReader { return validateTemplate(config.value); } + /** + * Get the configuration of the current integration. + * + * @param version The version of the config to retrieve. + * @returns The config if a valid config matching the version is present, otherwise null. + */ + async getConfig(version?: string): Promise> { + const maybeConfig = await this.getRawConfig(version); + if (!maybeConfig.ok) { + return maybeConfig; + } + return validateTemplate(pruneConfig(maybeConfig.value)); + } + /** * Retrieve assets associated with the integration. * This method greedily retrieves all assets. diff --git a/server/adaptors/integrations/repository/json_data_adaptor.ts b/server/adaptors/integrations/repository/json_data_adaptor.ts index 4c67c43fe6..05c0b11104 100644 --- a/server/adaptors/integrations/repository/json_data_adaptor.ts +++ b/server/adaptors/integrations/repository/json_data_adaptor.ts @@ -5,45 +5,12 @@ import { CatalogDataAdaptor, IntegrationPart } from './catalog_data_adaptor'; -/** - * Remove all fields from SerializedIntegration not present in IntegrationConfig - * - * @param rawConfig The raw config to prune - * @returns A config with all data fields removed - */ -const pruneConfig = (rawConfig: SerializedIntegration): IntegrationConfig => { - // Hacky workaround: we currently only need to prune 'data' fields, so just remove every 'data'. - // Lots of risky conversion in this method, so scope it to here and rewrite if more granular - // pruning is needed. - const prunePart = (part: T): T => { - const result = {} as { [key: string]: unknown }; - for (const [key, value] of Object.entries(part as { [key: string]: unknown })) { - if (key === 'data') { - continue; - } else if (Array.isArray(value)) { - result[key] = value.map((item) => { - if (item instanceof Object && item !== null) { - return prunePart(item); - } - return item; - }); - } else if (value instanceof Object && value !== null) { - result[key] = prunePart(value as { [key: string]: unknown }); - } else { - result[key] = value; - } - } - return (result as unknown) as T; - }; - - return prunePart(rawConfig); -}; - /** * A CatalogDataAdaptor that reads from a provided list of JSON objects. * Used to read Integration information when the user uploads their own catalog. */ export class JsonCatalogDataAdaptor implements CatalogDataAdaptor { + isConfigLocalized = true; integrationsList: SerializedIntegration[]; /** @@ -67,24 +34,28 @@ export class JsonCatalogDataAdaptor implements CatalogDataAdaptor { } async readFile(filename: string, type?: IntegrationPart): Promise> { - switch (type) { - case undefined: - const name = filename.split('-')[0]; - const version = filename.match(/\d+(\.\d+)*/); - for (const integ of this.integrationsList) { - if (integ.name === name && integ.version === version?.[0]) { - return { ok: true, value: pruneConfig(integ) }; - } - } - return { ok: false, error: new Error('Config file not found: ' + filename) }; - default: - return { ok: false, error: new Error('Unsupported type for json read: ' + type) }; + if (type !== undefined) { + return { + ok: false, + error: new Error('JSON adaptor does not support subtypes (isConfigLocalized: true)'), + }; + } + + const name = filename.split('-')[0]; + const version = filename.match(/\d+(\.\d+)*/); + for (const integ of this.integrationsList) { + if (integ.name === name && integ.version === version?.[0]) { + return { ok: true, value: integ }; + } } + return { ok: false, error: new Error('Config file not found: ' + filename) }; } async readFileRaw(_filename: string, _type?: IntegrationPart): Promise> { - // TODO - return { ok: false, error: new Error('Not Implemented') }; + return { + ok: false, + error: new Error('JSON adaptor does not support raw files (isConfigLocalized: true)'), + }; } async findIntegrations(dirname: string = '.'): Promise> { diff --git a/server/adaptors/integrations/validators.ts b/server/adaptors/integrations/validators.ts index 5aa65cf815..bd0ec482fc 100644 --- a/server/adaptors/integrations/validators.ts +++ b/server/adaptors/integrations/validators.ts @@ -12,6 +12,7 @@ const staticAsset: JSONSchemaType = { properties: { path: { type: 'string' }, annotation: { type: 'string', nullable: true }, + data: { type: 'string', nullable: true }, }, required: ['path'], additionalProperties: false, @@ -48,6 +49,7 @@ const templateSchema: JSONSchemaType = { properties: { name: { type: 'string' }, version: { type: 'string' }, + data: { type: 'string', nullable: true }, }, required: ['name', 'version'], }, @@ -60,6 +62,7 @@ const templateSchema: JSONSchemaType = { properties: { name: { type: 'string' }, version: { type: 'string' }, + data: { type: 'string', nullable: true }, }, required: ['name', 'version'], nullable: true, @@ -73,6 +76,7 @@ const templateSchema: JSONSchemaType = { name: { type: 'string' }, version: { type: 'string' }, language: { type: 'string' }, + data: { type: 'string', nullable: true }, }, required: ['name', 'version', 'language'], }, @@ -84,9 +88,8 @@ const templateSchema: JSONSchemaType = { sampleData: { type: 'object', properties: { - path: { - type: 'string', - }, + path: { type: 'string' }, + data: { type: 'string', nullable: true }, }, required: ['path'], additionalProperties: false, From 425852cc1b724e654d8f448890cccfe232b32c84 Mon Sep 17 00:00:00 2001 From: Simeon Widdis Date: Tue, 9 Jan 2024 16:33:29 -0800 Subject: [PATCH 16/36] Add localized config parsing to getAssets Signed-off-by: Simeon Widdis --- .../repository/__test__/integration.test.ts | 32 ++++---- .../repository/fs_data_adaptor.ts | 17 +---- .../repository/integration_reader.ts | 75 ++++++++++++------- .../integrations/repository/parse_ndjson.ts | 20 +++++ 4 files changed, 85 insertions(+), 59 deletions(-) create mode 100644 server/adaptors/integrations/repository/parse_ndjson.ts diff --git a/server/adaptors/integrations/repository/__test__/integration.test.ts b/server/adaptors/integrations/repository/__test__/integration.test.ts index 80c092b216..454f9ac1ac 100644 --- a/server/adaptors/integrations/repository/__test__/integration.test.ts +++ b/server/adaptors/integrations/repository/__test__/integration.test.ts @@ -91,8 +91,8 @@ describe('Integration', () => { const readFileMock = jest.spyOn(fs, 'readFile').mockImplementation((..._args) => { // Can't find any information on how to mock an actual file not found error, // But at least according to the current implementation this should be equivalent. - const error: any = new Error('ENOENT: File not found'); - error.code = 'ENOENT'; + const error: Error = new Error('ENOENT: File not found'); + (error as { code?: string }).code = 'ENOENT'; return Promise.reject(error); }); @@ -105,15 +105,15 @@ describe('Integration', () => { describe('getAssets', () => { it('should return linked saved object assets when available', async () => { - integration.getConfig = jest - .fn() - .mockResolvedValue({ ok: true, value: TEST_INTEGRATION_CONFIG }); - jest.spyOn(fs, 'readFile').mockResolvedValue('{"name":"asset1"}\n{"name":"asset2"}'); + jest + .spyOn(fs, 'readFile') + .mockResolvedValueOnce(JSON.stringify(TEST_INTEGRATION_CONFIG)) + .mockResolvedValue('{"name":"asset1"}\n{"name":"asset2"}'); const result = await integration.getAssets(TEST_INTEGRATION_CONFIG.version); expect(result.ok).toBe(true); - expect((result as any).value.savedObjects).toStrictEqual([ + expect((result as { value: { savedObjects: unknown } }).value.savedObjects).toStrictEqual([ { name: 'asset1' }, { name: 'asset2' }, ]); @@ -122,7 +122,7 @@ describe('Integration', () => { it('should return an error if the provided version has no config', async () => { integration.getConfig = jest.fn().mockResolvedValue({ ok: false, error: new Error() }); - expect(integration.getAssets()).resolves.toHaveProperty('ok', false); + await expect(integration.getAssets()).resolves.toHaveProperty('ok', false); }); it('should return an error if the saved object assets are invalid', async () => { @@ -158,7 +158,7 @@ describe('Integration', () => { const result = await integration.getSchemas(); expect(result.ok).toBe(true); - expect((result as any).value).toStrictEqual({ + expect((result as { value: unknown }).value).toStrictEqual({ mappings: { component1: { mapping: 'mapping1' }, component2: { mapping: 'mapping2' }, @@ -201,17 +201,17 @@ describe('Integration', () => { const result = await integration.getStatic('logo.png'); expect(result.ok).toBe(true); - expect((result as any).value).toStrictEqual(Buffer.from('logo data', 'ascii')); + expect((result as { value: unknown }).value).toStrictEqual(Buffer.from('logo data', 'ascii')); expect(readFileMock).toBeCalledWith(path.join('sample', 'static', 'logo.png')); }); it('should return an error if the static file is not found', async () => { jest.spyOn(fs, 'readFile').mockImplementation((..._args) => { - const error: any = new Error('ENOENT: File not found'); - error.code = 'ENOENT'; + const error: Error = new Error('ENOENT: File not found'); + (error as { code?: string }).code = 'ENOENT'; return Promise.reject(error); }); - expect(integration.getStatic('/logo.png')).resolves.toHaveProperty('ok', false); + await expect(integration.getStatic('/logo.png')).resolves.toHaveProperty('ok', false); }); }); @@ -224,7 +224,9 @@ describe('Integration', () => { const result = await integration.getSampleData(); expect(result.ok).toBe(true); - expect((result as any).value.sampleData).toStrictEqual([{ sample: true }]); + expect((result as { value: { sampleData: unknown } }).value.sampleData).toStrictEqual([ + { sample: true }, + ]); expect(readFileMock).toBeCalledWith(path.join('sample', 'data', 'sample.json'), { encoding: 'utf-8', }); @@ -236,7 +238,7 @@ describe('Integration', () => { const result = await integration.getSampleData(); expect(result.ok).toBe(true); - expect((result as any).value.sampleData).toBeNull(); + expect((result as { value: { sampleData: unknown } }).value.sampleData).toBeNull(); }); it('should catch and fail gracefully on invalid sample data', async () => { diff --git a/server/adaptors/integrations/repository/fs_data_adaptor.ts b/server/adaptors/integrations/repository/fs_data_adaptor.ts index 59ac3e9cdb..99d81f20cf 100644 --- a/server/adaptors/integrations/repository/fs_data_adaptor.ts +++ b/server/adaptors/integrations/repository/fs_data_adaptor.ts @@ -6,22 +6,7 @@ import * as fs from 'fs/promises'; import path from 'path'; import { CatalogDataAdaptor, IntegrationPart } from './catalog_data_adaptor'; - -function tryParseNDJson(content: string): object[] | null { - try { - const objects = []; - for (const line of content.split('\n')) { - if (line.trim() === '') { - // Other OSD ndjson parsers skip whitespace lines - continue; - } - objects.push(JSON.parse(line)); - } - return objects; - } catch (err) { - return null; - } -} +import { tryParseNDJson } from './parse_ndjson'; // Check if a location is a directory without an exception if location not found const safeIsDirectory = async (maybeDirectory: string): Promise => { diff --git a/server/adaptors/integrations/repository/integration_reader.ts b/server/adaptors/integrations/repository/integration_reader.ts index 9d71eb7c7c..a31f5d0e85 100644 --- a/server/adaptors/integrations/repository/integration_reader.ts +++ b/server/adaptors/integrations/repository/integration_reader.ts @@ -7,6 +7,7 @@ import path from 'path'; import { validateTemplate } from '../validators'; import { FileSystemCatalogDataAdaptor } from './fs_data_adaptor'; import { CatalogDataAdaptor } from './catalog_data_adaptor'; +import { tryParseNDJson } from './parse_ndjson'; /** * Helper method: Convert an Array> to Result>. @@ -194,6 +195,37 @@ export class IntegrationReader { return validateTemplate(pruneConfig(maybeConfig.value)); } + private async getQueries( + queriesList: Array<{ name: string; version: string; language: string; data?: string }> + ): Promise>> { + const queries = await Promise.all( + queriesList.map(async (item) => { + if (item.data) { + return { + ok: true as const, + value: { + language: item.language, + query: item.data, + }, + }; + } + const queryPath = `${item.name}-${item.version}.${item.language}`; + const query = await this.reader.readFileRaw(queryPath, 'assets'); + if (!query.ok) { + return query; + } + return { + ok: true as const, + value: { + language: item.language, + query: query.value.toString('utf8'), + }, + }; + }) + ); + return foldResults(queries); + } + /** * Retrieve assets associated with the integration. * This method greedily retrieves all assets. @@ -214,7 +246,7 @@ export class IntegrationReader { }>; }> > { - const configResult = await this.getConfig(version); + const configResult = await this.getRawConfig(version); if (!configResult.ok) { return configResult; } @@ -225,37 +257,24 @@ export class IntegrationReader { queries?: Array<{ query: string; language: string }>; } = {}; if (config.assets.savedObjects) { - const sobjPath = `${config.assets.savedObjects.name}-${config.assets.savedObjects.version}.ndjson`; - const assets = await this.reader.readFile(sobjPath, 'assets'); - if (!assets.ok) { - return assets; + if (this.reader.isConfigLocalized) { + const parsedSo = tryParseNDJson((config.assets.savedObjects as { data: string }).data); + resultValue.savedObjects = Array.isArray(parsedSo) ? parsedSo : undefined; + } else { + const sobjPath = `${config.assets.savedObjects.name}-${config.assets.savedObjects.version}.ndjson`; + const assets = await this.reader.readFile(sobjPath, 'assets'); + if (!assets.ok) { + return assets; + } + resultValue.savedObjects = assets.value as object[]; } - resultValue.savedObjects = assets.value as object[]; } if (config.assets.queries) { - resultValue.queries = []; - const queries = await Promise.all( - config.assets.queries.map(async (item) => { - const queryPath = `${item.name}-${item.version}.${item.language}`; - const query = await this.reader.readFileRaw(queryPath, 'assets'); - if (!query.ok) { - return query; - } - return { - ok: true as const, - value: { - language: item.language, - query: query.value.toString('utf8'), - }, - }; - }) - ); - for (const query of queries) { - if (!query.ok) { - return query; - } - resultValue.queries.push(query.value); + const queries = await this.getQueries(config.assets.queries); + if (!queries.ok) { + return queries; } + resultValue.queries = queries.value; } return { ok: true, value: resultValue }; } diff --git a/server/adaptors/integrations/repository/parse_ndjson.ts b/server/adaptors/integrations/repository/parse_ndjson.ts new file mode 100644 index 0000000000..522b22f897 --- /dev/null +++ b/server/adaptors/integrations/repository/parse_ndjson.ts @@ -0,0 +1,20 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export function tryParseNDJson(content: string): object[] | null { + try { + const objects = []; + for (const line of content.split('\n')) { + if (line.trim() === '') { + // Other OSD ndjson parsers skip whitespace lines + continue; + } + objects.push(JSON.parse(line)); + } + return objects; + } catch (err) { + return null; + } +} From 4c31ff6a92c8b019479846c3e088ad908974f684 Mon Sep 17 00:00:00 2001 From: Simeon Widdis Date: Tue, 9 Jan 2024 16:41:50 -0800 Subject: [PATCH 17/36] Convert getSampleData to use localized config Signed-off-by: Simeon Widdis --- .../repository/__test__/integration.test.ts | 20 +++++++++++++++---- .../repository/integration_reader.ts | 19 ++++++++++++++++-- 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/server/adaptors/integrations/repository/__test__/integration.test.ts b/server/adaptors/integrations/repository/__test__/integration.test.ts index 454f9ac1ac..921b18c402 100644 --- a/server/adaptors/integrations/repository/__test__/integration.test.ts +++ b/server/adaptors/integrations/repository/__test__/integration.test.ts @@ -217,9 +217,17 @@ describe('Integration', () => { describe('getSampleData', () => { it('should return sample data', async () => { - const sampleConfig = { sampleData: { path: 'sample.json' } }; - integration.getConfig = jest.fn().mockResolvedValue({ ok: true, value: sampleConfig }); - const readFileMock = jest.spyOn(fs, 'readFile').mockResolvedValue('[{"sample": true}]'); + const readFileMock = jest + .spyOn(fs, 'readFile') + .mockResolvedValueOnce( + JSON.stringify({ + ...TEST_INTEGRATION_CONFIG, + sampleData: { + path: 'sample.json', + }, + }) + ) + .mockResolvedValue('[{"sample": true}]'); const result = await integration.getSampleData(); @@ -233,7 +241,11 @@ describe('Integration', () => { }); it("should return null if there's no sample data", async () => { - integration.getConfig = jest.fn().mockResolvedValue({ ok: true, value: {} }); + jest.spyOn(fs, 'readFile').mockResolvedValueOnce( + JSON.stringify({ + ...TEST_INTEGRATION_CONFIG, + }) + ); const result = await integration.getSampleData(); diff --git a/server/adaptors/integrations/repository/integration_reader.ts b/server/adaptors/integrations/repository/integration_reader.ts index a31f5d0e85..bb73699923 100644 --- a/server/adaptors/integrations/repository/integration_reader.ts +++ b/server/adaptors/integrations/repository/integration_reader.ts @@ -294,7 +294,7 @@ export class IntegrationReader { sampleData: object[] | null; }> > { - const configResult = await this.getConfig(version); + const configResult = await this.getRawConfig(version); if (!configResult.ok) { return configResult; } @@ -302,7 +302,22 @@ export class IntegrationReader { const resultValue: { sampleData: object[] | null } = { sampleData: null }; if (config.sampleData) { - const jsonContent = await this.reader.readFile(config.sampleData.path, 'data'); + let jsonContent: Result; + + if (this.reader.isConfigLocalized) { + const parsedData = tryParseNDJson( + (config.sampleData as { path: string; data: string }).data + ); + if (parsedData === null) { + return { + ok: false, + error: new Error('Unable to parse included data in localized config'), + }; + } + jsonContent = { ok: true, value: parsedData }; + } else { + jsonContent = await this.reader.readFile(config.sampleData.path, 'data'); + } if (!jsonContent.ok) { return jsonContent; } From 6a8d64319cdb9abed705950dac3a232bb9ae3b51 Mon Sep 17 00:00:00 2001 From: Simeon Widdis Date: Wed, 10 Jan 2024 11:19:28 -0800 Subject: [PATCH 18/36] Move localized reader logic to helper method Signed-off-by: Simeon Widdis --- ...ion.test.ts => integration_reader.test.ts} | 5 +- .../repository/integration_reader.ts | 115 ++++++++++++------ server/adaptors/integrations/types.ts | 4 +- 3 files changed, 80 insertions(+), 44 deletions(-) rename server/adaptors/integrations/repository/__test__/{integration.test.ts => integration_reader.test.ts} (98%) diff --git a/server/adaptors/integrations/repository/__test__/integration.test.ts b/server/adaptors/integrations/repository/__test__/integration_reader.test.ts similarity index 98% rename from server/adaptors/integrations/repository/__test__/integration.test.ts rename to server/adaptors/integrations/repository/__test__/integration_reader.test.ts index 921b18c402..e42bb7f718 100644 --- a/server/adaptors/integrations/repository/__test__/integration.test.ts +++ b/server/adaptors/integrations/repository/__test__/integration_reader.test.ts @@ -231,10 +231,7 @@ describe('Integration', () => { const result = await integration.getSampleData(); - expect(result.ok).toBe(true); - expect((result as { value: { sampleData: unknown } }).value.sampleData).toStrictEqual([ - { sample: true }, - ]); + expect(result.value).toStrictEqual({ sampleData: [{ sample: true }] }); expect(readFileMock).toBeCalledWith(path.join('sample', 'data', 'sample.json'), { encoding: 'utf-8', }); diff --git a/server/adaptors/integrations/repository/integration_reader.ts b/server/adaptors/integrations/repository/integration_reader.ts index bb73699923..f92345072e 100644 --- a/server/adaptors/integrations/repository/integration_reader.ts +++ b/server/adaptors/integrations/repository/integration_reader.ts @@ -6,8 +6,7 @@ import path from 'path'; import { validateTemplate } from '../validators'; import { FileSystemCatalogDataAdaptor } from './fs_data_adaptor'; -import { CatalogDataAdaptor } from './catalog_data_adaptor'; -import { tryParseNDJson } from './parse_ndjson'; +import { CatalogDataAdaptor, IntegrationPart } from './catalog_data_adaptor'; /** * Helper method: Convert an Array> to Result>. @@ -107,6 +106,59 @@ export class IntegrationReader { this.reader = reader ?? new FileSystemCatalogDataAdaptor(directory); } + /** + * Retrieve data from correct source regardless of if reader is config-localized or not. + * + * TODO refactor to assemble filename from `type` instead of requiring caller to format it. + * + * @param item An item which may have data in it. + * @param fileParams Information about the file to read if the config is not localized. + * @param format How to package the returned data. + * If 'json', return `object | object[]`. If 'binary', return `Buffer`. + * @returns A result with the data, with a format based on the format field. + */ + private async fetchDataOrReadFile( + item: { data?: string }, + fileParams: { filename: string; type?: IntegrationPart }, + format: 'json' + ): Promise>; + private async fetchDataOrReadFile( + item: { data?: string }, + fileParams: { filename: string; type?: IntegrationPart }, + format: 'binary' + ): Promise>; + private async fetchDataOrReadFile( + item: { data?: string }, + fileParams: { filename: string; type?: IntegrationPart }, + format: 'json' | 'binary' + ): Promise> { + if (this.reader.isConfigLocalized) { + if (!item.data) { + return { + ok: false, + error: new Error( + 'The config for the provided reader is localized, but no data field is present.' + ), + }; + } + try { + if (format === 'json') { + return { ok: true, value: JSON.parse(item.data) }; + } else { + return { ok: true, value: Buffer.from(item.data, 'base64') }; + } + } catch (error) { + return { ok: false, error }; + } + } + + if (format === 'json') { + return this.reader.readFile(fileParams.filename, fileParams.type); + } else { + return this.reader.readFileRaw(fileParams.filename, fileParams.type); + } + } + /** * Like getConfig(), but thoroughly checks all nested integration dependencies for validity. * @@ -174,6 +226,7 @@ export class IntegrationReader { const configFile = `${this.name}-${maybeVersion}.json`; + // Even config-localized readers must support config-read. const config = await this.reader.readFile(configFile); if (!config.ok) { return config; @@ -200,17 +253,11 @@ export class IntegrationReader { ): Promise>> { const queries = await Promise.all( queriesList.map(async (item) => { - if (item.data) { - return { - ok: true as const, - value: { - language: item.language, - query: item.data, - }, - }; - } - const queryPath = `${item.name}-${item.version}.${item.language}`; - const query = await this.reader.readFileRaw(queryPath, 'assets'); + const query = await this.fetchDataOrReadFile( + item, + { filename: `${item.name}-${item.version}.${item.language}`, type: 'assets' }, + 'binary' + ); if (!query.ok) { return query; } @@ -257,17 +304,18 @@ export class IntegrationReader { queries?: Array<{ query: string; language: string }>; } = {}; if (config.assets.savedObjects) { - if (this.reader.isConfigLocalized) { - const parsedSo = tryParseNDJson((config.assets.savedObjects as { data: string }).data); - resultValue.savedObjects = Array.isArray(parsedSo) ? parsedSo : undefined; - } else { - const sobjPath = `${config.assets.savedObjects.name}-${config.assets.savedObjects.version}.ndjson`; - const assets = await this.reader.readFile(sobjPath, 'assets'); - if (!assets.ok) { - return assets; - } - resultValue.savedObjects = assets.value as object[]; + const assets = await this.fetchDataOrReadFile( + config.assets.savedObjects as { data?: string }, + { + filename: `${config.assets.savedObjects.name}-${config.assets.savedObjects.version}.ndjson`, + type: 'assets', + }, + 'json' + ); + if (!assets.ok) { + return assets; } + resultValue.savedObjects = assets.value as object[]; } if (config.assets.queries) { const queries = await this.getQueries(config.assets.queries); @@ -302,22 +350,11 @@ export class IntegrationReader { const resultValue: { sampleData: object[] | null } = { sampleData: null }; if (config.sampleData) { - let jsonContent: Result; - - if (this.reader.isConfigLocalized) { - const parsedData = tryParseNDJson( - (config.sampleData as { path: string; data: string }).data - ); - if (parsedData === null) { - return { - ok: false, - error: new Error('Unable to parse included data in localized config'), - }; - } - jsonContent = { ok: true, value: parsedData }; - } else { - jsonContent = await this.reader.readFile(config.sampleData.path, 'data'); - } + const jsonContent: Result = await this.fetchDataOrReadFile( + config.sampleData as { data?: string }, + { filename: config.sampleData.path, type: 'data' }, + 'json' + ); if (!jsonContent.ok) { return jsonContent; } diff --git a/server/adaptors/integrations/types.ts b/server/adaptors/integrations/types.ts index 95f7d92c7f..21c1a3db46 100644 --- a/server/adaptors/integrations/types.ts +++ b/server/adaptors/integrations/types.ts @@ -3,7 +3,9 @@ * SPDX-License-Identifier: Apache-2.0 */ -type Result = { ok: true; value: T } | { ok: false; error: E }; +type Result = + | { ok: true; value: T; error?: unknown } + | { ok: false; error: E; value?: unknown }; interface IntegrationConfig { name: string; From a2339705ef00ca5327b9c5005d466d5b07e2591c Mon Sep 17 00:00:00 2001 From: Simeon Widdis Date: Wed, 10 Jan 2024 11:28:20 -0800 Subject: [PATCH 19/36] Convert getSchemas to use new data retrieval Signed-off-by: Simeon Widdis --- .../__test__/integration_reader.test.ts | 21 +++++-------------- .../repository/integration_reader.ts | 6 +++++- 2 files changed, 10 insertions(+), 17 deletions(-) diff --git a/server/adaptors/integrations/repository/__test__/integration_reader.test.ts b/server/adaptors/integrations/repository/__test__/integration_reader.test.ts index e42bb7f718..05c8f5ab9d 100644 --- a/server/adaptors/integrations/repository/__test__/integration_reader.test.ts +++ b/server/adaptors/integrations/repository/__test__/integration_reader.test.ts @@ -140,39 +140,28 @@ describe('Integration', () => { describe('getSchemas', () => { it('should retrieve mappings and schemas for all components in the config', async () => { const sampleConfig = { + ...TEST_INTEGRATION_CONFIG, components: [ - { name: 'component1', version: '1.0.0' }, + { name: 'logs', version: '1.0.0' }, { name: 'component2', version: '2.0.0' }, ], }; - integration.getConfig = jest.fn().mockResolvedValue({ ok: true, value: sampleConfig }); - - const mappingFile1 = 'component1-1.0.0.mapping.json'; - const mappingFile2 = 'component2-2.0.0.mapping.json'; jest .spyOn(fs, 'readFile') + .mockResolvedValueOnce(JSON.stringify(sampleConfig)) .mockResolvedValueOnce(JSON.stringify({ mapping: 'mapping1' })) .mockResolvedValueOnce(JSON.stringify({ mapping: 'mapping2' })); const result = await integration.getSchemas(); - expect(result.ok).toBe(true); + expect(result).toMatchObject({ ok: true }); expect((result as { value: unknown }).value).toStrictEqual({ mappings: { - component1: { mapping: 'mapping1' }, + logs: { mapping: 'mapping1' }, component2: { mapping: 'mapping2' }, }, }); - - expect(fs.readFile).toHaveBeenCalledWith( - path.join(integration.directory, 'schemas', mappingFile1), - { encoding: 'utf-8' } - ); - expect(fs.readFile).toHaveBeenCalledWith( - path.join(integration.directory, 'schemas', mappingFile2), - { encoding: 'utf-8' } - ); }); it('should reject with an error if the config is invalid', async () => { diff --git a/server/adaptors/integrations/repository/integration_reader.ts b/server/adaptors/integrations/repository/integration_reader.ts index f92345072e..b9f0a094d3 100644 --- a/server/adaptors/integrations/repository/integration_reader.ts +++ b/server/adaptors/integrations/repository/integration_reader.ts @@ -406,7 +406,11 @@ export class IntegrationReader { }; for (const component of config.components) { const schemaFile = `${component.name}-${component.version}.mapping.json`; - const schema = await this.reader.readFile(schemaFile, 'schemas'); + const schema = await this.fetchDataOrReadFile( + component as { data?: string }, + { filename: schemaFile, type: 'schemas' }, + 'json' + ); if (!schema.ok) { return schema; } From 0904ceab37cba3b18e1e7036f560f918a53fe849 Mon Sep 17 00:00:00 2001 From: Simeon Widdis Date: Wed, 10 Jan 2024 13:01:43 -0800 Subject: [PATCH 20/36] Add localized config handling for getStatic Signed-off-by: Simeon Widdis --- .../repository/integration_reader.ts | 47 ++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/server/adaptors/integrations/repository/integration_reader.ts b/server/adaptors/integrations/repository/integration_reader.ts index b9f0a094d3..1c778b62bb 100644 --- a/server/adaptors/integrations/repository/integration_reader.ts +++ b/server/adaptors/integrations/repository/integration_reader.ts @@ -426,7 +426,52 @@ export class IntegrationReader { * @returns A buffer with the static's data if present, otherwise null. */ async getStatic(staticPath: string): Promise> { - return await this.reader.readFileRaw(staticPath, 'static'); + // Statics were originally designed to read straight from file system, + // so we use direct access if possible. + if (!this.reader.isConfigLocalized) { + return await this.reader.readFileRaw(staticPath, 'static'); + } + + // Otherwise, we need to search for the right static, by checking each version. + const versions = await this.reader.findIntegrationVersions(); + if (!versions.ok) { + return versions; + } + for (const version of versions.value) { + const config = await this.getConfig(version); + if (!config.ok || !config.value.statics) { + continue; + } + const statics = config.value.statics; + if (statics.logo?.path === staticPath) { + if (!('data' in statics.logo)) { + return { ok: false, error: new Error('Localized config missing static data') }; + } + return { ok: true, value: Buffer.from((statics.logo as { data: string }).data, 'base64') }; + } + if (statics?.darkModeLogo?.path === staticPath) { + if (!('data' in statics.darkModeLogo)) { + return { ok: false, error: new Error('Localized config missing static data') }; + } + return { + ok: true, + value: Buffer.from((statics.darkModeLogo as { data: string }).data, 'base64'), + }; + } + for (const iterStatic of [...(statics?.gallery ?? []), ...(statics?.darkModeGallery ?? [])]) { + if (iterStatic.path === staticPath) { + if (!('data' in iterStatic)) { + return { ok: false, error: new Error('Localized config missing static data') }; + } + return { ok: true, value: Buffer.from((iterStatic as { data: string }).data, 'base64') }; + } + } + } + + return { + ok: false, + error: new Error(`Static not found: ${staticPath}`, { code: 'ENOENT' } as ErrorOptions), + }; } private async serializeStaticAsset(asset: StaticAsset): Promise> { From 73cfce4cd07554c2d20a20afc68d96ef1edc1e0a Mon Sep 17 00:00:00 2001 From: Simeon Widdis Date: Wed, 10 Jan 2024 13:23:21 -0800 Subject: [PATCH 21/36] Add basic validation test for JSON reader Signed-off-by: Simeon Widdis --- .../__test__/local_repository_json.test.ts | 55 +++++++++++++++++++ .../repository/integration_reader.ts | 4 +- 2 files changed, 57 insertions(+), 2 deletions(-) create mode 100644 server/adaptors/integrations/__test__/local_repository_json.test.ts diff --git a/server/adaptors/integrations/__test__/local_repository_json.test.ts b/server/adaptors/integrations/__test__/local_repository_json.test.ts new file mode 100644 index 0000000000..168b784820 --- /dev/null +++ b/server/adaptors/integrations/__test__/local_repository_json.test.ts @@ -0,0 +1,55 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * Serialization tests for integrations in the local repository. + */ + +import { TemplateManager } from '../repository/repository'; +import { IntegrationReader, foldResults } from '../repository/integration_reader'; +import path from 'path'; +import * as fs from 'fs/promises'; +import { JsonCatalogDataAdaptor } from '../repository/json_data_adaptor'; + +const fetchSerializedIntegrations = async (): Promise> => { + const directory = path.join(__dirname, '../__data__/repository'); + const folders = await fs.readdir(directory); + const readers = await Promise.all( + folders.map(async (folder) => { + const integPath = path.join(directory, folder); + if (!(await fs.lstat(integPath)).isDirectory()) { + // If it's not a directory (e.g. a README), skip it + return Promise.resolve(null); + } + // Otherwise, all directories must be integrations + return new IntegrationReader(integPath); + }) + ); + const serializedIntegrationResults = await Promise.all( + (readers.filter((x) => x !== null) as IntegrationReader[]).map((r) => r.serialize()) + ); + return foldResults(serializedIntegrationResults); +}; + +describe('The Local Serialized Catalog', () => { + it('Should serialize without errors', async () => { + const serialized = await fetchSerializedIntegrations(); + expect(serialized.ok).toBe(true); + }); + + it('Should pass deep validation for all serialized integrations', async () => { + const serialized = await fetchSerializedIntegrations(); + const repository = new TemplateManager( + '.', + new JsonCatalogDataAdaptor(serialized.value as SerializedIntegration[]) + ); + + for (const integ of await repository.getIntegrationList()) { + const validationResult = await integ.deepCheck(); + console.log(integ.name, validationResult); + await expect(validationResult).toHaveProperty('ok', true); + } + }); +}); diff --git a/server/adaptors/integrations/repository/integration_reader.ts b/server/adaptors/integrations/repository/integration_reader.ts index 1c778b62bb..5123add5e7 100644 --- a/server/adaptors/integrations/repository/integration_reader.ts +++ b/server/adaptors/integrations/repository/integration_reader.ts @@ -14,7 +14,7 @@ import { CatalogDataAdaptor, IntegrationPart } from './catalog_data_adaptor'; * @param results The list of results to fold. * @returns A single result object with values in an array, or an error result. */ -const foldResults = (results: Array>) => +export const foldResults = (results: Array>) => results.reduce( (result, currentValue) => { if (!result.ok) { @@ -395,7 +395,7 @@ export class IntegrationReader { mappings: { [key: string]: unknown }; }> > { - const configResult = await this.getConfig(version); + const configResult = await this.getRawConfig(version); if (!configResult.ok) { return configResult; } From ae373e8d95ecd98aada0eb02a036b6d34b53eb6a Mon Sep 17 00:00:00 2001 From: Simeon Widdis Date: Wed, 10 Jan 2024 13:32:56 -0800 Subject: [PATCH 22/36] Add static validation to integration reader Signed-off-by: Simeon Widdis --- .../__test__/local_repository_json.test.ts | 27 ++++++++++++++++++- .../repository/integration_reader.ts | 2 +- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/server/adaptors/integrations/__test__/local_repository_json.test.ts b/server/adaptors/integrations/__test__/local_repository_json.test.ts index 168b784820..69fdad6a88 100644 --- a/server/adaptors/integrations/__test__/local_repository_json.test.ts +++ b/server/adaptors/integrations/__test__/local_repository_json.test.ts @@ -48,8 +48,33 @@ describe('The Local Serialized Catalog', () => { for (const integ of await repository.getIntegrationList()) { const validationResult = await integ.deepCheck(); - console.log(integ.name, validationResult); await expect(validationResult).toHaveProperty('ok', true); } }); + + it('Should correctly retrieve a logo', async () => { + const serialized = await fetchSerializedIntegrations(); + const repository = new TemplateManager( + '.', + new JsonCatalogDataAdaptor(serialized.value as SerializedIntegration[]) + ); + const integration = (await repository.getIntegration('nginx')) as IntegrationReader; + const logoStatic = await integration.getStatic('logo.svg'); + + expect(logoStatic).toHaveProperty('ok', true); + expect((logoStatic.value as Buffer).length).toBeGreaterThan(1000); + }); + + it('Should correctly retrieve a gallery image', async () => { + const serialized = await fetchSerializedIntegrations(); + const repository = new TemplateManager( + '.', + new JsonCatalogDataAdaptor(serialized.value as SerializedIntegration[]) + ); + const integration = (await repository.getIntegration('nginx')) as IntegrationReader; + const logoStatic = await integration.getStatic('dashboard1.png'); + + expect(logoStatic).toHaveProperty('ok', true); + expect((logoStatic.value as Buffer).length).toBeGreaterThan(1000); + }); }); diff --git a/server/adaptors/integrations/repository/integration_reader.ts b/server/adaptors/integrations/repository/integration_reader.ts index 5123add5e7..e9476c5edf 100644 --- a/server/adaptors/integrations/repository/integration_reader.ts +++ b/server/adaptors/integrations/repository/integration_reader.ts @@ -438,7 +438,7 @@ export class IntegrationReader { return versions; } for (const version of versions.value) { - const config = await this.getConfig(version); + const config = await this.getRawConfig(version); if (!config.ok || !config.value.statics) { continue; } From e8e984a9b3089bec0c4cd96f3f336772ab10320c Mon Sep 17 00:00:00 2001 From: Simeon Widdis Date: Wed, 10 Jan 2024 14:01:38 -0800 Subject: [PATCH 23/36] Add more tests for deepCheck on JSON catalog Signed-off-by: Simeon Widdis --- .../__test__/local_repository_json.test.ts | 40 +++++++++++++++++++ .../repository/integration_reader.ts | 7 +--- 2 files changed, 42 insertions(+), 5 deletions(-) diff --git a/server/adaptors/integrations/__test__/local_repository_json.test.ts b/server/adaptors/integrations/__test__/local_repository_json.test.ts index 69fdad6a88..0a4b78ee09 100644 --- a/server/adaptors/integrations/__test__/local_repository_json.test.ts +++ b/server/adaptors/integrations/__test__/local_repository_json.test.ts @@ -78,3 +78,43 @@ describe('The Local Serialized Catalog', () => { expect((logoStatic.value as Buffer).length).toBeGreaterThan(1000); }); }); + +describe('Integration validation', () => { + it('Should correctly fail an integration without schemas', async () => { + const TEST_INTEGRATION = 'nginx'; + const serialized = await fetchSerializedIntegrations(); + const transformedSerialized = (serialized.value as SerializedIntegration[]) + .filter((integ: { name: string; components: unknown[] }) => integ.name === TEST_INTEGRATION) + .map((integ) => { + return { + ...integ, + components: [] as SerializedIntegrationComponent[], + }; + }); + const integration = new IntegrationReader( + TEST_INTEGRATION, + new JsonCatalogDataAdaptor(transformedSerialized) + ); + + await expect(integration.deepCheck()).resolves.toHaveProperty('ok', false); + }); + + it('Should correctly fail an integration without assets', async () => { + const TEST_INTEGRATION = 'nginx'; + const serialized = await fetchSerializedIntegrations(); + const transformedSerialized = (serialized.value as SerializedIntegration[]) + .filter((integ: { name: string; components: unknown[] }) => integ.name === TEST_INTEGRATION) + .map((integ) => { + return { + ...integ, + assets: {} as SerializedIntegrationAssets, + }; + }); + const integration = new IntegrationReader( + TEST_INTEGRATION, + new JsonCatalogDataAdaptor(transformedSerialized) + ); + + await expect(integration.deepCheck()).resolves.toHaveProperty('ok', false); + }); +}); diff --git a/server/adaptors/integrations/repository/integration_reader.ts b/server/adaptors/integrations/repository/integration_reader.ts index e9476c5edf..fef20c3032 100644 --- a/server/adaptors/integrations/repository/integration_reader.ts +++ b/server/adaptors/integrations/repository/integration_reader.ts @@ -171,12 +171,9 @@ export class IntegrationReader { } try { - const schemas = await this.getSchemas(); - if (!schemas.ok || Object.keys(schemas.value.mappings).length === 0) { - return { ok: false, error: new Error('The integration has no schemas available') }; - } + // Some other checks are included in getConfig validation. const assets = await this.getAssets(); - if (!assets.ok || Object.keys(assets).length === 0) { + if (!assets.ok || Object.keys(assets.value).length === 0) { return { ok: false, error: new Error('An integration must have at least one asset') }; } } catch (err) { From 873b424d41f88f3a7e3053dbcb3958d0a78a1ed5 Mon Sep 17 00:00:00 2001 From: Simeon Widdis Date: Wed, 10 Jan 2024 14:07:51 -0800 Subject: [PATCH 24/36] Add tests for json adaptor edge cases Signed-off-by: Simeon Widdis --- .../__test__/json_data_adaptor.test.ts | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/server/adaptors/integrations/repository/__test__/json_data_adaptor.test.ts b/server/adaptors/integrations/repository/__test__/json_data_adaptor.test.ts index c154ce5794..e52f725634 100644 --- a/server/adaptors/integrations/repository/__test__/json_data_adaptor.test.ts +++ b/server/adaptors/integrations/repository/__test__/json_data_adaptor.test.ts @@ -83,4 +83,27 @@ describe('JSON Data Adaptor', () => { expect(integs).toEqual(['sample1', 'sample2']); }); + + it('Should reject any attempts to read a file with a type', async () => { + const adaptor = new JsonCatalogDataAdaptor(TEST_CATALOG_NO_SERIALIZATION); + await expect(adaptor.readFile('logs-1.0.0.json', 'schemas')).resolves.toHaveProperty( + 'ok', + false + ); + }); + + it('Should reject any attempts to read a raw file', async () => { + const adaptor = new JsonCatalogDataAdaptor(TEST_CATALOG_NO_SERIALIZATION); + await expect(adaptor.readFileRaw('logo.svg', 'static')).resolves.toHaveProperty('ok', false); + }); + + it('Should reject nested directory searching', async () => { + const adaptor = new JsonCatalogDataAdaptor(TEST_CATALOG_NO_SERIALIZATION); + await expect(adaptor.findIntegrations('sample1')).resolves.toHaveProperty('ok', false); + }); + + it('Should report unknown directory type if integration list is empty', async () => { + const adaptor = new JsonCatalogDataAdaptor([]); + await expect(adaptor.getDirectoryType()).resolves.toBe('unknown'); + }); }); From c607a13dd5ccc5783dd2a4a7b35b5aa2cd069d90 Mon Sep 17 00:00:00 2001 From: Simeon Widdis Date: Wed, 10 Jan 2024 14:46:10 -0800 Subject: [PATCH 25/36] Add reserialization tests Signed-off-by: Simeon Widdis --- .../__test__/local_repository_json.test.ts | 86 +++++++++++++++++++ .../repository/integration_reader.ts | 27 ++++-- 2 files changed, 106 insertions(+), 7 deletions(-) diff --git a/server/adaptors/integrations/__test__/local_repository_json.test.ts b/server/adaptors/integrations/__test__/local_repository_json.test.ts index 0a4b78ee09..f09166b458 100644 --- a/server/adaptors/integrations/__test__/local_repository_json.test.ts +++ b/server/adaptors/integrations/__test__/local_repository_json.test.ts @@ -77,6 +77,62 @@ describe('The Local Serialized Catalog', () => { expect(logoStatic).toHaveProperty('ok', true); expect((logoStatic.value as Buffer).length).toBeGreaterThan(1000); }); + + it('Should correctly retrieve a dark mode logo', async () => { + const TEST_INTEGRATION = 'nginx'; + const serialized = await fetchSerializedIntegrations(); + const config = (serialized.value as SerializedIntegration[]).filter( + (integ: { name: string; components: unknown[] }) => integ.name === TEST_INTEGRATION + )[0]; + + if (!config.statics) { + throw new Error('NginX integration missing statics (invalid test)'); + } + config.statics.darkModeGallery = config.statics.gallery; + config.statics.darkModeLogo = { + ...(config.statics.logo as SerializedStaticAsset), + path: 'dark_logo.svg', + }; + + const reader = new IntegrationReader('nginx', new JsonCatalogDataAdaptor([config])); + + await expect(reader.getStatic('dark_logo.svg')).resolves.toHaveProperty('ok', true); + }); + + it('Should correctly re-serialize', async () => { + const TEST_INTEGRATION = 'nginx'; + const serialized = await fetchSerializedIntegrations(); + const config = (serialized.value as SerializedIntegration[]).filter( + (integ: { name: string }) => integ.name === TEST_INTEGRATION + )[0]; + + const reader = new IntegrationReader('nginx', new JsonCatalogDataAdaptor([config])); + const reserialized = await reader.serialize(); + + expect(reserialized.value).toEqual(config); + }); + + it('Should correctly re-serialize with dark mode values', async () => { + const TEST_INTEGRATION = 'nginx'; + const serialized = await fetchSerializedIntegrations(); + const config = (serialized.value as SerializedIntegration[]).filter( + (integ: { name: string }) => integ.name === TEST_INTEGRATION + )[0]; + + if (!config.statics) { + throw new Error('NginX integration missing statics (invalid test)'); + } + config.statics.darkModeGallery = config.statics.gallery; + config.statics.darkModeLogo = { + ...(config.statics.logo as SerializedStaticAsset), + path: 'dark_logo.svg', + }; + + const reader = new IntegrationReader('nginx', new JsonCatalogDataAdaptor([config])); + const reserialized = await reader.serialize(); + + expect(reserialized.value).toEqual(config); + }); }); describe('Integration validation', () => { @@ -118,3 +174,33 @@ describe('Integration validation', () => { await expect(integration.deepCheck()).resolves.toHaveProperty('ok', false); }); }); + +describe('JSON Catalog with invalid data', () => { + it('Should report an error if images are missing data', async () => { + const TEST_INTEGRATION = 'nginx'; + const serialized = await fetchSerializedIntegrations(); + const baseConfig = (serialized.value as SerializedIntegration[]).filter( + (integ: { name: string; components: unknown[] }) => integ.name === TEST_INTEGRATION + )[0]; + + if (!baseConfig.statics) { + throw new Error('NginX integration missing statics (invalid test)'); + } + + baseConfig.statics = { + logo: { path: 'logo.svg' } as SerializedStaticAsset, + darkModeLogo: { path: 'dm_logo.svg' } as SerializedStaticAsset, + gallery: [{ path: '1.png' }] as SerializedStaticAsset[], + darkModeGallery: [{ path: 'dm_1.png' }] as SerializedStaticAsset[], + }; + const reader = new IntegrationReader( + TEST_INTEGRATION, + new JsonCatalogDataAdaptor([baseConfig]) + ); + + await expect(reader.getStatic('logo.svg')).resolves.toHaveProperty('ok', false); + await expect(reader.getStatic('dm_logo.svg')).resolves.toHaveProperty('ok', false); + await expect(reader.getStatic('1.png')).resolves.toHaveProperty('ok', false); + await expect(reader.getStatic('dm_1.png')).resolves.toHaveProperty('ok', false); + }); +}); diff --git a/server/adaptors/integrations/repository/integration_reader.ts b/server/adaptors/integrations/repository/integration_reader.ts index fef20c3032..e9cd8e82b7 100644 --- a/server/adaptors/integrations/repository/integration_reader.ts +++ b/server/adaptors/integrations/repository/integration_reader.ts @@ -137,7 +137,8 @@ export class IntegrationReader { return { ok: false, error: new Error( - 'The config for the provided reader is localized, but no data field is present.' + 'The config for the provided reader is localized, but no data field is present. ' + + JSON.stringify(item) ), }; } @@ -544,7 +545,7 @@ export class IntegrationReader { * @returns A large object which includes all of the integration's data. */ async serialize(version?: string): Promise> { - const configResult = await this.getConfig(version); + const configResult = await this.getRawConfig(version); if (!configResult.ok) { return configResult; } @@ -555,7 +556,11 @@ export class IntegrationReader { const componentResults = await Promise.all( config.components.map((component) => - this.reader.readFile(`${component.name}-${component.version}.mapping.json`, 'schemas') + this.fetchDataOrReadFile( + component, + { filename: `${component.name}-${component.version}.mapping.json`, type: 'schemas' }, + 'json' + ) ) ); const componentsResult = foldResults(componentResults); @@ -571,9 +576,13 @@ export class IntegrationReader { if (config.assets.savedObjects) { const soMetadata = config.assets.savedObjects; - const soResult = await this.reader.readFile( - `${soMetadata.name}-${soMetadata.version}.ndjson`, - 'assets' + const soResult = await this.fetchDataOrReadFile( + config.assets.savedObjects, + { + filename: `${soMetadata.name}-${soMetadata.version}.ndjson`, + type: 'assets', + }, + 'json' ); if (!soResult.ok) { return soResult; @@ -584,7 +593,11 @@ export class IntegrationReader { if (config.assets.queries) { const queryResults = await Promise.all( config.assets.queries.map((query) => - this.reader.readFileRaw(`${query.name}-${query.version}.${query.language}`, 'assets') + this.fetchDataOrReadFile( + query, + { filename: `${query.name}-${query.version}.${query.language}`, type: 'assets' }, + 'binary' + ) ) ); const queriesResult = foldResults(queryResults); From f143cb9e9cda66acd71171066618953cdf7258e7 Mon Sep 17 00:00:00 2001 From: Simeon Widdis Date: Wed, 10 Jan 2024 15:31:10 -0800 Subject: [PATCH 26/36] Add tests and remove redundant error checks for 90% coverage Signed-off-by: Simeon Widdis --- ...y_json.test.ts => json_repository.test.ts} | 18 ++++++ ...ry.test.ts => local_fs_repository.test.ts} | 0 .../__test__/compare_versions.test.ts | 30 ---------- .../repository/__test__/utils.test.ts | 59 +++++++++++++++++++ .../repository/integration_reader.ts | 25 ++------ server/adaptors/integrations/types.ts | 4 +- 6 files changed, 83 insertions(+), 53 deletions(-) rename server/adaptors/integrations/__test__/{local_repository_json.test.ts => json_repository.test.ts} (91%) rename server/adaptors/integrations/__test__/{local_repository.test.ts => local_fs_repository.test.ts} (100%) delete mode 100644 server/adaptors/integrations/repository/__test__/compare_versions.test.ts create mode 100644 server/adaptors/integrations/repository/__test__/utils.test.ts diff --git a/server/adaptors/integrations/__test__/local_repository_json.test.ts b/server/adaptors/integrations/__test__/json_repository.test.ts similarity index 91% rename from server/adaptors/integrations/__test__/local_repository_json.test.ts rename to server/adaptors/integrations/__test__/json_repository.test.ts index f09166b458..ce50f2c34b 100644 --- a/server/adaptors/integrations/__test__/local_repository_json.test.ts +++ b/server/adaptors/integrations/__test__/json_repository.test.ts @@ -203,4 +203,22 @@ describe('JSON Catalog with invalid data', () => { await expect(reader.getStatic('1.png')).resolves.toHaveProperty('ok', false); await expect(reader.getStatic('dm_1.png')).resolves.toHaveProperty('ok', false); }); + + it('Should report an error on read if a schema has invalid JSON', async () => { + const TEST_INTEGRATION = 'nginx'; + const serialized = await fetchSerializedIntegrations(); + const baseConfig = (serialized.value as SerializedIntegration[]).filter( + (integ: { name: string; components: unknown[] }) => integ.name === TEST_INTEGRATION + )[0]; + + expect(baseConfig.components.length).toBeGreaterThanOrEqual(2); + baseConfig.components[1].data = '{"invalid_json": true'; + + const reader = new IntegrationReader( + TEST_INTEGRATION, + new JsonCatalogDataAdaptor([baseConfig]) + ); + + await expect(reader.getSchemas()).resolves.toHaveProperty('ok', false); + }); }); diff --git a/server/adaptors/integrations/__test__/local_repository.test.ts b/server/adaptors/integrations/__test__/local_fs_repository.test.ts similarity index 100% rename from server/adaptors/integrations/__test__/local_repository.test.ts rename to server/adaptors/integrations/__test__/local_fs_repository.test.ts diff --git a/server/adaptors/integrations/repository/__test__/compare_versions.test.ts b/server/adaptors/integrations/repository/__test__/compare_versions.test.ts deleted file mode 100644 index 03efce1e82..0000000000 --- a/server/adaptors/integrations/repository/__test__/compare_versions.test.ts +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { compareVersions } from '../integration_reader'; - -describe('compareVersions', () => { - it('should return 0 for equal versions', () => { - expect(compareVersions('1.2.3', '1.2.3')).toBe(0); - }); - - it('should return -1 for a < b', () => { - expect(compareVersions('1.2.3', '1.2.4')).toBe(-1); - expect(compareVersions('1.2.3', '1.3.0')).toBe(-1); - expect(compareVersions('1.2.3', '2.0.0')).toBe(-1); - }); - - it('should return 1 for a > b', () => { - expect(compareVersions('1.2.4', '1.2.3')).toBe(1); - expect(compareVersions('1.3.0', '1.2.3')).toBe(1); - expect(compareVersions('2.0.0', '1.2.3')).toBe(1); - }); - - it('should handle versions with different numbers of parts', () => { - expect(compareVersions('1.2.3', '1.2')).toBe(1); - expect(compareVersions('1.2', '1.2.3')).toBe(-1); - expect(compareVersions('1.2.3', '1.2.3.4')).toBe(-1); - }); -}); diff --git a/server/adaptors/integrations/repository/__test__/utils.test.ts b/server/adaptors/integrations/repository/__test__/utils.test.ts new file mode 100644 index 0000000000..231bfc78e6 --- /dev/null +++ b/server/adaptors/integrations/repository/__test__/utils.test.ts @@ -0,0 +1,59 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { compareVersions, foldResults } from '../integration_reader'; + +describe('compareVersions', () => { + it('should return 0 for equal versions', () => { + expect(compareVersions('1.2.3', '1.2.3')).toBe(0); + }); + + it('should return -1 for a < b', () => { + expect(compareVersions('1.2.3', '1.2.4')).toBe(-1); + expect(compareVersions('1.2.3', '1.3.0')).toBe(-1); + expect(compareVersions('1.2.3', '2.0.0')).toBe(-1); + }); + + it('should return 1 for a > b', () => { + expect(compareVersions('1.2.4', '1.2.3')).toBe(1); + expect(compareVersions('1.3.0', '1.2.3')).toBe(1); + expect(compareVersions('2.0.0', '1.2.3')).toBe(1); + }); + + it('should handle versions with different numbers of parts', () => { + expect(compareVersions('1.2.3', '1.2')).toBe(1); + expect(compareVersions('1.2', '1.2.3')).toBe(-1); + expect(compareVersions('1.2.3', '1.2.3.4')).toBe(-1); + }); +}); + +describe('foldResults', () => { + it('should return an empty array result if input array is empty', () => { + const results: Array> = []; + const result = foldResults(results); + expect(result).toEqual({ ok: true, value: [] }); + }); + + it('should fold results into a single array if all input results are ok', () => { + const results: Array> = [ + { ok: true, value: 1 }, + { ok: true, value: 2 }, + { ok: true, value: 3 }, + ]; + const result = foldResults(results); + expect(result).toEqual({ ok: true, value: [1, 2, 3] }); + }); + + it('should return the first error result encountered if any results are not ok', () => { + const results: Array> = [ + { ok: true, value: 1 }, + { ok: false, error: new Error('Error 1') }, + { ok: true, value: 3 }, + { ok: false, error: new Error('Error 2') }, + ]; + const result = foldResults(results); + expect(result).toEqual({ ok: false, error: new Error('Error 1') }); + }); +}); diff --git a/server/adaptors/integrations/repository/integration_reader.ts b/server/adaptors/integrations/repository/integration_reader.ts index e9cd8e82b7..48693e87ea 100644 --- a/server/adaptors/integrations/repository/integration_reader.ts +++ b/server/adaptors/integrations/repository/integration_reader.ts @@ -171,14 +171,10 @@ export class IntegrationReader { return configResult; } - try { - // Some other checks are included in getConfig validation. - const assets = await this.getAssets(); - if (!assets.ok || Object.keys(assets.value).length === 0) { - return { ok: false, error: new Error('An integration must have at least one asset') }; - } - } catch (err) { - return { ok: false, error: err }; + // Some other checks are included in getConfig validation. + const assets = await this.getAssets(); + if (!assets.ok || Object.keys(assets.value).length === 0) { + return { ok: false, error: new Error('An integration must have at least one asset') }; } return configResult; @@ -194,7 +190,6 @@ export class IntegrationReader { async getLatestVersion(): Promise { const versions = await this.reader.findIntegrationVersions(); if (!versions.ok) { - console.error(versions.error); return null; } if (versions.value.length === 0) { @@ -494,17 +489,11 @@ export class IntegrationReader { if (statics.logo) { const serializeResult = await this.serializeStaticAsset(statics.logo); - if (!serializeResult.ok) { - return serializeResult; - } serialized.logo = serializeResult.value; } if (statics.darkModeLogo) { const serializeResult = await this.serializeStaticAsset(statics.darkModeLogo); - if (!serializeResult.ok) { - return serializeResult; - } serialized.darkModeLogo = serializeResult.value; } @@ -513,9 +502,6 @@ export class IntegrationReader { statics.gallery.map((asset) => this.serializeStaticAsset(asset)) ); const foldedResult = foldResults(results); - if (!foldedResult.ok) { - return foldedResult; - } serialized.gallery = foldedResult.value; } @@ -524,9 +510,6 @@ export class IntegrationReader { statics.darkModeGallery.map((asset) => this.serializeStaticAsset(asset)) ); const foldedResult = foldResults(results); - if (!foldedResult.ok) { - return foldedResult; - } serialized.darkModeGallery = foldedResult.value; } diff --git a/server/adaptors/integrations/types.ts b/server/adaptors/integrations/types.ts index 21c1a3db46..5e7565a133 100644 --- a/server/adaptors/integrations/types.ts +++ b/server/adaptors/integrations/types.ts @@ -4,8 +4,8 @@ */ type Result = - | { ok: true; value: T; error?: unknown } - | { ok: false; error: E; value?: unknown }; + | { ok: true; value: T; error?: undefined } + | { ok: false; error: E; value?: undefined }; interface IntegrationConfig { name: string; From 59257692d94db21d103c61238c6f3302cb7b7abe Mon Sep 17 00:00:00 2001 From: Simeon Widdis Date: Wed, 10 Jan 2024 15:35:19 -0800 Subject: [PATCH 27/36] Fix lints in repository.test.ts Signed-off-by: Simeon Widdis --- .../integrations/repository/__test__/repository.test.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/server/adaptors/integrations/repository/__test__/repository.test.ts b/server/adaptors/integrations/repository/__test__/repository.test.ts index 5ecd6630be..816b44eaa0 100644 --- a/server/adaptors/integrations/repository/__test__/repository.test.ts +++ b/server/adaptors/integrations/repository/__test__/repository.test.ts @@ -28,7 +28,7 @@ describe('Repository', () => { jest.spyOn(fs, 'lstat').mockResolvedValue({ isDirectory: () => true } as Stats); jest .spyOn(IntegrationReader.prototype, 'getConfig') - .mockResolvedValue({ ok: true, value: {} as any }); + .mockResolvedValue({ ok: true, value: ({} as unknown) as IntegrationConfig }); const integrations = await repository.getIntegrationList(); @@ -51,7 +51,7 @@ describe('Repository', () => { jest .spyOn(IntegrationReader.prototype, 'getConfig') - .mockResolvedValue({ ok: true, value: {} as any }); + .mockResolvedValue({ ok: true, value: ({} as unknown) as IntegrationConfig }); const integrations = await repository.getIntegrationList(); @@ -73,7 +73,7 @@ describe('Repository', () => { jest.spyOn(fs, 'lstat').mockResolvedValue({ isDirectory: () => true } as Stats); jest .spyOn(IntegrationReader.prototype, 'getConfig') - .mockResolvedValue({ ok: true, value: {} as any }); + .mockResolvedValue({ ok: true, value: ({} as unknown) as IntegrationConfig }); const integration = await repository.getIntegration('integrationName'); From 6546a73df84154684963ef65edff963afa6255b7 Mon Sep 17 00:00:00 2001 From: Simeon Widdis Date: Wed, 10 Jan 2024 16:10:04 -0800 Subject: [PATCH 28/36] Fix lints for integrations_builder.ts Signed-off-by: Simeon Widdis --- .../integrations/integrations_builder.ts | 43 ++++++++++++------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/server/adaptors/integrations/integrations_builder.ts b/server/adaptors/integrations/integrations_builder.ts index 946b6f20fc..7c630dc5cd 100644 --- a/server/adaptors/integrations/integrations_builder.ts +++ b/server/adaptors/integrations/integrations_builder.ts @@ -4,7 +4,6 @@ */ import { v4 as uuidv4 } from 'uuid'; -import { uuidRx } from 'public/components/custom_panels/redux/panel_slice'; import { SavedObjectsClientContract } from '../../../../../src/core/server'; import { IntegrationReader } from './repository/integration_reader'; import { SavedObjectsBulkCreateObject } from '../../../../../src/core/public'; @@ -14,6 +13,13 @@ interface BuilderOptions { dataSource: string; } +interface SavedObject { + id: string; + type: string; + attributes: { title: string }; + references: Array<{ id: string }>; +} + export class IntegrationInstanceBuilder { client: SavedObjectsClientContract; @@ -36,14 +42,17 @@ export class IntegrationInstanceBuilder { } return assets.value; }) - .then((assets) => this.remapIDs(assets.savedObjects!)) + .then((assets) => this.remapIDs(assets.savedObjects! as SavedObject[])) .then((assets) => this.remapDataSource(assets, options.dataSource)) .then((assets) => this.postAssets(assets)) .then((refs) => this.buildInstance(integration, refs, options)); return instance; } - remapDataSource(assets: any[], dataSource: string | undefined): any[] { + remapDataSource( + assets: SavedObject[], + dataSource: string | undefined + ): Array<{ type: string; attributes: { title: string } }> { if (!dataSource) return assets; assets = assets.map((asset) => { if (asset.type === 'index-pattern') { @@ -54,7 +63,7 @@ export class IntegrationInstanceBuilder { return assets; } - remapIDs(assets: any[]): any[] { + remapIDs(assets: SavedObject[]): SavedObject[] { const toRemap = assets.filter((asset) => asset.id); const idMap = new Map(); return toRemap.map((item) => { @@ -73,20 +82,22 @@ export class IntegrationInstanceBuilder { }); } - async postAssets(assets: any[]): Promise { + async postAssets(assets: SavedObjectsBulkCreateObject[]): Promise { try { - const response = await this.client.bulkCreate(assets as SavedObjectsBulkCreateObject[]); - const refs: AssetReference[] = response.saved_objects.map((obj: any) => { - return { - assetType: obj.type, - assetId: obj.id, - status: 'available', // Assuming a successfully created object is available - isDefaultAsset: obj.type === 'dashboard', // Assuming for now that dashboards are default - description: obj.attributes?.title, - }; - }); + const response = await this.client.bulkCreate(assets); + const refs: AssetReference[] = (response.saved_objects as SavedObject[]).map( + (obj: SavedObject) => { + return { + assetType: obj.type, + assetId: obj.id, + status: 'available', // Assuming a successfully created object is available + isDefaultAsset: obj.type === 'dashboard', // Assuming for now that dashboards are default + description: obj.attributes?.title, + }; + } + ); return Promise.resolve(refs); - } catch (err: any) { + } catch (err) { return Promise.reject(err); } } From 62b238d920d8f695f86b7bbadb10a0a5704774e6 Mon Sep 17 00:00:00 2001 From: Simeon Widdis Date: Thu, 11 Jan 2024 09:52:33 -0800 Subject: [PATCH 29/36] Update snapshots Signed-off-by: Simeon Widdis --- .../__snapshots__/create.test.tsx.snap | 78 +- .../__snapshots__/log_config.test.tsx.snap | 10 +- .../service_config.test.tsx.snap | 30 +- .../__snapshots__/trace_config.test.tsx.snap | 20 +- .../live_tail_button.test.tsx.snap | 10 +- .../__snapshots__/search.test.tsx.snap | 50 +- .../custom_panel_table.test.tsx.snap | 20 +- .../custom_panel_view.test.tsx.snap | 70 +- .../__snapshots__/empty_panel.test.tsx.snap | 10 +- .../visualization_container.test.tsx.snap | 10 +- .../visualization_flyout.test.tsx.snap | 40 +- .../connection_details.test.tsx.snap | 10 +- .../data_connection.test.tsx.snap | 36 +- ...data_connections_description.test.tsx.snap | 10 +- ...anage_data_connections_table.test.tsx.snap | 108 +- .../__snapshots__/no_access.test.tsx.snap | 10 +- .../__snapshots__/no_results.test.tsx.snap | 10 +- .../__snapshots__/flyout_button.test.tsx.snap | 10 +- .../json_code_block.test.tsx.snap | 10 +- .../patterns_header.test.tsx.snap | 26 +- .../patterns_table.test.tsx.snap | 50 +- .../__snapshots__/save_panel.test.tsx.snap | 20 +- .../__snapshots__/field.test.tsx.snap | 43 +- .../__snapshots__/sidebar.test.tsx.snap | 978 +++++++++++++----- .../timechart_header.test.tsx.snap | 10 +- .../__snapshots__/config_panel.test.tsx.snap | 120 ++- .../saved_query_table.test.tsx.snap | 70 +- .../added_integration.test.tsx.snap | 40 +- .../added_integration_flyout.test.tsx.snap | 80 +- .../added_integration_table.test.tsx.snap | 60 +- ...ilable_integration_card_view.test.tsx.snap | 30 +- ...lable_integration_table_view.test.tsx.snap | 60 +- .../integration_details.test.tsx.snap | 10 +- .../integration_fields.test.tsx.snap | 10 +- .../integration_header.test.tsx.snap | 10 +- .../setup_integration.test.tsx.snap | 62 +- .../__snapshots__/searchbar.test.tsx.snap | 10 +- .../__snapshots__/sidebar.test.tsx.snap | 30 +- .../metrics_export.test.tsx.snap | 10 +- .../metrics_export_panel.test.tsx.snap | 10 +- .../__snapshots__/top_menu.test.tsx.snap | 50 +- .../__snapshots__/empty_view.test.tsx.snap | 10 +- .../__snapshots__/note_table.test.tsx.snap | 36 +- .../__snapshots__/notebook.test.tsx.snap | 24 +- .../__snapshots__/para_input.test.tsx.snap | 30 +- .../__snapshots__/paragraphs.test.tsx.snap | 48 +- .../__snapshots__/search_bar.test.tsx.snap | 50 +- .../filter_edit_popover.test.tsx.snap | 20 +- .../__snapshots__/filters.test.tsx.snap | 10 +- .../__snapshots__/dashboard.test.tsx.snap | 10 +- .../dashboard_table.test.tsx.snap | 170 ++- .../latency_trend_cell.test.tsx.snap | 10 +- .../__snapshots__/mode_picker.test.tsx.snap | 36 +- .../top_error_rates_table.test.tsx.snap | 120 ++- .../top_latency_table.test.tsx.snap | 150 ++- .../__snapshots__/services.test.tsx.snap | 80 +- .../services_table.test.tsx.snap | 50 +- .../service_breakdown_panel.test.tsx.snap | 10 +- .../span_detail_flyout.test.tsx.snap | 40 +- .../__snapshots__/traces.test.tsx.snap | 60 +- .../__snapshots__/traces_table.test.tsx.snap | 70 +- .../__snapshots__/gauge.test.tsx.snap | 10 +- .../__snapshots__/metrics.test.tsx.snap | 10 +- .../__snapshots__/text.test.tsx.snap | 1 + 64 files changed, 2469 insertions(+), 927 deletions(-) diff --git a/public/components/application_analytics/__tests__/__snapshots__/create.test.tsx.snap b/public/components/application_analytics/__tests__/__snapshots__/create.test.tsx.snap index 375a076cd0..e7c2dbdedf 100644 --- a/public/components/application_analytics/__tests__/__snapshots__/create.test.tsx.snap +++ b/public/components/application_analytics/__tests__/__snapshots__/create.test.tsx.snap @@ -7417,7 +7417,11 @@ Object { viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - /> + > + + + > + + + > + + @@ -7910,7 +7922,11 @@ Object { viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - /> + > + + @@ -7991,7 +8007,11 @@ Object { viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - /> + > + + + > + + @@ -8522,7 +8546,11 @@ Object { viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - /> + > + + + > + + + > + + @@ -9015,7 +9051,11 @@ Object { viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - /> + > + + @@ -9096,7 +9136,11 @@ Object { viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - /> + > + + + > + + @@ -17802,7 +17850,11 @@ Object { viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - /> + > + +
- - + > + + + - - + > + + + - - + > + + + @@ -1044,7 +1052,7 @@ exports[`Service Config component renders empty service config 1`] = ` size="m" type="search" > - - + > + + + diff --git a/public/components/application_analytics/__tests__/__snapshots__/trace_config.test.tsx.snap b/public/components/application_analytics/__tests__/__snapshots__/trace_config.test.tsx.snap index ca51495382..8b70a1a6a6 100644 --- a/public/components/application_analytics/__tests__/__snapshots__/trace_config.test.tsx.snap +++ b/public/components/application_analytics/__tests__/__snapshots__/trace_config.test.tsx.snap @@ -231,7 +231,7 @@ exports[`Trace Config component renders empty trace config 1`] = ` size="m" type="arrowRight" > - - + > + + + - - + > + + + diff --git a/public/components/common/live_tail/__tests__/__snapshots__/live_tail_button.test.tsx.snap b/public/components/common/live_tail/__tests__/__snapshots__/live_tail_button.test.tsx.snap index 3e8c7b716a..d16f1b4662 100644 --- a/public/components/common/live_tail/__tests__/__snapshots__/live_tail_button.test.tsx.snap +++ b/public/components/common/live_tail/__tests__/__snapshots__/live_tail_button.test.tsx.snap @@ -150,7 +150,7 @@ exports[`Live tail button starts live tail with 5s interval 1`] = ` size="m" type="stop" > - - + > + + + - - + > + + + - - + > + + + - - + > + + + @@ -746,7 +758,7 @@ exports[`Explorer Search component renders basic component 1`] = ` size="m" type="refresh" > - - + > + + + - - + > + + + - - + > + + + @@ -294,7 +298,7 @@ exports[`Panels Table Component renders empty panel table container 1`] = ` size="m" type="arrowDown" > - - + > + + + - - + > + + + - - + > + + + - - + > + + + - - + > + + + - - + > + + + @@ -3739,7 +3759,7 @@ exports[`Panels View Component renders panel view container without visualizatio size="m" type="refresh" > - - + > + + + - - + > + + + - - + > + + + - - + > + + +
diff --git a/public/components/custom_panels/panel_modules/visualization_flyout/__tests__/__snapshots__/visualization_flyout.test.tsx.snap b/public/components/custom_panels/panel_modules/visualization_flyout/__tests__/__snapshots__/visualization_flyout.test.tsx.snap index 0e37e1e4a2..c20ca8ae6a 100644 --- a/public/components/custom_panels/panel_modules/visualization_flyout/__tests__/__snapshots__/visualization_flyout.test.tsx.snap +++ b/public/components/custom_panels/panel_modules/visualization_flyout/__tests__/__snapshots__/visualization_flyout.test.tsx.snap @@ -133,7 +133,11 @@ exports[`Visualization Flyout Component renders add visualization Flyout 1`] = ` viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - /> + > + +
+ > + +
+ > + +
+ > + +
+ > + +
- - + > + + + diff --git a/public/components/datasources/components/__tests__/__snapshots__/connection_details.test.tsx.snap b/public/components/datasources/components/__tests__/__snapshots__/connection_details.test.tsx.snap index 6fb23b7abb..5b35615a54 100644 --- a/public/components/datasources/components/__tests__/__snapshots__/connection_details.test.tsx.snap +++ b/public/components/datasources/components/__tests__/__snapshots__/connection_details.test.tsx.snap @@ -298,7 +298,7 @@ exports[`Connection Details test Renders connection details for s3 datasource 1` size="m" type="iInCircle" > - - + > + + + + > + + + > + +
+ > + + @@ -603,7 +615,11 @@ exports[`Data Connection Page test Renders S3 data connection page with data 1`] viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - /> + > + +
+ > + +
+ > + +
- - + > + + + + > + +
@@ -150,7 +154,11 @@ exports[`Manage Data Connections Table test Renders manage data connections tabl viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - /> + > + + @@ -199,7 +207,11 @@ exports[`Manage Data Connections Table test Renders manage data connections tabl viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - /> + > + +
@@ -329,7 +341,11 @@ exports[`Manage Data Connections Table test Renders manage data connections tabl viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - /> + > + + + > + + + > + +
@@ -453,7 +477,11 @@ exports[`Manage Data Connections Table test Renders manage data connections tabl viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - /> + > + + + > + + + > + + @@ -577,7 +613,11 @@ exports[`Manage Data Connections Table test Renders manage data connections tabl viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - /> + > + + + > + + + > + + @@ -701,7 +749,11 @@ exports[`Manage Data Connections Table test Renders manage data connections tabl viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - /> + > + + + > + + + > + + @@ -805,7 +865,11 @@ exports[`Manage Data Connections Table test Renders manage data connections tabl viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - /> + > + + @@ -840,7 +904,11 @@ exports[`Manage Data Connections Table test Renders manage data connections tabl viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - /> + > + +
    + > + + diff --git a/public/components/datasources/components/__tests__/__snapshots__/no_access.test.tsx.snap b/public/components/datasources/components/__tests__/__snapshots__/no_access.test.tsx.snap index a4b27f4544..5fd77b87ba 100644 --- a/public/components/datasources/components/__tests__/__snapshots__/no_access.test.tsx.snap +++ b/public/components/datasources/components/__tests__/__snapshots__/no_access.test.tsx.snap @@ -36,7 +36,7 @@ exports[`No access test Renders no access view of data source 1`] = ` size="xxl" type="alert" > - - + > + + + - - + > + + + - - + > + + + diff --git a/public/components/event_analytics/explorer/events_views/json_code_block/__tests__/__snapshots__/json_code_block.test.tsx.snap b/public/components/event_analytics/explorer/events_views/json_code_block/__tests__/__snapshots__/json_code_block.test.tsx.snap index b318643346..e45c3c4272 100644 --- a/public/components/event_analytics/explorer/events_views/json_code_block/__tests__/__snapshots__/json_code_block.test.tsx.snap +++ b/public/components/event_analytics/explorer/events_views/json_code_block/__tests__/__snapshots__/json_code_block.test.tsx.snap @@ -173,7 +173,7 @@ exports[`Doc viewer JSON block component Renders JSON block component 1`] = ` size="m" type="copy" > - - + > + + + diff --git a/public/components/event_analytics/explorer/log_patterns/__tests__/__snapshots__/patterns_header.test.tsx.snap b/public/components/event_analytics/explorer/log_patterns/__tests__/__snapshots__/patterns_header.test.tsx.snap index 8777405139..681b600aed 100644 --- a/public/components/event_analytics/explorer/log_patterns/__tests__/__snapshots__/patterns_header.test.tsx.snap +++ b/public/components/event_analytics/explorer/log_patterns/__tests__/__snapshots__/patterns_header.test.tsx.snap @@ -101,7 +101,7 @@ exports[`Patterns header component Renders header of log patterns 1`] = ` size="m" type="gear" > - - + > + + + @@ -223,7 +227,11 @@ exports[`Patterns header component Renders header of log patterns 1`] = ` viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - /> + > + + @@ -587,7 +595,7 @@ exports[`Patterns header component Renders header of log patterns 1`] = ` size="s" type="popout" > - - + > + + + - - + > + + + - - + > + + + @@ -1011,7 +1019,7 @@ exports[`Pattern table component Renders pattern table 1`] = ` size="s" type="arrowDown" > - - + > + + + - - + > + + + @@ -1250,7 +1266,7 @@ exports[`Pattern table component Renders pattern table 1`] = ` size="m" type="arrowRight" > - - + > + + + diff --git a/public/components/event_analytics/explorer/save_panel/__tests__/__snapshots__/save_panel.test.tsx.snap b/public/components/event_analytics/explorer/save_panel/__tests__/__snapshots__/save_panel.test.tsx.snap index f6f024c453..b94a45bd65 100644 --- a/public/components/event_analytics/explorer/save_panel/__tests__/__snapshots__/save_panel.test.tsx.snap +++ b/public/components/event_analytics/explorer/save_panel/__tests__/__snapshots__/save_panel.test.tsx.snap @@ -390,7 +390,7 @@ exports[`Saved query table component Renders saved query table 1`] = ` className="euiFormControlLayoutClearButton__icon" type="cross" > - - + > + + + @@ -434,7 +438,7 @@ exports[`Saved query table component Renders saved query table 1`] = ` size="m" type="arrowDown" > - - + > + + + diff --git a/public/components/event_analytics/explorer/sidebar/__tests__/__snapshots__/field.test.tsx.snap b/public/components/event_analytics/explorer/sidebar/__tests__/__snapshots__/field.test.tsx.snap index acf3d81679..0c780860f0 100644 --- a/public/components/event_analytics/explorer/sidebar/__tests__/__snapshots__/field.test.tsx.snap +++ b/public/components/event_analytics/explorer/sidebar/__tests__/__snapshots__/field.test.tsx.snap @@ -64,7 +64,7 @@ exports[`Field component Renders a sidebar field 1`] = ` title="string" type="tokenString" > - - + > + + string + + + + @@ -152,7 +159,7 @@ exports[`Field component Renders a sidebar field 1`] = ` size="m" type="inputOutput" > - - + > + + + @@ -260,7 +271,7 @@ exports[`Field component Renders a sidebar field 1`] = ` size="m" type="inspect" > - - + > + + + @@ -329,7 +344,7 @@ exports[`Field component Renders a sidebar field 1`] = ` size="m" type="cross" > - - + > + + + diff --git a/public/components/event_analytics/explorer/sidebar/__tests__/__snapshots__/sidebar.test.tsx.snap b/public/components/event_analytics/explorer/sidebar/__tests__/__snapshots__/sidebar.test.tsx.snap index 102994f08e..59d4966c25 100644 --- a/public/components/event_analytics/explorer/sidebar/__tests__/__snapshots__/sidebar.test.tsx.snap +++ b/public/components/event_analytics/explorer/sidebar/__tests__/__snapshots__/sidebar.test.tsx.snap @@ -253,7 +253,7 @@ exports[`Siderbar component Renders empty sidebar component 1`] = ` size="s" type="search" > - - + > + + + @@ -1190,7 +1194,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` title="long" type="tokenString" > - - + > + + long + + + + @@ -1330,7 +1341,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="inspect" > - - + > + + + @@ -1398,7 +1413,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="cross" > - - + > + + + @@ -1577,7 +1596,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` title="text" type="tokenString" > - - + > + + text + + + + @@ -1717,7 +1743,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="inspect" > - - + > + + + @@ -1785,7 +1815,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="cross" > - - + > + + + @@ -1964,7 +1998,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` title="integer" type="tokenString" > - - + > + + integer + + + + @@ -2104,7 +2145,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="inspect" > - - + > + + + @@ -2172,7 +2217,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="cross" > - - + > + + + @@ -2351,7 +2400,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` title="long" type="tokenString" > - - + > + + long + + + + @@ -2491,7 +2547,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="inspect" > - - + > + + + @@ -2559,7 +2619,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="cross" > - - + > + + + @@ -2738,7 +2802,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` title="text" type="tokenString" > - - + > + + text + + + + @@ -2878,7 +2949,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="inspect" > - - + > + + + @@ -2946,7 +3021,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="cross" > - - + > + + + @@ -3125,7 +3204,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` title="long" type="tokenString" > - - + > + + long + + + + @@ -3265,7 +3351,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="inspect" > - - + > + + + @@ -3333,7 +3423,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="cross" > - - + > + + + @@ -3670,7 +3764,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` title="string" type="tokenString" > - - + > + + string + + + + @@ -3758,7 +3859,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="inputOutput" > - - + > + + + @@ -3866,7 +3971,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="inspect" > - - + > + + + @@ -3935,7 +4044,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="plusInCircleFilled" > - - + > + + + @@ -4114,7 +4227,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` title="long" type="tokenString" > - - + > + + long + + + + @@ -4254,7 +4374,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="inspect" > - - + > + + + @@ -4323,7 +4447,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="plusInCircleFilled" > - - + > + + + @@ -4502,7 +4630,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` title="ip" type="tokenIP" > - - + > + + ip + + + + @@ -4642,7 +4777,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="inspect" > - - + > + + + @@ -4711,7 +4850,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="plusInCircleFilled" > - - + > + + + @@ -4890,7 +5033,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` title="struct" type="tokenString" > - - + > + + struct + + + + @@ -5030,7 +5180,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="inspect" > - - + > + + + @@ -5099,7 +5253,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="plusInCircleFilled" > - - + > + + + @@ -5278,7 +5436,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` title="string" type="tokenString" > - - + > + + string + + + + @@ -5366,7 +5531,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="inputOutput" > - - + > + + + @@ -5474,7 +5643,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="inspect" > - - + > + + + @@ -5543,7 +5716,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="plusInCircleFilled" > - - + > + + + @@ -5722,7 +5899,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` title="struct" type="tokenString" > - - + > + + struct + + + + @@ -5862,7 +6046,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="inspect" > - - + > + + + @@ -5931,7 +6119,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="plusInCircleFilled" > - - + > + + + @@ -6110,7 +6302,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` title="string" type="tokenString" > - - + > + + string + + + + @@ -6198,7 +6397,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="inputOutput" > - - + > + + + @@ -6306,7 +6509,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="inspect" > - - + > + + + @@ -6375,7 +6582,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="plusInCircleFilled" > - - + > + + + @@ -6554,7 +6765,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` title="string" type="tokenString" > - - + > + + string + + + + @@ -6642,7 +6860,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="inputOutput" > - - + > + + + @@ -6750,7 +6972,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="inspect" > - - + > + + + @@ -6819,7 +7045,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="plusInCircleFilled" > - - + > + + + @@ -6998,7 +7228,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` title="ip" type="tokenIP" > - - + > + + ip + + + + @@ -7138,7 +7375,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="inspect" > - - + > + + + @@ -7207,7 +7448,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="plusInCircleFilled" > - - + > + + + @@ -7386,7 +7631,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` title="struct" type="tokenString" > - - + > + + struct + + + + @@ -7526,7 +7778,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="inspect" > - - + > + + + @@ -7595,7 +7851,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="plusInCircleFilled" > - - + > + + + @@ -7774,7 +8034,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` title="double" type="tokenString" > - - + > + + double + + + + @@ -7914,7 +8181,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="inspect" > - - + > + + + @@ -7983,7 +8254,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="plusInCircleFilled" > - - + > + + + @@ -8162,7 +8437,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` title="string" type="tokenString" > - - + > + + string + + + + @@ -8250,7 +8532,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="inputOutput" > - - + > + + + @@ -8358,7 +8644,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="inspect" > - - + > + + + @@ -8427,7 +8717,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="plusInCircleFilled" > - - + > + + + @@ -8606,7 +8900,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` title="long" type="tokenString" > - - + > + + long + + + + @@ -8746,7 +9047,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="inspect" > - - + > + + + @@ -8815,7 +9120,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="plusInCircleFilled" > - - + > + + + @@ -8994,7 +9303,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` title="string" type="tokenString" > - - + > + + string + + + + @@ -9082,7 +9398,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="inputOutput" > - - + > + + + @@ -9190,7 +9510,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="inspect" > - - + > + + + @@ -9259,7 +9583,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="plusInCircleFilled" > - - + > + + + @@ -9438,7 +9766,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` title="string" type="tokenString" > - - + > + + string + + + + @@ -9526,7 +9861,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="inputOutput" > - - + > + + + @@ -9634,7 +9973,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="inspect" > - - + > + + + @@ -9703,7 +10046,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="plusInCircleFilled" > - - + > + + + @@ -9882,7 +10229,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` title="string" type="tokenString" > - - + > + + string + + + + @@ -9970,7 +10324,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="inputOutput" > - - + > + + + @@ -10078,7 +10436,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="inspect" > - - + > + + + @@ -10147,7 +10509,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="plusInCircleFilled" > - - + > + + + @@ -10326,7 +10692,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` title="string" type="tokenString" > - - + > + + string + + + + @@ -10414,7 +10787,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="inputOutput" > - - + > + + + @@ -10522,7 +10899,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="inspect" > - - + > + + + @@ -10591,7 +10972,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="plusInCircleFilled" > - - + > + + + @@ -10770,7 +11155,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` title="date" type="tokenDate" > - - + > + + date + + + + @@ -10951,7 +11343,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="inspect" > - - + > + + + @@ -11020,7 +11416,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="plusInCircleFilled" > - - + > + + + @@ -11199,7 +11599,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` title="string" type="tokenString" > - - + > + + string + + + + @@ -11287,7 +11694,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="inputOutput" > - - + > + + + @@ -11395,7 +11806,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="inspect" > - - + > + + + @@ -11464,7 +11879,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="plusInCircleFilled" > - - + > + + + @@ -11643,7 +12062,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` title="date" type="tokenDate" > - - + > + + date + + + + @@ -11744,7 +12170,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="inputOutput" > - - + > + + + @@ -11839,7 +12269,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="inspect" > - - + > + + + @@ -11908,7 +12342,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="plusInCircleFilled" > - - + > + + + diff --git a/public/components/event_analytics/explorer/timechart_header/__tests__/__snapshots__/timechart_header.test.tsx.snap b/public/components/event_analytics/explorer/timechart_header/__tests__/__snapshots__/timechart_header.test.tsx.snap index de94c5f728..92c7549d7f 100644 --- a/public/components/event_analytics/explorer/timechart_header/__tests__/__snapshots__/timechart_header.test.tsx.snap +++ b/public/components/event_analytics/explorer/timechart_header/__tests__/__snapshots__/timechart_header.test.tsx.snap @@ -300,7 +300,7 @@ exports[`Time chart header component Renders Time chart header component 1`] = ` size="s" type="arrowDown" > - - + > + + + diff --git a/public/components/event_analytics/explorer/visualizations/config_panel/__tests__/__snapshots__/config_panel.test.tsx.snap b/public/components/event_analytics/explorer/visualizations/config_panel/__tests__/__snapshots__/config_panel.test.tsx.snap index a223888b9b..951ef271ea 100644 --- a/public/components/event_analytics/explorer/visualizations/config_panel/__tests__/__snapshots__/config_panel.test.tsx.snap +++ b/public/components/event_analytics/explorer/visualizations/config_panel/__tests__/__snapshots__/config_panel.test.tsx.snap @@ -4312,7 +4312,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] size="s" type="visBarVerticalStacked" > - - + > + + + @@ -4433,7 +4437,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] size="m" type="arrowDown" > - - + > + + + @@ -8054,7 +8062,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] size="m" type="arrowRight" > - - + > + + + - - + > + + + - - + > + + + - - + > + + + - - + > + + + @@ -13430,7 +13458,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] size="m" type="iInCircle" > - - + > + + + @@ -13671,7 +13703,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] size="m" type="iInCircle" > - - + > + + + @@ -13912,7 +13948,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] size="m" type="iInCircle" > - - + > + + + @@ -14153,7 +14193,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] size="m" type="iInCircle" > - - + > + + + @@ -15075,7 +15119,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] size="m" type="arrowRight" > - - + > + + + - - + > + + + @@ -507,7 +511,7 @@ exports[`Saved query table component Renders saved query table 1`] = ` size="m" type="arrowDown" > - - + > + + + - - + > + + + @@ -1225,7 +1237,7 @@ exports[`Saved query table component Renders saved query table 1`] = ` size="m" type="visBarVerticalStacked" > - - + > + + + @@ -1464,7 +1480,7 @@ exports[`Saved query table component Renders saved query table 1`] = ` size="s" type="arrowDown" > - - + > + + + - - + > + + + @@ -1703,7 +1727,7 @@ exports[`Saved query table component Renders saved query table 1`] = ` size="m" type="arrowRight" > - - + > + + + diff --git a/public/components/integrations/components/__tests__/__snapshots__/added_integration.test.tsx.snap b/public/components/integrations/components/__tests__/__snapshots__/added_integration.test.tsx.snap index 7ef7eb7859..4f499e10ed 100644 --- a/public/components/integrations/components/__tests__/__snapshots__/added_integration.test.tsx.snap +++ b/public/components/integrations/components/__tests__/__snapshots__/added_integration.test.tsx.snap @@ -176,7 +176,7 @@ exports[`Added Integration View Test Renders added integration view using dummy color="danger" type="dot" > - - + > + + + @@ -243,7 +247,7 @@ exports[`Added Integration View Test Renders added integration view using dummy size="m" type="trash" > - - + > + + + @@ -572,7 +580,7 @@ exports[`Added Integration View Test Renders added integration view using dummy size="m" type="search" > - - + > + + + @@ -796,7 +808,7 @@ exports[`Added Integration View Test Renders added integration view using dummy size="m" type="arrowDown" > - - + > + + + + > + +
    + > + + @@ -389,7 +397,11 @@ exports[`Add Integration Flyout Test Renders add integration flyout with dummy i viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - /> + > + +
    + > + + @@ -648,7 +664,11 @@ exports[`Add Integration Flyout Test Renders add integration flyout with dummy i viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - /> + > + +
    + > + + @@ -907,7 +931,11 @@ exports[`Add Integration Flyout Test Renders add integration flyout with dummy i viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - /> + > + +
    + > + + @@ -1154,7 +1186,11 @@ exports[`Add Integration Flyout Test Renders add integration flyout with dummy i viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - /> + > + +
    + > + + @@ -1437,7 +1477,7 @@ exports[`Add Integration Flyout Test Renders add integration flyout with dummy i size="m" type="cross" > - - + > + + + @@ -1569,7 +1613,7 @@ exports[`Add Integration Flyout Test Renders add integration flyout with dummy i size="s" type="popout" > - - + > + + + - - + > + + + @@ -487,7 +491,7 @@ exports[`Added Integration Table View Test Renders added integration table view size="m" type="arrowDown" > - - + > + + + - - + > + + +
    @@ -1191,7 +1203,7 @@ exports[`Added Integration Table View Test Renders added integration table view size="s" type="arrowDown" > - - + > + + + - - + > + + + @@ -1430,7 +1450,7 @@ exports[`Added Integration Table View Test Renders added integration table view size="m" type="arrowRight" > - - + > + + + diff --git a/public/components/integrations/components/__tests__/__snapshots__/available_integration_card_view.test.tsx.snap b/public/components/integrations/components/__tests__/__snapshots__/available_integration_card_view.test.tsx.snap index 9f6372b915..6f47d925a0 100644 --- a/public/components/integrations/components/__tests__/__snapshots__/available_integration_card_view.test.tsx.snap +++ b/public/components/integrations/components/__tests__/__snapshots__/available_integration_card_view.test.tsx.snap @@ -125,7 +125,7 @@ exports[`Available Integration Card View Test Renders nginx integration card vie size="m" type="search" > - - + > + + + @@ -269,7 +273,7 @@ exports[`Available Integration Card View Test Renders nginx integration card vie size="m" type="list" > - - + > + + + - - + > + + + - - + > + + + @@ -471,7 +475,7 @@ exports[`Available Integration Table View Test Renders nginx integration table v size="m" type="list" > - - + > + + + - - + > + + + - - + > + + + - - + > + + + @@ -1446,7 +1466,7 @@ exports[`Available Integration Table View Test Renders nginx integration table v size="m" type="arrowRight" > - - + > + + + diff --git a/public/components/integrations/components/__tests__/__snapshots__/integration_details.test.tsx.snap b/public/components/integrations/components/__tests__/__snapshots__/integration_details.test.tsx.snap index 5274b335b7..18d1867951 100644 --- a/public/components/integrations/components/__tests__/__snapshots__/integration_details.test.tsx.snap +++ b/public/components/integrations/components/__tests__/__snapshots__/integration_details.test.tsx.snap @@ -120,7 +120,7 @@ exports[`Available Integration Table View Test Renders nginx integration table v size="s" type="popout" > - - + > + + + diff --git a/public/components/integrations/components/__tests__/__snapshots__/integration_fields.test.tsx.snap b/public/components/integrations/components/__tests__/__snapshots__/integration_fields.test.tsx.snap index 77fb9d7a07..9617512f0f 100644 --- a/public/components/integrations/components/__tests__/__snapshots__/integration_fields.test.tsx.snap +++ b/public/components/integrations/components/__tests__/__snapshots__/integration_fields.test.tsx.snap @@ -160,7 +160,7 @@ exports[`Available Integration Table View Test Renders nginx integration table v size="m" type="search" > - - + > + + + diff --git a/public/components/integrations/components/__tests__/__snapshots__/integration_header.test.tsx.snap b/public/components/integrations/components/__tests__/__snapshots__/integration_header.test.tsx.snap index 9aa43c4964..41591c2408 100644 --- a/public/components/integrations/components/__tests__/__snapshots__/integration_header.test.tsx.snap +++ b/public/components/integrations/components/__tests__/__snapshots__/integration_header.test.tsx.snap @@ -67,7 +67,7 @@ exports[`Integration Header Test Renders integration header as expected 1`] = ` size="s" type="popout" > - - + > + + + diff --git a/public/components/integrations/components/__tests__/__snapshots__/setup_integration.test.tsx.snap b/public/components/integrations/components/__tests__/__snapshots__/setup_integration.test.tsx.snap index ac06da656e..8f555a0d9b 100644 --- a/public/components/integrations/components/__tests__/__snapshots__/setup_integration.test.tsx.snap +++ b/public/components/integrations/components/__tests__/__snapshots__/setup_integration.test.tsx.snap @@ -288,7 +288,7 @@ exports[`Integration Setup Page Renders integration setup page as expected 1`] = size="m" type="arrowDown" > - - + > + + + @@ -590,7 +594,7 @@ exports[`Integration Setup Page Renders integration setup page as expected 1`] = className="euiFormControlLayoutClearButton__icon" type="cross" > - - + > + + + @@ -641,7 +649,7 @@ exports[`Integration Setup Page Renders integration setup page as expected 1`] = size="m" type="arrowDown" > - - + > + + + @@ -751,7 +763,11 @@ exports[`Integration Setup Page Renders integration setup page as expected 1`] = viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - /> + > + + @@ -781,7 +797,11 @@ exports[`Integration Setup Page Renders integration setup page as expected 1`] = viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - /> + > + + @@ -868,7 +888,7 @@ exports[`Integration Setup Page Renders integration setup page as expected 1`] = size="m" type="cross" > - - + > + + + - - + > + + + - - + > + + + diff --git a/public/components/metrics/sidebar/__tests__/__snapshots__/sidebar.test.tsx.snap b/public/components/metrics/sidebar/__tests__/__snapshots__/sidebar.test.tsx.snap index 898fc9dfd0..a22e4729ce 100644 --- a/public/components/metrics/sidebar/__tests__/__snapshots__/sidebar.test.tsx.snap +++ b/public/components/metrics/sidebar/__tests__/__snapshots__/sidebar.test.tsx.snap @@ -198,7 +198,7 @@ exports[`Side Bar Component renders Side Bar Component 1`] = ` size="m" type="search" > - - + > + + + @@ -293,7 +297,7 @@ exports[`Side Bar Component renders Side Bar Component 1`] = ` size="m" type="arrowRight" > - - + > + + + - - + > + + + - - + > + + + - - + > + + + diff --git a/public/components/metrics/top_menu/__tests__/__snapshots__/top_menu.test.tsx.snap b/public/components/metrics/top_menu/__tests__/__snapshots__/top_menu.test.tsx.snap index cb3497bdcf..9c64eae1cd 100644 --- a/public/components/metrics/top_menu/__tests__/__snapshots__/top_menu.test.tsx.snap +++ b/public/components/metrics/top_menu/__tests__/__snapshots__/top_menu.test.tsx.snap @@ -253,7 +253,7 @@ exports[`Metrics Top Menu Component renders Top Menu Component when enabled 1`] size="m" type="arrowDown" > - - + > + + + @@ -563,7 +567,7 @@ exports[`Metrics Top Menu Component renders Top Menu Component when enabled 1`] size="s" type="arrowDown" > - - + > + + + - - + > + + + @@ -753,7 +765,7 @@ exports[`Metrics Top Menu Component renders Top Menu Component when enabled 1`] size="m" type="refresh" > - - + > + + + - - + > + + + - - + > + + + spec renders the component 1`] = ` viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - /> + > + +
    @@ -358,7 +362,11 @@ exports[` spec renders the component 1`] = ` viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - /> + > + +
    @@ -841,7 +849,11 @@ exports[` spec renders the component 1`] = ` viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - /> + > + +
      spec renders the component 1`] = ` viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - /> + > + +
    @@ -973,7 +989,11 @@ exports[` spec renders the empty component 1`] = ` viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - /> + > + +
    @@ -1009,7 +1029,11 @@ exports[` spec renders the empty component 1`] = ` viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - /> + > + + diff --git a/public/components/notebooks/components/__tests__/__snapshots__/notebook.test.tsx.snap b/public/components/notebooks/components/__tests__/__snapshots__/notebook.test.tsx.snap index b2bc5ba057..a55b86bc52 100644 --- a/public/components/notebooks/components/__tests__/__snapshots__/notebook.test.tsx.snap +++ b/public/components/notebooks/components/__tests__/__snapshots__/notebook.test.tsx.snap @@ -48,7 +48,11 @@ exports[` spec Renders the empty component 1`] = ` viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - /> + > + + @@ -129,7 +133,11 @@ exports[` spec Renders the empty component 1`] = ` viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - /> + > + + @@ -224,7 +232,11 @@ exports[` spec Renders the empty component 1`] = ` viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - /> + > + +
    spec Renders the empty component 1`] = ` viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - /> + > + +
    spec renders the markdown component 1`] = ` viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - /> + > + +
    @@ -137,7 +141,11 @@ exports[` spec renders the visualization component 1`] = ` viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - /> + > + + @@ -238,7 +250,11 @@ exports[` spec renders the visualization component 1`] = ` viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - /> + > + + @@ -251,7 +267,11 @@ exports[` spec renders the visualization component 1`] = ` viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - /> + > + +
    diff --git a/public/components/notebooks/components/paragraph_components/__tests__/__snapshots__/paragraphs.test.tsx.snap b/public/components/notebooks/components/paragraph_components/__tests__/__snapshots__/paragraphs.test.tsx.snap index c28f96d28d..df055e89ca 100644 --- a/public/components/notebooks/components/paragraph_components/__tests__/__snapshots__/paragraphs.test.tsx.snap +++ b/public/components/notebooks/components/paragraph_components/__tests__/__snapshots__/paragraphs.test.tsx.snap @@ -29,7 +29,11 @@ exports[` spec renders the component 1`] = ` viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - /> + > + + @@ -56,7 +60,11 @@ exports[` spec renders the component 1`] = ` viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - /> + > + + @@ -119,7 +127,11 @@ exports[` spec renders the component 1`] = ` viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - /> + > + + @@ -150,7 +162,11 @@ exports[` spec renders the component 1`] = ` viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - /> + > + + spec renders the component 1`] = ` viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - /> + > + + @@ -187,7 +207,11 @@ exports[` spec renders the component 1`] = ` viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - /> + > + + spec renders the component 1`] = ` viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - /> + > + + @@ -249,7 +277,11 @@ exports[` spec renders the component 1`] = ` viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - /> + > + +
    - - + > + + + - - + > + + + @@ -451,7 +459,7 @@ exports[`Search bar components renders search bar 1`] = ` size="m" type="search" > - - + > + + + @@ -931,7 +943,7 @@ exports[`Search bar components renders search bar 1`] = ` size="m" type="refresh" > - - + > + + + - - + > + + + diff --git a/public/components/trace_analytics/components/common/filters/__tests__/__snapshots__/filter_edit_popover.test.tsx.snap b/public/components/trace_analytics/components/common/filters/__tests__/__snapshots__/filter_edit_popover.test.tsx.snap index 7fde9a70a6..8dc64c168d 100644 --- a/public/components/trace_analytics/components/common/filters/__tests__/__snapshots__/filter_edit_popover.test.tsx.snap +++ b/public/components/trace_analytics/components/common/filters/__tests__/__snapshots__/filter_edit_popover.test.tsx.snap @@ -290,7 +290,7 @@ exports[`Filter popover component renders filter popover 1`] = ` size="m" type="arrowDown" > - - + > + + + @@ -554,7 +558,7 @@ exports[`Filter popover component renders filter popover 1`] = ` size="m" type="arrowDown" > - - + > + + + diff --git a/public/components/trace_analytics/components/common/filters/__tests__/__snapshots__/filters.test.tsx.snap b/public/components/trace_analytics/components/common/filters/__tests__/__snapshots__/filters.test.tsx.snap index 3d483d4dd2..e886fa6400 100644 --- a/public/components/trace_analytics/components/common/filters/__tests__/__snapshots__/filters.test.tsx.snap +++ b/public/components/trace_analytics/components/common/filters/__tests__/__snapshots__/filters.test.tsx.snap @@ -80,7 +80,7 @@ exports[`Filter component renders filters 1`] = ` size="m" type="filter" > - - + > + + + diff --git a/public/components/trace_analytics/components/dashboard/__tests__/__snapshots__/dashboard.test.tsx.snap b/public/components/trace_analytics/components/dashboard/__tests__/__snapshots__/dashboard.test.tsx.snap index f828066af8..1fff402475 100644 --- a/public/components/trace_analytics/components/dashboard/__tests__/__snapshots__/dashboard.test.tsx.snap +++ b/public/components/trace_analytics/components/dashboard/__tests__/__snapshots__/dashboard.test.tsx.snap @@ -1405,7 +1405,7 @@ exports[`Dashboard component renders empty dashboard 1`] = ` size="m" type="arrowDown" > - - + > + + + - - + > + + + - - + > + + +
    @@ -1241,7 +1249,7 @@ exports[`Dashboard table component renders dashboard table 1`] = ` size="s" type="questionInCircle" > - - + > + + + @@ -1291,7 +1303,7 @@ exports[`Dashboard table component renders dashboard table 1`] = ` size="m" type="sortDown" > - - + > + + + @@ -1391,7 +1407,7 @@ exports[`Dashboard table component renders dashboard table 1`] = ` size="s" type="questionInCircle" > - - + > + + +
    @@ -1489,7 +1509,7 @@ exports[`Dashboard table component renders dashboard table 1`] = ` size="s" type="questionInCircle" > - - + > + + +
    @@ -1597,7 +1621,7 @@ exports[`Dashboard table component renders dashboard table 1`] = ` size="s" type="questionInCircle" > - - + > + + +
    @@ -1706,7 +1734,7 @@ exports[`Dashboard table component renders dashboard table 1`] = ` size="s" type="questionInCircle" > - - + > + + +
    @@ -1828,7 +1860,7 @@ exports[`Dashboard table component renders dashboard table 1`] = ` size="s" type="questionInCircle" > - - + > + + +
    @@ -1959,7 +1995,7 @@ exports[`Dashboard table component renders dashboard table 1`] = ` size="s" type="questionInCircle" > - - + > + + + @@ -2397,7 +2437,7 @@ exports[`Dashboard table component renders dashboard table 1`] = ` size="s" type="questionInCircle" > - - + > + + +
    @@ -2506,7 +2550,7 @@ exports[`Dashboard table component renders dashboard table 1`] = ` size="s" type="questionInCircle" > - - + > + + +
    @@ -2615,7 +2663,7 @@ exports[`Dashboard table component renders dashboard table 1`] = ` size="s" type="questionInCircle" > - - + > + + +
    @@ -2734,7 +2786,7 @@ exports[`Dashboard table component renders dashboard table 1`] = ` size="s" type="questionInCircle" > - - + > + + +
    @@ -2916,7 +2972,7 @@ exports[`Dashboard table component renders dashboard table 1`] = ` size="s" type="arrowDown" > - - + > + + + - - + > + + + @@ -3155,7 +3219,7 @@ exports[`Dashboard table component renders dashboard table 1`] = ` size="m" type="arrowRight" > - - + > + + + diff --git a/public/components/trace_analytics/components/dashboard/__tests__/__snapshots__/latency_trend_cell.test.tsx.snap b/public/components/trace_analytics/components/dashboard/__tests__/__snapshots__/latency_trend_cell.test.tsx.snap index 4b415df6f9..6c4844fa12 100644 --- a/public/components/trace_analytics/components/dashboard/__tests__/__snapshots__/latency_trend_cell.test.tsx.snap +++ b/public/components/trace_analytics/components/dashboard/__tests__/__snapshots__/latency_trend_cell.test.tsx.snap @@ -142,7 +142,7 @@ exports[`Latency trend cell component renders latency trend cell 1`] = ` size="m" type="magnifyWithPlus" > - - + > + + + diff --git a/public/components/trace_analytics/components/dashboard/__tests__/__snapshots__/mode_picker.test.tsx.snap b/public/components/trace_analytics/components/dashboard/__tests__/__snapshots__/mode_picker.test.tsx.snap index 469f17277f..95690a4bae 100644 --- a/public/components/trace_analytics/components/dashboard/__tests__/__snapshots__/mode_picker.test.tsx.snap +++ b/public/components/trace_analytics/components/dashboard/__tests__/__snapshots__/mode_picker.test.tsx.snap @@ -86,7 +86,7 @@ exports[`Mode picker component renders mode picker 1`] = ` size="m" type="arrowDown" > - - + > + + + - - + > + + + + > + +
    @@ -674,7 +686,7 @@ exports[`Mode picker component renders mode picker 2`] = ` size="s" type="search" > - - + > + + +
    diff --git a/public/components/trace_analytics/components/dashboard/__tests__/__snapshots__/top_error_rates_table.test.tsx.snap b/public/components/trace_analytics/components/dashboard/__tests__/__snapshots__/top_error_rates_table.test.tsx.snap index 71733fa84d..dee301c004 100644 --- a/public/components/trace_analytics/components/dashboard/__tests__/__snapshots__/top_error_rates_table.test.tsx.snap +++ b/public/components/trace_analytics/components/dashboard/__tests__/__snapshots__/top_error_rates_table.test.tsx.snap @@ -805,7 +805,7 @@ exports[`Error Rates Table component renders top error rates table with data 1`] size="s" type="arrowDown" > - - + > + + + - - + > + + +
    @@ -1056,7 +1064,7 @@ exports[`Error Rates Table component renders top error rates table with data 1`] size="s" type="questionInCircle" > - - + > + + +
    @@ -1154,7 +1166,7 @@ exports[`Error Rates Table component renders top error rates table with data 1`] size="s" type="questionInCircle" > - - + > + + +
    @@ -1262,7 +1278,7 @@ exports[`Error Rates Table component renders top error rates table with data 1`] size="s" type="questionInCircle" > - - + > + + +
    @@ -1384,7 +1404,7 @@ exports[`Error Rates Table component renders top error rates table with data 1`] size="s" type="questionInCircle" > - - + > + + +
    @@ -1508,7 +1532,7 @@ exports[`Error Rates Table component renders top error rates table with data 1`] size="s" type="questionInCircle" > - - + > + + +
    @@ -1617,7 +1645,7 @@ exports[`Error Rates Table component renders top error rates table with data 1`] size="s" type="questionInCircle" > - - + > + + +
    @@ -1736,7 +1768,7 @@ exports[`Error Rates Table component renders top error rates table with data 1`] size="s" type="questionInCircle" > - - + > + + +
    @@ -1914,7 +1950,7 @@ exports[`Error Rates Table component renders top error rates table with data 1`] size="s" type="arrowDown" > - - + > + + + - - + > + + + @@ -2153,7 +2197,7 @@ exports[`Error Rates Table component renders top error rates table with data 1`] size="m" type="arrowRight" > - - + > + + + diff --git a/public/components/trace_analytics/components/dashboard/__tests__/__snapshots__/top_latency_table.test.tsx.snap b/public/components/trace_analytics/components/dashboard/__tests__/__snapshots__/top_latency_table.test.tsx.snap index d0279c1869..edcc7059d9 100644 --- a/public/components/trace_analytics/components/dashboard/__tests__/__snapshots__/top_latency_table.test.tsx.snap +++ b/public/components/trace_analytics/components/dashboard/__tests__/__snapshots__/top_latency_table.test.tsx.snap @@ -1164,7 +1164,7 @@ exports[`Latency Table component renders top error rates table with data 1`] = ` size="s" type="arrowDown" > - - + > + + + - - + > + + +
    @@ -1421,7 +1429,7 @@ exports[`Latency Table component renders top error rates table with data 1`] = ` size="s" type="questionInCircle" > - - + > + + + @@ -1471,7 +1483,7 @@ exports[`Latency Table component renders top error rates table with data 1`] = ` size="m" type="sortDown" > - - + > + + + @@ -1571,7 +1587,7 @@ exports[`Latency Table component renders top error rates table with data 1`] = ` size="s" type="questionInCircle" > - - + > + + +
    @@ -1680,7 +1700,7 @@ exports[`Latency Table component renders top error rates table with data 1`] = ` size="s" type="questionInCircle" > - - + > + + +
    @@ -1789,7 +1813,7 @@ exports[`Latency Table component renders top error rates table with data 1`] = ` size="s" type="questionInCircle" > - - + > + + +
    @@ -1911,7 +1939,7 @@ exports[`Latency Table component renders top error rates table with data 1`] = ` size="s" type="questionInCircle" > - - + > + + +
    @@ -2042,7 +2074,7 @@ exports[`Latency Table component renders top error rates table with data 1`] = ` size="s" type="questionInCircle" > - - + > + + + @@ -2480,7 +2516,7 @@ exports[`Latency Table component renders top error rates table with data 1`] = ` size="s" type="questionInCircle" > - - + > + + +
    @@ -2589,7 +2629,7 @@ exports[`Latency Table component renders top error rates table with data 1`] = ` size="s" type="questionInCircle" > - - + > + + +
    @@ -2708,7 +2752,7 @@ exports[`Latency Table component renders top error rates table with data 1`] = ` size="s" type="questionInCircle" > - - + > + + +
    @@ -2886,7 +2934,7 @@ exports[`Latency Table component renders top error rates table with data 1`] = ` size="s" type="arrowDown" > - - + > + + + - - + > + + + @@ -3125,7 +3181,7 @@ exports[`Latency Table component renders top error rates table with data 1`] = ` size="m" type="arrowRight" > - - + > + + + diff --git a/public/components/trace_analytics/components/services/__tests__/__snapshots__/services.test.tsx.snap b/public/components/trace_analytics/components/services/__tests__/__snapshots__/services.test.tsx.snap index 042830c076..b4e2ead80a 100644 --- a/public/components/trace_analytics/components/services/__tests__/__snapshots__/services.test.tsx.snap +++ b/public/components/trace_analytics/components/services/__tests__/__snapshots__/services.test.tsx.snap @@ -282,7 +282,7 @@ exports[`Services component renders empty services page 1`] = ` size="m" type="arrowDown" > - - + > + + + - - + > + + + @@ -922,7 +930,7 @@ exports[`Services component renders empty services page 1`] = ` size="s" type="arrowDown" > - - + > + + + - - + > + + + @@ -1076,7 +1092,7 @@ exports[`Services component renders empty services page 1`] = ` size="m" type="refresh" > - - + > + + + - - + > + + + @@ -1875,7 +1899,7 @@ exports[`Services component renders empty services page 1`] = ` size="m" type="search" > - - + > + + + @@ -2042,7 +2070,7 @@ exports[`Services component renders empty services page 1`] = ` size="m" type="arrowRight" > - - + > + + + - - + > + + + - - + > + + + @@ -3065,7 +3073,7 @@ exports[`Services table component renders services table 1`] = ` size="s" type="arrowDown" > - - + > + + + - - + > + + + @@ -3304,7 +3320,7 @@ exports[`Services table component renders services table 1`] = ` size="m" type="arrowRight" > - - + > + + + diff --git a/public/components/trace_analytics/components/traces/__tests__/__snapshots__/service_breakdown_panel.test.tsx.snap b/public/components/trace_analytics/components/traces/__tests__/__snapshots__/service_breakdown_panel.test.tsx.snap index db4ecbdadf..9024b9fa83 100644 --- a/public/components/trace_analytics/components/traces/__tests__/__snapshots__/service_breakdown_panel.test.tsx.snap +++ b/public/components/trace_analytics/components/traces/__tests__/__snapshots__/service_breakdown_panel.test.tsx.snap @@ -318,7 +318,7 @@ exports[`Service breakdown panel component renders service breakdown panel 1`] = color="#7492e7" type="dot" > - - + > + + +
    diff --git a/public/components/trace_analytics/components/traces/__tests__/__snapshots__/span_detail_flyout.test.tsx.snap b/public/components/trace_analytics/components/traces/__tests__/__snapshots__/span_detail_flyout.test.tsx.snap index e4eb22e85d..4f5a9b424e 100644 --- a/public/components/trace_analytics/components/traces/__tests__/__snapshots__/span_detail_flyout.test.tsx.snap +++ b/public/components/trace_analytics/components/traces/__tests__/__snapshots__/span_detail_flyout.test.tsx.snap @@ -60,7 +60,11 @@ exports[` spec renders the empty component 1`] = ` viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - /> + > + +
    spec renders the empty component 1`] = ` viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - /> + > + +
    spec renders the empty component 1`] = ` viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - /> + > + +
    spec renders the empty component 1`] = ` viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - /> + > + +
    spec renders the empty component 1`] = ` viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - /> + > + +
    spec renders the empty component 1`] = ` size="m" type="cross" > - spec renders the empty component 1`] = ` viewBox="0 0 16 16" width={16} xmlns="http://www.w3.org/2000/svg" - /> - + > + + + diff --git a/public/components/trace_analytics/components/traces/__tests__/__snapshots__/traces.test.tsx.snap b/public/components/trace_analytics/components/traces/__tests__/__snapshots__/traces.test.tsx.snap index 1be451ac0a..eb5619545b 100644 --- a/public/components/trace_analytics/components/traces/__tests__/__snapshots__/traces.test.tsx.snap +++ b/public/components/trace_analytics/components/traces/__tests__/__snapshots__/traces.test.tsx.snap @@ -281,7 +281,7 @@ exports[`Traces component renders empty traces page 1`] = ` size="m" type="arrowDown" > - - + > + + + - - + > + + + @@ -920,7 +928,7 @@ exports[`Traces component renders empty traces page 1`] = ` size="s" type="arrowDown" > - - + > + + + - - + > + + + @@ -1074,7 +1090,7 @@ exports[`Traces component renders empty traces page 1`] = ` size="m" type="refresh" > - - + > + + + - - + > + + + diff --git a/public/components/trace_analytics/components/traces/__tests__/__snapshots__/traces_table.test.tsx.snap b/public/components/trace_analytics/components/traces/__tests__/__snapshots__/traces_table.test.tsx.snap index 43f7391229..0662d5db1e 100644 --- a/public/components/trace_analytics/components/traces/__tests__/__snapshots__/traces_table.test.tsx.snap +++ b/public/components/trace_analytics/components/traces/__tests__/__snapshots__/traces_table.test.tsx.snap @@ -187,7 +187,7 @@ exports[`Traces table component renders empty traces table message 1`] = ` size="m" type="popout" > - - + > + + + - - + > + + + - - + > + + + @@ -2719,7 +2731,7 @@ exports[`Traces table component renders traces table 1`] = ` size="m" type="copyClipboard" > - - + > + + + @@ -3079,7 +3095,7 @@ exports[`Traces table component renders traces table 1`] = ` size="s" type="arrowDown" > - - + > + + + - - + > + + + @@ -3318,7 +3342,7 @@ exports[`Traces table component renders traces table 1`] = ` size="m" type="arrowRight" > - - + > + + + diff --git a/public/components/visualizations/charts/__tests__/__snapshots__/gauge.test.tsx.snap b/public/components/visualizations/charts/__tests__/__snapshots__/gauge.test.tsx.snap index 10c63f396a..6c6d9253e7 100644 --- a/public/components/visualizations/charts/__tests__/__snapshots__/gauge.test.tsx.snap +++ b/public/components/visualizations/charts/__tests__/__snapshots__/gauge.test.tsx.snap @@ -567,7 +567,7 @@ exports[`Gauge component Renders gauge component 1`] = ` size="xxl" type="visGauge" > - - + > + + + - - + > + + +

    Text From 859cbd7bc6189a438f971f4a4b2daf1ba315e798 Mon Sep 17 00:00:00 2001 From: Simeon Widdis Date: Thu, 11 Jan 2024 09:55:24 -0800 Subject: [PATCH 30/36] Revert "Update snapshots" This reverts commit 62b238d920d8f695f86b7bbadb10a0a5704774e6. Signed-off-by: Simeon Widdis --- .../__snapshots__/create.test.tsx.snap | 78 +- .../__snapshots__/log_config.test.tsx.snap | 10 +- .../service_config.test.tsx.snap | 30 +- .../__snapshots__/trace_config.test.tsx.snap | 20 +- .../live_tail_button.test.tsx.snap | 10 +- .../__snapshots__/search.test.tsx.snap | 50 +- .../custom_panel_table.test.tsx.snap | 20 +- .../custom_panel_view.test.tsx.snap | 70 +- .../__snapshots__/empty_panel.test.tsx.snap | 10 +- .../visualization_container.test.tsx.snap | 10 +- .../visualization_flyout.test.tsx.snap | 40 +- .../connection_details.test.tsx.snap | 10 +- .../data_connection.test.tsx.snap | 36 +- ...data_connections_description.test.tsx.snap | 10 +- ...anage_data_connections_table.test.tsx.snap | 108 +- .../__snapshots__/no_access.test.tsx.snap | 10 +- .../__snapshots__/no_results.test.tsx.snap | 10 +- .../__snapshots__/flyout_button.test.tsx.snap | 10 +- .../json_code_block.test.tsx.snap | 10 +- .../patterns_header.test.tsx.snap | 26 +- .../patterns_table.test.tsx.snap | 50 +- .../__snapshots__/save_panel.test.tsx.snap | 20 +- .../__snapshots__/field.test.tsx.snap | 43 +- .../__snapshots__/sidebar.test.tsx.snap | 978 +++++------------- .../timechart_header.test.tsx.snap | 10 +- .../__snapshots__/config_panel.test.tsx.snap | 120 +-- .../saved_query_table.test.tsx.snap | 70 +- .../added_integration.test.tsx.snap | 40 +- .../added_integration_flyout.test.tsx.snap | 80 +- .../added_integration_table.test.tsx.snap | 60 +- ...ilable_integration_card_view.test.tsx.snap | 30 +- ...lable_integration_table_view.test.tsx.snap | 60 +- .../integration_details.test.tsx.snap | 10 +- .../integration_fields.test.tsx.snap | 10 +- .../integration_header.test.tsx.snap | 10 +- .../setup_integration.test.tsx.snap | 62 +- .../__snapshots__/searchbar.test.tsx.snap | 10 +- .../__snapshots__/sidebar.test.tsx.snap | 30 +- .../metrics_export.test.tsx.snap | 10 +- .../metrics_export_panel.test.tsx.snap | 10 +- .../__snapshots__/top_menu.test.tsx.snap | 50 +- .../__snapshots__/empty_view.test.tsx.snap | 10 +- .../__snapshots__/note_table.test.tsx.snap | 36 +- .../__snapshots__/notebook.test.tsx.snap | 24 +- .../__snapshots__/para_input.test.tsx.snap | 30 +- .../__snapshots__/paragraphs.test.tsx.snap | 48 +- .../__snapshots__/search_bar.test.tsx.snap | 50 +- .../filter_edit_popover.test.tsx.snap | 20 +- .../__snapshots__/filters.test.tsx.snap | 10 +- .../__snapshots__/dashboard.test.tsx.snap | 10 +- .../dashboard_table.test.tsx.snap | 170 +-- .../latency_trend_cell.test.tsx.snap | 10 +- .../__snapshots__/mode_picker.test.tsx.snap | 36 +- .../top_error_rates_table.test.tsx.snap | 120 +-- .../top_latency_table.test.tsx.snap | 150 +-- .../__snapshots__/services.test.tsx.snap | 80 +- .../services_table.test.tsx.snap | 50 +- .../service_breakdown_panel.test.tsx.snap | 10 +- .../span_detail_flyout.test.tsx.snap | 40 +- .../__snapshots__/traces.test.tsx.snap | 60 +- .../__snapshots__/traces_table.test.tsx.snap | 70 +- .../__snapshots__/gauge.test.tsx.snap | 10 +- .../__snapshots__/metrics.test.tsx.snap | 10 +- .../__snapshots__/text.test.tsx.snap | 1 - 64 files changed, 927 insertions(+), 2469 deletions(-) diff --git a/public/components/application_analytics/__tests__/__snapshots__/create.test.tsx.snap b/public/components/application_analytics/__tests__/__snapshots__/create.test.tsx.snap index e7c2dbdedf..375a076cd0 100644 --- a/public/components/application_analytics/__tests__/__snapshots__/create.test.tsx.snap +++ b/public/components/application_analytics/__tests__/__snapshots__/create.test.tsx.snap @@ -7417,11 +7417,7 @@ Object { viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - > - - + /> - - + /> - - + />

    @@ -7922,11 +7910,7 @@ Object { viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - > - - + />
    @@ -8007,11 +7991,7 @@ Object { viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - > - - + /> - - + />
    @@ -8546,11 +8522,7 @@ Object { viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - > - - + />
    - - + /> - - + /> @@ -9051,11 +9015,7 @@ Object { viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - > - - + /> @@ -9136,11 +9096,7 @@ Object { viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - > - - + />
    - - + /> @@ -17850,11 +17802,7 @@ Object { viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - > - - + />
    - - - - + /> + - - - - + /> + - - - - + /> + @@ -1052,7 +1044,7 @@ exports[`Service Config component renders empty service config 1`] = ` size="m" type="search" > - - - - + /> + diff --git a/public/components/application_analytics/__tests__/__snapshots__/trace_config.test.tsx.snap b/public/components/application_analytics/__tests__/__snapshots__/trace_config.test.tsx.snap index 8b70a1a6a6..ca51495382 100644 --- a/public/components/application_analytics/__tests__/__snapshots__/trace_config.test.tsx.snap +++ b/public/components/application_analytics/__tests__/__snapshots__/trace_config.test.tsx.snap @@ -231,7 +231,7 @@ exports[`Trace Config component renders empty trace config 1`] = ` size="m" type="arrowRight" > - - - - + /> + - - - - + /> + diff --git a/public/components/common/live_tail/__tests__/__snapshots__/live_tail_button.test.tsx.snap b/public/components/common/live_tail/__tests__/__snapshots__/live_tail_button.test.tsx.snap index d16f1b4662..3e8c7b716a 100644 --- a/public/components/common/live_tail/__tests__/__snapshots__/live_tail_button.test.tsx.snap +++ b/public/components/common/live_tail/__tests__/__snapshots__/live_tail_button.test.tsx.snap @@ -150,7 +150,7 @@ exports[`Live tail button starts live tail with 5s interval 1`] = ` size="m" type="stop" > - - - - + /> + - - - - + /> + - - - - + /> + - - - - + /> + @@ -758,7 +746,7 @@ exports[`Explorer Search component renders basic component 1`] = ` size="m" type="refresh" > - - - - + /> + - - - - + /> + - - - - + /> + @@ -298,7 +294,7 @@ exports[`Panels Table Component renders empty panel table container 1`] = ` size="m" type="arrowDown" > - - - - + /> + - - - - + /> + - - - - + /> + - - - - + /> + - - - - + /> + - - - - + /> + @@ -3759,7 +3739,7 @@ exports[`Panels View Component renders panel view container without visualizatio size="m" type="refresh" > - - - - + /> + - - - - + /> + - - - - + /> + - - - - + /> +
    diff --git a/public/components/custom_panels/panel_modules/visualization_flyout/__tests__/__snapshots__/visualization_flyout.test.tsx.snap b/public/components/custom_panels/panel_modules/visualization_flyout/__tests__/__snapshots__/visualization_flyout.test.tsx.snap index c20ca8ae6a..0e37e1e4a2 100644 --- a/public/components/custom_panels/panel_modules/visualization_flyout/__tests__/__snapshots__/visualization_flyout.test.tsx.snap +++ b/public/components/custom_panels/panel_modules/visualization_flyout/__tests__/__snapshots__/visualization_flyout.test.tsx.snap @@ -133,11 +133,7 @@ exports[`Visualization Flyout Component renders add visualization Flyout 1`] = ` viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - > - - + />
    - - + />
    - - + />
    - - + />
    - - + />
    - - - - + /> + diff --git a/public/components/datasources/components/__tests__/__snapshots__/connection_details.test.tsx.snap b/public/components/datasources/components/__tests__/__snapshots__/connection_details.test.tsx.snap index 5b35615a54..6fb23b7abb 100644 --- a/public/components/datasources/components/__tests__/__snapshots__/connection_details.test.tsx.snap +++ b/public/components/datasources/components/__tests__/__snapshots__/connection_details.test.tsx.snap @@ -298,7 +298,7 @@ exports[`Connection Details test Renders connection details for s3 datasource 1` size="m" type="iInCircle" > - - - - + /> + - - + /> - - + />
    - - + /> @@ -615,11 +603,7 @@ exports[`Data Connection Page test Renders S3 data connection page with data 1`] viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - > - - + />
    - - + />
    - - + />
    - - - - + /> + - - + />
    @@ -154,11 +150,7 @@ exports[`Manage Data Connections Table test Renders manage data connections tabl viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - > - - + /> @@ -207,11 +199,7 @@ exports[`Manage Data Connections Table test Renders manage data connections tabl viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - > - - + />
    @@ -341,11 +329,7 @@ exports[`Manage Data Connections Table test Renders manage data connections tabl viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - > - - + /> - - + /> - - + />
    @@ -477,11 +453,7 @@ exports[`Manage Data Connections Table test Renders manage data connections tabl viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - > - - + /> - - + /> - - + /> @@ -613,11 +577,7 @@ exports[`Manage Data Connections Table test Renders manage data connections tabl viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - > - - + /> - - + /> - - + /> @@ -749,11 +701,7 @@ exports[`Manage Data Connections Table test Renders manage data connections tabl viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - > - - + /> - - + /> - - + /> @@ -865,11 +805,7 @@ exports[`Manage Data Connections Table test Renders manage data connections tabl viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - > - - + /> @@ -904,11 +840,7 @@ exports[`Manage Data Connections Table test Renders manage data connections tabl viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - > - - + />
      - - + /> diff --git a/public/components/datasources/components/__tests__/__snapshots__/no_access.test.tsx.snap b/public/components/datasources/components/__tests__/__snapshots__/no_access.test.tsx.snap index 5fd77b87ba..a4b27f4544 100644 --- a/public/components/datasources/components/__tests__/__snapshots__/no_access.test.tsx.snap +++ b/public/components/datasources/components/__tests__/__snapshots__/no_access.test.tsx.snap @@ -36,7 +36,7 @@ exports[`No access test Renders no access view of data source 1`] = ` size="xxl" type="alert" > - - - - + /> + - - - - + /> + - - - - + /> + diff --git a/public/components/event_analytics/explorer/events_views/json_code_block/__tests__/__snapshots__/json_code_block.test.tsx.snap b/public/components/event_analytics/explorer/events_views/json_code_block/__tests__/__snapshots__/json_code_block.test.tsx.snap index e45c3c4272..b318643346 100644 --- a/public/components/event_analytics/explorer/events_views/json_code_block/__tests__/__snapshots__/json_code_block.test.tsx.snap +++ b/public/components/event_analytics/explorer/events_views/json_code_block/__tests__/__snapshots__/json_code_block.test.tsx.snap @@ -173,7 +173,7 @@ exports[`Doc viewer JSON block component Renders JSON block component 1`] = ` size="m" type="copy" > - - - - + /> + diff --git a/public/components/event_analytics/explorer/log_patterns/__tests__/__snapshots__/patterns_header.test.tsx.snap b/public/components/event_analytics/explorer/log_patterns/__tests__/__snapshots__/patterns_header.test.tsx.snap index 681b600aed..8777405139 100644 --- a/public/components/event_analytics/explorer/log_patterns/__tests__/__snapshots__/patterns_header.test.tsx.snap +++ b/public/components/event_analytics/explorer/log_patterns/__tests__/__snapshots__/patterns_header.test.tsx.snap @@ -101,7 +101,7 @@ exports[`Patterns header component Renders header of log patterns 1`] = ` size="m" type="gear" > - - - - + /> + @@ -227,11 +223,7 @@ exports[`Patterns header component Renders header of log patterns 1`] = ` viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - > - - + /> @@ -595,7 +587,7 @@ exports[`Patterns header component Renders header of log patterns 1`] = ` size="s" type="popout" > - - - - + /> + - - - - + /> + - - - - + /> + @@ -1019,7 +1011,7 @@ exports[`Pattern table component Renders pattern table 1`] = ` size="s" type="arrowDown" > - - - - + /> + - - - - + /> + @@ -1266,7 +1250,7 @@ exports[`Pattern table component Renders pattern table 1`] = ` size="m" type="arrowRight" > - - - - + /> + diff --git a/public/components/event_analytics/explorer/save_panel/__tests__/__snapshots__/save_panel.test.tsx.snap b/public/components/event_analytics/explorer/save_panel/__tests__/__snapshots__/save_panel.test.tsx.snap index b94a45bd65..f6f024c453 100644 --- a/public/components/event_analytics/explorer/save_panel/__tests__/__snapshots__/save_panel.test.tsx.snap +++ b/public/components/event_analytics/explorer/save_panel/__tests__/__snapshots__/save_panel.test.tsx.snap @@ -390,7 +390,7 @@ exports[`Saved query table component Renders saved query table 1`] = ` className="euiFormControlLayoutClearButton__icon" type="cross" > - - - - + /> + @@ -438,7 +434,7 @@ exports[`Saved query table component Renders saved query table 1`] = ` size="m" type="arrowDown" > - - - - + /> + diff --git a/public/components/event_analytics/explorer/sidebar/__tests__/__snapshots__/field.test.tsx.snap b/public/components/event_analytics/explorer/sidebar/__tests__/__snapshots__/field.test.tsx.snap index 0c780860f0..acf3d81679 100644 --- a/public/components/event_analytics/explorer/sidebar/__tests__/__snapshots__/field.test.tsx.snap +++ b/public/components/event_analytics/explorer/sidebar/__tests__/__snapshots__/field.test.tsx.snap @@ -64,7 +64,7 @@ exports[`Field component Renders a sidebar field 1`] = ` title="string" type="tokenString" > - - - string - - - - + /> + @@ -159,7 +152,7 @@ exports[`Field component Renders a sidebar field 1`] = ` size="m" type="inputOutput" > - - - - + /> + @@ -271,7 +260,7 @@ exports[`Field component Renders a sidebar field 1`] = ` size="m" type="inspect" > - - - - + /> + @@ -344,7 +329,7 @@ exports[`Field component Renders a sidebar field 1`] = ` size="m" type="cross" > - - - - + /> + diff --git a/public/components/event_analytics/explorer/sidebar/__tests__/__snapshots__/sidebar.test.tsx.snap b/public/components/event_analytics/explorer/sidebar/__tests__/__snapshots__/sidebar.test.tsx.snap index 59d4966c25..102994f08e 100644 --- a/public/components/event_analytics/explorer/sidebar/__tests__/__snapshots__/sidebar.test.tsx.snap +++ b/public/components/event_analytics/explorer/sidebar/__tests__/__snapshots__/sidebar.test.tsx.snap @@ -253,7 +253,7 @@ exports[`Siderbar component Renders empty sidebar component 1`] = ` size="s" type="search" > - - - - + /> + @@ -1194,7 +1190,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` title="long" type="tokenString" > - - - long - - - - + /> + @@ -1341,7 +1330,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="inspect" > - - - - + /> + @@ -1413,7 +1398,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="cross" > - - - - + /> + @@ -1596,7 +1577,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` title="text" type="tokenString" > - - - text - - - - + /> + @@ -1743,7 +1717,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="inspect" > - - - - + /> + @@ -1815,7 +1785,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="cross" > - - - - + /> + @@ -1998,7 +1964,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` title="integer" type="tokenString" > - - - integer - - - - + /> + @@ -2145,7 +2104,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="inspect" > - - - - + /> + @@ -2217,7 +2172,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="cross" > - - - - + /> + @@ -2400,7 +2351,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` title="long" type="tokenString" > - - - long - - - - + /> + @@ -2547,7 +2491,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="inspect" > - - - - + /> + @@ -2619,7 +2559,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="cross" > - - - - + /> + @@ -2802,7 +2738,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` title="text" type="tokenString" > - - - text - - - - + /> + @@ -2949,7 +2878,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="inspect" > - - - - + /> + @@ -3021,7 +2946,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="cross" > - - - - + /> + @@ -3204,7 +3125,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` title="long" type="tokenString" > - - - long - - - - + /> + @@ -3351,7 +3265,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="inspect" > - - - - + /> + @@ -3423,7 +3333,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="cross" > - - - - + /> + @@ -3764,7 +3670,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` title="string" type="tokenString" > - - - string - - - - + /> + @@ -3859,7 +3758,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="inputOutput" > - - - - + /> + @@ -3971,7 +3866,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="inspect" > - - - - + /> + @@ -4044,7 +3935,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="plusInCircleFilled" > - - - - + /> + @@ -4227,7 +4114,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` title="long" type="tokenString" > - - - long - - - - + /> + @@ -4374,7 +4254,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="inspect" > - - - - + /> + @@ -4447,7 +4323,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="plusInCircleFilled" > - - - - + /> + @@ -4630,7 +4502,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` title="ip" type="tokenIP" > - - - ip - - - - + /> + @@ -4777,7 +4642,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="inspect" > - - - - + /> + @@ -4850,7 +4711,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="plusInCircleFilled" > - - - - + /> + @@ -5033,7 +4890,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` title="struct" type="tokenString" > - - - struct - - - - + /> + @@ -5180,7 +5030,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="inspect" > - - - - + /> + @@ -5253,7 +5099,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="plusInCircleFilled" > - - - - + /> + @@ -5436,7 +5278,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` title="string" type="tokenString" > - - - string - - - - + /> + @@ -5531,7 +5366,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="inputOutput" > - - - - + /> + @@ -5643,7 +5474,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="inspect" > - - - - + /> + @@ -5716,7 +5543,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="plusInCircleFilled" > - - - - + /> + @@ -5899,7 +5722,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` title="struct" type="tokenString" > - - - struct - - - - + /> + @@ -6046,7 +5862,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="inspect" > - - - - + /> + @@ -6119,7 +5931,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="plusInCircleFilled" > - - - - + /> + @@ -6302,7 +6110,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` title="string" type="tokenString" > - - - string - - - - + /> + @@ -6397,7 +6198,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="inputOutput" > - - - - + /> + @@ -6509,7 +6306,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="inspect" > - - - - + /> + @@ -6582,7 +6375,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="plusInCircleFilled" > - - - - + /> + @@ -6765,7 +6554,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` title="string" type="tokenString" > - - - string - - - - + /> + @@ -6860,7 +6642,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="inputOutput" > - - - - + /> + @@ -6972,7 +6750,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="inspect" > - - - - + /> + @@ -7045,7 +6819,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="plusInCircleFilled" > - - - - + /> + @@ -7228,7 +6998,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` title="ip" type="tokenIP" > - - - ip - - - - + /> + @@ -7375,7 +7138,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="inspect" > - - - - + /> + @@ -7448,7 +7207,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="plusInCircleFilled" > - - - - + /> + @@ -7631,7 +7386,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` title="struct" type="tokenString" > - - - struct - - - - + /> + @@ -7778,7 +7526,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="inspect" > - - - - + /> + @@ -7851,7 +7595,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="plusInCircleFilled" > - - - - + /> + @@ -8034,7 +7774,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` title="double" type="tokenString" > - - - double - - - - + /> + @@ -8181,7 +7914,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="inspect" > - - - - + /> + @@ -8254,7 +7983,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="plusInCircleFilled" > - - - - + /> + @@ -8437,7 +8162,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` title="string" type="tokenString" > - - - string - - - - + /> + @@ -8532,7 +8250,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="inputOutput" > - - - - + /> + @@ -8644,7 +8358,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="inspect" > - - - - + /> + @@ -8717,7 +8427,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="plusInCircleFilled" > - - - - + /> + @@ -8900,7 +8606,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` title="long" type="tokenString" > - - - long - - - - + /> + @@ -9047,7 +8746,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="inspect" > - - - - + /> + @@ -9120,7 +8815,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="plusInCircleFilled" > - - - - + /> + @@ -9303,7 +8994,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` title="string" type="tokenString" > - - - string - - - - + /> + @@ -9398,7 +9082,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="inputOutput" > - - - - + /> + @@ -9510,7 +9190,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="inspect" > - - - - + /> + @@ -9583,7 +9259,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="plusInCircleFilled" > - - - - + /> + @@ -9766,7 +9438,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` title="string" type="tokenString" > - - - string - - - - + /> + @@ -9861,7 +9526,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="inputOutput" > - - - - + /> + @@ -9973,7 +9634,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="inspect" > - - - - + /> + @@ -10046,7 +9703,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="plusInCircleFilled" > - - - - + /> + @@ -10229,7 +9882,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` title="string" type="tokenString" > - - - string - - - - + /> + @@ -10324,7 +9970,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="inputOutput" > - - - - + /> + @@ -10436,7 +10078,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="inspect" > - - - - + /> + @@ -10509,7 +10147,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="plusInCircleFilled" > - - - - + /> + @@ -10692,7 +10326,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` title="string" type="tokenString" > - - - string - - - - + /> + @@ -10787,7 +10414,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="inputOutput" > - - - - + /> + @@ -10899,7 +10522,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="inspect" > - - - - + /> + @@ -10972,7 +10591,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="plusInCircleFilled" > - - - - + /> + @@ -11155,7 +10770,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` title="date" type="tokenDate" > - - - date - - - - + /> + @@ -11343,7 +10951,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="inspect" > - - - - + /> + @@ -11416,7 +11020,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="plusInCircleFilled" > - - - - + /> + @@ -11599,7 +11199,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` title="string" type="tokenString" > - - - string - - - - + /> + @@ -11694,7 +11287,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="inputOutput" > - - - - + /> + @@ -11806,7 +11395,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="inspect" > - - - - + /> + @@ -11879,7 +11464,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="plusInCircleFilled" > - - - - + /> + @@ -12062,7 +11643,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` title="date" type="tokenDate" > - - - date - - - - + /> + @@ -12170,7 +11744,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="inputOutput" > - - - - + /> + @@ -12269,7 +11839,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="inspect" > - - - - + /> + @@ -12342,7 +11908,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` size="m" type="plusInCircleFilled" > - - - - + /> + diff --git a/public/components/event_analytics/explorer/timechart_header/__tests__/__snapshots__/timechart_header.test.tsx.snap b/public/components/event_analytics/explorer/timechart_header/__tests__/__snapshots__/timechart_header.test.tsx.snap index 92c7549d7f..de94c5f728 100644 --- a/public/components/event_analytics/explorer/timechart_header/__tests__/__snapshots__/timechart_header.test.tsx.snap +++ b/public/components/event_analytics/explorer/timechart_header/__tests__/__snapshots__/timechart_header.test.tsx.snap @@ -300,7 +300,7 @@ exports[`Time chart header component Renders Time chart header component 1`] = ` size="s" type="arrowDown" > - - - - + /> + diff --git a/public/components/event_analytics/explorer/visualizations/config_panel/__tests__/__snapshots__/config_panel.test.tsx.snap b/public/components/event_analytics/explorer/visualizations/config_panel/__tests__/__snapshots__/config_panel.test.tsx.snap index 951ef271ea..a223888b9b 100644 --- a/public/components/event_analytics/explorer/visualizations/config_panel/__tests__/__snapshots__/config_panel.test.tsx.snap +++ b/public/components/event_analytics/explorer/visualizations/config_panel/__tests__/__snapshots__/config_panel.test.tsx.snap @@ -4312,7 +4312,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] size="s" type="visBarVerticalStacked" > - - - - + /> + @@ -4437,7 +4433,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] size="m" type="arrowDown" > - - - - + /> + @@ -8062,7 +8054,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] size="m" type="arrowRight" > - - - - + /> + - - - - + /> + - - - - + /> + - - - - + /> + - - - - + /> + @@ -13458,7 +13430,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] size="m" type="iInCircle" > - - - - + /> + @@ -13703,7 +13671,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] size="m" type="iInCircle" > - - - - + /> + @@ -13948,7 +13912,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] size="m" type="iInCircle" > - - - - + /> + @@ -14193,7 +14153,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] size="m" type="iInCircle" > - - - - + /> + @@ -15119,7 +15075,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] size="m" type="arrowRight" > - - - - + /> + - - - - + /> + @@ -511,7 +507,7 @@ exports[`Saved query table component Renders saved query table 1`] = ` size="m" type="arrowDown" > - - - - + /> + - - - - + /> + @@ -1237,7 +1225,7 @@ exports[`Saved query table component Renders saved query table 1`] = ` size="m" type="visBarVerticalStacked" > - - - - + /> + @@ -1480,7 +1464,7 @@ exports[`Saved query table component Renders saved query table 1`] = ` size="s" type="arrowDown" > - - - - + /> + - - - - + /> + @@ -1727,7 +1703,7 @@ exports[`Saved query table component Renders saved query table 1`] = ` size="m" type="arrowRight" > - - - - + /> + diff --git a/public/components/integrations/components/__tests__/__snapshots__/added_integration.test.tsx.snap b/public/components/integrations/components/__tests__/__snapshots__/added_integration.test.tsx.snap index 4f499e10ed..7ef7eb7859 100644 --- a/public/components/integrations/components/__tests__/__snapshots__/added_integration.test.tsx.snap +++ b/public/components/integrations/components/__tests__/__snapshots__/added_integration.test.tsx.snap @@ -176,7 +176,7 @@ exports[`Added Integration View Test Renders added integration view using dummy color="danger" type="dot" > - - - - + /> + @@ -247,7 +243,7 @@ exports[`Added Integration View Test Renders added integration view using dummy size="m" type="trash" > - - - - + /> + @@ -580,7 +572,7 @@ exports[`Added Integration View Test Renders added integration view using dummy size="m" type="search" > - - - - + /> + @@ -808,7 +796,7 @@ exports[`Added Integration View Test Renders added integration view using dummy size="m" type="arrowDown" > - - - - + /> + - - + />
      - - + /> @@ -397,11 +389,7 @@ exports[`Add Integration Flyout Test Renders add integration flyout with dummy i viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - > - - + />
      - - + /> @@ -664,11 +648,7 @@ exports[`Add Integration Flyout Test Renders add integration flyout with dummy i viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - > - - + />
      - - + /> @@ -931,11 +907,7 @@ exports[`Add Integration Flyout Test Renders add integration flyout with dummy i viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - > - - + />
      - - + /> @@ -1186,11 +1154,7 @@ exports[`Add Integration Flyout Test Renders add integration flyout with dummy i viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - > - - + />
      - - + /> @@ -1477,7 +1437,7 @@ exports[`Add Integration Flyout Test Renders add integration flyout with dummy i size="m" type="cross" > - - - - + /> + @@ -1613,7 +1569,7 @@ exports[`Add Integration Flyout Test Renders add integration flyout with dummy i size="s" type="popout" > - - - - + /> + - - - - + /> + @@ -491,7 +487,7 @@ exports[`Added Integration Table View Test Renders added integration table view size="m" type="arrowDown" > - - - - + /> + - - - - + /> +
      @@ -1203,7 +1191,7 @@ exports[`Added Integration Table View Test Renders added integration table view size="s" type="arrowDown" > - - - - + /> + - - - - + /> + @@ -1450,7 +1430,7 @@ exports[`Added Integration Table View Test Renders added integration table view size="m" type="arrowRight" > - - - - + /> + diff --git a/public/components/integrations/components/__tests__/__snapshots__/available_integration_card_view.test.tsx.snap b/public/components/integrations/components/__tests__/__snapshots__/available_integration_card_view.test.tsx.snap index 6f47d925a0..9f6372b915 100644 --- a/public/components/integrations/components/__tests__/__snapshots__/available_integration_card_view.test.tsx.snap +++ b/public/components/integrations/components/__tests__/__snapshots__/available_integration_card_view.test.tsx.snap @@ -125,7 +125,7 @@ exports[`Available Integration Card View Test Renders nginx integration card vie size="m" type="search" > - - - - + /> + @@ -273,7 +269,7 @@ exports[`Available Integration Card View Test Renders nginx integration card vie size="m" type="list" > - - - - + /> + - - - - + /> + - - - - + /> + @@ -475,7 +471,7 @@ exports[`Available Integration Table View Test Renders nginx integration table v size="m" type="list" > - - - - + /> + - - - - + /> + - - - - + /> + - - - - + /> + @@ -1466,7 +1446,7 @@ exports[`Available Integration Table View Test Renders nginx integration table v size="m" type="arrowRight" > - - - - + /> + diff --git a/public/components/integrations/components/__tests__/__snapshots__/integration_details.test.tsx.snap b/public/components/integrations/components/__tests__/__snapshots__/integration_details.test.tsx.snap index 18d1867951..5274b335b7 100644 --- a/public/components/integrations/components/__tests__/__snapshots__/integration_details.test.tsx.snap +++ b/public/components/integrations/components/__tests__/__snapshots__/integration_details.test.tsx.snap @@ -120,7 +120,7 @@ exports[`Available Integration Table View Test Renders nginx integration table v size="s" type="popout" > - - - - + /> + diff --git a/public/components/integrations/components/__tests__/__snapshots__/integration_fields.test.tsx.snap b/public/components/integrations/components/__tests__/__snapshots__/integration_fields.test.tsx.snap index 9617512f0f..77fb9d7a07 100644 --- a/public/components/integrations/components/__tests__/__snapshots__/integration_fields.test.tsx.snap +++ b/public/components/integrations/components/__tests__/__snapshots__/integration_fields.test.tsx.snap @@ -160,7 +160,7 @@ exports[`Available Integration Table View Test Renders nginx integration table v size="m" type="search" > - - - - + /> + diff --git a/public/components/integrations/components/__tests__/__snapshots__/integration_header.test.tsx.snap b/public/components/integrations/components/__tests__/__snapshots__/integration_header.test.tsx.snap index 41591c2408..9aa43c4964 100644 --- a/public/components/integrations/components/__tests__/__snapshots__/integration_header.test.tsx.snap +++ b/public/components/integrations/components/__tests__/__snapshots__/integration_header.test.tsx.snap @@ -67,7 +67,7 @@ exports[`Integration Header Test Renders integration header as expected 1`] = ` size="s" type="popout" > - - - - + /> + diff --git a/public/components/integrations/components/__tests__/__snapshots__/setup_integration.test.tsx.snap b/public/components/integrations/components/__tests__/__snapshots__/setup_integration.test.tsx.snap index 8f555a0d9b..ac06da656e 100644 --- a/public/components/integrations/components/__tests__/__snapshots__/setup_integration.test.tsx.snap +++ b/public/components/integrations/components/__tests__/__snapshots__/setup_integration.test.tsx.snap @@ -288,7 +288,7 @@ exports[`Integration Setup Page Renders integration setup page as expected 1`] = size="m" type="arrowDown" > - - - - + /> + @@ -594,7 +590,7 @@ exports[`Integration Setup Page Renders integration setup page as expected 1`] = className="euiFormControlLayoutClearButton__icon" type="cross" > - - - - + /> + @@ -649,7 +641,7 @@ exports[`Integration Setup Page Renders integration setup page as expected 1`] = size="m" type="arrowDown" > - - - - + /> + @@ -763,11 +751,7 @@ exports[`Integration Setup Page Renders integration setup page as expected 1`] = viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - > - - + /> @@ -797,11 +781,7 @@ exports[`Integration Setup Page Renders integration setup page as expected 1`] = viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - > - - + /> @@ -888,7 +868,7 @@ exports[`Integration Setup Page Renders integration setup page as expected 1`] = size="m" type="cross" > - - - - + /> + - - - - + /> + - - - - + /> + diff --git a/public/components/metrics/sidebar/__tests__/__snapshots__/sidebar.test.tsx.snap b/public/components/metrics/sidebar/__tests__/__snapshots__/sidebar.test.tsx.snap index a22e4729ce..898fc9dfd0 100644 --- a/public/components/metrics/sidebar/__tests__/__snapshots__/sidebar.test.tsx.snap +++ b/public/components/metrics/sidebar/__tests__/__snapshots__/sidebar.test.tsx.snap @@ -198,7 +198,7 @@ exports[`Side Bar Component renders Side Bar Component 1`] = ` size="m" type="search" > - - - - + /> + @@ -297,7 +293,7 @@ exports[`Side Bar Component renders Side Bar Component 1`] = ` size="m" type="arrowRight" > - - - - + /> + - - - - + /> + - - - - + /> + - - - - + /> + diff --git a/public/components/metrics/top_menu/__tests__/__snapshots__/top_menu.test.tsx.snap b/public/components/metrics/top_menu/__tests__/__snapshots__/top_menu.test.tsx.snap index 9c64eae1cd..cb3497bdcf 100644 --- a/public/components/metrics/top_menu/__tests__/__snapshots__/top_menu.test.tsx.snap +++ b/public/components/metrics/top_menu/__tests__/__snapshots__/top_menu.test.tsx.snap @@ -253,7 +253,7 @@ exports[`Metrics Top Menu Component renders Top Menu Component when enabled 1`] size="m" type="arrowDown" > - - - - + /> + @@ -567,7 +563,7 @@ exports[`Metrics Top Menu Component renders Top Menu Component when enabled 1`] size="s" type="arrowDown" > - - - - + /> + - - - - + /> + @@ -765,7 +753,7 @@ exports[`Metrics Top Menu Component renders Top Menu Component when enabled 1`] size="m" type="refresh" > - - - - + /> + - - - - + /> + - - - - + /> + spec renders the component 1`] = ` viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - > - - + />
      @@ -362,11 +358,7 @@ exports[` spec renders the component 1`] = ` viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - > - - + />
      @@ -849,11 +841,7 @@ exports[` spec renders the component 1`] = ` viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - > - - + />
        spec renders the component 1`] = ` viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - > - - + />
      @@ -989,11 +973,7 @@ exports[` spec renders the empty component 1`] = ` viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - > - - + />
      @@ -1029,11 +1009,7 @@ exports[` spec renders the empty component 1`] = ` viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - > - - + /> diff --git a/public/components/notebooks/components/__tests__/__snapshots__/notebook.test.tsx.snap b/public/components/notebooks/components/__tests__/__snapshots__/notebook.test.tsx.snap index a55b86bc52..b2bc5ba057 100644 --- a/public/components/notebooks/components/__tests__/__snapshots__/notebook.test.tsx.snap +++ b/public/components/notebooks/components/__tests__/__snapshots__/notebook.test.tsx.snap @@ -48,11 +48,7 @@ exports[` spec Renders the empty component 1`] = ` viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - > - - + /> @@ -133,11 +129,7 @@ exports[` spec Renders the empty component 1`] = ` viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - > - - + /> @@ -232,11 +224,7 @@ exports[` spec Renders the empty component 1`] = ` viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - > - - + />
      spec Renders the empty component 1`] = ` viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - > - - + />
      spec renders the markdown component 1`] = ` viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - > - - + />
      @@ -141,11 +137,7 @@ exports[` spec renders the visualization component 1`] = ` viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - > - - + /> @@ -250,11 +238,7 @@ exports[` spec renders the visualization component 1`] = ` viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - > - - + /> @@ -267,11 +251,7 @@ exports[` spec renders the visualization component 1`] = ` viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - > - - + />
      diff --git a/public/components/notebooks/components/paragraph_components/__tests__/__snapshots__/paragraphs.test.tsx.snap b/public/components/notebooks/components/paragraph_components/__tests__/__snapshots__/paragraphs.test.tsx.snap index df055e89ca..c28f96d28d 100644 --- a/public/components/notebooks/components/paragraph_components/__tests__/__snapshots__/paragraphs.test.tsx.snap +++ b/public/components/notebooks/components/paragraph_components/__tests__/__snapshots__/paragraphs.test.tsx.snap @@ -29,11 +29,7 @@ exports[` spec renders the component 1`] = ` viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - > - - + /> @@ -60,11 +56,7 @@ exports[` spec renders the component 1`] = ` viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - > - - + /> @@ -127,11 +119,7 @@ exports[` spec renders the component 1`] = ` viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - > - - + /> @@ -162,11 +150,7 @@ exports[` spec renders the component 1`] = ` viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - > - - + /> spec renders the component 1`] = ` viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - > - - + /> @@ -207,11 +187,7 @@ exports[` spec renders the component 1`] = ` viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - > - - + /> spec renders the component 1`] = ` viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - > - - + /> @@ -277,11 +249,7 @@ exports[` spec renders the component 1`] = ` viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - > - - + />
      - - - - + /> + - - - - + /> + @@ -459,7 +451,7 @@ exports[`Search bar components renders search bar 1`] = ` size="m" type="search" > - - - - + /> + @@ -943,7 +931,7 @@ exports[`Search bar components renders search bar 1`] = ` size="m" type="refresh" > - - - - + /> + - - - - + /> + diff --git a/public/components/trace_analytics/components/common/filters/__tests__/__snapshots__/filter_edit_popover.test.tsx.snap b/public/components/trace_analytics/components/common/filters/__tests__/__snapshots__/filter_edit_popover.test.tsx.snap index 8dc64c168d..7fde9a70a6 100644 --- a/public/components/trace_analytics/components/common/filters/__tests__/__snapshots__/filter_edit_popover.test.tsx.snap +++ b/public/components/trace_analytics/components/common/filters/__tests__/__snapshots__/filter_edit_popover.test.tsx.snap @@ -290,7 +290,7 @@ exports[`Filter popover component renders filter popover 1`] = ` size="m" type="arrowDown" > - - - - + /> + @@ -558,7 +554,7 @@ exports[`Filter popover component renders filter popover 1`] = ` size="m" type="arrowDown" > - - - - + /> + diff --git a/public/components/trace_analytics/components/common/filters/__tests__/__snapshots__/filters.test.tsx.snap b/public/components/trace_analytics/components/common/filters/__tests__/__snapshots__/filters.test.tsx.snap index e886fa6400..3d483d4dd2 100644 --- a/public/components/trace_analytics/components/common/filters/__tests__/__snapshots__/filters.test.tsx.snap +++ b/public/components/trace_analytics/components/common/filters/__tests__/__snapshots__/filters.test.tsx.snap @@ -80,7 +80,7 @@ exports[`Filter component renders filters 1`] = ` size="m" type="filter" > - - - - + /> + diff --git a/public/components/trace_analytics/components/dashboard/__tests__/__snapshots__/dashboard.test.tsx.snap b/public/components/trace_analytics/components/dashboard/__tests__/__snapshots__/dashboard.test.tsx.snap index 1fff402475..f828066af8 100644 --- a/public/components/trace_analytics/components/dashboard/__tests__/__snapshots__/dashboard.test.tsx.snap +++ b/public/components/trace_analytics/components/dashboard/__tests__/__snapshots__/dashboard.test.tsx.snap @@ -1405,7 +1405,7 @@ exports[`Dashboard component renders empty dashboard 1`] = ` size="m" type="arrowDown" > - - - - + /> + - - - - + /> + - - - - + /> +
      @@ -1249,7 +1241,7 @@ exports[`Dashboard table component renders dashboard table 1`] = ` size="s" type="questionInCircle" > - - - - + /> + @@ -1303,7 +1291,7 @@ exports[`Dashboard table component renders dashboard table 1`] = ` size="m" type="sortDown" > - - - - + /> + @@ -1407,7 +1391,7 @@ exports[`Dashboard table component renders dashboard table 1`] = ` size="s" type="questionInCircle" > - - - - + /> +
      @@ -1509,7 +1489,7 @@ exports[`Dashboard table component renders dashboard table 1`] = ` size="s" type="questionInCircle" > - - - - + /> +
      @@ -1621,7 +1597,7 @@ exports[`Dashboard table component renders dashboard table 1`] = ` size="s" type="questionInCircle" > - - - - + /> +
      @@ -1734,7 +1706,7 @@ exports[`Dashboard table component renders dashboard table 1`] = ` size="s" type="questionInCircle" > - - - - + /> +
      @@ -1860,7 +1828,7 @@ exports[`Dashboard table component renders dashboard table 1`] = ` size="s" type="questionInCircle" > - - - - + /> +
      @@ -1995,7 +1959,7 @@ exports[`Dashboard table component renders dashboard table 1`] = ` size="s" type="questionInCircle" > - - - - + /> + @@ -2437,7 +2397,7 @@ exports[`Dashboard table component renders dashboard table 1`] = ` size="s" type="questionInCircle" > - - - - + /> +
      @@ -2550,7 +2506,7 @@ exports[`Dashboard table component renders dashboard table 1`] = ` size="s" type="questionInCircle" > - - - - + /> +
      @@ -2663,7 +2615,7 @@ exports[`Dashboard table component renders dashboard table 1`] = ` size="s" type="questionInCircle" > - - - - + /> +
      @@ -2786,7 +2734,7 @@ exports[`Dashboard table component renders dashboard table 1`] = ` size="s" type="questionInCircle" > - - - - + /> +
      @@ -2972,7 +2916,7 @@ exports[`Dashboard table component renders dashboard table 1`] = ` size="s" type="arrowDown" > - - - - + /> + - - - - + /> + @@ -3219,7 +3155,7 @@ exports[`Dashboard table component renders dashboard table 1`] = ` size="m" type="arrowRight" > - - - - + /> + diff --git a/public/components/trace_analytics/components/dashboard/__tests__/__snapshots__/latency_trend_cell.test.tsx.snap b/public/components/trace_analytics/components/dashboard/__tests__/__snapshots__/latency_trend_cell.test.tsx.snap index 6c4844fa12..4b415df6f9 100644 --- a/public/components/trace_analytics/components/dashboard/__tests__/__snapshots__/latency_trend_cell.test.tsx.snap +++ b/public/components/trace_analytics/components/dashboard/__tests__/__snapshots__/latency_trend_cell.test.tsx.snap @@ -142,7 +142,7 @@ exports[`Latency trend cell component renders latency trend cell 1`] = ` size="m" type="magnifyWithPlus" > - - - - + /> + diff --git a/public/components/trace_analytics/components/dashboard/__tests__/__snapshots__/mode_picker.test.tsx.snap b/public/components/trace_analytics/components/dashboard/__tests__/__snapshots__/mode_picker.test.tsx.snap index 95690a4bae..469f17277f 100644 --- a/public/components/trace_analytics/components/dashboard/__tests__/__snapshots__/mode_picker.test.tsx.snap +++ b/public/components/trace_analytics/components/dashboard/__tests__/__snapshots__/mode_picker.test.tsx.snap @@ -86,7 +86,7 @@ exports[`Mode picker component renders mode picker 1`] = ` size="m" type="arrowDown" > - - - - + /> + - - - - + /> + - - + />
      @@ -686,7 +674,7 @@ exports[`Mode picker component renders mode picker 2`] = ` size="s" type="search" > - - - - + /> +
      diff --git a/public/components/trace_analytics/components/dashboard/__tests__/__snapshots__/top_error_rates_table.test.tsx.snap b/public/components/trace_analytics/components/dashboard/__tests__/__snapshots__/top_error_rates_table.test.tsx.snap index dee301c004..71733fa84d 100644 --- a/public/components/trace_analytics/components/dashboard/__tests__/__snapshots__/top_error_rates_table.test.tsx.snap +++ b/public/components/trace_analytics/components/dashboard/__tests__/__snapshots__/top_error_rates_table.test.tsx.snap @@ -805,7 +805,7 @@ exports[`Error Rates Table component renders top error rates table with data 1`] size="s" type="arrowDown" > - - - - + /> + - - - - + /> +
      @@ -1064,7 +1056,7 @@ exports[`Error Rates Table component renders top error rates table with data 1`] size="s" type="questionInCircle" > - - - - + /> +
      @@ -1166,7 +1154,7 @@ exports[`Error Rates Table component renders top error rates table with data 1`] size="s" type="questionInCircle" > - - - - + /> +
      @@ -1278,7 +1262,7 @@ exports[`Error Rates Table component renders top error rates table with data 1`] size="s" type="questionInCircle" > - - - - + /> +
      @@ -1404,7 +1384,7 @@ exports[`Error Rates Table component renders top error rates table with data 1`] size="s" type="questionInCircle" > - - - - + /> +
      @@ -1532,7 +1508,7 @@ exports[`Error Rates Table component renders top error rates table with data 1`] size="s" type="questionInCircle" > - - - - + /> +
      @@ -1645,7 +1617,7 @@ exports[`Error Rates Table component renders top error rates table with data 1`] size="s" type="questionInCircle" > - - - - + /> +
      @@ -1768,7 +1736,7 @@ exports[`Error Rates Table component renders top error rates table with data 1`] size="s" type="questionInCircle" > - - - - + /> +
      @@ -1950,7 +1914,7 @@ exports[`Error Rates Table component renders top error rates table with data 1`] size="s" type="arrowDown" > - - - - + /> + - - - - + /> + @@ -2197,7 +2153,7 @@ exports[`Error Rates Table component renders top error rates table with data 1`] size="m" type="arrowRight" > - - - - + /> + diff --git a/public/components/trace_analytics/components/dashboard/__tests__/__snapshots__/top_latency_table.test.tsx.snap b/public/components/trace_analytics/components/dashboard/__tests__/__snapshots__/top_latency_table.test.tsx.snap index edcc7059d9..d0279c1869 100644 --- a/public/components/trace_analytics/components/dashboard/__tests__/__snapshots__/top_latency_table.test.tsx.snap +++ b/public/components/trace_analytics/components/dashboard/__tests__/__snapshots__/top_latency_table.test.tsx.snap @@ -1164,7 +1164,7 @@ exports[`Latency Table component renders top error rates table with data 1`] = ` size="s" type="arrowDown" > - - - - + /> + - - - - + /> +
      @@ -1429,7 +1421,7 @@ exports[`Latency Table component renders top error rates table with data 1`] = ` size="s" type="questionInCircle" > - - - - + /> + @@ -1483,7 +1471,7 @@ exports[`Latency Table component renders top error rates table with data 1`] = ` size="m" type="sortDown" > - - - - + /> + @@ -1587,7 +1571,7 @@ exports[`Latency Table component renders top error rates table with data 1`] = ` size="s" type="questionInCircle" > - - - - + /> +
      @@ -1700,7 +1680,7 @@ exports[`Latency Table component renders top error rates table with data 1`] = ` size="s" type="questionInCircle" > - - - - + /> +
      @@ -1813,7 +1789,7 @@ exports[`Latency Table component renders top error rates table with data 1`] = ` size="s" type="questionInCircle" > - - - - + /> +
      @@ -1939,7 +1911,7 @@ exports[`Latency Table component renders top error rates table with data 1`] = ` size="s" type="questionInCircle" > - - - - + /> +
      @@ -2074,7 +2042,7 @@ exports[`Latency Table component renders top error rates table with data 1`] = ` size="s" type="questionInCircle" > - - - - + /> + @@ -2516,7 +2480,7 @@ exports[`Latency Table component renders top error rates table with data 1`] = ` size="s" type="questionInCircle" > - - - - + /> +
      @@ -2629,7 +2589,7 @@ exports[`Latency Table component renders top error rates table with data 1`] = ` size="s" type="questionInCircle" > - - - - + /> +
      @@ -2752,7 +2708,7 @@ exports[`Latency Table component renders top error rates table with data 1`] = ` size="s" type="questionInCircle" > - - - - + /> +
      @@ -2934,7 +2886,7 @@ exports[`Latency Table component renders top error rates table with data 1`] = ` size="s" type="arrowDown" > - - - - + /> + - - - - + /> + @@ -3181,7 +3125,7 @@ exports[`Latency Table component renders top error rates table with data 1`] = ` size="m" type="arrowRight" > - - - - + /> + diff --git a/public/components/trace_analytics/components/services/__tests__/__snapshots__/services.test.tsx.snap b/public/components/trace_analytics/components/services/__tests__/__snapshots__/services.test.tsx.snap index b4e2ead80a..042830c076 100644 --- a/public/components/trace_analytics/components/services/__tests__/__snapshots__/services.test.tsx.snap +++ b/public/components/trace_analytics/components/services/__tests__/__snapshots__/services.test.tsx.snap @@ -282,7 +282,7 @@ exports[`Services component renders empty services page 1`] = ` size="m" type="arrowDown" > - - - - + /> + - - - - + /> + @@ -930,7 +922,7 @@ exports[`Services component renders empty services page 1`] = ` size="s" type="arrowDown" > - - - - + /> + - - - - + /> + @@ -1092,7 +1076,7 @@ exports[`Services component renders empty services page 1`] = ` size="m" type="refresh" > - - - - + /> + - - - - + /> + @@ -1899,7 +1875,7 @@ exports[`Services component renders empty services page 1`] = ` size="m" type="search" > - - - - + /> + @@ -2070,7 +2042,7 @@ exports[`Services component renders empty services page 1`] = ` size="m" type="arrowRight" > - - - - + /> + - - - - + /> + - - - - + /> + @@ -3073,7 +3065,7 @@ exports[`Services table component renders services table 1`] = ` size="s" type="arrowDown" > - - - - + /> + - - - - + /> + @@ -3320,7 +3304,7 @@ exports[`Services table component renders services table 1`] = ` size="m" type="arrowRight" > - - - - + /> + diff --git a/public/components/trace_analytics/components/traces/__tests__/__snapshots__/service_breakdown_panel.test.tsx.snap b/public/components/trace_analytics/components/traces/__tests__/__snapshots__/service_breakdown_panel.test.tsx.snap index 9024b9fa83..db4ecbdadf 100644 --- a/public/components/trace_analytics/components/traces/__tests__/__snapshots__/service_breakdown_panel.test.tsx.snap +++ b/public/components/trace_analytics/components/traces/__tests__/__snapshots__/service_breakdown_panel.test.tsx.snap @@ -318,7 +318,7 @@ exports[`Service breakdown panel component renders service breakdown panel 1`] = color="#7492e7" type="dot" > - - - - + /> +
      diff --git a/public/components/trace_analytics/components/traces/__tests__/__snapshots__/span_detail_flyout.test.tsx.snap b/public/components/trace_analytics/components/traces/__tests__/__snapshots__/span_detail_flyout.test.tsx.snap index 4f5a9b424e..e4eb22e85d 100644 --- a/public/components/trace_analytics/components/traces/__tests__/__snapshots__/span_detail_flyout.test.tsx.snap +++ b/public/components/trace_analytics/components/traces/__tests__/__snapshots__/span_detail_flyout.test.tsx.snap @@ -60,11 +60,7 @@ exports[` spec renders the empty component 1`] = ` viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - > - - + />
      spec renders the empty component 1`] = ` viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - > - - + />
      spec renders the empty component 1`] = ` viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - > - - + />
      spec renders the empty component 1`] = ` viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - > - - + />
      spec renders the empty component 1`] = ` viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" - > - - + />
      spec renders the empty component 1`] = ` size="m" type="cross" > - spec renders the empty component 1`] = ` viewBox="0 0 16 16" width={16} xmlns="http://www.w3.org/2000/svg" - > - - - + /> + diff --git a/public/components/trace_analytics/components/traces/__tests__/__snapshots__/traces.test.tsx.snap b/public/components/trace_analytics/components/traces/__tests__/__snapshots__/traces.test.tsx.snap index eb5619545b..1be451ac0a 100644 --- a/public/components/trace_analytics/components/traces/__tests__/__snapshots__/traces.test.tsx.snap +++ b/public/components/trace_analytics/components/traces/__tests__/__snapshots__/traces.test.tsx.snap @@ -281,7 +281,7 @@ exports[`Traces component renders empty traces page 1`] = ` size="m" type="arrowDown" > - - - - + /> + - - - - + /> + @@ -928,7 +920,7 @@ exports[`Traces component renders empty traces page 1`] = ` size="s" type="arrowDown" > - - - - + /> + - - - - + /> + @@ -1090,7 +1074,7 @@ exports[`Traces component renders empty traces page 1`] = ` size="m" type="refresh" > - - - - + /> + - - - - + /> + diff --git a/public/components/trace_analytics/components/traces/__tests__/__snapshots__/traces_table.test.tsx.snap b/public/components/trace_analytics/components/traces/__tests__/__snapshots__/traces_table.test.tsx.snap index 0662d5db1e..43f7391229 100644 --- a/public/components/trace_analytics/components/traces/__tests__/__snapshots__/traces_table.test.tsx.snap +++ b/public/components/trace_analytics/components/traces/__tests__/__snapshots__/traces_table.test.tsx.snap @@ -187,7 +187,7 @@ exports[`Traces table component renders empty traces table message 1`] = ` size="m" type="popout" > - - - - + /> + - - - - + /> + - - - - + /> + @@ -2731,7 +2719,7 @@ exports[`Traces table component renders traces table 1`] = ` size="m" type="copyClipboard" > - - - - + /> + @@ -3095,7 +3079,7 @@ exports[`Traces table component renders traces table 1`] = ` size="s" type="arrowDown" > - - - - + /> + - - - - + /> + @@ -3342,7 +3318,7 @@ exports[`Traces table component renders traces table 1`] = ` size="m" type="arrowRight" > - - - - + /> + diff --git a/public/components/visualizations/charts/__tests__/__snapshots__/gauge.test.tsx.snap b/public/components/visualizations/charts/__tests__/__snapshots__/gauge.test.tsx.snap index 6c6d9253e7..10c63f396a 100644 --- a/public/components/visualizations/charts/__tests__/__snapshots__/gauge.test.tsx.snap +++ b/public/components/visualizations/charts/__tests__/__snapshots__/gauge.test.tsx.snap @@ -567,7 +567,7 @@ exports[`Gauge component Renders gauge component 1`] = ` size="xxl" type="visGauge" > - - - - + /> + - - - - + /> +

      Text From ea08e472f38901cbda28721539c99eaecf64da20 Mon Sep 17 00:00:00 2001 From: Simeon Widdis Date: Tue, 16 Jan 2024 11:01:12 -0800 Subject: [PATCH 31/36] Use semver library for comparison Signed-off-by: Simeon Widdis --- .../repository/__test__/utils.test.ts | 26 +--------------- .../repository/integration_reader.ts | 30 ++----------------- 2 files changed, 3 insertions(+), 53 deletions(-) diff --git a/server/adaptors/integrations/repository/__test__/utils.test.ts b/server/adaptors/integrations/repository/__test__/utils.test.ts index 231bfc78e6..93294bbe62 100644 --- a/server/adaptors/integrations/repository/__test__/utils.test.ts +++ b/server/adaptors/integrations/repository/__test__/utils.test.ts @@ -3,31 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { compareVersions, foldResults } from '../integration_reader'; - -describe('compareVersions', () => { - it('should return 0 for equal versions', () => { - expect(compareVersions('1.2.3', '1.2.3')).toBe(0); - }); - - it('should return -1 for a < b', () => { - expect(compareVersions('1.2.3', '1.2.4')).toBe(-1); - expect(compareVersions('1.2.3', '1.3.0')).toBe(-1); - expect(compareVersions('1.2.3', '2.0.0')).toBe(-1); - }); - - it('should return 1 for a > b', () => { - expect(compareVersions('1.2.4', '1.2.3')).toBe(1); - expect(compareVersions('1.3.0', '1.2.3')).toBe(1); - expect(compareVersions('2.0.0', '1.2.3')).toBe(1); - }); - - it('should handle versions with different numbers of parts', () => { - expect(compareVersions('1.2.3', '1.2')).toBe(1); - expect(compareVersions('1.2', '1.2.3')).toBe(-1); - expect(compareVersions('1.2.3', '1.2.3.4')).toBe(-1); - }); -}); +import { foldResults } from '../integration_reader'; describe('foldResults', () => { it('should return an empty array result if input array is empty', () => { diff --git a/server/adaptors/integrations/repository/integration_reader.ts b/server/adaptors/integrations/repository/integration_reader.ts index 48693e87ea..c4b4318471 100644 --- a/server/adaptors/integrations/repository/integration_reader.ts +++ b/server/adaptors/integrations/repository/integration_reader.ts @@ -4,6 +4,7 @@ */ import path from 'path'; +import semver from 'semver'; import { validateTemplate } from '../validators'; import { FileSystemCatalogDataAdaptor } from './fs_data_adaptor'; import { CatalogDataAdaptor, IntegrationPart } from './catalog_data_adaptor'; @@ -63,33 +64,6 @@ const pruneConfig = (rawConfig: IntegrationConfig | SerializedIntegration): Inte return prunePart(rawConfig); }; -/** - * Helper function to compare version numbers. - * Assumes that the version numbers are valid, produces undefined behavior otherwise. - * - * @param a Left-hand number - * @param b Right-hand number - * @returns -1 if a < b, 1 if a > b, 0 otherwise. - */ -export function compareVersions(a: string, b: string): number { - const aParts = a.split('.').map((part) => Number.parseInt(part, 10)); - const bParts = b.split('.').map((part) => Number.parseInt(part, 10)); - - for (let i = 0; i < Math.max(aParts.length, bParts.length); i++) { - const aValue = i < aParts.length ? aParts[i] : 0; - const bValue = i < bParts.length ? bParts[i] : 0; - - if (aValue > bValue) { - return 1; - } - if (aValue < bValue) { - return -1; - } - } - - return 0; -} - /** * The Integration class represents the data for Integration Templates. * It is backed by the repository file system. @@ -196,7 +170,7 @@ export class IntegrationReader { return null; } // Sort descending - versions.value.sort((a, b) => -compareVersions(a, b)); + versions.value.sort(semver.rcompare); return versions.value[0]; } From 760788a901fe34d4aa2c0f00385c262522e3456e Mon Sep 17 00:00:00 2001 From: Simeon Widdis Date: Tue, 16 Jan 2024 11:10:34 -0800 Subject: [PATCH 32/36] Switch to upstream NDJson parser Signed-off-by: Simeon Widdis --- .../__test__/integration_reader.test.ts | 2 +- .../integrations/repository/fs_data_adaptor.ts | 2 +- .../integrations/repository/parse_ndjson.ts | 16 ++++++---------- 3 files changed, 8 insertions(+), 12 deletions(-) diff --git a/server/adaptors/integrations/repository/__test__/integration_reader.test.ts b/server/adaptors/integrations/repository/__test__/integration_reader.test.ts index 05c8f5ab9d..c2c25ba23c 100644 --- a/server/adaptors/integrations/repository/__test__/integration_reader.test.ts +++ b/server/adaptors/integrations/repository/__test__/integration_reader.test.ts @@ -113,7 +113,7 @@ describe('Integration', () => { const result = await integration.getAssets(TEST_INTEGRATION_CONFIG.version); expect(result.ok).toBe(true); - expect((result as { value: { savedObjects: unknown } }).value.savedObjects).toStrictEqual([ + expect((result as { value: { savedObjects: unknown } }).value.savedObjects).toEqual([ { name: 'asset1' }, { name: 'asset2' }, ]); diff --git a/server/adaptors/integrations/repository/fs_data_adaptor.ts b/server/adaptors/integrations/repository/fs_data_adaptor.ts index 99d81f20cf..d99344c0d9 100644 --- a/server/adaptors/integrations/repository/fs_data_adaptor.ts +++ b/server/adaptors/integrations/repository/fs_data_adaptor.ts @@ -48,7 +48,7 @@ export class FileSystemCatalogDataAdaptor implements CatalogDataAdaptor { const parsed = JSON.parse(content); return { ok: true, value: parsed }; } catch (err) { - const parsed = tryParseNDJson(content); + const parsed = await tryParseNDJson(content); if (parsed) { return { ok: true, value: parsed }; } diff --git a/server/adaptors/integrations/repository/parse_ndjson.ts b/server/adaptors/integrations/repository/parse_ndjson.ts index 522b22f897..fd200920d0 100644 --- a/server/adaptors/integrations/repository/parse_ndjson.ts +++ b/server/adaptors/integrations/repository/parse_ndjson.ts @@ -3,17 +3,13 @@ * SPDX-License-Identifier: Apache-2.0 */ -export function tryParseNDJson(content: string): object[] | null { +import { Readable } from 'stream'; +import { createSavedObjectsStreamFromNdJson } from '../../../../../../src/core/server/saved_objects/routes/utils'; + +export async function tryParseNDJson(content: string): Promise { try { - const objects = []; - for (const line of content.split('\n')) { - if (line.trim() === '') { - // Other OSD ndjson parsers skip whitespace lines - continue; - } - objects.push(JSON.parse(line)); - } - return objects; + const objects = await createSavedObjectsStreamFromNdJson(Readable.from(content)); + return await objects.toArray(); } catch (err) { return null; } From e81c3c5587737de49f30684519458bdfa00de717 Mon Sep 17 00:00:00 2001 From: Simeon Widdis Date: Tue, 16 Jan 2024 11:18:50 -0800 Subject: [PATCH 33/36] Add inline documentation for IntegrationPart Signed-off-by: Simeon Widdis --- .../adaptors/integrations/repository/catalog_data_adaptor.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/server/adaptors/integrations/repository/catalog_data_adaptor.ts b/server/adaptors/integrations/repository/catalog_data_adaptor.ts index a8c076231c..8dd3c8c616 100644 --- a/server/adaptors/integrations/repository/catalog_data_adaptor.ts +++ b/server/adaptors/integrations/repository/catalog_data_adaptor.ts @@ -3,6 +3,9 @@ * SPDX-License-Identifier: Apache-2.0 */ +// Matches the subdirectories of the File System serialization, used in the shipped catalog. +// Generally corresponds to each section of linked assets in the Integration Config format. +// This is helpful for asset location in non-localized config formats. export type IntegrationPart = 'assets' | 'data' | 'schemas' | 'static'; export interface CatalogDataAdaptor { From 77f1326510ffee80412b06ee47aeb42e634301d3 Mon Sep 17 00:00:00 2001 From: Simeon Widdis Date: Tue, 16 Jan 2024 12:14:43 -0800 Subject: [PATCH 34/36] Move deepCheck to utils Signed-off-by: Simeon Widdis --- .../integrations/__test__/builder.test.ts | 32 ++++++++++++---- .../__test__/json_repository.test.ts | 7 ++-- .../__test__/local_fs_repository.test.ts | 3 +- .../integrations/integrations_builder.ts | 4 +- .../repository/fs_data_adaptor.ts | 2 +- .../repository/integration_reader.ts | 20 ---------- .../integrations/repository/parse_ndjson.ts | 16 -------- .../adaptors/integrations/repository/utils.ts | 38 +++++++++++++++++++ 8 files changed, 71 insertions(+), 51 deletions(-) delete mode 100644 server/adaptors/integrations/repository/parse_ndjson.ts create mode 100644 server/adaptors/integrations/repository/utils.ts diff --git a/server/adaptors/integrations/__test__/builder.test.ts b/server/adaptors/integrations/__test__/builder.test.ts index 36f65cb7a1..e7819bb086 100644 --- a/server/adaptors/integrations/__test__/builder.test.ts +++ b/server/adaptors/integrations/__test__/builder.test.ts @@ -6,6 +6,12 @@ import { SavedObjectsClientContract } from '../../../../../../src/core/server'; import { IntegrationInstanceBuilder } from '../integrations_builder'; import { IntegrationReader } from '../repository/integration_reader'; +import * as mockUtils from '../repository/utils'; + +jest.mock('../repository/utils', () => ({ + ...jest.requireActual('../repository/utils'), + deepCheck: jest.fn(), +})); const mockSavedObjectsClient: SavedObjectsClientContract = ({ bulkCreate: jest.fn(), @@ -17,7 +23,6 @@ const mockSavedObjectsClient: SavedObjectsClientContract = ({ } as unknown) as SavedObjectsClientContract; const sampleIntegration: IntegrationReader = ({ - deepCheck: jest.fn().mockResolvedValue(true), getAssets: jest.fn().mockResolvedValue({ savedObjects: [ { @@ -104,8 +109,12 @@ describe('IntegrationInstanceBuilder', () => { }, }; + jest + .spyOn(mockUtils, 'deepCheck') + .mockResolvedValue({ ok: true, value: mockTemplate as IntegrationConfig }); + // Mock the implementation of the methods in the Integration class - sampleIntegration.deepCheck = jest.fn().mockResolvedValue({ ok: true, value: mockTemplate }); + // sampleIntegration.deepCheck = jest.fn().mockResolvedValue({ ok: true, value: mockTemplate }); sampleIntegration.getAssets = jest .fn() .mockResolvedValue({ ok: true, value: { savedObjects: remappedAssets } }); @@ -119,7 +128,6 @@ describe('IntegrationInstanceBuilder', () => { const instance = await builder.build(sampleIntegration, options); - expect(sampleIntegration.deepCheck).toHaveBeenCalled(); expect(sampleIntegration.getAssets).toHaveBeenCalled(); expect(remapIDsSpy).toHaveBeenCalledWith(remappedAssets); expect(postAssetsSpy).toHaveBeenCalledWith(remappedAssets); @@ -131,8 +139,8 @@ describe('IntegrationInstanceBuilder', () => { dataSource: 'instance-datasource', name: 'instance-name', }; - sampleIntegration.deepCheck = jest - .fn() + jest + .spyOn(mockUtils, 'deepCheck') .mockResolvedValue({ ok: false, error: new Error('Mock error') }); await expect(builder.build(sampleIntegration, options)).rejects.toThrowError('Mock error'); @@ -145,7 +153,9 @@ describe('IntegrationInstanceBuilder', () => { }; const errorMessage = 'Failed to get assets'; - sampleIntegration.deepCheck = jest.fn().mockResolvedValue({ ok: true, value: {} }); + jest + .spyOn(mockUtils, 'deepCheck') + .mockResolvedValue({ ok: true, value: ({} as unknown) as IntegrationConfig }); sampleIntegration.getAssets = jest .fn() .mockResolvedValue({ ok: false, error: new Error(errorMessage) }); @@ -165,7 +175,9 @@ describe('IntegrationInstanceBuilder', () => { }, ]; const errorMessage = 'Failed to post assets'; - sampleIntegration.deepCheck = jest.fn().mockResolvedValue({ ok: true, value: {} }); + jest + .spyOn(mockUtils, 'deepCheck') + .mockResolvedValue({ ok: true, value: ({} as unknown) as IntegrationConfig }); sampleIntegration.getAssets = jest .fn() .mockResolvedValue({ ok: true, value: { savedObjects: remappedAssets } }); @@ -180,10 +192,14 @@ describe('IntegrationInstanceBuilder', () => { const assets = [ { id: 'asset1', + type: 'unknown', + attributes: { title: 'asset1' }, references: [{ id: 'ref1' }, { id: 'ref2' }], }, { id: 'asset2', + type: 'unknown', + attributes: { title: 'asset1' }, references: [{ id: 'ref1' }, { id: 'ref3' }], }, ]; @@ -200,7 +216,7 @@ describe('IntegrationInstanceBuilder', () => { const remappedAssets = builder.remapIDs(assets); - expect(remappedAssets).toEqual(expectedRemappedAssets); + expect(remappedAssets).toMatchObject(expectedRemappedAssets); }); }); diff --git a/server/adaptors/integrations/__test__/json_repository.test.ts b/server/adaptors/integrations/__test__/json_repository.test.ts index ce50f2c34b..8295214ff8 100644 --- a/server/adaptors/integrations/__test__/json_repository.test.ts +++ b/server/adaptors/integrations/__test__/json_repository.test.ts @@ -12,6 +12,7 @@ import { IntegrationReader, foldResults } from '../repository/integration_reader import path from 'path'; import * as fs from 'fs/promises'; import { JsonCatalogDataAdaptor } from '../repository/json_data_adaptor'; +import { deepCheck } from '../repository/utils'; const fetchSerializedIntegrations = async (): Promise> => { const directory = path.join(__dirname, '../__data__/repository'); @@ -47,7 +48,7 @@ describe('The Local Serialized Catalog', () => { ); for (const integ of await repository.getIntegrationList()) { - const validationResult = await integ.deepCheck(); + const validationResult = await deepCheck(integ); await expect(validationResult).toHaveProperty('ok', true); } }); @@ -152,7 +153,7 @@ describe('Integration validation', () => { new JsonCatalogDataAdaptor(transformedSerialized) ); - await expect(integration.deepCheck()).resolves.toHaveProperty('ok', false); + await expect(deepCheck(integration)).resolves.toHaveProperty('ok', false); }); it('Should correctly fail an integration without assets', async () => { @@ -171,7 +172,7 @@ describe('Integration validation', () => { new JsonCatalogDataAdaptor(transformedSerialized) ); - await expect(integration.deepCheck()).resolves.toHaveProperty('ok', false); + await expect(deepCheck(integration)).resolves.toHaveProperty('ok', false); }); }); diff --git a/server/adaptors/integrations/__test__/local_fs_repository.test.ts b/server/adaptors/integrations/__test__/local_fs_repository.test.ts index c7919dddc1..dcacf02bbb 100644 --- a/server/adaptors/integrations/__test__/local_fs_repository.test.ts +++ b/server/adaptors/integrations/__test__/local_fs_repository.test.ts @@ -11,6 +11,7 @@ import { TemplateManager } from '../repository/repository'; import { IntegrationReader } from '../repository/integration_reader'; import path from 'path'; import * as fs from 'fs/promises'; +import { deepCheck } from '../repository/utils'; describe('The local repository', () => { it('Should only contain valid integration directories or files.', async () => { @@ -37,7 +38,7 @@ describe('The local repository', () => { const integrations: IntegrationReader[] = await repository.getIntegrationList(); await Promise.all( integrations.map(async (i) => { - const result = await i.deepCheck(); + const result = await deepCheck(i); if (!result.ok) { console.error(result.error); } diff --git a/server/adaptors/integrations/integrations_builder.ts b/server/adaptors/integrations/integrations_builder.ts index 7c630dc5cd..6866873d94 100644 --- a/server/adaptors/integrations/integrations_builder.ts +++ b/server/adaptors/integrations/integrations_builder.ts @@ -7,6 +7,7 @@ import { v4 as uuidv4 } from 'uuid'; import { SavedObjectsClientContract } from '../../../../../src/core/server'; import { IntegrationReader } from './repository/integration_reader'; import { SavedObjectsBulkCreateObject } from '../../../../../src/core/public'; +import { deepCheck } from './repository/utils'; interface BuilderOptions { name: string; @@ -28,8 +29,7 @@ export class IntegrationInstanceBuilder { } build(integration: IntegrationReader, options: BuilderOptions): Promise { - const instance = integration - .deepCheck() + const instance = deepCheck(integration) .then((result) => { if (!result.ok) { return Promise.reject(result.error); diff --git a/server/adaptors/integrations/repository/fs_data_adaptor.ts b/server/adaptors/integrations/repository/fs_data_adaptor.ts index d99344c0d9..52c5dff6d5 100644 --- a/server/adaptors/integrations/repository/fs_data_adaptor.ts +++ b/server/adaptors/integrations/repository/fs_data_adaptor.ts @@ -6,7 +6,7 @@ import * as fs from 'fs/promises'; import path from 'path'; import { CatalogDataAdaptor, IntegrationPart } from './catalog_data_adaptor'; -import { tryParseNDJson } from './parse_ndjson'; +import { tryParseNDJson } from './utils'; // Check if a location is a directory without an exception if location not found const safeIsDirectory = async (maybeDirectory: string): Promise => { diff --git a/server/adaptors/integrations/repository/integration_reader.ts b/server/adaptors/integrations/repository/integration_reader.ts index c4b4318471..245100c7e4 100644 --- a/server/adaptors/integrations/repository/integration_reader.ts +++ b/server/adaptors/integrations/repository/integration_reader.ts @@ -134,26 +134,6 @@ export class IntegrationReader { } } - /** - * Like getConfig(), but thoroughly checks all nested integration dependencies for validity. - * - * @returns a Result indicating whether the integration is valid. - */ - async deepCheck(): Promise> { - const configResult = await this.getConfig(); - if (!configResult.ok) { - return configResult; - } - - // Some other checks are included in getConfig validation. - const assets = await this.getAssets(); - if (!assets.ok || Object.keys(assets.value).length === 0) { - return { ok: false, error: new Error('An integration must have at least one asset') }; - } - - return configResult; - } - /** * Get the latest version of the integration available. * This method relies on the fact that integration configs have their versions in their name. diff --git a/server/adaptors/integrations/repository/parse_ndjson.ts b/server/adaptors/integrations/repository/parse_ndjson.ts deleted file mode 100644 index fd200920d0..0000000000 --- a/server/adaptors/integrations/repository/parse_ndjson.ts +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { Readable } from 'stream'; -import { createSavedObjectsStreamFromNdJson } from '../../../../../../src/core/server/saved_objects/routes/utils'; - -export async function tryParseNDJson(content: string): Promise { - try { - const objects = await createSavedObjectsStreamFromNdJson(Readable.from(content)); - return await objects.toArray(); - } catch (err) { - return null; - } -} diff --git a/server/adaptors/integrations/repository/utils.ts b/server/adaptors/integrations/repository/utils.ts new file mode 100644 index 0000000000..882110fc44 --- /dev/null +++ b/server/adaptors/integrations/repository/utils.ts @@ -0,0 +1,38 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { Readable } from 'stream'; +import { createSavedObjectsStreamFromNdJson } from '../../../../../../src/core/server/saved_objects/routes/utils'; +import { IntegrationReader } from './integration_reader'; + +export async function tryParseNDJson(content: string): Promise { + try { + const objects = await createSavedObjectsStreamFromNdJson(Readable.from(content)); + return await objects.toArray(); + } catch (err) { + return null; + } +} + +/** + * Check IntegrationReader nested dependencies for validity, + * as a supplement to shallow config validation. + * + * @returns a Result indicating whether the integration is valid, holding the integration's config. + */ +export async function deepCheck(reader: IntegrationReader): Promise> { + const configResult = await reader.getConfig(); + if (!configResult.ok) { + return configResult; + } + + // Deep checks not included in default config validation + const assets = await reader.getAssets(); + if (!assets.ok || Object.keys(assets.value).length === 0) { + return { ok: false, error: new Error('An integration must have at least one asset') }; + } + + return configResult; +} From bca1ac253d7da41a4e551ffe35ef509010a907db Mon Sep 17 00:00:00 2001 From: Simeon Widdis Date: Tue, 16 Jan 2024 13:15:09 -0800 Subject: [PATCH 35/36] Add further utility methods to utils Signed-off-by: Simeon Widdis --- .../__test__/json_repository.test.ts | 4 +- .../repository/__test__/utils.test.ts | 2 +- .../repository/integration_reader.ts | 56 +----------------- .../adaptors/integrations/repository/utils.ts | 57 +++++++++++++++++++ 4 files changed, 61 insertions(+), 58 deletions(-) diff --git a/server/adaptors/integrations/__test__/json_repository.test.ts b/server/adaptors/integrations/__test__/json_repository.test.ts index 8295214ff8..18872913ce 100644 --- a/server/adaptors/integrations/__test__/json_repository.test.ts +++ b/server/adaptors/integrations/__test__/json_repository.test.ts @@ -8,11 +8,11 @@ */ import { TemplateManager } from '../repository/repository'; -import { IntegrationReader, foldResults } from '../repository/integration_reader'; +import { IntegrationReader } from '../repository/integration_reader'; import path from 'path'; import * as fs from 'fs/promises'; import { JsonCatalogDataAdaptor } from '../repository/json_data_adaptor'; -import { deepCheck } from '../repository/utils'; +import { deepCheck, foldResults } from '../repository/utils'; const fetchSerializedIntegrations = async (): Promise> => { const directory = path.join(__dirname, '../__data__/repository'); diff --git a/server/adaptors/integrations/repository/__test__/utils.test.ts b/server/adaptors/integrations/repository/__test__/utils.test.ts index 93294bbe62..d9acb440e8 100644 --- a/server/adaptors/integrations/repository/__test__/utils.test.ts +++ b/server/adaptors/integrations/repository/__test__/utils.test.ts @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { foldResults } from '../integration_reader'; +import { foldResults } from '../utils'; describe('foldResults', () => { it('should return an empty array result if input array is empty', () => { diff --git a/server/adaptors/integrations/repository/integration_reader.ts b/server/adaptors/integrations/repository/integration_reader.ts index 245100c7e4..c545e06c2f 100644 --- a/server/adaptors/integrations/repository/integration_reader.ts +++ b/server/adaptors/integrations/repository/integration_reader.ts @@ -8,61 +8,7 @@ import semver from 'semver'; import { validateTemplate } from '../validators'; import { FileSystemCatalogDataAdaptor } from './fs_data_adaptor'; import { CatalogDataAdaptor, IntegrationPart } from './catalog_data_adaptor'; - -/** - * Helper method: Convert an Array> to Result>. - * - * @param results The list of results to fold. - * @returns A single result object with values in an array, or an error result. - */ -export const foldResults = (results: Array>) => - results.reduce( - (result, currentValue) => { - if (!result.ok) { - return result; - } - if (!currentValue.ok) { - return currentValue; - } - result.value.push(currentValue.value); - return result; - }, - { ok: true, value: [] } as Result - ); - -/** - * Remove all fields from SerializedIntegration not present in IntegrationConfig. - * - * @param rawConfig The raw config to prune - * @returns A config with all data fields removed - */ -const pruneConfig = (rawConfig: IntegrationConfig | SerializedIntegration): IntegrationConfig => { - // Hacky workaround: we currently only need to prune 'data' fields, so just remove every 'data'. - // Lots of risky conversion in this method, so scope it to here and rewrite if more granular - // pruning is needed. - const prunePart = (part: T): T => { - const result = {} as { [key: string]: unknown }; - for (const [key, value] of Object.entries(part as { [key: string]: unknown })) { - if (key === 'data') { - continue; - } else if (Array.isArray(value)) { - result[key] = value.map((item) => { - if (item instanceof Object && item !== null) { - return prunePart(item); - } - return item; - }); - } else if (value instanceof Object && value !== null) { - result[key] = prunePart(value as { [key: string]: unknown }); - } else { - result[key] = value; - } - } - return (result as unknown) as T; - }; - - return prunePart(rawConfig); -}; +import { foldResults, pruneConfig } from './utils'; /** * The Integration class represents the data for Integration Templates. diff --git a/server/adaptors/integrations/repository/utils.ts b/server/adaptors/integrations/repository/utils.ts index 882110fc44..b9ee28c7a5 100644 --- a/server/adaptors/integrations/repository/utils.ts +++ b/server/adaptors/integrations/repository/utils.ts @@ -36,3 +36,60 @@ export async function deepCheck(reader: IntegrationReader): Promise> to Result>. + * + * @param results The list of results to fold. + * @returns A single result object with values in an array, or an error result. + */ +export const foldResults = (results: Array>) => + results.reduce( + (result, currentValue) => { + if (!result.ok) { + return result; + } + if (!currentValue.ok) { + return currentValue; + } + result.value.push(currentValue.value); + return result; + }, + { ok: true, value: [] } as Result + ); + +/** + * Remove all fields from SerializedIntegration not present in IntegrationConfig. + * + * @param rawConfig The raw config to prune + * @returns A config with all data fields removed + */ +export const pruneConfig = ( + rawConfig: IntegrationConfig | SerializedIntegration +): IntegrationConfig => { + // Hacky workaround: we currently only need to prune 'data' fields, so just remove every 'data'. + // Lots of risky conversion in this method, so scope it to here and rewrite if more granular + // pruning is needed. + const prunePart = (part: T): T => { + const result = {} as { [key: string]: unknown }; + for (const [key, value] of Object.entries(part as { [key: string]: unknown })) { + if (key === 'data') { + continue; + } else if (Array.isArray(value)) { + result[key] = value.map((item) => { + if (item instanceof Object && item !== null) { + return prunePart(item); + } + return item; + }); + } else if (value instanceof Object && value !== null) { + result[key] = prunePart(value as { [key: string]: unknown }); + } else { + result[key] = value; + } + } + return (result as unknown) as T; + }; + + return prunePart(rawConfig); +}; From 25327fd0be14ed8a1e8b19c83fa2be4f50bf9388 Mon Sep 17 00:00:00 2001 From: Simeon Widdis Date: Tue, 16 Jan 2024 14:03:27 -0800 Subject: [PATCH 36/36] Refactor repository tests to not rely on result.ok == false Signed-off-by: Simeon Widdis --- .../__test__/integration_reader.test.ts | 64 ++++++++++++------- .../__test__/json_data_adaptor.test.ts | 16 +++-- .../repository/integration_reader.ts | 5 +- 3 files changed, 55 insertions(+), 30 deletions(-) diff --git a/server/adaptors/integrations/repository/__test__/integration_reader.test.ts b/server/adaptors/integrations/repository/__test__/integration_reader.test.ts index c2c25ba23c..a2677dd94f 100644 --- a/server/adaptors/integrations/repository/__test__/integration_reader.test.ts +++ b/server/adaptors/integrations/repository/__test__/integration_reader.test.ts @@ -57,7 +57,7 @@ describe('Integration', () => { const result = await integration.getConfig(); expect(spy).toHaveBeenCalled(); - expect(result.ok).toBe(false); + expect(result.error?.message).toContain('not a valid integration directory'); }); it('should return the parsed config template if it is valid', async () => { @@ -75,7 +75,7 @@ describe('Integration', () => { const result = await integration.getConfig(TEST_INTEGRATION_CONFIG.version); - expect(result.ok).toBe(false); + expect(result.error?.message).toBe('data/version must be string'); }); it('should return an error if the config file has syntax errors', async () => { @@ -83,7 +83,7 @@ describe('Integration', () => { const result = await integration.getConfig(TEST_INTEGRATION_CONFIG.version); - expect(result.ok).toBe(false); + expect(result.error?.message).toBe('Unable to parse file as JSON or NDJson'); }); it('should return an error if the integration config does not exist', async () => { @@ -99,7 +99,7 @@ describe('Integration', () => { const result = await integration.getConfig(TEST_INTEGRATION_CONFIG.version); expect(readFileMock).toHaveBeenCalled(); - expect(result.ok).toBe(false); + expect(result.error?.message).toContain('File not found'); }); }); @@ -120,20 +120,21 @@ describe('Integration', () => { }); it('should return an error if the provided version has no config', async () => { - integration.getConfig = jest.fn().mockResolvedValue({ ok: false, error: new Error() }); + jest.spyOn(fs, 'readFile').mockRejectedValueOnce(new Error('ENOENT: File not found')); + const result = await integration.getAssets(); - await expect(integration.getAssets()).resolves.toHaveProperty('ok', false); + expect(result.error?.message).toContain('File not found'); }); it('should return an error if the saved object assets are invalid', async () => { - integration.getConfig = jest - .fn() - .mockResolvedValue({ ok: true, value: TEST_INTEGRATION_CONFIG }); - jest.spyOn(fs, 'readFile').mockResolvedValue('{"unclosed":'); + jest + .spyOn(fs, 'readFile') + .mockResolvedValueOnce(JSON.stringify(TEST_INTEGRATION_CONFIG)) + .mockResolvedValue('{"unclosed":'); const result = await integration.getAssets(TEST_INTEGRATION_CONFIG.version); - expect(result.ok).toBe(false); + expect(result.error?.message).toBe('Unable to parse file as JSON or NDJson'); }); }); @@ -165,19 +166,25 @@ describe('Integration', () => { }); it('should reject with an error if the config is invalid', async () => { - integration.getConfig = jest.fn().mockResolvedValue({ ok: false, error: new Error() }); + jest.spyOn(fs, 'readFile').mockResolvedValueOnce( + JSON.stringify({ + ...TEST_INTEGRATION_CONFIG, + name: undefined, + }) + ); + const result = await integration.getSchemas(); - await expect(integration.getSchemas()).resolves.toHaveProperty('ok', false); + expect(result.error?.message).toBe("data must have required property 'name'"); }); it('should reject with an error if a mapping file is invalid', async () => { - const sampleConfig = { - components: [{ name: 'component1', version: '1.0.0' }], - }; - integration.getConfig = jest.fn().mockResolvedValue({ ok: true, value: sampleConfig }); - jest.spyOn(fs, 'readFile').mockRejectedValueOnce(new Error('Could not load schema')); + jest + .spyOn(fs, 'readFile') + .mockResolvedValueOnce(JSON.stringify(TEST_INTEGRATION_CONFIG)) + .mockRejectedValueOnce(new Error('Could not load schema')); - await expect(integration.getSchemas()).resolves.toHaveProperty('ok', false); + const result = await integration.getSchemas(); + expect(result.error?.message).toBe('Could not load schema'); }); }); @@ -200,7 +207,8 @@ describe('Integration', () => { (error as { code?: string }).code = 'ENOENT'; return Promise.reject(error); }); - await expect(integration.getStatic('/logo.png')).resolves.toHaveProperty('ok', false); + const result = await integration.getStatic('/logo.png'); + await expect(result.error?.message).toContain('File not found'); }); }); @@ -240,13 +248,21 @@ describe('Integration', () => { }); it('should catch and fail gracefully on invalid sample data', async () => { - const sampleConfig = { sampleData: { path: 'sample.json' } }; - integration.getConfig = jest.fn().mockResolvedValue({ ok: true, value: sampleConfig }); - jest.spyOn(fs, 'readFile').mockResolvedValue('[{"closingBracket": false]'); + jest + .spyOn(fs, 'readFile') + .mockResolvedValueOnce( + JSON.stringify({ + ...TEST_INTEGRATION_CONFIG, + sampleData: { + path: 'sample.json', + }, + }) + ) + .mockResolvedValue('[{"closingBracket": false]'); const result = await integration.getSampleData(); - expect(result.ok).toBe(false); + expect(result.error?.message).toBe('Unable to parse file as JSON or NDJson'); }); }); }); diff --git a/server/adaptors/integrations/repository/__test__/json_data_adaptor.test.ts b/server/adaptors/integrations/repository/__test__/json_data_adaptor.test.ts index e52f725634..8c703b7516 100644 --- a/server/adaptors/integrations/repository/__test__/json_data_adaptor.test.ts +++ b/server/adaptors/integrations/repository/__test__/json_data_adaptor.test.ts @@ -86,20 +86,26 @@ describe('JSON Data Adaptor', () => { it('Should reject any attempts to read a file with a type', async () => { const adaptor = new JsonCatalogDataAdaptor(TEST_CATALOG_NO_SERIALIZATION); - await expect(adaptor.readFile('logs-1.0.0.json', 'schemas')).resolves.toHaveProperty( - 'ok', - false + const result = await adaptor.readFile('logs-1.0.0.json', 'schemas'); + await expect(result.error?.message).toBe( + 'JSON adaptor does not support subtypes (isConfigLocalized: true)' ); }); it('Should reject any attempts to read a raw file', async () => { const adaptor = new JsonCatalogDataAdaptor(TEST_CATALOG_NO_SERIALIZATION); - await expect(adaptor.readFileRaw('logo.svg', 'static')).resolves.toHaveProperty('ok', false); + const result = await adaptor.readFileRaw('logo.svg', 'static'); + await expect(result.error?.message).toBe( + 'JSON adaptor does not support raw files (isConfigLocalized: true)' + ); }); it('Should reject nested directory searching', async () => { const adaptor = new JsonCatalogDataAdaptor(TEST_CATALOG_NO_SERIALIZATION); - await expect(adaptor.findIntegrations('sample1')).resolves.toHaveProperty('ok', false); + const result = await adaptor.findIntegrations('sample1'); + await expect(result.error?.message).toBe( + 'Finding integrations for custom dirs not supported for JSONreader' + ); }); it('Should report unknown directory type if integration list is empty', async () => { diff --git a/server/adaptors/integrations/repository/integration_reader.ts b/server/adaptors/integrations/repository/integration_reader.ts index c545e06c2f..0f28c5d420 100644 --- a/server/adaptors/integrations/repository/integration_reader.ts +++ b/server/adaptors/integrations/repository/integration_reader.ts @@ -105,7 +105,10 @@ export class IntegrationReader { version?: string ): Promise> { if ((await this.reader.getDirectoryType()) !== 'integration') { - return { ok: false, error: new Error(`${this.directory} is not a valid integration`) }; + return { + ok: false, + error: new Error(`${this.directory} is not a valid integration directory`), + }; } const maybeVersion: string | null = version ? version : await this.getLatestVersion();