Skip to content

Commit

Permalink
[Workspace] use registered nav groups in workspace form (opensearch-p…
Browse files Browse the repository at this point in the history
…roject#7221)

* Add registered use cases

Signed-off-by: Lin Wang <[email protected]>

* Separate use case service and fix UTs

Signed-off-by: Lin Wang <[email protected]>

* Add test case for workspace plugin

Signed-off-by: Lin Wang <[email protected]>

* Fix workspace unit tests

Signed-off-by: Lin Wang <[email protected]>

* Changeset file for PR opensearch-project#7221 created/updated

* Remove workspaceConfigurableApp$ in component

Signed-off-by: Lin Wang <[email protected]>

* Remove no need workspaceConfigurableApps$ and add navGroupUpdater ut

Signed-off-by: Lin Wang <[email protected]>

* Fix type error

Signed-off-by: Lin Wang <[email protected]>

* Remove centered horizontal position

Signed-off-by: Lin Wang <[email protected]>

* Fix isDashboardAdmin in workspace creator unit tests

Signed-off-by: Lin Wang <[email protected]>

* Fix dynamic nav groups missing in workspace list

Signed-off-by: Lin Wang <[email protected]>

---------

Signed-off-by: Lin Wang <[email protected]>
Co-authored-by: opensearch-changeset-bot[bot] <154024398+opensearch-changeset-bot[bot]@users.noreply.github.com>
  • Loading branch information
wanglam and opensearch-changeset-bot[bot] authored Jul 19, 2024
1 parent 352682b commit fceba91
Show file tree
Hide file tree
Showing 24 changed files with 759 additions and 247 deletions.
2 changes: 2 additions & 0 deletions changelogs/fragments/7221.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
feat:
- Use registered nav group as workspace use case ([#7221](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7221))
10 changes: 7 additions & 3 deletions src/plugins/workspace/public/application.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { AppMountParameters, ScopedHistory } from '../../../core/public';
import { OpenSearchDashboardsContextProvider } from '../../opensearch_dashboards_react/public';
import { WorkspaceFatalError } from './components/workspace_fatal_error';
import { WorkspaceCreatorApp } from './components/workspace_creator_app';
import { WorkspaceListApp } from './components/workspace_list_app';
import { WorkspaceListApp, WorkspaceListAppProps } from './components/workspace_list_app';
import { Services } from './types';
import { WorkspaceCreatorProps } from './components/workspace_creator/workspace_creator';
import { WorkspaceDetailApp } from './components/workspace_detail_app';
Expand Down Expand Up @@ -46,10 +46,14 @@ export const renderFatalErrorApp = (params: AppMountParameters, services: Servic
ReactDOM.unmountComponentAtNode(element);
};
};
export const renderListApp = ({ element }: AppMountParameters, services: Services) => {
export const renderListApp = (
{ element }: AppMountParameters,
services: Services,
props: WorkspaceListAppProps
) => {
ReactDOM.render(
<OpenSearchDashboardsContextProvider services={services}>
<WorkspaceListApp />
<WorkspaceListApp {...props} />
</OpenSearchDashboardsContextProvider>,
element
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,13 @@ import React from 'react';
import { PublicAppInfo } from 'opensearch-dashboards/public';
import { fireEvent, render, waitFor, act } from '@testing-library/react';
import { BehaviorSubject } from 'rxjs';
import { WorkspaceCreator as WorkspaceCreatorComponent } from './workspace_creator';
import {
WorkspaceCreator as WorkspaceCreatorComponent,
WorkspaceCreatorProps,
} from './workspace_creator';
import { coreMock } from '../../../../../core/public/mocks';
import { createOpenSearchDashboardsReactContext } from '../../../../opensearch_dashboards_react/public';
import { WORKSPACE_USE_CASES } from '../../../common/constants';

const workspaceClientCreate = jest
.fn()
Expand Down Expand Up @@ -43,7 +47,10 @@ const dataSourcesList = [

const mockCoreStart = coreMock.createStart();

const WorkspaceCreator = (props: any, isDashboardAdmin = false) => {
const WorkspaceCreator = ({
isDashboardAdmin = false,
...props
}: Partial<WorkspaceCreatorProps & { isDashboardAdmin: boolean }>) => {
const { Provider } = createOpenSearchDashboardsReactContext({
...mockCoreStart,
...{
Expand Down Expand Up @@ -86,10 +93,16 @@ const WorkspaceCreator = (props: any, isDashboardAdmin = false) => {
dataSourceManagement: {},
},
});
const registeredUseCases$ = new BehaviorSubject([
WORKSPACE_USE_CASES.observability,
WORKSPACE_USE_CASES['security-analytics'],
WORKSPACE_USE_CASES.analytics,
WORKSPACE_USE_CASES.search,
]);

return (
<Provider>
<WorkspaceCreatorComponent {...props} />
<WorkspaceCreatorComponent {...props} registeredUseCases$={registeredUseCases$} />
</Provider>
);
};
Expand Down Expand Up @@ -122,21 +135,13 @@ describe('WorkspaceCreator', () => {
});

it('should not create workspace when name is empty', async () => {
const { getByTestId } = render(
<WorkspaceCreator
workspaceConfigurableApps$={new BehaviorSubject([...PublicAPPInfoMap.values()])}
/>
);
const { getByTestId } = render(<WorkspaceCreator />);
fireEvent.click(getByTestId('workspaceForm-bottomBar-createButton'));
expect(workspaceClientCreate).not.toHaveBeenCalled();
});

it('should not create workspace with invalid name', async () => {
const { getByTestId } = render(
<WorkspaceCreator
workspaceConfigurableApps$={new BehaviorSubject([...PublicAPPInfoMap.values()])}
/>
);
const { getByTestId } = render(<WorkspaceCreator />);
const nameInput = getByTestId('workspaceForm-workspaceDetails-nameInputText');
fireEvent.input(nameInput, {
target: { value: '~' },
Expand All @@ -146,11 +151,7 @@ describe('WorkspaceCreator', () => {

it('should not create workspace without use cases', async () => {
setHrefSpy.mockReset();
const { getByTestId } = render(
<WorkspaceCreator
workspaceConfigurableApps$={new BehaviorSubject([...PublicAPPInfoMap.values()])}
/>
);
const { getByTestId } = render(<WorkspaceCreator />);
const nameInput = getByTestId('workspaceForm-workspaceDetails-nameInputText');
fireEvent.input(nameInput, {
target: { value: 'test workspace name' },
Expand All @@ -161,23 +162,15 @@ describe('WorkspaceCreator', () => {
});

it('cancel create workspace', async () => {
const { findByText, getByTestId } = render(
<WorkspaceCreator
workspaceConfigurableApps$={new BehaviorSubject([...PublicAPPInfoMap.values()])}
/>
);
const { findByText, getByTestId } = render(<WorkspaceCreator />);
fireEvent.click(getByTestId('workspaceForm-bottomBar-cancelButton'));
await findByText('Discard changes?');
fireEvent.click(getByTestId('confirmModalConfirmButton'));
expect(navigateToApp).toHaveBeenCalled();
});

it('create workspace with detailed information', async () => {
const { getByTestId } = render(
<WorkspaceCreator
workspaceConfigurableApps$={new BehaviorSubject([...PublicAPPInfoMap.values()])}
/>
);
const { getByTestId } = render(<WorkspaceCreator />);
const nameInput = getByTestId('workspaceForm-workspaceDetails-nameInputText');
fireEvent.input(nameInput, {
target: { value: 'test workspace name' },
Expand Down Expand Up @@ -217,11 +210,7 @@ describe('WorkspaceCreator', () => {

it('should show danger toasts after create workspace failed', async () => {
workspaceClientCreate.mockReturnValueOnce({ result: { id: 'failResult' }, success: false });
const { getByTestId } = render(
<WorkspaceCreator
workspaceConfigurableApps$={new BehaviorSubject([...PublicAPPInfoMap.values()])}
/>
);
const { getByTestId } = render(<WorkspaceCreator />);
const nameInput = getByTestId('workspaceForm-workspaceDetails-nameInputText');
fireEvent.input(nameInput, {
target: { value: 'test workspace name' },
Expand All @@ -239,11 +228,7 @@ describe('WorkspaceCreator', () => {
workspaceClientCreate.mockImplementationOnce(async () => {
throw new Error();
});
const { getByTestId } = render(
<WorkspaceCreator
workspaceConfigurableApps$={new BehaviorSubject([...PublicAPPInfoMap.values()])}
/>
);
const { getByTestId } = render(<WorkspaceCreator />);
const nameInput = getByTestId('workspaceForm-workspaceDetails-nameInputText');
fireEvent.input(nameInput, {
target: { value: 'test workspace name' },
Expand All @@ -257,12 +242,8 @@ describe('WorkspaceCreator', () => {
expect(notificationToastsAddSuccess).not.toHaveBeenCalled();
});

it('create workspace with current user', async () => {
const { getByTestId } = render(
<WorkspaceCreator
workspaceConfigurableApps$={new BehaviorSubject([...PublicAPPInfoMap.values()])}
/>
);
it('create workspace with customized permissions', async () => {
const { getByTestId } = render(<WorkspaceCreator />);
const nameInput = getByTestId('workspaceForm-workspaceDetails-nameInputText');
fireEvent.input(nameInput, {
target: { value: 'test workspace name' },
Expand Down Expand Up @@ -294,10 +275,7 @@ describe('WorkspaceCreator', () => {

it('create workspace with customized selected dataSources', async () => {
const { getByTestId, getByTitle, getByText } = render(
<WorkspaceCreator
workspaceConfigurableApps$={new BehaviorSubject([...PublicAPPInfoMap.values()])}
isDashboardAdmin={true}
/>
<WorkspaceCreator isDashboardAdmin={true} />
);
const nameInput = getByTestId('workspaceForm-workspaceDetails-nameInputText');
fireEvent.input(nameInput, {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,8 @@ import React, { useCallback } from 'react';
import { EuiPage, EuiPageBody, EuiPageHeader, EuiPageContent } from '@elastic/eui';
import { i18n } from '@osd/i18n';
import { useObservable } from 'react-use';
import { BehaviorSubject, of } from 'rxjs';
import { BehaviorSubject } from 'rxjs';

import { PublicAppInfo } from 'opensearch-dashboards/public';
import { useOpenSearchDashboards } from '../../../../opensearch_dashboards_react/public';
import { WorkspaceForm, WorkspaceFormSubmitData, WorkspaceOperationType } from '../workspace_form';
import { WORKSPACE_DETAIL_APP_ID } from '../../../common/constants';
Expand All @@ -18,9 +17,10 @@ import { WorkspaceClient } from '../../workspace_client';
import { convertPermissionSettingsToPermissions } from '../workspace_form';
import { DataSource } from '../../../common/types';
import { DataSourceManagementPluginSetup } from '../../../../../plugins/data_source_management/public';
import { WorkspaceUseCase } from '../../types';

export interface WorkspaceCreatorProps {
workspaceConfigurableApps$?: BehaviorSubject<PublicAppInfo[]>;
registeredUseCases$: BehaviorSubject<WorkspaceUseCase[]>;
}

export const WorkspaceCreator = (props: WorkspaceCreatorProps) => {
Expand All @@ -37,10 +37,8 @@ export const WorkspaceCreator = (props: WorkspaceCreatorProps) => {
workspaceClient: WorkspaceClient;
dataSourceManagement?: DataSourceManagementPluginSetup;
}>();
const workspaceConfigurableApps = useObservable(
props.workspaceConfigurableApps$ ?? of(undefined)
);
const isPermissionEnabled = application?.capabilities.workspaces.permissionEnabled;
const availableUseCases = useObservable(props.registeredUseCases$, []);

const handleWorkspaceFormSubmit = useCallback(
async (data: WorkspaceFormSubmitData) => {
Expand Down Expand Up @@ -96,7 +94,6 @@ export const WorkspaceCreator = (props: WorkspaceCreatorProps) => {
<EuiPageHeader pageTitle="Create a workspace" />
<EuiPageContent
verticalPosition="center"
horizontalPosition="center"
paddingSize="none"
color="subdued"
hasShadow={false}
Expand All @@ -107,10 +104,9 @@ export const WorkspaceCreator = (props: WorkspaceCreatorProps) => {
savedObjects={savedObjects}
onSubmit={handleWorkspaceFormSubmit}
operationType={WorkspaceOperationType.Create}
workspaceConfigurableApps={workspaceConfigurableApps}
permissionEnabled={isPermissionEnabled}
permissionLastAdminItemDeletable
dataSourceManagement={dataSourceManagement}
availableUseCases={availableUseCases}
/>
)}
</EuiPageContent>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@

import { act, fireEvent, render, screen, waitFor } from '@testing-library/react';
import React from 'react';
import { coreMock } from '../../../../../core/public/mocks';
import { createOpenSearchDashboardsReactContext } from '../../../../opensearch_dashboards_react/public';
import { BehaviorSubject } from 'rxjs';
import { PublicAppInfo, WorkspaceObject } from 'opensearch-dashboards/public';
import { coreMock } from '../../../../../core/public/mocks';
import { createOpenSearchDashboardsReactContext } from '../../../../opensearch_dashboards_react/public';
import { WORKSPACE_USE_CASES } from '../../../common/constants';
import { WorkspaceDetail } from './workspace_detail';

// all applications
Expand Down Expand Up @@ -71,9 +72,16 @@ const WorkspaceDetailPage = (props: any) => {
},
});

const registeredUseCases$ = new BehaviorSubject([
WORKSPACE_USE_CASES.observability,
WORKSPACE_USE_CASES['security-analytics'],
WORKSPACE_USE_CASES.analytics,
WORKSPACE_USE_CASES.search,
]);

return (
<Provider>
<WorkspaceDetail {...props} />
<WorkspaceDetail registeredUseCases$={registeredUseCases$} {...props} />
</Provider>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,16 @@ import {

import { useObservable } from 'react-use';
import { i18n } from '@osd/i18n';
import { CoreStart, PublicAppInfo } from 'opensearch-dashboards/public';
import { CoreStart } from 'opensearch-dashboards/public';
import { BehaviorSubject } from 'rxjs';
import { useOpenSearchDashboards } from '../../../../opensearch_dashboards_react/public';
import { WorkspaceUseCase } from '../../types';
import { WorkspaceDetailContent } from './workspace_detail_content';
import { WorkspaceUpdater } from './workspace_updater';
import { DetailTab } from '../workspace_form/constants';

export interface WorkspaceDetailProps {
workspaceConfigurableApps$?: BehaviorSubject<PublicAppInfo[]>;
registeredUseCases$: BehaviorSubject<WorkspaceUseCase[]>;
}

export const WorkspaceDetail = (props: WorkspaceDetailProps) => {
Expand Down Expand Up @@ -60,8 +61,8 @@ export const WorkspaceDetail = (props: WorkspaceDetailProps) => {
}),
content: (
<WorkspaceUpdater
workspaceConfigurableApps$={props.workspaceConfigurableApps$}
detailTab={DetailTab.Settings}
registeredUseCases$={props.registeredUseCases$}
/>
),
},
Expand All @@ -74,8 +75,8 @@ export const WorkspaceDetail = (props: WorkspaceDetailProps) => {
}),
content: (
<WorkspaceUpdater
workspaceConfigurableApps$={props.workspaceConfigurableApps$}
detailTab={DetailTab.Collaborators}
registeredUseCases$={props.registeredUseCases$}
/>
),
},
Expand Down
Loading

0 comments on commit fceba91

Please sign in to comment.