Skip to content

Commit

Permalink
[Workspace]Import sample data to current workspace (#6105)
Browse files Browse the repository at this point in the history
* Import sample data to workspace

Signed-off-by: Lin Wang <wonglam@amazon.com>

* Enable workspace ui plugin

Signed-off-by: Lin Wang <wonglam@amazon.com>

* Add changelog for import sample data to current workspace

Signed-off-by: Lin Wang <wonglam@amazon.com>

* feat: register sample data as standalone app (#8)

* feat: register sample data as standalone app

Signed-off-by: SuZhou-Joe <suzhou@amazon.com>

* feat: optimize code

Signed-off-by: SuZhou-Joe <suzhou@amazon.com>

* feat: add comment

Signed-off-by: SuZhou-Joe <suzhou@amazon.com>

* feat: use props to pass homeLink

Signed-off-by: SuZhou-Joe <suzhou@amazon.com>

* feat: add unit test

Signed-off-by: SuZhou-Joe <suzhou@amazon.com>

---------

Signed-off-by: SuZhou-Joe <suzhou@amazon.com>

* Retrieve workspace id from request

Signed-off-by: Lin Wang <wonglam@amazon.com>

* Remove workspace id in query

Signed-off-by: Lin Wang <wonglam@amazon.com>

* Move changelog to fragments

Signed-off-by: Lin Wang <wonglam@amazon.com>

* Fix sample data list unit tests

Signed-off-by: Lin Wang <wonglam@amazon.com>

* Remove no need workspaces deps

Signed-off-by: Lin Wang <wonglam@amazon.com>

* Remove manual created changelogs

Signed-off-by: Lin Wang <wonglam@amazon.com>

* Changeset file for PR #6105 created/updated

* Enable sample data in workspace overview page (#9)

* enable sample data in workspace overview page

Signed-off-by: Hailong Cui <ihailong@amazon.com>

* add comments for empty id

Signed-off-by: Hailong Cui <ihailong@amazon.com>

---------

Signed-off-by: Hailong Cui <ihailong@amazon.com>

* Add unit tests for getFinalSavedObjects in data sets util file

Signed-off-by: Lin Wang <wonglam@amazon.com>

* Add unit tests for renderImportSampleDataApp destroy

Signed-off-by: Lin Wang <wonglam@amazon.com>

* Address PR comments

Signed-off-by: Lin Wang <wonglam@amazon.com>

* Remove history listen in renderImportSampleDataApp

Signed-off-by: Lin Wang <wonglam@amazon.com>

* Remove Route for workspace import sample data entry point

Signed-off-by: Lin Wang <wonglam@amazon.com>

---------

Signed-off-by: Lin Wang <wonglam@amazon.com>
Signed-off-by: SuZhou-Joe <suzhou@amazon.com>
Signed-off-by: Hailong Cui <ihailong@amazon.com>
Co-authored-by: SuZhou-Joe <suzhou@amazon.com>
Co-authored-by: opensearch-changeset-bot[bot] <154024398+opensearch-changeset-bot[bot]@users.noreply.github.com>
Co-authored-by: Hailong Cui <ihailong@amazon.com>
  • Loading branch information
4 people committed May 24, 2024
1 parent 54b5eb5 commit 3e9a159
Show file tree
Hide file tree
Showing 26 changed files with 849 additions and 118 deletions.
2 changes: 2 additions & 0 deletions changelogs/fragments/6105.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
feat:
- [Workspace]Import sample data to current workspace ([#6105](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/6105))
1 change: 1 addition & 0 deletions src/plugins/home/common/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,4 @@
export const PLUGIN_ID = 'home';
export const HOME_APP_BASE_PATH = `/app/${PLUGIN_ID}`;
export const USE_NEW_HOME_PAGE = 'home:useNewHomePage';
export const IMPORT_SAMPLE_DATA_APP_ID = 'import_sample_data';
43 changes: 43 additions & 0 deletions src/plugins/home/public/application/application.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

import React, { useEffect, useRef } from 'react';
import { render } from '@testing-library/react';
import { coreMock } from '../../../../core/public/mocks';
import { renderImportSampleDataApp } from './application';

jest.mock('./components/home_app', () => ({
HomeApp: () => 'HomeApp',
ImportSampleDataApp: () => 'ImportSampleDataApp',
}));

const coreStartMocks = coreMock.createStart();

const ComponentForRender = (props: { renderFn: typeof renderImportSampleDataApp }) => {
const container = useRef<HTMLDivElement>(null);
useEffect(() => {
if (container.current) {
const destroyFn = props.renderFn(container.current, coreStartMocks);
return () => {
destroyFn.then((res) => res());
};
}
}, [props]);

return <div ref={container} />;
};

describe('renderImportSampleDataApp', () => {
it('should render ImportSampleDataApp when calling renderImportSampleDataApp', async () => {
const { container } = render(<ComponentForRender renderFn={renderImportSampleDataApp} />);
expect(container).toMatchInlineSnapshot(`
<div>
<div>
ImportSampleDataApp
</div>
</div>
`);
});
});
15 changes: 14 additions & 1 deletion src/plugins/home/public/application/application.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ import { i18n } from '@osd/i18n';
import { ScopedHistory, CoreStart } from 'opensearch-dashboards/public';
import { OpenSearchDashboardsContextProvider } from '../../../opensearch_dashboards_react/public';
// @ts-ignore
import { HomeApp } from './components/home_app';
import { HomeApp, ImportSampleDataApp } from './components/home_app';
import { getServices } from './opensearch_dashboards_services';

import './index.scss';
Expand Down Expand Up @@ -77,3 +77,16 @@ export const renderApp = async (
unlisten();
};
};

export const renderImportSampleDataApp = async (element: HTMLElement, coreStart: CoreStart) => {
render(
<OpenSearchDashboardsContextProvider services={{ ...coreStart }}>
<ImportSampleDataApp />
</OpenSearchDashboardsContextProvider>,
element
);

return () => {
unmountComponentAtNode(element);
};
};
39 changes: 29 additions & 10 deletions src/plugins/home/public/application/components/home_app.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,35 @@ const RedirectToDefaultApp = () => {
return null;
};

const renderTutorialDirectory = (props) => {
const { addBasePath, environmentService } = getServices();
const environment = environmentService.getEnvironment();
const isCloudEnabled = environment.cloud;

return (
<TutorialDirectory
addBasePath={addBasePath}
openTab={props.match.params.tab}
isCloudEnabled={isCloudEnabled}
withoutHomeBreadCrumb={props.withoutHomeBreadCrumb}
/>
);
};

export function ImportSampleDataApp() {
return (
<I18nProvider>
{renderTutorialDirectory({
// Pass a fixed tab to avoid TutorialDirectory missing openTab property
match: {
params: { tab: 'sampleData' },
},
withoutHomeBreadCrumb: true,
})}
</I18nProvider>
);
}

export function HomeApp({ directories, solutions }) {
const {
savedObjectsClient,
Expand All @@ -63,16 +92,6 @@ export function HomeApp({ directories, solutions }) {
const environment = environmentService.getEnvironment();
const isCloudEnabled = environment.cloud;

const renderTutorialDirectory = (props) => {
return (
<TutorialDirectory
addBasePath={addBasePath}
openTab={props.match.params.tab}
isCloudEnabled={isCloudEnabled}
/>
);
};

const renderTutorial = (props) => {
return (
<Tutorial
Expand Down
60 changes: 60 additions & 0 deletions src/plugins/home/public/application/components/home_app.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

import React from 'react';
import { render } from '@testing-library/react';
import { setServices } from '../opensearch_dashboards_services';
import { getMockedServices } from '../opensearch_dashboards_services.mock';
import { ImportSampleDataApp, HomeApp } from './home_app';

jest.mock('./legacy/home', () => ({
Home: () => <div>Home</div>,
}));

jest.mock('../load_tutorials', () => ({
getTutorial: () => {},
}));

jest.mock('./tutorial_directory', () => ({
TutorialDirectory: (props: { withoutHomeBreadCrumb?: boolean }) => (
<div
data-test-subj="tutorial_directory"
data-without-home-bread-crumb={!!props.withoutHomeBreadCrumb}
/>
),
}));

describe('<HomeApp />', () => {
let currentService: ReturnType<typeof getMockedServices>;
beforeEach(() => {
currentService = getMockedServices();
setServices(currentService);
});

it('should not pass withoutHomeBreadCrumb to TutorialDirectory component', async () => {
const originalHash = window.location.hash;
const { findByTestId } = render(<HomeApp />);
window.location.hash = '/tutorial_directory';
const tutorialRenderResult = await findByTestId('tutorial_directory');
expect(tutorialRenderResult.dataset.withoutHomeBreadCrumb).toEqual('false');

// revert to original hash
window.location.hash = originalHash;
});
});

describe('<ImportSampleDataApp />', () => {
let currentService: ReturnType<typeof getMockedServices>;
beforeEach(() => {
currentService = getMockedServices();
setServices(currentService);
});

it('should pass withoutHomeBreadCrumb to TutorialDirectory component', async () => {
const { findByTestId } = render(<ImportSampleDataApp />);
const tutorialRenderResult = await findByTestId('tutorial_directory');
expect(tutorialRenderResult.dataset.withoutHomeBreadCrumb).toEqual('true');
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -93,14 +93,17 @@ class TutorialDirectoryUi extends React.Component {

async componentDidMount() {
this._isMounted = true;

getServices().chrome.setBreadcrumbs([
{
const { chrome } = getServices();
const { withoutHomeBreadCrumb } = this.props;
const breadcrumbs = [{ text: addDataTitle }];
if (!withoutHomeBreadCrumb) {
breadcrumbs.splice(0, 0, {
text: homeTitle,
href: '#/',
},
{ text: addDataTitle },
]);
});
}

chrome.setBreadcrumbs(breadcrumbs);

const tutorialConfigs = await getTutorials();

Expand Down Expand Up @@ -322,6 +325,7 @@ TutorialDirectoryUi.propTypes = {
addBasePath: PropTypes.func.isRequired,
openTab: PropTypes.string,
isCloudEnabled: PropTypes.bool.isRequired,
withoutHomeBreadCrumb: PropTypes.bool,
};

export const TutorialDirectory = injectI18n(TutorialDirectoryUi);
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

import React from 'react';
import { render } from '@testing-library/react';
import { IntlProvider } from 'react-intl';
import { coreMock } from '../../../../../core/public/mocks';
import { setServices } from '../opensearch_dashboards_services';
import { getMockedServices } from '../opensearch_dashboards_services.mock';

const makeProps = () => {
const coreMocks = coreMock.createStart();
return {
addBasePath: coreMocks.http.basePath.prepend,
openTab: 'foo',
isCloudEnabled: false,
};
};

describe('<TutorialDirectory />', () => {
let currentService: ReturnType<typeof getMockedServices>;
beforeEach(() => {
currentService = getMockedServices();
setServices(currentService);
});
it('should render home breadcrumbs when withoutHomeBreadCrumb is undefined', async () => {
const finalProps = makeProps();
currentService.http.get.mockResolvedValueOnce([]);
// @ts-ignore
const { TutorialDirectory } = await import('./tutorial_directory');
render(
<IntlProvider locale="en">
<TutorialDirectory {...finalProps} />
</IntlProvider>
);
expect(currentService.chrome.setBreadcrumbs).toBeCalledWith([
{
href: '#/',
text: 'Home',
},
{
text: 'Add data',
},
]);
});

it('should not render home breadcrumbs when withoutHomeBreadCrumb is true', async () => {
const finalProps = makeProps();
currentService.http.get.mockResolvedValueOnce([]);
// @ts-ignore
const { TutorialDirectory } = await import('./tutorial_directory');
render(
<IntlProvider locale="en">
<TutorialDirectory {...finalProps} withoutHomeBreadCrumb />
</IntlProvider>
);
expect(currentService.chrome.setBreadcrumbs).toBeCalledWith([
{
text: 'Add data',
},
]);
});
});
2 changes: 1 addition & 1 deletion src/plugins/home/public/application/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,4 @@
* under the License.
*/

export { renderApp } from './application';
export { renderApp, renderImportSampleDataApp } from './application';
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

import { coreMock } from '../../../../core/public/mocks';
import { urlForwardingPluginMock } from '../../../url_forwarding/public/mocks';
import { homePluginMock } from '../mocks';
import {
EnvironmentService,
FeatureCatalogueRegistry,
SectionTypeService,
TutorialService,
} from '../services';
import { telemetryPluginMock } from '../../../telemetry/public/mocks';

export const getMockedServices = () => {
const coreMocks = coreMock.createStart();
const urlForwarding = urlForwardingPluginMock.createStartContract();
const homePlugin = homePluginMock.createSetupContract();
return {
...coreMocks,
...homePlugin,
telemetry: telemetryPluginMock.createStartContract(),
indexPatternService: jest.fn(),
dataSource: {
dataSourceEnabled: false,
hideLocalCluster: false,
noAuthenticationTypeEnabled: false,
usernamePasswordAuthEnabled: false,
awsSigV4AuthEnabled: false,
},
opensearchDashboardsVersion: '',
urlForwarding,
savedObjectsClient: coreMocks.savedObjects.client,
toastNotifications: coreMocks.notifications.toasts,
banners: coreMocks.overlays.banners,
trackUiMetric: jest.fn(),
getBasePath: jest.fn(),
addBasePath: jest.fn(),
environmentService: new EnvironmentService(),
tutorialService: new TutorialService(),
homeConfig: homePlugin.config,
featureCatalogue: new FeatureCatalogueRegistry(),
sectionTypes: new SectionTypeService(),
};
};
8 changes: 8 additions & 0 deletions src/plugins/home/public/plugin.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,5 +96,13 @@ describe('HomePublicPlugin', () => {
expect(setup).toHaveProperty('tutorials');
expect(setup.tutorials).toHaveProperty('setVariable');
});

test('wires up and register applications', async () => {
const coreMocks = coreMock.createSetup();
await new HomePublicPlugin(mockInitializerContext).setup(coreMocks, {
urlForwarding: urlForwardingPluginMock.createSetupContract(),
});
expect(coreMocks.application.register).toBeCalledTimes(2);
});
});
});
Loading

0 comments on commit 3e9a159

Please sign in to comment.