-
Notifications
You must be signed in to change notification settings - Fork 917
Commit
…patible data sources or only show used data sources (#6129) * add data source aggregated view to show all compatible data sources or only used data sources Signed-off-by: Lu Yu <[email protected]> * add change log Signed-off-by: Lu Yu <[email protected]> * address comments and add more tests Signed-off-by: Lu Yu <[email protected]> --------- Signed-off-by: Lu Yu <[email protected]> (cherry picked from commit 05abf5e) Signed-off-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> # Conflicts: # CHANGELOG.md
- Loading branch information
There are no files selected for viewing
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
/* | ||
* Copyright OpenSearch Contributors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
import { ShallowWrapper, shallow } from 'enzyme'; | ||
import React from 'react'; | ||
import { DataSourceAggregatedView } from './data_source_aggregated_view'; | ||
import { SavedObjectsClientContract } from '../../../../../core/public'; | ||
import { notificationServiceMock } from '../../../../../core/public/mocks'; | ||
import { getDataSourcesWithFieldsResponse, mockResponseForSavedObjectsCalls } from '../../mocks'; | ||
import { render } from '@testing-library/react'; | ||
|
||
describe('DataSourceAggregatedView', () => { | ||
let component: ShallowWrapper<any, Readonly<{}>, React.Component<{}, {}, any>>; | ||
let client: SavedObjectsClientContract; | ||
const { toasts } = notificationServiceMock.createStartContract(); | ||
|
||
beforeEach(() => { | ||
client = { | ||
find: jest.fn().mockResolvedValue([]), | ||
} as any; | ||
mockResponseForSavedObjectsCalls(client, 'find', getDataSourcesWithFieldsResponse); | ||
}); | ||
|
||
it('should render normally with local cluster not hidden and all options', () => { | ||
component = shallow( | ||
<DataSourceAggregatedView | ||
fullWidth={false} | ||
hideLocalCluster={false} | ||
savedObjectsClient={client} | ||
notifications={toasts} | ||
displayAllCompatibleDataSources={true} | ||
/> | ||
); | ||
expect(component).toMatchSnapshot(); | ||
expect(client.find).toBeCalledWith({ | ||
fields: ['id', 'title', 'auth.type'], | ||
perPage: 10000, | ||
type: 'data-source', | ||
}); | ||
expect(toasts.addWarning).toBeCalledTimes(0); | ||
}); | ||
|
||
it('should render normally with local cluster hidden and all options', () => { | ||
component = shallow( | ||
<DataSourceAggregatedView | ||
fullWidth={false} | ||
hideLocalCluster={true} | ||
savedObjectsClient={client} | ||
notifications={toasts} | ||
displayAllCompatibleDataSources={true} | ||
/> | ||
); | ||
expect(component).toMatchSnapshot(); | ||
expect(client.find).toBeCalledWith({ | ||
fields: ['id', 'title', 'auth.type'], | ||
perPage: 10000, | ||
type: 'data-source', | ||
}); | ||
expect(toasts.addWarning).toBeCalledTimes(0); | ||
}); | ||
|
||
it('should render normally with local cluster and actice selections', () => { | ||
component = shallow( | ||
<DataSourceAggregatedView | ||
fullWidth={false} | ||
hideLocalCluster={false} | ||
savedObjectsClient={client} | ||
notifications={toasts} | ||
displayAllCompatibleDataSources={false} | ||
activeDataSourceIds={['test1']} | ||
/> | ||
); | ||
expect(component).toMatchSnapshot(); | ||
expect(client.find).toBeCalledWith({ | ||
fields: ['id', 'title', 'auth.type'], | ||
perPage: 10000, | ||
type: 'data-source', | ||
}); | ||
expect(toasts.addWarning).toBeCalledTimes(0); | ||
}); | ||
|
||
it('should render normally with data source filter', () => { | ||
component = shallow( | ||
<DataSourceAggregatedView | ||
fullWidth={false} | ||
hideLocalCluster={false} | ||
savedObjectsClient={client} | ||
notifications={toasts} | ||
displayAllCompatibleDataSources={false} | ||
dataSourceFilter={(ds) => ds.attributes.auth.type !== 'no_auth'} | ||
/> | ||
); | ||
expect(component).toMatchSnapshot(); | ||
expect(client.find).toBeCalledWith({ | ||
fields: ['id', 'title', 'auth.type'], | ||
perPage: 10000, | ||
type: 'data-source', | ||
}); | ||
expect(toasts.addWarning).toBeCalledTimes(0); | ||
}); | ||
|
||
it('should render popup when clicking on info icon', async () => { | ||
const container = render( | ||
<DataSourceAggregatedView | ||
fullWidth={false} | ||
hideLocalCluster={false} | ||
savedObjectsClient={client} | ||
notifications={toasts} | ||
displayAllCompatibleDataSources={false} | ||
activeDataSourceIds={['test1']} | ||
/> | ||
); | ||
const infoIcon = await container.findByTestId('dataSourceAggregatedViewInfoButton'); | ||
infoIcon.click(); | ||
expect(container).toMatchSnapshot(); | ||
}); | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,173 @@ | ||
/* | ||
* Copyright OpenSearch Contributors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
import React from 'react'; | ||
import { | ||
EuiButtonEmpty, | ||
EuiButtonIcon, | ||
EuiContextMenu, | ||
EuiNotificationBadge, | ||
EuiPopover, | ||
} from '@elastic/eui'; | ||
import { i18n } from '@osd/i18n'; | ||
import { SavedObjectsClientContract, ToastsStart } from 'opensearch-dashboards/public'; | ||
import { getDataSourcesWithFields } from '../utils'; | ||
import { SavedObject } from '../../../../../core/public'; | ||
import { DataSourceAttributes } from '../../types'; | ||
|
||
interface DataSourceAggregatedViewProps { | ||
savedObjectsClient: SavedObjectsClientContract; | ||
notifications: ToastsStart; | ||
hideLocalCluster: boolean; | ||
fullWidth: boolean; | ||
activeDataSourceIds?: string[]; | ||
dataSourceFilter?: (dataSource: SavedObject<DataSourceAttributes>) => boolean; | ||
displayAllCompatibleDataSources: boolean; | ||
} | ||
|
||
interface DataSourceAggregatedViewState { | ||
isPopoverOpen: boolean; | ||
allDataSourcesIdToTitleMap: Map<string, any>; | ||
} | ||
|
||
export class DataSourceAggregatedView extends React.Component< | ||
DataSourceAggregatedViewProps, | ||
DataSourceAggregatedViewState | ||
> { | ||
private _isMounted: boolean = false; | ||
|
||
constructor(props: DataSourceAggregatedViewProps) { | ||
super(props); | ||
|
||
this.state = { | ||
isPopoverOpen: false, | ||
allDataSourcesIdToTitleMap: new Map(), | ||
}; | ||
} | ||
|
||
componentWillUnmount() { | ||
this._isMounted = false; | ||
} | ||
|
||
onClick() { | ||
this.setState({ ...this.state, isPopoverOpen: !this.state.isPopoverOpen }); | ||
} | ||
|
||
closePopover() { | ||
this.setState({ ...this.state, isPopoverOpen: false }); | ||
Check warning on line 59 in src/plugins/data_source_management/public/components/data_source_aggregated_view/data_source_aggregated_view.tsx Codecov / codecov/patchsrc/plugins/data_source_management/public/components/data_source_aggregated_view/data_source_aggregated_view.tsx#L59
|
||
} | ||
|
||
async componentDidMount() { | ||
this._isMounted = true; | ||
getDataSourcesWithFields(this.props.savedObjectsClient, ['id', 'title', 'auth.type']) | ||
.then((fetchedDataSources) => { | ||
if (fetchedDataSources?.length) { | ||
let filteredDataSources = fetchedDataSources; | ||
if (this.props.dataSourceFilter) { | ||
filteredDataSources = fetchedDataSources.filter((ds) => | ||
this.props.dataSourceFilter!(ds) | ||
); | ||
} | ||
|
||
const allDataSourcesIdToTitleMap = new Map(); | ||
|
||
filteredDataSources.forEach((ds) => { | ||
allDataSourcesIdToTitleMap.set(ds.id, ds.attributes!.title || ''); | ||
}); | ||
|
||
if (!this.props.hideLocalCluster) { | ||
allDataSourcesIdToTitleMap.set('', 'Local cluster'); | ||
} | ||
|
||
if (!this._isMounted) return; | ||
this.setState({ | ||
...this.state, | ||
allDataSourcesIdToTitleMap, | ||
}); | ||
} | ||
}) | ||
.catch(() => { | ||
this.props.notifications.addWarning( | ||
Check warning on line 92 in src/plugins/data_source_management/public/components/data_source_aggregated_view/data_source_aggregated_view.tsx Codecov / codecov/patchsrc/plugins/data_source_management/public/components/data_source_aggregated_view/data_source_aggregated_view.tsx#L92
|
||
i18n.translate('dataSource.fetchDataSourceError', { | ||
defaultMessage: 'Unable to fetch existing data sources', | ||
}) | ||
); | ||
}); | ||
} | ||
|
||
render() { | ||
const button = ( | ||
<EuiButtonIcon | ||
data-test-subj="dataSourceAggregatedViewInfoButton" | ||
iconType="iInCircle" | ||
display="empty" | ||
aria-label="show data sources" | ||
onClick={this.onClick.bind(this)} | ||
/> | ||
); | ||
|
||
let items = []; | ||
|
||
// only display active data sources | ||
if (this.props.activeDataSourceIds && this.props.activeDataSourceIds.length > 0) { | ||
items = this.props.activeDataSourceIds.map((id) => { | ||
return { | ||
name: this.state.allDataSourcesIdToTitleMap.get(id), | ||
disabled: true, | ||
}; | ||
}); | ||
} else { | ||
items = [...this.state.allDataSourcesIdToTitleMap.values()].map((title) => { | ||
return { | ||
name: title, | ||
disabled: true, | ||
}; | ||
}); | ||
} | ||
|
||
const title = this.props.displayAllCompatibleDataSources | ||
? `Data sources (${this.state.allDataSourcesIdToTitleMap.size})` | ||
: 'Selected data sources'; | ||
|
||
const panels = [ | ||
{ | ||
id: 0, | ||
title, | ||
items, | ||
}, | ||
]; | ||
|
||
return ( | ||
<> | ||
<EuiButtonEmpty | ||
className="euiHeaderLink" | ||
data-test-subj="dataSourceAggregatedViewContextMenuHeaderLink" | ||
aria-label={i18n.translate('dataSourceAggregatedView.dataSourceOptionsButtonAriaLabel', { | ||
defaultMessage: 'dataSourceAggregatedViewMenuButton', | ||
})} | ||
iconType="database" | ||
iconSide="left" | ||
size="s" | ||
disabled={true} | ||
> | ||
{'Data sources'} | ||
</EuiButtonEmpty> | ||
<EuiNotificationBadge color={'subdued'}> | ||
{this.props.activeDataSourceIds?.length || 'All'} | ||
</EuiNotificationBadge> | ||
<EuiPopover | ||
id={'dataSourceSViewContextMenuPopover'} | ||
button={button} | ||
isOpen={this.state.isPopoverOpen} | ||
closePopover={this.closePopover.bind(this)} | ||
panelPaddingSize="none" | ||
anchorPosition="downLeft" | ||
> | ||
<EuiContextMenu initialPanelId={0} panels={panels} /> | ||
</EuiPopover> | ||
</> | ||
); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
/* | ||
* Copyright OpenSearch Contributors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
export { DataSourceAggregatedView } from './data_source_aggregated_view'; |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.