Skip to content

Commit

Permalink
[ML] Update the Overview page (elastic#159609)
Browse files Browse the repository at this point in the history
## Summary

Resolves elastic#154294 and updates the
UI of the Overview page

- Updates panels layout
- Stores expand/collapsed state of the panels in the local storage
- Update empty states text and layout

<img width="1341" alt="image"
src="https://github.com/elastic/kibana/assets/5236598/8833fa2a-b574-44ee-bacb-e974186dd35f">

### Checklist

- [ ] Any text added follows [EUI's writing
guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses
sentence case text and includes [i18n
support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md)
- [ ]
[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html)
was added for features that require explanation or tutorials
- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios
- [x] Any UI touched in this PR is usable by keyboard only (learn more
about [keyboard accessibility](https://webaim.org/techniques/keyboard/))
- [x] Any UI touched in this PR does not create any new axe failures
(run axe in browser:
[FF](https://addons.mozilla.org/en-US/firefox/addon/axe-devtools/),
[Chrome](https://chrome.google.com/webstore/detail/axe-web-accessibility-tes/lhdoppojpmngadmnindnejefpokejbdd?hl=en-US))
- [x] This renders correctly on smaller devices using a responsive
layout. (You can test this [in your
browser](https://www.browserstack.com/guide/responsive-testing-on-local-server))
- [x] This was checked for [cross-browser
compatibility](https://www.elastic.co/support/matrix#matrix_browsers)

(cherry picked from commit 6ac52fb)
  • Loading branch information
darnautov committed Jun 20, 2023
1 parent 1bb316d commit 36c9a0c
Show file tree
Hide file tree
Showing 18 changed files with 441 additions and 303 deletions.
11 changes: 11 additions & 0 deletions x-pack/plugins/ml/common/types/storage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export const ML_GETTING_STARTED_CALLOUT_DISMISSED = 'ml.gettingStarted.isDismiss
export const ML_FROZEN_TIER_PREFERENCE = 'ml.frozenDataTierPreference';
export const ML_ANOMALY_EXPLORER_PANELS = 'ml.anomalyExplorerPanels';
export const ML_NOTIFICATIONS_LAST_CHECKED_AT = 'ml.notificationsLastCheckedAt';
export const ML_OVERVIEW_PANELS = 'ml.overviewPanels';

export type PartitionFieldConfig =
| {
Expand Down Expand Up @@ -52,6 +53,12 @@ export interface AnomalyExplorerPanelsState {
mainPage: { size: number };
}

export interface OverviewPanelsState {
nodes: boolean;
adJobs: boolean;
dfaJobs: boolean;
}

export interface MlStorageRecord {
[key: string]: unknown;
[ML_ENTITY_FIELDS_CONFIG]: PartitionFieldsConfig;
Expand All @@ -60,6 +67,7 @@ export interface MlStorageRecord {
[ML_FROZEN_TIER_PREFERENCE]: FrozenTierPreference;
[ML_ANOMALY_EXPLORER_PANELS]: AnomalyExplorerPanelsState | undefined;
[ML_NOTIFICATIONS_LAST_CHECKED_AT]: number | undefined;
[ML_OVERVIEW_PANELS]: OverviewPanelsState;
}

export type MlStorage = Partial<MlStorageRecord> | null;
Expand All @@ -78,6 +86,8 @@ export type TMlStorageMapped<T extends MlStorageKey> = T extends typeof ML_ENTIT
? AnomalyExplorerPanelsState | undefined
: T extends typeof ML_NOTIFICATIONS_LAST_CHECKED_AT
? number | undefined
: T extends typeof ML_OVERVIEW_PANELS
? OverviewPanelsState | undefined
: null;

export const ML_STORAGE_KEYS = [
Expand All @@ -87,4 +97,5 @@ export const ML_STORAGE_KEYS = [
ML_FROZEN_TIER_PREFERENCE,
ML_ANOMALY_EXPLORER_PANELS,
ML_NOTIFICATIONS_LAST_CHECKED_AT,
ML_OVERVIEW_PANELS,
] as const;
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
/*
* 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 {
EuiBadge,
EuiButtonIcon,
EuiFlexGroup,
EuiFlexItem,
EuiSplitPanel,
EuiText,
EuiTitle,
} from '@elastic/eui';
import React, { type FC } from 'react';
import { css } from '@emotion/react/dist/emotion-react.cjs';
import { useCurrentThemeVars } from '../../contexts/kibana';

export interface CollapsiblePanelProps {
isOpen: boolean;
onToggle: (isOpen: boolean) => void;

header: React.ReactElement;
headerItems?: React.ReactElement[];
}

export const CollapsiblePanel: FC<CollapsiblePanelProps> = ({
isOpen,
onToggle,
children,
header,
headerItems,
}) => {
const { euiTheme } = useCurrentThemeVars();

return (
<EuiSplitPanel.Outer
grow
hasShadow={false}
css={{
border: `${euiTheme.euiBorderWidthThin} solid ${
isOpen ? euiTheme.euiBorderColor : 'transparent'
}`,
}}
>
<EuiSplitPanel.Inner color={isOpen ? 'plain' : 'subdued'}>
<EuiFlexGroup justifyContent={'spaceBetween'} alignItems={'center'}>
<EuiFlexItem grow={false}>
<EuiFlexGroup gutterSize={'s'}>
<EuiFlexItem grow={false}>
<EuiButtonIcon
color={'text'}
iconType={isOpen ? 'arrowDown' : 'arrowRight'}
onClick={() => {
onToggle(!isOpen);
}}
/>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiTitle size="xxs">
<h2>{header}</h2>
</EuiTitle>
</EuiFlexItem>
</EuiFlexGroup>
</EuiFlexItem>
{headerItems ? (
<EuiFlexItem grow={false}>
<EuiFlexGroup gutterSize={'l'} alignItems={'center'}>
{headerItems.map((item, i) => {
return (
<EuiFlexItem key={i} grow={false}>
<div
css={
i < headerItems?.length - 1
? css`
border-right: ${euiTheme.euiBorderWidthThin} solid
${euiTheme.euiBorderColor};
padding-right: ${euiTheme.euiPanelPaddingModifiers.paddingLarge};
`
: null
}
>
{item}
</div>
</EuiFlexItem>
);
})}
</EuiFlexGroup>
</EuiFlexItem>
) : null}
</EuiFlexGroup>
</EuiSplitPanel.Inner>
{isOpen ? (
<EuiSplitPanel.Inner
css={{ borderTop: `${euiTheme.euiBorderWidthThin} solid ${euiTheme.euiBorderColor}` }}
grow={false}
>
{children}
</EuiSplitPanel.Inner>
) : null}
</EuiSplitPanel.Outer>
);
};

export interface StatEntry {
label: string;
value: number;
'data-test-subj'?: string;
}

export interface OverviewStatsBarProps {
inputStats: StatEntry[];
dataTestSub?: string;
}

export const OverviewStatsBar: FC<OverviewStatsBarProps> = ({ inputStats, dataTestSub }) => {
return (
<EuiFlexGroup data-test-subj={dataTestSub} alignItems={'center'} gutterSize={'m'}>
{inputStats.map(({ value, label, 'data-test-subj': dataTestSubjValue }) => {
return (
<EuiFlexItem grow={false} key={label}>
<EuiFlexGroup alignItems={'center'} gutterSize={'s'}>
<EuiFlexItem grow={false}>
<EuiText size={'s'}>{label}:</EuiText>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiBadge data-test-subj={dataTestSubjValue}>{value}</EuiBadge>
</EuiFlexItem>
</EuiFlexGroup>
</EuiFlexItem>
);
})}
</EuiFlexGroup>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/*
* 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 { CollapsiblePanel } from './collapsible_panel';
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,7 @@
*/

import React, { FC } from 'react';
import {
EuiButton,
EuiCallOut,
EuiEmptyPrompt,
EuiFlexGroup,
EuiFlexItem,
EuiImage,
EuiLink,
EuiTitle,
} from '@elastic/eui';
import { EuiButton, EuiEmptyPrompt, EuiImage, EuiLink } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n-react';
import dfaImage from './data_frame_analytics_kibana.png';
Expand All @@ -26,10 +17,7 @@ import { usePermissionCheck } from '../../../../../capabilities/check_capabiliti

export const AnalyticsEmptyPrompt: FC = () => {
const {
services: {
docLinks,
http: { basePath },
},
services: { docLinks },
} = useMlKibana();

const [canCreateDataFrameAnalytics, canStartStopDataFrameAnalytics] = usePermissionCheck([
Expand All @@ -40,7 +28,6 @@ export const AnalyticsEmptyPrompt: FC = () => {
const disabled =
!mlNodesAvailable() || !canCreateDataFrameAnalytics || !canStartStopDataFrameAnalytics;

const transformsLink = `${basePath.get()}/app/management/data/transform`;
const navigateToPath = useNavigateToPath();

const navigateToSourceSelection = async () => {
Expand All @@ -57,16 +44,15 @@ export const AnalyticsEmptyPrompt: FC = () => {
size="fullWidth"
src={dfaImage}
alt={i18n.translate('xpack.ml.dataFrame.analyticsList.emptyPromptTitle', {
defaultMessage: 'Create your first data frame analytics job',
defaultMessage: 'Analyze your data with data frame analytics',
})}
/>
}
color="subdued"
title={
<h2>
<FormattedMessage
id="xpack.ml.dataFrame.analyticsList.emptyPromptTitle"
defaultMessage="Create your first data frame analytics job"
defaultMessage="Analyze your data with data frame analytics"
/>
</h2>
}
Expand All @@ -78,77 +64,26 @@ export const AnalyticsEmptyPrompt: FC = () => {
defaultMessage="Train outlier detection, regression, or classification machine learning models using data frame analytics."
/>
</p>
<EuiCallOut
size="s"
title={
<FormattedMessage
id="xpack.ml.overview.analyticsList.emptyPromptHelperText"
defaultMessage="Before building a data frame analytics job, use {transforms} to construct an {sourcedata}."
values={{
transforms: (
<EuiLink href={transformsLink} target="blank" color={'accent'}>
<FormattedMessage
id="xpack.ml.overview.gettingStartedSectionTransforms"
defaultMessage="transforms"
/>
</EuiLink>
),
sourcedata: (
<EuiLink
href={docLinks.links.ml.dFAPrepareData}
target="blank"
color={'accent'}
external
>
<FormattedMessage
id="xpack.ml.overview.gettingStartedSectionSourceData"
defaultMessage="entity-centric source data set"
/>
</EuiLink>
),
}}
/>
}
iconType="iInCircle"
/>
</>
}
actions={[
<EuiButton
onClick={navigateToSourceSelection}
isDisabled={disabled}
color="primary"
iconType="plusInCircle"
fill
data-test-subj="mlAnalyticsCreateFirstButton"
>
{i18n.translate('xpack.ml.dataFrame.analyticsList.emptyPromptButtonText', {
defaultMessage: 'Create job',
defaultMessage: 'Create data frame analytics job',
})}
</EuiButton>,
<EuiLink href={docLinks.links.ml.dataFrameAnalytics} target="_blank" external>
<FormattedMessage
id="xpack.ml.common.readDocumentationLink"
defaultMessage="Read documentation"
/>
</EuiLink>,
]}
footer={
<EuiFlexGroup gutterSize={'xs'} alignItems={'center'}>
<EuiFlexItem grow={false}>
<EuiTitle size="xxs">
<h3>
<FormattedMessage
id="xpack.ml.common.learnMoreQuestion"
defaultMessage="Want to learn more?"
/>
</h3>
</EuiTitle>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiLink href={docLinks.links.ml.dataFrameAnalytics} target="_blank" external>
<FormattedMessage
id="xpack.ml.common.readDocumentationLink"
defaultMessage="Read documentation"
/>
</EuiLink>
</EuiFlexItem>
</EuiFlexGroup>
}
data-test-subj="mlNoDataFrameAnalyticsFound"
/>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ describe('get_analytics', () => {
// act and assert
expect(getAnalyticsJobsStats(mockResponse)).toEqual({
total: {
label: 'Total analytics jobs',
label: 'Total',
value: 2,
show: true,
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export function getInitialAnalyticsStats(): AnalyticStatsBarStats {
return {
total: {
label: i18n.translate('xpack.ml.overview.statsBar.totalAnalyticsLabel', {
defaultMessage: 'Total analytics jobs',
defaultMessage: 'Total',
}),
value: 0,
show: true,
Expand Down Expand Up @@ -97,12 +97,18 @@ export function getAnalyticsJobsStats(
);
resultStats.failed.show = resultStats.failed.value > 0;
resultStats.total.value = analyticsStats.count;

if (resultStats.total.value === 0) {
resultStats.started.show = false;
resultStats.stopped.show = false;
}

return resultStats;
}

export const getAnalyticsFactory = (
setAnalytics: React.Dispatch<React.SetStateAction<DataFrameAnalyticsListRow[]>>,
setAnalyticsStats: React.Dispatch<React.SetStateAction<AnalyticStatsBarStats | undefined>>,
setAnalyticsStats: (update: AnalyticStatsBarStats | undefined) => void,
setErrorMessage: React.Dispatch<
React.SetStateAction<GetDataFrameAnalyticsStatsResponseError | undefined>
>,
Expand Down
Loading

0 comments on commit 36c9a0c

Please sign in to comment.