diff --git a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/step_time_field/step_time_field.tsx b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/step_time_field/step_time_field.tsx
index 98ce22cd14227c..5d33a08557fed5 100644
--- a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/step_time_field/step_time_field.tsx
+++ b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/step_time_field/step_time_field.tsx
@@ -22,10 +22,10 @@ import {
EuiCallOut,
EuiFlexGroup,
EuiFlexItem,
- EuiPanel,
- EuiText,
+ EuiTitle,
EuiSpacer,
EuiLoadingSpinner,
+ EuiHorizontalRule,
} from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
import { ensureMinimumTime, extractTimeFields } from '../../lib';
@@ -43,6 +43,7 @@ interface StepTimeFieldProps {
goToPreviousStep: () => void;
createIndexPattern: (selectedTimeField: string | undefined, indexPatternId: string) => void;
indexPatternCreationType: IndexPatternCreationConfig;
+ selectedTimeField?: string;
}
interface StepTimeFieldState {
@@ -69,7 +70,7 @@ export class StepTimeField extends Component
-
-
-
-
-
-
+
+
+
+
-
-
-
-
+
+
+
+
+
+
+
+
);
}
@@ -236,7 +242,7 @@ export class StepTimeField extends Component
+ <>
-
+
-
+ >
);
}
}
diff --git a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/create_index_pattern_wizard.tsx b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/create_index_pattern_wizard.tsx
index 111be41cfc53a9..cd76ca09ccb741 100644
--- a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/create_index_pattern_wizard.tsx
+++ b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/create_index_pattern_wizard.tsx
@@ -19,10 +19,16 @@
import React, { ReactElement, Component } from 'react';
-import { EuiGlobalToastList, EuiGlobalToastListToast, EuiPanel } from '@elastic/eui';
+import {
+ EuiGlobalToastList,
+ EuiGlobalToastListToast,
+ EuiPageContent,
+ EuiHorizontalRule,
+} from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
import { i18n } from '@kbn/i18n';
import { withRouter, RouteComponentProps } from 'react-router-dom';
+import { DocLinksStart } from 'src/core/public';
import { StepIndexPattern } from './components/step_index_pattern';
import { StepTimeField } from './components/step_time_field';
import { Header } from './components/header';
@@ -31,21 +37,21 @@ import { EmptyState } from './components/empty_state';
import { context as contextType } from '../../../../kibana_react/public';
import { getCreateBreadcrumbs } from '../breadcrumbs';
-import { MAX_SEARCH_SIZE } from './constants';
import { ensureMinimumTime, getIndices } from './lib';
import { IndexPatternCreationConfig } from '../..';
import { IndexPatternManagmentContextValue } from '../../types';
-import { MatchedIndex } from './types';
+import { MatchedItem } from './types';
interface CreateIndexPatternWizardState {
step: number;
indexPattern: string;
- allIndices: MatchedIndex[];
+ allIndices: MatchedItem[];
remoteClustersExist: boolean;
isInitiallyLoadingIndices: boolean;
- isIncludingSystemIndices: boolean;
toasts: EuiGlobalToastListToast[];
indexPatternCreationType: IndexPatternCreationConfig;
+ selectedTimeField?: string;
+ docLinks: DocLinksStart;
}
export class CreateIndexPatternWizard extends Component<
@@ -69,9 +75,9 @@ export class CreateIndexPatternWizard extends Component<
allIndices: [],
remoteClustersExist: false,
isInitiallyLoadingIndices: true,
- isIncludingSystemIndices: false,
toasts: [],
indexPatternCreationType: context.services.indexPatternManagementStart.creation.getType(type),
+ docLinks: context.services.docLinks,
};
}
@@ -80,7 +86,7 @@ export class CreateIndexPatternWizard extends Component<
}
catchAndWarn = async (
- asyncFn: Promise,
+ asyncFn: Promise,
errorValue: [] | string[],
errorMsg: ReactElement
) => {
@@ -102,12 +108,6 @@ export class CreateIndexPatternWizard extends Component<
};
fetchData = async () => {
- this.setState({
- allIndices: [],
- isInitiallyLoadingIndices: true,
- remoteClustersExist: false,
- });
-
const indicesFailMsg = (
+ ).then((allIndices: MatchedItem[]) =>
this.setState({ allIndices, isInitiallyLoadingIndices: false })
);
this.catchAndWarn(
// if we get an error from remote cluster query, supply fallback value that allows user entry.
// ['a'] is fallback value
- getIndices(
- this.context.services.data.search.__LEGACY.esClient,
- this.state.indexPatternCreationType,
- `*:*`,
- 1
- ),
+ getIndices(this.context.services.http, this.state.indexPatternCreationType, `*:*`, false),
['a'],
clustersFailMsg
- ).then((remoteIndices: string[] | MatchedIndex[]) =>
+ ).then((remoteIndices: string[] | MatchedItem[]) =>
this.setState({ remoteClustersExist: !!remoteIndices.length })
);
};
@@ -189,7 +179,7 @@ export class CreateIndexPatternWizard extends Component<
if (isConfirmed) {
return history.push(`/patterns/${indexPatternId}`);
} else {
- return false;
+ return;
}
}
@@ -201,31 +191,21 @@ export class CreateIndexPatternWizard extends Component<
history.push(`/patterns/${createdId}`);
};
- goToTimeFieldStep = (indexPattern: string) => {
- this.setState({ step: 2, indexPattern });
+ goToTimeFieldStep = (indexPattern: string, selectedTimeField?: string) => {
+ this.setState({ step: 2, indexPattern, selectedTimeField });
};
goToIndexPatternStep = () => {
this.setState({ step: 1 });
};
- onChangeIncludingSystemIndices = () => {
- this.setState((prevState) => ({
- isIncludingSystemIndices: !prevState.isIncludingSystemIndices,
- }));
- };
-
renderHeader() {
- const { isIncludingSystemIndices } = this.state;
-
return (
);
}
@@ -234,7 +214,6 @@ export class CreateIndexPatternWizard extends Component<
const {
allIndices,
isInitiallyLoadingIndices,
- isIncludingSystemIndices,
step,
indexPattern,
remoteClustersExist,
@@ -244,8 +223,8 @@ export class CreateIndexPatternWizard extends Component<
return ;
}
- const hasDataIndices = allIndices.some(({ name }: MatchedIndex) => !name.startsWith('.'));
- if (!hasDataIndices && !isIncludingSystemIndices && !remoteClustersExist) {
+ const hasDataIndices = allIndices.some(({ name }: MatchedItem) => !name.startsWith('.'));
+ if (!hasDataIndices && !remoteClustersExist) {
return (
+
+ {header}
+
+
+
);
}
if (step === 2) {
return (
-
+
+ {header}
+
+
+
);
}
@@ -290,15 +282,11 @@ export class CreateIndexPatternWizard extends Component<
};
render() {
- const header = this.renderHeader();
const content = this.renderContent();
return (
-
-
- {header}
- {content}
-
+ <>
+ {content}
{
@@ -306,7 +294,7 @@ export class CreateIndexPatternWizard extends Component<
}}
toastLifeTimeMs={6000}
/>
-
+ >
);
}
}
diff --git a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/lib/__snapshots__/get_indices.test.ts.snap b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/lib/__snapshots__/get_indices.test.ts.snap
new file mode 100644
index 00000000000000..99876383b43437
--- /dev/null
+++ b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/lib/__snapshots__/get_indices.test.ts.snap
@@ -0,0 +1,69 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`getIndices response object to item array 1`] = `
+Array [
+ Object {
+ "item": Object {
+ "attributes": Array [
+ "frozen",
+ ],
+ "name": "frozen_index",
+ },
+ "name": "frozen_index",
+ "tags": Array [
+ Object {
+ "color": "default",
+ "key": "index",
+ "name": "Index",
+ },
+ Object {
+ "color": "danger",
+ "key": "frozen",
+ "name": "Frozen",
+ },
+ ],
+ },
+ Object {
+ "item": Object {
+ "indices": Array [],
+ "name": "test_alias",
+ },
+ "name": "test_alias",
+ "tags": Array [
+ Object {
+ "color": "default",
+ "key": "alias",
+ "name": "Alias",
+ },
+ ],
+ },
+ Object {
+ "item": Object {
+ "backing_indices": Array [],
+ "name": "test_data_stream",
+ "timestamp_field": "test_timestamp_field",
+ },
+ "name": "test_data_stream",
+ "tags": Array [
+ Object {
+ "color": "primary",
+ "key": "data_stream",
+ "name": "Data stream",
+ },
+ ],
+ },
+ Object {
+ "item": Object {
+ "name": "test_index",
+ },
+ "name": "test_index",
+ "tags": Array [
+ Object {
+ "color": "default",
+ "key": "index",
+ "name": "Index",
+ },
+ ],
+ },
+]
+`;
diff --git a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/lib/get_indices.test.ts b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/lib/get_indices.test.ts
index b1faca8a04964b..8e4dd37284333c 100644
--- a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/lib/get_indices.test.ts
+++ b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/lib/get_indices.test.ts
@@ -17,66 +17,31 @@
* under the License.
*/
-import { getIndices } from './get_indices';
+import { getIndices, responseToItemArray } from './get_indices';
import { IndexPatternCreationConfig } from '../../../../../index_pattern_management/public';
-// eslint-disable-next-line @kbn/eslint/no-restricted-paths
-import { LegacyApiCaller } from '../../../../../data/public/search/legacy';
+import { httpServiceMock } from '../../../../../../core/public/mocks';
+import { ResolveIndexResponseItemIndexAttrs } from '../types';
export const successfulResponse = {
- hits: {
- total: 1,
- max_score: 0.0,
- hits: [],
- },
- aggregations: {
- indices: {
- doc_count_error_upper_bound: 0,
- sum_other_doc_count: 0,
- buckets: [
- {
- key: '1',
- doc_count: 1,
- },
- {
- key: '2',
- doc_count: 1,
- },
- ],
+ indices: [
+ {
+ name: 'remoteCluster1:bar-01',
+ attributes: ['open'],
},
- },
-};
-
-export const exceptionResponse = {
- body: {
- error: {
- root_cause: [
- {
- type: 'index_not_found_exception',
- reason: 'no such index',
- index_uuid: '_na_',
- 'resource.type': 'index_or_alias',
- 'resource.id': 't',
- index: 't',
- },
- ],
- type: 'transport_exception',
- reason: 'unable to communicate with remote cluster [cluster_one]',
- caused_by: {
- type: 'index_not_found_exception',
- reason: 'no such index',
- index_uuid: '_na_',
- 'resource.type': 'index_or_alias',
- 'resource.id': 't',
- index: 't',
- },
+ ],
+ aliases: [
+ {
+ name: 'f-alias',
+ indices: ['freeze-index', 'my-index'],
},
- },
- status: 500,
-};
-
-export const errorResponse = {
- statusCode: 400,
- error: 'Bad Request',
+ ],
+ data_streams: [
+ {
+ name: 'foo',
+ backing_indices: ['foo-000001'],
+ timestamp_field: '@timestamp',
+ },
+ ],
};
const mockIndexPatternCreationType = new IndexPatternCreationConfig({
@@ -87,81 +52,62 @@ const mockIndexPatternCreationType = new IndexPatternCreationConfig({
isBeta: false,
});
-function esClientFactory(search: (params: any) => any): LegacyApiCaller {
- return {
- search,
- msearch: () => ({
- abort: () => {},
- ...new Promise((resolve) => resolve({})),
- }),
- };
-}
-
-const es = esClientFactory(() => successfulResponse);
+const http = httpServiceMock.createStartContract();
+http.get.mockResolvedValue(successfulResponse);
describe('getIndices', () => {
it('should work in a basic case', async () => {
- const result = await getIndices(es, mockIndexPatternCreationType, 'kibana', 1);
- expect(result.length).toBe(2);
- expect(result[0].name).toBe('1');
- expect(result[1].name).toBe('2');
+ const result = await getIndices(http, mockIndexPatternCreationType, 'kibana', false);
+ expect(result.length).toBe(3);
+ expect(result[0].name).toBe('f-alias');
+ expect(result[1].name).toBe('foo');
});
it('should ignore ccs query-all', async () => {
- expect((await getIndices(es, mockIndexPatternCreationType, '*:', 10)).length).toBe(0);
+ expect((await getIndices(http, mockIndexPatternCreationType, '*:', false)).length).toBe(0);
});
it('should ignore a single comma', async () => {
- expect((await getIndices(es, mockIndexPatternCreationType, ',', 10)).length).toBe(0);
- expect((await getIndices(es, mockIndexPatternCreationType, ',*', 10)).length).toBe(0);
- expect((await getIndices(es, mockIndexPatternCreationType, ',foobar', 10)).length).toBe(0);
- });
-
- it('should trim the input', async () => {
- let index;
- const esClient = esClientFactory(
- jest.fn().mockImplementation((params) => {
- index = params.index;
- })
- );
-
- await getIndices(esClient, mockIndexPatternCreationType, 'kibana ', 1);
- expect(index).toBe('kibana');
+ expect((await getIndices(http, mockIndexPatternCreationType, ',', false)).length).toBe(0);
+ expect((await getIndices(http, mockIndexPatternCreationType, ',*', false)).length).toBe(0);
+ expect((await getIndices(http, mockIndexPatternCreationType, ',foobar', false)).length).toBe(0);
});
- it('should use the limit', async () => {
- let limit;
- const esClient = esClientFactory(
- jest.fn().mockImplementation((params) => {
- limit = params.body.aggs.indices.terms.size;
- })
- );
- await getIndices(esClient, mockIndexPatternCreationType, 'kibana', 10);
- expect(limit).toBe(10);
+ it('response object to item array', () => {
+ const result = {
+ indices: [
+ {
+ name: 'test_index',
+ },
+ {
+ name: 'frozen_index',
+ attributes: ['frozen' as ResolveIndexResponseItemIndexAttrs],
+ },
+ ],
+ aliases: [
+ {
+ name: 'test_alias',
+ indices: [],
+ },
+ ],
+ data_streams: [
+ {
+ name: 'test_data_stream',
+ backing_indices: [],
+ timestamp_field: 'test_timestamp_field',
+ },
+ ],
+ };
+ expect(responseToItemArray(result, mockIndexPatternCreationType)).toMatchSnapshot();
+ expect(responseToItemArray({}, mockIndexPatternCreationType)).toEqual([]);
});
describe('errors', () => {
it('should handle errors gracefully', async () => {
- const esClient = esClientFactory(() => errorResponse);
- const result = await getIndices(esClient, mockIndexPatternCreationType, 'kibana', 1);
- expect(result.length).toBe(0);
- });
-
- it('should throw exceptions', async () => {
- const esClient = esClientFactory(() => {
- throw new Error('Fail');
+ http.get.mockImplementationOnce(() => {
+ throw new Error('Test error');
});
-
- await expect(
- getIndices(esClient, mockIndexPatternCreationType, 'kibana', 1)
- ).rejects.toThrow();
- });
-
- it('should handle index_not_found_exception errors gracefully', async () => {
- const esClient = esClientFactory(
- () => new Promise((resolve, reject) => reject(exceptionResponse))
- );
- const result = await getIndices(esClient, mockIndexPatternCreationType, 'kibana', 1);
+ const result = await getIndices(http, mockIndexPatternCreationType, 'kibana', false);
expect(result.length).toBe(0);
});
});
diff --git a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/lib/get_indices.ts b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/lib/get_indices.ts
index 9f75dc39a654c2..c6a11de1bc4fc0 100644
--- a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/lib/get_indices.ts
+++ b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/lib/get_indices.ts
@@ -17,17 +17,31 @@
* under the License.
*/
-import { get, sortBy } from 'lodash';
+import { sortBy } from 'lodash';
+import { HttpStart } from 'kibana/public';
+import { i18n } from '@kbn/i18n';
import { IndexPatternCreationConfig } from '../../../../../index_pattern_management/public';
-import { DataPublicPluginStart } from '../../../../../data/public';
-import { MatchedIndex } from '../types';
+import { MatchedItem, ResolveIndexResponse, ResolveIndexResponseItemIndexAttrs } from '../types';
+
+const aliasLabel = i18n.translate('indexPatternManagement.aliasLabel', { defaultMessage: 'Alias' });
+const dataStreamLabel = i18n.translate('indexPatternManagement.dataStreamLabel', {
+ defaultMessage: 'Data stream',
+});
+
+const indexLabel = i18n.translate('indexPatternManagement.indexLabel', {
+ defaultMessage: 'Index',
+});
+
+const frozenLabel = i18n.translate('indexPatternManagement.frozenLabel', {
+ defaultMessage: 'Frozen',
+});
export async function getIndices(
- es: DataPublicPluginStart['search']['__LEGACY']['esClient'],
+ http: HttpStart,
indexPatternCreationType: IndexPatternCreationConfig,
rawPattern: string,
- limit: number
-): Promise {
+ showAllIndices: boolean
+): Promise {
const pattern = rawPattern.trim();
// Searching for `*:` fails for CCS environments. The search request
@@ -48,54 +62,58 @@ export async function getIndices(
return [];
}
- // We need to always provide a limit and not rely on the default
- if (!limit) {
- throw new Error('`getIndices()` was called without the required `limit` parameter.');
- }
-
- const params = {
- ignoreUnavailable: true,
- index: pattern,
- ignore: [404],
- body: {
- size: 0, // no hits
- aggs: {
- indices: {
- terms: {
- field: '_index',
- size: limit,
- },
- },
- },
- },
- };
+ const query = showAllIndices ? { expand_wildcards: 'all' } : undefined;
try {
- const response = await es.search(params);
- if (!response || response.error || !response.aggregations) {
- return [];
- }
-
- return sortBy(
- response.aggregations.indices.buckets
- .map((bucket: { key: string; doc_count: number }) => {
- return bucket.key;
- })
- .map((indexName: string) => {
- return {
- name: indexName,
- tags: indexPatternCreationType.getIndexTags(indexName),
- };
- }),
- 'name'
+ const response = await http.get(
+ `/internal/index-pattern-management/resolve_index/${pattern}`,
+ { query }
);
- } catch (err) {
- const type = get(err, 'body.error.caused_by.type');
- if (type === 'index_not_found_exception') {
- // This happens in a CSS environment when the controlling node returns a 500 even though the data
- // nodes returned a 404. Remove this when/if this is handled: https://github.com/elastic/elasticsearch/issues/27461
+ if (!response) {
return [];
}
- throw err;
+
+ return responseToItemArray(response, indexPatternCreationType);
+ } catch {
+ return [];
}
}
+
+export const responseToItemArray = (
+ response: ResolveIndexResponse,
+ indexPatternCreationType: IndexPatternCreationConfig
+): MatchedItem[] => {
+ const source: MatchedItem[] = [];
+
+ (response.indices || []).forEach((index) => {
+ const tags: MatchedItem['tags'] = [{ key: 'index', name: indexLabel, color: 'default' }];
+ const isFrozen = (index.attributes || []).includes(ResolveIndexResponseItemIndexAttrs.FROZEN);
+
+ tags.push(...indexPatternCreationType.getIndexTags(index.name));
+ if (isFrozen) {
+ tags.push({ name: frozenLabel, key: 'frozen', color: 'danger' });
+ }
+
+ source.push({
+ name: index.name,
+ tags,
+ item: index,
+ });
+ });
+ (response.aliases || []).forEach((alias) => {
+ source.push({
+ name: alias.name,
+ tags: [{ key: 'alias', name: aliasLabel, color: 'default' }],
+ item: alias,
+ });
+ });
+ (response.data_streams || []).forEach((dataStream) => {
+ source.push({
+ name: dataStream.name,
+ tags: [{ key: 'data_stream', name: dataStreamLabel, color: 'primary' }],
+ item: dataStream,
+ });
+ });
+
+ return sortBy(source, 'name');
+};
diff --git a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/lib/get_matched_indices.test.ts b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/lib/get_matched_indices.test.ts
index 65840aa64046d1..c27eaa5ebc99ee 100644
--- a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/lib/get_matched_indices.test.ts
+++ b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/lib/get_matched_indices.test.ts
@@ -18,7 +18,7 @@
*/
import { getMatchedIndices } from './get_matched_indices';
-import { Tag } from '../types';
+import { Tag, MatchedItem } from '../types';
jest.mock('./../constants', () => ({
MAX_NUMBER_OF_MATCHING_INDICES: 6,
@@ -32,18 +32,18 @@ const indices = [
{ name: 'packetbeat', tags },
{ name: 'metricbeat', tags },
{ name: '.kibana', tags },
-];
+] as MatchedItem[];
const partialIndices = [
{ name: 'kibana', tags },
{ name: 'es', tags },
{ name: '.kibana', tags },
-];
+] as MatchedItem[];
const exactIndices = [
{ name: 'kibana', tags },
{ name: '.kibana', tags },
-];
+] as MatchedItem[];
describe('getMatchedIndices', () => {
it('should return all indices', () => {
diff --git a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/lib/get_matched_indices.ts b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/lib/get_matched_indices.ts
index 7e2eeb17ab3877..dbb166597152e1 100644
--- a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/lib/get_matched_indices.ts
+++ b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/lib/get_matched_indices.ts
@@ -33,7 +33,7 @@ function isSystemIndex(index: string): boolean {
return false;
}
-function filterSystemIndices(indices: MatchedIndex[], isIncludingSystemIndices: boolean) {
+function filterSystemIndices(indices: MatchedItem[], isIncludingSystemIndices: boolean) {
if (!indices) {
return indices;
}
@@ -65,12 +65,12 @@ function filterSystemIndices(indices: MatchedIndex[], isIncludingSystemIndices:
We call this `exact` matches because ES is telling us exactly what it matches
*/
-import { MatchedIndex } from '../types';
+import { MatchedItem } from '../types';
export function getMatchedIndices(
- unfilteredAllIndices: MatchedIndex[],
- unfilteredPartialMatchedIndices: MatchedIndex[],
- unfilteredExactMatchedIndices: MatchedIndex[],
+ unfilteredAllIndices: MatchedItem[],
+ unfilteredPartialMatchedIndices: MatchedItem[],
+ unfilteredExactMatchedIndices: MatchedItem[],
isIncludingSystemIndices: boolean = false
) {
const allIndices = filterSystemIndices(unfilteredAllIndices, isIncludingSystemIndices);
diff --git a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/types.ts b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/types.ts
index 634bbd856ea862..b23924837ffb78 100644
--- a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/types.ts
+++ b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/types.ts
@@ -17,12 +17,54 @@
* under the License.
*/
-export interface MatchedIndex {
+export interface MatchedItem {
name: string;
tags: Tag[];
+ item: {
+ name: string;
+ backing_indices?: string[];
+ timestamp_field?: string;
+ indices?: string[];
+ aliases?: string[];
+ attributes?: ResolveIndexResponseItemIndexAttrs[];
+ data_stream?: string;
+ };
+}
+
+export interface ResolveIndexResponse {
+ indices?: ResolveIndexResponseItemIndex[];
+ aliases?: ResolveIndexResponseItemAlias[];
+ data_streams?: ResolveIndexResponseItemDataStream[];
+}
+
+export interface ResolveIndexResponseItem {
+ name: string;
+}
+
+export interface ResolveIndexResponseItemDataStream extends ResolveIndexResponseItem {
+ backing_indices: string[];
+ timestamp_field: string;
+}
+
+export interface ResolveIndexResponseItemAlias extends ResolveIndexResponseItem {
+ indices: string[];
+}
+
+export interface ResolveIndexResponseItemIndex extends ResolveIndexResponseItem {
+ aliases?: string[];
+ attributes?: ResolveIndexResponseItemIndexAttrs[];
+ data_stream?: string;
+}
+
+export enum ResolveIndexResponseItemIndexAttrs {
+ OPEN = 'open',
+ CLOSED = 'closed',
+ HIDDEN = 'hidden',
+ FROZEN = 'frozen',
}
export interface Tag {
name: string;
key: string;
+ color: string;
}
diff --git a/src/plugins/index_pattern_management/public/components/field_editor/__snapshots__/field_editor.test.tsx.snap b/src/plugins/index_pattern_management/public/components/field_editor/__snapshots__/field_editor.test.tsx.snap
index 6bc99c356592e5..7a7545580d82a3 100644
--- a/src/plugins/index_pattern_management/public/components/field_editor/__snapshots__/field_editor.test.tsx.snap
+++ b/src/plugins/index_pattern_management/public/components/field_editor/__snapshots__/field_editor.test.tsx.snap
@@ -836,7 +836,6 @@ exports[`FieldEditor should show deprecated lang warning 1`] = `
testlang
,
"painlessLink":
,
"scriptsInAggregation":
Please familiarize yourself with
-
-
+
and with
-
-
+
before using scripted fields.
diff --git a/src/plugins/index_pattern_management/public/mocks.ts b/src/plugins/index_pattern_management/public/mocks.ts
index 93574cde7dc857..ec8100db420851 100644
--- a/src/plugins/index_pattern_management/public/mocks.ts
+++ b/src/plugins/index_pattern_management/public/mocks.ts
@@ -76,6 +76,13 @@ const createInstance = async () => {
};
};
+const docLinks = {
+ links: {
+ indexPatterns: {},
+ scriptedFields: {},
+ },
+};
+
const createIndexPatternManagmentContext = () => {
const {
chrome,
@@ -84,7 +91,6 @@ const createIndexPatternManagmentContext = () => {
uiSettings,
notifications,
overlays,
- docLinks,
} = coreMock.createStart();
const { http } = coreMock.createSetup();
const data = dataPluginMock.createStartContract();
diff --git a/src/plugins/index_pattern_management/public/service/creation/config.ts b/src/plugins/index_pattern_management/public/service/creation/config.ts
index 95a91fd7594caf..04510b1d64e1e2 100644
--- a/src/plugins/index_pattern_management/public/service/creation/config.ts
+++ b/src/plugins/index_pattern_management/public/service/creation/config.ts
@@ -18,7 +18,7 @@
*/
import { i18n } from '@kbn/i18n';
-import { MatchedIndex } from '../../components/create_index_pattern_wizard/types';
+import { MatchedItem } from '../../components/create_index_pattern_wizard/types';
const indexPatternTypeName = i18n.translate(
'indexPatternManagement.editIndexPattern.createIndex.defaultTypeName',
@@ -105,7 +105,7 @@ export class IndexPatternCreationConfig {
return [];
}
- public checkIndicesForErrors(indices: MatchedIndex[]) {
+ public checkIndicesForErrors(indices: MatchedItem[]) {
return undefined;
}
diff --git a/src/plugins/index_pattern_management/server/index.ts b/src/plugins/index_pattern_management/server/index.ts
new file mode 100644
index 00000000000000..02a46315898323
--- /dev/null
+++ b/src/plugins/index_pattern_management/server/index.ts
@@ -0,0 +1,25 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { PluginInitializerContext } from 'src/core/server';
+import { IndexPatternManagementPlugin } from './plugin';
+
+export function plugin(initializerContext: PluginInitializerContext) {
+ return new IndexPatternManagementPlugin(initializerContext);
+}
diff --git a/src/plugins/index_pattern_management/server/plugin.ts b/src/plugins/index_pattern_management/server/plugin.ts
new file mode 100644
index 00000000000000..ecca45cbcc453a
--- /dev/null
+++ b/src/plugins/index_pattern_management/server/plugin.ts
@@ -0,0 +1,70 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { PluginInitializerContext, CoreSetup, Plugin } from 'src/core/server';
+import { schema } from '@kbn/config-schema';
+
+export class IndexPatternManagementPlugin implements Plugin {
+ constructor(initializerContext: PluginInitializerContext) {}
+
+ public setup(core: CoreSetup) {
+ const router = core.http.createRouter();
+
+ router.get(
+ {
+ path: '/internal/index-pattern-management/resolve_index/{query}',
+ validate: {
+ params: schema.object({
+ query: schema.string(),
+ }),
+ query: schema.object({
+ expand_wildcards: schema.maybe(
+ schema.oneOf([
+ schema.literal('all'),
+ schema.literal('open'),
+ schema.literal('closed'),
+ schema.literal('hidden'),
+ schema.literal('none'),
+ ])
+ ),
+ }),
+ },
+ },
+ async (context, req, res) => {
+ const queryString = req.query.expand_wildcards
+ ? { expand_wildcards: req.query.expand_wildcards }
+ : null;
+ const result = await context.core.elasticsearch.legacy.client.callAsCurrentUser(
+ 'transport.request',
+ {
+ method: 'GET',
+ path: `/_resolve/index/${encodeURIComponent(req.params.query)}${
+ queryString ? '?' + new URLSearchParams(queryString).toString() : ''
+ }`,
+ }
+ );
+ return res.ok({ body: result });
+ }
+ );
+ }
+
+ public start() {}
+
+ public stop() {}
+}
diff --git a/test/functional/apps/management/_create_index_pattern_wizard.js b/test/functional/apps/management/_create_index_pattern_wizard.js
index 8209f3e1ac9d6d..cb8b5a6ddc65fb 100644
--- a/test/functional/apps/management/_create_index_pattern_wizard.js
+++ b/test/functional/apps/management/_create_index_pattern_wizard.js
@@ -22,6 +22,7 @@ import expect from '@kbn/expect';
export default function ({ getService, getPageObjects }) {
const kibanaServer = getService('kibanaServer');
const testSubjects = getService('testSubjects');
+ const es = getService('legacyEs');
const PageObjects = getPageObjects(['settings', 'common']);
describe('"Create Index Pattern" wizard', function () {
@@ -48,5 +49,59 @@ export default function ({ getService, getPageObjects }) {
expect(isEnabled).to.be.ok();
});
});
+
+ describe('data streams', () => {
+ it('can be an index pattern', async () => {
+ await es.transport.request({
+ path: '/_index_template/generic-logs',
+ method: 'PUT',
+ body: {
+ index_patterns: ['logs-*', 'test_data_stream'],
+ template: {
+ mappings: {
+ properties: {
+ '@timestamp': {
+ type: 'date',
+ },
+ },
+ },
+ },
+ data_stream: {
+ timestamp_field: '@timestamp',
+ },
+ },
+ });
+
+ await es.transport.request({
+ path: '/_data_stream/test_data_stream',
+ method: 'PUT',
+ });
+
+ await PageObjects.settings.createIndexPattern('test_data_stream', false);
+
+ await es.transport.request({
+ path: '/_data_stream/test_data_stream',
+ method: 'DELETE',
+ });
+ });
+ });
+
+ describe('index alias', () => {
+ it('can be an index pattern', async () => {
+ await es.transport.request({
+ path: '/blogs/_doc',
+ method: 'POST',
+ body: { user: 'matt', message: 20 },
+ });
+
+ await es.transport.request({
+ path: '/_aliases',
+ method: 'POST',
+ body: { actions: [{ add: { index: 'blogs', alias: 'alias1' } }] },
+ });
+
+ await PageObjects.settings.createIndexPattern('alias1', false);
+ });
+ });
});
}
diff --git a/x-pack/plugins/rollup/public/index_pattern_creation/rollup_index_pattern_creation_config.js b/x-pack/plugins/rollup/public/index_pattern_creation/rollup_index_pattern_creation_config.js
index 4ff189d8f1be08..643cc3efb0136d 100644
--- a/x-pack/plugins/rollup/public/index_pattern_creation/rollup_index_pattern_creation_config.js
+++ b/x-pack/plugins/rollup/public/index_pattern_creation/rollup_index_pattern_creation_config.js
@@ -100,6 +100,7 @@ export class RollupIndexPatternCreationConfig extends IndexPatternCreationConfig
{
key: this.type,
name: rollupIndexPatternIndexLabel,
+ color: 'primary',
},
]
: [];