Skip to content

Commit

Permalink
feat: consume current workspace in saved objects management and saved…
Browse files Browse the repository at this point in the history
… objects client (opensearch-project#261)

* feat: consume current workspace in saved objects management and saved objects client

Signed-off-by: SuZhou-Joe <suzhou@amazon.com>

* feat: add unit test

Signed-off-by: SuZhou-Joe <suzhou@amazon.com>

* feat: add unit test for each change

Signed-off-by: SuZhou-Joe <suzhou@amazon.com>

* fix: update snapshot of unit test

Signed-off-by: SuZhou-Joe <suzhou@amazon.com>

* fix: unit test

Signed-off-by: SuZhou-Joe <suzhou@amazon.com>

* fix: unit test

Signed-off-by: SuZhou-Joe <suzhou@amazon.com>

* fix: unit test

Signed-off-by: SuZhou-Joe <suzhou@amazon.com>

---------

Signed-off-by: SuZhou-Joe <suzhou@amazon.com>
  • Loading branch information
SuZhou-Joe committed Mar 18, 2024
1 parent b7a4a28 commit a6f2f3f
Show file tree
Hide file tree
Showing 25 changed files with 410 additions and 33 deletions.
2 changes: 1 addition & 1 deletion src/core/public/saved_objects/saved_objects_client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,7 @@ export class SavedObjectsClient {
* @returns The result of the create operation containing created saved objects.
*/
public bulkCreate = (
objects: SavedObjectsBulkCreateObject[] = [],
objects: Array<Omit<SavedObjectsBulkCreateObject, 'workspaces'>> = [],
options: SavedObjectsBulkCreateOptions = { overwrite: false }
) => {
const path = this.getPath(['_bulk_create']);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -866,6 +866,9 @@ describe('getSortedObjectsForExport()', () => {
],
Object {
namespace: undefined,
workspaces: Array [
foo,
],
},
],
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ async function fetchObjectsToExport({
}
const bulkGetResult = await savedObjectsClient.bulkGet(objects, {
namespace,
...(workspaces ? { workspaces } : {}),
});
const erroredObjects = bulkGetResult.saved_objects.filter((obj) => !!obj.error);
if (erroredObjects.length) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,12 @@ export async function fetchExportByTypeAndSearch(
http: HttpStart,
types: string[],
search: string | undefined,
includeReferencesDeep: boolean = false
includeReferencesDeep: boolean = false,
body?: Record<string, unknown>
): Promise<Blob> {
return http.post('/api/saved_objects/_export', {
body: JSON.stringify({
...body,
type: types,
search,
includeReferencesDeep,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

import { fetchExportObjects } from './fetch_export_objects';
import { httpServiceMock } from '../../../../core/public/mocks';

describe('fetchExportObjects', () => {
it('make http call with body provided', async () => {
const httpClient = httpServiceMock.createStartContract();
await fetchExportObjects(httpClient, [], false, {
workspaces: ['foo'],
});
expect(httpClient.post).toMatchInlineSnapshot(`
[MockFunction] {
"calls": Array [
Array [
"/api/saved_objects/_export",
Object {
"body": "{\\"workspaces\\":[\\"foo\\"],\\"objects\\":[],\\"includeReferencesDeep\\":false}",
},
],
],
"results": Array [
Object {
"type": "return",
"value": undefined,
},
],
}
`);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -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<string, unknown>
): Promise<Blob> {
return http.post('/api/saved_objects/_export', {
body: JSON.stringify({
...body,
objects,
includeReferencesDeep,
}),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ export interface SavedObjectCountOptions {
typesToInclude: string[];
namespacesToInclude?: string[];
searchString?: string;
workspaces?: string[];
}

export async function getSavedObjectCounts(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

import { importFile } from './import_file';
import { httpServiceMock } from '../../../../core/public/mocks';

describe('importFile', () => {
it('make http call with body provided', async () => {
const httpClient = httpServiceMock.createStartContract();
const blob = new Blob(['']);
await importFile(httpClient, new File([blob], 'foo.ndjson'), {
overwrite: true,
createNewCopies: false,
workspaces: ['foo'],
});
expect(httpClient.post).toMatchInlineSnapshot(`
[MockFunction] {
"calls": Array [
Array [
"/api/saved_objects/_import",
Object {
"body": FormData {},
"headers": Object {
"Content-Type": undefined,
},
"query": Object {
"overwrite": true,
"workspaces": Array [
"foo",
],
},
},
],
],
"results": Array [
Object {
"type": "return",
"value": undefined,
},
],
}
`);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,12 @@ interface ImportResponse {
export async function importFile(
http: HttpStart,
file: File,
{ createNewCopies, overwrite }: ImportMode,
{ createNewCopies, overwrite, workspaces }: ImportMode,
selectedDataSourceId?: string
) {
const formData = new FormData();
formData.append('file', file);
const query = createNewCopies ? { createNewCopies } : { overwrite };
const query = createNewCopies ? { createNewCopies, workspaces } : { overwrite, workspaces };
if (selectedDataSourceId) {
query.dataSourceId = selectedDataSourceId;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -303,4 +303,69 @@ describe('resolveImportErrors', () => {
}
`);
});

test('make http calls with workspaces', async () => {
httpMock.post.mockResolvedValueOnce({
success: false,
successCount: 0,
errors: [{ type: 'a', id: '1', error: { type: 'conflict' } }],
});
httpMock.post.mockResolvedValueOnce({
success: true,
successCount: 1,
successResults: [{ type: 'a', id: '1' }],
});
getConflictResolutions.mockResolvedValueOnce({});
getConflictResolutions.mockResolvedValueOnce({
'a:1': { retry: true, options: { overwrite: true } },
});
await resolveImportErrors({
http: httpMock,
getConflictResolutions,
state: {
importCount: 0,
unmatchedReferences: [{ existingIndexPatternId: '2', newIndexPatternId: '3', list: [] }],
failedImports: [
{
obj: { type: 'a', id: '1', meta: {} },
error: { type: 'missing_references', references: [{ type: 'index-pattern', id: '2' }] },
},
],
importMode: { createNewCopies: false, overwrite: false },
},
workspaces: ['foo'],
});
expect(httpMock.post.mock.calls).toMatchInlineSnapshot(`
Array [
Array [
"/api/saved_objects/_resolve_import_errors",
Object {
"body": FormData {},
"headers": Object {
"Content-Type": undefined,
},
"query": Object {
"workspaces": Array [
"foo",
],
},
},
],
Array [
"/api/saved_objects/_resolve_import_errors",
Object {
"body": FormData {},
"headers": Object {
"Content-Type": undefined,
},
"query": Object {
"workspaces": Array [
"foo",
],
},
},
],
]
`);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -90,12 +90,13 @@ async function callResolveImportErrorsApi(
file: File,
retries: any,
createNewCopies: boolean,
selectedDataSourceId?: string
selectedDataSourceId?: string,
workspaces?: string[]
): Promise<SavedObjectsImportResponse> {
const formData = new FormData();
formData.append('file', file);
formData.append('retries', JSON.stringify(retries));
const query = createNewCopies ? { createNewCopies } : {};
const query = createNewCopies ? { createNewCopies, workspaces } : { workspaces };
if (selectedDataSourceId) {
query.dataSourceId = selectedDataSourceId;
}
Expand Down Expand Up @@ -172,6 +173,7 @@ export async function resolveImportErrors({
getConflictResolutions,
state,
selectedDataSourceId,
workspaces,
}: {
http: HttpStart;
getConflictResolutions: (
Expand All @@ -186,6 +188,7 @@ export async function resolveImportErrors({
importMode: { createNewCopies: boolean; overwrite: boolean };
};
selectedDataSourceId: string;
workspaces?: string[];
}) {
const retryDecisionCache = new Map<string, RetryDecision>();
const replaceReferencesCache = new Map<string, Reference[]>();
Expand Down Expand Up @@ -275,7 +278,8 @@ export async function resolveImportErrors({
file!,
retries,
createNewCopies,
selectedDataSourceId
selectedDataSourceId,
workspaces
);
importCount = response.successCount; // reset the success count since we retry all successful results each time
failedImports = [];
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

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 @@ -184,6 +184,29 @@ describe('Flyout', () => {
);
});

it('should call importFile / resolveImportErrors with workspaces', async () => {
const component = shallowRender({ ...defaultProps, workspaces: ['foo'] });

// Ensure all promises resolve
await new Promise((resolve) => process.nextTick(resolve));
// Ensure the state changes are reflected
component.update();

await component.instance().import();
expect(importFileMock.mock.calls[0][2]).toMatchInlineSnapshot(`
Object {
"createNewCopies": true,
"overwrite": true,
"workspaces": Array [
"foo",
],
}
`);

await component.instance().resolveImportErrors();
expect(resolveImportErrorsMock.mock.calls[0][0].workspaces).toEqual(['foo']);
});

describe('conflicts', () => {
beforeEach(() => {
importFileMock.mockImplementation(() => ({
Expand All @@ -206,6 +229,7 @@ describe('Flyout', () => {
},
],
}));
resolveImportErrorsMock.mockClear();
resolveImportErrorsMock.mockImplementation(() => ({
status: 'success',
importCount: 1,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ export interface FlyoutProps {
hideLocalCluster: boolean;
savedObjects: SavedObjectsClientContract;
notifications: NotificationsStart;
workspaces?: string[];
}

export interface FlyoutState {
Expand Down Expand Up @@ -189,13 +190,21 @@ export class Flyout extends Component<FlyoutProps, FlyoutState> {
* 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, selectedDataSourceId } = this.state;
this.setState({ status: 'loading', error: undefined });

// Import the file
try {
const response = await importFile(http, file!, importMode, selectedDataSourceId);
const response = await importFile(
http,
file!,
{
...importMode,
workspaces,
},
selectedDataSourceId
);
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
Expand Down Expand Up @@ -251,13 +260,15 @@ export class Flyout extends Component<FlyoutProps, FlyoutState> {
status: 'loading',
loadingMessage: undefined,
});
const { workspaces } = this.props;

try {
const updatedState = await resolveImportErrors({
http: this.props.http,
state: this.state,
getConflictResolutions: this.getConflictResolutions,
selectedDataSourceId: this.state.selectedDataSourceId,
workspaces,
});
this.setState(updatedState);
} catch (e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ export interface ImportModeControlProps {
export interface ImportMode {
createNewCopies: boolean;
overwrite: boolean;
workspaces?: string[];
}

const createNewCopiesDisabled = {
Expand Down
Loading

0 comments on commit a6f2f3f

Please sign in to comment.