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 <ihailong@amazon.com>

* workspace filter

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

* managment workspace filter

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

---------

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

Saved objects page change (opensearch-project#123)

* hide import for application home page

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

* add workpspace into gotoApp link

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

* remove special logic for management workspace

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

* variable name change and more UTs

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

---------

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

filters

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

remove copy related

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

revert index pattern chagne

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

add unit test

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

remove permissions

Signed-off-by: Hailong Cui <ihailong@amazon.com>
  • Loading branch information
Hailong-am committed Oct 18, 2023
1 parent c271e74 commit d9df724
Show file tree
Hide file tree
Showing 16 changed files with 388 additions and 33 deletions.
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,12 +45,14 @@ export const Header = ({
onImport,
onRefresh,
filteredCount,
hideImport = false,
title,
}: {
onExportAll: () => void;
onImport: () => void;
onRefresh: () => void;
filteredCount: number;
hideImport: boolean;
title: string;
}) => (
<Fragment>
Expand Down Expand Up @@ -79,19 +81,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 d9df724

Please sign in to comment.