diff --git a/src/core/public/chrome/chrome_service.test.ts b/src/core/public/chrome/chrome_service.test.ts index 6e36775b90c2..0a1e87a0c611 100644 --- a/src/core/public/chrome/chrome_service.test.ts +++ b/src/core/public/chrome/chrome_service.test.ts @@ -41,7 +41,7 @@ import { notificationServiceMock } from '../notifications/notifications_service. import { uiSettingsServiceMock } from '../ui_settings/ui_settings_service.mock'; import { ChromeService } from './chrome_service'; import { getAppInfo } from '../application/utils'; -import { workspacesServiceMock } from '../fatal_errors/fatal_errors_service.mock'; +import { workspacesServiceMock } from '../workspace/workspaces_service.mock'; class FakeApp implements App { public title = `${this.id} App`; diff --git a/src/core/public/chrome/ui/header/__snapshots__/header.test.tsx.snap b/src/core/public/chrome/ui/header/__snapshots__/header.test.tsx.snap index a13ff88ff09d..42bc3cf0b586 100644 --- a/src/core/public/chrome/ui/header/__snapshots__/header.test.tsx.snap +++ b/src/core/public/chrome/ui/header/__snapshots__/header.test.tsx.snap @@ -1918,9 +1918,11 @@ exports[`Header handles visibility and lock changes 1`] = ` BasePath { "basePath": "/test", "get": [Function], + "getBasePath": [Function], "prepend": [Function], "remove": [Function], "serverBasePath": "/test", + "workspaceBasePath": "", } } branding={ @@ -2365,9 +2367,11 @@ exports[`Header handles visibility and lock changes 1`] = ` BasePath { "basePath": "/test", "get": [Function], + "getBasePath": [Function], "prepend": [Function], "remove": [Function], "serverBasePath": "/test", + "workspaceBasePath": "", } } branding={ diff --git a/src/core/public/chrome/ui/header/__snapshots__/header_logo.test.tsx.snap b/src/core/public/chrome/ui/header/__snapshots__/header_logo.test.tsx.snap index 7e44e456f320..f3543fdae8d0 100644 --- a/src/core/public/chrome/ui/header/__snapshots__/header_logo.test.tsx.snap +++ b/src/core/public/chrome/ui/header/__snapshots__/header_logo.test.tsx.snap @@ -6,9 +6,11 @@ exports[`Header logo when dark-themed uses custom dark-mode logo if branding dar BasePath { "basePath": "/base", "get": [Function], + "getBasePath": [Function], "prepend": [Function], "remove": [Function], "serverBasePath": "/base", + "workspaceBasePath": "", } } branding={ @@ -251,9 +253,11 @@ exports[`Header logo when dark-themed uses dashboards' dark logo if branding con BasePath { "basePath": "/base", "get": [Function], + "getBasePath": [Function], "prepend": [Function], "remove": [Function], "serverBasePath": "/base", + "workspaceBasePath": "", } } branding={ @@ -495,9 +499,11 @@ exports[`Header logo when dark-themed uses dashboards' dark logo if branding con BasePath { "basePath": "/base", "get": [Function], + "getBasePath": [Function], "prepend": [Function], "remove": [Function], "serverBasePath": "/base", + "workspaceBasePath": "", } } branding={ @@ -737,9 +743,11 @@ exports[`Header logo when dark-themed uses dashboards' dark logo if no branding BasePath { "basePath": "/base", "get": [Function], + "getBasePath": [Function], "prepend": [Function], "remove": [Function], "serverBasePath": "/base", + "workspaceBasePath": "", } } branding={Object {}} @@ -972,9 +980,11 @@ exports[`Header logo when dark-themed uses default-themed custom logo if brandin BasePath { "basePath": "/base", "get": [Function], + "getBasePath": [Function], "prepend": [Function], "remove": [Function], "serverBasePath": "/base", + "workspaceBasePath": "", } } branding={ @@ -1216,9 +1226,11 @@ exports[`Header logo when default-themed uses custom default-mode logo if brand BasePath { "basePath": "/base", "get": [Function], + "getBasePath": [Function], "prepend": [Function], "remove": [Function], "serverBasePath": "/base", + "workspaceBasePath": "", } } branding={ @@ -1460,9 +1472,11 @@ exports[`Header logo when default-themed uses dashboards logo if branding conta BasePath { "basePath": "/base", "get": [Function], + "getBasePath": [Function], "prepend": [Function], "remove": [Function], "serverBasePath": "/base", + "workspaceBasePath": "", } } branding={ @@ -1704,9 +1718,11 @@ exports[`Header logo when default-themed uses dashboards logo if branding conta BasePath { "basePath": "/base", "get": [Function], + "getBasePath": [Function], "prepend": [Function], "remove": [Function], "serverBasePath": "/base", + "workspaceBasePath": "", } } branding={ @@ -1946,9 +1962,11 @@ exports[`Header logo when default-themed uses dashboards logo if no branding is BasePath { "basePath": "/base", "get": [Function], + "getBasePath": [Function], "prepend": [Function], "remove": [Function], "serverBasePath": "/base", + "workspaceBasePath": "", } } branding={Object {}} diff --git a/src/core/public/chrome/ui/header/collapsible_nav.test.tsx b/src/core/public/chrome/ui/header/collapsible_nav.test.tsx index aeaf3177ef3b..0c91807c2983 100644 --- a/src/core/public/chrome/ui/header/collapsible_nav.test.tsx +++ b/src/core/public/chrome/ui/header/collapsible_nav.test.tsx @@ -37,7 +37,7 @@ import { ChromeNavLink, DEFAULT_APP_CATEGORIES } from '../../..'; import { httpServiceMock } from '../../../http/http_service.mock'; import { ChromeRecentlyAccessedHistoryItem } from '../../recently_accessed'; import { CollapsibleNav } from './collapsible_nav'; -import { workspacesServiceMock } from '../../../fatal_errors/fatal_errors_service.mock'; +import { workspacesServiceMock } from '../../../workspace/workspaces_service.mock'; jest.mock('@elastic/eui/lib/services/accessibility/html_id_generator', () => ({ htmlIdGenerator: () => () => 'mockId', diff --git a/src/core/public/chrome/ui/header/header.test.tsx b/src/core/public/chrome/ui/header/header.test.tsx index 08d050575385..12b31d53795f 100644 --- a/src/core/public/chrome/ui/header/header.test.tsx +++ b/src/core/public/chrome/ui/header/header.test.tsx @@ -36,7 +36,7 @@ import { httpServiceMock } from '../../../http/http_service.mock'; import { applicationServiceMock } from '../../../mocks'; import { Header } from './header'; import { StubBrowserStorage } from 'test_utils/stub_browser_storage'; -import { workspacesServiceMock } from '../../../fatal_errors/fatal_errors_service.mock'; +import { workspacesServiceMock } from '../../../workspace/workspaces_service.mock'; jest.mock('@elastic/eui/lib/services/accessibility/html_id_generator', () => ({ htmlIdGenerator: () => () => 'mockId', diff --git a/src/core/public/fatal_errors/fatal_errors_service.mock.ts b/src/core/public/fatal_errors/fatal_errors_service.mock.ts index 8baf7d824270..ff1b252fc128 100644 --- a/src/core/public/fatal_errors/fatal_errors_service.mock.ts +++ b/src/core/public/fatal_errors/fatal_errors_service.mock.ts @@ -30,8 +30,6 @@ import type { PublicMethodsOf } from '@osd/utility-types'; import { FatalErrorsService, FatalErrorsSetup } from './fatal_errors_service'; -import { BehaviorSubject } from 'rxjs'; -import { WorkspaceAttribute } from '../workspace'; const createSetupContractMock = () => { const setupContract: jest.Mocked = { @@ -60,35 +58,3 @@ export const fatalErrorsServiceMock = { createSetupContract: createSetupContractMock, createStartContract: createStartContractMock, }; - -const currentWorkspaceId$ = new BehaviorSubject(''); -const workspaceList$ = new BehaviorSubject([]); -const currentWorkspace$ = new BehaviorSubject(null); - -const createWorkspacesSetupContractMock = () => ({ - client: { - currentWorkspaceId$, - workspaceList$, - currentWorkspace$, - init: jest.fn(), - stop: jest.fn(), - enterWorkspace: jest.fn(), - exitWorkspace: jest.fn(), - create: jest.fn(), - delete: jest.fn(), - list: jest.fn(), - getCurrentWorkspace: jest.fn(), - getCurrentWorkspaceId: jest.fn(), - get: jest.fn(), - update: jest.fn(), - }, - formatUrlWithWorkspaceId: jest.fn(), - setFormatUrlWithWorkspaceId: jest.fn(), -}); - -const createWorkspacesStartContractMock = createWorkspacesSetupContractMock; - -export const workspacesServiceMock = { - createSetupContractMock: createWorkspacesStartContractMock, - createStartContract: createWorkspacesStartContractMock, -}; diff --git a/src/core/public/mocks.ts b/src/core/public/mocks.ts index e863d627c801..99d9f5a517f3 100644 --- a/src/core/public/mocks.ts +++ b/src/core/public/mocks.ts @@ -47,6 +47,7 @@ import { uiSettingsServiceMock } from './ui_settings/ui_settings_service.mock'; import { savedObjectsServiceMock } from './saved_objects/saved_objects_service.mock'; import { contextServiceMock } from './context/context_service.mock'; import { injectedMetadataServiceMock } from './injected_metadata/injected_metadata_service.mock'; +import { workspacesServiceMock } from './workspace/workspaces_service.mock'; export { chromeServiceMock } from './chrome/chrome_service.mock'; export { docLinksServiceMock } from './doc_links/doc_links_service.mock'; @@ -60,6 +61,7 @@ export { uiSettingsServiceMock } from './ui_settings/ui_settings_service.mock'; export { savedObjectsServiceMock } from './saved_objects/saved_objects_service.mock'; export { scopedHistoryMock } from './application/scoped_history.mock'; export { applicationServiceMock } from './application/application_service.mock'; +export { workspacesServiceMock } from './workspace/workspaces_service.mock'; function createCoreSetupMock({ basePath = '', @@ -85,6 +87,7 @@ function createCoreSetupMock({ getInjectedVar: injectedMetadataServiceMock.createSetupContract().getInjectedVar, getBranding: injectedMetadataServiceMock.createSetupContract().getBranding, }, + workspaces: workspacesServiceMock, }; return mock; @@ -106,6 +109,7 @@ function createCoreStartMock({ basePath = '' } = {}) { getBranding: injectedMetadataServiceMock.createStartContract().getBranding, }, fatalErrors: fatalErrorsServiceMock.createStartContract(), + workspaces: workspacesServiceMock.createStartContract(), }; return mock; diff --git a/src/core/public/plugins/plugins_service.test.ts b/src/core/public/plugins/plugins_service.test.ts index 9c36a791332d..01578523be5f 100644 --- a/src/core/public/plugins/plugins_service.test.ts +++ b/src/core/public/plugins/plugins_service.test.ts @@ -50,10 +50,7 @@ import { applicationServiceMock } from '../application/application_service.mock' import { i18nServiceMock } from '../i18n/i18n_service.mock'; import { overlayServiceMock } from '../overlays/overlay_service.mock'; import { chromeServiceMock } from '../chrome/chrome_service.mock'; -import { - fatalErrorsServiceMock, - workspacesServiceMock, -} from '../fatal_errors/fatal_errors_service.mock'; +import { fatalErrorsServiceMock } from '../fatal_errors/fatal_errors_service.mock'; import { uiSettingsServiceMock } from '../ui_settings/ui_settings_service.mock'; import { injectedMetadataServiceMock } from '../injected_metadata/injected_metadata_service.mock'; import { httpServiceMock } from '../http/http_service.mock'; @@ -61,6 +58,7 @@ import { CoreSetup, CoreStart, PluginInitializerContext } from '..'; import { docLinksServiceMock } from '../doc_links/doc_links_service.mock'; import { savedObjectsServiceMock } from '../saved_objects/saved_objects_service.mock'; import { contextServiceMock } from '../context/context_service.mock'; +import { workspacesServiceMock } from '../workspace/workspaces_service.mock'; export let mockPluginInitializers: Map; diff --git a/src/core/public/workspace/workspaces_service.mock.ts b/src/core/public/workspace/workspaces_service.mock.ts new file mode 100644 index 000000000000..245303cb4c93 --- /dev/null +++ b/src/core/public/workspace/workspaces_service.mock.ts @@ -0,0 +1,39 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { BehaviorSubject } from 'rxjs'; +import { WorkspaceAttribute } from '../workspace'; + +const currentWorkspaceId$ = new BehaviorSubject(''); +const workspaceList$ = new BehaviorSubject([]); +const currentWorkspace$ = new BehaviorSubject(null); + +const createWorkspacesSetupContractMock = () => ({ + client: { + currentWorkspaceId$, + workspaceList$, + currentWorkspace$, + init: jest.fn(), + stop: jest.fn(), + enterWorkspace: jest.fn(), + exitWorkspace: jest.fn(), + create: jest.fn(), + delete: jest.fn(), + list: jest.fn(), + getCurrentWorkspace: jest.fn(), + getCurrentWorkspaceId: jest.fn(), + get: jest.fn(), + update: jest.fn(), + }, + formatUrlWithWorkspaceId: jest.fn(), + setFormatUrlWithWorkspaceId: jest.fn(), +}); + +const createWorkspacesStartContractMock = createWorkspacesSetupContractMock; + +export const workspacesServiceMock = { + createSetupContractMock: createWorkspacesStartContractMock, + createStartContract: createWorkspacesStartContractMock, +}; diff --git a/src/core/server/index.ts b/src/core/server/index.ts index ca55cc8dc1d5..6a234a405e54 100644 --- a/src/core/server/index.ts +++ b/src/core/server/index.ts @@ -508,3 +508,5 @@ export const config = { appenders: appendersSchema as Type, }, }; + +export { formatWorkspaces, workspacesValidator } from './workspaces'; diff --git a/src/core/server/saved_objects/routes/bulk_create.ts b/src/core/server/saved_objects/routes/bulk_create.ts index 61a458d9a618..a43a69464308 100644 --- a/src/core/server/saved_objects/routes/bulk_create.ts +++ b/src/core/server/saved_objects/routes/bulk_create.ts @@ -30,7 +30,7 @@ import { schema } from '@osd/config-schema'; import { IRouter } from '../../http'; -import { formatWorkspaces, workspacesValidator } from './utils'; +import { formatWorkspaces, workspacesValidator } from '../../workspaces'; export const registerBulkCreateRoute = (router: IRouter) => { router.post( diff --git a/src/core/server/saved_objects/routes/find.ts b/src/core/server/saved_objects/routes/find.ts index 447ec8f6d7de..2ee7005f8e4f 100644 --- a/src/core/server/saved_objects/routes/find.ts +++ b/src/core/server/saved_objects/routes/find.ts @@ -30,7 +30,7 @@ import { schema } from '@osd/config-schema'; import { IRouter } from '../../http'; -import { formatWorkspaces, workspacesValidator } from './utils'; +import { formatWorkspaces, workspacesValidator } from '../../workspaces'; export const registerFindRoute = (router: IRouter) => { router.get( diff --git a/src/core/server/saved_objects/routes/import.ts b/src/core/server/saved_objects/routes/import.ts index 794f8ef84a79..9675d608541c 100644 --- a/src/core/server/saved_objects/routes/import.ts +++ b/src/core/server/saved_objects/routes/import.ts @@ -34,7 +34,8 @@ import { schema } from '@osd/config-schema'; import { IRouter } from '../../http'; import { importSavedObjectsFromStream } from '../import'; import { SavedObjectConfig } from '../saved_objects_config'; -import { createSavedObjectsStreamFromNdJson, formatWorkspaces, workspacesValidator } from './utils'; +import { createSavedObjectsStreamFromNdJson } from './utils'; +import { formatWorkspaces, workspacesValidator } from '../../workspaces'; interface FileStream extends Readable { hapi: { diff --git a/src/core/server/saved_objects/routes/utils.ts b/src/core/server/saved_objects/routes/utils.ts index c2b77655ff18..73bedf20b942 100644 --- a/src/core/server/saved_objects/routes/utils.ts +++ b/src/core/server/saved_objects/routes/utils.ts @@ -27,7 +27,6 @@ * specific language governing permissions and limitations * under the License. */ -import { schema } from '@osd/config-schema'; import { Readable } from 'stream'; import { SavedObject, SavedObjectsExportResultDetails } from 'src/core/server'; import { @@ -74,19 +73,3 @@ export function validateObjects( .join(', ')}`; } } - -export const workspacesValidator = schema.maybe( - schema.oneOf([schema.string(), schema.arrayOf(schema.string())]) -); - -export function formatWorkspaces(workspaces?: string | string[]): string[] | undefined { - if (Array.isArray(workspaces)) { - return workspaces; - } - - if (!workspaces) { - return undefined; - } - - return [workspaces]; -} diff --git a/src/core/server/workspaces/index.ts b/src/core/server/workspaces/index.ts index 5441216c7314..28079e7a36b7 100644 --- a/src/core/server/workspaces/index.ts +++ b/src/core/server/workspaces/index.ts @@ -13,3 +13,4 @@ export { export { WorkspaceAttribute, WorkspaceFindOptions } from './types'; export { WorkspacePermissionControl } from './workspace_permission_control'; +export { workspacesValidator, formatWorkspaces } from './utils'; diff --git a/src/core/server/workspaces/utils.ts b/src/core/server/workspaces/utils.ts new file mode 100644 index 000000000000..955b49a1e5e3 --- /dev/null +++ b/src/core/server/workspaces/utils.ts @@ -0,0 +1,22 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { schema } from '@osd/config-schema'; + +export const workspacesValidator = schema.maybe( + schema.oneOf([schema.string(), schema.arrayOf(schema.string())]) +); + +export function formatWorkspaces(workspaces?: string | string[]): string[] | undefined { + if (Array.isArray(workspaces)) { + return workspaces; + } + + if (!workspaces) { + return undefined; + } + + return [workspaces]; +} diff --git a/src/plugins/saved_objects_management/public/lib/fetch_export_by_type_and_search.ts b/src/plugins/saved_objects_management/public/lib/fetch_export_by_type_and_search.ts index e5f716347a76..1af8ac210696 100644 --- a/src/plugins/saved_objects_management/public/lib/fetch_export_by_type_and_search.ts +++ b/src/plugins/saved_objects_management/public/lib/fetch_export_by_type_and_search.ts @@ -34,10 +34,12 @@ export async function fetchExportByTypeAndSearch( http: HttpStart, types: string[], search: string | undefined, - includeReferencesDeep: boolean = false + includeReferencesDeep: boolean = false, + body?: Record ): Promise { return http.post('/api/saved_objects/_export', { body: JSON.stringify({ + ...body, type: types, search, includeReferencesDeep, diff --git a/src/plugins/saved_objects_management/public/lib/fetch_export_objects.ts b/src/plugins/saved_objects_management/public/lib/fetch_export_objects.ts index b2e2ea0f9165..43afcfec3056 100644 --- a/src/plugins/saved_objects_management/public/lib/fetch_export_objects.ts +++ b/src/plugins/saved_objects_management/public/lib/fetch_export_objects.ts @@ -33,10 +33,12 @@ import { HttpStart } from 'src/core/public'; export async function fetchExportObjects( http: HttpStart, objects: any[], - includeReferencesDeep: boolean = false + includeReferencesDeep: boolean = false, + body?: Record ): Promise { return http.post('/api/saved_objects/_export', { body: JSON.stringify({ + ...body, objects, includeReferencesDeep, }), diff --git a/src/plugins/saved_objects_management/public/lib/get_saved_object_counts.ts b/src/plugins/saved_objects_management/public/lib/get_saved_object_counts.ts index 6eaaac7d35f2..9039dae2be53 100644 --- a/src/plugins/saved_objects_management/public/lib/get_saved_object_counts.ts +++ b/src/plugins/saved_objects_management/public/lib/get_saved_object_counts.ts @@ -34,6 +34,7 @@ export interface SavedObjectCountOptions { typesToInclude: string[]; namespacesToInclude?: string[]; searchString?: string; + workspaces?: string[]; } export async function getSavedObjectCounts( diff --git a/src/plugins/saved_objects_management/public/lib/import_file.ts b/src/plugins/saved_objects_management/public/lib/import_file.ts index 33d63ec9d192..e63241b0c3bf 100644 --- a/src/plugins/saved_objects_management/public/lib/import_file.ts +++ b/src/plugins/saved_objects_management/public/lib/import_file.ts @@ -40,11 +40,11 @@ interface ImportResponse { export async function importFile( http: HttpStart, file: File, - { createNewCopies, overwrite }: ImportMode + { createNewCopies, overwrite, workspaces }: ImportMode ) { const formData = new FormData(); formData.append('file', file); - const query = createNewCopies ? { createNewCopies } : { overwrite }; + const query = createNewCopies ? { createNewCopies, workspaces } : { overwrite, workspaces }; return await http.post('/api/saved_objects/_import', { body: formData, headers: { diff --git a/src/plugins/saved_objects_management/public/management_section/objects_table/components/flyout.tsx b/src/plugins/saved_objects_management/public/management_section/objects_table/components/flyout.tsx index ad082513b277..2479772550d5 100644 --- a/src/plugins/saved_objects_management/public/management_section/objects_table/components/flyout.tsx +++ b/src/plugins/saved_objects_management/public/management_section/objects_table/components/flyout.tsx @@ -92,6 +92,7 @@ export interface FlyoutProps { overlays: OverlayStart; http: HttpStart; search: DataPublicPluginStart['search']; + workspaces?: string[]; } export interface FlyoutState { @@ -183,13 +184,16 @@ export class Flyout extends Component { * Does the initial import of a file, resolveImportErrors then handles errors and retries */ import = async () => { - const { http } = this.props; + const { http, workspaces } = this.props; const { file, importMode } = this.state; this.setState({ status: 'loading', error: undefined }); // Import the file try { - const response = await importFile(http, file!, importMode); + const response = await importFile(http, file!, { + ...importMode, + workspaces, + }); this.setState(processImportResponse(response), () => { // Resolve import errors right away if there's no index patterns to match // This will ask about overwriting each object, etc diff --git a/src/plugins/saved_objects_management/public/management_section/objects_table/components/import_mode_control.tsx b/src/plugins/saved_objects_management/public/management_section/objects_table/components/import_mode_control.tsx index beabcfbb6308..9953b5353b85 100644 --- a/src/plugins/saved_objects_management/public/management_section/objects_table/components/import_mode_control.tsx +++ b/src/plugins/saved_objects_management/public/management_section/objects_table/components/import_mode_control.tsx @@ -51,6 +51,7 @@ export interface ImportModeControlProps { export interface ImportMode { createNewCopies: boolean; overwrite: boolean; + workspaces?: string[]; } const createNewCopiesDisabled = { 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 5a6bf0713d95..60791db07eba 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 @@ -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'; @@ -102,6 +103,7 @@ describe('SavedObjectsTable', () => { let notifications: ReturnType; let savedObjects: ReturnType; let search: ReturnType['search']; + let workspaces: ReturnType; const shallowRender = (overrides: Partial = {}) => { return (shallowWithI18nProvider( @@ -121,6 +123,7 @@ describe('SavedObjectsTable', () => { notifications = notificationServiceMock.createStartContract(); savedObjects = savedObjectsServiceMock.createStartContract(); search = dataPluginMock.createStartContract().search; + workspaces = workspacesServiceMock.createSetupContractMock(); const applications = applicationServiceMock.createStartContract(); applications.capabilities = { @@ -161,6 +164,7 @@ describe('SavedObjectsTable', () => { goInspectObject: () => {}, canGoInApp: () => true, search, + workspaces, }; findObjectsMock.mockImplementation(() => ({ @@ -279,7 +283,9 @@ describe('SavedObjectsTable', () => { await component.instance().onExport(true); - expect(fetchExportObjectsMock).toHaveBeenCalledWith(http, mockSelectedSavedObjects, true); + expect(fetchExportObjectsMock).toHaveBeenCalledWith(http, mockSelectedSavedObjects, true, { + workspaces: ['public'], + }); expect(notifications.toasts.addSuccess).toHaveBeenCalledWith({ title: 'Your file is downloading in the background', }); @@ -322,7 +328,9 @@ describe('SavedObjectsTable', () => { await component.instance().onExport(true); - expect(fetchExportObjectsMock).toHaveBeenCalledWith(http, mockSelectedSavedObjects, true); + expect(fetchExportObjectsMock).toHaveBeenCalledWith(http, mockSelectedSavedObjects, true, { + workspaces: ['public'], + }); expect(notifications.toasts.addWarning).toHaveBeenCalledWith({ title: 'Your file is downloading in the background. ' + @@ -363,7 +371,8 @@ describe('SavedObjectsTable', () => { http, allowedTypes, undefined, - true + true, + { workspaces: ['public'] } ); expect(saveAsMock).toHaveBeenCalledWith(blob, 'export.ndjson'); expect(notifications.toasts.addSuccess).toHaveBeenCalledWith({ @@ -393,7 +402,8 @@ describe('SavedObjectsTable', () => { http, allowedTypes, 'test*', - true + true, + { workspaces: ['public'] } ); 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 412047ba66f0..b91e5c0cb2a8 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 @@ -65,6 +65,7 @@ import { OverlayStart, NotificationsStart, ApplicationStart, + WorkspacesStart, } from 'src/core/public'; import { RedirectAppLinks } from '../../../../opensearch_dashboards_react/public'; import { IndexPatternsContract } from '../../../../data/public'; @@ -116,6 +117,7 @@ export interface SavedObjectsTableProps { dateFormat: string; title: string; fullWidth: boolean; + workspaces: WorkspacesStart; } export interface SavedObjectsTableState { @@ -137,6 +139,7 @@ export interface SavedObjectsTableState { exportAllOptions: ExportAllOption[]; exportAllSelectedOptions: Record; isIncludeReferencesDeepChecked: boolean; + workspaceId: string | null; } export class SavedObjectsTable extends Component { @@ -167,11 +170,21 @@ export class SavedObjectsTable extends Component + this.setState({ + workspaceId, + }) + ); this.fetchSavedObjects(); this.fetchCounts(); } @@ -192,6 +205,7 @@ export class SavedObjectsTable extends Component ns.id) || []; @@ -405,7 +421,9 @@ export class SavedObjectsTable extends Component { const { editUrl } = savedObject.meta; diff --git a/src/plugins/saved_objects_management/server/routes/find.ts b/src/plugins/saved_objects_management/server/routes/find.ts index dd49fc7575df..af1f96aae58a 100644 --- a/src/plugins/saved_objects_management/server/routes/find.ts +++ b/src/plugins/saved_objects_management/server/routes/find.ts @@ -34,6 +34,7 @@ import { DataSourceAttributes } from 'src/plugins/data_source/common/data_source import { getIndexPatternTitle } from '../../../data/common/index_patterns/utils'; import { injectMetaAttributes } from '../lib'; import { ISavedObjectsManagement } from '../services'; +import { formatWorkspaces, workspacesValidator } from '../../../../core/server'; export const registerFindRoute = ( router: IRouter, @@ -64,6 +65,7 @@ export const registerFindRoute = ( fields: schema.oneOf([schema.string(), schema.arrayOf(schema.string())], { defaultValue: [], }), + workspaces: workspacesValidator, }), }, }, @@ -94,6 +96,7 @@ export const registerFindRoute = ( ...req.query, fields: undefined, searchFields: [...searchFields], + workspaces: formatWorkspaces(req.query.workspaces), }); const savedObjects = await Promise.all( diff --git a/src/plugins/saved_objects_management/server/routes/scroll_count.ts b/src/plugins/saved_objects_management/server/routes/scroll_count.ts index 63233748a896..1ce7445c40f9 100644 --- a/src/plugins/saved_objects_management/server/routes/scroll_count.ts +++ b/src/plugins/saved_objects_management/server/routes/scroll_count.ts @@ -41,6 +41,7 @@ export const registerScrollForCountRoute = (router: IRouter) => { typesToInclude: schema.arrayOf(schema.string()), namespacesToInclude: schema.maybe(schema.arrayOf(schema.string())), searchString: schema.maybe(schema.string()), + workspaces: schema.maybe(schema.arrayOf(schema.string())), }), }, }, @@ -53,6 +54,7 @@ export const registerScrollForCountRoute = (router: IRouter) => { const findOptions: SavedObjectsFindOptions = { type: req.body.typesToInclude, perPage: 1000, + workspaces: req.body.workspaces, }; const requestHasNamespaces =