Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add datasource picker to import saved object flyout when multiple data source is enabled #5781

Merged
merged 4 commits into from
Feb 5, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
- [Custom Branding] Relative URL should be allowed for logos ([#5572](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/5572))
- [Discover] Enhanced the data source selector with added sorting functionality ([#5609](https://github.com/opensearch-project/OpenSearch-Dashboards/issues/5609))
- [Multiple Datasource] Add datasource picker component and use it in devtools and tutorial page when multiple datasource is enabled ([#5756](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/5756))
- [Multiple Datasource] Add datasource picker to import saved object flyout when multiple data source is enabled ([#5781](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/5781))

### 🐛 Bug Fixes

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ export class DataSourcePicker extends React.Component {
})}
compressed
isDisabled={this.props.disabled}
fullWidth={this.props.fullWidth || false}
/>
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@
"discover",
"home",
"visBuilder",
"visAugmenter"
"visAugmenter",
"dataSource"
],
"extraPublicDirs": ["public/lib"],
"requiredBundles": ["opensearchDashboardsReact", "home"]
"requiredBundles": ["opensearchDashboardsReact", "home", "dataSourceManagement"]
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,15 @@
export async function importFile(
http: HttpStart,
file: File,
{ createNewCopies, overwrite }: ImportMode
{ createNewCopies, overwrite }: ImportMode,
selectedDataSourceId?: string
) {
const formData = new FormData();
formData.append('file', file);
const query = createNewCopies ? { createNewCopies } : { overwrite };
if (selectedDataSourceId) {
query.dataSourceId = selectedDataSourceId;

Check warning on line 50 in src/plugins/saved_objects_management/public/lib/import_file.ts

View check run for this annotation

Codecov / codecov/patch

src/plugins/saved_objects_management/public/lib/import_file.ts#L50

Added line #L50 was not covered by tests
}
return await http.post<ImportResponse>('/api/saved_objects/_import', {
body: formData,
headers: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,12 +89,16 @@
http: HttpStart,
file: File,
retries: any,
createNewCopies: boolean
createNewCopies: boolean,
selectedDataSourceId?: string
): Promise<SavedObjectsImportResponse> {
const formData = new FormData();
formData.append('file', file);
formData.append('retries', JSON.stringify(retries));
const query = createNewCopies ? { createNewCopies } : {};
if (selectedDataSourceId) {
query.dataSourceId = selectedDataSourceId;

Check warning on line 100 in src/plugins/saved_objects_management/public/lib/resolve_import_errors.ts

View check run for this annotation

Codecov / codecov/patch

src/plugins/saved_objects_management/public/lib/resolve_import_errors.ts#L100

Added line #L100 was not covered by tests
}
return http.post<any>('/api/saved_objects/_resolve_import_errors', {
headers: {
// Important to be undefined, it forces proper headers to be set for FormData
Expand Down Expand Up @@ -167,6 +171,7 @@
http,
getConflictResolutions,
state,
selectedDataSourceId,
}: {
http: HttpStart;
getConflictResolutions: (
Expand All @@ -180,6 +185,7 @@
file?: File;
importMode: { createNewCopies: boolean; overwrite: boolean };
};
selectedDataSourceId: string;
}) {
const retryDecisionCache = new Map<string, RetryDecision>();
const replaceReferencesCache = new Map<string, Reference[]>();
Expand Down Expand Up @@ -264,7 +270,13 @@
}

// Call API
const response = await callResolveImportErrorsApi(http, file!, retries, createNewCopies);
const response = await callResolveImportErrorsApi(
http,
file!,
retries,
createNewCopies,
selectedDataSourceId
);
importCount = response.successCount; // reset the success count since we retry all successful results each time
failedImports = [];
for (const { error, ...obj } of response.errors || []) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ interface MountParams {
core: CoreSetup<StartDependencies, SavedObjectsManagementPluginStart>;
serviceRegistry: ISavedObjectsManagementServiceRegistry;
mountParams: ManagementAppMountParams;
dataSourceEnabled: boolean;
}

let allowedObjectTypes: string[] | undefined;
Expand All @@ -58,6 +59,7 @@ export const mountManagementSection = async ({
core,
mountParams,
serviceRegistry,
dataSourceEnabled,
}: MountParams) => {
const [coreStart, { data, uiActions }, pluginStart] = await core.getStartServices();
const { element, history, setBreadcrumbs } = mountParams;
Expand Down Expand Up @@ -108,6 +110,7 @@ export const mountManagementSection = async ({
namespaceRegistry={pluginStart.namespaces}
allowedTypes={allowedObjectTypes}
setBreadcrumbs={setBreadcrumbs}
dataSourceEnabled={dataSourceEnabled}
/>
</Suspense>
</RedirectToHomeIfUnauthorized>
Expand Down

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 @@ -192,10 +192,15 @@ describe('Flyout', () => {
component.setState({ file: mockFile, isLegacyFile: false });
await component.instance().import();

expect(importFileMock).toHaveBeenCalledWith(defaultProps.http, mockFile, {
createNewCopies: false,
overwrite: true,
});
expect(importFileMock).toHaveBeenCalledWith(
defaultProps.http,
mockFile,
{
createNewCopies: true,
overwrite: true,
},
undefined
);
expect(component.state()).toMatchObject({
conflictedIndexPatterns: undefined,
conflictedSavedObjectsLinkedToSavedSearches: undefined,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,11 @@
EuiCallOut,
EuiSpacer,
EuiLink,
EuiFormFieldset,
} from '@elastic/eui';
import { i18n } from '@osd/i18n';
import { FormattedMessage } from '@osd/i18n/react';
import { OverlayStart, HttpStart } from 'src/core/public';
import { OverlayStart, HttpStart, SavedObjectsStart } from 'src/core/public';
import {
IndexPatternsContract,
IIndexPattern,
Expand All @@ -78,8 +79,10 @@
import { OverwriteModal } from './overwrite_modal';
import { ImportModeControl, ImportMode } from './import_mode_control';
import { ImportSummary } from './import_summary';
// eslint-disable-next-line @osd/eslint/no-restricted-paths
BionIT marked this conversation as resolved.
Show resolved Hide resolved
import { DataSourcePicker } from '../../../../../data_source_management/public/components/data_source_picker/data_source_picker.js';
BionIT marked this conversation as resolved.
Show resolved Hide resolved

const CREATE_NEW_COPIES_DEFAULT = false;
const CREATE_NEW_COPIES_DEFAULT = true;
bandinib-amzn marked this conversation as resolved.
Show resolved Hide resolved
BionIT marked this conversation as resolved.
Show resolved Hide resolved
const OVERWRITE_ALL_DEFAULT = true;

export interface FlyoutProps {
Expand All @@ -92,6 +95,9 @@
overlays: OverlayStart;
http: HttpStart;
search: DataPublicPluginStart['search'];
dataSourceEnabled: boolean;
savedObjects: SavedObjectsClientContract;
notifications: NotificationsStart;
}

export interface FlyoutState {
Expand All @@ -110,6 +116,7 @@
loadingMessage?: string;
isLegacyFile: boolean;
status: string;
selectedDataSourceId: string;
}

interface ConflictingRecord {
Expand Down Expand Up @@ -184,12 +191,12 @@
*/
import = async () => {
const { http } = this.props;
const { file, importMode } = this.state;
const { file, importMode, selectedDataSourceId } = 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, 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,6 +258,7 @@
http: this.props.http,
state: this.state,
getConflictResolutions: this.getConflictResolutions,
selectedDataSourceId: this.state.selectedDataSourceId,
});
this.setState(updatedState);
} catch (e) {
Expand Down Expand Up @@ -618,6 +626,8 @@
importMode,
} = this.state;

const { dataSourceEnabled } = this.props;

if (status === 'loading') {
return (
<EuiFlexGroup justifyContent="spaceAround">
Expand Down Expand Up @@ -749,7 +759,7 @@
label={
<FormattedMessage
id="savedObjectsManagement.objectsTable.flyout.selectFileToImportFormRowLabel"
defaultMessage="Select a file to import"
defaultMessage="Select file"
/>
}
>
Expand All @@ -765,14 +775,70 @@
onChange={this.setImportFile}
/>
</EuiFormRow>

{this.renderImportControl(importMode, isLegacyFile, dataSourceEnabled)}
</EuiForm>
);
}

onSelectedDataSourceChange = (e) => {
const dataSourceId = e[0] ? e[0].id : undefined;
this.setState({ selectedDataSourceId: dataSourceId });

Check warning on line 786 in src/plugins/saved_objects_management/public/management_section/objects_table/components/flyout.tsx

View check run for this annotation

Codecov / codecov/patch

src/plugins/saved_objects_management/public/management_section/objects_table/components/flyout.tsx#L786

Added line #L786 was not covered by tests
};

renderImportControl(importMode: ImportMode, isLegacyFile: boolean, dataSourceEnabled: boolean) {
if (dataSourceEnabled) {
return this.renderImportControlForDataSource(importMode, isLegacyFile);

Check warning on line 791 in src/plugins/saved_objects_management/public/management_section/objects_table/components/flyout.tsx

View check run for this annotation

Codecov / codecov/patch

src/plugins/saved_objects_management/public/management_section/objects_table/components/flyout.tsx#L791

Added line #L791 was not covered by tests
}
return (
<EuiFormRow fullWidth>
<ImportModeControl
initialValues={importMode}
isLegacyFile={isLegacyFile}
updateSelection={(newValues: ImportMode) => this.changeImportMode(newValues)}

Check warning on line 798 in src/plugins/saved_objects_management/public/management_section/objects_table/components/flyout.tsx

View check run for this annotation

Codecov / codecov/patch

src/plugins/saved_objects_management/public/management_section/objects_table/components/flyout.tsx#L798

Added line #L798 was not covered by tests
optionLabel={i18n.translate(
'savedObjectsManagement.objectsTable.importModeControl.importOptionsTitle',
{ defaultMessage: 'Import options' }
)}
/>
</EuiFormRow>
);
}

renderImportControlForDataSource(importMode: ImportMode, isLegacyFile: boolean) {
return (

Check warning on line 809 in src/plugins/saved_objects_management/public/management_section/objects_table/components/flyout.tsx

View check run for this annotation

Codecov / codecov/patch

src/plugins/saved_objects_management/public/management_section/objects_table/components/flyout.tsx#L809

Added line #L809 was not covered by tests
<div className="savedObjectImportControlForDataSource">
<EuiSpacer />
<EuiFormFieldset
legend={{
children: (
<EuiTitle size="xs">
<span>Import options</span>
</EuiTitle>
),
}}
>
<DataSourcePicker
savedObjectsClient={this.props.savedObjects}
notifications={this.props.notifications.toasts}
onSelectedDataSource={this.onSelectedDataSourceChange}
disabled={!this.props.dataSourceEnabled}
fullWidth={true}
/>
</EuiFormFieldset>
<EuiSpacer />
<EuiFormRow fullWidth>
<ImportModeControl
initialValues={importMode}
isLegacyFile={isLegacyFile}
updateSelection={(newValues: ImportMode) => this.changeImportMode(newValues)}
optionLabel={i18n.translate(
'savedObjectsManagement.objectsTable.importModeControl.importOptionsTitle',
{ defaultMessage: 'Conflict management' }
)}
/>
</EuiFormRow>
</EuiForm>
</div>
);
}

Expand Down
Loading
Loading