Skip to content

Commit

Permalink
[Workspace] Add Workspace filter to saved objects management page (op…
Browse files Browse the repository at this point in the history
…ensearch-project#6458)

* Add workspace filter into saved objects page (opensearch-project#211)

* Add workspace column/filter into saved objects page

Signed-off-by: Hailong Cui <ihailong@amazon.com>

fix failed test case

Signed-off-by: Hailong Cui <ihailong@amazon.com>

move workspace column to its own folder

Signed-off-by: Hailong Cui <ihailong@amazon.com>

* default workspace

Signed-off-by: Hailong Cui <ihailong@amazon.com>

fix test case

Signed-off-by: Hailong Cui <ihailong@amazon.com>

add test case

Signed-off-by: Hailong Cui <ihailong@amazon.com>

remove hide import

Signed-off-by: Hailong Cui <ihailong@amazon.com>

* address review comments

Signed-off-by: Hailong Cui <ihailong@amazon.com>

---------

Signed-off-by: Hailong Cui <ihailong@amazon.com>

* replace default workspace with public workspace (opensearch-project#322)

Signed-off-by: Hailong Cui <ihailong@amazon.com>

* Add workspace filter

Signed-off-by: Hailong Cui <ihailong@amazon.com>

* revert query params change

Signed-off-by: Hailong Cui <ihailong@amazon.com>

* udpate test case name to more clear

Signed-off-by: Hailong Cui <ihailong@amazon.com>

* support public workspace

Signed-off-by: Hailong Cui <ihailong@amazon.com>

* Add changelog

Signed-off-by: Hailong Cui <ihailong@amazon.com>

* update fetchExportByTypeAndSearch parameter

Co-authored-by: SuZhou-Joe <suzhou@amazon.com>
Signed-off-by: Hailong Cui <ihailong@amazon.com>

* remove virtrual public workspace

Signed-off-by: Hailong Cui <ihailong@amazon.com>

* update comments

Signed-off-by: Hailong Cui <ihailong@amazon.com>

* fix public workspace query when permission is not enabled

Signed-off-by: Hailong Cui <ihailong@amazon.com>

* home dashboards/listing page only show public workspace data

Signed-off-by: Hailong Cui <ihailong@amazon.com>

* Add more test case

Signed-off-by: Hailong Cui <ihailong@amazon.com>

---------

Signed-off-by: Hailong Cui <ihailong@amazon.com>
Signed-off-by: SuZhou-Joe <suzhou@amazon.com>
Co-authored-by: SuZhou-Joe <suzhou@amazon.com>
  • Loading branch information
Hailong-am and SuZhou-Joe committed Apr 18, 2024
1 parent d5bda77 commit 1f9b23c
Show file tree
Hide file tree
Showing 14 changed files with 8,437 additions and 163 deletions.
15 changes: 7 additions & 8 deletions src/core/public/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,13 @@ export type { Logos } from '../common';
export { PackageInfo, EnvironmentMode } from '../server/types';
/** @interal */
export { CoreContext, CoreSystem } from './core_system';
export { DEFAULT_APP_CATEGORIES } from '../utils';
export {
DEFAULT_APP_CATEGORIES,
WORKSPACE_TYPE,
cleanWorkspaceId,
PUBLIC_WORKSPACE_ID,
PUBLIC_WORKSPACE_NAME,
} from '../utils';
export {
AppCategory,
UiSettingsParams,
Expand Down Expand Up @@ -355,11 +361,4 @@ export { __osdBootstrap__ } from './osd_bootstrap';

export { WorkspacesStart, WorkspacesSetup, WorkspacesService } from './workspace';

export {
WORKSPACE_TYPE,
cleanWorkspaceId,
PUBLIC_WORKSPACE_ID,
PUBLIC_WORKSPACE_NAME,
} from '../utils';

export { debounce } from './utils';
4 changes: 2 additions & 2 deletions src/core/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,10 @@ export {
IContextProvider,
} from './context';
export { DEFAULT_APP_CATEGORIES } from './default_app_categories';
export { getWorkspaceIdFromUrl, formatUrlWithWorkspaceId, cleanWorkspaceId } from './workspace';
export {
WORKSPACE_PATH_PREFIX,
WORKSPACE_TYPE,
PUBLIC_WORKSPACE_ID,
PUBLIC_WORKSPACE_NAME,
WORKSPACE_TYPE,
} from './constants';
export { getWorkspaceIdFromUrl, formatUrlWithWorkspaceId, cleanWorkspaceId } from './workspace';

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -28,21 +28,24 @@
* under the License.
*/

import { HttpStart } from 'src/core/public';
import { HttpStart, SavedObjectsBaseOptions } from 'src/core/public';
import { formatWorkspaceIdParams } from '../utils';

export async function fetchExportByTypeAndSearch(
http: HttpStart,
types: string[],
search: string | undefined,
includeReferencesDeep: boolean = false,
body?: Record<string, unknown>
workspaces: SavedObjectsBaseOptions['workspaces']
): Promise<Blob> {
return http.post('/api/saved_objects/_export', {
body: JSON.stringify({
...body,
type: types,
search,
includeReferencesDeep,
}),
body: JSON.stringify(
formatWorkspaceIdParams({
workspaces,
type: types,
search,
includeReferencesDeep,
})
),
});
}

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 @@ -65,7 +65,7 @@ import {
import { Flyout, Relationships } from './components';
import { SavedObjectWithMetadata } from '../../types';
import { WorkspaceObject } from 'opensearch-dashboards/public';
import { PUBLIC_WORKSPACE_ID } from '../../../../../core/public';
import { PUBLIC_WORKSPACE_NAME, PUBLIC_WORKSPACE_ID } from '../../../../../core/public';
import { TableProps } from './components/table';

const allowedTypes = ['index-pattern', 'visualization', 'dashboard', 'search'];
Expand Down Expand Up @@ -140,9 +140,7 @@ describe('SavedObjectsTable', () => {
edit: false,
delete: false,
},
workspaces: {
enabled: false,
},
workspaces: {},
};

http.post.mockResolvedValue([]);
Expand Down Expand Up @@ -392,7 +390,7 @@ describe('SavedObjectsTable', () => {
allowedTypes,
undefined,
true,
{}
undefined
);
expect(saveAsMock).toHaveBeenCalledWith(blob, 'export.ndjson');
expect(notifications.toasts.addSuccess).toHaveBeenCalledWith({
Expand Down Expand Up @@ -423,76 +421,43 @@ describe('SavedObjectsTable', () => {
allowedTypes,
'test*',
true,
{}
undefined
);
expect(saveAsMock).toHaveBeenCalledWith(blob, 'export.ndjson');
expect(notifications.toasts.addSuccess).toHaveBeenCalledWith({
title: 'Your file is downloading in the background',
});
});

it('should make modules call with workspace', async () => {
getSavedObjectCountsMock.mockClear();
findObjectsMock.mockClear();
// @ts-expect-error
defaultProps.applications.capabilities.workspaces.enabled = true;
const mockSelectedSavedObjects = [
{ id: '1', type: 'index-pattern' },
{ id: '3', type: 'dashboard' },
] as SavedObjectWithMetadata[];

const mockSavedObjects = mockSelectedSavedObjects.map((obj) => ({
_id: obj.id,
_type: obj.type,
_source: {},
}));

const mockSavedObjectsClient = {
...defaultProps.savedObjectsClient,
bulkGet: jest.fn().mockImplementation(() => ({
savedObjects: mockSavedObjects,
})),
};

const workspacesStart = workspacesServiceMock.createStartContract();
workspacesStart.currentWorkspaceId$.next('foo');
it('should export all, accounting for the current workspace criteria', async () => {
const component = shallowRender();

const component = shallowRender({
savedObjectsClient: mockSavedObjectsClient,
workspaces: workspacesStart,
component.instance().onQueryChange({
query: Query.parse(`test workspaces:("${PUBLIC_WORKSPACE_NAME}")`),
});

// Ensure all promises resolve
await new Promise((resolve) => process.nextTick(resolve));
// Ensure the state changes are reflected
component.update();

// Set some as selected
component.instance().onSelectionChanged(mockSelectedSavedObjects);
// Set up mocks
const blob = new Blob([JSON.stringify(allSavedObjects)], { type: 'application/ndjson' });
fetchExportByTypeAndSearchMock.mockImplementation(() => blob);

await component.instance().onExport(true);
await component.instance().onExportAll();

expect(fetchExportObjectsMock).toHaveBeenCalledWith(http, mockSelectedSavedObjects, true, {
workspaces: ['foo'],
});
expect(fetchExportByTypeAndSearchMock).toHaveBeenCalledWith(
http,
['index-pattern', 'visualization', 'dashboard', 'search'],
undefined,
allowedTypes,
'test*',
true,
{
workspaces: ['foo'],
}
);
expect(
getSavedObjectCountsMock.mock.calls.every((item) => item[1].workspaces[0] === 'foo')
).toEqual(true);
expect(findObjectsMock.mock.calls.every((item) => item[1].workspaces[0] === 'foo')).toEqual(
true
[PUBLIC_WORKSPACE_ID]
);
// @ts-expect-error
defaultProps.applications.capabilities.workspaces.enabled = false;
expect(saveAsMock).toHaveBeenCalledWith(blob, 'export.ndjson');
expect(notifications.toasts.addSuccess).toHaveBeenCalledWith({
title: 'Your file is downloading in the background',
});
});
});

Expand Down Expand Up @@ -668,7 +633,7 @@ describe('SavedObjectsTable', () => {
});

describe('workspace filter', () => {
it('show workspace filter when workspace turn on and not in any workspace', async () => {
it('workspace filter include all visible workspaces when not in any workspace', async () => {
const applications = applicationServiceMock.createStartContract();
applications.capabilities = {
navLinks: {},
Expand Down Expand Up @@ -713,10 +678,10 @@ describe('SavedObjectsTable', () => {
expect(filters[1].options.length).toBe(3);
expect(filters[1].options[0].value).toBe('foo');
expect(filters[1].options[1].value).toBe('bar');
expect(filters[1].options[2].value).toBe(PUBLIC_WORKSPACE_ID);
expect(filters[1].options[2].value).toBe(PUBLIC_WORKSPACE_NAME);
});

it('show workspace filter when workspace turn on and enter a workspace', async () => {
it('workspace filter only include current workspaces when in a workspace', async () => {
const applications = applicationServiceMock.createStartContract();
applications.capabilities = {
navLinks: {},
Expand Down Expand Up @@ -761,7 +726,7 @@ describe('SavedObjectsTable', () => {
expect(wsFilter[0].options[0].value).toBe('foo');
});

it('workspace exists in find options when workspace on', async () => {
it('current workspace in find options when workspace on', async () => {
findObjectsMock.mockClear();
const applications = applicationServiceMock.createStartContract();
applications.capabilities = {
Expand Down Expand Up @@ -809,7 +774,7 @@ describe('SavedObjectsTable', () => {
});
});

it('workspace exists in find options when workspace on and not in any workspace', async () => {
it('all visible workspaces in find options when not in any workspace', async () => {
findObjectsMock.mockClear();
const applications = applicationServiceMock.createStartContract();
applications.capabilities = {
Expand Down Expand Up @@ -849,8 +814,7 @@ describe('SavedObjectsTable', () => {
expect(findObjectsMock).toBeCalledWith(
http,
expect.objectContaining({
workspaces: expect.arrayContaining(['workspace1', PUBLIC_WORKSPACE_ID]),
workspacesSearchOperator: expect.stringMatching('OR'),
workspaces: expect.arrayContaining(['workspace1', 'workspace2', PUBLIC_WORKSPACE_ID]),
})
);
});
Expand Down

0 comments on commit 1f9b23c

Please sign in to comment.