Skip to content

Commit

Permalink
[Workspace] Refactor: workspace detail page header (#7771)
Browse files Browse the repository at this point in the history
* fix workspace detail page header

Signed-off-by: yubonluo <yubonluo@amazon.com>

* Changeset file for PR #7771 created/updated

* optimize workspace detail page header

Signed-off-by: yubonluo <yubonluo@amazon.com>

* optimize the code

Signed-off-by: yubonluo <yubonluo@amazon.com>

* Add delete unit  test flow

Signed-off-by: yubonluo <yubonluo@amazon.com>

* optimize the code

Signed-off-by: yubonluo <yubonluo@amazon.com>

---------

Signed-off-by: yubonluo <yubonluo@amazon.com>
Co-authored-by: opensearch-changeset-bot[bot] <154024398+opensearch-changeset-bot[bot]@users.noreply.github.com>
Co-authored-by: Yulong Ruan <ruanyl@amazon.com>
  • Loading branch information
3 people committed Aug 23, 2024
1 parent a550601 commit a59f8ab
Show file tree
Hide file tree
Showing 10 changed files with 81 additions and 121 deletions.
2 changes: 2 additions & 0 deletions changelogs/fragments/7771.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
refactor:
- [Workspace] Refactor: workspace detail page header ([#7771](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7771))

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,7 @@ export const OpenSearchConnectionTable = ({
} = useOpenSearchDashboards<{ CoreStart: CoreStart; workspaceClient: WorkspaceClient }>();
const { formData, setSelectedDataSources } = useWorkspaceFormContext();
const [searchTerm, setSearchTerm] = useState('');
const [SelectedItems, setSelectedItems] = useState<DataSource[]>([]);
const [assignItems, setAssignItems] = useState<DataSource[]>([]);
const [selectedItems, setSelectedItems] = useState<DataSource[]>([]);
const [modalVisible, setModalVisible] = useState(false);

const filteredDataSources = useMemo(
Expand All @@ -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[]) => {
Expand Down Expand Up @@ -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',
Expand All @@ -160,7 +158,7 @@ export const OpenSearchConnectionTable = ({
return (
<>
<EuiFlexGroup justifyContent="spaceBetween" alignItems="center">
{SelectedItems.length > 0 && !modalVisible && (
{selectedItems.length > 0 && !modalVisible && (
<EuiFlexItem grow={false}>
<EuiButton
color="danger"
Expand All @@ -169,7 +167,7 @@ export const OpenSearchConnectionTable = ({
>
{i18n.translate('workspace.detail.dataSources.table.remove.button', {
defaultMessage: 'Remove {numberOfSelect} association(s)',
values: { numberOfSelect: SelectedItems.length },
values: { numberOfSelect: selectedItems.length },
})}
</EuiButton>
</EuiFlexItem>
Expand Down Expand Up @@ -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',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,14 @@ const WorkspaceDetailPage = (props: any) => {
},
},
dataSourceManagement,
navigationUI: {
HeaderControl: ({ controls }) => {
if (props.showDeleteModal) {
controls?.[0]?.run?.();
}
return null;
},
},
},
});

Expand Down Expand Up @@ -194,16 +202,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' },
Expand Down Expand Up @@ -277,13 +284,16 @@ describe('WorkspaceDetail', () => {

it('will not render xss content', async () => {
const alertSpy = jest.spyOn(window, 'alert').mockImplementation(() => {});
const workspaceService = createWorkspacesSetupContractMockWithValue({
...workspaceObject,
name: '<script>alert("name")</script>',
description: '<script>alert("description")</script>',
});
const { getByText } = render(WorkspaceDetailPage({ workspacesService: workspaceService }));
expect(getByText('<script>alert("description")</script>')).toBeInTheDocument();
const workspaceService = createWorkspacesSetupContractMockWithValue();
const { getByTestId } = render(
WorkspaceDetailPage({
workspacesService: workspaceService,
defaultValues: { ...defaultValues, description: '<script>alert("description")</script>' },
})
);
expect(getByTestId('workspaceForm-workspaceDetails-descriptionInputText').value).toEqual(
'<script>alert("description")</script>'
);
expect(alertSpy).toBeCalledTimes(0);
alertSpy.mockRestore();
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -34,17 +29,31 @@ 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<WorkspaceUseCase[]>;
}

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 {
Expand Down Expand Up @@ -146,25 +155,35 @@ export const WorkspaceDetail = (props: WorkspaceDetailProps) => {
: []),
];

const deleteButton = (
<EuiSmallButton
color="danger"
iconType="trash"
onClick={() => setDeletedWorkspace(currentWorkspace)}
>
{i18n.translate('workspace.detail.delete', {
defaultMessage: 'delete',
})}
</EuiSmallButton>
);

return (
<>
<EuiPage direction="column">
<EuiPageHeader rightSideItems={[deleteButton]} alignItems="center" />
<EuiPageBody>
<EuiText color="subdued">{currentWorkspace.description}</EuiText>
</EuiPageBody>
{currentWorkspace.description && (
<HeaderControl
controls={[
{
description: currentWorkspace.description,
} as TopNavControlDescriptionData,
]}
setMountPoint={application.setAppDescriptionControls}
/>
)}
<HeaderControl
controls={[
{
run: () => 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}
/>
<EuiSpacer />
<EuiPageContent>
<WorkspaceDetailPanel
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ export const useWorkspaceForm = ({
const handleResetForm = useCallback(() => {
const resetValues = defaultValuesRef.current;
setName(resetValues?.name ?? '');
setDescription(resetValues?.description);
setDescription(resetValues?.description ?? '');
setColor(resetValues?.color);
setFeatureConfigs(appendDefaultFeatureIds(resetValues?.features ?? []));
setPermissionSettings(initialPermissionSettingsRef.current);
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
* SPDX-License-Identifier: Apache-2.0
*/

import './workspace_detail_form.scss';
import React, { useEffect, useRef, useState } from 'react';
import {
EuiSpacer,
Expand All @@ -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;
Expand All @@ -34,7 +33,7 @@ interface FormGroupProps {
const FormGroup = ({ title, children, describe }: FormGroupProps) => (
<>
<EuiFlexGroup gutterSize="xl">
<EuiFlexItem grow={false} className="workspace-detail-form-group">
<EuiFlexItem grow={false} style={{ width: '15%' }}>
<EuiTitle size="xs">
<h3>{title}</h3>
</EuiTitle>
Expand Down Expand Up @@ -132,7 +131,7 @@ export const WorkspaceDetailForm = (props: WorkspaceFormProps) => {
</EuiFlexGroup>
<EuiHorizontalRule />
{detailTab === DetailTab.Details && (
<WorkspaceDetailFormDetailsProps availableUseCases={availableUseCases} />
<WorkspaceDetailFormDetails availableUseCases={availableUseCases} />
)}
{detailTab === DetailTab.Collaborators && (
<FormGroup title={usersAndPermissionsTitle}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import {
EuiColorPicker,
EuiCompressedFormRow,
EuiDescribedFormGroup,
EuiCompressedTextArea,
} from '@elastic/eui';
import React, { useEffect, useState } from 'react';
import { useObservable } from 'react-use';
Expand All @@ -17,7 +16,6 @@ import {
detailsColorLabel,
detailsUseCaseLabel,
detailsColorHelpText,
detailsDescriptionPlaceholder,
detailsDescriptionIntroduction,
detailsUseCaseHelpText,
} from './constants';
Expand All @@ -36,7 +34,7 @@ interface WorkspaceDetailFormDetailsProps {
>;
}

export const WorkspaceDetailFormDetailsProps = ({
export const WorkspaceDetailFormDetails = ({
availableUseCases,
}: WorkspaceDetailFormDetailsProps) => {
const {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ export const WorkspaceInitial = () => {
defaultMessage: 'Create a workspace',
})}
description={
<EuiToolTip content={isDashboardAdmin || noAdminToolTip}>
<EuiToolTip content={isDashboardAdmin ? null : noAdminToolTip}>
<>
{i18n.translate('workspace.initial.card.createWorkspace.description', {
defaultMessage: 'Organize projects by use case in a collaborative workspace.',
Expand Down

0 comments on commit a59f8ab

Please sign in to comment.