From fcf8d7b4b26ee04f4493bca2db3226b100e62885 Mon Sep 17 00:00:00 2001 From: Matthias Wilhelm Date: Thu, 17 Sep 2020 09:36:44 +0200 Subject: [PATCH] [Discover] Migrate discover.html Angular template to React (#75784) (#77704) Co-authored-by: Andrea Del Rio --- .../public/application/_discover.scss | 51 ++- .../__snapshots__/no_results.test.js.snap | 126 ------- .../angular/directives/_index.scss | 1 - .../_collapsible_sidebar.scss | 44 --- .../collapsible_sidebar/_depth.scss | 13 - .../collapsible_sidebar/_index.scss | 2 - .../collapsible_sidebar.ts | 88 ----- .../angular/directives/debounce/debounce.js | 6 +- .../directives/debounce/debounce.test.ts | 54 +-- .../angular/directives/debounce/index.js | 4 +- .../angular/directives/fixed_scroll.js | 224 ++++++------ .../angular/directives/fixed_scroll.test.js | 11 +- .../angular/directives/no_results.js | 65 +--- .../angular/directives/no_results.test.js | 29 -- .../public/application/angular/discover.html | 160 --------- .../public/application/angular/discover.js | 26 +- .../application/angular/discover_legacy.html | 36 ++ .../application/angular/discover_state.ts | 4 + .../doc_table/create_doc_table_react.tsx | 131 +++++++ .../angular/doc_table/doc_table.ts | 6 +- .../create_discover_legacy_directive.ts | 56 +++ .../components/discover_legacy.tsx | 324 ++++++++++++++++++ .../components/fetch_error/fetch_error.tsx | 24 +- .../fetch_error/{index.js => index.ts} | 0 .../hits_counter/hits_counter_directive.ts | 27 -- .../components/hits_counter/index.ts | 1 - .../loading_spinner/loading_spinner.tsx | 26 +- .../components/sidebar/discover_sidebar.tsx | 2 +- .../sidebar/discover_sidebar_directive.ts | 33 -- .../application/components/sidebar/index.ts | 1 - .../components/sidebar/lib/get_details.ts | 5 +- .../lib/get_index_pattern_field_list.ts | 4 +- .../components/skip_bottom_button/index.ts | 1 - .../skip_bottom_button_directive.ts | 23 -- .../components/timechart_header/index.ts | 1 - .../timechart_header.test.tsx | 18 +- .../timechart_header/timechart_header.tsx | 66 ++-- .../timechart_header_directive.ts | 32 -- src/plugins/discover/public/build_services.ts | 8 +- .../discover/public/get_inner_angular.ts | 34 +- src/plugins/discover/public/plugin.ts | 14 +- .../discover/public/saved_searches/types.ts | 1 + test/functional/page_objects/discover_page.ts | 2 +- .../server/lib/layouts/preserve_layout.css | 2 +- .../reporting/server/lib/layouts/print.css | 2 +- .../translations/translations/ja-JP.json | 4 - .../translations/translations/zh-CN.json | 4 - 47 files changed, 834 insertions(+), 962 deletions(-) delete mode 100644 src/plugins/discover/public/application/angular/directives/collapsible_sidebar/_collapsible_sidebar.scss delete mode 100644 src/plugins/discover/public/application/angular/directives/collapsible_sidebar/_depth.scss delete mode 100644 src/plugins/discover/public/application/angular/directives/collapsible_sidebar/_index.scss delete mode 100644 src/plugins/discover/public/application/angular/directives/collapsible_sidebar/collapsible_sidebar.ts delete mode 100644 src/plugins/discover/public/application/angular/discover.html create mode 100644 src/plugins/discover/public/application/angular/discover_legacy.html create mode 100644 src/plugins/discover/public/application/angular/doc_table/create_doc_table_react.tsx create mode 100644 src/plugins/discover/public/application/components/create_discover_legacy_directive.ts create mode 100644 src/plugins/discover/public/application/components/discover_legacy.tsx rename src/plugins/discover/public/application/components/fetch_error/{index.js => index.ts} (100%) delete mode 100644 src/plugins/discover/public/application/components/hits_counter/hits_counter_directive.ts delete mode 100644 src/plugins/discover/public/application/components/sidebar/discover_sidebar_directive.ts delete mode 100644 src/plugins/discover/public/application/components/skip_bottom_button/skip_bottom_button_directive.ts delete mode 100644 src/plugins/discover/public/application/components/timechart_header/timechart_header_directive.ts diff --git a/src/plugins/discover/public/application/_discover.scss b/src/plugins/discover/public/application/_discover.scss index 69df2a75b8d758..bc704439d161bb 100644 --- a/src/plugins/discover/public/application/_discover.scss +++ b/src/plugins/discover/public/application/_discover.scss @@ -5,6 +5,11 @@ overflow: hidden; } +.dscAppContainer { + > * { + position: relative; + } +} discover-app { flex-grow: 1; } @@ -17,9 +22,12 @@ discover-app { // SASSTODO: replace the z-index value with a variable .dscWrapper { + padding-left: $euiSizeXL; padding-right: $euiSizeS; - padding-left: 21px; z-index: 1; + @include euiBreakpoint('xs', 's', 'm') { + padding-left: $euiSizeS; + } } @include euiPanel('.dscWrapper__content'); @@ -104,14 +112,51 @@ discover-app { top: $euiSizeXS; } -[fixed-scroll] { +.dscTableFixedScroll { overflow-x: auto; padding-bottom: 0; - + .fixed-scroll-scroller { + + .dscTableFixedScroll__scroller { position: fixed; bottom: 0; overflow-x: auto; overflow-y: hidden; } } + +.dscCollapsibleSidebar { + position: relative; + z-index: $euiZLevel1; + + .dscCollapsibleSidebar__collapseButton { + position: absolute; + top: 0; + right: -$euiSizeXL + 4; + cursor: pointer; + z-index: -1; + min-height: $euiSizeM; + min-width: $euiSizeM; + padding: $euiSizeXS * .5; + } + + &.closed { + width: 0 !important; + border-right-width: 0; + border-left-width: 0; + .dscCollapsibleSidebar__collapseButton { + right: -$euiSizeL + 4; + } + } +} + +@include euiBreakpoint('xs', 's', 'm') { + .dscCollapsibleSidebar { + &.closed { + display: none; + } + + .dscCollapsibleSidebar__collapseButton { + display: none; + } + } +} diff --git a/src/plugins/discover/public/application/angular/directives/__snapshots__/no_results.test.js.snap b/src/plugins/discover/public/application/angular/directives/__snapshots__/no_results.test.js.snap index e7aea41e2d08e9..e69e10e29e8019 100644 --- a/src/plugins/discover/public/application/angular/directives/__snapshots__/no_results.test.js.snap +++ b/src/plugins/discover/public/application/angular/directives/__snapshots__/no_results.test.js.snap @@ -167,132 +167,6 @@ Array [ ] `; -exports[`DiscoverNoResults props shardFailures doesn't render failures list when there are no failures 1`] = ` -Array [ -
, -
-
-
-
- -
-
-
, -] -`; - -exports[`DiscoverNoResults props shardFailures renders failures list when there are failures 1`] = ` -Array [ -
, -
-
-
-
- -
-
-
-

- Address shard failures -

-

- The following shard failures occurred: -

-
-
- - Index ‘A’ - - , shard ‘1’ -
-
-
-
-              
-                {"reason":"Awful error"}
-              
-            
-
-
-
-
-
- - Index ‘B’ - - , shard ‘2’ -
-
-
-
-              
-                {"reason":"Bad error"}
-              
-            
-
-
-
-
-
, -] -`; - exports[`DiscoverNoResults props timeFieldName renders time range feedback 1`] = ` Array [
* { - visibility: hidden; - } - - .kbnCollapsibleSidebar__collapseButton { - visibility: visible; - - .chevron-cont:before { - content: "\F138"; - } - } - } -} - -@include euiBreakpoint('xs', 's', 'm') { - .collapsible-sidebar { - &.closed { - display: none; - } - - .kbnCollapsibleSidebar__collapseButton { - display: none; - } - } -} diff --git a/src/plugins/discover/public/application/angular/directives/collapsible_sidebar/_depth.scss b/src/plugins/discover/public/application/angular/directives/collapsible_sidebar/_depth.scss deleted file mode 100644 index 4bc59001f9931a..00000000000000 --- a/src/plugins/discover/public/application/angular/directives/collapsible_sidebar/_depth.scss +++ /dev/null @@ -1,13 +0,0 @@ -/** - * 1. The local nav contains tooltips which should pop over the filter bar. - * 2. The filter and local nav components should always appear above the dashboard grid items. - * 3. The filter and local nav components should always appear above the discover content. - * 4. The sidebar collapser button should appear above the main Discover content but below the top elements. - * 5. Dragged panels in dashboard should always appear above other panels. - */ -$kbnFilterBarDepth: 4; /* 1 */ -$kbnLocalNavDepth: 5; /* 1 */ -$kbnDashboardGridDepth: 1; /* 2 */ -$kbnDashboardDraggingGridDepth: 2; /* 5 */ -$kbnDiscoverWrapperDepth: 1; /* 3 */ -$kbnDiscoverSidebarDepth: 2; /* 4 */ diff --git a/src/plugins/discover/public/application/angular/directives/collapsible_sidebar/_index.scss b/src/plugins/discover/public/application/angular/directives/collapsible_sidebar/_index.scss deleted file mode 100644 index 1409920d11aa7f..00000000000000 --- a/src/plugins/discover/public/application/angular/directives/collapsible_sidebar/_index.scss +++ /dev/null @@ -1,2 +0,0 @@ -@import 'depth'; -@import 'collapsible_sidebar'; diff --git a/src/plugins/discover/public/application/angular/directives/collapsible_sidebar/collapsible_sidebar.ts b/src/plugins/discover/public/application/angular/directives/collapsible_sidebar/collapsible_sidebar.ts deleted file mode 100644 index 16fbb0af9f3fd4..00000000000000 --- a/src/plugins/discover/public/application/angular/directives/collapsible_sidebar/collapsible_sidebar.ts +++ /dev/null @@ -1,88 +0,0 @@ -/* - * 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 _ from 'lodash'; -import $ from 'jquery'; -import { IScope } from 'angular'; - -interface LazyScope extends IScope { - [key: string]: any; -} - -export function CollapsibleSidebarProvider() { - // simply a list of all of all of angulars .col-md-* classes except 12 - const listOfWidthClasses = _.times(11, function (i) { - return 'col-md-' + i; - }); - - return { - restrict: 'C', - link: ($scope: LazyScope, $elem: any) => { - let isCollapsed = false; - const $collapser = $( - `` - ); - // If the collapsable element has an id, also set aria-controls - if ($elem.attr('id')) { - $collapser.attr('aria-controls', $elem.attr('id')); - } - const $icon = $(''); - $collapser.append($icon); - const $siblings = $elem.siblings(); - - const siblingsClass = listOfWidthClasses.reduce((prev: string, className: string) => { - if (prev) return prev; - return $siblings.hasClass(className) && className; - }, ''); - - // If there is are only two elements we can assume the other one will take 100% of the width. - const hasSingleSibling = $siblings.length === 1 && siblingsClass; - - $collapser.on('click', function () { - if (isCollapsed) { - isCollapsed = false; - $elem.removeClass('closed'); - $icon.addClass('fa-chevron-circle-left'); - $icon.removeClass('fa-chevron-circle-right'); - $collapser.attr('aria-expanded', 'true'); - } else { - isCollapsed = true; - $elem.addClass('closed'); - $icon.removeClass('fa-chevron-circle-left'); - $icon.addClass('fa-chevron-circle-right'); - $collapser.attr('aria-expanded', 'false'); - } - - if (hasSingleSibling) { - $siblings.toggleClass(siblingsClass + ' col-md-12'); - } - - if ($scope.toggleSidebar) $scope.toggleSidebar(); - }); - - $collapser.appendTo($elem); - }, - }; -} diff --git a/src/plugins/discover/public/application/angular/directives/debounce/debounce.js b/src/plugins/discover/public/application/angular/directives/debounce/debounce.js index 586e8ed4fab593..8ce2b042c0efe4 100644 --- a/src/plugins/discover/public/application/angular/directives/debounce/debounce.js +++ b/src/plugins/discover/public/application/angular/directives/debounce/debounce.js @@ -21,7 +21,7 @@ import _ from 'lodash'; // Debounce service, angularized version of lodash debounce // borrowed heavily from https://github.com/shahata/angular-debounce -export function DebounceProviderTimeout($timeout) { +export function createDebounceProviderTimeout($timeout) { return function (func, wait, options) { let timeout; let args; @@ -66,7 +66,3 @@ export function DebounceProviderTimeout($timeout) { return debounce; }; } - -export function DebounceProvider(debounce) { - return debounce; -} diff --git a/src/plugins/discover/public/application/angular/directives/debounce/debounce.test.ts b/src/plugins/discover/public/application/angular/directives/debounce/debounce.test.ts index ccdee153002e46..0cdc214cf97f56 100644 --- a/src/plugins/discover/public/application/angular/directives/debounce/debounce.test.ts +++ b/src/plugins/discover/public/application/angular/directives/debounce/debounce.test.ts @@ -24,7 +24,7 @@ import 'angular-sanitize'; import 'angular-route'; // @ts-ignore -import { DebounceProvider } from './index'; +import { createDebounceProviderTimeout } from './debounce'; import { coreMock } from '../../../../../../../core/public/mocks'; import { initializeInnerAngularModule } from '../../../../get_inner_angular'; import { navigationPluginMock } from '../../../../../../navigation/public/mocks'; @@ -33,7 +33,6 @@ import { initAngularBootstrap } from '../../../../../../kibana_legacy/public'; describe('debounce service', function () { let debounce: (fn: () => void, timeout: number, options?: any) => any; - let debounceFromProvider: (fn: () => void, timeout: number, options?: any) => any; let $timeout: ITimeoutService; let spy: SinonSpy; @@ -51,22 +50,17 @@ describe('debounce service', function () { angular.mock.module('app/discover'); - angular.mock.inject( - ($injector: auto.IInjectorService, _$timeout_: ITimeoutService, Private: any) => { - $timeout = _$timeout_; + angular.mock.inject(($injector: auto.IInjectorService, _$timeout_: ITimeoutService) => { + $timeout = _$timeout_; - debounce = $injector.get('debounce'); - debounceFromProvider = Private(DebounceProvider); - } - ); + debounce = createDebounceProviderTimeout($timeout); + }); }); it('should have a cancel method', function () { const bouncer = debounce(() => {}, 100); - const bouncerFromProvider = debounceFromProvider(() => {}, 100); expect(bouncer).toHaveProperty('cancel'); - expect(bouncerFromProvider).toHaveProperty('cancel'); }); describe('delayed execution', function () { @@ -77,7 +71,6 @@ describe('debounce service', function () { it('should delay execution', function () { const bouncer = debounce(spy, 100); - const bouncerFromProvider = debounceFromProvider(spy, 100); bouncer(); sinon.assert.notCalled(spy); @@ -85,16 +78,10 @@ describe('debounce service', function () { sinon.assert.calledOnce(spy); spy.resetHistory(); - - bouncerFromProvider(); - sinon.assert.notCalled(spy); - $timeout.flush(); - sinon.assert.calledOnce(spy); }); it('should fire on leading edge', function () { const bouncer = debounce(spy, 100, { leading: true }); - const bouncerFromProvider = debounceFromProvider(spy, 100, { leading: true }); bouncer(); sinon.assert.calledOnce(spy); @@ -102,19 +89,10 @@ describe('debounce service', function () { sinon.assert.calledTwice(spy); spy.resetHistory(); - - bouncerFromProvider(); - sinon.assert.calledOnce(spy); - $timeout.flush(); - sinon.assert.calledTwice(spy); }); it('should only fire on leading edge', function () { const bouncer = debounce(spy, 100, { leading: true, trailing: false }); - const bouncerFromProvider = debounceFromProvider(spy, 100, { - leading: true, - trailing: false, - }); bouncer(); sinon.assert.calledOnce(spy); @@ -122,17 +100,11 @@ describe('debounce service', function () { sinon.assert.calledOnce(spy); spy.resetHistory(); - - bouncerFromProvider(); - sinon.assert.calledOnce(spy); - $timeout.flush(); - sinon.assert.calledOnce(spy); }); it('should reset delayed execution', function () { const cancelSpy = sinon.spy($timeout, 'cancel'); const bouncer = debounce(spy, 100); - const bouncerFromProvider = debounceFromProvider(spy, 100); bouncer(); sandbox.clock.tick(1); @@ -145,15 +117,6 @@ describe('debounce service', function () { spy.resetHistory(); cancelSpy.resetHistory(); - - bouncerFromProvider(); - sandbox.clock.tick(1); - - bouncerFromProvider(); - sinon.assert.notCalled(spy); - $timeout.flush(); - sinon.assert.calledOnce(spy); - sinon.assert.calledOnce(cancelSpy); }); }); @@ -161,7 +124,6 @@ describe('debounce service', function () { it('should cancel the $timeout', function () { const cancelSpy = sinon.spy($timeout, 'cancel'); const bouncer = debounce(spy, 100); - const bouncerFromProvider = debounceFromProvider(spy, 100); bouncer(); bouncer.cancel(); @@ -170,12 +132,6 @@ describe('debounce service', function () { $timeout.verifyNoPendingTasks(); cancelSpy.resetHistory(); - - bouncerFromProvider(); - bouncerFromProvider.cancel(); - sinon.assert.calledOnce(cancelSpy); - // throws if pending timeouts - $timeout.verifyNoPendingTasks(); }); }); }); diff --git a/src/plugins/discover/public/application/angular/directives/debounce/index.js b/src/plugins/discover/public/application/angular/directives/debounce/index.js index 35b83392636263..3c51895f198284 100644 --- a/src/plugins/discover/public/application/angular/directives/debounce/index.js +++ b/src/plugins/discover/public/application/angular/directives/debounce/index.js @@ -17,6 +17,4 @@ * under the License. */ -import './debounce'; - -export { DebounceProvider } from './debounce'; +export { createDebounceProviderTimeout } from './debounce'; diff --git a/src/plugins/discover/public/application/angular/directives/fixed_scroll.js b/src/plugins/discover/public/application/angular/directives/fixed_scroll.js index 182b4aeca9a23e..e2d5f10a0faf71 100644 --- a/src/plugins/discover/public/application/angular/directives/fixed_scroll.js +++ b/src/plugins/discover/public/application/angular/directives/fixed_scroll.js @@ -19,7 +19,7 @@ import $ from 'jquery'; import _ from 'lodash'; -import { DebounceProvider } from './debounce'; +import { createDebounceProviderTimeout } from './debounce'; const SCROLLER_HEIGHT = 20; @@ -28,124 +28,128 @@ const SCROLLER_HEIGHT = 20; * to the target element's real scrollbar. This is useful when the target element's horizontal scrollbar * might be waaaay down the page, like the doc table on Discover. */ -export function FixedScrollProvider(Private) { - const debounce = Private(DebounceProvider); - +export function FixedScrollProvider($timeout) { return { restrict: 'A', link: function ($scope, $el) { - let $window = $(window); - let $scroller = $('
').height(SCROLLER_HEIGHT); - - /** - * Remove the listeners bound in listen() - * @type {function} - */ - let unlisten = _.noop; - - /** - * Listen for scroll events on the $scroller and the $el, sets unlisten() - * - * unlisten must be called before calling or listen() will throw an Error - * - * Since the browser emits "scroll" events after setting scrollLeft - * the listeners also prevent tug-of-war - * - * @throws {Error} If unlisten was not called first - * @return {undefined} - */ - function listen() { - if (unlisten !== _.noop) { - throw new Error( - 'fixedScroll listeners were not cleaned up properly before re-listening!' - ); - } - - let blockTo; - function bind($from, $to) { - function handler() { - if (blockTo === $to) return (blockTo = null); - $to.scrollLeft((blockTo = $from).scrollLeft()); - } - - $from.on('scroll', handler); - return function () { - $from.off('scroll', handler); - }; - } - - unlisten = _.flow(bind($el, $scroller), bind($scroller, $el), function () { - unlisten = _.noop; - }); - } - - /** - * Revert DOM changes and event listeners - * @return {undefined} - */ - function cleanUp() { - unlisten(); - $scroller.detach(); - $el.css('padding-bottom', 0); - } - - /** - * Modify the DOM and attach event listeners based on need. - * Is called many times to re-setup, must be idempotent - * @return {undefined} - */ - function setup() { - cleanUp(); - - const containerWidth = $el.width(); - const contentWidth = $el.prop('scrollWidth'); - const containerHorizOverflow = contentWidth - containerWidth; - - const elTop = $el.offset().top - $window.scrollTop(); - const elBottom = elTop + $el.height(); - const windowVertOverflow = elBottom - $window.height(); - - const requireScroller = containerHorizOverflow > 0 && windowVertOverflow > 0; - if (!requireScroller) return; - - // push the content away from the scroller - $el.css('padding-bottom', SCROLLER_HEIGHT); - - // fill the scroller with a dummy element that mimics the content - $scroller - .width(containerWidth) - .html($('
').css({ width: contentWidth, height: SCROLLER_HEIGHT })) - .insertAfter($el); + return createFixedScroll($scope, $timeout)($el); + }, + }; +} - // listen for scroll events - listen(); +export function createFixedScroll($scope, $timeout) { + const debounce = createDebounceProviderTimeout($timeout); + return function (el) { + const $el = typeof el.css === 'function' ? el : $(el); + let $window = $(window); + let $scroller = $('
').height(SCROLLER_HEIGHT); + + /** + * Remove the listeners bound in listen() + * @type {function} + */ + let unlisten = _.noop; + + /** + * Listen for scroll events on the $scroller and the $el, sets unlisten() + * + * unlisten must be called before calling or listen() will throw an Error + * + * Since the browser emits "scroll" events after setting scrollLeft + * the listeners also prevent tug-of-war + * + * @throws {Error} If unlisten was not called first + * @return {undefined} + */ + function listen() { + if (unlisten !== _.noop) { + throw new Error('fixedScroll listeners were not cleaned up properly before re-listening!'); } - let width; - let scrollWidth; - function checkWidth() { - const newScrollWidth = $el.prop('scrollWidth'); - const newWidth = $el.width(); - - if (scrollWidth !== newScrollWidth || width !== newWidth) { - $scope.$apply(setup); - - scrollWidth = newScrollWidth; - width = newWidth; + let blockTo; + function bind($from, $to) { + function handler() { + if (blockTo === $to) return (blockTo = null); + $to.scrollLeft((blockTo = $from).scrollLeft()); } - } - const debouncedCheckWidth = debounce(checkWidth, 100, { - invokeApply: false, - }); - $scope.$watch(debouncedCheckWidth); + $from.on('scroll', handler); + return function () { + $from.off('scroll', handler); + }; + } - // cleanup when the scope is destroyed - $scope.$on('$destroy', function () { - cleanUp(); - debouncedCheckWidth.cancel(); - $scroller = $window = null; + unlisten = _.flow(bind($el, $scroller), bind($scroller, $el), function () { + unlisten = _.noop; }); - }, + } + + /** + * Revert DOM changes and event listeners + * @return {undefined} + */ + function cleanUp() { + unlisten(); + $scroller.detach(); + $el.css('padding-bottom', 0); + } + + /** + * Modify the DOM and attach event listeners based on need. + * Is called many times to re-setup, must be idempotent + * @return {undefined} + */ + function setup() { + cleanUp(); + + const containerWidth = $el.width(); + const contentWidth = $el.prop('scrollWidth'); + const containerHorizOverflow = contentWidth - containerWidth; + + const elTop = $el.offset().top - $window.scrollTop(); + const elBottom = elTop + $el.height(); + const windowVertOverflow = elBottom - $window.height(); + + const requireScroller = containerHorizOverflow > 0 && windowVertOverflow > 0; + if (!requireScroller) return; + + // push the content away from the scroller + $el.css('padding-bottom', SCROLLER_HEIGHT); + + // fill the scroller with a dummy element that mimics the content + $scroller + .width(containerWidth) + .html($('
').css({ width: contentWidth, height: SCROLLER_HEIGHT })) + .insertAfter($el); + + // listen for scroll events + listen(); + } + + let width; + let scrollWidth; + function checkWidth() { + const newScrollWidth = $el.prop('scrollWidth'); + const newWidth = $el.width(); + + if (scrollWidth !== newScrollWidth || width !== newWidth) { + $scope.$apply(setup); + + scrollWidth = newScrollWidth; + width = newWidth; + } + } + + const debouncedCheckWidth = debounce(checkWidth, 100, { + invokeApply: false, + }); + $scope.$watch(debouncedCheckWidth); + + function destroy() { + cleanUp(); + debouncedCheckWidth.cancel(); + $scroller = $window = null; + } + return destroy; }; } diff --git a/src/plugins/discover/public/application/angular/directives/fixed_scroll.test.js b/src/plugins/discover/public/application/angular/directives/fixed_scroll.test.js index 16293ca621e050..0e40499d1c9b54 100644 --- a/src/plugins/discover/public/application/angular/directives/fixed_scroll.test.js +++ b/src/plugins/discover/public/application/angular/directives/fixed_scroll.test.js @@ -23,17 +23,12 @@ import $ from 'jquery'; import sinon from 'sinon'; -import { PrivateProvider, initAngularBootstrap } from '../../../../../kibana_legacy/public'; +import { initAngularBootstrap } from '../../../../../kibana_legacy/public'; import { FixedScrollProvider } from './fixed_scroll'; -import { DebounceProviderTimeout } from './debounce/debounce'; const testModuleName = 'fixedScroll'; -angular - .module(testModuleName, []) - .provider('Private', PrivateProvider) - .service('debounce', ['$timeout', DebounceProviderTimeout]) - .directive('fixedScroll', FixedScrollProvider); +angular.module(testModuleName, []).directive('fixedScroll', FixedScrollProvider); describe('FixedScroll directive', function () { const sandbox = sinon.createSandbox(); @@ -127,7 +122,7 @@ describe('FixedScroll directive', function () { return { $container: $el, $content: $content, - $scroller: $parent.find('.fixed-scroll-scroller'), + $scroller: $parent.find('.dscTableFixedScroll__scroller'), }; }; }); diff --git a/src/plugins/discover/public/application/angular/directives/no_results.js b/src/plugins/discover/public/application/angular/directives/no_results.js index 965c1271c2f2c9..d8a39d9178e937 100644 --- a/src/plugins/discover/public/application/angular/directives/no_results.js +++ b/src/plugins/discover/public/application/angular/directives/no_results.js @@ -24,7 +24,6 @@ import PropTypes from 'prop-types'; import { EuiCallOut, EuiCode, - EuiCodeBlock, EuiDescriptionList, EuiFlexGroup, EuiFlexItem, @@ -37,72 +36,12 @@ import { getServices } from '../../../kibana_services'; // eslint-disable-next-line react/prefer-stateless-function export class DiscoverNoResults extends Component { static propTypes = { - shardFailures: PropTypes.array, timeFieldName: PropTypes.string, queryLanguage: PropTypes.string, }; render() { - const { shardFailures, timeFieldName, queryLanguage } = this.props; - - let shardFailuresMessage; - - if (shardFailures && shardFailures.length) { - const failures = shardFailures.map((failure, index) => ( -
- - - - - ), - failureShard: `‘${failure.shard}’`, - }} - /> - - - - - {JSON.stringify(failure.reason)} - - {index < shardFailures.length - 1 ? : undefined} -
- )); - - shardFailuresMessage = ( - - - - -

- -

- -

- -

- - {failures} -
-
- ); - } + const { timeFieldName, queryLanguage } = this.props; let timeFieldMessage; @@ -264,8 +203,6 @@ export class DiscoverNoResults extends Component { iconType="help" data-test-subj="discoverNoResults" /> - - {shardFailuresMessage} {timeFieldMessage} {luceneQueryMessage} diff --git a/src/plugins/discover/public/application/angular/directives/no_results.test.js b/src/plugins/discover/public/application/angular/directives/no_results.test.js index 7de792c6129931..60c50048a39ef5 100644 --- a/src/plugins/discover/public/application/angular/directives/no_results.test.js +++ b/src/plugins/discover/public/application/angular/directives/no_results.test.js @@ -42,35 +42,6 @@ beforeEach(() => { describe('DiscoverNoResults', () => { describe('props', () => { - describe('shardFailures', () => { - test('renders failures list when there are failures', () => { - const shardFailures = [ - { - index: 'A', - shard: '1', - reason: { reason: 'Awful error' }, - }, - { - index: 'B', - shard: '2', - reason: { reason: 'Bad error' }, - }, - ]; - - const component = renderWithIntl(); - - expect(component).toMatchSnapshot(); - }); - - test(`doesn't render failures list when there are no failures`, () => { - const shardFailures = []; - - const component = renderWithIntl(); - - expect(component).toMatchSnapshot(); - }); - }); - describe('timeFieldName', () => { test('renders time range feedback', () => { const component = renderWithIntl(); diff --git a/src/plugins/discover/public/application/angular/discover.html b/src/plugins/discover/public/application/angular/discover.html deleted file mode 100644 index e0e452aaa41c51..00000000000000 --- a/src/plugins/discover/public/application/angular/discover.html +++ /dev/null @@ -1,160 +0,0 @@ - -

{{screenTitle}}

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

- - - - - -
-
-
-
-
-
-
diff --git a/src/plugins/discover/public/application/angular/discover.js b/src/plugins/discover/public/application/angular/discover.js index b75ac75e5f2edb..7871cc4b16464e 100644 --- a/src/plugins/discover/public/application/angular/discover.js +++ b/src/plugins/discover/public/application/angular/discover.js @@ -29,12 +29,11 @@ import { getState, splitState } from './discover_state'; import { RequestAdapter } from '../../../../inspector/public'; import { SavedObjectSaveModal, showSaveModal } from '../../../../saved_objects/public'; import { getSortArray, getSortForSearchSource } from './doc_table'; +import { createFixedScroll } from './directives/fixed_scroll'; import * as columnActions from './doc_table/actions/columns'; - -import indexTemplate from './discover.html'; +import indexTemplateLegacy from './discover_legacy.html'; import { showOpenSearchPanel } from '../components/top_nav/show_open_search_panel'; import { addHelpMenuToAppChrome } from '../components/help_menu/help_menu_util'; -import '../components/fetch_error'; import { getPainlessError } from './get_painless_error'; import { discoverResponseHandler } from './response_handler'; import { @@ -71,7 +70,6 @@ import { indexPatterns as indexPatternsUtils, connectToQueryState, syncQueryStateWithUrl, - search, } from '../../../../data/public'; import { getIndexPatternId } from '../helpers/get_index_pattern_id'; import { addFatalError } from '../../../../kibana_legacy/public'; @@ -115,7 +113,7 @@ app.config(($routeProvider) => { }; const discoverRoute = { ...defaults, - template: indexTemplate, + template: indexTemplateLegacy, reloadOnSearch: false, resolve: { savedObjects: function ($route, Promise) { @@ -308,18 +306,10 @@ function discoverController($element, $route, $scope, $timeout, $window, Promise mode: 'absolute', }); }; - $scope.intervalOptions = search.aggs.intervalOptions; $scope.minimumVisibleRows = 50; $scope.fetchStatus = fetchStatuses.UNINITIALIZED; $scope.showSaveQuery = uiCapabilities.discover.saveQuery; - $scope.$watch( - () => uiCapabilities.discover.saveQuery, - (newCapability) => { - $scope.showSaveQuery = newCapability; - } - ); - let abortController; $scope.$on('$destroy', () => { if (abortController) abortController.abort(); @@ -471,7 +461,6 @@ function discoverController($element, $route, $scope, $timeout, $window, Promise ]; }; $scope.topNavMenu = getTopNavLinks(); - $scope.setHeaderActionMenu = getHeaderActionMenuMounter(); $scope.searchSource .setField('index', $scope.indexPattern) @@ -515,8 +504,6 @@ function discoverController($element, $route, $scope, $timeout, $window, Promise ]); } - $scope.screenTitle = savedSearch.title; - const getFieldCounts = async () => { // the field counts aren't set until we have the data back, // so we wait for the fetch to be done before proceeding @@ -612,6 +599,9 @@ function discoverController($element, $route, $scope, $timeout, $window, Promise timefield: getTimeField(), savedSearch: savedSearch, indexPatternList: $route.current.locals.savedObjects.ip.list, + config: config, + fixedScroll: createFixedScroll($scope, $timeout), + setHeaderActionMenu: getHeaderActionMenuMounter(), }; const shouldSearchOnPageLoad = () => { @@ -771,6 +761,7 @@ function discoverController($element, $route, $scope, $timeout, $window, Promise if (!init.complete) return; $scope.fetchCounter++; $scope.fetchError = undefined; + $scope.minimumVisibleRows = 50; if (!validateTimeRange(timefilter.getTime(), toastNotifications)) { $scope.resultState = 'none'; return; @@ -868,9 +859,6 @@ function discoverController($element, $route, $scope, $timeout, $window, Promise tabifiedData, getDimensions($scope.vis.data.aggs.aggs, $scope.timeRange) ); - if ($scope.vis.data.aggs.aggs[1]) { - $scope.bucketInterval = $scope.vis.data.aggs.aggs[1].buckets.getInterval(); - } $scope.updateTime(); } diff --git a/src/plugins/discover/public/application/angular/discover_legacy.html b/src/plugins/discover/public/application/angular/discover_legacy.html new file mode 100644 index 00000000000000..8582f71c0cb889 --- /dev/null +++ b/src/plugins/discover/public/application/angular/discover_legacy.html @@ -0,0 +1,36 @@ + + + + diff --git a/src/plugins/discover/public/application/angular/discover_state.ts b/src/plugins/discover/public/application/angular/discover_state.ts index ac0dc054485f04..5ddb6a92b5fd48 100644 --- a/src/plugins/discover/public/application/angular/discover_state.ts +++ b/src/plugins/discover/public/application/angular/discover_state.ts @@ -55,6 +55,10 @@ export interface AppState { * Array of the used sorting [[field,direction],...] */ sort?: string[][]; + /** + * id of the used saved query + */ + savedQuery?: string; } interface GetStateParams { diff --git a/src/plugins/discover/public/application/angular/doc_table/create_doc_table_react.tsx b/src/plugins/discover/public/application/angular/doc_table/create_doc_table_react.tsx new file mode 100644 index 00000000000000..ad2b674af014c8 --- /dev/null +++ b/src/plugins/discover/public/application/angular/doc_table/create_doc_table_react.tsx @@ -0,0 +1,131 @@ +/* + * 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 angular, { auto, ICompileService, IScope } from 'angular'; +import { render } from 'react-dom'; +import React, { useRef, useEffect } from 'react'; +import { getServices, IIndexPattern } from '../../../kibana_services'; +import { IndexPatternField } from '../../../../../data/common/index_patterns'; +export type AngularScope = IScope; + +export interface AngularDirective { + template: string; +} + +/** + * Compiles and injects the give angular template into the given dom node + * returns a function to cleanup the injected angular element + */ +export async function injectAngularElement( + domNode: Element, + template: string, + scopeProps: any, + getInjector: () => Promise +): Promise<() => void> { + const $injector = await getInjector(); + const rootScope: AngularScope = $injector.get('$rootScope'); + const $compile: ICompileService = $injector.get('$compile'); + const newScope = Object.assign(rootScope.$new(), scopeProps); + + const $target = angular.element(domNode); + const $element = angular.element(template); + + newScope.$apply(() => { + const linkFn = $compile($element); + $target.empty().append($element); + linkFn(newScope); + }); + + return () => { + newScope.$destroy(); + }; +} + +/** + * Converts a given legacy angular directive to a render function + * for usage in a react component. Note that the rendering is async + */ +export function convertDirectiveToRenderFn( + directive: AngularDirective, + getInjector: () => Promise +) { + return (domNode: Element, props: any) => { + let rejected = false; + + const cleanupFnPromise = injectAngularElement(domNode, directive.template, props, getInjector); + cleanupFnPromise.catch(() => { + rejected = true; + render(
error
, domNode); + }); + + return () => { + if (!rejected) { + // for cleanup + // http://roubenmeschian.com/rubo/?p=51 + cleanupFnPromise.then((cleanup) => cleanup()); + } + }; + }; +} + +export interface DocTableLegacyProps { + columns: string[]; + searchDescription?: string; + searchTitle?: string; + onFilter: (field: IndexPatternField | string, value: string, type: '+' | '-') => void; + rows: Array>; + indexPattern: IIndexPattern; + minimumVisibleRows: number; + onAddColumn: (column: string) => void; + onSort: (sort: string[][]) => void; + onMoveColumn: (columns: string, newIdx: number) => void; + onRemoveColumn: (column: string) => void; + sort?: string[][]; +} + +export function DocTableLegacy(renderProps: DocTableLegacyProps) { + const renderFn = convertDirectiveToRenderFn( + { + template: ``, + }, + () => getServices().getEmbeddableInjector() + ); + const ref = useRef(null); + useEffect(() => { + if (ref && ref.current) { + return renderFn(ref.current, renderProps); + } + }, [renderFn, renderProps]); + return
; +} diff --git a/src/plugins/discover/public/application/angular/doc_table/doc_table.ts b/src/plugins/discover/public/application/angular/doc_table/doc_table.ts index f972c158ff3dd6..735ee9f555740e 100644 --- a/src/plugins/discover/public/application/angular/doc_table/doc_table.ts +++ b/src/plugins/discover/public/application/angular/doc_table/doc_table.ts @@ -50,10 +50,6 @@ export function createDocTableDirective(pagerFactory: any, $filter: any) { inspectorAdapters: '=?', }, link: ($scope: LazyScope, $el: JQuery) => { - $scope.$watch('minimumVisibleRows', (minimumVisibleRows: number) => { - $scope.limit = Math.max(minimumVisibleRows || 50, $scope.limit || 50); - }); - $scope.persist = { sorting: $scope.sorting, columns: $scope.columns, @@ -77,7 +73,7 @@ export function createDocTableDirective(pagerFactory: any, $filter: any) { if (!hits) return; // Reset infinite scroll limit - $scope.limit = 50; + $scope.limit = $scope.minimumVisibleRows || 50; if (hits.length === 0) { dispatchRenderComplete($el[0]); diff --git a/src/plugins/discover/public/application/components/create_discover_legacy_directive.ts b/src/plugins/discover/public/application/components/create_discover_legacy_directive.ts new file mode 100644 index 00000000000000..a3502cbb211fa5 --- /dev/null +++ b/src/plugins/discover/public/application/components/create_discover_legacy_directive.ts @@ -0,0 +1,56 @@ +/* + * 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 { DiscoverLegacy } from './discover_legacy'; + +export function createDiscoverLegacyDirective(reactDirective: any) { + return reactDirective(DiscoverLegacy, [ + ['addColumn', { watchDepth: 'reference' }], + ['fetch', { watchDepth: 'reference' }], + ['fetchCounter', { watchDepth: 'reference' }], + ['fetchError', { watchDepth: 'reference' }], + ['fieldCounts', { watchDepth: 'reference' }], + ['histogramData', { watchDepth: 'reference' }], + ['hits', { watchDepth: 'reference' }], + ['indexPattern', { watchDepth: 'reference' }], + ['minimumVisibleRows', { watchDepth: 'reference' }], + ['onAddFilter', { watchDepth: 'reference' }], + ['onChangeInterval', { watchDepth: 'reference' }], + ['onMoveColumn', { watchDepth: 'reference' }], + ['onRemoveColumn', { watchDepth: 'reference' }], + ['onSetColumns', { watchDepth: 'reference' }], + ['onSkipBottomButtonClick', { watchDepth: 'reference' }], + ['onSort', { watchDepth: 'reference' }], + ['opts', { watchDepth: 'reference' }], + ['resetQuery', { watchDepth: 'reference' }], + ['resultState', { watchDepth: 'reference' }], + ['rows', { watchDepth: 'reference' }], + ['savedSearch', { watchDepth: 'reference' }], + ['searchSource', { watchDepth: 'reference' }], + ['setIndexPattern', { watchDepth: 'reference' }], + ['showSaveQuery', { watchDepth: 'reference' }], + ['state', { watchDepth: 'reference' }], + ['timefilterUpdateHandler', { watchDepth: 'reference' }], + ['timeRange', { watchDepth: 'reference' }], + ['topNavMenu', { watchDepth: 'reference' }], + ['updateQuery', { watchDepth: 'reference' }], + ['updateSavedQueryId', { watchDepth: 'reference' }], + ['vis', { watchDepth: 'reference' }], + ]); +} diff --git a/src/plugins/discover/public/application/components/discover_legacy.tsx b/src/plugins/discover/public/application/components/discover_legacy.tsx new file mode 100644 index 00000000000000..1a988436492592 --- /dev/null +++ b/src/plugins/discover/public/application/components/discover_legacy.tsx @@ -0,0 +1,324 @@ +/* + * 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 React, { useState, useCallback, useEffect } from 'react'; +import classNames from 'classnames'; +import { EuiButtonEmpty, EuiButtonIcon } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage, I18nProvider } from '@kbn/i18n/react'; +import { IUiSettingsClient, MountPoint } from 'kibana/public'; +import { HitsCounter } from './hits_counter'; +import { TimechartHeader } from './timechart_header'; +import { DiscoverSidebar } from './sidebar'; +import { getServices, IIndexPattern } from '../../kibana_services'; +// @ts-ignore +import { DiscoverNoResults } from '../angular/directives/no_results'; +import { DiscoverUninitialized } from '../angular/directives/uninitialized'; +import { DiscoverHistogram } from '../angular/directives/histogram'; +import { LoadingSpinner } from './loading_spinner/loading_spinner'; +import { DiscoverFetchError, FetchError } from './fetch_error/fetch_error'; +import { DocTableLegacy } from '../angular/doc_table/create_doc_table_react'; +import { SkipBottomButton } from './skip_bottom_button'; +import { + IndexPatternField, + search, + ISearchSource, + TimeRange, + Query, + IndexPatternAttributes, +} from '../../../../data/public'; +import { Chart } from '../angular/helpers/point_series'; +import { AppState } from '../angular/discover_state'; +import { SavedSearch } from '../../saved_searches'; + +import { SavedObject } from '../../../../../core/types'; +import { Vis } from '../../../../visualizations/public'; +import { TopNavMenuData } from '../../../../navigation/public'; + +export interface DiscoverLegacyProps { + addColumn: (column: string) => void; + fetch: () => void; + fetchCounter: number; + fetchError: FetchError; + fieldCounts: Record; + histogramData: Chart; + hits: number; + indexPattern: IIndexPattern; + minimumVisibleRows: number; + onAddFilter: (field: IndexPatternField | string, value: string, type: '+' | '-') => void; + onChangeInterval: (interval: string) => void; + onMoveColumn: (columns: string, newIdx: number) => void; + onRemoveColumn: (column: string) => void; + onSetColumns: (columns: string[]) => void; + onSkipBottomButtonClick: () => void; + onSort: (sort: string[][]) => void; + opts: { + savedSearch: SavedSearch; + config: IUiSettingsClient; + indexPatternList: Array>; + timefield: string; + sampleSize: number; + fixedScroll: (el: HTMLElement) => void; + setHeaderActionMenu: (menuMount: MountPoint | undefined) => void; + }; + resetQuery: () => void; + resultState: string; + rows: Array>; + searchSource: ISearchSource; + setIndexPattern: (id: string) => void; + showSaveQuery: boolean; + state: AppState; + timefilterUpdateHandler: (ranges: { from: number; to: number }) => void; + timeRange?: { from: string; to: string }; + topNavMenu: TopNavMenuData[]; + updateQuery: (payload: { dateRange: TimeRange; query?: Query }, isUpdate?: boolean) => void; + updateSavedQueryId: (savedQueryId?: string) => void; + vis?: Vis; +} + +export function DiscoverLegacy({ + addColumn, + fetch, + fetchCounter, + fetchError, + fieldCounts, + histogramData, + hits, + indexPattern, + minimumVisibleRows, + onAddFilter, + onChangeInterval, + onMoveColumn, + onRemoveColumn, + onSkipBottomButtonClick, + onSort, + opts, + resetQuery, + resultState, + rows, + searchSource, + setIndexPattern, + showSaveQuery, + state, + timefilterUpdateHandler, + timeRange, + topNavMenu, + updateQuery, + updateSavedQueryId, + vis, +}: DiscoverLegacyProps) { + const [isSidebarClosed, setIsSidebarClosed] = useState(false); + const { TopNavMenu } = getServices().navigation.ui; + const { savedSearch, indexPatternList } = opts; + const bucketAggConfig = vis?.data?.aggs?.aggs[1]; + const bucketInterval = + bucketAggConfig && search.aggs.isDateHistogramBucketAggConfig(bucketAggConfig) + ? bucketAggConfig.buckets?.getInterval() + : undefined; + const [fixedScrollEl, setFixedScrollEl] = useState(); + + useEffect(() => (fixedScrollEl ? opts.fixedScroll(fixedScrollEl) : undefined), [ + fixedScrollEl, + opts, + ]); + const fixedScrollRef = useCallback( + (node: HTMLElement) => { + if (node !== null) { + setFixedScrollEl(node); + } + }, + [setFixedScrollEl] + ); + const sidebarClassName = classNames({ + closed: isSidebarClosed, + }); + + const mainSectionClassName = classNames({ + 'col-md-10': !isSidebarClosed, + 'col-md-12': isSidebarClosed, + }); + + return ( + +
+

{savedSearch.title}

+ +
+
+
+ {!isSidebarClosed && ( +
+ +
+ )} + setIsSidebarClosed(!isSidebarClosed)} + data-test-subj="collapseSideBarButton" + aria-controls="discover-sidebar" + aria-expanded={isSidebarClosed ? 'false' : 'true'} + aria-label="Toggle sidebar" + className="dscCollapsibleSidebar__collapseButton" + /> +
+
+ {resultState === 'none' && ( + + )} + {resultState === 'uninitialized' && } + {/* @TODO: Solved in the Angular way to satisfy functional test - should be improved*/} + + {fetchError && } +
+ +
+
+ {resultState === 'ready' && ( +
+ + 0 ? hits : 0} + showResetButton={!!(savedSearch && savedSearch.id)} + onResetQuery={resetQuery} + /> + {opts.timefield && ( + + )} + + {opts.timefield && ( +
+ {vis && rows.length !== 0 && ( +
+ +
+ )} +
+ )} + +
+
+

+ +

+ {rows && rows.length && ( +
+ + + ​ + + {rows.length === opts.sampleSize && ( +
+ + + window.scrollTo(0, 0)}> + + +
+ )} +
+ )} +
+
+
+ )} +
+
+
+
+
+ ); +} diff --git a/src/plugins/discover/public/application/components/fetch_error/fetch_error.tsx b/src/plugins/discover/public/application/components/fetch_error/fetch_error.tsx index 880a493983adfa..dc8f1238eac6fd 100644 --- a/src/plugins/discover/public/application/components/fetch_error/fetch_error.tsx +++ b/src/plugins/discover/public/application/components/fetch_error/fetch_error.tsx @@ -20,18 +20,20 @@ import './fetch_error.scss'; import React, { Fragment } from 'react'; import { FormattedMessage, I18nProvider } from '@kbn/i18n/react'; import { EuiFlexGroup, EuiFlexItem, EuiCallOut, EuiCodeBlock, EuiSpacer } from '@elastic/eui'; -import { getAngularModule, getServices } from '../../../kibana_services'; +import { getServices } from '../../../kibana_services'; + +export interface FetchError { + lang: string; + script: string; + message: string; + error: string; +} interface Props { - fetchError: { - lang: string; - script: string; - message: string; - error: string; - }; + fetchError: FetchError; } -const DiscoverFetchError = ({ fetchError }: Props) => { +export const DiscoverFetchError = ({ fetchError }: Props) => { if (!fetchError) { return null; } @@ -92,9 +94,3 @@ const DiscoverFetchError = ({ fetchError }: Props) => { ); }; - -export function createFetchErrorDirective(reactDirective: any) { - return reactDirective(DiscoverFetchError); -} - -getAngularModule().directive('discoverFetchError', createFetchErrorDirective); diff --git a/src/plugins/discover/public/application/components/fetch_error/index.js b/src/plugins/discover/public/application/components/fetch_error/index.ts similarity index 100% rename from src/plugins/discover/public/application/components/fetch_error/index.js rename to src/plugins/discover/public/application/components/fetch_error/index.ts diff --git a/src/plugins/discover/public/application/components/hits_counter/hits_counter_directive.ts b/src/plugins/discover/public/application/components/hits_counter/hits_counter_directive.ts deleted file mode 100644 index 8d45e28370cade..00000000000000 --- a/src/plugins/discover/public/application/components/hits_counter/hits_counter_directive.ts +++ /dev/null @@ -1,27 +0,0 @@ -/* - * 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 { HitsCounter } from './hits_counter'; - -export function createHitsCounterDirective(reactDirective: any) { - return reactDirective(HitsCounter, [ - ['hits', { watchDepth: 'reference' }], - ['showResetButton', { watchDepth: 'reference' }], - ['onResetQuery', { watchDepth: 'reference' }], - ]); -} diff --git a/src/plugins/discover/public/application/components/hits_counter/index.ts b/src/plugins/discover/public/application/components/hits_counter/index.ts index 58e7a9eda7f51a..0ce95f061df17b 100644 --- a/src/plugins/discover/public/application/components/hits_counter/index.ts +++ b/src/plugins/discover/public/application/components/hits_counter/index.ts @@ -18,4 +18,3 @@ */ export { HitsCounter } from './hits_counter'; -export { createHitsCounterDirective } from './hits_counter_directive'; diff --git a/src/plugins/discover/public/application/components/loading_spinner/loading_spinner.tsx b/src/plugins/discover/public/application/components/loading_spinner/loading_spinner.tsx index 44b922bf0f708e..4e1754638d4796 100644 --- a/src/plugins/discover/public/application/components/loading_spinner/loading_spinner.tsx +++ b/src/plugins/discover/public/application/components/loading_spinner/loading_spinner.tsx @@ -18,24 +18,18 @@ */ import React from 'react'; import { EuiLoadingSpinner, EuiTitle, EuiSpacer } from '@elastic/eui'; -import { FormattedMessage, I18nProvider } from '@kbn/i18n/react'; +import { FormattedMessage } from '@kbn/i18n/react'; export function LoadingSpinner() { return ( - - <> - -

- -

-
- - - -
+ <> + +

+ +

+
+ + + ); } - -export function createLoadingSpinnerDirective(reactDirective: any) { - return reactDirective(LoadingSpinner); -} diff --git a/src/plugins/discover/public/application/components/sidebar/discover_sidebar.tsx b/src/plugins/discover/public/application/components/sidebar/discover_sidebar.tsx index 850624888b24a3..2407cff181901c 100644 --- a/src/plugins/discover/public/application/components/sidebar/discover_sidebar.tsx +++ b/src/plugins/discover/public/application/components/sidebar/discover_sidebar.tsx @@ -68,7 +68,7 @@ export interface DiscoverSidebarProps { /** * Currently selected index pattern */ - selectedIndexPattern: IndexPattern; + selectedIndexPattern?: IndexPattern; /** * Callback function to select another index pattern */ diff --git a/src/plugins/discover/public/application/components/sidebar/discover_sidebar_directive.ts b/src/plugins/discover/public/application/components/sidebar/discover_sidebar_directive.ts deleted file mode 100644 index b271c920e5e010..00000000000000 --- a/src/plugins/discover/public/application/components/sidebar/discover_sidebar_directive.ts +++ /dev/null @@ -1,33 +0,0 @@ -/* - * 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 { DiscoverSidebar } from './discover_sidebar'; - -export function createDiscoverSidebarDirective(reactDirective: any) { - return reactDirective(DiscoverSidebar, [ - ['columns', { watchDepth: 'reference' }], - ['fieldCounts', { watchDepth: 'reference' }], - ['hits', { watchDepth: 'reference' }], - ['indexPatternList', { watchDepth: 'reference' }], - ['onAddField', { watchDepth: 'reference' }], - ['onAddFilter', { watchDepth: 'reference' }], - ['onRemoveField', { watchDepth: 'reference' }], - ['selectedIndexPattern', { watchDepth: 'reference' }], - ['setIndexPattern', { watchDepth: 'reference' }], - ]); -} diff --git a/src/plugins/discover/public/application/components/sidebar/index.ts b/src/plugins/discover/public/application/components/sidebar/index.ts index 1b837840b52f69..aec8dfc86e817e 100644 --- a/src/plugins/discover/public/application/components/sidebar/index.ts +++ b/src/plugins/discover/public/application/components/sidebar/index.ts @@ -18,4 +18,3 @@ */ export { DiscoverSidebar } from './discover_sidebar'; -export { createDiscoverSidebarDirective } from './discover_sidebar_directive'; diff --git a/src/plugins/discover/public/application/components/sidebar/lib/get_details.ts b/src/plugins/discover/public/application/components/sidebar/lib/get_details.ts index 13051f88c9591a..22a6e7a6285551 100644 --- a/src/plugins/discover/public/application/components/sidebar/lib/get_details.ts +++ b/src/plugins/discover/public/application/components/sidebar/lib/get_details.ts @@ -25,8 +25,11 @@ export function getDetails( field: IndexPatternField, hits: Array>, columns: string[], - indexPattern: IndexPattern + indexPattern?: IndexPattern ) { + if (!indexPattern) { + return {}; + } const details = { ...fieldCalculator.getFieldValueCounts({ hits, diff --git a/src/plugins/discover/public/application/components/sidebar/lib/get_index_pattern_field_list.ts b/src/plugins/discover/public/application/components/sidebar/lib/get_index_pattern_field_list.ts index c96a8f5ce17b98..eff7c2ec3c1c84 100644 --- a/src/plugins/discover/public/application/components/sidebar/lib/get_index_pattern_field_list.ts +++ b/src/plugins/discover/public/application/components/sidebar/lib/get_index_pattern_field_list.ts @@ -20,8 +20,8 @@ import { difference } from 'lodash'; import { IndexPattern, IndexPatternField } from 'src/plugins/data/public'; export function getIndexPatternFieldList( - indexPattern: IndexPattern, - fieldCounts: Record + indexPattern?: IndexPattern, + fieldCounts?: Record ) { if (!indexPattern || !fieldCounts) return []; diff --git a/src/plugins/discover/public/application/components/skip_bottom_button/index.ts b/src/plugins/discover/public/application/components/skip_bottom_button/index.ts index 2feaa35e0d61f7..b3d93e40be0bd1 100644 --- a/src/plugins/discover/public/application/components/skip_bottom_button/index.ts +++ b/src/plugins/discover/public/application/components/skip_bottom_button/index.ts @@ -18,4 +18,3 @@ */ export { SkipBottomButton } from './skip_bottom_button'; -export { createSkipBottomButtonDirective } from './skip_bottom_button_directive'; diff --git a/src/plugins/discover/public/application/components/skip_bottom_button/skip_bottom_button_directive.ts b/src/plugins/discover/public/application/components/skip_bottom_button/skip_bottom_button_directive.ts deleted file mode 100644 index 27f17b25fd447c..00000000000000 --- a/src/plugins/discover/public/application/components/skip_bottom_button/skip_bottom_button_directive.ts +++ /dev/null @@ -1,23 +0,0 @@ -/* - * 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 { SkipBottomButton } from './skip_bottom_button'; - -export function createSkipBottomButtonDirective(reactDirective: any) { - return reactDirective(SkipBottomButton, [['onClick', { watchDepth: 'reference' }]]); -} diff --git a/src/plugins/discover/public/application/components/timechart_header/index.ts b/src/plugins/discover/public/application/components/timechart_header/index.ts index 43473319c318ce..34bed2cd72a742 100644 --- a/src/plugins/discover/public/application/components/timechart_header/index.ts +++ b/src/plugins/discover/public/application/components/timechart_header/index.ts @@ -18,4 +18,3 @@ */ export { TimechartHeader } from './timechart_header'; -export { createTimechartHeaderDirective } from './timechart_header_directive'; diff --git a/src/plugins/discover/public/application/components/timechart_header/timechart_header.test.tsx b/src/plugins/discover/public/application/components/timechart_header/timechart_header.test.tsx index a4c10e749d868e..7889b05a884154 100644 --- a/src/plugins/discover/public/application/components/timechart_header/timechart_header.test.tsx +++ b/src/plugins/discover/public/application/components/timechart_header/timechart_header.test.tsx @@ -29,8 +29,10 @@ describe('timechart header', function () { beforeAll(() => { props = { - from: 'May 14, 2020 @ 11:05:13.590', - to: 'May 14, 2020 @ 11:20:13.590', + timeRange: { + from: 'May 14, 2020 @ 11:05:13.590', + to: 'May 14, 2020 @ 11:20:13.590', + }, stateInterval: 's', options: [ { @@ -47,9 +49,11 @@ describe('timechart header', function () { }, ], onChangeInterval: jest.fn(), - showScaledInfo: undefined, - bucketIntervalDescription: 'second', - bucketIntervalScale: undefined, + bucketInterval: { + scaled: undefined, + description: 'second', + scale: undefined, + }, }; }); @@ -58,8 +62,8 @@ describe('timechart header', function () { expect(component.find(EuiIconTip).length).toBe(0); }); - it('TimechartHeader renders an info text by providing the showScaledInfo property', () => { - props.showScaledInfo = true; + it('TimechartHeader renders an info when bucketInterval.scale is set to true', () => { + props.bucketInterval!.scaled = true; component = mountWithIntl(); expect(component.find(EuiIconTip).length).toBe(1); }); diff --git a/src/plugins/discover/public/application/components/timechart_header/timechart_header.tsx b/src/plugins/discover/public/application/components/timechart_header/timechart_header.tsx index 8789847058affb..1451106827ee0d 100644 --- a/src/plugins/discover/public/application/components/timechart_header/timechart_header.tsx +++ b/src/plugins/discover/public/application/components/timechart_header/timechart_header.tsx @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -import React, { useState, useEffect } from 'react'; +import React, { useState, useEffect, useCallback } from 'react'; import { EuiFlexGroup, EuiFlexItem, @@ -27,16 +27,28 @@ import { } from '@elastic/eui'; import { I18nProvider } from '@kbn/i18n/react'; import { i18n } from '@kbn/i18n'; +import moment from 'moment'; export interface TimechartHeaderProps { /** - * the query from date string + * Format of date to be displayed */ - from: string; + dateFormat?: string; /** - * the query to date string + * Interval for the buckets of the recent request */ - to: string; + bucketInterval?: { + scaled?: boolean; + description?: string; + scale?: number; + }; + /** + * Range of dates to be displayed + */ + timeRange?: { + from: string; + to: string; + }; /** * Interval Options */ @@ -49,31 +61,29 @@ export interface TimechartHeaderProps { * selected interval */ stateInterval: string; - /** - * displays the scaled info of the interval - */ - showScaledInfo: boolean | undefined; - /** - * scaled info description - */ - bucketIntervalDescription: string; - /** - * bucket interval scale - */ - bucketIntervalScale: number | undefined; } export function TimechartHeader({ - from, - to, + bucketInterval, + dateFormat, + timeRange, options, onChangeInterval, stateInterval, - showScaledInfo, - bucketIntervalDescription, - bucketIntervalScale, }: TimechartHeaderProps) { const [interval, setInterval] = useState(stateInterval); + const toMoment = useCallback( + (datetime: string) => { + if (!datetime) { + return ''; + } + if (!dateFormat) { + return datetime; + } + return moment(datetime).format(dateFormat); + }, + [dateFormat] + ); useEffect(() => { setInterval(stateInterval); @@ -84,6 +94,10 @@ export function TimechartHeader({ onChangeInterval(e.target.value); }; + if (!timeRange || !bucketInterval) { + return null; + } + return ( @@ -95,7 +109,7 @@ export function TimechartHeader({ delay="long" > - {`${from} - ${to} ${ + {`${toMoment(timeRange.from)} - ${toMoment(timeRange.to)} ${ interval !== 'auto' ? i18n.translate('discover.timechartHeader.timeIntervalSelect.per', { defaultMessage: 'per', @@ -125,7 +139,7 @@ export function TimechartHeader({ value={interval} onChange={handleIntervalChange} append={ - showScaledInfo ? ( + bucketInterval.scaled ? ( 1 + bucketInterval!.scale && bucketInterval!.scale > 1 ? i18n.translate('discover.bucketIntervalTooltip.tooLargeBucketsText', { defaultMessage: 'buckets that are too large', }) : i18n.translate('discover.bucketIntervalTooltip.tooManyBucketsText', { defaultMessage: 'too many buckets', }), - bucketIntervalDescription, + bucketIntervalDescription: bucketInterval.description, }, })} color="warning" diff --git a/src/plugins/discover/public/application/components/timechart_header/timechart_header_directive.ts b/src/plugins/discover/public/application/components/timechart_header/timechart_header_directive.ts deleted file mode 100644 index 027236cd465215..00000000000000 --- a/src/plugins/discover/public/application/components/timechart_header/timechart_header_directive.ts +++ /dev/null @@ -1,32 +0,0 @@ -/* - * 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 { TimechartHeader } from './timechart_header'; - -export function createTimechartHeaderDirective(reactDirective: any) { - return reactDirective(TimechartHeader, [ - ['from', { watchDepth: 'reference' }], - ['to', { watchDepth: 'reference' }], - ['options', { watchDepth: 'reference' }], - ['onChangeInterval', { watchDepth: 'reference' }], - ['stateInterval', { watchDepth: 'reference' }], - ['showScaledInfo', { watchDepth: 'reference' }], - ['bucketIntervalDescription', { watchDepth: 'reference' }], - ['bucketIntervalScale', { watchDepth: 'reference' }], - ]); -} diff --git a/src/plugins/discover/public/build_services.ts b/src/plugins/discover/public/build_services.ts index 12562d8571a252..fdb14b3f1f63e2 100644 --- a/src/plugins/discover/public/build_services.ts +++ b/src/plugins/discover/public/build_services.ts @@ -44,6 +44,7 @@ import { createSavedSearchesLoader, SavedSearch } from './saved_searches'; import { getHistory } from './kibana_services'; import { KibanaLegacyStart } from '../../kibana_legacy/public'; import { UrlForwardingStart } from '../../url_forwarding/public'; +import { NavigationPublicPluginStart } from '../../navigation/public'; export interface DiscoverServices { addBasePath: (path: string) => string; @@ -58,6 +59,7 @@ export interface DiscoverServices { indexPatterns: IndexPatternsContract; inspector: InspectorPublicPluginStart; metadata: { branch: string }; + navigation: NavigationPublicPluginStart; share?: SharePluginStart; kibanaLegacy: KibanaLegacyStart; urlForwarding: UrlForwardingStart; @@ -65,6 +67,7 @@ export interface DiscoverServices { toastNotifications: ToastsStart; getSavedSearchById: (id: string) => Promise; getSavedSearchUrlById: (id: string) => Promise; + getEmbeddableInjector: any; uiSettings: IUiSettingsClient; visualizations: VisualizationsStart; } @@ -72,7 +75,8 @@ export interface DiscoverServices { export async function buildServices( core: CoreStart, plugins: DiscoverStartPlugins, - context: PluginInitializerContext + context: PluginInitializerContext, + getEmbeddableInjector: any ): Promise { const services: SavedObjectKibanaServices = { savedObjectsClient: core.savedObjects.client, @@ -92,6 +96,7 @@ export async function buildServices( docLinks: core.docLinks, theme: plugins.charts.theme, filterManager: plugins.data.query.filterManager, + getEmbeddableInjector, getSavedSearchById: async (id: string) => savedObjectService.get(id), getSavedSearchUrlById: async (id: string) => savedObjectService.urlFor(id), history: getHistory, @@ -100,6 +105,7 @@ export async function buildServices( metadata: { branch: context.env.packageInfo.branch, }, + navigation: plugins.navigation, share: plugins.share, kibanaLegacy: plugins.kibanaLegacy, urlForwarding: plugins.urlForwarding, diff --git a/src/plugins/discover/public/get_inner_angular.ts b/src/plugins/discover/public/get_inner_angular.ts index 85b0752f134631..1ca0bb20e8723b 100644 --- a/src/plugins/discover/public/get_inner_angular.ts +++ b/src/plugins/discover/public/get_inner_angular.ts @@ -40,16 +40,10 @@ import { createTableRowDirective } from './application/angular/doc_table/compone import { createPagerFactory } from './application/angular/doc_table/lib/pager/pager_factory'; import { createInfiniteScrollDirective } from './application/angular/doc_table/infinite_scroll'; import { createDocViewerDirective } from './application/angular/doc_viewer'; -import { CollapsibleSidebarProvider } from './application/angular/directives/collapsible_sidebar/collapsible_sidebar'; -// @ts-ignore -import { FixedScrollProvider } from './application/angular/directives/fixed_scroll'; -// @ts-ignore -import { DebounceProviderTimeout } from './application/angular/directives/debounce/debounce'; import { createRenderCompleteDirective } from './application/angular/directives/render_complete'; import { initAngularBootstrap, configureAppAngularModule, - KbnAccessibleClickProvider, PrivateProvider, PromiseServiceCreator, registerListenEventListener, @@ -57,14 +51,10 @@ import { createTopNavDirective, createTopNavHelper, } from '../../kibana_legacy/public'; -import { createDiscoverSidebarDirective } from './application/components/sidebar'; -import { createHitsCounterDirective } from '././application/components/hits_counter'; -import { createLoadingSpinnerDirective } from '././application/components/loading_spinner/loading_spinner'; -import { createTimechartHeaderDirective } from './application/components/timechart_header'; import { createContextErrorMessageDirective } from './application/components/context_error_message'; import { DiscoverStartPlugins } from './plugin'; import { getScopedHistory } from './kibana_services'; -import { createSkipBottomButtonDirective } from './application/components/skip_bottom_button'; +import { createDiscoverLegacyDirective } from './application/components/create_discover_legacy_directive'; /** * returns the main inner angular module, it contains all the parts of Angular Discover @@ -88,11 +78,9 @@ export function getInnerAngularModule( export function getInnerAngularModuleEmbeddable( name: string, core: CoreStart, - deps: DiscoverStartPlugins, - context: PluginInitializerContext + deps: DiscoverStartPlugins ) { - const module = initializeInnerAngularModule(name, core, deps.navigation, deps.data, true); - return module; + return initializeInnerAngularModule(name, core, deps.navigation, deps.data, true); } let initialized = false; @@ -129,8 +117,7 @@ export function initializeInnerAngularModule( ]) .config(watchMultiDecorator) .directive('icon', (reactDirective) => reactDirective(EuiIcon)) - .directive('renderComplete', createRenderCompleteDirective) - .service('debounce', ['$timeout', DebounceProviderTimeout]); + .directive('renderComplete', createRenderCompleteDirective); } return angular @@ -149,18 +136,9 @@ export function initializeInnerAngularModule( ]) .config(watchMultiDecorator) .run(registerListenEventListener) - .directive('icon', (reactDirective) => reactDirective(EuiIcon)) - .directive('kbnAccessibleClick', KbnAccessibleClickProvider) - .directive('collapsibleSidebar', CollapsibleSidebarProvider) - .directive('fixedScroll', FixedScrollProvider) .directive('renderComplete', createRenderCompleteDirective) - .directive('discoverSidebar', createDiscoverSidebarDirective) - .directive('skipBottomButton', createSkipBottomButtonDirective) - .directive('hitsCounter', createHitsCounterDirective) - .directive('loadingSpinner', createLoadingSpinnerDirective) - .directive('timechartHeader', createTimechartHeaderDirective) - .directive('contextErrorMessage', createContextErrorMessageDirective) - .service('debounce', ['$timeout', DebounceProviderTimeout]); + .directive('discoverLegacy', createDiscoverLegacyDirective) + .directive('contextErrorMessage', createContextErrorMessageDirective); } function createLocalPromiseModule() { diff --git a/src/plugins/discover/public/plugin.ts b/src/plugins/discover/public/plugin.ts index 0bdc5ad95b3918..4296a0867fbe5c 100644 --- a/src/plugins/discover/public/plugin.ts +++ b/src/plugins/discover/public/plugin.ts @@ -327,7 +327,12 @@ export class DiscoverPlugin if (this.servicesInitialized) { return { core, plugins }; } - const services = await buildServices(core, plugins, this.initializerContext); + const services = await buildServices( + core, + plugins, + this.initializerContext, + this.getEmbeddableInjector + ); setServices(services); this.servicesInitialized = true; @@ -380,12 +385,7 @@ export class DiscoverPlugin const { core, plugins } = await this.initializeServices(); getServices().kibanaLegacy.loadFontAwesome(); const { getInnerAngularModuleEmbeddable } = await import('./get_inner_angular'); - getInnerAngularModuleEmbeddable( - embeddableAngularName, - core, - plugins, - this.initializerContext - ); + getInnerAngularModuleEmbeddable(embeddableAngularName, core, plugins); const mountpoint = document.createElement('div'); this.embeddableInjector = angular.bootstrap(mountpoint, [embeddableAngularName]); } diff --git a/src/plugins/discover/public/saved_searches/types.ts b/src/plugins/discover/public/saved_searches/types.ts index d601d087afcee8..13361cb647ddc0 100644 --- a/src/plugins/discover/public/saved_searches/types.ts +++ b/src/plugins/discover/public/saved_searches/types.ts @@ -28,6 +28,7 @@ export interface SavedSearch { columns: string[]; sort: SortOrder[]; destroy: () => void; + lastSavedTitle?: string; } export interface SavedSearchLoader { get: (id: string) => Promise; diff --git a/test/functional/page_objects/discover_page.ts b/test/functional/page_objects/discover_page.ts index 5a224d930ee426..7a99509257bf7e 100644 --- a/test/functional/page_objects/discover_page.ts +++ b/test/functional/page_objects/discover_page.ts @@ -254,7 +254,7 @@ export function DiscoverPageProvider({ getService, getPageObjects }: FtrProvider } public async getSidebarWidth() { - const sidebar = await find.byCssSelector('.sidebar-list'); + const sidebar = await testSubjects.find('discover-sidebar'); return await sidebar.getAttribute('clientWidth'); } diff --git a/x-pack/plugins/reporting/server/lib/layouts/preserve_layout.css b/x-pack/plugins/reporting/server/lib/layouts/preserve_layout.css index 12ac5b27c7a4a1..35590df90fbb90 100644 --- a/x-pack/plugins/reporting/server/lib/layouts/preserve_layout.css +++ b/x-pack/plugins/reporting/server/lib/layouts/preserve_layout.css @@ -36,7 +36,7 @@ filter-bar, /* hide unusable controls */ discover-app .dscTimechart, discover-app .dscSidebar__container, -discover-app .kbnCollapsibleSidebar__collapseButton, +discover-app .dscCollapsibleSidebar__collapseButton, discover-app .discover-table-footer { display: none; } diff --git a/x-pack/plugins/reporting/server/lib/layouts/print.css b/x-pack/plugins/reporting/server/lib/layouts/print.css index 9b07e3c923138d..3ff39974536d25 100644 --- a/x-pack/plugins/reporting/server/lib/layouts/print.css +++ b/x-pack/plugins/reporting/server/lib/layouts/print.css @@ -35,7 +35,7 @@ filter-bar, /* hide unusable controls */ discover-app .dscTimechart, discover-app .dscSidebar__container, -discover-app .kbnCollapsibleSidebar__collapseButton, +discover-app .dscCollapsibleSidebar__collapseButton, discover-app .discover-table-footer { display: none; } diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index cdb70f2c8cec74..6f7aaed561d4c9 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -1435,10 +1435,7 @@ "discover.localMenu.saveTitle": "保存", "discover.localMenu.shareSearchDescription": "検索を共有します", "discover.localMenu.shareTitle": "共有", - "discover.noResults.addressShardFailuresTitle": "シャードエラーの解決", "discover.noResults.expandYourTimeRangeTitle": "時間範囲を拡大", - "discover.noResults.indexFailureIndexText": "インデックス {failureIndex}", - "discover.noResults.indexFailureShardText": "{index}、シャード {failureShard}", "discover.noResults.queryMayNotMatchTitle": "1つ以上の表示されているインデックスに日付フィールドが含まれています。クエリが現在の時間範囲のデータと一致しないか、現在選択された時間範囲にデータが全く存在しない可能性があります。データが存在する時間範囲に変えることができます。", "discover.noResults.searchExamples.400to499StatusCodeExampleTitle": "400-499のすべてのステータスコードを検索", "discover.noResults.searchExamples.400to499StatusCodeWithPhpExtensionExampleTitle": "400-499のphp拡張子のステータスコードを検索", @@ -1449,7 +1446,6 @@ "discover.noResults.searchExamples.queryStringSyntaxLinkText": "クエリ文字列の構文", "discover.noResults.searchExamples.refineYourQueryTitle": "クエリの調整", "discover.noResults.searchExamples.statusField200StatusCodeExampleTitle": "ステータスフィールドの200を検索", - "discover.noResults.shardFailuresDescription": "次のシャードエラーが発生しました。", "discover.notifications.invalidTimeRangeText": "指定された時間範囲が無効です。(開始:'{from}'、終了:'{to}')", "discover.notifications.invalidTimeRangeTitle": "無効な時間範囲", "discover.notifications.notSavedSearchTitle": "検索「{savedSearchTitle}」は保存されませんでした。", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 68eb59d3e4e89e..3121a80d808d0a 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -1436,10 +1436,7 @@ "discover.localMenu.saveTitle": "保存", "discover.localMenu.shareSearchDescription": "共享搜索", "discover.localMenu.shareTitle": "共享", - "discover.noResults.addressShardFailuresTitle": "解决分片错误", "discover.noResults.expandYourTimeRangeTitle": "展开时间范围", - "discover.noResults.indexFailureIndexText": "索引 {failureIndex}", - "discover.noResults.indexFailureShardText": "{index},分片 {failureShard}", "discover.noResults.queryMayNotMatchTitle": "您正在查看的一个或多个索引包含日期字段。您的查询在当前时间范围内可能不匹配任何数据,也可能在当前选定的时间范围内没有任何数据。您可以尝试将时间范围更改为包含数据的时间范围。", "discover.noResults.searchExamples.400to499StatusCodeExampleTitle": "查找所有介于 400-499 之间的状态代码", "discover.noResults.searchExamples.400to499StatusCodeWithPhpExtensionExampleTitle": "查找状态代码 400-499 以及扩展名 php", @@ -1450,7 +1447,6 @@ "discover.noResults.searchExamples.queryStringSyntaxLinkText": "查询字符串语法", "discover.noResults.searchExamples.refineYourQueryTitle": "优化您的查询", "discover.noResults.searchExamples.statusField200StatusCodeExampleTitle": "在状态字段中查找 200", - "discover.noResults.shardFailuresDescription": "发生了以下分片错误:", "discover.notifications.invalidTimeRangeText": "提供的时间范围无效。(起始:“{from}”,结束:“{to}”)", "discover.notifications.invalidTimeRangeTitle": "时间范围无效", "discover.notifications.notSavedSearchTitle": "搜索“{savedSearchTitle}”未保存。",