Skip to content

Commit

Permalink
Overview page add state for missing data source (#2237)
Browse files Browse the repository at this point in the history
* added callout for no data sources pathway in workspaces

Signed-off-by: Adam Tackett <[email protected]>

* reset dashboard if datasource is deleted

Signed-off-by: Adam Tackett <[email protected]>

* handle refresh, adjust naming, unit test

Signed-off-by: Adam Tackett <[email protected]>

* add i18n, finally block, move function

Signed-off-by: Adam Tackett <[email protected]>

---------

Signed-off-by: Adam Tackett <[email protected]>
Co-authored-by: Adam Tackett <[email protected]>
(cherry picked from commit 3631968)
Signed-off-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
  • Loading branch information
github-actions[bot] and Adam Tackett committed Nov 12, 2024
1 parent eb74123 commit aa5885d
Show file tree
Hide file tree
Showing 11 changed files with 415 additions and 29 deletions.
1 change: 1 addition & 0 deletions common/constants/shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export const JOBS_ENDPOINT_BASE = '/_plugins/_async_query';
export const JOB_RESULT_ENDPOINT = '/result';

export const tutorialSampleDataPluginId = 'import_sample_data';
export const dataSourceManagementPluginId = 'dataSources';

export const observabilityID = 'observability-logs';
export const observabilityTitle = 'Observability';
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`Add dashboard callout renders add datasource callout 1`] = `
<AddDataSourceCallout>
<EuiPanel
hasShadow={true}
paddingSize="m"
>
<div
className="euiPanel euiPanel--paddingMedium euiPanel--borderRadiusMedium euiPanel--plain euiPanel--hasShadow"
>
<EuiFlexGroup
alignItems="center"
direction="column"
gutterSize="m"
justifyContent="center"
>
<div
className="euiFlexGroup euiFlexGroup--gutterMedium euiFlexGroup--alignItemsCenter euiFlexGroup--justifyContentCenter euiFlexGroup--directionColumn euiFlexGroup--responsive"
>
<EuiFlexItem
grow={false}
>
<div
className="euiFlexItem euiFlexItem--flexGrowZero"
>
<EuiIcon
size="xxl"
type="database"
>
<EuiIconBeaker
aria-hidden={true}
className="euiIcon euiIcon--xxLarge euiIcon-isLoading"
focusable="false"
role="img"
style={null}
>
<svg
aria-hidden={true}
className="euiIcon euiIcon--xxLarge euiIcon-isLoading"
focusable="false"
height={16}
role="img"
style={null}
viewBox="0 0 16 16"
width={16}
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M5.277 10.088c.02.014.04.03.057.047.582.55 1.134.812 1.666.812.586 0 1.84-.293 3.713-.88L9 6.212V2H7v4.212l-1.723 3.876Zm-.438.987L3.539 14h8.922l-1.32-2.969C9.096 11.677 7.733 12 7 12c-.74 0-1.463-.315-2.161-.925ZM6 2H5V1h6v1h-1v4l3.375 7.594A1 1 0 0 1 12.461 15H3.54a1 1 0 0 1-.914-1.406L6 6V2Z"
/>
</svg>
</EuiIconBeaker>
</EuiIcon>
</div>
</EuiFlexItem>
<EuiFlexItem
grow={false}
>
<div
className="euiFlexItem euiFlexItem--flexGrowZero"
>
<EuiTitle
size="m"
>
<h3
className="euiTitle euiTitle--medium"
>
No connected data sources
</h3>
</EuiTitle>
</div>
</EuiFlexItem>
<EuiFlexItem
grow={false}
style={
Object {
"maxWidth": "40%",
}
}
>
<div
className="euiFlexItem euiFlexItem--flexGrowZero"
style={
Object {
"maxWidth": "40%",
}
}
>
<EuiText
textAlign="center"
>
<div
className="euiText euiText--medium"
>
<EuiTextAlign
textAlign="center"
>
<div
className="euiTextAlign euiTextAlign--center"
>
<p
style={
Object {
"margin": 0,
}
}
>
There are no data sources associated to the workspace. Associate data sources or request your administrator to associate data sources for you to get started.
</p>
</div>
</EuiTextAlign>
</div>
</EuiText>
</div>
</EuiFlexItem>
<EuiFlexItem
grow={false}
>
<div
className="euiFlexItem euiFlexItem--flexGrowZero"
>
<EuiButton
color="primary"
fill={true}
onClick={[Function]}
>
<EuiButtonDisplay
baseClassName="euiButton"
color="primary"
disabled={false}
element="button"
fill={true}
isDisabled={false}
onClick={[Function]}
type="button"
>
<button
className="euiButton euiButton--primary euiButton--fill"
disabled={false}
onClick={[Function]}
style={
Object {
"minWidth": undefined,
}
}
type="button"
>
<EuiButtonContent
className="euiButton__content"
iconGap="m"
iconSide="left"
textProps={
Object {
"className": "euiButton__text",
}
}
>
<span
className="euiButtonContent euiButton__content"
>
<span
className="euiButton__text"
>
Manage data sources
</span>
</span>
</EuiButtonContent>
</button>
</EuiButtonDisplay>
</EuiButton>
</div>
</EuiFlexItem>
</div>
</EuiFlexGroup>
</div>
</EuiPanel>
</AddDataSourceCallout>
`;
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`Dashboard controls should render 1`] = `
exports[`Dashboard controls - checkDataSource useEffect simplified should render 1`] = `
<DashboardControls>
<AddDashboardCallout>
<EuiPanel
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

import { configure, mount } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
import React from 'react';
import { AddDataSourceCallout } from '../add_datasource_callout';

describe('Add dashboard callout', () => {
configure({ adapter: new Adapter() });

const wrapper = mount(<AddDataSourceCallout />);

it('renders add datasource callout', async () => {
expect(wrapper).toMatchSnapshot();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -7,32 +7,92 @@ import { configure, mount } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
import React from 'react';
import { DashboardControls } from '../dashboard_controls';
import { coreRefs } from '../../../../framework/core_refs';
import { setObservabilityDashboardsId } from '../utils';
import { getWorkspaceIdFromUrl } from '../../../../../../../src/core/public/utils';
import { act } from 'react-dom/test-utils';

configure({ adapter: new Adapter() });

const mountDashboardControls = () => {
return mount(<DashboardControls />);
};

jest.mock('../../../getting_started/components/utils', () => ({
redirectToDashboards: jest.fn(),
}));

jest.mock('../../../../framework/core_refs', () => ({
coreRefs: {
contentManagement: {
updatePageSection: jest.fn(),
savedObjectsClient: {
find: jest.fn(),
},
http: {
basePath: {
getBasePath: jest.fn(() => '/basePath'),
},
},
},
}));

describe('Dashboard controls', () => {
jest.mock('../utils', () => ({
setObservabilityDashboardsId: jest.fn(),
}));

jest.mock('../../../../../common/utils', () => ({
getOverviewPage: jest.fn(() => ({
removeSection: jest.fn(),
})),
}));

jest.mock('../../../../../../../src/core/public/utils', () => ({
getWorkspaceIdFromUrl: jest.fn(),
}));

describe('Dashboard controls - checkDataSource useEffect simplified', () => {
beforeEach(() => {
jest.clearAllMocks();
});

it('should render', () => {
const wrapper = mountDashboardControls();
const wrapper = mount(<DashboardControls />);
expect(wrapper).toMatchSnapshot();
});

it('should handle no data sources in a workspace', async () => {
getWorkspaceIdFromUrl.mockReturnValue('workspace123');
coreRefs.savedObjectsClient.find.mockResolvedValue({ savedObjects: [] });

const mockSetObservabilityDashboardsId = setObservabilityDashboardsId;

await act(async () => {
mount(<DashboardControls />);
await new Promise((resolve) => setImmediate(resolve));
});

expect(mockSetObservabilityDashboardsId).toHaveBeenCalledWith(null);
});

it('should handle existing data sources in a workspace', async () => {
getWorkspaceIdFromUrl.mockReturnValue('workspace123');
coreRefs.savedObjectsClient.find.mockResolvedValue({ savedObjects: [{ id: 'ds1' }] });

const mockSetObservabilityDashboardsId = setObservabilityDashboardsId;

await act(async () => {
mount(<DashboardControls />);
await new Promise((resolve) => setImmediate(resolve));
});

expect(mockSetObservabilityDashboardsId).not.toHaveBeenCalled();
});

it('should handle non-workspace scenario', async () => {
getWorkspaceIdFromUrl.mockReturnValue(null);

const mockSetObservabilityDashboardsId = setObservabilityDashboardsId;

await act(async () => {
mount(<DashboardControls />);
await new Promise((resolve) => setImmediate(resolve));
});

expect(mockSetObservabilityDashboardsId).not.toHaveBeenCalled();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import SampleDataLightPNG from './assets/SampleDataLight.png';

export function AddDashboardCallout() {
const showFlyout = useObservable(ObsDashboardStateManager.showFlyout$);
const isDarkMode = uiSettingsService.get('theme:darkMode');
const isDarkMode = uiSettingsService?.get('theme:darkMode') ?? false;

return (
<EuiPanel paddingSize="m" hasShadow={true}>
Expand Down
56 changes: 56 additions & 0 deletions public/components/overview/components/add_datasource_callout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

import React from 'react';
import {
EuiFlexGroup,
EuiFlexItem,
EuiPanel,
EuiIcon,
EuiTitle,
EuiText,
EuiButton,
} from '@elastic/eui';
import { i18n } from '@osd/i18n';
import { coreRefs } from '../../../framework/core_refs';
import { dataSourceManagementPluginId } from '../../../../common/constants/shared';

export function AddDataSourceCallout() {
return (
<EuiPanel paddingSize="m" hasShadow={true}>
<EuiFlexGroup justifyContent="center" alignItems="center" direction="column" gutterSize="m">
<EuiFlexItem grow={false}>
<EuiIcon size="xxl" type="database" />
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiTitle size="m">
<h3>No connected data sources</h3>
</EuiTitle>
</EuiFlexItem>
<EuiFlexItem grow={false} style={{ maxWidth: '40%' }}>
<EuiText textAlign="center">
<p style={{ margin: 0 }}>
{i18n.translate('traceAnalytics.noDataSourcesMessage', {
defaultMessage:
'There are no data sources associated to the workspace. Associate data sources or request your administrator to associate data sources for you to get started.',
})}
</p>
</EuiText>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiButton
fill
color="primary"
onClick={() =>
coreRefs.application?.navigateToApp(dataSourceManagementPluginId, { path: '#/' })
}
>
Manage data sources
</EuiButton>
</EuiFlexItem>
</EuiFlexGroup>
</EuiPanel>
);
}
Loading

0 comments on commit aa5885d

Please sign in to comment.