Skip to content

Commit

Permalink
default workspace
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Hailong-am committed Mar 8, 2024
1 parent 568d414 commit 023fa9b
Show file tree
Hide file tree
Showing 12 changed files with 121 additions and 64 deletions.
2 changes: 1 addition & 1 deletion src/core/public/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -356,4 +356,4 @@ export { __osdBootstrap__ } from './osd_bootstrap';

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

export { WORKSPACE_TYPE, cleanWorkspaceId } from '../utils';
export { WORKSPACE_TYPE, cleanWorkspaceId, DEFAULT_WORKSPACE_ID } from '../utils';
7 changes: 6 additions & 1 deletion src/core/server/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,12 @@ export {
} from './metrics';

export { AppCategory, WorkspaceAttribute } from '../types';
export { DEFAULT_APP_CATEGORIES, PUBLIC_WORKSPACE_ID, WORKSPACE_TYPE } from '../utils';
export {
DEFAULT_APP_CATEGORIES,
PUBLIC_WORKSPACE_ID,
WORKSPACE_TYPE,
DEFAULT_WORKSPACE_ID,
} from '../utils';

export {
SavedObject,
Expand Down
2 changes: 2 additions & 0 deletions src/core/utils/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,5 @@ export const WORKSPACE_TYPE = 'workspace';
export const WORKSPACE_PATH_PREFIX = '/w';

export const PUBLIC_WORKSPACE_ID = 'public';

export const DEFAULT_WORKSPACE_ID = 'default';
7 changes: 6 additions & 1 deletion src/core/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,9 @@ export {
} from './context';
export { DEFAULT_APP_CATEGORIES } from './default_app_categories';
export { getWorkspaceIdFromUrl, formatUrlWithWorkspaceId, cleanWorkspaceId } from './workspace';
export { WORKSPACE_PATH_PREFIX, PUBLIC_WORKSPACE_ID, WORKSPACE_TYPE } from './constants';
export {
WORKSPACE_PATH_PREFIX,
PUBLIC_WORKSPACE_ID,
WORKSPACE_TYPE,
DEFAULT_WORKSPACE_ID,
} from './constants';

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 @@ -40,29 +40,10 @@ describe('Header', () => {
onRefresh: () => {},
totalCount: 4,
filteredCount: 2,
title: '',
};

const component = shallow(<Header {...props} />);

expect(component).toMatchSnapshot();
});
});

describe('Header - workspace enabled', () => {
it('should hide `Import` button for application home state', () => {
const props = {
onExportAll: () => {},
onImport: () => {},
onRefresh: () => {},
totalCount: 4,
filteredCount: 2,
hideImport: true,
title: 'Saved Objectes',
};

const component = shallow(<Header {...props} />);

expect(component.find('EuiButtonEmpty[data-test-subj="importObjects"]').exists()).toBe(false);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -45,15 +45,11 @@ export const Header = ({
onImport,
onRefresh,
filteredCount,
hideImport,
title,
}: {
onExportAll: () => void;
onImport: () => void;
onRefresh: () => void;
filteredCount: number;
hideImport?: boolean;
title: string;
}) => (
<Fragment>
<EuiFlexGroup justifyContent="spaceBetween" alignItems="baseline">
Expand Down Expand Up @@ -86,21 +82,19 @@ export const Header = ({
/>
</EuiButtonEmpty>
</EuiFlexItem>
{!hideImport && (
<EuiFlexItem grow={false}>
<EuiButtonEmpty
size="s"
iconType="importAction"
data-test-subj="importObjects"
onClick={onImport}
>
<FormattedMessage
id="savedObjectsManagement.objectsTable.header.importButtonLabel"
defaultMessage="Import"
/>
</EuiButtonEmpty>
</EuiFlexItem>
)}
<EuiFlexItem grow={false}>
<EuiButtonEmpty
size="s"
iconType="importAction"
data-test-subj="importObjects"
onClick={onImport}
>
<FormattedMessage
id="savedObjectsManagement.objectsTable.header.importButtonLabel"
defaultMessage="Import"
/>
</EuiButtonEmpty>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiButtonEmpty size="s" iconType="refresh" onClick={onRefresh}>
<FormattedMessage
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ import {
import { Flyout, Relationships } from './components';
import { SavedObjectWithMetadata } from '../../types';
import { WorkspaceObject } from 'opensearch-dashboards/public';
import { DEFAULT_WORKSPACE_ID } from '../../../../../core/public';
import { TableProps } from './components/table';
import { waitFor } from '@testing-library/dom';

Expand Down Expand Up @@ -647,7 +648,9 @@ describe('SavedObjectsTable', () => {
);
expect(component.state('selectedSavedObjects').length).toBe(0);
});
});

describe('workspace filter', () => {
it('show workspace filter when workspace turn on and not in any workspace', async () => {
const applications = applicationServiceMock.createStartContract();
applications.capabilities = {
Expand Down Expand Up @@ -690,9 +693,10 @@ describe('SavedObjectsTable', () => {
expect(filters.length).toBe(2);
expect(filters[0].field).toBe('type');
expect(filters[1].field).toBe('workspaces');
expect(filters[1].options.length).toBe(2);
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(DEFAULT_WORKSPACE_ID);
});

it('show workspace filter when workspace turn on and enter a workspace', async () => {
Expand Down Expand Up @@ -740,7 +744,8 @@ describe('SavedObjectsTable', () => {
expect(wsFilter[0].options[0].value).toBe('foo');
});

it('workspace exists in query options when workspace on', async () => {
it('workspace exists in find options when workspace on', async () => {
findObjectsMock.mockClear();
const applications = applicationServiceMock.createStartContract();
applications.capabilities = {
navLinks: {},
Expand Down Expand Up @@ -777,17 +782,61 @@ describe('SavedObjectsTable', () => {
// Ensure the state changes are reflected
component.update();

waitFor(
() => {
expect(http.get).toHaveBeenCalledWith(
expect.stringMatching('/api/opensearch-dashboards/management/saved_objects/_find'),
expect.objectContaining({
workspaces: expect.arrayContaining(['workspace1']),
})
);
await waitFor(() => {
expect(findObjectsMock).toBeCalledWith(
http,
expect.objectContaining({
workspaces: expect.arrayContaining(['workspace1']),
})
);
});
});

it('workspace exists in find options when workspace on and not in any workspace', async () => {
findObjectsMock.mockClear();
const applications = applicationServiceMock.createStartContract();
applications.capabilities = {
navLinks: {},
management: {},
catalogue: {},
savedObjectsManagement: {
read: true,
edit: false,
delete: false,
},
{ timeout: 1000 }
);
workspaces: {
enabled: true,
},
};

const workspaceList: WorkspaceObject[] = [
{
id: 'workspace1',
name: 'foo',
},
{
id: 'workspace2',
name: 'bar',
},
];
workspaces.workspaceList$.next(workspaceList);

const component = shallowRender({ applications, workspaces });

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

await waitFor(() => {
expect(findObjectsMock).toBeCalledWith(
http,
expect.objectContaining({
workspaces: expect.arrayContaining(['workspace1', 'default']),
workspacesSearchOperator: expect.stringMatching('OR'),
})
);
});
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ import {
WorkspaceAttribute,
} from 'src/core/public';
import { Subscription } from 'rxjs';
import { DEFAULT_WORKSPACE_ID } from '../../../../../core/public';
import { RedirectAppLinks } from '../../../../opensearch_dashboards_react/public';
import { IndexPatternsContract } from '../../../../data/public';
import {
Expand Down Expand Up @@ -192,7 +193,7 @@ export class SavedObjectsTable extends Component<SavedObjectsTableProps, SavedOb
} else {
// application home
if (!currentWorkspaceId) {
return availableWorkspaces?.map((ws) => ws.id);
return availableWorkspaces?.map((ws) => ws.id).concat(DEFAULT_WORKSPACE_ID);
} else {
return [currentWorkspaceId];
}
Expand All @@ -201,10 +202,13 @@ export class SavedObjectsTable extends Component<SavedObjectsTableProps, SavedOb

private get wsNameIdLookup() {
const { availableWorkspaces } = this.state;
const workspaceNameIdMap = new Map<string, string>();
workspaceNameIdMap.set(DEFAULT_WORKSPACE_ID, DEFAULT_WORKSPACE_ID);
// Assumption: workspace name is unique across the system
return availableWorkspaces?.reduce((map, ws) => {
availableWorkspaces?.reduce((map, ws) => {
return map.set(ws.name, ws.id);
}, new Map<string, string>());
}, workspaceNameIdMap);
return workspaceNameIdMap;
}

private formatWorkspaceIdParams<T extends { workspaces?: string[] }>(
Expand Down Expand Up @@ -352,6 +356,13 @@ export class SavedObjectsTable extends Component<SavedObjectsTableProps, SavedOb
findOptions.workspaces = workspaceIds;
}

if (findOptions.workspaces) {
if (findOptions.workspaces.indexOf(DEFAULT_WORKSPACE_ID) !== -1) {
// search both saved objects with workspace and without workspace
findOptions.workspacesSearchOperator = 'OR';
}
}

if (findOptions.type.length > 1) {
findOptions.sortField = 'type';
}
Expand Down Expand Up @@ -962,6 +973,14 @@ export class SavedObjectsTable extends Component<SavedObjectsTableProps, SavedOb
};
});

if (!currentWorkspaceId) {
wsFilterOptions.push({
name: DEFAULT_WORKSPACE_ID,
value: DEFAULT_WORKSPACE_ID,
view: `Default (${wsCounts[DEFAULT_WORKSPACE_ID] || 0})`,
});
}

filters.push({
type: 'field_value_selection',
field: 'workspaces',
Expand All @@ -973,9 +992,6 @@ export class SavedObjectsTable extends Component<SavedObjectsTableProps, SavedOb
});
}

// workspace enable and no workspace is selected
const hideImport = workspaceEnabled && !currentWorkspaceId;

return (
<EuiPageContent horizontalPosition="center">
{this.renderFlyout()}
Expand All @@ -987,8 +1003,6 @@ export class SavedObjectsTable extends Component<SavedObjectsTableProps, SavedOb
onImport={this.showImportFlyout}
onRefresh={this.refreshObjects}
filteredCount={filteredItemCount}
hideImport={hideImport}
title={this.props.title}
/>
<EuiSpacer size="xs" />
<RedirectAppLinks application={applications}>
Expand Down
1 change: 1 addition & 0 deletions src/plugins/saved_objects_management/server/routes/find.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ export const registerFindRoute = (
workspaces: schema.maybe(
schema.oneOf([schema.string(), schema.arrayOf(schema.string())])
),
workspacesSearchOperator: schema.maybe(schema.string()),
}),
},
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@

import { schema } from '@osd/config-schema';
import { IRouter, SavedObjectsFindOptions } from 'src/core/server';
import { DEFAULT_WORKSPACE_ID } from '../../../../core/server';
import { findAll } from '../lib';

export const registerScrollForCountRoute = (router: IRouter) => {
Expand Down Expand Up @@ -69,6 +70,10 @@ export const registerScrollForCountRoute = (router: IRouter) => {
if (requestHasWorkspaces) {
counts.workspaces = {};
findOptions.workspaces = req.body.workspaces;
if (findOptions.workspaces.indexOf(DEFAULT_WORKSPACE_ID) !== -1) {
// search both saved objects with workspace and without workspace
findOptions.workspacesSearchOperator = 'OR';
}
}

if (req.body.searchString) {
Expand All @@ -91,7 +96,7 @@ export const registerScrollForCountRoute = (router: IRouter) => {
});
}
if (requestHasWorkspaces) {
const resultWorkspaces = result.workspaces || [];
const resultWorkspaces = result.workspaces || [DEFAULT_WORKSPACE_ID];
resultWorkspaces.forEach((ws) => {
counts.workspaces[ws] = counts.workspaces[ws] || 0;
counts.workspaces[ws]++;
Expand Down
4 changes: 3 additions & 1 deletion src/plugins/workspace/public/plugin.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,9 @@ describe('Workspace plugin', () => {
it('#setup register workspace dropdown menu when setup', async () => {
const setupMock = coreMock.createSetup();
const workspacePlugin = new WorkspacePlugin();
await workspacePlugin.setup(setupMock);
await workspacePlugin.setup(setupMock, {
savedObjectsManagement: savedObjectsManagementPluginMock.createSetupContract(),
});
expect(setupMock.chrome.registerCollapsibleNavHeader).toBeCalledTimes(1);
});
});

0 comments on commit 023fa9b

Please sign in to comment.