diff --git a/src/legacy/core_plugins/timelion/public/components/timelionhelp_tabs.js b/src/legacy/core_plugins/timelion/public/components/timelionhelp_tabs.js
new file mode 100644
index 00000000000000..833478ec974416
--- /dev/null
+++ b/src/legacy/core_plugins/timelion/public/components/timelionhelp_tabs.js
@@ -0,0 +1,63 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import PropTypes from 'prop-types';
+import React from 'react';
+
+import {
+ EuiTabs,
+ EuiTab
+} from '@elastic/eui';
+
+import { FormattedMessage } from '@kbn/i18n/react';
+
+function handleClick(activateTab, tabName) {
+ activateTab(tabName);
+}
+
+export function TimelionHelpTabs(props) {
+ return (
+
+ handleClick(props.activateTab, 'funcref')}
+ >
+
+
+ handleClick(props.activateTab, 'keyboardtips')}
+ >
+
+
+
+ );
+}
+
+TimelionHelpTabs.propTypes = {
+ activeTab: PropTypes.string.isRequired,
+ activateTab: PropTypes.func.isRequired
+};
+
diff --git a/src/legacy/core_plugins/timelion/public/components/timelionhelp_tabs_directive.js b/src/legacy/core_plugins/timelion/public/components/timelionhelp_tabs_directive.js
new file mode 100644
index 00000000000000..4cee7b5159bbc3
--- /dev/null
+++ b/src/legacy/core_plugins/timelion/public/components/timelionhelp_tabs_directive.js
@@ -0,0 +1,34 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import 'ngreact';
+
+import { wrapInI18nContext } from 'ui/i18n';
+import { uiModules } from 'ui/modules';
+const module = uiModules.get('apps/timelion', ['react']);
+
+import { TimelionHelpTabs } from './timelionhelp_tabs';
+
+module.directive('timelionHelpTabs', function (reactDirective) {
+ return reactDirective(
+ wrapInI18nContext(TimelionHelpTabs),
+ undefined,
+ { restrict: 'E' }
+ );
+});
diff --git a/src/legacy/core_plugins/timelion/public/directives/timelion_help/timelion_help.html b/src/legacy/core_plugins/timelion/public/directives/timelion_help/timelion_help.html
index 38dcd7c1027b79..54ad485c51cc43 100644
--- a/src/legacy/core_plugins/timelion/public/directives/timelion_help/timelion_help.html
+++ b/src/legacy/core_plugins/timelion/public/directives/timelion_help/timelion_help.html
@@ -611,131 +611,131 @@
i18n-default-message="Help"
>
-
-
-
-
+
+
-
-
-
- .{{function.name}}()
- {{function.help}}
-
-
-
-
-
-
-
-
-
-
-
- {{arg.name}}
- {{arg.types.join(', ')}}
- {{arg.help}}
-
-
-
-
-
-
-
-
-
-
-
-
+
+
-
-
-
-
-
-
-
- Ctrl/Cmd + Enter
-
-
+
+
+
+ .{{function.name}}()
+ {{function.help}}
+
+
+
+
+
+
+
+
+
+
+
+ {{arg.name}}
+ {{arg.types.join(', ')}}
+ {{arg.help}}
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
- Enter/Tab
-
- Esc
-
-
-
-
-
+
+
+
+
+
+
+ Ctrl/Cmd + Enter
+
+
+
+
+
+
+
+
+
+
+
+ Enter/Tab
+
+ Esc
+
+
+
diff --git a/src/legacy/core_plugins/timelion/public/directives/timelion_help/timelion_help.js b/src/legacy/core_plugins/timelion/public/directives/timelion_help/timelion_help.js
index f9a44fc03b6d2d..97ca1b2edb9fb5 100644
--- a/src/legacy/core_plugins/timelion/public/directives/timelion_help/timelion_help.js
+++ b/src/legacy/core_plugins/timelion/public/directives/timelion_help/timelion_help.js
@@ -21,6 +21,7 @@ import template from './timelion_help.html';
import { uiModules } from 'ui/modules';
import _ from 'lodash';
import moment from 'moment';
+import '../../components/timelionhelp_tabs_directive';
const app = uiModules.get('apps/timelion', []);
@@ -34,6 +35,11 @@ app.directive('timelionHelp', function ($http, i18n) {
details: null
};
+ $scope.activeTab = 'funcref';
+ $scope.activateTab = function (tabName) {
+ $scope.activeTab = tabName;
+ };
+
function init() {
$scope.es = {
invalidCount: 0
diff --git a/src/legacy/ui/public/angular-bootstrap/index.js b/src/legacy/ui/public/angular-bootstrap/index.js
index dd3ca05c9ebd90..e05df0df444588 100644
--- a/src/legacy/ui/public/angular-bootstrap/index.js
+++ b/src/legacy/ui/public/angular-bootstrap/index.js
@@ -33,7 +33,6 @@ angular.module('ui.bootstrap', [
'ui.bootstrap.tooltip',
'ui.bootstrap.popover',
'ui.bootstrap.progressbar',
- 'ui.bootstrap.tabs',
'ui.bootstrap.timepicker',
'ui.bootstrap.typeahead'
]);
@@ -50,8 +49,6 @@ angular.module('ui.bootstrap.tpls', [
'template/progressbar/bar.html',
'template/progressbar/progress.html',
'template/progressbar/progressbar.html',
- 'template/tabs/tab.html',
- 'template/tabs/tabset.html',
'template/timepicker/timepicker.html',
'template/typeahead/typeahead-match.html',
'template/typeahead/typeahead-popup.html'
@@ -66,7 +63,6 @@ import './pagination/pagination';
import './popover/popover';
import './position/position';
import './progressbar/progressbar';
-import './tabs/tabs';
import './timepicker/timepicker';
import './tooltip/tooltip';
import './transition/transition';
@@ -138,18 +134,6 @@ angular.module('template/progressbar/progressbar.html', []).run(['$templateCache
$templateCache.put('template/progressbar/progressbar.html', progressbar);
}]);
-import tab from './tabs/tab.html';
-
-angular.module('template/tabs/tab.html', []).run(['$templateCache', function($templateCache) {
- $templateCache.put('template/tabs/tab.html', tab);
-}]);
-
-import tabset from './tabs/tabset.html';
-
-angular.module('template/tabs/tabset.html', []).run(['$templateCache', function($templateCache) {
- $templateCache.put('template/tabs/tabset.html', tabset);
-}]);
-
import timepicker from './timepicker/timepicker.html';
angular.module('template/timepicker/timepicker.html', []).run(['$templateCache', function($templateCache) {
diff --git a/src/legacy/ui/public/angular-bootstrap/tabs/tab.html b/src/legacy/ui/public/angular-bootstrap/tabs/tab.html
deleted file mode 100755
index d76dd67caf234d..00000000000000
--- a/src/legacy/ui/public/angular-bootstrap/tabs/tab.html
+++ /dev/null
@@ -1,3 +0,0 @@
-
- {{heading}}
-
diff --git a/src/legacy/ui/public/angular-bootstrap/tabs/tabs.js b/src/legacy/ui/public/angular-bootstrap/tabs/tabs.js
deleted file mode 100755
index d6f8161d6a57a7..00000000000000
--- a/src/legacy/ui/public/angular-bootstrap/tabs/tabs.js
+++ /dev/null
@@ -1,279 +0,0 @@
-
-/**
- * @ngdoc overview
- * @name ui.bootstrap.tabs
- *
- * @description
- * AngularJS version of the tabs directive.
- */
-
-angular.module('ui.bootstrap.tabs', [])
-
-.controller('TabsetController', ['$scope', function TabsetCtrl($scope) {
- var ctrl = this,
- tabs = ctrl.tabs = $scope.tabs = [];
-
- ctrl.select = function(selectedTab) {
- angular.forEach(tabs, function(tab) {
- if (tab.active && tab !== selectedTab) {
- tab.active = false;
- tab.onDeselect();
- }
- });
- selectedTab.active = true;
- selectedTab.onSelect();
- };
-
- ctrl.addTab = function addTab(tab) {
- tabs.push(tab);
- // we can't run the select function on the first tab
- // since that would select it twice
- if (tabs.length === 1) {
- tab.active = true;
- } else if (tab.active) {
- ctrl.select(tab);
- }
- };
-
- ctrl.removeTab = function removeTab(tab) {
- var index = tabs.indexOf(tab);
- //Select a new tab if the tab to be removed is selected and not destroyed
- if (tab.active && tabs.length > 1 && !destroyed) {
- //If this is the last tab, select the previous tab. else, the next tab.
- var newActiveIndex = index == tabs.length - 1 ? index - 1 : index + 1;
- ctrl.select(tabs[newActiveIndex]);
- }
- tabs.splice(index, 1);
- };
-
- var destroyed;
- $scope.$on('$destroy', function() {
- destroyed = true;
- });
-}])
-
-/**
- * @ngdoc directive
- * @name ui.bootstrap.tabs.directive:tabset
- * @restrict EA
- *
- * @description
- * Tabset is the outer container for the tabs directive
- *
- * @param {boolean=} vertical Whether or not to use vertical styling for the tabs.
- * @param {boolean=} justified Whether or not to use justified styling for the tabs.
- *
- * @example
-
-
-
- First Content!
- Second Content!
-
-
-
- First Vertical Content!
- Second Vertical Content!
-
-
- First Justified Content!
- Second Justified Content!
-
-
-
- */
-.directive('tabset', function() {
- return {
- restrict: 'EA',
- transclude: true,
- replace: true,
- scope: {
- type: '@'
- },
- controller: 'TabsetController',
- templateUrl: 'template/tabs/tabset.html',
- link: function(scope, element, attrs) {
- scope.vertical = angular.isDefined(attrs.vertical) ? scope.$parent.$eval(attrs.vertical) : false;
- scope.justified = angular.isDefined(attrs.justified) ? scope.$parent.$eval(attrs.justified) : false;
- }
- };
-})
-
-/**
- * @ngdoc directive
- * @name ui.bootstrap.tabs.directive:tab
- * @restrict EA
- *
- * @param {string=} heading The visible heading, or title, of the tab. Set HTML headings with {@link ui.bootstrap.tabs.directive:tabHeading tabHeading}.
- * @param {string=} select An expression to evaluate when the tab is selected.
- * @param {boolean=} active A binding, telling whether or not this tab is selected.
- * @param {boolean=} disabled A binding, telling whether or not this tab is disabled.
- *
- * @description
- * Creates a tab with a heading and content. Must be placed within a {@link ui.bootstrap.tabs.directive:tabset tabset}.
- *
- * @example
-
-
-
-
- Select item 1, using active binding
-
-
- Enable/disable item 2, using disabled binding
-
-
-
- First Tab
-
- Alert me!
- Second Tab, with alert callback and html heading!
-
-
- {{item.content}}
-
-
-
-
-
- function TabsDemoCtrl($scope) {
- $scope.items = [
- { title:"Dynamic Title 1", content:"Dynamic Item 0" },
- { title:"Dynamic Title 2", content:"Dynamic Item 1", disabled: true }
- ];
-
- $scope.alertMe = function() {
- setTimeout(function() {
- alert("You've selected the alert tab!");
- });
- };
- };
-
-
- */
-
-/**
- * @ngdoc directive
- * @name ui.bootstrap.tabs.directive:tabHeading
- * @restrict EA
- *
- * @description
- * Creates an HTML heading for a {@link ui.bootstrap.tabs.directive:tab tab}. Must be placed as a child of a tab element.
- *
- * @example
-
-
-
-
- HTML in my titles?!
- And some content, too!
-
-
- Icon heading?!?
- That's right.
-
-
-
-
- */
-.directive('tab', ['$parse', function($parse) {
- return {
- require: '^tabset',
- restrict: 'EA',
- replace: true,
- templateUrl: 'template/tabs/tab.html',
- transclude: true,
- scope: {
- active: '=?',
- heading: '@',
- onSelect: '&select', //This callback is called in contentHeadingTransclude
- //once it inserts the tab's content into the dom
- onDeselect: '&deselect'
- },
- controller: function() {
- //Empty controller so other directives can require being 'under' a tab
- },
- compile: function(elm, attrs, transclude) {
- return function postLink(scope, elm, attrs, tabsetCtrl) {
- scope.$watch('active', function(active) {
- if (active) {
- tabsetCtrl.select(scope);
- }
- });
-
- scope.disabled = false;
- if ( attrs.disabled ) {
- scope.$parent.$watch($parse(attrs.disabled), function(value) {
- scope.disabled = !! value;
- });
- }
-
- scope.select = function() {
- if ( !scope.disabled ) {
- scope.active = true;
- }
- };
-
- tabsetCtrl.addTab(scope);
- scope.$on('$destroy', function() {
- tabsetCtrl.removeTab(scope);
- });
-
- //We need to transclude later, once the content container is ready.
- //when this link happens, we're inside a tab heading.
- scope.$transcludeFn = transclude;
- };
- }
- };
-}])
-
-.directive('tabHeadingTransclude', [function() {
- return {
- restrict: 'A',
- require: '^tab',
- link: function(scope, elm, attrs, tabCtrl) {
- scope.$watch('headingElement', function updateHeadingElement(heading) {
- if (heading) {
- elm.html('');
- elm.append(heading);
- }
- });
- }
- };
-}])
-
-.directive('tabContentTransclude', function() {
- return {
- restrict: 'A',
- require: '^tabset',
- link: function(scope, elm, attrs) {
- var tab = scope.$eval(attrs.tabContentTransclude);
-
- //Now our tab is ready to be transcluded: both the tab heading area
- //and the tab content area are loaded. Transclude 'em both.
- tab.$transcludeFn(tab.$parent, function(contents) {
- angular.forEach(contents, function(node) {
- if (isTabHeading(node)) {
- //Let tabHeadingTransclude know.
- tab.headingElement = node;
- } else {
- elm.append(node);
- }
- });
- });
- }
- };
- function isTabHeading(node) {
- return node.tagName && (
- node.hasAttribute('tab-heading') ||
- node.hasAttribute('data-tab-heading') ||
- node.tagName.toLowerCase() === 'tab-heading' ||
- node.tagName.toLowerCase() === 'data-tab-heading'
- );
- }
-})
-
-;
diff --git a/src/legacy/ui/public/angular-bootstrap/tabs/tabset.html b/src/legacy/ui/public/angular-bootstrap/tabs/tabset.html
deleted file mode 100755
index b953a49161925d..00000000000000
--- a/src/legacy/ui/public/angular-bootstrap/tabs/tabset.html
+++ /dev/null
@@ -1,10 +0,0 @@
-
diff --git a/x-pack/plugins/searchprofiler/public/app.js b/x-pack/plugins/searchprofiler/public/app.js
index ae720e587a7357..ee879f188aa3bf 100644
--- a/x-pack/plugins/searchprofiler/public/app.js
+++ b/x-pack/plugins/searchprofiler/public/app.js
@@ -18,6 +18,7 @@ import _ from 'lodash';
import 'ace';
import 'angular-ui-ace';
import 'plugins/searchprofiler/directives';
+import './components/searchprofiler_tabs_directive';
import { Range } from './range';
import { nsToPretty } from 'plugins/searchprofiler/filters/ns_to_pretty';
import { msToPretty } from 'plugins/searchprofiler/filters/ms_to_pretty';
@@ -149,10 +150,10 @@ function profileVizController($scope, $route, $interval, $http, HighlightService
return id.replace('[', '').replace(']', '');
});
}
- $scope.hasAggregations = data[0].aggregations != null && data[0].aggregations.length > 0;
- $scope.hasSearch = data[0].searches != null && data[0].searches.length > 0;
$scope.profileResponse = data;
- if (!$scope.hasAggregations) {
+
+ const hasAggregations = data[0].aggregations != null && data[0].aggregations.length > 0;
+ if (!hasAggregations) {
// No aggs, reset back to search panel
$scope.activateTab('search');
}
@@ -163,7 +164,7 @@ function profileVizController($scope, $route, $interval, $http, HighlightService
$scope.resetHighlightPanel();
// Reset active tab map
$scope.activeTab = {};
- if (tab === 'aggregations' && $scope.hasAggregations) {
+ if (tab === 'aggregations') {
$scope.activeTab.aggregations = true;
} else {
// Everything has a search, so default to this
diff --git a/x-pack/plugins/searchprofiler/public/components/searchprofiler_tabs.js b/x-pack/plugins/searchprofiler/public/components/searchprofiler_tabs.js
new file mode 100644
index 00000000000000..5394e56cef70ad
--- /dev/null
+++ b/x-pack/plugins/searchprofiler/public/components/searchprofiler_tabs.js
@@ -0,0 +1,65 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+
+import _ from 'lodash';
+import PropTypes from 'prop-types';
+import React from 'react';
+
+import {
+ EuiTabs,
+ EuiTab
+} from '@elastic/eui';
+
+import { FormattedMessage } from '@kbn/i18n/react';
+
+function hasSearch(profileResponse) {
+ const aggs = _.get(profileResponse, '[0].searches', []);
+ return aggs.length > 0;
+}
+
+function hasAggregations(profileResponse) {
+ const aggs = _.get(profileResponse, '[0].aggregations', []);
+ return aggs.length > 0;
+}
+
+
+function handleClick(activateTab, tabName) {
+ activateTab(tabName);
+}
+
+export function SearchProfilerTabs(props) {
+ return (
+
+ handleClick(props.activateTab, 'search')}
+ >
+
+
+ handleClick(props.activateTab, 'aggregations')}
+ >
+
+
+
+ );
+}
+
+SearchProfilerTabs.propTypes = {
+ activeTab: PropTypes.any.isRequired,
+ activateTab: PropTypes.func.isRequired,
+ profileResponse: PropTypes.array.isRequired,
+};
diff --git a/x-pack/plugins/searchprofiler/public/components/searchprofiler_tabs_directive.js b/x-pack/plugins/searchprofiler/public/components/searchprofiler_tabs_directive.js
new file mode 100644
index 00000000000000..6cfeb97f05ebd4
--- /dev/null
+++ b/x-pack/plugins/searchprofiler/public/components/searchprofiler_tabs_directive.js
@@ -0,0 +1,21 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import 'ngreact';
+
+import { wrapInI18nContext } from 'ui/i18n';
+import { uiModules } from 'ui/modules';
+const module = uiModules.get('apps/searchprofiler', ['react']);
+
+import { SearchProfilerTabs } from './searchprofiler_tabs';
+
+module.directive('searchProfilerTabs', function (reactDirective) {
+ return reactDirective(
+ wrapInI18nContext(SearchProfilerTabs),
+ undefined,
+ { restrict: 'E' }
+ );
+});
diff --git a/x-pack/plugins/searchprofiler/public/templates/index.html b/x-pack/plugins/searchprofiler/public/templates/index.html
index 9ddac34a3d0733..e5039e937c5561 100644
--- a/x-pack/plugins/searchprofiler/public/templates/index.html
+++ b/x-pack/plugins/searchprofiler/public/templates/index.html
@@ -2,20 +2,17 @@