diff --git a/x-pack/legacy/plugins/uptime/common/constants/plugin.ts b/x-pack/legacy/plugins/uptime/common/constants/plugin.ts index 01f38d37189d1b..47f77ea985f322 100644 --- a/x-pack/legacy/plugins/uptime/common/constants/plugin.ts +++ b/x-pack/legacy/plugins/uptime/common/constants/plugin.ts @@ -5,6 +5,7 @@ */ export const PLUGIN = { + APP_ROOT_ID: 'react-uptime-root', ID: 'uptime', ROUTER_BASE_NAME: '/app/uptime#/', LOCAL_STORAGE_KEY: 'xpack.uptime', diff --git a/x-pack/legacy/plugins/uptime/public/app.ts b/x-pack/legacy/plugins/uptime/public/app.ts index 255c51c9e48cea..b068f8a9becda5 100644 --- a/x-pack/legacy/plugins/uptime/public/app.ts +++ b/x-pack/legacy/plugins/uptime/public/app.ts @@ -4,4 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ -import './apps/kibana_app'; +import './apps/index'; diff --git a/x-pack/legacy/plugins/uptime/public/apps/kibana_app.ts b/x-pack/legacy/plugins/uptime/public/apps/index.ts similarity index 57% rename from x-pack/legacy/plugins/uptime/public/apps/kibana_app.ts rename to x-pack/legacy/plugins/uptime/public/apps/index.ts index bc82dc0cddeece..2fa548c3c27174 100644 --- a/x-pack/legacy/plugins/uptime/public/apps/kibana_app.ts +++ b/x-pack/legacy/plugins/uptime/public/apps/index.ts @@ -4,7 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ -import { compose } from '../lib/compose/kibana_compose'; -import { startApp } from './start_app'; +import chrome from 'ui/chrome'; +import { npStart } from 'ui/new_platform'; +import { Plugin } from './plugin'; -startApp(compose()); +new Plugin({ opaqueId: Symbol('uptime') }, chrome).start(npStart); diff --git a/x-pack/legacy/plugins/uptime/public/apps/plugin.ts b/x-pack/legacy/plugins/uptime/public/apps/plugin.ts new file mode 100644 index 00000000000000..bc4e30b79cb157 --- /dev/null +++ b/x-pack/legacy/plugins/uptime/public/apps/plugin.ts @@ -0,0 +1,58 @@ +/* + * 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 { LegacyCoreStart, PluginInitializerContext } from 'src/core/public'; +import { PluginsStart } from 'ui/new_platform/new_platform'; +import { Chrome } from 'ui/chrome'; +import { UMFrontendLibs } from '../lib/lib'; +import { PLUGIN } from '../../common/constants'; +import { getKibanaFrameworkAdapter } from '../lib/adapters/framework/new_platform_adapter'; +import template from './template.html'; +import { UptimeApp } from '../uptime_app'; +import { createApolloClient } from '../lib/adapters/framework/apollo_client_adapter'; + +export interface StartObject { + core: LegacyCoreStart; + plugins: PluginsStart; +} + +export class Plugin { + constructor( + // @ts-ignore this is added to satisfy the New Platform typing constraint, + // but we're not leveraging any of its functionality yet. + private readonly initializerContext: PluginInitializerContext, + private readonly chrome: Chrome + ) { + this.chrome = chrome; + } + + public start(start: StartObject): void { + const { + core, + plugins: { + data: { autocomplete }, + }, + } = start; + const libs: UMFrontendLibs = { + framework: getKibanaFrameworkAdapter(core, autocomplete), + }; + // @ts-ignore improper type description + this.chrome.setRootTemplate(template); + const checkForRoot = () => { + return new Promise(resolve => { + const ready = !!document.getElementById(PLUGIN.APP_ROOT_ID); + if (ready) { + resolve(); + } else { + setTimeout(() => resolve(checkForRoot()), 10); + } + }); + }; + checkForRoot().then(() => { + libs.framework.render(UptimeApp, createApolloClient); + }); + } +} diff --git a/x-pack/legacy/plugins/uptime/public/apps/start_app.tsx b/x-pack/legacy/plugins/uptime/public/apps/start_app.tsx deleted file mode 100644 index 4b07f936ae3635..00000000000000 --- a/x-pack/legacy/plugins/uptime/public/apps/start_app.tsx +++ /dev/null @@ -1,19 +0,0 @@ -/* - * 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 'react-vis/dist/style.css'; -import 'ui/angular-bootstrap'; -import 'ui/autoload/all'; -import 'ui/autoload/styles'; -import 'ui/courier'; -import 'ui/persisted_log'; -import { createApolloClient } from '../lib/adapters/framework/apollo_client_adapter'; -import { UMFrontendLibs } from '../lib/lib'; -import { UptimeApp } from '../uptime_app'; - -export async function startApp(libs: UMFrontendLibs) { - libs.framework.render(UptimeApp, createApolloClient); -} diff --git a/x-pack/legacy/plugins/uptime/public/apps/template.html b/x-pack/legacy/plugins/uptime/public/apps/template.html new file mode 100644 index 00000000000000..a6fb47048a9b1d --- /dev/null +++ b/x-pack/legacy/plugins/uptime/public/apps/template.html @@ -0,0 +1 @@ +
\ No newline at end of file diff --git a/x-pack/legacy/plugins/uptime/public/badge.ts b/x-pack/legacy/plugins/uptime/public/badge.ts index 76c2b72f5ead63..a1b4f85348f06b 100644 --- a/x-pack/legacy/plugins/uptime/public/badge.ts +++ b/x-pack/legacy/plugins/uptime/public/badge.ts @@ -4,5 +4,5 @@ * you may not use this file except in compliance with the Elastic License. */ -import { Badge } from 'ui/chrome/api/badge'; -export type UMBadge = Badge | undefined; +import { ChromeBadge } from 'src/core/public'; +export type UMBadge = ChromeBadge | undefined; diff --git a/x-pack/legacy/plugins/uptime/public/breadcrumbs.ts b/x-pack/legacy/plugins/uptime/public/breadcrumbs.ts index 31aa1e491a9996..ff0dca3887ff2c 100644 --- a/x-pack/legacy/plugins/uptime/public/breadcrumbs.ts +++ b/x-pack/legacy/plugins/uptime/public/breadcrumbs.ts @@ -5,24 +5,20 @@ */ import { i18n } from '@kbn/i18n'; +import { ChromeBreadcrumb } from 'src/core/public'; -export interface UMBreadcrumb { - text: string; - href?: string; -} - -const makeOverviewBreadcrumb = (search?: string): UMBreadcrumb => ({ +const makeOverviewBreadcrumb = (search?: string): ChromeBreadcrumb => ({ text: i18n.translate('xpack.uptime.breadcrumbs.overviewBreadcrumbText', { defaultMessage: 'Uptime', }), href: `#/${search ? search : ''}`, }); -export const getOverviewPageBreadcrumbs = (search?: string): UMBreadcrumb[] => [ +export const getOverviewPageBreadcrumbs = (search?: string): ChromeBreadcrumb[] => [ makeOverviewBreadcrumb(search), ]; -export const getMonitorPageBreadcrumb = (name: string, search?: string): UMBreadcrumb[] => [ +export const getMonitorPageBreadcrumb = (name: string, search?: string): ChromeBreadcrumb[] => [ makeOverviewBreadcrumb(search), { text: name }, ]; diff --git a/x-pack/legacy/plugins/uptime/public/components/functional/kuery_bar/index.tsx b/x-pack/legacy/plugins/uptime/public/components/functional/kuery_bar/index.tsx index b979cbf2456bd2..f529c9cd9d53fc 100644 --- a/x-pack/legacy/plugins/uptime/public/components/functional/kuery_bar/index.tsx +++ b/x-pack/legacy/plugins/uptime/public/components/functional/kuery_bar/index.tsx @@ -6,18 +6,17 @@ import React, { useState, useEffect, useContext } from 'react'; import { uniqueId, startsWith } from 'lodash'; -import { npStart } from 'ui/new_platform'; import { EuiCallOut } from '@elastic/eui'; import styled from 'styled-components'; import { FormattedMessage } from '@kbn/i18n/react'; -import { StaticIndexPattern } from 'ui/index_patterns'; import { fromKueryExpression, toElasticsearchQuery } from '@kbn/es-query'; +import { AutocompleteProviderRegister, AutocompleteSuggestion } from 'src/plugins/data/public'; +import { StaticIndexPattern } from 'src/legacy/core_plugins/data/public/index_patterns/index_patterns'; import { Typeahead } from './typeahead'; import { getIndexPattern } from '../../../lib/adapters/index_pattern'; import { UptimeSettingsContext } from '../../../contexts'; import { useUrlParams } from '../../../hooks'; import { toStaticIndexPattern } from '../../../lib/helper'; -import { AutocompleteSuggestion } from '../../../../../../../../src/plugins/data/public'; const Container = styled.div` margin-bottom: 10px; @@ -28,10 +27,7 @@ interface State { isLoadingIndexPattern: boolean; } -const getAutocompleteProvider = (language: string) => - npStart.plugins.data.autocomplete.getProvider(language); - -function convertKueryToEsQuery(kuery: string, indexPattern: StaticIndexPattern) { +function convertKueryToEsQuery(kuery: string, indexPattern: unknown) { const ast = fromKueryExpression(kuery); return toElasticsearchQuery(ast, indexPattern); } @@ -39,9 +35,10 @@ function convertKueryToEsQuery(kuery: string, indexPattern: StaticIndexPattern) function getSuggestions( query: string, selectionStart: number, - apmIndexPattern: StaticIndexPattern + apmIndexPattern: StaticIndexPattern, + autocomplete: Pick ) { - const autocompleteProvider = getAutocompleteProvider('kuery'); + const autocompleteProvider = autocomplete.getProvider('kuery'); if (!autocompleteProvider) { return []; } @@ -62,7 +59,11 @@ function getSuggestions( return suggestions; } -export function KueryBar() { +interface Props { + autocomplete: Pick; +} + +export function KueryBar({ autocomplete }: Props) { const [state, setState] = useState({ suggestions: [], isLoadingIndexPattern: true, @@ -94,7 +95,12 @@ export function KueryBar() { currentRequestCheck = currentRequest; try { - let suggestions = await getSuggestions(inputValue, selectionStart, indexPattern); + let suggestions = await getSuggestions( + inputValue, + selectionStart, + indexPattern, + autocomplete + ); suggestions = suggestions .filter((suggestion: AutocompleteSuggestion) => !startsWith(suggestion.text, 'span.')) .slice(0, 15); diff --git a/x-pack/legacy/plugins/uptime/public/lib/adapters/framework/capabilities_adapter.ts b/x-pack/legacy/plugins/uptime/public/lib/adapters/framework/capabilities_adapter.ts index 135648d7b6fa31..e3faf34b7696d7 100644 --- a/x-pack/legacy/plugins/uptime/public/lib/adapters/framework/capabilities_adapter.ts +++ b/x-pack/legacy/plugins/uptime/public/lib/adapters/framework/capabilities_adapter.ts @@ -4,16 +4,14 @@ * you may not use this file except in compliance with the Elastic License. */ -import { capabilities as uiCapabilities } from 'ui/capabilities'; - interface IntegratedAppsAvailability { [key: string]: boolean; } export const getIntegratedAppAvailability = ( + capabilities: any, integratedApps: string[] ): IntegratedAppsAvailability => { - const capabilities = uiCapabilities.get(); return integratedApps.reduce((supportedSolutions: IntegratedAppsAvailability, solutionName) => { supportedSolutions[solutionName] = capabilities[solutionName] && capabilities[solutionName].show === true; diff --git a/x-pack/legacy/plugins/uptime/public/lib/adapters/framework/kibana_framework_adapter.ts b/x-pack/legacy/plugins/uptime/public/lib/adapters/framework/kibana_framework_adapter.ts deleted file mode 100644 index dee8a957e54dab..00000000000000 --- a/x-pack/legacy/plugins/uptime/public/lib/adapters/framework/kibana_framework_adapter.ts +++ /dev/null @@ -1,140 +0,0 @@ -/* - * 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 ReactDOM from 'react-dom'; -import { unmountComponentAtNode } from 'react-dom'; -import chrome from 'ui/chrome'; -import { ELASTIC_WEBSITE_URL, DOC_LINK_VERSION } from 'ui/documentation_links'; -import { PLUGIN, INTEGRATED_SOLUTIONS } from '../../../../common/constants'; -import { BootstrapUptimeApp, UMFrameworkAdapter } from '../../lib'; -import { CreateGraphQLClient } from './framework_adapter_types'; -import { renderUptimeKibanaGlobalHelp } from './kibana_global_help'; -import { getTelemetryMonitorPageLogger, getTelemetryOverviewPageLogger } from '../telemetry'; -import { getIntegratedAppAvailability } from './capabilities_adapter'; - -export class UMKibanaFrameworkAdapter implements UMFrameworkAdapter { - private uiRoutes: any; - private xsrfHeader: string; - private uriPath: string; - - constructor(uiRoutes: any) { - this.uiRoutes = uiRoutes; - this.xsrfHeader = chrome.getXsrfToken(); - this.uriPath = `${chrome.getBasePath()}/api/uptime/graphql`; - } - - /** - * This function will acquire all the existing data from Kibana - * services and persisted state expected by the plugin's props - * interface. It then renders the plugin. - */ - public render = ( - renderComponent: BootstrapUptimeApp, - createGraphQLClient: CreateGraphQLClient - ) => { - const route = { - controllerAs: 'uptime', - // @ts-ignore angular - controller: ($scope, $route, config, $location, $window) => { - const graphQLClient = createGraphQLClient(this.uriPath, this.xsrfHeader); - $scope.$$postDigest(() => { - const elem = document.getElementById('uptimeReactRoot'); - - // set up route with current base path - const basePath = chrome.getBasePath(); - const routerBasename = basePath.endsWith('/') - ? `${basePath}/${PLUGIN.ROUTER_BASE_NAME}` - : basePath + PLUGIN.ROUTER_BASE_NAME; - - /** - * TODO: this is a redirect hack to deal with a problem that largely - * in testing but rarely occurs in the real world, where the specified - * URL contains `.../app/uptime{SOME_URL_PARAM_TEXT}#` instead of - * a path like `.../app/uptime#{SOME_URL_PARAM_TEXT}`. - * - * This redirect will almost never be triggered in practice, but it makes more - * sense to include it here rather than altering the existing testing - * infrastructure underlying the rest of Kibana. - * - * We welcome a more permanent solution that will result in the deletion of the - * block below. - */ - if ($location.absUrl().indexOf(PLUGIN.ROUTER_BASE_NAME) === -1) { - $window.location.replace(routerBasename); - } - - // determine whether dark mode is enabled - const darkMode = config.get('theme:darkMode', false) || false; - - /** - * We pass this global help setup as a prop to the app, because for - * localization it's necessary to have the provider mounted before - * we can render our help links, as they rely on i18n. - */ - const renderGlobalHelpControls = () => - // render Uptime feedback link in global help menu - chrome.helpExtension.set((element: HTMLDivElement) => { - ReactDOM.render( - renderUptimeKibanaGlobalHelp(ELASTIC_WEBSITE_URL, DOC_LINK_VERSION), - element - ); - return () => ReactDOM.unmountComponentAtNode(element); - }); - - /** - * These values will let Uptime know if the integrated solutions - * are available. If any/all of them are unavaialble, we should not show - * links/integrations to those apps. - */ - const { - apm: isApmAvailable, - infrastructure: isInfraAvailable, - logs: isLogsAvailable, - } = getIntegratedAppAvailability(INTEGRATED_SOLUTIONS); - - ReactDOM.render( - renderComponent({ - basePath, - client: graphQLClient, - darkMode, - isApmAvailable, - isInfraAvailable, - isLogsAvailable, - logMonitorPageLoad: getTelemetryMonitorPageLogger(this.xsrfHeader, basePath), - logOverviewPageLoad: getTelemetryOverviewPageLogger(this.xsrfHeader, basePath), - renderGlobalHelpControls, - routerBasename, - setBadge: chrome.badge.set, - setBreadcrumbs: chrome.breadcrumbs.set, - }), - elem - ); - this.manageAngularLifecycle($scope, $route, elem); - }); - }, - template: - '', - }; - this.uiRoutes.enable(); - // TODO: hack to refer all routes to same endpoint, use a more proper way of achieving this - this.uiRoutes.otherwise(route); - }; - - // @ts-ignore angular params - private manageAngularLifecycle = ($scope, $route, elem) => { - const lastRoute = $route.current; - const deregister = $scope.$on('$locationChangeSuccess', () => { - const currentRoute = $route.current; - if (lastRoute.$$route && lastRoute.$$route.template === currentRoute.$$route.template) { - $route.current = lastRoute; - } - }); - $scope.$on('$destroy', () => { - deregister(); - unmountComponentAtNode(elem); - }); - }; -} diff --git a/x-pack/legacy/plugins/uptime/public/lib/adapters/framework/new_platform_adapter.tsx b/x-pack/legacy/plugins/uptime/public/lib/adapters/framework/new_platform_adapter.tsx new file mode 100644 index 00000000000000..e35d8e93ca4a72 --- /dev/null +++ b/x-pack/legacy/plugins/uptime/public/lib/adapters/framework/new_platform_adapter.tsx @@ -0,0 +1,76 @@ +/* + * 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 { ChromeBreadcrumb, CoreStart } from 'src/core/public'; +import React from 'react'; +import ReactDOM from 'react-dom'; +import { get } from 'lodash'; +import { AutocompleteProviderRegister } from 'src/plugins/data/public'; +import { CreateGraphQLClient } from './framework_adapter_types'; +import { UptimeApp, UptimeAppProps } from '../../../uptime_app'; +import { getIntegratedAppAvailability } from './capabilities_adapter'; +import { INTEGRATED_SOLUTIONS, PLUGIN } from '../../../../common/constants'; +import { getTelemetryMonitorPageLogger, getTelemetryOverviewPageLogger } from '../telemetry'; +import { renderUptimeKibanaGlobalHelp } from './kibana_global_help'; +import { UMFrameworkAdapter, BootstrapUptimeApp } from '../../lib'; +import { createApolloClient } from './apollo_client_adapter'; + +export const getKibanaFrameworkAdapter = ( + core: CoreStart, + autocomplete: Pick +): UMFrameworkAdapter => { + const { + application: { capabilities }, + chrome: { setBadge, setHelpExtension }, + docLinks: { DOC_LINK_VERSION, ELASTIC_WEBSITE_URL }, + http: { basePath }, + i18n, + } = core; + let breadcrumbs: ChromeBreadcrumb[] = []; + core.chrome.getBreadcrumbs$().subscribe((nextBreadcrumbs?: ChromeBreadcrumb[]) => { + breadcrumbs = nextBreadcrumbs || []; + }); + const { apm, infrastructure, logs } = getIntegratedAppAvailability( + capabilities, + INTEGRATED_SOLUTIONS + ); + const canSave = get(capabilities, 'uptime.save', false); + const props: UptimeAppProps = { + basePath: basePath.get(), + canSave, + client: createApolloClient(`${basePath.get()}/api/uptime/graphql`, 'true'), + darkMode: core.uiSettings.get('theme:darkMode'), + autocomplete, + i18n, + isApmAvailable: apm, + isInfraAvailable: infrastructure, + isLogsAvailable: logs, + kibanaBreadcrumbs: breadcrumbs, + logMonitorPageLoad: getTelemetryMonitorPageLogger('true', basePath.get()), + logOverviewPageLoad: getTelemetryOverviewPageLogger('true', basePath.get()), + renderGlobalHelpControls: () => + setHelpExtension((element: HTMLElement) => { + ReactDOM.render( + renderUptimeKibanaGlobalHelp(ELASTIC_WEBSITE_URL, DOC_LINK_VERSION), + element + ); + return () => ReactDOM.unmountComponentAtNode(element); + }), + routerBasename: basePath.prepend(PLUGIN.ROUTER_BASE_NAME), + setBadge, + setBreadcrumbs: core.chrome.setBreadcrumbs, + }; + + return { + // TODO: these parameters satisfy the interface but are no longer needed + render: async (createComponent: BootstrapUptimeApp, cgc: CreateGraphQLClient) => { + const node = await document.getElementById('react-uptime-root'); + if (node) { + ReactDOM.render(, node); + } + }, + }; +}; diff --git a/x-pack/legacy/plugins/uptime/public/lib/compose/kibana_compose.ts b/x-pack/legacy/plugins/uptime/public/lib/compose/kibana_compose.ts deleted file mode 100644 index 759c161d32cdd7..00000000000000 --- a/x-pack/legacy/plugins/uptime/public/lib/compose/kibana_compose.ts +++ /dev/null @@ -1,17 +0,0 @@ -/* - * 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 uiRoutes from 'ui/routes'; -import { UMKibanaFrameworkAdapter } from '../adapters/framework/kibana_framework_adapter'; -import { UMFrontendLibs } from '../lib'; - -export function compose(): UMFrontendLibs { - const libs: UMFrontendLibs = { - framework: new UMKibanaFrameworkAdapter(uiRoutes), - }; - - return libs; -} diff --git a/x-pack/legacy/plugins/uptime/public/lib/lib.ts b/x-pack/legacy/plugins/uptime/public/lib/lib.ts index 65a7f18711fd0f..0a744bff815c78 100644 --- a/x-pack/legacy/plugins/uptime/public/lib/lib.ts +++ b/x-pack/legacy/plugins/uptime/public/lib/lib.ts @@ -7,8 +7,8 @@ import { NormalizedCacheObject } from 'apollo-cache-inmemory'; import ApolloClient from 'apollo-client'; import React from 'react'; +import { ChromeBreadcrumb } from 'src/core/public'; import { UMBadge } from '../badge'; -import { UMBreadcrumb } from '../breadcrumbs'; import { UptimeAppProps } from '../uptime_app'; import { CreateGraphQLClient } from './adapters/framework/framework_adapter_types'; @@ -16,7 +16,7 @@ export interface UMFrontendLibs { framework: UMFrameworkAdapter; } -export type UMUpdateBreadcrumbs = (breadcrumbs: UMBreadcrumb[]) => void; +export type UMUpdateBreadcrumbs = (breadcrumbs: ChromeBreadcrumb[]) => void; export type UMUpdateBadge = (badge: UMBadge) => void; diff --git a/x-pack/legacy/plugins/uptime/public/pages/overview.tsx b/x-pack/legacy/plugins/uptime/public/pages/overview.tsx index 3bd09bcba143c0..7c1b81b0e15c86 100644 --- a/x-pack/legacy/plugins/uptime/public/pages/overview.tsx +++ b/x-pack/legacy/plugins/uptime/public/pages/overview.tsx @@ -9,6 +9,7 @@ import { i18n } from '@kbn/i18n'; import { fromKueryExpression, toElasticsearchQuery } from '@kbn/es-query'; import React, { Fragment, useContext, useEffect, useState } from 'react'; import styled from 'styled-components'; +import { AutocompleteProviderRegister } from 'src/plugins/data/public'; import { getOverviewPageBreadcrumbs } from '../breadcrumbs'; import { EmptyState, @@ -29,12 +30,13 @@ import { combineFiltersAndUserSearch, stringifyKueries, toStaticIndexPattern } f interface OverviewPageProps { basePath: string; - logOverviewPageLoad: () => void; + autocomplete: Pick; history: any; location: { pathname: string; search: string; }; + logOverviewPageLoad: () => void; setBreadcrumbs: UMUpdateBreadcrumbs; } @@ -54,7 +56,12 @@ const EuiFlexItemStyled = styled(EuiFlexItem)` } `; -export const OverviewPage = ({ basePath, logOverviewPageLoad, setBreadcrumbs }: Props) => { +export const OverviewPage = ({ + basePath, + autocomplete, + logOverviewPageLoad, + setBreadcrumbs, +}: Props) => { const { colors, setHeadingText } = useContext(UptimeSettingsContext); const [getUrlParams, updateUrl] = useUrlParams(); const { absoluteDateRangeStart, absoluteDateRangeEnd, ...params } = getUrlParams(); @@ -129,7 +136,7 @@ export const OverviewPage = ({ basePath, logOverviewPageLoad, setBreadcrumbs }: - + ; + i18n: I18nStart; isApmAvailable: boolean; isInfraAvailable: boolean; isLogsAvailable: boolean; + kibanaBreadcrumbs: ChromeBreadcrumb[]; logMonitorPageLoad: () => void; logOverviewPageLoad: () => void; routerBasename: string; @@ -50,8 +54,11 @@ export interface UptimeAppProps { const Application = (props: UptimeAppProps) => { const { basePath, + canSave, client, darkMode, + autocomplete, + i18n: i18nCore, isApmAvailable, isInfraAvailable, isLogsAvailable, @@ -89,7 +96,7 @@ const Application = (props: UptimeAppProps) => { useEffect(() => { renderGlobalHelpControls(); setBadge( - !capabilities.get().uptime.save + !canSave ? { text: i18n.translate('xpack.uptime.badge.readOnly.text', { defaultMessage: 'Read only', @@ -140,7 +147,7 @@ const Application = (props: UptimeAppProps) => { }; return ( - + { render={routerProps => ( { /> - + ); };