From 856a82046ddd612c48551c9bcde2d3de0a3f3b5b Mon Sep 17 00:00:00 2001 From: Sandra Gonzales Date: Fri, 1 May 2020 10:42:05 -0400 Subject: [PATCH 1/5] [EPM] fix updates available filter (#64957) * fix filter * remove unneeded installationVersion from package * use filter instead of reduce * fix type error --- .../ingest_manager/common/types/models/epm.ts | 1 - .../sections/epm/screens/detail/header.tsx | 7 ++++++- .../sections/epm/screens/detail/index.tsx | 5 ++++- .../sections/epm/screens/home/index.tsx | 20 +++++++++++-------- .../ingest_manager/types/index.ts | 1 + .../server/services/epm/packages/index.ts | 1 - 6 files changed, 23 insertions(+), 12 deletions(-) diff --git a/x-pack/plugins/ingest_manager/common/types/models/epm.ts b/x-pack/plugins/ingest_manager/common/types/models/epm.ts index f8779a879a049..82de90e4735f2 100644 --- a/x-pack/plugins/ingest_manager/common/types/models/epm.ts +++ b/x-pack/plugins/ingest_manager/common/types/models/epm.ts @@ -205,7 +205,6 @@ export interface RegistryVarsEntry { interface PackageAdditions { title: string; latestVersion: string; - installedVersion?: string; assets: AssetsGroupedByServiceByType; } diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/screens/detail/header.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/screens/detail/header.tsx index d20350c5db631..cf51296d468a9 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/screens/detail/header.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/screens/detail/header.tsx @@ -29,7 +29,12 @@ const Text = styled.span` type HeaderProps = PackageInfo & { iconType?: IconType }; export function Header(props: HeaderProps) { - const { iconType, name, title, version, installedVersion, latestVersion } = props; + const { iconType, name, title, version, latestVersion } = props; + + let installedVersion; + if ('savedObject' in props) { + installedVersion = props.savedObject.attributes.version; + } const hasWriteCapabilites = useCapabilities().write; const { toListView } = useLinks(); const ADD_DATASOURCE_URI = useLink(`${EPM_PATH}/${name}-${version}/add-datasource`); diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/screens/detail/index.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/screens/detail/index.tsx index 1f3eb2cc9362e..848d278819d1d 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/screens/detail/index.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/screens/detail/index.tsx @@ -32,7 +32,10 @@ export function Detail() { const packageInfo = response.data?.response; const title = packageInfo?.title; const name = packageInfo?.name; - const installedVersion = packageInfo?.installedVersion; + let installedVersion; + if (packageInfo && 'savedObject' in packageInfo) { + installedVersion = packageInfo.savedObject.attributes.version; + } const status: InstallStatus = packageInfo?.status as any; // track install status state diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/screens/home/index.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/screens/home/index.tsx index bf785147502b5..983a322de1088 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/screens/home/index.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/screens/home/index.tsx @@ -67,29 +67,34 @@ export function EPMHomePage() { function InstalledPackages() { const { data: allPackages, isLoading: isLoadingPackages } = useGetPackages(); const [selectedCategory, setSelectedCategory] = useState(''); - const packages = - allPackages && allPackages.response && selectedCategory === '' - ? allPackages.response.filter(pkg => pkg.status === 'installed') - : []; const title = i18n.translate('xpack.ingestManager.epmList.installedTitle', { defaultMessage: 'Installed integrations', }); + const allInstalledPackages = + allPackages && allPackages.response + ? allPackages.response.filter(pkg => pkg.status === 'installed') + : []; + + const updatablePackages = allInstalledPackages.filter( + item => 'savedObject' in item && item.version > item.savedObject.attributes.version + ); + const categories = [ { id: '', title: i18n.translate('xpack.ingestManager.epmList.allFilterLinkText', { defaultMessage: 'All', }), - count: packages.length, + count: allInstalledPackages.length, }, { id: 'updates_available', title: i18n.translate('xpack.ingestManager.epmList.updatesAvailableFilterLinkText', { defaultMessage: 'Updates available', }), - count: 0, // TODO: Update with real count when available + count: updatablePackages.length, }, ]; @@ -106,7 +111,7 @@ function InstalledPackages() { isLoading={isLoadingPackages} controls={controls} title={title} - list={packages} + list={selectedCategory === 'updates_available' ? updatablePackages : allInstalledPackages} /> ); } @@ -134,7 +139,6 @@ function AvailablePackages() { }, ...(categoriesRes ? categoriesRes.response : []), ]; - const controls = categories ? ( ( ? { ...from, status: InstallationStatus.installed, - installedVersion: savedObject.attributes.version, savedObject, } : { From d314e4624e49e264ea32fd1585b4edb1ca5df779 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B8ren=20Louv-Jansen?= Date: Sat, 2 May 2020 22:12:13 +0200 Subject: [PATCH 2/5] Use HDR for percentiles (#64758) --- .../__snapshots__/fetcher.test.ts.snap | 6 ++++++ .../__snapshots__/queries.test.ts.snap | 6 ++++++ .../plugins/apm/server/lib/transaction_groups/fetcher.ts | 6 +++++- .../lib/transactions/__snapshots__/queries.test.ts.snap | 9 +++++++++ .../__snapshots__/fetcher.test.ts.snap | 3 +++ .../transactions/charts/get_timeseries_data/fetcher.ts | 6 +++++- x-pack/plugins/apm/typings/elasticsearch/aggregations.ts | 1 + 7 files changed, 35 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/apm/server/lib/transaction_groups/__snapshots__/fetcher.test.ts.snap b/x-pack/plugins/apm/server/lib/transaction_groups/__snapshots__/fetcher.test.ts.snap index 580cafff95e0c..64f06ad0a81cd 100644 --- a/x-pack/plugins/apm/server/lib/transaction_groups/__snapshots__/fetcher.test.ts.snap +++ b/x-pack/plugins/apm/server/lib/transaction_groups/__snapshots__/fetcher.test.ts.snap @@ -16,6 +16,9 @@ Array [ "p95": Object { "percentiles": Object { "field": "transaction.duration.us", + "hdr": Object { + "number_of_significant_value_digits": 2, + }, "percents": Array [ 95, ], @@ -126,6 +129,9 @@ Array [ "p95": Object { "percentiles": Object { "field": "transaction.duration.us", + "hdr": Object { + "number_of_significant_value_digits": 2, + }, "percents": Array [ 95, ], diff --git a/x-pack/plugins/apm/server/lib/transaction_groups/__snapshots__/queries.test.ts.snap b/x-pack/plugins/apm/server/lib/transaction_groups/__snapshots__/queries.test.ts.snap index 1096c1638f3f2..b93f842b878cb 100644 --- a/x-pack/plugins/apm/server/lib/transaction_groups/__snapshots__/queries.test.ts.snap +++ b/x-pack/plugins/apm/server/lib/transaction_groups/__snapshots__/queries.test.ts.snap @@ -14,6 +14,9 @@ Object { "p95": Object { "percentiles": Object { "field": "transaction.duration.us", + "hdr": Object { + "number_of_significant_value_digits": 2, + }, "percents": Array [ 95, ], @@ -120,6 +123,9 @@ Object { "p95": Object { "percentiles": Object { "field": "transaction.duration.us", + "hdr": Object { + "number_of_significant_value_digits": 2, + }, "percents": Array [ 95, ], diff --git a/x-pack/plugins/apm/server/lib/transaction_groups/fetcher.ts b/x-pack/plugins/apm/server/lib/transaction_groups/fetcher.ts index 39f2be551ab6e..fb1aafc2d6c95 100644 --- a/x-pack/plugins/apm/server/lib/transaction_groups/fetcher.ts +++ b/x-pack/plugins/apm/server/lib/transaction_groups/fetcher.ts @@ -83,7 +83,11 @@ export function transactionGroupsFetcher( sample: { top_hits: { size: 1, sort } }, avg: { avg: { field: TRANSACTION_DURATION } }, p95: { - percentiles: { field: TRANSACTION_DURATION, percents: [95] } + percentiles: { + field: TRANSACTION_DURATION, + percents: [95], + hdr: { number_of_significant_value_digits: 2 } + } }, sum: { sum: { field: TRANSACTION_DURATION } } } diff --git a/x-pack/plugins/apm/server/lib/transactions/__snapshots__/queries.test.ts.snap b/x-pack/plugins/apm/server/lib/transactions/__snapshots__/queries.test.ts.snap index 49e0e0669c241..cc5900919f829 100644 --- a/x-pack/plugins/apm/server/lib/transactions/__snapshots__/queries.test.ts.snap +++ b/x-pack/plugins/apm/server/lib/transactions/__snapshots__/queries.test.ts.snap @@ -333,6 +333,9 @@ Object { "pct": Object { "percentiles": Object { "field": "transaction.duration.us", + "hdr": Object { + "number_of_significant_value_digits": 2, + }, "percents": Array [ 95, 99, @@ -425,6 +428,9 @@ Object { "pct": Object { "percentiles": Object { "field": "transaction.duration.us", + "hdr": Object { + "number_of_significant_value_digits": 2, + }, "percents": Array [ 95, 99, @@ -522,6 +528,9 @@ Object { "pct": Object { "percentiles": Object { "field": "transaction.duration.us", + "hdr": Object { + "number_of_significant_value_digits": 2, + }, "percents": Array [ 95, 99, diff --git a/x-pack/plugins/apm/server/lib/transactions/charts/get_timeseries_data/__snapshots__/fetcher.test.ts.snap b/x-pack/plugins/apm/server/lib/transactions/charts/get_timeseries_data/__snapshots__/fetcher.test.ts.snap index 6c8430a3e71cf..25ebb15fd73e8 100644 --- a/x-pack/plugins/apm/server/lib/transactions/charts/get_timeseries_data/__snapshots__/fetcher.test.ts.snap +++ b/x-pack/plugins/apm/server/lib/transactions/charts/get_timeseries_data/__snapshots__/fetcher.test.ts.snap @@ -21,6 +21,9 @@ Array [ "pct": Object { "percentiles": Object { "field": "transaction.duration.us", + "hdr": Object { + "number_of_significant_value_digits": 2, + }, "percents": Array [ 95, 99, diff --git a/x-pack/plugins/apm/server/lib/transactions/charts/get_timeseries_data/fetcher.ts b/x-pack/plugins/apm/server/lib/transactions/charts/get_timeseries_data/fetcher.ts index 8a2e01c9a7891..e33b98592da2d 100644 --- a/x-pack/plugins/apm/server/lib/transactions/charts/get_timeseries_data/fetcher.ts +++ b/x-pack/plugins/apm/server/lib/transactions/charts/get_timeseries_data/fetcher.ts @@ -69,7 +69,11 @@ export function timeseriesFetcher({ aggs: { avg: { avg: { field: TRANSACTION_DURATION } }, pct: { - percentiles: { field: TRANSACTION_DURATION, percents: [95, 99] } + percentiles: { + field: TRANSACTION_DURATION, + percents: [95, 99], + hdr: { number_of_significant_value_digits: 2 } + } } } }, diff --git a/x-pack/plugins/apm/typings/elasticsearch/aggregations.ts b/x-pack/plugins/apm/typings/elasticsearch/aggregations.ts index 8a8d256cf4273..0739e8e6120bf 100644 --- a/x-pack/plugins/apm/typings/elasticsearch/aggregations.ts +++ b/x-pack/plugins/apm/typings/elasticsearch/aggregations.ts @@ -86,6 +86,7 @@ export interface AggregationOptionsByType { percentiles: { field: string; percents?: number[]; + hdr?: { number_of_significant_value_digits: number }; }; extended_stats: { field: string; From 8eeaf96cf57f910c0944ba0d5a0609bfd0c11e1c Mon Sep 17 00:00:00 2001 From: Dario Gieselaar Date: Sat, 2 May 2020 23:36:26 +0200 Subject: [PATCH 3/5] [APM] Fix paths for ts optimization script (#65012) --- x-pack/plugins/apm/scripts/optimize-tsconfig/paths.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/apm/scripts/optimize-tsconfig/paths.js b/x-pack/plugins/apm/scripts/optimize-tsconfig/paths.js index cab55a2526202..aeccd403c5ce6 100644 --- a/x-pack/plugins/apm/scripts/optimize-tsconfig/paths.js +++ b/x-pack/plugins/apm/scripts/optimize-tsconfig/paths.js @@ -5,7 +5,7 @@ */ const path = require('path'); -const xpackRoot = path.resolve(__dirname, '../../../../..'); +const xpackRoot = path.resolve(__dirname, '../../../..'); const kibanaRoot = path.resolve(xpackRoot, '..'); const tsconfigTpl = path.resolve(__dirname, './tsconfig.json'); From c995a333de4384f14233dcd61031267fbb6b50bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B8ren=20Louv-Jansen?= Date: Sun, 3 May 2020 09:19:16 +0200 Subject: [PATCH 4/5] [APM] Fix failing `ApmIndices` test (#64965) * [APM] Fix failing Indicies Settings test * Cleanup Co-authored-by: Elastic Machine --- .../components/app/Settings/ApmIndices/index.test.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/x-pack/plugins/apm/public/components/app/Settings/ApmIndices/index.test.tsx b/x-pack/plugins/apm/public/components/app/Settings/ApmIndices/index.test.tsx index 272c4b3add415..b03960861e0ad 100644 --- a/x-pack/plugins/apm/public/components/app/Settings/ApmIndices/index.test.tsx +++ b/x-pack/plugins/apm/public/components/app/Settings/ApmIndices/index.test.tsx @@ -4,15 +4,15 @@ * you may not use this file except in compliance with the Elastic License. */ -import { render, wait } from '@testing-library/react'; +import { render } from '@testing-library/react'; import React from 'react'; import { ApmIndices } from '.'; import * as hooks from '../../../../hooks/useFetcher'; import { MockApmPluginContextWrapper } from '../../../../context/ApmPluginContext/MockApmPluginContext'; describe('ApmIndices', () => { - it('should not get stuck in infinite loop', async () => { - spyOn(hooks, 'useFetcher').and.returnValue({ + it('should not get stuck in infinite loop', () => { + const spy = spyOn(hooks, 'useFetcher').and.returnValue({ data: undefined, status: 'loading' }); @@ -30,6 +30,6 @@ describe('ApmIndices', () => { `); - await wait(); + expect(spy).toHaveBeenCalledTimes(2); }); }); From 4d19323150e9f09fab8fdd5e85cd81a2e494bbf6 Mon Sep 17 00:00:00 2001 From: Vadim Dalecky Date: Mon, 4 May 2020 10:29:29 +0200 Subject: [PATCH 5/5] onEvent prop for expression component (#64995) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: 🎸 add onEvent prop to expression component * feat: 🎸 add type safety to onEvent prop in expression component Co-authored-by: Elastic Machine --- src/plugins/expressions/public/index.ts | 2 +- .../public/react_expression_renderer.test.tsx | 41 +++++++++++++++++++ .../public/react_expression_renderer.tsx | 12 +++++- src/plugins/expressions/public/render.ts | 6 +-- 4 files changed, 56 insertions(+), 5 deletions(-) diff --git a/src/plugins/expressions/public/index.ts b/src/plugins/expressions/public/index.ts index c57db6029ec2e..6814764ee5faa 100644 --- a/src/plugins/expressions/public/index.ts +++ b/src/plugins/expressions/public/index.ts @@ -37,7 +37,7 @@ export { ReactExpressionRendererProps, ReactExpressionRendererType, } from './react_expression_renderer'; -export { ExpressionRenderHandler } from './render'; +export { ExpressionRenderHandler, ExpressionRendererEvent } from './render'; export { AnyExpressionFunctionDefinition, AnyExpressionTypeDefinition, diff --git a/src/plugins/expressions/public/react_expression_renderer.test.tsx b/src/plugins/expressions/public/react_expression_renderer.test.tsx index 65cc5fc1569cb..caa9bc68dffb8 100644 --- a/src/plugins/expressions/public/react_expression_renderer.test.tsx +++ b/src/plugins/expressions/public/react_expression_renderer.test.tsx @@ -26,6 +26,7 @@ import { ExpressionLoader } from './loader'; import { mount } from 'enzyme'; import { EuiProgress } from '@elastic/eui'; import { RenderErrorHandlerFnType } from './types'; +import { ExpressionRendererEvent } from './render'; jest.mock('./loader', () => { return { @@ -135,4 +136,44 @@ describe('ExpressionRenderer', () => { expect(instance.find(EuiProgress)).toHaveLength(0); expect(instance.find('[data-test-subj="custom-error"]')).toHaveLength(0); }); + + it('should fire onEvent prop on every events$ observable emission in loader', () => { + const dataSubject = new Subject(); + const data$ = dataSubject.asObservable().pipe(share()); + const renderSubject = new Subject(); + const render$ = renderSubject.asObservable().pipe(share()); + const loadingSubject = new Subject(); + const loading$ = loadingSubject.asObservable().pipe(share()); + const eventsSubject = new Subject(); + const events$ = eventsSubject.asObservable().pipe(share()); + + const onEvent = jest.fn(); + const event: ExpressionRendererEvent = { + name: 'foo', + data: { + bar: 'baz', + }, + }; + + (ExpressionLoader as jest.Mock).mockImplementation(() => { + return { + render$, + data$, + loading$, + events$, + update: jest.fn(), + }; + }); + + mount(); + + expect(onEvent).toHaveBeenCalledTimes(0); + + act(() => { + eventsSubject.next(event); + }); + + expect(onEvent).toHaveBeenCalledTimes(1); + expect(onEvent.mock.calls[0][0]).toBe(event); + }); }); diff --git a/src/plugins/expressions/public/react_expression_renderer.tsx b/src/plugins/expressions/public/react_expression_renderer.tsx index 2c99f173c9f33..9e237d36ef627 100644 --- a/src/plugins/expressions/public/react_expression_renderer.tsx +++ b/src/plugins/expressions/public/react_expression_renderer.tsx @@ -27,6 +27,7 @@ import theme from '@elastic/eui/dist/eui_theme_light.json'; import { IExpressionLoaderParams, RenderError } from './types'; import { ExpressionAstExpression, IInterpreterRenderHandlers } from '../common'; import { ExpressionLoader } from './loader'; +import { ExpressionRendererEvent } from './render'; // Accept all options of the runner as props except for the // dom element which is provided by the component itself @@ -36,6 +37,7 @@ export interface ReactExpressionRendererProps extends IExpressionLoaderParams { expression: string | ExpressionAstExpression; renderError?: (error?: string | null) => React.ReactElement | React.ReactElement[]; padding?: 'xs' | 's' | 'm' | 'l' | 'xl'; + onEvent?: (event: ExpressionRendererEvent) => void; } export type ReactExpressionRendererType = React.ComponentType; @@ -60,6 +62,7 @@ export const ReactExpressionRenderer = ({ padding, renderError, expression, + onEvent, ...expressionLoaderOptions }: ReactExpressionRendererProps) => { const mountpoint: React.MutableRefObject = useRef(null); @@ -99,6 +102,13 @@ export const ReactExpressionRenderer = ({ } : expressionLoaderOptions.onRenderError, }); + if (onEvent) { + subs.push( + expressionLoaderRef.current.events$.subscribe(event => { + onEvent(event); + }) + ); + } subs.push( expressionLoaderRef.current.loading$.subscribe(() => { hasHandledErrorRef.current = false; @@ -123,7 +133,7 @@ export const ReactExpressionRenderer = ({ errorRenderHandlerRef.current = null; }; - }, [hasCustomRenderErrorHandler]); + }, [hasCustomRenderErrorHandler, onEvent]); // Re-fetch data automatically when the inputs change useShallowCompareEffect( diff --git a/src/plugins/expressions/public/render.ts b/src/plugins/expressions/public/render.ts index 4aaf0da60fc60..c8a4022a01131 100644 --- a/src/plugins/expressions/public/render.ts +++ b/src/plugins/expressions/public/render.ts @@ -32,7 +32,7 @@ export interface ExpressionRenderHandlerParams { onRenderError: RenderErrorHandlerFnType; } -interface Event { +export interface ExpressionRendererEvent { name: string; data: any; } @@ -45,7 +45,7 @@ interface UpdateValue { export class ExpressionRenderHandler { render$: Observable; update$: Observable; - events$: Observable; + events$: Observable; private element: HTMLElement; private destroyFn?: any; @@ -63,7 +63,7 @@ export class ExpressionRenderHandler { this.element = element; this.eventsSubject = new Rx.Subject(); - this.events$ = this.eventsSubject.asObservable() as Observable; + this.events$ = this.eventsSubject.asObservable() as Observable; this.onRenderError = onRenderError || defaultRenderErrorHandler;