Skip to content

Commit

Permalink
Modify toast + popover warning to include incompatible datasources
Browse files Browse the repository at this point in the history
Signed-off-by: Huy Nguyen <[email protected]>
  • Loading branch information
huyaboo committed May 3, 2024
1 parent b5121d3 commit 3469153
Show file tree
Hide file tree
Showing 11 changed files with 374 additions and 71 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,8 @@ export const LocalCluster: DataSourceOption = {
}),
id: '',
};

export const NO_DATASOURCES_CONNECTED_MESSAGE = 'No data sources connected yet.';
export const CONNECT_DATASOURCES_MESSAGE = 'Connect your data sources to get started.';
export const NO_COMPATIBLE_DATASOURCES_MESSAGE = 'No compatible data sources are available.';
export const ADD_COMPATIBLE_DATASOURCES_MESSAGE = 'Add a compatible data source.';
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@

import { ShallowWrapper, shallow } from 'enzyme';
import React from 'react';
import { i18n } from '@osd/i18n';
import { DataSourceAggregatedView } from './data_source_aggregated_view';
import { SavedObject, SavedObjectsClientContract } from '../../../../../core/public';
import { IToasts, SavedObject, SavedObjectsClientContract } from '../../../../../core/public';
import {
applicationServiceMock,
notificationServiceMock,
Expand All @@ -20,6 +21,12 @@ import {
import * as utils from '../utils';
import { EuiSelectable, EuiSwitch } from '@elastic/eui';
import { DataSourceAttributes } from '../../types';
import {
ADD_COMPATIBLE_DATASOURCES_MESSAGE,
CONNECT_DATASOURCES_MESSAGE,
NO_COMPATIBLE_DATASOURCES_MESSAGE,
NO_DATASOURCES_CONNECTED_MESSAGE,
} from '../constants';

describe('DataSourceAggregatedView: read all view (displayAllCompatibleDataSources is set to true)', () => {
let component: ShallowWrapper<any, Readonly<{}>, React.Component<{}, {}, any>>;
Expand Down Expand Up @@ -269,3 +276,64 @@ describe('DataSourceAggregatedView: read active view (displayAllCompatibleDataSo
}
);
});

describe('DataSourceAggregatedView warning messages', () => {
const client = {} as any;
const uiSettings = uiSettingsServiceMock.createStartContract();
const nextTick = () => new Promise((res) => process.nextTick(res));
let toasts: IToasts;
const noDataSourcesConnectedMessage = `${NO_DATASOURCES_CONNECTED_MESSAGE} ${CONNECT_DATASOURCES_MESSAGE}`;
const noCompatibleDataSourcesMessage = `${NO_COMPATIBLE_DATASOURCES_MESSAGE} ${ADD_COMPATIBLE_DATASOURCES_MESSAGE}`;

beforeEach(() => {
toasts = notificationServiceMock.createStartContract().toasts;
mockUiSettingsCalls(uiSettings, 'get', 'test1');
});

it.each([
{
findFunc: jest.fn().mockResolvedValue(getDataSourcesWithFieldsResponse),
defaultMessage: noCompatibleDataSourcesMessage,
activeDataSourceIds: ['test2'],
},
{
findFunc: jest.fn().mockResolvedValue({ savedObjects: [] }),
defaultMessage: noDataSourcesConnectedMessage,
activeDataSourceIds: ['test2'],
},
{
findFunc: jest.fn().mockResolvedValue(getDataSourcesWithFieldsResponse),
defaultMessage: noCompatibleDataSourcesMessage,
activeDataSourceIds: undefined,
},
{
findFunc: jest.fn().mockResolvedValue({ savedObjects: [] }),
defaultMessage: noDataSourcesConnectedMessage,
activeDataSourceIds: undefined,
},
])(
'should display correct warning message when no datasource selections are available and local cluster is hidden',
async ({ findFunc, defaultMessage, activeDataSourceIds }) => {
client.find = findFunc;
shallow(
<DataSourceAggregatedView
fullWidth={false}
hideLocalCluster={true}
savedObjectsClient={client}
notifications={toasts}
displayAllCompatibleDataSources={!!!activeDataSourceIds}
activeDataSourceIds={activeDataSourceIds}
dataSourceFilter={(_) => false}
uiSettings={uiSettings}
/>
);
await nextTick();

expect(toasts.add).toBeCalledWith(
expect.objectContaining({
title: i18n.translate('dataSource.noAvailableDataSourceError', { defaultMessage }),
})
);
}
);
});
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ interface DataSourceAggregatedViewState extends DataSourceBaseState {
allDataSourcesIdToTitleMap: Map<string, any>;
switchChecked: boolean;
defaultDataSource: string | null;
hasIncompatibleDataSources: boolean;
}

interface DataSourceOptionDisplay extends DataSourceOption {
Expand All @@ -68,6 +69,7 @@ export class DataSourceAggregatedView extends React.Component<
showError: false,
switchChecked: false,
defaultDataSource: null,
hasIncompatibleDataSources: false,
};
}

Expand Down Expand Up @@ -113,11 +115,12 @@ export class DataSourceAggregatedView extends React.Component<
}

if (allDataSourcesIdToTitleMap.size === 0) {
handleNoAvailableDataSourceError(
this.onEmptyState.bind(this),
this.props.notifications,
this.props.application
);
handleNoAvailableDataSourceError({
changeState: this.onEmptyState.bind(this, !!fetchedDataSources?.length),
notifications: this.props.notifications,
application: this.props.application,
hasIncompatibleDatasources: !!fetchedDataSources?.length,
});
return;
}

Expand All @@ -133,8 +136,8 @@ export class DataSourceAggregatedView extends React.Component<
});
}

onEmptyState() {
this.setState({ showEmptyState: true });
onEmptyState(hasIncompatibleDataSources: boolean) {
this.setState({ showEmptyState: true, hasIncompatibleDataSources });
}

onError() {
Expand All @@ -143,7 +146,12 @@ export class DataSourceAggregatedView extends React.Component<

render() {
if (this.state.showEmptyState) {
return <NoDataSource application={this.props.application} />;
return (
<NoDataSource
application={this.props.application}
hasIncompatibleDatasources={this.state.hasIncompatibleDataSources}
/>
);
}
if (this.state.showError) {
return <DataSourceErrorMenu application={this.props.application} />;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ interface DataSourceMultiSeletableState extends DataSourceBaseState {
dataSourceOptions: SelectedDataSourceOption[];
selectedOptions: SelectedDataSourceOption[];
defaultDataSource: string | null;
hasIncompatibleDatasources: boolean;
}

export class DataSourceMultiSelectable extends React.Component<
Expand All @@ -51,6 +52,7 @@ export class DataSourceMultiSelectable extends React.Component<
defaultDataSource: null,
showEmptyState: false,
showError: false,
hasIncompatibleDatasources: false,
};
}

Expand Down Expand Up @@ -90,12 +92,13 @@ export class DataSourceMultiSelectable extends React.Component<
if (!this._isMounted) return;

if (selectedOptions.length === 0) {
handleNoAvailableDataSourceError(
this.onEmptyState.bind(this),
this.props.notifications,
this.props.application,
this.props.onSelectedDataSources
);
handleNoAvailableDataSourceError({

Check warning on line 95 in src/plugins/data_source_management/public/components/data_source_multi_selectable/data_source_multi_selectable.tsx

View check run for this annotation

Codecov / codecov/patch

src/plugins/data_source_management/public/components/data_source_multi_selectable/data_source_multi_selectable.tsx#L95

Added line #L95 was not covered by tests
changeState: this.onEmptyState.bind(this, !!fetchedDataSources?.length),
notifications: this.props.notifications,
application: this.props.application,
callback: this.props.onSelectedDataSources,
hasIncompatibleDatasources: !!fetchedDataSources?.length,
});
return;
}

Expand All @@ -115,8 +118,8 @@ export class DataSourceMultiSelectable extends React.Component<
}
}

onEmptyState() {
this.setState({ showEmptyState: true });
onEmptyState(hasIncompatibleDatasources: boolean) {
this.setState({ showEmptyState: true, hasIncompatibleDatasources });

Check warning on line 122 in src/plugins/data_source_management/public/components/data_source_multi_selectable/data_source_multi_selectable.tsx

View check run for this annotation

Codecov / codecov/patch

src/plugins/data_source_management/public/components/data_source_multi_selectable/data_source_multi_selectable.tsx#L122

Added line #L122 was not covered by tests
}

onError() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
*/

import { ShallowWrapper, shallow, mount } from 'enzyme';
import { i18n } from '@osd/i18n';
import { SavedObjectsClientContract } from '../../../../../core/public';
import { notificationServiceMock } from '../../../../../core/public/mocks';
import React from 'react';
Expand All @@ -12,13 +13,21 @@ import { AuthType } from '../../types';
import { getDataSourcesWithFieldsResponse, mockResponseForSavedObjectsCalls } from '../../mocks';
import { render } from '@testing-library/react';
import * as utils from '../utils';
import {
NO_DATASOURCES_CONNECTED_MESSAGE,
CONNECT_DATASOURCES_MESSAGE,
NO_COMPATIBLE_DATASOURCES_MESSAGE,
ADD_COMPATIBLE_DATASOURCES_MESSAGE,
} from '../constants';

describe('DataSourceSelectable', () => {
let component: ShallowWrapper<any, Readonly<{}>, React.Component<{}, {}, any>>;

let client: SavedObjectsClientContract;
const { toasts } = notificationServiceMock.createStartContract();
const nextTick = () => new Promise((res) => process.nextTick(res));
const noDataSourcesConnectedMessage = `${NO_DATASOURCES_CONNECTED_MESSAGE} ${CONNECT_DATASOURCES_MESSAGE}`;
const noCompatibleDataSourcesMessage = `${NO_COMPATIBLE_DATASOURCES_MESSAGE} ${ADD_COMPATIBLE_DATASOURCES_MESSAGE}`;

beforeEach(() => {
client = {
Expand Down Expand Up @@ -145,6 +154,7 @@ describe('DataSourceSelectable', () => {
},
],
showError: false,
hasIncompatibleDatasources: false,
});

containerInstance.onChange([{ id: 'test2', label: 'test2', checked: 'on' }]);
Expand All @@ -167,6 +177,7 @@ describe('DataSourceSelectable', () => {
},
],
showError: false,
hasIncompatibleDatasources: false,
});

expect(onSelectedDataSource).toBeCalledWith([{ id: 'test2', label: 'test2' }]);
Expand Down Expand Up @@ -345,6 +356,7 @@ describe('DataSourceSelectable', () => {
},
],
showError: false,
hasIncompatibleDatasources: false,
});
});

Expand Down Expand Up @@ -374,6 +386,7 @@ describe('DataSourceSelectable', () => {
selectedOption: [],
showEmptyState: false,
showError: true,
hasIncompatibleDatasources: false,
});

containerInstance.onChange([{ id: 'test2', label: 'test2', checked: 'on' }]);
Expand All @@ -396,27 +409,59 @@ describe('DataSourceSelectable', () => {
},
],
showError: true,
hasIncompatibleDatasources: false,
});

expect(onSelectedDataSource).toBeCalledWith([{ id: 'test2', label: 'test2' }]);
expect(onSelectedDataSource).toHaveBeenCalled();
});
it('should render no data source when no data source filtered out and hide local cluster', async () => {
const onSelectedDataSource = jest.fn();
render(
<DataSourceSelectable
savedObjectsClient={client}
notifications={toasts}
onSelectedDataSources={onSelectedDataSource}
disabled={false}
hideLocalCluster={true}
fullWidth={false}
selectedOption={[{ id: 'test2' }]}
dataSourceFilter={(ds) => false}
/>
);
await nextTick();
expect(toasts.add).toBeCalled();
expect(onSelectedDataSource).toBeCalledWith([]);
});

it.each([
{
findFunc: jest.fn().mockResolvedValue({ savedObjects: [] }),
defaultMessage: noDataSourcesConnectedMessage,
selectedOption: undefined,
},
{
findFunc: jest.fn().mockResolvedValue({ savedObjects: [] }),
defaultMessage: noDataSourcesConnectedMessage,
selectedOption: [{ id: 'test2' }],
},
{
findFunc: jest.fn().mockResolvedValue(getDataSourcesWithFieldsResponse),
defaultMessage: noCompatibleDataSourcesMessage,
selectedOption: undefined,
},
{
findFunc: jest.fn().mockResolvedValue(getDataSourcesWithFieldsResponse),
defaultMessage: noCompatibleDataSourcesMessage,
selectedOption: [{ id: 'test2' }],
},
])(
'should render correct message when there are no datasource options available and local cluster is hidden',
async ({ findFunc, selectedOption, defaultMessage }) => {
client.find = findFunc;
const onSelectedDataSource = jest.fn();
render(
<DataSourceSelectable
savedObjectsClient={client}
notifications={toasts}
onSelectedDataSources={onSelectedDataSource}
disabled={false}
hideLocalCluster={true}
fullWidth={false}
selectedOption={selectedOption}
dataSourceFilter={(ds) => false}
/>
);
await nextTick();

expect(toasts.add).toBeCalledWith(
expect.objectContaining({
title: i18n.translate('dataSource.noAvailableDataSourceError', { defaultMessage }),
})
);
expect(onSelectedDataSource).toBeCalledWith([]);
}
);
});
Loading

0 comments on commit 3469153

Please sign in to comment.