mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
Refactor Observability Overview Page (#146182)
This commit is contained in:
parent
55ca52ddb7
commit
dd86c7f25c
8 changed files with 350 additions and 276 deletions
|
@ -31,7 +31,7 @@ export function NewsFeed({ items }: Props) {
|
|||
// The news feed is manually added/edited, to prevent any errors caused by typos or missing fields,
|
||||
// wraps the component with EuiErrorBoundary to avoid breaking the entire page.
|
||||
<EuiErrorBoundary>
|
||||
<EuiFlexGrid direction="column" gutterSize="s">
|
||||
<EuiFlexGrid direction="row" gutterSize="s" alignItems="start">
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiTitle size="xs">
|
||||
<h4>
|
||||
|
@ -58,7 +58,7 @@ function NewsItem({ item }: { item: INewsItem }) {
|
|||
|
||||
return (
|
||||
<EuiPanel hasBorder={true}>
|
||||
<EuiFlexGrid direction="column" gutterSize="s">
|
||||
<EuiFlexGrid direction="row" gutterSize="s">
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiTitle size="xxs">
|
||||
<h4>{item.title.en}</h4>
|
||||
|
|
|
@ -42,7 +42,7 @@ const resources = [
|
|||
|
||||
export function Resources() {
|
||||
return (
|
||||
<EuiFlexGrid direction="column">
|
||||
<EuiFlexGrid direction="row">
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiTitle size="xs">
|
||||
<h4>
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* 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 {
|
||||
EuiFlyout,
|
||||
EuiFlyoutHeader,
|
||||
EuiTitle,
|
||||
EuiSpacer,
|
||||
EuiText,
|
||||
EuiFlyoutBody,
|
||||
} from '@elastic/eui';
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
import { ObservabilityStatus } from '../../../components/app/observability_status';
|
||||
|
||||
interface DataAsssistantFlyoutProps {
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
export function DataAssistantFlyout({ onClose }: DataAsssistantFlyoutProps) {
|
||||
return (
|
||||
<EuiFlyout
|
||||
ownFocus
|
||||
aria-labelledby="statusVisualizationFlyoutTitle"
|
||||
className="oblt__flyout"
|
||||
size="s"
|
||||
onClose={onClose}
|
||||
>
|
||||
<EuiFlyoutHeader hasBorder>
|
||||
<EuiTitle size="m">
|
||||
<h2 id="statusVisualizationFlyoutTitle" data-test-subj="statusVisualizationFlyoutTitle">
|
||||
<FormattedMessage
|
||||
id="xpack.observability.overview.statusVisualizationFlyoutTitle"
|
||||
defaultMessage="Data assistant"
|
||||
/>
|
||||
</h2>
|
||||
</EuiTitle>
|
||||
<EuiSpacer size="s" />
|
||||
<EuiText size="s">
|
||||
<p>
|
||||
<FormattedMessage
|
||||
id="xpack.observability.overview.statusVisualizationFlyoutDescription"
|
||||
defaultMessage="Track your progress towards adding observability integrations and features."
|
||||
/>
|
||||
</p>
|
||||
</EuiText>
|
||||
</EuiFlyoutHeader>
|
||||
<EuiFlyoutBody>
|
||||
<ObservabilityStatus />
|
||||
</EuiFlyoutBody>
|
||||
</EuiFlyout>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,110 @@
|
|||
/*
|
||||
* 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, { useRef } from 'react';
|
||||
import {
|
||||
EuiButton,
|
||||
EuiButtonEmpty,
|
||||
EuiFlexGroup,
|
||||
EuiFlexItem,
|
||||
EuiText,
|
||||
EuiTourStep,
|
||||
} from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
|
||||
import { DatePicker } from '../../../components/shared/date_picker';
|
||||
import { useDatePickerContext } from '../../../hooks/use_date_picker_context';
|
||||
import { useObservabilityTourContext } from '../../../components/shared/tour';
|
||||
|
||||
export interface HeaderActionsProps {
|
||||
showTour?: boolean;
|
||||
onGuidedSetupClick: () => void;
|
||||
onTimeRangeRefresh: () => void;
|
||||
onTourDismiss: () => void;
|
||||
}
|
||||
|
||||
export function HeaderActions({
|
||||
showTour = false,
|
||||
onGuidedSetupClick,
|
||||
onTimeRangeRefresh,
|
||||
onTourDismiss,
|
||||
}: HeaderActionsProps) {
|
||||
const buttonRef = useRef();
|
||||
|
||||
const { relativeStart, relativeEnd, refreshInterval, refreshPaused } = useDatePickerContext();
|
||||
|
||||
const { endTour, isTourVisible } = useObservabilityTourContext();
|
||||
|
||||
return (
|
||||
<EuiFlexGroup direction="row" gutterSize="s" justifyContent="flexEnd">
|
||||
<EuiFlexItem grow={false}>
|
||||
<DatePicker
|
||||
rangeFrom={relativeStart}
|
||||
rangeTo={relativeEnd}
|
||||
refreshInterval={refreshInterval}
|
||||
refreshPaused={refreshPaused}
|
||||
width="auto"
|
||||
onTimeRangeRefresh={onTimeRangeRefresh}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiButton
|
||||
// @ts-expect-error the EUI verson that kibana uses right now doesn't have the correct types
|
||||
buttonRef={buttonRef}
|
||||
color="text"
|
||||
data-test-subj="guidedSetupButton"
|
||||
id="guidedSetupButton"
|
||||
iconType="wrench"
|
||||
onClick={() => {
|
||||
if (isTourVisible) {
|
||||
endTour();
|
||||
}
|
||||
|
||||
onGuidedSetupClick();
|
||||
}}
|
||||
>
|
||||
<FormattedMessage
|
||||
id="xpack.observability.overview.guidedSetupButton"
|
||||
defaultMessage="Data assistant"
|
||||
/>
|
||||
</EuiButton>
|
||||
|
||||
{showTour ? (
|
||||
<EuiTourStep
|
||||
// @ts-expect-error the EUI verson that kibana uses right now doesn't have the correct types
|
||||
anchor={() => buttonRef.current}
|
||||
step={1}
|
||||
stepsTotal={1}
|
||||
isStepOpen
|
||||
maxWidth={400}
|
||||
onFinish={onTourDismiss}
|
||||
title={i18n.translate('xpack.observability.overview.guidedSetupTourTitle', {
|
||||
defaultMessage: 'Data assistant is always available',
|
||||
})}
|
||||
content={
|
||||
<EuiText size="s">
|
||||
<FormattedMessage
|
||||
id="xpack.observability.overview.guidedSetupTourContent"
|
||||
defaultMessage="If you're ever in doubt you can always access the data assistant and view your next steps by clicking here."
|
||||
/>
|
||||
</EuiText>
|
||||
}
|
||||
footerAction={
|
||||
<EuiButtonEmpty color="text" flush="right" size="xs" onClick={onTourDismiss}>
|
||||
<FormattedMessage
|
||||
id="xpack.observability.overview.guidedSetupTourDismissButton"
|
||||
defaultMessage="Dismiss"
|
||||
/>
|
||||
</EuiButtonEmpty>
|
||||
}
|
||||
/>
|
||||
) : null}
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
);
|
||||
}
|
|
@ -5,6 +5,8 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
export * from './data_assistant_flyout';
|
||||
export * from './data_sections';
|
||||
export * from './loading_observability';
|
||||
export * from './empty_section';
|
||||
export * from './header_actions';
|
||||
export * from './loading_observability';
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* 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 { useEffect } from 'react';
|
||||
import { useKibana } from '@kbn/kibana-react-plugin/public';
|
||||
|
||||
import { useTrackPageview } from '../../../../..';
|
||||
import { useUiTracker } from '../../../../../hooks/use_track_metric';
|
||||
import { ObservabilityAppServices } from '../../../../../application/types';
|
||||
import { CAPABILITIES_KEYS } from '../constants';
|
||||
|
||||
export const useOverviewMetrics = ({ hasAnyData }: { hasAnyData: boolean | undefined }) => {
|
||||
const {
|
||||
application: { capabilities },
|
||||
} = useKibana<ObservabilityAppServices>().services;
|
||||
|
||||
const trackMetric = useUiTracker({ app: 'observability-overview' });
|
||||
|
||||
useTrackPageview({ app: 'observability-overview', path: 'overview' });
|
||||
useTrackPageview({ app: 'observability-overview', path: 'overview', delay: 15000 });
|
||||
|
||||
useEffect(() => {
|
||||
if (hasAnyData !== true) {
|
||||
return;
|
||||
}
|
||||
|
||||
CAPABILITIES_KEYS.forEach((feature) => {
|
||||
if (capabilities[feature].show === false) {
|
||||
trackMetric({
|
||||
metric: `oblt_disabled_feature_${feature === 'infrastructure' ? 'metrics' : feature}`,
|
||||
});
|
||||
}
|
||||
});
|
||||
}, [capabilities, hasAnyData, trackMetric]);
|
||||
|
||||
return {
|
||||
trackMetric,
|
||||
};
|
||||
};
|
|
@ -5,60 +5,56 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import {
|
||||
EuiButton,
|
||||
EuiButtonEmpty,
|
||||
EuiFlexGroup,
|
||||
EuiFlexItem,
|
||||
EuiFlyout,
|
||||
EuiFlyoutSize,
|
||||
EuiFlyoutBody,
|
||||
EuiFlyoutHeader,
|
||||
EuiHorizontalRule,
|
||||
EuiSpacer,
|
||||
EuiText,
|
||||
EuiTitle,
|
||||
EuiTourStep,
|
||||
} from '@elastic/eui';
|
||||
import { EuiFlexGroup, EuiFlexItem, EuiHorizontalRule, EuiSpacer } from '@elastic/eui';
|
||||
import { BoolQuery } from '@kbn/es-query';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
import { useKibana } from '@kbn/kibana-react-plugin/public';
|
||||
import { AlertConsumers } from '@kbn/rule-data-utils';
|
||||
import React, { useMemo, useRef, useCallback, useState, useEffect } from 'react';
|
||||
import React, { useMemo, useRef, useCallback, useState } from 'react';
|
||||
|
||||
import { calculateBucketSize } from './helpers';
|
||||
import { HeaderActionsProps } from './types';
|
||||
|
||||
import { EmptySections } from '../../../../components/app/empty_sections';
|
||||
import { observabilityFeatureId } from '../../../../../common';
|
||||
import { useTrackPageview, useUiTracker } from '../../../..';
|
||||
import { ObservabilityHeaderMenu } from '../../../../components/app/header';
|
||||
import { NewsFeed } from '../../../../components/app/news_feed';
|
||||
import { Resources } from '../../../../components/app/resources';
|
||||
import { DatePicker } from '../../../../components/shared/date_picker';
|
||||
import { useBreadcrumbs } from '../../../../hooks/use_breadcrumbs';
|
||||
import { useFetcher } from '../../../../hooks/use_fetcher';
|
||||
import { useHasData } from '../../../../hooks/use_has_data';
|
||||
import { usePluginContext } from '../../../../hooks/use_plugin_context';
|
||||
import { buildEsQuery } from '../../../../utils/build_es_query';
|
||||
import { getNewsFeed } from '../../../../services/get_news_feed';
|
||||
import { DataSections, LoadingObservability } from '../../components';
|
||||
|
||||
import {
|
||||
DataSections,
|
||||
LoadingObservability,
|
||||
HeaderActions,
|
||||
DataAssistantFlyout,
|
||||
} from '../../components';
|
||||
import { EmptySections } from '../../../../components/app/empty_sections';
|
||||
import { ObservabilityHeaderMenu } from '../../../../components/app/header';
|
||||
import { Resources } from '../../../../components/app/resources';
|
||||
import { NewsFeed } from '../../../../components/app/news_feed';
|
||||
import { SectionContainer } from '../../../../components/app/section';
|
||||
import { ObservabilityAppServices } from '../../../../application/types';
|
||||
import { useGetUserCasesPermissions } from '../../../../hooks/use_get_user_cases_permissions';
|
||||
import { paths } from '../../../../config';
|
||||
import { useDatePickerContext } from '../../../../hooks/use_date_picker_context';
|
||||
import { ObservabilityStatusProgress } from '../../../../components/app/observability_status/observability_status_progress';
|
||||
import { ObservabilityStatus } from '../../../../components/app/observability_status';
|
||||
|
||||
import { useBreadcrumbs } from '../../../../hooks/use_breadcrumbs';
|
||||
import { useDatePickerContext } from '../../../../hooks/use_date_picker_context';
|
||||
import { useFetcher } from '../../../../hooks/use_fetcher';
|
||||
import { useGetUserCasesPermissions } from '../../../../hooks/use_get_user_cases_permissions';
|
||||
import { useGuidedSetupProgress } from '../../../../hooks/use_guided_setup_progress';
|
||||
import { useObservabilityTourContext } from '../../../../components/shared/tour';
|
||||
import { CAPABILITIES_KEYS, ALERTS_PER_PAGE, ALERTS_TABLE_ID } from './constants';
|
||||
import { useHasData } from '../../../../hooks/use_has_data';
|
||||
import { useOverviewMetrics } from './helpers/use_metrics';
|
||||
import { usePluginContext } from '../../../../hooks/use_plugin_context';
|
||||
|
||||
import { observabilityFeatureId } from '../../../../../common';
|
||||
import { observabilityAlertFeatureIds, paths } from '../../../../config';
|
||||
import { ALERTS_PER_PAGE, ALERTS_TABLE_ID } from './constants';
|
||||
|
||||
import type { ObservabilityAppServices } from '../../../../application/types';
|
||||
|
||||
export function OverviewPage() {
|
||||
const trackMetric = useUiTracker({ app: 'observability-overview' });
|
||||
useTrackPageview({ app: 'observability-overview', path: 'overview' });
|
||||
useTrackPageview({ app: 'observability-overview', path: 'overview', delay: 15000 });
|
||||
const {
|
||||
cases: {
|
||||
ui: { getCasesContext },
|
||||
},
|
||||
http,
|
||||
triggersActionsUi: { alertsTableConfigurationRegistry, getAlertsStateTable: AlertsStateTable },
|
||||
} = useKibana<ObservabilityAppServices>().services;
|
||||
|
||||
const { ObservabilityPageTemplate } = usePluginContext();
|
||||
|
||||
useBreadcrumbs([
|
||||
{
|
||||
text: i18n.translate('xpack.observability.breadcrumbs.overviewLinkText', {
|
||||
|
@ -66,17 +62,23 @@ export function OverviewPage() {
|
|||
}),
|
||||
},
|
||||
]);
|
||||
const [isFlyoutVisible, setIsFlyoutVisible] = useState(false);
|
||||
|
||||
const {
|
||||
cases,
|
||||
http,
|
||||
application: { capabilities },
|
||||
triggersActionsUi: { alertsTableConfigurationRegistry, getAlertsStateTable: AlertsStateTable },
|
||||
} = useKibana<ObservabilityAppServices>().services;
|
||||
const { data: newsFeed } = useFetcher(() => getNewsFeed({ http }), [http]);
|
||||
const { hasAnyData, isAllRequestsComplete } = useHasData();
|
||||
const refetch = useRef<() => void>();
|
||||
|
||||
const { trackMetric } = useOverviewMetrics({ hasAnyData });
|
||||
|
||||
const CasesContext = getCasesContext();
|
||||
const userCasesPermissions = useGetUserCasesPermissions();
|
||||
|
||||
const [isDataAssistantFlyoutVisible, setIsDataAssistantFlyoutVisible] = useState(false);
|
||||
|
||||
const { isGuidedSetupProgressDismissed } = useGuidedSetupProgress();
|
||||
const [isGuidedSetupTourVisible, setGuidedSetupTourVisible] = useState(false);
|
||||
|
||||
const { ObservabilityPageTemplate } = usePluginContext();
|
||||
const { relativeStart, relativeEnd, absoluteStart, absoluteEnd } = useDatePickerContext();
|
||||
|
||||
const [esQuery, setEsQuery] = useState<{ bool: BoolQuery }>(
|
||||
buildEsQuery({
|
||||
from: relativeStart,
|
||||
|
@ -84,15 +86,6 @@ export function OverviewPage() {
|
|||
})
|
||||
);
|
||||
|
||||
const { data: newsFeed } = useFetcher(() => getNewsFeed({ http }), [http]);
|
||||
|
||||
const { hasAnyData, isAllRequestsComplete } = useHasData();
|
||||
const refetch = useRef<() => void>();
|
||||
|
||||
const [isGuidedSetupTourVisible, setGuidedSetupTourVisible] = useState(false);
|
||||
const hideGuidedSetupTour = useCallback(() => setGuidedSetupTourVisible(false), []);
|
||||
const { isGuidedSetupProgressDismissed } = useGuidedSetupProgress();
|
||||
|
||||
const bucketSize = useMemo(
|
||||
() =>
|
||||
calculateBucketSize({
|
||||
|
@ -102,15 +95,7 @@ export function OverviewPage() {
|
|||
[absoluteStart, absoluteEnd]
|
||||
);
|
||||
|
||||
const handleGuidedSetupClick = useCallback(() => {
|
||||
if (isGuidedSetupProgressDismissed) {
|
||||
trackMetric({ metric: 'guided_setup_view_details_after_dismiss' });
|
||||
}
|
||||
hideGuidedSetupTour();
|
||||
setIsFlyoutVisible(true);
|
||||
}, [trackMetric, isGuidedSetupProgressDismissed, hideGuidedSetupTour]);
|
||||
|
||||
const onTimeRangeRefresh = useCallback(() => {
|
||||
const handleTimeRangeRefresh = useCallback(() => {
|
||||
setEsQuery(
|
||||
buildEsQuery({
|
||||
from: relativeStart,
|
||||
|
@ -120,29 +105,24 @@ export function OverviewPage() {
|
|||
return refetch.current && refetch.current();
|
||||
}, [relativeEnd, relativeStart]);
|
||||
|
||||
const CasesContext = cases.ui.getCasesContext();
|
||||
const userCasesPermissions = useGetUserCasesPermissions();
|
||||
const handleCloseGuidedSetupTour = () => {
|
||||
setGuidedSetupTourVisible(false);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (hasAnyData !== true) {
|
||||
return;
|
||||
const handleGuidedSetupClick = useCallback(() => {
|
||||
if (isGuidedSetupProgressDismissed) {
|
||||
trackMetric({ metric: 'guided_setup_view_details_after_dismiss' });
|
||||
}
|
||||
|
||||
CAPABILITIES_KEYS.forEach((feature) => {
|
||||
if (capabilities[feature].show === false) {
|
||||
trackMetric({
|
||||
metric: `oblt_disabled_feature_${feature === 'infrastructure' ? 'metrics' : feature}`,
|
||||
});
|
||||
}
|
||||
});
|
||||
}, [capabilities, hasAnyData, trackMetric]);
|
||||
handleCloseGuidedSetupTour();
|
||||
|
||||
setIsDataAssistantFlyoutVisible(true);
|
||||
}, [trackMetric, isGuidedSetupProgressDismissed]);
|
||||
|
||||
if (hasAnyData === undefined) {
|
||||
return <LoadingObservability />;
|
||||
}
|
||||
|
||||
const alertsLink = paths.observability.alerts;
|
||||
|
||||
return (
|
||||
<ObservabilityPageTemplate
|
||||
isPageDataLoaded={isAllRequestsComplete}
|
||||
|
@ -153,194 +133,83 @@ export function OverviewPage() {
|
|||
rightSideItems: [
|
||||
<HeaderActions
|
||||
showTour={isGuidedSetupTourVisible}
|
||||
onTourDismiss={hideGuidedSetupTour}
|
||||
handleGuidedSetupClick={handleGuidedSetupClick}
|
||||
onTimeRangeRefresh={onTimeRangeRefresh}
|
||||
onGuidedSetupClick={handleGuidedSetupClick}
|
||||
onTourDismiss={handleCloseGuidedSetupTour}
|
||||
onTimeRangeRefresh={handleTimeRangeRefresh}
|
||||
/>,
|
||||
],
|
||||
rightSideGroupProps: {
|
||||
responsive: true,
|
||||
},
|
||||
}}
|
||||
>
|
||||
<>
|
||||
<ObservabilityHeaderMenu />
|
||||
<ObservabilityStatusProgress
|
||||
onViewDetailsClick={() => setIsFlyoutVisible(true)}
|
||||
onDismissClick={() => setGuidedSetupTourVisible(true)}
|
||||
/>
|
||||
<EuiFlexGroup direction="column" gutterSize="s">
|
||||
<EuiFlexItem>
|
||||
<SectionContainer
|
||||
initialIsOpen={hasAnyData}
|
||||
title={i18n.translate('xpack.observability.overview.alerts.title', {
|
||||
defaultMessage: 'Alerts',
|
||||
})}
|
||||
hasError={false}
|
||||
appLink={{
|
||||
href: alertsLink,
|
||||
label: i18n.translate('xpack.observability.overview.alerts.appLink', {
|
||||
defaultMessage: 'Show alerts',
|
||||
}),
|
||||
}}
|
||||
<ObservabilityHeaderMenu />
|
||||
|
||||
<ObservabilityStatusProgress
|
||||
onDismissClick={() => setGuidedSetupTourVisible(true)}
|
||||
onViewDetailsClick={() => setIsDataAssistantFlyoutVisible(true)}
|
||||
/>
|
||||
|
||||
<EuiFlexGroup direction="column" gutterSize="s">
|
||||
<EuiFlexItem>
|
||||
<SectionContainer
|
||||
title={i18n.translate('xpack.observability.overview.alerts.title', {
|
||||
defaultMessage: 'Alerts',
|
||||
})}
|
||||
appLink={{
|
||||
href: paths.observability.alerts,
|
||||
label: i18n.translate('xpack.observability.overview.alerts.appLink', {
|
||||
defaultMessage: 'Show alerts',
|
||||
}),
|
||||
}}
|
||||
initialIsOpen={hasAnyData}
|
||||
hasError={false}
|
||||
>
|
||||
<CasesContext
|
||||
owner={[observabilityFeatureId]}
|
||||
permissions={userCasesPermissions}
|
||||
features={{ alerts: { sync: false } }}
|
||||
>
|
||||
<CasesContext
|
||||
owner={[observabilityFeatureId]}
|
||||
permissions={userCasesPermissions}
|
||||
features={{ alerts: { sync: false } }}
|
||||
>
|
||||
<AlertsStateTable
|
||||
alertsTableConfigurationRegistry={alertsTableConfigurationRegistry}
|
||||
configurationId={AlertConsumers.OBSERVABILITY}
|
||||
id={ALERTS_TABLE_ID}
|
||||
flyoutSize={'s' as EuiFlyoutSize}
|
||||
featureIds={[
|
||||
AlertConsumers.APM,
|
||||
AlertConsumers.INFRASTRUCTURE,
|
||||
AlertConsumers.LOGS,
|
||||
AlertConsumers.UPTIME,
|
||||
]}
|
||||
query={esQuery}
|
||||
showExpandToDetails={false}
|
||||
pageSize={ALERTS_PER_PAGE}
|
||||
/>
|
||||
</CasesContext>
|
||||
</SectionContainer>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
{/* Data sections */}
|
||||
{<DataSections bucketSize={bucketSize} />}
|
||||
<EmptySections />
|
||||
</EuiFlexItem>
|
||||
<EuiSpacer size="s" />
|
||||
</EuiFlexGroup>
|
||||
<EuiHorizontalRule />
|
||||
<EuiFlexGroup>
|
||||
<EuiFlexItem>
|
||||
{/* Resources / What's New sections */}
|
||||
<EuiFlexGroup>
|
||||
<EuiFlexItem grow={4}>
|
||||
{!!newsFeed?.items?.length && <NewsFeed items={newsFeed.items.slice(0, 3)} />}
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={2}>
|
||||
<Resources />
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</>
|
||||
{isFlyoutVisible && (
|
||||
<EuiFlyout
|
||||
className="oblt__flyout"
|
||||
size="s"
|
||||
ownFocus
|
||||
onClose={() => setIsFlyoutVisible(false)}
|
||||
aria-labelledby="statusVisualizationFlyoutTitle"
|
||||
>
|
||||
<EuiFlyoutHeader hasBorder>
|
||||
<EuiTitle size="m">
|
||||
<h2
|
||||
id="statusVisualizationFlyoutTitle"
|
||||
data-test-subj="statusVisualizationFlyoutTitle"
|
||||
>
|
||||
<FormattedMessage
|
||||
id="xpack.observability.overview.statusVisualizationFlyoutTitle"
|
||||
defaultMessage="Data assistant"
|
||||
/>
|
||||
</h2>
|
||||
</EuiTitle>
|
||||
<EuiSpacer size="s" />
|
||||
<EuiText size="s">
|
||||
<p>
|
||||
<FormattedMessage
|
||||
id="xpack.observability.overview.statusVisualizationFlyoutDescription"
|
||||
defaultMessage="Track your progress towards adding observability integrations and features."
|
||||
/>
|
||||
</p>
|
||||
</EuiText>
|
||||
</EuiFlyoutHeader>
|
||||
<EuiFlyoutBody>
|
||||
<ObservabilityStatus />
|
||||
</EuiFlyoutBody>
|
||||
</EuiFlyout>
|
||||
)}
|
||||
<AlertsStateTable
|
||||
alertsTableConfigurationRegistry={alertsTableConfigurationRegistry}
|
||||
configurationId={AlertConsumers.OBSERVABILITY}
|
||||
id={ALERTS_TABLE_ID}
|
||||
flyoutSize="s"
|
||||
featureIds={observabilityAlertFeatureIds}
|
||||
pageSize={ALERTS_PER_PAGE}
|
||||
query={esQuery}
|
||||
showExpandToDetails={false}
|
||||
/>
|
||||
</CasesContext>
|
||||
</SectionContainer>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
{/* Data sections */}
|
||||
<DataSections bucketSize={bucketSize} />
|
||||
<EmptySections />
|
||||
</EuiFlexItem>
|
||||
<EuiSpacer size="s" />
|
||||
</EuiFlexGroup>
|
||||
|
||||
<EuiHorizontalRule />
|
||||
|
||||
<EuiFlexGroup>
|
||||
<EuiFlexItem>
|
||||
{/* Resources / What's New sections */}
|
||||
<EuiFlexGroup>
|
||||
<EuiFlexItem grow={4}>
|
||||
{!!newsFeed?.items?.length && <NewsFeed items={newsFeed.items.slice(0, 3)} />}
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={2}>
|
||||
<Resources />
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
|
||||
{isDataAssistantFlyoutVisible ? (
|
||||
<DataAssistantFlyout onClose={() => setIsDataAssistantFlyoutVisible(false)} />
|
||||
) : null}
|
||||
</ObservabilityPageTemplate>
|
||||
);
|
||||
}
|
||||
|
||||
function HeaderActions({
|
||||
showTour = false,
|
||||
onTourDismiss,
|
||||
handleGuidedSetupClick,
|
||||
onTimeRangeRefresh,
|
||||
}: HeaderActionsProps) {
|
||||
const { relativeStart, relativeEnd, refreshInterval, refreshPaused } = useDatePickerContext();
|
||||
const { endTour: endObservabilityTour, isTourVisible: isObservabilityTourVisible } =
|
||||
useObservabilityTourContext();
|
||||
|
||||
const buttonRef = useRef();
|
||||
|
||||
return (
|
||||
<EuiFlexGroup wrap gutterSize="s" justifyContent="flexEnd">
|
||||
<EuiFlexItem grow={false}>
|
||||
<DatePicker
|
||||
rangeFrom={relativeStart}
|
||||
rangeTo={relativeEnd}
|
||||
refreshInterval={refreshInterval}
|
||||
refreshPaused={refreshPaused}
|
||||
width="auto"
|
||||
onTimeRangeRefresh={onTimeRangeRefresh}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false} style={{ alignItems: 'flex-end' }}>
|
||||
<EuiButton
|
||||
// @ts-expect-error the EUI verson that kibana uses right now doesn't have the correct types
|
||||
buttonRef={buttonRef}
|
||||
data-test-subj="guidedSetupButton"
|
||||
id="guidedSetupButton"
|
||||
color="text"
|
||||
iconType="wrench"
|
||||
onClick={() => {
|
||||
// End the Observability tour if it's visible and the user clicks the data assistant button
|
||||
if (isObservabilityTourVisible) {
|
||||
endObservabilityTour();
|
||||
}
|
||||
handleGuidedSetupClick();
|
||||
}}
|
||||
>
|
||||
<FormattedMessage
|
||||
id="xpack.observability.overview.guidedSetupButton"
|
||||
defaultMessage="Data assistant"
|
||||
/>
|
||||
</EuiButton>
|
||||
{showTour ? (
|
||||
<EuiTourStep
|
||||
// @ts-expect-error the EUI verson that kibana uses right now doesn't have the correct types
|
||||
anchor={() => buttonRef.current}
|
||||
isStepOpen
|
||||
title={i18n.translate('xpack.observability.overview.guidedSetupTourTitle', {
|
||||
defaultMessage: 'Data assistant is always available',
|
||||
})}
|
||||
content={
|
||||
<EuiText size="s">
|
||||
<FormattedMessage
|
||||
id="xpack.observability.overview.guidedSetupTourContent"
|
||||
defaultMessage="If you're ever in doubt you can always access the data assistant and view your next steps by clicking here."
|
||||
/>
|
||||
</EuiText>
|
||||
}
|
||||
step={1}
|
||||
stepsTotal={1}
|
||||
maxWidth={400}
|
||||
onFinish={onTourDismiss}
|
||||
footerAction={
|
||||
<EuiButtonEmpty color="text" flush="right" size="xs" onClick={onTourDismiss}>
|
||||
<FormattedMessage
|
||||
id="xpack.observability.overview.guidedSetupTourDismissButton"
|
||||
defaultMessage="Dismiss"
|
||||
/>
|
||||
</EuiButtonEmpty>
|
||||
}
|
||||
/>
|
||||
) : null}
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -10,10 +10,3 @@ export interface Bucket {
|
|||
end?: number;
|
||||
}
|
||||
export type BucketSize = { bucketSize: number; intervalString: string } | undefined;
|
||||
|
||||
export interface HeaderActionsProps {
|
||||
showTour?: boolean;
|
||||
onTourDismiss: () => void;
|
||||
handleGuidedSetupClick: () => void;
|
||||
onTimeRangeRefresh: () => void;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue