Skip to content

Commit

Permalink
feat: import sample data saved objects to workspace (#118) (#152)
Browse files Browse the repository at this point in the history
---------




(cherry picked from commit 98b77d0)

Signed-off-by: Lin Wang <wonglam@amazon.com>
Signed-off-by: Yulong Ruan <ruanyl@amazon.com>
Signed-off-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Yulong Ruan <ruanyu1@gmail.com>
  • Loading branch information
3 people authored Sep 14, 2023
1 parent bbe28b8 commit b0201d8
Show file tree
Hide file tree
Showing 15 changed files with 356 additions and 88 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,10 @@ export class SampleDataSetCards extends React.Component {
loadSampleDataSets = async (dataSourceId) => {
let sampleDataSets;
try {
sampleDataSets = await listSampleDataSets(dataSourceId);
sampleDataSets = await listSampleDataSets(
dataSourceId,
getServices().workspaces.currentWorkspaceId$.getValue()
);
} catch (fetchError) {
this.toastNotifications.addDanger({
title: i18n.translate('home.sampleDataSet.unableToLoadListErrorMessage', {
Expand Down Expand Up @@ -114,7 +117,12 @@ export class SampleDataSetCards extends React.Component {
}));

try {
await installSampleDataSet(id, targetSampleDataSet.defaultIndex, dataSourceId);
await installSampleDataSet(
id,
targetSampleDataSet.defaultIndex,
dataSourceId,
getServices().workspaces.currentWorkspaceId$.getValue()
);
} catch (fetchError) {
if (this._isMounted) {
this.setState((prevState) => ({
Expand Down Expand Up @@ -162,7 +170,12 @@ export class SampleDataSetCards extends React.Component {
}));

try {
await uninstallSampleDataSet(id, targetSampleDataSet.defaultIndex, dataSourceId);
await uninstallSampleDataSet(
id,
targetSampleDataSet.defaultIndex,
dataSourceId,
getServices().workspaces.currentWorkspaceId$.getValue()
);
} catch (fetchError) {
if (this._isMounted) {
this.setState((prevState) => ({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import {
SavedObjectsClientContract,
IUiSettingsClient,
ApplicationStart,
WorkspaceStart,
} from 'opensearch-dashboards/public';
import { UiStatsMetricType } from '@osd/analytics';
import { TelemetryPluginStart } from '../../../telemetry/public';
Expand Down Expand Up @@ -73,6 +74,7 @@ export interface HomeOpenSearchDashboardsServices {
getBranding: () => HomePluginBranding;
};
dataSource?: DataSourcePluginStart;
workspaces: WorkspaceStart;
}

let services: HomeOpenSearchDashboardsServices | null = null;
Expand Down
23 changes: 16 additions & 7 deletions src/plugins/home/public/application/sample_data_client.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,13 @@ function clearIndexPatternsCache() {
getServices().indexPatternService.clearCache();
}

export async function listSampleDataSets(dataSourceId) {
const query = buildQuery(dataSourceId);
export async function listSampleDataSets(dataSourceId, workspaceId) {
const query = buildQuery(dataSourceId, workspaceId);
return await getServices().http.get(sampleDataUrl, { query });
}

export async function installSampleDataSet(id, sampleDataDefaultIndex, dataSourceId) {
const query = buildQuery(dataSourceId);
export async function installSampleDataSet(id, sampleDataDefaultIndex, dataSourceId, workspaceId) {
const query = buildQuery(dataSourceId, workspaceId);
await getServices().http.post(`${sampleDataUrl}/${id}`, { query });

if (getServices().uiSettings.isDefault('defaultIndex')) {
Expand All @@ -52,8 +52,13 @@ export async function installSampleDataSet(id, sampleDataDefaultIndex, dataSourc
clearIndexPatternsCache();
}

export async function uninstallSampleDataSet(id, sampleDataDefaultIndex, dataSourceId) {
const query = buildQuery(dataSourceId);
export async function uninstallSampleDataSet(
id,
sampleDataDefaultIndex,
dataSourceId,
workspaceId
) {
const query = buildQuery(dataSourceId, workspaceId);
await getServices().http.delete(`${sampleDataUrl}/${id}`, { query });

const uiSettings = getServices().uiSettings;
Expand All @@ -68,12 +73,16 @@ export async function uninstallSampleDataSet(id, sampleDataDefaultIndex, dataSou
clearIndexPatternsCache();
}

function buildQuery(dataSourceId) {
function buildQuery(dataSourceId, workspaceId) {
const query = {};

if (dataSourceId) {
query.data_source_id = dataSourceId;
}

if (workspaceId) {
query.workspace_id = workspaceId;
}

return query;
}
1 change: 1 addition & 0 deletions src/plugins/home/public/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ export class HomePublicPlugin
featureCatalogue: this.featuresCatalogueRegistry,
injectedMetadata: coreStart.injectedMetadata,
dataSource,
workspaces: coreStart.workspaces,
});
coreStart.chrome.docTitle.change(
i18n.translate('home.pageTitle', { defaultMessage: 'Home' })
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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, appendDataSourceId } from '../util';
import { addPrefixTo } from '../util';

const ecommerceName = i18n.translate('home.sampleData.ecommerceSpecTitle', {
defaultMessage: 'Sample eCommerce orders',
Expand All @@ -54,13 +54,11 @@ export const ecommerceSpecProvider = function (): SampleDatasetSchema {
previewImagePath: '/plugins/home/assets/sample_data_resources/ecommerce/dashboard.png',
darkPreviewImagePath: '/plugins/home/assets/sample_data_resources/ecommerce/dashboard_dark.png',
overviewDashboard: DASHBOARD_ID,
getDataSourceIntegratedDashboard: appendDataSourceId(DASHBOARD_ID),
getDashboardWithPrefix: addPrefixTo(DASHBOARD_ID),
appLinks: initialAppLinks,
defaultIndex: DEFAULT_INDEX,
getDataSourceIntegratedDefaultIndex: appendDataSourceId(DEFAULT_INDEX),
getDataSourceIntegratedDefaultIndex: addPrefixTo(DEFAULT_INDEX),
savedObjects: getSavedObjects(),
getDataSourceIntegratedSavedObjects: (dataSourceId?: string, dataSourceTitle?: string) =>
getSavedObjectsWithDataSource(getSavedObjects(), dataSourceId, dataSourceTitle),
dataIndices: [
{
id: 'ecommerce',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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, appendDataSourceId } from '../util';
import { addPrefixTo } from '../util';

const flightsName = i18n.translate('home.sampleData.flightsSpecTitle', {
defaultMessage: 'Sample flight data',
Expand All @@ -54,13 +54,11 @@ export const flightsSpecProvider = function (): SampleDatasetSchema {
previewImagePath: '/plugins/home/assets/sample_data_resources/flights/dashboard.png',
darkPreviewImagePath: '/plugins/home/assets/sample_data_resources/flights/dashboard_dark.png',
overviewDashboard: DASHBOARD_ID,
getDataSourceIntegratedDashboard: appendDataSourceId(DASHBOARD_ID),
getDashboardWithPrefix: addPrefixTo(DASHBOARD_ID),
appLinks: initialAppLinks,
defaultIndex: DEFAULT_INDEX,
getDataSourceIntegratedDefaultIndex: appendDataSourceId(DEFAULT_INDEX),
getDataSourceIntegratedDefaultIndex: addPrefixTo(DEFAULT_INDEX),
savedObjects: getSavedObjects(),
getDataSourceIntegratedSavedObjects: (dataSourceId?: string, dataSourceTitle?: string) =>
getSavedObjectsWithDataSource(getSavedObjects(), dataSourceId, dataSourceTitle),
dataIndices: [
{
id: 'flights',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 { appendDataSourceId, getSavedObjectsWithDataSource } from '../util';
import { addPrefixTo } from '../util';

const logsName = i18n.translate('home.sampleData.logsSpecTitle', {
defaultMessage: 'Sample web logs',
Expand All @@ -54,13 +54,11 @@ export const logsSpecProvider = function (): SampleDatasetSchema {
previewImagePath: '/plugins/home/assets/sample_data_resources/logs/dashboard.png',
darkPreviewImagePath: '/plugins/home/assets/sample_data_resources/logs/dashboard_dark.png',
overviewDashboard: DASHBOARD_ID,
getDataSourceIntegratedDashboard: appendDataSourceId(DASHBOARD_ID),
getDashboardWithPrefix: addPrefixTo(DASHBOARD_ID),
appLinks: initialAppLinks,
defaultIndex: DEFAULT_INDEX,
getDataSourceIntegratedDefaultIndex: appendDataSourceId(DEFAULT_INDEX),
getDataSourceIntegratedDefaultIndex: addPrefixTo(DEFAULT_INDEX),
savedObjects: getSavedObjects(),
getDataSourceIntegratedSavedObjects: (dataSourceId?: string, dataSourceTitle?: string) =>
getSavedObjectsWithDataSource(getSavedObjects(), dataSourceId, dataSourceTitle),
dataIndices: [
{
id: 'logs',
Expand Down
124 changes: 75 additions & 49 deletions src/plugins/home/server/services/sample_data/data_sets/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,60 +4,74 @@
*/

import { SavedObject } from 'opensearch-dashboards/server';
import { cloneDeep } from 'lodash';

export const appendDataSourceId = (id: string) => {
return (dataSourceId?: string) => (dataSourceId ? `${dataSourceId}_` + id : id);
const withPrefix = (...args: Array<string | undefined>) => (id: string) => {
const prefix = args.filter(Boolean).join('_');
if (prefix) {
return `${prefix}_${id}`;
}
return id;
};

export const getSavedObjectsWithDataSource = (
saveObjectList: SavedObject[],
dataSourceId?: string,
dataSourceTitle?: string
): SavedObject[] => {
if (dataSourceId) {
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;
}
});
export const addPrefixTo = (id: string) => (...args: Array<string | undefined>) => {
return withPrefix(...args)(id);
};

const overrideSavedObjectId = (savedObject: SavedObject, idGenerator: (id: string) => string) => {
savedObject.id = idGenerator(savedObject.id);
// update reference
if (savedObject.type === 'dashboard') {
savedObject.references.map((reference) => {
if (reference.id) {
reference.id = idGenerator(reference.id);
}
});
}

// update reference
if (saveObject.type === 'visualization' || saveObject.type === 'search') {
const searchSourceString = saveObject.attributes?.kibanaSavedObjectMeta?.searchSourceJSON;
const visStateString = saveObject.attributes?.visState;
// update reference
if (savedObject.type === 'visualization' || savedObject.type === 'search') {
const searchSourceString = savedObject.attributes?.kibanaSavedObjectMeta?.searchSourceJSON;
const visStateString = savedObject.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 (searchSourceString) {
const searchSource = JSON.parse(searchSourceString);
if (searchSource.index) {
searchSource.index = idGenerator(searchSource.index);
savedObject.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;
}
});
if (visStateString) {
const visState = JSON.parse(visStateString);
const controlList = visState.params?.controls;
if (controlList) {
controlList.map((control) => {
if (control.indexPattern) {
control.indexPattern = idGenerator(control.indexPattern);
}
saveObject.attributes.visState = JSON.stringify(visState);
}
});
}
savedObject.attributes.visState = JSON.stringify(visState);
}
}
};

export const getDataSourceIntegratedSavedObjects = (
savedObjectList: SavedObject[],
dataSourceId?: string,
dataSourceTitle?: string
): SavedObject[] => {
savedObjectList = cloneDeep(savedObjectList);
if (dataSourceId) {
return savedObjectList.map((savedObject) => {
overrideSavedObjectId(savedObject, withPrefix(dataSourceId));

// update reference
if (saveObject.type === 'index-pattern') {
saveObject.references = [
if (savedObject.type === 'index-pattern') {
savedObject.references = [
{
id: `${dataSourceId}`,
type: 'data-source',
Expand All @@ -68,17 +82,29 @@ export const getSavedObjectsWithDataSource = (

if (dataSourceTitle) {
if (
saveObject.type === 'dashboard' ||
saveObject.type === 'visualization' ||
saveObject.type === 'search'
savedObject.type === 'dashboard' ||
savedObject.type === 'visualization' ||
savedObject.type === 'search'
) {
saveObject.attributes.title = saveObject.attributes.title + `_${dataSourceTitle}`;
savedObject.attributes.title = savedObject.attributes.title + `_${dataSourceTitle}`;
}
}

return saveObject;
return savedObject;
});
}

return saveObjectList;
return savedObjectList;
};

export const getWorkspaceIntegratedSavedObjects = (
savedObjectList: SavedObject[],
workspaceId?: string
) => {
savedObjectList = cloneDeep(savedObjectList);

savedObjectList.forEach((savedObject) => {
overrideSavedObjectId(savedObject, withPrefix(workspaceId));
});
return savedObjectList;
};
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ export interface SampleDatasetSchema<T = unknown> {

// saved object id of main dashboard for sample data set
overviewDashboard: string;
getDataSourceIntegratedDashboard: (dataSourceId?: string) => string;
getDashboardWithPrefix: (...args: Array<string | undefined>) => string;
appLinks: AppLinkSchema[];

// saved object id of default index-pattern for sample data set
Expand All @@ -98,10 +98,6 @@ export interface SampleDatasetSchema<T = unknown> {
// 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<SavedObject<T>>;
getDataSourceIntegratedSavedObjects: (
dataSourceId?: string,
dataSourceTitle?: string
) => Array<SavedObject<T>>;
dataIndices: DataIndexSchema[];
status?: string | undefined;
statusMsg?: unknown;
Expand Down
Loading

0 comments on commit b0201d8

Please sign in to comment.