From 4af88db1cbc6789d408e99800e508c0964ae36e5 Mon Sep 17 00:00:00 2001 From: Kristen Tian Date: Thu, 8 Jun 2023 21:54:26 -0700 Subject: [PATCH 1/6] Enable data client with sample data server side --- config/opensearch_dashboards.yml | 2 +- src/plugins/home/opensearch_dashboards.json | 2 +- .../components/tutorial_directory.js | 2 +- .../public/application/sample_data_client.js | 15 ++- .../sample_data/data_sets/ecommerce/index.ts | 2 +- .../data_sets/ecommerce/saved_objects.ts | 1 + .../services/sample_data/routes/install.ts | 23 ++-- .../services/sample_data/routes/list.ts | 115 ++++++++++-------- .../services/sample_data/routes/uninstall.ts | 28 ++--- 9 files changed, 110 insertions(+), 80 deletions(-) diff --git a/config/opensearch_dashboards.yml b/config/opensearch_dashboards.yml index d7e0d390b0fc..f26866c37305 100644 --- a/config/opensearch_dashboards.yml +++ b/config/opensearch_dashboards.yml @@ -230,7 +230,7 @@ # vis_builder.enabled: false # Set the value of this setting to true to enable multiple data source feature. -#data_source.enabled: false +data_source.enabled: false # Set the value of these settings to customize crypto materials to encryption saved credentials # in data sources. #data_source.encryption.wrappingKeyName: 'changeme' diff --git a/src/plugins/home/opensearch_dashboards.json b/src/plugins/home/opensearch_dashboards.json index 3cb42faaeec2..35a81bc7adb9 100644 --- a/src/plugins/home/opensearch_dashboards.json +++ b/src/plugins/home/opensearch_dashboards.json @@ -4,7 +4,7 @@ "server": true, "ui": true, "requiredPlugins": ["data", "urlForwarding"], - "optionalPlugins": ["usageCollection", "telemetry"], + "optionalPlugins": ["usageCollection", "telemetry", "dataSource"], "requiredBundles": [ "opensearchDashboardsReact" ] diff --git a/src/plugins/home/public/application/components/tutorial_directory.js b/src/plugins/home/public/application/components/tutorial_directory.js index ce9cf071d3a0..b474f7521ba2 100644 --- a/src/plugins/home/public/application/components/tutorial_directory.js +++ b/src/plugins/home/public/application/components/tutorial_directory.js @@ -248,7 +248,7 @@ class TutorialDirectoryUi extends React.Component {

diff --git a/src/plugins/home/public/application/sample_data_client.js b/src/plugins/home/public/application/sample_data_client.js index bf30f516dfc7..1845bf497123 100644 --- a/src/plugins/home/public/application/sample_data_client.js +++ b/src/plugins/home/public/application/sample_data_client.js @@ -36,8 +36,9 @@ function clearIndexPatternsCache() { getServices().indexPatternService.clearCache(); } -export async function listSampleDataSets() { - return await getServices().http.get(sampleDataUrl); +export async function listSampleDataSets(dataSourceId) { + const query = buildQuery(dataSourceId); + return await getServices().http.get(sampleDataUrl, { query }); } export async function installSampleDataSet(id, sampleDataDefaultIndex) { @@ -64,3 +65,13 @@ export async function uninstallSampleDataSet(id, sampleDataDefaultIndex) { clearIndexPatternsCache(); } + +function buildQuery(dataSourceId) { + const query = {}; + + if (dataSourceId) { + query.data_source = dataSourceId; + } + + return query; +} diff --git a/src/plugins/home/server/services/sample_data/data_sets/ecommerce/index.ts b/src/plugins/home/server/services/sample_data/data_sets/ecommerce/index.ts index 43cf0925a8b4..506ef0b58e4c 100644 --- a/src/plugins/home/server/services/sample_data/data_sets/ecommerce/index.ts +++ b/src/plugins/home/server/services/sample_data/data_sets/ecommerce/index.ts @@ -49,7 +49,7 @@ export const ecommerceSpecProvider = function (): SampleDatasetSchema { description: ecommerceDescription, previewImagePath: '/plugins/home/assets/sample_data_resources/ecommerce/dashboard.png', darkPreviewImagePath: '/plugins/home/assets/sample_data_resources/ecommerce/dashboard_dark.png', - overviewDashboard: '722b74f0-b882-11e8-a6d9-e546fe2bba5f', + overviewDashboard: '722b74f0-b882-11e8-a6d9-e546fe2bba5f', // todo: add dataSourceId appLinks: initialAppLinks, defaultIndex: 'ff959d40-b880-11e8-a6d9-e546fe2bba5f', savedObjects: getSavedObjects(), diff --git a/src/plugins/home/server/services/sample_data/data_sets/ecommerce/saved_objects.ts b/src/plugins/home/server/services/sample_data/data_sets/ecommerce/saved_objects.ts index 81fb2fa21256..515d5e3c6b83 100644 --- a/src/plugins/home/server/services/sample_data/data_sets/ecommerce/saved_objects.ts +++ b/src/plugins/home/server/services/sample_data/data_sets/ecommerce/saved_objects.ts @@ -33,6 +33,7 @@ import { i18n } from '@osd/i18n'; import { SavedObject } from 'opensearch-dashboards/server'; +// todo: add dataSourceId in id export const getSavedObjects = (): SavedObject[] => [ { id: '37cc8650-b882-11e8-a6d9-e546fe2bba5f', diff --git a/src/plugins/home/server/services/sample_data/routes/install.ts b/src/plugins/home/server/services/sample_data/routes/install.ts index eec5f0d5bc86..5f2cd8b77c12 100644 --- a/src/plugins/home/server/services/sample_data/routes/install.ts +++ b/src/plugins/home/server/services/sample_data/routes/install.ts @@ -103,13 +103,20 @@ export function createInstallRoute( { path: '/api/sample_data/{id}', validate: { - params: schema.object({ id: schema.string() }), + params: schema.object({ + id: schema.string(), + }), // TODO validate now as date - query: schema.object({ now: schema.maybe(schema.string()) }), + query: schema.object({ + now: schema.maybe(schema.string()), + data_source_id: schema.maybe(schema.string()), + }), }, }, async (context, req, res) => { const { params, query } = req; + const dataSourceId = query.data_source_id; + const sampleDataset = sampleDatasets.find(({ id }) => id === params.id); if (!sampleDataset) { return res.notFound(); @@ -118,13 +125,17 @@ export function createInstallRoute( const now = query.now ? new Date(query.now) : new Date(); const nowReference = dateToIso8601IgnoringTime(now); const counts = {}; + const caller = dataSourceId + ? context.dataSource.opensearch.legacy.getClient(dataSourceId).callAPI + : context.core.opensearch.legacy.client.callAsCurrentUser; + for (let i = 0; i < sampleDataset.dataIndices.length; i++) { const dataIndexConfig = sampleDataset.dataIndices[i]; const index = createIndexName(sampleDataset.id, dataIndexConfig.id); // clean up any old installation of dataset try { - await context.core.opensearch.legacy.client.callAsCurrentUser('indices.delete', { + await caller('indices.delete', { index, }); } catch (err) { @@ -139,10 +150,7 @@ export function createInstallRoute( mappings: { properties: dataIndexConfig.fields }, }, }; - await context.core.opensearch.legacy.client.callAsCurrentUser( - 'indices.create', - createIndexParams - ); + await caller('indices.create', createIndexParams); } catch (err) { const errMsg = `Unable to create sample data index "${index}", error: ${err.message}`; logger.warn(errMsg); @@ -167,6 +175,7 @@ export function createInstallRoute( let createResults; try { + // todo: double check on data source id createResults = await context.core.savedObjects.client.bulkCreate( sampleDataset.savedObjects.map(({ version, ...savedObject }) => savedObject), { overwrite: true } diff --git a/src/plugins/home/server/services/sample_data/routes/list.ts b/src/plugins/home/server/services/sample_data/routes/list.ts index a0665132dd10..ed571b6ae5d7 100644 --- a/src/plugins/home/server/services/sample_data/routes/list.ts +++ b/src/plugins/home/server/services/sample_data/routes/list.ts @@ -29,6 +29,7 @@ */ import { IRouter } from 'src/core/server'; +import { schema } from '@osd/config-schema'; import { SampleDatasetSchema } from '../lib/sample_dataset_registry_types'; import { createIndexName } from '../lib/create_index_name'; @@ -37,66 +38,78 @@ const INSTALLED = 'installed'; const UNKNOWN = 'unknown'; export const createListRoute = (router: IRouter, sampleDatasets: SampleDatasetSchema[]) => { - router.get({ path: '/api/sample_data', validate: false }, async (context, req, res) => { - const registeredSampleDatasets = sampleDatasets.map((sampleDataset) => { - return { - id: sampleDataset.id, - name: sampleDataset.name, - description: sampleDataset.description, - previewImagePath: sampleDataset.previewImagePath, - darkPreviewImagePath: sampleDataset.darkPreviewImagePath, - overviewDashboard: sampleDataset.overviewDashboard, - appLinks: sampleDataset.appLinks, - defaultIndex: sampleDataset.defaultIndex, - dataIndices: sampleDataset.dataIndices.map(({ id }) => ({ id })), - status: sampleDataset.status, - statusMsg: sampleDataset.statusMsg, - }; - }); - const isInstalledPromises = registeredSampleDatasets.map(async (sampleDataset) => { - for (let i = 0; i < sampleDataset.dataIndices.length; i++) { - const dataIndexConfig = sampleDataset.dataIndices[i]; - const index = createIndexName(sampleDataset.id, dataIndexConfig.id); - try { - const indexExists = await context.core.opensearch.legacy.client.callAsCurrentUser( - 'indices.exists', - { index } - ); - if (!indexExists) { - sampleDataset.status = NOT_INSTALLED; + router.get( + { + path: '/api/sample_data', + validate: { + query: schema.object({ data_source_id: schema.maybe(schema.string()) }), + }, + }, + async (context, req, res) => { + const registeredSampleDatasets = sampleDatasets.map((sampleDataset) => { + return { + id: sampleDataset.id, + name: sampleDataset.name, + description: sampleDataset.description, + previewImagePath: sampleDataset.previewImagePath, + darkPreviewImagePath: sampleDataset.darkPreviewImagePath, + overviewDashboard: sampleDataset.overviewDashboard, + appLinks: sampleDataset.appLinks, + defaultIndex: sampleDataset.defaultIndex, + dataIndices: sampleDataset.dataIndices.map(({ id }) => ({ id })), + status: sampleDataset.status, + statusMsg: sampleDataset.statusMsg, + }; + }); + const isInstalledPromises = registeredSampleDatasets.map(async (sampleDataset) => { + const dataSourceId = req.query.data_source_id; + + const caller = dataSourceId + ? context.dataSource.opensearch.legacy.getClient(dataSourceId).callAPI + : context.core.opensearch.legacy.client.callAsCurrentUser; + + for (let i = 0; i < sampleDataset.dataIndices.length; i++) { + const dataIndexConfig = sampleDataset.dataIndices[i]; + const index = createIndexName(sampleDataset.id, dataIndexConfig.id); + try { + const indexExists = await caller('indices.exists', { index }); + if (!indexExists) { + sampleDataset.status = NOT_INSTALLED; + return; + } + + const { count } = await caller('count', { + index, + }); + if (count === 0) { + sampleDataset.status = NOT_INSTALLED; + return; + } + } catch (err) { + sampleDataset.status = UNKNOWN; + sampleDataset.statusMsg = err.message; return; } - - const { count } = await context.core.opensearch.legacy.client.callAsCurrentUser('count', { - index, - }); - if (count === 0) { + } + try { + // todo: prepend dataSourceId + await context.core.savedObjects.client.get('dashboard', sampleDataset.overviewDashboard); + } catch (err) { + if (context.core.savedObjects.client.errors.isNotFoundError(err)) { sampleDataset.status = NOT_INSTALLED; return; } - } catch (err) { + sampleDataset.status = UNKNOWN; sampleDataset.statusMsg = err.message; return; } - } - try { - await context.core.savedObjects.client.get('dashboard', sampleDataset.overviewDashboard); - } catch (err) { - if (context.core.savedObjects.client.errors.isNotFoundError(err)) { - sampleDataset.status = NOT_INSTALLED; - return; - } - - sampleDataset.status = UNKNOWN; - sampleDataset.statusMsg = err.message; - return; - } - sampleDataset.status = INSTALLED; - }); + sampleDataset.status = INSTALLED; + }); - await Promise.all(isInstalledPromises); - return res.ok({ body: registeredSampleDatasets }); - }); + await Promise.all(isInstalledPromises); + return res.ok({ body: registeredSampleDatasets }); + } + ); }; diff --git a/src/plugins/home/server/services/sample_data/routes/uninstall.ts b/src/plugins/home/server/services/sample_data/routes/uninstall.ts index e38a2224aae8..9328e3d83461 100644 --- a/src/plugins/home/server/services/sample_data/routes/uninstall.ts +++ b/src/plugins/home/server/services/sample_data/routes/uninstall.ts @@ -45,34 +45,29 @@ export function createUninstallRoute( path: '/api/sample_data/{id}', validate: { params: schema.object({ id: schema.string() }), + query: schema.object({ + data_source_id: schema.maybe(schema.string()), + }), }, }, - async ( - { - core: { - opensearch: { - legacy: { - client: { callAsCurrentUser }, - }, - }, - savedObjects: { client: savedObjectsClient }, - }, - }, - request, - response - ) => { + async (context, request, response) => { const sampleDataset = sampleDatasets.find(({ id }) => id === request.params.id); + const dataSourceId = request.query.data_source_id; if (!sampleDataset) { return response.notFound(); } + const caller = dataSourceId + ? context.dataSource.opensearch.legacy.getClient(dataSourceId).callAPI + : context.core.opensearch.legacy.client.callAsCurrentUser; + for (let i = 0; i < sampleDataset.dataIndices.length; i++) { const dataIndexConfig = sampleDataset.dataIndices[i]; const index = createIndexName(sampleDataset.id, dataIndexConfig.id); try { - await callAsCurrentUser('indices.delete', { index }); + await caller('indices.delete', { index }); } catch (err) { return response.customError({ statusCode: err.status, @@ -83,8 +78,9 @@ export function createUninstallRoute( } } + // todo: dataSourceId const deletePromises = sampleDataset.savedObjects.map(({ type, id }) => - savedObjectsClient.delete(type, id) + context.core.savedObjects.client.delete(type, id) ); try { From 7055ed81faf72aaa69eac4daaf8580a780a5d68e Mon Sep 17 00:00:00 2001 From: Kristen Tian Date: Fri, 9 Jun 2023 17:22:11 -0700 Subject: [PATCH 2/6] Add dataSourceId into savedObject Signed-off-by: Kristen Tian --- .../sample_data/data_sets/ecommerce/index.ts | 4 +++- .../sample_data/data_sets/flights/index.ts | 4 +++- .../sample_data/data_sets/logs/index.ts | 4 +++- .../services/sample_data/data_sets/util.ts | 20 +++++++++++++++++++ .../lib/sample_dataset_registry_types.ts | 2 +- .../services/sample_data/routes/install.ts | 13 +++++++----- .../services/sample_data/routes/list.ts | 5 ++++- .../services/sample_data/routes/uninstall.ts | 4 ++-- 8 files changed, 44 insertions(+), 12 deletions(-) create mode 100644 src/plugins/home/server/services/sample_data/data_sets/util.ts diff --git a/src/plugins/home/server/services/sample_data/data_sets/ecommerce/index.ts b/src/plugins/home/server/services/sample_data/data_sets/ecommerce/index.ts index 506ef0b58e4c..b33580086c68 100644 --- a/src/plugins/home/server/services/sample_data/data_sets/ecommerce/index.ts +++ b/src/plugins/home/server/services/sample_data/data_sets/ecommerce/index.ts @@ -33,6 +33,7 @@ import { i18n } from '@osd/i18n'; import { getSavedObjects } from './saved_objects'; import { fieldMappings } from './field_mappings'; import { SampleDatasetSchema, AppLinkSchema } from '../../lib/sample_dataset_registry_types'; +import { getSavedObjectsWithDataSource } from '../util'; const ecommerceName = i18n.translate('home.sampleData.ecommerceSpecTitle', { defaultMessage: 'Sample eCommerce orders', @@ -52,7 +53,8 @@ export const ecommerceSpecProvider = function (): SampleDatasetSchema { overviewDashboard: '722b74f0-b882-11e8-a6d9-e546fe2bba5f', // todo: add dataSourceId appLinks: initialAppLinks, defaultIndex: 'ff959d40-b880-11e8-a6d9-e546fe2bba5f', - savedObjects: getSavedObjects(), + savedObjects: (dataSourceId: string) => + getSavedObjectsWithDataSource(getSavedObjects(), dataSourceId), dataIndices: [ { id: 'ecommerce', diff --git a/src/plugins/home/server/services/sample_data/data_sets/flights/index.ts b/src/plugins/home/server/services/sample_data/data_sets/flights/index.ts index e90cdaea3b8a..100fb80b55c6 100644 --- a/src/plugins/home/server/services/sample_data/data_sets/flights/index.ts +++ b/src/plugins/home/server/services/sample_data/data_sets/flights/index.ts @@ -33,6 +33,7 @@ import { i18n } from '@osd/i18n'; import { getSavedObjects } from './saved_objects'; import { fieldMappings } from './field_mappings'; import { SampleDatasetSchema, AppLinkSchema } from '../../lib/sample_dataset_registry_types'; +import { getSavedObjectsWithDataSource } from '../util'; const flightsName = i18n.translate('home.sampleData.flightsSpecTitle', { defaultMessage: 'Sample flight data', @@ -52,7 +53,8 @@ export const flightsSpecProvider = function (): SampleDatasetSchema { overviewDashboard: '7adfa750-4c81-11e8-b3d7-01146121b73d', appLinks: initialAppLinks, defaultIndex: 'd3d7af60-4c81-11e8-b3d7-01146121b73d', - savedObjects: getSavedObjects(), + savedObjects: (dataSourceId: string) => + getSavedObjectsWithDataSource(getSavedObjects(), dataSourceId), dataIndices: [ { id: 'flights', diff --git a/src/plugins/home/server/services/sample_data/data_sets/logs/index.ts b/src/plugins/home/server/services/sample_data/data_sets/logs/index.ts index 1438de8ad64f..5a679d63abf7 100644 --- a/src/plugins/home/server/services/sample_data/data_sets/logs/index.ts +++ b/src/plugins/home/server/services/sample_data/data_sets/logs/index.ts @@ -33,6 +33,7 @@ import { i18n } from '@osd/i18n'; import { getSavedObjects } from './saved_objects'; import { fieldMappings } from './field_mappings'; import { SampleDatasetSchema, AppLinkSchema } from '../../lib/sample_dataset_registry_types'; +import { getSavedObjectsWithDataSource } from '../util'; const logsName = i18n.translate('home.sampleData.logsSpecTitle', { defaultMessage: 'Sample web logs', @@ -52,7 +53,8 @@ export const logsSpecProvider = function (): SampleDatasetSchema { overviewDashboard: 'edf84fe0-e1a0-11e7-b6d5-4dc382ef7f5b', appLinks: initialAppLinks, defaultIndex: '90943e30-9a47-11e8-b64d-95841ca0b247', - savedObjects: getSavedObjects(), + savedObjects: (dataSourceId: string) => + getSavedObjectsWithDataSource(getSavedObjects(), dataSourceId), dataIndices: [ { id: 'logs', diff --git a/src/plugins/home/server/services/sample_data/data_sets/util.ts b/src/plugins/home/server/services/sample_data/data_sets/util.ts new file mode 100644 index 000000000000..86125750aa03 --- /dev/null +++ b/src/plugins/home/server/services/sample_data/data_sets/util.ts @@ -0,0 +1,20 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { SavedObject } from 'opensearch-dashboards/server'; + +export const getSavedObjectsWithDataSource = ( + saveObjectList: SavedObject[], + dataSourceId?: string +): SavedObject[] => { + if (dataSourceId) { + return saveObjectList.map((saveObject) => ({ + ...saveObject, + id: `${dataSourceId}_` + saveObject.id, + })); + } + + return saveObjectList; +}; diff --git a/src/plugins/home/server/services/sample_data/lib/sample_dataset_registry_types.ts b/src/plugins/home/server/services/sample_data/lib/sample_dataset_registry_types.ts index 86ac5bcc5779..779d2775882b 100644 --- a/src/plugins/home/server/services/sample_data/lib/sample_dataset_registry_types.ts +++ b/src/plugins/home/server/services/sample_data/lib/sample_dataset_registry_types.ts @@ -95,7 +95,7 @@ export interface SampleDatasetSchema { // OpenSearch Dashboards saved objects (index patter, visualizations, dashboard, ...) // Should provide a nice demo of OpenSearch Dashboards's functionality with the sample data set - savedObjects: Array>; + savedObjects: (dataSourceId?: string) => Array>; dataIndices: DataIndexSchema[]; status?: string | undefined; statusMsg?: unknown; diff --git a/src/plugins/home/server/services/sample_data/routes/install.ts b/src/plugins/home/server/services/sample_data/routes/install.ts index 5f2cd8b77c12..0e9d736492fa 100644 --- a/src/plugins/home/server/services/sample_data/routes/install.ts +++ b/src/plugins/home/server/services/sample_data/routes/install.ts @@ -30,6 +30,7 @@ import { schema } from '@osd/config-schema'; import { IRouter, Logger, RequestHandlerContext } from 'src/core/server'; +import { data } from 'jquery'; import { SampleDatasetSchema } from '../lib/sample_dataset_registry_types'; import { createIndexName } from '../lib/create_index_name'; import { @@ -44,7 +45,7 @@ const insertDataIntoIndex = ( dataIndexConfig: any, index: string, nowReference: string, - context: RequestHandlerContext, + caller: (endpoint: string, clientParams?: Record, options?: any) => Promise, logger: Logger ) => { function updateTimestamps(doc: any) { @@ -73,7 +74,8 @@ const insertDataIntoIndex = ( bulk.push(insertCmd); bulk.push(updateTimestamps(doc)); }); - const resp = await context.core.opensearch.legacy.client.callAsCurrentUser('bulk', { + + const resp = await caller('bulk', { body: bulk, }); if (resp.errors) { @@ -162,7 +164,7 @@ export function createInstallRoute( dataIndexConfig, index, nowReference, - context, + caller, logger ); (counts as any)[index] = count; @@ -174,10 +176,11 @@ export function createInstallRoute( } let createResults; + const savedObjectsList = sampleDataset.savedObjects(dataSourceId); try { // todo: double check on data source id createResults = await context.core.savedObjects.client.bulkCreate( - sampleDataset.savedObjects.map(({ version, ...savedObject }) => savedObject), + savedObjectsList.map(({ version, ...savedObject }) => savedObject), { overwrite: true } ); } catch (err) { @@ -201,7 +204,7 @@ export function createInstallRoute( return res.ok({ body: { opensearchIndicesCreated: counts, - opensearchDashboardsSavedObjectsLoaded: sampleDataset.savedObjects.length, + opensearchDashboardsSavedObjectsLoaded: savedObjectsList.length, }, }); } diff --git a/src/plugins/home/server/services/sample_data/routes/list.ts b/src/plugins/home/server/services/sample_data/routes/list.ts index ed571b6ae5d7..8c09effb0d03 100644 --- a/src/plugins/home/server/services/sample_data/routes/list.ts +++ b/src/plugins/home/server/services/sample_data/routes/list.ts @@ -93,7 +93,10 @@ export const createListRoute = (router: IRouter, sampleDatasets: SampleDatasetSc } try { // todo: prepend dataSourceId - await context.core.savedObjects.client.get('dashboard', sampleDataset.overviewDashboard); + const dashboardId = dataSourceId + ? `${dataSourceId}_${sampleDataset.overviewDashboard}` + : sampleDataset.overviewDashboard; + await context.core.savedObjects.client.get('dashboard', dashboardId); } catch (err) { if (context.core.savedObjects.client.errors.isNotFoundError(err)) { sampleDataset.status = NOT_INSTALLED; diff --git a/src/plugins/home/server/services/sample_data/routes/uninstall.ts b/src/plugins/home/server/services/sample_data/routes/uninstall.ts index 9328e3d83461..d556a675395d 100644 --- a/src/plugins/home/server/services/sample_data/routes/uninstall.ts +++ b/src/plugins/home/server/services/sample_data/routes/uninstall.ts @@ -78,8 +78,8 @@ export function createUninstallRoute( } } - // todo: dataSourceId - const deletePromises = sampleDataset.savedObjects.map(({ type, id }) => + const savedObjectsList = sampleDataset.savedObjects(dataSourceId); + const deletePromises = savedObjectsList.map(({ type, id }) => context.core.savedObjects.client.delete(type, id) ); From 28bd84fec17c6b6a2ec05ae38b38f83c54cfecb9 Mon Sep 17 00:00:00 2001 From: Kristen Tian Date: Sun, 11 Jun 2023 15:43:54 -0700 Subject: [PATCH 3/6] Functional list, install uninstall Signed-off-by: Kristen Tian --- config/opensearch_dashboards.yml | 2 +- .../components/tutorial_directory.js | 2 +- .../public/application/sample_data_client.js | 12 ++-- .../sample_data/data_sets/ecommerce/index.ts | 11 +-- .../data_sets/ecommerce/saved_objects.ts | 1 - .../sample_data/data_sets/flights/index.ts | 9 ++- .../sample_data/data_sets/logs/index.ts | 9 ++- .../services/sample_data/data_sets/util.ts | 70 +++++++++++++++++-- .../lib/sample_dataset_registry_types.ts | 4 +- .../services/sample_data/routes/install.ts | 23 +++++- .../services/sample_data/routes/list.ts | 11 +-- .../services/sample_data/routes/uninstall.ts | 1 + .../sample_data/sample_data_registry.ts | 4 +- 13 files changed, 125 insertions(+), 34 deletions(-) diff --git a/config/opensearch_dashboards.yml b/config/opensearch_dashboards.yml index f26866c37305..d7e0d390b0fc 100644 --- a/config/opensearch_dashboards.yml +++ b/config/opensearch_dashboards.yml @@ -230,7 +230,7 @@ # vis_builder.enabled: false # Set the value of this setting to true to enable multiple data source feature. -data_source.enabled: false +#data_source.enabled: false # Set the value of these settings to customize crypto materials to encryption saved credentials # in data sources. #data_source.encryption.wrappingKeyName: 'changeme' diff --git a/src/plugins/home/public/application/components/tutorial_directory.js b/src/plugins/home/public/application/components/tutorial_directory.js index b474f7521ba2..ce9cf071d3a0 100644 --- a/src/plugins/home/public/application/components/tutorial_directory.js +++ b/src/plugins/home/public/application/components/tutorial_directory.js @@ -248,7 +248,7 @@ class TutorialDirectoryUi extends React.Component {

diff --git a/src/plugins/home/public/application/sample_data_client.js b/src/plugins/home/public/application/sample_data_client.js index 1845bf497123..045736c428f6 100644 --- a/src/plugins/home/public/application/sample_data_client.js +++ b/src/plugins/home/public/application/sample_data_client.js @@ -41,8 +41,9 @@ export async function listSampleDataSets(dataSourceId) { return await getServices().http.get(sampleDataUrl, { query }); } -export async function installSampleDataSet(id, sampleDataDefaultIndex) { - await getServices().http.post(`${sampleDataUrl}/${id}`); +export async function installSampleDataSet(id, sampleDataDefaultIndex, dataSourceId) { + const query = buildQuery(dataSourceId); + await getServices().http.post(`${sampleDataUrl}/${id}`, { query }); if (getServices().uiSettings.isDefault('defaultIndex')) { getServices().uiSettings.set('defaultIndex', sampleDataDefaultIndex); @@ -51,8 +52,9 @@ export async function installSampleDataSet(id, sampleDataDefaultIndex) { clearIndexPatternsCache(); } -export async function uninstallSampleDataSet(id, sampleDataDefaultIndex) { - await getServices().http.delete(`${sampleDataUrl}/${id}`); +export async function uninstallSampleDataSet(id, sampleDataDefaultIndex, dataSourceId) { + const query = buildQuery(dataSourceId); + await getServices().http.delete(`${sampleDataUrl}/${id}`, { query }); const uiSettings = getServices().uiSettings; @@ -70,7 +72,7 @@ function buildQuery(dataSourceId) { const query = {}; if (dataSourceId) { - query.data_source = dataSourceId; + query.data_source_id = dataSourceId; } return query; diff --git a/src/plugins/home/server/services/sample_data/data_sets/ecommerce/index.ts b/src/plugins/home/server/services/sample_data/data_sets/ecommerce/index.ts index b33580086c68..898e4f7f5cba 100644 --- a/src/plugins/home/server/services/sample_data/data_sets/ecommerce/index.ts +++ b/src/plugins/home/server/services/sample_data/data_sets/ecommerce/index.ts @@ -43,6 +43,8 @@ const ecommerceDescription = i18n.translate('home.sampleData.ecommerceSpecDescri }); const initialAppLinks = [] as AppLinkSchema[]; +const DEFAULT_INDEX = 'ff959d40-b880-11e8-a6d9-e546fe2bba5f'; + export const ecommerceSpecProvider = function (): SampleDatasetSchema { return { id: 'ecommerce', @@ -50,11 +52,12 @@ export const ecommerceSpecProvider = function (): SampleDatasetSchema { description: ecommerceDescription, previewImagePath: '/plugins/home/assets/sample_data_resources/ecommerce/dashboard.png', darkPreviewImagePath: '/plugins/home/assets/sample_data_resources/ecommerce/dashboard_dark.png', - overviewDashboard: '722b74f0-b882-11e8-a6d9-e546fe2bba5f', // todo: add dataSourceId + overviewDashboard: '722b74f0-b882-11e8-a6d9-e546fe2bba5f', appLinks: initialAppLinks, - defaultIndex: 'ff959d40-b880-11e8-a6d9-e546fe2bba5f', - savedObjects: (dataSourceId: string) => - getSavedObjectsWithDataSource(getSavedObjects(), dataSourceId), + defaultIndex: (dataSourceId?: string) => + dataSourceId ? `${dataSourceId}_` + DEFAULT_INDEX : DEFAULT_INDEX, + savedObjects: (dataSourceId?: string, dataSourceTitle?: string) => + getSavedObjectsWithDataSource(getSavedObjects(), dataSourceId, dataSourceTitle), dataIndices: [ { id: 'ecommerce', diff --git a/src/plugins/home/server/services/sample_data/data_sets/ecommerce/saved_objects.ts b/src/plugins/home/server/services/sample_data/data_sets/ecommerce/saved_objects.ts index 515d5e3c6b83..81fb2fa21256 100644 --- a/src/plugins/home/server/services/sample_data/data_sets/ecommerce/saved_objects.ts +++ b/src/plugins/home/server/services/sample_data/data_sets/ecommerce/saved_objects.ts @@ -33,7 +33,6 @@ import { i18n } from '@osd/i18n'; import { SavedObject } from 'opensearch-dashboards/server'; -// todo: add dataSourceId in id export const getSavedObjects = (): SavedObject[] => [ { id: '37cc8650-b882-11e8-a6d9-e546fe2bba5f', diff --git a/src/plugins/home/server/services/sample_data/data_sets/flights/index.ts b/src/plugins/home/server/services/sample_data/data_sets/flights/index.ts index 100fb80b55c6..e60654107683 100644 --- a/src/plugins/home/server/services/sample_data/data_sets/flights/index.ts +++ b/src/plugins/home/server/services/sample_data/data_sets/flights/index.ts @@ -43,6 +43,8 @@ const flightsDescription = i18n.translate('home.sampleData.flightsSpecDescriptio }); const initialAppLinks = [] as AppLinkSchema[]; +const DEFAULT_INDEX = 'd3d7af60-4c81-11e8-b3d7-01146121b73d'; + export const flightsSpecProvider = function (): SampleDatasetSchema { return { id: 'flights', @@ -52,9 +54,10 @@ export const flightsSpecProvider = function (): SampleDatasetSchema { darkPreviewImagePath: '/plugins/home/assets/sample_data_resources/flights/dashboard_dark.png', overviewDashboard: '7adfa750-4c81-11e8-b3d7-01146121b73d', appLinks: initialAppLinks, - defaultIndex: 'd3d7af60-4c81-11e8-b3d7-01146121b73d', - savedObjects: (dataSourceId: string) => - getSavedObjectsWithDataSource(getSavedObjects(), dataSourceId), + defaultIndex: (dataSourceId?: string) => + dataSourceId ? `${dataSourceId}_` + DEFAULT_INDEX : DEFAULT_INDEX, + savedObjects: (dataSourceId?: string, dataSourceTitle?: string) => + getSavedObjectsWithDataSource(getSavedObjects(), dataSourceId, dataSourceTitle), dataIndices: [ { id: 'flights', diff --git a/src/plugins/home/server/services/sample_data/data_sets/logs/index.ts b/src/plugins/home/server/services/sample_data/data_sets/logs/index.ts index 5a679d63abf7..c61aeb059b21 100644 --- a/src/plugins/home/server/services/sample_data/data_sets/logs/index.ts +++ b/src/plugins/home/server/services/sample_data/data_sets/logs/index.ts @@ -43,6 +43,8 @@ const logsDescription = i18n.translate('home.sampleData.logsSpecDescription', { }); const initialAppLinks = [] as AppLinkSchema[]; +const DEFAULT_INDEX = '90943e30-9a47-11e8-b64d-95841ca0b247'; + export const logsSpecProvider = function (): SampleDatasetSchema { return { id: 'logs', @@ -52,9 +54,10 @@ export const logsSpecProvider = function (): SampleDatasetSchema { darkPreviewImagePath: '/plugins/home/assets/sample_data_resources/logs/dashboard_dark.png', overviewDashboard: 'edf84fe0-e1a0-11e7-b6d5-4dc382ef7f5b', appLinks: initialAppLinks, - defaultIndex: '90943e30-9a47-11e8-b64d-95841ca0b247', - savedObjects: (dataSourceId: string) => - getSavedObjectsWithDataSource(getSavedObjects(), dataSourceId), + defaultIndex: (dataSourceId?: string) => + dataSourceId ? `${dataSourceId}_` + DEFAULT_INDEX : DEFAULT_INDEX, + savedObjects: (dataSourceId?: string, dataSourceTitle?: string) => + getSavedObjectsWithDataSource(getSavedObjects(), dataSourceId, dataSourceTitle), dataIndices: [ { id: 'logs', diff --git a/src/plugins/home/server/services/sample_data/data_sets/util.ts b/src/plugins/home/server/services/sample_data/data_sets/util.ts index 86125750aa03..3d3c97308528 100644 --- a/src/plugins/home/server/services/sample_data/data_sets/util.ts +++ b/src/plugins/home/server/services/sample_data/data_sets/util.ts @@ -7,13 +7,73 @@ import { SavedObject } from 'opensearch-dashboards/server'; export const getSavedObjectsWithDataSource = ( saveObjectList: SavedObject[], - dataSourceId?: string + dataSourceId?: string, + dataSourceTitle?: string ): SavedObject[] => { if (dataSourceId) { - return saveObjectList.map((saveObject) => ({ - ...saveObject, - id: `${dataSourceId}_` + saveObject.id, - })); + return saveObjectList.map((saveObject) => { + saveObject.id = `${dataSourceId}_` + saveObject.id; + // update reference + if (saveObject.type === 'dashboard') { + saveObject.references.map((reference) => { + if (reference.id) { + reference.id = `${dataSourceId}_` + reference.id; + } + }); + } + + // update reference + if (saveObject.type === 'visualization' || saveObject.type === 'search') { + const searchSourceString = saveObject.attributes?.kibanaSavedObjectMeta?.searchSourceJSON; + const visStateString = saveObject.attributes?.visState; + + if (searchSourceString) { + const searchSource = JSON.parse(searchSourceString); + if (searchSource.index) { + searchSource.index = `${dataSourceId}_` + searchSource.index; + saveObject.attributes.kibanaSavedObjectMeta.searchSourceJSON = JSON.stringify( + searchSource + ); + } + } + + if (visStateString) { + const visState = JSON.parse(visStateString); + const controlList = visState.params?.controls; + if (controlList) { + controlList.map((control) => { + if (control.indexPattern) { + control.indexPattern = `${dataSourceId}_` + control.indexPattern; + } + }); + } + saveObject.attributes.visState = JSON.stringify(visState); + } + } + + // update reference + if (saveObject.type === 'index-pattern') { + saveObject.references = [ + { + id: `${dataSourceId}`, + type: 'data-source', + name: 'dataSource', + }, + ]; + } + + if (dataSourceTitle) { + if ( + saveObject.type === 'dashboard' || + saveObject.type === 'visualization' || + saveObject.type === 'search' + ) { + saveObject.attributes.title = saveObject.attributes.title + `_${dataSourceTitle}`; + } + } + + return saveObject; + }); } return saveObjectList; diff --git a/src/plugins/home/server/services/sample_data/lib/sample_dataset_registry_types.ts b/src/plugins/home/server/services/sample_data/lib/sample_dataset_registry_types.ts index 779d2775882b..66670b72e8d0 100644 --- a/src/plugins/home/server/services/sample_data/lib/sample_dataset_registry_types.ts +++ b/src/plugins/home/server/services/sample_data/lib/sample_dataset_registry_types.ts @@ -91,11 +91,11 @@ export interface SampleDatasetSchema { appLinks: AppLinkSchema[]; // saved object id of default index-pattern for sample data set - defaultIndex: string; + defaultIndex: (dataSourceId?: string) => string; // OpenSearch Dashboards saved objects (index patter, visualizations, dashboard, ...) // Should provide a nice demo of OpenSearch Dashboards's functionality with the sample data set - savedObjects: (dataSourceId?: string) => Array>; + savedObjects: (dataSourceId?: string, dataSourceTitle?: string) => Array>; dataIndices: DataIndexSchema[]; status?: string | undefined; statusMsg?: unknown; diff --git a/src/plugins/home/server/services/sample_data/routes/install.ts b/src/plugins/home/server/services/sample_data/routes/install.ts index 0e9d736492fa..19063e9f0fcf 100644 --- a/src/plugins/home/server/services/sample_data/routes/install.ts +++ b/src/plugins/home/server/services/sample_data/routes/install.ts @@ -148,7 +148,9 @@ export function createInstallRoute( const createIndexParams = { index, body: { - settings: { index: { number_of_shards: 1, auto_expand_replicas: '0-1' } }, + settings: dataSourceId + ? { index: { number_of_shards: 1 } } + : { index: { number_of_shards: 1, auto_expand_replicas: '0-1' } }, mappings: { properties: dataIndexConfig.fields }, }, }; @@ -175,10 +177,25 @@ export function createInstallRoute( } } + let dataSourceTitle; + if (dataSourceId) { + const dataSource = await context.core.savedObjects.client + .get('data-source', dataSourceId) + .then((response) => { + const attributes: any = response?.attributes || {}; + return { + id: response.id, + title: attributes.title, + }; + }); + + dataSourceTitle = dataSource.title; + } + let createResults; - const savedObjectsList = sampleDataset.savedObjects(dataSourceId); + const savedObjectsList = sampleDataset.savedObjects(dataSourceId, dataSourceTitle); + try { - // todo: double check on data source id createResults = await context.core.savedObjects.client.bulkCreate( savedObjectsList.map(({ version, ...savedObject }) => savedObject), { overwrite: true } diff --git a/src/plugins/home/server/services/sample_data/routes/list.ts b/src/plugins/home/server/services/sample_data/routes/list.ts index 8c09effb0d03..43c167943b65 100644 --- a/src/plugins/home/server/services/sample_data/routes/list.ts +++ b/src/plugins/home/server/services/sample_data/routes/list.ts @@ -46,6 +46,8 @@ export const createListRoute = (router: IRouter, sampleDatasets: SampleDatasetSc }, }, async (context, req, res) => { + const dataSourceId = req.query.data_source_id; + const registeredSampleDatasets = sampleDatasets.map((sampleDataset) => { return { id: sampleDataset.id, @@ -55,15 +57,13 @@ export const createListRoute = (router: IRouter, sampleDatasets: SampleDatasetSc darkPreviewImagePath: sampleDataset.darkPreviewImagePath, overviewDashboard: sampleDataset.overviewDashboard, appLinks: sampleDataset.appLinks, - defaultIndex: sampleDataset.defaultIndex, + defaultIndex: sampleDataset.defaultIndex(dataSourceId), dataIndices: sampleDataset.dataIndices.map(({ id }) => ({ id })), status: sampleDataset.status, statusMsg: sampleDataset.statusMsg, }; }); const isInstalledPromises = registeredSampleDatasets.map(async (sampleDataset) => { - const dataSourceId = req.query.data_source_id; - const caller = dataSourceId ? context.dataSource.opensearch.legacy.getClient(dataSourceId).callAPI : context.core.opensearch.legacy.client.callAsCurrentUser; @@ -73,6 +73,7 @@ export const createListRoute = (router: IRouter, sampleDatasets: SampleDatasetSc const index = createIndexName(sampleDataset.id, dataIndexConfig.id); try { const indexExists = await caller('indices.exists', { index }); + if (!indexExists) { sampleDataset.status = NOT_INSTALLED; return; @@ -81,6 +82,7 @@ export const createListRoute = (router: IRouter, sampleDatasets: SampleDatasetSc const { count } = await caller('count', { index, }); + if (count === 0) { sampleDataset.status = NOT_INSTALLED; return; @@ -92,10 +94,11 @@ export const createListRoute = (router: IRouter, sampleDatasets: SampleDatasetSc } } try { - // todo: prepend dataSourceId + // todo: change to function provider accept dataSourceId const dashboardId = dataSourceId ? `${dataSourceId}_${sampleDataset.overviewDashboard}` : sampleDataset.overviewDashboard; + await context.core.savedObjects.client.get('dashboard', dashboardId); } catch (err) { if (context.core.savedObjects.client.errors.isNotFoundError(err)) { diff --git a/src/plugins/home/server/services/sample_data/routes/uninstall.ts b/src/plugins/home/server/services/sample_data/routes/uninstall.ts index d556a675395d..730de6afff30 100644 --- a/src/plugins/home/server/services/sample_data/routes/uninstall.ts +++ b/src/plugins/home/server/services/sample_data/routes/uninstall.ts @@ -79,6 +79,7 @@ export function createUninstallRoute( } const savedObjectsList = sampleDataset.savedObjects(dataSourceId); + const deletePromises = savedObjectsList.map(({ type, id }) => context.core.savedObjects.client.delete(type, id) ); diff --git a/src/plugins/home/server/services/sample_data/sample_data_registry.ts b/src/plugins/home/server/services/sample_data/sample_data_registry.ts index d90de532c339..7ab4db4681c5 100644 --- a/src/plugins/home/server/services/sample_data/sample_data_registry.ts +++ b/src/plugins/home/server/services/sample_data/sample_data_registry.ts @@ -84,12 +84,12 @@ export class SampleDataRegistry { } const defaultIndexSavedObjectJson = value.savedObjects.find((savedObjectJson: any) => { return ( - savedObjectJson.type === 'index-pattern' && savedObjectJson.id === value.defaultIndex + savedObjectJson.type === 'index-pattern' && savedObjectJson.id === value.defaultIndex() ); }); if (!defaultIndexSavedObjectJson) { throw new Error( - `Unable to register sample dataset spec, defaultIndex: "${value.defaultIndex}" does not exist in savedObjects list.` + `Unable to register sample dataset spec, defaultIndex: "${value.defaultIndex()}" does not exist in savedObjects list.` ); } From f1aae37fc8ce0066447dae3ef22d503d41d25181 Mon Sep 17 00:00:00 2001 From: Kristen Tian Date: Mon, 12 Jun 2023 14:05:55 -0700 Subject: [PATCH 4/6] add change log Signed-off-by: Kristen Tian --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 04dc5d82b498..4b1cb3d616ed 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) - Replace re2 with RegExp in timeline and add unit tests ([#3908](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/3908)) - Add category option within groups for context menus ([#4144](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4144)) - [Saved Object Service] Add Repository Factory Provider ([#4149](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4149)) +- [Multiple DataSource] Backend support for adding sample data ([#4268](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4268)) ### 🐛 Bug Fixes From 8eefe190c13dd87a13d39f53376cb8228057b34f Mon Sep 17 00:00:00 2001 From: Kristen Tian Date: Tue, 13 Jun 2023 13:18:25 -0700 Subject: [PATCH 5/6] address comments Signed-off-by: Kristen Tian --- .../server/client/configure_client.ts | 2 +- .../server/legacy/configure_legacy_client.ts | 2 +- .../services/sample_data/routes/install.ts | 41 ++++++++++--------- 3 files changed, 23 insertions(+), 22 deletions(-) diff --git a/src/plugins/data_source/server/client/configure_client.ts b/src/plugins/data_source/server/client/configure_client.ts index 77a0e067bbc0..acbdfddb3fc4 100644 --- a/src/plugins/data_source/server/client/configure_client.ts +++ b/src/plugins/data_source/server/client/configure_client.ts @@ -74,7 +74,7 @@ export const configureClient = async ( requireDecryption ); } catch (error: any) { - logger.error( + logger.debug( `Failed to get data source client for dataSourceId: [${dataSourceId}]. ${error}: ${error.stack}` ); // Re-throw as DataSourceError diff --git a/src/plugins/data_source/server/legacy/configure_legacy_client.ts b/src/plugins/data_source/server/legacy/configure_legacy_client.ts index 0d074cf77d4a..8341e844edc8 100644 --- a/src/plugins/data_source/server/legacy/configure_legacy_client.ts +++ b/src/plugins/data_source/server/legacy/configure_legacy_client.ts @@ -60,7 +60,7 @@ export const configureLegacyClient = async ( dataSourceId ); } catch (error: any) { - logger.error( + logger.debug( `Failed to get data source client for dataSourceId: [${dataSourceId}]. ${error}: ${error.stack}` ); // Re-throw as DataSourceError diff --git a/src/plugins/home/server/services/sample_data/routes/install.ts b/src/plugins/home/server/services/sample_data/routes/install.ts index 19063e9f0fcf..596231d75e73 100644 --- a/src/plugins/home/server/services/sample_data/routes/install.ts +++ b/src/plugins/home/server/services/sample_data/routes/install.ts @@ -29,8 +29,7 @@ */ import { schema } from '@osd/config-schema'; -import { IRouter, Logger, RequestHandlerContext } from 'src/core/server'; -import { data } from 'jquery'; +import { IRouter, Logger } from 'src/core/server'; import { SampleDatasetSchema } from '../lib/sample_dataset_registry_types'; import { createIndexName } from '../lib/create_index_name'; import { @@ -105,9 +104,7 @@ export function createInstallRoute( { path: '/api/sample_data/{id}', validate: { - params: schema.object({ - id: schema.string(), - }), + params: schema.object({ id: schema.string() }), // TODO validate now as date query: schema.object({ now: schema.maybe(schema.string()), @@ -131,6 +128,25 @@ export function createInstallRoute( ? context.dataSource.opensearch.legacy.getClient(dataSourceId).callAPI : context.core.opensearch.legacy.client.callAsCurrentUser; + let dataSourceTitle; + try { + if (dataSourceId) { + const dataSource = await context.core.savedObjects.client + .get('data-source', dataSourceId) + .then((response) => { + const attributes: any = response?.attributes || {}; + return { + id: response.id, + title: attributes.title, + }; + }); + + dataSourceTitle = dataSource.title; + } + } catch (err) { + return res.internalError({ body: err }); + } + for (let i = 0; i < sampleDataset.dataIndices.length; i++) { const dataIndexConfig = sampleDataset.dataIndices[i]; const index = createIndexName(sampleDataset.id, dataIndexConfig.id); @@ -177,21 +193,6 @@ export function createInstallRoute( } } - let dataSourceTitle; - if (dataSourceId) { - const dataSource = await context.core.savedObjects.client - .get('data-source', dataSourceId) - .then((response) => { - const attributes: any = response?.attributes || {}; - return { - id: response.id, - title: attributes.title, - }; - }); - - dataSourceTitle = dataSource.title; - } - let createResults; const savedObjectsList = sampleDataset.savedObjects(dataSourceId, dataSourceTitle); From 7406970fd2782fee6a52bbdf1bc0c4a936bbb42b Mon Sep 17 00:00:00 2001 From: Kristen Tian Date: Tue, 13 Jun 2023 21:27:11 -0700 Subject: [PATCH 6/6] add ut Signed-off-by: Kristen Tian --- .lycheeexclude | 1 + .../sample_data/data_sets/ecommerce/index.ts | 8 +- .../sample_data/data_sets/flights/index.ts | 8 +- .../sample_data/data_sets/logs/index.ts | 8 +- .../services/sample_data/data_sets/util.ts | 4 + .../lib/sample_dataset_registry_types.ts | 2 +- .../sample_data/routes/install.test.ts | 160 ++++++++++++++++++ .../services/sample_data/routes/install.ts | 8 +- .../services/sample_data/routes/list.test.ts | 122 +++++++++++++ .../services/sample_data/routes/list.ts | 9 +- .../sample_data/routes/uninstall.test.ts | 101 +++++++++++ .../sample_data/sample_data_registry.ts | 4 +- 12 files changed, 411 insertions(+), 24 deletions(-) create mode 100644 src/plugins/home/server/services/sample_data/routes/install.test.ts create mode 100644 src/plugins/home/server/services/sample_data/routes/list.test.ts create mode 100644 src/plugins/home/server/services/sample_data/routes/uninstall.test.ts diff --git a/.lycheeexclude b/.lycheeexclude index 35ae861e8f91..bb378e308868 100644 --- a/.lycheeexclude +++ b/.lycheeexclude @@ -121,3 +121,4 @@ https://yarnpkg.com/latest.msi https://forum.opensearch.org/ https://facebook.github.io/jest/ https://facebook.github.io/jest/docs/cli.html +http://helpmenow.com/problem2 diff --git a/src/plugins/home/server/services/sample_data/data_sets/ecommerce/index.ts b/src/plugins/home/server/services/sample_data/data_sets/ecommerce/index.ts index 898e4f7f5cba..0321c428cf68 100644 --- a/src/plugins/home/server/services/sample_data/data_sets/ecommerce/index.ts +++ b/src/plugins/home/server/services/sample_data/data_sets/ecommerce/index.ts @@ -33,7 +33,7 @@ import { i18n } from '@osd/i18n'; import { getSavedObjects } from './saved_objects'; import { fieldMappings } from './field_mappings'; import { SampleDatasetSchema, AppLinkSchema } from '../../lib/sample_dataset_registry_types'; -import { getSavedObjectsWithDataSource } from '../util'; +import { getSavedObjectsWithDataSource, appendDataSourceId } from '../util'; const ecommerceName = i18n.translate('home.sampleData.ecommerceSpecTitle', { defaultMessage: 'Sample eCommerce orders', @@ -44,6 +44,7 @@ const ecommerceDescription = i18n.translate('home.sampleData.ecommerceSpecDescri const initialAppLinks = [] as AppLinkSchema[]; const DEFAULT_INDEX = 'ff959d40-b880-11e8-a6d9-e546fe2bba5f'; +const DASHBOARD_ID = '722b74f0-b882-11e8-a6d9-e546fe2bba5f'; export const ecommerceSpecProvider = function (): SampleDatasetSchema { return { @@ -52,10 +53,9 @@ export const ecommerceSpecProvider = function (): SampleDatasetSchema { description: ecommerceDescription, previewImagePath: '/plugins/home/assets/sample_data_resources/ecommerce/dashboard.png', darkPreviewImagePath: '/plugins/home/assets/sample_data_resources/ecommerce/dashboard_dark.png', - overviewDashboard: '722b74f0-b882-11e8-a6d9-e546fe2bba5f', + overviewDashboard: appendDataSourceId(DASHBOARD_ID), appLinks: initialAppLinks, - defaultIndex: (dataSourceId?: string) => - dataSourceId ? `${dataSourceId}_` + DEFAULT_INDEX : DEFAULT_INDEX, + defaultIndex: appendDataSourceId(DEFAULT_INDEX), savedObjects: (dataSourceId?: string, dataSourceTitle?: string) => getSavedObjectsWithDataSource(getSavedObjects(), dataSourceId, dataSourceTitle), dataIndices: [ diff --git a/src/plugins/home/server/services/sample_data/data_sets/flights/index.ts b/src/plugins/home/server/services/sample_data/data_sets/flights/index.ts index e60654107683..038744419f3e 100644 --- a/src/plugins/home/server/services/sample_data/data_sets/flights/index.ts +++ b/src/plugins/home/server/services/sample_data/data_sets/flights/index.ts @@ -33,7 +33,7 @@ import { i18n } from '@osd/i18n'; import { getSavedObjects } from './saved_objects'; import { fieldMappings } from './field_mappings'; import { SampleDatasetSchema, AppLinkSchema } from '../../lib/sample_dataset_registry_types'; -import { getSavedObjectsWithDataSource } from '../util'; +import { getSavedObjectsWithDataSource, appendDataSourceId } from '../util'; const flightsName = i18n.translate('home.sampleData.flightsSpecTitle', { defaultMessage: 'Sample flight data', @@ -44,6 +44,7 @@ const flightsDescription = i18n.translate('home.sampleData.flightsSpecDescriptio const initialAppLinks = [] as AppLinkSchema[]; const DEFAULT_INDEX = 'd3d7af60-4c81-11e8-b3d7-01146121b73d'; +const DASHBOARD_ID = '7adfa750-4c81-11e8-b3d7-01146121b73d'; export const flightsSpecProvider = function (): SampleDatasetSchema { return { @@ -52,10 +53,9 @@ export const flightsSpecProvider = function (): SampleDatasetSchema { description: flightsDescription, previewImagePath: '/plugins/home/assets/sample_data_resources/flights/dashboard.png', darkPreviewImagePath: '/plugins/home/assets/sample_data_resources/flights/dashboard_dark.png', - overviewDashboard: '7adfa750-4c81-11e8-b3d7-01146121b73d', + overviewDashboard: appendDataSourceId(DASHBOARD_ID), appLinks: initialAppLinks, - defaultIndex: (dataSourceId?: string) => - dataSourceId ? `${dataSourceId}_` + DEFAULT_INDEX : DEFAULT_INDEX, + defaultIndex: appendDataSourceId(DEFAULT_INDEX), savedObjects: (dataSourceId?: string, dataSourceTitle?: string) => getSavedObjectsWithDataSource(getSavedObjects(), dataSourceId, dataSourceTitle), dataIndices: [ diff --git a/src/plugins/home/server/services/sample_data/data_sets/logs/index.ts b/src/plugins/home/server/services/sample_data/data_sets/logs/index.ts index c61aeb059b21..e4afabcdd212 100644 --- a/src/plugins/home/server/services/sample_data/data_sets/logs/index.ts +++ b/src/plugins/home/server/services/sample_data/data_sets/logs/index.ts @@ -33,7 +33,7 @@ import { i18n } from '@osd/i18n'; import { getSavedObjects } from './saved_objects'; import { fieldMappings } from './field_mappings'; import { SampleDatasetSchema, AppLinkSchema } from '../../lib/sample_dataset_registry_types'; -import { getSavedObjectsWithDataSource } from '../util'; +import { appendDataSourceId, getSavedObjectsWithDataSource } from '../util'; const logsName = i18n.translate('home.sampleData.logsSpecTitle', { defaultMessage: 'Sample web logs', @@ -44,6 +44,7 @@ const logsDescription = i18n.translate('home.sampleData.logsSpecDescription', { const initialAppLinks = [] as AppLinkSchema[]; const DEFAULT_INDEX = '90943e30-9a47-11e8-b64d-95841ca0b247'; +const DASHBOARD_ID = 'edf84fe0-e1a0-11e7-b6d5-4dc382ef7f5b'; export const logsSpecProvider = function (): SampleDatasetSchema { return { @@ -52,10 +53,9 @@ export const logsSpecProvider = function (): SampleDatasetSchema { description: logsDescription, previewImagePath: '/plugins/home/assets/sample_data_resources/logs/dashboard.png', darkPreviewImagePath: '/plugins/home/assets/sample_data_resources/logs/dashboard_dark.png', - overviewDashboard: 'edf84fe0-e1a0-11e7-b6d5-4dc382ef7f5b', + overviewDashboard: appendDataSourceId(DASHBOARD_ID), appLinks: initialAppLinks, - defaultIndex: (dataSourceId?: string) => - dataSourceId ? `${dataSourceId}_` + DEFAULT_INDEX : DEFAULT_INDEX, + defaultIndex: appendDataSourceId(DEFAULT_INDEX), savedObjects: (dataSourceId?: string, dataSourceTitle?: string) => getSavedObjectsWithDataSource(getSavedObjects(), dataSourceId, dataSourceTitle), dataIndices: [ diff --git a/src/plugins/home/server/services/sample_data/data_sets/util.ts b/src/plugins/home/server/services/sample_data/data_sets/util.ts index 3d3c97308528..46022f1c22d3 100644 --- a/src/plugins/home/server/services/sample_data/data_sets/util.ts +++ b/src/plugins/home/server/services/sample_data/data_sets/util.ts @@ -5,6 +5,10 @@ import { SavedObject } from 'opensearch-dashboards/server'; +export const appendDataSourceId = (id: string) => { + return (dataSourceId?: string) => (dataSourceId ? `${dataSourceId}_` + id : id); +}; + export const getSavedObjectsWithDataSource = ( saveObjectList: SavedObject[], dataSourceId?: string, diff --git a/src/plugins/home/server/services/sample_data/lib/sample_dataset_registry_types.ts b/src/plugins/home/server/services/sample_data/lib/sample_dataset_registry_types.ts index 66670b72e8d0..76632ee4489d 100644 --- a/src/plugins/home/server/services/sample_data/lib/sample_dataset_registry_types.ts +++ b/src/plugins/home/server/services/sample_data/lib/sample_dataset_registry_types.ts @@ -87,7 +87,7 @@ export interface SampleDatasetSchema { darkPreviewImagePath: string; // saved object id of main dashboard for sample data set - overviewDashboard: string; + overviewDashboard: (dataSourceId?: string) => string; appLinks: AppLinkSchema[]; // saved object id of default index-pattern for sample data set diff --git a/src/plugins/home/server/services/sample_data/routes/install.test.ts b/src/plugins/home/server/services/sample_data/routes/install.test.ts new file mode 100644 index 000000000000..ad7b421c23d5 --- /dev/null +++ b/src/plugins/home/server/services/sample_data/routes/install.test.ts @@ -0,0 +1,160 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { CoreSetup, RequestHandlerContext } from 'src/core/server'; +import { coreMock, httpServerMock } from '../../../../../../core/server/mocks'; +import { flightsSpecProvider } from '../data_sets'; +import { SampleDatasetSchema } from '../lib/sample_dataset_registry_types'; +import { createInstallRoute } from './install'; + +const flightsSampleDataset = flightsSpecProvider(); + +const sampleDatasets: SampleDatasetSchema[] = [flightsSampleDataset]; + +describe('sample data install route', () => { + let mockCoreSetup: MockedKeys; + let mockLogger; + let mockUsageTracker; + + beforeEach(() => { + mockCoreSetup = coreMock.createSetup(); + mockLogger = { + warn: jest.fn(), + }; + + mockUsageTracker = { + addInstall: jest.fn(), + addUninstall: jest.fn(), + }; + }); + + it('handler calls expected api with the given request', async () => { + const mockClient = jest.fn().mockResolvedValue(true); + + const mockSOClientGetResponse = { + saved_objects: [ + { + type: 'dashboard', + id: '12345', + namespaces: ['default'], + attributes: { title: 'dashboard' }, + }, + ], + }; + const mockSOClient = { bulkCreate: jest.fn().mockResolvedValue(mockSOClientGetResponse) }; + + const mockContext = { + core: { + opensearch: { + legacy: { + client: { callAsCurrentUser: mockClient }, + }, + }, + savedObjects: { client: mockSOClient }, + }, + }; + const mockBody = { id: 'flights' }; + const mockQuery = {}; + const mockRequest = httpServerMock.createOpenSearchDashboardsRequest({ + params: mockBody, + query: mockQuery, + }); + const mockResponse = httpServerMock.createResponseFactory(); + + createInstallRoute( + mockCoreSetup.http.createRouter(), + sampleDatasets, + mockLogger, + mockUsageTracker + ); + + const mockRouter = mockCoreSetup.http.createRouter.mock.results[0].value; + const handler = mockRouter.post.mock.calls[0][1]; + + await handler((mockContext as unknown) as RequestHandlerContext, mockRequest, mockResponse); + + expect(mockClient.mock.calls[1][1].body.settings).toMatchObject({ + index: { number_of_shards: 1, auto_expand_replicas: '0-1' }, + }); + + // expect(mockClient).toBeCalledTimes(2); + expect(mockResponse.ok).toBeCalled(); + expect(mockResponse.ok.mock.calls[0][0]).toMatchObject({ + body: { + opensearchIndicesCreated: { opensearch_dashboards_sample_data_flights: 13059 }, + opensearchDashboardsSavedObjectsLoaded: 20, + }, + }); + }); + + it('handler calls expected api with the given request with data source', async () => { + const mockDataSourceId = 'dataSource'; + + const mockClient = jest.fn().mockResolvedValue(true); + + const mockSOClientGetResponse = { + saved_objects: [ + { + type: 'dashboard', + id: '12345', + namespaces: ['default'], + attributes: { title: 'dashboard' }, + }, + ], + }; + const mockSOClient = { + bulkCreate: jest.fn().mockResolvedValue(mockSOClientGetResponse), + get: jest.fn().mockResolvedValue(mockSOClientGetResponse), + }; + + const mockContext = { + dataSource: { + opensearch: { + legacy: { + getClient: (id) => { + return { + callAPI: mockClient, + }; + }, + }, + }, + }, + core: { + savedObjects: { client: mockSOClient }, + }, + }; + const mockBody = { id: 'flights' }; + const mockQuery = { data_source_id: mockDataSourceId }; + const mockRequest = httpServerMock.createOpenSearchDashboardsRequest({ + params: mockBody, + query: mockQuery, + }); + const mockResponse = httpServerMock.createResponseFactory(); + + createInstallRoute( + mockCoreSetup.http.createRouter(), + sampleDatasets, + mockLogger, + mockUsageTracker + ); + + const mockRouter = mockCoreSetup.http.createRouter.mock.results[0].value; + const handler = mockRouter.post.mock.calls[0][1]; + + await handler((mockContext as unknown) as RequestHandlerContext, mockRequest, mockResponse); + + expect(mockClient.mock.calls[1][1].body.settings).toMatchObject({ + index: { number_of_shards: 1 }, + }); + + expect(mockResponse.ok).toBeCalled(); + expect(mockResponse.ok.mock.calls[0][0]).toMatchObject({ + body: { + opensearchIndicesCreated: { opensearch_dashboards_sample_data_flights: 13059 }, + opensearchDashboardsSavedObjectsLoaded: 20, + }, + }); + }); +}); diff --git a/src/plugins/home/server/services/sample_data/routes/install.ts b/src/plugins/home/server/services/sample_data/routes/install.ts index 596231d75e73..3a321c3bdf0a 100644 --- a/src/plugins/home/server/services/sample_data/routes/install.ts +++ b/src/plugins/home/server/services/sample_data/routes/install.ts @@ -29,7 +29,7 @@ */ import { schema } from '@osd/config-schema'; -import { IRouter, Logger } from 'src/core/server'; +import { IRouter, LegacyCallAPIOptions, Logger } from 'src/core/server'; import { SampleDatasetSchema } from '../lib/sample_dataset_registry_types'; import { createIndexName } from '../lib/create_index_name'; import { @@ -44,7 +44,11 @@ const insertDataIntoIndex = ( dataIndexConfig: any, index: string, nowReference: string, - caller: (endpoint: string, clientParams?: Record, options?: any) => Promise, + caller: ( + endpoint: string, + clientParams?: Record, + options?: LegacyCallAPIOptions + ) => Promise, logger: Logger ) => { function updateTimestamps(doc: any) { diff --git a/src/plugins/home/server/services/sample_data/routes/list.test.ts b/src/plugins/home/server/services/sample_data/routes/list.test.ts new file mode 100644 index 000000000000..70201fafd06b --- /dev/null +++ b/src/plugins/home/server/services/sample_data/routes/list.test.ts @@ -0,0 +1,122 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { CoreSetup, RequestHandlerContext } from 'src/core/server'; +import { coreMock, httpServerMock } from '../../../../../../core/server/mocks'; +import { createListRoute } from './list'; +import { flightsSpecProvider } from '../data_sets'; +import { SampleDatasetSchema } from '../lib/sample_dataset_registry_types'; + +const flightsSampleDataset = flightsSpecProvider(); + +const sampleDatasets: SampleDatasetSchema[] = [flightsSampleDataset]; + +describe('sample data list route', () => { + let mockCoreSetup: MockedKeys; + + beforeEach(() => { + mockCoreSetup = coreMock.createSetup(); + }); + + it('handler calls expected api with the given request', async () => { + const mockClient = jest.fn().mockResolvedValueOnce(true).mockResolvedValueOnce({ count: 1 }); + + const mockSOClientGetResponse = { + saved_objects: [ + { + type: 'dashboard', + id: '7adfa750-4c81-11e8-b3d7-01146121b73d', + namespaces: ['default'], + attributes: { title: 'dashboard' }, + }, + ], + }; + const mockSOClient = { get: jest.fn().mockResolvedValue(mockSOClientGetResponse) }; + + const mockContext = { + core: { + opensearch: { + legacy: { + client: { callAsCurrentUser: mockClient }, + }, + }, + savedObjects: { client: mockSOClient }, + }, + }; + const mockBody = {}; + const mockQuery = {}; + const mockRequest = httpServerMock.createOpenSearchDashboardsRequest({ + body: mockBody, + query: mockQuery, + }); + const mockResponse = httpServerMock.createResponseFactory(); + + createListRoute(mockCoreSetup.http.createRouter(), sampleDatasets); + + const mockRouter = mockCoreSetup.http.createRouter.mock.results[0].value; + const handler = mockRouter.get.mock.calls[0][1]; + + await handler((mockContext as unknown) as RequestHandlerContext, mockRequest, mockResponse); + + expect(mockClient).toBeCalledTimes(2); + expect(mockResponse.ok).toBeCalled(); + expect(mockSOClient.get.mock.calls[0][1]).toMatch('7adfa750-4c81-11e8-b3d7-01146121b73d'); + }); + + it('handler calls expected api with the given request with data source', async () => { + const mockDataSourceId = 'dataSource'; + const mockClient = jest.fn().mockResolvedValueOnce(true).mockResolvedValueOnce({ count: 1 }); + + const mockSOClientGetResponse = { + saved_objects: [ + { + type: 'dashboard', + id: `${mockDataSourceId}_7adfa750-4c81-11e8-b3d7-01146121b73d`, + namespaces: ['default'], + attributes: { title: 'dashboard' }, + }, + ], + }; + const mockSOClient = { get: jest.fn().mockResolvedValue(mockSOClientGetResponse) }; + + const mockContext = { + dataSource: { + opensearch: { + legacy: { + getClient: (id) => { + return { + callAPI: mockClient, + }; + }, + }, + }, + }, + core: { + savedObjects: { client: mockSOClient }, + }, + }; + + const mockBody = {}; + const mockQuery = { data_source_id: mockDataSourceId }; + const mockRequest = httpServerMock.createOpenSearchDashboardsRequest({ + body: mockBody, + query: mockQuery, + }); + const mockResponse = httpServerMock.createResponseFactory(); + + createListRoute(mockCoreSetup.http.createRouter(), sampleDatasets); + + const mockRouter = mockCoreSetup.http.createRouter.mock.results[0].value; + const handler = mockRouter.get.mock.calls[0][1]; + + await handler((mockContext as unknown) as RequestHandlerContext, mockRequest, mockResponse); + + expect(mockClient).toBeCalledTimes(2); + expect(mockResponse.ok).toBeCalled(); + expect(mockSOClient.get.mock.calls[0][1]).toMatch( + `${mockDataSourceId}_7adfa750-4c81-11e8-b3d7-01146121b73d` + ); + }); +}); diff --git a/src/plugins/home/server/services/sample_data/routes/list.ts b/src/plugins/home/server/services/sample_data/routes/list.ts index 43c167943b65..bc6fac2b76f3 100644 --- a/src/plugins/home/server/services/sample_data/routes/list.ts +++ b/src/plugins/home/server/services/sample_data/routes/list.ts @@ -55,7 +55,7 @@ export const createListRoute = (router: IRouter, sampleDatasets: SampleDatasetSc description: sampleDataset.description, previewImagePath: sampleDataset.previewImagePath, darkPreviewImagePath: sampleDataset.darkPreviewImagePath, - overviewDashboard: sampleDataset.overviewDashboard, + overviewDashboard: sampleDataset.overviewDashboard(dataSourceId), appLinks: sampleDataset.appLinks, defaultIndex: sampleDataset.defaultIndex(dataSourceId), dataIndices: sampleDataset.dataIndices.map(({ id }) => ({ id })), @@ -94,12 +94,7 @@ export const createListRoute = (router: IRouter, sampleDatasets: SampleDatasetSc } } try { - // todo: change to function provider accept dataSourceId - const dashboardId = dataSourceId - ? `${dataSourceId}_${sampleDataset.overviewDashboard}` - : sampleDataset.overviewDashboard; - - await context.core.savedObjects.client.get('dashboard', dashboardId); + await context.core.savedObjects.client.get('dashboard', sampleDataset.overviewDashboard); } catch (err) { if (context.core.savedObjects.client.errors.isNotFoundError(err)) { sampleDataset.status = NOT_INSTALLED; diff --git a/src/plugins/home/server/services/sample_data/routes/uninstall.test.ts b/src/plugins/home/server/services/sample_data/routes/uninstall.test.ts new file mode 100644 index 000000000000..7d9797d752cb --- /dev/null +++ b/src/plugins/home/server/services/sample_data/routes/uninstall.test.ts @@ -0,0 +1,101 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { CoreSetup, RequestHandlerContext } from 'src/core/server'; +import { coreMock, httpServerMock } from '../../../../../../core/server/mocks'; +import { flightsSpecProvider } from '../data_sets'; +import { SampleDatasetSchema } from '../lib/sample_dataset_registry_types'; +import { createUninstallRoute } from './uninstall'; + +const flightsSampleDataset = flightsSpecProvider(); + +const sampleDatasets: SampleDatasetSchema[] = [flightsSampleDataset]; + +describe('sample data uninstall route', () => { + let mockCoreSetup: MockedKeys; + let mockUsageTracker; + let mockClient; + let mockSOClient; + + beforeEach(() => { + mockCoreSetup = coreMock.createSetup(); + + mockUsageTracker = { + addInstall: jest.fn(), + addUninstall: jest.fn(), + }; + + mockClient = jest.fn(); + mockSOClient = { delete: jest.fn().mockResolvedValue(true) }; + }); + + it('handler calls expected api with the given request', async () => { + const mockContext = { + core: { + opensearch: { + legacy: { + client: { callAsCurrentUser: mockClient }, + }, + }, + savedObjects: { client: mockSOClient }, + }, + }; + const mockBody = { id: 'flights' }; + const mockQuery = {}; + const mockRequest = httpServerMock.createOpenSearchDashboardsRequest({ + params: mockBody, + query: mockQuery, + }); + const mockResponse = httpServerMock.createResponseFactory(); + + createUninstallRoute(mockCoreSetup.http.createRouter(), sampleDatasets, mockUsageTracker); + + const mockRouter = mockCoreSetup.http.createRouter.mock.results[0].value; + const handler = mockRouter.delete.mock.calls[0][1]; + + await handler((mockContext as unknown) as RequestHandlerContext, mockRequest, mockResponse); + + expect(mockClient).toBeCalled(); + expect(mockSOClient.delete).toBeCalled(); + }); + + it('handler calls expected api with the given request with data source', async () => { + const mockDataSourceId = 'dataSource'; + + const mockContext = { + dataSource: { + opensearch: { + legacy: { + getClient: (id) => { + return { + callAPI: mockClient, + }; + }, + }, + }, + }, + core: { + savedObjects: { client: mockSOClient }, + }, + }; + const mockBody = { id: 'flights' }; + const mockQuery = { data_source_id: mockDataSourceId }; + const mockRequest = httpServerMock.createOpenSearchDashboardsRequest({ + params: mockBody, + query: mockQuery, + }); + const mockResponse = httpServerMock.createResponseFactory(); + + createUninstallRoute(mockCoreSetup.http.createRouter(), sampleDatasets, mockUsageTracker); + + const mockRouter = mockCoreSetup.http.createRouter.mock.results[0].value; + const handler = mockRouter.delete.mock.calls[0][1]; + + await handler((mockContext as unknown) as RequestHandlerContext, mockRequest, mockResponse); + + expect(mockClient).toBeCalled(); + expect(mockSOClient.delete).toBeCalled(); + }); +}); diff --git a/src/plugins/home/server/services/sample_data/sample_data_registry.ts b/src/plugins/home/server/services/sample_data/sample_data_registry.ts index 7ab4db4681c5..5f298fd86ef3 100644 --- a/src/plugins/home/server/services/sample_data/sample_data_registry.ts +++ b/src/plugins/home/server/services/sample_data/sample_data_registry.ts @@ -95,12 +95,12 @@ export class SampleDataRegistry { const dashboardSavedObjectJson = value.savedObjects.find((savedObjectJson: any) => { return ( - savedObjectJson.type === 'dashboard' && savedObjectJson.id === value.overviewDashboard + savedObjectJson.type === 'dashboard' && savedObjectJson.id === value.overviewDashboard() ); }); if (!dashboardSavedObjectJson) { throw new Error( - `Unable to register sample dataset spec, overviewDashboard: "${value.overviewDashboard}" does not exist in savedObject list.` + `Unable to register sample dataset spec, overviewDashboard: "${value.overviewDashboard()}" does not exist in savedObject list.` ); } this.sampleDatasets.push(value);