mirror of
https://github.com/elastic/kibana.git
synced 2025-06-27 18:51:07 -04:00
[Unified Observability] Overview style updates (#124702)
* Big chunk of style updates * New layout and position for news and resources * Alerts updated * Rename headings and links * Removed unncessary prop * More fixes * Remove active status * Fixing tests * fix tests * fix checks Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Ester Marti <ester.martivilaseca@elastic.co>
This commit is contained in:
parent
809246721d
commit
3c73b605aa
14 changed files with 166 additions and 146 deletions
|
@ -18,12 +18,12 @@ interface Props {
|
|||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
const CHART_HEIGHT = 170;
|
||||
const CHART_HEIGHT = 120;
|
||||
|
||||
export function ChartContainer({
|
||||
isInitialLoad,
|
||||
children,
|
||||
iconSize = 'xl',
|
||||
iconSize = 'l',
|
||||
height = CHART_HEIGHT,
|
||||
}: Props) {
|
||||
if (isInitialLoad) {
|
||||
|
|
|
@ -9,7 +9,7 @@ import {
|
|||
EuiErrorBoundary,
|
||||
EuiFlexGroup,
|
||||
EuiFlexItem,
|
||||
EuiHorizontalRule,
|
||||
EuiPanel,
|
||||
EuiLink,
|
||||
EuiText,
|
||||
EuiTitle,
|
||||
|
@ -56,9 +56,10 @@ function NewsItem({ item }: { item: INewsItem }) {
|
|||
const theme = useContext(ThemeContext);
|
||||
|
||||
return (
|
||||
<EuiPanel hasBorder={true}>
|
||||
<EuiFlexGroup direction="column" gutterSize="s">
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiTitle size="xxxs">
|
||||
<EuiTitle size="xxs">
|
||||
<h4>{item.title.en}</h4>
|
||||
</EuiTitle>
|
||||
</EuiFlexItem>
|
||||
|
@ -67,12 +68,12 @@ function NewsItem({ item }: { item: INewsItem }) {
|
|||
<EuiFlexItem>
|
||||
<EuiFlexGroup direction="column" gutterSize="s" alignItems="baseline">
|
||||
<EuiFlexItem>
|
||||
<EuiText grow={false} size="xs" color="subdued">
|
||||
<EuiText grow={false} size="s" color="subdued">
|
||||
{limitString(item.description.en, 128)}
|
||||
</EuiText>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiText size="xs">
|
||||
<EuiText size="s">
|
||||
<EuiLink href={item.link_url.en} target="_blank" external>
|
||||
{i18n.translate('xpack.observability.news.readFullStory', {
|
||||
defaultMessage: 'Read full story',
|
||||
|
@ -97,7 +98,7 @@ function NewsItem({ item }: { item: INewsItem }) {
|
|||
)}
|
||||
</EuiFlexGroup>
|
||||
</EuiFlexItem>
|
||||
<EuiHorizontalRule margin="s" />
|
||||
</EuiFlexGroup>
|
||||
</EuiPanel>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -42,7 +42,7 @@ const resources = [
|
|||
|
||||
export function Resources() {
|
||||
return (
|
||||
<EuiFlexGroup direction="column" alignItems="flexStart" gutterSize="xs">
|
||||
<EuiFlexGroup direction="column" alignItems="flexStart">
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiTitle size="xs">
|
||||
<h4>
|
||||
|
|
|
@ -9,15 +9,14 @@ import {
|
|||
EuiBadge,
|
||||
EuiFlexGroup,
|
||||
EuiFlexItem,
|
||||
EuiHorizontalRule,
|
||||
EuiIconTip,
|
||||
EuiLink,
|
||||
EuiText,
|
||||
EuiSpacer,
|
||||
EuiTitle,
|
||||
EuiButton,
|
||||
EuiButtonEmpty,
|
||||
EuiLoadingSpinner,
|
||||
EuiCallOut,
|
||||
EuiPanel,
|
||||
} from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
|
@ -68,7 +67,7 @@ export function AlertsSection() {
|
|||
return (
|
||||
<EuiFlexGroup alignItems="center" justifyContent="center" responsive={false}>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiLoadingSpinner size="xl" />
|
||||
<EuiLoadingSpinner size="l" />
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
);
|
||||
|
@ -99,7 +98,12 @@ export function AlertsSection() {
|
|||
|
||||
return (
|
||||
<div>
|
||||
<EuiFlexGroup alignItems="center" justifyContent="spaceBetween" responsive={false}>
|
||||
<EuiFlexGroup
|
||||
alignItems="center"
|
||||
justifyContent="spaceBetween"
|
||||
responsive={false}
|
||||
gutterSize="s"
|
||||
>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiTitle size="xs">
|
||||
<h4>
|
||||
|
@ -110,31 +114,33 @@ export function AlertsSection() {
|
|||
</EuiTitle>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiButton size="s" href={manageLink}>
|
||||
<EuiButtonEmpty iconType="sortRight" color="text" size="xs" href={manageLink}>
|
||||
{i18n.translate('xpack.observability.overview.alert.appLink', {
|
||||
defaultMessage: 'Manage alerts',
|
||||
defaultMessage: 'Show all alerts',
|
||||
})}
|
||||
</EuiButton>
|
||||
</EuiButtonEmpty>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
<>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiSpacer />
|
||||
<EuiSpacer size="s" />
|
||||
<EuiSelect
|
||||
compressed
|
||||
fullWidth={true}
|
||||
id="filterAlerts"
|
||||
options={[allTypes, ...filterOptions]}
|
||||
value={filter}
|
||||
onChange={(e) => setFilter(e.target.value)}
|
||||
prepend="Show"
|
||||
/>
|
||||
<EuiSpacer />
|
||||
<EuiSpacer size="s" />
|
||||
</EuiFlexItem>
|
||||
{alerts
|
||||
.filter((alert) => filter === ALL_TYPES || alert.consumer === filter)
|
||||
.map((alert, index) => {
|
||||
const isLastElement = index === alerts.length - 1;
|
||||
return (
|
||||
<EuiFlexGroup>
|
||||
<EuiFlexItem>
|
||||
<EuiPanel>
|
||||
<EuiFlexGroup direction="column" gutterSize="s" key={alert.id}>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiLink
|
||||
|
@ -158,25 +164,27 @@ export function AlertsSection() {
|
|||
</EuiFlexGroup>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiFlexGroup gutterSize="s">
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiText color="subdued" size="xs">
|
||||
Updated {moment.duration(moment().diff(alert.updatedAt)).humanize()} ago
|
||||
</EuiText>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexGroup gutterSize="s" alignItems="center">
|
||||
{alert.muteAll && (
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiIconTip
|
||||
type="minusInCircle"
|
||||
content={i18n.translate('xpack.observability.overview.alerts.muted', {
|
||||
<EuiBadge color="hollow">
|
||||
{i18n.translate('xpack.observability.overview.alerts.muted', {
|
||||
defaultMessage: 'Muted',
|
||||
})}
|
||||
/>
|
||||
</EuiBadge>
|
||||
</EuiFlexItem>
|
||||
)}
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiText color="subdued" size="xs">
|
||||
Last updated{' '}
|
||||
{moment.duration(moment().diff(alert.updatedAt)).humanize()} ago
|
||||
</EuiText>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiFlexItem>
|
||||
{!isLastElement && <EuiHorizontalRule margin="xs" />}
|
||||
</EuiFlexGroup>
|
||||
</EuiPanel>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
);
|
||||
})}
|
||||
|
|
|
@ -84,12 +84,12 @@ describe('APMSection', () => {
|
|||
status: fetcherHook.FETCH_STATUS.SUCCESS,
|
||||
refetch: jest.fn(),
|
||||
});
|
||||
const { getByText, queryAllByTestId } = render(
|
||||
const { getByRole, getByText, queryAllByTestId } = render(
|
||||
<APMSection bucketSize={{ intervalString: '60s', bucketSize: 60 }} />
|
||||
);
|
||||
|
||||
expect(getByText('APM')).toBeInTheDocument();
|
||||
expect(getByText('View in app')).toBeInTheDocument();
|
||||
expect(getByRole('heading')).toHaveTextContent('Services');
|
||||
expect(getByText('Show service inventory')).toBeInTheDocument();
|
||||
expect(getByText('Services 11')).toBeInTheDocument();
|
||||
expect(getByText('Throughput 900.0 tpm')).toBeInTheDocument();
|
||||
expect(queryAllByTestId('loading')).toEqual([]);
|
||||
|
@ -101,12 +101,12 @@ describe('APMSection', () => {
|
|||
status: fetcherHook.FETCH_STATUS.SUCCESS,
|
||||
refetch: jest.fn(),
|
||||
});
|
||||
const { getByText, queryAllByTestId } = render(
|
||||
const { getByRole, getByText, queryAllByTestId } = render(
|
||||
<APMSection bucketSize={{ intervalString: '60s', bucketSize: 60 }} />
|
||||
);
|
||||
|
||||
expect(getByText('APM')).toBeInTheDocument();
|
||||
expect(getByText('View in app')).toBeInTheDocument();
|
||||
expect(getByRole('heading')).toHaveTextContent('Services');
|
||||
expect(getByText('Show service inventory')).toBeInTheDocument();
|
||||
expect(getByText('Services 11')).toBeInTheDocument();
|
||||
expect(getByText('Throughput 312.00k tpm')).toBeInTheDocument();
|
||||
expect(queryAllByTestId('loading')).toEqual([]);
|
||||
|
@ -117,13 +117,13 @@ describe('APMSection', () => {
|
|||
status: fetcherHook.FETCH_STATUS.LOADING,
|
||||
refetch: jest.fn(),
|
||||
});
|
||||
const { getByText, queryAllByText, getByTestId } = render(
|
||||
const { getByRole, queryAllByText, getByTestId } = render(
|
||||
<APMSection bucketSize={{ intervalString: '60s', bucketSize: 60 }} />
|
||||
);
|
||||
|
||||
expect(getByText('APM')).toBeInTheDocument();
|
||||
expect(getByRole('heading')).toHaveTextContent('Services');
|
||||
expect(getByTestId('loading')).toBeInTheDocument();
|
||||
expect(queryAllByText('View in app')).toEqual([]);
|
||||
expect(queryAllByText('Show service inventory')).toEqual([]);
|
||||
expect(queryAllByText('Services 11')).toEqual([]);
|
||||
expect(queryAllByText('Throughput 312.00k tpm')).toEqual([]);
|
||||
});
|
||||
|
|
|
@ -93,12 +93,12 @@ export function APMSection({ bucketSize }: Props) {
|
|||
return (
|
||||
<SectionContainer
|
||||
title={i18n.translate('xpack.observability.overview.apm.title', {
|
||||
defaultMessage: 'APM',
|
||||
defaultMessage: 'Services',
|
||||
})}
|
||||
appLink={{
|
||||
href: appLink,
|
||||
label: i18n.translate('xpack.observability.overview.apm.appLink', {
|
||||
defaultMessage: 'View in app',
|
||||
defaultMessage: 'Show service inventory',
|
||||
}),
|
||||
}}
|
||||
hasError={status === FETCH_STATUS.FAILURE}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { EuiAccordion, EuiPanel, EuiSpacer, EuiTitle, EuiButton } from '@elastic/eui';
|
||||
import { EuiAccordion, EuiPanel, EuiSpacer, EuiTitle, EuiButtonEmpty } from '@elastic/eui';
|
||||
import React from 'react';
|
||||
import { ErrorPanel } from './error_panel';
|
||||
import { usePluginContext } from '../../../hooks/use_plugin_context';
|
||||
|
@ -25,29 +25,32 @@ interface Props {
|
|||
export function SectionContainer({ title, appLink, children, hasError }: Props) {
|
||||
const { core } = usePluginContext();
|
||||
return (
|
||||
<EuiPanel hasBorder={true}>
|
||||
<EuiPanel hasShadow={true} color="subdued">
|
||||
<EuiAccordion
|
||||
initialIsOpen
|
||||
id={title}
|
||||
buttonContentClassName="accordion-button"
|
||||
buttonContent={
|
||||
<EuiTitle size="s">
|
||||
<EuiTitle size="xs">
|
||||
<h5>{title}</h5>
|
||||
</EuiTitle>
|
||||
}
|
||||
extraAction={
|
||||
appLink?.href && (
|
||||
<EuiButton size="s" href={core.http.basePath.prepend(appLink.href)}>
|
||||
<EuiButtonEmpty
|
||||
iconType={'sortRight'}
|
||||
size="xs"
|
||||
color="text"
|
||||
href={core.http.basePath.prepend(appLink.href)}
|
||||
>
|
||||
{appLink.label}
|
||||
</EuiButton>
|
||||
</EuiButtonEmpty>
|
||||
)
|
||||
}
|
||||
>
|
||||
<>
|
||||
<EuiSpacer size="s" />
|
||||
<EuiPanel hasShadow={false} paddingSize="s">
|
||||
{hasError ? <ErrorPanel /> : <>{children}</>}
|
||||
</EuiPanel>
|
||||
<EuiPanel hasShadow={true}>{hasError ? <ErrorPanel /> : <>{children}</>}</EuiPanel>
|
||||
</>
|
||||
</EuiAccordion>
|
||||
</EuiPanel>
|
||||
|
|
|
@ -92,17 +92,17 @@ export function LogsSection({ bucketSize }: Props) {
|
|||
return (
|
||||
<SectionContainer
|
||||
title={i18n.translate('xpack.observability.overview.logs.title', {
|
||||
defaultMessage: 'Logs',
|
||||
defaultMessage: 'Log Events',
|
||||
})}
|
||||
appLink={{
|
||||
href: appLink,
|
||||
label: i18n.translate('xpack.observability.overview.logs.appLink', {
|
||||
defaultMessage: 'View in app',
|
||||
defaultMessage: 'Show log stream',
|
||||
}),
|
||||
}}
|
||||
hasError={status === FETCH_STATUS.FAILURE}
|
||||
>
|
||||
<EuiTitle size="xs">
|
||||
<EuiTitle size="xxs">
|
||||
<h4>
|
||||
{i18n.translate('xpack.observability.overview.logs.subtitle', {
|
||||
defaultMessage: 'Logs rate per minute',
|
||||
|
|
|
@ -202,12 +202,12 @@ export function MetricsSection({ bucketSize }: Props) {
|
|||
return (
|
||||
<SectionContainer
|
||||
title={i18n.translate('xpack.observability.overview.metrics.title', {
|
||||
defaultMessage: 'Metrics',
|
||||
defaultMessage: 'Hosts',
|
||||
})}
|
||||
appLink={{
|
||||
href: appLink,
|
||||
label: i18n.translate('xpack.observability.overview.metrics.appLink', {
|
||||
defaultMessage: 'View in app',
|
||||
defaultMessage: 'Show inventory',
|
||||
}),
|
||||
}}
|
||||
hasError={status === FETCH_STATUS.FAILURE}
|
||||
|
|
|
@ -74,17 +74,17 @@ export function UptimeSection({ bucketSize }: Props) {
|
|||
const { appLink, stats, series } = data || {};
|
||||
|
||||
const downColor = theme.eui.euiColorVis2;
|
||||
const upColor = theme.eui.euiColorLightShade;
|
||||
const upColor = theme.eui.euiColorMediumShade;
|
||||
|
||||
return (
|
||||
<SectionContainer
|
||||
title={i18n.translate('xpack.observability.overview.uptime.title', {
|
||||
defaultMessage: 'Uptime',
|
||||
defaultMessage: 'Monitors',
|
||||
})}
|
||||
appLink={{
|
||||
href: appLink,
|
||||
label: i18n.translate('xpack.observability.overview.uptime.appLink', {
|
||||
defaultMessage: 'View in app',
|
||||
defaultMessage: 'Show monitors',
|
||||
}),
|
||||
}}
|
||||
hasError={status === FETCH_STATUS.FAILURE}
|
||||
|
|
|
@ -78,7 +78,7 @@ describe('UXSection', () => {
|
|||
);
|
||||
|
||||
expect(getByText('User Experience')).toBeInTheDocument();
|
||||
expect(getByText('View in app')).toBeInTheDocument();
|
||||
expect(getByText('Show dashboard')).toBeInTheDocument();
|
||||
expect(getByText('elastic-co-frontend')).toBeInTheDocument();
|
||||
expect(getByText('Largest contentful paint')).toBeInTheDocument();
|
||||
expect(getByText('1.94 s')).toBeInTheDocument();
|
||||
|
@ -113,7 +113,7 @@ describe('UXSection', () => {
|
|||
|
||||
expect(getByText('User Experience')).toBeInTheDocument();
|
||||
expect(getAllByText('--')).toHaveLength(3);
|
||||
expect(queryAllByText('View in app')).toEqual([]);
|
||||
expect(queryAllByText('Show dashboard')).toEqual([]);
|
||||
expect(getByText('elastic-co-frontend')).toBeInTheDocument();
|
||||
});
|
||||
it('shows empty state', () => {
|
||||
|
@ -128,7 +128,7 @@ describe('UXSection', () => {
|
|||
|
||||
expect(getByText('User Experience')).toBeInTheDocument();
|
||||
expect(getAllByText('No data is available.')).toHaveLength(3);
|
||||
expect(queryAllByText('View in app')).toEqual([]);
|
||||
expect(queryAllByText('Show dashboard')).toEqual([]);
|
||||
expect(getByText('elastic-co-frontend')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -57,7 +57,7 @@ export function UXSection({ bucketSize }: Props) {
|
|||
appLink={{
|
||||
href: appLink,
|
||||
label: i18n.translate('xpack.observability.overview.ux.appLink', {
|
||||
defaultMessage: 'View in app',
|
||||
defaultMessage: 'Show dashboard',
|
||||
}),
|
||||
}}
|
||||
hasError={status === FETCH_STATUS.FAILURE}
|
||||
|
|
|
@ -23,7 +23,7 @@ interface Props {
|
|||
export function DataSections({ bucketSize }: Props) {
|
||||
return (
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiFlexGroup direction="column">
|
||||
<EuiFlexGroup direction="column" gutterSize="s">
|
||||
<EuiFlexItem grow={false}>
|
||||
<LogsSection bucketSize={bucketSize} />
|
||||
</EuiFlexItem>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { EuiFlexGroup, EuiFlexItem, EuiSpacer, EuiPanel } from '@elastic/eui';
|
||||
import { EuiFlexGroup, EuiFlexItem, EuiSpacer, EuiPanel, EuiHorizontalRule } from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import React from 'react';
|
||||
import { useTrackPageview } from '../..';
|
||||
|
@ -100,30 +100,38 @@ export function OverviewPage({ routeParams }: Props) {
|
|||
{hasData && (
|
||||
<>
|
||||
<ObservabilityHeaderMenu />
|
||||
<EuiFlexGroup>
|
||||
<EuiFlexItem grow={6}>
|
||||
{/* Data sections */}
|
||||
{hasAnyData && <DataSections bucketSize={bucketSize} />}
|
||||
<EmptySections />
|
||||
<EuiSpacer size="l" />
|
||||
<EuiFlexGroup>
|
||||
<EuiFlexGroup direction="column" gutterSize="s">
|
||||
<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>
|
||||
<EuiFlexGroup direction="column" gutterSize="s">
|
||||
{hasDataMap?.alert?.hasData && (
|
||||
<EuiFlexItem>
|
||||
<EuiPanel hasBorder={true}>
|
||||
<EuiPanel color="subdued">
|
||||
<AlertsSection />
|
||||
</EuiPanel>
|
||||
</EuiFlexItem>
|
||||
)}
|
||||
</EuiFlexGroup>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
{/* Data sections */}
|
||||
{hasAnyData && <DataSections bucketSize={bucketSize} />}
|
||||
<EmptySections />
|
||||
</EuiFlexItem>
|
||||
<EuiSpacer size="s" />
|
||||
</EuiFlexGroup>
|
||||
<EuiHorizontalRule />
|
||||
<EuiFlexGroup>
|
||||
<EuiFlexItem>
|
||||
{/* Resources / What's New sections */}
|
||||
<EuiFlexGroup direction="row">
|
||||
<EuiFlexItem grow={4}>
|
||||
{!!newsFeed?.items?.length && <NewsFeed items={newsFeed.items.slice(0, 3)} />}
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={2}>
|
||||
<Resources />
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</>
|
||||
)}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue