Skip to content

Commit

Permalink
add workspace filter into saved objects page (opensearch-project#76)
Browse files Browse the repository at this point in the history
* add workspace filter into saved objects page

Signed-off-by: Hailong Cui <[email protected]>

* workspace filter

Signed-off-by: Hailong Cui <[email protected]>

* managment workspace filter

Signed-off-by: Hailong Cui <[email protected]>

---------

Signed-off-by: Hailong Cui <[email protected]>

Saved objects page change (opensearch-project#123)

* hide import for application home page

Signed-off-by: Hailong Cui <[email protected]>

* add workpspace into gotoApp link

Signed-off-by: Hailong Cui <[email protected]>

* remove special logic for management workspace

Signed-off-by: Hailong Cui <[email protected]>

* variable name change and more UTs

Signed-off-by: Hailong Cui <[email protected]>

---------

Signed-off-by: Hailong Cui <[email protected]>

filters

Signed-off-by: Hailong Cui <[email protected]>

remove copy related

Signed-off-by: Hailong Cui <[email protected]>

revert index pattern chagne

Signed-off-by: Hailong Cui <[email protected]>
  • Loading branch information
Hailong-am committed Oct 9, 2023
1 parent c05b434 commit 27b8e37
Show file tree
Hide file tree
Showing 19 changed files with 331 additions and 35 deletions.
1 change: 1 addition & 0 deletions src/core/public/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,4 @@
export { shareWeakReplay } from './share_weak_replay';
export { Sha256 } from './crypto';
export { MountWrapper, mountReactNode } from './mount';
export { WORKSPACE_PATH_PREFIX, WORKSPACE_TYPE } from '../../utils';
1 change: 1 addition & 0 deletions src/core/types/saved_objects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ export interface SavedObject<T = unknown> {
originId?: string;
/** Workspaces that this saved object exists in. */
workspaces?: string[];
permissions?: Permissions;
}

export interface SavedObjectError {
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 @@ -4,3 +4,5 @@
*/

export const WORKSPACE_TYPE = 'workspace';

export const WORKSPACE_PATH_PREFIX = '/w';
2 changes: 1 addition & 1 deletion src/core/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,4 @@ export {
IContextProvider,
} from './context';
export { DEFAULT_APP_CATEGORIES } from './default_app_categories';
export { WORKSPACE_TYPE } from './constants';
export { WORKSPACE_TYPE, WORKSPACE_PATH_PREFIX } from './constants';
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,14 @@ export interface SavedObjectCountOptions {
typesToInclude: string[];
namespacesToInclude?: string[];
searchString?: string;
workspaces?: string[];
}

export async function getSavedObjectCounts(
http: HttpStart,
options: SavedObjectCountOptions
): Promise<Record<string, number>> {
return await http.post<Record<string, number>>(
): Promise<Record<string, Record<string, number>>> {
return await http.post<Record<string, Record<string, number>>>(
`/api/opensearch-dashboards/management/saved_objects/scroll/counts`,
{ body: JSON.stringify(options) }
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ describe('getQueryText', () => {
return [{ value: 'lala' }, { value: 'lolo' }];
} else if (field === 'namespaces') {
return [{ value: 'default' }];
} else if (field === 'workspaces') {
return [{ value: 'workspaces' }];
}
return [];
},
Expand All @@ -47,6 +49,7 @@ describe('getQueryText', () => {
queryText: 'foo bar',
visibleTypes: 'lala',
visibleNamespaces: 'default',
visibleWorkspaces: 'workspaces',
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,15 @@ import { Query } from '@elastic/eui';
interface ParsedQuery {
queryText?: string;
visibleTypes?: string[];
visibleNamespaces?: string[];
visibleWorkspaces?: string[];
}

export function parseQuery(query: Query): ParsedQuery {
let queryText: string | undefined;
let visibleTypes: string[] | undefined;
let visibleNamespaces: string[] | undefined;
let visibleWorkspaces: string[] | undefined;

if (query) {
if (query.ast.getTermClauses().length) {
Expand All @@ -53,11 +56,15 @@ export function parseQuery(query: Query): ParsedQuery {
if (query.ast.getFieldClauses('namespaces')) {
visibleNamespaces = query.ast.getFieldClauses('namespaces')[0].value as string[];
}
if (query.ast.getFieldClauses('workspaces')) {
visibleWorkspaces = query.ast.getFieldClauses('workspaces')[0].value as string[];
}
}

return {
queryText,
visibleTypes,
visibleNamespaces,
visibleWorkspaces,
};
}

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

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,
};

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,11 +45,13 @@ export const Header = ({
onImport,
onRefresh,
filteredCount,
hideImport = false,
}: {
onExportAll: () => void;
onImport: () => void;
onRefresh: () => void;
filteredCount: number;
hideImport: boolean;
}) => (
<Fragment>
<EuiFlexGroup justifyContent="spaceBetween" alignItems="baseline">
Expand Down Expand Up @@ -82,19 +84,21 @@ export const Header = ({
/>
</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>
{!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="refresh" onClick={onRefresh}>
<FormattedMessage
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import { actionServiceMock } from '../../../services/action_service.mock';
import { columnServiceMock } from '../../../services/column_service.mock';
import { SavedObjectsManagementAction } from '../../..';
import { Table, TableProps } from './table';
import { WorkspaceAttribute } from 'opensearch-dashboards/public';

const defaultProps: TableProps = {
basePath: httpServiceMock.createSetupContract().basePath,
Expand Down Expand Up @@ -115,6 +116,36 @@ describe('Table', () => {
expect(component).toMatchSnapshot();
});

it('should render gotoApp link correctly for workspace', () => {
const item = {
id: 'dashboard-1',
type: 'dashboard',
workspaces: ['ws-1'],
attributes: {},
references: [],
meta: {
title: `My-Dashboard-test`,
icon: 'indexPatternApp',
editUrl: '/management/opensearch-dashboards/objects/savedDashboards/dashboard-1',
inAppUrl: {
path: '/app/dashboards#/view/dashboard-1',
uiCapabilitiesPath: 'dashboard.show',
},
},
};
const props = {
...defaultProps,
availableWorkspaces: [{ id: 'ws-1', name: 'My workspace' } as WorkspaceAttribute],
items: [item],
};
const component = shallowWithI18nProvider(<Table {...props} />);

const table = component.find('EuiBasicTable');
const columns = table.prop('columns') as any[];
const content = columns[1].render('My-Dashboard-test', item);
expect(content.props.href).toEqual('/w/ws-1/app/dashboards#/view/dashboard-1');
});

it('should handle query parse error', () => {
const onQueryChangeMock = jest.fn();
const customizedProps = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
* under the License.
*/

import { IBasePath } from 'src/core/public';
import { IBasePath, WorkspaceAttribute } from 'src/core/public';
import React, { PureComponent, Fragment } from 'react';
import moment from 'moment';
import {
Expand Down Expand Up @@ -56,6 +56,7 @@ import {
SavedObjectsManagementAction,
SavedObjectsManagementColumnServiceStart,
} from '../../../services';
import { WORKSPACE_PATH_PREFIX } from '../../../../../../core/public/utils';

export interface TableProps {
basePath: IBasePath;
Expand Down Expand Up @@ -83,6 +84,7 @@ export interface TableProps {
onShowRelationships: (object: SavedObjectWithMetadata) => void;
canGoInApp: (obj: SavedObjectWithMetadata) => boolean;
dateFormat: string;
availableWorkspaces?: WorkspaceAttribute[];
}

interface TableState {
Expand Down Expand Up @@ -177,8 +179,11 @@ export class Table extends PureComponent<TableProps, TableState> {
columnRegistry,
namespaceRegistry,
dateFormat,
availableWorkspaces,
} = this.props;

const visibleWsIds = availableWorkspaces?.map((ws) => ws.id) || [];

const pagination = {
pageIndex,
pageSize,
Expand Down Expand Up @@ -226,13 +231,20 @@ export class Table extends PureComponent<TableProps, TableState> {
sortable: false,
'data-test-subj': 'savedObjectsTableRowTitle',
render: (title: string, object: SavedObjectWithMetadata) => {
const { path = '' } = object.meta.inAppUrl || {};
let { path = '' } = object.meta.inAppUrl || {};
const canGoInApp = this.props.canGoInApp(object);
if (!canGoInApp) {
return <EuiText size="s">{title || getDefaultTitle(object)}</EuiText>;
}
if (object.workspaces?.length) {
// first workspace login user have permission
const [workspaceId] = object.workspaces.filter((wsId) => visibleWsIds.includes(wsId));
path = workspaceId ? `${WORKSPACE_PATH_PREFIX}/${workspaceId}${path}` : path;
}
return (
<EuiLink href={basePath.prepend(path)}>{title || getDefaultTitle(object)}</EuiLink>
<EuiLink href={basePath.prepend(path, { withoutWorkspace: true })}>
{title || getDefaultTitle(object)}
</EuiLink>
);
},
} as EuiTableFieldDataColumnType<SavedObjectWithMetadata<any>>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ import {
notificationServiceMock,
savedObjectsServiceMock,
applicationServiceMock,
workspacesServiceMock,
} from '../../../../../core/public/mocks';
import { dataPluginMock } from '../../../../data/public/mocks';
import { serviceRegistryMock } from '../../services/service_registry.mock';
Expand Down Expand Up @@ -102,6 +103,7 @@ describe('SavedObjectsTable', () => {
let notifications: ReturnType<typeof notificationServiceMock.createStartContract>;
let savedObjects: ReturnType<typeof savedObjectsServiceMock.createStartContract>;
let search: ReturnType<typeof dataPluginMock.createStartContract>['search'];
let workspaces: ReturnType<typeof workspacesServiceMock.createStartContract>;

const shallowRender = (overrides: Partial<SavedObjectsTableProps> = {}) => {
return (shallowWithI18nProvider(
Expand All @@ -121,6 +123,7 @@ describe('SavedObjectsTable', () => {
notifications = notificationServiceMock.createStartContract();
savedObjects = savedObjectsServiceMock.createStartContract();
search = dataPluginMock.createStartContract().search;
workspaces = workspacesServiceMock.createStartContract();

const applications = applicationServiceMock.createStartContract();
applications.capabilities = {
Expand Down Expand Up @@ -154,6 +157,7 @@ describe('SavedObjectsTable', () => {
savedObjectsClient: savedObjects.client,
indexPatterns: dataPluginMock.createStartContract().indexPatterns,
http,
workspaces,
overlays,
notifications,
applications,
Expand Down
Loading

0 comments on commit 27b8e37

Please sign in to comment.