Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support multi data source in Region map #6654

Merged
merged 1 commit into from
Apr 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
- [Multiple Datasource] Modify selectable picker to remove group label and close popover after selection ([#6515](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/6515))
- [Multiple Datasource] Extract the button component for datasource picker to avoid duplicate code ([#6559](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/6559))
- [Workspace] Add workspaces filter to saved objects page. ([#6458](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/6458))
- [Multiple Datasource] Support multi data source in Region map ([#6654](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/6654))

### 🐛 Bug Fixes

Expand Down
5 changes: 3 additions & 2 deletions src/plugins/region_map/opensearch_dashboards.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@
],
"requiredBundles": [
"opensearchDashboardsUtils",
"charts",
"charts",
"visDefaultEditor"
]
],
"optionalPlugins": ["dataSource"]
}
12 changes: 8 additions & 4 deletions src/plugins/region_map/public/choropleth_layer.js
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,8 @@ export class ChoroplethLayer extends OpenSearchDashboardsMapLayer {
leaflet,
layerChosenByUser,
http,
uiSettings
uiSettings,
dataSourceRefId
) {
super();
this._serviceSettings = serviceSettings;
Expand All @@ -119,6 +120,7 @@ export class ChoroplethLayer extends OpenSearchDashboardsMapLayer {
this._http = http;
this._visParams = null;
this._uiSettings = uiSettings;
this._dataSourceRefId = dataSourceRefId;

// eslint-disable-next-line no-undef
this._leafletLayer = this._leaflet.geoJson(null, {
Expand Down Expand Up @@ -249,7 +251,7 @@ CORS configuration of the server permits requests from the OpenSearch Dashboards
try {
const services = getServices(this._http);
const indexSize = this._uiSettings.get(CUSTOM_VECTOR_MAP_MAX_SIZE_SETTING);
const result = await services.getIndexData(this._layerName, indexSize);
const result = await services.getIndexData(this._layerName, indexSize, this._dataSourceRefId);

const finalResult = {
type: 'FeatureCollection',
Expand Down Expand Up @@ -346,7 +348,8 @@ CORS configuration of the server permits requests from the OpenSearch Dashboards
leaflet,
layerChosenByUser,
http,
uiSettings
uiSettings,
dataSourceRefId
) {
const clonedLayer = new ChoroplethLayer(
name,
Expand All @@ -359,7 +362,8 @@ CORS configuration of the server permits requests from the OpenSearch Dashboards
leaflet,
layerChosenByUser,
http,
uiSettings
uiSettings,
dataSourceRefId
);
clonedLayer.setJoinField(this._joinField);
clonedLayer.setColorRamp(this._colorRamp);
Expand Down
26 changes: 16 additions & 10 deletions src/plugins/region_map/public/region_map_type.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,18 +55,18 @@ export function createRegionMapTypeDefinition(dependencies) {
return arr1.concat(arr2).filter((item) => !arr1.includes(item) || !arr2.includes(item));
};

const getCustomIndices = async () => {
const getCustomIndices = async (dataSourceRefId) => {
try {
const result = await services.getCustomIndices();
const result = await services.getCustomIndices(dataSourceRefId);
return result.resp;
} catch (e) {
return false;
}
};

const getJoinFields = async (indexName) => {
const getJoinFields = async (indexName, dataSourceRefId) => {
try {
const result = await services.getIndexMapping(indexName);
const result = await services.getIndexMapping(indexName, dataSourceRefId);
const properties = diffArray(Object.keys(result.resp[indexName].mappings.properties), [
'location',
]);
Expand All @@ -82,17 +82,17 @@ export function createRegionMapTypeDefinition(dependencies) {
}
};

const addSchemaToCustomLayer = async (customlayer) => {
const joinFields = await getJoinFields(customlayer.index);
const addSchemaToCustomLayer = async (customlayer, dataSourceRefId) => {
const joinFields = await getJoinFields(customlayer, dataSourceRefId);
const customLayerWithSchema = {
attribution:
'<a rel="noreferrer noopener" href="http://www.naturalearthdata.com/about/terms-of-use">Made with NaturalEarth</a>',
created_at: '2017-04-26T17:12:15.978370',
format: 'geojson',
fields: joinFields,
id: customlayer.index,
id: customlayer,
meta: undefined,
name: customlayer.index,
name: customlayer,
origin: 'user-upload',
};

Expand Down Expand Up @@ -147,6 +147,7 @@ provided base maps, or add your own. Darker colors represent higher values.',
vectorLayers: [],
customVectorLayers: [],
tmsLayers: [],
dataSourceRefId: '',
},
schemas: new Schemas([
{
Expand Down Expand Up @@ -199,7 +200,12 @@ provided base maps, or add your own. Darker colors represent higher values.',
const customVectorLayers = regionmapsConfig.layers.map(
mapToLayerWithId.bind(null, ORIGIN.OPENSEARCH_DASHBOARDS_YML)
);
const customIndices = await getCustomIndices();

// Read the data source reference id from index pattern if available, empty string means for local clusters
const dataSourceRefId = vis.data.indexPattern?.dataSourceRef?.id || '';
vis.type.editorConfig.collections.dataSourceRefId = dataSourceRefId;

const customIndices = await getCustomIndices(dataSourceRefId);

let selectedLayer = vectorLayers[0];
let selectedJoinField = selectedLayer ? selectedLayer.fields[0] : null;
Expand All @@ -214,7 +220,7 @@ provided base maps, or add your own. Darker colors represent higher values.',
.filter(
(layer) => !vectorLayers.some((vectorLayer) => vectorLayer.layerId === layer.layerId)
);
const promises = customIndices.map(addSchemaToCustomLayer);
const promises = customIndices.map((idx) => addSchemaToCustomLayer(idx, dataSourceRefId));
const newCustomLayers = await Promise.all(promises);

// backfill v1 manifest for now
Expand Down
7 changes: 4 additions & 3 deletions src/plugins/region_map/public/region_map_visualization.js
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,6 @@ export function createRegionMapVisualization({
const metricFieldFormatter = getFormatService().deserialize(this._params.metric.format);

this._choroplethLayer.setLayerChosenByUser(this._params.layerChosenByUser);

this._choroplethLayer.setJoinField(this._params.selectedJoinField.name);
this._choroplethLayer.setColorRamp(truncatedColorMaps[this._params.colorSchema].value);
this._choroplethLayer.setLineWeight(this._params.outlineWeight);
Expand Down Expand Up @@ -231,7 +230,8 @@ export function createRegionMapVisualization({
(await lazyLoadMapsLegacyModules()).L,
this._params.layerChosenByUser,
http,
uiSettings
uiSettings,
this.vis.type.editorConfig.collections.dataSourceRefId
);
} else {
const { ChoroplethLayer } = await import('./choropleth_layer');
Expand All @@ -246,7 +246,8 @@ export function createRegionMapVisualization({
(await lazyLoadMapsLegacyModules()).L,
this._params.layerChosenByUser,
http,
uiSettings
uiSettings,
this.vis.type.editorConfig.collections.dataSourceRefId
);
}
this._choroplethLayer.setLayerChosenByUser(this._params.layerChosenByUser);
Expand Down
31 changes: 19 additions & 12 deletions src/plugins/region_map/public/services.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,46 +6,53 @@
import { CoreStart, HttpFetchError } from 'opensearch-dashboards/public';

export interface Services {
getCustomIndices: () => Promise<undefined | HttpFetchError>;
getIndexData: (indexName: string, size: number) => Promise<undefined | HttpFetchError>;
getIndexMapping: (indexName: string) => Promise<undefined | HttpFetchError>;
getCustomIndices: (dataSourceRefId: string) => Promise<undefined | HttpFetchError>;
getIndexData: (
indexName: string,
size: number,
dataSourceRefId: string
) => Promise<undefined | HttpFetchError>;
getIndexMapping: (
indexName: string,
dataSourceRefId: string
) => Promise<undefined | HttpFetchError>;
}

export function getServices(http: CoreStart['http']): Services {
return {
getCustomIndices: async () => {
getCustomIndices: async (dataSourceRefId: string) => {
try {
const response = await http.post('../api/geospatial/_indices', {
return await http.post('../api/geospatial/_indices', {
body: JSON.stringify({
index: '*-map',
}),
query: { dataSourceId: dataSourceRefId },
});
return response;
} catch (e) {
return e;
}
},
getIndexData: async (indexName: string, size: number) => {
getIndexData: async (indexName: string, size: number, dataSourceRefId: string) => {
try {
const response = await http.post('../api/geospatial/_search', {
return await http.post('../api/geospatial/_search', {
body: JSON.stringify({
index: indexName,
size,
}),
query: { dataSourceId: dataSourceRefId },
});
return response;
} catch (e) {
return e;
}
},
getIndexMapping: async (indexName: string) => {
getIndexMapping: async (indexName: string, dataSourceRefId: string) => {
try {
const response = await http.post('../api/geospatial/_mappings', {
return await http.post('../api/geospatial/_mappings', {
body: JSON.stringify({
index: indexName,
}),
query: { dataSourceId: dataSourceRefId },
});
return response;
} catch (e) {
return e;
}
Expand Down
38 changes: 31 additions & 7 deletions src/plugins/region_map/server/routes/opensearch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,28 @@ export function registerGeospatialRoutes(router: IRouter) {
body: schema.object({
index: schema.string(),
}),
query: schema.maybe(schema.object({}, { unknowns: 'allow' })),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why we use { unknowns: 'allow' } here? isn't dataSourceId the only parameter allowed?

},
},
async (context, req, res) => {
const client = context.core.opensearch.client.asCurrentUser;
try {
const { index } = req.body;
const indices = await client.cat.indices({
index,
let client;
// @ts-ignore
if (!req.query.dataSourceId) {
client = context.core.opensearch.client.asCurrentUser;
} else {
// @ts-ignore
client = await context.dataSource.opensearch.getClient(req.query.dataSourceId);
}
const response = await client.cat.indices({
index: req.body.index,
format: 'json',
});
const indexNames = response.body.map((index: any) => index.index);
return res.ok({
body: {
ok: true,
resp: indices.body,
resp: indexNames,
},
});
} catch (err: any) {
Expand Down Expand Up @@ -59,10 +67,18 @@ export function registerGeospatialRoutes(router: IRouter) {
index: schema.string(),
size: schema.number(),
}),
query: schema.maybe(schema.object({}, { unknowns: 'allow' })),
},
},
async (context, req, res) => {
const client = context.core.opensearch.client.asCurrentUser;
let client;
// @ts-ignore
if (!req.query.dataSourceId) {
client = context.core.opensearch.client.asCurrentUser;
} else {
// @ts-ignore
client = await context.dataSource.opensearch.getClient(req.query.dataSourceId);
}
Comment on lines +76 to +81
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we extract this to be a util function for reuse? I saw 3 places are uses this

try {
const { index, size } = req.body;
const params = { index, body: {}, size };
Expand Down Expand Up @@ -91,10 +107,18 @@ export function registerGeospatialRoutes(router: IRouter) {
body: schema.object({
index: schema.string(),
}),
query: schema.maybe(schema.object({}, { unknowns: 'allow' })),
},
},
async (context, req, res) => {
const client = context.core.opensearch.client.asCurrentUser;
let client;
// @ts-ignore
if (!req.query.dataSourceId) {
client = context.core.opensearch.client.asCurrentUser;
} else {
// @ts-ignore
client = await context.dataSource.opensearch.getClient(req.query.dataSourceId);
}
try {
const { index } = req.body;
const mappings = await client.indices.getMapping({ index });
Expand Down
Loading