diff --git a/changelogs/fragments/7771.yml b/changelogs/fragments/7771.yml new file mode 100644 index 00000000000..1c9eccd3225 --- /dev/null +++ b/changelogs/fragments/7771.yml @@ -0,0 +1,2 @@ +refactor: +- [Workspace] Refactor: workspace detail page header ([#7771](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7771)) \ No newline at end of file diff --git a/src/plugins/workspace/public/components/workspace_detail/__snapshots__/workspace_detail.test.tsx.snap b/src/plugins/workspace/public/components/workspace_detail/__snapshots__/workspace_detail.test.tsx.snap index b9e165a79c3..b1036d4d80e 100644 --- a/src/plugins/workspace/public/components/workspace_detail/__snapshots__/workspace_detail.test.tsx.snap +++ b/src/plugins/workspace/public/components/workspace_detail/__snapshots__/workspace_detail.test.tsx.snap @@ -5,65 +5,6 @@ exports[`WorkspaceDetail render workspace detail page normally 1`] = `
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
- this is my foo workspace description -
-
-
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 ed6ce46965a..278b7ffcba8 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 @@ -41,8 +41,7 @@ export const OpenSearchConnectionTable = ({ } = useOpenSearchDashboards<{ CoreStart: CoreStart; workspaceClient: WorkspaceClient }>(); const { formData, setSelectedDataSources } = useWorkspaceFormContext(); const [searchTerm, setSearchTerm] = useState(''); - const [SelectedItems, setSelectedItems] = useState([]); - const [assignItems, setAssignItems] = useState([]); + const [selectedItems, setSelectedItems] = useState([]); const [modalVisible, setModalVisible] = useState(false); const filteredDataSources = useMemo( @@ -53,9 +52,8 @@ export const OpenSearchConnectionTable = ({ [searchTerm, assignedDataSources] ); - const onSelectionChange = (selectedItems: DataSource[]) => { - setSelectedItems(selectedItems); - setAssignItems(selectedItems); + const onSelectionChange = (selectedDataSources: DataSource[]) => { + setSelectedItems(selectedDataSources); }; const handleUnassignDataSources = async (dataSources: DataSource[]) => { @@ -138,7 +136,7 @@ export const OpenSearchConnectionTable = ({ icon: 'unlink', type: 'icon', onClick: (item: DataSource) => { - setAssignItems([item]); + setSelectedItems([item]); setModalVisible(true); }, 'data-test-subj': 'workspace-detail-dataSources-table-actions-remove', @@ -160,7 +158,7 @@ export const OpenSearchConnectionTable = ({ return ( <> - {SelectedItems.length > 0 && !modalVisible && ( + {selectedItems.length > 0 && !modalVisible && ( {i18n.translate('workspace.detail.dataSources.table.remove.button', { defaultMessage: 'Remove {numberOfSelect} association(s)', - values: { numberOfSelect: SelectedItems.length }, + values: { numberOfSelect: selectedItems.length }, })} @@ -205,9 +203,10 @@ export const OpenSearchConnectionTable = ({ })} onCancel={() => { setModalVisible(false); + setSelectedItems([]); }} onConfirm={() => { - handleUnassignDataSources(assignItems); + handleUnassignDataSources(selectedItems); }} cancelButtonText={i18n.translate('workspace.detail.dataSources.modal.cancelButton', { defaultMessage: 'Cancel', 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 cc23f3af8ec..41344d975cf 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 @@ -119,6 +119,14 @@ const WorkspaceDetailPage = (props: any) => { }, }, dataSourceManagement, + navigationUI: { + HeaderControl: ({ controls }) => { + if (props.showDeleteModal) { + controls?.[0]?.run?.(); + } + return null; + }, + }, }, }); @@ -198,16 +206,15 @@ describe('WorkspaceDetail', () => { expect(document.querySelector('#dataSources')).toHaveClass('euiTab-isSelected'); }); - it('click on delete button will show delete modal', async () => { + it('delete button will been shown at page header', async () => { const workspaceService = createWorkspacesSetupContractMockWithValue(workspaceObject); - const { getByText, getByTestId, queryByText } = render( - WorkspaceDetailPage({ workspacesService: workspaceService }) + const { getByText, getByTestId } = render( + WorkspaceDetailPage({ + workspacesService: workspaceService, + showDeleteModal: true, + }) ); - fireEvent.click(getByText('delete')); expect(getByText('Delete workspace')).toBeInTheDocument(); - fireEvent.click(getByText('Cancel')); - expect(queryByText('Delete workspace')).toBeNull(); - fireEvent.click(getByText('delete')); const input = getByTestId('delete-workspace-modal-input'); fireEvent.change(input, { target: { value: 'delete' }, @@ -281,13 +288,16 @@ describe('WorkspaceDetail', () => { it('will not render xss content', async () => { const alertSpy = jest.spyOn(window, 'alert').mockImplementation(() => {}); - const workspaceService = createWorkspacesSetupContractMockWithValue({ - ...workspaceObject, - name: '', - description: '', - }); - const { getByText } = render(WorkspaceDetailPage({ workspacesService: workspaceService })); - expect(getByText('')).toBeInTheDocument(); + const workspaceService = createWorkspacesSetupContractMockWithValue(); + const { getByTestId } = render( + WorkspaceDetailPage({ + workspacesService: workspaceService, + defaultValues: { ...defaultValues, description: '' }, + }) + ); + expect(getByTestId('workspaceForm-workspaceDetails-descriptionInputText').value).toEqual( + '' + ); expect(alertSpy).toBeCalledTimes(0); alertSpy.mockRestore(); }); 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 6e3e628e453..8f02be4e690 100644 --- a/src/plugins/workspace/public/components/workspace_detail/workspace_detail.tsx +++ b/src/plugins/workspace/public/components/workspace_detail/workspace_detail.tsx @@ -6,14 +6,9 @@ import React, { useEffect, useState } from 'react'; import { EuiPage, - EuiText, EuiSpacer, - EuiFlexItem, EuiPageBody, - EuiFlexGroup, - EuiPageHeader, EuiPageContent, - EuiSmallButton, EuiConfirmModal, EuiTabbedContent, } from '@elastic/eui'; @@ -34,6 +29,11 @@ import { useOpenSearchDashboards } from '../../../../opensearch_dashboards_react import { DataSourceManagementPluginSetup } from '../../../../../plugins/data_source_management/public'; import { SelectDataSourceDetailPanel } from './select_data_source_panel'; import { WorkspaceBottomBar } from './workspace_bottom_bar'; +import { + NavigationPublicPluginStart, + TopNavControlDescriptionData, + TopNavControlIconData, +} from '../../../../navigation/public'; export interface WorkspaceDetailProps { registeredUseCases$: BehaviorSubject; @@ -41,10 +41,19 @@ export interface WorkspaceDetailProps { export const WorkspaceDetail = (props: WorkspaceDetailProps) => { const { - services: { workspaces, application, http, savedObjects, dataSourceManagement, uiSettings }, + services: { + workspaces, + application, + http, + savedObjects, + dataSourceManagement, + uiSettings, + navigationUI: { HeaderControl }, + }, } = useOpenSearchDashboards<{ CoreStart: CoreStart; dataSourceManagement?: DataSourceManagementPluginSetup; + navigationUI: NavigationPublicPluginStart['ui']; }>(); const { @@ -146,25 +155,35 @@ export const WorkspaceDetail = (props: WorkspaceDetailProps) => { : []), ]; - const deleteButton = ( - setDeletedWorkspace(currentWorkspace)} - > - {i18n.translate('workspace.detail.delete', { - defaultMessage: 'delete', - })} - - ); - return ( <> - - - {currentWorkspace.description} - + {currentWorkspace.description && ( + + )} + setDeletedWorkspace(currentWorkspace), + color: 'danger', + iconType: 'trash', + ariaLabel: i18n.translate('workspace.detail.delete.button', { + defaultMessage: 'Delete', + }), + testId: 'workspace-detail-delete-button', + controlType: 'icon', + display: 'base', + } as TopNavControlIconData, + ]} + setMountPoint={application.setAppRightControls} + /> { const resetValues = defaultValuesRef.current; setName(resetValues?.name ?? ''); - setDescription(resetValues?.description); + setDescription(resetValues?.description ?? ''); setColor(resetValues?.color); setFeatureConfigs(appendDefaultFeatureIds(resetValues?.features ?? [])); setPermissionSettings(initialPermissionSettingsRef.current); diff --git a/src/plugins/workspace/public/components/workspace_form/workspace_detail_form.scss b/src/plugins/workspace/public/components/workspace_form/workspace_detail_form.scss deleted file mode 100644 index 12d65515160..00000000000 --- a/src/plugins/workspace/public/components/workspace_form/workspace_detail_form.scss +++ /dev/null @@ -1,8 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -.workspace-detail-form-group { - width: 15%; -} diff --git a/src/plugins/workspace/public/components/workspace_form/workspace_detail_form.tsx b/src/plugins/workspace/public/components/workspace_form/workspace_detail_form.tsx index a8015120d40..bc3ce92067f 100644 --- a/src/plugins/workspace/public/components/workspace_form/workspace_detail_form.tsx +++ b/src/plugins/workspace/public/components/workspace_form/workspace_detail_form.tsx @@ -3,7 +3,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -import './workspace_detail_form.scss'; import React, { useEffect, useRef, useState } from 'react'; import { EuiSpacer, @@ -23,7 +22,7 @@ import { WorkspacePermissionSettingPanel } from './workspace_permission_setting_ import { DetailTab, usersAndPermissionsTitle } from './constants'; import { WorkspaceFormErrorCallout } from './workspace_form_error_callout'; import { useWorkspaceFormContext } from './workspace_form_context'; -import { WorkspaceDetailFormDetailsProps } from './workspace_detail_form_details'; +import { WorkspaceDetailFormDetails } from './workspace_detail_form_details'; interface FormGroupProps { title: React.ReactNode; @@ -34,7 +33,7 @@ interface FormGroupProps { const FormGroup = ({ title, children, describe }: FormGroupProps) => ( <> - +

{title}

@@ -132,7 +131,7 @@ export const WorkspaceDetailForm = (props: WorkspaceFormProps) => {
{detailTab === DetailTab.Details && ( - + )} {detailTab === DetailTab.Collaborators && ( diff --git a/src/plugins/workspace/public/components/workspace_form/workspace_detail_form_details.tsx b/src/plugins/workspace/public/components/workspace_form/workspace_detail_form_details.tsx index 27de826141b..ec79f063acc 100644 --- a/src/plugins/workspace/public/components/workspace_form/workspace_detail_form_details.tsx +++ b/src/plugins/workspace/public/components/workspace_form/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'; @@ -36,7 +34,7 @@ interface WorkspaceDetailFormDetailsProps { >; } -export const WorkspaceDetailFormDetailsProps = ({ +export const WorkspaceDetailFormDetails = ({ availableUseCases, }: WorkspaceDetailFormDetailsProps) => { const { diff --git a/src/plugins/workspace/public/components/workspace_initial/workspace_initial.tsx b/src/plugins/workspace/public/components/workspace_initial/workspace_initial.tsx index 7d88210820f..96e91613ce0 100644 --- a/src/plugins/workspace/public/components/workspace_initial/workspace_initial.tsx +++ b/src/plugins/workspace/public/components/workspace_initial/workspace_initial.tsx @@ -69,7 +69,7 @@ export const WorkspaceInitial = () => { defaultMessage: 'Create a workspace', })} description={ - + <> {i18n.translate('workspace.initial.card.createWorkspace.description', { defaultMessage: 'Organize projects by use case in a collaborative workspace.',