From 49aef21bd4178dd72dafc6decdf11d875a3eb4fa Mon Sep 17 00:00:00 2001 From: Jason Stoltzfus Date: Thu, 18 Mar 2021 09:27:16 -0400 Subject: [PATCH] [App Search] Result settings logic - actions and reducers (#94629) --- .../components/result_settings/constants.ts | 14 + .../components/result_settings/index.ts | 1 + .../result_settings_logic.test.ts | 398 ++++++++++++++++++ .../result_settings/result_settings_logic.ts | 190 +++++++++ .../components/result_settings/types.ts | 37 ++ .../components/result_settings/utils.test.ts | 174 ++++++++ .../components/result_settings/utils.ts | 117 +++++ 7 files changed, 931 insertions(+) create mode 100644 x-pack/plugins/enterprise_search/public/applications/app_search/components/result_settings/result_settings_logic.test.ts create mode 100644 x-pack/plugins/enterprise_search/public/applications/app_search/components/result_settings/result_settings_logic.ts create mode 100644 x-pack/plugins/enterprise_search/public/applications/app_search/components/result_settings/types.ts create mode 100644 x-pack/plugins/enterprise_search/public/applications/app_search/components/result_settings/utils.test.ts create mode 100644 x-pack/plugins/enterprise_search/public/applications/app_search/components/result_settings/utils.ts diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/result_settings/constants.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/result_settings/constants.ts index 433f23db7562..d5e7035348b4 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/result_settings/constants.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/result_settings/constants.ts @@ -7,7 +7,21 @@ import { i18n } from '@kbn/i18n'; +import { FieldResultSetting } from './types'; + export const RESULT_SETTINGS_TITLE = i18n.translate( 'xpack.enterpriseSearch.appSearch.engine.resultSettings.title', { defaultMessage: 'Result Settings' } ); + +export const DEFAULT_FIELD_SETTINGS: FieldResultSetting = { + raw: true, + snippet: false, + snippetFallback: false, +}; + +export const DISABLED_FIELD_SETTINGS: FieldResultSetting = { + raw: false, + snippet: false, + snippetFallback: false, +}; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/result_settings/index.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/result_settings/index.ts index b605aa5714e9..3336de732a50 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/result_settings/index.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/result_settings/index.ts @@ -6,4 +6,5 @@ */ export { RESULT_SETTINGS_TITLE } from './constants'; +export { ResultSettingsLogic } from './result_settings_logic'; export { ResultSettings } from './result_settings'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/result_settings/result_settings_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/result_settings/result_settings_logic.test.ts new file mode 100644 index 000000000000..914794037464 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/result_settings/result_settings_logic.test.ts @@ -0,0 +1,398 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { LogicMounter } from '../../../__mocks__'; + +import { Schema, SchemaConflicts, SchemaTypes } from '../../../shared/types'; + +import { OpenModal, ServerFieldResultSettingObject } from './types'; + +import { ResultSettingsLogic } from '.'; + +describe('ResultSettingsLogic', () => { + const { mount } = new LogicMounter(ResultSettingsLogic); + + const DEFAULT_VALUES = { + dataLoading: true, + saving: false, + openModal: OpenModal.None, + nonTextResultFields: {}, + resultFields: {}, + serverResultFields: {}, + textResultFields: {}, + lastSavedResultFields: {}, + schema: {}, + schemaConflicts: {}, + }; + + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('has expected default values', () => { + mount(); + expect(ResultSettingsLogic.values).toEqual(DEFAULT_VALUES); + }); + + describe('actions', () => { + describe('initializeResultFields', () => { + const serverResultFields: ServerFieldResultSettingObject = { + foo: { raw: { size: 5 } }, + bar: { raw: { size: 5 } }, + }; + const schema: Schema = { + foo: 'text' as SchemaTypes, + bar: 'number' as SchemaTypes, + baz: 'text' as SchemaTypes, + }; + const schemaConflicts: SchemaConflicts = { + foo: { + text: ['foo'], + number: ['foo'], + geolocation: [], + date: [], + }, + }; + + it('will initialize all result field state within the UI, based on provided server data', () => { + mount({ + dataLoading: true, + saving: true, + openModal: OpenModal.ConfirmSaveModal, + }); + + ResultSettingsLogic.actions.initializeResultFields( + serverResultFields, + schema, + schemaConflicts + ); + + expect(ResultSettingsLogic.values).toEqual({ + ...DEFAULT_VALUES, + dataLoading: false, + saving: false, + // It converts the passed server result fields to a client results field and stores it + // as resultFields + resultFields: { + foo: { + raw: true, + rawSize: 5, + snippet: false, + snippetFallback: false, + }, + // Baz was not part of the original serverResultFields, it was injected based on the schema + baz: { + raw: false, + snippet: false, + snippetFallback: false, + }, + bar: { + raw: true, + rawSize: 5, + snippet: false, + snippetFallback: false, + }, + }, + // It also saves it as lastSavedResultFields + lastSavedResultFields: { + foo: { + raw: true, + rawSize: 5, + snippet: false, + snippetFallback: false, + }, + // Baz was not part of the original serverResultFields, it was injected based on the schema + baz: { + raw: false, + snippet: false, + snippetFallback: false, + }, + bar: { + raw: true, + rawSize: 5, + snippet: false, + snippetFallback: false, + }, + }, + // The resultFields are also partitioned to either nonTextResultFields or textResultFields + // depending on their type within the passed schema + nonTextResultFields: { + bar: { + raw: true, + rawSize: 5, + snippet: false, + snippetFallback: false, + }, + }, + textResultFields: { + // Baz was not part of the original serverResultFields, it was injected based on the schema + baz: { + raw: false, + snippet: false, + snippetFallback: false, + }, + foo: { + raw: true, + rawSize: 5, + snippet: false, + snippetFallback: false, + }, + }, + // It stores the originally passed results as serverResultFields + serverResultFields: { + foo: { raw: { size: 5 } }, + // Baz was not part of the original serverResultFields, it was injected based on the schema + baz: {}, + bar: { raw: { size: 5 } }, + }, + // The modal should be reset back to closed if it had been opened previously + openModal: OpenModal.None, + // Stores the provided schema details + schema, + schemaConflicts, + }); + }); + + it('default schema conflicts data if none was provided', () => { + mount(); + + ResultSettingsLogic.actions.initializeResultFields(serverResultFields, schema); + + expect(ResultSettingsLogic.values.schemaConflicts).toEqual({}); + }); + }); + + describe('openConfirmSaveModal', () => { + mount({ + openModal: OpenModal.None, + }); + + ResultSettingsLogic.actions.openConfirmSaveModal(); + + expect(ResultSettingsLogic.values).toEqual({ + ...DEFAULT_VALUES, + openModal: OpenModal.ConfirmSaveModal, + }); + }); + + describe('openConfirmResetModal', () => { + mount({ + openModal: OpenModal.None, + }); + + ResultSettingsLogic.actions.openConfirmResetModal(); + + expect(ResultSettingsLogic.values).toEqual({ + ...DEFAULT_VALUES, + openModal: OpenModal.ConfirmResetModal, + }); + }); + + describe('closeModals', () => { + it('should close open modals', () => { + mount({ + openModal: OpenModal.ConfirmSaveModal, + }); + + ResultSettingsLogic.actions.closeModals(); + + expect(ResultSettingsLogic.values).toEqual({ + ...DEFAULT_VALUES, + openModal: OpenModal.None, + }); + }); + }); + + describe('clearAllFields', () => { + it('should remove all settings that have been set for each field', () => { + mount({ + nonTextResultFields: { + foo: { raw: false, snippet: false, snippetFallback: false }, + bar: { raw: true, snippet: false, snippetFallback: true }, + }, + textResultFields: { + qux: { raw: false, snippet: false, snippetFallback: false }, + quux: { raw: true, snippet: false, snippetFallback: true }, + }, + resultFields: { + quuz: { raw: false, snippet: false, snippetFallback: false }, + corge: { raw: true, snippet: false, snippetFallback: true }, + }, + serverResultFields: { + grault: { raw: { size: 5 } }, + garply: { raw: true }, + }, + }); + + ResultSettingsLogic.actions.clearAllFields(); + + expect(ResultSettingsLogic.values).toEqual({ + ...DEFAULT_VALUES, + nonTextResultFields: { + foo: {}, + bar: {}, + }, + textResultFields: { + qux: {}, + quux: {}, + }, + resultFields: { + quuz: {}, + corge: {}, + }, + serverResultFields: { + grault: {}, + garply: {}, + }, + }); + }); + }); + + describe('resetAllFields', () => { + it('should reset all settings to their default values per field', () => { + mount({ + nonTextResultFields: { + foo: { raw: true, snippet: true, snippetFallback: true }, + bar: { raw: true, snippet: true, snippetFallback: true }, + }, + textResultFields: { + qux: { raw: true, snippet: true, snippetFallback: true }, + quux: { raw: true, snippet: true, snippetFallback: true }, + }, + resultFields: { + quuz: { raw: true, snippet: true, snippetFallback: true }, + corge: { raw: true, snippet: true, snippetFallback: true }, + }, + serverResultFields: { + grault: { raw: { size: 5 } }, + garply: { raw: true }, + }, + }); + + ResultSettingsLogic.actions.resetAllFields(); + + expect(ResultSettingsLogic.values).toEqual({ + ...DEFAULT_VALUES, + nonTextResultFields: { + bar: { raw: true, snippet: false, snippetFallback: false }, + foo: { raw: true, snippet: false, snippetFallback: false }, + }, + textResultFields: { + qux: { raw: true, snippet: false, snippetFallback: false }, + quux: { raw: true, snippet: false, snippetFallback: false }, + }, + resultFields: { + quuz: { raw: true, snippet: false, snippetFallback: false }, + corge: { raw: true, snippet: false, snippetFallback: false }, + }, + serverResultFields: { + grault: { raw: {} }, + garply: { raw: {} }, + }, + }); + }); + + it('should close open modals', () => { + mount({ + openModal: OpenModal.ConfirmSaveModal, + }); + + ResultSettingsLogic.actions.resetAllFields(); + + expect(ResultSettingsLogic.values).toEqual({ + ...DEFAULT_VALUES, + openModal: OpenModal.None, + }); + }); + }); + + describe('updateField', () => { + const initialValues = { + nonTextResultFields: { + foo: { raw: true, snippet: true, snippetFallback: true }, + bar: { raw: true, snippet: true, snippetFallback: true }, + }, + textResultFields: { + foo: { raw: true, snippet: true, snippetFallback: true }, + bar: { raw: true, snippet: true, snippetFallback: true }, + }, + resultFields: { + foo: { raw: true, snippet: true, snippetFallback: true }, + bar: { raw: true, snippet: true, snippetFallback: true }, + }, + serverResultFields: { + foo: { raw: { size: 5 } }, + bar: { raw: true }, + }, + }; + + it('should update settings for an individual field', () => { + mount(initialValues); + + ResultSettingsLogic.actions.updateField('foo', { + raw: true, + snippet: false, + snippetFallback: false, + }); + + expect(ResultSettingsLogic.values).toEqual({ + ...DEFAULT_VALUES, + // the settings for foo are updated below for any *ResultFields state in which they appear + nonTextResultFields: { + foo: { raw: true, snippet: false, snippetFallback: false }, + bar: { raw: true, snippet: true, snippetFallback: true }, + }, + textResultFields: { + foo: { raw: true, snippet: false, snippetFallback: false }, + bar: { raw: true, snippet: true, snippetFallback: true }, + }, + resultFields: { + foo: { raw: true, snippet: false, snippetFallback: false }, + bar: { raw: true, snippet: true, snippetFallback: true }, + }, + serverResultFields: { + // Note that the specified settings for foo get converted to a "server" format here + foo: { raw: {} }, + bar: { raw: true }, + }, + }); + }); + + it('should do nothing if the specified field does not exist', () => { + mount(initialValues); + + ResultSettingsLogic.actions.updateField('baz', { + raw: false, + snippet: false, + snippetFallback: false, + }); + + // 'baz' does not exist in state, so nothing is updated + expect(ResultSettingsLogic.values).toEqual({ + ...DEFAULT_VALUES, + ...initialValues, + }); + }); + }); + + describe('saving', () => { + it('sets saving to true and close any open modals', () => { + mount({ + saving: false, + }); + + ResultSettingsLogic.actions.saving(); + + expect(ResultSettingsLogic.values).toEqual({ + ...DEFAULT_VALUES, + saving: true, + openModal: OpenModal.None, + }); + }); + }); + }); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/result_settings/result_settings_logic.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/result_settings/result_settings_logic.ts new file mode 100644 index 000000000000..b2ffd3de19f0 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/result_settings/result_settings_logic.ts @@ -0,0 +1,190 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { kea, MakeLogicType } from 'kea'; + +import { Schema, SchemaConflicts } from '../../../shared/types'; + +import { + FieldResultSetting, + FieldResultSettingObject, + OpenModal, + ServerFieldResultSettingObject, +} from './types'; + +import { + clearAllFields, + clearAllServerFields, + convertServerResultFieldsToResultFields, + convertToServerFieldResultSetting, + resetAllFields, + resetAllServerFields, + splitResultFields, +} from './utils'; + +interface ResultSettingsActions { + openConfirmResetModal(): void; + openConfirmSaveModal(): void; + closeModals(): void; + initializeResultFields( + serverResultFields: ServerFieldResultSettingObject, + schema: Schema, + schemaConflicts?: SchemaConflicts + ): { + serverResultFields: ServerFieldResultSettingObject; + resultFields: FieldResultSettingObject; + schema: Schema; + schemaConflicts: SchemaConflicts; + nonTextResultFields: FieldResultSettingObject; + textResultFields: FieldResultSettingObject; + }; + clearAllFields(): void; + resetAllFields(): void; + updateField( + fieldName: string, + settings: FieldResultSetting + ): { fieldName: string; settings: FieldResultSetting }; + saving(): void; +} + +interface ResultSettingsValues { + dataLoading: boolean; + saving: boolean; + openModal: OpenModal; + nonTextResultFields: FieldResultSettingObject; + textResultFields: FieldResultSettingObject; + resultFields: FieldResultSettingObject; + serverResultFields: ServerFieldResultSettingObject; + lastSavedResultFields: FieldResultSettingObject; + schema: Schema; + schemaConflicts: SchemaConflicts; +} + +export const ResultSettingsLogic = kea>({ + path: ['enterprise_search', 'app_search', 'result_settings_logic'], + actions: () => ({ + openConfirmResetModal: () => true, + openConfirmSaveModal: () => true, + closeModals: () => true, + initializeResultFields: (serverResultFields, schema, schemaConflicts) => { + const resultFields = convertServerResultFieldsToResultFields(serverResultFields, schema); + Object.keys(schema).forEach((fieldName) => { + if (!serverResultFields.hasOwnProperty(fieldName)) { + serverResultFields[fieldName] = {}; + } + }); + + return { + serverResultFields, + resultFields, + schema, + schemaConflicts, + ...splitResultFields(resultFields, schema), + }; + }, + clearAllFields: () => true, + resetAllFields: () => true, + updateField: (fieldName, settings) => ({ fieldName, settings }), + saving: () => true, + }), + reducers: () => ({ + dataLoading: [ + true, + { + initializeResultFields: () => false, + }, + ], + saving: [ + false, + { + initializeResultFields: () => false, + saving: () => true, + }, + ], + openModal: [ + OpenModal.None, + { + initializeResultFields: () => OpenModal.None, + closeModals: () => OpenModal.None, + resetAllFields: () => OpenModal.None, + openConfirmResetModal: () => OpenModal.ConfirmResetModal, + openConfirmSaveModal: () => OpenModal.ConfirmSaveModal, + saving: () => OpenModal.None, + }, + ], + nonTextResultFields: [ + {}, + { + initializeResultFields: (_, { nonTextResultFields }) => nonTextResultFields, + clearAllFields: (nonTextResultFields) => clearAllFields(nonTextResultFields), + resetAllFields: (nonTextResultFields) => resetAllFields(nonTextResultFields), + updateField: (nonTextResultFields, { fieldName, settings }) => + nonTextResultFields.hasOwnProperty(fieldName) + ? { ...nonTextResultFields, [fieldName]: settings } + : nonTextResultFields, + }, + ], + textResultFields: [ + {}, + { + initializeResultFields: (_, { textResultFields }) => textResultFields, + clearAllFields: (textResultFields) => clearAllFields(textResultFields), + resetAllFields: (textResultFields) => resetAllFields(textResultFields), + updateField: (textResultFields, { fieldName, settings }) => + textResultFields.hasOwnProperty(fieldName) + ? { ...textResultFields, [fieldName]: settings } + : textResultFields, + }, + ], + resultFields: [ + {}, + { + initializeResultFields: (_, { resultFields }) => resultFields, + clearAllFields: (resultFields) => clearAllFields(resultFields), + resetAllFields: (resultFields) => resetAllFields(resultFields), + updateField: (resultFields, { fieldName, settings }) => + resultFields.hasOwnProperty(fieldName) + ? { ...resultFields, [fieldName]: settings } + : resultFields, + }, + ], + serverResultFields: [ + {}, + { + initializeResultFields: (_, { serverResultFields }) => serverResultFields, + clearAllFields: (serverResultFields) => clearAllServerFields(serverResultFields), + resetAllFields: (serverResultFields) => resetAllServerFields(serverResultFields), + updateField: (serverResultFields, { fieldName, settings }) => { + return serverResultFields.hasOwnProperty(fieldName) + ? { + ...serverResultFields, + [fieldName]: convertToServerFieldResultSetting(settings), + } + : serverResultFields; + }, + }, + ], + lastSavedResultFields: [ + {}, + { + initializeResultFields: (_, { resultFields }) => resultFields, + }, + ], + schema: [ + {}, + { + initializeResultFields: (_, { schema }) => schema, + }, + ], + schemaConflicts: [ + {}, + { + initializeResultFields: (_, { schemaConflicts }) => schemaConflicts || {}, + }, + ], + }), +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/result_settings/types.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/result_settings/types.ts new file mode 100644 index 000000000000..da763dfe7cdc --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/result_settings/types.ts @@ -0,0 +1,37 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export enum OpenModal { + None, + ConfirmResetModal, + ConfirmSaveModal, +} +export interface ServerFieldResultSetting { + raw?: + | { + size?: number; + } + | boolean; + snippet?: + | { + size?: number; + fallback?: boolean; + } + | boolean; +} + +export type ServerFieldResultSettingObject = Record; + +export interface FieldResultSetting { + raw: boolean; + rawSize?: number; + snippet: boolean; + snippetSize?: number; + snippetFallback: boolean; +} + +export type FieldResultSettingObject = Record; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/result_settings/utils.test.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/result_settings/utils.test.ts new file mode 100644 index 000000000000..2482ecab5892 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/result_settings/utils.test.ts @@ -0,0 +1,174 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { SchemaTypes } from '../../../shared/types'; + +import { + convertServerResultFieldsToResultFields, + convertToServerFieldResultSetting, + clearAllServerFields, + clearAllFields, + resetAllServerFields, + resetAllFields, + splitResultFields, +} from './utils'; + +describe('clearAllFields', () => { + it('will reset every key in an object back to an empty object', () => { + expect( + clearAllFields({ + foo: { raw: false, snippet: false, snippetFallback: false }, + bar: { raw: true, snippet: false, snippetFallback: true }, + }) + ).toEqual({ + foo: {}, + bar: {}, + }); + }); +}); + +describe('clearAllServerFields', () => { + it('will reset every key in an object back to an empty object', () => { + expect( + clearAllServerFields({ + foo: { raw: { size: 5 } }, + bar: { raw: true }, + }) + ).toEqual({ + foo: {}, + bar: {}, + }); + }); +}); + +describe('resetAllFields', () => { + it('will reset every key in an object back to a default object', () => { + expect( + resetAllFields({ + foo: { raw: false, snippet: true, snippetFallback: true }, + bar: { raw: false, snippet: true, snippetFallback: true }, + }) + ).toEqual({ + foo: { raw: true, snippet: false, snippetFallback: false }, + bar: { raw: true, snippet: false, snippetFallback: false }, + }); + }); +}); + +describe('resetAllServerFields', () => { + it('will reset every key in an object back to a default object', () => { + expect( + resetAllServerFields({ + foo: { raw: { size: 5 } }, + bar: { snippet: true }, + }) + ).toEqual({ + foo: { raw: {} }, + bar: { raw: {} }, + }); + }); +}); + +describe('convertServerResultFieldsToResultFields', () => { + it('will convert a server settings object to a format that the front-end expects', () => { + expect( + convertServerResultFieldsToResultFields( + { + foo: { + raw: { size: 5 }, + snippet: { size: 3, fallback: true }, + }, + }, + { + foo: 'text' as SchemaTypes, + } + ) + ).toEqual({ + foo: { + raw: true, + rawSize: 5, + snippet: true, + snippetFallback: true, + snippetSize: 3, + }, + }); + }); +}); + +describe('convertToServerFieldResultSetting', () => { + it('will convert a settings object to a format that the server expects', () => { + expect( + convertToServerFieldResultSetting({ + raw: true, + rawSize: 5, + snippet: true, + snippetFallback: true, + snippetSize: 3, + }) + ).toEqual({ + raw: { size: 5 }, + snippet: { size: 3, fallback: true }, + }); + }); + + it('will not include snippet or raw information if they are set to false', () => { + expect( + convertToServerFieldResultSetting({ + raw: false, + rawSize: 5, + snippet: false, + snippetFallback: true, + snippetSize: 3, + }) + ).toEqual({}); + }); + + it('will not include sizes if they are not included, or fallback if it is false', () => { + expect( + convertToServerFieldResultSetting({ + raw: true, + snippet: true, + snippetFallback: false, + }) + ).toEqual({ + raw: {}, + snippet: {}, + }); + }); +}); + +describe('splitResultFields', () => { + it('will split results based on their schema type', () => { + expect( + splitResultFields( + { + foo: { + raw: true, + rawSize: 5, + snippet: false, + snippetFallback: false, + }, + bar: { + raw: true, + rawSize: 5, + snippet: false, + snippetFallback: false, + }, + }, + { + foo: 'text' as SchemaTypes, + bar: 'number' as SchemaTypes, + } + ) + ).toEqual({ + nonTextResultFields: { + bar: { raw: true, rawSize: 5, snippet: false, snippetFallback: false }, + }, + textResultFields: { foo: { raw: true, rawSize: 5, snippet: false, snippetFallback: false } }, + }); + }); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/result_settings/utils.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/result_settings/utils.ts new file mode 100644 index 000000000000..0311132542d9 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/result_settings/utils.ts @@ -0,0 +1,117 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { Schema } from '../../../shared/types'; + +import { DEFAULT_FIELD_SETTINGS, DISABLED_FIELD_SETTINGS } from './constants'; +import { + FieldResultSetting, + FieldResultSettingObject, + ServerFieldResultSetting, + ServerFieldResultSettingObject, +} from './types'; + +const updateAllFields = ( + fields: FieldResultSettingObject | ServerFieldResultSettingObject, + newValue: FieldResultSetting | {} +) => { + return Object.keys(fields).reduce( + (acc, fieldName) => ({ ...acc, [fieldName]: { ...newValue } }), + {} + ); +}; + +const convertToFieldResultSetting = (serverFieldResultSetting: ServerFieldResultSetting) => { + const fieldResultSetting: FieldResultSetting = { + raw: !!serverFieldResultSetting.raw, + snippet: !!serverFieldResultSetting.snippet, + snippetFallback: !!( + serverFieldResultSetting.snippet && + typeof serverFieldResultSetting.snippet === 'object' && + serverFieldResultSetting.snippet.fallback + ), + }; + + if ( + serverFieldResultSetting.raw && + typeof serverFieldResultSetting.raw === 'object' && + serverFieldResultSetting.raw.size + ) { + fieldResultSetting.rawSize = serverFieldResultSetting.raw.size; + } + + if ( + serverFieldResultSetting.snippet && + typeof serverFieldResultSetting.snippet === 'object' && + serverFieldResultSetting.snippet.size + ) { + fieldResultSetting.snippetSize = serverFieldResultSetting.snippet.size; + } + + return fieldResultSetting; +}; + +export const clearAllFields = (fields: FieldResultSettingObject) => updateAllFields(fields, {}); + +export const clearAllServerFields = (fields: ServerFieldResultSettingObject) => + updateAllFields(fields, {}); + +export const resetAllFields = (fields: FieldResultSettingObject) => + updateAllFields(fields, DEFAULT_FIELD_SETTINGS); + +export const resetAllServerFields = (fields: ServerFieldResultSettingObject) => + updateAllFields(fields, { raw: {} }); + +export const convertServerResultFieldsToResultFields = ( + serverResultFields: ServerFieldResultSettingObject, + schema: Schema +) => { + const resultFields: FieldResultSettingObject = Object.keys(schema).reduce( + (acc: FieldResultSettingObject, fieldName: string) => ({ + ...acc, + [fieldName]: serverResultFields[fieldName] + ? convertToFieldResultSetting(serverResultFields[fieldName]) + : DISABLED_FIELD_SETTINGS, + }), + {} + ); + return resultFields; +}; + +export const convertToServerFieldResultSetting = (fieldResultSetting: FieldResultSetting) => { + const serverFieldResultSetting: ServerFieldResultSetting = {}; + if (fieldResultSetting.raw) { + serverFieldResultSetting.raw = {}; + if (fieldResultSetting.rawSize) { + serverFieldResultSetting.raw.size = fieldResultSetting.rawSize; + } + } + + if (fieldResultSetting.snippet) { + serverFieldResultSetting.snippet = {}; + if (fieldResultSetting.snippetFallback) { + serverFieldResultSetting.snippet.fallback = fieldResultSetting.snippetFallback; + } + if (fieldResultSetting.snippetSize) { + serverFieldResultSetting.snippet.size = fieldResultSetting.snippetSize; + } + } + + return serverFieldResultSetting; +}; + +export const splitResultFields = (resultFields: FieldResultSettingObject, schema: Schema) => { + const textResultFields: FieldResultSettingObject = {}; + const nonTextResultFields: FieldResultSettingObject = {}; + const keys = Object.keys(schema); + keys.forEach((fieldName) => { + (schema[fieldName] === 'text' ? textResultFields : nonTextResultFields)[fieldName] = + resultFields[fieldName]; + }); + + return { textResultFields, nonTextResultFields }; +};