Removes support for legacy exports (#110738)

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Christiane (Tina) Heiligers 2021-09-03 07:22:14 -07:00 committed by GitHub
parent ed18699e38
commit 66cb058fa7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
21 changed files with 32 additions and 1530 deletions

View file

@ -238,7 +238,6 @@ exports[`Flyout conflicts should allow conflict resolution 2`] = `
"title": undefined,
},
],
"isLegacyFile": false,
"loadingMessage": undefined,
"status": "loading",
"successfulImports": Array [],
@ -276,278 +275,6 @@ exports[`Flyout conflicts should allow conflict resolution 2`] = `
}
`;
exports[`Flyout legacy conflicts should allow conflict resolution 1`] = `
<EuiFlyout
data-test-subj="importSavedObjectsFlyout"
onClose={[MockFunction]}
size="s"
>
<EuiFlyoutHeader
hasBorder={true}
>
<EuiTitle
size="m"
>
<h2>
<FormattedMessage
defaultMessage="Import saved objects"
id="savedObjectsManagement.objectsTable.flyout.importSavedObjectTitle"
values={Object {}}
/>
</h2>
</EuiTitle>
</EuiFlyoutHeader>
<EuiFlyoutBody>
<span>
<EuiSpacer
size="s"
/>
<EuiCallOut
color="warning"
data-test-subj="importSavedObjectsLegacyWarning"
iconType="help"
title={
<FormattedMessage
defaultMessage="Support for JSON files is going away"
id="savedObjectsManagement.objectsTable.flyout.legacyFileUsedTitle"
values={Object {}}
/>
}
>
<p>
<FormattedMessage
defaultMessage="Use our updated export to generate NDJSON files, and you'll be all set."
id="savedObjectsManagement.objectsTable.flyout.legacyFileUsedBody"
values={Object {}}
/>
</p>
</EuiCallOut>
<EuiSpacer
size="m"
/>
</span>
<span>
<EuiSpacer
size="s"
/>
<EuiCallOut
color="warning"
data-test-subj="importSavedObjectsConflictsWarning"
iconType="help"
title={
<FormattedMessage
defaultMessage="Index Pattern Conflicts"
id="savedObjectsManagement.objectsTable.flyout.indexPatternConflictsTitle"
values={Object {}}
/>
}
>
<p>
<FormattedMessage
defaultMessage="The following saved objects use index patterns that do not exist. Please select the index patterns you'd like re-associated with them. You can {indexPatternLink} if necessary."
id="savedObjectsManagement.objectsTable.flyout.indexPatternConflictsDescription"
values={
Object {
"indexPatternLink": <EuiLink
href=""
>
<FormattedMessage
defaultMessage="create a new index pattern"
id="savedObjectsManagement.objectsTable.flyout.indexPatternConflictsCalloutLinkText"
values={Object {}}
/>
</EuiLink>,
}
}
/>
</p>
</EuiCallOut>
</span>
<EuiInMemoryTable
columns={
Array [
Object {
"description": "ID of the index pattern",
"field": "existingIndexPatternId",
"name": "ID",
"sortable": true,
},
Object {
"description": "How many affected objects",
"field": "list",
"name": "Count",
"render": [Function],
},
Object {
"description": "Sample of affected objects",
"field": "list",
"name": "Sample of affected objects",
"render": [Function],
},
Object {
"field": "existingIndexPatternId",
"name": "New index pattern",
"render": [Function],
},
]
}
items={
Array [
Object {
"existingIndexPatternId": "MyIndexPattern*",
"list": Array [
Object {
"id": "MyIndexPattern*",
"title": "MyIndexPattern*",
"type": "index-pattern",
},
],
"newIndexPatternId": undefined,
},
Object {
"existingIndexPatternId": "filterIndex",
"list": Array [
Object {
"id": "filterIndex",
"title": "MyIndexPattern*",
"type": "index-pattern",
},
],
"newIndexPatternId": undefined,
},
]
}
onTableChange={[Function]}
pagination={
Object {
"pageIndex": 0,
"pageSize": 5,
"pageSizeOptions": Array [
5,
10,
25,
],
}
}
responsive={true}
tableLayout="fixed"
/>
</EuiFlyoutBody>
<EuiFlyoutFooter>
<EuiFlexGroup
justifyContent="spaceBetween"
>
<EuiFlexItem
grow={false}
>
<EuiButtonEmpty
data-test-subj="importSavedObjectsCancelBtn"
disabled={false}
onClick={[MockFunction]}
size="s"
>
<FormattedMessage
defaultMessage="Cancel"
id="savedObjectsManagement.objectsTable.flyout.import.cancelButtonLabel"
values={Object {}}
/>
</EuiButtonEmpty>
</EuiFlexItem>
<EuiFlexItem
grow={false}
>
<EuiButton
data-test-subj="importSavedObjectsConfirmBtn"
fill={true}
isLoading={false}
onClick={[Function]}
size="s"
>
<FormattedMessage
defaultMessage="Confirm all changes"
id="savedObjectsManagement.objectsTable.flyout.importSuccessful.confirmAllChangesButtonLabel"
values={Object {}}
/>
</EuiButton>
</EuiFlexItem>
</EuiFlexGroup>
</EuiFlyoutFooter>
</EuiFlyout>
`;
exports[`Flyout legacy conflicts should handle errors 2`] = `
Array [
<EuiCallOut
color="warning"
data-test-subj="importSavedObjectsLegacyWarning"
iconType="help"
title={
<FormattedMessage
defaultMessage="Support for JSON files is going away"
id="savedObjectsManagement.objectsTable.flyout.legacyFileUsedTitle"
values={Object {}}
/>
}
>
<p>
<FormattedMessage
defaultMessage="Use our updated export to generate NDJSON files, and you'll be all set."
id="savedObjectsManagement.objectsTable.flyout.legacyFileUsedBody"
values={Object {}}
/>
</p>
</EuiCallOut>,
<EuiCallOut
color="warning"
data-test-subj="importSavedObjectsConflictsWarning"
iconType="help"
title={
<FormattedMessage
defaultMessage="Index Pattern Conflicts"
id="savedObjectsManagement.objectsTable.flyout.indexPatternConflictsTitle"
values={Object {}}
/>
}
>
<p>
<FormattedMessage
defaultMessage="The following saved objects use index patterns that do not exist. Please select the index patterns you'd like re-associated with them. You can {indexPatternLink} if necessary."
id="savedObjectsManagement.objectsTable.flyout.indexPatternConflictsDescription"
values={
Object {
"indexPatternLink": <EuiLink
href=""
>
<FormattedMessage
defaultMessage="create a new index pattern"
id="savedObjectsManagement.objectsTable.flyout.indexPatternConflictsCalloutLinkText"
values={Object {}}
/>
</EuiLink>,
}
}
/>
</p>
</EuiCallOut>,
<EuiCallOut
color="danger"
title={
<FormattedMessage
defaultMessage="Sorry, there was an error"
id="savedObjectsManagement.objectsTable.flyout.errorCalloutTitle"
values={Object {}}
/>
}
>
<p
data-test-subj="importSavedObjectsErrorText"
>
The file could not be processed due to error: "foobar"
</p>
</EuiCallOut>,
]
`;
exports[`Flyout should render import step 1`] = `
<EuiFlyout
data-test-subj="importSavedObjectsFlyout"
@ -593,7 +320,7 @@ exports[`Flyout should render import step 1`] = `
labelType="label"
>
<EuiFilePicker
accept=".ndjson, .json"
accept=".ndjson"
compressed={false}
display="large"
fullWidth={true}
@ -622,7 +349,6 @@ exports[`Flyout should render import step 1`] = `
"overwrite": true,
}
}
isLegacyFile={false}
updateSelection={[Function]}
/>
</EuiFormRow>

View file

@ -16,11 +16,6 @@ jest.doMock('../../../lib/resolve_import_errors', () => ({
resolveImportErrors: resolveImportErrorsMock,
}));
export const importLegacyFileMock = jest.fn();
jest.doMock('../../../lib/import_legacy_file', () => ({
importLegacyFile: importLegacyFileMock,
}));
export const resolveSavedObjectsMock = jest.fn();
export const resolveSavedSearchesMock = jest.fn();
export const resolveIndexPatternConflictsMock = jest.fn();

View file

@ -6,15 +6,7 @@
* Side Public License, v 1.
*/
import {
importFileMock,
importLegacyFileMock,
resolveImportErrorsMock,
resolveIndexPatternConflictsMock,
resolveSavedObjectsMock,
resolveSavedSearchesMock,
saveObjectsMock,
} from './flyout.test.mocks';
import { importFileMock, resolveImportErrorsMock } from './flyout.test.mocks';
import React from 'react';
import { shallowWithI18nProvider } from '@kbn/test/jest';
@ -28,10 +20,6 @@ const mockFile = ({
name: 'foo.ndjson',
path: '/home/foo.ndjson',
} as unknown) as File;
const legacyMockFile = ({
name: 'foo.json',
path: '/home/foo.json',
} as unknown) as File;
describe('Flyout', () => {
let defaultProps: FlyoutProps;
@ -107,31 +95,6 @@ describe('Flyout', () => {
expect(component.state('file')).toBe(undefined);
});
it('should handle invalid files', async () => {
const component = shallowRender(defaultProps);
// Ensure all promises resolve
await new Promise((resolve) => process.nextTick(resolve));
// Ensure the state changes are reflected
component.update();
importLegacyFileMock.mockImplementation(() => {
throw new Error('foobar');
});
await component.instance().legacyImport();
expect(component.state('error')).toBe('The file could not be processed.');
importLegacyFileMock.mockImplementation(() => ({
invalid: true,
}));
await component.instance().legacyImport();
expect(component.state('error')).toBe(
'Saved objects file format is invalid and cannot be imported.'
);
});
describe('conflicts', () => {
beforeEach(() => {
importFileMock.mockImplementation(() => ({
@ -169,7 +132,7 @@ describe('Flyout', () => {
// Ensure the state changes are reflected
component.update();
component.setState({ file: mockFile, isLegacyFile: false });
component.setState({ file: mockFile });
await component.instance().import();
expect(importFileMock).toHaveBeenCalledWith(defaultProps.http, mockFile, {
@ -207,7 +170,7 @@ describe('Flyout', () => {
// Ensure the state changes are reflected
component.update();
component.setState({ file: mockFile, isLegacyFile: false });
component.setState({ file: mockFile });
await component.instance().import();
// Ensure it looks right
@ -250,7 +213,7 @@ describe('Flyout', () => {
successfulImports,
}));
component.setState({ file: mockFile, isLegacyFile: false });
component.setState({ file: mockFile });
// Go through the import flow
await component.instance().import();
@ -267,194 +230,4 @@ describe('Flyout', () => {
expect(cancelButton.prop('disabled')).toBe(true);
});
});
describe('legacy conflicts', () => {
const mockData = [
{
_id: '1',
_type: 'search',
},
{
_id: '2',
_type: 'index-pattern',
},
{
_id: '3',
_type: 'invalid',
},
];
const mockConflictedIndexPatterns = [
{
doc: {
_type: 'index-pattern',
_id: '1',
_source: {
title: 'MyIndexPattern*',
},
},
obj: {
searchSource: {
getOwnField: (field: string) => {
if (field === 'index') {
return 'MyIndexPattern*';
}
if (field === 'filter') {
return [{ meta: { index: 'filterIndex' } }];
}
},
},
_serialize: () => {
return { references: [{ id: 'MyIndexPattern*' }, { id: 'filterIndex' }] };
},
},
},
];
const mockConflictedSavedObjectsLinkedToSavedSearches = [2];
const mockConflictedSearchDocs = [3];
beforeEach(() => {
importLegacyFileMock.mockImplementation(() => mockData);
resolveSavedObjectsMock.mockImplementation(() => ({
conflictedIndexPatterns: mockConflictedIndexPatterns,
conflictedSavedObjectsLinkedToSavedSearches: mockConflictedSavedObjectsLinkedToSavedSearches,
conflictedSearchDocs: mockConflictedSearchDocs,
importedObjectCount: 2,
confirmModalPromise: () => {},
}));
});
it('should figure out unmatchedReferences', async () => {
const component = shallowRender(defaultProps);
// Ensure all promises resolve
await new Promise((resolve) => process.nextTick(resolve));
// Ensure the state changes are reflected
component.update();
component.setState({ file: legacyMockFile, isLegacyFile: true });
await component.instance().legacyImport();
expect(importLegacyFileMock).toHaveBeenCalledWith(legacyMockFile);
// Remove the last element from data since it should be filtered out
expect(resolveSavedObjectsMock).toHaveBeenCalledWith(
mockData.slice(0, 2).map((doc) => ({ ...doc, _migrationVersion: {} })),
true,
defaultProps.serviceRegistry.all().map((s) => s.service),
defaultProps.indexPatterns,
defaultProps.overlays.openConfirm
);
expect(component.state()).toMatchObject({
conflictedIndexPatterns: mockConflictedIndexPatterns,
conflictedSavedObjectsLinkedToSavedSearches: mockConflictedSavedObjectsLinkedToSavedSearches,
conflictedSearchDocs: mockConflictedSearchDocs,
importCount: 2,
status: 'idle',
error: undefined,
unmatchedReferences: [
{
existingIndexPatternId: 'MyIndexPattern*',
newIndexPatternId: undefined,
list: [
{
id: 'MyIndexPattern*',
title: 'MyIndexPattern*',
type: 'index-pattern',
},
],
},
{
existingIndexPatternId: 'filterIndex',
list: [
{
id: 'filterIndex',
title: 'MyIndexPattern*',
type: 'index-pattern',
},
],
newIndexPatternId: undefined,
},
],
});
});
it('should allow conflict resolution', async () => {
const component = shallowRender(defaultProps);
// Ensure all promises resolve
await new Promise((resolve) => process.nextTick(resolve));
// Ensure the state changes are reflected
component.update();
component.setState({ file: legacyMockFile, isLegacyFile: true });
await component.instance().legacyImport();
// Ensure it looks right
component.update();
expect(component).toMatchSnapshot();
// Ensure we can change the resolution
component.instance().onIndexChanged('MyIndexPattern*', { target: { value: '2' } });
expect(component.state('unmatchedReferences')![0].newIndexPatternId).toBe('2');
// Let's resolve now
await component
.find('EuiButton[data-test-subj="importSavedObjectsConfirmBtn"]')
.simulate('click');
// Ensure all promises resolve
await new Promise((resolve) => process.nextTick(resolve));
expect(resolveIndexPatternConflictsMock).toHaveBeenCalledWith(
component.instance().resolutions,
mockConflictedIndexPatterns,
true,
{
search: defaultProps.search,
indexPatterns: defaultProps.indexPatterns,
}
);
expect(saveObjectsMock).toHaveBeenCalledWith(
mockConflictedSavedObjectsLinkedToSavedSearches,
true
);
expect(resolveSavedSearchesMock).toHaveBeenCalledWith(
mockConflictedSearchDocs,
defaultProps.serviceRegistry.all().map((s) => s.service),
defaultProps.indexPatterns,
true
);
});
it('should handle errors', async () => {
const component = shallowRender(defaultProps);
// Ensure all promises resolve
await new Promise((resolve) => process.nextTick(resolve));
// Ensure the state changes are reflected
component.update();
resolveIndexPatternConflictsMock.mockImplementation(() => {
throw new Error('foobar');
});
component.setState({ file: legacyMockFile, isLegacyFile: true });
// Go through the import flow
await component.instance().legacyImport();
component.update();
// Set a resolution
component.instance().onIndexChanged('MyIndexPattern*', { target: { value: '2' } });
await component
.find('EuiButton[data-test-subj="importSavedObjectsConfirmBtn"]')
.simulate('click');
// Ensure all promises resolve
await new Promise((resolve) => process.nextTick(resolve));
expect(component.state('error')).toMatchInlineSnapshot(
`"The file could not be processed due to error: \\"foobar\\""`
);
expect(component.find('EuiFlyoutBody EuiCallOut')).toMatchSnapshot();
});
});
});

View file

@ -7,7 +7,7 @@
*/
import React, { Component, Fragment, ReactNode } from 'react';
import { take, get as getField } from 'lodash';
import { take } from 'lodash';
import {
EuiFlyout,
EuiFlyoutBody,
@ -39,18 +39,10 @@ import {
} from '../../../../../data/public';
import {
importFile,
importLegacyFile,
resolveImportErrors,
logLegacyImport,
processImportResponse,
ProcessedImportResponse,
} from '../../../lib';
import {
resolveSavedObjects,
resolveSavedSearches,
resolveIndexPatternConflicts,
saveObjects,
} from '../../../lib/resolve_saved_objects';
import { ISavedObjectsManagementServiceRegistry } from '../../../services';
import { FailedImportConflict, RetryDecision } from '../../../lib/resolve_import_errors';
import { OverwriteModal } from './overwrite_modal';
@ -89,7 +81,6 @@ export interface FlyoutState {
indexPatterns?: IndexPattern[];
importMode: ImportMode;
loadingMessage?: string;
isLegacyFile: boolean;
status: string;
}
@ -129,7 +120,6 @@ export class Flyout extends Component<FlyoutProps, FlyoutState> {
indexPatterns: undefined,
importMode: { createNewCopies: CREATE_NEW_COPIES_DEFAULT, overwrite: OVERWRITE_ALL_DEFAULT },
loadingMessage: undefined,
isLegacyFile: false,
status: 'idle',
};
}
@ -152,14 +142,11 @@ export class Flyout extends Component<FlyoutProps, FlyoutState> {
setImportFile = (files: FileList | null) => {
if (!files || !files[0]) {
this.setState({ file: undefined, isLegacyFile: false });
this.setState({ file: undefined });
return;
}
const file = files[0];
this.setState({
file,
isLegacyFile: /\.json$/i.test(file.name) || file.type === 'application/json',
});
this.setState({ file });
};
/**
@ -246,103 +233,6 @@ export class Flyout extends Component<FlyoutProps, FlyoutState> {
}
};
legacyImport = async () => {
const { serviceRegistry, indexPatterns, overlays, http, allowedTypes } = this.props;
const { file, importMode } = this.state;
this.setState({ status: 'loading', error: undefined });
// Log warning on server, don't wait for response
logLegacyImport(http);
let contents;
try {
contents = await importLegacyFile(file!);
} catch (e) {
this.setState({
status: 'error',
error: i18n.translate(
'savedObjectsManagement.objectsTable.flyout.importLegacyFileErrorMessage',
{ defaultMessage: 'The file could not be processed.' }
),
});
return;
}
if (!Array.isArray(contents)) {
this.setState({
status: 'error',
error: i18n.translate(
'savedObjectsManagement.objectsTable.flyout.invalidFormatOfImportedFileErrorMessage',
{ defaultMessage: 'Saved objects file format is invalid and cannot be imported.' }
),
});
return;
}
contents = contents
.filter((content) => allowedTypes.includes(content._type))
.map((doc) => ({
...doc,
// The server assumes that documents with no migrationVersion are up to date.
// That assumption enables Kibana and other API consumers to not have to build
// up migrationVersion prior to creating new objects. But it means that imports
// need to set migrationVersion to something other than undefined, so that imported
// docs are not seen as automatically up-to-date.
_migrationVersion: doc._migrationVersion || {},
}));
const {
conflictedIndexPatterns,
conflictedSavedObjectsLinkedToSavedSearches,
conflictedSearchDocs,
importedObjectCount,
failedImports,
} = await resolveSavedObjects(
contents,
importMode.overwrite,
serviceRegistry.all().map((e) => e.service),
indexPatterns,
overlays.openConfirm
);
const byId: Record<string, any[]> = {};
conflictedIndexPatterns
.map(({ doc, obj }) => {
return { doc, obj: obj._serialize() };
})
.forEach(({ doc, obj }) =>
obj.references.forEach((ref: Record<string, any>) => {
byId[ref.id] = byId[ref.id] != null ? byId[ref.id].concat({ doc, obj }) : [{ doc, obj }];
})
);
const unmatchedReferences = Object.entries(byId).reduce(
(accum, [existingIndexPatternId, list]) => {
accum.push({
existingIndexPatternId,
newIndexPatternId: undefined,
list: list.map(({ doc }) => ({
id: existingIndexPatternId,
type: doc._type,
title: doc._source.title,
})),
});
return accum;
},
[] as any[]
);
this.setState({
conflictedIndexPatterns,
conflictedSavedObjectsLinkedToSavedSearches,
conflictedSearchDocs,
failedImports,
unmatchedReferences,
importCount: importedObjectCount,
status: unmatchedReferences.length === 0 ? 'success' : 'idle',
});
};
public get hasUnmatchedReferences() {
return this.state.unmatchedReferences && this.state.unmatchedReferences.length > 0;
}
@ -362,89 +252,6 @@ export class Flyout extends Component<FlyoutProps, FlyoutState> {
);
}
confirmLegacyImport = async () => {
const {
conflictedIndexPatterns,
importMode,
conflictedSavedObjectsLinkedToSavedSearches,
conflictedSearchDocs,
failedImports,
} = this.state;
const { serviceRegistry, indexPatterns, search } = this.props;
this.setState({
error: undefined,
status: 'loading',
loadingMessage: undefined,
});
let importCount = this.state.importCount;
if (this.hasUnmatchedReferences) {
try {
const resolutions = this.resolutions;
// Do not Promise.all these calls as the order matters
this.setState({
loadingMessage: i18n.translate(
'savedObjectsManagement.objectsTable.flyout.confirmLegacyImport.resolvingConflictsLoadingMessage',
{ defaultMessage: 'Resolving conflicts…' }
),
});
if (resolutions.length) {
importCount += await resolveIndexPatternConflicts(
resolutions,
conflictedIndexPatterns!,
importMode.overwrite,
{ indexPatterns, search }
);
}
this.setState({
loadingMessage: i18n.translate(
'savedObjectsManagement.objectsTable.flyout.confirmLegacyImport.savingConflictsLoadingMessage',
{ defaultMessage: 'Saving conflicts…' }
),
});
importCount += await saveObjects(
conflictedSavedObjectsLinkedToSavedSearches!,
importMode.overwrite
);
this.setState({
loadingMessage: i18n.translate(
'savedObjectsManagement.objectsTable.flyout.confirmLegacyImport.savedSearchAreLinkedProperlyLoadingMessage',
{ defaultMessage: 'Ensure saved searches are linked properly…' }
),
});
importCount += await resolveSavedSearches(
conflictedSearchDocs!,
serviceRegistry.all().map((e) => e.service),
indexPatterns,
importMode.overwrite
);
this.setState({
loadingMessage: i18n.translate(
'savedObjectsManagement.objectsTable.flyout.confirmLegacyImport.retryingFailedObjectsLoadingMessage',
{ defaultMessage: 'Retrying failed objects…' }
),
});
importCount += await saveObjects(
failedImports!.map(({ obj }) => obj) as any[],
importMode.overwrite
);
} catch (e) {
this.setState({
status: 'error',
error: getErrorMessage(e),
loadingMessage: undefined,
});
return;
}
}
this.setState({ status: 'success', importCount });
};
onIndexChanged = (id: string, e: any) => {
const value = e.target.value;
this.setState((state) => {
@ -613,10 +420,8 @@ export class Flyout extends Component<FlyoutProps, FlyoutState> {
const {
status,
loadingMessage,
importCount,
failedImports = [],
successfulImports = [],
isLegacyFile,
importMode,
importWarnings,
} = this.state;
@ -635,7 +440,8 @@ export class Flyout extends Component<FlyoutProps, FlyoutState> {
);
}
if (!isLegacyFile && status === 'success') {
// Import summary for completed import
if (status === 'success') {
return (
<ImportSummary
basePath={this.props.http.basePath}
@ -646,108 +452,7 @@ export class Flyout extends Component<FlyoutProps, FlyoutState> {
);
}
// Import summary for failed legacy import
if (failedImports.length && !this.hasUnmatchedReferences) {
return (
<EuiCallOut
data-test-subj="importSavedObjectsFailedWarning"
title={
<FormattedMessage
id="savedObjectsManagement.objectsTable.flyout.importFailedTitle"
defaultMessage="Import failed"
/>
}
color="warning"
iconType="help"
>
<p>
<FormattedMessage
id="savedObjectsManagement.objectsTable.flyout.importFailedDescription"
defaultMessage="Failed to import {failedImportCount} of {totalImportCount} objects. Import failed"
values={{
failedImportCount: failedImports.length,
totalImportCount: importCount + failedImports.length,
}}
/>
</p>
<p>
{failedImports
.map(({ error, obj }) => {
if (error.type === 'missing_references') {
return error.references.map((reference) => {
return i18n.translate(
'savedObjectsManagement.objectsTable.flyout.importFailedMissingReference',
{
defaultMessage: '{type} [id={id}] could not locate {refType} [id={refId}]',
values: {
id: obj.id,
type: obj.type,
refId: reference.id,
refType: reference.type,
},
}
);
});
} else if (error.type === 'unsupported_type') {
return i18n.translate(
'savedObjectsManagement.objectsTable.flyout.importFailedUnsupportedType',
{
defaultMessage: '{type} [id={id}] unsupported type',
values: {
id: obj.id,
type: obj.type,
},
}
);
}
return getField(error, 'body.message', (error as any).message ?? '');
})
.join(' ')}
</p>
</EuiCallOut>
);
}
// Import summary for completed legacy import
if (status === 'success') {
if (importCount === 0) {
return (
<EuiCallOut
data-test-subj="importSavedObjectsSuccessNoneImported"
title={
<FormattedMessage
id="savedObjectsManagement.objectsTable.flyout.importSuccessfulCallout.noObjectsImportedTitle"
defaultMessage="No objects imported"
/>
}
color="primary"
/>
);
}
return (
<EuiCallOut
data-test-subj="importSavedObjectsSuccess"
title={
<FormattedMessage
id="savedObjectsManagement.objectsTable.flyout.importSuccessfulTitle"
defaultMessage="Import successful"
/>
}
color="success"
iconType="check"
>
<p>
<FormattedMessage
id="savedObjectsManagement.objectsTable.flyout.importSuccessfulDescription"
defaultMessage="Successfully imported {importCount} objects."
values={{ importCount }}
/>
</p>
</EuiCallOut>
);
}
// Failed imports
if (this.hasUnmatchedReferences) {
return this.renderUnmatchedReferences();
}
@ -768,7 +473,7 @@ export class Flyout extends Component<FlyoutProps, FlyoutState> {
}
>
<EuiFilePicker
accept=".ndjson, .json"
accept=".ndjson"
fullWidth
initialPromptText={
<FormattedMessage
@ -782,7 +487,6 @@ export class Flyout extends Component<FlyoutProps, FlyoutState> {
<EuiFormRow fullWidth>
<ImportModeControl
initialValues={importMode}
isLegacyFile={isLegacyFile}
updateSelection={(newValues: ImportMode) => this.changeImportMode(newValues)}
/>
</EuiFormRow>
@ -791,7 +495,7 @@ export class Flyout extends Component<FlyoutProps, FlyoutState> {
}
renderFooter() {
const { isLegacyFile, status } = this.state;
const { status } = this.state;
const { done, close } = this.props;
let confirmButton;
@ -808,7 +512,7 @@ export class Flyout extends Component<FlyoutProps, FlyoutState> {
} else if (this.hasUnmatchedReferences) {
confirmButton = (
<EuiButton
onClick={isLegacyFile ? this.confirmLegacyImport : this.resolveImportErrors}
onClick={this.resolveImportErrors}
size="s"
fill
isLoading={status === 'loading'}
@ -823,7 +527,7 @@ export class Flyout extends Component<FlyoutProps, FlyoutState> {
} else {
confirmButton = (
<EuiButton
onClick={isLegacyFile ? this.legacyImport : this.import}
onClick={this.import}
size="s"
fill
isLoading={status === 'loading'}
@ -843,7 +547,7 @@ export class Flyout extends Component<FlyoutProps, FlyoutState> {
<EuiButtonEmpty
onClick={close}
size="s"
disabled={status === 'loading' || (isLegacyFile === false && status === 'success')}
disabled={status === 'loading' || status === 'success'}
data-test-subj="importSavedObjectsCancelBtn"
>
<FormattedMessage
@ -862,33 +566,6 @@ export class Flyout extends Component<FlyoutProps, FlyoutState> {
return null;
}
let legacyFileWarning;
if (this.state.isLegacyFile) {
legacyFileWarning = (
<>
<EuiCallOut
data-test-subj="importSavedObjectsLegacyWarning"
title={
<FormattedMessage
id="savedObjectsManagement.objectsTable.flyout.legacyFileUsedTitle"
defaultMessage="Support for JSON files is going away"
/>
}
color="warning"
iconType="help"
>
<p>
<FormattedMessage
id="savedObjectsManagement.objectsTable.flyout.legacyFileUsedBody"
defaultMessage="Use our updated export to generate NDJSON files, and you'll be all set."
/>
</p>
</EuiCallOut>
<EuiSpacer size="m" />
</>
);
}
let indexPatternConflictsWarning;
if (this.hasUnmatchedReferences) {
indexPatternConflictsWarning = (
@ -925,18 +602,12 @@ export class Flyout extends Component<FlyoutProps, FlyoutState> {
);
}
if (!legacyFileWarning && !indexPatternConflictsWarning) {
if (!indexPatternConflictsWarning) {
return null;
}
return (
<Fragment>
{legacyFileWarning && (
<span>
<EuiSpacer size="s" />
{legacyFileWarning}
</span>
)}
{indexPatternConflictsWarning && (
<span>
<EuiSpacer size="s" />

View file

@ -32,14 +32,9 @@ describe('ImportModeControl', () => {
jest.resetAllMocks();
});
const props: ImportModeControlProps = { initialValues, updateSelection, isLegacyFile: false };
const props: ImportModeControlProps = { initialValues, updateSelection };
it('returns partial import mode control when used with a legacy file', async () => {
const wrapper = shallowWithI18nProvider(<ImportModeControl {...props} isLegacyFile={true} />);
expect(wrapper.find('EuiFormFieldset')).toHaveLength(0);
});
it('returns full import mode control when used without a legacy file', async () => {
it('returns full import mode control', async () => {
const wrapper = shallowWithI18nProvider(<ImportModeControl {...props} />);
expect(wrapper.find('EuiFormFieldset')).toHaveLength(1);
});

View file

@ -22,7 +22,6 @@ import { i18n } from '@kbn/i18n';
export interface ImportModeControlProps {
initialValues: ImportMode;
isLegacyFile: boolean;
updateSelection: (result: ImportMode) => void;
}
@ -87,11 +86,7 @@ const createLabel = ({ text, tooltip }: { text: string; tooltip: string }) => (
</EuiFlexGroup>
);
export const ImportModeControl = ({
initialValues,
isLegacyFile,
updateSelection,
}: ImportModeControlProps) => {
export const ImportModeControl = ({ initialValues, updateSelection }: ImportModeControlProps) => {
const [createNewCopies, setCreateNewCopies] = useState(initialValues.createNewCopies);
const [overwrite, setOverwrite] = useState(initialValues.overwrite);
@ -104,20 +99,6 @@ export const ImportModeControl = ({
updateSelection({ createNewCopies, overwrite, ...partial });
};
const overwriteRadio = (
<EuiRadioGroup
options={[overwriteEnabled, overwriteDisabled]}
idSelected={overwrite ? overwriteEnabled.id : overwriteDisabled.id}
onChange={(id: string) => onChange({ overwrite: id === overwriteEnabled.id })}
disabled={createNewCopies && !isLegacyFile}
data-test-subj={'savedObjectsManagement-importModeControl-overwriteRadioGroup'}
/>
);
if (isLegacyFile) {
return overwriteRadio;
}
return (
<EuiFormFieldset
legend={{
@ -134,7 +115,13 @@ export const ImportModeControl = ({
checked={!createNewCopies}
onChange={() => onChange({ createNewCopies: false })}
>
{overwriteRadio}
<EuiRadioGroup
options={[overwriteEnabled, overwriteDisabled]}
idSelected={overwrite ? overwriteEnabled.id : overwriteDisabled.id}
onChange={(id: string) => onChange({ overwrite: id === overwriteEnabled.id })}
disabled={createNewCopies}
data-test-subj={'savedObjectsManagement-importModeControl-overwriteRadioGroup'}
/>
</EuiCheckableCard>
<EuiSpacer size="s" />

View file

@ -12,8 +12,8 @@ import { FtrProviderContext } from '../../ftr_provider_context';
export default function ({ getService, getPageObjects }: FtrProviderContext) {
const PageObjects = getPageObjects(['dashboard', 'header', 'settings', 'savedObjects', 'common']);
const dashboardExpect = getService('dashboardExpect');
describe('bwc import', function describeIndexTests() {
// Legacy imports are no longer supported https://github.com/elastic/kibana/issues/103921
describe.skip('bwc import', function describeIndexTests() {
before(async function () {
await PageObjects.dashboard.initTests();
await PageObjects.settings.navigateTo();

View file

@ -22,8 +22,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
'common',
'savedObjects',
]);
describe('dashboard time zones', function () {
// Legacy imports are no longer supported https://github.com/elastic/kibana/issues/103921
describe.skip('dashboard time zones', function () {
this.tags('includeFirefox');
before(async () => {

View file

@ -11,8 +11,6 @@ import path from 'path';
import { keyBy } from 'lodash';
import { FtrProviderContext } from '../../ftr_provider_context';
const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
function uniq<T>(input: T[]): T[] {
return [...new Set(input)];
}
@ -210,284 +208,5 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
expect(isSavedObjectImported).to.be(true);
});
});
describe('.json file', () => {
beforeEach(async function () {
await esArchiver.load('test/functional/fixtures/es_archiver/saved_objects_imports');
await kibanaServer.uiSettings.replace({});
await PageObjects.settings.navigateTo();
await PageObjects.settings.clickKibanaSavedObjects();
});
afterEach(async function () {
await esArchiver.unload('test/functional/fixtures/es_archiver/saved_objects_imports');
});
it('should import saved objects', async function () {
await PageObjects.savedObjects.importFile(
path.join(__dirname, 'exports', '_import_objects.json')
);
await PageObjects.savedObjects.checkImportSucceeded();
await PageObjects.savedObjects.clickImportDone();
const objects = await PageObjects.savedObjects.getRowTitles();
const isSavedObjectImported = objects.includes('Log Agents');
expect(isSavedObjectImported).to.be(true);
});
it('should provide dialog to allow the importing of saved objects with index pattern conflicts', async function () {
await PageObjects.savedObjects.importFile(
path.join(__dirname, 'exports', '_import_objects-conflicts.json')
);
await PageObjects.savedObjects.checkImportLegacyWarning();
await PageObjects.savedObjects.checkImportConflictsWarning();
await PageObjects.settings.associateIndexPattern(
'd1e4c910-a2e6-11e7-bb30-233be9be6a15',
'logstash-*'
);
await PageObjects.savedObjects.clickConfirmChanges();
await PageObjects.header.waitUntilLoadingHasFinished();
await PageObjects.savedObjects.clickImportDone();
const objects = await PageObjects.savedObjects.getRowTitles();
const isSavedObjectImported = objects.includes('saved object with index pattern conflict');
expect(isSavedObjectImported).to.be(true);
});
it('should allow the user to override duplicate saved objects', async function () {
// This data has already been loaded by the "visualize" esArchive. We'll load it again
// so that we can override the existing visualization.
await PageObjects.savedObjects.importFile(
path.join(__dirname, 'exports', '_import_objects_exists.json'),
false
);
await PageObjects.savedObjects.checkImportLegacyWarning();
await PageObjects.savedObjects.checkImportConflictsWarning();
await PageObjects.settings.associateIndexPattern('logstash-*', 'logstash-*');
await PageObjects.savedObjects.clickConfirmChanges();
// Override the visualization.
await PageObjects.common.clickConfirmOnModal();
const isSuccessful = await testSubjects.exists('importSavedObjectsSuccess');
expect(isSuccessful).to.be(true);
});
it('should allow the user to cancel overriding duplicate saved objects', async function () {
// This data has already been loaded by the "visualize" esArchive. We'll load it again
// so that we can be prompted to override the existing visualization.
await PageObjects.savedObjects.importFile(
path.join(__dirname, 'exports', '_import_objects_exists.json'),
false
);
await PageObjects.savedObjects.checkImportLegacyWarning();
await PageObjects.savedObjects.checkImportConflictsWarning();
await PageObjects.settings.associateIndexPattern('logstash-*', 'logstash-*');
await PageObjects.savedObjects.clickConfirmChanges();
// *Don't* override the visualization.
await PageObjects.common.clickCancelOnModal();
const isSuccessful = await testSubjects.exists('importSavedObjectsSuccessNoneImported');
expect(isSuccessful).to.be(true);
});
it('should allow the user to confirm overriding multiple duplicate saved objects', async function () {
// This data has already been loaded by the "visualize" esArchive. We'll load it again
// so that we can override the existing visualization.
await PageObjects.savedObjects.importFile(
path.join(__dirname, 'exports', '_import_objects_multiple_exists.json'),
false
);
await PageObjects.savedObjects.checkImportLegacyWarning();
await PageObjects.savedObjects.checkImportConflictsWarning();
await PageObjects.settings.associateIndexPattern('logstash-*', 'logstash-*');
await PageObjects.savedObjects.clickConfirmChanges();
// Override the visualizations.
await PageObjects.common.clickConfirmOnModal(false);
// as the second confirm can pop instantly, we can't wait for it to be hidden
// with is why we call clickConfirmOnModal with ensureHidden: false in previous statement
// but as the initial popin can take a few ms before fading, we need to wait a little
// to avoid clicking twice on the same modal.
await delay(1000);
await PageObjects.common.clickConfirmOnModal(true);
const isSuccessful = await testSubjects.exists('importSavedObjectsSuccess');
expect(isSuccessful).to.be(true);
});
it('should allow the user to confirm overriding multiple duplicate index patterns', async function () {
// This data has already been loaded by the "visualize" esArchive. We'll load it again
// so that we can override the existing visualization.
await PageObjects.savedObjects.importFile(
path.join(__dirname, 'exports', '_import_index_patterns_multiple_exists.json'),
false
);
// Override the index patterns.
await PageObjects.common.clickConfirmOnModal(false);
// as the second confirm can pop instantly, we can't wait for it to be hidden
// with is why we call clickConfirmOnModal with ensureHidden: false in previous statement
// but as the initial popin can take a few ms before fading, we need to wait a little
// to avoid clicking twice on the same modal.
await delay(1000);
await PageObjects.common.clickConfirmOnModal(true);
const isSuccessful = await testSubjects.exists('importSavedObjectsSuccess');
expect(isSuccessful).to.be(true);
});
it('should import saved objects linked to saved searches', async function () {
await PageObjects.savedObjects.importFile(
path.join(__dirname, 'exports', '_import_objects_saved_search.json')
);
await PageObjects.savedObjects.checkImportSucceeded();
await PageObjects.savedObjects.clickImportDone();
await PageObjects.savedObjects.importFile(
path.join(__dirname, 'exports', '_import_objects_connected_to_saved_search.json')
);
await PageObjects.savedObjects.checkImportSucceeded();
await PageObjects.savedObjects.clickImportDone();
const objects = await PageObjects.savedObjects.getRowTitles();
const isSavedObjectImported = objects.includes('saved object connected to saved search');
expect(isSavedObjectImported).to.be(true);
});
it('should not import saved objects linked to saved searches when saved search does not exist', async function () {
await PageObjects.savedObjects.importFile(
path.join(__dirname, 'exports', '_import_objects_connected_to_saved_search.json')
);
await PageObjects.savedObjects.checkImportFailedWarning();
await PageObjects.savedObjects.clickImportDone();
const objects = await PageObjects.savedObjects.getRowTitles();
const isSavedObjectImported = objects.includes('saved object connected to saved search');
expect(isSavedObjectImported).to.be(false);
});
it('should not import saved objects linked to saved searches when saved search index pattern does not exist', async function () {
// First, import the saved search
await PageObjects.savedObjects.importFile(
path.join(__dirname, 'exports', '_import_objects_saved_search.json')
);
// Wait for all the saves to happen
await PageObjects.savedObjects.checkImportSucceeded();
await PageObjects.savedObjects.clickImportDone();
// Second, we need to delete the index pattern
await PageObjects.savedObjects.clickCheckboxByTitle('logstash-*');
await PageObjects.savedObjects.clickDelete();
// Last, import a saved object connected to the saved search
// This should NOT show the conflicts
await PageObjects.savedObjects.importFile(
path.join(__dirname, 'exports', '_import_objects_connected_to_saved_search.json')
);
// Wait for all the saves to happen
await PageObjects.savedObjects.checkNoneImported();
await PageObjects.savedObjects.clickImportDone();
const objects = await PageObjects.savedObjects.getRowTitles();
const isSavedObjectImported = objects.includes('saved object connected to saved search');
expect(isSavedObjectImported).to.be(false);
});
it('should import saved objects with index patterns when index patterns already exists', async () => {
// First, import the objects
await PageObjects.savedObjects.importFile(
path.join(__dirname, 'exports', '_import_objects_with_index_patterns.json')
);
await PageObjects.savedObjects.clickImportDone();
const objects = await PageObjects.savedObjects.getRowTitles();
const isSavedObjectImported = objects.includes('saved object imported with index pattern');
expect(isSavedObjectImported).to.be(true);
});
it('should preserve index patterns selection when switching between pages', async () => {
await PageObjects.savedObjects.importFile(
path.join(__dirname, 'exports', '_import_objects_missing_all_index_patterns.json')
);
await PageObjects.savedObjects.setOverriddenIndexPatternValue(
'missing-index-pattern-1',
'index-pattern-test-1'
);
const flyout = await testSubjects.find('importSavedObjectsFlyout');
await (await flyout.findByTestSubject('pagination-button-next')).click();
await PageObjects.savedObjects.setOverriddenIndexPatternValue(
'missing-index-pattern-7',
'index-pattern-test-2'
);
await (await flyout.findByTestSubject('pagination-button-previous')).click();
const selectedIdForMissingIndexPattern1 = await testSubjects.getAttribute(
'managementChangeIndexSelection-missing-index-pattern-1',
'value'
);
expect(selectedIdForMissingIndexPattern1).to.eql('f1e4c910-a2e6-11e7-bb30-233be9be6a20');
await (await flyout.findByTestSubject('pagination-button-next')).click();
const selectedIdForMissingIndexPattern7 = await testSubjects.getAttribute(
'managementChangeIndexSelection-missing-index-pattern-7',
'value'
);
expect(selectedIdForMissingIndexPattern7).to.eql('f1e4c910-a2e6-11e7-bb30-233be9be6a87');
});
it('should display an explicit error message when importing object from a higher Kibana version', async () => {
await PageObjects.savedObjects.importFile(
path.join(__dirname, 'exports', '_import_higher_version.ndjson')
);
await PageObjects.savedObjects.checkImportError();
const errorText = await PageObjects.savedObjects.getImportErrorText();
expect(errorText).to.contain(
`has property "visualization" which belongs to a more recent version of Kibana [9.15.82]`
);
});
describe('when bigger than savedObjects.maxImportPayloadBytes (not Cloud)', function () {
// see --savedObjects.maxImportPayloadBytes in config file
this.tags(['skipCloud']);
it('should display an explicit error message when importing a file bigger than allowed', async () => {
await PageObjects.savedObjects.importFile(
path.join(__dirname, 'exports', '_import_too_big.ndjson')
);
await PageObjects.savedObjects.checkImportError();
const errorText = await PageObjects.savedObjects.getImportErrorText();
expect(errorText).to.contain(`Payload content length greater than maximum allowed`);
});
});
it('should display an explicit error message when importing an invalid file', async () => {
await PageObjects.savedObjects.importFile(
path.join(__dirname, 'exports', '_import_invalid_format.ndjson')
);
await PageObjects.savedObjects.checkImportError();
const errorText = await PageObjects.savedObjects.getImportErrorText();
expect(errorText).to.contain(`Unexpected token T in JSON at position 0`);
});
});
});
}

View file

@ -30,7 +30,7 @@ export default function ({ getService, getPageObjects }) {
it('should import saved objects mgmt', async function () {
await PageObjects.settings.clickKibanaSavedObjects();
await PageObjects.savedObjects.importFile(
path.join(__dirname, 'exports', 'mgmt_import_objects.json')
path.join(__dirname, 'exports', 'mgmt_import_objects.ndjson')
);
await PageObjects.settings.associateIndexPattern(
'4c3f3c30-ac94-11e8-a651-614b2788174a',

File diff suppressed because one or more lines are too long

View file

@ -1,19 +0,0 @@
[
{
"_id": "082f1d60-a2e7-11e7-bb30-233be9be6a15",
"_type": "visualization",
"_source": {
"title": "Log Agents",
"visState": "{\"title\":\"Log Agents\",\"type\":\"area\",\"params\":{\"type\":\"area\",\"grid\":{\"categoryLines\":false,\"style\":{\"color\":\"#eee\"}},\"categoryAxes\":[{\"id\":\"CategoryAxis-1\",\"type\":\"category\",\"position\":\"bottom\",\"show\":true,\"style\":{},\"scale\":{\"type\":\"linear\"},\"labels\":{\"show\":true,\"truncate\":100},\"title\":{\"text\":\"agent.raw: Descending\"}}],\"valueAxes\":[{\"id\":\"ValueAxis-1\",\"name\":\"LeftAxis-1\",\"type\":\"value\",\"position\":\"left\",\"show\":true,\"style\":{},\"scale\":{\"type\":\"linear\",\"mode\":\"normal\"},\"labels\":{\"show\":true,\"rotate\":0,\"filter\":false,\"truncate\":100},\"title\":{\"text\":\"Count\"}}],\"seriesParams\":[{\"show\":\"true\",\"type\":\"area\",\"mode\":\"stacked\",\"data\":{\"label\":\"Count\",\"id\":\"1\"},\"drawLinesBetweenPoints\":true,\"showCircles\":true,\"interpolate\":\"linear\",\"valueAxis\":\"ValueAxis-1\"}],\"addTooltip\":true,\"addLegend\":true,\"legendPosition\":\"right\",\"times\":[],\"addTimeMarker\":false},\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"segment\",\"params\":{\"field\":\"agent.raw\",\"size\":5,\"order\":\"desc\",\"orderBy\":\"1\"}}]}",
"uiStateJSON": "{}",
"description": "",
"version": 1,
"kibanaSavedObjectMeta": {
"searchSourceJSON": "{\"index\":\"f1e4c910-a2e6-11e7-bb30-233be9be6a15\",\"filter\":[],\"query\":{\"query\":\"\",\"language\":\"lucene\"}}"
}
},
"_meta": {
"savedObjectVersion": 2
}
}
]

View file

@ -1,20 +0,0 @@
[
{
"_id": "saved_object_connected_to_saved_search",
"_type": "visualization",
"_source": {
"title": "saved object connected to saved search",
"visState": "{\"title\":\"PHP Viz\",\"type\":\"horizontal_bar\",\"params\":{\"type\":\"histogram\",\"grid\":{\"categoryLines\":false,\"style\":{\"color\":\"#eee\"}},\"categoryAxes\":[{\"id\":\"CategoryAxis-1\",\"type\":\"category\",\"position\":\"left\",\"show\":true,\"style\":{},\"scale\":{\"type\":\"linear\"},\"labels\":{\"show\":true,\"rotate\":0,\"filter\":false,\"truncate\":200},\"title\":{}}],\"valueAxes\":[{\"id\":\"ValueAxis-1\",\"name\":\"LeftAxis-1\",\"type\":\"value\",\"position\":\"bottom\",\"show\":true,\"style\":{},\"scale\":{\"type\":\"linear\",\"mode\":\"normal\"},\"labels\":{\"show\":true,\"rotate\":75,\"filter\":true,\"truncate\":100},\"title\":{\"text\":\"Count\"}}],\"seriesParams\":[{\"show\":true,\"type\":\"histogram\",\"mode\":\"normal\",\"data\":{\"label\":\"Count\",\"id\":\"1\"},\"valueAxis\":\"ValueAxis-1\",\"drawLinesBetweenPoints\":true,\"showCircles\":true}],\"addTooltip\":true,\"addLegend\":true,\"legendPosition\":\"right\",\"times\":[],\"addTimeMarker\":false},\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"schema\":\"metric\",\"params\":{}}]}",
"uiStateJSON": "{}",
"description": "",
"savedSearchId": "c45e6c50-ba72-11e7-a8f9-ad70f02e633d",
"version": 1,
"kibanaSavedObjectMeta": {
"searchSourceJSON": "{\"filter\":[],\"query\":{\"query\":\"\",\"language\":\"lucene\"}}"
}
},
"_meta": {
"savedObjectVersion": 2
}
}
]

View file

@ -1,19 +0,0 @@
[
{
"_id": "Shared-Item-Visualization-AreaChart",
"_type": "visualization",
"_source": {
"title": "Shared-Item Visualization AreaChart",
"visState": "{\"title\":\"New Visualization\",\"type\":\"area\",\"params\":{\"shareYAxis\":true,\"addTooltip\":true,\"addLegend\":true,\"smoothLines\":false,\"scale\":\"linear\",\"interpolate\":\"linear\",\"mode\":\"stacked\",\"times\":[],\"addTimeMarker\":false,\"defaultYExtents\":false,\"setYExtents\":false,\"yAxis\":{}},\"aggs\":[{\"id\":\"1\",\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"type\":\"date_histogram\",\"schema\":\"segment\",\"params\":{\"field\":\"@timestamp\",\"interval\":\"auto\",\"customInterval\":\"2h\",\"min_doc_count\":1,\"extended_bounds\":{}}}],\"listeners\":{}}",
"uiStateJSON": "{}",
"description": "AreaChart",
"version": 1,
"kibanaSavedObjectMeta": {
"searchSourceJSON": "{\"index\":\"logstash-*\",\"query\":{\"query_string\":{\"query\":\"*\",\"analyze_wildcard\":true}},\"filter\":[]}"
}
},
"_meta": {
"savedObjectVersion": 2
}
}
]

View file

@ -1,121 +0,0 @@
[
{
"_id": "test-vis-1",
"_type": "visualization",
"_source": {
"title": "Test VIS 1",
"visState": "{\"title\":\"test vis 1\",\"type\":\"histogram\"}",
"uiStateJSON": "{}",
"description": "",
"version": 1,
"kibanaSavedObjectMeta": {
"searchSourceJSON": "{\"index\":\"missing-index-pattern-1\",\"query\":{}}"
}
},
"_meta": {
"savedObjectVersion": 2
}
},
{
"_id": "test-vis-2",
"_type": "visualization",
"_source": {
"title": "Test VIS 2",
"visState": "{\"title\":\"test vis 2\",\"type\":\"histogram\"}",
"uiStateJSON": "{}",
"description": "",
"version": 1,
"kibanaSavedObjectMeta": {
"searchSourceJSON": "{\"index\":\"missing-index-pattern-2\",\"query\":{}}"
}
},
"_meta": {
"savedObjectVersion": 2
}
},
{
"_id": "test-vis-3",
"_type": "visualization",
"_source": {
"title": "Test VIS 3",
"visState": "{\"title\":\"test vis 3\",\"type\":\"histogram\"}",
"uiStateJSON": "{}",
"description": "",
"version": 1,
"kibanaSavedObjectMeta": {
"searchSourceJSON": "{\"index\":\"missing-index-pattern-3\",\"query\":{}}"
}
},
"_meta": {
"savedObjectVersion": 2
}
},
{
"_id": "test-vis-4",
"_type": "visualization",
"_source": {
"title": "Test VIS 4",
"visState": "{\"title\":\"test vis 4\",\"type\":\"histogram\"}",
"uiStateJSON": "{}",
"description": "",
"version": 1,
"kibanaSavedObjectMeta": {
"searchSourceJSON": "{\"index\":\"missing-index-pattern-4\",\"query\":{}}"
}
},
"_meta": {
"savedObjectVersion": 2
}
},
{
"_id": "test-vis-5",
"_type": "visualization",
"_source": {
"title": "Test VIS 5",
"visState": "{\"title\":\"test vis 5\",\"type\":\"histogram\"}",
"uiStateJSON": "{}",
"description": "",
"version": 1,
"kibanaSavedObjectMeta": {
"searchSourceJSON": "{\"index\":\"missing-index-pattern-5\",\"query\":{}}"
}
},
"_meta": {
"savedObjectVersion": 2
}
},
{
"_id": "test-vis-6",
"_type": "visualization",
"_source": {
"title": "Test VIS 6",
"visState": "{\"title\":\"test vis 6\",\"type\":\"histogram\"}",
"uiStateJSON": "{}",
"description": "",
"version": 1,
"kibanaSavedObjectMeta": {
"searchSourceJSON": "{\"index\":\"missing-index-pattern-6\",\"query\":{}}"
}
},
"_meta": {
"savedObjectVersion": 2
}
},
{
"_id": "test-vis-7",
"_type": "visualization",
"_source": {
"title": "Test VIS 7",
"visState": "{\"title\":\"test vis 7\",\"type\":\"histogram\"}",
"uiStateJSON": "{}",
"description": "",
"version": 1,
"kibanaSavedObjectMeta": {
"searchSourceJSON": "{\"index\":\"missing-index-pattern-7\",\"query\":{}}"
}
},
"_meta": {
"savedObjectVersion": 2
}
}
]

View file

@ -1,36 +0,0 @@
[
{
"_id": "test-1",
"_type": "visualization",
"_source": {
"title": "Visualization test 1",
"visState": "{\"title\":\"New Visualization\",\"type\":\"area\",\"params\":{\"shareYAxis\":true,\"addTooltip\":true,\"addLegend\":true,\"smoothLines\":false,\"scale\":\"linear\",\"interpolate\":\"linear\",\"mode\":\"stacked\",\"times\":[],\"addTimeMarker\":false,\"defaultYExtents\":false,\"setYExtents\":false,\"yAxis\":{}},\"aggs\":[{\"id\":\"1\",\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"type\":\"date_histogram\",\"schema\":\"segment\",\"params\":{\"field\":\"@timestamp\",\"interval\":\"auto\",\"customInterval\":\"2h\",\"min_doc_count\":1,\"extended_bounds\":{}}}],\"listeners\":{}}",
"uiStateJSON": "{}",
"description": "AreaChart",
"version": 1,
"kibanaSavedObjectMeta": {
"searchSourceJSON": "{\"index\":\"logstash-*\",\"query\":{\"query_string\":{\"query\":\"*\",\"analyze_wildcard\":true}},\"filter\":[]}"
}
},
"_meta": {
"savedObjectVersion": 2
}
},
{
"_id": "test-2",
"_type": "visualization",
"_source": {
"title": "Visualization test 2",
"visState": "{\"title\":\"New Visualization\",\"type\":\"area\",\"params\":{\"shareYAxis\":true,\"addTooltip\":true,\"addLegend\":true,\"smoothLines\":false,\"scale\":\"linear\",\"interpolate\":\"linear\",\"mode\":\"stacked\",\"times\":[],\"addTimeMarker\":false,\"defaultYExtents\":false,\"setYExtents\":false,\"yAxis\":{}},\"aggs\":[{\"id\":\"1\",\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"type\":\"date_histogram\",\"schema\":\"segment\",\"params\":{\"field\":\"@timestamp\",\"interval\":\"auto\",\"customInterval\":\"2h\",\"min_doc_count\":1,\"extended_bounds\":{}}}],\"listeners\":{}}",
"uiStateJSON": "{}",
"description": "AreaChart",
"version": 1,
"kibanaSavedObjectMeta": {
"searchSourceJSON": "{\"index\":\"logstash-*\",\"query\":{\"query_string\":{\"query\":\"*\",\"analyze_wildcard\":true}},\"filter\":[]}"
}
},
"_meta": {
"savedObjectVersion": 2
}
}
]

View file

@ -1,25 +0,0 @@
[
{
"_id": "c45e6c50-ba72-11e7-a8f9-ad70f02e633d",
"_type": "search",
"_source": {
"title": "PHP saved search",
"description": "",
"hits": 0,
"columns": [
"_source"
],
"sort": [
"@timestamp",
"desc"
],
"version": 1,
"kibanaSavedObjectMeta": {
"searchSourceJSON": "{\"index\":\"f1e4c910-a2e6-11e7-bb30-233be9be6a15\",\"highlightAll\":true,\"version\":true,\"query\":{\"language\":\"lucene\",\"query\":\"php\"},\"filter\":[]}"
}
},
"_meta": {
"savedObjectVersion": 2
}
}
]

File diff suppressed because one or more lines are too long

View file

@ -1,37 +0,0 @@
[
{
"_id": "6aea5700-ac94-11e8-a651-614b2788174a",
"_type": "search",
"_source": {
"title": "mysavedsearch",
"description": "",
"hits": 0,
"columns": [
"_source"
],
"sort": [
"@timestamp",
"desc"
],
"version": 1,
"kibanaSavedObjectMeta": {
"searchSourceJSON": "{\"index\":\"4c3f3c30-ac94-11e8-a651-614b2788174a\",\"highlightAll\":true,\"version\":true,\"query\":{\"query\":\"\",\"language\":\"lucene\"},\"filter\":[]}"
}
}
},
{
"_id": "8411daa0-ac94-11e8-a651-614b2788174a",
"_type": "visualization",
"_source": {
"title": "mysavedviz",
"visState": "{\"title\":\"mysavedviz\",\"type\":\"pie\",\"params\":{\"type\":\"pie\",\"addTooltip\":true,\"addLegend\":true,\"legendPosition\":\"right\",\"isDonut\":true,\"labels\":{\"show\":false,\"values\":true,\"last_level\":true,\"truncate\":100}},\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"schema\":\"metric\",\"params\":{}}]}",
"uiStateJSON": "{}",
"description": "",
"savedSearchId": "6aea5700-ac94-11e8-a651-614b2788174a",
"version": 1,
"kibanaSavedObjectMeta": {
"searchSourceJSON": "{\"query\":{\"query\":\"\",\"language\":\"lucene\"},\"filter\":[]}"
}
}
}
]

View file

@ -3302,32 +3302,17 @@
"savedObjectsManagement.objectsTable.exportObjectsConfirmModal.exportOptionsLabel": "オプション",
"savedObjectsManagement.objectsTable.exportObjectsConfirmModal.includeReferencesDeepLabel": "関連オブジェクトを含める",
"savedObjectsManagement.objectsTable.exportObjectsConfirmModalDescription": "エクスポートするタイプを選択してください",
"savedObjectsManagement.objectsTable.flyout.confirmLegacyImport.resolvingConflictsLoadingMessage": "矛盾を解決中…",
"savedObjectsManagement.objectsTable.flyout.confirmLegacyImport.retryingFailedObjectsLoadingMessage": "失敗したオブジェクトを再試行中…",
"savedObjectsManagement.objectsTable.flyout.confirmLegacyImport.savedSearchAreLinkedProperlyLoadingMessage": "保存された検索が正しくリンクされていることを確認してください…",
"savedObjectsManagement.objectsTable.flyout.confirmLegacyImport.savingConflictsLoadingMessage": "矛盾を保存中…",
"savedObjectsManagement.objectsTable.flyout.errorCalloutTitle": "申し訳ございません、エラーが発生しました",
"savedObjectsManagement.objectsTable.flyout.import.cancelButtonLabel": "キャンセル",
"savedObjectsManagement.objectsTable.flyout.import.confirmButtonLabel": "インポート",
"savedObjectsManagement.objectsTable.flyout.importFailedDescription": "{totalImportCount}個中{failedImportCount}個のオブジェクトのインポートに失敗しました。インポート失敗",
"savedObjectsManagement.objectsTable.flyout.importFailedMissingReference": "{type} [id={id}]は{refType} [id={refId}]を見つけられませんでした",
"savedObjectsManagement.objectsTable.flyout.importFailedTitle": "インポート失敗",
"savedObjectsManagement.objectsTable.flyout.importFailedUnsupportedType": "{type} [id={id}]サポートされていないタイプ",
"savedObjectsManagement.objectsTable.flyout.importFileErrorMessage": "エラーのためファイルを処理できませんでした:「{error}」",
"savedObjectsManagement.objectsTable.flyout.importLegacyFileErrorMessage": "ファイルを処理できませんでした。",
"savedObjectsManagement.objectsTable.flyout.importPromptText": "インポート",
"savedObjectsManagement.objectsTable.flyout.importSavedObjectTitle": "保存されたオブジェクトのインポート",
"savedObjectsManagement.objectsTable.flyout.importSuccessful.confirmAllChangesButtonLabel": "すべての変更を確定",
"savedObjectsManagement.objectsTable.flyout.importSuccessful.confirmButtonLabel": "完了",
"savedObjectsManagement.objectsTable.flyout.importSuccessfulCallout.noObjectsImportedTitle": "オブジェクトがインポートされませんでした",
"savedObjectsManagement.objectsTable.flyout.importSuccessfulDescription": "{importCount}個のオブジェクトがインポートされました。",
"savedObjectsManagement.objectsTable.flyout.importSuccessfulTitle": "インポート成功",
"savedObjectsManagement.objectsTable.flyout.indexPatternConflictsCalloutLinkText": "新規インデックスパターンを作成",
"savedObjectsManagement.objectsTable.flyout.indexPatternConflictsDescription": "次の保存されたオブジェクトは、存在しないインデックスパターンを使用しています。関連付け直す別のインデックスパターンを選択してください。必要に応じて、{indexPatternLink}できます。",
"savedObjectsManagement.objectsTable.flyout.indexPatternConflictsTitle": "インデックスパターンの矛盾",
"savedObjectsManagement.objectsTable.flyout.invalidFormatOfImportedFileErrorMessage": "保存されたオブジェクトのファイル形式が無効なため、インポートできません。",
"savedObjectsManagement.objectsTable.flyout.legacyFileUsedBody": "最新のレポートでNDJSONファイルを作成すれば完了です。",
"savedObjectsManagement.objectsTable.flyout.legacyFileUsedTitle": "JSONファイルのサポートが終了します",
"savedObjectsManagement.objectsTable.flyout.renderConflicts.columnCountDescription": "影響されるオブジェクトの数です",
"savedObjectsManagement.objectsTable.flyout.renderConflicts.columnCountName": "カウント",
"savedObjectsManagement.objectsTable.flyout.renderConflicts.columnIdDescription": "インデックスパターンのIDです",

View file

@ -3320,32 +3320,17 @@
"savedObjectsManagement.objectsTable.exportObjectsConfirmModal.includeReferencesDeepLabel": "包括相关对象",
"savedObjectsManagement.objectsTable.exportObjectsConfirmModalDescription": "选择要导出的类型",
"savedObjectsManagement.objectsTable.exportObjectsConfirmModalTitle": "导出 {filteredItemCount, plural, other {# 个对象}}",
"savedObjectsManagement.objectsTable.flyout.confirmLegacyImport.resolvingConflictsLoadingMessage": "正在解决冲突……",
"savedObjectsManagement.objectsTable.flyout.confirmLegacyImport.retryingFailedObjectsLoadingMessage": "正在重试失败的对象……",
"savedObjectsManagement.objectsTable.flyout.confirmLegacyImport.savedSearchAreLinkedProperlyLoadingMessage": "确保已保存搜索已正确链接……",
"savedObjectsManagement.objectsTable.flyout.confirmLegacyImport.savingConflictsLoadingMessage": "正在保存冲突……",
"savedObjectsManagement.objectsTable.flyout.errorCalloutTitle": "抱歉,有错误",
"savedObjectsManagement.objectsTable.flyout.import.cancelButtonLabel": "取消",
"savedObjectsManagement.objectsTable.flyout.import.confirmButtonLabel": "导入",
"savedObjectsManagement.objectsTable.flyout.importFailedDescription": "{totalImportCount} 个对象中有 {failedImportCount} 个无法导入。导入失败",
"savedObjectsManagement.objectsTable.flyout.importFailedMissingReference": "{type} [id={id}] 无法找到 {refType} [id={refId}]",
"savedObjectsManagement.objectsTable.flyout.importFailedTitle": "导入失败",
"savedObjectsManagement.objectsTable.flyout.importFailedUnsupportedType": "{type} [id={id}] 不受支持的类型",
"savedObjectsManagement.objectsTable.flyout.importFileErrorMessage": "由于以下错误,无法处理文件:“{error}”",
"savedObjectsManagement.objectsTable.flyout.importLegacyFileErrorMessage": "无法处理该文件。",
"savedObjectsManagement.objectsTable.flyout.importPromptText": "导入",
"savedObjectsManagement.objectsTable.flyout.importSavedObjectTitle": "导入已保存对象",
"savedObjectsManagement.objectsTable.flyout.importSuccessful.confirmAllChangesButtonLabel": "确认所有更改",
"savedObjectsManagement.objectsTable.flyout.importSuccessful.confirmButtonLabel": "完成",
"savedObjectsManagement.objectsTable.flyout.importSuccessfulCallout.noObjectsImportedTitle": "未导入任何对象",
"savedObjectsManagement.objectsTable.flyout.importSuccessfulDescription": "已成功导入 {importCount} 个对象。",
"savedObjectsManagement.objectsTable.flyout.importSuccessfulTitle": "导入成功",
"savedObjectsManagement.objectsTable.flyout.indexPatternConflictsCalloutLinkText": "创建新的索引模式",
"savedObjectsManagement.objectsTable.flyout.indexPatternConflictsDescription": "以下已保存对象使用不存在的索引模式。请选择要重新关联的索引模式。必要时可以{indexPatternLink}。",
"savedObjectsManagement.objectsTable.flyout.indexPatternConflictsTitle": "索引模式冲突",
"savedObjectsManagement.objectsTable.flyout.invalidFormatOfImportedFileErrorMessage": "已保存对象文件格式无效,无法导入。",
"savedObjectsManagement.objectsTable.flyout.legacyFileUsedBody": "只需使用更新的导出功能生成 NDJSON 文件,便万事俱备。",
"savedObjectsManagement.objectsTable.flyout.legacyFileUsedTitle": "将不再支持 JSON 文件",
"savedObjectsManagement.objectsTable.flyout.renderConflicts.columnCountDescription": "受影响对象数目",
"savedObjectsManagement.objectsTable.flyout.renderConflicts.columnCountName": "计数",
"savedObjectsManagement.objectsTable.flyout.renderConflicts.columnIdDescription": "索引模式的 ID",