diff --git a/src/plugins/es_ui_shared/static/forms/helpers/field_validators/is_json.ts b/src/plugins/es_ui_shared/static/forms/helpers/field_validators/is_json.ts
index 5626fc80bb749..dc8321aa07004 100644
--- a/src/plugins/es_ui_shared/static/forms/helpers/field_validators/is_json.ts
+++ b/src/plugins/es_ui_shared/static/forms/helpers/field_validators/is_json.ts
@@ -17,25 +17,6 @@
* under the License.
*/
-/*
- * Licensed to Elasticsearch B.V. under one or more contributor
- * license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright
- * ownership. Elasticsearch B.V. licenses this file to you under
- * the Apache License, Version 2.0 (the "License"); you may
- * not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
import { ValidationFunc } from '../../hook_form_lib';
import { isJSON } from '../../../validators/string';
import { ERROR_CODE } from './types';
diff --git a/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/index.ts b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/index.ts
index 663017e2e47af..cc4c17c5c63a3 100644
--- a/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/index.ts
+++ b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/index.ts
@@ -63,6 +63,10 @@ export * from './max_shingle_size_parameter';
export * from './relations_parameter';
+export * from './other_type_name_parameter';
+
+export * from './other_type_json_parameter';
+
export const PARAMETER_SERIALIZERS = [relationsSerializer, dynamicSerializer];
export const PARAMETER_DESERIALIZERS = [relationsDeserializer, dynamicDeserializer];
diff --git a/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/other_type_json_parameter.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/other_type_json_parameter.tsx
new file mode 100644
index 0000000000000..64e50f711a249
--- /dev/null
+++ b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/other_type_json_parameter.tsx
@@ -0,0 +1,92 @@
+/*
+ * 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 {
+ UseField,
+ JsonEditorField,
+ ValidationFuncArg,
+ fieldValidators,
+ FieldConfig,
+} from '../../../shared_imports';
+
+const { isJsonField } = fieldValidators;
+
+/**
+ * This is a special component that does not have an explicit entry in {@link PARAMETERS_DEFINITION}.
+ *
+ * We use it to store custom defined parameters in a field called "otherTypeJson".
+ */
+
+const fieldConfig: FieldConfig = {
+ label: i18n.translate('xpack.idxMgmt.mappingsEditor.otherTypeJsonFieldLabel', {
+ defaultMessage: 'Type Parameters JSON',
+ }),
+ defaultValue: {},
+ validations: [
+ {
+ validator: isJsonField(
+ i18n.translate(
+ 'xpack.idxMgmt.mappingsEditor.parameters.validations.otherTypeJsonInvalidJSONErrorMessage',
+ {
+ defaultMessage: 'Invalid JSON.',
+ }
+ )
+ ),
+ },
+ {
+ validator: ({ value }: ValidationFuncArg) => {
+ const json = JSON.parse(value);
+ if (Array.isArray(json)) {
+ return {
+ message: i18n.translate(
+ 'xpack.idxMgmt.mappingsEditor.parameters.validations.otherTypeJsonArrayNotAllowedErrorMessage',
+ {
+ defaultMessage: 'Arrays are not allowed.',
+ }
+ ),
+ };
+ }
+ },
+ },
+ {
+ validator: ({ value }: ValidationFuncArg) => {
+ const json = JSON.parse(value);
+ if (json.type) {
+ return {
+ code: 'ERR_CUSTOM_TYPE_OVERRIDDEN',
+ message: i18n.translate(
+ 'xpack.idxMgmt.mappingsEditor.parameters.validations.otherTypeJsonTypeFieldErrorMessage',
+ {
+ defaultMessage: 'Cannot override the "type" field.',
+ }
+ ),
+ };
+ }
+ },
+ },
+ ],
+ deserializer: (value: any) => {
+ if (value === '') {
+ return value;
+ }
+ return JSON.stringify(value, null, 2);
+ },
+ serializer: (value: string) => {
+ try {
+ return JSON.parse(value);
+ } catch (error) {
+ // swallow error and return non-parsed value;
+ return value;
+ }
+ },
+};
+
+export const OtherTypeJsonParameter = () => (
+
+);
diff --git a/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/other_type_name_parameter.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/other_type_name_parameter.tsx
new file mode 100644
index 0000000000000..6004e484323a1
--- /dev/null
+++ b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/other_type_name_parameter.tsx
@@ -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 { UseField, TextField, FieldConfig } from '../../../shared_imports';
+import { fieldValidators } from '../../../shared_imports';
+
+const { emptyField } = fieldValidators;
+
+/**
+ * This is a special component that does not have an explicit entry in {@link PARAMETERS_DEFINITION}.
+ *
+ * We use it to store the name of types unknown to the mappings editor in the "subType" path.
+ */
+
+const fieldConfig: FieldConfig = {
+ label: i18n.translate('xpack.idxMgmt.mappingsEditor.otherTypeNameFieldLabel', {
+ defaultMessage: 'Type Name',
+ }),
+ defaultValue: '',
+ validations: [
+ {
+ validator: emptyField(
+ i18n.translate(
+ 'xpack.idxMgmt.mappingsEditor.parameters.validations.otherTypeNameIsRequiredErrorMessage',
+ {
+ defaultMessage: 'The type name is required.',
+ }
+ )
+ ),
+ },
+ ],
+};
+
+export const OtherTypeNameParameter = () => (
+
+);
diff --git a/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/create_field/create_field.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/create_field/create_field.tsx
index 60b025ce644ef..b41f35b983885 100644
--- a/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/create_field/create_field.tsx
+++ b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/create_field/create_field.tsx
@@ -5,6 +5,7 @@
*/
import React, { useEffect, useCallback } from 'react';
import classNames from 'classnames';
+import * as _ from 'lodash';
import { i18n } from '@kbn/i18n';
@@ -31,7 +32,7 @@ import {
filterTypesForNonRootFields,
} from '../../../../lib';
import { Field, MainType, SubType, NormalizedFields, ComboBoxOption } from '../../../../types';
-import { NameParameter, TypeParameter } from '../../field_parameters';
+import { NameParameter, TypeParameter, OtherTypeNameParameter } from '../../field_parameters';
import { getParametersFormForType } from './required_parameters_forms';
const formWrapper = (props: any) => ;
@@ -155,9 +156,9 @@ export const CreateField = React.memo(function CreateFieldComponent({
},
[form, getSubTypeMeta]
);
-
const renderFormFields = useCallback(
({ type }) => {
+ const isOtherType = type === 'other';
const { subTypeOptions, subTypeLabel } = getSubTypeMeta(type);
const docLink = documentationService.getTypeDocLink(type) as string;
@@ -178,7 +179,13 @@ export const CreateField = React.memo(function CreateFieldComponent({
docLink={docLink}
/>
- {/* Field sub type (if any) */}
+ {/* Other type */}
+ {isOtherType && (
+
+
+
+ )}
+ {/* Field sub type (if any) - will never be the case if we have an "other" type */}
{subTypeOptions && (
{/* Documentation link */}
-
-
- {i18n.translate(
- 'xpack.idxMgmt.mappingsEditor.editField.typeDocumentation',
- {
- defaultMessage: '{type} documentation',
- values: {
- type: subTypeDefinition
- ? subTypeDefinition.label
- : typeDefinition.label,
- },
- }
- )}
-
-
+ {linkDocumentation && (
+
+
+ {i18n.translate(
+ 'xpack.idxMgmt.mappingsEditor.editField.typeDocumentation',
+ {
+ defaultMessage: '{type} documentation',
+ values: {
+ type: subTypeDefinition
+ ? subTypeDefinition.label
+ : typeDefinition.label,
+ },
+ }
+ )}
+
+
+ )}
{/* Field path */}
diff --git a/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/edit_field/edit_field_header_form.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/edit_field/edit_field_header_form.tsx
index ddb808094428d..75a083d64b6db 100644
--- a/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/edit_field/edit_field_header_form.tsx
+++ b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/edit_field/edit_field_header_form.tsx
@@ -17,7 +17,7 @@ import {
} from '../../../../lib';
import { TYPE_DEFINITION } from '../../../../constants';
-import { NameParameter, TypeParameter } from '../../field_parameters';
+import { NameParameter, TypeParameter, OtherTypeNameParameter } from '../../field_parameters';
import { FieldDescriptionSection } from './field_description_section';
interface Props {
@@ -80,9 +80,17 @@ export const EditFieldHeaderForm = React.memo(
/>
- {/* Field sub type (if any) */}
+ {/* Other type */}
+ {type === 'other' && (
+
+
+
+ )}
+
+ {/* Field sub type (if any) - will never be the case if we have an "other" type */}
{hasSubType && (
+ {' '}
} = {
shape: ShapeType,
dense_vector: DenseVectorType,
object: ObjectType,
+ other: OtherType,
nested: NestedType,
join: JoinType,
};
diff --git a/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/other_type.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/other_type.tsx
new file mode 100644
index 0000000000000..c403bbfb79056
--- /dev/null
+++ b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/other_type.tsx
@@ -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 React from 'react';
+
+import { OtherTypeJsonParameter } from '../../field_parameters';
+import { BasicParametersSection } from '../edit_field';
+
+export const OtherType = () => {
+ return (
+
+
+
+ );
+};
diff --git a/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/fields_list_item.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/fields_list_item.tsx
index fca40513b4e2b..ad874a672bdbe 100644
--- a/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/fields_list_item.tsx
+++ b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/fields_list_item.tsx
@@ -16,12 +16,15 @@ import {
import { i18n } from '@kbn/i18n';
import { NormalizedField, NormalizedFields } from '../../../types';
+import { getTypeLabelFromType } from '../../../lib';
import {
TYPE_DEFINITION,
CHILD_FIELD_INDENT_SIZE,
LEFT_PADDING_SIZE_FIELD_ITEM_WRAPPER,
} from '../../../constants';
+
import { ChainedMultifieldsWarning } from '../../chained_multifields_warning';
+
import { FieldsList } from './fields_list';
import { CreateField } from './create_field';
import { DeleteFieldProvider } from './delete_field_provider';
@@ -268,7 +271,7 @@ function FieldListItemComponent(
dataType: TYPE_DEFINITION[source.type].label,
},
})
- : TYPE_DEFINITION[source.type].label}
+ : getTypeLabelFromType(source.type)}
diff --git a/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/search_fields/search_result_item.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/search_fields/search_result_item.tsx
index dbb8a788514bc..614b7cb56bef6 100644
--- a/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/search_fields/search_result_item.tsx
+++ b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/search_fields/search_result_item.tsx
@@ -11,6 +11,7 @@ import { i18n } from '@kbn/i18n';
import { SearchResult } from '../../../types';
import { TYPE_DEFINITION } from '../../../constants';
import { useDispatch } from '../../../mappings_state';
+import { getTypeLabelFromType } from '../../../lib';
import { DeleteFieldProvider } from '../fields/delete_field_provider';
interface Props {
@@ -115,7 +116,7 @@ export const SearchResultItem = React.memo(function FieldListItemFlatComponent({
dataType: TYPE_DEFINITION[source.type].label,
},
})
- : TYPE_DEFINITION[source.type].label}
+ : getTypeLabelFromType(source.type)}
diff --git a/x-pack/plugins/index_management/public/application/components/mappings_editor/constants/data_types_definition.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/constants/data_types_definition.tsx
index f904281181c48..4206fe8b696da 100644
--- a/x-pack/plugins/index_management/public/application/components/mappings_editor/constants/data_types_definition.tsx
+++ b/x-pack/plugins/index_management/public/application/components/mappings_editor/constants/data_types_definition.tsx
@@ -784,6 +784,20 @@ export const TYPE_DEFINITION: { [key in DataType]: DataTypeDefinition } = {
),
},
+ other: {
+ label: i18n.translate('xpack.idxMgmt.mappingsEditor.dataType.otherDescription', {
+ defaultMessage: 'Other',
+ }),
+ value: 'other',
+ description: () => (
+
+
+
+ ),
+ },
};
export const MAIN_TYPES: MainType[] = [
@@ -811,6 +825,7 @@ export const MAIN_TYPES: MainType[] = [
'shape',
'text',
'token_count',
+ 'other',
];
export const MAIN_DATA_TYPE_DEFINITION: {
diff --git a/x-pack/plugins/index_management/public/application/components/mappings_editor/lib/search_fields.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/lib/search_fields.tsx
index 5a277073c5f1a..618d106b0e7a1 100644
--- a/x-pack/plugins/index_management/public/application/components/mappings_editor/lib/search_fields.tsx
+++ b/x-pack/plugins/index_management/public/application/components/mappings_editor/lib/search_fields.tsx
@@ -185,8 +185,6 @@ const getSearchMetadata = (searchData: SearchData, fieldData: FieldData): Search
const score = calculateScore(metadata);
const display = getJSXdisplayFromMeta(searchData, fieldData, metadata);
- // console.log(fieldData.path, score, metadata);
-
return {
...metadata,
display,
diff --git a/x-pack/plugins/index_management/public/application/components/mappings_editor/lib/serializers.ts b/x-pack/plugins/index_management/public/application/components/mappings_editor/lib/serializers.ts
index 131d886ff05d9..6b817c829251f 100644
--- a/x-pack/plugins/index_management/public/application/components/mappings_editor/lib/serializers.ts
+++ b/x-pack/plugins/index_management/public/application/components/mappings_editor/lib/serializers.ts
@@ -45,16 +45,19 @@ const runParametersDeserializers = (field: Field): Field =>
);
export const fieldSerializer: SerializerFunc = (field: Field) => {
+ const { otherTypeJson, ...rest } = field;
+ const updatedField: Field = Boolean(otherTypeJson) ? { ...otherTypeJson, ...rest } : { ...rest };
+
// If a subType is present, use it as type for ES
- if ({}.hasOwnProperty.call(field, 'subType')) {
- field.type = field.subType as DataType;
- delete field.subType;
+ if ({}.hasOwnProperty.call(updatedField, 'subType')) {
+ updatedField.type = updatedField.subType as DataType;
+ delete updatedField.subType;
}
// Delete temp fields
- delete (field as any).useSameAnalyzerForSearch;
+ delete (updatedField as any).useSameAnalyzerForSearch;
- return sanitizeField(runParametersSerializers(field));
+ return sanitizeField(runParametersSerializers(updatedField));
};
export const fieldDeserializer: SerializerFunc = (field: Field): Field => {
@@ -70,8 +73,18 @@ export const fieldDeserializer: SerializerFunc = (field: Field): Field =>
field.type = type;
}
- (field as any).useSameAnalyzerForSearch =
- {}.hasOwnProperty.call(field, 'search_analyzer') === false;
+ if (field.type === 'other') {
+ const { type, subType, name, ...otherTypeJson } = field;
+ /**
+ * For "other" type (type we don't support through a form)
+ * we grab all the parameters and put them in the "otherTypeJson" object
+ * that we will render in a JSON editor.
+ */
+ field.otherTypeJson = otherTypeJson;
+ } else {
+ (field as any).useSameAnalyzerForSearch =
+ {}.hasOwnProperty.call(field, 'search_analyzer') === false;
+ }
return runParametersDeserializers(field);
};
diff --git a/x-pack/plugins/index_management/public/application/components/mappings_editor/lib/utils.ts b/x-pack/plugins/index_management/public/application/components/mappings_editor/lib/utils.ts
index e8f63265d378f..6bb3c4bc23807 100644
--- a/x-pack/plugins/index_management/public/application/components/mappings_editor/lib/utils.ts
+++ b/x-pack/plugins/index_management/public/application/components/mappings_editor/lib/utils.ts
@@ -25,6 +25,7 @@ import {
PARAMETERS_DEFINITION,
TYPE_NOT_ALLOWED_MULTIFIELD,
TYPE_ONLY_ALLOWED_AT_ROOT_LEVEL,
+ TYPE_DEFINITION,
} from '../constants';
import { State } from '../reducer';
@@ -70,6 +71,9 @@ export const getFieldMeta = (field: Field, isMultiField?: boolean): FieldMeta =>
};
};
+export const getTypeLabelFromType = (type: DataType) =>
+ TYPE_DEFINITION[type] ? TYPE_DEFINITION[type].label : `${TYPE_DEFINITION.other.label}: ${type}`;
+
export const getFieldConfig = (param: ParameterName, prop?: string): FieldConfig => {
if (prop !== undefined) {
if (
@@ -121,7 +125,7 @@ const replaceAliasPathByAliasId = (
};
export const getMainTypeFromSubType = (subType: SubType): MainType =>
- SUB_TYPE_MAP_TO_MAIN[subType] as MainType;
+ (SUB_TYPE_MAP_TO_MAIN[subType] ?? 'other') as MainType;
/**
* In order to better work with the recursive pattern of the mappings `properties`, this method flatten the fields
@@ -286,7 +290,9 @@ export const deNormalize = ({ rootLevelFields, byId, aliases }: NormalizedFields
const { source, childFields, childFieldsName } = serializedFieldsById[id];
const { name, ...normalizedField } = source;
const field: Omit = normalizedField;
+
to[name] = field;
+
if (childFields) {
field[childFieldsName!] = {};
return deNormalizePaths(childFields, field[childFieldsName!]);
diff --git a/x-pack/plugins/index_management/public/application/components/mappings_editor/types.ts b/x-pack/plugins/index_management/public/application/components/mappings_editor/types.ts
index dbbffe5a0bd31..5b18af68ed55b 100644
--- a/x-pack/plugins/index_management/public/application/components/mappings_editor/types.ts
+++ b/x-pack/plugins/index_management/public/application/components/mappings_editor/types.ts
@@ -56,7 +56,12 @@ export type MainType =
| 'date_nanos'
| 'geo_point'
| 'geo_shape'
- | 'token_count';
+ | 'token_count'
+ /**
+ * 'other' is a special type that only exists inside of MappingsEditor as a placeholder
+ * for undocumented field types.
+ */
+ | 'other';
export type SubType = NumericType | RangeType;
@@ -156,6 +161,10 @@ interface FieldBasic {
subType?: SubType;
properties?: { [key: string]: Omit };
fields?: { [key: string]: Omit };
+
+ // other* exist together as a holder of types that the mappings editor does not yet know about but
+ // enables the user to create mappings with them.
+ otherTypeJson?: GenericObject;
}
type FieldParams = {