-
Notifications
You must be signed in to change notification settings - Fork 8.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Mappings editor] Accommodate legacy index templates (#55388)
- Loading branch information
Showing
14 changed files
with
471 additions
and
68 deletions.
There are no files selected for viewing
17 changes: 17 additions & 0 deletions
17
...gement/public/app/components/mappings_editor/__jest__/client_integration/helpers/index.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License; | ||
* you may not use this file except in compliance with the Elastic License. | ||
*/ | ||
import { setup as mappingsEditorSetup } from './mappings_editor.helpers'; | ||
|
||
export { | ||
nextTick, | ||
getRandomString, | ||
findTestSubject, | ||
TestBed, | ||
} from '../../../../../../../../../../test_utils'; | ||
|
||
export const componentHelpers = { | ||
mappingsEditor: { setup: mappingsEditorSetup }, | ||
}; |
16 changes: 16 additions & 0 deletions
16
...components/mappings_editor/__jest__/client_integration/helpers/mappings_editor.helpers.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License; | ||
* you may not use this file except in compliance with the Elastic License. | ||
*/ | ||
|
||
import { registerTestBed } from '../../../../../../../../../../test_utils'; | ||
import { MappingsEditor } from '../../../mappings_editor'; | ||
|
||
export const setup = (props: any) => | ||
registerTestBed(MappingsEditor, { | ||
memoryRouter: { | ||
wrapComponent: false, | ||
}, | ||
defaultProps: props, | ||
}); |
55 changes: 55 additions & 0 deletions
55
...ublic/app/components/mappings_editor/__jest__/client_integration/mappings_editor.test.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License; | ||
* you may not use this file except in compliance with the Elastic License. | ||
*/ | ||
|
||
import { componentHelpers } from './helpers'; | ||
|
||
const { setup } = componentHelpers.mappingsEditor; | ||
const mockOnUpdate = () => undefined; | ||
|
||
describe('<MappingsEditor />', () => { | ||
describe('multiple mappings detection', () => { | ||
test('should show a warning when multiple mappings are detected', async () => { | ||
const defaultValue = { | ||
type1: { | ||
properties: { | ||
name1: { | ||
type: 'keyword', | ||
}, | ||
}, | ||
}, | ||
type2: { | ||
properties: { | ||
name2: { | ||
type: 'keyword', | ||
}, | ||
}, | ||
}, | ||
}; | ||
const testBed = await setup({ onUpdate: mockOnUpdate, defaultValue })(); | ||
const { exists } = testBed; | ||
|
||
expect(exists('mappingsEditor')).toBe(true); | ||
expect(exists('mappingTypesDetectedCallout')).toBe(true); | ||
expect(exists('documentFields')).toBe(false); | ||
}); | ||
|
||
test('should not show a warning when mappings a single-type', async () => { | ||
const defaultValue = { | ||
properties: { | ||
name1: { | ||
type: 'keyword', | ||
}, | ||
}, | ||
}; | ||
const testBed = await setup({ onUpdate: mockOnUpdate, defaultValue })(); | ||
const { exists } = testBed; | ||
|
||
expect(exists('mappingsEditor')).toBe(true); | ||
expect(exists('mappingTypesDetectedCallout')).toBe(false); | ||
expect(exists('documentFields')).toBe(true); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
42 changes: 42 additions & 0 deletions
42
...management/public/app/components/mappings_editor/components/multiple_mappings_warning.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License; | ||
* you may not use this file except in compliance with the Elastic License. | ||
*/ | ||
|
||
import React from 'react'; | ||
import { i18n } from '@kbn/i18n'; | ||
import { FormattedMessage } from '@kbn/i18n/react'; | ||
import { EuiCallOut, EuiLink } from '@elastic/eui'; | ||
|
||
import { documentationService } from '../../../services/documentation'; | ||
|
||
export const MultipleMappingsWarning = () => ( | ||
<EuiCallOut | ||
title={i18n.translate('xpack.idxMgmt.mappingsEditor.mappingTypesDetectedCallOutTitle', { | ||
defaultMessage: 'Mapping types detected', | ||
})} | ||
iconType="alert" | ||
color="warning" | ||
data-test-subj="mappingTypesDetectedCallout" | ||
> | ||
<p> | ||
<FormattedMessage | ||
id="xpack.idxMgmt.mappingsEditor.mappingTypesDetectedCallOutDescription" | ||
defaultMessage="The mappings for this template uses types, which have been removed. {docsLink}" | ||
values={{ | ||
docsLink: ( | ||
<EuiLink href={documentationService.getAlternativeToMappingTypesLink()} target="_blank"> | ||
{i18n.translate( | ||
'xpack.idxMgmt.mappingsEditor.mappingTypesDetectedCallOutDocumentationLink', | ||
{ | ||
defaultMessage: 'Consider these alternatives to mapping types.', | ||
} | ||
)} | ||
</EuiLink> | ||
), | ||
}} | ||
/> | ||
</p> | ||
</EuiCallOut> | ||
); |
128 changes: 128 additions & 0 deletions
128
..._management/public/app/components/mappings_editor/lib/extract_mappings_definition.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License; | ||
* you may not use this file except in compliance with the Elastic License. | ||
*/ | ||
|
||
import { extractMappingsDefinition } from './extract_mappings_definition'; | ||
|
||
describe('extractMappingsDefinition', () => { | ||
test('should detect that the mappings has multiple types and return null', () => { | ||
const mappings = { | ||
type1: { | ||
properties: { | ||
name1: { | ||
type: 'keyword', | ||
}, | ||
}, | ||
}, | ||
type2: { | ||
properties: { | ||
name2: { | ||
type: 'keyword', | ||
}, | ||
}, | ||
}, | ||
}; | ||
|
||
expect(extractMappingsDefinition(mappings)).toBe(null); | ||
}); | ||
|
||
test('should detect that the mappings has multiple types even when one of the type has not defined any "properties"', () => { | ||
const mappings = { | ||
type1: { | ||
_source: { | ||
excludes: [], | ||
includes: [], | ||
enabled: true, | ||
}, | ||
_routing: { | ||
required: false, | ||
}, | ||
}, | ||
type2: { | ||
properties: { | ||
name2: { | ||
type: 'keyword', | ||
}, | ||
}, | ||
}, | ||
}; | ||
|
||
expect(extractMappingsDefinition(mappings)).toBe(null); | ||
}); | ||
|
||
test('should detect that one of the mapping type is invalid and filter it out', () => { | ||
const mappings = { | ||
type1: { | ||
invalidSetting: { | ||
excludes: [], | ||
includes: [], | ||
enabled: true, | ||
}, | ||
_routing: { | ||
required: false, | ||
}, | ||
}, | ||
type2: { | ||
properties: { | ||
name2: { | ||
type: 'keyword', | ||
}, | ||
}, | ||
}, | ||
}; | ||
|
||
expect(extractMappingsDefinition(mappings)).toBe(mappings.type2); | ||
}); | ||
|
||
test('should detect that the mappings has one type and return its mapping definition', () => { | ||
const mappings = { | ||
myType: { | ||
_source: { | ||
excludes: [], | ||
includes: [], | ||
enabled: true, | ||
}, | ||
_meta: {}, | ||
_routing: { | ||
required: false, | ||
}, | ||
dynamic: true, | ||
properties: { | ||
title: { | ||
type: 'keyword', | ||
}, | ||
}, | ||
}, | ||
}; | ||
|
||
expect(extractMappingsDefinition(mappings)).toBe(mappings.myType); | ||
}); | ||
|
||
test('should detect that the mappings has one type at root level', () => { | ||
const mappings = { | ||
_source: { | ||
excludes: [], | ||
includes: [], | ||
enabled: true, | ||
}, | ||
_meta: {}, | ||
_routing: { | ||
required: false, | ||
}, | ||
dynamic: true, | ||
numeric_detection: false, | ||
date_detection: true, | ||
dynamic_date_formats: ['strict_date_optional_time'], | ||
dynamic_templates: [], | ||
properties: { | ||
title: { | ||
type: 'keyword', | ||
}, | ||
}, | ||
}; | ||
|
||
expect(extractMappingsDefinition(mappings)).toBe(mappings); | ||
}); | ||
}); |
103 changes: 103 additions & 0 deletions
103
...index_management/public/app/components/mappings_editor/lib/extract_mappings_definition.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License; | ||
* you may not use this file except in compliance with the Elastic License. | ||
*/ | ||
import { isPlainObject } from 'lodash'; | ||
|
||
import { GenericObject } from '../types'; | ||
import { | ||
validateMappingsConfiguration, | ||
mappingsConfigurationSchemaKeys, | ||
} from './mappings_validator'; | ||
|
||
const ALLOWED_PARAMETERS = [...mappingsConfigurationSchemaKeys, 'dynamic_templates', 'properties']; | ||
|
||
const isMappingDefinition = (obj: GenericObject): boolean => { | ||
const areAllKeysValid = Object.keys(obj).every(key => ALLOWED_PARAMETERS.includes(key)); | ||
|
||
if (!areAllKeysValid) { | ||
return false; | ||
} | ||
|
||
const { properties, dynamic_templates: dynamicTemplates, ...mappingsConfiguration } = obj; | ||
|
||
const { errors } = validateMappingsConfiguration(mappingsConfiguration); | ||
const isConfigurationValid = errors.length === 0; | ||
const isPropertiesValid = properties === undefined || isPlainObject(properties); | ||
const isDynamicTemplatesValid = dynamicTemplates === undefined || Array.isArray(dynamicTemplates); | ||
|
||
// If the configuration, the properties and the dynamic templates are valid | ||
// we can assume that the mapping is declared at root level (no types) | ||
return isConfigurationValid && isPropertiesValid && isDynamicTemplatesValid; | ||
}; | ||
|
||
/** | ||
* 5.x index templates can be created with multiple types. | ||
* e.g. | ||
``` | ||
const mappings = { | ||
type1: { | ||
properties: { | ||
name1: { | ||
type: 'keyword', | ||
}, | ||
}, | ||
}, | ||
type2: { | ||
properties: { | ||
name2: { | ||
type: 'keyword', | ||
}, | ||
}, | ||
}, | ||
}; | ||
``` | ||
* A mappings can also be declared under an explicit "_doc" property. | ||
``` | ||
const mappings = { | ||
_doc: { | ||
_source: { | ||
"enabled": false | ||
}, | ||
properties: { | ||
name1: { | ||
type: 'keyword', | ||
}, | ||
}, | ||
}, | ||
}; | ||
``` | ||
* This helpers parse the mappings provided an removes any possible mapping "type" declared | ||
* | ||
* @param mappings The mappings object to validate | ||
*/ | ||
export const extractMappingsDefinition = (mappings: GenericObject = {}): GenericObject | null => { | ||
if (isMappingDefinition(mappings)) { | ||
// No need to go any further | ||
return mappings; | ||
} | ||
|
||
// At this point there must be one or more type mappings | ||
const typedMappings = Object.values(mappings).reduce((acc: GenericObject[], value) => { | ||
if (isMappingDefinition(value)) { | ||
acc.push(value as GenericObject); | ||
} | ||
return acc; | ||
}, []); | ||
|
||
// If there are no typed mappings found this means that one of the type must did not pass | ||
// the "isMappingDefinition()" validation. | ||
// In theory this should never happen but let's make sure the UI does not try to load an invalid mapping | ||
if (typedMappings.length === 0) { | ||
return null; | ||
} | ||
|
||
// If there's only one mapping type then we can consume it as if the type doesn't exist. | ||
if (typedMappings.length === 1) { | ||
return typedMappings[0]; | ||
} | ||
|
||
// If there's more than one mapping type, then the mappings object isn't usable. | ||
return null; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.