Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -79,11 +79,11 @@ describe('HasDataContextProvider', () => {
});

describe('when no plugin has registered', () => {
it('hasAnyData returns false and all apps return undefined', async () => {
it('hasAnyData returns undefined and all apps return undefined', async () => {
const { result, waitForNextUpdate } = renderHook(() => useHasData(), { wrapper });
expect(result.current).toMatchObject({
hasDataMap: {},
hasAnyData: false,
hasAnyData: undefined,
isAllRequestsComplete: false,
forceUpdate: expect.any(String),
onRefreshTimeRange: expect.any(Function),
Expand Down Expand Up @@ -132,7 +132,7 @@ describe('HasDataContextProvider', () => {
const { result, waitForNextUpdate } = renderHook(() => useHasData(), { wrapper });
expect(result.current).toEqual({
hasDataMap: {},
hasAnyData: false,
hasAnyData: undefined,
isAllRequestsComplete: false,
forceUpdate: expect.any(String),
onRefreshTimeRange: expect.any(Function),
Expand Down Expand Up @@ -188,7 +188,7 @@ describe('HasDataContextProvider', () => {
const { result, waitForNextUpdate } = renderHook(() => useHasData(), { wrapper });
expect(result.current).toEqual({
hasDataMap: {},
hasAnyData: false,
hasAnyData: undefined,
isAllRequestsComplete: false,
forceUpdate: expect.any(String),
onRefreshTimeRange: expect.any(Function),
Expand Down Expand Up @@ -246,7 +246,7 @@ describe('HasDataContextProvider', () => {
const { result, waitForNextUpdate } = renderHook(() => useHasData(), { wrapper });
expect(result.current).toEqual({
hasDataMap: {},
hasAnyData: false,
hasAnyData: undefined,
isAllRequestsComplete: false,
forceUpdate: expect.any(String),
onRefreshTimeRange: expect.any(Function),
Expand Down Expand Up @@ -301,7 +301,7 @@ describe('HasDataContextProvider', () => {
});
expect(result.current).toEqual({
hasDataMap: {},
hasAnyData: false,
hasAnyData: undefined,
isAllRequestsComplete: false,
forceUpdate: expect.any(String),
onRefreshTimeRange: expect.any(Function),
Expand Down Expand Up @@ -346,7 +346,7 @@ describe('HasDataContextProvider', () => {
});
expect(result.current).toEqual({
hasDataMap: {},
hasAnyData: false,
hasAnyData: undefined,
isAllRequestsComplete: false,
forceUpdate: expect.any(String),
onRefreshTimeRange: expect.any(Function),
Expand Down Expand Up @@ -406,7 +406,7 @@ describe('HasDataContextProvider', () => {
const { result, waitForNextUpdate } = renderHook(() => useHasData(), { wrapper });
expect(result.current).toEqual({
hasDataMap: {},
hasAnyData: false,
hasAnyData: undefined,
isAllRequestsComplete: false,
forceUpdate: expect.any(String),
onRefreshTimeRange: expect.any(Function),
Expand Down Expand Up @@ -484,7 +484,7 @@ describe('HasDataContextProvider', () => {
const { result, waitForNextUpdate } = renderHook(() => useHasData(), { wrapper });
expect(result.current).toEqual({
hasDataMap: {},
hasAnyData: false,
hasAnyData: undefined,
isAllRequestsComplete: false,
forceUpdate: expect.any(String),
onRefreshTimeRange: expect.any(Function),
Expand Down Expand Up @@ -534,7 +534,7 @@ describe('HasDataContextProvider', () => {
const { result, waitForNextUpdate } = renderHook(() => useHasData(), { wrapper });
expect(result.current).toEqual({
hasDataMap: {},
hasAnyData: false,
hasAnyData: undefined,
isAllRequestsComplete: false,
forceUpdate: expect.any(String),
onRefreshTimeRange: expect.any(Function),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* 2.0.
*/

import { uniqueId } from 'lodash';
import { isEmpty, uniqueId } from 'lodash';
import React, { createContext, useEffect, useState } from 'react';
import { useRouteMatch } from 'react-router-dom';
import { Alert } from '../../../alerting/common';
Expand All @@ -31,7 +31,7 @@ export type HasDataMap = Record<

export interface HasDataContextValue {
hasDataMap: Partial<HasDataMap>;
hasAnyData: boolean;
hasAnyData?: boolean;
isAllRequestsComplete: boolean;
onRefreshTimeRange: () => void;
forceUpdate: string;
Expand Down Expand Up @@ -153,7 +153,7 @@ export function HasDataContextProvider({ children }: { children: React.ReactNode
<HasDataContext.Provider
value={{
hasDataMap,
hasAnyData,
hasAnyData: isEmpty(hasDataMap) ? undefined : hasAnyData,
isAllRequestsComplete,
forceUpdate,
onRefreshTimeRange: () => {
Expand Down
124 changes: 15 additions & 109 deletions x-pack/plugins/observability/public/pages/landing/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,32 +5,14 @@
* 2.0.
*/

import {
EuiButton,
EuiCard,
EuiFlexGrid,
EuiFlexGroup,
EuiFlexItem,
EuiImage,
EuiSpacer,
EuiText,
EuiTitle,
} from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import React, { useContext } from 'react';
import styled, { ThemeContext } from 'styled-components';
import { FleetPanel } from '../../components/app/fleet_panel';
import { ObservabilityHeaderMenu } from '../../components/app/header';
import React from 'react';
import { useBreadcrumbs } from '../../hooks/use_breadcrumbs';
import { usePluginContext } from '../../hooks/use_plugin_context';
import { useTrackPageview } from '../../hooks/use_track_metric';
import { appsSection } from '../home/section';
import { getNoDataConfig } from '../../utils/no_data_config';
import './styles.scss';

const EuiCardWithoutPadding = styled(EuiCard)`
padding: 0;
`;

export function LandingPage() {
useTrackPageview({ app: 'observability-overview', path: 'landing' });
useTrackPageview({ app: 'observability-overview', path: 'landing', delay: 15000 });
Expand All @@ -43,96 +25,20 @@ export function LandingPage() {
]);

const { core, ObservabilityPageTemplate } = usePluginContext();
const theme = useContext(ThemeContext);

return (
<ObservabilityPageTemplate restrictWidth={1200}>
<ObservabilityHeaderMenu />
<EuiFlexGroup direction="column">
{/* title and description */}
<EuiFlexItem className="obsLanding__title">
<EuiTitle size="s">
<h2>
{i18n.translate('xpack.observability.home.sectionTitle', {
defaultMessage: 'Unified visibility across your entire ecosystem',
})}
</h2>
</EuiTitle>
<EuiSpacer size="m" />
<EuiText size="s" color="subdued">
{i18n.translate('xpack.observability.home.sectionsubtitle', {
defaultMessage:
'Monitor, analyze, and react to events happening anywhere in your environment by bringing logs, metrics, and traces together at scale in a single stack.',
})}
</EuiText>
</EuiFlexItem>

{/* Apps sections */}
<EuiFlexItem>
<EuiSpacer size="s" />
<EuiFlexGroup>
<EuiFlexItem>
<EuiFlexGrid columns={2} className="obsLanding__appSection">
{appsSection.map((app) => (
<EuiFlexItem key={app.id}>
<EuiCardWithoutPadding
display="plain"
layout="horizontal"
title={
<EuiTitle size="xs" className="title">
<h3>{app.title}</h3>
</EuiTitle>
}
description={app.description}
/>
</EuiFlexItem>
))}
</EuiFlexGrid>
</EuiFlexItem>
<EuiFlexItem>
<EuiImage
size="xl"
alt="observability overview image"
url={core.http.basePath.prepend(
`/plugins/observability/assets/illustration_${
theme.darkMode ? 'dark' : 'light'
}.svg`
)}
/>
</EuiFlexItem>
</EuiFlexGroup>
</EuiFlexItem>

<EuiSpacer size="xxl" />
const noDataConfig = getNoDataConfig({
// Set it to false because the landing page is only visible when there's no data
hasData: false,
basePath: core.http.basePath,
docsLink: core.docLinks.links.observability.guide,
});

{/* Get started button */}
<EuiFlexItem>
<EuiFlexGroup justifyContent="center" gutterSize="none">
<EuiFlexItem grow={false}>
<EuiButton
fill
iconType="sortRight"
iconSide="right"
href={core.http.basePath.prepend('/app/home#/tutorial_directory/logging')}
>
{i18n.translate('xpack.observability.home.getStatedButton', {
defaultMessage: 'Get started',
})}
</EuiButton>
</EuiFlexItem>
</EuiFlexGroup>
</EuiFlexItem>

<EuiSpacer size="xxl" />

<EuiFlexItem>
<EuiFlexGroup justifyContent="spaceAround">
<EuiFlexItem grow={false}>
<FleetPanel />
</EuiFlexItem>
</EuiFlexGroup>
</EuiFlexItem>
</EuiFlexGroup>
</ObservabilityPageTemplate>
return (
<ObservabilityPageTemplate
noDataConfig={noDataConfig}
restrictWidth
// No side nav since nothing is setup
showSolutionNav={false}
/>
);
}
88 changes: 53 additions & 35 deletions x-pack/plugins/observability/public/pages/overview/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { useTimeRange } from '../../hooks/use_time_range';
import { RouteParams } from '../../routes';
import { getNewsFeed } from '../../services/get_news_feed';
import { getBucketSize } from '../../utils/get_bucket_size';
import { getNoDataConfig } from '../../utils/no_data_config';
import { DataSections } from './data_sections';
import { LoadingObservability } from './loading_observability';

Expand Down Expand Up @@ -57,12 +58,20 @@ export function OverviewPage({ routeParams }: Props) {

const { data: newsFeed } = useFetcher(() => getNewsFeed({ core }), [core]);

const { hasDataMap, hasAnyData } = useHasData();
const { hasDataMap, hasAnyData, isAllRequestsComplete } = useHasData();

if (hasAnyData === undefined) {
return <LoadingObservability />;
}

const hasData = hasAnyData === true || (isAllRequestsComplete === false ? undefined : false);

const noDataConfig = getNoDataConfig({
hasData,
basePath: core.http.basePath,
docsLink: core.docLinks.links.observability.guide,
});

const alerts = (hasDataMap.alert?.hasData as Alert[]) || [];

const { refreshInterval = 10000, refreshPaused = true } = routeParams.query;
Expand All @@ -74,44 +83,53 @@ export function OverviewPage({ routeParams }: Props) {

return (
<ObservabilityPageTemplate
pageHeader={{
pageTitle: overviewPageTitle,
rightSideItems: [
<DatePicker
rangeFrom={relativeTime.start}
rangeTo={relativeTime.end}
refreshInterval={refreshInterval}
refreshPaused={refreshPaused}
/>,
],
}}
noDataConfig={noDataConfig}
pageHeader={
hasData
? {
pageTitle: overviewPageTitle,
rightSideItems: [
<DatePicker
rangeFrom={relativeTime.start}
rangeTo={relativeTime.end}
refreshInterval={refreshInterval}
refreshPaused={refreshPaused}
/>,
],
}
: undefined
}
>
<ObservabilityHeaderMenu />
<EuiFlexGroup>
<EuiFlexItem grow={6}>
{/* Data sections */}
{hasAnyData && <DataSections bucketSize={bucketSize?.intervalString!} />}
<EmptySections />
<EuiSpacer size="l" />
{hasData && (
<>
<ObservabilityHeaderMenu />
<EuiFlexGroup>
<EuiFlexItem>
{/* Resources / What's New sections */}
<EuiPanel hasBorder={true}>
<Resources />
<EuiSpacer size="l" />
{!!newsFeed?.items?.length && <NewsFeed items={newsFeed.items.slice(0, 5)} />}
</EuiPanel>
<EuiFlexItem grow={6}>
{/* Data sections */}
{hasAnyData && <DataSections bucketSize={bucketSize?.intervalString!} />}
<EmptySections />
<EuiSpacer size="l" />
<EuiFlexGroup>
<EuiFlexItem>
{/* Resources / What's New sections */}
<EuiPanel hasBorder={true}>
<Resources />
<EuiSpacer size="l" />
{!!newsFeed?.items?.length && <NewsFeed items={newsFeed.items.slice(0, 5)} />}
</EuiPanel>
</EuiFlexItem>
{!!alerts.length && (
<EuiFlexItem>
<EuiPanel hasBorder={true}>
<AlertsSection alerts={alerts} />
</EuiPanel>
</EuiFlexItem>
)}
</EuiFlexGroup>
</EuiFlexItem>
{!!alerts.length && (
<EuiFlexItem>
<EuiPanel hasBorder={true}>
<AlertsSection alerts={alerts} />
</EuiPanel>
</EuiFlexItem>
)}
</EuiFlexGroup>
</EuiFlexItem>
</EuiFlexGroup>
</>
)}
</ObservabilityPageTemplate>
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export function LoadingObservability() {
const { ObservabilityPageTemplate } = usePluginContext();

return (
<ObservabilityPageTemplate template="centeredContent">
<ObservabilityPageTemplate template="centeredContent" showSolutionNav={false}>
<ObservabilityHeaderMenu />
<EuiFlexGroup>
<EuiFlexItem grow={false}>
Expand Down
Loading