Add allow auto create to index templates (#170079)

## Summary
Closes #163123

Add the optional property `allow_auto_create` under Stack Management >
Index Management > Index Templates > Logistics Step.



![image](1b92b912-3ec2-4e71-b64f-05856a54409c)


### Checklist

- [x] Any text added follows [EUI's writing
guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses
sentence case text and includes [i18n
support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md)
- [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] Any UI touched in this PR is usable by keyboard only (learn more
about [keyboard accessibility](https://webaim.org/techniques/keyboard/))
- [x] This renders correctly on smaller devices using a responsive
layout. (You can test this [in your
browser](https://www.browserstack.com/guide/responsive-testing-on-local-server))
- [x] This was checked for [cross-browser
compatibility](https://www.elastic.co/support/matrix#matrix_browsers)


## Release Note
The property `allow_auto_create` can be set on index templates
This commit is contained in:
Brad White 2023-11-07 10:15:44 -07:00 committed by GitHub
parent 36515713a6
commit 7f0ddc9661
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 102 additions and 9 deletions

View file

@ -40,6 +40,7 @@ const templateToClone = getComposableTemplate({
template: {
mappings: MAPPINGS,
},
allowAutoCreate: true,
});
describe('<TemplateClone />', () => {
@ -97,7 +98,7 @@ describe('<TemplateClone />', () => {
actions.clickNextButton();
});
const { priority, version, _kbnMeta } = templateToClone;
const { priority, version, _kbnMeta, allowAutoCreate } = templateToClone;
expect(httpSetup.post).toHaveBeenLastCalledWith(
`${API_BASE_PATH}/index_templates`,
expect.objectContaining({
@ -106,6 +107,7 @@ describe('<TemplateClone />', () => {
indexPatterns: DEFAULT_INDEX_PATTERNS,
priority,
version,
allowAutoCreate,
_kbnMeta,
}),
})

View file

@ -532,6 +532,7 @@ describe('<TemplateCreate />', () => {
await actions.completeStepOne({
name: TEMPLATE_NAME,
indexPatterns: DEFAULT_INDEX_PATTERNS,
allowAutoCreate: true,
});
// Component templates
await actions.completeStepTwo('test_component_template_1');
@ -558,6 +559,7 @@ describe('<TemplateCreate />', () => {
body: JSON.stringify({
name: TEMPLATE_NAME,
indexPatterns: DEFAULT_INDEX_PATTERNS,
allowAutoCreate: true,
_kbnMeta: {
type: 'default',
hasDatastream: false,
@ -631,6 +633,7 @@ describe('<TemplateCreate />', () => {
body: JSON.stringify({
index_patterns: DEFAULT_INDEX_PATTERNS,
data_stream: {},
allow_auto_create: false,
}),
})
);

View file

@ -140,6 +140,7 @@ describe('<TemplateEdit />', () => {
name: 'test',
indexPatterns: ['myPattern*'],
version: 1,
allowAutoCreate: false,
dataStream: {
hidden: true,
anyUnknownKey: 'should_be_kept',
@ -198,6 +199,7 @@ describe('<TemplateEdit />', () => {
await actions.completeStepOne({
indexPatterns: UPDATED_INDEX_PATTERN,
priority: 3,
allowAutoCreate: true,
});
// Component templates
await actions.completeStepTwo();
@ -252,6 +254,7 @@ describe('<TemplateEdit />', () => {
indexPatterns: UPDATED_INDEX_PATTERN,
priority: 3,
version: templateToEdit.version,
allowAutoCreate: true,
_kbnMeta: {
type: 'default',
hasDatastream: false,

View file

@ -146,6 +146,7 @@ export const formSetup = async (initTestBed: SetupFunc<TestSubjects>) => {
priority,
version,
dataStream,
allowAutoCreate,
}: Partial<TemplateDeserialized> = {}) => {
const { component, form, find } = testBed;
@ -184,6 +185,10 @@ export const formSetup = async (initTestBed: SetupFunc<TestSubjects>) => {
form.setInputValue('versionField.input', JSON.stringify(version));
}
if (allowAutoCreate) {
form.toggleEuiSwitch('allowAutoCreateField.input');
}
clickNextButton();
});
@ -332,6 +337,7 @@ export type TestSubjects =
| 'orderField.input'
| 'priorityField.input'
| 'dataStreamField.input'
| 'allowAutoCreateField.input'
| 'pageTitle'
| 'previewTab'
| 'removeFieldButton'

View file

@ -16,8 +16,16 @@ import {
const hasEntries = (data: object = {}) => Object.entries(data).length > 0;
export function serializeTemplate(templateDeserialized: TemplateDeserialized): TemplateSerialized {
const { version, priority, indexPatterns, template, composedOf, dataStream, _meta } =
templateDeserialized;
const {
version,
priority,
indexPatterns,
template,
composedOf,
dataStream,
_meta,
allowAutoCreate,
} = templateDeserialized;
return {
version,
@ -26,6 +34,7 @@ export function serializeTemplate(templateDeserialized: TemplateDeserialized): T
index_patterns: indexPatterns,
data_stream: dataStream,
composed_of: composedOf,
allow_auto_create: allowAutoCreate,
_meta,
};
}
@ -43,6 +52,7 @@ export function deserializeTemplate(
_meta,
composed_of: composedOf,
data_stream: dataStream,
allow_auto_create: allowAutoCreate,
} = templateEs;
const { settings } = template;
@ -64,6 +74,7 @@ export function deserializeTemplate(
ilmPolicy: settings?.index?.lifecycle,
composedOf,
dataStream,
allowAutoCreate,
_meta,
_kbnMeta: {
type,

View file

@ -24,6 +24,7 @@ export interface TemplateSerialized {
priority?: number;
_meta?: { [key: string]: any };
data_stream?: {};
allow_auto_create?: boolean;
}
/**
@ -42,6 +43,7 @@ export interface TemplateDeserialized {
composedOf?: string[]; // Composable template only
version?: number;
priority?: number; // Composable template only
allowAutoCreate?: boolean;
order?: number; // Legacy template only
ilmPolicy?: {
name: string;

View file

@ -112,6 +112,19 @@ function getFieldsMeta(esDocsBase: string) {
}),
testSubject: 'versionField',
},
allowAutoCreate: {
title: i18n.translate('xpack.idxMgmt.templateForm.stepLogistics.allowAutoCreateTitle', {
defaultMessage: 'Allow auto create',
}),
description: i18n.translate(
'xpack.idxMgmt.templateForm.stepLogistics.allowAutoCreateDescription',
{
defaultMessage:
'Indices can be automatically created even if auto-creation of indices is disabled via actions.auto_create_index.',
}
),
testSubject: 'allowAutoCreateField',
},
};
}
@ -185,9 +198,8 @@ export const StepLogistics: React.FunctionComponent<Props> = React.memo(
});
}, [onChange, isFormValid, validate, getFormData]);
const { name, indexPatterns, createDataStream, order, priority, version } = getFieldsMeta(
documentationService.getEsDocsBase()
);
const { name, indexPatterns, createDataStream, order, priority, version, allowAutoCreate } =
getFieldsMeta(documentationService.getEsDocsBase());
return (
<>
@ -294,6 +306,16 @@ export const StepLogistics: React.FunctionComponent<Props> = React.memo(
/>
</FormRow>
{/* Allow auto create */}
{isLegacy === false && (
<FormRow title={allowAutoCreate.title} description={allowAutoCreate.description}>
<UseField
path="allowAutoCreate"
componentProps={{ 'data-test-subj': allowAutoCreate.testSubject }}
/>
</FormRow>
)}
{/* _meta */}
{isLegacy === false && (
<FormRow

View file

@ -25,7 +25,7 @@ import { FormattedMessage } from '@kbn/i18n-react';
import { serializers } from '../../../../shared_imports';
import { serializeLegacyTemplate, serializeTemplate } from '../../../../../common/lib';
import { TemplateDeserialized, getTemplateParameter } from '../../../../../common';
import { TemplateDeserialized, getTemplateParameter, Aliases } from '../../../../../common';
import { SimulateTemplate } from '../../index_templates';
import { WizardSection } from '../template_form';
@ -38,8 +38,8 @@ const NoneDescriptionText = () => (
/>
);
const getDescriptionText = (data: any) => {
const hasEntries = data && Object.entries(data).length > 0;
const getDescriptionText = (data: Aliases | boolean | undefined) => {
const hasEntries = typeof data === 'boolean' ? data : data && Object.entries(data).length > 0;
return hasEntries ? (
<FormattedMessage
@ -88,6 +88,7 @@ export const StepReview: React.FunctionComponent<Props> = React.memo(
version,
order,
priority,
allowAutoCreate,
composedOf,
_meta,
_kbnMeta: { isLegacy },
@ -186,6 +187,21 @@ export const StepReview: React.FunctionComponent<Props> = React.memo(
{version ? version : <NoneDescriptionText />}
</EuiDescriptionListDescription>
{/* Allow auto create */}
{isLegacy !== true && (
<>
<EuiDescriptionListTitle>
<FormattedMessage
id="xpack.idxMgmt.templateForm.stepReview.summaryTab.allowAutoCreateLabel"
defaultMessage="Allow auto create"
/>
</EuiDescriptionListTitle>
<EuiDescriptionListDescription>
{getDescriptionText(allowAutoCreate)}
</EuiDescriptionListDescription>
</>
)}
{/* components */}
{isLegacy !== true && (
<>

View file

@ -158,6 +158,13 @@ export const schemas: Record<string, FormSchema> = {
}),
formatters: [toInt],
},
allowAutoCreate: {
type: FIELD_TYPES.TOGGLE,
label: i18n.translate('xpack.idxMgmt.templateForm.stepLogistics.fieldAllowAutoCreateLabel', {
defaultMessage: 'Allow auto create (optional)',
}),
defaultValue: false,
},
_meta: {
label: i18n.translate('xpack.idxMgmt.templateForm.stepLogistics.metaFieldEditorLabel', {
defaultMessage: '_meta field data (optional)',

View file

@ -50,6 +50,7 @@ export const TabSummary: React.FunctionComponent<Props> = ({ templateDetails })
ilmPolicy,
_meta,
_kbnMeta: { isLegacy, hasDatastream },
allowAutoCreate,
} = templateDetails;
const numIndexPatterns = indexPatterns.length;
@ -192,6 +193,21 @@ export const TabSummary: React.FunctionComponent<Props> = ({ templateDetails })
<EuiDescriptionListDescription>
{version || version === 0 ? version : i18nTexts.none}
</EuiDescriptionListDescription>
{/* Allow auto create */}
{isLegacy !== true && (
<>
<EuiDescriptionListTitle>
<FormattedMessage
id="xpack.idxMgmt.templateDetails.summaryTab.allowAutoCreateDescriptionListTitle"
defaultMessage="Allow auto create"
/>
</EuiDescriptionListTitle>
<EuiDescriptionListDescription>
{allowAutoCreate ? i18nTexts.yes : i18nTexts.no}
</EuiDescriptionListDescription>
</>
)}
</EuiDescriptionList>
</EuiFlexItem>
</EuiFlexGroup>

View file

@ -13,6 +13,7 @@ export const templateSchema = schema.object({
version: schema.maybe(schema.number()),
order: schema.maybe(schema.number()),
priority: schema.maybe(schema.number()),
allowAutoCreate: schema.maybe(schema.boolean()),
template: schema.maybe(
schema.object({
settings: schema.maybe(schema.object({}, { unknowns: 'allow' })),

View file

@ -21,6 +21,7 @@ export const getComposableTemplate = ({
hasDatastream = false,
isLegacy = false,
type = 'default',
allowAutoCreate = false,
}: Partial<
TemplateDeserialized & {
isLegacy?: boolean;
@ -33,6 +34,7 @@ export const getComposableTemplate = ({
version,
priority,
indexPatterns,
allowAutoCreate,
template: {
aliases,
mappings,
@ -58,6 +60,7 @@ export const getTemplate = ({
hasDatastream = false,
isLegacy = false,
type = 'default',
allowAutoCreate = false,
}: Partial<
TemplateDeserialized & {
isLegacy?: boolean;
@ -70,6 +73,7 @@ export const getTemplate = ({
version,
order,
indexPatterns,
allowAutoCreate,
template: {
aliases,
mappings,