diff --git a/changelogs/fragments/7771.yml b/changelogs/fragments/7771.yml
new file mode 100644
index 000000000000..1c9eccd32254
--- /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 b9e165a79c3a..b1036d4d80ed 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 ed6ce46965ac..278b7ffcba85 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 cc23f3af8ec8..41344d975cfb 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 6e3e628e4538..8f02be4e6909 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 12d655151605..000000000000
--- 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 a8015120d407..bc3ce92067ff 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 27de826141b2..ec79f063acc5 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 7d88210820f4..96e91613ce07 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.',