diff --git a/NOTICE.txt b/NOTICE.txt index 230e511746022..955c3127fa955 100644 --- a/NOTICE.txt +++ b/NOTICE.txt @@ -1,5 +1,5 @@ Kibana source code with Kibana X-Pack source code -Copyright 2012-2019 Elasticsearch B.V. +Copyright 2012-2020 Elasticsearch B.V. --- Pretty handling of logarithmic axes. diff --git a/package.json b/package.json index 651ffb60d7b88..a0f5dd3af14c0 100644 --- a/package.json +++ b/package.json @@ -234,7 +234,7 @@ "react-resize-detector": "^4.2.0", "react-router-dom": "^5.1.2", "react-sizeme": "^2.3.6", - "react-use": "^13.10.2", + "react-use": "^13.13.0", "reactcss": "1.2.3", "redux": "4.0.0", "redux-actions": "2.2.1", diff --git a/src/core/public/application/integration_tests/router.test.tsx b/src/core/public/application/integration_tests/router.test.tsx index ffc10820a9c37..10544c348afb0 100644 --- a/src/core/public/application/integration_tests/router.test.tsx +++ b/src/core/public/application/integration_tests/router.test.tsx @@ -18,7 +18,7 @@ */ import React from 'react'; -import { createMemoryHistory, History } from 'history'; +import { createMemoryHistory, History, createHashHistory } from 'history'; import { AppRouter, AppNotFound } from '../ui'; import { EitherApp, MockedMounterMap, MockedMounterTuple } from '../test_types'; @@ -27,7 +27,15 @@ import { createRenderer, createAppMounter, createLegacyAppMounter } from './util describe('AppContainer', () => { let mounters: MockedMounterMap; let history: History; - let navigate: ReturnType; + let update: ReturnType; + + const navigate = (path: string) => { + history.push(path); + return update(); + }; + + const mockMountersToMounters = () => + new Map([...mounters].map(([appId, { mounter }]) => [appId, mounter])); beforeEach(() => { mounters = new Map([ @@ -38,14 +46,14 @@ describe('AppContainer', () => { createAppMounter('app3', '
App 3
', '/custom/path'), ] as Array>); history = createMemoryHistory(); - navigate = createRenderer(, history.push); + update = createRenderer(); }); it('calls mount handler and returned unmount function when navigating between apps', async () => { const dom1 = await navigate('/app/app1'); const app1 = mounters.get('app1')!; - expect(app1.mount).toHaveBeenCalled(); + expect(app1.mounter.mount).toHaveBeenCalled(); expect(dom1?.html()).toMatchInlineSnapshot(` "
basename: /app/app1 @@ -53,11 +61,11 @@ describe('AppContainer', () => {
" `); - const app1Unmount = await app1.mount.mock.results[0].value; + const app1Unmount = await app1.mounter.mount.mock.results[0].value; const dom2 = await navigate('/app/app2'); expect(app1Unmount).toHaveBeenCalled(); - expect(mounters.get('app2')!.mount).toHaveBeenCalled(); + expect(mounters.get('app2')!.mounter.mount).toHaveBeenCalled(); expect(dom2?.html()).toMatchInlineSnapshot(` "
basename: /app/app2 @@ -70,29 +78,77 @@ describe('AppContainer', () => { mounters.set(...createAppMounter('spaces', '
Custom Space
', '/spaces/fake-login')); mounters.set(...createAppMounter('login', '
Login Page
', '/fake-login')); history = createMemoryHistory(); - navigate = createRenderer(, history.push); + update = createRenderer(); await navigate('/fake-login'); - expect(mounters.get('spaces')!.mount).not.toHaveBeenCalled(); - expect(mounters.get('login')!.mount).toHaveBeenCalled(); + expect(mounters.get('spaces')!.mounter.mount).not.toHaveBeenCalled(); + expect(mounters.get('login')!.mounter.mount).toHaveBeenCalled(); }); it('should not mount when partial route path has higher specificity', async () => { mounters.set(...createAppMounter('login', '
Login Page
', '/fake-login')); mounters.set(...createAppMounter('spaces', '
Custom Space
', '/spaces/fake-login')); history = createMemoryHistory(); - navigate = createRenderer(, history.push); + update = createRenderer(); await navigate('/spaces/fake-login'); - expect(mounters.get('spaces')!.mount).toHaveBeenCalled(); - expect(mounters.get('login')!.mount).not.toHaveBeenCalled(); + expect(mounters.get('spaces')!.mounter.mount).toHaveBeenCalled(); + expect(mounters.get('login')!.mounter.mount).not.toHaveBeenCalled(); + }); + + it('should not remount when changing pages within app', async () => { + const { mounter, unmount } = mounters.get('app1')!; + await navigate('/app/app1/page1'); + expect(mounter.mount).toHaveBeenCalledTimes(1); + + // Navigating to page within app does not trigger re-render + await navigate('/app/app1/page2'); + expect(mounter.mount).toHaveBeenCalledTimes(1); + expect(unmount).not.toHaveBeenCalled(); + }); + + it('should not remount when going back within app', async () => { + const { mounter, unmount } = mounters.get('app1')!; + await navigate('/app/app1/page1'); + expect(mounter.mount).toHaveBeenCalledTimes(1); + + // Hitting back button within app does not trigger re-render + await navigate('/app/app1/page2'); + history.goBack(); + await update(); + expect(mounter.mount).toHaveBeenCalledTimes(1); + expect(unmount).not.toHaveBeenCalled(); + }); + + it('should not remount when when changing pages within app using hash history', async () => { + history = createHashHistory(); + update = createRenderer(); + + const { mounter, unmount } = mounters.get('app1')!; + await navigate('/app/app1/page1'); + expect(mounter.mount).toHaveBeenCalledTimes(1); + + // Changing hash history does not trigger re-render + await navigate('/app/app1/page2'); + expect(mounter.mount).toHaveBeenCalledTimes(1); + expect(unmount).not.toHaveBeenCalled(); + }); + + it('should unmount when changing between apps', async () => { + const { mounter, unmount } = mounters.get('app1')!; + await navigate('/app/app1/page1'); + expect(mounter.mount).toHaveBeenCalledTimes(1); + + // Navigating to other app triggers unmount + await navigate('/app/app2/page1'); + expect(unmount).toHaveBeenCalledTimes(1); }); it('calls legacy mount handler', async () => { await navigate('/app/legacyApp1'); - expect(mounters.get('legacyApp1')!.mount.mock.calls[0]).toMatchInlineSnapshot(` + expect(mounters.get('legacyApp1')!.mounter.mount.mock.calls[0]).toMatchInlineSnapshot(` Array [ Object { "appBasePath": "/app/legacyApp1", @@ -104,7 +160,7 @@ describe('AppContainer', () => { it('handles legacy apps with subapps', async () => { await navigate('/app/baseApp'); - expect(mounters.get('baseApp:legacyApp2')!.mount.mock.calls[0]).toMatchInlineSnapshot(` + expect(mounters.get('baseApp:legacyApp2')!.mounter.mount.mock.calls[0]).toMatchInlineSnapshot(` Array [ Object { "appBasePath": "/app/baseApp", diff --git a/src/core/public/application/integration_tests/utils.tsx b/src/core/public/application/integration_tests/utils.tsx index b8ade4d1d8787..6367d1fa12697 100644 --- a/src/core/public/application/integration_tests/utils.tsx +++ b/src/core/public/application/integration_tests/utils.tsx @@ -26,19 +26,13 @@ import { App, LegacyApp, AppMountParameters } from '../types'; import { MockedMounter, MockedMounterTuple } from '../test_types'; type Dom = ReturnType | null; -type Renderer = (item: string) => Dom | Promise; +type Renderer = () => Dom | Promise; -export const createRenderer = ( - element: ReactElement | null, - callback?: (item: string) => void | Promise -): Renderer => { +export const createRenderer = (element: ReactElement | null): Renderer => { const dom: Dom = element && mount({element}); - return item => + return () => new Promise(async resolve => { - if (callback) { - await callback(item); - } if (dom) { dom.update(); } @@ -50,19 +44,26 @@ export const createAppMounter = ( appId: string, html: string, appRoute = `/app/${appId}` -): MockedMounterTuple => [ - appId, - { - appRoute, - appBasePath: appRoute, - mount: jest.fn(async ({ appBasePath: basename, element }: AppMountParameters) => { - Object.assign(element, { - innerHTML: `
\nbasename: ${basename}\nhtml: ${html}\n
`, - }); - return jest.fn(() => Object.assign(element, { innerHTML: '' })); - }), - }, -]; +): MockedMounterTuple => { + const unmount = jest.fn(); + return [ + appId, + { + mounter: { + appRoute, + appBasePath: appRoute, + mount: jest.fn(async ({ appBasePath: basename, element }: AppMountParameters) => { + Object.assign(element, { + innerHTML: `
\nbasename: ${basename}\nhtml: ${html}\n
`, + }); + unmount.mockImplementation(() => Object.assign(element, { innerHTML: '' })); + return unmount; + }), + }, + unmount, + }, + ]; +}; export const createLegacyAppMounter = ( appId: string, @@ -70,9 +71,12 @@ export const createLegacyAppMounter = ( ): MockedMounterTuple => [ appId, { - appRoute: `/app/${appId.split(':')[0]}`, - appBasePath: `/app/${appId.split(':')[0]}`, - unmountBeforeMounting: true, - mount: legacyMount, + mounter: { + appRoute: `/app/${appId.split(':')[0]}`, + appBasePath: `/app/${appId.split(':')[0]}`, + unmountBeforeMounting: true, + mount: legacyMount, + }, + unmount: jest.fn(), }, ]; diff --git a/src/core/public/application/test_types.ts b/src/core/public/application/test_types.ts index f5fb639eaa32c..3d992cb950eb4 100644 --- a/src/core/public/application/test_types.ts +++ b/src/core/public/application/test_types.ts @@ -17,7 +17,7 @@ * under the License. */ -import { App, LegacyApp, Mounter } from './types'; +import { App, LegacyApp, Mounter, AppUnmount } from './types'; import { ApplicationService } from './application_service'; /** @internal */ @@ -25,11 +25,19 @@ export type ApplicationServiceContract = PublicMethodsOf; /** @internal */ export type EitherApp = App | LegacyApp; /** @internal */ +export type MockedUnmount = jest.Mocked; +/** @internal */ export type MockedMounter = jest.Mocked>>; /** @internal */ -export type MockedMounterTuple = [string, MockedMounter]; +export type MockedMounterTuple = [ + string, + { mounter: MockedMounter; unmount: MockedUnmount } +]; /** @internal */ -export type MockedMounterMap = Map>; +export type MockedMounterMap = Map< + string, + { mounter: MockedMounter; unmount: MockedUnmount } +>; /** @internal */ export type MockLifecycle< T extends keyof ApplicationService, diff --git a/src/core/public/application/ui/app_container.tsx b/src/core/public/application/ui/app_container.tsx index 96ee91c7c21fb..153582e805fa1 100644 --- a/src/core/public/application/ui/app_container.tsx +++ b/src/core/public/application/ui/app_container.tsx @@ -65,7 +65,7 @@ export const AppContainer: FunctionComponent = ({ mounter, appId }: Props mount(); return unmount; - }); + }, [mounter]); return ( diff --git a/src/core/server/rendering/views/styles.tsx b/src/core/server/rendering/views/styles.tsx index 40261321dcffc..f41627bcfe07f 100644 --- a/src/core/server/rendering/views/styles.tsx +++ b/src/core/server/rendering/views/styles.tsx @@ -78,7 +78,7 @@ export const Styles: FunctionComponent = ({ darkMode }) => { background-repeat: no-repeat; background-size: contain; /* SVG optimized according to http://codepen.io/tigt/post/optimizing-svgs-in-data-uris */ - background-image: url'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzMCIgaGVpZ2h0PSIzOSIgdmlld0JveD0iMCAwIDMwIDM5Ij4gIDxnIGZpbGw9Im5vbmUiIGZpbGwtcnVsZT0iZXZlbm9kZCI+ICAgIDxwb2x5Z29uIGZpbGw9IiNGMDRFOTgiIHBvaW50cz0iMCAwIDAgMzQuNTQ3IDI5LjkyMiAuMDIiLz4gICAgPHBhdGggZmlsbD0iIzM0Mzc0MSIgZD0iTTAsMTQuNCBMMCwzNC41NDY4IEwxNC4yODcyLDE4LjA2MTIgQzEwLjA0MTYsMTUuNzM4IDUuMTgwNCwxNC40IDAsMTQuNCIvPiAgICA8cGF0aCBmaWxsPSIjMDBCRkIzIiBkPSJNMTcuMzc0MiwxOS45OTY4IEwyLjcyMSwzNi45MDQ4IEwxLjQzMzQsMzguMzg5MiBMMjkuMjYzOCwzOC4zODkyIEMyNy43NjE0LDMwLjgzODggMjMuNDA0MiwyNC4zMjY0IDE3LjM3NDIsMTkuOTk2OCIvPiAgPC9nPjwvc3ZnPg=='); + background-image: url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzMCIgaGVpZ2h0PSIzOSIgdmlld0JveD0iMCAwIDMwIDM5Ij4gIDxnIGZpbGw9Im5vbmUiIGZpbGwtcnVsZT0iZXZlbm9kZCI+ICAgIDxwb2x5Z29uIGZpbGw9IiNGMDRFOTgiIHBvaW50cz0iMCAwIDAgMzQuNTQ3IDI5LjkyMiAuMDIiLz4gICAgPHBhdGggZmlsbD0iIzM0Mzc0MSIgZD0iTTAsMTQuNCBMMCwzNC41NDY4IEwxNC4yODcyLDE4LjA2MTIgQzEwLjA0MTYsMTUuNzM4IDUuMTgwNCwxNC40IDAsMTQuNCIvPiAgICA8cGF0aCBmaWxsPSIjMDBCRkIzIiBkPSJNMTcuMzc0MiwxOS45OTY4IEwyLjcyMSwzNi45MDQ4IEwxLjQzMzQsMzguMzg5MiBMMjkuMjYzOCwzOC4zODkyIEMyNy43NjE0LDMwLjgzODggMjMuNDA0MiwyNC4zMjY0IDE3LjM3NDIsMTkuOTk2OCIvPiAgPC9nPjwvc3ZnPg=='); } .kibanaWelcomeTitle { diff --git a/src/legacy/core_plugins/console/server/api_server/es_6_0/filter.js b/src/legacy/core_plugins/console/server/api_server/es_6_0/filter.js index 2a1a903c8565f..bf669cff788e8 100644 --- a/src/legacy/core_plugins/console/server/api_server/es_6_0/filter.js +++ b/src/legacy/core_plugins/console/server/api_server/es_6_0/filter.js @@ -260,7 +260,7 @@ filters.range = { gt: 1, lte: 20, lt: 20, - time_zone: '+1:00', + time_zone: '+01:00', format: 'dd/MM/yyyy||yyyy', execution: { __one_of: ['index', 'fielddata'] }, }, diff --git a/src/legacy/core_plugins/console/server/api_server/es_6_0/query/dsl.js b/src/legacy/core_plugins/console/server/api_server/es_6_0/query/dsl.js index 3ff9bed848346..a5f0d15dee0e9 100644 --- a/src/legacy/core_plugins/console/server/api_server/es_6_0/query/dsl.js +++ b/src/legacy/core_plugins/console/server/api_server/es_6_0/query/dsl.js @@ -467,7 +467,7 @@ export function queryDsl(api) { __one_of: [true, false], }, tie_breaker: 0, - time_zone: '+1:00', + time_zone: '+01:00', }, simple_query_string: { __template: { @@ -493,7 +493,7 @@ export function queryDsl(api) { gt: 10, lte: 20, lt: 20, - time_zone: '+1:00', + time_zone: '+01:00', boost: 1.0, format: 'dd/MM/yyyy||yyyy', }, diff --git a/src/legacy/core_plugins/tile_map/index.ts b/src/legacy/core_plugins/tile_map/index.ts index 298675e75b0d7..27f019318a82b 100644 --- a/src/legacy/core_plugins/tile_map/index.ts +++ b/src/legacy/core_plugins/tile_map/index.ts @@ -30,7 +30,14 @@ const tileMapPluginInitializer: LegacyPluginInitializer = ({ Plugin }: LegacyPlu uiExports: { styleSheetPaths: resolve(__dirname, 'public/index.scss'), hacks: [resolve(__dirname, 'public/legacy')], - injectDefaultVars: server => ({}), + injectDefaultVars: server => { + const serverConfig = server.config(); + const mapConfig: Record = serverConfig.get('map'); + + return { + emsTileLayerId: mapConfig.emsTileLayerId, + }; + }, }, config(Joi: any) { return Joi.object({ diff --git a/src/legacy/core_plugins/vis_type_vega/index.ts b/src/legacy/core_plugins/vis_type_vega/index.ts index 153cd6afb3ccc..52c253c6ac0b5 100644 --- a/src/legacy/core_plugins/vis_type_vega/index.ts +++ b/src/legacy/core_plugins/vis_type_vega/index.ts @@ -33,9 +33,15 @@ const vegaPluginInitializer: LegacyPluginInitializer = ({ Plugin }: LegacyPlugin uiExports: { styleSheetPaths: resolve(__dirname, 'public/index.scss'), hacks: [resolve(__dirname, 'public/legacy')], - injectDefaultVars: server => ({ - enableExternalUrls: server.config().get('vega.enableExternalUrls'), - }), + injectDefaultVars: server => { + const serverConfig = server.config(); + const mapConfig: Record = serverConfig.get('map'); + + return { + emsTileLayerId: mapConfig.emsTileLayerId, + enableExternalUrls: serverConfig.get('vega.enableExternalUrls'), + }; + }, }, init: (server: Legacy.Server) => ({}), config(Joi: any) { diff --git a/src/legacy/ui/public/vis/editors/default/components/agg_params.tsx b/src/legacy/ui/public/vis/editors/default/components/agg_params.tsx index 4f4c0bda6520a..1515ed86db070 100644 --- a/src/legacy/ui/public/vis/editors/default/components/agg_params.tsx +++ b/src/legacy/ui/public/vis/editors/default/components/agg_params.tsx @@ -20,10 +20,11 @@ import React, { useReducer, useEffect, useMemo } from 'react'; import { EuiForm, EuiAccordion, EuiSpacer, EuiFormRow } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; +import useUnmount from 'react-use/lib/useUnmount'; import { VisState } from 'ui/vis'; -import { aggTypes, AggType, AggParam, AggConfig } from 'ui/agg_types/'; import { IndexPattern } from 'ui/index_patterns'; +import { aggTypes, AggType, AggParam, AggConfig } from 'ui/agg_types/'; import { DefaultEditorAggSelect } from './agg_select'; import { DefaultEditorAggParam } from './agg_param'; @@ -44,9 +45,6 @@ import { } from './agg_params_state'; import { editorConfigProviders } from '../../config/editor_config_providers'; import { FixedParam, TimeIntervalParam, EditorParamConfig } from '../../config/types'; -// TODO: Below import is temporary, use `react-use` lib instead. -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { useUnmount } from '../../../../../../../plugins/kibana_react/public/util/use_unmount'; import { AggGroupNames } from '../agg_groups'; import { OnAggParamsChange } from './agg_common_props'; diff --git a/src/plugins/expressions/public/expression_renderer.tsx b/src/plugins/expressions/public/expression_renderer.tsx index 3989f4ed7d698..5c04d8405479f 100644 --- a/src/plugins/expressions/public/expression_renderer.tsx +++ b/src/plugins/expressions/public/expression_renderer.tsx @@ -22,9 +22,9 @@ import React from 'react'; import classNames from 'classnames'; import { Subscription } from 'rxjs'; import { filter } from 'rxjs/operators'; +import useShallowCompareEffect from 'react-use/lib/useShallowCompareEffect'; import { EuiLoadingChart, EuiProgress } from '@elastic/eui'; import theme from '@elastic/eui/dist/eui_theme_light.json'; -import { useShallowCompareEffect } from '../../kibana_react/public'; import { IExpressionLoaderParams, IInterpreterRenderHandlers, RenderError } from './types'; import { ExpressionAST } from '../common/types'; import { ExpressionLoader } from './loader'; diff --git a/src/plugins/kibana_react/public/index.ts b/src/plugins/kibana_react/public/index.ts index 258b0e94ef955..10b7dd2b4da44 100644 --- a/src/plugins/kibana_react/public/index.ts +++ b/src/plugins/kibana_react/public/index.ts @@ -25,4 +25,4 @@ export * from './overlays'; export * from './ui_settings'; export * from './field_icon'; export * from './table_list_view'; -export { toMountPoint, useObservable, useShallowCompareEffect } from './util'; +export { toMountPoint } from './util'; diff --git a/src/plugins/kibana_react/public/ui_settings/use_ui_setting.test.tsx b/src/plugins/kibana_react/public/ui_settings/use_ui_setting.test.tsx index 0879b0cb3f36a..db6d92a12841a 100644 --- a/src/plugins/kibana_react/public/ui_settings/use_ui_setting.test.tsx +++ b/src/plugins/kibana_react/public/ui_settings/use_ui_setting.test.tsx @@ -24,10 +24,10 @@ import { useUiSetting$ } from './use_ui_setting'; import { createKibanaReactContext } from '../context'; import { KibanaServices } from '../context/types'; import { Subject } from 'rxjs'; -import { useObservable } from '../util/use_observable'; import { coreMock } from '../../../../core/public/mocks'; +import useObservable from 'react-use/lib/useObservable'; -jest.mock('../util/use_observable'); +jest.mock('react-use/lib/useObservable'); const useObservableSpy = (useObservable as any) as jest.SpyInstance; useObservableSpy.mockImplementation((observable, def) => def); diff --git a/src/plugins/kibana_react/public/ui_settings/use_ui_setting.ts b/src/plugins/kibana_react/public/ui_settings/use_ui_setting.ts index 295515bfa51af..a8bc01bb8d2c4 100644 --- a/src/plugins/kibana_react/public/ui_settings/use_ui_setting.ts +++ b/src/plugins/kibana_react/public/ui_settings/use_ui_setting.ts @@ -18,8 +18,8 @@ */ import { useCallback, useMemo } from 'react'; +import useObservable from 'react-use/lib/useObservable'; import { useKibana } from '../context'; -import { useObservable } from '../util/use_observable'; /** * Returns the current UI-settings value. diff --git a/src/plugins/kibana_react/public/util/index.ts b/src/plugins/kibana_react/public/util/index.ts index 4f64d6c9c81ab..71a281dbdaad3 100644 --- a/src/plugins/kibana_react/public/util/index.ts +++ b/src/plugins/kibana_react/public/util/index.ts @@ -17,7 +17,4 @@ * under the License. */ -export * from './use_observable'; -export * from './use_unmount'; export * from './react_mount'; -export * from './use_shallow_compare_effect'; diff --git a/src/plugins/kibana_react/public/util/use_observable.test.tsx b/src/plugins/kibana_react/public/util/use_observable.test.tsx deleted file mode 100644 index 2dfbea06ecbb3..0000000000000 --- a/src/plugins/kibana_react/public/util/use_observable.test.tsx +++ /dev/null @@ -1,54 +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 { renderHook, act } from '@testing-library/react-hooks'; -import { Subject } from 'rxjs'; -import { useObservable } from './use_observable'; - -test('default initial value is undefined', () => { - const subject$ = new Subject(); - const { result } = renderHook(() => useObservable(subject$)); - - expect(result.current).toBe(undefined); -}); - -test('can specify initial value', () => { - const subject$ = new Subject(); - const { result } = renderHook(() => useObservable(subject$, 123)); - - expect(result.current).toBe(123); -}); - -test('returns the latest value of observables', () => { - const subject$ = new Subject(); - const { result } = renderHook(() => useObservable(subject$, 123)); - - act(() => { - subject$.next(125); - }); - expect(result.current).toBe(125); - - act(() => { - subject$.next(300); - subject$.next(400); - }); - expect(result.current).toBe(400); -}); - -xtest('subscribes to observable only once', () => {}); diff --git a/src/plugins/kibana_react/public/util/use_observable.ts b/src/plugins/kibana_react/public/util/use_observable.ts deleted file mode 100644 index 6a7ce1f5290d2..0000000000000 --- a/src/plugins/kibana_react/public/util/use_observable.ts +++ /dev/null @@ -1,34 +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 { useLayoutEffect, useState } from 'react'; -import { Observable } from 'rxjs'; - -export function useObservable(observable$: Observable): T | undefined; -export function useObservable(observable$: Observable, initialValue: T): T; -export function useObservable(observable$: Observable, initialValue?: T): T | undefined { - const [value, update] = useState(initialValue); - - useLayoutEffect(() => { - const s = observable$.subscribe(update); - return () => s.unsubscribe(); - }, [observable$]); - - return value; -} diff --git a/src/plugins/kibana_react/public/util/use_shallow_compare_effect.test.ts b/src/plugins/kibana_react/public/util/use_shallow_compare_effect.test.ts deleted file mode 100644 index 810c727fcdb0b..0000000000000 --- a/src/plugins/kibana_react/public/util/use_shallow_compare_effect.test.ts +++ /dev/null @@ -1,86 +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 { renderHook } from '@testing-library/react-hooks'; -import { useShallowCompareEffect } from './use_shallow_compare_effect'; - -describe('useShallowCompareEffect', () => { - test("doesn't run effect on shallow change", () => { - const callback = jest.fn(); - let deps = [1, { a: 'b' }, true]; - const { rerender } = renderHook(() => useShallowCompareEffect(callback, deps)); - - expect(callback).toHaveBeenCalledTimes(1); - callback.mockClear(); - - // no change - rerender(); - expect(callback).toHaveBeenCalledTimes(0); - callback.mockClear(); - - // no-change (new object with same properties) - deps = [1, { a: 'b' }, true]; - rerender(); - expect(callback).toHaveBeenCalledTimes(0); - callback.mockClear(); - - // change (new primitive value) - deps = [2, { a: 'b' }, true]; - rerender(); - expect(callback).toHaveBeenCalledTimes(1); - callback.mockClear(); - - // no-change - rerender(); - expect(callback).toHaveBeenCalledTimes(0); - callback.mockClear(); - - // change (new primitive value) - deps = [1, { a: 'b' }, false]; - rerender(); - expect(callback).toHaveBeenCalledTimes(1); - callback.mockClear(); - - // change (new properties on object) - deps = [1, { a: 'c' }, false]; - rerender(); - expect(callback).toHaveBeenCalledTimes(1); - callback.mockClear(); - }); - - test('runs effect on deep change', () => { - const callback = jest.fn(); - let deps = [1, { a: { b: 'c' } }, true]; - const { rerender } = renderHook(() => useShallowCompareEffect(callback, deps)); - - expect(callback).toHaveBeenCalledTimes(1); - callback.mockClear(); - - // no change - rerender(); - expect(callback).toHaveBeenCalledTimes(0); - callback.mockClear(); - - // change (new nested object ) - deps = [1, { a: { b: 'c' } }, true]; - rerender(); - expect(callback).toHaveBeenCalledTimes(1); - callback.mockClear(); - }); -}); diff --git a/src/plugins/kibana_react/public/util/use_shallow_compare_effect.ts b/src/plugins/kibana_react/public/util/use_shallow_compare_effect.ts deleted file mode 100644 index dfba7b907f5fb..0000000000000 --- a/src/plugins/kibana_react/public/util/use_shallow_compare_effect.ts +++ /dev/null @@ -1,80 +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 React, { useEffect, useRef } from 'react'; - -/** - * Similar to https://github.com/kentcdodds/use-deep-compare-effect - * but uses shallow compare instead of deep - */ -export function useShallowCompareEffect( - callback: React.EffectCallback, - deps: React.DependencyList -) { - useEffect(callback, useShallowCompareMemoize(deps)); -} -function useShallowCompareMemoize(deps: React.DependencyList) { - const ref = useRef(undefined); - - if (!ref.current || deps.some((dep, index) => !shallowEqual(dep, ref.current![index]))) { - ref.current = deps; - } - - return ref.current; -} -// https://github.com/facebook/fbjs/blob/master/packages/fbjs/src/core/shallowEqual.js -function shallowEqual(objA: any, objB: any): boolean { - if (is(objA, objB)) { - return true; - } - - if (typeof objA !== 'object' || objA === null || typeof objB !== 'object' || objB === null) { - return false; - } - - const keysA = Object.keys(objA); - const keysB = Object.keys(objB); - - if (keysA.length !== keysB.length) { - return false; - } - - // Test for A's keys different from B. - for (let i = 0; i < keysA.length; i++) { - if ( - !Object.prototype.hasOwnProperty.call(objB, keysA[i]) || - !is(objA[keysA[i]], objB[keysA[i]]) - ) { - return false; - } - } - - return true; -} - -/** - * IE11 does not support Object.is - */ -function is(x: any, y: any): boolean { - if (x === y) { - return x !== 0 || y !== 0 || 1 / x === 1 / y; - } else { - return x !== x && y !== y; - } -} diff --git a/src/plugins/kibana_react/public/util/use_unmount.ts b/src/plugins/kibana_react/public/util/use_unmount.ts deleted file mode 100644 index 009bf8c4caa1c..0000000000000 --- a/src/plugins/kibana_react/public/util/use_unmount.ts +++ /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 { useEffect } from 'react'; - -export function useUnmount(fn: () => void): void { - useEffect(() => fn, []); -} diff --git a/test/functional/apps/home/_newsfeed.ts b/test/functional/apps/home/_newsfeed.ts index 35d7ac8adefa5..0019b817b72d8 100644 --- a/test/functional/apps/home/_newsfeed.ts +++ b/test/functional/apps/home/_newsfeed.ts @@ -24,7 +24,8 @@ export default function({ getService, getPageObjects }: FtrProviderContext) { const globalNav = getService('globalNav'); const PageObjects = getPageObjects(['common', 'newsfeed']); - describe('Newsfeed', () => { + // Failing: https://github.com/elastic/kibana/issues/53860 + describe.skip('Newsfeed', () => { before(async () => { await PageObjects.newsfeed.resetPage(); }); diff --git a/vars/githubPr.groovy b/vars/githubPr.groovy index 09a166192bf7a..ce164ab98ab1e 100644 --- a/vars/githubPr.groovy +++ b/vars/githubPr.groovy @@ -35,7 +35,7 @@ def withDefaultPrComments(closure) { def message = getNextCommentMessage(info) postComment(message) - if (lastComment) { + if (lastComment && lastComment.user.login == 'kibanamachine') { deleteComment(lastComment.id) } } @@ -49,7 +49,7 @@ def isPr() { def getLatestBuildComment() { return getComments() .reverse() - .find { it.user.login == 'elasticmachine' && it.body =~ /