diff --git a/changelogs/fragments/8501.yml b/changelogs/fragments/8501.yml
new file mode 100644
index 000000000000..bf37aaa28f7d
--- /dev/null
+++ b/changelogs/fragments/8501.yml
@@ -0,0 +1,2 @@
+feat:
+- Add collaborator table to workspace detail page ([#8501](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/8501))
\ No newline at end of file
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
index 5b26f89a2ed2..cac0c18b0287 100644
--- 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
@@ -101,9 +101,9 @@ describe('WorkspaceFormSummaryPanel', () => {
expect(screen.getByText('Data Source 2')).toBeInTheDocument();
expect(screen.getByText('Data Source 3')).toBeInTheDocument();
expect(screen.getByText('user1')).toBeInTheDocument();
- expect(screen.getByText('Owner')).toBeInTheDocument();
+ expect(screen.getByText('Admin')).toBeInTheDocument();
expect(screen.getByText('group1')).toBeInTheDocument();
- expect(screen.getByText('Read')).toBeInTheDocument();
+ expect(screen.getByText('Read only')).toBeInTheDocument();
expect(screen.getByText('+1 more')).toBeInTheDocument();
expect(screen.queryByText('user2')).toBeNull();
expect(screen.getByText('Cancel')).toBeInTheDocument();
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 f530088f15f5..0b7f2ad1ef6f 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
@@ -223,6 +223,11 @@ exports[`WorkspaceDetail render workspace detail page normally 1`] = `
+
+ Manage workspace access and permissions.
+
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 07ed9d425679..f6902d427b36 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
@@ -16,6 +16,7 @@ import { WorkspaceFormProvider, WorkspaceOperationType } from '../workspace_form
import { DataSourceConnectionType } from '../../../common/types';
import * as utilsExports from '../../utils';
import { IntlProvider } from 'react-intl';
+import { of } from 'rxjs';
// all applications
const PublicAPPInfoMap = new Map([
@@ -131,6 +132,9 @@ const WorkspaceDetailPage = (props: any) => {
return null;
},
},
+ collaboratorTypes: {
+ getTypes$: jest.fn().mockReturnValue(of([])),
+ },
},
});
diff --git a/src/plugins/workspace/public/components/workspace_detail_app.tsx b/src/plugins/workspace/public/components/workspace_detail_app.tsx
index 66ea4f3f8b9c..a393026552a5 100644
--- a/src/plugins/workspace/public/components/workspace_detail_app.tsx
+++ b/src/plugins/workspace/public/components/workspace_detail_app.tsx
@@ -92,7 +92,7 @@ export const WorkspaceDetailApp = (props: WorkspaceDetailPropsWithOnAppLeave) =>
}, [currentWorkspace, savedObjects, http, notifications]);
const handleWorkspaceFormSubmit = useCallback(
- async (data: WorkspaceFormSubmitData) => {
+ async (data: WorkspaceFormSubmitData, refresh?: boolean) => {
let result;
if (isFormSubmitting) {
return;
@@ -127,7 +127,8 @@ export const WorkspaceDetailApp = (props: WorkspaceDetailPropsWithOnAppLeave) =>
defaultMessage: 'Update workspace successfully',
}),
});
- if (application && http) {
+ setIsFormSubmitting(false);
+ if (application && http && refresh) {
// Redirect page after one second, leave one second time to show update successful toast.
window.setTimeout(() => {
window.location.href = formatUrlWithWorkspaceId(
diff --git a/src/plugins/workspace/public/components/workspace_form/__snapshots__/add_collaborator_button.test.tsx.snap b/src/plugins/workspace/public/components/workspace_form/__snapshots__/add_collaborator_button.test.tsx.snap
new file mode 100644
index 000000000000..98482f3f71b1
--- /dev/null
+++ b/src/plugins/workspace/public/components/workspace_form/__snapshots__/add_collaborator_button.test.tsx.snap
@@ -0,0 +1,124 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`AddCollaboratorButton should render normally 1`] = `
+Object {
+ "asFragment": [Function],
+ "baseElement":
+
+
+
+
+
+
+
+ Add collaborators
+
+
+
+
+
+
+ ,
+ "container":
+
+
+
+
+
+
+ Add collaborators
+
+
+
+
+
+
,
+ "debug": [Function],
+ "findAllByAltText": [Function],
+ "findAllByDisplayValue": [Function],
+ "findAllByLabelText": [Function],
+ "findAllByPlaceholderText": [Function],
+ "findAllByRole": [Function],
+ "findAllByTestId": [Function],
+ "findAllByText": [Function],
+ "findAllByTitle": [Function],
+ "findByAltText": [Function],
+ "findByDisplayValue": [Function],
+ "findByLabelText": [Function],
+ "findByPlaceholderText": [Function],
+ "findByRole": [Function],
+ "findByTestId": [Function],
+ "findByText": [Function],
+ "findByTitle": [Function],
+ "getAllByAltText": [Function],
+ "getAllByDisplayValue": [Function],
+ "getAllByLabelText": [Function],
+ "getAllByPlaceholderText": [Function],
+ "getAllByRole": [Function],
+ "getAllByTestId": [Function],
+ "getAllByText": [Function],
+ "getAllByTitle": [Function],
+ "getByAltText": [Function],
+ "getByDisplayValue": [Function],
+ "getByLabelText": [Function],
+ "getByPlaceholderText": [Function],
+ "getByRole": [Function],
+ "getByTestId": [Function],
+ "getByText": [Function],
+ "getByTitle": [Function],
+ "queryAllByAltText": [Function],
+ "queryAllByDisplayValue": [Function],
+ "queryAllByLabelText": [Function],
+ "queryAllByPlaceholderText": [Function],
+ "queryAllByRole": [Function],
+ "queryAllByTestId": [Function],
+ "queryAllByText": [Function],
+ "queryAllByTitle": [Function],
+ "queryByAltText": [Function],
+ "queryByDisplayValue": [Function],
+ "queryByLabelText": [Function],
+ "queryByPlaceholderText": [Function],
+ "queryByRole": [Function],
+ "queryByTestId": [Function],
+ "queryByText": [Function],
+ "queryByTitle": [Function],
+ "rerender": [Function],
+ "unmount": [Function],
+}
+`;
diff --git a/src/plugins/workspace/public/components/workspace_form/__snapshots__/workspace_collaborator_table.test.tsx.snap b/src/plugins/workspace/public/components/workspace_form/__snapshots__/workspace_collaborator_table.test.tsx.snap
new file mode 100644
index 000000000000..caaa8456ecdb
--- /dev/null
+++ b/src/plugins/workspace/public/components/workspace_form/__snapshots__/workspace_collaborator_table.test.tsx.snap
@@ -0,0 +1,1262 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`WorkspaceCollaboratorTable should render normally 1`] = `
+Object {
+ "asFragment": [Function],
+ "baseElement":
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Type
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Access level
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ admin
+
+
+
+
+
+
+
+ User
+
+
+
+
+
+
+
+ Admin
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ group
+
+
+
+
+
+
+
+ Group
+
+
+
+
+
+
+
+ Read only
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Rows per page
+ :
+ 10
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ,
+ "container":
+
+
+
+
+
+
+
+
+
+
+
+
+ Type
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Access level
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ admin
+
+
+
+
+
+
+
+ User
+
+
+
+
+
+
+
+ Admin
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ group
+
+
+
+
+
+
+
+ Group
+
+
+
+
+
+
+
+ Read only
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Rows per page
+ :
+ 10
+
+
+
+
+
+
+
+
+
+
+
+
+
+
,
+ "debug": [Function],
+ "findAllByAltText": [Function],
+ "findAllByDisplayValue": [Function],
+ "findAllByLabelText": [Function],
+ "findAllByPlaceholderText": [Function],
+ "findAllByRole": [Function],
+ "findAllByTestId": [Function],
+ "findAllByText": [Function],
+ "findAllByTitle": [Function],
+ "findByAltText": [Function],
+ "findByDisplayValue": [Function],
+ "findByLabelText": [Function],
+ "findByPlaceholderText": [Function],
+ "findByRole": [Function],
+ "findByTestId": [Function],
+ "findByText": [Function],
+ "findByTitle": [Function],
+ "getAllByAltText": [Function],
+ "getAllByDisplayValue": [Function],
+ "getAllByLabelText": [Function],
+ "getAllByPlaceholderText": [Function],
+ "getAllByRole": [Function],
+ "getAllByTestId": [Function],
+ "getAllByText": [Function],
+ "getAllByTitle": [Function],
+ "getByAltText": [Function],
+ "getByDisplayValue": [Function],
+ "getByLabelText": [Function],
+ "getByPlaceholderText": [Function],
+ "getByRole": [Function],
+ "getByTestId": [Function],
+ "getByText": [Function],
+ "getByTitle": [Function],
+ "queryAllByAltText": [Function],
+ "queryAllByDisplayValue": [Function],
+ "queryAllByLabelText": [Function],
+ "queryAllByPlaceholderText": [Function],
+ "queryAllByRole": [Function],
+ "queryAllByTestId": [Function],
+ "queryAllByText": [Function],
+ "queryAllByTitle": [Function],
+ "queryByAltText": [Function],
+ "queryByDisplayValue": [Function],
+ "queryByLabelText": [Function],
+ "queryByPlaceholderText": [Function],
+ "queryByRole": [Function],
+ "queryByTestId": [Function],
+ "queryByText": [Function],
+ "queryByTitle": [Function],
+ "rerender": [Function],
+ "unmount": [Function],
+}
+`;
diff --git a/src/plugins/workspace/public/components/workspace_form/add_collaborator_button.test.tsx b/src/plugins/workspace/public/components/workspace_form/add_collaborator_button.test.tsx
new file mode 100644
index 000000000000..f5466a1f0996
--- /dev/null
+++ b/src/plugins/workspace/public/components/workspace_form/add_collaborator_button.test.tsx
@@ -0,0 +1,108 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React from 'react';
+import { fireEvent, render } from '@testing-library/react';
+
+import { AddCollaboratorButton } from './add_collaborator_button';
+
+describe('AddCollaboratorButton', () => {
+ const mockProps = {
+ displayedTypes: [],
+ permissionSettings: [
+ {
+ id: 0,
+ modes: ['library_write', 'write'],
+ type: 'user',
+ userId: 'admin',
+ },
+ {
+ id: 1,
+ modes: ['library_read', 'read'],
+ type: 'group',
+ group: 'group',
+ },
+ ],
+ handleSubmitPermissionSettings: jest.fn(),
+ };
+
+ it('should render normally', () => {
+ expect(render( )).toMatchSnapshot();
+ });
+
+ it('should display menu popover when clicked', () => {
+ const { getByTestId } = render( );
+ const button = getByTestId('add-collaborator-button');
+ fireEvent.click(button);
+ expect(getByTestId('add-collaborator-popover')).toBeInTheDocument();
+ });
+
+ it('should emit onAdd when clicked menu item', () => {
+ const mockOnAdd = jest.fn();
+ const displayedTypes = [
+ {
+ name: 'add user',
+ buttonLabel: 'add user',
+ onAdd: mockOnAdd,
+ id: 'user',
+ },
+ {
+ name: 'add group',
+ buttonLabel: 'add group',
+ onAdd: mockOnAdd,
+ id: 'group',
+ },
+ ];
+ const { getByTestId, getByText } = render(
+
+ );
+ const button = getByTestId('add-collaborator-button');
+ fireEvent.click(button);
+ expect(getByTestId('add-collaborator-popover')).toBeInTheDocument();
+ const addUserButton = getByText('add user');
+ fireEvent.click(addUserButton);
+ expect(mockOnAdd).toHaveBeenCalled();
+ });
+
+ it('should call handleSubmitPermissionSettings with newPermissionSettings when adding in modal', () => {
+ const mockOnAdd = jest.fn().mockImplementation(({ onAddCollaborators }) => {
+ onAddCollaborators([
+ {
+ accessLevel: 'readOnly',
+ collaboratorId: '2',
+ permissionType: 'user',
+ },
+ ]);
+ });
+ const displayedTypes = [
+ {
+ name: 'add user',
+ buttonLabel: 'add user',
+ onAdd: mockOnAdd,
+ id: 'user',
+ },
+ {
+ name: 'add group',
+ buttonLabel: 'add group',
+ onAdd: mockOnAdd,
+ id: 'group',
+ },
+ ];
+ const { getByTestId, getByText } = render(
+
+ );
+ const button = getByTestId('add-collaborator-button');
+ fireEvent.click(button);
+ expect(getByTestId('add-collaborator-popover')).toBeInTheDocument();
+ const addUserButton = getByText('add user');
+ fireEvent.click(addUserButton);
+ expect(mockOnAdd).toHaveBeenCalled();
+ expect(mockProps.handleSubmitPermissionSettings).toHaveBeenCalledWith([
+ { id: 0, modes: ['library_write', 'write'], type: 'user', userId: 'admin' },
+ { group: 'group', id: 1, modes: ['library_read', 'read'], type: 'group' },
+ { id: 2, modes: ['library_read', 'read'], type: 'user', userId: '2' },
+ ]);
+ });
+});
diff --git a/src/plugins/workspace/public/components/workspace_form/add_collaborator_button.tsx b/src/plugins/workspace/public/components/workspace_form/add_collaborator_button.tsx
new file mode 100644
index 000000000000..fe957574603b
--- /dev/null
+++ b/src/plugins/workspace/public/components/workspace_form/add_collaborator_button.tsx
@@ -0,0 +1,100 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React, { useState, useRef, useCallback } from 'react';
+import { EuiPopover, EuiContextMenu, EuiButton, EuiContextMenuPanelDescriptor } from '@elastic/eui';
+import { i18n } from '@osd/i18n';
+import { WorkspaceCollaboratorType } from '../../services/workspace_collaborator_types_service';
+import { WorkspaceCollaborator } from '../../types';
+import { PermissionSetting } from './workspace_collaborator_table';
+import { generateNextPermissionSettingsId } from './utils';
+import { accessLevelNameToWorkspacePermissionModesMap } from '../../constants';
+import { WorkspacePermissionItemType } from './constants';
+import { WorkspacePermissionSetting } from './types';
+
+interface Props {
+ displayedTypes: WorkspaceCollaboratorType[];
+ permissionSettings: PermissionSetting[];
+ handleSubmitPermissionSettings: (permissionSettings: WorkspacePermissionSetting[]) => void;
+}
+
+export const AddCollaboratorButton = ({
+ displayedTypes,
+ permissionSettings,
+ handleSubmitPermissionSettings,
+}: Props) => {
+ const [isPopoverOpen, setIsPopoverOpen] = useState(false);
+
+ const nextIdRef = useRef(generateNextPermissionSettingsId(permissionSettings));
+
+ const nextIdGenerator = useCallback(() => {
+ const nextId = nextIdRef.current;
+ nextIdRef.current++;
+ return nextId;
+ }, []);
+
+ const onAddCollaborators = async (collaborators: WorkspaceCollaborator[]) => {
+ const addedSettings = collaborators.map(({ permissionType, accessLevel, collaboratorId }) => ({
+ type: permissionType as WorkspacePermissionItemType,
+ modes: accessLevelNameToWorkspacePermissionModesMap[accessLevel],
+ id: nextIdGenerator(),
+ ...(permissionType === WorkspacePermissionItemType.User
+ ? {
+ userId: collaboratorId,
+ }
+ : {
+ group: collaboratorId,
+ }),
+ }));
+ const newPermissionSettings = [...permissionSettings, ...addedSettings];
+ handleSubmitPermissionSettings(newPermissionSettings as WorkspacePermissionSetting[]);
+ };
+
+ const panelItems = displayedTypes.map(({ id, buttonLabel, onAdd }) => ({
+ id,
+ name: buttonLabel,
+ onClick: () => {
+ onAdd({ onAddCollaborators });
+ setIsPopoverOpen(false);
+ },
+ }));
+
+ return (
+ setIsPopoverOpen((prev) => !prev)}
+ size="s"
+ data-test-subj="add-collaborator-button"
+ >
+ {i18n.translate('workspace.workspaceDetail.collaborator.add', {
+ defaultMessage: 'Add collaborators',
+ })}
+
+ }
+ isOpen={isPopoverOpen}
+ closePopover={() => setIsPopoverOpen(false)}
+ panelPaddingSize="none"
+ anchorPosition="downLeft"
+ initialFocus={false}
+ >
+
+
+ );
+};
diff --git a/src/plugins/workspace/public/components/workspace_form/constants.ts b/src/plugins/workspace/public/components/workspace_form/constants.ts
index 8d63d200e0de..4e1da05cb0a8 100644
--- a/src/plugins/workspace/public/components/workspace_form/constants.ts
+++ b/src/plugins/workspace/public/components/workspace_form/constants.ts
@@ -6,6 +6,7 @@
import { i18n } from '@osd/i18n';
import { WorkspacePermissionMode } from '../../../common/constants';
import { PermissionModeId } from '../../../../../core/public';
+import { WORKSPACE_ACCESS_LEVEL_NAMES } from '../../constants';
export enum WorkspaceOperationType {
Create = 'create',
@@ -126,29 +127,29 @@ export const PERMISSION_ACCESS_LEVEL_LABEL_ID = 'workspace-form-permission-acces
export const permissionModeOptions = [
{
value: PermissionModeId.Read,
- inputDisplay: i18n.translate(
- 'workspace.form.permissionSettingPanel.permissionModeOptions.read',
- {
- defaultMessage: 'Read',
- }
- ),
+ inputDisplay: WORKSPACE_ACCESS_LEVEL_NAMES.readOnly,
},
{
value: PermissionModeId.ReadAndWrite,
- inputDisplay: i18n.translate(
- 'workspace.form.permissionSettingPanel.permissionModeOptions.readAndWrite',
- {
- defaultMessage: 'Read & Write',
- }
- ),
+ inputDisplay: WORKSPACE_ACCESS_LEVEL_NAMES.readAndWrite,
},
{
value: PermissionModeId.Owner,
- inputDisplay: i18n.translate(
- 'workspace.form.permissionSettingPanel.permissionModeOptions.owner',
- {
- defaultMessage: 'Owner',
- }
- ),
+ inputDisplay: WORKSPACE_ACCESS_LEVEL_NAMES.admin,
+ },
+];
+
+export const typeOptions = [
+ {
+ value: WorkspacePermissionItemType.User,
+ inputDisplay: i18n.translate('workspace.form.permissionSettingPanel.typeOptions.user', {
+ defaultMessage: 'User',
+ }),
+ },
+ {
+ value: WorkspacePermissionItemType.Group,
+ inputDisplay: i18n.translate('workspace.form.permissionSettingPanel.typeOptions.group', {
+ defaultMessage: 'Group',
+ }),
},
];
diff --git a/src/plugins/workspace/public/components/workspace_form/types.ts b/src/plugins/workspace/public/components/workspace_form/types.ts
index 9c8da46e5be9..43c960f274d5 100644
--- a/src/plugins/workspace/public/components/workspace_form/types.ts
+++ b/src/plugins/workspace/public/components/workspace_form/types.ts
@@ -39,6 +39,7 @@ export interface WorkspaceFormSubmitData {
color?: string;
permissionSettings?: WorkspacePermissionSetting[];
selectedDataSourceConnections?: DataSourceConnection[];
+ shouldNavigate?: boolean;
}
export enum WorkspaceFormErrorCode {
@@ -78,7 +79,7 @@ export type WorkspaceFormErrors = {
export interface WorkspaceFormProps {
application: ApplicationStart;
savedObjects: SavedObjectsStart;
- onSubmit?: (formData: WorkspaceFormSubmitData) => void;
+ onSubmit?: (formData: WorkspaceFormSubmitData, refresh?: boolean) => void;
defaultValues?: Partial;
operationType: WorkspaceOperationType;
permissionEnabled?: boolean;
diff --git a/src/plugins/workspace/public/components/workspace_form/use_workspace_form.test.ts b/src/plugins/workspace/public/components/workspace_form/use_workspace_form.test.ts
index 078ce9af3e45..52d65091cb89 100644
--- a/src/plugins/workspace/public/components/workspace_form/use_workspace_form.test.ts
+++ b/src/plugins/workspace/public/components/workspace_form/use_workspace_form.test.ts
@@ -124,7 +124,8 @@ describe('useWorkspaceForm', () => {
expect.objectContaining({
name: 'test-workspace-name',
features: ['use-case-observability'],
- })
+ }),
+ true
);
});
it('should update selected use case', () => {
diff --git a/src/plugins/workspace/public/components/workspace_form/use_workspace_form.ts b/src/plugins/workspace/public/components/workspace_form/use_workspace_form.ts
index 5fb740ef12b2..a2c2cee12066 100644
--- a/src/plugins/workspace/public/components/workspace_form/use_workspace_form.ts
+++ b/src/plugins/workspace/public/components/workspace_form/use_workspace_form.ts
@@ -120,17 +120,36 @@ export const useWorkspaceForm = ({
return;
}
- onSubmit?.({
+ onSubmit?.(
+ {
+ name: currentFormData.name!,
+ description: currentFormData.description,
+ color: currentFormData.color || '#FFFFFF',
+ features: currentFormData.features,
+ permissionSettings: currentFormData.permissionSettings as WorkspacePermissionSetting[],
+ selectedDataSourceConnections: currentFormData.selectedDataSourceConnections,
+ },
+ true
+ );
+ },
+ [onSubmit, permissionEnabled]
+ );
+
+ const handleSubmitPermissionSettings = (settings: WorkspacePermissionSetting[]) => {
+ setPermissionSettings(settings);
+ const currentFormData = getFormDataRef.current();
+ onSubmit?.(
+ {
name: currentFormData.name!,
description: currentFormData.description,
color: currentFormData.color || '#FFFFFF',
features: currentFormData.features,
- permissionSettings: currentFormData.permissionSettings as WorkspacePermissionSetting[],
+ permissionSettings: settings,
selectedDataSourceConnections: currentFormData.selectedDataSourceConnections,
- });
- },
- [onSubmit, permissionEnabled]
- );
+ },
+ false
+ );
+ };
const handleColorChange = useCallback['onChange']>((text) => {
setColor(text);
@@ -165,5 +184,6 @@ export const useWorkspaceForm = ({
setPermissionSettings,
setSelectedDataSourceConnections,
onAppLeave,
+ handleSubmitPermissionSettings,
};
};
diff --git a/src/plugins/workspace/public/components/workspace_form/utils.test.ts b/src/plugins/workspace/public/components/workspace_form/utils.test.ts
index 9f2557ecbfa5..e387393c4a31 100644
--- a/src/plugins/workspace/public/components/workspace_form/utils.test.ts
+++ b/src/plugins/workspace/public/components/workspace_form/utils.test.ts
@@ -700,21 +700,21 @@ describe('isWorkspacePermissionSetting', () => {
describe('getPermissionModeName', () => {
it('should return Owner for a valid WorkspacePermissionMode mode', () => {
const result = getPermissionModeName(['library_write', 'write'] as WorkspacePermissionMode[]);
- expect(result).toBe('Owner');
+ expect(result).toBe('Admin');
});
it('should return Read & write for a valid WorkspacePermissionMode mode', () => {
const result = getPermissionModeName(['library_write', 'read'] as WorkspacePermissionMode[]);
- expect(result).toBe('Read & Write');
+ expect(result).toBe('Read and write');
});
it('should return Read for a valid WorkspacePermissionMode mode', () => {
const result = getPermissionModeName(['library_read', 'read'] as WorkspacePermissionMode[]);
- expect(result).toBe('Read');
+ expect(result).toBe('Read only');
});
it('should return Read for a invalid WorkspacePermissionMode mode', () => {
const result = getPermissionModeName([] as WorkspacePermissionMode[]);
- expect(result).toBe('Read');
+ expect(result).toBe('Read only');
});
});
diff --git a/src/plugins/workspace/public/components/workspace_form/utils.ts b/src/plugins/workspace/public/components/workspace_form/utils.ts
index 5bbc1125fbeb..a1fdb319e1aa 100644
--- a/src/plugins/workspace/public/components/workspace_form/utils.ts
+++ b/src/plugins/workspace/public/components/workspace_form/utils.ts
@@ -422,26 +422,7 @@ export const generatePermissionSettingsState = (
];
}
- const finalPermissionSettings = [...(permissionSettings ?? [])];
- const userPermissionExists = finalPermissionSettings.find(
- (setting) => setting.type === WorkspacePermissionItemType.User
- );
- const groupPermissionExists = finalPermissionSettings.find(
- (setting) => setting.type === WorkspacePermissionItemType.Group
- );
- if (!userPermissionExists) {
- finalPermissionSettings.push({
- ...emptyUserPermission,
- id: generateNextPermissionSettingsId(finalPermissionSettings),
- } as typeof finalPermissionSettings[0]);
- }
- if (!groupPermissionExists) {
- finalPermissionSettings.push({
- ...emptyUserGroupPermission,
- id: generateNextPermissionSettingsId(finalPermissionSettings),
- } as typeof finalPermissionSettings[0]);
- }
- return finalPermissionSettings;
+ return [...(permissionSettings ?? [])];
};
interface PermissionSettingLike
diff --git a/src/plugins/workspace/public/components/workspace_form/workspace_collaborator_table.test.tsx b/src/plugins/workspace/public/components/workspace_form/workspace_collaborator_table.test.tsx
new file mode 100644
index 000000000000..1b4e514e62c8
--- /dev/null
+++ b/src/plugins/workspace/public/components/workspace_form/workspace_collaborator_table.test.tsx
@@ -0,0 +1,146 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React from 'react';
+import { fireEvent, render } from '@testing-library/react';
+
+import { WorkspaceCollaboratorTable } from './workspace_collaborator_table';
+import { createOpenSearchDashboardsReactContext } from '../../../../opensearch_dashboards_react/public';
+import { coreMock } from '../../../../../core/public/mocks';
+
+const mockCoreStart = coreMock.createStart();
+
+const mockOverlays = {
+ openModal: jest.fn(),
+};
+
+const { Provider } = createOpenSearchDashboardsReactContext({
+ ...mockCoreStart,
+ overlays: mockOverlays,
+});
+
+describe('WorkspaceCollaboratorTable', () => {
+ const mockProps = {
+ displayedCollaboratorTypes: [],
+ permissionSettings: [
+ {
+ id: 0,
+ modes: ['library_write', 'write'],
+ type: 'user',
+ userId: 'admin',
+ },
+ {
+ id: 1,
+ modes: ['library_read', 'read'],
+ type: 'group',
+ group: 'group',
+ },
+ ],
+ handleSubmitPermissionSettings: jest.fn(),
+ };
+
+ it('should render normally', () => {
+ expect(render( )).toMatchSnapshot();
+ });
+
+ it('should render empty state when no permission settings', () => {
+ const permissionSettings = [];
+
+ const { getByText } = render(
+
+ );
+ expect(getByText('Your workspace doesn’t have any collaborators.')).toBeInTheDocument();
+ });
+
+ it('should render data on table based on permission settings', () => {
+ const { getByText } = render( );
+ expect(getByText('admin')).toBeInTheDocument();
+ expect(getByText('group')).toBeInTheDocument();
+ });
+
+ it('should openModal when clicking box actions menu', () => {
+ const permissionSettings = [
+ {
+ id: 0,
+ modes: ['library_write', 'write'],
+ type: 'user',
+ userId: 'admin',
+ },
+ ];
+
+ const { getByText, getByTestId } = render(
+
+
+
+ );
+ const action = getByTestId('workspace-detail-collaborator-table-actions-box');
+ fireEvent.click(action);
+ const deleteCollaborator = getByText('Delete collaborator');
+ fireEvent.click(deleteCollaborator);
+ expect(mockOverlays.openModal).toHaveBeenCalled();
+
+ const changeAccessLevel = getByText('Change access level');
+ fireEvent.click(changeAccessLevel);
+ expect(mockOverlays.openModal).toHaveBeenCalled();
+ });
+
+ it('should openModal when clicking multi selection delete', () => {
+ const permissionSettings = [
+ {
+ id: 0,
+ modes: ['library_write', 'write'],
+ type: 'user',
+ userId: 'admin',
+ },
+ {
+ id: 1,
+ modes: ['library_read', 'read'],
+ type: 'group',
+ group: 'group',
+ },
+ ];
+
+ const { getByText, getByTestId } = render(
+
+
+
+ );
+ fireEvent.click(getByTestId('checkboxSelectRow-0'));
+ fireEvent.click(getByTestId('checkboxSelectRow-1'));
+ const deleteCollaborator = getByText('Delete 2 collaborators');
+ fireEvent.click(deleteCollaborator);
+ expect(mockOverlays.openModal).toHaveBeenCalled();
+ });
+
+ it('should openModal when clicking action tools when multi selection', () => {
+ const permissionSettings = [
+ {
+ id: 0,
+ modes: ['library_write', 'write'],
+ type: 'user',
+ userId: 'admin',
+ },
+ {
+ id: 1,
+ modes: ['library_read', 'read'],
+ type: 'group',
+ group: 'group',
+ },
+ ];
+
+ const { getByText, getByTestId } = render(
+
+
+
+ );
+ fireEvent.click(getByTestId('checkboxSelectRow-0'));
+ fireEvent.click(getByTestId('checkboxSelectRow-1'));
+ const actions = getByTestId('workspace-detail-collaborator-table-actions');
+ fireEvent.click(actions);
+ const changeAccessLevel = getByText('Change access level');
+ fireEvent.click(changeAccessLevel);
+ expect(mockOverlays.openModal).toHaveBeenCalled();
+ });
+});
diff --git a/src/plugins/workspace/public/components/workspace_form/workspace_collaborator_table.tsx b/src/plugins/workspace/public/components/workspace_form/workspace_collaborator_table.tsx
new file mode 100644
index 000000000000..0b510cb1f597
--- /dev/null
+++ b/src/plugins/workspace/public/components/workspace_form/workspace_collaborator_table.tsx
@@ -0,0 +1,393 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React, { useMemo, useState } from 'react';
+import {
+ EuiSearchBarProps,
+ EuiBasicTableColumn,
+ EuiButtonIcon,
+ EuiConfirmModal,
+ EuiInMemoryTable,
+ EuiPopover,
+ EuiContextMenu,
+ EuiButton,
+ EuiTableSelectionType,
+ EuiEmptyPrompt,
+ EuiContextMenuPanelDescriptor,
+ EuiText,
+} from '@elastic/eui';
+import { i18n } from '@osd/i18n';
+import { WorkspacePermissionSetting } from './types';
+import { WorkspacePermissionItemType, permissionModeOptions, typeOptions } from './constants';
+import { getPermissionModeId } from './utils';
+import { useOpenSearchDashboards } from '../../../../opensearch_dashboards_react/public';
+import { AddCollaboratorButton } from './add_collaborator_button';
+import { WorkspaceCollaboratorType } from '../../services/workspace_collaborator_types_service';
+import {
+ WORKSPACE_ACCESS_LEVEL_NAMES,
+ accessLevelNameToWorkspacePermissionModesMap,
+} from '../../constants';
+import { WorkspaceCollaboratorAccessLevel } from '../../types';
+
+export type PermissionSetting = Pick &
+ Partial;
+
+interface Props {
+ permissionSettings: PermissionSetting[];
+ displayedCollaboratorTypes: WorkspaceCollaboratorType[];
+ handleSubmitPermissionSettings: (permissionSettings: WorkspacePermissionSetting[]) => void;
+}
+
+export const WorkspaceCollaboratorTable = ({
+ permissionSettings,
+ displayedCollaboratorTypes,
+ handleSubmitPermissionSettings,
+}: Props) => {
+ const [selection, setSelection] = useState([]);
+ const { overlays } = useOpenSearchDashboards();
+
+ const items = useMemo(() => {
+ return permissionSettings.map((setting) => {
+ const basicSettings = {
+ ...setting,
+ // This is used for table display and search match.
+ displayedType:
+ typeOptions.find((option) => option.value === setting.type)?.inputDisplay ?? '',
+ accessLevel:
+ permissionModeOptions.find(
+ (option) => option.value === getPermissionModeId(setting.modes ?? [])
+ )?.inputDisplay ?? '',
+ };
+ // Unique primary key and filter null value
+ if (setting.type === WorkspacePermissionItemType.User) {
+ return {
+ ...basicSettings,
+ // Id represents the index of the permission setting in the array, will use primaryId for displayed id
+ primaryId: setting.userId,
+ };
+ } else if (setting.type === WorkspacePermissionItemType.Group) {
+ return {
+ ...basicSettings,
+ primaryId: setting.group,
+ };
+ }
+ return basicSettings;
+ });
+ }, [permissionSettings]);
+
+ const emptyStateMessage = useMemo(() => {
+ return (
+
+ {i18n.translate('workspace.workspaceDetail.collaborator.emptyState.title', {
+ defaultMessage: 'Your workspace doesn’t have any collaborators.',
+ })}
+
+ }
+ titleSize="s"
+ body={i18n.translate('workspace.workspaceDetail.collaborator.emptyState.body', {
+ defaultMessage:
+ 'Currently you’re the only user who has access to the workspace as an owner. Share this workspace by adding collaborators.',
+ })}
+ actions={
+
+ }
+ />
+ );
+ }, [displayedCollaboratorTypes, permissionSettings, handleSubmitPermissionSettings]);
+
+ const openDeleteConfirmModal = ({ onConfirm }: { onConfirm: () => void }) => {
+ const modal = overlays.openModal(
+ modal.close()}
+ onConfirm={onConfirm}
+ cancelButtonText="Cancel"
+ confirmButtonText="Confirm"
+ >
+
+
+ {i18n.translate('workspace.detail.collaborator.delete.confirm', {
+ defaultMessage:
+ 'Delete collaborator? The collaborators will not have access to the workspace.',
+ })}
+
+
+
+ );
+ return modal;
+ };
+
+ const renderToolsLeft = () => {
+ if (selection.length === 0) {
+ return;
+ }
+
+ const onClick = () => {
+ const modal = openDeleteConfirmModal({
+ onConfirm: () => {
+ let newSettings = permissionSettings;
+ selection.forEach(({ id }) => {
+ newSettings = newSettings.filter((_item) => _item.id !== id);
+ });
+ handleSubmitPermissionSettings(newSettings as WorkspacePermissionSetting[]);
+ setSelection([]);
+ modal.close();
+ },
+ });
+ };
+
+ return (
+
+ {i18n.translate('workspace.detail.collaborator.delete', {
+ defaultMessage: 'Delete {num} collaborators',
+ values: {
+ num: selection.length,
+ },
+ })}
+
+ );
+ };
+
+ const renderToolsRight = () => {
+ if (selection.length === 0) {
+ return;
+ }
+ return (
+
+ );
+ };
+
+ const search: EuiSearchBarProps = {
+ box: {
+ incremental: true,
+ },
+ filters: [
+ {
+ type: 'field_value_selection',
+ field: 'displayedType',
+ name: 'Type',
+ multiSelect: false,
+ options: Array.from(new Set(items.map(({ displayedType }) => displayedType ?? ''))).map(
+ (item) => ({
+ value: item,
+ name: item,
+ })
+ ),
+ },
+ {
+ type: 'field_value_selection',
+ field: 'accessLevel',
+ name: 'Access level',
+ multiSelect: false,
+ options: Array.from(new Set(items.map(({ accessLevel }) => accessLevel ?? ''))).map(
+ (item) => ({
+ value: item,
+ name: item,
+ })
+ ),
+ },
+ ],
+ toolsLeft: renderToolsLeft(),
+ toolsRight: renderToolsRight(),
+ };
+
+ const columns: Array> = [
+ {
+ field: 'primaryId',
+ name: 'ID',
+ },
+ {
+ field: 'displayedType',
+ name: 'Type',
+ },
+ {
+ field: 'accessLevel',
+ name: 'Access level',
+ },
+ {
+ name: 'Actions',
+ field: '',
+ render: (item: PermissionSetting) => (
+
+ ),
+ },
+ ];
+ const selectionValue: EuiTableSelectionType = {
+ onSelectionChange: (newSelection) => setSelection(newSelection),
+ };
+
+ return (
+
+ );
+};
+
+const Actions = ({
+ isTableAction,
+ selection,
+ permissionSettings,
+ handleSubmitPermissionSettings,
+ openDeleteConfirmModal,
+}: {
+ isTableAction: boolean;
+ selection?: PermissionSetting[];
+ permissionSettings: PermissionSetting[];
+ handleSubmitPermissionSettings: (permissionSettings: WorkspacePermissionSetting[]) => void;
+ openDeleteConfirmModal?: ({ onConfirm }: { onConfirm: () => void }) => { close: () => void };
+}) => {
+ const [isPopoverOpen, setIsPopoverOpen] = useState(false);
+ const { overlays } = useOpenSearchDashboards();
+
+ const accessLevelOptions = (Object.keys(
+ WORKSPACE_ACCESS_LEVEL_NAMES
+ ) as WorkspaceCollaboratorAccessLevel[]).map((level) => ({
+ name: WORKSPACE_ACCESS_LEVEL_NAMES[level],
+ onClick: async () => {
+ setIsPopoverOpen(false);
+ if (selection) {
+ const modal = overlays.openModal(
+ modal.close()}
+ onConfirm={() => {
+ let newSettings = permissionSettings;
+ selection.forEach(({ id }) => {
+ newSettings = newSettings.map((item) =>
+ id === item.id
+ ? {
+ ...item,
+ modes: accessLevelNameToWorkspacePermissionModesMap[level],
+ }
+ : item
+ );
+ });
+ handleSubmitPermissionSettings(newSettings as WorkspacePermissionSetting[]);
+ modal.close();
+ }}
+ cancelButtonText="Cancel"
+ confirmButtonText="Confirm"
+ >
+
+
+ {i18n.translate('workspace.detail.collaborator.changeAccessLevel.confirmation', {
+ defaultMessage:
+ 'Do you want to change access level to {numCollaborators} collaborator{pluralSuffix} to "{accessLevel}"?',
+ values: {
+ numCollaborators: selection.length,
+ pluralSuffix: selection.length > 1 ? 's' : '',
+ accessLevel: WORKSPACE_ACCESS_LEVEL_NAMES[level],
+ },
+ })}
+
+
+
+ );
+ }
+ },
+ icon: '',
+ }));
+
+ const panelItems = ([
+ {
+ id: 0,
+ items: [
+ {
+ name: i18n.translate('workspace.detail.collaborator.actions.change.access', {
+ defaultMessage: 'Change access level',
+ }),
+ panel: 1,
+ },
+ isTableAction && {
+ name: i18n.translate('workspace.detail.collaborator.actions.delete', {
+ defaultMessage: 'Delete collaborator',
+ }),
+ onClick: () => {
+ setIsPopoverOpen(false);
+ if (selection && openDeleteConfirmModal) {
+ const modal = openDeleteConfirmModal({
+ onConfirm: () => {
+ let newSettings = permissionSettings;
+ selection.forEach(({ id }) => {
+ newSettings = newSettings.filter((_item) => _item.id !== id);
+ });
+ handleSubmitPermissionSettings(newSettings as WorkspacePermissionSetting[]);
+ modal.close();
+ },
+ });
+ }
+ },
+ },
+ ].filter(Boolean),
+ },
+ {
+ id: 1,
+ title: i18n.translate('workspace.detail.collaborator.actions.change.access', {
+ defaultMessage: 'Change access level',
+ }),
+ items: accessLevelOptions,
+ },
+ ] as unknown) as EuiContextMenuPanelDescriptor[];
+
+ const button = isTableAction ? (
+ setIsPopoverOpen(true)}
+ data-test-subj="workspace-detail-collaborator-table-actions-box"
+ />
+ ) : (
+ setIsPopoverOpen(true)}
+ data-test-subj="workspace-detail-collaborator-table-actions"
+ >
+ {i18n.translate('workspace.detail.collaborator.actions.', {
+ defaultMessage: 'Actions',
+ })}
+
+ );
+ return (
+ setIsPopoverOpen(false)}
+ panelPaddingSize="none"
+ anchorPosition="downLeft"
+ ownFocus={false}
+ >
+
+
+ );
+};
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 c6e453c6714a..1466ef3bae66 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,7 @@
* SPDX-License-Identifier: Apache-2.0
*/
-import React, { useRef } from 'react';
+import React from 'react';
import {
EuiSpacer,
EuiForm,
@@ -17,38 +17,16 @@ import {
} from '@elastic/eui';
import { i18n } from '@osd/i18n';
+import { useObservable } from 'react-use';
import { WorkspaceFormProps } from './types';
-import { WorkspacePermissionSettingPanel } from './workspace_permission_setting_panel';
-import { DetailTab, usersAndPermissionsTitle } from './constants';
+import { DetailTab } from './constants';
import { WorkspaceFormErrorCallout } from './workspace_form_error_callout';
import { useWorkspaceFormContext } from './workspace_form_context';
import { WorkspaceDetailFormDetails } from './workspace_detail_form_details';
-
-interface FormGroupProps {
- title: React.ReactNode;
- children: React.ReactNode;
- describe?: string;
-}
-
-const FormGroup = ({ title, children, describe }: FormGroupProps) => (
- <>
-
-
-
- {title}
-
-
- {describe}
-
-
-
-
- {children}
-
-
-
- >
-);
+import { WorkspaceCollaboratorTable } from './workspace_collaborator_table';
+import { WorkspaceCollaboratorTypesService } from '../../services/workspace_collaborator_types_service';
+import { AddCollaboratorButton } from './add_collaborator_button';
+import { useOpenSearchDashboards } from '../../../../opensearch_dashboards_react/public';
interface WorkspaceDetailedFormProps extends Omit {
detailTab?: DetailTab;
@@ -56,7 +34,7 @@ interface WorkspaceDetailedFormProps extends Omit {
- const { detailTab, detailTitle, defaultValues, availableUseCases } = props;
+ const { detailTab, detailTitle, availableUseCases } = props;
const {
formId,
formData,
@@ -66,11 +44,14 @@ export const WorkspaceDetailForm = (props: WorkspaceDetailedFormProps) => {
numberOfErrors,
handleResetForm,
handleFormSubmit,
- setPermissionSettings,
+ handleSubmitPermissionSettings,
} = useWorkspaceFormContext();
- const disabledUserOrGroupInputIdsRef = useRef(
- defaultValues?.permissionSettings?.map((item) => item.id) ?? []
- );
+
+ const {
+ services: { collaboratorTypes },
+ } = useOpenSearchDashboards<{ collaboratorTypes: WorkspaceCollaboratorTypesService }>();
+
+ const displayedCollaboratorTypes = useObservable(collaboratorTypes.getTypes$()) ?? [];
return (
{
- {isEditing ? (
+ {detailTab === DetailTab.Collaborators ? (
+
+ ) : isEditing ? (
{
)}
-
+
+ {i18n.translate('workspace.detail.collaborator.description', {
+ defaultMessage: 'Manage workspace access and permissions.',
+ })}
+
+ {detailTab === DetailTab.Collaborators ? (
+
+ ) : (
+
+ )}
{numberOfErrors > 0 && (
<>
@@ -120,21 +116,11 @@ export const WorkspaceDetailForm = (props: WorkspaceDetailedFormProps) => {
)}
{detailTab === DetailTab.Collaborators && (
-
-
-
+
)}
diff --git a/src/plugins/workspace/public/components/workspace_form/workspace_form_context.tsx b/src/plugins/workspace/public/components/workspace_form/workspace_form_context.tsx
index e9403cfd7e15..0ec3bffebc77 100644
--- a/src/plugins/workspace/public/components/workspace_form/workspace_form_context.tsx
+++ b/src/plugins/workspace/public/components/workspace_form/workspace_form_context.tsx
@@ -10,6 +10,7 @@ import { WorkspaceFormProps, WorkspaceFormErrors } from './types';
import { AppMountParameters, PublicAppInfo } from '../../../../../core/public';
import { useWorkspaceForm } from './use_workspace_form';
import { WorkspaceFormDataState } from '../workspace_form';
+import { WorkspacePermissionSetting } from './types';
interface WorkspaceFormContextProps {
formId: string;
@@ -31,6 +32,7 @@ interface WorkspaceFormContextProps {
>;
setSelectedDataSourceConnections: React.Dispatch>;
onAppLeave: AppMountParameters['onAppLeave'];
+ handleSubmitPermissionSettings: (permissionSettings: WorkspacePermissionSetting[]) => void;
}
const initialContextValue: WorkspaceFormContextProps = {} as WorkspaceFormContextProps;
diff --git a/src/plugins/workspace/public/components/workspace_form/workspace_permission_setting_input.test.tsx b/src/plugins/workspace/public/components/workspace_form/workspace_permission_setting_input.test.tsx
index 72d0415f5984..ed2168330f6e 100644
--- a/src/plugins/workspace/public/components/workspace_form/workspace_permission_setting_input.test.tsx
+++ b/src/plugins/workspace/public/components/workspace_form/workspace_permission_setting_input.test.tsx
@@ -76,7 +76,7 @@ describe('WorkspacePermissionSettingInput', () => {
});
expect(renderResult.getByDisplayValue('foo')).toBeInTheDocument();
- expect(renderResult.getByText('Read')).toBeInTheDocument();
+ expect(renderResult.getByText('Read only')).toBeInTheDocument();
});
it('should render consistent group id and permission modes', () => {
const { renderResult } = setup({
@@ -86,7 +86,7 @@ describe('WorkspacePermissionSettingInput', () => {
});
expect(renderResult.getByDisplayValue('bar')).toBeInTheDocument();
- expect(renderResult.getByText('Read & Write')).toBeInTheDocument();
+ expect(renderResult.getByText('Read and write')).toBeInTheDocument();
});
it('should call onGroupOrUserIdChange with user id', () => {
const { renderResult, onGroupOrUserIdChangeMock } = setup();
@@ -116,7 +116,7 @@ describe('WorkspacePermissionSettingInput', () => {
expect(onPermissionModesChangeMock).not.toHaveBeenCalled();
fireEvent.click(renderResult.getAllByTestId('workspace-permissionModeOptions')[0]);
- fireEvent.click(renderResult.getByText('Owner'));
+ fireEvent.click(renderResult.getByText('Admin'));
expect(onPermissionModesChangeMock).toHaveBeenCalledWith(['library_write', 'write'], 0);
});
@@ -133,7 +133,7 @@ describe('WorkspacePermissionSettingInput', () => {
expect(onTypeChangeMock).not.toHaveBeenCalled();
fireEvent.click(renderResult.getByTestId('workspace-typeOptions'));
- fireEvent.click(renderResult.getByText('User Group'));
+ fireEvent.click(renderResult.getByText('Group'));
expect(onTypeChangeMock).toHaveBeenCalledWith('group', 0);
});
});
diff --git a/src/plugins/workspace/public/components/workspace_form/workspace_permission_setting_input.tsx b/src/plugins/workspace/public/components/workspace_form/workspace_permission_setting_input.tsx
index 49421c22179e..4da620841398 100644
--- a/src/plugins/workspace/public/components/workspace_form/workspace_permission_setting_input.tsx
+++ b/src/plugins/workspace/public/components/workspace_form/workspace_permission_setting_input.tsx
@@ -20,24 +20,10 @@ import {
PERMISSION_COLLABORATOR_LABEL_ID,
PERMISSION_ACCESS_LEVEL_LABEL_ID,
permissionModeOptions,
+ typeOptions,
} from './constants';
import { getPermissionModeId } from './utils';
-const typeOptions = [
- {
- value: WorkspacePermissionItemType.User,
- inputDisplay: i18n.translate('workspace.form.permissionSettingPanel.typeOptions.user', {
- defaultMessage: 'User',
- }),
- },
- {
- value: WorkspacePermissionItemType.Group,
- inputDisplay: i18n.translate('workspace.form.permissionSettingPanel.typeOptions.group', {
- defaultMessage: 'User Group',
- }),
- },
-];
-
export interface WorkspacePermissionSettingInputProps {
index: number;
type: WorkspacePermissionItemType;
diff --git a/src/plugins/workspace/public/components/workspace_form/workspace_permission_setting_panel.test.tsx b/src/plugins/workspace/public/components/workspace_form/workspace_permission_setting_panel.test.tsx
index 2bf0903361c0..24b2ec5b4e2e 100644
--- a/src/plugins/workspace/public/components/workspace_form/workspace_permission_setting_panel.test.tsx
+++ b/src/plugins/workspace/public/components/workspace_form/workspace_permission_setting_panel.test.tsx
@@ -77,10 +77,10 @@ describe('WorkspacePermissionSettingInput', () => {
const { renderResult } = setup();
expect(renderResult.getByDisplayValue('foo')).toBeInTheDocument();
- expect(renderResult.getByText('Read')).toBeInTheDocument();
+ expect(renderResult.getByText('Read only')).toBeInTheDocument();
expect(renderResult.getByDisplayValue('bar')).toBeInTheDocument();
- expect(renderResult.getByText('Read & Write')).toBeInTheDocument();
+ expect(renderResult.getByText('Read and write')).toBeInTheDocument();
});
it('should call onChange with new user permission modes', () => {
@@ -88,7 +88,7 @@ describe('WorkspacePermissionSettingInput', () => {
expect(onChangeMock).not.toHaveBeenCalled();
fireEvent.click(renderResult.getAllByTestId('workspace-permissionModeOptions')[0]);
- fireEvent.click(renderResult.getAllByText('Read & Write')[1]);
+ fireEvent.click(renderResult.getAllByText('Read and write')[1]);
expect(onChangeMock).toHaveBeenCalledWith([
{
id: 0,
@@ -110,7 +110,7 @@ describe('WorkspacePermissionSettingInput', () => {
expect(onChangeMock).not.toHaveBeenCalled();
fireEvent.click(renderResult.getAllByTestId('workspace-permissionModeOptions')[1]);
- fireEvent.click(renderResult.getByText('Owner'));
+ fireEvent.click(renderResult.getByText('Admin'));
expect(onChangeMock).toHaveBeenCalledWith([
{
id: 0,
diff --git a/src/plugins/workspace/public/constants.ts b/src/plugins/workspace/public/constants.ts
index e81ac8ddf20c..2eb7f9bbfde2 100644
--- a/src/plugins/workspace/public/constants.ts
+++ b/src/plugins/workspace/public/constants.ts
@@ -6,6 +6,7 @@
import { i18n } from '@osd/i18n';
import { WorkspaceCollaboratorAccessLevel } from './types';
+import { WorkspacePermissionMode } from '../common/constants';
export const WORKSPACE_ACCESS_LEVEL_NAMES: { [key in WorkspaceCollaboratorAccessLevel]: string } = {
readOnly: i18n.translate('workspace.accessLevel.readOnlyName', {
@@ -18,3 +19,11 @@ export const WORKSPACE_ACCESS_LEVEL_NAMES: { [key in WorkspaceCollaboratorAccess
defaultMessage: 'Admin',
}),
};
+
+export const accessLevelNameToWorkspacePermissionModesMap: {
+ [key in WorkspaceCollaboratorAccessLevel]: WorkspacePermissionMode[];
+} = {
+ readOnly: [WorkspacePermissionMode.LibraryRead, WorkspacePermissionMode.Read],
+ readAndWrite: [WorkspacePermissionMode.LibraryWrite, WorkspacePermissionMode.Read],
+ admin: [WorkspacePermissionMode.LibraryWrite, WorkspacePermissionMode.Write],
+};