From 575d30da5cddb344a9a9e9ff0dda39ec2bda5022 Mon Sep 17 00:00:00 2001 From: CJ Cenizal Date: Tue, 27 Jun 2017 17:19:10 -0700 Subject: [PATCH 1/9] Create Index Pattern Creation wizard. - Create a directive for each step in the wizard. - Reorganize files into conventional folder structure. - Rename files with more conventional and consistent naming patterns. - Improve translation key names. - Display indices, partial matches, exact matches. - Add loading, empty, and success states. - Add option to include system indices. --- .../__tests__/create_index_pattern.js | 139 --------- .../create_index_pattern.html | 147 --------- .../create_index_pattern.js | 254 --------------- .../get_default_pattern_for_interval.js | 17 - .../indices/create_index_pattern/index.js | 1 - .../pick_create_button_text.js | 23 -- .../create_index_pattern_wizard.html | 152 +++++++++ .../create_index_pattern_wizard.js | 290 ++++++++++++++++++ .../create_index_pattern_wizard/index.js | 1 + .../matching_indices_list/index.js | 1 + .../matching_indices_list.html | 64 ++++ .../matching_indices_list.js | 52 ++++ .../matching_indices_list.less | 3 + .../send_create_index_pattern_request.js | 0 .../step_index_pattern/index.js | 1 + .../step_index_pattern.html | 163 ++++++++++ .../step_index_pattern/step_index_pattern.js | 96 ++++++ .../step_index_pattern.less | 5 + .../step_time_field/index.js | 1 + .../step_time_field/step_time_field.html | 148 +++++++++ .../step_time_field/step_time_field.js | 60 ++++ .../step_time_field/step_time_field.less | 9 + .../management/sections/indices/index.html | 4 +- .../management/sections/indices/index.js | 2 +- src/core_plugins/kibana/translations/en.json | 80 ++--- ...ndex_name.js => validate_index_pattern.js} | 8 +- src/ui/public/directives/info.js | 4 +- ...ndex_name.js => validate_index_pattern.js} | 10 +- .../documentation_links.js | 4 + src/ui/public/partials/info.html | 14 +- .../_create_index_pattern_wizard.js | 37 +++ .../apps/management/_creation_form_changes.js | 32 -- .../_index_pattern_create_delete.js | 2 +- .../apps/management/_initial_state.js | 44 --- test/functional/apps/management/index.js | 3 +- test/functional/page_objects/settings_page.js | 31 +- .../components/info_button/_info_button.scss | 1 + ui_framework/components/panel/_panel.scss | 23 +- .../components/table/_controlled_table.scss | 6 +- ui_framework/dist/ui_framework.css | 41 ++- 40 files changed, 1232 insertions(+), 741 deletions(-) delete mode 100644 src/core_plugins/kibana/public/management/sections/indices/create_index_pattern/__tests__/create_index_pattern.js delete mode 100644 src/core_plugins/kibana/public/management/sections/indices/create_index_pattern/create_index_pattern.html delete mode 100644 src/core_plugins/kibana/public/management/sections/indices/create_index_pattern/create_index_pattern.js delete mode 100644 src/core_plugins/kibana/public/management/sections/indices/create_index_pattern/get_default_pattern_for_interval.js delete mode 100644 src/core_plugins/kibana/public/management/sections/indices/create_index_pattern/index.js delete mode 100644 src/core_plugins/kibana/public/management/sections/indices/create_index_pattern/pick_create_button_text.js create mode 100644 src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/create_index_pattern_wizard.html create mode 100644 src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/create_index_pattern_wizard.js create mode 100644 src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/index.js create mode 100644 src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/matching_indices_list/index.js create mode 100644 src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/matching_indices_list/matching_indices_list.html create mode 100644 src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/matching_indices_list/matching_indices_list.js create mode 100644 src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/matching_indices_list/matching_indices_list.less rename src/core_plugins/kibana/public/management/sections/indices/{create_index_pattern => create_index_pattern_wizard}/send_create_index_pattern_request.js (100%) create mode 100644 src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/step_index_pattern/index.js create mode 100644 src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/step_index_pattern/step_index_pattern.html create mode 100644 src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/step_index_pattern/step_index_pattern.js create mode 100644 src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/step_index_pattern/step_index_pattern.less create mode 100644 src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/step_time_field/index.js create mode 100644 src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/step_time_field/step_time_field.html create mode 100644 src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/step_time_field/step_time_field.js create mode 100644 src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/step_time_field/step_time_field.less rename src/ui/public/directives/__tests__/{validate_index_name.js => validate_index_pattern.js} (91%) rename src/ui/public/directives/{validate_index_name.js => validate_index_pattern.js} (73%) create mode 100644 test/functional/apps/management/_create_index_pattern_wizard.js delete mode 100644 test/functional/apps/management/_creation_form_changes.js delete mode 100644 test/functional/apps/management/_initial_state.js diff --git a/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern/__tests__/create_index_pattern.js b/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern/__tests__/create_index_pattern.js deleted file mode 100644 index f29a6be44cd98..0000000000000 --- a/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern/__tests__/create_index_pattern.js +++ /dev/null @@ -1,139 +0,0 @@ -import angular from 'angular'; -import ngMock from 'ng_mock'; -import jQuery from 'jquery'; -import expect from 'expect.js'; -import sinon from 'sinon'; - -import createIndexPatternTemplate from '../create_index_pattern.html'; -import { StubIndexPatternsApiClientModule } from 'ui/index_patterns/__tests__/stub_index_patterns_api_client'; -import { IndexPatternsApiClientProvider } from 'ui/index_patterns'; -import MockLogstashFieldsProvider from 'fixtures/logstash_fields'; - -describe('createIndexPattern UI', () => { - let setup; - const trash = []; - - beforeEach(ngMock.module('kibana', StubIndexPatternsApiClientModule, ($provide) => { - $provide.constant('buildSha', 'abc1234'); - $provide.constant('$route', { - current: { - params: {}, - locals: { - indexPatternIds: [] - } - } - }); - })); - - beforeEach(ngMock.inject(($injector) => { - setup = function () { - const Private = $injector.get('Private'); - const $compile = $injector.get('$compile'); - const $rootScope = $injector.get('$rootScope'); - - const fields = Private(MockLogstashFieldsProvider); - const indexPatternsApiClient = Private(IndexPatternsApiClientProvider); - const $scope = $rootScope.$new(); - const $view = jQuery($compile(angular.element('
').html(createIndexPatternTemplate))($scope)); - trash.push(() => $scope.$destroy()); - $scope.$apply(); - - const setNameTo = (name) => { - $view.findTestSubject('createIndexPatternNameInput') - .val(name) - .change() - .blur(); - - // ensure that name successfully applied - const form = $view.find('form').scope().form; - expect(form.name).to.have.property('$viewValue', name); - }; - - return { - $view, - $scope, - setNameTo, - indexPatternsApiClient, - fields - }; - }; - })); - - afterEach(() => { - trash.forEach(fn => fn()); - trash.length = 0; - }); - - describe('defaults', () => { - it('renders `logstash-*` into the name input', () => { - const { $view } = setup(); - - const $name = $view.findTestSubject('createIndexPatternNameInput'); - expect($name).to.have.length(1); - expect($name.val()).to.be('logstash-*'); - }); - - it('attempts to getFieldsForWildcard for `logstash-*`', () => { - const { indexPatternsApiClient } = setup(); - const { getFieldsForWildcard } = indexPatternsApiClient; - - sinon.assert.called(getFieldsForWildcard); - const calledWithPattern = getFieldsForWildcard.getCalls().some(call => { - const [params] = call.args; - return ( - params && - params.pattern && - params.pattern === 'logstash-*' - ); - }); - - if (!calledWithPattern) { - throw new Error('expected indexPatternsApiClient.getFieldsForWildcard to be called with pattern = logstash-*'); - } - }); - - it('loads the time fields into the select box', () => { - const { $view, fields } = setup(); - - const timeFieldOptions = $view.findTestSubject('createIndexPatternTimeFieldSelect') - .find('option') - .toArray() - .map(option => option.innerText); - - fields.forEach((field) => { - if (!field.scripted && field.type === 'date') { - expect(timeFieldOptions).to.contain(field.name); - } else { - expect(timeFieldOptions).to.not.contain(field.name); - } - }); - }); - - it('displays the option (off) to expand wildcards', () => { - const { $view } = setup(); - const $enableExpand = $view.findTestSubject('createIndexPatternEnableExpand'); - expect($enableExpand).to.have.length(1); - expect($enableExpand.is(':checked')).to.be(false); - }); - }); - - describe('cross cluster pattern', () => { - it('name input accepts `cluster2:logstash-*` pattern', () => { - const { $view, setNameTo } = setup(); - setNameTo('cluster2:logstash-*'); - - const $name = $view.findTestSubject('createIndexPatternNameInput'); - const classes = [...$name.get(0).classList]; - expect(classes).to.contain('ng-valid'); - expect(classes).to.not.contain('ng-invalid'); - }); - - it('removes the option to expand wildcards', () => { - const { $view, setNameTo } = setup(); - setNameTo('cluster2:logstash-*'); - - const $enableExpand = $view.findTestSubject('createIndexPatternEnableExpand'); - expect($enableExpand).to.have.length(0); - }); - }); -}); diff --git a/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern/create_index_pattern.html b/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern/create_index_pattern.html deleted file mode 100644 index 5bc4f9ec40338..0000000000000 --- a/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern/create_index_pattern.html +++ /dev/null @@ -1,147 +0,0 @@ - - -
-

- -

- -
- -
- -
- - -
- -
- - -
-

- - - {{controller.timeFieldOptionsError}} - -

-
- - -
-

-
-
- - -
- - -
- -
-
- - -
- - - -
-

- -

- - - - - -

- -

-
-
- - - -
-
-
-
-
diff --git a/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern/create_index_pattern.js b/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern/create_index_pattern.js deleted file mode 100644 index f4bbf40250e94..0000000000000 --- a/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern/create_index_pattern.js +++ /dev/null @@ -1,254 +0,0 @@ -import _ from 'lodash'; -import { IndexPatternMissingIndices } from 'ui/errors'; -import 'ui/directives/validate_index_name'; -import 'ui/directives/auto_select_if_only_one'; -import { RefreshKibanaIndex } from '../refresh_kibana_index'; -import uiRoutes from 'ui/routes'; -import { uiModules } from 'ui/modules'; -import template from './create_index_pattern.html'; -import { sendCreateIndexPatternRequest } from './send_create_index_pattern_request'; -import { pickCreateButtonText } from './pick_create_button_text'; - -uiRoutes -.when('/management/kibana/index', { - template, -}); - -uiModules.get('apps/management') -.controller('managementIndicesCreate', function ($scope, kbnUrl, Private, Notifier, indexPatterns, es, config, Promise, $translate) { - const notify = new Notifier(); - const refreshKibanaIndex = Private(RefreshKibanaIndex); - let loadingCount = 0; - - // Configure the new index pattern we're going to create. - this.formValues = { - name: config.get('indexPattern:placeholder'), - expandWildcard: false, - timeFieldOption: null, - }; - - // UI state. - this.timeFieldOptions = []; - this.timeFieldOptionsError = null; - - const getTimeFieldOptions = () => { - loadingCount += 1; - return Promise.resolve() - .then(() => { - const { name } = this.formValues; - if (!name) { - return []; - } - return indexPatterns.fieldsFetcher.fetchForWildcard(name); - }) - .then(fields => { - const dateFields = fields.filter(field => field.type === 'date'); - - if (dateFields.length === 0) { - return { - options: [ - { - display: $translate.instant('KIBANA-INDICES_DONT_CONTAIN_TIME_FIELDS') - } - ] - }; - } - - return { - options: [ - { - display: $translate.instant('KIBANA-NO_DATE_FIELD_DESIRED') - }, - ...dateFields.map(field => ({ - display: field.name, - fieldName: field.name - })), - ] - }; - }) - .catch(err => { - if (err instanceof IndexPatternMissingIndices) { - return { - error: $translate.instant('KIBANA-INDICES_MATCH_PATTERN') - }; - } - - throw err; - }) - .finally(() => { - loadingCount -= 1; - }); - }; - - const findTimeFieldOption = match => { - if (!match) return; - - return this.timeFieldOptions.find(option => ( - // comparison is not done with _.isEqual() because options get a unique - // `$$hashKey` tag attached to them by ng-repeat - option.fieldName === match.fieldName && - option.display === match.display - )); - }; - - const pickDefaultTimeFieldOption = () => { - const noOptions = this.timeFieldOptions.length === 0; - // options that represent a time field - const fieldOptions = this.timeFieldOptions.filter(option => !!option.fieldName); - // options like "I don't want the time filter" or "There are no date fields" - const nonFieldOptions = this.timeFieldOptions.filter(option => !option.fieldName); - // if there are multiple field or non-field options then we can't select a default, the user must choose - const tooManyOptions = fieldOptions.length > 1 || nonFieldOptions.length > 1; - - if (noOptions || tooManyOptions) { - return null; - } - - if (fieldOptions.length === 1) { - return fieldOptions[0]; - } - - return nonFieldOptions[0]; - }; - - this.isTimeBased = () => { - if (!this.formValues.timeFieldOption) { - // if they haven't choosen a time field, assume they will - return true; - } - - // if timeFieldOption has a fieldName it's a time field, otherwise - // it's a way to opt-out of the time field or an indication that there - // are no fields available - return Boolean(this.formValues.timeFieldOption.fieldName); - }; - - this.canEnableExpandWildcard = () => { - return ( - this.isTimeBased() && - !this.isCrossClusterName() && - _.includes(this.formValues.name, '*') - ); - }; - - this.isExpandWildcardEnabled = () => { - return ( - this.canEnableExpandWildcard() && - !!this.formValues.expandWildcard - ); - }; - - this.isCrossClusterName = () => { - return ( - this.formValues.name && - this.formValues.name.includes(':') - ); - }; - - this.isLoading = () => { - return loadingCount > 0; - }; - - let activeRefreshTimeFieldOptionsCall; - this.refreshTimeFieldOptions = () => { - // if there is an active refreshTimeFieldOptions() call then we use - // their prevOption, allowing the previous selection to persist - // across simultaneous calls to refreshTimeFieldOptions() - const prevOption = activeRefreshTimeFieldOptionsCall - ? activeRefreshTimeFieldOptionsCall.prevOption - : this.formValues.timeFieldOption; - - // `thisCall` is our unique "token" to verify that we are still the - // most recent call. When we are not the most recent call we don't - // modify the controller in any way to prevent race conditions - const thisCall = activeRefreshTimeFieldOptionsCall = { prevOption }; - - loadingCount += 1; - this.timeFieldOptions = []; - this.timeFieldOptionsError = null; - this.formValues.timeFieldOption = null; - getTimeFieldOptions() - .then(({ options, error }) => { - if (thisCall !== activeRefreshTimeFieldOptionsCall) return; - - this.timeFieldOptions = options; - this.timeFieldOptionsError = error; - if (!this.timeFieldOptions) { - return; - } - - // Restore the preivously selected state, or select the default option in the UI - const restoredOption = findTimeFieldOption(prevOption); - const defaultOption = pickDefaultTimeFieldOption(); - this.formValues.timeFieldOption = restoredOption || defaultOption; - }) - .catch(notify.error) - .finally(() => { - loadingCount -= 1; - if (thisCall === activeRefreshTimeFieldOptionsCall) { - activeRefreshTimeFieldOptionsCall = null; - } - }); - }; - - this.createIndexPattern = () => { - const { - name, - timeFieldOption, - } = this.formValues; - - const id = name; - - const timeFieldName = timeFieldOption - ? timeFieldOption.fieldName - : undefined; - - const notExpandable = this.isExpandWildcardEnabled() - ? undefined - : true; - - loadingCount += 1; - sendCreateIndexPatternRequest(indexPatterns, { - id, - timeFieldName, - notExpandable, - }).then(createdId => { - if (!createdId) { - return; - } - - refreshKibanaIndex().then(() => { - if (!config.get('defaultIndex')) { - config.set('defaultIndex', id); - } - - indexPatterns.cache.clear(id); - kbnUrl.change(`/management/kibana/indices/${id}`); - - // force loading while kbnUrl.change takes effect - loadingCount = Infinity; - }); - }).catch(err => { - if (err instanceof IndexPatternMissingIndices) { - return notify.error($translate.instant('KIBANA-NO_INDICES_MATCHING_PATTERN')); - } - - notify.fatal(err); - }).finally(() => { - loadingCount -= 1; - }); - }; - - $scope.$watch('controller.formValues.name', () => { - this.refreshTimeFieldOptions(); - }); - - $scope.$watchMulti([ - 'controller.isLoading()', - 'form.name.$error.indexNameInput', - 'controller.formValues.timeFieldOption' - ], ([loading, invalidIndexName, timeFieldOption]) => { - const state = { loading, invalidIndexName, timeFieldOption }; - this.createButtonText = pickCreateButtonText($translate, state); - }); -}); diff --git a/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern/get_default_pattern_for_interval.js b/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern/get_default_pattern_for_interval.js deleted file mode 100644 index 6ce16209644de..0000000000000 --- a/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern/get_default_pattern_for_interval.js +++ /dev/null @@ -1,17 +0,0 @@ -const intervalToDefaultPatternMap = { - hours: '[logstash-]YYYY.MM.DD.HH', - days: '[logstash-]YYYY.MM.DD', - weeks: '[logstash-]GGGG.WW', - months: '[logstash-]YYYY.MM', - years: '[logstash-]YYYY', -}; - -export function getDefaultPatternForInterval(interval) { - const defaultPattern = intervalToDefaultPatternMap[interval]; - - if (defaultPattern) { - return defaultPattern; - } - - return 'logstash-*'; -} diff --git a/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern/index.js b/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern/index.js deleted file mode 100644 index fd1fdd05795e9..0000000000000 --- a/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern/index.js +++ /dev/null @@ -1 +0,0 @@ -import './create_index_pattern'; diff --git a/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern/pick_create_button_text.js b/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern/pick_create_button_text.js deleted file mode 100644 index 44c5462ac0441..0000000000000 --- a/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern/pick_create_button_text.js +++ /dev/null @@ -1,23 +0,0 @@ -export function pickCreateButtonText($translate, state) { - const { - loading, - invalidIndexName, - timeFieldOption - } = state; - - if (loading) { - return $translate.instant('KIBANA-LOADING'); - } - - if (invalidIndexName) { - return $translate.instant('KIBANA-INVALID_INDEX_PATTERN'); - } - - if (!timeFieldOption) { - return $translate.instant('KIBANA-FIELD_IS_REQUIRED', { - fieldName: $translate.instant('KIBANA-TIME_FILTER_FIELD_NAME') - }); - } - - return $translate.instant('KIBANA-CREATE'); -} diff --git a/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/create_index_pattern_wizard.html b/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/create_index_pattern_wizard.html new file mode 100644 index 0000000000000..9a5a543ce988c --- /dev/null +++ b/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/create_index_pattern_wizard.html @@ -0,0 +1,152 @@ + + +
+ +
+
+

+ +
+ + +
+
+ +

+
+ + +
+
+ +
+
+

+ +
+

+ + + + +

+
+
+
+ + +
+
+
+

+ +
+

+ + +

+
+ + +
+
+
+
+
+ + +
+ + + + + +
+
+
+
diff --git a/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/create_index_pattern_wizard.js b/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/create_index_pattern_wizard.js new file mode 100644 index 0000000000000..490491ee96d2d --- /dev/null +++ b/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/create_index_pattern_wizard.js @@ -0,0 +1,290 @@ +import _ from 'lodash'; +import { IndexPatternMissingIndices } from 'ui/errors'; +import 'ui/directives/validate_index_pattern'; +import 'ui/directives/auto_select_if_only_one'; +import { RefreshKibanaIndex } from '../refresh_kibana_index'; +import { documentationLinks } from 'ui/documentation_links/documentation_links'; +import uiRoutes from 'ui/routes'; +import { uiModules } from 'ui/modules'; +import template from './create_index_pattern_wizard.html'; +import { sendCreateIndexPatternRequest } from './send_create_index_pattern_request'; +import './step_index_pattern'; +import './step_time_field'; +import './matching_indices_list'; +import 'ui/indices'; + +uiRoutes +.when('/management/kibana/index', { + template, +}); + +uiModules.get('apps/management') +.controller('managementIndicesCreate', function ( + $injector, + $scope, + $timeout, + $translate, + config, + es, + indexPatterns, + kbnUrl, + Notifier, + Private, + Promise +) { + const indicesService = $injector.get('indices'); + const notify = new Notifier(); + const refreshKibanaIndex = Private(RefreshKibanaIndex); + const loadingOption = { + display: 'Loading...', + }; + const disabledDividerOption = { + isDisabled: true, + display: '───', + }; + const noTimeFieldOption = { + display: $translate.instant('KIBANA-CREATE_INDEX_PATTERN_STEP_2_NO_DATE_FIELD_OPTION') + }; + + this.documentationLinks = documentationLinks; + + // Configure the new index pattern we're going to create. + this.formValues = { + name: '', + expandWildcard: false, + timeFieldOption: loadingOption, + }; + + // UI state. + this.timeFieldOptions = [ + loadingOption, + ]; + this.wizardStep = 'indexPattern'; + this.isFetchingExistingIndices = true; + this.isFetchingMatchingIndices = false; + this.isFetchingTimeFieldOptions = false; + this.isCreatingIndexPattern = false; + this.doesIncludeSystemIndices = false; + this.timeFieldError = undefined; + let allIndices = []; + let matchingIndices = []; + let partialMatchingIndices = []; + this.allIndices = []; + this.matchingIndices = []; + this.partialMatchingIndices = []; + + function createReasonableWait() { + return new Promise(resolve => { + // Make every fetch take a set amount of time so the user gets some feedback that something + // is happening. + $timeout(() => { + resolve(); + }, 500); + }); + } + + const whiteListIndices = indices => { + if (!indices) { + return indices; + } + + if (this.doesIncludeSystemIndices) { + return indices; + } + + // All system indices begin with a period. + return indices.filter(index => ( + index.indexOf('.') !== 0 + )); + }; + + const updateWhiteListedIndices = () => { + this.allIndices = whiteListIndices(allIndices); + this.matchingIndices = whiteListIndices(matchingIndices); + this.partialMatchingIndices = whiteListIndices(partialMatchingIndices); + }; + + this.onIncludeSystemIndicesChange = () => { + updateWhiteListedIndices(); + }; + + let mostRecentFetchMatchingIndicesRequest; + + this.fetchMatchingIndices = () => { + this.isFetchingMatchingIndices = true; + + // Default to searching for all indices. + const exactSearchQuery = this.formValues.name; + let partialSearchQuery = this.formValues.name; + + if (!_.endsWith(partialSearchQuery, '*')) { + partialSearchQuery = `${partialSearchQuery}*`; + } + if (!_.startsWith(partialSearchQuery, '*')) { + partialSearchQuery = `*${partialSearchQuery}`; + } + + const thisFetchMatchingIndicesRequest = mostRecentFetchMatchingIndicesRequest = Promise.all([ + indicesService.getIndices(exactSearchQuery), + indicesService.getIndices(partialSearchQuery), + createReasonableWait(), + ]) + .then(([ + matchingIndicesResponse, + partialMatchingIndicesResponse, + ]) => { + if (thisFetchMatchingIndicesRequest === mostRecentFetchMatchingIndicesRequest) { + matchingIndices = matchingIndicesResponse.sort(); + partialMatchingIndices = partialMatchingIndicesResponse.sort(); + updateWhiteListedIndices(); + this.isFetchingMatchingIndices = false; + } + }); + }; + + this.fetchExistingIndices = () => { + this.isFetchingExistingIndices = true; + Promise.all([ + indicesService.getIndices('*'), + createReasonableWait(), + ]) + .then(([allIndicesResponse]) => { + // Cache all indices. + allIndices = allIndicesResponse.sort(); + updateWhiteListedIndices(); + this.isFetchingExistingIndices = false; + }); + }; + + this.isSystemIndicesCheckBoxVisible = () => ( + this.wizardStep === 'indexPattern' + ); + + this.goToIndexPatternStep = () => { + this.wizardStep = 'indexPattern'; + }; + + this.goToTimeFieldStep = () => { + // Re-initialize this step. + this.formValues.timeFieldOption = undefined; + this.fetchTimeFieldOptions(); + this.wizardStep = 'timeField'; + }; + + this.hasIndices = () => ( + this.allIndices.length + ); + + this.isTimeBased = () => ( + this.formValues.timeFieldOption !== undefined + && this.formValues.timeFieldOption !== noTimeFieldOption + && this.formValues.timeFieldOption !== loadingOption + ); + + const isExpandWildcardEnabled = () => ( + this.canEnableExpandWildcard() + && !!this.formValues.expandWildcard + ); + + const isCrossClusterName = () => ( + this.formValues.name + && this.formValues.name.includes(':') + ); + + this.canEnableExpandWildcard = () => ( + this.isTimeBased() + && !isCrossClusterName() + && _.includes(this.formValues.name, '*') + ); + + const extractTimeFieldsFromFields = fields => { + const dateFields = fields.filter(field => field.type === 'date'); + + if (dateFields.length === 0) { + return [{ + display: $translate.instant('KIBANA-CREATE_INDEX_PATTERN_STEP_2_NO_TIME_FIELDS') + }]; + } + + return [ + ...dateFields.map(field => ({ + display: field.name, + fieldName: field.name + })), + disabledDividerOption, + noTimeFieldOption, + ]; + }; + + this.fetchTimeFieldOptions = () => { + this.isFetchingTimeFieldOptions = true; + this.formValues.timeFieldOption = loadingOption; + this.timeFieldOptions = [loadingOption]; + + Promise.all([ + indexPatterns.fieldsFetcher.fetchForWildcard(this.formValues.name), + createReasonableWait(), + ]) + .then(([fields]) => { + this.timeFieldOptions = extractTimeFieldsFromFields(fields); + }) + .catch(err => { + if (err instanceof IndexPatternMissingIndices) { + this.timeFieldError = $translate.instant('KIBANA-CREATE_INDEX_PATTERN_STEP_2_NO_MAPPING_ERROR'); + } + + notify.error(err); + }) + .finally(() => { + this.isFetchingTimeFieldOptions = false; + }); + }; + + this.createIndexPattern = () => { + this.isCreatingIndexPattern = true; + + const { + name, + timeFieldOption, + } = this.formValues; + + const id = name; + + const timeFieldName = timeFieldOption + ? timeFieldOption.fieldName + : undefined; + + const notExpandable = isExpandWildcardEnabled() + ? undefined + : true; + + sendCreateIndexPatternRequest(indexPatterns, { + id, + timeFieldName, + notExpandable, + }).then(createdId => { + if (!createdId) { + return; + } + + refreshKibanaIndex().then(() => { + if (!config.get('defaultIndex')) { + config.set('defaultIndex', id); + } + + indexPatterns.cache.clear(id); + kbnUrl.change(`/management/kibana/indices/${id}`); + }); + }).catch(err => { + if (err instanceof IndexPatternMissingIndices) { + return notify.error($translate.instant('KIBANA-CREATE_INDEX_PATTERN_STEP_2_INDICES_DONT_MATCH_PATTERN')); + } + + notify.fatal(err); + }).finally(() => { + this.isCreatingIndexPattern = false; + }); + }; + + this.fetchExistingIndices(); +}); diff --git a/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/index.js b/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/index.js new file mode 100644 index 0000000000000..e6b701ce12c25 --- /dev/null +++ b/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/index.js @@ -0,0 +1 @@ +import './create_index_pattern_wizard'; diff --git a/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/matching_indices_list/index.js b/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/matching_indices_list/index.js new file mode 100644 index 0000000000000..5571f47154ed6 --- /dev/null +++ b/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/matching_indices_list/index.js @@ -0,0 +1 @@ +import './matching_indices_list'; diff --git a/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/matching_indices_list/matching_indices_list.html b/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/matching_indices_list/matching_indices_list.html new file mode 100644 index 0000000000000..12fa95821c3da --- /dev/null +++ b/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/matching_indices_list/matching_indices_list.html @@ -0,0 +1,64 @@ +
+
+
+

+ +
+

+
+
+
+ +
+ +
+
+

+ +

+
+ +
+ + + + +
+
+ + +
    +
  • +

    + {{index}} +

    +
  • +
+
+
diff --git a/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/matching_indices_list/matching_indices_list.js b/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/matching_indices_list/matching_indices_list.js new file mode 100644 index 0000000000000..d2d8d55db0bff --- /dev/null +++ b/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/matching_indices_list/matching_indices_list.js @@ -0,0 +1,52 @@ +import 'ui/pager_control'; +import 'ui/pager'; +import { uiModules } from 'ui/modules'; +import './matching_indices_list.less'; +import template from './matching_indices_list.html'; + +const module = uiModules.get('apps/management'); + +module.directive('matchingIndicesList', function ($filter, pagerFactory) { + return { + restrict: 'E', + replace: true, + template, + transclude: true, + controllerAs: 'matchingIndicesList', + bindToController: true, + scope: { + indices: '=', + isLoading: '=', + }, + link: function (scope) { + scope.$watch('matchingIndicesList.indices', () => { + scope.matchingIndicesList.calculateItemsOnPage(); + }); + }, + controller: function () { + this.pageOfIndices = []; + + this.calculateItemsOnPage = () => { + const limitTo = $filter('limitTo'); + this.pager.setTotalItems(this.indices.length); + this.pageOfIndices = limitTo(this.indices, this.pager.pageSize, this.pager.startIndex); + }; + + this.pager = pagerFactory.create(this.indices.length, 10, 1); + + this.hasMultiplePages = () => { + return this.indices.length > this.pager.pageSize; + }; + + this.onPageNext = () => { + this.pager.nextPage(); + this.calculateItemsOnPage(); + }; + + this.onPagePrevious = () => { + this.pager.previousPage(); + this.calculateItemsOnPage(); + }; + }, + }; +}); diff --git a/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/matching_indices_list/matching_indices_list.less b/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/matching_indices_list/matching_indices_list.less new file mode 100644 index 0000000000000..598a153ca5055 --- /dev/null +++ b/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/matching_indices_list/matching_indices_list.less @@ -0,0 +1,3 @@ +.matchingIndicesListLoadingPrompt { + min-height: 60px; +} diff --git a/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern/send_create_index_pattern_request.js b/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/send_create_index_pattern_request.js similarity index 100% rename from src/core_plugins/kibana/public/management/sections/indices/create_index_pattern/send_create_index_pattern_request.js rename to src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/send_create_index_pattern_request.js diff --git a/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/step_index_pattern/index.js b/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/step_index_pattern/index.js new file mode 100644 index 0000000000000..90b9da92c0559 --- /dev/null +++ b/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/step_index_pattern/index.js @@ -0,0 +1 @@ +import './step_index_pattern'; diff --git a/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/step_index_pattern/step_index_pattern.html b/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/step_index_pattern/step_index_pattern.html new file mode 100644 index 0000000000000..634eb83be461e --- /dev/null +++ b/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/step_index_pattern/step_index_pattern.html @@ -0,0 +1,163 @@ +
+
+
+

+
+
+ +
+
+
+
+ +
+ + +
+ +
+ +

+ You can use a * as a wildcard in your index pattern. +

+ +

+ You can't use empty spaces or the characters \\ / ? \" < > , |. +

+
+ + + +
+
+ + +
+
+ + + + + + You've entered an invalid index pattern. Please adjust it to match any of your {{stepIndexPattern.allIndices.length}} indices, below. + + + +
+ + + + + + Your index pattern can match any of your {{stepIndexPattern.allIndices.length}} indices, below. + + + +
+ +
+ + + + The index pattern you've entered doesn't match any indices. You can match any of your {{stepIndexPattern.allIndices.length}} indices, below. + + + +
+ +
+ + + + Your index pattern doesn't match any indices, but you have {{stepIndexPattern.partialMatchingIndices.length}} {{stepIndexPattern.partialMatchingIndices.length > 1 ? 'indices' : 'index'}} which {{stepIndexPattern.partialMatchingIndices.length > 1 ? 'look' : 'looks'}} similar. + + + +
+ +
+ + + + + + Success! Your index pattern matches {{stepIndexPattern.matchingIndices.length}} {{stepIndexPattern.matchingIndices.length > 1 ? 'indices' : 'index'}}. + + + +
+
+
+
+
diff --git a/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/step_index_pattern/step_index_pattern.js b/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/step_index_pattern/step_index_pattern.js new file mode 100644 index 0000000000000..3f4f089169929 --- /dev/null +++ b/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/step_index_pattern/step_index_pattern.js @@ -0,0 +1,96 @@ +import { uiModules } from 'ui/modules'; +import './step_index_pattern.less'; +import template from './step_index_pattern.html'; +import { documentationLinks } from 'ui/documentation_links/documentation_links'; + +const module = uiModules.get('apps/management'); + +module.directive('stepIndexPattern', function () { + return { + restrict: 'E', + template, + replace: true, + controllerAs: 'stepIndexPattern', + bindToController: true, + scope: { + fetchExistingIndices: '&', + isFetchingExistingIndices: '=', + fetchMatchingIndices: '&', + isFetchingMatchingIndices: '=', + hasIndices: '&', + indexPatternName: '=', + allIndices: '=', + partialMatchingIndices: '=', + matchingIndices: '=', + goToNextStep: '&', + }, + link: function (scope) { + scope.$watch('stepIndexPattern.allIndices', scope.stepIndexPattern.updateList); + scope.$watch('stepIndexPattern.matchingIndices', scope.stepIndexPattern.updateList); + scope.$watch('stepIndexPattern.indexPatternName', () => { + // Only send the request if there's valid input. + if (scope.stepIndexPattern.indexPatternNameForm && scope.stepIndexPattern.indexPatternNameForm.$valid) { + scope.stepIndexPattern.fetchMatchingIndices(); + } + + // If the index pattern name is invalid, we should reflect that state in the list. + scope.stepIndexPattern.updateList(); + }); + scope.$watch('stepIndexPattern.indexPatternNameForm.$error', () => { + // If we immediately replace the input with an invalid string, then only the form state + // changes, but not the `indexPatternName` value, so we need to watch both. + scope.stepIndexPattern.updateList(); + }); + }, + controller: function () { + this.matchingIndicesListType = 'noMatches'; + this.documentationLinks = documentationLinks; + + this.canGoToNextStep = () => ( + !this.isFetchingMatchingIndices + && !this.indexPatternNameForm.$invalid + && this.hasExactMatches() + ); + + const hasInvalidIndexPattern = () => ( + this.indexPatternNameForm + && !this.indexPatternNameForm.$error.required + && this.indexPatternNameForm.$error.indexPattern + ); + + const hasNoInput = () => ( + !this.indexPatternName + || !this.indexPatternName.trim() + ); + + this.hasExactMatches = () => ( + this.matchingIndices.length + ); + + const hasPartialMatches = () => ( + !this.matchingIndices.length + && this.partialMatchingIndices.length + ); + + this.updateList = () => { + if (hasInvalidIndexPattern()) { + return this.matchingIndicesListType = 'invalidIndexPattern'; + } + + if (hasNoInput()) { + return this.matchingIndicesListType = 'noInput'; + } + + if (this.hasExactMatches()) { + return this.matchingIndicesListType = 'exactMatches'; + } + + if (hasPartialMatches()) { + return this.matchingIndicesListType = 'partialMatches'; + } + + this.matchingIndicesListType = 'noMatches'; + }; + }, + }; +}); diff --git a/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/step_index_pattern/step_index_pattern.less b/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/step_index_pattern/step_index_pattern.less new file mode 100644 index 0000000000000..20dc8a63ecf5f --- /dev/null +++ b/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/step_index_pattern/step_index_pattern.less @@ -0,0 +1,5 @@ +.createIndexPatternInputContainer { + display: flex; + justify-content: space-between; + align-items: flex-end; +} diff --git a/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/step_time_field/index.js b/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/step_time_field/index.js new file mode 100644 index 0000000000000..02994a505bd11 --- /dev/null +++ b/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/step_time_field/index.js @@ -0,0 +1 @@ +import './step_time_field'; diff --git a/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/step_time_field/step_time_field.html b/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/step_time_field/step_time_field.html new file mode 100644 index 0000000000000..49827ba599c39 --- /dev/null +++ b/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/step_time_field/step_time_field.html @@ -0,0 +1,148 @@ +
+
+
+

+
+
+ +
+

+ You've defined {{stepTimeField.indexPatternName}} as your index pattern. Now you can specify some optional settings before we create it. +

+ + +
+
+ + + + +

+ +

+
+ +
+ +
+ +

+
+ + + + + + + + + +
+

+ +

+ +

+
+
+ + +
+
+
+ + + +
+
+
+
+
diff --git a/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/step_time_field/step_time_field.js b/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/step_time_field/step_time_field.js new file mode 100644 index 0000000000000..bd46828ce4122 --- /dev/null +++ b/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/step_time_field/step_time_field.js @@ -0,0 +1,60 @@ +import 'ui/toggle_panel'; +import { uiModules } from 'ui/modules'; +import './step_time_field.less'; +import template from './step_time_field.html'; +import { documentationLinks } from 'ui/documentation_links/documentation_links'; + +const module = uiModules.get('apps/management'); + +module.directive('stepTimeField', function ($translate) { + return { + restrict: 'E', + template, + replace: true, + controllerAs: 'stepTimeField', + bindToController: true, + scope: { + indexPatternName: '=', + expandWildcard: '=', + canEnableExpandWildcard: '&', + timeFieldOptions: '=', + timeFieldOptionsError: '=', + selectedTimeFieldOption: '=', + fetchTimeFieldOptions: '&', + isFetchingTimeFieldOptions: '=', + goToPreviousStep: '&', + createIndexPattern: '&', + }, + link: function (scope) { + scope.$watch('stepTimeField.canEnableExpandWildcard()', canEnableExpandWildcard => { + if (!canEnableExpandWildcard) { + scope.stepTimeField.isAdvancedOptionsVisible = false; + } + }); + }, + controller: function () { + this.isAdvancedOptionsVisible = false; + this.matchingIndicesListType = 'noMatches'; + this.documentationLinks = documentationLinks; + + this.getAdvancedOptionsButtonLabel = () => { + return $translate.instant('KIBANA-CREATE_INDEX_PATTERN_STEP_2_ADVANCED_OPTIONS_BUTTON'); + }; + + this.onToggleAdvancedOptions = () => { + this.isAdvancedOptionsVisible = !this.isAdvancedOptionsVisible; + }; + + this.isTimeFieldSelectDisabled = () => ( + this.isFetchingTimeFieldOptions + || this.timeFieldOptionsError + || this.timeFieldOptions.length === 1 + ); + + this.canCreateIndexPattern = () => ( + !this.timeFieldOptionsError + && !this.isFetchingTimeFieldOptions + ); + }, + }; +}); diff --git a/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/step_time_field/step_time_field.less b/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/step_time_field/step_time_field.less new file mode 100644 index 0000000000000..3548c6d861ade --- /dev/null +++ b/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/step_time_field/step_time_field.less @@ -0,0 +1,9 @@ +/** + * 1. Match select width. + */ +.timeFieldNameLabel { + width: 400px; /* 1 */ + display: flex; + align-items: center; + justify-content: space-between; +} diff --git a/src/core_plugins/kibana/public/management/sections/indices/index.html b/src/core_plugins/kibana/public/management/sections/indices/index.html index f12b3b5cc3c95..b0b9bcbd4f0a4 100644 --- a/src/core_plugins/kibana/public/management/sections/indices/index.html +++ b/src/core_plugins/kibana/public/management/sections/indices/index.html @@ -6,10 +6,10 @@
ng-if="editingId" href="#/management/kibana/index" class="kuiButton kuiButton--primary kuiButton--small" - aria-label="{{ 'KIBANA-ADD_NEW' | translate }}" + aria-label="{{ 'KIBANA-CREATE_INDEX_PATTERN_BUTTON' | translate }}" > - +
diff --git a/src/core_plugins/kibana/public/management/sections/indices/index.js b/src/core_plugins/kibana/public/management/sections/indices/index.js index f53024a762411..6613d590755fe 100644 --- a/src/core_plugins/kibana/public/management/sections/indices/index.js +++ b/src/core_plugins/kibana/public/management/sections/indices/index.js @@ -1,5 +1,5 @@ import { management } from 'ui/management'; -import './create_index_pattern'; +import './create_index_pattern_wizard'; import './edit_index_pattern'; import uiRoutes from 'ui/routes'; import { uiModules } from 'ui/modules'; diff --git a/src/core_plugins/kibana/translations/en.json b/src/core_plugins/kibana/translations/en.json index 54af102ae8f5c..e2824c99b3a27 100644 --- a/src/core_plugins/kibana/translations/en.json +++ b/src/core_plugins/kibana/translations/en.json @@ -1,52 +1,40 @@ { "UI-WELCOME_MESSAGE": "Loading Kibana", "UI-WELCOME_ERROR": "Kibana did not load properly. Check the server output for more information.", - "KIBANA-CONFIGURE_INDEX_PATTERN": "Configure an index pattern", - "KIBANA-MUST_CONFIGURE_INDEX_PATTERN": "In order to use Kibana you must configure at least one index pattern. Index patterns are used to identify the Elasticsearch index to run search and analytics against. They are also used to configure fields.", - "KIBANA-INDEX_NAME_CREATED_BY_EVENT_TIMES": "Use event times to create index names ", - "KIBANA-DEPRECATED": "[DEPRECATED]", - "KIBANA-ALERT_INDEX_PATTERN_DEPRECATED": "Time-interval based index patterns are deprecated!", - "KIBANA-WE": " We", - "KIBANA-STRONGLY_RECOMMEND": " strongly recommend", - "KIBANA-WILD_CARD_PATTERN": " using wildcard pattern names instead of time-interval based index patterns.", - "KIBANA-RECOMMEND_WILD_CARD_PATTERN_DETAILS": "Kibana is now smart enough to automatically determine which indices to search against within the current time range for wildcard index patterns. This means that wildcard index patterns now get the same performance optimizations when searching within a time range as time-interval patterns.", - "KIBANA-INDEX_PATTERN_INTERVAL": "Index pattern interval", - "KIBANA-INDEX_NAME_OR_PATTERN": "Index name or pattern", - "KIBANA-WILDCARD_DYNAMIC_INDEX_PATTERNS": "Patterns allow you to define dynamic index names using * as a wildcard. Example: logstash-*", - "KIBANA-STATIC_TEXT_IN_DYNAMIC_INDEX_PATTERNS": "Patterns allow you to define dynamic index names. Static text in an index name is denoted using brackets. Example: [logstash-]YYYY.MM.DD. Please note that weeks are setup to use ISO weeks which start on Monday.", - "KIBANA-NOTE_COLON": "Note:", - "KIBANA-WEEKLY_ISO_NOTICE": "I noticed you are using weekly indices. Kibana requires ISO weeks be used in your index creation.", - "KIBANA-EXPAND_INDEX_PATTERN": "Expand index pattern when searching", - "KIBANA-WILDCARD_DEFAULT_EXPANDED_TO_CURRENT_TIME_RANGE": "With this option selected, searches against any time-based index pattern that contains a wildcard will automatically be expanded to query only the indices that contain data within the currently selected time range.", - "KIBANA-SEARCH_AGAINST_INDEX_PATTERN": "Searching against the index pattern ", - "KIBANA-LOGSTASH_WILDCARD": "logstash-*", - "KIBANA-ACTUALLY_QUERY": " will actually query Elasticsearch for the specific matching indices (e.g. ", - "KIBANA-EXAMPLE_TIME_RANGE": "logstash-2015.12.21", - "KIBANA-FALL_WITHIN_CURRENT_TIME_RANGE": ") that fall within the current time range.", - "KIBANA-EXPAND_INDEX_PATTERN_DEPRECATION": "With recent changes to Elasticsearch, this option should no longer be necessary and will likely be removed in future versions of Kibana.", - "KIBANA-SAMPLE_ALERT": "Attempted to match the following indices and aliases:", - "KIBANA-EXPAND_SEARCH": "Expand Search", - "KIBANA-EXISTING_MATCH_PERCENT": "Pattern matches {{indexExistingMatchPercent}} of existing indices and aliases", - "KIBANA-NON_MATCHING_INDICES_AND_ALIASES": "Indices and aliases that were found, but did not match the pattern:", - "KIBANA-MORE": "more", - "KIBANA-TIME_FILTER_FIELD_NAME": "Time Filter field name", - "KIBANA-NO_DATE_FIELD_DESIRED": "I don't want to use the Time Filter", - "KIBANA-REFRESH_FIELDS": "refresh fields", - "KIBANA-INDICES_DONT_CONTAIN_TIME_FIELDS": "The indices which match this index pattern don't contain any time fields.", - "KIBANA-INVALID_INDEX_PATTERN": "Invalid index name pattern.", - "KIBANA-DATE_FORMAT_DOCS": "Date Format Documentation", - "KIBANA-WIKI_ISO_WEEK_DATE": "Wikipedia: ISO Week Date", - "KIBANA-NO_INDICES_MATCHING_PATTERN": "Could not locate any indices matching that pattern. Please add the index to Elasticsearch", - "KIBANA-PATTERN_DOES_NOT_MATCH_EXIST_INDICES": "Pattern does not match any existing indices", - "KIBANA-INVALID_NON_UNIQUE_INDEX_NAME_CREATED": "Invalid pattern, interval does not create unique index names", - "KIBANA-FIELD_FILTER_EVENTS_GLOBAL_TIME" : "This field will be used to filter events with the global time filter", - "KIBANA-INTERVAL_INDEX_NAMES_ROTATE" : "The interval at which index names rotate.", + "KIBANA-CREATE_INDEX_PATTERN_TITLE": "Create index pattern", + "KIBANA-CREATE_INDEX_PATTERN_INTRO": "Kibana uses index patterns to retrieve data from Elasticsearch, for things like visualizations.", + "KIBANA-CREATE_INDEX_PATTERN_INCLUDE_SYSTEM_INDICES_CHECKBOX_LABEL": "Include system indices", + "KIBANA-CREATE_INDEX_PATTERN_LOADING_DATA_TITLE": "Checking for Elasticsearch data", + "KIBANA-CREATE_INDEX_PATTERN_LOADING_DATA_BODY": "Reticulating splines...", + "KIBANA-CREATE_INDEX_PATTERN_NO_DATA_TITLE": "Couldn't find any Elasticsearch data", + "KIBANA-CREATE_INDEX_PATTERN_NO_DATA_BODY": "You'll need to index some data into Elasticsearch before you can create an index pattern.", + "KIBANA-CREATE_INDEX_PATTERN_NO_DATA_LEARN_LINK": "Learn how.", + "KIBANA-CREATE_INDEX_PATTERN_NO_DATA_LEARN_LINK_ALT": "Learn how to index data into Elasticsearch", + "KIBANA-CREATE_INDEX_PATTERN_NO_DATA_RELOAD_BUTTON": "Check for new data", + "KIBANA-CREATE_INDEX_PATTERN_STEP_1_TITLE": "Step 1 of 2: Define index pattern", + "KIBANA-CREATE_INDEX_PATTERN_STEP_1_INDEX_PATTERN_LABEL": "Index pattern", + "KIBANA-CREATE_INDEX_PATTERN_STEP_1_SEARCH_SINGLE_INDEX": "You only have a single index. You can create an index pattern to match it.", + "KIBANA-CREATE_INDEX_PATTERN_STEP_1_SEARCHING_TITLE": "Looking for matching indices", + "KIBANA-CREATE_INDEX_PATTERN_STEP_1_SEARCHING_BODY": "Just a sec...", + "KIBANA-CREATE_INDEX_PATTERN_STEP_1_SUBMIT_BUTTON" : "Next step", + "KIBANA-CREATE_INDEX_PATTERN_STEP_2_TITLE": "Step 2 of 2: Optional settings", + "KIBANA-CREATE_INDEX_PATTERN_STEP_2_TIME_FIELD_LABEL": "Choose optional Time Filter field name", + "KIBANA-CREATE_INDEX_PATTERN_STEP_2_TIME_FIELD_LOADING": "Please wait while we fetch your time field options", + "KIBANA-CREATE_INDEX_PATTERN_STEP_2_TIME_FIELD_HELP": "The Time Filter will use this field to filter your data by time.", + "KIBANA-CREATE_INDEX_PATTERN_STEP_2_ADVANCED_OPTIONS_BUTTON": "Advanced Time Field filter options", + "KIBANA-CREATE_INDEX_PATTERN_STEP_2_EXPAND_LABEL": "Expand index pattern (DEPRECATED)", + "KIBANA-CREATE_INDEX_PATTERN_STEP_2_EXPAND_CHECKBOX_LABEL": "Expand index pattern when searching", + "KIBANA-CREATE_INDEX_PATTERN_STEP_2_EXPAND_HELP_1": "With this option selected, searches against any time-based index pattern which contains a wildcard will automatically expand to query only the indices which contain data within the currently selected time range.", + "KIBANA-CREATE_INDEX_PATTERN_STEP_2_EXPAND_HELP_2": "Searching against the index pattern 'logstash-*' will actually query Elasticsearch for the specific matching indices (e.g. 'logstash-2015.12.21') that fall within the current time range.", + "KIBANA-CREATE_INDEX_PATTERN_STEP_2_EXPAND_HELP_3": "With recent changes to Elasticsearch, this option should no longer be necessary and will likely be removed in future versions of Kibana.", + "KIBANA-CREATE_INDEX_PATTERN_STEP_2_NO_DATE_FIELD_OPTION": "I don't want to use the Time Filter", + "KIBANA-CREATE_INDEX_PATTERN_STEP_2_REFRESH_FIELDS_BUTTON": "Refresh", + "KIBANA-CREATE_INDEX_PATTERN_STEP_2_NO_TIME_FIELDS": "The indices which match this index pattern don't contain any time fields.", + "KIBANA-CREATE_INDEX_PATTERN_STEP_2_INDICES_DONT_MATCH_PATTERN": "Could not locate any indices matching that pattern. Please add the index to Elasticsearch", + "KIBANA-CREATE_INDEX_PATTERN_STEP_2_BACK_BUTTON" : "Back", + "KIBANA-CREATE_INDEX_PATTERN_STEP_2_SUBMIT_BUTTON" : "Create index pattern", + "KIBANA-CREATE_INDEX_PATTERN_STEP_2_NO_MAPPING_ERROR" : "Unable to fetch mapping. Do you have indices matching the pattern?", "KIBANA-WARNING" : "Warning", "KIBANA-NO_DEFAULT_INDEX_PATTERN" : "No default index pattern. You must select or create one to continue.", - "KIBANA-LOADING": "Loading", - "KIBANA-INDICES_MATCH_PATTERN" : "Unable to fetch mapping. Do you have indices matching the pattern?", - "KIBANA-ADD_NEW" : "Create Index Pattern", - "KIBANA-SEE" : "See", - "KIBANA-CREATE" : "Create", - "KIBANA-FIELD_IS_REQUIRED": "{{fieldName}} is required" + "KIBANA-CREATE_INDEX_PATTERN_BUTTON" : "Create Index Pattern" } diff --git a/src/ui/public/directives/__tests__/validate_index_name.js b/src/ui/public/directives/__tests__/validate_index_pattern.js similarity index 91% rename from src/ui/public/directives/__tests__/validate_index_name.js rename to src/ui/public/directives/__tests__/validate_index_pattern.js index 72667f91a89f6..6ac547cb74e92 100644 --- a/src/ui/public/directives/__tests__/validate_index_name.js +++ b/src/ui/public/directives/__tests__/validate_index_pattern.js @@ -1,14 +1,14 @@ import expect from 'expect.js'; import ngMock from 'ng_mock'; -import 'ui/directives/validate_index_name'; +import 'ui/directives/validate_index_pattern'; // Load the kibana app dependencies. -describe('Validate index name directive', function () { +describe('Validate index pattern directive', function () { let $compile; let $rootScope; - const noWildcardHtml = ''; - const allowWildcardHtml = ''; + const noWildcardHtml = ''; + const allowWildcardHtml = ''; beforeEach(ngMock.module('kibana')); diff --git a/src/ui/public/directives/info.js b/src/ui/public/directives/info.js index ee0ccbf1eb0ef..5099c72fba922 100644 --- a/src/ui/public/directives/info.js +++ b/src/ui/public/directives/info.js @@ -1,4 +1,4 @@ -import html from 'ui/partials/info.html'; +import template from 'ui/partials/info.html'; import { uiModules } from 'ui/modules'; uiModules @@ -10,7 +10,7 @@ uiModules info: '@', placement: '@' }, - template: html, + template, link: function ($scope) { $scope.placement = $scope.placement || 'top'; } diff --git a/src/ui/public/directives/validate_index_name.js b/src/ui/public/directives/validate_index_pattern.js similarity index 73% rename from src/ui/public/directives/validate_index_name.js rename to src/ui/public/directives/validate_index_pattern.js index 9d727885f5272..9c3c29d8d55c6 100644 --- a/src/ui/public/directives/validate_index_name.js +++ b/src/ui/public/directives/validate_index_pattern.js @@ -4,13 +4,17 @@ import { uiModules } from 'ui/modules'; uiModules .get('kibana') - .directive('validateIndexName', function () { + .directive('validateIndexPattern', function () { return { restrict: 'A', require: 'ngModel', link: function ($scope, elem, attr, ngModel) { const illegalCharacters = ['\\', '/', '?', '"', '<', '>', '|', ' ', ',']; - const allowWildcard = !_.isUndefined(attr.allowWildcard) && attr.allowWildcard !== 'false'; + + const allowWildcard = + !_.isUndefined(attr.validateIndexPatternAllowWildcard) + && attr.validateIndexPatternAllowWildcard !== 'false'; + if (!allowWildcard) { illegalCharacters.push('*'); } @@ -24,7 +28,7 @@ uiModules return !match; }; - ngModel.$validators.indexNameInput = function (modelValue, viewValue) { + ngModel.$validators.indexPattern = function (modelValue, viewValue) { return isValid(viewValue); }; } diff --git a/src/ui/public/documentation_links/documentation_links.js b/src/ui/public/documentation_links/documentation_links.js index 4c8c72bbe0ee5..70989a24a4c4f 100644 --- a/src/ui/public/documentation_links/documentation_links.js +++ b/src/ui/public/documentation_links/documentation_links.js @@ -21,6 +21,10 @@ export const documentationLinks = { painlessSyntax: `${ELASTIC_WEBSITE_URL}guide/en/elasticsearch/reference/${DOC_LINK_VERSION}/modules-scripting-painless-syntax.html`, luceneExpressions: `${ELASTIC_WEBSITE_URL}guide/en/elasticsearch/reference/${DOC_LINK_VERSION}/modules-scripting-expression.html` }, + indexPatterns: { + loadingData: `${ELASTIC_WEBSITE_URL}guide/en/kibana/${DOC_LINK_VERSION}/tutorial-load-dataset.html`, + introduction: `${ELASTIC_WEBSITE_URL}guide/en/kibana/${DOC_LINK_VERSION}/index-patterns.html`, + }, query: { luceneQuerySyntax: `${ELASTIC_WEBSITE_URL}guide/en/elasticsearch/reference/${DOC_LINK_VERSION}/query-dsl-query-string-query.html#query-string-syntax`, diff --git a/src/ui/public/partials/info.html b/src/ui/public/partials/info.html index 01a0670fb7a6a..65091ced75b09 100644 --- a/src/ui/public/partials/info.html +++ b/src/ui/public/partials/info.html @@ -1,4 +1,10 @@ - \ No newline at end of file + diff --git a/test/functional/apps/management/_create_index_pattern_wizard.js b/test/functional/apps/management/_create_index_pattern_wizard.js new file mode 100644 index 0000000000000..0637fbb548ac6 --- /dev/null +++ b/test/functional/apps/management/_create_index_pattern_wizard.js @@ -0,0 +1,37 @@ +import expect from 'expect.js'; + +export default function ({ getService, getPageObjects }) { + const kibanaServer = getService('kibanaServer'); + const PageObjects = getPageObjects(['settings', 'common']); + + describe('"Create Index Pattern" wizard', function () { + beforeEach(function () { + // delete .kibana index and then wait for Kibana to re-create it + return kibanaServer.uiSettings.replace({}) + .then(function () { + return PageObjects.settings.navigateTo(); + }) + .then(function () { + return PageObjects.settings.clickKibanaIndices(); + }); + }); + + describe('step 1 next button', function () { + it('is disabled by default', function () { + return PageObjects.settings.getCreateIndexPatternGoToStep2Button().isEnabled() + .then(function (isEnabled) { + expect(isEnabled).not.to.be.ok(); + }); + }); + + it('is enabled once an index pattern with matching indices has been entered', async function () { + await PageObjects.settings.setIndexPatternField(); + await PageObjects.common.sleep(2000); + return PageObjects.settings.getCreateIndexPatternGoToStep2Button().isEnabled() + .then(function (isEnabled) { + expect(isEnabled).to.be.ok(); + }); + }); + }); + }); +} diff --git a/test/functional/apps/management/_creation_form_changes.js b/test/functional/apps/management/_creation_form_changes.js deleted file mode 100644 index 66bafe4bebd26..0000000000000 --- a/test/functional/apps/management/_creation_form_changes.js +++ /dev/null @@ -1,32 +0,0 @@ -import expect from 'expect.js'; - -export default function ({ getService, getPageObjects }) { - const kibanaServer = getService('kibanaServer'); - const screenshots = getService('screenshots'); - const PageObjects = getPageObjects(['settings', 'common']); - - describe('user input reactions', function () { - beforeEach(function () { - // delete .kibana index and then wait for Kibana to re-create it - return kibanaServer.uiSettings.replace({}) - .then(function () { - return PageObjects.settings.navigateTo(); - }) - .then(function () { - return PageObjects.settings.clickKibanaIndices(); - }); - }); - - it('should enable creation after selecting time field', function () { - // select a time field and check that Create button is enabled - return PageObjects.settings.selectTimeFieldOption('@timestamp') - .then(function () { - return PageObjects.settings.getCreateButton().isEnabled() - .then(function (enabled) { - screenshots.take('Settings-indices-enable-creation'); - expect(enabled).to.be.ok(); - }); - }); - }); - }); -} diff --git a/test/functional/apps/management/_index_pattern_create_delete.js b/test/functional/apps/management/_index_pattern_create_delete.js index 5f55e744c94b5..523c763bdacf9 100644 --- a/test/functional/apps/management/_index_pattern_create_delete.js +++ b/test/functional/apps/management/_index_pattern_create_delete.js @@ -82,7 +82,7 @@ export default function ({ getService, getPageObjects }) { it('should return to index pattern creation page', function returnToPage() { return retry.try(function tryingForTime() { - return PageObjects.settings.getCreateButton(); + return PageObjects.settings.getCreateIndexPatternGoToStep2Button(); }); }); diff --git a/test/functional/apps/management/_initial_state.js b/test/functional/apps/management/_initial_state.js deleted file mode 100644 index 50601a33f3462..0000000000000 --- a/test/functional/apps/management/_initial_state.js +++ /dev/null @@ -1,44 +0,0 @@ -import expect from 'expect.js'; - -export default function ({ getService, getPageObjects }) { - const kibanaServer = getService('kibanaServer'); - const log = getService('log'); - const PageObjects = getPageObjects(['settings', 'common']); - - describe('initial state', function () { - before(function () { - // delete .kibana index and then wait for Kibana to re-create it - return kibanaServer.uiSettings.replace({}) - .then(function () { - return PageObjects.settings.navigateTo(); - }) - .then(function () { - return PageObjects.settings.clickKibanaIndices(); - }); - }); - - it('should contain default index pattern', function () { - const defaultPattern = 'logstash-*'; - - return PageObjects.settings.getIndexPatternField().getProperty('value') - .then(function (pattern) { - expect(pattern).to.be(defaultPattern); - }); - }); - - it('should not select the time field', function () { - return PageObjects.settings.getTimeFieldNameField().isSelected() - .then(function (timeFieldIsSelected) { - log.debug('timeField isSelected = ' + timeFieldIsSelected); - expect(timeFieldIsSelected).to.not.be.ok(); - }); - }); - - it('should not enable creation', function () { - return PageObjects.settings.getCreateIndexPatternButton().isEnabled() - .then(function (enabled) { - expect(enabled).to.not.be.ok(); - }); - }); - }); -} diff --git a/test/functional/apps/management/index.js b/test/functional/apps/management/index.js index afaea2d42cff7..df5de51c23572 100644 --- a/test/functional/apps/management/index.js +++ b/test/functional/apps/management/index.js @@ -15,8 +15,7 @@ export default function ({ getService, loadTestFile }) { await esArchiver.unload('empty_kibana'); }); - loadTestFile(require.resolve('./_initial_state')); - loadTestFile(require.resolve('./_creation_form_changes')); + loadTestFile(require.resolve('./_create_index_pattern_wizard')); loadTestFile(require.resolve('./_index_pattern_create_delete')); loadTestFile(require.resolve('./_index_pattern_results_sort')); loadTestFile(require.resolve('./_index_pattern_popularity')); diff --git a/test/functional/page_objects/settings_page.js b/test/functional/page_objects/settings_page.js index 533c9d2374a6d..518b5ba648cb0 100644 --- a/test/functional/page_objects/settings_page.js +++ b/test/functional/page_objects/settings_page.js @@ -89,15 +89,6 @@ export function SettingsPageProvider({ getService, getPageObjects }) { .findDisplayedByCssSelector('option[label="' + selection + '"]'); } - getCreateIndexPatternButton() { - return testSubjects.find('createIndexPatternCreateButton'); - } - - getCreateButton() { - return remote.setFindTimeout(defaultFindTimeout) - .findDisplayedByCssSelector('[type="submit"]'); - } - async clickDefaultIndexButton() { await testSubjects.find('setDefaultIndexPatternButton').click(); await PageObjects.header.waitUntilLoadingHasFinished(); @@ -272,13 +263,16 @@ export function SettingsPageProvider({ getService, getPageObjects }) { await PageObjects.header.waitUntilLoadingHasFinished(); } - async createIndexPattern(indexPatternName = 'logstash-*', timefield = '@timestamp') { + async createIndexPattern(indexPatternName, timefield = '@timestamp') { await retry.try(async () => { await this.navigateTo(); await this.clickKibanaIndices(); await this.setIndexPatternField(indexPatternName); + await PageObjects.common.sleep(2000); + await this.getCreateIndexPatternGoToStep2Button().click(); + await PageObjects.common.sleep(2000); await this.selectTimeFieldOption(timefield); - await this.getCreateButton().click(); + await this.getCreateIndexPatternCreateButton().click(); }); await PageObjects.header.waitUntilLoadingHasFinished(); await retry.try(async () => { @@ -292,12 +286,19 @@ export function SettingsPageProvider({ getService, getPageObjects }) { }); } - async setIndexPatternField(pattern) { - log.debug(`setIndexPatternField(${pattern})`); - return testSubjects.find('createIndexPatternNameInput') - .clearValue().type(pattern); + async setIndexPatternField(indexPatternName = 'logstash-*') { + log.debug(`setIndexPatternField(${indexPatternName})`); + return this.getIndexPatternField() + .clearValue().type(indexPatternName); + } + + getCreateIndexPatternGoToStep2Button() { + return testSubjects.find('createIndexPatternGoToStep2Button'); } + getCreateIndexPatternCreateButton() { + return testSubjects.find('createIndexPatternCreateButton'); + } async removeIndexPattern() { let alertText; diff --git a/ui_framework/components/info_button/_info_button.scss b/ui_framework/components/info_button/_info_button.scss index 104dbb9d7cbde..0bd55d7506ddc 100644 --- a/ui_framework/components/info_button/_info_button.scss +++ b/ui_framework/components/info_button/_info_button.scss @@ -1,5 +1,6 @@ .kuiInfoButton { font-size: 16px; + line-height: 0; background-color: transparent; color: $globalLinkColor; cursor: pointer; diff --git a/ui_framework/components/panel/_panel.scss b/ui_framework/components/panel/_panel.scss index cf8e398fab2fb..bd0e55b41f563 100644 --- a/ui_framework/components/panel/_panel.scss +++ b/ui_framework/components/panel/_panel.scss @@ -3,12 +3,29 @@ border-radius: $globalBorderRadius; } +.kuiPanel--prompt { + display: flex; + flex-direction: column; + align-items: center; + text-align: center; + justify-content: center; + min-height: 300px; + + .kuiPanelBody { + padding: 30px; + max-width: 500px; + } +} + +.kuiPanel--noBorder { + border: none; +} + .kuiPanel--withToolBar { border-top: none; border-radius: 0; } - .kuiPanel--centered { display: flex; justify-content: center; @@ -25,9 +42,13 @@ border-bottom: $globalBorderThin; } + /** + * 1. This way we can use h1, h2, etc. + */ .kuiPanelHeader__title { font-size: $globalTitleFontSize; line-height: $globalLineHeight; + margin: 0; /* 1 */ } /** diff --git a/ui_framework/components/table/_controlled_table.scss b/ui_framework/components/table/_controlled_table.scss index 57993e52bdced..8d8d241685bad 100644 --- a/ui_framework/components/table/_controlled_table.scss +++ b/ui_framework/components/table/_controlled_table.scss @@ -1,5 +1,5 @@ /** - * 1. Make seamless transition from ToolBar to Table header. + * 1. Make seamless transition from ToolBar to Table header and contained Menu. * 1. Make seamless transition from Table to ToolBarFooter header. */ .kuiControlledTable { @@ -10,4 +10,8 @@ .kuiToolBarFooter { border-top: none; /* 2 */ } + + .kuiMenu--contained { + border-top: none; /* 1 */ + } } diff --git a/ui_framework/dist/ui_framework.css b/ui_framework/dist/ui_framework.css index 9938b1eb38df5..99b2785037246 100644 --- a/ui_framework/dist/ui_framework.css +++ b/ui_framework/dist/ui_framework.css @@ -1450,6 +1450,7 @@ body { .kuiInfoButton { font-size: 16px; + line-height: 0; background-color: transparent; color: #0079a5; cursor: pointer; @@ -2568,6 +2569,33 @@ body { border: 1px solid #D9D9D9; border-radius: 4px; } +.kuiPanel--prompt { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + -webkit-box-align: center; + -webkit-align-items: center; + -ms-flex-align: center; + align-items: center; + text-align: center; + -webkit-box-pack: center; + -webkit-justify-content: center; + -ms-flex-pack: center; + justify-content: center; + min-height: 300px; } + .kuiPanel--prompt .kuiPanelBody { + padding: 30px; + max-width: 500px; } + +.kuiPanel--noBorder { + border: none; } + .kuiPanel--withToolBar { border-top: none; border-radius: 0; } @@ -2644,9 +2672,14 @@ body { outline: none; border-color: #0079a5; } +/** + * 1. This way we can use h1, h2, etc. + */ .kuiPanelHeader__title { font-size: 18px; - line-height: 1.5; } + line-height: 1.5; + margin: 0; + /* 1 */ } /** * 1. Undo what barSection mixin does. @@ -2759,7 +2792,7 @@ body { /* 2 */ } /** - * 1. Make seamless transition from ToolBar to Table header. + * 1. Make seamless transition from ToolBar to Table header and contained Menu. * 1. Make seamless transition from Table to ToolBarFooter header. */ .kuiControlledTable .kuiTable { @@ -2770,6 +2803,10 @@ body { border-top: none; /* 2 */ } +.kuiControlledTable .kuiMenu--contained { + border-top: none; + /* 1 */ } + /** * 1. Prevent cells from expanding based on content size. This substitutes for table-layout: fixed. */ From 4a73c23970dc958cd6d76fa716ef4b15b8b7bf0a Mon Sep 17 00:00:00 2001 From: CJ Cenizal Date: Thu, 6 Jul 2017 13:16:36 -0700 Subject: [PATCH 2/9] Remove all translations. --- .../create_index_pattern_wizard.html | 54 +++++++++-------- .../create_index_pattern_wizard.js | 9 ++- .../matching_indices_list.html | 14 ++--- .../step_index_pattern.html | 24 ++++---- .../step_time_field/step_time_field.html | 60 ++++++++++--------- .../step_time_field/step_time_field.js | 6 +- .../edit_index_pattern.html | 3 +- .../management/sections/indices/index.html | 7 ++- src/core_plugins/kibana/translations/en.json | 37 +----------- 9 files changed, 89 insertions(+), 125 deletions(-) diff --git a/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/create_index_pattern_wizard.html b/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/create_index_pattern_wizard.html index 9a5a543ce988c..32043dcc26f6f 100644 --- a/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/create_index_pattern_wizard.html +++ b/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/create_index_pattern_wizard.html @@ -8,10 +8,9 @@
-

+

+ Create index pattern +

@@ -26,18 +25,16 @@ ng-change="controller.onIncludeSystemIndicesChange()" > - + + Include system indices +
-

+

+ Kibana uses index patterns to retrieve data from Elasticsearch, for things like visualizations. +

@@ -52,10 +49,9 @@ class="kuiPanel kuiPanel--prompt kuiPanel--noBorder kuiVerticalRhythm" >
-

+

+ Checking for Elasticsearch data +

@@ -64,7 +60,9 @@ aria-hidden="true" class="kuiStatusText__icon kuiIcon fa-spinner fa-spin" > - + + Reticulating splines... +

@@ -75,21 +73,23 @@
-

+

+ Couldn't find any Elasticsearch data +

- + + You'll need to index some data into Elasticsearch before you can create an index pattern. + + > + Learn how. +

@@ -102,7 +102,9 @@ aria-hidden="true" class="kuiButton__icon kuiIcon fa-refresh" > - + + Check for new data +
diff --git a/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/create_index_pattern_wizard.js b/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/create_index_pattern_wizard.js index 490491ee96d2d..eef82bbac6046 100644 --- a/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/create_index_pattern_wizard.js +++ b/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/create_index_pattern_wizard.js @@ -23,7 +23,6 @@ uiModules.get('apps/management') $injector, $scope, $timeout, - $translate, config, es, indexPatterns, @@ -43,7 +42,7 @@ uiModules.get('apps/management') display: '───', }; const noTimeFieldOption = { - display: $translate.instant('KIBANA-CREATE_INDEX_PATTERN_STEP_2_NO_DATE_FIELD_OPTION') + display: `I don't want to use the Time Filter`, }; this.documentationLinks = documentationLinks; @@ -202,7 +201,7 @@ uiModules.get('apps/management') if (dateFields.length === 0) { return [{ - display: $translate.instant('KIBANA-CREATE_INDEX_PATTERN_STEP_2_NO_TIME_FIELDS') + display: `The indices which match this index pattern don't contain any time fields.`, }]; } @@ -230,7 +229,7 @@ uiModules.get('apps/management') }) .catch(err => { if (err instanceof IndexPatternMissingIndices) { - this.timeFieldError = $translate.instant('KIBANA-CREATE_INDEX_PATTERN_STEP_2_NO_MAPPING_ERROR'); + this.timeFieldError = 'Unable to fetch mapping. Do you have indices matching the pattern?'; } notify.error(err); @@ -277,7 +276,7 @@ uiModules.get('apps/management') }); }).catch(err => { if (err instanceof IndexPatternMissingIndices) { - return notify.error($translate.instant('KIBANA-CREATE_INDEX_PATTERN_STEP_2_INDICES_DONT_MATCH_PATTERN')); + return notify.error(`Couldn't locate any indices matching that pattern. Please add the index to Elasticsearch`); } notify.fatal(err); diff --git a/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/matching_indices_list/matching_indices_list.html b/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/matching_indices_list/matching_indices_list.html index 12fa95821c3da..f911b06758a92 100644 --- a/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/matching_indices_list/matching_indices_list.html +++ b/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/matching_indices_list/matching_indices_list.html @@ -4,16 +4,14 @@ class="kuiPanel kuiPanel--prompt kuiVerticalRhythm matchingIndicesListLoadingPrompt" >
-

+

+ Looking for matching indices +

-

+

+ Just a sec... +

diff --git a/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/step_index_pattern/step_index_pattern.html b/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/step_index_pattern/step_index_pattern.html index 634eb83be461e..d53286fba32c4 100644 --- a/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/step_index_pattern/step_index_pattern.html +++ b/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/step_index_pattern/step_index_pattern.html @@ -1,10 +1,9 @@
-

+

+ Step 1 of 2: Define index pattern +

@@ -22,8 +21,9 @@ + > + Index pattern +
- + + Next step +
@@ -76,13 +78,15 @@ is-collapsed="!stepTimeField.isAdvancedOptionsVisible" on-toggle="stepTimeField.onToggleAdvancedOptions" button-text="{{stepTimeField.getAdvancedOptionsButtonLabel()}}" + button-text="Advanced Time Field filter options" > + > + Expand index pattern (DEPRECATED) + @@ -103,20 +107,17 @@ id="expandIndexPatternCheckBoxHelpText" class="kuiVerticalRhythm" > -

+

+ With this option selected, searches against any time-based index pattern which contains a wildcard will automatically expand to query only the indices which contain data within the currently selected time range. +

-

+

+ Searching against the index pattern 'logstash-*' will actually query Elasticsearch for the specific matching indices (e.g. 'logstash-2015.12.21') that fall within the current time range. +

-

+

+ With recent changes to Elasticsearch, this option should no longer be necessary and will likely be removed in future versions of Kibana. +

@@ -130,7 +131,7 @@ > - + Back @@ -139,8 +140,9 @@ ng-disabled="!stepTimeField.canCreateIndexPattern()" class="kuiButton kuiButton--primary" type="submit" - translate="KIBANA-CREATE_INDEX_PATTERN_STEP_2_SUBMIT_BUTTON" - > + > + Create index pattern +
diff --git a/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/step_time_field/step_time_field.js b/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/step_time_field/step_time_field.js index bd46828ce4122..209f141b54aa3 100644 --- a/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/step_time_field/step_time_field.js +++ b/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/step_time_field/step_time_field.js @@ -6,7 +6,7 @@ import { documentationLinks } from 'ui/documentation_links/documentation_links'; const module = uiModules.get('apps/management'); -module.directive('stepTimeField', function ($translate) { +module.directive('stepTimeField', function () { return { restrict: 'E', template, @@ -37,10 +37,6 @@ module.directive('stepTimeField', function ($translate) { this.matchingIndicesListType = 'noMatches'; this.documentationLinks = documentationLinks; - this.getAdvancedOptionsButtonLabel = () => { - return $translate.instant('KIBANA-CREATE_INDEX_PATTERN_STEP_2_ADVANCED_OPTIONS_BUTTON'); - }; - this.onToggleAdvancedOptions = () => { this.isAdvancedOptionsVisible = !this.isAdvancedOptionsVisible; }; diff --git a/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/edit_index_pattern.html b/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/edit_index_pattern.html index cd47475efafa4..a63714d1bc23b 100644 --- a/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/edit_index_pattern.html +++ b/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/edit_index_pattern.html @@ -15,7 +15,8 @@

- : {{indexPattern.timeFieldName}} + + Time Filter field name: {{indexPattern.timeFieldName}}

diff --git a/src/core_plugins/kibana/public/management/sections/indices/index.html b/src/core_plugins/kibana/public/management/sections/indices/index.html index b0b9bcbd4f0a4..05acbf52c320f 100644 --- a/src/core_plugins/kibana/public/management/sections/indices/index.html +++ b/src/core_plugins/kibana/public/management/sections/indices/index.html @@ -6,10 +6,9 @@
ng-if="editingId" href="#/management/kibana/index" class="kuiButton kuiButton--primary kuiButton--small" - aria-label="{{ 'KIBANA-CREATE_INDEX_PATTERN_BUTTON' | translate }}" > - + Create Index Pattern
@@ -20,7 +19,9 @@
> diff --git a/src/core_plugins/kibana/translations/en.json b/src/core_plugins/kibana/translations/en.json index e2824c99b3a27..ce01f2c8a8a4e 100644 --- a/src/core_plugins/kibana/translations/en.json +++ b/src/core_plugins/kibana/translations/en.json @@ -1,40 +1,5 @@ { "UI-WELCOME_MESSAGE": "Loading Kibana", "UI-WELCOME_ERROR": "Kibana did not load properly. Check the server output for more information.", - "KIBANA-CREATE_INDEX_PATTERN_TITLE": "Create index pattern", - "KIBANA-CREATE_INDEX_PATTERN_INTRO": "Kibana uses index patterns to retrieve data from Elasticsearch, for things like visualizations.", - "KIBANA-CREATE_INDEX_PATTERN_INCLUDE_SYSTEM_INDICES_CHECKBOX_LABEL": "Include system indices", - "KIBANA-CREATE_INDEX_PATTERN_LOADING_DATA_TITLE": "Checking for Elasticsearch data", - "KIBANA-CREATE_INDEX_PATTERN_LOADING_DATA_BODY": "Reticulating splines...", - "KIBANA-CREATE_INDEX_PATTERN_NO_DATA_TITLE": "Couldn't find any Elasticsearch data", - "KIBANA-CREATE_INDEX_PATTERN_NO_DATA_BODY": "You'll need to index some data into Elasticsearch before you can create an index pattern.", - "KIBANA-CREATE_INDEX_PATTERN_NO_DATA_LEARN_LINK": "Learn how.", - "KIBANA-CREATE_INDEX_PATTERN_NO_DATA_LEARN_LINK_ALT": "Learn how to index data into Elasticsearch", - "KIBANA-CREATE_INDEX_PATTERN_NO_DATA_RELOAD_BUTTON": "Check for new data", - "KIBANA-CREATE_INDEX_PATTERN_STEP_1_TITLE": "Step 1 of 2: Define index pattern", - "KIBANA-CREATE_INDEX_PATTERN_STEP_1_INDEX_PATTERN_LABEL": "Index pattern", - "KIBANA-CREATE_INDEX_PATTERN_STEP_1_SEARCH_SINGLE_INDEX": "You only have a single index. You can create an index pattern to match it.", - "KIBANA-CREATE_INDEX_PATTERN_STEP_1_SEARCHING_TITLE": "Looking for matching indices", - "KIBANA-CREATE_INDEX_PATTERN_STEP_1_SEARCHING_BODY": "Just a sec...", - "KIBANA-CREATE_INDEX_PATTERN_STEP_1_SUBMIT_BUTTON" : "Next step", - "KIBANA-CREATE_INDEX_PATTERN_STEP_2_TITLE": "Step 2 of 2: Optional settings", - "KIBANA-CREATE_INDEX_PATTERN_STEP_2_TIME_FIELD_LABEL": "Choose optional Time Filter field name", - "KIBANA-CREATE_INDEX_PATTERN_STEP_2_TIME_FIELD_LOADING": "Please wait while we fetch your time field options", - "KIBANA-CREATE_INDEX_PATTERN_STEP_2_TIME_FIELD_HELP": "The Time Filter will use this field to filter your data by time.", - "KIBANA-CREATE_INDEX_PATTERN_STEP_2_ADVANCED_OPTIONS_BUTTON": "Advanced Time Field filter options", - "KIBANA-CREATE_INDEX_PATTERN_STEP_2_EXPAND_LABEL": "Expand index pattern (DEPRECATED)", - "KIBANA-CREATE_INDEX_PATTERN_STEP_2_EXPAND_CHECKBOX_LABEL": "Expand index pattern when searching", - "KIBANA-CREATE_INDEX_PATTERN_STEP_2_EXPAND_HELP_1": "With this option selected, searches against any time-based index pattern which contains a wildcard will automatically expand to query only the indices which contain data within the currently selected time range.", - "KIBANA-CREATE_INDEX_PATTERN_STEP_2_EXPAND_HELP_2": "Searching against the index pattern 'logstash-*' will actually query Elasticsearch for the specific matching indices (e.g. 'logstash-2015.12.21') that fall within the current time range.", - "KIBANA-CREATE_INDEX_PATTERN_STEP_2_EXPAND_HELP_3": "With recent changes to Elasticsearch, this option should no longer be necessary and will likely be removed in future versions of Kibana.", - "KIBANA-CREATE_INDEX_PATTERN_STEP_2_NO_DATE_FIELD_OPTION": "I don't want to use the Time Filter", - "KIBANA-CREATE_INDEX_PATTERN_STEP_2_REFRESH_FIELDS_BUTTON": "Refresh", - "KIBANA-CREATE_INDEX_PATTERN_STEP_2_NO_TIME_FIELDS": "The indices which match this index pattern don't contain any time fields.", - "KIBANA-CREATE_INDEX_PATTERN_STEP_2_INDICES_DONT_MATCH_PATTERN": "Could not locate any indices matching that pattern. Please add the index to Elasticsearch", - "KIBANA-CREATE_INDEX_PATTERN_STEP_2_BACK_BUTTON" : "Back", - "KIBANA-CREATE_INDEX_PATTERN_STEP_2_SUBMIT_BUTTON" : "Create index pattern", - "KIBANA-CREATE_INDEX_PATTERN_STEP_2_NO_MAPPING_ERROR" : "Unable to fetch mapping. Do you have indices matching the pattern?", - "KIBANA-WARNING" : "Warning", - "KIBANA-NO_DEFAULT_INDEX_PATTERN" : "No default index pattern. You must select or create one to continue.", - "KIBANA-CREATE_INDEX_PATTERN_BUTTON" : "Create Index Pattern" + "KIBANA-WARNING" : "Warning" } From c00e7b1e7be47e068335ba370cf81fda1f65f396 Mon Sep 17 00:00:00 2001 From: CJ Cenizal Date: Thu, 6 Jul 2017 13:24:09 -0700 Subject: [PATCH 3/9] Fix typos in disallowed index pattern characters. --- .../step_index_pattern/step_index_pattern.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/step_index_pattern/step_index_pattern.html b/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/step_index_pattern/step_index_pattern.html index d53286fba32c4..12c03337f40bc 100644 --- a/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/step_index_pattern/step_index_pattern.html +++ b/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/step_index_pattern/step_index_pattern.html @@ -52,7 +52,7 @@

id="indexPatternNameFieldHelp2" class="kuiText kuiSubduedText" > - You can't use empty spaces or the characters \\ / ? \" < > , |. + You can't use empty spaces or the characters \ / ? " < > , |.

From 7db6da3628daa35c7ae199f61b1e64e4577c3b66 Mon Sep 17 00:00:00 2001 From: CJ Cenizal Date: Thu, 6 Jul 2017 13:28:04 -0700 Subject: [PATCH 4/9] Make 'Expand index pattern' deprecation notice more apparent. --- .../step_time_field/step_time_field.html | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/step_time_field/step_time_field.html b/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/step_time_field/step_time_field.html index fa732337a0cfc..9ced2d1cf9893 100644 --- a/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/step_time_field/step_time_field.html +++ b/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/step_time_field/step_time_field.html @@ -107,16 +107,16 @@

id="expandIndexPatternCheckBoxHelpText" class="kuiVerticalRhythm" > -

- With this option selected, searches against any time-based index pattern which contains a wildcard will automatically expand to query only the indices which contain data within the currently selected time range. +

+ Recent changes to Elasticsearch have made this option largerly unnecessary. It will likely be removed in a future version of Kibana.

- Searching against the index pattern 'logstash-*' will actually query Elasticsearch for the specific matching indices (e.g. 'logstash-2015.12.21') that fall within the current time range. + With this option selected, searches against any time-based index pattern which contains a wildcard will automatically expand to query only the indices which contain data within the currently selected time range.

- With recent changes to Elasticsearch, this option should no longer be necessary and will likely be removed in future versions of Kibana. + Searching against the index pattern 'logstash-*' will actually query Elasticsearch for the specific matching indices (e.g. 'logstash-2015.12.21') that fall within the current time range.

From ffc879f521c510cbc0ccb53a56d38c2c73ca99c4 Mon Sep 17 00:00:00 2001 From: CJ Cenizal Date: Thu, 6 Jul 2017 13:34:39 -0700 Subject: [PATCH 5/9] Update UI when errors within array change. --- .../step_index_pattern/step_index_pattern.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/step_index_pattern/step_index_pattern.js b/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/step_index_pattern/step_index_pattern.js index 3f4f089169929..854e27aca8891 100644 --- a/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/step_index_pattern/step_index_pattern.js +++ b/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/step_index_pattern/step_index_pattern.js @@ -36,7 +36,7 @@ module.directive('stepIndexPattern', function () { // If the index pattern name is invalid, we should reflect that state in the list. scope.stepIndexPattern.updateList(); }); - scope.$watch('stepIndexPattern.indexPatternNameForm.$error', () => { + scope.$watchCollection('stepIndexPattern.indexPatternNameForm.$error', () => { // If we immediately replace the input with an invalid string, then only the form state // changes, but not the `indexPatternName` value, so we need to watch both. scope.stepIndexPattern.updateList(); From caaf63d92b5b0611bbcea224a2e2869cfa4df1e2 Mon Sep 17 00:00:00 2001 From: CJ Cenizal Date: Thu, 6 Jul 2017 14:06:57 -0700 Subject: [PATCH 6/9] Remove unused time field error. --- .../create_index_pattern_wizard.js | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/create_index_pattern_wizard.js b/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/create_index_pattern_wizard.js index eef82bbac6046..d93673009eb58 100644 --- a/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/create_index_pattern_wizard.js +++ b/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/create_index_pattern_wizard.js @@ -64,7 +64,6 @@ uiModules.get('apps/management') this.isFetchingTimeFieldOptions = false; this.isCreatingIndexPattern = false; this.doesIncludeSystemIndices = false; - this.timeFieldError = undefined; let allIndices = []; let matchingIndices = []; let partialMatchingIndices = []; @@ -228,10 +227,6 @@ uiModules.get('apps/management') this.timeFieldOptions = extractTimeFieldsFromFields(fields); }) .catch(err => { - if (err instanceof IndexPatternMissingIndices) { - this.timeFieldError = 'Unable to fetch mapping. Do you have indices matching the pattern?'; - } - notify.error(err); }) .finally(() => { From a86fddd5791ad1066fa6eb73c4a1b876c18edaa0 Mon Sep 17 00:00:00 2001 From: CJ Cenizal Date: Tue, 11 Jul 2017 12:10:58 -0700 Subject: [PATCH 7/9] Update getIndices to support cross-cluster search. --- .../create_index_pattern_wizard.js | 19 +++++-- .../matching_indices_list.html | 2 +- src/ui/public/indices/get_indices.js | 57 +++++++++++-------- 3 files changed, 46 insertions(+), 32 deletions(-) diff --git a/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/create_index_pattern_wizard.js b/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/create_index_pattern_wizard.js index d93673009eb58..8dc091ca2695e 100644 --- a/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/create_index_pattern_wizard.js +++ b/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/create_index_pattern_wizard.js @@ -31,6 +31,7 @@ uiModules.get('apps/management') Private, Promise ) { + const MAX_NUMBER_OF_MATCHING_INDICES = 3; const indicesService = $injector.get('indices'); const notify = new Notifier(); const refreshKibanaIndex = Private(RefreshKibanaIndex); @@ -92,7 +93,7 @@ uiModules.get('apps/management') // All system indices begin with a period. return indices.filter(index => ( - index.indexOf('.') !== 0 + index.name.indexOf('.') !== 0 )); }; @@ -123,8 +124,8 @@ uiModules.get('apps/management') } const thisFetchMatchingIndicesRequest = mostRecentFetchMatchingIndicesRequest = Promise.all([ - indicesService.getIndices(exactSearchQuery), - indicesService.getIndices(partialSearchQuery), + indicesService.getIndices(exactSearchQuery, MAX_NUMBER_OF_MATCHING_INDICES), + indicesService.getIndices(partialSearchQuery, MAX_NUMBER_OF_MATCHING_INDICES), createReasonableWait(), ]) .then(([ @@ -137,13 +138,17 @@ uiModules.get('apps/management') updateWhiteListedIndices(); this.isFetchingMatchingIndices = false; } + }).catch(error => { + notify.error(error); }); }; this.fetchExistingIndices = () => { this.isFetchingExistingIndices = true; + const allExistingLocalAndRemoteIndicesPattern = '*,*:*'; + Promise.all([ - indicesService.getIndices('*'), + indicesService.getIndices(allExistingLocalAndRemoteIndicesPattern, MAX_NUMBER_OF_MATCHING_INDICES), createReasonableWait(), ]) .then(([allIndicesResponse]) => { @@ -151,6 +156,8 @@ uiModules.get('apps/management') allIndices = allIndicesResponse.sort(); updateWhiteListedIndices(); this.isFetchingExistingIndices = false; + }).catch(error => { + notify.error(error); }); }; @@ -226,8 +233,8 @@ uiModules.get('apps/management') .then(([fields]) => { this.timeFieldOptions = extractTimeFieldsFromFields(fields); }) - .catch(err => { - notify.error(err); + .catch(error => { + notify.error(error); }) .finally(() => { this.isFetchingTimeFieldOptions = false; diff --git a/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/matching_indices_list/matching_indices_list.html b/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/matching_indices_list/matching_indices_list.html index f911b06758a92..18d2d01e46a1a 100644 --- a/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/matching_indices_list/matching_indices_list.html +++ b/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/matching_indices_list/matching_indices_list.html @@ -54,7 +54,7 @@ ng-repeat="index in matchingIndicesList.pageOfIndices" >

- {{index}} + {{index.name}}

diff --git a/src/ui/public/indices/get_indices.js b/src/ui/public/indices/get_indices.js index 8218c07408e87..513f5755f74bd 100644 --- a/src/ui/public/indices/get_indices.js +++ b/src/ui/public/indices/get_indices.js @@ -1,34 +1,41 @@ -import { pluck, reduce, size } from 'lodash'; - export function IndicesGetIndicesProvider(esAdmin) { - const getIndexNamesFromAliasesResponse = json => { - // Assume this function won't be called in the event of a 404. - return reduce(json, (list, { aliases }, indexName) => { - list.push(indexName); - if (size(aliases) > 0) { - list.push(...Object.keys(aliases)); - } - return list; - }, []); - }; - - const getIndexNamesFromIndicesResponse = json => { - if (json.status === 404) { - return []; + return async function getIndices(indexPattern, maxNumberOfMatchingIndices) { + if (!indexPattern) { + throw new Error('Please provide an indexPattern string to getIndices().'); } - return pluck(json, 'index'); - }; + if (!maxNumberOfMatchingIndices || maxNumberOfMatchingIndices < 0) { + throw new Error('Please provide a maxNumberOfMatchingIndices value greater than 0 to getIndices().'); + } - return async function getIndices(query) { - const aliases = await esAdmin.indices.getAlias({ index: query, allowNoIndices: true, ignore: 404 }); + const result = await esAdmin.search({ + index: indexPattern, + ignore: [404], + body: { + size: 0, // no hits + aggs: { + indices: { + terms: { + field: '_index', + size: maxNumberOfMatchingIndices, + } + } + } + } + }); - // If aliases return 200, they'll include matching indices, too. - if (aliases.status === 404) { - const indices = await esAdmin.cat.indices({ index: query, format: 'json', ignore: 404 }); - return getIndexNamesFromIndicesResponse(indices); + if ( + result.status === 404 + || !result.aggregations + ) { + return []; } - return getIndexNamesFromAliasesResponse(aliases); + const indices = result.aggregations.indices.buckets.map(bucket => ({ + name: bucket.key, + docCount: bucket.doc_count, + })); + + return indices; }; } From 0619c4400b4f2b1e20ad5bdc4c6c2168ba5fa708 Mon Sep 17 00:00:00 2001 From: CJ Cenizal Date: Tue, 11 Jul 2017 12:12:29 -0700 Subject: [PATCH 8/9] Increase number of matching indices. --- .../create_index_pattern_wizard/create_index_pattern_wizard.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/create_index_pattern_wizard.js b/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/create_index_pattern_wizard.js index 8dc091ca2695e..57dfcb7f1c660 100644 --- a/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/create_index_pattern_wizard.js +++ b/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/create_index_pattern_wizard.js @@ -31,7 +31,7 @@ uiModules.get('apps/management') Private, Promise ) { - const MAX_NUMBER_OF_MATCHING_INDICES = 3; + const MAX_NUMBER_OF_MATCHING_INDICES = 20; const indicesService = $injector.get('indices'); const notify = new Notifier(); const refreshKibanaIndex = Private(RefreshKibanaIndex); From 763dfe84c44632a63ee19cf9b0a6e9091fc1ef67 Mon Sep 17 00:00:00 2001 From: CJ Cenizal Date: Tue, 11 Jul 2017 15:02:39 -0700 Subject: [PATCH 9/9] WIP --- .../create_index_pattern_wizard.js | 4 +- src/ui/public/indices/get_indices.js | 62 +++++++++++++++---- 2 files changed, 50 insertions(+), 16 deletions(-) diff --git a/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/create_index_pattern_wizard.js b/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/create_index_pattern_wizard.js index 57dfcb7f1c660..c0c0937ede0dc 100644 --- a/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/create_index_pattern_wizard.js +++ b/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/create_index_pattern_wizard.js @@ -92,9 +92,7 @@ uiModules.get('apps/management') } // All system indices begin with a period. - return indices.filter(index => ( - index.name.indexOf('.') !== 0 - )); + return indices.filter(index => !index.name.startsWith('.')); }; const updateWhiteListedIndices = () => { diff --git a/src/ui/public/indices/get_indices.js b/src/ui/public/indices/get_indices.js index 513f5755f74bd..d9d9a06aa94c4 100644 --- a/src/ui/public/indices/get_indices.js +++ b/src/ui/public/indices/get_indices.js @@ -1,3 +1,35 @@ +import { pluck, reduce, size } from 'lodash'; + +const getIndexNamesFromAliasesResponse = response => { + if (response.status === 404) { + return []; + } + + return reduce(response, (list, { aliases }, indexName) => { + if (size(aliases) > 0) { + list.push(...Object.keys(aliases).map(alias => ({ + name: alias, + }))); + } + + return list; + }, []); +}; + +const getIndexNamesFromSearchResponse = response => { + if ( + response.status === 404 + || !response.aggregations + ) { + return []; + } + + return response.aggregations.indices.buckets.map(bucket => ({ + name: bucket.key, + docCount: bucket.doc_count, + })); +}; + export function IndicesGetIndicesProvider(esAdmin) { return async function getIndices(indexPattern, maxNumberOfMatchingIndices) { if (!indexPattern) { @@ -8,9 +40,23 @@ export function IndicesGetIndicesProvider(esAdmin) { throw new Error('Please provide a maxNumberOfMatchingIndices value greater than 0 to getIndices().'); } - const result = await esAdmin.search({ + // Cross-cluster search query missing the index pattern part. + if (!indexPattern.split(':')[1]) { + return []; + } + + // const aliasesResponse = await esAdmin.indices.getAlias({ + // index: indexPattern, + // allowNoIndices: true, + // ignore: 404, + // }); + + const aliases = [];//getIndexNamesFromAliasesResponse(aliasesResponse); + + const searchResponse = await esAdmin.search({ index: indexPattern, ignore: [404], + allow_no_indices: true, body: { size: 0, // no hits aggs: { @@ -24,18 +70,8 @@ export function IndicesGetIndicesProvider(esAdmin) { } }); - if ( - result.status === 404 - || !result.aggregations - ) { - return []; - } - - const indices = result.aggregations.indices.buckets.map(bucket => ({ - name: bucket.key, - docCount: bucket.doc_count, - })); + const indices = getIndexNamesFromSearchResponse(searchResponse); - return indices; + return [...new Set([...aliases, ...indices])]; }; }