mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 01:13:23 -04:00
[Search] Make Reference Field in Semantic_text Optional (#215562)
## Summary This PR focus on making the `reference field` optional when adding `semantic_text` field from Index Mapping. Previously, `semantic_text` field was dependent on a text field and `copy_to` functionality which is not required anymore. https://github.com/user-attachments/assets/f19d0c1b-ac34-4f8d-b75d-993dd8720739 Added a label `optional` in the field after the video recording. <img width="1227" alt="Screenshot 2025-03-26 at 1 25 22 PM" src="https://github.com/user-attachments/assets/a11ed104-df50-47f4-a13f-9cf7187b2ad1" /> ### Checklist Check the PR satisfies following conditions. Reviewers should verify this PR satisfies this list as well. - [X] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios - [x] [Flaky Test Runner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was used on any tests changed --------- Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
This commit is contained in:
parent
40e95f00f1
commit
ab07c23962
10 changed files with 91 additions and 25 deletions
|
@ -21834,7 +21834,6 @@
|
|||
"xpack.idxMgmt.mappingsEditor.parameters.validations.pathIsRequiredErrorMessage": "Sélectionnez un champ vers lequel pointer l'alias.",
|
||||
"xpack.idxMgmt.mappingsEditor.parameters.validations.positionIncrementGapIsRequiredErrorMessage": "Définir une valeur d'écart d'incrément de position",
|
||||
"xpack.idxMgmt.mappingsEditor.parameters.validations.priorityIsRequiredErrorMessage": "Spécifiez une priorité.",
|
||||
"xpack.idxMgmt.mappingsEditor.parameters.validations.referenceFieldIsRequiredErrorMessage": "Le champ de référence est obligatoire.",
|
||||
"xpack.idxMgmt.mappingsEditor.parameters.validations.scalingFactorIsRequiredErrorMessage": "Facteur de montée en charge obligatoire.",
|
||||
"xpack.idxMgmt.mappingsEditor.parameters.validations.smallerZeroErrorMessage": "La valeur doit être supérieure ou égale à 0.",
|
||||
"xpack.idxMgmt.mappingsEditor.parameters.validations.spacesNotAllowedErrorMessage": "Les espaces ne sont pas autorisés.",
|
||||
|
|
|
@ -21813,7 +21813,6 @@
|
|||
"xpack.idxMgmt.mappingsEditor.parameters.validations.pathIsRequiredErrorMessage": "エイリアスが指し示すフィールドを選択します。",
|
||||
"xpack.idxMgmt.mappingsEditor.parameters.validations.positionIncrementGapIsRequiredErrorMessage": "位置のインクリメントギャップ値の設定",
|
||||
"xpack.idxMgmt.mappingsEditor.parameters.validations.priorityIsRequiredErrorMessage": "優先度を指定します。",
|
||||
"xpack.idxMgmt.mappingsEditor.parameters.validations.referenceFieldIsRequiredErrorMessage": "参照フィールドは必須です。",
|
||||
"xpack.idxMgmt.mappingsEditor.parameters.validations.scalingFactorIsRequiredErrorMessage": "スケーリングファクターが必要です。",
|
||||
"xpack.idxMgmt.mappingsEditor.parameters.validations.smallerZeroErrorMessage": "値は0と同じかそれ以上でなければなりません。",
|
||||
"xpack.idxMgmt.mappingsEditor.parameters.validations.spacesNotAllowedErrorMessage": "スペースは使用できません。",
|
||||
|
|
|
@ -21856,7 +21856,6 @@
|
|||
"xpack.idxMgmt.mappingsEditor.parameters.validations.pathIsRequiredErrorMessage": "选择将别名指向的字段。",
|
||||
"xpack.idxMgmt.mappingsEditor.parameters.validations.positionIncrementGapIsRequiredErrorMessage": "设置位置递增间隔值",
|
||||
"xpack.idxMgmt.mappingsEditor.parameters.validations.priorityIsRequiredErrorMessage": "指定优先级。",
|
||||
"xpack.idxMgmt.mappingsEditor.parameters.validations.referenceFieldIsRequiredErrorMessage": "“参考字段”必填。",
|
||||
"xpack.idxMgmt.mappingsEditor.parameters.validations.scalingFactorIsRequiredErrorMessage": "缩放因数必填。",
|
||||
"xpack.idxMgmt.mappingsEditor.parameters.validations.smallerZeroErrorMessage": "值必须大于或等于 0。",
|
||||
"xpack.idxMgmt.mappingsEditor.parameters.validations.spacesNotAllowedErrorMessage": "不允许使用空格。",
|
||||
|
|
|
@ -128,7 +128,12 @@ const createActions = (testBed: TestBed<TestSubjects>) => {
|
|||
return { field: find(testSubject as TestSubjects), testSubject };
|
||||
};
|
||||
|
||||
const addField = async (name: string, type: string, subType?: string) => {
|
||||
const addField = async (
|
||||
name: string,
|
||||
type: string,
|
||||
subType?: string,
|
||||
referenceFieldValue?: string
|
||||
) => {
|
||||
await act(async () => {
|
||||
form.setInputValue('nameParameterInput', name);
|
||||
jest.advanceTimersByTime(0); // advance timers to allow the form to validate
|
||||
|
@ -151,6 +156,11 @@ const createActions = (testBed: TestBed<TestSubjects>) => {
|
|||
});
|
||||
}
|
||||
|
||||
if (referenceFieldValue !== undefined) {
|
||||
form.setSelectValue('select', referenceFieldValue);
|
||||
jest.advanceTimersByTime(0); // advance timers to allow the form to validate
|
||||
}
|
||||
|
||||
await act(async () => {
|
||||
find('createFieldForm.addButton').simulate('click');
|
||||
jest.advanceTimersByTime(0); // advance timers to allow the form to validate
|
||||
|
|
|
@ -506,6 +506,44 @@ describe('Mappings editor: core', () => {
|
|||
const newField = { name: 'someNewField', type: 'semantic_text' };
|
||||
await addField(newField.name, newField.type);
|
||||
|
||||
updatedMappings = {
|
||||
...updatedMappings,
|
||||
properties: {
|
||||
...updatedMappings.properties,
|
||||
[newField.name]: { reference_field: '', type: 'semantic_text' },
|
||||
},
|
||||
};
|
||||
|
||||
({ data } = await getMappingsEditorData(component));
|
||||
|
||||
expect(data).toEqual(updatedMappings);
|
||||
});
|
||||
|
||||
test('updates mapping with reference field value for semantic_text field', async () => {
|
||||
let updatedMappings = { ...defaultMappings };
|
||||
|
||||
const {
|
||||
find,
|
||||
actions: { addField },
|
||||
component,
|
||||
} = testBed;
|
||||
|
||||
/**
|
||||
* Mapped fields
|
||||
*/
|
||||
await act(async () => {
|
||||
find('addFieldButton').simulate('click');
|
||||
jest.advanceTimersByTime(0); // advance timers to allow the form to validate
|
||||
});
|
||||
component.update();
|
||||
|
||||
const newField = {
|
||||
name: 'someNewField',
|
||||
type: 'semantic_text',
|
||||
referenceField: 'address.city',
|
||||
};
|
||||
await addField(newField.name, newField.type, undefined, newField.referenceField);
|
||||
|
||||
updatedMappings = {
|
||||
...updatedMappings,
|
||||
properties: {
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
|
||||
import React from 'react';
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { EuiText } from '@elastic/eui';
|
||||
import { getFieldConfig } from '../../../lib';
|
||||
import { useMappingsState } from '../../../mappings_state_context';
|
||||
import { SuperSelectField, UseField } from '../../../shared_imports';
|
||||
|
@ -41,6 +43,16 @@ export const ReferenceFieldSelects = () => {
|
|||
euiFieldProps={{
|
||||
options: referenceFieldOptions,
|
||||
}}
|
||||
labelAppend={
|
||||
<EuiText size="xs" color="subdued">
|
||||
{i18n.translate(
|
||||
'xpack.idxMgmt.mappingsEditor.createField.referenceField.optionalLabel',
|
||||
{
|
||||
defaultMessage: 'Optional',
|
||||
}
|
||||
)}
|
||||
</EuiText>
|
||||
}
|
||||
data-test-subj="referenceFieldSelect"
|
||||
/>
|
||||
)}
|
||||
|
|
|
@ -127,15 +127,11 @@ export const CreateField = React.memo(function CreateFieldComponent({
|
|||
const defaultName = getFieldByPathName(allSemanticFields, 'semantic_text')
|
||||
? ''
|
||||
: 'semantic_text';
|
||||
const referenceField =
|
||||
Object.values(allSemanticFields.byId)
|
||||
.find((field) => field.source.type === 'text' && !field.isMultiField)
|
||||
?.path.join('.') || '';
|
||||
if (!form.getFormData().name) {
|
||||
form.setFieldValue('name', defaultName);
|
||||
}
|
||||
if (!form.getFormData().reference_field) {
|
||||
form.setFieldValue('reference_field', referenceField);
|
||||
form.setFieldValue('reference_field', '');
|
||||
}
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
|
|
|
@ -1109,18 +1109,6 @@ export const PARAMETERS_DEFINITION: { [key in ParameterName]: ParameterDefinitio
|
|||
helpText: i18n.translate('xpack.idxMgmt.mappingsEditor.parameters.referenceFieldHelpText', {
|
||||
defaultMessage: 'Reference field for model inference.',
|
||||
}),
|
||||
validations: [
|
||||
{
|
||||
validator: emptyField(
|
||||
i18n.translate(
|
||||
'xpack.idxMgmt.mappingsEditor.parameters.validations.referenceFieldIsRequiredErrorMessage',
|
||||
{
|
||||
defaultMessage: 'Reference field is required.',
|
||||
}
|
||||
)
|
||||
),
|
||||
},
|
||||
],
|
||||
},
|
||||
schema: t.string,
|
||||
},
|
||||
|
|
|
@ -462,8 +462,25 @@ describe('utils', () => {
|
|||
} as any;
|
||||
expect(getStateWithCopyToFields(state)).toEqual(state);
|
||||
});
|
||||
test('returns state if semantic text field has no reference field', () => {
|
||||
test('returns state if reference field in semantic_text is empty', () => {
|
||||
const state = {
|
||||
fields: {
|
||||
byId: {
|
||||
'88ebcfdb-19b7-4458-9ea2-9488df54453d': {
|
||||
id: '88ebcfdb-19b7-4458-9ea2-9488df54453d',
|
||||
isMultiField: false,
|
||||
source: {
|
||||
name: 'title',
|
||||
type: 'semantic_text',
|
||||
inference_id: 'id',
|
||||
reference_field: '',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
} as any;
|
||||
|
||||
const expectedState = {
|
||||
fields: {
|
||||
byId: {
|
||||
'88ebcfdb-19b7-4458-9ea2-9488df54453d': {
|
||||
|
@ -478,7 +495,7 @@ describe('utils', () => {
|
|||
},
|
||||
},
|
||||
} as any;
|
||||
expect(getStateWithCopyToFields(state)).toEqual(state);
|
||||
expect(getStateWithCopyToFields(state)).toEqual(expectedState);
|
||||
});
|
||||
test('adds text field with copy to to state if semantic text field has reference field', () => {
|
||||
const state = {
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
|
||||
import { cloneDeep } from 'lodash';
|
||||
import { cloneDeep, isEmpty } from 'lodash';
|
||||
import { InferenceServiceSettings } from '@elastic/elasticsearch/lib/api/types';
|
||||
import { LocalInferenceServiceSettings } from '@kbn/ml-trained-models-utils/src/constants/trained_models';
|
||||
import {
|
||||
|
@ -702,7 +702,7 @@ export function getStateWithCopyToFields(state: State): State {
|
|||
// Make sure we don't accidentally modify existing state
|
||||
let updatedState = cloneDeep(state);
|
||||
for (const field of Object.values(updatedState.fields.byId)) {
|
||||
if (field.source.type === 'semantic_text' && field.source.reference_field) {
|
||||
if (field.source.type === 'semantic_text') {
|
||||
// Check fields already added to the list of to-update fields first
|
||||
// API will not accept reference_field so removing it now
|
||||
const { reference_field: referenceField, ...source } = field.source;
|
||||
|
@ -711,6 +711,14 @@ export function getStateWithCopyToFields(state: State): State {
|
|||
throw new Error('Reference field is not a string');
|
||||
}
|
||||
field.source = source;
|
||||
|
||||
/*
|
||||
If no reference field is associated,
|
||||
no further processing is needed, so we can skip to the next one.
|
||||
*/
|
||||
if (isEmpty(referenceField)) {
|
||||
continue;
|
||||
}
|
||||
const existingTextField =
|
||||
getFieldByPathName(updatedState.fields, referenceField) ||
|
||||
getFieldByPathName(updatedState.mappingViewFields || { byId: {} }, referenceField);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue