From 8619423351c9c0a02b2845869c41610660dcafec Mon Sep 17 00:00:00 2001 From: Joe Reuter Date: Mon, 10 Feb 2020 11:27:16 +0100 Subject: [PATCH 1/5] fix default app id key (#56997) --- src/plugins/kibana_legacy/server/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/kibana_legacy/server/index.ts b/src/plugins/kibana_legacy/server/index.ts index ca8ad6410eec3..4d0fe8364a66c 100644 --- a/src/plugins/kibana_legacy/server/index.ts +++ b/src/plugins/kibana_legacy/server/index.ts @@ -28,7 +28,7 @@ export const config: PluginConfigDescriptor = { schema: configSchema, deprecations: ({ renameFromRoot }) => [ // TODO: Remove deprecation once defaultAppId is deleted - renameFromRoot('kibana.defaultAppId', 'kibanaLegacy.defaultAppId', true), + renameFromRoot('kibana.defaultAppId', 'kibana_legacy.defaultAppId', true), ], }; From e0b7ffff69cac4f2431d248cb5b642670cad2070 Mon Sep 17 00:00:00 2001 From: MadameSheema Date: Mon, 10 Feb 2020 11:54:11 +0100 Subject: [PATCH 2/5] [SIEM] Overview Cypress test refactor (#56887) * extracts stub to a custom command * refactors overview tests Co-authored-by: Elastic Machine --- .../smoke_tests/overview/overview.spec.ts | 33 ++-- .../plugins/siem/cypress/screens/overview.ts | 144 ++++++++++++++++++ .../plugins/siem/cypress/support/commands.js | 10 ++ .../plugins/siem/cypress/support/index.d.ts | 11 ++ .../plugins/siem/cypress/tasks/overview.ts | 21 +++ .../plugins/siem/cypress/urls/navigation.ts | 1 + 6 files changed, 198 insertions(+), 22 deletions(-) create mode 100644 x-pack/legacy/plugins/siem/cypress/screens/overview.ts create mode 100644 x-pack/legacy/plugins/siem/cypress/support/index.d.ts create mode 100644 x-pack/legacy/plugins/siem/cypress/tasks/overview.ts diff --git a/x-pack/legacy/plugins/siem/cypress/integration/smoke_tests/overview/overview.spec.ts b/x-pack/legacy/plugins/siem/cypress/integration/smoke_tests/overview/overview.spec.ts index be66fdc86be36..64002aadc86d8 100644 --- a/x-pack/legacy/plugins/siem/cypress/integration/smoke_tests/overview/overview.spec.ts +++ b/x-pack/legacy/plugins/siem/cypress/integration/smoke_tests/overview/overview.spec.ts @@ -4,40 +4,29 @@ * you may not use this file except in compliance with the Elastic License. */ -import { OVERVIEW_PAGE } from '../../lib/urls'; -import { clearFetch, stubApi } from '../../lib/fixtures/helpers'; -import { - HOST_STATS, - NETWORK_STATS, - OVERVIEW_HOST_STATS, - OVERVIEW_NETWORK_STATS, - STAT_AUDITD, -} from '../../lib/overview/selectors'; +import { OVERVIEW_PAGE } from '../../../urls/navigation'; +import { HOST_STATS, NETWORK_STATS } from '../../../screens/overview'; +import { expandHostStats, expandNetworkStats } from '../../../tasks/overview'; import { loginAndWaitForPage } from '../../lib/util/helpers'; describe('Overview Page', () => { - beforeEach(() => { - clearFetch(); - stubApi('overview'); + before(() => { + cy.stubSIEMapi('overview'); loginAndWaitForPage(OVERVIEW_PAGE); }); - it('Host and Network stats render with correct values', () => { - cy.get(OVERVIEW_HOST_STATS) - .find('button') - .invoke('click'); - - cy.get(OVERVIEW_NETWORK_STATS) - .find('button') - .invoke('click'); - - cy.get(STAT_AUDITD.domId); + it('Host stats render with correct values', () => { + expandHostStats(); HOST_STATS.forEach(stat => { cy.get(stat.domId) .invoke('text') .should('eq', stat.value); }); + }); + + it('Network stats render with correct values', () => { + expandNetworkStats(); NETWORK_STATS.forEach(stat => { cy.get(stat.domId) diff --git a/x-pack/legacy/plugins/siem/cypress/screens/overview.ts b/x-pack/legacy/plugins/siem/cypress/screens/overview.ts new file mode 100644 index 0000000000000..95facc8974400 --- /dev/null +++ b/x-pack/legacy/plugins/siem/cypress/screens/overview.ts @@ -0,0 +1,144 @@ +/* + * 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. + */ + +// Host Stats +export const STAT_AUDITD = { + value: '123', + domId: '[data-test-subj="host-stat-auditbeatAuditd"]', +}; +export const ENDGAME_DNS = { + value: '391', + domId: '[data-test-subj="host-stat-endgameDns"]', +}; +export const ENDGAME_FILE = { + value: '392', + domId: '[data-test-subj="host-stat-endgameFile"]', +}; +export const ENDGAME_IMAGE_LOAD = { + value: '393', + domId: '[data-test-subj="host-stat-endgameImageLoad"]', +}; +export const ENDGAME_NETWORK = { + value: '394', + domId: '[data-test-subj="host-stat-endgameNetwork"]', +}; +export const ENDGAME_PROCESS = { + value: '395', + domId: '[data-test-subj="host-stat-endgameProcess"]', +}; +export const ENDGAME_REGISTRY = { + value: '396', + domId: '[data-test-subj="host-stat-endgameRegistry"]', +}; +export const ENDGAME_SECURITY = { + value: '397', + domId: '[data-test-subj="host-stat-endgameSecurity"]', +}; +export const STAT_FILEBEAT = { + value: '890', + domId: '[data-test-subj="host-stat-filebeatSystemModule"]', +}; +export const STAT_FIM = { + value: '345', + domId: '[data-test-subj="host-stat-auditbeatFIM"]', +}; +export const STAT_LOGIN = { + value: '456', + domId: '[data-test-subj="host-stat-auditbeatLogin"]', +}; +export const STAT_PACKAGE = { + value: '567', + domId: '[data-test-subj="host-stat-auditbeatPackage"]', +}; +export const STAT_PROCESS = { + value: '678', + domId: '[data-test-subj="host-stat-auditbeatProcess"]', +}; +export const STAT_USER = { + value: '789', + domId: '[data-test-subj="host-stat-auditbeatUser"]', +}; +export const STAT_WINLOGBEAT_SECURITY = { + value: '70', + domId: '[data-test-subj="host-stat-winlogbeatSecurity"]', +}; +export const STAT_WINLOGBEAT_MWSYSMON_OPERATIONAL = { + value: '30', + domId: '[data-test-subj="host-stat-winlogbeatMWSysmonOperational"]', +}; + +export const HOST_STATS = [ + STAT_AUDITD, + ENDGAME_DNS, + ENDGAME_FILE, + ENDGAME_IMAGE_LOAD, + ENDGAME_NETWORK, + ENDGAME_PROCESS, + ENDGAME_REGISTRY, + ENDGAME_SECURITY, + STAT_FILEBEAT, + STAT_FIM, + STAT_LOGIN, + STAT_PACKAGE, + STAT_PROCESS, + STAT_USER, + STAT_WINLOGBEAT_SECURITY, + STAT_WINLOGBEAT_MWSYSMON_OPERATIONAL, +]; + +// Network Stats +export const STAT_SOCKET = { + value: '578,502', + domId: '[data-test-subj="network-stat-auditbeatSocket"]', +}; +export const STAT_CISCO = { + value: '999', + domId: '[data-test-subj="network-stat-filebeatCisco"]', +}; +export const STAT_NETFLOW = { + value: '2,544', + domId: '[data-test-subj="network-stat-filebeatNetflow"]', +}; +export const STAT_PANW = { + value: '678', + domId: '[data-test-subj="network-stat-filebeatPanw"]', +}; +export const STAT_SURICATA = { + value: '303,699', + domId: '[data-test-subj="network-stat-filebeatSuricata"]', +}; +export const STAT_ZEEK = { + value: '71,129', + domId: '[data-test-subj="network-stat-filebeatZeek"]', +}; +export const STAT_DNS = { + value: '1,090', + domId: '[data-test-subj="network-stat-packetbeatDNS"]', +}; +export const STAT_FLOW = { + value: '722,153', + domId: '[data-test-subj="network-stat-packetbeatFlow"]', +}; +export const STAT_TLS = { + value: '340', + domId: '[data-test-subj="network-stat-packetbeatTLS"]', +}; + +export const NETWORK_STATS = [ + STAT_SOCKET, + STAT_CISCO, + STAT_NETFLOW, + STAT_PANW, + STAT_SURICATA, + STAT_ZEEK, + STAT_DNS, + STAT_FLOW, + STAT_TLS, +]; + +export const OVERVIEW_HOST_STATS = '[data-test-subj="overview-hosts-stats"]'; + +export const OVERVIEW_NETWORK_STATS = '[data-test-subj="overview-network-stats"]'; diff --git a/x-pack/legacy/plugins/siem/cypress/support/commands.js b/x-pack/legacy/plugins/siem/cypress/support/commands.js index 9a2e54b102c5e..e697dbce0f249 100644 --- a/x-pack/legacy/plugins/siem/cypress/support/commands.js +++ b/x-pack/legacy/plugins/siem/cypress/support/commands.js @@ -29,3 +29,13 @@ // // -- This is will overwrite an existing command -- // Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... }) + +Cypress.Commands.add('stubSIEMapi', function(dataFileName) { + cy.on('window:before:load', win => { + // @ts-ignore no null, this is a temp hack see issue above + win.fetch = null; + }); + cy.server(); + cy.fixture(dataFileName).as(`${dataFileName}JSON`); + cy.route('POST', 'api/siem/graphql', `@${dataFileName}JSON`); +}); diff --git a/x-pack/legacy/plugins/siem/cypress/support/index.d.ts b/x-pack/legacy/plugins/siem/cypress/support/index.d.ts new file mode 100644 index 0000000000000..5d5173170a9f9 --- /dev/null +++ b/x-pack/legacy/plugins/siem/cypress/support/index.d.ts @@ -0,0 +1,11 @@ +/* + * 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. + */ + +declare namespace Cypress { + interface Chainable { + stubSIEMapi(dataFileName: string): Chainable; + } +} diff --git a/x-pack/legacy/plugins/siem/cypress/tasks/overview.ts b/x-pack/legacy/plugins/siem/cypress/tasks/overview.ts new file mode 100644 index 0000000000000..0ca4059a90097 --- /dev/null +++ b/x-pack/legacy/plugins/siem/cypress/tasks/overview.ts @@ -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 { OVERVIEW_HOST_STATS, OVERVIEW_NETWORK_STATS } from '../screens/overview'; + +export const expand = (statType: string) => { + cy.get(statType) + .find('button') + .invoke('click'); +}; + +export const expandHostStats = () => { + expand(OVERVIEW_HOST_STATS); +}; + +export const expandNetworkStats = () => { + expand(OVERVIEW_NETWORK_STATS); +}; diff --git a/x-pack/legacy/plugins/siem/cypress/urls/navigation.ts b/x-pack/legacy/plugins/siem/cypress/urls/navigation.ts index 4675829df839a..35db3003ac436 100644 --- a/x-pack/legacy/plugins/siem/cypress/urls/navigation.ts +++ b/x-pack/legacy/plugins/siem/cypress/urls/navigation.ts @@ -5,3 +5,4 @@ */ export const TIMELINES_PAGE = '/app/siem#/timelines'; +export const OVERVIEW_PAGE = '/app/siem#/overview'; From bdba16d92c28c95a0c078f45548436e33104d59f Mon Sep 17 00:00:00 2001 From: Jean-Louis Leysens Date: Mon, 10 Feb 2020 12:14:55 +0100 Subject: [PATCH 3/5] Update CCR auto follower copy (#57135) * Update CCR auto follower copy. "pattern" -> "replication" * Update copy in test expectation Co-authored-by: Elastic Machine --- .../client_integration/auto_follow_pattern_list.test.js | 2 +- .../auto_follow_pattern_action_menu.tsx | 4 ++-- .../auto_follow_pattern_table/auto_follow_pattern_table.js | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/x-pack/legacy/plugins/cross_cluster_replication/__jest__/client_integration/auto_follow_pattern_list.test.js b/x-pack/legacy/plugins/cross_cluster_replication/__jest__/client_integration/auto_follow_pattern_list.test.js index 1003569733d91..88d8f98b973bd 100644 --- a/x-pack/legacy/plugins/cross_cluster_replication/__jest__/client_integration/auto_follow_pattern_list.test.js +++ b/x-pack/legacy/plugins/cross_cluster_replication/__jest__/client_integration/auto_follow_pattern_list.test.js @@ -286,7 +286,7 @@ describe('', () => { actions.clickAutoFollowPatternAt(0); find('autoFollowPatternActionMenuButton').simulate('click'); expect(exists('autoFollowPatternDetail.closeFlyoutButton')).toBe(true); - expect(actions.getPatternsActionMenuItemText(0)).toEqual('Resume pattern'); + expect(actions.getPatternsActionMenuItemText(0)).toEqual('Resume replication'); expect(actions.getPatternsActionMenuItemText(1)).toEqual('Edit pattern'); expect(actions.getPatternsActionMenuItemText(2)).toEqual('Delete pattern'); }); diff --git a/x-pack/legacy/plugins/cross_cluster_replication/public/app/components/auto_follow_pattern_action_menu/auto_follow_pattern_action_menu.tsx b/x-pack/legacy/plugins/cross_cluster_replication/public/app/components/auto_follow_pattern_action_menu/auto_follow_pattern_action_menu.tsx index 7c129eac9cbd9..12654e56bde97 100644 --- a/x-pack/legacy/plugins/cross_cluster_replication/public/app/components/auto_follow_pattern_action_menu/auto_follow_pattern_action_menu.tsx +++ b/x-pack/legacy/plugins/cross_cluster_replication/public/app/components/auto_follow_pattern_action_menu/auto_follow_pattern_action_menu.tsx @@ -68,7 +68,7 @@ const AutoFollowPatternActionMenuUI: FunctionComponent = ({ ? patterns[0].active ? { name: i18n.translate('xpack.crossClusterReplication.pauseAutoFollowPatternsLabel', { - defaultMessage: 'Pause {total, plural, one {pattern} other {patterns}}', + defaultMessage: 'Pause {total, plural, one {replication} other {replications}}', values: { total: patterns.length }, }), icon: , @@ -79,7 +79,7 @@ const AutoFollowPatternActionMenuUI: FunctionComponent = ({ } : { name: i18n.translate('xpack.crossClusterReplication.resumeAutoFollowPatternsLabel', { - defaultMessage: 'Resume {total, plural, one {pattern} other {patterns}}', + defaultMessage: 'Resume {total, plural, one {replication} other {replications}}', values: { total: patterns.length }, }), icon: , diff --git a/x-pack/legacy/plugins/cross_cluster_replication/public/app/sections/home/auto_follow_pattern_list/components/auto_follow_pattern_table/auto_follow_pattern_table.js b/x-pack/legacy/plugins/cross_cluster_replication/public/app/sections/home/auto_follow_pattern_list/components/auto_follow_pattern_table/auto_follow_pattern_table.js index 08b1770e39963..956a9f10d810b 100644 --- a/x-pack/legacy/plugins/cross_cluster_replication/public/app/sections/home/auto_follow_pattern_list/components/auto_follow_pattern_table/auto_follow_pattern_table.js +++ b/x-pack/legacy/plugins/cross_cluster_replication/public/app/sections/home/auto_follow_pattern_list/components/auto_follow_pattern_table/auto_follow_pattern_table.js @@ -180,13 +180,13 @@ export class AutoFollowPatternTable extends PureComponent { ? i18n.translate( 'xpack.crossClusterReplication.autoFollowPatternList.table.actionPauseDescription', { - defaultMessage: 'Pause auto-follow pattern', + defaultMessage: 'Pause replication', } ) : i18n.translate( 'xpack.crossClusterReplication.autoFollowPatternList.table.actionResumeDescription', { - defaultMessage: 'Resume auto-follow pattern', + defaultMessage: 'Resume replication', } ); From 56571bac847b1579dbaca2d292614744a248d297 Mon Sep 17 00:00:00 2001 From: Maryia Lapata Date: Mon, 10 Feb 2020 14:32:28 +0300 Subject: [PATCH 4/5] Remove confirm modal directive and factory (#56846) * Graph: replace confirmModal * Remove confirmModal from visualize * Remove confirmModal from dashboard * Remove confirm_modal * Remove confirmModalPromises * Replace confirmModal * FIx TS * Add data-test-subj for graph confirm modal * Update public.api.md * Remove unused translation * Update mock test --- .../public/overlays/modal/modal_service.tsx | 3 +- src/core/public/public.api.md | 1 + .../kibana/public/dashboard/legacy_imports.ts | 4 - .../public/dashboard/np_ready/application.ts | 12 +- .../dashboard/np_ready/dashboard_app.tsx | 5 +- .../np_ready/dashboard_app_controller.tsx | 56 ++++--- .../kibana/public/dashboard/np_ready/types.ts | 12 -- .../create_index_pattern_wizard.js | 15 +- .../create_index_pattern_wizard/index.js | 2 +- .../edit_index_pattern/edit_index_pattern.js | 25 ++-- .../management/sections/objects/_objects.js | 3 +- .../management/sections/objects/_view.js | 23 ++- .../objects/lib/resolve_saved_objects.js | 33 +++-- .../kibana/public/visualize/legacy_imports.ts | 2 - .../public/visualize/np_ready/application.ts | 11 -- .../core_plugins/timelion/public/app.js | 20 ++- src/legacy/ui/public/autoload/modules.js | 1 - .../public/modals/__tests__/confirm_modal.js | 137 ------------------ .../modals/__tests__/confirm_modal_promise.js | 115 --------------- .../ui/public/modals/confirm_modal.html | 10 -- src/legacy/ui/public/modals/confirm_modal.js | 119 --------------- .../ui/public/modals/confirm_modal_promise.js | 49 ------- src/legacy/ui/public/modals/index.js | 24 --- .../ui/public/modals/modal_overlay.html | 1 - src/legacy/ui/public/modals/modal_overlay.js | 40 ----- .../new_platform/new_platform.karma_mock.js | 6 +- src/legacy/ui/public/react_components.js | 4 +- .../saved_objects/__tests__/saved_object.js | 20 +-- x-pack/legacy/plugins/graph/public/app.js | 27 ++-- .../plugins/graph/public/application.ts | 14 +- .../plugins/graph/public/legacy_imports.ts | 2 - x-pack/legacy/plugins/graph/public/plugin.ts | 1 + .../translations/translations/ja-JP.json | 1 - .../translations/translations/zh-CN.json | 1 - 34 files changed, 137 insertions(+), 662 deletions(-) delete mode 100644 src/legacy/ui/public/modals/__tests__/confirm_modal.js delete mode 100644 src/legacy/ui/public/modals/__tests__/confirm_modal_promise.js delete mode 100644 src/legacy/ui/public/modals/confirm_modal.html delete mode 100644 src/legacy/ui/public/modals/confirm_modal.js delete mode 100644 src/legacy/ui/public/modals/confirm_modal_promise.js delete mode 100644 src/legacy/ui/public/modals/index.js delete mode 100644 src/legacy/ui/public/modals/modal_overlay.html delete mode 100644 src/legacy/ui/public/modals/modal_overlay.js diff --git a/src/core/public/overlays/modal/modal_service.tsx b/src/core/public/overlays/modal/modal_service.tsx index ba7887b1afa5c..3cf1fe745be8e 100644 --- a/src/core/public/overlays/modal/modal_service.tsx +++ b/src/core/public/overlays/modal/modal_service.tsx @@ -20,7 +20,7 @@ /* eslint-disable max-classes-per-file */ import { i18n as t } from '@kbn/i18n'; -import { EuiModal, EuiConfirmModal, EuiOverlayMask } from '@elastic/eui'; +import { EuiModal, EuiConfirmModal, EuiOverlayMask, EuiConfirmModalProps } from '@elastic/eui'; import React from 'react'; import { render, unmountComponentAtNode } from 'react-dom'; import { Subject } from 'rxjs'; @@ -68,6 +68,7 @@ export interface OverlayModalConfirmOptions { className?: string; closeButtonAriaLabel?: string; 'data-test-subj'?: string; + defaultFocusedButton?: EuiConfirmModalProps['defaultFocusedButton']; } /** diff --git a/src/core/public/public.api.md b/src/core/public/public.api.md index fb48524c20fb9..aa7ca4fee675e 100644 --- a/src/core/public/public.api.md +++ b/src/core/public/public.api.md @@ -6,6 +6,7 @@ import { Breadcrumb } from '@elastic/eui'; import { EuiButtonEmptyProps } from '@elastic/eui'; +import { EuiConfirmModalProps } from '@elastic/eui'; import { EuiGlobalToastListToast } from '@elastic/eui'; import { ExclusiveUnion } from '@elastic/eui'; import { IconType } from '@elastic/eui'; diff --git a/src/legacy/core_plugins/kibana/public/dashboard/legacy_imports.ts b/src/legacy/core_plugins/kibana/public/dashboard/legacy_imports.ts index b729691831e9a..57edf5e838170 100644 --- a/src/legacy/core_plugins/kibana/public/dashboard/legacy_imports.ts +++ b/src/legacy/core_plugins/kibana/public/dashboard/legacy_imports.ts @@ -30,15 +30,11 @@ export const legacyChrome = chrome; export { SavedObjectSaveOpts } from 'ui/saved_objects/types'; export { npSetup, npStart } from 'ui/new_platform'; export { subscribeWithScope } from 'ui/utils/subscribe_with_scope'; -// @ts-ignore -export { ConfirmationButtonTypes } from 'ui/modals/confirm_modal'; export { KbnUrl } from 'ui/url/kbn_url'; // @ts-ignore export { createTopNavDirective, createTopNavHelper } from 'ui/kbn_top_nav/kbn_top_nav'; // @ts-ignore export { KbnUrlProvider, RedirectWhenMissingProvider } from 'ui/url/index'; -// @ts-ignore -export { confirmModalFactory } from 'ui/modals/confirm_modal'; export { IInjector } from 'ui/chrome'; export { SavedObjectLoader } from 'ui/saved_objects'; export { VISUALIZE_EMBEDDABLE_TYPE } from '../../../visualizations/public/embeddable'; diff --git a/src/legacy/core_plugins/kibana/public/dashboard/np_ready/application.ts b/src/legacy/core_plugins/kibana/public/dashboard/np_ready/application.ts index 3af0b29b80acb..e608eb7b7f48c 100644 --- a/src/legacy/core_plugins/kibana/public/dashboard/np_ready/application.ts +++ b/src/legacy/core_plugins/kibana/public/dashboard/np_ready/application.ts @@ -17,7 +17,7 @@ * under the License. */ -import { EuiConfirmModal, EuiIcon } from '@elastic/eui'; +import { EuiIcon } from '@elastic/eui'; import angular, { IModule } from 'angular'; import { i18nDirective, i18nFilter, I18nProvider } from '@kbn/i18n/angular'; import { @@ -30,7 +30,6 @@ import { import { Storage } from '../../../../../../plugins/kibana_utils/public'; import { configureAppAngularModule, - confirmModalFactory, createTopNavDirective, createTopNavHelper, IPrivate, @@ -111,7 +110,6 @@ function createLocalAngularModule(core: AppMountContext['core'], navigation: Nav createLocalConfigModule(core); createLocalKbnUrlModule(); createLocalTopNavModule(navigation); - createLocalConfirmModalModule(); createLocalIconModule(); const dashboardAngularModule = angular.module(moduleName, [ @@ -122,7 +120,6 @@ function createLocalAngularModule(core: AppMountContext['core'], navigation: Nav 'app/dashboard/TopNav', 'app/dashboard/KbnUrl', 'app/dashboard/Promise', - 'app/dashboard/ConfirmModal', 'app/dashboard/icon', ]); return dashboardAngularModule; @@ -134,13 +131,6 @@ function createLocalIconModule() { .directive('icon', reactDirective => reactDirective(EuiIcon)); } -function createLocalConfirmModalModule() { - angular - .module('app/dashboard/ConfirmModal', ['react']) - .factory('confirmModal', confirmModalFactory) - .directive('confirmModal', reactDirective => reactDirective(EuiConfirmModal)); -} - function createLocalKbnUrlModule() { angular .module('app/dashboard/KbnUrl', ['app/dashboard/Private', 'ngRoute']) diff --git a/src/legacy/core_plugins/kibana/public/dashboard/np_ready/dashboard_app.tsx b/src/legacy/core_plugins/kibana/public/dashboard/np_ready/dashboard_app.tsx index 0537e3f8fc456..ad69ef322a909 100644 --- a/src/legacy/core_plugins/kibana/public/dashboard/np_ready/dashboard_app.tsx +++ b/src/legacy/core_plugins/kibana/public/dashboard/np_ready/dashboard_app.tsx @@ -25,7 +25,7 @@ import { IInjector } from '../legacy_imports'; import { ViewMode } from '../../../../embeddable_api/public/np_ready/public'; import { SavedObjectDashboard } from '../saved_dashboard/saved_dashboard'; -import { DashboardAppState, SavedDashboardPanel, ConfirmModalFn } from './types'; +import { DashboardAppState, SavedDashboardPanel } from './types'; import { IIndexPattern, TimeRange, @@ -87,8 +87,6 @@ export interface DashboardAppScope extends ng.IScope { export function initDashboardAppDirective(app: any, deps: RenderDeps) { app.directive('dashboardApp', function($injector: IInjector) { - const confirmModal = $injector.get('confirmModal'); - return { restrict: 'E', controllerAs: 'dashboardApp', @@ -105,7 +103,6 @@ export function initDashboardAppDirective(app: any, deps: RenderDeps) { $route, $scope, $routeParams, - confirmModal, indexPatterns: deps.npDataStart.indexPatterns, kbnUrlStateStorage, history, diff --git a/src/legacy/core_plugins/kibana/public/dashboard/np_ready/dashboard_app_controller.tsx b/src/legacy/core_plugins/kibana/public/dashboard/np_ready/dashboard_app_controller.tsx index c44e36eab8c76..0b55adc1d52be 100644 --- a/src/legacy/core_plugins/kibana/public/dashboard/np_ready/dashboard_app_controller.tsx +++ b/src/legacy/core_plugins/kibana/public/dashboard/np_ready/dashboard_app_controller.tsx @@ -19,6 +19,7 @@ import _, { uniq } from 'lodash'; import { i18n } from '@kbn/i18n'; +import { EUI_MODAL_CANCEL_BUTTON } from '@elastic/eui'; import React from 'react'; import angular from 'angular'; @@ -27,12 +28,7 @@ import { map } from 'rxjs/operators'; import { History } from 'history'; import { DashboardEmptyScreen, DashboardEmptyScreenProps } from './dashboard_empty_screen'; -import { - ConfirmationButtonTypes, - migrateLegacyQuery, - SavedObjectSaveOpts, - subscribeWithScope, -} from '../legacy_imports'; +import { migrateLegacyQuery, SavedObjectSaveOpts, subscribeWithScope } from '../legacy_imports'; import { COMPARE_ALL_OPTIONS, compareFilters, @@ -63,7 +59,7 @@ import { openAddPanelFlyout, ViewMode, } from '../../../../embeddable_api/public/np_ready/public'; -import { ConfirmModalFn, NavAction, SavedDashboardPanel } from './types'; +import { NavAction, SavedDashboardPanel } from './types'; import { showOptionsPopover } from './top_nav/show_options_popover'; import { DashboardSaveModal } from './top_nav/save_modal'; @@ -90,7 +86,6 @@ export interface DashboardAppControllerDependencies extends RenderDeps { $routeParams: any; indexPatterns: IndexPatternsContract; dashboardConfig: KibanaLegacyStart['dashboardConfig']; - confirmModal: ConfirmModalFn; history: History; kbnUrlStateStorage: IKbnUrlStateStorage; } @@ -108,7 +103,6 @@ export class DashboardAppController { dashboardConfig, localStorage, indexPatterns, - confirmModal, savedQueryService, embeddables, share, @@ -635,27 +629,31 @@ export class DashboardAppController { } } - confirmModal( - i18n.translate('kbn.dashboard.changeViewModeConfirmModal.discardChangesDescription', { - defaultMessage: `Once you discard your changes, there's no getting them back.`, - }), - { - onConfirm: revertChangesAndExitEditMode, - onCancel: _.noop, - confirmButtonText: i18n.translate( - 'kbn.dashboard.changeViewModeConfirmModal.confirmButtonLabel', - { defaultMessage: 'Discard changes' } - ), - cancelButtonText: i18n.translate( - 'kbn.dashboard.changeViewModeConfirmModal.cancelButtonLabel', - { defaultMessage: 'Continue editing' } - ), - defaultFocusedButton: ConfirmationButtonTypes.CANCEL, - title: i18n.translate('kbn.dashboard.changeViewModeConfirmModal.discardChangesTitle', { - defaultMessage: 'Discard changes to dashboard?', + overlays + .openConfirm( + i18n.translate('kbn.dashboard.changeViewModeConfirmModal.discardChangesDescription', { + defaultMessage: `Once you discard your changes, there's no getting them back.`, }), - } - ); + { + confirmButtonText: i18n.translate( + 'kbn.dashboard.changeViewModeConfirmModal.confirmButtonLabel', + { defaultMessage: 'Discard changes' } + ), + cancelButtonText: i18n.translate( + 'kbn.dashboard.changeViewModeConfirmModal.cancelButtonLabel', + { defaultMessage: 'Continue editing' } + ), + defaultFocusedButton: EUI_MODAL_CANCEL_BUTTON, + title: i18n.translate('kbn.dashboard.changeViewModeConfirmModal.discardChangesTitle', { + defaultMessage: 'Discard changes to dashboard?', + }), + } + ) + .then(isConfirmed => { + if (isConfirmed) { + revertChangesAndExitEditMode(); + } + }); }; /** diff --git a/src/legacy/core_plugins/kibana/public/dashboard/np_ready/types.ts b/src/legacy/core_plugins/kibana/public/dashboard/np_ready/types.ts index 3151fbf821b9f..146affda28200 100644 --- a/src/legacy/core_plugins/kibana/public/dashboard/np_ready/types.ts +++ b/src/legacy/core_plugins/kibana/public/dashboard/np_ready/types.ts @@ -137,15 +137,3 @@ export interface StagedFilter { operator: string; index: string; } - -export type ConfirmModalFn = ( - message: string, - confirmOptions: { - onConfirm: () => void; - onCancel: () => void; - confirmButtonText: string; - cancelButtonText: string; - defaultFocusedButton: string; - title: string; - } -) => void; diff --git a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/create_index_pattern_wizard.js b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/create_index_pattern_wizard.js index 77b43a651d548..b5c6000eb2fe1 100644 --- a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/create_index_pattern_wizard.js +++ b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/create_index_pattern_wizard.js @@ -43,6 +43,7 @@ export class CreateIndexPatternWizard extends Component { indexPatternCreationType: PropTypes.object.isRequired, config: PropTypes.object.isRequired, changeUrl: PropTypes.func.isRequired, + openConfirm: PropTypes.func.isRequired, }).isRequired, }; @@ -142,12 +143,16 @@ export class CreateIndexPatternWizard extends Component { values: { title: this.title }, defaultMessage: "An index pattern with the title '{title}' already exists.", }); - try { - await services.confirmModalPromise(confirmMessage, { - confirmButtonText: 'Go to existing pattern', - }); + + const isConfirmed = await services.openConfirm(confirmMessage, { + confirmButtonText: i18n.translate('kbn.management.indexPattern.goToPatternButtonLabel', { + defaultMessage: 'Go to existing pattern', + }), + }); + + if (isConfirmed) { return services.changeUrl(`/management/kibana/index_patterns/${indexPatternId}`); - } catch (err) { + } else { return false; } } diff --git a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/index.js b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/index.js index d1087b4575e82..d06bc8784de51 100644 --- a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/index.js +++ b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/index.js @@ -43,10 +43,10 @@ uiRoutes.when('/management/kibana/index_pattern', { $http: npStart.core.http, savedObjectsClient: npStart.core.savedObjects.client, indexPatternCreationType, - confirmModalPromise: $injector.get('confirmModalPromise'), changeUrl: url => { $scope.$evalAsync(() => kbnUrl.changePath(url)); }, + openConfirm: npStart.core.overlays.openConfirm, }; const initialQuery = $routeParams.id ? decodeURIComponent($routeParams.id) : undefined; diff --git a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/edit_index_pattern/edit_index_pattern.js b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/edit_index_pattern/edit_index_pattern.js index eb7358c66e226..0cbac20a947bf 100644 --- a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/edit_index_pattern/edit_index_pattern.js +++ b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/edit_index_pattern/edit_index_pattern.js @@ -198,8 +198,7 @@ uiModules $route, Promise, config, - Private, - confirmModal + Private ) { const { startSyncingState, @@ -290,15 +289,19 @@ uiModules confirmButtonText: i18n.translate('kbn.management.editIndexPattern.refreshButton', { defaultMessage: 'Refresh', }), - onConfirm: async () => { - await $scope.indexPattern.init(true); - $scope.fields = $scope.indexPattern.getNonScriptedFields(); - }, title: i18n.translate('kbn.management.editIndexPattern.refreshHeader', { defaultMessage: 'Refresh field list?', }), }; - confirmModal(confirmMessage, confirmModalOptions); + + npStart.core.overlays + .openConfirm(confirmMessage, confirmModalOptions) + .then(async isConfirmed => { + if (isConfirmed) { + await $scope.indexPattern.init(true); + $scope.fields = $scope.indexPattern.getNonScriptedFields(); + } + }); }; $scope.removePattern = function() { @@ -322,12 +325,16 @@ uiModules confirmButtonText: i18n.translate('kbn.management.editIndexPattern.deleteButton', { defaultMessage: 'Delete', }), - onConfirm: doRemove, title: i18n.translate('kbn.management.editIndexPattern.deleteHeader', { defaultMessage: 'Delete index pattern?', }), }; - confirmModal('', confirmModalOptions); + + npStart.core.overlays.openConfirm('', confirmModalOptions).then(isConfirmed => { + if (isConfirmed) { + doRemove(); + } + }); }; $scope.setDefaultPattern = function() { diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/_objects.js b/src/legacy/core_plugins/kibana/public/management/sections/objects/_objects.js index c16e4cb00c2bd..e3ab862cd84b7 100644 --- a/src/legacy/core_plugins/kibana/public/management/sections/objects/_objects.js +++ b/src/legacy/core_plugins/kibana/public/management/sections/objects/_objects.js @@ -38,7 +38,6 @@ function updateObjectsTable($scope, $injector) { const $http = $injector.get('$http'); const kbnUrl = $injector.get('kbnUrl'); const config = $injector.get('config'); - const confirmModalPromise = $injector.get('confirmModalPromise'); const savedObjectsClient = npStart.core.savedObjects.client; const services = savedObjectManagementRegistry.all().map(obj => obj.service); @@ -54,7 +53,7 @@ function updateObjectsTable($scope, $injector) { fatalError(error, location)); } const confirmModalOptions = { - onConfirm: doDelete, confirmButtonText: i18n.translate( 'kbn.management.objects.confirmModalOptions.deleteButtonLabel', { @@ -244,12 +244,19 @@ uiModules defaultMessage: 'Delete saved Kibana object?', }), }; - confirmModal( - i18n.translate('kbn.management.objects.confirmModalOptions.modalDescription', { - defaultMessage: "You can't recover deleted objects", - }), - confirmModalOptions - ); + + overlays + .openConfirm( + i18n.translate('kbn.management.objects.confirmModalOptions.modalDescription', { + defaultMessage: "You can't recover deleted objects", + }), + confirmModalOptions + ) + .then(isConfirmed => { + if (isConfirmed) { + doDelete(); + } + }); }; $scope.submit = function() { diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/lib/resolve_saved_objects.js b/src/legacy/core_plugins/kibana/public/management/sections/objects/lib/resolve_saved_objects.js index e3cee4186e278..e13e8c1efe8f7 100644 --- a/src/legacy/core_plugins/kibana/public/management/sections/objects/lib/resolve_saved_objects.js +++ b/src/legacy/core_plugins/kibana/public/management/sections/objects/lib/resolve_saved_objects.js @@ -79,24 +79,25 @@ async function importIndexPattern(doc, indexPatterns, overwriteAll, confirmModal let newId = await emptyPattern.create(overwriteAll); if (!newId) { // We can override and we want to prompt for confirmation - try { - await confirmModalPromise( - i18n.translate('kbn.management.indexPattern.confirmOverwriteLabel', { - values: { title: this.title }, - defaultMessage: "Are you sure you want to overwrite '{title}'?", + const isConfirmed = await confirmModalPromise( + i18n.translate('kbn.management.indexPattern.confirmOverwriteLabel', { + values: { title: this.title }, + defaultMessage: "Are you sure you want to overwrite '{title}'?", + }), + { + title: i18n.translate('kbn.management.indexPattern.confirmOverwriteTitle', { + defaultMessage: 'Overwrite {type}?', + values: { type }, }), - { - title: i18n.translate('kbn.management.indexPattern.confirmOverwriteTitle', { - defaultMessage: 'Overwrite {type}?', - values: { type }, - }), - confirmButtonText: i18n.translate('kbn.management.indexPattern.confirmOverwriteButton', { - defaultMessage: 'Overwrite', - }), - } - ); + confirmButtonText: i18n.translate('kbn.management.indexPattern.confirmOverwriteButton', { + defaultMessage: 'Overwrite', + }), + } + ); + + if (isConfirmed) { newId = await emptyPattern.create(true); - } catch (err) { + } else { return; } } diff --git a/src/legacy/core_plugins/kibana/public/visualize/legacy_imports.ts b/src/legacy/core_plugins/kibana/public/visualize/legacy_imports.ts index d3a7f6ac1ff7d..ff7d167ccaacd 100644 --- a/src/legacy/core_plugins/kibana/public/visualize/legacy_imports.ts +++ b/src/legacy/core_plugins/kibana/public/visualize/legacy_imports.ts @@ -46,8 +46,6 @@ export { subscribeWithScope } from 'ui/utils/subscribe_with_scope'; export { EventsProvider } from 'ui/events'; // @ts-ignore export { createTopNavDirective, createTopNavHelper } from 'ui/kbn_top_nav/kbn_top_nav'; -// @ts-ignore -export { confirmModalFactory } from 'ui/modals/confirm_modal'; export { registerTimefilterWithGlobalStateFactory } from 'ui/timefilter/setup_router'; // @ts-ignore export { KbnUrlProvider, RedirectWhenMissingProvider } from 'ui/url'; diff --git a/src/legacy/core_plugins/kibana/public/visualize/np_ready/application.ts b/src/legacy/core_plugins/kibana/public/visualize/np_ready/application.ts index 222b035708976..44e7e9c2a7413 100644 --- a/src/legacy/core_plugins/kibana/public/visualize/np_ready/application.ts +++ b/src/legacy/core_plugins/kibana/public/visualize/np_ready/application.ts @@ -18,7 +18,6 @@ */ import angular, { IModule } from 'angular'; -import { EuiConfirmModal } from '@elastic/eui'; import { i18nDirective, i18nFilter, I18nProvider } from '@kbn/i18n/angular'; import { AppMountContext, LegacyCoreStart } from 'kibana/public'; @@ -26,7 +25,6 @@ import { AppStateProvider, AppState, configureAppAngularModule, - confirmModalFactory, createTopNavDirective, createTopNavHelper, EventsProvider, @@ -93,7 +91,6 @@ function createLocalAngularModule(core: AppMountContext['core'], navigation: Nav createLocalStateModule(); createLocalPersistedStateModule(); createLocalTopNavModule(navigation); - createLocalConfirmModalModule(); const visualizeAngularModule: IModule = angular.module(moduleName, [ ...thirdPartyAngularDependencies, @@ -103,18 +100,10 @@ function createLocalAngularModule(core: AppMountContext['core'], navigation: Nav 'app/visualize/PersistedState', 'app/visualize/TopNav', 'app/visualize/State', - 'app/visualize/ConfirmModal', ]); return visualizeAngularModule; } -function createLocalConfirmModalModule() { - angular - .module('app/visualize/ConfirmModal', ['react']) - .factory('confirmModal', confirmModalFactory) - .directive('confirmModal', reactDirective => reactDirective(EuiConfirmModal)); -} - function createLocalStateModule() { angular .module('app/visualize/State', [ diff --git a/src/legacy/core_plugins/timelion/public/app.js b/src/legacy/core_plugins/timelion/public/app.js index a7fa9e0290a1c..ff8f75c23435e 100644 --- a/src/legacy/core_plugins/timelion/public/app.js +++ b/src/legacy/core_plugins/timelion/public/app.js @@ -114,7 +114,6 @@ app.controller('timelion', function( $timeout, AppState, config, - confirmModal, kbnUrl, Private ) { @@ -230,7 +229,6 @@ app.controller('timelion', function( } const confirmModalOptions = { - onConfirm: doDelete, confirmButtonText: i18n.translate('timelion.topNavMenu.delete.modal.confirmButtonLabel', { defaultMessage: 'Delete', }), @@ -241,12 +239,18 @@ app.controller('timelion', function( }; $scope.$evalAsync(() => { - confirmModal( - i18n.translate('timelion.topNavMenu.delete.modal.warningText', { - defaultMessage: `You can't recover deleted sheets.`, - }), - confirmModalOptions - ); + npStart.core.overlays + .openConfirm( + i18n.translate('timelion.topNavMenu.delete.modal.warningText', { + defaultMessage: `You can't recover deleted sheets.`, + }), + confirmModalOptions + ) + .then(isConfirmed => { + if (isConfirmed) { + doDelete(); + } + }); }); }, testId: 'timelionDeleteButton', diff --git a/src/legacy/ui/public/autoload/modules.js b/src/legacy/ui/public/autoload/modules.js index 938796ed279ea..b40f051a5ec10 100644 --- a/src/legacy/ui/public/autoload/modules.js +++ b/src/legacy/ui/public/autoload/modules.js @@ -23,7 +23,6 @@ import '../config'; import '../notify'; import '../private'; import '../promises'; -import '../modals'; import '../state_management/app_state'; import '../state_management/global_state'; import '../style_compile'; diff --git a/src/legacy/ui/public/modals/__tests__/confirm_modal.js b/src/legacy/ui/public/modals/__tests__/confirm_modal.js deleted file mode 100644 index 6c05fb977c701..0000000000000 --- a/src/legacy/ui/public/modals/__tests__/confirm_modal.js +++ /dev/null @@ -1,137 +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 angular from 'angular'; -import expect from '@kbn/expect'; -import ngMock from 'ng_mock'; -import sinon from 'sinon'; -import _ from 'lodash'; - -describe('ui/modals/confirm_modal', function() { - let confirmModal; - let $rootScope; - - beforeEach(function() { - ngMock.module('kibana'); - ngMock.inject(function($injector) { - confirmModal = $injector.get('confirmModal'); - $rootScope = $injector.get('$rootScope'); - }); - }); - - function findByDataTestSubj(dataTestSubj) { - return angular.element(document.body).find(`[data-test-subj=${dataTestSubj}]`); - } - - afterEach(function() { - const confirmButton = findByDataTestSubj('confirmModalConfirmButton'); - if (confirmButton) { - angular.element(confirmButton).click(); - } - }); - - describe('throws an exception', function() { - it('when no custom confirm button passed', function() { - expect(() => confirmModal('hi', { onConfirm: _.noop })).to.throwError(); - }); - - it('when no custom noConfirm function is passed', function() { - expect(() => confirmModal('hi', { confirmButtonText: 'bye' })).to.throwError(); - }); - - it('when showClose is on but title is not given', function() { - const options = { customConfirmButton: 'b', onConfirm: _.noop, showClose: true }; - expect(() => confirmModal('hi', options)).to.throwError(); - }); - }); - - it('shows the message', function() { - const myMessage = 'Hi, how are you?'; - confirmModal(myMessage, { confirmButtonText: 'GREAT!', onConfirm: _.noop }); - - $rootScope.$digest(); - const message = findByDataTestSubj('confirmModalBodyText')[0].innerText.trim(); - expect(message).to.equal(myMessage); - }); - - describe('shows custom text', function() { - const confirmModalOptions = { - confirmButtonText: 'Troodon', - cancelButtonText: 'Dilophosaurus', - title: 'Dinosaurs', - onConfirm: _.noop, - }; - - it('for confirm button', () => { - confirmModal("What's your favorite dinosaur?", confirmModalOptions); - $rootScope.$digest(); - const confirmButtonText = findByDataTestSubj('confirmModalConfirmButton')[0].innerText.trim(); - expect(confirmButtonText).to.equal('Troodon'); - }); - - it('for cancel button', () => { - confirmModal("What's your favorite dinosaur?", confirmModalOptions); - $rootScope.$digest(); - const cancelButtonText = findByDataTestSubj('confirmModalCancelButton')[0].innerText.trim(); - expect(cancelButtonText).to.equal('Dilophosaurus'); - }); - - it('for title text', () => { - confirmModal("What's your favorite dinosaur?", confirmModalOptions); - $rootScope.$digest(); - const titleText = findByDataTestSubj('confirmModalTitleText')[0].innerText.trim(); - expect(titleText).to.equal('Dinosaurs'); - }); - }); - - describe('callbacks are called:', function() { - const confirmCallback = sinon.spy(); - const cancelCallback = sinon.spy(); - - const confirmModalOptions = { - confirmButtonText: 'bye', - onConfirm: confirmCallback, - onCancel: cancelCallback, - title: 'hi', - }; - - beforeEach(() => { - confirmCallback.resetHistory(); - cancelCallback.resetHistory(); - }); - - it('onCancel', function() { - confirmModal('hi', confirmModalOptions); - $rootScope.$digest(); - findByDataTestSubj('confirmModalCancelButton').click(); - - expect(confirmCallback.called).to.be(false); - expect(cancelCallback.called).to.be(true); - }); - - it('onConfirm', function() { - confirmModal('hi', confirmModalOptions); - $rootScope.$digest(); - findByDataTestSubj('confirmModalConfirmButton').click(); - - expect(confirmCallback.called).to.be(true); - expect(cancelCallback.called).to.be(false); - }); - }); -}); diff --git a/src/legacy/ui/public/modals/__tests__/confirm_modal_promise.js b/src/legacy/ui/public/modals/__tests__/confirm_modal_promise.js deleted file mode 100644 index 0967b3caefbbb..0000000000000 --- a/src/legacy/ui/public/modals/__tests__/confirm_modal_promise.js +++ /dev/null @@ -1,115 +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 expect from '@kbn/expect'; -import testSubjSelector from '@kbn/test-subj-selector'; -import ngMock from 'ng_mock'; -import sinon from 'sinon'; -import $ from 'jquery'; - -describe('ui/modals/confirm_modal_promise', function() { - let $rootScope; - let message; - let confirmModalPromise; - let promise; - - beforeEach(function() { - ngMock.module('kibana'); - ngMock.inject(function($injector) { - confirmModalPromise = $injector.get('confirmModalPromise'); - $rootScope = $injector.get('$rootScope'); - }); - - message = 'woah'; - - promise = confirmModalPromise(message, { confirmButtonText: 'click me' }); - }); - - afterEach(function() { - $rootScope.$digest(); - $(testSubjSelector('confirmModalConfirmButton')).click(); - }); - - describe('before timeout completes', function() { - it('returned promise is not resolved', function() { - const callback = sinon.spy(); - promise.then(callback, callback); - $rootScope.$apply(); - expect(callback.called).to.be(false); - }); - }); - - describe('after timeout completes', function() { - it('confirmation dialogue is loaded to dom with message', function() { - $rootScope.$digest(); - const confirmModalElement = $(testSubjSelector('confirmModal')); - expect(confirmModalElement).to.not.be(undefined); - - const htmlString = confirmModalElement[0].innerHTML; - - expect(htmlString.indexOf(message)).to.be.greaterThan(0); - }); - - describe('when confirmed', function() { - it('promise is fulfilled with true', function() { - const confirmCallback = sinon.spy(); - const cancelCallback = sinon.spy(); - - promise.then(confirmCallback, cancelCallback); - $rootScope.$digest(); - const confirmButton = $(testSubjSelector('confirmModalConfirmButton')); - - confirmButton.click(); - expect(confirmCallback.called).to.be(true); - expect(cancelCallback.called).to.be(false); - }); - }); - - describe('when canceled', function() { - it('promise is rejected with false', function() { - const confirmCallback = sinon.spy(); - const cancelCallback = sinon.spy(); - promise.then(confirmCallback, cancelCallback); - - $rootScope.$digest(); - const noButton = $(testSubjSelector('confirmModalCancelButton')); - noButton.click(); - - expect(cancelCallback.called).to.be(true); - expect(confirmCallback.called).to.be(false); - }); - }); - - describe('error is thrown', function() { - it('when no confirm button text is used', function() { - const confirmCallback = sinon.spy(); - const cancelCallback = sinon.spy(); - confirmModalPromise(message).then(confirmCallback, cancelCallback); - - $rootScope.$digest(); - sinon.assert.notCalled(confirmCallback); - sinon.assert.calledOnce(cancelCallback); - sinon.assert.calledWithExactly( - cancelCallback, - sinon.match.has('message', sinon.match(/confirmation button text/)) - ); - }); - }); - }); -}); diff --git a/src/legacy/ui/public/modals/confirm_modal.html b/src/legacy/ui/public/modals/confirm_modal.html deleted file mode 100644 index 3eabe81fe9bd3..0000000000000 --- a/src/legacy/ui/public/modals/confirm_modal.html +++ /dev/null @@ -1,10 +0,0 @@ - diff --git a/src/legacy/ui/public/modals/confirm_modal.js b/src/legacy/ui/public/modals/confirm_modal.js deleted file mode 100644 index c609beff2fb16..0000000000000 --- a/src/legacy/ui/public/modals/confirm_modal.js +++ /dev/null @@ -1,119 +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 angular from 'angular'; -import { i18n } from '@kbn/i18n'; -import { noop } from 'lodash'; -import { uiModules } from '../modules'; -import template from './confirm_modal.html'; -import { ModalOverlay } from './modal_overlay'; - -const module = uiModules.get('kibana'); - -import { - EUI_MODAL_CONFIRM_BUTTON as CONFIRM_BUTTON, - EUI_MODAL_CANCEL_BUTTON as CANCEL_BUTTON, -} from '@elastic/eui'; - -export const ConfirmationButtonTypes = { - CONFIRM: CONFIRM_BUTTON, - CANCEL: CANCEL_BUTTON, -}; - -export function confirmModalFactory($rootScope, $compile) { - let modalPopover; - const confirmQueue = []; - - /** - * @param {String} message - the message to show in the body of the confirmation dialog. - * @param {ConfirmModalOptions} - Options to further customize the dialog. - */ - return function confirmModal(message, customOptions) { - const defaultOptions = { - onCancel: noop, - cancelButtonText: i18n.translate('common.ui.modals.cancelButtonLabel', { - defaultMessage: 'Cancel', - }), - defaultFocusedButton: ConfirmationButtonTypes.CONFIRM, - }; - - if (!customOptions.confirmButtonText || !customOptions.onConfirm) { - throw new Error('Please specify confirmation button text and onConfirm action'); - } - - const options = Object.assign(defaultOptions, customOptions); - - // Special handling for onClose - if no specific callback was supplied, default to the - // onCancel callback. - options.onClose = customOptions.onClose || options.onCancel; - - const confirmScope = $rootScope.$new(); - - confirmScope.message = message; - confirmScope.defaultFocusedButton = options.defaultFocusedButton; - confirmScope.confirmButtonText = options.confirmButtonText; - confirmScope.cancelButtonText = options.cancelButtonText; - confirmScope.title = options.title; - confirmScope.onConfirm = () => { - destroy(); - options.onConfirm(); - }; - confirmScope.onCancel = () => { - destroy(); - options.onCancel(); - }; - confirmScope.onClose = () => { - destroy(); - options.onClose(); - }; - - function showModal(confirmScope) { - const modalInstance = $compile(template)(confirmScope); - modalPopover = new ModalOverlay(modalInstance); - } - - if (modalPopover) { - confirmQueue.unshift(confirmScope); - } else { - showModal(confirmScope); - } - - function destroy() { - modalPopover.destroy(); - modalPopover = undefined; - angular.element(document.body).off('keydown'); - confirmScope.$destroy(); - - if (confirmQueue.length > 0) { - showModal(confirmQueue.pop()); - } - } - }; -} - -/** - * @typedef {Object} ConfirmModalOptions - * @property {String} confirmButtonText - * @property {String=} cancelButtonText - * @property {function} onConfirm - * @property {function=} onCancel - * @property {String=} title - If given, shows a title on the confirm modal. - */ - -module.factory('confirmModal', confirmModalFactory); diff --git a/src/legacy/ui/public/modals/confirm_modal_promise.js b/src/legacy/ui/public/modals/confirm_modal_promise.js deleted file mode 100644 index 54f568e80bff0..0000000000000 --- a/src/legacy/ui/public/modals/confirm_modal_promise.js +++ /dev/null @@ -1,49 +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 { uiModules } from '../modules'; -import './'; - -const module = uiModules.get('kibana'); - -/** - * @typedef {Object} PromisifiedConfirmOptions - * @property {String} confirmButtonText - * @property {String=} cancelButtonText - */ - -/** - * A "promisified" version of ConfirmModal that binds onCancel and onConfirm to - * Resolve and Reject methods. - */ -module.factory('confirmModalPromise', function(Promise, confirmModal) { - /** - * @param {String} message - * @param {PromisifiedConfirmOptions} customOptions - */ - return (message, customOptions) => - new Promise((resolve, reject) => { - const defaultOptions = { - onConfirm: resolve, - onCancel: reject, - }; - const confirmOptions = Object.assign(defaultOptions, customOptions); - confirmModal(message, confirmOptions); - }); -}); diff --git a/src/legacy/ui/public/modals/index.js b/src/legacy/ui/public/modals/index.js deleted file mode 100644 index d061264345959..0000000000000 --- a/src/legacy/ui/public/modals/index.js +++ /dev/null @@ -1,24 +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 './confirm_modal'; -import './confirm_modal_promise'; - -export { ConfirmationButtonTypes } from './confirm_modal'; -export { ModalOverlay } from './modal_overlay'; diff --git a/src/legacy/ui/public/modals/modal_overlay.html b/src/legacy/ui/public/modals/modal_overlay.html deleted file mode 100644 index 2abc5768f46f1..0000000000000 --- a/src/legacy/ui/public/modals/modal_overlay.html +++ /dev/null @@ -1 +0,0 @@ -
diff --git a/src/legacy/ui/public/modals/modal_overlay.js b/src/legacy/ui/public/modals/modal_overlay.js deleted file mode 100644 index 6ddecee9f2f71..0000000000000 --- a/src/legacy/ui/public/modals/modal_overlay.js +++ /dev/null @@ -1,40 +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 angular from 'angular'; -import modalOverlayTemplate from './modal_overlay.html'; - -/** - * Appends the modal to the dom on instantiation, and removes it when destroy is called. - */ -export class ModalOverlay { - constructor(modalElement) { - this.overlayElement = angular.element(modalOverlayTemplate); - this.overlayElement.append(modalElement); - - angular.element(document.body).append(this.overlayElement); - } - - /** - * Removes the overlay and modal from the dom. - */ - destroy() { - this.overlayElement.remove(); - } -} diff --git a/src/legacy/ui/public/new_platform/new_platform.karma_mock.js b/src/legacy/ui/public/new_platform/new_platform.karma_mock.js index 985dbc78e2f77..47ef690c4f83e 100644 --- a/src/legacy/ui/public/new_platform/new_platform.karma_mock.js +++ b/src/legacy/ui/public/new_platform/new_platform.karma_mock.js @@ -176,7 +176,11 @@ let isAutoRefreshSelectorEnabled = true; export const npStart = { core: { - chrome: {}, + chrome: { + overlays: { + openModal: sinon.fake(), + }, + }, }, plugins: { management: { diff --git a/src/legacy/ui/public/react_components.js b/src/legacy/ui/public/react_components.js index fea25d2c71da3..b771e37c9d538 100644 --- a/src/legacy/ui/public/react_components.js +++ b/src/legacy/ui/public/react_components.js @@ -19,14 +19,12 @@ import 'ngreact'; -import { EuiConfirmModal, EuiIcon, EuiIconTip } from '@elastic/eui'; +import { EuiIcon, EuiIconTip } from '@elastic/eui'; import { uiModules } from './modules'; const app = uiModules.get('app/kibana', ['react']); -app.directive('confirmModal', reactDirective => reactDirective(EuiConfirmModal)); - app.directive('icon', reactDirective => reactDirective(EuiIcon)); app.directive('iconTip', reactDirective => diff --git a/src/legacy/ui/public/saved_objects/__tests__/saved_object.js b/src/legacy/ui/public/saved_objects/__tests__/saved_object.js index ace87a15f7b58..d027d8b6c99da 100644 --- a/src/legacy/ui/public/saved_objects/__tests__/saved_object.js +++ b/src/legacy/ui/public/saved_objects/__tests__/saved_object.js @@ -26,7 +26,7 @@ import { createSavedObjectClass } from '../saved_object'; import StubIndexPattern from 'test_utils/stub_index_pattern'; import { npStart } from 'ui/new_platform'; import { InvalidJSONProperty } from '../../../../../plugins/kibana_utils/public'; -import { npSetup } from '../../new_platform/new_platform.karma_mock'; +import { npSetup, npStart as npStartMock } from '../../new_platform/new_platform.karma_mock'; const getConfig = cfg => cfg; @@ -89,18 +89,12 @@ describe('Saved Object', function() { obj[fName].restore && obj[fName].restore(); } - beforeEach( - ngMock.module( - 'kibana', - // Use the native window.confirm instead of our specialized version to make testing - // this easier. - function($provide) { - const overrideConfirm = message => - window.confirm(message) ? Promise.resolve() : Promise.reject(); - $provide.decorator('confirmModalPromise', () => overrideConfirm); - } - ) - ); + beforeEach(() => { + // Use the native window.confirm instead of our specialized version to make testing + // this easier. + npStartMock.core.overlays.openModal = message => + window.confirm(message) ? Promise.resolve() : Promise.reject(); + }); beforeEach( ngMock.inject(function($window) { diff --git a/x-pack/legacy/plugins/graph/public/app.js b/x-pack/legacy/plugins/graph/public/app.js index 38a601daa178e..7010e1fa773ea 100644 --- a/x-pack/legacy/plugins/graph/public/app.js +++ b/x-pack/legacy/plugins/graph/public/app.js @@ -49,6 +49,7 @@ export function initGraphApp(angularModule, deps) { storage, canEditDrillDownUrls, graphSavePolicy, + overlays, } = deps; const app = angularModule; @@ -162,7 +163,7 @@ export function initGraphApp(angularModule, deps) { }); //======== Controller for basic UI ================== - app.controller('graphuiPlugin', function($scope, $route, $location, confirmModal) { + app.controller('graphuiPlugin', function($scope, $route, $location) { function handleError(err) { const toastTitle = i18n.translate('xpack.graph.errorToastTitle', { defaultMessage: 'Graph Error', @@ -382,23 +383,29 @@ export function initGraphApp(angularModule, deps) { return; } const confirmModalOptions = { - onConfirm: callback, - onCancel: () => {}, confirmButtonText: i18n.translate('xpack.graph.leaveWorkspace.confirmButtonLabel', { defaultMessage: 'Leave anyway', }), title: i18n.translate('xpack.graph.leaveWorkspace.modalTitle', { defaultMessage: 'Unsaved changes', }), + 'data-test-subj': 'confirmModal', ...options, }; - confirmModal( - text || - i18n.translate('xpack.graph.leaveWorkspace.confirmText', { - defaultMessage: 'If you leave now, you will lose unsaved changes.', - }), - confirmModalOptions - ); + + overlays + .openConfirm( + text || + i18n.translate('xpack.graph.leaveWorkspace.confirmText', { + defaultMessage: 'If you leave now, you will lose unsaved changes.', + }), + confirmModalOptions + ) + .then(isConfirmed => { + if (isConfirmed) { + callback(); + } + }); } $scope.confirmWipeWorkspace = canWipeWorkspace; diff --git a/x-pack/legacy/plugins/graph/public/application.ts b/x-pack/legacy/plugins/graph/public/application.ts index 8f486ab6ad51a..80a797b7f0724 100644 --- a/x-pack/legacy/plugins/graph/public/application.ts +++ b/x-pack/legacy/plugins/graph/public/application.ts @@ -4,8 +4,6 @@ * you may not use this file except in compliance with the Elastic License. */ -import { EuiConfirmModal } from '@elastic/eui'; - // inner angular imports // these are necessary to bootstrap the local angular. // They can stay even after NP cutover @@ -20,12 +18,12 @@ import { SavedObjectsClientContract, ToastsStart, IUiSettingsClient, + OverlayStart, } from 'kibana/public'; import { configureAppAngularModule, createTopNavDirective, createTopNavHelper, - confirmModalFactory, addAppRedirectMessageToUrl, } from './legacy_imports'; // @ts-ignore @@ -64,6 +62,7 @@ export interface GraphDependencies { storage: Storage; canEditDrillDownUrls: boolean; graphSavePolicy: string; + overlays: OverlayStart; } export const renderApp = ({ appBasePath, element, ...deps }: GraphDependencies) => { @@ -120,24 +119,15 @@ function mountGraphApp(appBasePath: string, element: HTMLElement) { function createLocalAngularModule(navigation: NavigationStart) { createLocalI18nModule(); createLocalTopNavModule(navigation); - createLocalConfirmModalModule(); const graphAngularModule = angular.module(moduleName, [ ...thirdPartyAngularDependencies, 'graphI18n', 'graphTopNav', - 'graphConfirmModal', ]); return graphAngularModule; } -function createLocalConfirmModalModule() { - angular - .module('graphConfirmModal', ['react']) - .factory('confirmModal', confirmModalFactory) - .directive('confirmModal', reactDirective => reactDirective(EuiConfirmModal)); -} - function createLocalTopNavModule(navigation: NavigationStart) { angular .module('graphTopNav', ['react']) diff --git a/x-pack/legacy/plugins/graph/public/legacy_imports.ts b/x-pack/legacy/plugins/graph/public/legacy_imports.ts index f1839d62a0667..73a96016054fc 100644 --- a/x-pack/legacy/plugins/graph/public/legacy_imports.ts +++ b/x-pack/legacy/plugins/graph/public/legacy_imports.ts @@ -11,8 +11,6 @@ export { SavedObject, SavedObjectKibanaServices } from 'ui/saved_objects/types'; // @ts-ignore export { createTopNavDirective, createTopNavHelper } from 'ui/kbn_top_nav/kbn_top_nav'; // @ts-ignore -export { confirmModalFactory } from 'ui/modals/confirm_modal'; -// @ts-ignore export { addAppRedirectMessageToUrl } from 'ui/notify'; export { createSavedObjectClass } from 'ui/saved_objects/saved_object'; export { configureAppAngularModule } from '../../../../../src/plugins/kibana_legacy/public'; diff --git a/x-pack/legacy/plugins/graph/public/plugin.ts b/x-pack/legacy/plugins/graph/public/plugin.ts index ab610d76be101..48758ee1ec770 100644 --- a/x-pack/legacy/plugins/graph/public/plugin.ts +++ b/x-pack/legacy/plugins/graph/public/plugin.ts @@ -50,6 +50,7 @@ export class GraphPlugin implements Plugin { config: contextCore.uiSettings, toastNotifications: contextCore.notifications.toasts, indexPatterns: this.npDataStart!.indexPatterns, + overlays: contextCore.overlays, }); }, }); diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 5d45a275ede11..e9a5d9611c806 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -352,7 +352,6 @@ "common.ui.flotCharts.thuLabel": "木", "common.ui.flotCharts.tueLabel": "火", "common.ui.flotCharts.wedLabel": "水", - "common.ui.modals.cancelButtonLabel": "キャンセル", "common.ui.paginateControls.pageSizeLabel": "ページサイズ", "common.ui.paginateControls.scrollTopButtonLabel": "最上部に移動", "common.ui.savedObjects.confirmModal.overwriteButtonLabel": "上書き", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 6bbb3e59b25e3..201e3c35ee282 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -352,7 +352,6 @@ "common.ui.flotCharts.thuLabel": "周四", "common.ui.flotCharts.tueLabel": "周二", "common.ui.flotCharts.wedLabel": "周三", - "common.ui.modals.cancelButtonLabel": "取消", "common.ui.paginateControls.pageSizeLabel": "页面大小", "common.ui.paginateControls.scrollTopButtonLabel": "滚动至顶部", "common.ui.savedObjects.confirmModal.overwriteButtonLabel": "覆盖", From 09f1cad573e7683ac0b6548966ba1c5bc3de49ec Mon Sep 17 00:00:00 2001 From: Joe Reuter Date: Mon, 10 Feb 2020 12:48:18 +0100 Subject: [PATCH 5/5] Check for legacy imports in vis types and fix problems (#56763) --- .eslintignore | 1 - .eslintrc.js | 2 + src/dev/precommit_hook/casing_check_config.js | 4 - .../public/discover/get_inner_angular.ts | 3 +- .../public/metric_vis_type.test.ts | 3 + .../public/get_inner_angular.ts | 4 +- .../paginated_table/paginated_table.test.ts | 10 +- .../vis_type_table/public/table_vis.mock.ts | 46 -- .../public/table_vis_controller.test.ts | 66 +-- .../public/components/tag_cloud_options.tsx | 2 +- .../components/tag_cloud_visualization.js | 8 +- .../public/legacy_imports.ts | 2 + .../lib/get_default_query_language.js | 4 +- .../public/components/lib/tick_formatter.js | 4 +- .../components/lib/tick_formatter.test.js | 6 +- .../components/panel_config/gauge.test.js | 4 + .../public/components/vis_editor.js | 14 +- .../public/components/vis_types/table/vis.js | 4 +- .../components/vis_types/timeseries/vis.js | 3 +- .../vis_type_timeseries/public/legacy.ts | 2 +- .../public/legacy_imports.ts} | 6 +- .../public/lib/fetch_fields.js | 9 +- .../vis_type_timeseries/public/metrics_fn.ts | 2 +- .../public/metrics_type.ts | 3 +- .../vis_type_timeseries/public/plugin.ts | 32 +- .../public/request_handler.js | 12 +- .../vis_type_timeseries/public/services.ts | 11 +- .../visualizations/views/timeseries/index.js | 6 +- .../public/__mocks__/services.ts | 55 +++ .../public/__tests__/vega_visualization.js | 3 + .../public/components/vega_vis_editor.tsx | 4 +- .../public/data_model/es_query_parser.js | 2 +- .../public/data_model/es_query_parser.test.js | 6 +- .../public/data_model/search_cache.test.js | 1 + .../public/data_model/time_cache.test.js | 1 + .../public/data_model/vega_parser.test.js | 1 + ...a_config_provider.js => legacy_imports.ts} | 10 +- .../vis_type_vega/public/plugin.ts | 15 +- .../vis_type_vega/public/services.ts | 13 + .../public/shim/legacy_dependencies_plugin.ts | 3 + .../vis_type_vega/public/vega_type.ts | 2 +- .../public/vega_view/vega_base_view.js | 19 +- .../public/vega_view/vega_map_layer.js | 2 +- .../public/vega_view/vega_map_view.js | 10 +- .../vislib/__tests__/response_handlers.js | 1 + .../angular-bootstrap/bindHtml/bindHtml.js | 10 - .../ui/public/angular-bootstrap/index.js | 47 -- .../angular-bootstrap/tooltip/position.js | 152 ------- .../angular-bootstrap/tooltip/tooltip.js | 374 ---------------- .../angular_bootstrap/bind_html/bind_html.js | 17 + .../public/angular_bootstrap/index.ts | 50 +++ .../angular_bootstrap/tooltip/position.js | 167 +++++++ .../angular_bootstrap/tooltip/tooltip.js | 423 ++++++++++++++++++ .../tooltip/tooltip_html_unsafe_popup.html} | 0 .../tooltip/tooltip_popup.html} | 0 src/plugins/kibana_legacy/public/index.ts | 2 + .../plugins/graph/public/legacy_imports.ts | 1 - x-pack/legacy/plugins/graph/public/plugin.ts | 2 + 58 files changed, 901 insertions(+), 765 deletions(-) delete mode 100644 src/legacy/core_plugins/vis_type_table/public/table_vis.mock.ts rename src/legacy/core_plugins/{vis_type_vega/public/helpers/index.js => vis_type_timeseries/public/legacy_imports.ts} (79%) create mode 100644 src/legacy/core_plugins/vis_type_vega/public/__mocks__/services.ts rename src/legacy/core_plugins/vis_type_vega/public/{helpers/vega_config_provider.js => legacy_imports.ts} (77%) delete mode 100755 src/legacy/ui/public/angular-bootstrap/bindHtml/bindHtml.js delete mode 100644 src/legacy/ui/public/angular-bootstrap/index.js delete mode 100755 src/legacy/ui/public/angular-bootstrap/tooltip/position.js delete mode 100755 src/legacy/ui/public/angular-bootstrap/tooltip/tooltip.js create mode 100755 src/plugins/kibana_legacy/public/angular_bootstrap/bind_html/bind_html.js create mode 100644 src/plugins/kibana_legacy/public/angular_bootstrap/index.ts create mode 100755 src/plugins/kibana_legacy/public/angular_bootstrap/tooltip/position.js create mode 100755 src/plugins/kibana_legacy/public/angular_bootstrap/tooltip/tooltip.js rename src/{legacy/ui/public/angular-bootstrap/tooltip/tooltip-html-unsafe-popup.html => plugins/kibana_legacy/public/angular_bootstrap/tooltip/tooltip_html_unsafe_popup.html} (100%) rename src/{legacy/ui/public/angular-bootstrap/tooltip/tooltip-popup.html => plugins/kibana_legacy/public/angular_bootstrap/tooltip/tooltip_popup.html} (100%) diff --git a/.eslintignore b/.eslintignore index 86a01b68ecab1..c3921bd22e1ab 100644 --- a/.eslintignore +++ b/.eslintignore @@ -11,7 +11,6 @@ bower_components /src/plugins/data/common/es_query/kuery/ast/_generated_/** /src/legacy/core_plugins/vis_type_timelion/public/_generated_/** src/legacy/core_plugins/vis_type_vislib/public/vislib/__tests__/lib/fixtures/mock_data -/src/legacy/ui/public/angular-bootstrap /src/legacy/ui/public/flot-charts /test/fixtures/scenarios /src/legacy/core_plugins/console/public/webpackShims diff --git a/.eslintrc.js b/.eslintrc.js index 199f3743fd621..abfe5e0a6cc27 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -302,6 +302,8 @@ module.exports = { 'test/plugin_functional/plugins/**/public/np_ready/**/*', 'test/plugin_functional/plugins/**/server/np_ready/**/*', 'src/legacy/core_plugins/**/public/np_ready/**/*', + 'src/legacy/core_plugins/vis_type_*/public/**/*', + '!src/legacy/core_plugins/vis_type_*/public/legacy*', 'src/legacy/core_plugins/**/server/np_ready/**/*', 'x-pack/legacy/plugins/**/public/np_ready/**/*', 'x-pack/legacy/plugins/**/server/np_ready/**/*', diff --git a/src/dev/precommit_hook/casing_check_config.js b/src/dev/precommit_hook/casing_check_config.js index 78fc041345577..ef114f51f3100 100644 --- a/src/dev/precommit_hook/casing_check_config.js +++ b/src/dev/precommit_hook/casing_check_config.js @@ -88,7 +88,6 @@ export const IGNORE_DIRECTORY_GLOBS = [ 'src/babel-*', 'packages/*', 'packages/kbn-ui-framework/generator-kui', - 'src/legacy/ui/public/angular-bootstrap', 'src/legacy/ui/public/flot-charts', 'src/legacy/ui/public/utils/lodash-mixins', 'test/functional/fixtures/es_archiver/visualize_source-filters', @@ -124,9 +123,6 @@ export const TEMPORARILY_IGNORED_PATHS = [ 'src/legacy/core_plugins/timelion/server/series_functions/__tests__/fixtures/tlConfig.js', 'src/fixtures/config_upgrade_from_4.0.0_to_4.0.1-snapshot.json', 'src/legacy/core_plugins/vis_type_vislib/public/vislib/__tests__/lib/fixtures/mock_data/terms/_seriesMultiple.js', - 'src/legacy/ui/public/angular-bootstrap/bindHtml/bindHtml.js', - 'src/legacy/ui/public/angular-bootstrap/tooltip/tooltip-html-unsafe-popup.html', - 'src/legacy/ui/public/angular-bootstrap/tooltip/tooltip-popup.html', 'src/legacy/ui/public/assets/favicons/android-chrome-192x192.png', 'src/legacy/ui/public/assets/favicons/android-chrome-256x256.png', 'src/legacy/ui/public/assets/favicons/android-chrome-512x512.png', diff --git a/src/legacy/core_plugins/kibana/public/discover/get_inner_angular.ts b/src/legacy/core_plugins/kibana/public/discover/get_inner_angular.ts index cc4dabd123ff4..eb6d7e6467f2f 100644 --- a/src/legacy/core_plugins/kibana/public/discover/get_inner_angular.ts +++ b/src/legacy/core_plugins/kibana/public/discover/get_inner_angular.ts @@ -21,7 +21,6 @@ // these are necessary to bootstrap the local angular. // They can stay even after NP cutover import angular from 'angular'; -import 'ui/angular-bootstrap'; import { EuiIcon } from '@elastic/eui'; // @ts-ignore import { StateProvider } from 'ui/state_management/state'; @@ -64,6 +63,7 @@ import { createFieldChooserDirective } from './np_ready/components/field_chooser import { createDiscoverFieldDirective } from './np_ready/components/field_chooser/discover_field'; import { CollapsibleSidebarProvider } from './np_ready/angular/directives/collapsible_sidebar/collapsible_sidebar'; import { DiscoverStartPlugins } from './plugin'; +import { initAngularBootstrap } from '../../../../../plugins/kibana_legacy/public'; import { createCssTruncateDirective } from './np_ready/angular/directives/css_truncate'; // @ts-ignore import { FixedScrollProvider } from './np_ready/angular/directives/fixed_scroll'; @@ -85,6 +85,7 @@ import { * needs to render, so in the end the current 'kibana' angular module is no longer necessary */ export function getInnerAngularModule(name: string, core: CoreStart, deps: DiscoverStartPlugins) { + initAngularBootstrap(); const module = initializeInnerAngularModule(name, core, deps.navigation, deps.data); configureAppAngularModule(module, core as LegacyCoreStart, true); return module; diff --git a/src/legacy/core_plugins/vis_type_metric/public/metric_vis_type.test.ts b/src/legacy/core_plugins/vis_type_metric/public/metric_vis_type.test.ts index 4f535c62f56a0..28565e0181b84 100644 --- a/src/legacy/core_plugins/vis_type_metric/public/metric_vis_type.test.ts +++ b/src/legacy/core_plugins/vis_type_metric/public/metric_vis_type.test.ts @@ -19,6 +19,9 @@ import $ from 'jquery'; +// TODO This is an integration test and thus requires a running platform. When moving to the new platform, +// this test has to be migrated to the newly created integration test environment. +// eslint-disable-next-line @kbn/eslint/no-restricted-paths import { npStart } from 'ui/new_platform'; // @ts-ignore import getStubIndexPattern from 'fixtures/stubbed_logstash_index_pattern'; diff --git a/src/legacy/core_plugins/vis_type_table/public/get_inner_angular.ts b/src/legacy/core_plugins/vis_type_table/public/get_inner_angular.ts index 9f3a8327c9ad9..18d8e7bc9d8bb 100644 --- a/src/legacy/core_plugins/vis_type_table/public/get_inner_angular.ts +++ b/src/legacy/core_plugins/vis_type_table/public/get_inner_angular.ts @@ -21,7 +21,6 @@ // these are necessary to bootstrap the local angular. // They can stay even after NP cutover import angular from 'angular'; -import 'ui/angular-bootstrap'; import 'angular-recursion'; import { i18nDirective, i18nFilter, I18nProvider } from '@kbn/i18n/angular'; import { CoreStart, LegacyCoreStart, IUiSettingsClient } from 'kibana/public'; @@ -34,6 +33,9 @@ import { StateManagementConfigProvider, configureAppAngularModule, } from './legacy_imports'; +import { initAngularBootstrap } from '../../../../plugins/kibana_legacy/public'; + +initAngularBootstrap(); const thirdPartyAngularDependencies = ['ngSanitize', 'ui.bootstrap', 'RecursionHelper']; diff --git a/src/legacy/core_plugins/vis_type_table/public/paginated_table/paginated_table.test.ts b/src/legacy/core_plugins/vis_type_table/public/paginated_table/paginated_table.test.ts index 781782e42fbaf..7352236f03feb 100644 --- a/src/legacy/core_plugins/vis_type_table/public/paginated_table/paginated_table.test.ts +++ b/src/legacy/core_plugins/vis_type_table/public/paginated_table/paginated_table.test.ts @@ -22,11 +22,15 @@ import angular, { IRootScopeService, IScope, ICompileService } from 'angular'; import $ from 'jquery'; import 'angular-sanitize'; import 'angular-mocks'; -import '../table_vis.mock'; import { getAngularModule } from '../get_inner_angular'; import { initTableVisLegacyModule } from '../table_vis_legacy_module'; -import { npStart } from '../legacy_imports'; +import { coreMock } from '../../../../../core/public/mocks'; + +jest.mock('ui/new_platform'); +jest.mock('../../../../../plugins/kibana_legacy/public/angular/angular_config', () => ({ + configureAppAngularModule: () => {}, +})); interface Sort { columnIndex: number; @@ -69,7 +73,7 @@ describe('Table Vis - Paginated table', () => { let paginatedTable: any; const initLocalAngular = () => { - const tableVisModule = getAngularModule('kibana/table_vis', npStart.core); + const tableVisModule = getAngularModule('kibana/table_vis', coreMock.createStart()); initTableVisLegacyModule(tableVisModule); }; diff --git a/src/legacy/core_plugins/vis_type_table/public/table_vis.mock.ts b/src/legacy/core_plugins/vis_type_table/public/table_vis.mock.ts deleted file mode 100644 index d04964cb7af03..0000000000000 --- a/src/legacy/core_plugins/vis_type_table/public/table_vis.mock.ts +++ /dev/null @@ -1,46 +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 { createUiNewPlatformMock } from 'ui/new_platform/__mocks__/helpers'; -import { StubBrowserStorage } from 'test_utils/stub_browser_storage'; -import { injectedMetadataServiceMock } from '../../../../core/public/mocks'; - -jest.doMock('ui/new_platform', () => { - const npMock = createUiNewPlatformMock(); - return { - npSetup: { - ...npMock.npSetup, - core: { - ...npMock.npSetup.core, - injectedMetadata: injectedMetadataServiceMock.createSetupContract(), - }, - }, - npStart: { - ...npMock.npStart, - core: { - ...npMock.npStart.core, - injectedMetadata: injectedMetadataServiceMock.createStartContract(), - }, - }, - }; -}); - -Object.assign(window, { - sessionStorage: new StubBrowserStorage(), -}); diff --git a/src/legacy/core_plugins/vis_type_table/public/table_vis_controller.test.ts b/src/legacy/core_plugins/vis_type_table/public/table_vis_controller.test.ts index d8912975227bf..0e1e48d00a1b2 100644 --- a/src/legacy/core_plugins/vis_type_table/public/table_vis_controller.test.ts +++ b/src/legacy/core_plugins/vis_type_table/public/table_vis_controller.test.ts @@ -21,21 +21,26 @@ import angular, { IRootScopeService, IScope, ICompileService } from 'angular'; import 'angular-mocks'; import 'angular-sanitize'; import $ from 'jquery'; -import './table_vis.mock'; // @ts-ignore import StubIndexPattern from 'test_utils/stub_index_pattern'; import { getAngularModule } from './get_inner_angular'; import { initTableVisLegacyModule } from './table_vis_legacy_module'; -import { npStart, IAggConfig, tabifyAggResponse } from './legacy_imports'; import { tableVisTypeDefinition } from './table_vis_type'; import { Vis } from '../../visualizations/public'; -import { setup as visualizationsSetup } from '../../visualizations/public/np_ready/public/legacy'; // eslint-disable-next-line import { stubFields } from '../../../../plugins/data/public/stubs'; // eslint-disable-next-line -import { setFieldFormats } from '../../../../plugins/data/public/services'; import { tableVisResponseHandler } from './table_vis_response_handler'; +import { coreMock } from '../../../../core/public/mocks'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { AggConfigs } from 'ui/agg_types'; +import { tabifyAggResponse, IAggConfig } from './legacy_imports'; + +jest.mock('ui/new_platform'); +jest.mock('../../../../plugins/kibana_legacy/public/angular/angular_config', () => ({ + configureAppAngularModule: () => {}, +})); interface TableVisScope extends IScope { [key: string]: any; @@ -79,14 +84,11 @@ describe('Table Vis - Controller', () => { let stubIndexPattern: any; const initLocalAngular = () => { - const tableVisModule = getAngularModule('kibana/table_vis', npStart.core); + const tableVisModule = getAngularModule('kibana/table_vis', coreMock.createStart()); initTableVisLegacyModule(tableVisModule); }; beforeEach(initLocalAngular); - beforeAll(() => { - visualizationsSetup.types.createBaseVisualization(tableVisTypeDefinition); - }); beforeEach(angular.mock.module('kibana/table_vis')); beforeEach( @@ -98,38 +100,38 @@ describe('Table Vis - Controller', () => { ); beforeEach(() => { - setFieldFormats(({ - getDefaultInstance: jest.fn(), - } as unknown) as any); stubIndexPattern = new StubIndexPattern( 'logstash-*', (cfg: any) => cfg, 'time', stubFields, - npStart.core + coreMock.createStart() ); }); function getRangeVis(params?: object) { - // @ts-ignore - return new Vis(stubIndexPattern, { - type: 'table', - params: params || {}, - aggs: [ - { type: 'count', schema: 'metric' }, - { - type: 'range', - schema: 'bucket', - params: { - field: 'bytes', - ranges: [ - { from: 0, to: 1000 }, - { from: 1000, to: 2000 }, - ], + return ({ + type: tableVisTypeDefinition, + params: Object.assign({}, tableVisTypeDefinition.visConfig.defaults, params), + aggs: new AggConfigs( + stubIndexPattern, + [ + { type: 'count', schema: 'metric' }, + { + type: 'range', + schema: 'bucket', + params: { + field: 'bytes', + ranges: [ + { from: 0, to: 1000 }, + { from: 1000, to: 2000 }, + ], + }, }, - }, - ], - }); + ], + tableVisTypeDefinition.editorConfig.schemas.all + ), + } as unknown) as Vis; } const dimensions = { @@ -241,13 +243,13 @@ describe('Table Vis - Controller', () => { const vis = getRangeVis({ showPartialRows: true }); initController(vis); - expect(vis.isHierarchical()).toEqual(true); + expect(vis.type.hierarchicalData(vis)).toEqual(true); }); test('passes partialRows:false to tabify based on the vis params', () => { const vis = getRangeVis({ showPartialRows: false }); initController(vis); - expect(vis.isHierarchical()).toEqual(false); + expect(vis.type.hierarchicalData(vis)).toEqual(false); }); }); diff --git a/src/legacy/core_plugins/vis_type_tagcloud/public/components/tag_cloud_options.tsx b/src/legacy/core_plugins/vis_type_tagcloud/public/components/tag_cloud_options.tsx index eed5ffe8c3584..ab7c2cd980c42 100644 --- a/src/legacy/core_plugins/vis_type_tagcloud/public/components/tag_cloud_options.tsx +++ b/src/legacy/core_plugins/vis_type_tagcloud/public/components/tag_cloud_options.tsx @@ -21,10 +21,10 @@ import React from 'react'; import { EuiPanel } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { ValidatedDualRange } from 'ui/validated_range'; import { VisOptionsProps } from '../../../vis_default_editor/public'; import { SelectOption, SwitchOption } from '../../../vis_type_vislib/public'; import { TagCloudVisParams } from '../types'; +import { ValidatedDualRange } from '../legacy_imports'; function TagCloudOptions({ stateParams, setValue, vis }: VisOptionsProps) { const handleFontSizeChange = ([minFontSize, maxFontSize]: [string | number, string | number]) => { diff --git a/src/legacy/core_plugins/vis_type_tagcloud/public/components/tag_cloud_visualization.js b/src/legacy/core_plugins/vis_type_tagcloud/public/components/tag_cloud_visualization.js index f2163abbbc723..5528278adf4eb 100644 --- a/src/legacy/core_plugins/vis_type_tagcloud/public/components/tag_cloud_visualization.js +++ b/src/legacy/core_plugins/vis_type_tagcloud/public/components/tag_cloud_visualization.js @@ -21,9 +21,9 @@ import React from 'react'; import * as Rx from 'rxjs'; import { take } from 'rxjs/operators'; import { render, unmountComponentAtNode } from 'react-dom'; +import { I18nProvider } from '@kbn/i18n/react'; -import { getFormat } from 'ui/visualize/loader/pipeline_helpers/utilities'; -import { I18nContext } from 'ui/i18n'; +import { getFormat } from '../legacy_imports'; import { Label } from './label'; import { TagCloud } from './tag_cloud'; @@ -65,9 +65,9 @@ export function createTagCloudVisualization({ colors }) { this._containerNode.appendChild(this._feedbackNode); this._feedbackMessage = React.createRef(); render( - + - , + , this._feedbackNode ); diff --git a/src/legacy/core_plugins/vis_type_tagcloud/public/legacy_imports.ts b/src/legacy/core_plugins/vis_type_tagcloud/public/legacy_imports.ts index ecc56ea0c34be..d5b442bc5b346 100644 --- a/src/legacy/core_plugins/vis_type_tagcloud/public/legacy_imports.ts +++ b/src/legacy/core_plugins/vis_type_tagcloud/public/legacy_imports.ts @@ -18,3 +18,5 @@ */ export { Schemas } from 'ui/agg_types'; +export { ValidatedDualRange } from 'ui/validated_range'; +export { getFormat } from 'ui/visualize/loader/pipeline_helpers/utilities'; diff --git a/src/legacy/core_plugins/vis_type_timeseries/public/components/lib/get_default_query_language.js b/src/legacy/core_plugins/vis_type_timeseries/public/components/lib/get_default_query_language.js index 61662787c982d..26723da5ab5c9 100644 --- a/src/legacy/core_plugins/vis_type_timeseries/public/components/lib/get_default_query_language.js +++ b/src/legacy/core_plugins/vis_type_timeseries/public/components/lib/get_default_query_language.js @@ -17,8 +17,8 @@ * under the License. */ -import chrome from 'ui/chrome'; +import { getUISettings } from '../../services'; export function getDefaultQueryLanguage() { - return chrome.getUiSettingsClient().get('search:queryLanguage'); + return getUISettings().get('search:queryLanguage'); } diff --git a/src/legacy/core_plugins/vis_type_timeseries/public/components/lib/tick_formatter.js b/src/legacy/core_plugins/vis_type_timeseries/public/components/lib/tick_formatter.js index 0705805312d2f..3ab8e0f6b885e 100644 --- a/src/legacy/core_plugins/vis_type_timeseries/public/components/lib/tick_formatter.js +++ b/src/legacy/core_plugins/vis_type_timeseries/public/components/lib/tick_formatter.js @@ -19,11 +19,11 @@ import handlebars from 'handlebars/dist/handlebars'; import { isNumber } from 'lodash'; -import { npStart } from 'ui/new_platform'; import { inputFormats, outputFormats, isDuration } from '../lib/durations'; +import { getFieldFormats } from '../../services'; export const createTickFormatter = (format = '0,0.[00]', template, getConfig = null) => { - const fieldFormats = npStart.plugins.data.fieldFormats; + const fieldFormats = getFieldFormats(); if (!template) template = '{{value}}'; const render = handlebars.compile(template, { knownHelpersOnly: true }); diff --git a/src/legacy/core_plugins/vis_type_timeseries/public/components/lib/tick_formatter.test.js b/src/legacy/core_plugins/vis_type_timeseries/public/components/lib/tick_formatter.test.js index 76d3cff17343e..e87cba126bb46 100644 --- a/src/legacy/core_plugins/vis_type_timeseries/public/components/lib/tick_formatter.test.js +++ b/src/legacy/core_plugins/vis_type_timeseries/public/components/lib/tick_formatter.test.js @@ -17,9 +17,9 @@ * under the License. */ -import { npStart } from 'ui/new_platform'; import { createTickFormatter } from './tick_formatter'; import { getFieldFormatsRegistry } from '../../../../../../test_utils/public/stub_field_formats'; +import { setFieldFormats } from '../../services'; const mockUiSettings = { get: item => { @@ -46,9 +46,7 @@ const mockCore = { }; describe('createTickFormatter(format, template)', () => { - npStart.plugins.data = { - fieldFormats: getFieldFormatsRegistry(mockCore), - }; + setFieldFormats(getFieldFormatsRegistry(mockCore)); test('returns a number with two decimal place by default', () => { const fn = createTickFormatter(); diff --git a/src/legacy/core_plugins/vis_type_timeseries/public/components/panel_config/gauge.test.js b/src/legacy/core_plugins/vis_type_timeseries/public/components/panel_config/gauge.test.js index 9ec8184dbaebb..d92dafadb68bc 100644 --- a/src/legacy/core_plugins/vis_type_timeseries/public/components/panel_config/gauge.test.js +++ b/src/legacy/core_plugins/vis_type_timeseries/public/components/panel_config/gauge.test.js @@ -26,6 +26,10 @@ jest.mock('plugins/data', () => { }; }); +jest.mock('../lib/get_default_query_language', () => ({ + getDefaultQueryLanguage: () => 'kuery', +})); + import { GaugePanelConfig } from './gauge'; describe('GaugePanelConfig', () => { diff --git a/src/legacy/core_plugins/vis_type_timeseries/public/components/vis_editor.js b/src/legacy/core_plugins/vis_type_timeseries/public/components/vis_editor.js index 3dedb67bd1d99..b2dd1813e6d20 100644 --- a/src/legacy/core_plugins/vis_type_timeseries/public/components/vis_editor.js +++ b/src/legacy/core_plugins/vis_type_timeseries/public/components/vis_editor.js @@ -30,13 +30,11 @@ import { createBrushHandler } from '../lib/create_brush_handler'; import { fetchFields } from '../lib/fetch_fields'; import { extractIndexPatterns } from '../../../../../plugins/vis_type_timeseries/common/extract_index_patterns'; import { esKuery } from '../../../../../plugins/data/public'; - -import { npStart } from 'ui/new_platform'; +import { getSavedObjectsClient, getUISettings, getDataStart, getCoreStart } from '../services'; import { CoreStartContextProvider } from '../contexts/query_input_bar_context'; import { KibanaContextProvider } from '../../../../../plugins/kibana_react/public'; import { Storage } from '../../../../../plugins/kibana_utils/public'; -import { timefilter } from 'ui/timefilter'; const VIS_STATE_DEBOUNCE_DELAY = 200; const APP_NAME = 'VisEditor'; @@ -52,7 +50,7 @@ export class VisEditor extends Component { visFields: props.visFields, extractedIndexPatterns: [''], }; - this.onBrush = createBrushHandler(timefilter); + this.onBrush = createBrushHandler(getDataStart().query.timefilter); this.visDataSubject = new Rx.BehaviorSubject(this.props.visData); this.visData$ = this.visDataSubject.asObservable().pipe(share()); @@ -60,8 +58,8 @@ export class VisEditor extends Component { // core dependencies required by React components downstream. this.coreContext = { appName: APP_NAME, - uiSettings: npStart.core.uiSettings, - savedObjectsClient: npStart.core.savedObjects.client, + uiSettings: getUISettings(), + savedObjectsClient: getSavedObjectsClient(), store: this.localStorage, }; } @@ -175,8 +173,8 @@ export class VisEditor extends Component { services={{ appName: APP_NAME, storage: this.localStorage, - data: npStart.plugins.data, - ...npStart.core, + data: getDataStart(), + ...getCoreStart(), }} >
diff --git a/src/legacy/core_plugins/vis_type_timeseries/public/components/vis_types/table/vis.js b/src/legacy/core_plugins/vis_type_timeseries/public/components/vis_types/table/vis.js index 94f4506cd0172..1fe9358cbfea9 100644 --- a/src/legacy/core_plugins/vis_type_timeseries/public/components/vis_types/table/vis.js +++ b/src/legacy/core_plugins/vis_type_timeseries/public/components/vis_types/table/vis.js @@ -20,7 +20,6 @@ import _, { isArray, last, get } from 'lodash'; import React, { Component } from 'react'; import PropTypes from 'prop-types'; -import { npStart } from 'ui/new_platform'; import { createTickFormatter } from '../../lib/tick_formatter'; import { calculateLabel } from '../../../../../../../plugins/vis_type_timeseries/common/calculate_label'; import { isSortable } from './is_sortable'; @@ -28,6 +27,7 @@ import { EuiToolTip, EuiIcon } from '@elastic/eui'; import { replaceVars } from '../../lib/replace_vars'; import { fieldFormats } from '../../../../../../../plugins/data/public'; import { FormattedMessage } from '@kbn/i18n/react'; +import { getFieldFormats } from '../../../services'; import { METRIC_TYPES } from '../../../../../../../plugins/vis_type_timeseries/common/metric_types'; @@ -49,7 +49,7 @@ export class TableVis extends Component { constructor(props) { super(props); - const fieldFormatsService = npStart.plugins.data.fieldFormats; + const fieldFormatsService = getFieldFormats(); const DateFormat = fieldFormatsService.getType(fieldFormats.FIELD_FORMAT_IDS.DATE); this.dateFormatter = new DateFormat({}, this.props.getConfig); diff --git a/src/legacy/core_plugins/vis_type_timeseries/public/components/vis_types/timeseries/vis.js b/src/legacy/core_plugins/vis_type_timeseries/public/components/vis_types/timeseries/vis.js index 5243f5f92a621..954d3d174bb8c 100644 --- a/src/legacy/core_plugins/vis_type_timeseries/public/components/vis_types/timeseries/vis.js +++ b/src/legacy/core_plugins/vis_type_timeseries/public/components/vis_types/timeseries/vis.js @@ -22,7 +22,6 @@ import React, { Component } from 'react'; import reactCSS from 'reactcss'; import { startsWith, get, cloneDeep, map } from 'lodash'; -import { toastNotifications } from 'ui/notify'; import { htmlIdGenerator } from '@elastic/eui'; import { ScaleType } from '@elastic/charts'; @@ -36,6 +35,7 @@ import { areFieldsDifferent } from '../../lib/charts'; import { createXaxisFormatter } from '../../lib/create_xaxis_formatter'; import { isBackgroundDark } from '../../../lib/set_is_reversed'; import { STACKED_OPTIONS } from '../../../visualizations/constants'; +import { getCoreStart } from '../../../services'; export class TimeseriesVisualization extends Component { static propTypes = { @@ -108,6 +108,7 @@ export class TimeseriesVisualization extends Component { createTickFormatter(get(model, 'formatter'), get(model, 'value_template'), getConfig); componentDidUpdate() { + const toastNotifications = getCoreStart().notifications.toasts; if ( this.showToastNotification && this.notificationReason !== this.showToastNotification.reason diff --git a/src/legacy/core_plugins/vis_type_timeseries/public/legacy.ts b/src/legacy/core_plugins/vis_type_timeseries/public/legacy.ts index 93b35ee284f18..fb22bbd4146e2 100644 --- a/src/legacy/core_plugins/vis_type_timeseries/public/legacy.ts +++ b/src/legacy/core_plugins/vis_type_timeseries/public/legacy.ts @@ -32,4 +32,4 @@ const plugins: Readonly = { const pluginInstance = plugin({} as PluginInitializerContext); export const setup = pluginInstance.setup(npSetup.core, plugins); -export const start = pluginInstance.start(npStart.core); +export const start = pluginInstance.start(npStart.core, npStart.plugins); diff --git a/src/legacy/core_plugins/vis_type_vega/public/helpers/index.js b/src/legacy/core_plugins/vis_type_timeseries/public/legacy_imports.ts similarity index 79% rename from src/legacy/core_plugins/vis_type_vega/public/helpers/index.js rename to src/legacy/core_plugins/vis_type_timeseries/public/legacy_imports.ts index e9d6eb21fd3c7..401acfc8df766 100644 --- a/src/legacy/core_plugins/vis_type_vega/public/helpers/index.js +++ b/src/legacy/core_plugins/vis_type_timeseries/public/legacy_imports.ts @@ -17,4 +17,8 @@ * under the License. */ -export * from './vega_config_provider'; +export { PersistedState } from 'ui/persisted_state'; +// @ts-ignore +export { defaultFeedbackMessage } from 'ui/vis/default_feedback_message'; +// @ts-ignore +export { timezoneProvider } from 'ui/vis/lib/timezone'; diff --git a/src/legacy/core_plugins/vis_type_timeseries/public/lib/fetch_fields.js b/src/legacy/core_plugins/vis_type_timeseries/public/lib/fetch_fields.js index 68e694f23fa7f..9c64d0da2d88a 100644 --- a/src/legacy/core_plugins/vis_type_timeseries/public/lib/fetch_fields.js +++ b/src/legacy/core_plugins/vis_type_timeseries/public/lib/fetch_fields.js @@ -16,19 +16,16 @@ * specific language governing permissions and limitations * under the License. */ -import { kfetch } from 'ui/kfetch'; -import { toastNotifications } from 'ui/notify'; import { i18n } from '@kbn/i18n'; import { extractIndexPatterns } from '../../../../../plugins/vis_type_timeseries/common/extract_index_patterns'; +import { getCoreStart } from '../services'; export async function fetchFields(indexPatterns = ['*']) { const patterns = Array.isArray(indexPatterns) ? indexPatterns : [indexPatterns]; try { const indexFields = await Promise.all( patterns.map(pattern => { - return kfetch({ - method: 'GET', - pathname: '/api/metrics/fields', + return getCoreStart().http.get('/api/metrics/fields', { query: { index: pattern, }, @@ -43,7 +40,7 @@ export async function fetchFields(indexPatterns = ['*']) { }, {}); return fields; } catch (error) { - toastNotifications.addDanger({ + getCoreStart().notifications.toasts.addDanger({ title: i18n.translate('visTypeTimeseries.fetchFields.loadIndexPatternFieldsErrorMessage', { defaultMessage: 'Unable to load index_pattern fields', }), diff --git a/src/legacy/core_plugins/vis_type_timeseries/public/metrics_fn.ts b/src/legacy/core_plugins/vis_type_timeseries/public/metrics_fn.ts index 225d81b71b8e0..5786399fc7830 100644 --- a/src/legacy/core_plugins/vis_type_timeseries/public/metrics_fn.ts +++ b/src/legacy/core_plugins/vis_type_timeseries/public/metrics_fn.ts @@ -19,11 +19,11 @@ import { get } from 'lodash'; import { i18n } from '@kbn/i18n'; -import { PersistedState } from 'ui/persisted_state'; import { ExpressionFunction, KibanaContext, Render } from '../../../../plugins/expressions/public'; // @ts-ignore import { metricsRequestHandler } from './request_handler'; +import { PersistedState } from './legacy_imports'; const name = 'tsvb'; type Context = KibanaContext | null; diff --git a/src/legacy/core_plugins/vis_type_timeseries/public/metrics_type.ts b/src/legacy/core_plugins/vis_type_timeseries/public/metrics_type.ts index 22d2b3b10e566..01750ee0c448d 100644 --- a/src/legacy/core_plugins/vis_type_timeseries/public/metrics_type.ts +++ b/src/legacy/core_plugins/vis_type_timeseries/public/metrics_type.ts @@ -18,8 +18,7 @@ */ import { i18n } from '@kbn/i18n'; -// @ts-ignore -import { defaultFeedbackMessage } from 'ui/vis/default_feedback_message'; +import { defaultFeedbackMessage } from './legacy_imports'; // @ts-ignore import { metricsRequestHandler } from './request_handler'; diff --git a/src/legacy/core_plugins/vis_type_timeseries/public/plugin.ts b/src/legacy/core_plugins/vis_type_timeseries/public/plugin.ts index 4d1222d6f5a87..38a9c68487854 100644 --- a/src/legacy/core_plugins/vis_type_timeseries/public/plugin.ts +++ b/src/legacy/core_plugins/vis_type_timeseries/public/plugin.ts @@ -16,29 +16,31 @@ * specific language governing permissions and limitations * under the License. */ -import { - PluginInitializerContext, - CoreSetup, - CoreStart, - Plugin, - SavedObjectsClientContract, - IUiSettingsClient, -} from '../../../../core/public'; +import { PluginInitializerContext, CoreSetup, CoreStart, Plugin } from 'kibana/public'; import { Plugin as ExpressionsPublicPlugin } from '../../../../plugins/expressions/public'; import { VisualizationsSetup } from '../../visualizations/public'; import { createMetricsFn } from './metrics_fn'; import { metricsVisDefinition } from './metrics_type'; -import { setSavedObjectsClient, setUISettings, setI18n } from './services'; +import { + setSavedObjectsClient, + setUISettings, + setI18n, + setFieldFormats, + setCoreStart, + setDataStart, +} from './services'; +import { DataPublicPluginStart } from '../../../../plugins/data/public'; /** @internal */ export interface MetricsPluginSetupDependencies { expressions: ReturnType; visualizations: VisualizationsSetup; } -export interface MetricsVisualizationDependencies { - uiSettings: IUiSettingsClient; - savedObjectsClient: SavedObjectsClientContract; + +/** @internal */ +export interface MetricsPluginStartDependencies { + data: DataPublicPluginStart; } /** @internal */ @@ -58,9 +60,11 @@ export class MetricsPlugin implements Plugin, void> { visualizations.types.createReactVisualization(metricsVisDefinition); } - public start(core: CoreStart) { - // nothing to do here yet + public start(core: CoreStart, { data }: MetricsPluginStartDependencies) { setSavedObjectsClient(core.savedObjects); setI18n(core.i18n); + setFieldFormats(data.fieldFormats); + setDataStart(data); + setCoreStart(core); } } diff --git a/src/legacy/core_plugins/vis_type_timeseries/public/request_handler.js b/src/legacy/core_plugins/vis_type_timeseries/public/request_handler.js index 84f62612aa974..032ef335314d9 100644 --- a/src/legacy/core_plugins/vis_type_timeseries/public/request_handler.js +++ b/src/legacy/core_plugins/vis_type_timeseries/public/request_handler.js @@ -18,10 +18,8 @@ */ import { validateInterval } from './lib/validate_interval'; -import { timezoneProvider } from 'ui/vis/lib/timezone'; -import { timefilter } from 'ui/timefilter'; -import { kfetch } from 'ui/kfetch'; -import { getUISettings } from './services'; +import { timezoneProvider } from './legacy_imports'; +import { getUISettings, getDataStart, getCoreStart } from './services'; export const metricsRequestHandler = async ({ uiState, @@ -34,7 +32,7 @@ export const metricsRequestHandler = async ({ const config = getUISettings(); const timezone = timezoneProvider(config)(); const uiStateObj = uiState.get(visParams.type, {}); - const parsedTimeRange = timefilter.calculateBounds(timeRange); + const parsedTimeRange = getDataStart().query.timefilter.timefilter.calculateBounds(timeRange); const scaledDataFormat = config.get('dateFormat:scaled'); const dateFormat = config.get('dateFormat'); @@ -44,9 +42,7 @@ export const metricsRequestHandler = async ({ validateInterval(parsedTimeRange, visParams, maxBuckets); - const resp = await kfetch({ - pathname: '/api/metrics/vis/data', - method: 'POST', + const resp = await getCoreStart().http.post('/api/metrics/vis/data', { body: JSON.stringify({ timerange: { timezone, diff --git a/src/legacy/core_plugins/vis_type_timeseries/public/services.ts b/src/legacy/core_plugins/vis_type_timeseries/public/services.ts index af04578b8e27f..c16ed47f54874 100644 --- a/src/legacy/core_plugins/vis_type_timeseries/public/services.ts +++ b/src/legacy/core_plugins/vis_type_timeseries/public/services.ts @@ -17,13 +17,22 @@ * under the License. */ -import { I18nStart, SavedObjectsStart, IUiSettingsClient } from 'src/core/public'; +import { I18nStart, SavedObjectsStart, IUiSettingsClient, CoreStart } from 'src/core/public'; import { createGetterSetter } from '../../../../plugins/kibana_utils/public'; +import { DataPublicPluginStart, FieldFormatsStart } from '../../../../plugins/data/public'; export const [getUISettings, setUISettings] = createGetterSetter('UISettings'); +export const [getFieldFormats, setFieldFormats] = createGetterSetter( + 'FieldFormats' +); + export const [getSavedObjectsClient, setSavedObjectsClient] = createGetterSetter( 'SavedObjectsClient' ); +export const [getCoreStart, setCoreStart] = createGetterSetter('CoreStart'); + +export const [getDataStart, setDataStart] = createGetterSetter('DataStart'); + export const [getI18n, setI18n] = createGetterSetter('I18n'); diff --git a/src/legacy/core_plugins/vis_type_timeseries/public/visualizations/views/timeseries/index.js b/src/legacy/core_plugins/vis_type_timeseries/public/visualizations/views/timeseries/index.js index bcd0b6314cef1..986111b462b35 100644 --- a/src/legacy/core_plugins/vis_type_timeseries/public/visualizations/views/timeseries/index.js +++ b/src/legacy/core_plugins/vis_type_timeseries/public/visualizations/views/timeseries/index.js @@ -33,9 +33,9 @@ import { } from '@elastic/charts'; import { EuiIcon } from '@elastic/eui'; -import { timezoneProvider } from 'ui/vis/lib/timezone'; +import { timezoneProvider } from '../../../legacy_imports'; import { eventBus, ACTIVE_CURSOR } from '../../lib/active_cursor'; -import chrome from 'ui/chrome'; +import { getUISettings } from '../../../services'; import { GRID_LINE_CONFIG, ICON_TYPES_MAP, STACKED_OPTIONS } from '../../constants'; import { AreaSeriesDecorator } from './decorators/area_decorator'; import { BarSeriesDecorator } from './decorators/bar_decorator'; @@ -85,7 +85,7 @@ export const TimeSeries = ({ }, []); // eslint-disable-line const tooltipFormatter = decorateFormatter(xAxisFormatter); - const uiSettings = chrome.getUiSettingsClient(); + const uiSettings = getUISettings(); const timeZone = timezoneProvider(uiSettings)(); const hasBarChart = series.some(({ bars }) => bars.show); diff --git a/src/legacy/core_plugins/vis_type_vega/public/__mocks__/services.ts b/src/legacy/core_plugins/vis_type_vega/public/__mocks__/services.ts new file mode 100644 index 0000000000000..64a9aaaf3b7a6 --- /dev/null +++ b/src/legacy/core_plugins/vis_type_vega/public/__mocks__/services.ts @@ -0,0 +1,55 @@ +/* + * 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 { createGetterSetter } from '../../../../../plugins/kibana_utils/common'; +import { DataPublicPluginStart } from '../../../../../plugins/data/public'; +import { IUiSettingsClient, NotificationsStart, SavedObjectsStart } from 'kibana/public'; +import { dataPluginMock } from '../../../../../plugins/data/public/mocks'; +import { coreMock } from '../../../../../core/public/mocks'; + +export const [getData, setData] = createGetterSetter('Data'); +setData(dataPluginMock.createStartContract()); + +export const [getNotifications, setNotifications] = createGetterSetter( + 'Notifications' +); +setNotifications(coreMock.createStart().notifications); + +export const [getUISettings, setUISettings] = createGetterSetter('UISettings'); +setUISettings(coreMock.createStart().uiSettings); + +export const [getSavedObjects, setSavedObjects] = createGetterSetter( + 'SavedObjects' +); +setSavedObjects(coreMock.createStart().savedObjects); + +export const [getInjectedVars, setInjectedVars] = createGetterSetter<{ + esShardTimeout: number; + enableExternalUrls: boolean; + emsTileLayerId: unknown; +}>('InjectedVars'); +setInjectedVars({ + emsTileLayerId: {}, + enableExternalUrls: true, + esShardTimeout: 10000, +}); + +export const getEsShardTimeout = () => getInjectedVars().esShardTimeout; +export const getEnableExternalUrls = () => getInjectedVars().enableExternalUrls; +export const getEmsTileLayerId = () => getInjectedVars().emsTileLayerId; diff --git a/src/legacy/core_plugins/vis_type_vega/public/__tests__/vega_visualization.js b/src/legacy/core_plugins/vis_type_vega/public/__tests__/vega_visualization.js index 6c9eb86a9d2c0..b2ad45b5d7b6d 100644 --- a/src/legacy/core_plugins/vis_type_vega/public/__tests__/vega_visualization.js +++ b/src/legacy/core_plugins/vis_type_vega/public/__tests__/vega_visualization.js @@ -43,6 +43,9 @@ import { SearchCache } from '../data_model/search_cache'; import { setup as visualizationsSetup } from '../../../visualizations/public/np_ready/public/legacy'; import { createVegaTypeDefinition } from '../vega_type'; +// TODO This is an integration test and thus requires a running platform. When moving to the new platform, +// this test has to be migrated to the newly created integration test environment. +// eslint-disable-next-line @kbn/eslint/no-restricted-paths import { npStart } from 'ui/new_platform'; const THRESHOLD = 0.1; diff --git a/src/legacy/core_plugins/vis_type_vega/public/components/vega_vis_editor.tsx b/src/legacy/core_plugins/vis_type_vega/public/components/vega_vis_editor.tsx index 18d48aea5d39a..707a6830b5ba4 100644 --- a/src/legacy/core_plugins/vis_type_vega/public/components/vega_vis_editor.tsx +++ b/src/legacy/core_plugins/vis_type_vega/public/components/vega_vis_editor.tsx @@ -24,7 +24,7 @@ import compactStringify from 'json-stringify-pretty-compact'; import hjson from 'hjson'; import { i18n } from '@kbn/i18n'; -import { toastNotifications } from 'ui/notify'; +import { getNotifications } from '../services'; import { VisParams } from '../vega_fn'; import { VegaHelpMenu } from './vega_help_menu'; import { VegaActionsMenu } from './vega_actions_menu'; @@ -50,7 +50,7 @@ function format(value: string, stringify: typeof compactStringify, options?: any return stringify(spec, options); } catch (err) { // This is a common case - user tries to format an invalid HJSON text - toastNotifications.addError(err, { + getNotifications().toasts.addError(err, { title: i18n.translate('visTypeVega.editor.formatError', { defaultMessage: 'Error formatting spec', }), diff --git a/src/legacy/core_plugins/vis_type_vega/public/data_model/es_query_parser.js b/src/legacy/core_plugins/vis_type_vega/public/data_model/es_query_parser.js index 2f25f70610a81..7c239800483f0 100644 --- a/src/legacy/core_plugins/vis_type_vega/public/data_model/es_query_parser.js +++ b/src/legacy/core_plugins/vis_type_vega/public/data_model/es_query_parser.js @@ -21,7 +21,7 @@ import _ from 'lodash'; import moment from 'moment'; import { i18n } from '@kbn/i18n'; -import { getEsShardTimeout } from '../helpers'; +import { getEsShardTimeout } from '../services'; const TIMEFILTER = '%timefilter%'; const AUTOINTERVAL = '%autointerval%'; diff --git a/src/legacy/core_plugins/vis_type_vega/public/data_model/es_query_parser.test.js b/src/legacy/core_plugins/vis_type_vega/public/data_model/es_query_parser.test.js index 691e5e8944241..c519da33ab1c9 100644 --- a/src/legacy/core_plugins/vis_type_vega/public/data_model/es_query_parser.test.js +++ b/src/legacy/core_plugins/vis_type_vega/public/data_model/es_query_parser.test.js @@ -21,10 +21,6 @@ import { cloneDeep } from 'lodash'; import moment from 'moment'; import { EsQueryParser } from './es_query_parser'; -jest.mock('../helpers', () => ({ - getEsShardTimeout: jest.fn(() => '10000'), -})); - const second = 1000; const minute = 60 * second; const hour = 60 * minute; @@ -47,6 +43,8 @@ function create(min, max, dashboardCtx) { return inst; } +jest.mock('../services'); + describe(`EsQueryParser time`, () => { test(`roundInterval(4s)`, () => { expect(EsQueryParser._roundInterval(4 * second)).toBe(`1s`); diff --git a/src/legacy/core_plugins/vis_type_vega/public/data_model/search_cache.test.js b/src/legacy/core_plugins/vis_type_vega/public/data_model/search_cache.test.js index 0ec018f46c02b..92f80545ce1b5 100644 --- a/src/legacy/core_plugins/vis_type_vega/public/data_model/search_cache.test.js +++ b/src/legacy/core_plugins/vis_type_vega/public/data_model/search_cache.test.js @@ -18,6 +18,7 @@ */ import { SearchCache } from './search_cache'; +jest.mock('../services'); describe(`SearchCache`, () => { class FauxEs { diff --git a/src/legacy/core_plugins/vis_type_vega/public/data_model/time_cache.test.js b/src/legacy/core_plugins/vis_type_vega/public/data_model/time_cache.test.js index b76709ea2c934..074744a0bda5e 100644 --- a/src/legacy/core_plugins/vis_type_vega/public/data_model/time_cache.test.js +++ b/src/legacy/core_plugins/vis_type_vega/public/data_model/time_cache.test.js @@ -18,6 +18,7 @@ */ import { TimeCache } from './time_cache'; +jest.mock('../services'); describe(`TimeCache`, () => { class FauxTimefilter { diff --git a/src/legacy/core_plugins/vis_type_vega/public/data_model/vega_parser.test.js b/src/legacy/core_plugins/vis_type_vega/public/data_model/vega_parser.test.js index 1bc8b1f90daab..78d1cad874311 100644 --- a/src/legacy/core_plugins/vis_type_vega/public/data_model/vega_parser.test.js +++ b/src/legacy/core_plugins/vis_type_vega/public/data_model/vega_parser.test.js @@ -20,6 +20,7 @@ import { cloneDeep } from 'lodash'; import { VegaParser } from './vega_parser'; import { bypassExternalUrlCheck } from '../vega_view/vega_base_view'; +jest.mock('../services'); describe(`VegaParser._setDefaultValue`, () => { function check(spec, expected, ...params) { diff --git a/src/legacy/core_plugins/vis_type_vega/public/helpers/vega_config_provider.js b/src/legacy/core_plugins/vis_type_vega/public/legacy_imports.ts similarity index 77% rename from src/legacy/core_plugins/vis_type_vega/public/helpers/vega_config_provider.js rename to src/legacy/core_plugins/vis_type_vega/public/legacy_imports.ts index cc41b18479f93..9e1067ed9099a 100644 --- a/src/legacy/core_plugins/vis_type_vega/public/helpers/vega_config_provider.js +++ b/src/legacy/core_plugins/vis_type_vega/public/legacy_imports.ts @@ -17,7 +17,9 @@ * under the License. */ -import chrome from 'ui/chrome'; - -export const getEsShardTimeout = () => chrome.getInjected('esShardTimeout'); -export const getEnableExternalUrls = () => chrome.getInjected('enableExternalUrls'); +// @ts-ignore +export { defaultFeedbackMessage } from 'ui/vis/default_feedback_message'; +// @ts-ignore +export { KibanaMapLayer } from 'ui/vis/map/kibana_map_layer'; +// @ts-ignore +export { KibanaMap } from 'ui/vis/map/kibana_map'; diff --git a/src/legacy/core_plugins/vis_type_vega/public/plugin.ts b/src/legacy/core_plugins/vis_type_vega/public/plugin.ts index 75444a4a4f8e4..9721de9848cfc 100644 --- a/src/legacy/core_plugins/vis_type_vega/public/plugin.ts +++ b/src/legacy/core_plugins/vis_type_vega/public/plugin.ts @@ -21,7 +21,13 @@ import { LegacyDependenciesPlugin, LegacyDependenciesPluginSetup } from './shim' import { Plugin as ExpressionsPublicPlugin } from '../../../../plugins/expressions/public'; import { Plugin as DataPublicPlugin } from '../../../../plugins/data/public'; import { VisualizationsSetup } from '../../visualizations/public'; -import { setNotifications, setData, setSavedObjects } from './services'; +import { + setNotifications, + setData, + setSavedObjects, + setInjectedVars, + setUISettings, +} from './services'; import { createVegaFn } from './vega_fn'; import { createVegaTypeDefinition } from './vega_type'; @@ -59,6 +65,13 @@ export class VegaPlugin implements Plugin, void> { core: CoreSetup, { data, expressions, visualizations, __LEGACY }: VegaPluginSetupDependencies ) { + setInjectedVars({ + esShardTimeout: core.injectedMetadata.getInjectedVar('esShardTimeout') as number, + enableExternalUrls: core.injectedMetadata.getInjectedVar('enableExternalUrls') as boolean, + emsTileLayerId: core.injectedMetadata.getInjectedVar('emsTileLayerId', true), + }); + setUISettings(core.uiSettings); + const visualizationDependencies: Readonly = { core, plugins: { diff --git a/src/legacy/core_plugins/vis_type_vega/public/services.ts b/src/legacy/core_plugins/vis_type_vega/public/services.ts index 94723f1a378d2..88e0e0098bf8c 100644 --- a/src/legacy/core_plugins/vis_type_vega/public/services.ts +++ b/src/legacy/core_plugins/vis_type_vega/public/services.ts @@ -21,6 +21,7 @@ import { SavedObjectsStart } from 'kibana/public'; import { NotificationsStart } from 'src/core/public'; import { DataPublicPluginStart } from '../../../../plugins/data/public'; import { createGetterSetter } from '../../../../plugins/kibana_utils/public'; +import { IUiSettingsClient } from '../../../../core/public'; export const [getData, setData] = createGetterSetter('Data'); @@ -28,6 +29,18 @@ export const [getNotifications, setNotifications] = createGetterSetter('UISettings'); + export const [getSavedObjects, setSavedObjects] = createGetterSetter( 'SavedObjects' ); + +export const [getInjectedVars, setInjectedVars] = createGetterSetter<{ + esShardTimeout: number; + enableExternalUrls: boolean; + emsTileLayerId: unknown; +}>('InjectedVars'); + +export const getEsShardTimeout = () => getInjectedVars().esShardTimeout; +export const getEnableExternalUrls = () => getInjectedVars().enableExternalUrls; +export const getEmsTileLayerId = () => getInjectedVars().emsTileLayerId; diff --git a/src/legacy/core_plugins/vis_type_vega/public/shim/legacy_dependencies_plugin.ts b/src/legacy/core_plugins/vis_type_vega/public/shim/legacy_dependencies_plugin.ts index 5cf65d62a6aed..8925f76cffa43 100644 --- a/src/legacy/core_plugins/vis_type_vega/public/shim/legacy_dependencies_plugin.ts +++ b/src/legacy/core_plugins/vis_type_vega/public/shim/legacy_dependencies_plugin.ts @@ -17,7 +17,10 @@ * under the License. */ +// TODO remove this file as soon as serviceSettings is exposed in the new platform +// eslint-disable-next-line @kbn/eslint/no-restricted-paths import chrome from 'ui/chrome'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths import 'ui/vis/map/service_settings'; import { CoreStart, Plugin } from 'kibana/public'; diff --git a/src/legacy/core_plugins/vis_type_vega/public/vega_type.ts b/src/legacy/core_plugins/vis_type_vega/public/vega_type.ts index a7ca0dd3bb349..1d4655b4d525f 100644 --- a/src/legacy/core_plugins/vis_type_vega/public/vega_type.ts +++ b/src/legacy/core_plugins/vis_type_vega/public/vega_type.ts @@ -19,7 +19,7 @@ import { i18n } from '@kbn/i18n'; // @ts-ignore -import { defaultFeedbackMessage } from 'ui/vis/default_feedback_message'; +import { defaultFeedbackMessage } from './legacy_imports'; import { Status } from '../../visualizations/public'; import { DefaultEditorSize } from '../../vis_default_editor/public'; import { VegaVisualizationDependencies } from './plugin'; diff --git a/src/legacy/core_plugins/vis_type_vega/public/vega_view/vega_base_view.js b/src/legacy/core_plugins/vis_type_vega/public/vega_view/vega_base_view.js index 9d6adfd11aedd..a6c17547d058e 100644 --- a/src/legacy/core_plugins/vis_type_vega/public/vega_view/vega_base_view.js +++ b/src/legacy/core_plugins/vis_type_vega/public/vega_view/vega_base_view.js @@ -17,7 +17,6 @@ * under the License. */ -import chrome from 'ui/chrome'; import $ from 'jquery'; import moment from 'moment'; import dateMath from '@elastic/datemath'; @@ -29,7 +28,7 @@ import { i18n } from '@kbn/i18n'; import { TooltipHandler } from './vega_tooltip'; import { esFilters } from '../../../../../plugins/data/public'; -import { getEnableExternalUrls } from '../helpers/vega_config_provider'; +import { getEnableExternalUrls } from '../services'; vega.scheme('elastic', VISUALIZATION_COLORS); @@ -279,20 +278,14 @@ export class VegaBaseView { * @param {string} [index] as defined in Kibana, or default if missing */ async removeFilterHandler(query, index) { - const $injector = await chrome.dangerouslyGetActiveInjector(); const indexId = await this._findIndex(index); const filter = esFilters.buildQueryFilter(query, indexId); - // This is a workaround for the https://github.com/elastic/kibana/issues/18863 - // Once fixed, replace with a direct call (no await is needed because its not async) - // this._queryfilter.removeFilter(filter); - $injector.get('$rootScope').$evalAsync(() => { - try { - this._filterManager.removeFilter(filter); - } catch (err) { - this.onError(err); - } - }); + try { + this._filterManager.removeFilter(filter); + } catch (err) { + this.onError(err); + } } removeAllFiltersHandler() { diff --git a/src/legacy/core_plugins/vis_type_vega/public/vega_view/vega_map_layer.js b/src/legacy/core_plugins/vis_type_vega/public/vega_view/vega_map_layer.js index 2794de6946ba0..38540e9f218fb 100644 --- a/src/legacy/core_plugins/vis_type_vega/public/vega_view/vega_map_layer.js +++ b/src/legacy/core_plugins/vis_type_vega/public/vega_view/vega_map_layer.js @@ -19,7 +19,7 @@ import L from 'leaflet'; import 'leaflet-vega'; -import { KibanaMapLayer } from 'ui/vis/map/kibana_map_layer'; +import { KibanaMapLayer } from '../legacy_imports'; export class VegaMapLayer extends KibanaMapLayer { constructor(spec, options) { diff --git a/src/legacy/core_plugins/vis_type_vega/public/vega_view/vega_map_view.js b/src/legacy/core_plugins/vis_type_vega/public/vega_view/vega_map_view.js index 82bcd6626789f..487c90d01ada3 100644 --- a/src/legacy/core_plugins/vis_type_vega/public/vega_view/vega_map_view.js +++ b/src/legacy/core_plugins/vis_type_vega/public/vega_view/vega_map_view.js @@ -17,12 +17,12 @@ * under the License. */ -import { KibanaMap } from 'ui/vis/map/kibana_map'; import * as vega from 'vega-lib'; +import { i18n } from '@kbn/i18n'; import { VegaBaseView } from './vega_base_view'; import { VegaMapLayer } from './vega_map_layer'; -import { i18n } from '@kbn/i18n'; -import chrome from 'ui/chrome'; +import { KibanaMap } from '../legacy_imports'; +import { getEmsTileLayerId, getUISettings } from '../services'; export class VegaMapView extends VegaBaseView { async _initViewCustomizations() { @@ -35,10 +35,10 @@ export class VegaMapView extends VegaBaseView { const tmsServices = await this._serviceSettings.getTMSServices(); // In some cases, Vega may be initialized twice, e.g. after awaiting... if (!this._$container) return; - const emsTileLayerId = chrome.getInjected('emsTileLayerId', true); + const emsTileLayerId = getEmsTileLayerId(); const mapStyle = mapConfig.mapStyle === 'default' ? emsTileLayerId.bright : mapConfig.mapStyle; - const isDarkMode = chrome.getUiSettingsClient().get('theme:darkMode'); + const isDarkMode = getUISettings().get('theme:darkMode'); baseMapOpts = tmsServices.find(s => s.id === mapStyle); baseMapOpts = { ...baseMapOpts, diff --git a/src/legacy/core_plugins/vis_type_vislib/public/vislib/__tests__/response_handlers.js b/src/legacy/core_plugins/vis_type_vislib/public/vislib/__tests__/response_handlers.js index 642a032d8b9c2..3574fb232883d 100644 --- a/src/legacy/core_plugins/vis_type_vislib/public/vislib/__tests__/response_handlers.js +++ b/src/legacy/core_plugins/vis_type_vislib/public/vislib/__tests__/response_handlers.js @@ -21,6 +21,7 @@ import sinon from 'sinon'; import ngMock from 'ng_mock'; import expect from '@kbn/expect'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths import { aggResponseIndex } from 'ui/agg_response'; import { vislibSeriesResponseHandler } from '../response_handler'; diff --git a/src/legacy/ui/public/angular-bootstrap/bindHtml/bindHtml.js b/src/legacy/ui/public/angular-bootstrap/bindHtml/bindHtml.js deleted file mode 100755 index bafc738268626..0000000000000 --- a/src/legacy/ui/public/angular-bootstrap/bindHtml/bindHtml.js +++ /dev/null @@ -1,10 +0,0 @@ -angular.module('ui.bootstrap.bindHtml', []) - - .directive('bindHtmlUnsafe', function () { - return function (scope, element, attr) { - element.addClass('ng-binding').data('$binding', attr.bindHtmlUnsafe); - scope.$watch(attr.bindHtmlUnsafe, function bindHtmlUnsafeWatchAction(value) { - element.html(value || ''); - }); - }; - }); diff --git a/src/legacy/ui/public/angular-bootstrap/index.js b/src/legacy/ui/public/angular-bootstrap/index.js deleted file mode 100644 index f574345af48ab..0000000000000 --- a/src/legacy/ui/public/angular-bootstrap/index.js +++ /dev/null @@ -1,47 +0,0 @@ - -/* eslint-disable */ - -/** - * TODO: Write custom components that address our needs to directly and deprecate these Bootstrap components. - */ - -import 'angular'; - -import { uiModules } from 'ui/modules'; - -uiModules.get('kibana', [ - 'ui.bootstrap', -]); - -/* - * angular-ui-bootstrap - * http://angular-ui.github.io/bootstrap/ - - * Version: 0.12.1 - 2015-02-20 - * License: MIT - */ -angular.module('ui.bootstrap', [ - 'ui.bootstrap.tpls', - 'ui.bootstrap.bindHtml', - 'ui.bootstrap.tooltip', -]); - -angular.module('ui.bootstrap.tpls', [ - 'template/tooltip/tooltip-html-unsafe-popup.html', - 'template/tooltip/tooltip-popup.html', -]); - -import './bindHtml/bindHtml'; -import './tooltip/tooltip'; - -import tooltipUnsafePopup from './tooltip/tooltip-html-unsafe-popup.html'; - -angular.module('template/tooltip/tooltip-html-unsafe-popup.html', []).run(['$templateCache', function($templateCache) { - $templateCache.put('template/tooltip/tooltip-html-unsafe-popup.html', tooltipUnsafePopup); -}]); - -import tooltipPopup from './tooltip/tooltip-popup.html'; - -angular.module('template/tooltip/tooltip-popup.html', []).run(['$templateCache', function($templateCache) { - $templateCache.put('template/tooltip/tooltip-popup.html', tooltipPopup); -}]); diff --git a/src/legacy/ui/public/angular-bootstrap/tooltip/position.js b/src/legacy/ui/public/angular-bootstrap/tooltip/position.js deleted file mode 100755 index 3444c33449152..0000000000000 --- a/src/legacy/ui/public/angular-bootstrap/tooltip/position.js +++ /dev/null @@ -1,152 +0,0 @@ -angular.module('ui.bootstrap.position', []) - -/** - * A set of utility methods that can be use to retrieve position of DOM elements. - * It is meant to be used where we need to absolute-position DOM elements in - * relation to other, existing elements (this is the case for tooltips, popovers, - * typeahead suggestions etc.). - */ - .factory('$position', ['$document', '$window', function ($document, $window) { - - function getStyle(el, cssprop) { - if (el.currentStyle) { //IE - return el.currentStyle[cssprop]; - } else if ($window.getComputedStyle) { - return $window.getComputedStyle(el)[cssprop]; - } - // finally try and get inline style - return el.style[cssprop]; - } - - /** - * Checks if a given element is statically positioned - * @param element - raw DOM element - */ - function isStaticPositioned(element) { - return (getStyle(element, 'position') || 'static' ) === 'static'; - } - - /** - * returns the closest, non-statically positioned parentOffset of a given element - * @param element - */ - var parentOffsetEl = function (element) { - var docDomEl = $document[0]; - var offsetParent = element.offsetParent || docDomEl; - while (offsetParent && offsetParent !== docDomEl && isStaticPositioned(offsetParent) ) { - offsetParent = offsetParent.offsetParent; - } - return offsetParent || docDomEl; - }; - - return { - /** - * Provides read-only equivalent of jQuery's position function: - * http://api.jquery.com/position/ - */ - position: function (element) { - var elBCR = this.offset(element); - var offsetParentBCR = { top: 0, left: 0 }; - var offsetParentEl = parentOffsetEl(element[0]); - if (offsetParentEl != $document[0]) { - offsetParentBCR = this.offset(angular.element(offsetParentEl)); - offsetParentBCR.top += offsetParentEl.clientTop - offsetParentEl.scrollTop; - offsetParentBCR.left += offsetParentEl.clientLeft - offsetParentEl.scrollLeft; - } - - var boundingClientRect = element[0].getBoundingClientRect(); - return { - width: boundingClientRect.width || element.prop('offsetWidth'), - height: boundingClientRect.height || element.prop('offsetHeight'), - top: elBCR.top - offsetParentBCR.top, - left: elBCR.left - offsetParentBCR.left - }; - }, - - /** - * Provides read-only equivalent of jQuery's offset function: - * http://api.jquery.com/offset/ - */ - offset: function (element) { - var boundingClientRect = element[0].getBoundingClientRect(); - return { - width: boundingClientRect.width || element.prop('offsetWidth'), - height: boundingClientRect.height || element.prop('offsetHeight'), - top: boundingClientRect.top + ($window.pageYOffset || $document[0].documentElement.scrollTop), - left: boundingClientRect.left + ($window.pageXOffset || $document[0].documentElement.scrollLeft) - }; - }, - - /** - * Provides coordinates for the targetEl in relation to hostEl - */ - positionElements: function (hostEl, targetEl, positionStr, appendToBody) { - - var positionStrParts = positionStr.split('-'); - var pos0 = positionStrParts[0], pos1 = positionStrParts[1] || 'center'; - - var hostElPos, - targetElWidth, - targetElHeight, - targetElPos; - - hostElPos = appendToBody ? this.offset(hostEl) : this.position(hostEl); - - targetElWidth = targetEl.prop('offsetWidth'); - targetElHeight = targetEl.prop('offsetHeight'); - - var shiftWidth = { - center: function () { - return hostElPos.left + hostElPos.width / 2 - targetElWidth / 2; - }, - left: function () { - return hostElPos.left; - }, - right: function () { - return hostElPos.left + hostElPos.width; - } - }; - - var shiftHeight = { - center: function () { - return hostElPos.top + hostElPos.height / 2 - targetElHeight / 2; - }, - top: function () { - return hostElPos.top; - }, - bottom: function () { - return hostElPos.top + hostElPos.height; - } - }; - - switch (pos0) { - case 'right': - targetElPos = { - top: shiftHeight[pos1](), - left: shiftWidth[pos0]() - }; - break; - case 'left': - targetElPos = { - top: shiftHeight[pos1](), - left: hostElPos.left - targetElWidth - }; - break; - case 'bottom': - targetElPos = { - top: shiftHeight[pos0](), - left: shiftWidth[pos1]() - }; - break; - default: - targetElPos = { - top: hostElPos.top - targetElHeight, - left: shiftWidth[pos1]() - }; - break; - } - - return targetElPos; - } - }; - }]); diff --git a/src/legacy/ui/public/angular-bootstrap/tooltip/tooltip.js b/src/legacy/ui/public/angular-bootstrap/tooltip/tooltip.js deleted file mode 100755 index b59b2922d8089..0000000000000 --- a/src/legacy/ui/public/angular-bootstrap/tooltip/tooltip.js +++ /dev/null @@ -1,374 +0,0 @@ -import './position'; - -/** - * The following features are still outstanding: animation as a - * function, placement as a function, inside, support for more triggers than - * just mouse enter/leave, html tooltips, and selector delegation. - */ -angular.module( 'ui.bootstrap.tooltip', [ 'ui.bootstrap.position' ] ) - -/** - * The $tooltip service creates tooltip- and popover-like directives as well as - * houses global options for them. - */ -.provider( '$tooltip', function () { - // The default options tooltip and popover. - var defaultOptions = { - placement: 'top', - animation: true, - popupDelay: 0 - }; - - // Default hide triggers for each show trigger - var triggerMap = { - 'mouseenter': 'mouseleave', - 'click': 'click', - 'focus': 'blur' - }; - - // The options specified to the provider globally. - var globalOptions = {}; - - /** - * `options({})` allows global configuration of all tooltips in the - * application. - * - * var app = angular.module( 'App', ['ui.bootstrap.tooltip'], function( $tooltipProvider ) { - * // place tooltips left instead of top by default - * $tooltipProvider.options( { placement: 'left' } ); - * }); - */ - this.options = function( value ) { - angular.extend( globalOptions, value ); - }; - - /** - * This allows you to extend the set of trigger mappings available. E.g.: - * - * $tooltipProvider.setTriggers( 'openTrigger': 'closeTrigger' ); - */ - this.setTriggers = function setTriggers ( triggers ) { - angular.extend( triggerMap, triggers ); - }; - - /** - * This is a helper function for translating camel-case to snake-case. - */ - function snake_case(name){ - var regexp = /[A-Z]/g; - var separator = '-'; - return name.replace(regexp, function(letter, pos) { - return (pos ? separator : '') + letter.toLowerCase(); - }); - } - - /** - * Returns the actual instance of the $tooltip service. - * TODO support multiple triggers - */ - this.$get = [ '$window', '$compile', '$timeout', '$document', '$position', '$interpolate', function ( $window, $compile, $timeout, $document, $position, $interpolate ) { - return function $tooltip ( type, prefix, defaultTriggerShow ) { - var options = angular.extend( {}, defaultOptions, globalOptions ); - - /** - * Returns an object of show and hide triggers. - * - * If a trigger is supplied, - * it is used to show the tooltip; otherwise, it will use the `trigger` - * option passed to the `$tooltipProvider.options` method; else it will - * default to the trigger supplied to this directive factory. - * - * The hide trigger is based on the show trigger. If the `trigger` option - * was passed to the `$tooltipProvider.options` method, it will use the - * mapped trigger from `triggerMap` or the passed trigger if the map is - * undefined; otherwise, it uses the `triggerMap` value of the show - * trigger; else it will just use the show trigger. - */ - function getTriggers ( trigger ) { - var show = trigger || options.trigger || defaultTriggerShow; - var hide = triggerMap[show] || show; - return { - show: show, - hide: hide - }; - } - - var directiveName = snake_case( type ); - - var startSym = $interpolate.startSymbol(); - var endSym = $interpolate.endSymbol(); - var template = - '
'+ - '
'; - - return { - restrict: 'EA', - compile: function (tElem, tAttrs) { - var tooltipLinker = $compile( template ); - - return function link ( scope, element, attrs ) { - var tooltip; - var tooltipLinkedScope; - var transitionTimeout; - var popupTimeout; - var appendToBody = angular.isDefined( options.appendToBody ) ? options.appendToBody : false; - var triggers = getTriggers( undefined ); - var hasEnableExp = angular.isDefined(attrs[prefix+'Enable']); - var ttScope = scope.$new(true); - - var positionTooltip = function () { - - var ttPosition = $position.positionElements(element, tooltip, ttScope.placement, appendToBody); - ttPosition.top += 'px'; - ttPosition.left += 'px'; - - // Now set the calculated positioning. - tooltip.css( ttPosition ); - }; - - // By default, the tooltip is not open. - // TODO add ability to start tooltip opened - ttScope.isOpen = false; - - function toggleTooltipBind () { - if ( ! ttScope.isOpen ) { - showTooltipBind(); - } else { - hideTooltipBind(); - } - } - - // Show the tooltip with delay if specified, otherwise show it immediately - function showTooltipBind() { - if(hasEnableExp && !scope.$eval(attrs[prefix+'Enable'])) { - return; - } - - prepareTooltip(); - - if ( ttScope.popupDelay ) { - // Do nothing if the tooltip was already scheduled to pop-up. - // This happens if show is triggered multiple times before any hide is triggered. - if (!popupTimeout) { - popupTimeout = $timeout( show, ttScope.popupDelay, false ); - popupTimeout - .then(reposition => reposition()) - .catch((error) => { - // if the timeout is canceled then the string `canceled` is thrown. To prevent - // this from triggering an 'unhandled promise rejection' in angular 1.5+ the - // $timeout service explicitly tells $q that the promise it generated is "handled" - // but that does not include down chain promises like the one created by calling - // `popupTimeout.then()`. Because of this we need to ignore the "canceled" string - // and only propagate real errors - if (error !== 'canceled') { - throw error - } - }); - } - } else { - show()(); - } - } - - function hideTooltipBind () { - scope.$evalAsync(function () { - hide(); - }); - } - - // Show the tooltip popup element. - function show() { - - popupTimeout = null; - - // If there is a pending remove transition, we must cancel it, lest the - // tooltip be mysteriously removed. - if ( transitionTimeout ) { - $timeout.cancel( transitionTimeout ); - transitionTimeout = null; - } - - // Don't show empty tooltips. - if ( ! ttScope.content ) { - return angular.noop; - } - - createTooltip(); - - // Set the initial positioning. - tooltip.css({ top: 0, left: 0, display: 'block' }); - ttScope.$digest(); - - positionTooltip(); - - // And show the tooltip. - ttScope.isOpen = true; - ttScope.$digest(); // digest required as $apply is not called - - // Return positioning function as promise callback for correct - // positioning after draw. - return positionTooltip; - } - - // Hide the tooltip popup element. - function hide() { - // First things first: we don't show it anymore. - ttScope.isOpen = false; - - //if tooltip is going to be shown after delay, we must cancel this - $timeout.cancel( popupTimeout ); - popupTimeout = null; - - // And now we remove it from the DOM. However, if we have animation, we - // need to wait for it to expire beforehand. - // FIXME: this is a placeholder for a port of the transitions library. - if ( ttScope.animation ) { - if (!transitionTimeout) { - transitionTimeout = $timeout(removeTooltip, 500); - } - } else { - removeTooltip(); - } - } - - function createTooltip() { - // There can only be one tooltip element per directive shown at once. - if (tooltip) { - removeTooltip(); - } - tooltipLinkedScope = ttScope.$new(); - tooltip = tooltipLinker(tooltipLinkedScope, function (tooltip) { - if ( appendToBody ) { - $document.find( 'body' ).append( tooltip ); - } else { - element.after( tooltip ); - } - }); - } - - function removeTooltip() { - transitionTimeout = null; - if (tooltip) { - tooltip.remove(); - tooltip = null; - } - if (tooltipLinkedScope) { - tooltipLinkedScope.$destroy(); - tooltipLinkedScope = null; - } - } - - function prepareTooltip() { - prepPlacement(); - prepPopupDelay(); - } - - /** - * Observe the relevant attributes. - */ - attrs.$observe( type, function ( val ) { - ttScope.content = val; - - if (!val && ttScope.isOpen ) { - hide(); - } - }); - - attrs.$observe( prefix+'Title', function ( val ) { - ttScope.title = val; - }); - - function prepPlacement() { - var val = attrs[ prefix + 'Placement' ]; - ttScope.placement = angular.isDefined( val ) ? val : options.placement; - } - - function prepPopupDelay() { - var val = attrs[ prefix + 'PopupDelay' ]; - var delay = parseInt( val, 10 ); - ttScope.popupDelay = ! isNaN(delay) ? delay : options.popupDelay; - } - - var unregisterTriggers = function () { - element.unbind(triggers.show, showTooltipBind); - element.unbind(triggers.hide, hideTooltipBind); - }; - - function prepTriggers() { - var val = attrs[ prefix + 'Trigger' ]; - unregisterTriggers(); - - triggers = getTriggers( val ); - - if ( triggers.show === triggers.hide ) { - element.bind( triggers.show, toggleTooltipBind ); - } else { - element.bind( triggers.show, showTooltipBind ); - element.bind( triggers.hide, hideTooltipBind ); - } - } - prepTriggers(); - - var animation = scope.$eval(attrs[prefix + 'Animation']); - ttScope.animation = angular.isDefined(animation) ? !!animation : options.animation; - - var appendToBodyVal = scope.$eval(attrs[prefix + 'AppendToBody']); - appendToBody = angular.isDefined(appendToBodyVal) ? appendToBodyVal : appendToBody; - - // if a tooltip is attached to we need to remove it on - // location change as its parent scope will probably not be destroyed - // by the change. - if ( appendToBody ) { - scope.$on('$locationChangeSuccess', function closeTooltipOnLocationChangeSuccess () { - if ( ttScope.isOpen ) { - hide(); - } - }); - } - - // Make sure tooltip is destroyed and removed. - scope.$on('$destroy', function onDestroyTooltip() { - $timeout.cancel( transitionTimeout ); - $timeout.cancel( popupTimeout ); - unregisterTriggers(); - removeTooltip(); - ttScope = null; - }); - }; - } - }; - }; - }]; -}) - -.directive( 'tooltip', [ '$tooltip', function ( $tooltip ) { - return $tooltip( 'tooltip', 'tooltip', 'mouseenter' ); -}]) - -.directive( 'tooltipPopup', function () { - return { - restrict: 'EA', - replace: true, - scope: { content: '@', placement: '@', animation: '&', isOpen: '&' }, - templateUrl: 'template/tooltip/tooltip-popup.html' - }; -}) - -.directive( 'tooltipHtmlUnsafe', [ '$tooltip', function ( $tooltip ) { - return $tooltip( 'tooltipHtmlUnsafe', 'tooltip', 'mouseenter' ); -}]) - -.directive( 'tooltipHtmlUnsafePopup', function () { - return { - restrict: 'EA', - replace: true, - scope: { content: '@', placement: '@', animation: '&', isOpen: '&' }, - templateUrl: 'template/tooltip/tooltip-html-unsafe-popup.html' - }; -}); \ No newline at end of file diff --git a/src/plugins/kibana_legacy/public/angular_bootstrap/bind_html/bind_html.js b/src/plugins/kibana_legacy/public/angular_bootstrap/bind_html/bind_html.js new file mode 100755 index 0000000000000..77844a3dd1363 --- /dev/null +++ b/src/plugins/kibana_legacy/public/angular_bootstrap/bind_html/bind_html.js @@ -0,0 +1,17 @@ +/* eslint-disable */ + +import angular from 'angular'; + +export function initBindHtml() { + angular + .module('ui.bootstrap.bindHtml', []) + + .directive('bindHtmlUnsafe', function() { + return function(scope, element, attr) { + element.addClass('ng-binding').data('$binding', attr.bindHtmlUnsafe); + scope.$watch(attr.bindHtmlUnsafe, function bindHtmlUnsafeWatchAction(value) { + element.html(value || ''); + }); + }; + }); +} diff --git a/src/plugins/kibana_legacy/public/angular_bootstrap/index.ts b/src/plugins/kibana_legacy/public/angular_bootstrap/index.ts new file mode 100644 index 0000000000000..1f15107a02762 --- /dev/null +++ b/src/plugins/kibana_legacy/public/angular_bootstrap/index.ts @@ -0,0 +1,50 @@ +/* eslint-disable */ + +import { once } from 'lodash'; +import angular from 'angular'; + +// @ts-ignore +import { initBindHtml } from './bind_html/bind_html'; +// @ts-ignore +import { initBootstrapTooltip } from './tooltip/tooltip'; + +import tooltipPopup from './tooltip/tooltip_popup.html'; + +import tooltipUnsafePopup from './tooltip/tooltip_html_unsafe_popup.html'; + +export const initAngularBootstrap = once(() => { + /* + * angular-ui-bootstrap + * http://angular-ui.github.io/bootstrap/ + + * Version: 0.12.1 - 2015-02-20 + * License: MIT + */ + angular.module('ui.bootstrap', [ + 'ui.bootstrap.tpls', + 'ui.bootstrap.bindHtml', + 'ui.bootstrap.tooltip', + ]); + + angular.module('ui.bootstrap.tpls', [ + 'template/tooltip/tooltip-html-unsafe-popup.html', + 'template/tooltip/tooltip-popup.html', + ]); + + initBindHtml(); + initBootstrapTooltip(); + + angular.module('template/tooltip/tooltip-html-unsafe-popup.html', []).run([ + '$templateCache', + function($templateCache: any) { + $templateCache.put('template/tooltip/tooltip-html-unsafe-popup.html', tooltipUnsafePopup); + }, + ]); + + angular.module('template/tooltip/tooltip-popup.html', []).run([ + '$templateCache', + function($templateCache: any) { + $templateCache.put('template/tooltip/tooltip-popup.html', tooltipPopup); + }, + ]); +}); diff --git a/src/plugins/kibana_legacy/public/angular_bootstrap/tooltip/position.js b/src/plugins/kibana_legacy/public/angular_bootstrap/tooltip/position.js new file mode 100755 index 0000000000000..24c8a8c5979cd --- /dev/null +++ b/src/plugins/kibana_legacy/public/angular_bootstrap/tooltip/position.js @@ -0,0 +1,167 @@ +/* eslint-disable */ + +import angular from 'angular'; + +export function initBootstrapPosition() { + angular + .module('ui.bootstrap.position', []) + + /** + * A set of utility methods that can be use to retrieve position of DOM elements. + * It is meant to be used where we need to absolute-position DOM elements in + * relation to other, existing elements (this is the case for tooltips, popovers, + * typeahead suggestions etc.). + */ + .factory('$position', [ + '$document', + '$window', + function($document, $window) { + function getStyle(el, cssprop) { + if (el.currentStyle) { + //IE + return el.currentStyle[cssprop]; + } else if ($window.getComputedStyle) { + return $window.getComputedStyle(el)[cssprop]; + } + // finally try and get inline style + return el.style[cssprop]; + } + + /** + * Checks if a given element is statically positioned + * @param element - raw DOM element + */ + function isStaticPositioned(element) { + return (getStyle(element, 'position') || 'static') === 'static'; + } + + /** + * returns the closest, non-statically positioned parentOffset of a given element + * @param element + */ + const parentOffsetEl = function(element) { + const docDomEl = $document[0]; + let offsetParent = element.offsetParent || docDomEl; + while (offsetParent && offsetParent !== docDomEl && isStaticPositioned(offsetParent)) { + offsetParent = offsetParent.offsetParent; + } + return offsetParent || docDomEl; + }; + + return { + /** + * Provides read-only equivalent of jQuery's position function: + * http://api.jquery.com/position/ + */ + position: function(element) { + const elBCR = this.offset(element); + let offsetParentBCR = { top: 0, left: 0 }; + const offsetParentEl = parentOffsetEl(element[0]); + if (offsetParentEl != $document[0]) { + offsetParentBCR = this.offset(angular.element(offsetParentEl)); + offsetParentBCR.top += offsetParentEl.clientTop - offsetParentEl.scrollTop; + offsetParentBCR.left += offsetParentEl.clientLeft - offsetParentEl.scrollLeft; + } + + const boundingClientRect = element[0].getBoundingClientRect(); + return { + width: boundingClientRect.width || element.prop('offsetWidth'), + height: boundingClientRect.height || element.prop('offsetHeight'), + top: elBCR.top - offsetParentBCR.top, + left: elBCR.left - offsetParentBCR.left, + }; + }, + + /** + * Provides read-only equivalent of jQuery's offset function: + * http://api.jquery.com/offset/ + */ + offset: function(element) { + const boundingClientRect = element[0].getBoundingClientRect(); + return { + width: boundingClientRect.width || element.prop('offsetWidth'), + height: boundingClientRect.height || element.prop('offsetHeight'), + top: + boundingClientRect.top + + ($window.pageYOffset || $document[0].documentElement.scrollTop), + left: + boundingClientRect.left + + ($window.pageXOffset || $document[0].documentElement.scrollLeft), + }; + }, + + /** + * Provides coordinates for the targetEl in relation to hostEl + */ + positionElements: function(hostEl, targetEl, positionStr, appendToBody) { + const positionStrParts = positionStr.split('-'); + const pos0 = positionStrParts[0]; + const pos1 = positionStrParts[1] || 'center'; + + let hostElPos; + let targetElWidth; + let targetElHeight; + let targetElPos; + + hostElPos = appendToBody ? this.offset(hostEl) : this.position(hostEl); + + targetElWidth = targetEl.prop('offsetWidth'); + targetElHeight = targetEl.prop('offsetHeight'); + + const shiftWidth = { + center: function() { + return hostElPos.left + hostElPos.width / 2 - targetElWidth / 2; + }, + left: function() { + return hostElPos.left; + }, + right: function() { + return hostElPos.left + hostElPos.width; + }, + }; + + const shiftHeight = { + center: function() { + return hostElPos.top + hostElPos.height / 2 - targetElHeight / 2; + }, + top: function() { + return hostElPos.top; + }, + bottom: function() { + return hostElPos.top + hostElPos.height; + }, + }; + + switch (pos0) { + case 'right': + targetElPos = { + top: shiftHeight[pos1](), + left: shiftWidth[pos0](), + }; + break; + case 'left': + targetElPos = { + top: shiftHeight[pos1](), + left: hostElPos.left - targetElWidth, + }; + break; + case 'bottom': + targetElPos = { + top: shiftHeight[pos0](), + left: shiftWidth[pos1](), + }; + break; + default: + targetElPos = { + top: hostElPos.top - targetElHeight, + left: shiftWidth[pos1](), + }; + break; + } + + return targetElPos; + }, + }; + }, + ]); +} diff --git a/src/plugins/kibana_legacy/public/angular_bootstrap/tooltip/tooltip.js b/src/plugins/kibana_legacy/public/angular_bootstrap/tooltip/tooltip.js new file mode 100755 index 0000000000000..05235fde9419b --- /dev/null +++ b/src/plugins/kibana_legacy/public/angular_bootstrap/tooltip/tooltip.js @@ -0,0 +1,423 @@ +/* eslint-disable */ + +import angular from 'angular'; + +import { initBootstrapPosition } from './position'; + +export function initBootstrapTooltip() { + initBootstrapPosition(); + /** + * The following features are still outstanding: animation as a + * function, placement as a function, inside, support for more triggers than + * just mouse enter/leave, html tooltips, and selector delegation. + */ + angular + .module('ui.bootstrap.tooltip', ['ui.bootstrap.position']) + + /** + * The $tooltip service creates tooltip- and popover-like directives as well as + * houses global options for them. + */ + .provider('$tooltip', function() { + // The default options tooltip and popover. + const defaultOptions = { + placement: 'top', + animation: true, + popupDelay: 0, + }; + + // Default hide triggers for each show trigger + const triggerMap = { + mouseenter: 'mouseleave', + click: 'click', + focus: 'blur', + }; + + // The options specified to the provider globally. + const globalOptions = {}; + + /** + * `options({})` allows global configuration of all tooltips in the + * application. + * + * var app = angular.module( 'App', ['ui.bootstrap.tooltip'], function( $tooltipProvider ) { + * // place tooltips left instead of top by default + * $tooltipProvider.options( { placement: 'left' } ); + * }); + */ + this.options = function(value) { + angular.extend(globalOptions, value); + }; + + /** + * This allows you to extend the set of trigger mappings available. E.g.: + * + * $tooltipProvider.setTriggers( 'openTrigger': 'closeTrigger' ); + */ + this.setTriggers = function setTriggers(triggers) { + angular.extend(triggerMap, triggers); + }; + + /** + * This is a helper function for translating camel-case to snake-case. + */ + function snake_case(name) { + const regexp = /[A-Z]/g; + const separator = '-'; + return name.replace(regexp, function(letter, pos) { + return (pos ? separator : '') + letter.toLowerCase(); + }); + } + + /** + * Returns the actual instance of the $tooltip service. + * TODO support multiple triggers + */ + this.$get = [ + '$window', + '$compile', + '$timeout', + '$document', + '$position', + '$interpolate', + function($window, $compile, $timeout, $document, $position, $interpolate) { + return function $tooltip(type, prefix, defaultTriggerShow) { + const options = angular.extend({}, defaultOptions, globalOptions); + + /** + * Returns an object of show and hide triggers. + * + * If a trigger is supplied, + * it is used to show the tooltip; otherwise, it will use the `trigger` + * option passed to the `$tooltipProvider.options` method; else it will + * default to the trigger supplied to this directive factory. + * + * The hide trigger is based on the show trigger. If the `trigger` option + * was passed to the `$tooltipProvider.options` method, it will use the + * mapped trigger from `triggerMap` or the passed trigger if the map is + * undefined; otherwise, it uses the `triggerMap` value of the show + * trigger; else it will just use the show trigger. + */ + function getTriggers(trigger) { + const show = trigger || options.trigger || defaultTriggerShow; + const hide = triggerMap[show] || show; + return { + show: show, + hide: hide, + }; + } + + const directiveName = snake_case(type); + + const startSym = $interpolate.startSymbol(); + const endSym = $interpolate.endSymbol(); + const template = + '
' + + '
'; + + return { + restrict: 'EA', + compile: function(tElem, tAttrs) { + const tooltipLinker = $compile(template); + + return function link(scope, element, attrs) { + let tooltip; + let tooltipLinkedScope; + let transitionTimeout; + let popupTimeout; + let appendToBody = angular.isDefined(options.appendToBody) + ? options.appendToBody + : false; + let triggers = getTriggers(undefined); + const hasEnableExp = angular.isDefined(attrs[prefix + 'Enable']); + let ttScope = scope.$new(true); + + const positionTooltip = function() { + const ttPosition = $position.positionElements( + element, + tooltip, + ttScope.placement, + appendToBody + ); + ttPosition.top += 'px'; + ttPosition.left += 'px'; + + // Now set the calculated positioning. + tooltip.css(ttPosition); + }; + + // By default, the tooltip is not open. + // TODO add ability to start tooltip opened + ttScope.isOpen = false; + + function toggleTooltipBind() { + if (!ttScope.isOpen) { + showTooltipBind(); + } else { + hideTooltipBind(); + } + } + + // Show the tooltip with delay if specified, otherwise show it immediately + function showTooltipBind() { + if (hasEnableExp && !scope.$eval(attrs[prefix + 'Enable'])) { + return; + } + + prepareTooltip(); + + if (ttScope.popupDelay) { + // Do nothing if the tooltip was already scheduled to pop-up. + // This happens if show is triggered multiple times before any hide is triggered. + if (!popupTimeout) { + popupTimeout = $timeout(show, ttScope.popupDelay, false); + popupTimeout + .then(reposition => reposition()) + .catch(error => { + // if the timeout is canceled then the string `canceled` is thrown. To prevent + // this from triggering an 'unhandled promise rejection' in angular 1.5+ the + // $timeout service explicitly tells $q that the promise it generated is "handled" + // but that does not include down chain promises like the one created by calling + // `popupTimeout.then()`. Because of this we need to ignore the "canceled" string + // and only propagate real errors + if (error !== 'canceled') { + throw error; + } + }); + } + } else { + show()(); + } + } + + function hideTooltipBind() { + scope.$evalAsync(function() { + hide(); + }); + } + + // Show the tooltip popup element. + function show() { + popupTimeout = null; + + // If there is a pending remove transition, we must cancel it, lest the + // tooltip be mysteriously removed. + if (transitionTimeout) { + $timeout.cancel(transitionTimeout); + transitionTimeout = null; + } + + // Don't show empty tooltips. + if (!ttScope.content) { + return angular.noop; + } + + createTooltip(); + + // Set the initial positioning. + tooltip.css({ top: 0, left: 0, display: 'block' }); + ttScope.$digest(); + + positionTooltip(); + + // And show the tooltip. + ttScope.isOpen = true; + ttScope.$digest(); // digest required as $apply is not called + + // Return positioning function as promise callback for correct + // positioning after draw. + return positionTooltip; + } + + // Hide the tooltip popup element. + function hide() { + // First things first: we don't show it anymore. + ttScope.isOpen = false; + + //if tooltip is going to be shown after delay, we must cancel this + $timeout.cancel(popupTimeout); + popupTimeout = null; + + // And now we remove it from the DOM. However, if we have animation, we + // need to wait for it to expire beforehand. + // FIXME: this is a placeholder for a port of the transitions library. + if (ttScope.animation) { + if (!transitionTimeout) { + transitionTimeout = $timeout(removeTooltip, 500); + } + } else { + removeTooltip(); + } + } + + function createTooltip() { + // There can only be one tooltip element per directive shown at once. + if (tooltip) { + removeTooltip(); + } + tooltipLinkedScope = ttScope.$new(); + tooltip = tooltipLinker(tooltipLinkedScope, function(tooltip) { + if (appendToBody) { + $document.find('body').append(tooltip); + } else { + element.after(tooltip); + } + }); + } + + function removeTooltip() { + transitionTimeout = null; + if (tooltip) { + tooltip.remove(); + tooltip = null; + } + if (tooltipLinkedScope) { + tooltipLinkedScope.$destroy(); + tooltipLinkedScope = null; + } + } + + function prepareTooltip() { + prepPlacement(); + prepPopupDelay(); + } + + /** + * Observe the relevant attributes. + */ + attrs.$observe(type, function(val) { + ttScope.content = val; + + if (!val && ttScope.isOpen) { + hide(); + } + }); + + attrs.$observe(prefix + 'Title', function(val) { + ttScope.title = val; + }); + + function prepPlacement() { + const val = attrs[prefix + 'Placement']; + ttScope.placement = angular.isDefined(val) ? val : options.placement; + } + + function prepPopupDelay() { + const val = attrs[prefix + 'PopupDelay']; + const delay = parseInt(val, 10); + ttScope.popupDelay = !isNaN(delay) ? delay : options.popupDelay; + } + + const unregisterTriggers = function() { + element.unbind(triggers.show, showTooltipBind); + element.unbind(triggers.hide, hideTooltipBind); + }; + + function prepTriggers() { + const val = attrs[prefix + 'Trigger']; + unregisterTriggers(); + + triggers = getTriggers(val); + + if (triggers.show === triggers.hide) { + element.bind(triggers.show, toggleTooltipBind); + } else { + element.bind(triggers.show, showTooltipBind); + element.bind(triggers.hide, hideTooltipBind); + } + } + + prepTriggers(); + + const animation = scope.$eval(attrs[prefix + 'Animation']); + ttScope.animation = angular.isDefined(animation) + ? !!animation + : options.animation; + + const appendToBodyVal = scope.$eval(attrs[prefix + 'AppendToBody']); + appendToBody = angular.isDefined(appendToBodyVal) + ? appendToBodyVal + : appendToBody; + + // if a tooltip is attached to we need to remove it on + // location change as its parent scope will probably not be destroyed + // by the change. + if (appendToBody) { + scope.$on( + '$locationChangeSuccess', + function closeTooltipOnLocationChangeSuccess() { + if (ttScope.isOpen) { + hide(); + } + } + ); + } + + // Make sure tooltip is destroyed and removed. + scope.$on('$destroy', function onDestroyTooltip() { + $timeout.cancel(transitionTimeout); + $timeout.cancel(popupTimeout); + unregisterTriggers(); + removeTooltip(); + ttScope = null; + }); + }; + }, + }; + }; + }, + ]; + }) + + .directive('tooltip', [ + '$tooltip', + function($tooltip) { + return $tooltip('tooltip', 'tooltip', 'mouseenter'); + }, + ]) + + .directive('tooltipPopup', function() { + return { + restrict: 'EA', + replace: true, + scope: { content: '@', placement: '@', animation: '&', isOpen: '&' }, + templateUrl: 'template/tooltip/tooltip-popup.html', + }; + }) + + .directive('tooltipHtmlUnsafe', [ + '$tooltip', + function($tooltip) { + return $tooltip('tooltipHtmlUnsafe', 'tooltip', 'mouseenter'); + }, + ]) + + .directive('tooltipHtmlUnsafePopup', function() { + return { + restrict: 'EA', + replace: true, + scope: { content: '@', placement: '@', animation: '&', isOpen: '&' }, + templateUrl: 'template/tooltip/tooltip-html-unsafe-popup.html', + }; + }); +} diff --git a/src/legacy/ui/public/angular-bootstrap/tooltip/tooltip-html-unsafe-popup.html b/src/plugins/kibana_legacy/public/angular_bootstrap/tooltip/tooltip_html_unsafe_popup.html similarity index 100% rename from src/legacy/ui/public/angular-bootstrap/tooltip/tooltip-html-unsafe-popup.html rename to src/plugins/kibana_legacy/public/angular_bootstrap/tooltip/tooltip_html_unsafe_popup.html diff --git a/src/legacy/ui/public/angular-bootstrap/tooltip/tooltip-popup.html b/src/plugins/kibana_legacy/public/angular_bootstrap/tooltip/tooltip_popup.html similarity index 100% rename from src/legacy/ui/public/angular-bootstrap/tooltip/tooltip-popup.html rename to src/plugins/kibana_legacy/public/angular_bootstrap/tooltip/tooltip_popup.html diff --git a/src/plugins/kibana_legacy/public/index.ts b/src/plugins/kibana_legacy/public/index.ts index 6e7a3cf87b87c..19833d638fe4c 100644 --- a/src/plugins/kibana_legacy/public/index.ts +++ b/src/plugins/kibana_legacy/public/index.ts @@ -24,6 +24,8 @@ export const plugin = (initializerContext: PluginInitializerContext) => new KibanaLegacyPlugin(initializerContext); export * from './plugin'; + +export { initAngularBootstrap } from './angular_bootstrap'; export * from './angular'; export * from './notify'; export * from './utils'; diff --git a/x-pack/legacy/plugins/graph/public/legacy_imports.ts b/x-pack/legacy/plugins/graph/public/legacy_imports.ts index 73a96016054fc..27184f5701235 100644 --- a/x-pack/legacy/plugins/graph/public/legacy_imports.ts +++ b/x-pack/legacy/plugins/graph/public/legacy_imports.ts @@ -4,7 +4,6 @@ * you may not use this file except in compliance with the Elastic License. */ -import 'ui/angular-bootstrap'; import 'ace'; export { SavedObject, SavedObjectKibanaServices } from 'ui/saved_objects/types'; diff --git a/x-pack/legacy/plugins/graph/public/plugin.ts b/x-pack/legacy/plugins/graph/public/plugin.ts index 48758ee1ec770..b4ca4bf423181 100644 --- a/x-pack/legacy/plugins/graph/public/plugin.ts +++ b/x-pack/legacy/plugins/graph/public/plugin.ts @@ -10,6 +10,7 @@ import { Plugin as DataPlugin } from 'src/plugins/data/public'; import { Storage } from '../../../../../src/plugins/kibana_utils/public'; import { LicensingPluginSetup } from '../../../../plugins/licensing/public'; import { NavigationPublicPluginStart as NavigationStart } from '../../../../../src/plugins/navigation/public'; +import { initAngularBootstrap } from '../../../../../src/plugins/kibana_legacy/public'; export interface GraphPluginStartDependencies { npData: ReturnType; @@ -26,6 +27,7 @@ export class GraphPlugin implements Plugin { private savedObjectsClient: SavedObjectsClientContract | null = null; setup(core: CoreSetup, { licensing }: GraphPluginSetupDependencies) { + initAngularBootstrap(); core.application.register({ id: 'graph', title: 'Graph',