diff --git a/src/plugins/workspace/public/application.tsx b/src/plugins/workspace/public/application.tsx index 31965012d16c..ab7924e82d34 100644 --- a/src/plugins/workspace/public/application.tsx +++ b/src/plugins/workspace/public/application.tsx @@ -5,7 +5,7 @@ import React from 'react'; import ReactDOM from 'react-dom'; -import { HashRouter as Router, Route, Switch, Redirect } from 'react-router-dom'; +import { HashRouter as Router, Route, Switch } from 'react-router-dom'; import { AppMountParameters, ScopedHistory } from '../../../core/public'; import { OpenSearchDashboardsContextProvider } from '../../opensearch_dashboards_react/public'; import { WorkspaceFatalError } from './components/workspace_fatal_error'; @@ -15,7 +15,6 @@ import { Services } from './types'; import { WorkspaceCreatorProps } from './components/workspace_creator/workspace_creator'; import { WorkspaceDetailApp } from './components/workspace_detail_app'; import { WorkspaceDetailProps } from './components/workspace_detail/workspace_detail'; -import { DetailTab } from './components/workspace_form/constants'; export const renderCreatorApp = ( { element }: AppMountParameters, diff --git a/src/plugins/workspace/public/components/workspace_form/constants.ts b/src/plugins/workspace/public/components/forms/constants.ts similarity index 100% rename from src/plugins/workspace/public/components/workspace_form/constants.ts rename to src/plugins/workspace/public/components/forms/constants.ts diff --git a/src/plugins/workspace/public/components/forms/fields/index.ts b/src/plugins/workspace/public/components/forms/fields/index.ts new file mode 100644 index 000000000000..5025fddeed45 --- /dev/null +++ b/src/plugins/workspace/public/components/forms/fields/index.ts @@ -0,0 +1,8 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export { WorkspaceColorField } from './workspace_color_field'; +export { WorkspaceNameField } from './workspace_name_field'; +export { WorkspaceDescriptionField } from './workspace_description_field'; diff --git a/src/plugins/workspace/public/components/forms/fields/workspace_color_field.tsx b/src/plugins/workspace/public/components/forms/fields/workspace_color_field.tsx new file mode 100644 index 000000000000..c35a2ca3ff8d --- /dev/null +++ b/src/plugins/workspace/public/components/forms/fields/workspace_color_field.tsx @@ -0,0 +1,45 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; +import { + EuiColorPicker, + EuiColorPickerProps, + EuiCompressedFormRow, + EuiSpacer, + EuiText, +} from '@elastic/eui'; +import { i18n } from '@osd/i18n'; + +interface WorkspaceColorFieldProps extends Pick { + value?: string; + error?: string; +} + +export const WorkspaceColorField = ({ value, error, onChange }: WorkspaceColorFieldProps) => { + return ( + + <> + + {i18n.translate('workspace.form.workspaceDetails.color.description', { + defaultMessage: 'Select a background color for the icon representing this workspace.', + })} + + + + + + ); +}; diff --git a/src/plugins/workspace/public/components/workspace_form/fields/workspace_description_field.test.tsx b/src/plugins/workspace/public/components/forms/fields/workspace_description_field.test.tsx similarity index 100% rename from src/plugins/workspace/public/components/workspace_form/fields/workspace_description_field.test.tsx rename to src/plugins/workspace/public/components/forms/fields/workspace_description_field.test.tsx diff --git a/src/plugins/workspace/public/components/workspace_form/fields/workspace_description_field.tsx b/src/plugins/workspace/public/components/forms/fields/workspace_description_field.tsx similarity index 100% rename from src/plugins/workspace/public/components/workspace_form/fields/workspace_description_field.tsx rename to src/plugins/workspace/public/components/forms/fields/workspace_description_field.tsx diff --git a/src/plugins/workspace/public/components/workspace_form/fields/workspace_name_field.test.tsx b/src/plugins/workspace/public/components/forms/fields/workspace_name_field.test.tsx similarity index 100% rename from src/plugins/workspace/public/components/workspace_form/fields/workspace_name_field.test.tsx rename to src/plugins/workspace/public/components/forms/fields/workspace_name_field.test.tsx diff --git a/src/plugins/workspace/public/components/workspace_form/fields/workspace_name_field.tsx b/src/plugins/workspace/public/components/forms/fields/workspace_name_field.tsx similarity index 100% rename from src/plugins/workspace/public/components/workspace_form/fields/workspace_name_field.tsx rename to src/plugins/workspace/public/components/forms/fields/workspace_name_field.tsx diff --git a/src/plugins/workspace/public/components/forms/index.ts b/src/plugins/workspace/public/components/forms/index.ts new file mode 100644 index 000000000000..c36236d7e38d --- /dev/null +++ b/src/plugins/workspace/public/components/forms/index.ts @@ -0,0 +1,27 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export { WorkspaceDetailForm } from './workspace_detail_form'; +export { SelectDataSourcePanel } from './select_data_source_panel'; +export { WorkspaceFormErrorCallout } from './workspace_form_error_callout'; +export { WorkspaceUseCase } from './workspace_use_case'; +export { WorkspacePermissionSettingPanel } from './workspace_permission_setting_panel'; +export { WorkspaceCancelModal } from './workspace_cancel_modal'; +export { WorkspaceNameField, WorkspaceDescriptionField, WorkspaceColorField } from './fields'; + +export { WorkspaceFormSubmitData, WorkspaceBaseFormProps, WorkspaceFormDataState } from './types'; +export { + WorkspaceOperationType, + DetailTab, + DetailTabTitles, + WorkspacePermissionItemType, +} from './constants'; +export { + convertPermissionsToPermissionSettings, + convertPermissionSettingsToPermissions, +} from './utils'; + +export { WorkspaceFormProvider, useWorkspaceFormContext } from './workspace_form_context'; +export { useWorkspaceForm } from './use_workspace_form'; diff --git a/src/plugins/workspace/public/components/workspace_form/select_data_source_panel.test.tsx b/src/plugins/workspace/public/components/forms/select_data_source_panel.test.tsx similarity index 100% rename from src/plugins/workspace/public/components/workspace_form/select_data_source_panel.test.tsx rename to src/plugins/workspace/public/components/forms/select_data_source_panel.test.tsx diff --git a/src/plugins/workspace/public/components/workspace_form/select_data_source_panel.tsx b/src/plugins/workspace/public/components/forms/select_data_source_panel.tsx similarity index 100% rename from src/plugins/workspace/public/components/workspace_form/select_data_source_panel.tsx rename to src/plugins/workspace/public/components/forms/select_data_source_panel.tsx diff --git a/src/plugins/workspace/public/components/workspace_form/types.ts b/src/plugins/workspace/public/components/forms/types.ts similarity index 80% rename from src/plugins/workspace/public/components/workspace_form/types.ts rename to src/plugins/workspace/public/components/forms/types.ts index 6f0c6a2d2f70..899cffb896b8 100644 --- a/src/plugins/workspace/public/components/workspace_form/types.ts +++ b/src/plugins/workspace/public/components/forms/types.ts @@ -31,17 +31,12 @@ export type WorkspacePermissionSetting = export interface WorkspaceFormSubmitData { name: string; description?: string; - features?: string[]; + features: string[]; color?: string; permissionSettings?: WorkspacePermissionSetting[]; selectedDataSources?: DataSource[]; } -export interface WorkspaceFormData extends WorkspaceFormSubmitData { - id: string; - reserved?: boolean; -} - export enum WorkspaceFormErrorCode { InvalidWorkspaceName, WorkspaceNameMissing, @@ -65,7 +60,7 @@ export interface WorkspaceFormError { export type WorkspaceFormErrors = { [key in keyof Omit< - WorkspaceFormData, + WorkspaceFormSubmitData, 'permissionSettings' | 'description' | 'selectedDataSources' >]?: WorkspaceFormError; } & { @@ -76,19 +71,29 @@ export type WorkspaceFormErrors = { selectedDataSources?: { [key: number]: WorkspaceFormError }; }; -export interface WorkspaceFormProps { +export interface WorkspaceBaseFormProps { application: ApplicationStart; savedObjects: SavedObjectsStart; onSubmit?: (formData: WorkspaceFormSubmitData) => void; - defaultValues?: Partial; - operationType: WorkspaceOperationType; + defaultValues?: Partial; permissionEnabled?: boolean; - detailTab?: DetailTab; dataSourceManagement?: DataSourceManagementPluginSetup; availableUseCases: WorkspaceUseCase[]; +} + +export interface WorkspaceDetailedFormProps extends WorkspaceBaseFormProps { + operationType: WorkspaceOperationType; + detailTab?: DetailTab; detailTitle?: string; + defaultValues?: WorkspaceFormSubmitData; } -export interface WorkspaceDetailedFormProps extends WorkspaceFormProps { - defaultValues?: WorkspaceFormData; +export interface WorkspaceFormDataState + extends Omit { + name: string; + useCase: string | undefined; + selectedDataSources: DataSource[]; + permissionSettings: Array< + Pick & Partial + >; } diff --git a/src/plugins/workspace/public/components/workspace_form/use_workspace_form.test.ts b/src/plugins/workspace/public/components/forms/use_workspace_form.test.ts similarity index 95% rename from src/plugins/workspace/public/components/workspace_form/use_workspace_form.test.ts rename to src/plugins/workspace/public/components/forms/use_workspace_form.test.ts index c946cb35a68c..3c3bbc59cf95 100644 --- a/src/plugins/workspace/public/components/workspace_form/use_workspace_form.test.ts +++ b/src/plugins/workspace/public/components/forms/use_workspace_form.test.ts @@ -8,10 +8,10 @@ import { renderHook, act } from '@testing-library/react-hooks'; import { applicationServiceMock } from '../../../../../core/public/mocks'; import { WorkspacePermissionMode } from '../../../common/constants'; import { WorkspaceOperationType, WorkspacePermissionItemType } from './constants'; -import { WorkspaceFormData, WorkspaceFormErrorCode } from './types'; +import { WorkspaceFormErrorCode, WorkspaceFormSubmitData } from './types'; import { useWorkspaceForm } from './use_workspace_form'; -const setup = (defaultValues?: WorkspaceFormData, permissionEnabled = false) => { +const setup = (defaultValues?: Partial, permissionEnabled = false) => { const onSubmitMock = jest.fn(); const renderResult = renderHook(useWorkspaceForm, { initialProps: { @@ -31,7 +31,6 @@ const setup = (defaultValues?: WorkspaceFormData, permissionEnabled = false) => describe('useWorkspaceForm', () => { it('should return invalid workspace name error and not call onSubmit when invalid name', async () => { const { renderResult, onSubmitMock } = setup({ - id: 'foo', name: '~', }); expect(renderResult.result.current.formErrors).toEqual({}); @@ -51,7 +50,6 @@ describe('useWorkspaceForm', () => { }); it('should return "Use case is required. Select a use case." and not call onSubmit', async () => { const { renderResult, onSubmitMock } = setup({ - id: 'foo', name: 'test-workspace-name', }); expect(renderResult.result.current.formErrors).toEqual({}); @@ -72,7 +70,6 @@ describe('useWorkspaceForm', () => { it('should return "Add workspace owner." and not call onSubmit', async () => { const { renderResult, onSubmitMock } = setup( { - id: 'foo', name: 'test-workspace-name', }, true @@ -111,7 +108,6 @@ describe('useWorkspaceForm', () => { }); it('should call onSubmit with workspace name and features', async () => { const { renderResult, onSubmitMock } = setup({ - id: 'foo', name: 'test-workspace-name', features: ['use-case-observability'], }); @@ -129,7 +125,6 @@ describe('useWorkspaceForm', () => { }); it('should update selected use case', () => { const { renderResult } = setup({ - id: 'foo', name: 'test-workspace-name', features: ['use-case-observability'], }); @@ -143,7 +138,6 @@ describe('useWorkspaceForm', () => { it('should reset workspace form', () => { const { renderResult } = setup({ - id: 'test', name: 'current-workspace-name', features: ['use-case-observability'], }); diff --git a/src/plugins/workspace/public/components/workspace_form/use_workspace_form.ts b/src/plugins/workspace/public/components/forms/use_workspace_form.ts similarity index 89% rename from src/plugins/workspace/public/components/workspace_form/use_workspace_form.ts rename to src/plugins/workspace/public/components/forms/use_workspace_form.ts index 422161bea948..a5fa28d48617 100644 --- a/src/plugins/workspace/public/components/workspace_form/use_workspace_form.ts +++ b/src/plugins/workspace/public/components/forms/use_workspace_form.ts @@ -12,8 +12,12 @@ import { getUseCaseFeatureConfig, isUseCaseFeatureConfig, } from '../../utils'; -import { DataSource } from '../../../common/types'; -import { WorkspaceFormProps, WorkspaceFormErrors, WorkspacePermissionSetting } from './types'; +import { + WorkspaceFormErrors, + WorkspacePermissionSetting, + WorkspaceBaseFormProps, + WorkspaceFormDataState, +} from './types'; import { appendDefaultFeatureIds, generatePermissionSettingsState, @@ -21,17 +25,25 @@ import { getNumberOfErrors, validateWorkspaceForm, } from './utils'; -import { WorkspacePermissionItemType } from './constants'; +import { WorkspaceOperationType, WorkspacePermissionItemType } from './constants'; const workspaceHtmlIdGenerator = htmlIdGenerator(); +export interface UseWorkspaceFormOptions + extends Pick< + WorkspaceBaseFormProps, + 'application' | 'defaultValues' | 'onSubmit' | 'permissionEnabled' + > { + operationType: WorkspaceOperationType; +} + export const useWorkspaceForm = ({ application, defaultValues, operationType, onSubmit, permissionEnabled, -}: WorkspaceFormProps) => { +}: UseWorkspaceFormOptions) => { const applications = useApplications(application); const [name, setName] = useState(defaultValues?.name ?? ''); const [description, setDescription] = useState(defaultValues?.description); @@ -49,10 +61,12 @@ export const useWorkspaceForm = ({ featureConfigs, ]); const [permissionSettings, setPermissionSettings] = useState< - Array & Partial> + WorkspaceFormDataState['permissionSettings'] >(initialPermissionSettingsRef.current); - const [selectedDataSources, setSelectedDataSources] = useState( + const [selectedDataSources, setSelectedDataSources] = useState< + WorkspaceFormDataState['selectedDataSources'] + >( defaultValues?.selectedDataSources && defaultValues.selectedDataSources.length > 0 ? defaultValues.selectedDataSources : [] @@ -61,7 +75,7 @@ export const useWorkspaceForm = ({ const [formErrors, setFormErrors] = useState({}); const numberOfErrors = useMemo(() => getNumberOfErrors(formErrors), [formErrors]); const formIdRef = useRef(); - const getFormData = () => ({ + const getFormData = (): WorkspaceFormDataState => ({ name, description, features: featureConfigs, diff --git a/src/plugins/workspace/public/components/workspace_form/utils.test.ts b/src/plugins/workspace/public/components/forms/utils.test.ts similarity index 100% rename from src/plugins/workspace/public/components/workspace_form/utils.test.ts rename to src/plugins/workspace/public/components/forms/utils.test.ts diff --git a/src/plugins/workspace/public/components/workspace_form/utils.ts b/src/plugins/workspace/public/components/forms/utils.ts similarity index 97% rename from src/plugins/workspace/public/components/workspace_form/utils.ts rename to src/plugins/workspace/public/components/forms/utils.ts index a1a340a78db6..ccc15b7b18f5 100644 --- a/src/plugins/workspace/public/components/workspace_form/utils.ts +++ b/src/plugins/workspace/public/components/forms/utils.ts @@ -20,7 +20,7 @@ import { } from './constants'; import { - WorkspaceFormData, + WorkspaceFormDataState, WorkspaceFormError, WorkspaceFormErrorCode, WorkspaceFormErrors, @@ -304,11 +304,7 @@ export const isSelectedDataSourcesDuplicated = ( ) => selectedDataSources.some((ds) => ds.id === row.id); export const validateWorkspaceForm = ( - formData: Omit, 'permissionSettings'> & { - permissionSettings?: Array< - Pick & Partial - >; - }, + formData: Partial, isPermissionEnabled: boolean ) => { const formErrors: WorkspaceFormErrors = {}; @@ -461,12 +457,8 @@ const isSamePermissionSetting = (a: PermissionSettingLike, b: PermissionSettingL }; export const getNumberOfChanges = ( - newFormData: Partial> & { - permissionSettings?: Array< - Pick & Partial - >; - }, - initialFormData: Partial> + newFormData: Partial, + initialFormData: Partial ) => { let count = 0; if (newFormData.name !== initialFormData.name) { diff --git a/src/plugins/workspace/public/components/workspace_form/workspace_cancel_modal.tsx b/src/plugins/workspace/public/components/forms/workspace_cancel_modal.tsx similarity index 100% rename from src/plugins/workspace/public/components/workspace_form/workspace_cancel_modal.tsx rename to src/plugins/workspace/public/components/forms/workspace_cancel_modal.tsx diff --git a/src/plugins/workspace/public/components/workspace_form/workspace_detail_form.scss b/src/plugins/workspace/public/components/forms/workspace_detail_form.scss similarity index 100% rename from src/plugins/workspace/public/components/workspace_form/workspace_detail_form.scss rename to src/plugins/workspace/public/components/forms/workspace_detail_form.scss diff --git a/src/plugins/workspace/public/components/workspace_form/workspace_detail_form.tsx b/src/plugins/workspace/public/components/forms/workspace_detail_form.tsx similarity index 97% rename from src/plugins/workspace/public/components/workspace_form/workspace_detail_form.tsx rename to src/plugins/workspace/public/components/forms/workspace_detail_form.tsx index a8015120d407..2490f6fec3ea 100644 --- a/src/plugins/workspace/public/components/workspace_form/workspace_detail_form.tsx +++ b/src/plugins/workspace/public/components/forms/workspace_detail_form.tsx @@ -18,7 +18,7 @@ import { } from '@elastic/eui'; import { i18n } from '@osd/i18n'; -import { WorkspaceFormProps } from './types'; +import { WorkspaceDetailedFormProps } from './types'; import { WorkspacePermissionSettingPanel } from './workspace_permission_setting_panel'; import { DetailTab, usersAndPermissionsTitle } from './constants'; import { WorkspaceFormErrorCallout } from './workspace_form_error_callout'; @@ -51,7 +51,7 @@ const FormGroup = ({ title, children, describe }: FormGroupProps) => ( ); -export const WorkspaceDetailForm = (props: WorkspaceFormProps) => { +export const WorkspaceDetailForm = (props: WorkspaceDetailedFormProps) => { const { detailTab, detailTitle, defaultValues, availableUseCases } = props; const { formId, diff --git a/src/plugins/workspace/public/components/workspace_form/workspace_detail_form_details.tsx b/src/plugins/workspace/public/components/forms/workspace_detail_form_details.tsx similarity index 98% rename from src/plugins/workspace/public/components/workspace_form/workspace_detail_form_details.tsx rename to src/plugins/workspace/public/components/forms/workspace_detail_form_details.tsx index 27de826141b2..5b88fd1fedf8 100644 --- a/src/plugins/workspace/public/components/workspace_form/workspace_detail_form_details.tsx +++ b/src/plugins/workspace/public/components/forms/workspace_detail_form_details.tsx @@ -8,7 +8,6 @@ import { EuiColorPicker, EuiCompressedFormRow, EuiDescribedFormGroup, - EuiCompressedTextArea, } from '@elastic/eui'; import React, { useEffect, useState } from 'react'; import { useObservable } from 'react-use'; @@ -17,7 +16,6 @@ import { detailsColorLabel, detailsUseCaseLabel, detailsColorHelpText, - detailsDescriptionPlaceholder, detailsDescriptionIntroduction, detailsUseCaseHelpText, } from './constants'; diff --git a/src/plugins/workspace/public/components/workspace_form/workspace_form_context.tsx b/src/plugins/workspace/public/components/forms/workspace_form_context.tsx similarity index 81% rename from src/plugins/workspace/public/components/workspace_form/workspace_form_context.tsx rename to src/plugins/workspace/public/components/forms/workspace_form_context.tsx index 417921f170d3..e963676e57f7 100644 --- a/src/plugins/workspace/public/components/workspace_form/workspace_form_context.tsx +++ b/src/plugins/workspace/public/components/forms/workspace_form_context.tsx @@ -3,12 +3,12 @@ * SPDX-License-Identifier: Apache-2.0 */ -import React, { createContext, useContext, FormEventHandler, ReactNode } from 'react'; +import React, { createContext, useContext, FormEventHandler } from 'react'; import { EuiColorPickerOutput } from '@elastic/eui/src/components/color_picker/color_picker'; import { DataSource } from '../../../common/types'; -import { WorkspaceFormProps, WorkspaceFormErrors, WorkspacePermissionSetting } from './types'; +import { WorkspaceFormErrors, WorkspacePermissionSetting } from './types'; import { PublicAppInfo } from '../../../../../core/public'; -import { useWorkspaceForm } from './use_workspace_form'; +import { useWorkspaceForm, UseWorkspaceFormOptions } from './use_workspace_form'; interface WorkspaceFormContextProps { formId: string; @@ -35,9 +35,6 @@ interface WorkspaceFormContextProps { const initialContextValue: WorkspaceFormContextProps = {} as WorkspaceFormContextProps; export const WorkspaceFormContext = createContext(initialContextValue); -interface ContextProps extends WorkspaceFormProps { - children: ReactNode; -} export const WorkspaceFormProvider = ({ children, @@ -46,17 +43,13 @@ export const WorkspaceFormProvider = ({ operationType, onSubmit, permissionEnabled, - savedObjects, - availableUseCases, -}: ContextProps) => { +}: React.PropsWithChildren) => { const workspaceFormContextValue = useWorkspaceForm({ application, defaultValues, operationType, onSubmit, permissionEnabled, - savedObjects, - availableUseCases, }); return ( diff --git a/src/plugins/workspace/public/components/workspace_form/workspace_form_error_callout.test.tsx b/src/plugins/workspace/public/components/forms/workspace_form_error_callout.test.tsx similarity index 100% rename from src/plugins/workspace/public/components/workspace_form/workspace_form_error_callout.test.tsx rename to src/plugins/workspace/public/components/forms/workspace_form_error_callout.test.tsx diff --git a/src/plugins/workspace/public/components/workspace_form/workspace_form_error_callout.tsx b/src/plugins/workspace/public/components/forms/workspace_form_error_callout.tsx similarity index 100% rename from src/plugins/workspace/public/components/workspace_form/workspace_form_error_callout.tsx rename to src/plugins/workspace/public/components/forms/workspace_form_error_callout.tsx diff --git a/src/plugins/workspace/public/components/workspace_form/workspace_permission_setting_input.test.tsx b/src/plugins/workspace/public/components/forms/workspace_permission_setting_input.test.tsx similarity index 100% rename from src/plugins/workspace/public/components/workspace_form/workspace_permission_setting_input.test.tsx rename to src/plugins/workspace/public/components/forms/workspace_permission_setting_input.test.tsx diff --git a/src/plugins/workspace/public/components/workspace_form/workspace_permission_setting_input.tsx b/src/plugins/workspace/public/components/forms/workspace_permission_setting_input.tsx similarity index 100% rename from src/plugins/workspace/public/components/workspace_form/workspace_permission_setting_input.tsx rename to src/plugins/workspace/public/components/forms/workspace_permission_setting_input.tsx diff --git a/src/plugins/workspace/public/components/workspace_form/workspace_permission_setting_panel.test.tsx b/src/plugins/workspace/public/components/forms/workspace_permission_setting_panel.test.tsx similarity index 100% rename from src/plugins/workspace/public/components/workspace_form/workspace_permission_setting_panel.test.tsx rename to src/plugins/workspace/public/components/forms/workspace_permission_setting_panel.test.tsx diff --git a/src/plugins/workspace/public/components/workspace_form/workspace_permission_setting_panel.tsx b/src/plugins/workspace/public/components/forms/workspace_permission_setting_panel.tsx similarity index 100% rename from src/plugins/workspace/public/components/workspace_form/workspace_permission_setting_panel.tsx rename to src/plugins/workspace/public/components/forms/workspace_permission_setting_panel.tsx diff --git a/src/plugins/workspace/public/components/workspace_form/workspace_use_case.scss b/src/plugins/workspace/public/components/forms/workspace_use_case.scss similarity index 100% rename from src/plugins/workspace/public/components/workspace_form/workspace_use_case.scss rename to src/plugins/workspace/public/components/forms/workspace_use_case.scss diff --git a/src/plugins/workspace/public/components/workspace_form/workspace_use_case.test.tsx b/src/plugins/workspace/public/components/forms/workspace_use_case.test.tsx similarity index 100% rename from src/plugins/workspace/public/components/workspace_form/workspace_use_case.test.tsx rename to src/plugins/workspace/public/components/forms/workspace_use_case.test.tsx diff --git a/src/plugins/workspace/public/components/workspace_form/workspace_use_case.tsx b/src/plugins/workspace/public/components/forms/workspace_use_case.tsx similarity index 98% rename from src/plugins/workspace/public/components/workspace_form/workspace_use_case.tsx rename to src/plugins/workspace/public/components/forms/workspace_use_case.tsx index 1a222238fc0c..1fb5c2984c46 100644 --- a/src/plugins/workspace/public/components/workspace_form/workspace_use_case.tsx +++ b/src/plugins/workspace/public/components/forms/workspace_use_case.tsx @@ -108,7 +108,7 @@ export const WorkspaceUseCase = ({ error={formErrors.features?.message} fullWidth > - + {displayedUseCases.map(({ id, title, description }) => ( ; diff --git a/src/plugins/workspace/public/components/workspace_creator/__snapshots__/workspace_faq_panel.test.tsx.snap b/src/plugins/workspace/public/components/workspace_creator/__snapshots__/workspace_faq_panel.test.tsx.snap new file mode 100644 index 000000000000..9fe60a2ab6e1 --- /dev/null +++ b/src/plugins/workspace/public/components/workspace_creator/__snapshots__/workspace_faq_panel.test.tsx.snap @@ -0,0 +1,66 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`WorkspaceFaqPanel renders correctly 1`] = ` +
+
+
+

+ FAQs +

+
+
+

+ Can I change the workspace use case later? +

+

+ You can only change to the All use case after workspace creation. +

+
+
+
+
+

+ Why can’t I find the data sources I want to attached to the workspace? +

+

+ Available data sources to all workspaces here are configured by OpenSearch admin. Contact OpenSearch admin within your organization to add the requested data source. +

+
+
+
+
+

+ Do the added team members automatically gain access to the attached data sources? +

+

+ No. Adding team members will only grant them access to the created workspace. To grant access to the attached data sources, contact the data source admin within your organization. +

+
+
+
+
+
+`; diff --git a/src/plugins/workspace/public/components/workspace_creator/utils.ts b/src/plugins/workspace/public/components/workspace_creator/utils.ts new file mode 100644 index 000000000000..9be647c1a30b --- /dev/null +++ b/src/plugins/workspace/public/components/workspace_creator/utils.ts @@ -0,0 +1,19 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export const RIGHT_SIDEBAR_SCROLL_KEY = 'data-right-sidebar-scroll'; + +export enum RightSidebarScrollField { + Name = 'name', + Description = 'description', + Color = 'color', + UseCase = 'useCase', + DataSource = 'dataSource', + Member = 'member', +} + +export const generateRightSidebarScrollProps = (key: RightSidebarScrollField) => { + return { [RIGHT_SIDEBAR_SCROLL_KEY]: key }; +}; diff --git a/src/plugins/workspace/public/components/workspace_form/workspace_create_action_panel.test.tsx b/src/plugins/workspace/public/components/workspace_creator/workspace_create_action_panel.test.tsx similarity index 100% rename from src/plugins/workspace/public/components/workspace_form/workspace_create_action_panel.test.tsx rename to src/plugins/workspace/public/components/workspace_creator/workspace_create_action_panel.test.tsx diff --git a/src/plugins/workspace/public/components/workspace_form/workspace_create_action_panel.tsx b/src/plugins/workspace/public/components/workspace_creator/workspace_create_action_panel.tsx similarity index 77% rename from src/plugins/workspace/public/components/workspace_form/workspace_create_action_panel.tsx rename to src/plugins/workspace/public/components/workspace_creator/workspace_create_action_panel.tsx index 0b914c0a7658..636f70b73f69 100644 --- a/src/plugins/workspace/public/components/workspace_form/workspace_create_action_panel.tsx +++ b/src/plugins/workspace/public/components/workspace_creator/workspace_create_action_panel.tsx @@ -3,12 +3,11 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { EuiSmallButton, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import { EuiSmallButton, EuiFlexGroup, EuiFlexItem, EuiSmallButtonEmpty } from '@elastic/eui'; import { i18n } from '@osd/i18n'; import React, { useState, useCallback } from 'react'; import type { ApplicationStart } from 'opensearch-dashboards/public'; -import type { WorkspaceFormData } from './types'; -import { WorkspaceCancelModal } from './workspace_cancel_modal'; +import { WorkspaceFormDataState, WorkspaceCancelModal } from '../forms'; import { MAX_WORKSPACE_DESCRIPTION_LENGTH, MAX_WORKSPACE_NAME_LENGTH, @@ -16,7 +15,7 @@ import { interface WorkspaceCreateActionPanelProps { formId: string; - formData: Partial>; + formData: WorkspaceFormDataState; application: ApplicationStart; } @@ -34,26 +33,26 @@ export const WorkspaceCreateActionPanel = ({ return ( <> - + - - {i18n.translate('workspace.form.bottomBar.cancel', { + {i18n.translate('workspace.form.right.sidebar.buttons.cancelText', { defaultMessage: 'Cancel', })} - + - {i18n.translate('workspace.form.bottomBar.createWorkspace', { + {i18n.translate('workspace.form.right.sidebar.buttons.createWorkspaceText', { defaultMessage: 'Create workspace', })} diff --git a/src/plugins/workspace/public/components/workspace_creator/workspace_creator.tsx b/src/plugins/workspace/public/components/workspace_creator/workspace_creator.tsx index 26bed213d142..b21d720393c0 100644 --- a/src/plugins/workspace/public/components/workspace_creator/workspace_creator.tsx +++ b/src/plugins/workspace/public/components/workspace_creator/workspace_creator.tsx @@ -10,15 +10,14 @@ import { useObservable } from 'react-use'; import { BehaviorSubject } from 'rxjs'; import { useOpenSearchDashboards } from '../../../../opensearch_dashboards_react/public'; -import { WorkspaceForm, WorkspaceFormSubmitData, WorkspaceOperationType } from '../workspace_form'; +import { WorkspaceFormSubmitData, convertPermissionSettingsToPermissions } from '../forms'; import { WORKSPACE_DETAIL_APP_ID } from '../../../common/constants'; import { formatUrlWithWorkspaceId } from '../../../../../core/public/utils'; 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'; -import { WorkspaceFormData } from '../workspace_form/types'; +import { WorkspaceCreatorForm } from './workspace_creator_form'; import { NavigationPublicPluginStart } from '../../../../../plugins/navigation/public'; export interface WorkspaceCreatorProps { @@ -42,7 +41,7 @@ export const WorkspaceCreator = (props: WorkspaceCreatorProps) => { navigationUI: NavigationPublicPluginStart['ui']; }>(); - const defaultWorkspaceFormValues: Partial = { + const defaultWorkspaceFormValues = { color: euiPaletteColorBlind()[0], }; @@ -117,11 +116,10 @@ export const WorkspaceCreator = (props: WorkspaceCreatorProps) => { hasShadow={false} > {application && savedObjects && ( - @@ -49,21 +47,21 @@ const setup = ( const mockDataSourceManagementSetup = ({} as unknown) as DataSourceManagementPluginSetup; -describe('WorkspaceForm', () => { +describe('WorkspaceCreatorForm', () => { it('should enable data source panel for dashboard admin and when data source is enabled', () => { - const { getByText } = setup(true, mockDataSourceManagementSetup); + const { getByTestId } = setup(true, mockDataSourceManagementSetup); - expect(getByText('Associate data source')).toBeInTheDocument(); + expect(getByTestId('workspaceForm-select-dataSource-addNew')).toBeInTheDocument(); }); it('should not display data source panel for non dashboard admin', () => { - const { queryByText } = setup(false, mockDataSourceManagementSetup); + const { queryByTestId } = setup(false, mockDataSourceManagementSetup); - expect(queryByText('Associate data source')).not.toBeInTheDocument(); + expect(queryByTestId('workspaceForm-select-dataSource-addNew')).not.toBeInTheDocument(); }); it('should not display data source panel when data source is disabled', () => { - const { queryByText } = setup(true, undefined); + const { queryByTestId } = setup(true, undefined); - expect(queryByText('Associate data source')).not.toBeInTheDocument(); + expect(queryByTestId('workspaceForm-select-dataSource-addNew')).not.toBeInTheDocument(); }); }); diff --git a/src/plugins/workspace/public/components/workspace_creator/workspace_creator_form.tsx b/src/plugins/workspace/public/components/workspace_creator/workspace_creator_form.tsx new file mode 100644 index 000000000000..213348f05934 --- /dev/null +++ b/src/plugins/workspace/public/components/workspace_creator/workspace_creator_form.tsx @@ -0,0 +1,146 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React, { useRef } from 'react'; +import { EuiSpacer, EuiForm, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; + +import { + useWorkspaceForm, + WorkspaceOperationType, + WorkspaceBaseFormProps, + SelectDataSourcePanel, + WorkspaceFormErrorCallout, + WorkspaceUseCase, + WorkspaceNameField, + WorkspaceDescriptionField, + WorkspacePermissionSettingPanel, + WorkspaceColorField, +} from '../forms'; +import { WorkspaceFormSummaryPanel } from './workspace_form_summary_panel'; +import { WorkspaceFaqPanel } from './workspace_faq_panel'; +import './workspace_creator_form.scss'; +import { generateRightSidebarScrollProps, RightSidebarScrollField } from './utils'; +import { WorkspaceCreateActionPanel } from './workspace_create_action_panel'; + +export const WorkspaceCreatorForm = (props: WorkspaceBaseFormProps) => { + const { + application, + savedObjects, + defaultValues, + permissionEnabled, + dataSourceManagement: isDataSourceEnabled, + availableUseCases, + } = props; + const { + formId, + formData, + formErrors, + numberOfErrors, + setName, + setDescription, + handleFormSubmit, + handleColorChange, + handleUseCaseChange, + setPermissionSettings, + setSelectedDataSources, + } = useWorkspaceForm({ ...props, operationType: WorkspaceOperationType.Create }); + + const disabledUserOrGroupInputIdsRef = useRef( + defaultValues?.permissionSettings?.map((item) => item.id) ?? [] + ); + const isDashboardAdmin = application?.capabilities?.dashboards?.isDashboardAdmin ?? false; + + return ( + + + + {numberOfErrors > 0 && ( + <> + + + + )} + + +
+ + +
+ + +
+ + + {/* SelectDataSourcePanel is only visible for dashboard admin and when data source is enabled*/} + {isDashboardAdmin && isDataSourceEnabled && ( +
+ +
+ )} + + {permissionEnabled && ( +
+ +
+ )} + + + + + +
+
+ + + +
+ +
+ +
+
+
+ + ); +}; diff --git a/src/plugins/workspace/public/components/workspace_creator/workspace_faq_panel.test.tsx b/src/plugins/workspace/public/components/workspace_creator/workspace_faq_panel.test.tsx new file mode 100644 index 000000000000..e8d737b32242 --- /dev/null +++ b/src/plugins/workspace/public/components/workspace_creator/workspace_faq_panel.test.tsx @@ -0,0 +1,15 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; +import { render } from '@testing-library/react'; +import { WorkspaceFaqPanel } from './workspace_faq_panel'; + +describe('WorkspaceFaqPanel', () => { + it('renders correctly', () => { + const tree = render(); + expect(tree.container).toMatchSnapshot(); + }); +}); diff --git a/src/plugins/workspace/public/components/workspace_creator/workspace_faq_panel.tsx b/src/plugins/workspace/public/components/workspace_creator/workspace_faq_panel.tsx new file mode 100644 index 000000000000..218e9a7618cf --- /dev/null +++ b/src/plugins/workspace/public/components/workspace_creator/workspace_faq_panel.tsx @@ -0,0 +1,72 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; +import { EuiCard, EuiSpacer, EuiText } from '@elastic/eui'; +import { i18n } from '@osd/i18n'; + +const WorkspaceFaqItem = ({ question, answer }: { question: string; answer: string }) => { + return ( + +

{question}

+

{answer}

+
+ ); +}; + +const FAQs = [ + { + question: i18n.translate('workspace.form.faq.panel.question1', { + defaultMessage: 'Can I change the workspace use case later?', + }), + answer: i18n.translate('workspace.form.faq.panel.answer1', { + defaultMessage: 'You can only change to the All use case after workspace creation.', + }), + }, + { + question: i18n.translate('workspace.form.faq.panel.question2', { + defaultMessage: 'Why can’t I find the data sources I want to attached to the workspace? ', + }), + answer: i18n.translate('workspace.form.faq.panel.answer2', { + defaultMessage: + 'Available data sources to all workspaces here are configured by OpenSearch admin. Contact OpenSearch admin within your organization to add the requested data source. ', + }), + }, + { + question: i18n.translate('workspace.form.faq.panel.question3', { + defaultMessage: + 'Do the added team members automatically gain access to the attached data sources?', + }), + answer: i18n.translate('workspace.form.faq.panel.answer3', { + defaultMessage: + 'No. Adding team members will only grant them access to the created workspace. To grant access to the attached data sources, contact the data source admin within your organization.', + }), + }, +]; + +export const WorkspaceFaqPanel = () => { + return ( + + {FAQs.map(({ question, answer }, index) => ( + + + {index !== FAQs.length - 1 && ( + <> + + + + )} + + ))} + + ); +}; diff --git a/src/plugins/workspace/public/components/workspace_creator/workspace_form_summary_panel.test.tsx b/src/plugins/workspace/public/components/workspace_creator/workspace_form_summary_panel.test.tsx new file mode 100644 index 000000000000..d8bf7e83d38e --- /dev/null +++ b/src/plugins/workspace/public/components/workspace_creator/workspace_form_summary_panel.test.tsx @@ -0,0 +1,182 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; +import { render, screen, fireEvent } from '@testing-library/react'; +import { + WorkspaceFormSummaryPanel, + ExpandableTextList, + FieldSummaryItem, +} from './workspace_form_summary_panel'; +import { RightSidebarScrollField } from './utils'; +import { WorkspacePermissionItemType } from '../forms'; + +describe('WorkspaceFormSummaryPanel', () => { + const formData = { + features: [], + useCase: 'useCase1', + name: 'Test Workspace', + description: 'This is a test workspace', + color: '#000000', + selectedDataSources: [ + { id: 'data-source-1', title: 'Data Source 1' }, + { id: 'data-source-2', title: 'Data Source 2' }, + { id: 'data-source-3', title: 'Data Source 3' }, + ], + permissionSettings: [ + { id: 1, type: WorkspacePermissionItemType.User, userId: 'user1' }, + { id: 2, type: WorkspacePermissionItemType.Group, group: 'group1' }, + { id: 3, type: WorkspacePermissionItemType.User, userId: 'user2' }, + ], + }; + + const availableUseCases = [ + { + id: 'useCase1', + title: 'Use Case 1', + description: 'This is Use Case 1', + features: [], + }, + { + id: 'useCase2', + title: 'Use Case 2', + description: 'This is Use Case 2', + features: [], + }, + ]; + + it('renders summary panel with correct data', () => { + render( + + ); + + expect(screen.getByText('Summary')).toBeInTheDocument(); + expect(screen.getByText('Use Case 1')).toBeInTheDocument(); + expect(screen.getByText('This is Use Case 1')).toBeInTheDocument(); + expect(screen.getByText('Test Workspace')).toBeInTheDocument(); + expect(screen.getByText('This is a test workspace')).toBeInTheDocument(); + expect(screen.getByText('#000000')).toBeInTheDocument(); + expect(screen.getByText('Data Source 1')).toBeInTheDocument(); + expect(screen.getByText('user1')).toBeInTheDocument(); + expect(screen.getByText('group1')).toBeInTheDocument(); + expect(screen.queryByText('user2')).toBeNull(); + }); + + it('renders placeholders for empty form data', () => { + render( + + ); + + expect(screen.getByText('Summary')).toBeInTheDocument(); + + // Use case placeholder + const useCasePlaceholder = screen.getByTestId('workspaceFormRightSideBarSummary-useCase-Value'); + expect(useCasePlaceholder).toHaveTextContent('—'); + + // Name placeholder + const namePlaceholder = screen.getByTestId('workspaceFormRightSideBarSummary-name-Value'); + expect(namePlaceholder).toHaveTextContent('—'); + + // Description placeholder + const descriptionPlaceholder = screen.getByTestId( + 'workspaceFormRightSideBarSummary-description-Value' + ); + expect(descriptionPlaceholder).toHaveTextContent('—'); + + // Color placeholder + const colorPlaceholder = screen.getByTestId('workspaceFormRightSideBarSummary-color-Value'); + expect(colorPlaceholder).toHaveTextContent('—'); + + // Data sources placeholder + const dataSourcesPlaceholder = screen.getByTestId( + 'workspaceFormRightSideBarSummary-dataSource-Value' + ); + expect(dataSourcesPlaceholder).toHaveTextContent('—'); + + // Permissions placeholder + const permissionsPlaceholder = screen.getByTestId( + 'workspaceFormRightSideBarSummary-member-Value' + ); + expect(permissionsPlaceholder).toHaveTextContent('—'); + }); +}); + +describe('ExpandableTextList', () => { + it('renders all texts when expanded', () => { + const texts = ['Text 1', 'Text 2', 'Text 3', 'Text 4']; + render(); + + expect(screen.getByText('Text 1')).toBeInTheDocument(); + expect(screen.getByText('Text 2')).toBeInTheDocument(); + expect(screen.queryByText('Text 3')).not.toBeInTheDocument(); + expect(screen.queryByText('Text 4')).not.toBeInTheDocument(); + + fireEvent.click(screen.getByText('Show all')); + + expect(screen.getByText('Text 3')).toBeInTheDocument(); + expect(screen.getByText('Text 4')).toBeInTheDocument(); + }); + it('should not show "Show all" button when all texts can be displayed', () => { + const texts = ['Text 1', 'Text 2']; + render(); + + expect(screen.getByText('Text 1')).toBeInTheDocument(); + expect(screen.getByText('Text 2')).toBeInTheDocument(); + expect(screen.queryByText('Show all')).not.toBeInTheDocument(); + }); +}); + +describe('FieldSummaryItem', () => { + it('renders title and content correctly', () => { + render( + Content for Name + ); + + expect(screen.getByText('Name')).toBeInTheDocument(); + expect(screen.getByText('Content for Name')).toBeInTheDocument(); + }); + + it('renders placeholder when no content is provided', () => { + render(); + + expect(screen.getByText('Name')).toBeInTheDocument(); + expect(screen.getByText('—')).toBeInTheDocument(); + }); + + it('scrolls to the corresponding field when title is clicked', () => { + const originScrollIntoView = window.HTMLElement.prototype.scrollIntoView; + const scrollIntoViewMock = jest.fn(); + window.HTMLElement.prototype.scrollIntoView = scrollIntoViewMock; + + render( +
+
+ Content for Name +
+ ); + + fireEvent.click(screen.getByText('Name')); + + expect(scrollIntoViewMock).toHaveBeenCalledWith({ + behavior: 'smooth', + block: 'center', + }); + window.HTMLElement.prototype.scrollIntoView = originScrollIntoView; + }); +}); diff --git a/src/plugins/workspace/public/components/workspace_creator/workspace_form_summary_panel.tsx b/src/plugins/workspace/public/components/workspace_creator/workspace_form_summary_panel.tsx new file mode 100644 index 000000000000..661d49d41457 --- /dev/null +++ b/src/plugins/workspace/public/components/workspace_creator/workspace_form_summary_panel.tsx @@ -0,0 +1,201 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React, { useCallback, useState } from 'react'; +import { + EuiCard, + EuiFlexGroup, + EuiFlexItem, + EuiIcon, + EuiSpacer, + EuiText, + EuiTextColor, + EuiLink, +} from '@elastic/eui'; +import { i18n } from '@osd/i18n'; +import { WorkspaceFormDataState } from '../forms'; +import { WorkspaceUseCase } from '../../types'; +import { RightSidebarScrollField, RIGHT_SIDEBAR_SCROLL_KEY } from './utils'; + +export const FieldSummaryItem = ({ + field, + children, + bottomGap = true, +}: React.PropsWithChildren<{ + field: RightSidebarScrollField; + bottomGap?: boolean; +}>) => { + const handleTitleClick = useCallback(() => { + const element = document.querySelector( + `.workspaceCreateFormContainer [${RIGHT_SIDEBAR_SCROLL_KEY}="${field}"]` + ); + + element?.scrollIntoView({ behavior: 'smooth', block: 'center' }); + }, [field]); + + const renderTitle = () => { + return { + [RightSidebarScrollField.UseCase]: i18n.translate( + 'workspace.form.summary.panel.useCase.title', + { + defaultMessage: 'Use case', + } + ), + [RightSidebarScrollField.Name]: i18n.translate('workspace.form.summary.panel.name.title', { + defaultMessage: 'Name', + }), + [RightSidebarScrollField.Description]: i18n.translate( + 'workspace.form.summary.panel.description.title', + { + defaultMessage: 'Description', + } + ), + [RightSidebarScrollField.Color]: i18n.translate('workspace.form.summary.panel.color.title', { + defaultMessage: 'Accent color', + }), + [RightSidebarScrollField.DataSource]: i18n.translate( + 'workspace.form.summary.panel.dataSources.title', + { + defaultMessage: 'Data sources', + } + ), + [RightSidebarScrollField.Member]: i18n.translate( + 'workspace.form.summary.panel.members.title', + { + defaultMessage: 'Members', + } + ), + }[field]; + }; + + return ( + <> + +
+ + {renderTitle()} + +
+
+ + + {!!children ? children : } + + {bottomGap && ( + <> + + + + )} + + ); +}; + +export const ExpandableTextList = ({ + texts, + collapseDisplayCount, +}: { + texts: string[]; + collapseDisplayCount: number; +}) => { + const [isExpanded, setIsExpanded] = useState(false); + const uniqueTexts = Array.from(new Set(texts)); + const displayedTexts = isExpanded ? uniqueTexts : uniqueTexts.slice(0, collapseDisplayCount); + return ( + <> + {displayedTexts.map((text) => ( + + {text} + + ))} + {uniqueTexts.length > collapseDisplayCount && ( + { + setIsExpanded((flag) => !flag); + }} + > + {isExpanded + ? i18n.translate('workspace.form.summary.members.showLess', { + defaultMessage: 'Show less', + }) + : i18n.translate('workspace.form.summary.members.showAll', { + defaultMessage: 'Show all', + })} + + )} + + ); +}; + +interface WorkspaceFormSummaryPanelProps { + formData: WorkspaceFormDataState; + availableUseCases: WorkspaceUseCase[]; + permissionEnabled?: boolean; +} + +export const WorkspaceFormSummaryPanel = ({ + formData, + availableUseCases, + permissionEnabled, +}: WorkspaceFormSummaryPanelProps) => { + const useCase = availableUseCases.find((item) => item.id === formData.useCase); + const userAndGroups = formData.permissionSettings.flatMap((setting) => { + if ('userId' in setting && !!setting.userId) { + return [setting.userId]; + } + if ('group' in setting && !!setting.group) { + return [setting.group]; + } + return []; + }); + + return ( + + + {useCase && ( + <> + {useCase.title} + {useCase.description} + + )} + + {formData.name} + + {formData.description?.trim()} + + + {formData.color && ( + + + + + + {formData.color} + + + )} + + + {formData.selectedDataSources.length > 0 && ( + title)} + collapseDisplayCount={2} + /> + )} + + {permissionEnabled && ( + + {userAndGroups.length > 0 && ( + + )} + + )} + + ); +}; diff --git a/src/plugins/workspace/public/components/workspace_detail/opensearch_connections_table.tsx b/src/plugins/workspace/public/components/workspace_detail/opensearch_connections_table.tsx index ed6ce46965ac..6b0184ba1e08 100644 --- a/src/plugins/workspace/public/components/workspace_detail/opensearch_connections_table.tsx +++ b/src/plugins/workspace/public/components/workspace_detail/opensearch_connections_table.tsx @@ -20,7 +20,7 @@ import { i18n } from '@osd/i18n'; import { CoreStart, WorkspaceObject } from '../../../../../core/public'; import { DataSource } from '../../../common/types'; import { WorkspaceClient } from '../../workspace_client'; -import { convertPermissionSettingsToPermissions, useWorkspaceFormContext } from '../workspace_form'; +import { convertPermissionSettingsToPermissions, useWorkspaceFormContext } from '../forms'; import { useOpenSearchDashboards } from '../../../../opensearch_dashboards_react/public'; interface OpenSearchConnectionTableProps { diff --git a/src/plugins/workspace/public/components/workspace_detail/select_data_source_panel.test.tsx b/src/plugins/workspace/public/components/workspace_detail/select_data_source_panel.test.tsx index 6a81482096ec..dc7daf957d33 100644 --- a/src/plugins/workspace/public/components/workspace_detail/select_data_source_panel.test.tsx +++ b/src/plugins/workspace/public/components/workspace_detail/select_data_source_panel.test.tsx @@ -3,11 +3,11 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { act, fireEvent, render, screen, waitFor } from '@testing-library/react'; +import { 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 { WorkspaceFormProvider, WorkspaceOperationType } from '../workspace_form'; +import { WorkspaceFormProvider, WorkspaceOperationType } from '../forms'; import { SelectDataSourceDetailPanel } from './select_data_source_panel'; import * as utils from '../../utils'; import { IntlProvider } from 'react-intl'; @@ -80,12 +80,10 @@ const WorkspaceDetailPage = (props: any) => { diff --git a/src/plugins/workspace/public/components/workspace_detail/select_data_source_panel.tsx b/src/plugins/workspace/public/components/workspace_detail/select_data_source_panel.tsx index db4c06fa75f4..0cf5ea588b28 100644 --- a/src/plugins/workspace/public/components/workspace_detail/select_data_source_panel.tsx +++ b/src/plugins/workspace/public/components/workspace_detail/select_data_source_panel.tsx @@ -24,7 +24,7 @@ import { OpenSearchConnectionTable } from './opensearch_connections_table'; import { AssociationDataSourceModal } from './association_data_source_modal'; import { useOpenSearchDashboards } from '../../../../opensearch_dashboards_react/public'; import { CoreStart, SavedObjectsStart, WorkspaceObject } from '../../../../../core/public'; -import { convertPermissionSettingsToPermissions, useWorkspaceFormContext } from '../workspace_form'; +import { convertPermissionSettingsToPermissions, useWorkspaceFormContext } from '../forms'; export interface SelectDataSourcePanelProps { savedObjects: SavedObjectsStart; diff --git a/src/plugins/workspace/public/components/workspace_detail/workspace_detail.test.tsx b/src/plugins/workspace/public/components/workspace_detail/workspace_detail.test.tsx index cc23f3af8ec8..a272bc94d534 100644 --- a/src/plugins/workspace/public/components/workspace_detail/workspace_detail.test.tsx +++ b/src/plugins/workspace/public/components/workspace_detail/workspace_detail.test.tsx @@ -11,7 +11,7 @@ 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'; -import { WorkspaceFormProvider, WorkspaceOperationType } from '../workspace_form'; +import { WorkspaceFormProvider, WorkspaceOperationType } from '../forms'; import { MemoryRouter } from 'react-router-dom'; // all applications @@ -132,12 +132,10 @@ const WorkspaceDetailPage = (props: any) => { diff --git a/src/plugins/workspace/public/components/workspace_detail/workspace_detail.tsx b/src/plugins/workspace/public/components/workspace_detail/workspace_detail.tsx index a95756947424..da7164325199 100644 --- a/src/plugins/workspace/public/components/workspace_detail/workspace_detail.tsx +++ b/src/plugins/workspace/public/components/workspace_detail/workspace_detail.tsx @@ -8,9 +8,7 @@ import { EuiPage, EuiText, EuiSpacer, - EuiFlexItem, EuiPageBody, - EuiFlexGroup, EuiPageHeader, EuiPageContent, EuiSmallButton, @@ -22,12 +20,17 @@ import { useObservable } from 'react-use'; import { BehaviorSubject, of } from 'rxjs'; import { useHistory, useLocation } from 'react-router-dom'; import { WorkspaceUseCase } from '../../types'; -import { WorkspaceDetailForm, useWorkspaceFormContext } from '../workspace_form'; +import { + WorkspaceDetailForm, + useWorkspaceFormContext, + DetailTab, + DetailTabTitles, + WorkspaceOperationType, +} from '../forms'; import { WorkspaceDetailPanel } from './workspace_detail_panel'; import { DeleteWorkspaceModal } from '../delete_workspace_modal'; import { WORKSPACE_LIST_APP_ID } from '../../../common/constants'; import { cleanWorkspaceId } from '../../../../../core/public/utils'; -import { DetailTab, DetailTabTitles, WorkspaceOperationType } from '../workspace_form/constants'; import { CoreStart, WorkspaceAttribute } from '../../../../../core/public'; import { getFirstUseCaseOfFeatureConfigs, getUseCaseUrl } from '../../utils'; import { useOpenSearchDashboards } from '../../../../opensearch_dashboards_react/public'; diff --git a/src/plugins/workspace/public/components/workspace_detail_app.tsx b/src/plugins/workspace/public/components/workspace_detail_app.tsx index 1347b130575b..b74149b03ea7 100644 --- a/src/plugins/workspace/public/components/workspace_detail_app.tsx +++ b/src/plugins/workspace/public/components/workspace_detail_app.tsx @@ -12,13 +12,13 @@ import { EuiBreadcrumb } from '@elastic/eui'; import { of } from 'rxjs'; import { useOpenSearchDashboards } from '../../../opensearch_dashboards_react/public'; import { WorkspaceDetail, WorkspaceDetailProps } from './workspace_detail/workspace_detail'; -import { WorkspaceFormProvider } from './workspace_form'; +import { WorkspaceFormProvider } from './forms'; import { WorkspaceFormSubmitData, WorkspaceOperationType, convertPermissionSettingsToPermissions, convertPermissionsToPermissionSettings, -} from './workspace_form'; +} from './forms'; import { DataSource } from '../../common/types'; import { WorkspaceClient } from '../workspace_client'; import { formatUrlWithWorkspaceId } from '../../../../core/public/utils'; @@ -166,12 +166,10 @@ export const WorkspaceDetailApp = (props: WorkspaceDetailProps) => { return ( diff --git a/src/plugins/workspace/public/components/workspace_form/index.ts b/src/plugins/workspace/public/components/workspace_form/index.ts deleted file mode 100644 index 42164ca530e2..000000000000 --- a/src/plugins/workspace/public/components/workspace_form/index.ts +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -export { WorkspaceForm } from './workspace_form'; -export { WorkspaceDetailForm } from './workspace_detail_form'; -export { WorkspaceFormSubmitData } from './types'; -export { WorkspaceOperationType } from './constants'; -export { - convertPermissionsToPermissionSettings, - convertPermissionSettingsToPermissions, -} from './utils'; -export { WorkspaceFormProvider, useWorkspaceFormContext } from './workspace_form_context'; diff --git a/src/plugins/workspace/public/components/workspace_form/workspace_enter_details_panel.tsx b/src/plugins/workspace/public/components/workspace_form/workspace_enter_details_panel.tsx deleted file mode 100644 index fc4a669426b5..000000000000 --- a/src/plugins/workspace/public/components/workspace_form/workspace_enter_details_panel.tsx +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { - EuiColorPicker, - EuiCompressedFieldText, - EuiCompressedFormRow, - EuiSpacer, - EuiText, - EuiCompressedTextArea, -} from '@elastic/eui'; -import { i18n } from '@osd/i18n'; -import React from 'react'; -import { EuiColorPickerOutput } from '@elastic/eui/src/components/color_picker/color_picker'; -import { WorkspaceFormErrors } from './types'; -import { WorkspaceNameField } from './fields/workspace_name_field'; -import { WorkspaceDescriptionField } from './fields/workspace_description_field'; - -export interface EnterDetailsPanelProps { - formErrors: WorkspaceFormErrors; - name?: string; - description?: string; - color?: string; - readOnly: boolean; - onNameChange: (newValue: string) => void; - onDescriptionChange: (newValue: string) => void; - handleColorChange: (text: string, output: EuiColorPickerOutput) => void; -} - -export const EnterDetailsPanel = ({ - formErrors, - name, - description, - color, - readOnly, - onNameChange, - onDescriptionChange, - handleColorChange, -}: EnterDetailsPanelProps) => { - return ( - <> - - - -
- - {i18n.translate('workspace.form.workspaceDetails.color.description', { - defaultMessage: 'Select a background color for the icon representing this workspace.', - })} - - - -
-
- - ); -}; diff --git a/src/plugins/workspace/public/components/workspace_form/workspace_form.tsx b/src/plugins/workspace/public/components/workspace_form/workspace_form.tsx deleted file mode 100644 index a968f560fb03..000000000000 --- a/src/plugins/workspace/public/components/workspace_form/workspace_form.tsx +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React, { useRef } from 'react'; -import { EuiPanel, EuiSpacer, EuiTitle, EuiForm } from '@elastic/eui'; - -import { WorkspaceFormProps } from './types'; -import { useWorkspaceForm } from './use_workspace_form'; -import { WorkspacePermissionSettingPanel } from './workspace_permission_setting_panel'; -import { WorkspaceUseCase } from './workspace_use_case'; -import { WorkspaceFormErrorCallout } from './workspace_form_error_callout'; -import { WorkspaceCreateActionPanel } from './workspace_create_action_panel'; -import { SelectDataSourcePanel } from './select_data_source_panel'; -import { EnterDetailsPanel } from './workspace_enter_details_panel'; -import { - selectDataSourceTitle, - usersAndPermissionsTitle, - workspaceDetailsTitle, - workspaceUseCaseTitle, -} from './constants'; - -export const WorkspaceForm = (props: WorkspaceFormProps) => { - const { - application, - savedObjects, - defaultValues, - permissionEnabled, - dataSourceManagement: isDataSourceEnabled, - availableUseCases, - operationType, - } = props; - const { - formId, - formData, - formErrors, - numberOfErrors, - numberOfChanges, - setName, - setDescription, - handleFormSubmit, - handleColorChange, - handleUseCaseChange, - setPermissionSettings, - setSelectedDataSources, - } = useWorkspaceForm(props); - - const disabledUserOrGroupInputIdsRef = useRef( - defaultValues?.permissionSettings?.map((item) => item.id) ?? [] - ); - const isDashboardAdmin = application?.capabilities?.dashboards?.isDashboardAdmin ?? false; - - return ( - - {numberOfErrors > 0 && ( - <> - - - - )} - - - -

{workspaceDetailsTitle}

-
- - -
- - - -

{workspaceUseCaseTitle}

-
- - -
- - {permissionEnabled && ( - - -

{usersAndPermissionsTitle}

-
- - -
- )} - - - {/* SelectDataSourcePanel is only visible for dashboard admin and when data source is enabled*/} - {isDashboardAdmin && isDataSourceEnabled && ( - - -

{selectDataSourceTitle}

-
- -
- )} - - -
- ); -};