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]>

add unit test

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

remove permissions

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

pick up workspaceEnabled changes

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

Use formatUrlWithWorkspaceId to foramt inAppURL for saved objects page

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

fix unit test

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

Remove workspacesEnabledSubscription

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

Add unit test

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

Add unit test

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

address review comments

Signed-off-by: Hailong Cui <[email protected]>
  • Loading branch information
Hailong-am committed Feb 27, 2024
1 parent 8ff9e88 commit aa6e38e
Show file tree
Hide file tree
Showing 18 changed files with 565 additions and 37 deletions.
1 change: 1 addition & 0 deletions src/core/public/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ export {
StringValidationRegex,
StringValidationRegexString,
WorkspaceObject,
WorkspaceAttribute,
} from '../types';

export {
Expand Down
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,29 @@ 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,12 +45,14 @@ export const Header = ({
onImport,
onRefresh,
filteredCount,
hideImport,
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,50 @@ 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],
};
// not in a workspace
let component = shallowWithI18nProvider(<Table {...props} />);

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

// in a workspace
const currentWorkspaceId = 'foo-ws';
component = shallowWithI18nProvider(
<Table {...props} currentWorkspaceId={currentWorkspaceId} />
);

table = component.find('EuiBasicTable');
columns = table.prop('columns') as any[];
content = columns[1].render('My-Dashboard-test', item);
expect(content.props.href).toEqual(
`http://localhost/w/${currentWorkspaceId}/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 { formatUrlWithWorkspaceId } from '../../../../../../core/public/utils';

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

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

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

const pagination = {
pageIndex,
pageSize,
Expand Down Expand Up @@ -231,9 +238,19 @@ export class Table extends PureComponent<TableProps, TableState> {
if (!canGoInApp) {
return <EuiText size="s">{title || getDefaultTitle(object)}</EuiText>;
}
return (
<EuiLink href={basePath.prepend(path)}>{title || getDefaultTitle(object)}</EuiLink>
);
let inAppUrl = basePath.prepend(path);
if (object.workspaces?.length) {
if (currentWorkspaceId) {
inAppUrl = formatUrlWithWorkspaceId(path, currentWorkspaceId, basePath);
} else {
// first workspace user have permission
const [workspaceId] = object.workspaces.filter((wsId) => visibleWsIds.includes(wsId));
if (workspaceId) {
inAppUrl = formatUrlWithWorkspaceId(path, workspaceId, basePath);
}
}
}
return <EuiLink href={inAppUrl}>{title || getDefaultTitle(object)}</EuiLink>;
},
} as EuiTableFieldDataColumnType<SavedObjectWithMetadata<any>>,
{
Expand Down
Loading

0 comments on commit aa6e38e

Please sign in to comment.