diff --git a/x-pack/plugins/index_management/__jest__/client_integration/helpers/http_requests.ts b/x-pack/plugins/index_management/__jest__/client_integration/helpers/http_requests.ts
index 8bd8672b8fbb..79daba4c7386 100644
--- a/x-pack/plugins/index_management/__jest__/client_integration/helpers/http_requests.ts
+++ b/x-pack/plugins/index_management/__jest__/client_integration/helpers/http_requests.ts
@@ -147,6 +147,12 @@ const registerHttpRequestMockHelpers = (
const setSimulateTemplateResponse = (response?: HttpResponse, error?: ResponseError) =>
mockResponse('POST', `${API_BASE_PATH}/index_templates/simulate`, response, error);
+ const setSimulateTemplateByNameResponse = (
+ name: string,
+ response?: HttpResponse,
+ error?: ResponseError
+ ) => mockResponse('POST', `${API_BASE_PATH}/index_templates/simulate/${name}`, response, error);
+
const setLoadComponentTemplatesResponse = (response?: HttpResponse, error?: ResponseError) =>
mockResponse('GET', `${API_BASE_PATH}/component_templates`, response, error);
@@ -229,6 +235,7 @@ const registerHttpRequestMockHelpers = (
setLoadIndexStatsResponse,
setUpdateIndexSettingsResponse,
setSimulateTemplateResponse,
+ setSimulateTemplateByNameResponse,
setLoadComponentTemplatesResponse,
setLoadNodesPluginsResponse,
setLoadTelemetryResponse,
diff --git a/x-pack/plugins/index_management/__jest__/client_integration/home/index_templates_tab.test.ts b/x-pack/plugins/index_management/__jest__/client_integration/home/index_templates_tab.test.ts
index 615b8df18f90..ea536becfcca 100644
--- a/x-pack/plugins/index_management/__jest__/client_integration/home/index_templates_tab.test.ts
+++ b/x-pack/plugins/index_management/__jest__/client_integration/home/index_templates_tab.test.ts
@@ -617,7 +617,9 @@ describe('Index Templates tab', () => {
const { find, actions, exists } = testBed;
httpRequestsMockHelpers.setLoadTemplateResponse(templates[0].name, template);
- httpRequestsMockHelpers.setSimulateTemplateResponse({ simulateTemplate: 'response' });
+ httpRequestsMockHelpers.setSimulateTemplateByNameResponse(templates[0].name, {
+ simulateTemplate: 'response',
+ });
await actions.clickTemplateAt(0);
diff --git a/x-pack/plugins/index_management/public/application/components/index_templates/simulate_template/simulate_template.tsx b/x-pack/plugins/index_management/public/application/components/index_templates/simulate_template/simulate_template.tsx
index ed22baae580c..fd1df7ba4469 100644
--- a/x-pack/plugins/index_management/public/application/components/index_templates/simulate_template/simulate_template.tsx
+++ b/x-pack/plugins/index_management/public/application/components/index_templates/simulate_template/simulate_template.tsx
@@ -23,22 +23,25 @@ export interface Filters {
}
interface Props {
- template: { [key: string]: any };
+ template?: { [key: string]: any };
filters?: Filters;
+ templateName?: string;
}
-export const SimulateTemplate = React.memo(({ template, filters }: Props) => {
+export const SimulateTemplate = React.memo(({ template, filters, templateName }: Props) => {
const [templatePreview, setTemplatePreview] = useState('{}');
const updatePreview = useCallback(async () => {
- if (!template || Object.keys(template).length === 0) {
+ if (!templateName && (!template || Object.keys(template).length === 0)) {
return;
}
- const indexTemplate = serializeTemplate(
- stripEmptyFields(template, { types: ['string'] }) as TemplateDeserialized
- );
- const { data, error } = await simulateIndexTemplate(indexTemplate);
+ const indexTemplate = templateName
+ ? undefined
+ : serializeTemplate(
+ stripEmptyFields(template, { types: ['string'] }) as TemplateDeserialized
+ );
+ const { data, error } = await simulateIndexTemplate({ template: indexTemplate, templateName });
let filteredTemplate = data;
if (data) {
@@ -67,7 +70,7 @@ export const SimulateTemplate = React.memo(({ template, filters }: Props) => {
}
setTemplatePreview(JSON.stringify(filteredTemplate ?? error, null, 2));
- }, [template, filters]);
+ }, [template, filters, templateName]);
useEffect(() => {
updatePreview();
diff --git a/x-pack/plugins/index_management/public/application/sections/home/template_list/template_details/tabs/tab_preview.tsx b/x-pack/plugins/index_management/public/application/sections/home/template_list/template_details/tabs/tab_preview.tsx
index 38f4a8b4f787..02df1f6e1c68 100644
--- a/x-pack/plugins/index_management/public/application/sections/home/template_list/template_details/tabs/tab_preview.tsx
+++ b/x-pack/plugins/index_management/public/application/sections/home/template_list/template_details/tabs/tab_preview.tsx
@@ -8,14 +8,13 @@
import React from 'react';
import { FormattedMessage } from '@kbn/i18n-react';
import { EuiText, EuiSpacer } from '@elastic/eui';
-import { TemplateDeserialized } from '../../../../../../../common';
import { SimulateTemplate } from '../../../../../components/index_templates';
interface Props {
- templateDetails: TemplateDeserialized;
+ templateName: string;
}
-export const TabPreview = ({ templateDetails }: Props) => {
+export const TabPreview = ({ templateName }: Props) => {
return (
@@ -29,7 +28,7 @@ export const TabPreview = ({ templateDetails }: Props) => {
-
+
);
};
diff --git a/x-pack/plugins/index_management/public/application/sections/home/template_list/template_details/template_details_content.tsx b/x-pack/plugins/index_management/public/application/sections/home/template_list/template_details/template_details_content.tsx
index d2156d1aa958..75446c0c05f2 100644
--- a/x-pack/plugins/index_management/public/application/sections/home/template_list/template_details/template_details_content.tsx
+++ b/x-pack/plugins/index_management/public/application/sections/home/template_list/template_details/template_details_content.tsx
@@ -171,7 +171,7 @@ export const TemplateDetailsContent = ({
[SETTINGS_TAB_ID]: ,
[MAPPINGS_TAB_ID]: ,
[ALIASES_TAB_ID]: ,
- [PREVIEW_TAB_ID]: ,
+ [PREVIEW_TAB_ID]: ,
};
const tabContent = tabToComponentMap[activeTab];
diff --git a/x-pack/plugins/index_management/public/application/services/api.ts b/x-pack/plugins/index_management/public/application/services/api.ts
index 08baa4971357..9f03007014c4 100644
--- a/x-pack/plugins/index_management/public/application/services/api.ts
+++ b/x-pack/plugins/index_management/public/application/services/api.ts
@@ -319,11 +319,23 @@ export async function updateTemplate(template: TemplateDeserialized) {
return result;
}
-export function simulateIndexTemplate(template: { [key: string]: any }) {
+export function simulateIndexTemplate({
+ template,
+ templateName,
+}: {
+ template?: { [key: string]: any };
+ templateName?: string;
+}) {
+ const path = templateName
+ ? `${API_BASE_PATH}/index_templates/simulate/${templateName}`
+ : `${API_BASE_PATH}/index_templates/simulate`;
+
+ const body = templateName ? undefined : JSON.stringify(template);
+
return sendRequest({
- path: `${API_BASE_PATH}/index_templates/simulate`,
+ path,
method: 'post',
- body: JSON.stringify(template),
+ body,
}).then((result) => {
uiMetricService.trackMetric(METRIC_TYPE.COUNT, UIM_TEMPLATE_SIMULATE);
return result;
diff --git a/x-pack/plugins/index_management/server/routes/api/templates/register_simulate_route.ts b/x-pack/plugins/index_management/server/routes/api/templates/register_simulate_route.ts
index 3dc6201f0831..60e2cfbf8a53 100644
--- a/x-pack/plugins/index_management/server/routes/api/templates/register_simulate_route.ts
+++ b/x-pack/plugins/index_management/server/routes/api/templates/register_simulate_route.ts
@@ -15,23 +15,38 @@ const bodySchema = schema.object({}, { unknowns: 'allow' });
export function registerSimulateRoute({ router, lib: { handleEsError } }: RouteDependencies) {
router.post(
{
- path: addBasePath('/index_templates/simulate'),
- validate: { body: bodySchema },
+ path: addBasePath('/index_templates/simulate/{templateName?}'),
+ validate: {
+ body: schema.nullable(bodySchema),
+ params: schema.object({ templateName: schema.maybe(schema.string()) }),
+ },
},
async (context, request, response) => {
const { client } = (await context.core).elasticsearch;
const template = request.body as TypeOf;
+ // Until ES fixes a bug on their side we need to send a fake index pattern
+ // that won't match any indices.
+ // Issue: https://github.com/elastic/elasticsearch/issues/59152
+ // eslint-disable-next-line @typescript-eslint/naming-convention
+ const index_patterns = ['a_fake_index_pattern_that_wont_match_any_indices'];
+ const templateName = request.params.templateName;
+
+ const params: estypes.IndicesSimulateTemplateRequest = templateName
+ ? {
+ name: templateName,
+ body: {
+ index_patterns,
+ },
+ }
+ : {
+ body: {
+ ...template,
+ index_patterns,
+ },
+ };
try {
- const templatePreview = await client.asCurrentUser.indices.simulateTemplate({
- body: {
- ...template,
- // Until ES fixes a bug on their side we need to send a fake index pattern
- // that won't match any indices.
- // Issue: https://github.com/elastic/elasticsearch/issues/59152
- index_patterns: ['a_fake_index_pattern_that_wont_match_any_indices'],
- },
- } as estypes.IndicesSimulateTemplateRequest);
+ const templatePreview = await client.asCurrentUser.indices.simulateTemplate(params);
return response.ok({ body: templatePreview });
} catch (error) {
diff --git a/x-pack/test/api_integration/apis/management/index_management/lib/templates.api.ts b/x-pack/test/api_integration/apis/management/index_management/lib/templates.api.ts
index bae578e6c049..21585d9f699a 100644
--- a/x-pack/test/api_integration/apis/management/index_management/lib/templates.api.ts
+++ b/x-pack/test/api_integration/apis/management/index_management/lib/templates.api.ts
@@ -53,6 +53,12 @@ export function templatesApi(getService: FtrProviderContext['getService']) {
.set('kbn-xsrf', 'xxx')
.send(payload);
+ const simulateTemplateByName = (name: string) =>
+ supertest
+ .post(`${API_BASE_PATH}/index_templates/simulate/${name}`)
+ .set('kbn-xsrf', 'xxx')
+ .send();
+
return {
getAllTemplates,
getOneTemplate,
@@ -61,5 +67,6 @@ export function templatesApi(getService: FtrProviderContext['getService']) {
deleteTemplates,
cleanUpTemplates,
simulateTemplate,
+ simulateTemplateByName,
};
}
diff --git a/x-pack/test/api_integration/apis/management/index_management/templates.ts b/x-pack/test/api_integration/apis/management/index_management/templates.ts
index 66d6f34baa64..1fe7e022bfc9 100644
--- a/x-pack/test/api_integration/apis/management/index_management/templates.ts
+++ b/x-pack/test/api_integration/apis/management/index_management/templates.ts
@@ -24,6 +24,7 @@ export default function ({ getService }: FtrProviderContext) {
updateTemplate,
cleanUpTemplates,
simulateTemplate,
+ simulateTemplateByName,
} = templatesApi(getService);
describe('index templates', () => {
@@ -452,6 +453,18 @@ export default function ({ getService }: FtrProviderContext) {
const { body } = await simulateTemplate(payload).expect(200);
expect(body.template).to.be.ok();
});
+
+ it('should simulate an index template by name', async () => {
+ const templateName = `template-${getRandomString()}`;
+ const payload = getTemplatePayload(templateName, [getRandomString()]);
+
+ await createTemplate(payload).expect(200);
+
+ await simulateTemplateByName(templateName).expect(200);
+
+ // cleanup
+ await deleteTemplates([{ name: templateName }]);
+ });
});
});
}
diff --git a/x-pack/test/functional/apps/index_management/index_template_wizard.ts b/x-pack/test/functional/apps/index_management/index_template_wizard.ts
index cf6f1bf6a44a..581a0b276164 100644
--- a/x-pack/test/functional/apps/index_management/index_template_wizard.ts
+++ b/x-pack/test/functional/apps/index_management/index_template_wizard.ts
@@ -107,6 +107,76 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
});
});
+ // https://github.com/elastic/kibana/pull/195174
+ it('can preview index template that matches a_fake_index_pattern_that_wont_match_any_indices', async () => {
+ // Click Create Template button
+ await testSubjects.click('createTemplateButton');
+ const pageTitleText = await testSubjects.getVisibleText('pageTitle');
+ expect(pageTitleText).to.be('Create template');
+
+ const stepTitle1 = await testSubjects.getVisibleText('stepTitle');
+ expect(stepTitle1).to.be('Logistics');
+
+ // Fill out required fields
+ await testSubjects.setValue('nameField', 'a-star');
+ await testSubjects.setValue('indexPatternsField', 'a*');
+ await testSubjects.setValue('priorityField', '1000');
+
+ // Click Next button
+ await pageObjects.indexManagement.clickNextButton();
+
+ // Verify empty prompt
+ const emptyPrompt = await testSubjects.exists('emptyPrompt');
+ expect(emptyPrompt).to.be(true);
+
+ // Click Next button
+ await pageObjects.indexManagement.clickNextButton();
+
+ // Verify step title
+ const stepTitle2 = await testSubjects.getVisibleText('stepTitle');
+ expect(stepTitle2).to.be('Index settings (optional)');
+
+ // Click Next button
+ await pageObjects.indexManagement.clickNextButton();
+
+ // Verify step title
+ const stepTitle3 = await testSubjects.getVisibleText('stepTitle');
+ expect(stepTitle3).to.be('Mappings (optional)');
+
+ // Click Next button
+ await pageObjects.indexManagement.clickNextButton();
+
+ // Verify step title
+ const stepTitle4 = await testSubjects.getVisibleText('stepTitle');
+ expect(stepTitle4).to.be('Aliases (optional)');
+
+ // Click Next button
+ await pageObjects.indexManagement.clickNextButton();
+
+ // Verify step title
+ const stepTitle = await testSubjects.getVisibleText('stepTitle');
+ expect(stepTitle).to.be("Review details for 'a-star'");
+
+ // Verify that summary exists
+ const summaryTabContent = await testSubjects.exists('summaryTabContent');
+ expect(summaryTabContent).to.be(true);
+
+ // Verify that index mode is set to "Standard"
+ expect(await testSubjects.exists('indexModeTitle')).to.be(true);
+ expect(await testSubjects.getVisibleText('indexModeValue')).to.be('Standard');
+
+ // Click Create template
+ await pageObjects.indexManagement.clickNextButton();
+
+ // Click preview tab, we know its the last one
+ const tabs = await testSubjects.findAll('tab');
+ await tabs[tabs.length - 1].click();
+ const templatePreview = await testSubjects.getVisibleText('simulateTemplatePreview');
+ expect(templatePreview).to.not.contain('error');
+
+ await testSubjects.click('closeDetailsButton');
+ });
+
describe('Mappings step', () => {
beforeEach(async () => {
await pageObjects.common.navigateToApp('indexManagement');