diff --git a/src/plugins/saved_objects_management/public/management_section/objects_table/__snapshots__/saved_objects_table.test.tsx.snap b/src/plugins/saved_objects_management/public/management_section/objects_table/__snapshots__/saved_objects_table.test.tsx.snap
index 61ca73929555..da0c642b8872 100644
--- a/src/plugins/saved_objects_management/public/management_section/objects_table/__snapshots__/saved_objects_table.test.tsx.snap
+++ b/src/plugins/saved_objects_management/public/management_section/objects_table/__snapshots__/saved_objects_table.test.tsx.snap
@@ -209,11 +209,13 @@ exports[`SavedObjectsTable should render normally 1`] = `
>
diff --git a/src/plugins/saved_objects_management/public/management_section/objects_table/components/__snapshots__/header.test.tsx.snap b/src/plugins/saved_objects_management/public/management_section/objects_table/components/__snapshots__/header.test.tsx.snap
index 1ebba756345f..6b9d1038f445 100644
--- a/src/plugins/saved_objects_management/public/management_section/objects_table/components/__snapshots__/header.test.tsx.snap
+++ b/src/plugins/saved_objects_management/public/management_section/objects_table/components/__snapshots__/header.test.tsx.snap
@@ -10,7 +10,9 @@ exports[`Header should render normally 1`] = `
grow={false}
>
-
+
+ Saved Objects
+
-
-
-
-
-
diff --git a/src/plugins/saved_objects_management/public/management_section/objects_table/components/__snapshots__/table.test.tsx.snap b/src/plugins/saved_objects_management/public/management_section/objects_table/components/__snapshots__/table.test.tsx.snap
index d1a11186543a..2fdad7b98874 100644
--- a/src/plugins/saved_objects_management/public/management_section/objects_table/components/__snapshots__/table.test.tsx.snap
+++ b/src/plugins/saved_objects_management/public/management_section/objects_table/components/__snapshots__/table.test.tsx.snap
@@ -40,11 +40,6 @@ exports[`Table prevents saved objects from being deleted 1`] = `
values={Object {}}
/>
,
- ,
,
- ,
{
onExportAll: () => {},
onImport: () => {},
onRefresh: () => {},
+ onCopy: () => {},
+ title: 'Saved Objects',
+ selectedCount: 0,
totalCount: 4,
filteredCount: 2,
+ showDuplicateAll: false,
+ hideImport: false,
};
const component = shallow();
@@ -47,3 +52,43 @@ describe('Header', () => {
expect(component).toMatchSnapshot();
});
});
+
+describe('Header - workspace enabled', () => {
+ it('should render `Duplicate All` button when workspace enabled', () => {
+ const props = {
+ onExportAll: () => {},
+ onImport: () => {},
+ onRefresh: () => {},
+ onCopy: () => {},
+ title: 'Saved Objects',
+ selectedCount: 0,
+ totalCount: 4,
+ filteredCount: 2,
+ showDuplicateAll: true,
+ hideImport: false,
+ };
+
+ const component = shallow();
+
+ expect(component.find('EuiButtonEmpty[data-test-subj="copyObjects"]').exists()).toBe(true);
+ });
+
+ it('should hide `Import` button for application home state', () => {
+ const props = {
+ onExportAll: () => {},
+ onImport: () => {},
+ onRefresh: () => {},
+ onCopy: () => {},
+ title: 'Saved Objects',
+ selectedCount: 0,
+ totalCount: 4,
+ filteredCount: 2,
+ showDuplicateAll: true,
+ hideImport: true,
+ };
+
+ const component = shallow();
+
+ expect(component.find('EuiButtonEmpty[data-test-subj="importObjects"]').exists()).toBe(false);
+ });
+});
diff --git a/src/plugins/saved_objects_management/public/management_section/objects_table/components/header.tsx b/src/plugins/saved_objects_management/public/management_section/objects_table/components/header.tsx
index b6803c92d9a0..fa3d36c73c14 100644
--- a/src/plugins/saved_objects_management/public/management_section/objects_table/components/header.tsx
+++ b/src/plugins/saved_objects_management/public/management_section/objects_table/components/header.tsx
@@ -48,6 +48,8 @@ export const Header = ({
filteredCount,
title,
selectedCount,
+ hideImport = false,
+ showDuplicateAll = false,
}: {
onExportAll: () => void;
onImport: () => void;
@@ -56,6 +58,8 @@ export const Header = ({
filteredCount: number;
title: string;
selectedCount: number;
+ hideImport: boolean;
+ showDuplicateAll: boolean;
}) => (
@@ -67,19 +71,21 @@ export const Header = ({
-
-
-
-
-
+ {showDuplicateAll && (
+
+
+
+
+
+ )}
-
-
-
-
-
+ {!hideImport && (
+
+
+
+
+
+ )}
{
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();
+
+ 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 = {
diff --git a/src/plugins/saved_objects_management/public/management_section/objects_table/components/table.tsx b/src/plugins/saved_objects_management/public/management_section/objects_table/components/table.tsx
index d7a1d66ff288..ef4ebbfc4c78 100644
--- a/src/plugins/saved_objects_management/public/management_section/objects_table/components/table.tsx
+++ b/src/plugins/saved_objects_management/public/management_section/objects_table/components/table.tsx
@@ -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 {
@@ -57,6 +57,7 @@ import {
SavedObjectsManagementAction,
SavedObjectsManagementColumnServiceStart,
} from '../../../services';
+import { WORKSPACE_PATH_PREFIX } from '../../../../../../core/public/utils';
export interface TableProps {
basePath: IBasePath;
@@ -84,6 +85,8 @@ export interface TableProps {
onShowRelationships: (object: SavedObjectWithMetadata) => void;
canGoInApp: (obj: SavedObjectWithMetadata) => boolean;
dateFormat: string;
+ availableWorkspaces?: WorkspaceAttribute[];
+ showDuplicate: boolean;
}
interface TableState {
@@ -178,8 +181,12 @@ export class Table extends PureComponent {
actionRegistry,
columnRegistry,
dateFormat,
+ availableWorkspaces,
+ showDuplicate,
} = this.props;
+ const visibleWsIds = availableWorkspaces?.map((ws) => ws.id) || [];
+
const pagination = {
pageIndex,
pageSize,
@@ -227,13 +234,20 @@ export class Table extends PureComponent {
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 {title || getDefaultTitle(object)};
}
+ if (object.workspaces) {
+ // first workspace login user have permission
+ const [workspaceId] = object.workspaces.filter((wsId) => visibleWsIds.includes(wsId));
+ path = workspaceId ? `${WORKSPACE_PATH_PREFIX}/${workspaceId}${path}` : path;
+ }
return (
- {title || getDefaultTitle(object)}
+
+ {title || getDefaultTitle(object)}
+
);
},
} as EuiTableFieldDataColumnType>,
@@ -352,6 +366,78 @@ export class Table extends PureComponent {
const activeActionContents = this.state.activeAction?.render() ?? null;
+ const tools = [
+
+
+ ,
+
+
+ }
+ >
+
+ }
+ checked={this.state.isIncludeReferencesDeepChecked}
+ onChange={this.toggleIsIncludeReferencesDeepChecked}
+ />
+
+
+
+
+
+
+ ,
+ ];
+
+ const duplicateButton = (
+
+ );
+
+ if (showDuplicate) {
+ tools.splice(1, 0, duplicateButton);
+ }
+
return (
{activeActionContents}
@@ -359,70 +445,7 @@ export class Table extends PureComponent {
box={{ 'data-test-subj': 'savedObjectSearchBar' }}
filters={filters as any}
onChange={this.onChange}
- toolsRight={[
-
-
- ,
- ,
-
-
- }
- >
-
- }
- checked={this.state.isIncludeReferencesDeepChecked}
- onChange={this.toggleIsIncludeReferencesDeepChecked}
- />
-
-
-
-
-
-
- ,
- ]}
+ toolsRight={tools}
/>
{queryParseError}
diff --git a/src/plugins/saved_objects_management/public/management_section/objects_table/saved_objects_table.test.tsx b/src/plugins/saved_objects_management/public/management_section/objects_table/saved_objects_table.test.tsx
index dcc54d5016b0..ace6f1e4271c 100644
--- a/src/plugins/saved_objects_management/public/management_section/objects_table/saved_objects_table.test.tsx
+++ b/src/plugins/saved_objects_management/public/management_section/objects_table/saved_objects_table.test.tsx
@@ -284,7 +284,7 @@ describe('SavedObjectsTable', () => {
await component.instance().onExport(true);
expect(fetchExportObjectsMock).toHaveBeenCalledWith(http, mockSelectedSavedObjects, true, {
- workspaces: ['public'],
+ workspaces: undefined,
});
expect(notifications.toasts.addSuccess).toHaveBeenCalledWith({
title: 'Your file is downloading in the background',
@@ -329,7 +329,7 @@ describe('SavedObjectsTable', () => {
await component.instance().onExport(true);
expect(fetchExportObjectsMock).toHaveBeenCalledWith(http, mockSelectedSavedObjects, true, {
- workspaces: ['public'],
+ workspaces: undefined,
});
expect(notifications.toasts.addWarning).toHaveBeenCalledWith({
title:
@@ -372,7 +372,7 @@ describe('SavedObjectsTable', () => {
allowedTypes,
undefined,
true,
- { workspaces: ['public'] }
+ { workspaces: undefined }
);
expect(saveAsMock).toHaveBeenCalledWith(blob, 'export.ndjson');
expect(notifications.toasts.addSuccess).toHaveBeenCalledWith({
@@ -403,7 +403,7 @@ describe('SavedObjectsTable', () => {
allowedTypes,
'test*',
true,
- { workspaces: ['public'] }
+ { workspaces: undefined }
);
expect(saveAsMock).toHaveBeenCalledWith(blob, 'export.ndjson');
expect(notifications.toasts.addSuccess).toHaveBeenCalledWith({
diff --git a/src/plugins/saved_objects_management/public/management_section/objects_table/saved_objects_table.tsx b/src/plugins/saved_objects_management/public/management_section/objects_table/saved_objects_table.tsx
index 33c3b9a64da2..cb93ff3b4995 100644
--- a/src/plugins/saved_objects_management/public/management_section/objects_table/saved_objects_table.tsx
+++ b/src/plugins/saved_objects_management/public/management_section/objects_table/saved_objects_table.tsx
@@ -146,14 +146,16 @@ export interface SavedObjectsTableState {
exportAllOptions: ExportAllOption[];
exportAllSelectedOptions: Record;
isIncludeReferencesDeepChecked: boolean;
- workspaceId: string | null;
- availableWorkspace?: WorkspaceAttribute[];
+ currentWorkspaceId: string | null;
+ availableWorkspaces?: WorkspaceAttribute[];
+ workspaceEnabled: boolean;
}
export class SavedObjectsTable extends Component {
private _isMounted = false;
private currentWorkspaceIdSubscription?: Subscription;
private workspacesSubscription?: Subscription;
+ private workspacesEnabledSubscription?: Subscription;
constructor(props: SavedObjectsTableProps) {
super(props);
@@ -183,30 +185,31 @@ export class SavedObjectsTable extends Component ws.id);
- } else if (workspaceId === PUBLIC_WORKSPACE_ID) {
- return [PUBLIC_WORKSPACE_ID];
} else {
- return [workspaceId, PUBLIC_WORKSPACE_ID];
+ // application home
+ if (!currentWorkspaceId) {
+ return availableWorkspaces?.map((ws) => ws.id);
+ } else {
+ return [currentWorkspaceId];
+ }
}
}
private get wsNameIdLookup() {
- const { availableWorkspace } = this.state;
+ const { availableWorkspaces } = this.state;
// Assumption: workspace name is unique across the system
- return availableWorkspace?.reduce((map, ws) => {
+ return availableWorkspaces?.reduce((map, ws) => {
return map.set(ws.name, ws.id);
}, new Map());
}
@@ -224,6 +227,7 @@ export class SavedObjectsTable extends Component {
@@ -304,12 +308,16 @@ export class SavedObjectsTable extends Component
this.setState({
- workspaceId,
+ currentWorkspaceId: workspaceId,
})
);
this.workspacesSubscription = workspace.workspaceList$.subscribe((workspaceList) => {
- this.setState({ availableWorkspace: workspaceList });
+ this.setState({ availableWorkspaces: workspaceList });
+ });
+
+ this.workspacesEnabledSubscription = workspace.workspaceEnabled$.subscribe((enabled) => {
+ this.setState({ workspaceEnabled: enabled });
});
};
@@ -684,16 +692,14 @@ export class SavedObjectsTable extends Component {
@@ -1035,6 +1043,9 @@ export class SavedObjectsTable extends Component
@@ -1080,6 +1093,8 @@ export class SavedObjectsTable extends Component