Skip to content

Commit

Permalink
Merge branch 'workspace' into feature/move-utils
Browse files Browse the repository at this point in the history
  • Loading branch information
SuZhou-Joe authored Oct 12, 2023
2 parents cfbe94d + e36a7b6 commit 20a64a5
Show file tree
Hide file tree
Showing 13 changed files with 147 additions and 26 deletions.
2 changes: 1 addition & 1 deletion src/core/public/workspace/workspaces_service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { isEqual } from 'lodash';

import { CoreService, WorkspaceAttribute } from '../../types';

type WorkspaceObject = WorkspaceAttribute & { readonly?: boolean };
type WorkspaceObject = WorkspaceAttribute & { libraryReadonly?: boolean };

interface WorkspaceObservables {
/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ const TopNav = ({
currentAppState?.viewMode,
navActions,
dashboardConfig.getHideWriteControls(),
services.workspaces.workspaceEnabled$.value
services.application.capabilities.workspaces.enabled
)
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ export const getNavActions = (
currentContainer?: DashboardContainer
) => {
const {
application,
embeddable,
data: { query: queryService },
notifications,
Expand All @@ -77,7 +78,7 @@ export const getNavActions = (
const navActions: {
[key: string]: NavAction;
} = {};
const workspaceEnabled = workspaces.workspaceEnabled$.value;
const workspaceEnabled = application.capabilities.workspaces.enabled;

if (!stateContainer) {
return navActions;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ import { PageWrapper } from './page_wrapper';
import { StartDependencies, SavedObjectsManagementPluginStart } from '../plugin';
import { ISavedObjectsManagementServiceRegistry } from '../services';
import { getAllowedTypes } from './../lib';
import { WORKSPACE_TYPE } from '../../../../core/public';

interface MountParams {
core: CoreSetup<StartDependencies, SavedObjectsManagementPluginStart>;
Expand Down

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 @@ -135,6 +135,9 @@ describe('SavedObjectsTable', () => {
edit: false,
delete: false,
},
workspaces: {
enabled: false,
},
};

http.post.mockResolvedValue([]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ export class SavedObjectsTable extends Component<SavedObjectsTableProps, SavedOb
isIncludeReferencesDeepChecked: true,
currentWorkspaceId: this.props.workspaces.currentWorkspaceId$.getValue(),
availableWorkspaces: this.props.workspaces.workspaceList$.getValue(),
workspaceEnabled: this.props.workspaces.workspaceEnabled$.getValue(),
workspaceEnabled: this.props.applications.capabilities.workspaces.enabled,
};
}

Expand Down Expand Up @@ -326,10 +326,6 @@ export class SavedObjectsTable extends Component<SavedObjectsTableProps, SavedOb
this.workspacesSubscription = workspace.workspaceList$.subscribe((workspaceList) => {
this.setState({ availableWorkspaces: workspaceList });
});

this.workspacesEnabledSubscription = workspace.workspaceEnabled$.subscribe((enabled) => {
this.setState({ workspaceEnabled: enabled });
});
};

fetchSavedObject = (type: string, id: string) => {
Expand Down
63 changes: 58 additions & 5 deletions src/plugins/saved_objects_management/public/plugin.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,23 @@
* under the License.
*/

const mountManagementSectionMock = jest.fn();
jest.doMock('./management_section', () => ({
mountManagementSection: mountManagementSectionMock,
}));
import { waitFor } from '@testing-library/dom';
import { coreMock } from '../../../core/public/mocks';
import { homePluginMock } from '../../home/public/mocks';
import { managementPluginMock } from '../../management/public/mocks';
import { dataPluginMock } from '../../data/public/mocks';
import { uiActionsPluginMock } from '../../ui_actions/public/mocks';
import { SavedObjectsManagementPlugin } from './plugin';
import {
MANAGE_LIBRARY_TITLE_WORDINGS,
SAVED_QUERIES_WORDINGS,
SAVED_SEARCHES_WORDINGS,
} from './constants';
import { DEFAULT_APP_CATEGORIES } from '../../../core/public';

describe('SavedObjectsManagementPlugin', () => {
let plugin: SavedObjectsManagementPlugin;
Expand All @@ -50,19 +61,61 @@ describe('SavedObjectsManagementPlugin', () => {
const homeSetup = homePluginMock.createSetupContract();
const managementSetup = managementPluginMock.createSetupContract();
const uiActionsSetup = uiActionsPluginMock.createSetupContract();
const registerMock = jest.fn((params) => params.mount({} as any, {} as any));

await plugin.setup(coreSetup, {
home: homeSetup,
management: managementSetup,
uiActions: uiActionsSetup,
});
await plugin.setup(
{
...coreSetup,
application: {
...coreSetup.application,
register: registerMock,
},
},
{
home: homeSetup,
management: managementSetup,
uiActions: uiActionsSetup,
}
);

expect(homeSetup.featureCatalogue.register).toHaveBeenCalledTimes(1);
expect(homeSetup.featureCatalogue.register).toHaveBeenCalledWith(
expect.objectContaining({
id: 'saved_objects',
})
);
expect(registerMock).toBeCalledWith(
expect.objectContaining({
id: 'objects',
title: MANAGE_LIBRARY_TITLE_WORDINGS,
order: 10000,
category: DEFAULT_APP_CATEGORIES.opensearchDashboards,
})
);
expect(registerMock).toBeCalledWith(
expect.objectContaining({
id: 'objects_searches',
title: SAVED_SEARCHES_WORDINGS,
order: 8000,
category: DEFAULT_APP_CATEGORIES.opensearchDashboards,
})
);
expect(registerMock).toBeCalledWith(
expect.objectContaining({
id: 'objects_query',
title: SAVED_QUERIES_WORDINGS,
order: 8001,
category: DEFAULT_APP_CATEGORIES.opensearchDashboards,
})
);
waitFor(
() => {
expect(mountManagementSectionMock).toBeCalledTimes(3);
},
{
container: document.body,
}
);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ export const getTopNavConfig = (
workspaces,
}: VisualizeServices
) => {
const workspaceEnabled = workspaces.workspaceEnabled$.value;
const workspaceEnabled = application.capabilities.workspaces.enabled;
const { vis, embeddableHandler } = visInstance;
const savedVis = 'savedVis' in visInstance ? visInstance.savedVis : undefined;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export function DeleteWorkspaceModal(props: DeleteWorkspaceModalProps) {
</ul>
<EuiSpacer />
<EuiText color="subdued">
To confirm your action, type <b style={{ color: '#000' }}>delete</b>.
To confirm your action, type <b>delete</b>.
</EuiText>
<EuiFieldText
placeholder="delete"
Expand Down
2 changes: 2 additions & 0 deletions src/plugins/workspace/server/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@ export class WorkspacePlugin implements Plugin<{}, {}> {
new SavedObjectsClient(repositoryFactory.createInternalRepository())
);

core.capabilities.registerProvider(() => ({ workspaces: { enabled: true } }));

return {
client: this.client,
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,20 @@ describe('WorkspaceSavedObjectsClientWrapper', () => {

expect(SavedObjectsErrorHelpers.isForbiddenError(error)).toBe(true);
});

it('should able to create with override', async () => {
const createResult = await permittedSavedObjectedClient.create(
'dashboard',
{},
{
id: 'inner-workspace-dashboard-1',
overwrite: true,
workspaces: ['workspace-1'],
}
);

expect(createResult.error).toBeUndefined();
});
});

describe('bulkCreate', () => {
Expand Down Expand Up @@ -312,6 +326,47 @@ describe('WorkspaceSavedObjectsClientWrapper', () => {
expect(result.saved_objects.length).toEqual(1);
await permittedSavedObjectedClient.delete('dashboard', objectId);
});

it('should throw forbidden error when create with override', async () => {
let error;
try {
await notPermittedSavedObjectedClient.bulkCreate(
[
{
id: 'inner-workspace-dashboard-1',
type: 'dashboard',
attributes: {},
},
],
{
overwrite: true,
workspaces: ['workspace-1'],
}
);
} catch (e) {
error = e;
}

expect(SavedObjectsErrorHelpers.isForbiddenError(error)).toBe(true);
});

it('should able to bulk create with override', async () => {
const createResult = await permittedSavedObjectedClient.bulkCreate(
[
{
id: 'inner-workspace-dashboard-1',
type: 'dashboard',
attributes: {},
},
],
{
overwrite: true,
workspaces: ['workspace-1'],
}
);

expect(createResult.saved_objects).toHaveLength(1);
});
});

describe('update', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,14 @@ export class WorkspaceSavedObjectsClientWrapper {
throw generateSavedObjectsPermissionError();
}

if (options.overwrite) {
/**
*
* If target workspaces parameter exists, we don't need to do permission validation again.
* The bulk create method in repository doesn't allow extends workspaces with override.
* If target workspaces parameter doesn't exists, we need to check if has permission to object's workspaces or ACL.
*
*/
if (!hasTargetWorkspaces && options.overwrite) {
for (const object of objects) {
const { type, id } = object;
if (id) {
Expand All @@ -274,10 +281,7 @@ export class WorkspaceSavedObjectsClientWrapper {
!(await this.validateWorkspacesAndSavedObjectsPermissions(
rawObject,
wrapperOptions.request,
!hasTargetWorkspaces
? // If no workspaces are passed, we need to check the workspace permission of object when overwrite.
[WorkspacePermissionMode.LibraryWrite]
: [],
[WorkspacePermissionMode.LibraryWrite],
[WorkspacePermissionMode.Write],
false
))
Expand All @@ -301,24 +305,29 @@ export class WorkspaceSavedObjectsClientWrapper {
if (
hasTargetWorkspaces &&
!(await this.validateMultiWorkspacesPermissions(
options.workspaces ?? [],
options?.workspaces ?? [],
wrapperOptions.request,
[WorkspacePermissionMode.LibraryWrite]
))
) {
throw generateWorkspacePermissionError();
}

/**
*
* If target workspaces parameter exists, we don't need to do permission validation again.
* The create method in repository doesn't allow extends workspaces with override.
* If target workspaces parameter doesn't exists, we need to check if has permission to object's workspaces or ACL.
*
*/
if (
options?.overwrite &&
options.id &&
!hasTargetWorkspaces &&
!(await this.validateWorkspacesAndSavedObjectsPermissions(
await wrapperOptions.client.get(type, options.id),
wrapperOptions.request,
!hasTargetWorkspaces
? // If no workspaces are passed, we need to check the workspace permission of object when overwrite.
[WorkspacePermissionMode.LibraryWrite]
: [],
[WorkspacePermissionMode.LibraryWrite],
[WorkspacePermissionMode.Write],
false
))
Expand Down

0 comments on commit 20a64a5

Please sign in to comment.