diff --git a/src/plugins/discover/public/application/main/components/top_nav/open_options_popover.scss b/src/plugins/discover/public/application/main/components/top_nav/open_options_popover.scss index f68b2bfe74a9d3..28c68506aedc5a 100644 --- a/src/plugins/discover/public/application/main/components/top_nav/open_options_popover.scss +++ b/src/plugins/discover/public/application/main/components/top_nav/open_options_popover.scss @@ -1,5 +1,5 @@ -$dscOptionsPopoverWidth: $euiSizeL * 12; +$dscOptionsPopoverWidth: $euiSizeL * 14; .dscOptionsPopover { width: $dscOptionsPopoverWidth; -} \ No newline at end of file +} diff --git a/src/plugins/discover/public/application/main/components/top_nav/open_options_popover.test.tsx b/src/plugins/discover/public/application/main/components/top_nav/open_options_popover.test.tsx index c9564a3ed029dc..8363bfdc576162 100644 --- a/src/plugins/discover/public/application/main/components/top_nav/open_options_popover.test.tsx +++ b/src/plugins/discover/public/application/main/components/top_nav/open_options_popover.test.tsx @@ -35,7 +35,7 @@ import { OptionsPopover } from './open_options_popover'; test('should display the correct text if datagrid is selected', () => { const element = document.createElement('div'); const component = mountWithIntl(); - expect(findTestSubject(component, 'docTableMode').text()).toBe('New table'); + expect(findTestSubject(component, 'docTableMode').text()).toBe('Document Explorer'); }); test('should display the correct text if legacy table is selected', () => { @@ -45,5 +45,5 @@ test('should display the correct text if legacy table is selected', () => { uiSettings.set('doc_table:legacy', true); const element = document.createElement('div'); const component = mountWithIntl(); - expect(findTestSubject(component, 'docTableMode').text()).toBe('Classic table'); + expect(findTestSubject(component, 'docTableMode').text()).toBe('Classic'); }); diff --git a/src/plugins/discover/public/application/main/components/top_nav/open_options_popover.tsx b/src/plugins/discover/public/application/main/components/top_nav/open_options_popover.tsx index 1b567813c6f7b7..a68888acb1f483 100644 --- a/src/plugins/discover/public/application/main/components/top_nav/open_options_popover.tsx +++ b/src/plugins/discover/public/application/main/components/top_nav/open_options_popover.tsx @@ -41,11 +41,11 @@ export function OptionsPopover(props: OptionsPopoverProps) { const isLegacy = uiSettings.get(DOC_TABLE_LEGACY); const mode = isLegacy - ? i18n.translate('discover.openOptionsPopover.legacyTableText', { - defaultMessage: 'Classic table', + ? i18n.translate('discover.openOptionsPopover.classicDiscoverText', { + defaultMessage: 'Classic', }) - : i18n.translate('discover.openOptionsPopover.dataGridText', { - defaultMessage: 'New table', + : i18n.translate('discover.openOptionsPopover.documentExplorerText', { + defaultMessage: 'Document Explorer', }); return ( @@ -60,8 +60,8 @@ export function OptionsPopover(props: OptionsPopoverProps) { viewModeLabel: ( ), @@ -72,21 +72,33 @@ export function OptionsPopover(props: OptionsPopoverProps) { - + {isLegacy ? ( + + ) : ( + + )} - - - {i18n.translate('discover.openOptionsPopover.goToAdvancedSettings', { - defaultMessage: 'Get started', - })} - + {isLegacy && ( + <> + + + {i18n.translate('discover.openOptionsPopover.tryDocumentExplorer', { + defaultMessage: 'Try Document Explorer', + })} + + + )} - {i18n.translate('discover.openOptionsPopover.gotToAllSettings', { - defaultMessage: 'All Discover options', + {i18n.translate('discover.openOptionsPopover.gotToSettings', { + defaultMessage: 'View Discover settings', })} diff --git a/src/plugins/discover/server/ui_settings.ts b/src/plugins/discover/server/ui_settings.ts index df06260d45d212..e9aa51a7384b2f 100644 --- a/src/plugins/discover/server/ui_settings.ts +++ b/src/plugins/discover/server/ui_settings.ts @@ -158,14 +158,14 @@ export const getUiSettings: () => Record = () => ({ schema: schema.arrayOf(schema.string()), }, [DOC_TABLE_LEGACY]: { - name: i18n.translate('discover.advancedSettings.docTableVersionName', { - defaultMessage: 'Use classic table', + name: i18n.translate('discover.advancedSettings.disableDocumentExplorer', { + defaultMessage: 'Document Explorer or classic view', }), value: true, - description: i18n.translate('discover.advancedSettings.docTableVersionDescription', { + description: i18n.translate('discover.advancedSettings.disableDocumentExplorerDescription', { defaultMessage: - 'Discover uses a new table layout that includes better data sorting, drag-and-drop columns, and a full screen view. ' + - 'Turn on this option to use the classic table. Turn off to use the new table. ', + 'To use the new Document Explorer instead of the classic view, turn off this option. ' + + 'The Document Explorer offers better data sorting, resizable columns, and a full screen view.', }), category: ['discover'], schema: schema.boolean(), diff --git a/test/functional/apps/visualize/_timelion.ts b/test/functional/apps/visualize/_timelion.ts index afbcba7df52167..f8991e17319bde 100644 --- a/test/functional/apps/visualize/_timelion.ts +++ b/test/functional/apps/visualize/_timelion.ts @@ -265,8 +265,11 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { await monacoEditor.typeCodeEditorValue('.es(index=', 'timelionCodeEditor'); // wait for index patterns will be loaded await common.sleep(500); - const suggestions = await timelion.getSuggestionItemsText(); - expect(suggestions[0].includes('log')).to.eql(true); + // other suggestions might be shown for a short amount of time - retry until metric suggestions show up + await retry.try(async () => { + const suggestions = await timelion.getSuggestionItemsText(); + expect(suggestions[0].includes('log')).to.eql(true); + }); }); it('should show field suggestions for timefield argument when index pattern set', async () => { @@ -275,9 +278,12 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { '.es(index=logstash-*, timefield=', 'timelionCodeEditor' ); - const suggestions = await timelion.getSuggestionItemsText(); - expect(suggestions.length).to.eql(4); - expect(suggestions[0].includes('@timestamp')).to.eql(true); + // other suggestions might be shown for a short amount of time - retry until metric suggestions show up + await retry.try(async () => { + const suggestions = await timelion.getSuggestionItemsText(); + expect(suggestions.length).to.eql(4); + expect(suggestions[0].includes('@timestamp')).to.eql(true); + }); }); it('should show field suggestions for split argument when index pattern set', async () => { @@ -288,9 +294,12 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { ); // wait for split fields to load await common.sleep(300); - const suggestions = await timelion.getSuggestionItemsText(); + // other suggestions might be shown for a short amount of time - retry until metric suggestions show up + await retry.try(async () => { + const suggestions = await timelion.getSuggestionItemsText(); - expect(suggestions[0].includes('@message.raw')).to.eql(true); + expect(suggestions[0].includes('@message.raw')).to.eql(true); + }); }); it('should show field suggestions for metric argument when index pattern set', async () => { diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_creation/components/create_analytics_advanced_editor/create_analytics_advanced_editor.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_creation/components/create_analytics_advanced_editor/create_analytics_advanced_editor.tsx index 31072089b8d5cf..0a83ed6db65392 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_creation/components/create_analytics_advanced_editor/create_analytics_advanced_editor.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_creation/components/create_analytics_advanced_editor/create_analytics_advanced_editor.tsx @@ -7,10 +7,19 @@ import React, { FC, Fragment, useEffect, useMemo, useRef } from 'react'; import { debounce } from 'lodash'; -import { EuiCallOut, EuiFieldText, EuiForm, EuiFormRow, EuiSpacer, EuiSwitch } from '@elastic/eui'; +import { + EuiCallOut, + EuiFieldText, + EuiForm, + EuiFormRow, + EuiSpacer, + EuiSwitch, + EuiText, +} from '@elastic/eui'; import { i18n } from '@kbn/i18n'; +import { useMlKibana } from '../../../../../contexts/kibana'; import { CodeEditor } from '../../../../../../../../../../src/plugins/kibana_react/public'; import { useNotifications } from '../../../../../contexts/kibana'; import { ml } from '../../../../../services/ml_api_service'; @@ -36,11 +45,22 @@ export const CreateAnalyticsAdvancedEditor: FC = (prop const forceInput = useRef(null); const { toasts } = useNotifications(); + const { + services: { + application: { capabilities }, + }, + } = useMlKibana(); const onChange = (str: string) => { setAdvancedEditorRawString(str); }; + const canCreateDataView = useMemo( + () => + capabilities.savedObjectsManagement.edit === true || capabilities.indexPatterns.save === true, + [capabilities] + ); + const debouncedJobIdCheck = useMemo( () => debounce(async () => { @@ -200,18 +220,34 @@ export const CreateAnalyticsAdvancedEditor: FC = (prop {!isJobCreated && ( + {i18n.translate( + 'xpack.ml.dataframe.analytics.create.dataViewPermissionWarning', + { + defaultMessage: 'You need permission to create data views.', + } + )} + , + ] + : []), + ...(createIndexPattern && destinationIndexPatternTitleExists + ? [ + i18n.translate('xpack.ml.dataframe.analytics.create.dataViewExistsError', { + defaultMessage: 'A data view with this title already exists.', + }), + ] + : []), + ]} > = ({ setCurrentStep, }) => { const { - services: { docLinks, notifications }, + services: { + docLinks, + notifications, + application: { capabilities }, + }, } = useMlKibana(); const createIndexLink = docLinks.links.apis.createIndex; const { setFormState } = actions; @@ -71,6 +75,11 @@ export const DetailsStepForm: FC = ({ (cloneJob !== undefined && resultsField === DEFAULT_RESULTS_FIELD) ); + const canCreateDataView = useMemo( + () => + capabilities.savedObjectsManagement.edit === true || capabilities.indexPatterns.save === true, + [capabilities] + ); const forceInput = useRef(null); const isStepInvalid = @@ -149,6 +158,12 @@ export const DetailsStepForm: FC = ({ } }, [destIndexSameAsId, jobId]); + useEffect(() => { + if (canCreateDataView === false) { + setFormState({ createIndexPattern: false }); + } + }, [capabilities]); + return ( = ({ + {i18n.translate('xpack.ml.dataframe.analytics.create.dataViewPermissionWarning', { + defaultMessage: 'You need permission to create data views.', + })} + , + ] + : []), ...(createIndexPattern && destinationIndexPatternTitleExists ? [ i18n.translate('xpack.ml.dataframe.analytics.create.dataViewExistsError', { @@ -373,7 +399,7 @@ export const DetailsStepForm: FC = ({ ]} > = ({ destIndex }) => { const { services: { http: { basePath }, + application: { capabilities }, }, } = useMlKibana(); + const canCreateDataView = useMemo( + () => + capabilities.savedObjectsManagement.edit === true || capabilities.indexPatterns.save === true, + [capabilities] + ); + return ( <> - - - ), }} /> + {canCreateDataView === true ? ( + + + + ), + }} + /> + ) : null} ); diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/rtl_helpers.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/rtl_helpers.tsx index 612cbfcc4bfdfc..04d74844beb83c 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/rtl_helpers.tsx +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/rtl_helpers.tsx @@ -23,7 +23,7 @@ import { ObservabilityPublicPluginsStart } from '../../../plugin'; import { EuiThemeProvider } from '../../../../../../../src/plugins/kibana_react/common'; import { lensPluginMock } from '../../../../../lens/public/mocks'; import * as useAppIndexPatternHook from './hooks/use_app_index_pattern'; -import { IndexPatternContextProvider } from './hooks/use_app_index_pattern'; +import { IndexPatternContext, IndexPatternContextProvider } from './hooks/use_app_index_pattern'; import { AllSeries, SeriesContextValue, UrlStorageContext } from './hooks/use_series_storage'; import * as fetcherHook from '../../../hooks/use_fetcher'; @@ -234,7 +234,7 @@ export const mockUseHasData = () => { return { spy, onRefreshTimeRange }; }; -export const mockAppIndexPattern = () => { +export const mockAppIndexPattern = (props?: Partial) => { const loadIndexPattern = jest.fn(); const spy = jest.spyOn(useAppIndexPatternHook, 'useAppIndexPatternContext').mockReturnValue({ indexPattern: mockIndexPattern, @@ -244,6 +244,7 @@ export const mockAppIndexPattern = () => { loadIndexPattern, indexPatterns: { ux: mockIndexPattern } as unknown as Record, indexPatternErrors: {} as any, + ...(props || {}), }); return { spy, loadIndexPattern }; }; diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/report_metric_options.test.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/report_metric_options.test.tsx new file mode 100644 index 00000000000000..767b765ba1f199 --- /dev/null +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/report_metric_options.test.tsx @@ -0,0 +1,55 @@ +/* + * 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 React from 'react'; +import { screen } from '@testing-library/react'; +import { mockAppIndexPattern, mockIndexPattern, mockUxSeries, render } from '../rtl_helpers'; +import { getDefaultConfigs } from '../configurations/default_configs'; +import { PERCENTILE } from '../configurations/constants'; +import { ReportMetricOptions } from './report_metric_options'; + +describe('ReportMetricOptions', function () { + const dataViewSeries = getDefaultConfigs({ + reportType: 'kpi-over-time', + indexPattern: mockIndexPattern, + dataType: 'ux', + }); + + it('should render properly', async function () { + render( + + ); + + expect(await screen.findByText('No data available')).toBeInTheDocument(); + }); + + it('should display loading if index pattern is not available and is loading', async function () { + mockAppIndexPattern({ loading: true, indexPatterns: undefined }); + const { container } = render( + + ); + + expect(container.getElementsByClassName('euiLoadingSpinner').length).toBe(1); + }); + + it('should not display loading if index pattern is already loaded', async function () { + mockAppIndexPattern({ loading: true }); + render( + + ); + + expect(await screen.findByText('Page load time')).toBeInTheDocument(); + }); +}); diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/report_metric_options.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/report_metric_options.tsx index 410356d0078d85..bc7c2328dcbba4 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/report_metric_options.tsx +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/report_metric_options.tsx @@ -127,7 +127,7 @@ export function ReportMetricOptions({ seriesId, series, seriesConfig }: Props) { )} {series.selectedMetricField && - (indexPattern && !loading ? ( + (indexPattern ? ( {alertData.link && !isInApp && ( diff --git a/x-pack/plugins/observability/public/utils/no_data_config.ts b/x-pack/plugins/observability/public/utils/no_data_config.ts index c8e7daaf688bc2..fdd70401e70979 100644 --- a/x-pack/plugins/observability/public/utils/no_data_config.ts +++ b/x-pack/plugins/observability/public/utils/no_data_config.ts @@ -32,7 +32,7 @@ export function getNoDataConfig({ defaultMessage: 'Use Beats and APM agents to send observability data to Elasticsearch. We make it easy with support for many popular systems, apps, and languages.', }), - href: basePath.prepend(`/app/home#/tutorial/apm`), + href: basePath.prepend(`/app/integrations/browse`), }, }, docsLink, diff --git a/x-pack/plugins/osquery/public/components/app.tsx b/x-pack/plugins/osquery/public/components/app.tsx index f4c805d3753511..ef249d5b8c7aab 100644 --- a/x-pack/plugins/osquery/public/components/app.tsx +++ b/x-pack/plugins/osquery/public/components/app.tsx @@ -9,7 +9,17 @@ import React, { useMemo } from 'react'; import { FormattedMessage } from '@kbn/i18n/react'; -import { EuiButtonEmpty, EuiFlexGroup, EuiFlexItem, EuiTabs, EuiTab } from '@elastic/eui'; +import { + EuiButtonEmpty, + EuiFlexGroup, + EuiFlexItem, + EuiTabs, + EuiTab, + EuiLoadingElastic, + EuiPage, + EuiPageBody, + EuiPageContent, +} from '@elastic/eui'; import { useLocation } from 'react-router-dom'; import { Container, Nav, Wrapper } from './layouts'; @@ -24,6 +34,24 @@ const OsqueryAppComponent = () => { const section = useMemo(() => location.pathname.split('/')[1] ?? 'overview', [location.pathname]); const { data: osqueryIntegration, isFetched } = useOsqueryIntegrationStatus(); + if (!isFetched) { + return ( + + + + + + + + ); + } + if (isFetched && osqueryIntegration?.install_status !== 'installed') { return ; } diff --git a/x-pack/plugins/osquery/server/routes/status/create_status_route.ts b/x-pack/plugins/osquery/server/routes/status/create_status_route.ts index 630ec8b3743c86..ae79ef851bed97 100644 --- a/x-pack/plugins/osquery/server/routes/status/create_status_route.ts +++ b/x-pack/plugins/osquery/server/routes/status/create_status_route.ts @@ -107,6 +107,50 @@ export const createStatusRoute = (router: IRouter, osqueryContext: OsqueryAppCon pkgName: OSQUERY_INTEGRATION_NAME, }); + const agentPolicyIds = uniq(map(policyPackages?.items, 'policy_id')); + const agentPolicies = mapKeys( + await agentPolicyService?.getByIds(internalSavedObjectsClient, agentPolicyIds), + 'id' + ); + + await Promise.all( + map(migrationObject.packs, async (packObject) => { + await internalSavedObjectsClient.create( + packSavedObjectType, + { + // @ts-expect-error update types + name: packObject.name, + // @ts-expect-error update types + description: packObject.description, + // @ts-expect-error update types + queries: convertPackQueriesToSO(packObject.queries), + // @ts-expect-error update types + enabled: packObject.enabled, + created_at: new Date().toISOString(), + created_by: 'system', + updated_at: new Date().toISOString(), + updated_by: 'system', + }, + { + // @ts-expect-error update types + references: packObject.policy_ids.map((policyId: string) => ({ + id: policyId, + name: agentPolicies[policyId].name, + type: AGENT_POLICY_SAVED_OBJECT_TYPE, + })), + refresh: 'wait_for', + } + ); + }) + ); + + // delete unnecessary package policies + await packagePolicyService?.delete( + internalSavedObjectsClient, + esClient, + migrationObject.packagePoliciesToDelete + ); + // updatePackagePolicies await Promise.all( map(migrationObject.agentPolicyToPackage, async (value, key) => { @@ -151,49 +195,6 @@ export const createStatusRoute = (router: IRouter, osqueryContext: OsqueryAppCon } }) ); - - const agentPolicyIds = uniq(map(policyPackages?.items, 'policy_id')); - const agentPolicies = mapKeys( - await agentPolicyService?.getByIds(internalSavedObjectsClient, agentPolicyIds), - 'id' - ); - - await Promise.all( - map(migrationObject.packs, async (packObject) => { - await internalSavedObjectsClient.create( - packSavedObjectType, - { - // @ts-expect-error update types - name: packObject.name, - // @ts-expect-error update types - description: packObject.description, - // @ts-expect-error update types - queries: convertPackQueriesToSO(packObject.queries), - // @ts-expect-error update types - enabled: packObject.enabled, - created_at: new Date().toISOString(), - created_by: 'system', - updated_at: new Date().toISOString(), - updated_by: 'system', - }, - { - // @ts-expect-error update types - references: packObject.policy_ids.map((policyId: string) => ({ - id: policyId, - name: agentPolicies[policyId].name, - type: AGENT_POLICY_SAVED_OBJECT_TYPE, - })), - refresh: 'wait_for', - } - ); - }) - ); - - await packagePolicyService?.delete( - internalSavedObjectsClient, - esClient, - migrationObject.packagePoliciesToDelete - ); // eslint-disable-next-line no-empty } catch (e) {} } diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_details/step_details_form.tsx b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_details/step_details_form.tsx index eda95013f60bd1..ad40a65fdf2e5b 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_details/step_details_form.tsx +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_details/step_details_form.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { FC, useEffect, useState } from 'react'; +import React, { FC, useEffect, useState, useMemo } from 'react'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; @@ -20,6 +20,7 @@ import { EuiSelect, EuiSpacer, EuiCallOut, + EuiText, } from '@elastic/eui'; import { KBN_FIELD_TYPES } from '../../../../../../../../../src/plugins/data/common'; @@ -68,6 +69,7 @@ interface StepDetailsFormProps { export const StepDetailsForm: FC = React.memo( ({ overrides = {}, onChange, searchItems, stepDefineState }) => { const deps = useAppDependencies(); + const { capabilities } = deps.application; const toastNotifications = useToastNotifications(); const { esIndicesCreateIndex } = useDocumentationLinks(); @@ -83,9 +85,18 @@ export const StepDetailsForm: FC = React.memo( const [transformIds, setTransformIds] = useState([]); const [indexNames, setIndexNames] = useState([]); + const canCreateDataView = useMemo( + () => + capabilities.savedObjectsManagement.edit === true || + capabilities.indexPatterns.save === true, + [capabilities] + ); + // Index pattern state const [indexPatternTitles, setIndexPatternTitles] = useState([]); - const [createIndexPattern, setCreateIndexPattern] = useState(defaults.createIndexPattern); + const [createIndexPattern, setCreateIndexPattern] = useState( + canCreateDataView === false ? false : defaults.createIndexPattern + ); const [indexPatternAvailableTimeFields, setIndexPatternAvailableTimeFields] = useState< string[] >([]); @@ -443,18 +454,31 @@ export const StepDetailsForm: FC = React.memo( ) : null} + {i18n.translate('xpack.transform.stepDetailsForm.dataViewPermissionWarning', { + defaultMessage: 'You need permission to create data views.', + })} + , + ] + : []), + ...(createIndexPattern && indexPatternTitleExists + ? [ + i18n.translate('xpack.transform.stepDetailsForm.dataViewTitleError', { + defaultMessage: 'A data view with this title already exists.', + }), + ] + : []), + ]} > { + describe('lens dashboard tests', () => { before(async () => { await PageObjects.common.navigateToApp('dashboard'); await security.testUser.setRoles( @@ -70,7 +69,10 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await find.clickByButtonText('lnsXYvis'); await dashboardAddPanel.closeAddPanel(); await PageObjects.lens.goToTimeRange(); - await clickInChart(6, 5); // hardcoded position of bar, depends heavy on data and charts implementation + await retry.try(async () => { + await clickInChart(6, 5); // hardcoded position of bar, depends heavy on data and charts implementation + await testSubjects.existOrFail('applyFiltersPopoverButton', { timeout: 2500 }); + }); await retry.try(async () => { await testSubjects.click('applyFiltersPopoverButton'); diff --git a/x-pack/test/functional/apps/uptime/ping_redirects.ts b/x-pack/test/functional/apps/uptime/ping_redirects.ts index 03185ac9f14669..06352d37ada282 100644 --- a/x-pack/test/functional/apps/uptime/ping_redirects.ts +++ b/x-pack/test/functional/apps/uptime/ping_redirects.ts @@ -19,7 +19,8 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { const monitor = () => uptime.monitor; - describe('Ping redirects', () => { + // FLAKY: https://github.com/elastic/kibana/issues/118476 + describe.skip('Ping redirects', () => { const start = '~ 15 minutes ago'; const end = 'now';