Skip to content

Commit

Permalink
refactor datasource_selectable to address comments
Browse files Browse the repository at this point in the history
Signed-off-by: Joshua Li <joshuali925@gmail.com>
  • Loading branch information
joshuali925 committed Oct 5, 2023
1 parent e8f219b commit 3642ef5
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 78 deletions.
2 changes: 1 addition & 1 deletion src/plugins/data/public/data_sources/datasource/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export interface IDataSourceGroup {

export interface ISourceDataSet {
ds: DataSourceType;
data_sets: string[] | IndexPatternOption[];
data_sets: Array<string | IndexPatternOption>;
}

// to-dos: add common interfaces for datasource
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@
* SPDX-License-Identifier: Apache-2.0
*/

import React, { useEffect } from 'react';
import { i18n } from '@osd/i18n';
import { EuiComboBox } from '@elastic/eui';
import { i18n } from '@osd/i18n';
import React, { useEffect } from 'react';
import { ISourceDataSet, IndexPatternOption } from '../datasource';
import { DataSourceType, GenericDataSource } from '../datasource_services';
import { DataSourceGroup, DataSourceSelectableProps } from './types';
import { ISourceDataSet, IndexPatternOption } from '../datasource';

type DataSourceTypeKey = 'DEFAULT_INDEX_PATTERNS' | 's3glue' | 'spark';

Expand All @@ -19,94 +19,93 @@ const DATASOURCE_TYPE_DISPLAY_NAME_MAP: Record<DataSourceTypeKey, string> = {
spark: 'Spark',
};

type DataSetType = string | IndexPatternOption;
type DataSetType = ISourceDataSet['data_sets'][number];

interface DataSetWithSource {
ds: GenericDataSource;
data_sets: string[] | IndexPatternOption[];
data_sets: DataSetType[];
}

// Fetches data sets for a given datasource and returns it along with the source.
const fetchDataSetWithSource = async (ds: GenericDataSource): Promise<DataSetWithSource> => {
const dataSet = await ds.getDataSet();
return {
ds,
data_sets: dataSet,
};
};

// Map through all data sources and fetch their respective data sets.
const fetchDataSets = (dataSources: GenericDataSource[]) =>
dataSources.map((ds) => fetchDataSetWithSource(ds));

const isIndexPatterns = (dataSet: DataSetType): dataSet is IndexPatternOption => {
if (typeof dataSet === 'string') return false;

return !!(dataSet.title && dataSet.id);
};

// Get the option format for the combo box from the dataSource and dataSet.
const getSourceOptions = (dataSource: DataSourceType, dataSet: DataSetType) => {
const optionContent = {
type: dataSource.getType(),
name: dataSource.getName(),
ds: dataSource,
};
if (isIndexPatterns(dataSet)) {
const ip = dataSet as IndexPatternOption;
return {
...optionContent,
label: ip.title,
value: ip.id,
};
}
return {
...optionContent,
label: dataSource.getName(),
value: dataSource.getName(),
};
};

// Convert fetched data sets into a structured format suitable for selector rendering.
const getSourceList = (allDataSets: ISourceDataSet[]) => {
const finalList = [] as DataSourceGroup[];
allDataSets.forEach((curDataSet) => {
const typeKey = curDataSet.ds.getType() as DataSourceTypeKey;
const groupName = DATASOURCE_TYPE_DISPLAY_NAME_MAP[typeKey] || 'Default Group';

const existingGroup = finalList.find((item) => item.label === groupName);
const mappedOptions = curDataSet.data_sets?.map((dataSet) =>
getSourceOptions(curDataSet.ds, dataSet)
);

// check if add new datasource group or add to existing one
if (existingGroup) {
const existingOptionIds = new Set(existingGroup.options.map((opt) => opt.label));
const nonDuplicateOptions = mappedOptions.filter((opt) => !existingOptionIds.has(opt.label));
existingGroup.options.push(...nonDuplicateOptions);
} else {
finalList.push({
label: groupName,
options: mappedOptions,
});
}
});
return finalList;
};

export const DataSourceSelectable = ({
dataSources, // list of all available datasource connections.
dataSourceOptionList, // combo box renderable option list derived from dataSources
selectedSources, // current selected datasource in the form of [{ label: xxx, value: xxx }]
onDataSourceSelect,
setDataSourceOptionList,
onFetchDataSetError, // onFetchDataSetError, Callback for handling dataset fetch errors. Ensure it's memoized.
onFetchDataSetError, // onFetchDataSetError, Callback for handling data set fetch errors. Ensure it's memoized.
singleSelection = true,
}: DataSourceSelectableProps) => {
// This effect fetches datasets and prepares the datasource list for UI rendering.
// This effect fetches data sets and prepares the datasource list for UI rendering.
useEffect(() => {
// Fetches datasets for a given datasource and returns it along with the source.
const fetchDataSetWithSource = async (ds: GenericDataSource): Promise<DataSetWithSource> => {
const dataSet = await ds.getDataSet();
return {
ds,
data_sets: dataSet,
};
};

// Map through all data sources and fetch their respective datasets.
const fetchDataSets = () => dataSources.map((ds: DataSourceType) => fetchDataSetWithSource(ds));

const isIndexPatterns = (dataset: string | IndexPatternOption): boolean => {
if (typeof dataset === 'string') return false;

return dataset.title !== undefined && dataset.id !== undefined;
};

// Get the option format for the combo box from the dataSource and dataSet.
const getSourceOptions = (dataSource: DataSourceType, dataSet: DataSetType) => {
const optionContent = {
type: dataSource.getType(),
name: dataSource.getName(),
ds: dataSource,
};
if (isIndexPatterns(dataSet)) {
const ip = dataSet as IndexPatternOption;
return {
...optionContent,
label: ip.title,
value: ip.id,
};
}
return {
...optionContent,
label: dataSource.getName(),
value: dataSource.getName(),
};
};

// Convert fetched datasets into a structured format suitable for selector rendering.
const getSourceList = (allDataSets: ISourceDataSet[]) => {
const finalList = [] as DataSourceGroup[];
allDataSets.forEach((curDataSet) => {
const typeKey = curDataSet.ds.getType() as DataSourceTypeKey;
const groupName = DATASOURCE_TYPE_DISPLAY_NAME_MAP[typeKey] || 'Default Group';

const existingGroup = finalList.find((item) => item.label === groupName);
const mappedOptions = curDataSet.data_sets?.map((dataSet) =>
getSourceOptions(curDataSet.ds, dataSet)
);

// check if add new datasource group or add to existing one
if (existingGroup) {
const existingOptionIds = new Set(existingGroup.options.map((opt) => opt.label));
const nonDuplicateOptions = mappedOptions.filter(
(opt) => !existingOptionIds.has(opt.label)
);
existingGroup.options.push(...nonDuplicateOptions);
} else {
finalList.push({
label: groupName,
options: mappedOptions,
});
}
});
return finalList;
};

Promise.all(fetchDataSets())
Promise.all(fetchDataSets(dataSources))
.then((results) => {
setDataSourceOptionList(getSourceList(results));
})
Expand Down

0 comments on commit 3642ef5

Please sign in to comment.