Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Workspace] use registered nav groups in workspace form #7221

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
410cb8f
Add registered use cases
wanglam Jul 9, 2024
594d4ad
Separate use case service and fix UTs
wanglam Jul 10, 2024
f0fac52
Add test case for workspace plugin
wanglam Jul 11, 2024
fa43321
Fix workspace unit tests
wanglam Jul 11, 2024
b2b501a
Changeset file for PR #7221 created/updated
opensearch-changeset-bot[bot] Jul 11, 2024
920fce7
Remove workspaceConfigurableApp$ in component
wanglam Jul 11, 2024
95bd537
Remove no need workspaceConfigurableApps$ and add navGroupUpdater ut
wanglam Jul 11, 2024
8a47971
Merge remote-tracking branch 'origin/main' into workspace-use-registe…
wanglam Jul 12, 2024
110b71a
Merge branch 'main' into workspace-use-registered-nav-groups
wanglam Jul 15, 2024
e3a3234
Fix type error
wanglam Jul 15, 2024
6d45179
Remove centered horizontal position
wanglam Jul 15, 2024
1737c87
Merge branch 'main' into workspace-use-registered-nav-groups
wanglam Jul 16, 2024
dcf1d84
Merge branch 'main' into workspace-use-registered-nav-groups
wanglam Jul 16, 2024
673e877
Merge remote-tracking branch 'origin/main' into workspace-use-registe…
wanglam Jul 16, 2024
eb8394f
Fix isDashboardAdmin in workspace creator unit tests
wanglam Jul 16, 2024
c76c339
Merge branch 'main' into workspace-use-registered-nav-groups
wanglam Jul 17, 2024
ef67f1f
Fix dynamic nav groups missing in workspace list
wanglam Jul 17, 2024
199f21e
Merge branch 'main' into workspace-use-registered-nav-groups
wanglam Jul 17, 2024
6aafb87
Merge remote-tracking branch 'origin/main' into workspace-use-registe…
wanglam Jul 18, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading