From 14a72f6e48df7a012cc610d9ed76f2d021f7388b Mon Sep 17 00:00:00 2001 From: Ignacio Rivas Date: Thu, 9 Sep 2021 13:38:13 +0200 Subject: [PATCH] [Upgrade Assistant] External links with checkpoint time-range applied (#111252) * Bound query around last checkpoint date * Fix tests * Also test discover url contains search params * Small refactor * Keep state about lastCheckpoint in parent component * Remove space * Address CR changes Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../helpers/app_context.mock.ts | 19 +++++++--- .../fix_logs_step/fix_logs_step.test.tsx | 23 ++++++++++-- .../deprecations_count_checkpoint.tsx | 32 +++++------------ .../overview/fix_logs_step/external_links.tsx | 36 ++++++++++++------- .../overview/fix_logs_step/fix_logs_step.tsx | 16 +++++++-- .../public/application/lib/logs_checkpoint.ts | 30 ++++++++++++++++ .../upgrade_assistant/public/plugin.ts | 3 +- .../plugins/upgrade_assistant/public/types.ts | 3 -- .../plugins/upgrade_assistant/tsconfig.json | 1 + 9 files changed, 113 insertions(+), 50 deletions(-) create mode 100644 x-pack/plugins/upgrade_assistant/public/application/lib/logs_checkpoint.ts diff --git a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/app_context.mock.ts b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/app_context.mock.ts index 7550055d8242dc..42c05c2d80d37c 100644 --- a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/app_context.mock.ts +++ b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/app_context.mock.ts @@ -33,13 +33,24 @@ const idToUrlMap = { SNAPSHOT_RESTORE_LOCATOR: 'snapshotAndRestoreUrl', DISCOVER_APP_LOCATOR: 'discoverUrl', }; +type IdKey = keyof typeof idToUrlMap; + +const stringifySearchParams = (params: Record) => { + const stringifiedParams = Object.keys(params).reduce((list, key) => { + const value = typeof params[key] === 'object' ? JSON.stringify(params[key]) : params[key]; + + return { ...list, [key]: value }; + }, {}); + + return new URLSearchParams(stringifiedParams).toString(); +}; const shareMock = sharePluginMock.createSetupContract(); -shareMock.url.locators.get = (id) => ({ - // @ts-expect-error This object is missing some properties that we're not using in the UI +// @ts-expect-error This object is missing some properties that we're not using in the UI +shareMock.url.locators.get = (id: IdKey) => ({ useUrl: (): string | undefined => idToUrlMap[id], - // @ts-expect-error This object is missing some properties that we're not using in the UI - getUrl: (): string | undefined => idToUrlMap[id], + getUrl: (params: Record): string | undefined => + `${idToUrlMap[id]}?${stringifySearchParams(params)}`, }); export const getAppContextMock = () => ({ diff --git a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/overview/fix_logs_step/fix_logs_step.test.tsx b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/overview/fix_logs_step/fix_logs_step.test.tsx index acc64e2872642d..e19ea5b1dfd994 100644 --- a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/overview/fix_logs_step/fix_logs_step.test.tsx +++ b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/overview/fix_logs_step/fix_logs_step.test.tsx @@ -7,6 +7,20 @@ import { act } from 'react-dom/test-utils'; +// Once the logs team register the kibana locators in their app, we should be able +// to remove this mock and follow a similar approach to how discover link is tested. +// See: https://github.com/elastic/kibana/issues/104855 +const MOCKED_TIME = '2021-09-05T10:49:01.805Z'; +jest.mock('../../../../public/application/lib/logs_checkpoint', () => { + const originalModule = jest.requireActual('../../../../public/application/lib/logs_checkpoint'); + + return { + __esModule: true, + ...originalModule, + loadLogsCheckpoint: jest.fn().mockReturnValue('2021-09-05T10:49:01.805Z'), + }; +}); + import { DeprecationLoggingStatus } from '../../../../common/types'; import { DEPRECATION_LOGS_SOURCE_ID } from '../../../../common/constants'; import { setupEnvironment } from '../../helpers'; @@ -180,7 +194,7 @@ describe('Overview - Fix deprecation logs step', () => { expect(exists('viewObserveLogs')).toBe(true); expect(find('viewObserveLogs').props().href).toBe( - `/app/logs/stream?sourceId=${DEPRECATION_LOGS_SOURCE_ID}` + `/app/logs/stream?sourceId=${DEPRECATION_LOGS_SOURCE_ID}&logPosition=(end:now,start:'${MOCKED_TIME}')` ); }); @@ -194,7 +208,12 @@ describe('Overview - Fix deprecation logs step', () => { component.update(); expect(exists('viewDiscoverLogs')).toBe(true); - expect(find('viewDiscoverLogs').props().href).toBe('discoverUrl'); + + const decodedUrl = decodeURIComponent(find('viewDiscoverLogs').props().href); + expect(decodedUrl).toContain('discoverUrl'); + ['"language":"kuery"', '"query":"@timestamp+>'].forEach((param) => { + expect(decodedUrl).toContain(param); + }); }); }); diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_logs_step/deprecations_count_checkpoint/deprecations_count_checkpoint.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_logs_step/deprecations_count_checkpoint/deprecations_count_checkpoint.tsx index f0a4096687f6ca..244583e9154c16 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_logs_step/deprecations_count_checkpoint/deprecations_count_checkpoint.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_logs_step/deprecations_count_checkpoint/deprecations_count_checkpoint.tsx @@ -5,17 +5,13 @@ * 2.0. */ -import React, { FunctionComponent, useState, useEffect } from 'react'; +import React, { FunctionComponent, useEffect } from 'react'; import moment from 'moment-timezone'; import { FormattedDate, FormattedTime, FormattedMessage } from '@kbn/i18n/react'; import { i18n } from '@kbn/i18n'; import { EuiCallOut, EuiButton, EuiLoadingContent } from '@elastic/eui'; import { useAppContext } from '../../../../app_context'; -import { Storage } from '../../../../../shared_imports'; - -const LS_SETTING_ID = 'kibana.upgradeAssistant.lastCheckpoint'; -const localStorage = new Storage(window.localStorage); const i18nTexts = { calloutTitle: (warningsCount: number, previousCheck: string) => ( @@ -51,32 +47,22 @@ const i18nTexts = { ), }; -const getPreviousCheckpointDate = () => { - const storedValue = moment(localStorage.get(LS_SETTING_ID)); - - if (storedValue.isValid()) { - return storedValue.toISOString(); - } - - const now = moment().toISOString(); - localStorage.set(LS_SETTING_ID, now); - - return now; -}; - interface Props { + checkpoint: string; + setCheckpoint: (value: string) => void; setHasNoDeprecationLogs: (hasNoLogs: boolean) => void; } export const DeprecationsCountCheckpoint: FunctionComponent = ({ + checkpoint, + setCheckpoint, setHasNoDeprecationLogs, }) => { const { services: { api }, } = useAppContext(); - const [previousCheck, setPreviousCheck] = useState(getPreviousCheckpointDate()); const { data, error, isLoading, resendRequest, isInitialRequest } = api.getDeprecationLogsCount( - previousCheck + checkpoint ); const logsCount = data?.count || 0; @@ -87,9 +73,7 @@ export const DeprecationsCountCheckpoint: FunctionComponent = ({ const onResetClick = () => { const now = moment().toISOString(); - - setPreviousCheck(now); - localStorage.set(LS_SETTING_ID, now); + setCheckpoint(now); }; useEffect(() => { @@ -126,7 +110,7 @@ export const DeprecationsCountCheckpoint: FunctionComponent = ({ return ( { - const { indexPatterns: indexPatternService } = dataService; +interface Props { + checkpoint: string; +} - const results = await indexPatternService.find(DEPRECATION_LOGS_INDEX_PATTERN); +const getDeprecationIndexPatternId = async (dataService: DataPublicPluginStart) => { + const results = await dataService.dataViews.find(DEPRECATION_LOGS_INDEX_PATTERN); // Since the find might return also results with wildcard matchers we need to find the // index pattern that has an exact match with our title. const deprecationIndexPattern = results.find( @@ -30,7 +33,7 @@ const getDeprecationIndexPatternId = async (dataService: DataPublicPluginStart) if (deprecationIndexPattern) { return deprecationIndexPattern.id; } else { - const newIndexPattern = await indexPatternService.createAndSave({ + const newIndexPattern = await dataService.dataViews.createAndSave({ title: DEPRECATION_LOGS_INDEX_PATTERN, allowNoIndex: true, }); @@ -38,7 +41,7 @@ const getDeprecationIndexPatternId = async (dataService: DataPublicPluginStart) } }; -const DiscoverAppLink: FunctionComponent = () => { +const DiscoverAppLink: FunctionComponent = ({ checkpoint }) => { const { services: { data: dataService }, plugins: { share }, @@ -55,12 +58,19 @@ const DiscoverAppLink: FunctionComponent = () => { return; } - const url = await locator.getUrl({ indexPatternId }); + const url = await locator.getUrl({ + indexPatternId, + query: { + language: 'kuery', + query: `@timestamp > "${checkpoint}"`, + }, + }); + setDiscoveryUrl(url); }; getDiscoveryUrl(); - }, [dataService, share.url.locators]); + }, [dataService, checkpoint, share.url.locators]); return ( @@ -72,14 +82,16 @@ const DiscoverAppLink: FunctionComponent = () => { ); }; -const ObservabilityAppLink: FunctionComponent = () => { +const ObservabilityAppLink: FunctionComponent = ({ checkpoint }) => { const { services: { core: { http }, }, } = useAppContext(); const logStreamUrl = http?.basePath?.prepend( - `/app/logs/stream?sourceId=${DEPRECATION_LOGS_SOURCE_ID}` + `/app/logs/stream?sourceId=${DEPRECATION_LOGS_SOURCE_ID}&logPosition=(end:now,start:${encode( + checkpoint + )})` ); return ( @@ -92,7 +104,7 @@ const ObservabilityAppLink: FunctionComponent = () => { ); }; -export const ExternalLinks: FunctionComponent = () => { +export const ExternalLinks: FunctionComponent = ({ checkpoint }) => { return ( @@ -106,7 +118,7 @@ export const ExternalLinks: FunctionComponent = () => {

- +
@@ -120,7 +132,7 @@ export const ExternalLinks: FunctionComponent = () => {

- +
diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_logs_step/fix_logs_step.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_logs_step/fix_logs_step.tsx index 189dc4e39c0b22..c0977847d121cb 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_logs_step/fix_logs_step.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_logs_step/fix_logs_step.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { FunctionComponent } from 'react'; +import React, { FunctionComponent, useState, useEffect } from 'react'; import { i18n } from '@kbn/i18n'; import { EuiText, EuiSpacer, EuiPanel, EuiCallOut } from '@elastic/eui'; @@ -15,6 +15,7 @@ import { ExternalLinks } from './external_links'; import { DeprecationsCountCheckpoint } from './deprecations_count_checkpoint'; import { useDeprecationLogging } from './use_deprecation_logging'; import { DeprecationLoggingToggle } from './deprecation_logging_toggle'; +import { loadLogsCheckpoint, saveLogsCheckpoint } from '../../../lib/logs_checkpoint'; import type { OverviewStepProps } from '../../types'; const i18nTexts = { @@ -54,6 +55,11 @@ interface Props { const FixLogsStep: FunctionComponent = ({ setIsComplete }) => { const state = useDeprecationLogging(); + const [checkpoint, setCheckpoint] = useState(loadLogsCheckpoint()); + + useEffect(() => { + saveLogsCheckpoint(checkpoint); + }, [checkpoint]); return ( <> @@ -86,14 +92,18 @@ const FixLogsStep: FunctionComponent = ({ setIsComplete }) => {

{i18nTexts.analyzeTitle}

- +

{i18nTexts.deprecationsCountCheckpointTitle}

- + )} diff --git a/x-pack/plugins/upgrade_assistant/public/application/lib/logs_checkpoint.ts b/x-pack/plugins/upgrade_assistant/public/application/lib/logs_checkpoint.ts new file mode 100644 index 00000000000000..59c3adaed95df7 --- /dev/null +++ b/x-pack/plugins/upgrade_assistant/public/application/lib/logs_checkpoint.ts @@ -0,0 +1,30 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import moment from 'moment-timezone'; + +import { Storage } from '../../shared_imports'; + +const SETTING_ID = 'kibana.upgradeAssistant.lastCheckpoint'; +const localStorage = new Storage(window.localStorage); + +export const loadLogsCheckpoint = () => { + const storedValue = moment(localStorage.get(SETTING_ID)); + + if (storedValue.isValid()) { + return storedValue.toISOString(); + } + + const now = moment().toISOString(); + localStorage.set(SETTING_ID, now); + + return now; +}; + +export const saveLogsCheckpoint = (value: string) => { + localStorage.set(SETTING_ID, value); +}; diff --git a/x-pack/plugins/upgrade_assistant/public/plugin.ts b/x-pack/plugins/upgrade_assistant/public/plugin.ts index 2385bbe8b33fbd..24a9d75a7508b0 100644 --- a/x-pack/plugins/upgrade_assistant/public/plugin.ts +++ b/x-pack/plugins/upgrade_assistant/public/plugin.ts @@ -43,7 +43,7 @@ export class UpgradeAssistantUIPlugin title: pluginName, order: 1, async mount(params) { - const [coreStart, { discover, data }] = await coreSetup.getStartServices(); + const [coreStart, { data }] = await coreSetup.getStartServices(); const { chrome: { docTitle }, @@ -62,7 +62,6 @@ export class UpgradeAssistantUIPlugin core: coreStart, data, history: params.history, - discover, api: apiService, breadcrumbs: breadcrumbService, }, diff --git a/x-pack/plugins/upgrade_assistant/public/types.ts b/x-pack/plugins/upgrade_assistant/public/types.ts index 8b5ac002c25ac8..55c43e452a8642 100644 --- a/x-pack/plugins/upgrade_assistant/public/types.ts +++ b/x-pack/plugins/upgrade_assistant/public/types.ts @@ -6,7 +6,6 @@ */ import { ScopedHistory } from 'kibana/public'; -import { DiscoverStart } from 'src/plugins/discover/public'; import { ManagementSetup } from 'src/plugins/management/public'; import { DataPublicPluginStart } from 'src/plugins/data/public'; import { SharePluginSetup } from 'src/plugins/share/public'; @@ -30,7 +29,6 @@ export interface SetupDependencies { export interface StartDependencies { licensing: LicensingPluginStart; - discover: DiscoverStart; data: DataPublicPluginStart; } @@ -50,7 +48,6 @@ export interface AppDependencies { }; services: { core: CoreStart; - discover: DiscoverStart; data: DataPublicPluginStart; breadcrumbs: BreadcrumbService; history: ScopedHistory; diff --git a/x-pack/plugins/upgrade_assistant/tsconfig.json b/x-pack/plugins/upgrade_assistant/tsconfig.json index 39d7404ebea9d5..4336acb77c2eb6 100644 --- a/x-pack/plugins/upgrade_assistant/tsconfig.json +++ b/x-pack/plugins/upgrade_assistant/tsconfig.json @@ -7,6 +7,7 @@ "declarationMap": true }, "include": [ + "../../../typings/**/*", "__jest__/**/*", "common/**/*", "public/**/*",