Skip to content

Commit

Permalink
[ML] Data Frame Analytics: ensure map view supports dark theme (#85886)
Browse files Browse the repository at this point in the history
* use current eui theme in map

* ensure labels do not overlap. add job type legend

* reduce padding in legend popover
  • Loading branch information
alvarezmelissa87 authored Dec 15, 2020
1 parent 013c176 commit 11713ac
Show file tree
Hide file tree
Showing 7 changed files with 168 additions and 105 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,5 @@ export {
COLOR_RANGE,
COLOR_RANGE_SCALE,
useCurrentEuiTheme,
EuiThemeType,
} from './use_color_range';
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,8 @@ export const useColorRange = (
return scaleTypes[colorRangeScale];
};

export type EuiThemeType = typeof euiThemeLight | typeof euiThemeDark;

export function useCurrentEuiTheme() {
const uiSettings = useUiSettings();
return useMemo(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,19 +28,10 @@
display: 'inline-block';
}

.mlJobMapLegend__trainedModel {
width: 0;
height: 0;
border-left: $euiSizeS solid $euiColorGhost;
border-right: $euiSizeS solid $euiColorGhost;
border-bottom: $euiSizeM solid $euiColorVis3;
display: 'inline-block';
}

.mlJobMapLegend__sourceNode {
height: $euiSizeM;
width: $euiSizeM;
background-color: $euiColorLightShade;
background-color: $euiColorWarning;
border: $euiBorderThin;
border-radius: $euiBorderRadius;
display: 'inline-block';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ import React, {
import cytoscape from 'cytoscape';
// @ts-ignore no declaration file
import dagre from 'cytoscape-dagre';
import { cytoscapeOptions } from './cytoscape_options';
import { EuiThemeType } from '../../../../components/color_range_legend';
import { getCytoscapeOptions } from './cytoscape_options';

cytoscape.use(dagre);

Expand All @@ -25,6 +26,7 @@ export const CytoscapeContext = createContext<cytoscape.Core | undefined>(undefi
interface CytoscapeProps {
children?: ReactNode;
elements: cytoscape.ElementDefinition[];
theme: EuiThemeType;
height: number;
itemsDeleted: boolean;
resetCy: boolean;
Expand Down Expand Up @@ -59,23 +61,24 @@ function getLayoutOptions(width: number, height: number) {
name: 'dagre',
rankDir: 'LR',
fit: true,
padding: 30,
spacingFactor: 0.85,
padding: 20,
spacingFactor: 0.95,
boundingBox: { x1: 0, y1: 0, w: width, h: height },
};
}

export function Cytoscape({
children,
elements,
theme,
height,
itemsDeleted,
resetCy,
style,
width,
}: CytoscapeProps) {
const [ref, cy] = useCytoscape({
...cytoscapeOptions,
...getCytoscapeOptions(theme),
elements,
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@
*/

import cytoscape from 'cytoscape';
import theme from '@elastic/eui/dist/eui_theme_light.json';
import {
ANALYSIS_CONFIG_TYPE,
JOB_MAP_NODE_TYPES,
} from '../../../../../../common/constants/data_frame_analytics';
import { EuiThemeType } from '../../../../components/color_range_legend';
import classificationJobIcon from './icons/ml_classification_job.svg';
import outlierDetectionJobIcon from './icons/ml_outlier_detection_job.svg';
import regressionJobIcon from './icons/ml_regression_job.svg';
Expand All @@ -24,7 +24,7 @@ const MAP_SHAPES = {
} as const;
type MapShapes = typeof MAP_SHAPES[keyof typeof MAP_SHAPES];

function shapeForNode(el: cytoscape.NodeSingular): MapShapes {
function shapeForNode(el: cytoscape.NodeSingular, theme: EuiThemeType): MapShapes {
const type = el.data('type');
switch (type) {
case JOB_MAP_NODE_TYPES.ANALYTICS:
Expand Down Expand Up @@ -55,7 +55,7 @@ function iconForNode(el: cytoscape.NodeSingular) {
}
}

function borderColorForNode(el: cytoscape.NodeSingular) {
function borderColorForNode(el: cytoscape.NodeSingular, theme: EuiThemeType) {
if (el.selected()) {
return theme.euiColorPrimary;
}
Expand All @@ -76,7 +76,7 @@ function borderColorForNode(el: cytoscape.NodeSingular) {
}
}

export const cytoscapeOptions: cytoscape.CytoscapeOptions = {
export const getCytoscapeOptions = (theme: EuiThemeType): cytoscape.CytoscapeOptions => ({
autoungrabify: true,
boxSelectionEnabled: false,
maxZoom: 3,
Expand All @@ -86,10 +86,10 @@ export const cytoscapeOptions: cytoscape.CytoscapeOptions = {
selector: 'node',
style: {
'background-color': (el: cytoscape.NodeSingular) =>
el.data('isRoot') ? theme.euiColorLightShade : theme.euiColorGhost,
el.data('isRoot') ? theme.euiColorWarning : theme.euiColorGhost,
'background-height': '60%',
'background-width': '60%',
'border-color': (el: cytoscape.NodeSingular) => borderColorForNode(el),
'border-color': (el: cytoscape.NodeSingular) => borderColorForNode(el, theme),
'border-style': 'solid',
// @ts-ignore
'background-image': (el: cytoscape.NodeSingular) => iconForNode(el),
Expand All @@ -100,7 +100,7 @@ export const cytoscapeOptions: cytoscape.CytoscapeOptions = {
'font-size': theme.euiFontSizeXS,
'min-zoomed-font-size': parseInt(theme.euiSizeL, 10),
label: 'data(label)',
shape: (el: cytoscape.NodeSingular) => shapeForNode(el),
shape: (el: cytoscape.NodeSingular) => shapeForNode(el, theme),
'text-background-color': theme.euiColorLightestShade,
'text-background-opacity': 0,
'text-background-padding': theme.paddingSizes.xs,
Expand Down Expand Up @@ -128,4 +128,4 @@ export const cytoscapeOptions: cytoscape.CytoscapeOptions = {
},
},
],
};
});
Original file line number Diff line number Diff line change
Expand Up @@ -4,84 +4,145 @@
* you may not use this file except in compliance with the Elastic License.
*/

import React, { FC } from 'react';
import { EuiFlexGroup, EuiFlexItem, EuiText } from '@elastic/eui';
import React, { FC, useState } from 'react';
import { i18n } from '@kbn/i18n';
import {
EuiButtonIcon,
EuiFlexGroup,
EuiFlexItem,
EuiListGroupItem,
EuiListGroup,
EuiPopover,
EuiText,
} from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
import { JOB_MAP_NODE_TYPES } from '../../../../../../common/constants/data_frame_analytics';
import { EuiThemeType } from '../../../../components/color_range_legend';

export const JobMapLegend: FC = () => (
<EuiFlexGroup className="mlJobMapLegend__container" alignItems="center">
<EuiFlexItem grow={false}>
<EuiFlexGroup gutterSize="xs" alignItems="center">
<EuiFlexItem grow={false}>
<span className="mlJobMapLegend__indexPattern" />
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiText size="xs" color="subdued">
<FormattedMessage
id="xpack.ml.dataframe.analyticsMap.legend.indexLabel"
defaultMessage="index"
/>
</EuiText>
</EuiFlexItem>
</EuiFlexGroup>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiFlexGroup gutterSize="xs" alignItems="center">
<EuiFlexItem grow={false}>
<span className="mlJobMapLegend__transform" />
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiText size="xs" color="subdued">
{JOB_MAP_NODE_TYPES.TRANSFORM}
</EuiText>
</EuiFlexItem>
</EuiFlexGroup>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiFlexGroup gutterSize="xs" alignItems="center">
<EuiFlexItem grow={false}>
<span className="mlJobMapLegend__analytics" />
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiText size="xs" color="subdued">
<FormattedMessage
id="xpack.ml.dataframe.analyticsMap.legend.analyticsJobLabel"
defaultMessage="analytics job"
/>
</EuiText>
</EuiFlexItem>
</EuiFlexGroup>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiFlexGroup gutterSize="xs" alignItems="center">
<EuiFlexItem grow={false}>
<span className="mlJobMapLegend__trainedModel" />
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiText size="xs" color="subdued">
<FormattedMessage
id="xpack.ml.dataframe.analyticsMap.legend.trainedModelLabel"
defaultMessage="trained model"
/>
</EuiText>
</EuiFlexItem>
</EuiFlexGroup>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiFlexGroup gutterSize="xs" alignItems="center">
<EuiFlexItem grow={false}>
<span className="mlJobMapLegend__sourceNode" />
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiText size="xs" color="subdued">
<FormattedMessage
id="xpack.ml.dataframe.analyticsMap.legend.rootNodeLabel"
defaultMessage="source node"
/>
</EuiText>
</EuiFlexItem>
</EuiFlexGroup>
</EuiFlexItem>
</EuiFlexGroup>
const getJobTypeList = () => (
<>
<EuiListGroup flush>
<EuiListGroupItem iconType="outlierDetectionJob" label="Outlier detection" size="xs" />

<EuiListGroupItem iconType="regressionJob" label="Regression" size="xs" />

<EuiListGroupItem iconType="classificationJob" label="Classification" size="xs" />
</EuiListGroup>
</>
);

export const JobMapLegend: FC<{ theme: EuiThemeType }> = ({ theme }) => {
const [showJobTypes, setShowJobTypes] = useState<boolean>(false);

return (
<EuiFlexGroup className="mlJobMapLegend__container" alignItems="center">
<EuiFlexItem grow={false}>
<EuiFlexGroup gutterSize="xs" alignItems="center">
<EuiFlexItem grow={false}>
<span className="mlJobMapLegend__sourceNode" />
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiText size="xs" color="subdued">
<FormattedMessage
id="xpack.ml.dataframe.analyticsMap.legend.rootNodeLabel"
defaultMessage="source node"
/>
</EuiText>
</EuiFlexItem>
</EuiFlexGroup>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiFlexGroup gutterSize="xs" alignItems="center">
<EuiFlexItem grow={false}>
<span className="mlJobMapLegend__indexPattern" />
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiText size="xs" color="subdued">
<FormattedMessage
id="xpack.ml.dataframe.analyticsMap.legend.indexLabel"
defaultMessage="index"
/>
</EuiText>
</EuiFlexItem>
</EuiFlexGroup>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiFlexGroup gutterSize="xs" alignItems="center">
<EuiFlexItem grow={false}>
<span className="mlJobMapLegend__transform" />
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiText size="xs" color="subdued">
{JOB_MAP_NODE_TYPES.TRANSFORM}
</EuiText>
</EuiFlexItem>
</EuiFlexGroup>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiFlexGroup gutterSize="xs" alignItems="center">
<EuiFlexItem grow={false}>
<span
style={{
display: 'inline-block',
width: '0px',
height: '0px',
borderLeft: `${theme.euiSizeS} solid ${theme.euiPageBackgroundColor}`,
borderRight: `${theme.euiSizeS} solid ${theme.euiPageBackgroundColor}`,
borderBottom: `${theme.euiSizeM} solid ${theme.euiColorVis3}`,
}}
/>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiText size="xs" color="subdued">
<FormattedMessage
id="xpack.ml.dataframe.analyticsMap.legend.trainedModelLabel"
defaultMessage="trained model"
/>
</EuiText>
</EuiFlexItem>
</EuiFlexGroup>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiFlexGroup gutterSize="xs" alignItems="center">
<EuiFlexItem grow={false}>
<span className="mlJobMapLegend__analytics" />
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiFlexGroup gutterSize="xs" alignItems="center">
<EuiFlexItem grow={false}>
<EuiText size="xs" color="subdued">
<FormattedMessage
id="xpack.ml.dataframe.analyticsMap.legend.analyticsJobLabel"
defaultMessage="analytics jobs"
/>
</EuiText>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiPopover
ownFocus
button={
<EuiButtonIcon
iconSize="s"
onClick={() => setShowJobTypes(!showJobTypes)}
iconType={showJobTypes ? 'arrowUp' : 'arrowDown'}
aria-label={i18n.translate(
'xpack.ml.dataframe.analyticsMap.legend.showJobTypesAriaLabel',
{
defaultMessage: 'Show job types',
}
)}
/>
}
isOpen={showJobTypes}
closePopover={() => setShowJobTypes(false)}
>
{getJobTypeList()}
</EuiPopover>
</EuiFlexItem>
</EuiFlexGroup>
</EuiFlexItem>
</EuiFlexGroup>
</EuiFlexItem>
</EuiFlexGroup>
);
};
Loading

0 comments on commit 11713ac

Please sign in to comment.