diff --git a/x-pack/plugins/observability_shared/kibana.jsonc b/x-pack/plugins/observability_shared/kibana.jsonc index 0fbda610b58f2..91b5a9c7d5760 100644 --- a/x-pack/plugins/observability_shared/kibana.jsonc +++ b/x-pack/plugins/observability_shared/kibana.jsonc @@ -9,7 +9,7 @@ "configPath": ["xpack", "observability_shared"], "requiredPlugins": ["cases", "guidedOnboarding", "uiActions"], "optionalPlugins": [], - "requiredBundles": ["data", "inspector", "kibanaReact"], + "requiredBundles": ["data", "inspector", "kibanaReact", "kibanaUtils"], "extraPublicDirs": ["common"] } } diff --git a/x-pack/plugins/observability_shared/public/components/action_menu/action_menu.tsx b/x-pack/plugins/observability_shared/public/components/action_menu/action_menu.tsx new file mode 100644 index 0000000000000..7eb916adadeff --- /dev/null +++ b/x-pack/plugins/observability_shared/public/components/action_menu/action_menu.tsx @@ -0,0 +1,19 @@ +/* + * 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 { EuiPopover, EuiHorizontalRule, EuiPopoverProps } from '@elastic/eui'; +import React, { HTMLAttributes } from 'react'; + +type Props = EuiPopoverProps & HTMLAttributes; + +export function ActionMenuDivider() { + return ; +} + +export function ActionMenu(props: Props) { + return ; +} diff --git a/x-pack/plugins/observability_shared/public/components/load_when_in_view/get_load_when_in_view_lazy.tsx b/x-pack/plugins/observability_shared/public/components/load_when_in_view/get_load_when_in_view_lazy.tsx new file mode 100644 index 0000000000000..eb83b2682f341 --- /dev/null +++ b/x-pack/plugins/observability_shared/public/components/load_when_in_view/get_load_when_in_view_lazy.tsx @@ -0,0 +1,20 @@ +/* + * 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, { lazy, Suspense } from 'react'; +import { EuiLoadingSpinner } from '@elastic/eui'; +import { LoadWhenInViewProps } from './load_when_in_view'; + +const LoadWhenInViewLazy = lazy(() => import('./load_when_in_view')); + +export function LoadWhenInView(props: LoadWhenInViewProps) { + return ( + }> + + + ); +} diff --git a/x-pack/plugins/observability_shared/public/components/load_when_in_view/load_when_in_view.tsx b/x-pack/plugins/observability_shared/public/components/load_when_in_view/load_when_in_view.tsx new file mode 100644 index 0000000000000..2a0892e7c8dee --- /dev/null +++ b/x-pack/plugins/observability_shared/public/components/load_when_in_view/load_when_in_view.tsx @@ -0,0 +1,52 @@ +/* + * 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, { useEffect, useState } from 'react'; +import { EuiSkeletonRectangle } from '@elastic/eui'; +import useIntersection from 'react-use/lib/useIntersection'; + +export interface LoadWhenInViewProps { + children: JSX.Element; + initialHeight?: string | number; + placeholderTitle: string; +} + +// eslint-disable-next-line import/no-default-export +export default function LoadWhenInView({ + children, + placeholderTitle, + initialHeight = 100, +}: LoadWhenInViewProps) { + const intersectionRef = React.useRef(null); + const intersection = useIntersection(intersectionRef, { + root: null, + rootMargin: '0px', + threshold: 0.25, + }); + + const [isVisible, setIsVisible] = useState(false); + + useEffect(() => { + if (intersection && intersection.intersectionRatio > 0.25) { + setIsVisible(true); + } + }, [intersection, intersection?.intersectionRatio]); + + return isVisible ? ( + children + ) : ( +
+ +
+ ); +} diff --git a/x-pack/plugins/observability_shared/public/components/navigation_warning_prompt/context.tsx b/x-pack/plugins/observability_shared/public/components/navigation_warning_prompt/context.tsx new file mode 100644 index 0000000000000..73e0502890728 --- /dev/null +++ b/x-pack/plugins/observability_shared/public/components/navigation_warning_prompt/context.tsx @@ -0,0 +1,32 @@ +/* + * 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, { useState, PropsWithChildren } from 'react'; +import { createContext, useContext } from 'react'; + +interface ContextValues { + prompt?: string; + setPrompt: (prompt: string | undefined) => void; +} + +export const NavigationWarningPromptContext = createContext({ + setPrompt: (prompt: string | undefined) => {}, +}); + +export const useNavigationWarningPrompt = () => { + return useContext(NavigationWarningPromptContext); +}; + +export function NavigationWarningPromptProvider({ children }: PropsWithChildren<{}>) { + const [prompt, setPrompt] = useState(undefined); + + return ( + + {children} + + ); +} diff --git a/x-pack/plugins/observability_shared/public/components/navigation_warning_prompt/index.ts b/x-pack/plugins/observability_shared/public/components/navigation_warning_prompt/index.ts new file mode 100644 index 0000000000000..52e14b066a72c --- /dev/null +++ b/x-pack/plugins/observability_shared/public/components/navigation_warning_prompt/index.ts @@ -0,0 +1,9 @@ +/* + * 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. + */ + +export * from './context'; +export * from './prompt'; diff --git a/x-pack/plugins/observability_shared/public/components/navigation_warning_prompt/prompt.tsx b/x-pack/plugins/observability_shared/public/components/navigation_warning_prompt/prompt.tsx new file mode 100644 index 0000000000000..4ef6e6032d141 --- /dev/null +++ b/x-pack/plugins/observability_shared/public/components/navigation_warning_prompt/prompt.tsx @@ -0,0 +1,26 @@ +/* + * 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, { useEffect } from 'react'; +import { useNavigationWarningPrompt } from './context'; + +interface Props { + prompt?: string; +} + +export const Prompt: React.FC = ({ prompt }) => { + const { setPrompt } = useNavigationWarningPrompt(); + + useEffect(() => { + setPrompt(prompt); + return () => { + setPrompt(undefined); + }; + }, [prompt, setPrompt]); + + return null; +}; diff --git a/x-pack/plugins/observability_shared/public/components/section/section.tsx b/x-pack/plugins/observability_shared/public/components/section/section.tsx new file mode 100644 index 0000000000000..44d49c526312e --- /dev/null +++ b/x-pack/plugins/observability_shared/public/components/section/section.tsx @@ -0,0 +1,63 @@ +/* + * 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 { + EuiText, + EuiListGroup, + EuiSpacer, + EuiListGroupItem, + EuiListGroupItemProps, +} from '@elastic/eui'; +import React, { ReactNode } from 'react'; +import styled from 'styled-components'; +import { EuiListGroupProps } from '@elastic/eui'; + +export function SectionTitle({ children }: { children?: ReactNode }) { + return ( + <> + +
{children}
+
+ + + ); +} + +export function SectionSubtitle({ children }: { children?: ReactNode }) { + return ( + <> + + {children} + + + + ); +} + +export function SectionLinks({ children, ...props }: { children?: ReactNode } & EuiListGroupProps) { + return ( + + {children} + + ); +} + +export function SectionSpacer() { + return ; +} + +export const Section = styled.div` + margin-bottom: 16px; + &:last-of-type { + margin-bottom: 0; + } +`; + +export type SectionLinkProps = EuiListGroupItemProps; +export function SectionLink(props: SectionLinkProps) { + return ; +} diff --git a/x-pack/plugins/observability_shared/public/hooks/use_chart_theme.tsx b/x-pack/plugins/observability_shared/public/hooks/use_chart_theme.tsx new file mode 100644 index 0000000000000..87e9e61036a71 --- /dev/null +++ b/x-pack/plugins/observability_shared/public/hooks/use_chart_theme.tsx @@ -0,0 +1,42 @@ +/* + * 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 { PartialTheme } from '@elastic/charts'; +import { EUI_CHARTS_THEME_DARK, EUI_CHARTS_THEME_LIGHT } from '@elastic/eui/dist/eui_charts_theme'; +import { useMemo } from 'react'; +import { useTheme } from './use_theme'; + +export function useChartTheme(): PartialTheme[] { + const theme = useTheme(); + const baseChartTheme = theme.darkMode + ? EUI_CHARTS_THEME_DARK.theme + : EUI_CHARTS_THEME_LIGHT.theme; + + return useMemo( + () => [ + { + chartMargins: { + left: 10, + right: 10, + top: 35, + bottom: 10, + }, + background: { + color: 'transparent', + }, + lineSeriesStyle: { + point: { visible: false }, + }, + areaSeriesStyle: { + point: { visible: false }, + }, + }, + baseChartTheme, + ], + [baseChartTheme] + ); +} diff --git a/x-pack/plugins/observability_shared/public/hooks/use_kibana_ui_settings.ts b/x-pack/plugins/observability_shared/public/hooks/use_kibana_ui_settings.ts new file mode 100644 index 0000000000000..f448e07125d8b --- /dev/null +++ b/x-pack/plugins/observability_shared/public/hooks/use_kibana_ui_settings.ts @@ -0,0 +1,21 @@ +/* + * 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 { UI_SETTINGS } from '@kbn/data-plugin/public'; +import { useKibana } from '@kbn/kibana-react-plugin/public'; + +export { UI_SETTINGS }; + +type SettingKeys = keyof typeof UI_SETTINGS; +type SettingValues = typeof UI_SETTINGS[SettingKeys]; + +export function useKibanaUISettings(key: SettingValues): T { + const { + services: { uiSettings }, + } = useKibana(); + return uiSettings!.get(key); +} diff --git a/x-pack/plugins/observability_shared/public/hooks/use_link_props.test.tsx b/x-pack/plugins/observability_shared/public/hooks/use_link_props.test.tsx new file mode 100644 index 0000000000000..43650406cc929 --- /dev/null +++ b/x-pack/plugins/observability_shared/public/hooks/use_link_props.test.tsx @@ -0,0 +1,183 @@ +/* + * 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 { renderHook } from '@testing-library/react-hooks'; +import { createMemoryHistory } from 'history'; +import React, { PropsWithChildren } from 'react'; +import { Router } from 'react-router-dom'; +import { encode } from '@kbn/rison'; +import { coreMock } from '@kbn/core/public/mocks'; +import { CoreScopedHistory } from '@kbn/core/public'; +import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; +import { LinkDescriptor, useLinkProps } from './use_link_props'; + +const PREFIX = '/test-basepath/s/test-space/app/'; + +const coreStartMock = coreMock.createStart(); + +coreStartMock.application.getUrlForApp.mockImplementation((app, options) => { + return `${PREFIX}${app}${options?.path}`; +}); + +const INTERNAL_APP = 'metrics'; + +const history = createMemoryHistory(); +history.push(`${PREFIX}${INTERNAL_APP}`); +const scopedHistory = new CoreScopedHistory(history, `${PREFIX}${INTERNAL_APP}`); + +function ProviderWrapper({ children }: PropsWithChildren<{}>) { + return ( + + {children}; + + ); +} + +const renderUseLinkPropsHook = (props?: Partial) => { + return renderHook(() => useLinkProps({ app: INTERNAL_APP, ...props }), { + wrapper: ProviderWrapper, + }); +}; +describe('useLinkProps hook', () => { + describe('Handles internal linking', () => { + it('Provides the correct baseline props', () => { + const { result } = renderUseLinkPropsHook({ pathname: '/' }); + expect(result.current.href).toBe('/test-basepath/s/test-space/app/metrics/'); + expect(result.current.onClick).toBeDefined(); + }); + + it('Provides the correct props with options', () => { + const { result } = renderUseLinkPropsHook({ + pathname: '/inventory', + search: { + type: 'host', + id: 'some-id', + count: '12345', + }, + }); + expect(result.current.href).toBe( + '/test-basepath/s/test-space/app/metrics/inventory?type=host&id=some-id&count=12345' + ); + expect(result.current.onClick).toBeDefined(); + }); + + it('Provides the correct props with more complex encoding', () => { + const { result } = renderUseLinkPropsHook({ + pathname: '/inventory', + search: { + type: 'host + host', + name: 'this name has spaces and ** and %', + id: 'some-id', + count: '12345', + animals: ['dog', 'cat', 'bear'], + }, + }); + expect(result.current.href).toBe( + '/test-basepath/s/test-space/app/metrics/inventory?type=host%20%2B%20host&name=this%20name%20has%20spaces%20and%20**%20and%20%25&id=some-id&count=12345&animals=dog,cat,bear' + ); + expect(result.current.onClick).toBeDefined(); + }); + + it('Provides the correct props with a consumer using Rison encoding for search', () => { + const state = { + refreshInterval: { pause: true, value: 0 }, + time: { from: 12345, to: 54321 }, + }; + const { result } = renderUseLinkPropsHook({ + pathname: '/inventory', + search: { + type: 'host + host', + state: encode(state), + }, + }); + expect(result.current.href).toBe( + '/test-basepath/s/test-space/app/metrics/inventory?type=host%20%2B%20host&state=(refreshInterval:(pause:!t,value:0),time:(from:12345,to:54321))' + ); + expect(result.current.onClick).toBeDefined(); + }); + }); + + describe('Handles external linking', () => { + it('Provides the correct baseline props', () => { + const { result } = renderUseLinkPropsHook({ + app: 'ml', + pathname: '/', + }); + expect(result.current.href).toBe('/test-basepath/s/test-space/app/ml/'); + expect(result.current.onClick).toBeDefined(); + }); + + it('Provides the correct props with pathname options', () => { + const { result } = renderUseLinkPropsHook({ + app: 'ml', + pathname: '/explorer', + search: { + type: 'host', + id: 'some-id', + count: '12345', + }, + }); + expect(result.current.href).toBe( + '/test-basepath/s/test-space/app/ml/explorer?type=host&id=some-id&count=12345' + ); + expect(result.current.onClick).toBeDefined(); + }); + + it('Provides the correct props with hash options', () => { + const { result } = renderUseLinkPropsHook({ + app: 'ml', + pathname: '/explorer', + search: { + type: 'host', + id: 'some-id', + count: '12345', + }, + }); + expect(result.current.href).toBe( + '/test-basepath/s/test-space/app/ml/explorer?type=host&id=some-id&count=12345' + ); + expect(result.current.onClick).toBeDefined(); + }); + + it('Provides the correct props with more complex encoding', () => { + const { result } = renderUseLinkPropsHook({ + app: 'ml', + pathname: '/explorer', + search: { + type: 'host + host', + name: 'this name has spaces and ** and %', + id: 'some-id', + count: '12345', + animals: ['dog', 'cat', 'bear'], + }, + }); + expect(result.current.href).toBe( + '/test-basepath/s/test-space/app/ml/explorer?type=host%20%2B%20host&name=this%20name%20has%20spaces%20and%20**%20and%20%25&id=some-id&count=12345&animals=dog,cat,bear' + ); + expect(result.current.onClick).toBeDefined(); + }); + + it('Provides the correct props with a consumer using Rison encoding for search', () => { + const state = { + refreshInterval: { pause: true, value: 0 }, + time: { from: 12345, to: 54321 }, + }; + const { result } = renderUseLinkPropsHook({ + app: 'rison-app', + hash: 'rison-route', + search: { + type: 'host + host', + state: encode(state), + }, + }); + expect(result.current.href).toBe( + '/test-basepath/s/test-space/app/rison-app#rison-route?type=host%20%2B%20host&state=(refreshInterval:(pause:!t,value:0),time:(from:12345,to:54321))' + ); + expect(result.current.onClick).toBeDefined(); + }); + }); +}); diff --git a/x-pack/plugins/observability_shared/public/hooks/use_link_props.ts b/x-pack/plugins/observability_shared/public/hooks/use_link_props.ts new file mode 100644 index 0000000000000..f230a7097cf6d --- /dev/null +++ b/x-pack/plugins/observability_shared/public/hooks/use_link_props.ts @@ -0,0 +1,125 @@ +/* + * 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 { useMemo } from 'react'; +import { stringify } from 'query-string'; +import { url as urlUtils } from '@kbn/kibana-utils-plugin/public'; +import { useKibana } from '@kbn/kibana-react-plugin/public'; +import { usePrefixPathWithBasepath } from './use_prefix_path_with_basepath'; +import { useNavigationWarningPrompt } from '../components/navigation_warning_prompt'; + +type Search = Record; + +export interface LinkDescriptor { + app: string; + pathname?: string; + hash?: string; + search?: Search; +} + +export interface LinkProps { + href?: string; + onClick?: (e: React.MouseEvent | React.MouseEvent) => void; +} + +export interface Options { + hrefOnly?: boolean; +} + +export const useLinkProps = ( + { app, pathname, hash, search }: LinkDescriptor, + options: Options = {} +): LinkProps => { + validateParams({ app, pathname, hash, search }); + + const { prompt } = useNavigationWarningPrompt(); + const prefixer = usePrefixPathWithBasepath(); + const navigateToApp = useKibana().services.application?.navigateToApp; + const { hrefOnly } = options; + + const encodedSearch = useMemo(() => { + return search ? encodeSearch(search) : undefined; + }, [search]); + + const mergedHash = useMemo(() => { + // The URI spec defines that the query should appear before the fragment + // https://tools.ietf.org/html/rfc3986#section-3 (e.g. url.format()). However, in Kibana, apps that use + // hash based routing expect the query to be part of the hash. This will handle that. + return hash && encodedSearch ? `${hash}?${encodedSearch}` : hash; + }, [hash, encodedSearch]); + + const mergedPathname = useMemo(() => { + return pathname && encodedSearch ? `${pathname}?${encodedSearch}` : pathname; + }, [pathname, encodedSearch]); + + const href = useMemo(() => { + const builtPathname = pathname ?? ''; + const builtHash = mergedHash ? `#${mergedHash}` : ''; + const builtSearch = !hash ? (encodedSearch ? `?${encodedSearch}` : '') : ''; + + const link = `${builtPathname}${builtSearch}${builtHash}`; + + return prefixer(app, link); + }, [mergedHash, hash, encodedSearch, pathname, prefixer, app]); + + const onClick = useMemo(() => { + return (e: React.MouseEvent | React.MouseEvent) => { + if (!shouldHandleLinkEvent(e)) { + return; + } + + e.preventDefault(); + + const navigate = () => { + if (navigateToApp) { + const navigationPath = mergedHash ? `#${mergedHash}` : mergedPathname; + navigateToApp(app, { path: navigationPath ? navigationPath : undefined }); + } + }; + + // A component somewhere within the app hierarchy is requesting that we + // prompt the user before navigating. + if (prompt) { + const wantsToNavigate = window.confirm(prompt); + if (wantsToNavigate) { + navigate(); + } else { + return; + } + } else { + navigate(); + } + }; + }, [navigateToApp, mergedHash, mergedPathname, app, prompt]); + + return { + href, + // Sometimes it may not be desirable to have onClick call "navigateToApp". + // E.g. the management section of Kibana cannot be successfully deeplinked to via + // "navigateToApp". In those cases we can choose to defer to legacy behaviour. + onClick: hrefOnly ? undefined : onClick, + }; +}; + +const encodeSearch = (search: Search) => { + return stringify(urlUtils.encodeQuery(search), { sort: false, encode: false }); +}; + +const validateParams = ({ app, pathname, hash, search }: LinkDescriptor) => { + if (!app && hash) { + throw new Error( + 'The metrics and logs apps use browserHistory. Please provide a pathname rather than a hash.' + ); + } +}; + +const isModifiedEvent = (event: any) => + !!(event.metaKey || event.altKey || event.ctrlKey || event.shiftKey); + +export const shouldHandleLinkEvent = ( + e: React.MouseEvent | React.MouseEvent +) => !e.defaultPrevented && !isModifiedEvent(e); diff --git a/x-pack/plugins/observability_shared/public/hooks/use_prefix_path_with_basepath.tsx b/x-pack/plugins/observability_shared/public/hooks/use_prefix_path_with_basepath.tsx new file mode 100644 index 0000000000000..05fde570878da --- /dev/null +++ b/x-pack/plugins/observability_shared/public/hooks/use_prefix_path_with_basepath.tsx @@ -0,0 +1,23 @@ +/* + * 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 { useMemo } from 'react'; +import { useKibana } from '@kbn/kibana-react-plugin/public'; + +export const usePrefixPathWithBasepath = () => { + const getUrlForApp = useKibana().services.application?.getUrlForApp; + const prefixer = useMemo(() => { + if (!getUrlForApp) { + throw new Error('Application core service is unavailable'); + } + + return (app: string, path: string) => { + return getUrlForApp(app, { path }); + }; + }, [getUrlForApp]); + return prefixer; +}; diff --git a/x-pack/plugins/observability_shared/public/hooks/use_time_zone.ts b/x-pack/plugins/observability_shared/public/hooks/use_time_zone.ts new file mode 100644 index 0000000000000..0e7a8cf7c6a7e --- /dev/null +++ b/x-pack/plugins/observability_shared/public/hooks/use_time_zone.ts @@ -0,0 +1,21 @@ +/* + * 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 { useUiSetting } from '@kbn/kibana-react-plugin/public'; +import moment from 'moment-timezone'; + +export const useTimeZone = () => { + const timeZone = useUiSetting('dateFormat:tz'); + + const localTZ = moment.tz.guess(); + + if (!timeZone || timeZone === 'Browser') { + return localTZ; + } + + return timeZone; +}; diff --git a/x-pack/plugins/observability_shared/public/index.ts b/x-pack/plugins/observability_shared/public/index.ts index 274f894150653..6bf3b67716a91 100644 --- a/x-pack/plugins/observability_shared/public/index.ts +++ b/x-pack/plugins/observability_shared/public/index.ts @@ -11,38 +11,38 @@ export type { ObservabilitySharedPluginSetup, ObservabilitySharedPluginStart, } from './plugin'; +export const plugin = () => { + return new ObservabilitySharedPlugin(); +}; export type { ObservabilityPageTemplateProps, LazyObservabilityPageTemplateProps, + NavigationSection, } from './components/page_template/page_template'; - export type { NavigationEntry } from './components/page_template/page_template'; export { HeaderMenuPortal } from './components/header_menu'; - -export { - type ObservabilityActionContextMenuItemProps, - getContextMenuItemsFromActions, -} from './services/get_context_menu_items_from_actions'; - -export { useObservabilityTourContext } from './components/tour'; - -export const plugin = () => { - return new ObservabilitySharedPlugin(); -}; - +export { useObservabilityTourContext, observTourStepStorageKey } from './components/tour'; +export { ActionMenu, ActionMenuDivider } from './components/action_menu/action_menu'; export { - observabilityFeatureId, - observabilityAppId, - casesFeatureId, - sloFeatureId, -} from '../common'; + Section, + SectionLink, + SectionLinks, + SectionSpacer, + SectionSubtitle, + SectionTitle, +} from './components/section/section'; +export type { SectionLinkProps } from './components/section/section'; +export { LoadWhenInView } from './components/load_when_in_view/get_load_when_in_view_lazy'; -export { useTheme } from './hooks/use_theme'; export { InspectorContextProvider } from './contexts/inspector/inspector_context'; +export type { AddInspectorRequest } from './contexts/inspector/inspector_context'; export { useInspectorContext } from './contexts/inspector/use_inspector_context'; + +export { useTheme } from './hooks/use_theme'; export { useEsSearch, createEsParams } from './hooks/use_es_search'; export { useFetcher, FETCH_STATUS } from './hooks/use_fetcher'; +export type { FetcherResult } from './hooks/use_fetcher'; export { useKibanaSpace } from './hooks/use_kibana_space'; export { useBreadcrumbs } from './hooks/use_breadcrumbs'; export { @@ -54,6 +54,24 @@ export { export type { TrackEvent } from './hooks/use_track_metric'; export { useQuickTimeRanges } from './hooks/use_quick_time_ranges'; export { useGetUserCasesPermissions } from './hooks/use_get_user_cases_permissions'; +export { useTimeZone } from './hooks/use_time_zone'; +export { useChartTheme } from './hooks/use_chart_theme'; +export { useLinkProps, shouldHandleLinkEvent } from './hooks/use_link_props'; +export type { LinkDescriptor, Options as UseLinkPropsOptions } from './hooks/use_link_props'; +export { NavigationWarningPromptProvider, Prompt } from './components/navigation_warning_prompt'; export type { ApmIndicesConfig, UXMetrics } from './types'; + export { noCasesPermissions } from './utils/cases_permissions'; + +export { + type ObservabilityActionContextMenuItemProps, + getContextMenuItemsFromActions, +} from './services/get_context_menu_items_from_actions'; + +export { + observabilityFeatureId, + observabilityAppId, + casesFeatureId, + sloFeatureId, +} from '../common'; diff --git a/x-pack/plugins/observability_shared/tsconfig.json b/x-pack/plugins/observability_shared/tsconfig.json index cfaa7b9ea6c7d..fdc6df3fe3158 100644 --- a/x-pack/plugins/observability_shared/tsconfig.json +++ b/x-pack/plugins/observability_shared/tsconfig.json @@ -29,6 +29,8 @@ "@kbn/spaces-plugin", "@kbn/core-application-browser", "@kbn/datemath", + "@kbn/rison", + "@kbn/kibana-utils-plugin", ], "exclude": ["target/**/*"] }