Skip to content

Commit

Permalink
[Mappings editor] Add support for the _size parameter (elastic#119365) (
Browse files Browse the repository at this point in the history
  • Loading branch information
sebelga committed Dec 8, 2021
1 parent 6e7c791 commit 485aad9
Show file tree
Hide file tree
Showing 36 changed files with 722 additions and 191 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,14 @@ readonly links: {
}>;
readonly watcher: Record<string, string>;
readonly ccs: Record<string, string>;
readonly plugins: Record<string, string>;
readonly plugins: {
azureRepo: string;
gcsRepo: string;
hdfsRepo: string;
s3Repo: string;
snapshotRestoreRepos: string;
mapperSize: string;
};
readonly snapshotRestore: Record<string, string>;
readonly ingest: Record<string, string>;
readonly fleet: Readonly<{
Expand Down
10 changes: 9 additions & 1 deletion src/core/public/doc_links/doc_links_service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -486,6 +486,7 @@ export class DocLinksService {
hdfsRepo: `${PLUGIN_DOCS}repository-hdfs.html`,
s3Repo: `${PLUGIN_DOCS}repository-s3.html`,
snapshotRestoreRepos: `${PLUGIN_DOCS}repository.html`,
mapperSize: `${PLUGIN_DOCS}mapper-size-usage.html`,
},
snapshotRestore: {
guide: `${ELASTICSEARCH_DOCS}snapshot-restore.html`,
Expand Down Expand Up @@ -874,7 +875,14 @@ export interface DocLinksStart {
}>;
readonly watcher: Record<string, string>;
readonly ccs: Record<string, string>;
readonly plugins: Record<string, string>;
readonly plugins: {
azureRepo: string;
gcsRepo: string;
hdfsRepo: string;
s3Repo: string;
snapshotRestoreRepos: string;
mapperSize: string;
};
readonly snapshotRestore: Record<string, string>;
readonly ingest: Record<string, string>;
readonly fleet: Readonly<{
Expand Down
9 changes: 8 additions & 1 deletion src/core/public/public.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -761,7 +761,14 @@ export interface DocLinksStart {
}>;
readonly watcher: Record<string, string>;
readonly ccs: Record<string, string>;
readonly plugins: Record<string, string>;
readonly plugins: {
azureRepo: string;
gcsRepo: string;
hdfsRepo: string;
s3Repo: string;
snapshotRestoreRepos: string;
mapperSize: string;
};
readonly snapshotRestore: Record<string, string>;
readonly ingest: Record<string, string>;
readonly fleet: Readonly<{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,17 @@ const registerHttpRequestMockHelpers = (server: SinonFakeServer) => {
]);
};

const setLoadNodesPluginsResponse = (response?: HttpResponse, error?: any) => {
const status = error ? error.status || 400 : 200;
const body = error ? error.body : response;

server.respondWith('GET', `${API_BASE_PATH}/nodes/plugins`, [
status,
{ 'Content-Type': 'application/json' },
JSON.stringify(body),
]);
};

return {
setLoadTemplatesResponse,
setLoadIndicesResponse,
Expand All @@ -136,6 +147,7 @@ const registerHttpRequestMockHelpers = (server: SinonFakeServer) => {
setUpdateTemplateResponse,
setSimulateTemplateResponse,
setLoadComponentTemplatesResponse,
setLoadNodesPluginsResponse,
};
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ describe('<TemplateCreate />', () => {
jest.useFakeTimers();

httpRequestsMockHelpers.setLoadComponentTemplatesResponse(componentTemplates);
httpRequestsMockHelpers.setLoadNodesPluginsResponse([]);

// disable all react-beautiful-dnd development warnings
(window as any)['__react-beautiful-dnd-disable-dev-warnings'] = true;
Expand Down Expand Up @@ -296,14 +297,18 @@ describe('<TemplateCreate />', () => {
});

describe('mappings (step 4)', () => {
beforeEach(async () => {
const navigateToMappingsStep = async () => {
const { actions } = testBed;
// Logistics
await actions.completeStepOne({ name: TEMPLATE_NAME, indexPatterns: ['index1'] });
// Component templates
await actions.completeStepTwo();
// Index settings
await actions.completeStepThree('{}');
};

beforeEach(async () => {
await navigateToMappingsStep();
});

it('should set the correct page title', () => {
Expand Down Expand Up @@ -337,6 +342,43 @@ describe('<TemplateCreate />', () => {

expect(find('fieldsListItem').length).toBe(1);
});

describe('plugin parameters', () => {
const selectMappingsEditorTab = async (
tab: 'fields' | 'runtimeFields' | 'templates' | 'advanced'
) => {
const tabIndex = ['fields', 'runtimeFields', 'templates', 'advanced'].indexOf(tab);
const tabElement = testBed.find('mappingsEditor.formTab').at(tabIndex);
await act(async () => {
tabElement.simulate('click');
});
testBed.component.update();
};

test('should not render the _size parameter if the mapper size plugin is not installed', async () => {
const { exists } = testBed;
// Navigate to the advanced configuration
await selectMappingsEditorTab('advanced');

expect(exists('mappingsEditor.advancedConfiguration.sizeEnabledToggle')).toBe(false);
});

test('should render the _size parameter if the mapper size plugin is installed', async () => {
httpRequestsMockHelpers.setLoadNodesPluginsResponse(['mapper-size']);

await act(async () => {
testBed = await setup();
});
testBed.component.update();
await navigateToMappingsStep();

await selectMappingsEditorTab('advanced');

expect(testBed.exists('mappingsEditor.advancedConfiguration.sizeEnabledToggle')).toBe(
true
);
});
});
});

describe('aliases (step 5)', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -339,4 +339,6 @@ export type TestSubjects =
| 'versionField'
| 'aliasesEditor'
| 'settingsEditor'
| 'versionField.input';
| 'versionField.input'
| 'mappingsEditor.formTab'
| 'mappingsEditor.advancedConfiguration.sizeEnabledToggle';
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* 2.0.
*/

import React from 'react';
import React, { ComponentType, MemoExoticComponent } from 'react';
import SemVer from 'semver/classes/semver';

/* eslint-disable-next-line @kbn/eslint/no-restricted-paths */
Expand All @@ -18,6 +18,7 @@ import {
import { MAJOR_VERSION } from '../../../../../../../common';
import { MappingsEditorProvider } from '../../../mappings_editor_context';
import { createKibanaReactContext } from '../../../shared_imports';
import { Props as MappingsEditorProps } from '../../../mappings_editor';

export const kibanaVersion = new SemVer(MAJOR_VERSION);

Expand Down Expand Up @@ -82,17 +83,21 @@ const { Provider: KibanaReactContextProvider } = createKibanaReactContext({
},
});

const defaultProps = {
const defaultProps: MappingsEditorProps = {
docLinks: docLinksServiceMock.createStartContract(),
onChange: () => undefined,
esNodesPlugins: [],
};

export const WithAppDependencies = (Comp: any) => (props: any) =>
(
<KibanaReactContextProvider>
<MappingsEditorProvider>
<GlobalFlyoutProvider>
<Comp {...defaultProps} {...props} />
</GlobalFlyoutProvider>
</MappingsEditorProvider>
</KibanaReactContextProvider>
);
export const WithAppDependencies =
(Comp: MemoExoticComponent<ComponentType<MappingsEditorProps>>) =>
(props: Partial<MappingsEditorProps>) =>
(
<KibanaReactContextProvider>
<MappingsEditorProvider>
<GlobalFlyoutProvider>
<Comp {...defaultProps} {...props} />
</GlobalFlyoutProvider>
</MappingsEditorProvider>
</KibanaReactContextProvider>
);
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,19 @@ import { EuiSpacer } from '@elastic/eui';

import { useForm, Form } from '../../shared_imports';
import { GenericObject, MappingsConfiguration } from '../../types';
import { MapperSizePluginId } from '../../constants';
import { useDispatch } from '../../mappings_state_context';
import { DynamicMappingSection } from './dynamic_mapping_section';
import { SourceFieldSection } from './source_field_section';
import { MetaFieldSection } from './meta_field_section';
import { RoutingSection } from './routing_section';
import { MapperSizePluginSection } from './mapper_size_plugin_section';
import { configurationFormSchema } from './configuration_form_schema';

interface Props {
value?: MappingsConfiguration;
/** List of plugins installed in the cluster nodes */
esNodesPlugins: string[];
}

const formSerializer = (formData: GenericObject) => {
Expand All @@ -35,6 +39,7 @@ const formSerializer = (formData: GenericObject) => {
sourceField,
metaField,
_routing,
_size,
} = formData;

const dynamic = dynamicMappingsEnabled ? true : throwErrorsForUnmappedFields ? 'strict' : false;
Expand All @@ -47,6 +52,7 @@ const formSerializer = (formData: GenericObject) => {
_source: sourceField,
_meta: metaField,
_routing,
_size,
};

return serialized;
Expand All @@ -67,6 +73,8 @@ const formDeserializer = (formData: GenericObject) => {
},
_meta,
_routing,
// For the Mapper Size plugin
_size,
} = formData;

return {
Expand All @@ -84,10 +92,11 @@ const formDeserializer = (formData: GenericObject) => {
},
metaField: _meta ?? {},
_routing,
_size,
};
};

export const ConfigurationForm = React.memo(({ value }: Props) => {
export const ConfigurationForm = React.memo(({ value, esNodesPlugins }: Props) => {
const isMounted = useRef(false);

const { form } = useForm({
Expand All @@ -100,6 +109,9 @@ export const ConfigurationForm = React.memo(({ value }: Props) => {
const dispatch = useDispatch();
const { subscribe, submit, reset, getFormData } = form;

const isMapperSizeSectionVisible =
value?._size !== undefined || esNodesPlugins.includes(MapperSizePluginId);

useEffect(() => {
const subscription = subscribe(({ data, isValid, validate }) => {
dispatch({
Expand Down Expand Up @@ -150,6 +162,7 @@ export const ConfigurationForm = React.memo(({ value }: Props) => {
<SourceFieldSection />
<EuiSpacer size="xl" />
<RoutingSection />
{isMapperSizeSectionVisible && <MapperSizePluginSection />}
</Form>
);
});
Original file line number Diff line number Diff line change
Expand Up @@ -192,4 +192,12 @@ export const configurationFormSchema: FormSchema = {
defaultValue: false,
},
},
_size: {
enabled: {
label: i18n.translate('xpack.idxMgmt.mappingsEditor.configuration.sizeLabel', {
defaultMessage: 'Index the _source field size in bytes',
}),
defaultValue: false,
},
},
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* 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 React from 'react';

import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n-react';
import { EuiLink, EuiCode } from '@elastic/eui';

import { documentationService } from '../../../../services/documentation';
import { UseField, FormRow, ToggleField } from '../../shared_imports';

export const MapperSizePluginSection = () => {
return (
<FormRow
title={i18n.translate('xpack.idxMgmt.mappingsEditor.sizeTitle', {
defaultMessage: '_size',
})}
description={
<FormattedMessage
id="xpack.idxMgmt.mappingsEditor.sizeDescription"
defaultMessage="The Mapper Size plugin can index the size of the original {_source} field. {docsLink}"
values={{
docsLink: (
<EuiLink href={documentationService.docLinks.plugins.mapperSize} target="_blank">
{i18n.translate('xpack.idxMgmt.mappingsEditor.sizeDocumentionLink', {
defaultMessage: 'Learn more.',
})}
</EuiLink>
),
_source: <EuiCode>_source</EuiCode>,
}}
/>
}
>
<UseField
path="_size.enabled"
component={ToggleField}
componentProps={{ 'data-test-subj': 'sizeEnabledToggle' }}
/>
</FormRow>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,12 @@ import { LoadMappingsProvider } from './load_mappings_provider';

interface Props {
onJson(json: { [key: string]: any }): void;
/** List of plugins installed in the cluster nodes */
esNodesPlugins: string[];
}

export const LoadMappingsFromJsonButton = ({ onJson }: Props) => (
<LoadMappingsProvider onJson={onJson}>
export const LoadMappingsFromJsonButton = ({ onJson, esNodesPlugins }: Props) => (
<LoadMappingsProvider onJson={onJson} esNodesPlugins={esNodesPlugins}>
{(openModal) => (
<EuiButtonEmpty onClick={openModal} size="s">
{i18n.translate('xpack.idxMgmt.mappingsEditor.loadFromJsonButtonLabel', {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import { registerTestBed, TestBed } from '@kbn/test/jest';
import { LoadMappingsProvider } from './load_mappings_provider';

const ComponentToTest = ({ onJson }: { onJson: () => void }) => (
<LoadMappingsProvider onJson={onJson}>
<LoadMappingsProvider onJson={onJson} esNodesPlugins={[]}>
{(openModal) => (
<button onClick={openModal} data-test-subj="load-json-button">
Load JSON
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ type OpenJsonModalFunc = () => void;

interface Props {
onJson(json: { [key: string]: any }): void;
/** List of plugins installed in the cluster nodes */
esNodesPlugins: string[];
children: (openModal: OpenJsonModalFunc) => React.ReactNode;
}

Expand Down Expand Up @@ -120,7 +122,7 @@ const getErrorMessage = (error: MappingsValidationError) => {
}
};

export const LoadMappingsProvider = ({ onJson, children }: Props) => {
export const LoadMappingsProvider = ({ onJson, esNodesPlugins, children }: Props) => {
const [state, setState] = useState<State>({ isModalOpen: false });
const [totalErrorsToDisplay, setTotalErrorsToDisplay] = useState<number>(MAX_ERRORS_TO_DISPLAY);
const jsonContent = useRef<Parameters<OnJsonEditorUpdateHandler>['0'] | undefined>();
Expand Down Expand Up @@ -153,7 +155,7 @@ export const LoadMappingsProvider = ({ onJson, children }: Props) => {
if (isValidJson) {
// Parse and validate the JSON to make sure it won't break the UI
const unparsed = jsonContent.current.data.format();
const { value: parsed, errors } = validateMappings(unparsed);
const { value: parsed, errors } = validateMappings(unparsed, esNodesPlugins);

if (errors) {
setState({ isModalOpen: true, json: { unparsed, parsed }, errors });
Expand Down
Loading

0 comments on commit 485aad9

Please sign in to comment.