[ML] (Accessibility) Fix page heading structure (#56741)

* [ML] (Accessibility) Fix page heading structure

* [ML] Fix file datavisualizer SCSS import

* [ML] Switch to EuiTitle for influencers list and data viz cards

* [ML] Fix positioning of chart tooltip in Single Metric Viewer
This commit is contained in:
Pete Harverson 2020-02-06 09:27:22 +00:00 committed by GitHub
parent 927be66613
commit 595c869780
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
37 changed files with 1544 additions and 1355 deletions

View file

@ -67,7 +67,7 @@ export const CreateJobLinkCard: FC<Props> = ({
</EuiFlexItem>
<EuiFlexItem>
<EuiTitle size="s">
<h4>{title}</h4>
<h3>{title}</h3>
</EuiTitle>
<EuiText color="subdued">
<p>{description}</p>

View file

@ -15,23 +15,23 @@
}
.progress {
display:inline-block;
width: calc(100% - 34px); // SASSTODO: Calc porper value
display: inline-block;
width: calc(100% - 34px); // SASSTODO: Calc proper value
height: 22px;
min-width: 70px;
margin-bottom: 0px;
color: $euiColorDarkShade;
background-color : transparent;
background-color: transparent;
.progress-bar-holder {
width: calc(100% - 28px); // SASSTODO: Calc porper value
width: calc(100% - 28px); // SASSTODO: Calc proper value
}
.progress-bar {
height: $euiSizeXS / 2;
margin-top: $euiSizeM;
text-align: right;
line-height: 18px; // SASSTODO: Calc porper value
line-height: 18px; // SASSTODO: Calc proper value
display: inline-block;
transition: none;
}
@ -42,6 +42,7 @@
.progress-bar {
background-color: $mlColorCritical;
}
.score-label {
border-color: $mlColorCritical;
}
@ -51,6 +52,7 @@
.progress-bar {
background-color: $mlColorMajor;
}
.score-label {
border-color: $mlColorMajor;
}
@ -60,6 +62,7 @@
.progress-bar {
background-color: $mlColorMinor;
}
.score-label {
border-color: $mlColorMinor;
}
@ -69,6 +72,7 @@
.progress-bar {
background-color: $mlColorWarning;
}
.score-label {
border-color: $mlColorWarning;
}
@ -99,8 +103,7 @@
}
}
// SASSTODO: Can .eui-textBreakAll
// SASSTODO: Can .eui-textBreakAll
.ml-influencers-list-tooltip {
word-break: break-all;
}

View file

@ -11,7 +11,7 @@
import PropTypes from 'prop-types';
import React from 'react';
import { EuiFlexGroup, EuiFlexItem, EuiSpacer, EuiText, EuiTitle, EuiToolTip } from '@elastic/eui';
import { EuiFlexGroup, EuiFlexItem, EuiSpacer, EuiTitle, EuiToolTip } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
import { abbreviateWholeNumber } from '../../formatters/abbreviate_whole_number';
@ -115,7 +115,7 @@ function InfluencersByName({ influencerFieldName, influencerFilter, fieldValues
return (
<React.Fragment key={influencerFieldName}>
<EuiTitle size="xs" data-test-subj={`mlInfluencerFieldName ${influencerFieldName}`}>
<h4>{influencerFieldName}</h4>
<h3>{influencerFieldName}</h3>
</EuiTitle>
<EuiSpacer size="xs" />
{influencerValues}
@ -131,17 +131,17 @@ InfluencersByName.propTypes = {
export function InfluencersList({ influencers, influencerFilter }) {
if (influencers === undefined || Object.keys(influencers).length === 0) {
return (
<EuiFlexGroup justifyContent="spaceAround">
<EuiFlexGroup justifyContent="spaceAround" className="ml-influencers-list">
<EuiFlexItem grow={false}>
<EuiSpacer size="xxl" />
<EuiText>
<h4>
<EuiTitle size="xs" className="influencer-title">
<h3>
<FormattedMessage
id="xpack.ml.influencersList.noInfluencersFoundTitle"
defaultMessage="No influencers found"
/>
</h4>
</EuiText>
</h3>
</EuiTitle>
</EuiFlexItem>
</EuiFlexGroup>
);

View file

@ -62,12 +62,12 @@ export const DatavisualizerSelector: FC = () => {
<EuiFlexGroup gutterSize="xl">
<EuiFlexItem grow={false}>
<EuiTitle size="l">
<h2>
<h1>
<FormattedMessage
id="xpack.ml.datavisualizer.selector.dataVisualizerTitle"
defaultMessage="Data Visualizer"
/>
</h2>
</h1>
</EuiTitle>
</EuiFlexItem>
</EuiFlexGroup>

View file

@ -1,3 +0,0 @@
.file-datavisualizer__content {
padding: $euiSize;
}

View file

@ -1,2 +1 @@
@import 'file_datavisualizer';
@import 'components/index';

View file

@ -60,12 +60,12 @@ export function LoadingPanel() {
<EuiPageContent className="file-datavisualizer-about-panel__content" paddingSize="l">
<div style={{ textAlign: 'center' }}>
<EuiTitle size="s">
<h3 role="alert">
<h1 role="alert">
<FormattedMessage
id="xpack.ml.fileDatavisualizer.aboutPanel.analyzingDataTitle"
defaultMessage="Analyzing data"
/>
</h3>
</h1>
</EuiTitle>
<EuiSpacer size="l" />

View file

@ -27,7 +27,7 @@ export function WelcomeContent() {
</EuiFlexItem>
<EuiFlexItem>
<EuiTitle size="m">
<h3>
<h1>
<FormattedMessage
id="xpack.ml.fileDatavisualizer.welcomeContent.visualizeDataFromLogFileTitle"
defaultMessage="Visualize data from a log file&nbsp;{experimentalBadge}"
@ -44,7 +44,7 @@ export function WelcomeContent() {
),
}}
/>
</h3>
</h1>
</EuiTitle>
<EuiSpacer size="s" />
<EuiText>

View file

@ -15,12 +15,12 @@ export function AnalysisSummary({ results }) {
return (
<React.Fragment>
<EuiTitle size="s">
<h3>
<h2>
<FormattedMessage
id="xpack.ml.fileDatavisualizer.analysisSummary.summaryTitle"
defaultMessage="Summary"
/>
</h3>
</h2>
</EuiTitle>
<EuiSpacer size="m" />

View file

@ -22,12 +22,12 @@ export function FileContents({ data, format, numberOfLines }) {
return (
<React.Fragment>
<EuiTitle size="s">
<h3>
<h2>
<FormattedMessage
id="xpack.ml.fileDatavisualizer.fileContents.fileContentsTitle"
defaultMessage="File contents"
/>
</h3>
</h2>
</EuiTitle>
<div>

View file

@ -36,6 +36,7 @@ export class FileDataVisualizerView extends Component {
this.state = {
files: {},
fileName: '',
fileContents: '',
fileSize: 0,
fileTooLarge: false,
@ -71,6 +72,7 @@ export class FileDataVisualizerView extends Component {
loading: files.length > 0,
bottomBarVisible: files.length > 0,
loaded: false,
fileName: '',
fileContents: '',
fileSize: 0,
fileTooLarge: false,
@ -93,6 +95,7 @@ export class FileDataVisualizerView extends Component {
const data = fileContents.data;
this.setState({
fileContents: data,
fileName: file.name,
fileSize: file.size,
});
@ -110,6 +113,7 @@ export class FileDataVisualizerView extends Component {
loaded: false,
loading: false,
fileTooLarge: true,
fileName: file.name,
fileSize: file.size,
});
}
@ -240,6 +244,7 @@ export class FileDataVisualizerView extends Component {
loaded,
results,
fileContents,
fileName,
fileSize,
fileTooLarge,
fileCouldNotBeRead,
@ -256,7 +261,7 @@ export class FileDataVisualizerView extends Component {
: [];
return (
<div className="file-datavisualizer__content">
<div>
{mode === MODE.READ && (
<React.Fragment>
{!loading && !loaded && <AboutPanel onFilePickerChange={this.onFilePickerChange} />}
@ -275,6 +280,7 @@ export class FileDataVisualizerView extends Component {
{loaded && (
<ResultsView
results={results}
fileName={fileName}
data={fileContents}
showEditFlyout={() => this.showEditFlyout()}
/>
@ -304,8 +310,8 @@ export class FileDataVisualizerView extends Component {
<React.Fragment>
<ImportView
results={results}
fileName={fileName}
fileContents={fileContents}
fileSize={fileSize}
indexPatterns={this.props.indexPatterns}
kibanaConfig={this.props.kibanaConfig}
showBottomBar={this.showBottomBar}

View file

@ -7,7 +7,15 @@
import { FormattedMessage } from '@kbn/i18n/react';
import React, { Component } from 'react';
import { EuiButton, EuiSpacer, EuiPanel, EuiTitle } from '@elastic/eui';
import {
EuiButton,
EuiPage,
EuiPageBody,
EuiPageContentHeader,
EuiPanel,
EuiSpacer,
EuiTitle,
} from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { importerFactory } from './importer';
@ -433,113 +441,121 @@ export class ImportView extends Component {
initialized === true;
return (
<React.Fragment>
<EuiPanel>
<EuiTitle size="s">
<h3>
<FormattedMessage
id="xpack.ml.fileDatavisualizer.importView.importDataTitle"
defaultMessage="Import data"
/>
&nbsp;
<ExperimentalBadge
tooltipContent={
<FormattedMessage
id="xpack.ml.fileDatavisualizer.importView.experimentalFeatureTooltip"
defaultMessage="Experimental feature. We'd love to hear your feedback."
/>
}
/>
</h3>
</EuiTitle>
<ImportSettings
index={index}
indexPattern={indexPattern}
initialized={initialized}
onIndexChange={this.onIndexChange}
createIndexPattern={createIndexPattern}
onCreateIndexPatternChange={this.onCreateIndexPatternChange}
onIndexPatternChange={this.onIndexPatternChange}
indexSettingsString={indexSettingsString}
mappingsString={mappingsString}
pipelineString={pipelineString}
onIndexSettingsStringChange={this.onIndexSettingsStringChange}
onMappingsStringChange={this.onMappingsStringChange}
onPipelineStringChange={this.onPipelineStringChange}
indexNameError={indexNameError}
indexPatternNameError={indexPatternNameError}
/>
<EuiPage>
<EuiPageBody>
<EuiPageContentHeader>
<EuiTitle>
<h1>{this.props.fileName}</h1>
</EuiTitle>
</EuiPageContentHeader>
<EuiSpacer size="m" />
<EuiPanel>
<EuiTitle size="s">
<h2>
<FormattedMessage
id="xpack.ml.fileDatavisualizer.importView.importDataTitle"
defaultMessage="Import data"
/>
&nbsp;
<ExperimentalBadge
tooltipContent={
<FormattedMessage
id="xpack.ml.fileDatavisualizer.importView.experimentalFeatureTooltip"
defaultMessage="Experimental feature. We'd love to hear your feedback."
/>
}
/>
</h2>
</EuiTitle>
{(initialized === false || importing === true) && (
<EuiButton
isDisabled={disableImport}
onClick={this.clickImport}
isLoading={importing}
iconSide="right"
fill
>
<FormattedMessage
id="xpack.ml.fileDatavisualizer.importView.importButtonLabel"
defaultMessage="Import"
/>
</EuiButton>
)}
<ImportSettings
index={index}
indexPattern={indexPattern}
initialized={initialized}
onIndexChange={this.onIndexChange}
createIndexPattern={createIndexPattern}
onCreateIndexPatternChange={this.onCreateIndexPatternChange}
onIndexPatternChange={this.onIndexPatternChange}
indexSettingsString={indexSettingsString}
mappingsString={mappingsString}
pipelineString={pipelineString}
onIndexSettingsStringChange={this.onIndexSettingsStringChange}
onMappingsStringChange={this.onMappingsStringChange}
onPipelineStringChange={this.onPipelineStringChange}
indexNameError={indexNameError}
indexPatternNameError={indexPatternNameError}
/>
{initialized === true && importing === false && (
<EuiButton onClick={this.clickReset}>
<FormattedMessage
id="xpack.ml.fileDatavisualizer.importView.resetButtonLabel"
defaultMessage="Reset"
/>
</EuiButton>
)}
</EuiPanel>
{initialized === true && (
<React.Fragment>
<EuiSpacer size="m" />
<EuiPanel>
<ImportProgress statuses={statuses} />
{(initialized === false || importing === true) && (
<EuiButton
isDisabled={disableImport}
onClick={this.clickImport}
isLoading={importing}
iconSide="right"
fill
>
<FormattedMessage
id="xpack.ml.fileDatavisualizer.importView.importButtonLabel"
defaultMessage="Import"
/>
</EuiButton>
)}
{imported === true && (
<React.Fragment>
<EuiSpacer size="m" />
{initialized === true && importing === false && (
<EuiButton onClick={this.clickReset}>
<FormattedMessage
id="xpack.ml.fileDatavisualizer.importView.resetButtonLabel"
defaultMessage="Reset"
/>
</EuiButton>
)}
</EuiPanel>
<ImportSummary
index={index}
indexPattern={indexPattern === '' ? index : indexPattern}
ingestPipelineId={ingestPipelineId}
docCount={docCount}
importFailures={importFailures}
createIndexPattern={createIndexPattern}
createPipeline={createPipeline}
/>
{initialized === true && (
<React.Fragment>
<EuiSpacer size="m" />
<EuiSpacer size="l" />
<EuiPanel>
<ImportProgress statuses={statuses} />
<ResultsLinks
index={index}
indexPatternId={indexPatternId}
timeFieldName={timeFieldName}
createIndexPattern={createIndexPattern}
/>
</React.Fragment>
)}
</EuiPanel>
</React.Fragment>
)}
{errors.length > 0 && (
<React.Fragment>
<EuiSpacer size="m" />
{imported === true && (
<React.Fragment>
<EuiSpacer size="m" />
<ImportErrors errors={errors} statuses={statuses} />
</React.Fragment>
)}
</React.Fragment>
<ImportSummary
index={index}
indexPattern={indexPattern === '' ? index : indexPattern}
ingestPipelineId={ingestPipelineId}
docCount={docCount}
importFailures={importFailures}
createIndexPattern={createIndexPattern}
createPipeline={createPipeline}
/>
<EuiSpacer size="l" />
<ResultsLinks
index={index}
indexPatternId={indexPatternId}
timeFieldName={timeFieldName}
createIndexPattern={createIndexPattern}
/>
</React.Fragment>
)}
</EuiPanel>
</React.Fragment>
)}
{errors.length > 0 && (
<React.Fragment>
<EuiSpacer size="m" />
<ImportErrors errors={errors} statuses={statuses} />
</React.Fragment>
)}
</EuiPageBody>
</EuiPage>
);
}
}

View file

@ -7,13 +7,22 @@
import { injectI18n, FormattedMessage } from '@kbn/i18n/react';
import React from 'react';
import { EuiTabbedContent, EuiButton, EuiSpacer, EuiPanel } from '@elastic/eui';
import {
EuiButton,
EuiPage,
EuiPageBody,
EuiPageContentHeader,
EuiPanel,
EuiTabbedContent,
EuiSpacer,
EuiTitle,
} from '@elastic/eui';
import { FileContents } from '../file_contents';
import { AnalysisSummary } from '../analysis_summary';
import { FieldsStats } from '../fields_stats';
export const ResultsView = injectI18n(function({ data, results, showEditFlyout, intl }) {
export const ResultsView = injectI18n(function({ data, fileName, results, showEditFlyout, intl }) {
console.log(results);
const tabs = [
@ -28,35 +37,45 @@ export const ResultsView = injectI18n(function({ data, results, showEditFlyout,
];
return (
<div className="results">
<EuiPanel>
<FileContents
data={data}
format={results.format}
numberOfLines={results.num_lines_analyzed}
/>
</EuiPanel>
<EuiSpacer size="m" />
<EuiPanel>
<AnalysisSummary results={results} />
<EuiPage>
<EuiPageBody>
<EuiPageContentHeader>
<EuiTitle>
<h1>{fileName}</h1>
</EuiTitle>
</EuiPageContentHeader>
<EuiSpacer size="m" />
<div className="results">
<EuiPanel>
<FileContents
data={data}
format={results.format}
numberOfLines={results.num_lines_analyzed}
/>
</EuiPanel>
<EuiButton onClick={() => showEditFlyout()}>
<FormattedMessage
id="xpack.ml.fileDatavisualizer.resultsView.overrideSettingsButtonLabel"
defaultMessage="Override settings"
/>
</EuiButton>
</EuiPanel>
<EuiSpacer size="m" />
<EuiSpacer size="m" />
<EuiPanel>
<AnalysisSummary results={results} />
<EuiPanel>
<EuiTabbedContent tabs={tabs} initialSelectedTab={tabs[0]} onTabClick={() => {}} />
</EuiPanel>
</div>
<EuiSpacer size="m" />
<EuiButton onClick={() => showEditFlyout()}>
<FormattedMessage
id="xpack.ml.fileDatavisualizer.resultsView.overrideSettingsButtonLabel"
defaultMessage="Override settings"
/>
</EuiButton>
</EuiPanel>
<EuiSpacer size="m" />
<EuiPanel>
<EuiTabbedContent tabs={tabs} initialSelectedTab={tabs[0]} onTabClick={() => {}} />
</EuiPanel>
</div>
</EuiPageBody>
</EuiPage>
);
});

View file

@ -100,4 +100,8 @@
padding: $euiSizeS $euiSizeS 0px $euiSizeS;
text-align: center;
}
.mlFieldDataCard__valuesTitle {
text-transform: uppercase;
}
}

View file

@ -5,7 +5,7 @@
*/
import React, { FC } from 'react';
import { EuiIcon, EuiSpacer, EuiText } from '@elastic/eui';
import { EuiIcon, EuiSpacer, EuiText, EuiTitle } from '@elastic/eui';
import { Axis, BarSeries, Chart, Settings } from '@elastic/charts';
import { FormattedMessage } from '@kbn/i18n/react';
@ -50,15 +50,15 @@ export const BooleanContent: FC<FieldDataCardProps> = ({ config }) => {
<EuiSpacer size="m" />
<div>
<EuiText size="s">
<h6>
<EuiTitle size="xxxs" className="mlFieldDataCard__valuesTitle">
<span>
<FormattedMessage
id="xpack.ml.fieldDataCard.cardBoolean.valuesLabel"
defaultMessage="Values"
/>
</h6>
</EuiText>
<EuiSpacer size="s" />
</span>
</EuiTitle>
<EuiSpacer size="xs" />
<Chart renderer="canvas" className="story-chart" size={{ height: 200 }}>
<Axis id="bottom" position="bottom" showOverlappingTicks />
<Settings

View file

@ -5,7 +5,7 @@
*/
import React, { FC } from 'react';
import { EuiIcon, EuiSpacer, EuiText } from '@elastic/eui';
import { EuiIcon, EuiSpacer, EuiText, EuiTitle } from '@elastic/eui';
// @ts-ignore
import { formatDate } from '@elastic/eui/lib/services/format';
@ -57,16 +57,15 @@ export const KeywordContent: FC<FieldDataCardProps> = ({ config }) => {
<EuiSpacer size="m" />
<div>
<EuiText size="s">
<h6>
<EuiTitle size="xxxs" className="mlFieldDataCard__valuesTitle">
<span>
<FormattedMessage
id="xpack.ml.fieldDataCard.cardKeyword.topValuesLabel"
defaultMessage="Top values"
/>
</h6>
</EuiText>
<EuiSpacer size="s" />
</span>
</EuiTitle>
<EuiSpacer size="xs" />
<TopValues stats={stats} fieldFormat={fieldFormat} barColor="secondary" />
</div>
</div>

View file

@ -6,7 +6,7 @@
import React, { FC } from 'react';
import { EuiListGroup, EuiListGroupItem, EuiSpacer, EuiText } from '@elastic/eui';
import { EuiListGroup, EuiListGroupItem, EuiSpacer, EuiTitle } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
@ -32,8 +32,8 @@ export const ExamplesList: FC<Props> = ({ examples }) => {
return (
<div>
<EuiText size="s">
<h6>
<EuiTitle size="xxxs" className="mlFieldDataCard__valuesTitle">
<span>
<FormattedMessage
id="xpack.ml.fieldDataCard.cardText.examplesTitle"
defaultMessage="{numExamples, plural, one {value} other {examples}}"
@ -41,8 +41,8 @@ export const ExamplesList: FC<Props> = ({ examples }) => {
numExamples: examples.length,
}}
/>
</h6>
</EuiText>
</span>
</EuiTitle>
<EuiSpacer size="s" />
<EuiListGroup flush={true} showToolTips={true}>
{examplesContent}

View file

@ -22,7 +22,7 @@
border-radius: $euiBorderRadius;
display: inline-block;
// SASSTODO: Make a proper selector
// SASSTODO: Make a proper selector
i {
color: $euiColorPrimary;
margin-right: $euiSizeXS;
@ -46,7 +46,7 @@
.results-container {
padding: 0px 0px $euiSize 0px;
// SASSTODO: Overwrite of bootstrap
// SASSTODO: Overwrite of bootstrap
.col-xs-12 {
width: calc(100% - #{$euiSizeXL});
padding-left: $euiSize;
@ -61,6 +61,8 @@
}
.panel-title {
font-size: $euiFontSizeM;
font-weight: 400;
color: $euiColorDarkShade;
display: inline-block;
padding-bottom: $euiSizeXS;
@ -75,7 +77,7 @@
.ml-controls {
padding-bottom: $euiSizeS;
// SASSTODO: Make a proper selector
// SASSTODO: Make a proper selector
label {
font-size: $euiFontSizeXS;
padding: $euiSizeXS;
@ -111,6 +113,7 @@
margin-left: 176px;
height: 22px;
white-space: nowrap;
// background-color: #CCC;
.sl-cell {
height: 10px;
@ -125,15 +128,19 @@
color: $euiColorDarkShade;
}
}
.sl-cell-hover {
visibility: visible;
i {
display: block;
margin-top: -6px;
}
}
.sl-cell-active-hover {
visibility: visible;
.floating-time-label {
display: inline-block;
}
@ -160,6 +167,7 @@
overflow: hidden;
text-overflow: ellipsis;
}
div.lane-label.lane-label-masked {
opacity: 0.3;
}
@ -180,15 +188,19 @@
border-right: $euiBorderThin;
vertical-align: top;
position: relative;
.sl-cell-inner, .sl-cell-inner-dragselect {
.sl-cell-inner,
.sl-cell-inner-dragselect {
height: 26px;
margin: 1px;
border-radius: 2px;
text-align: center;
}
.sl-cell-inner.sl-cell-inner-masked {
opacity: 0.2;
}
.sl-cell-inner.sl-cell-inner-selected,
.sl-cell-inner-dragselect.sl-cell-inner-selected {
border: 2px solid $euiColorDarkShade;
@ -200,13 +212,16 @@
opacity: 0.4;
}
}
.sl-cell:hover {
.sl-cell-inner {
opacity: 0.8;
cursor: pointer;
}
}
.sl-cell.ds-selected {
.sl-cell-inner,
.sl-cell-inner-dragselect {
border: 2px solid $euiColorDarkShade;
@ -230,14 +245,17 @@
height: 25px;
margin-top: $euiSizeXS / 2;
margin-left: 175px;
/* hide d3's domain line */
path.domain {
display: none;
}
/* hide d3's tick line */
g.tick line {
display: none;
}
/* override d3's default tick styles */
g.tick text {
font-size: 11px;
@ -249,12 +267,12 @@
line.gridLine {
stroke: $euiBorderColor;
fill: none;
shape-rendering : crispEdges;
stroke-width : 1px;
shape-rendering: crispEdges;
stroke-width: 1px;
}
rect.gridCell {
shape-rendering : crispEdges;
shape-rendering: crispEdges;
}
rect.hovered {
@ -278,6 +296,7 @@
/* using !important in the following rule because other related legacy rules have more specifity. */
.mlDragselectDragging {
.sl-cell-inner,
.sl-cell-inner-dragselect {
opacity: 0.6 !important;
@ -290,14 +309,17 @@
div.lane {
div.cells-container {
.sl-cell.ds-selected {
.sl-cell-inner,
.sl-cell-inner-dragselect {
border-width: 0px !important;
opacity: 1 !important;
}
.sl-cell-inner.sl-cell-inner-selected {
border-width: $euiSizeXS / 2 !important;
}
.sl-cell-inner.sl-cell-inner-masked {
opacity: 0.6 !important;
}

View file

@ -21,8 +21,12 @@ import {
EuiFlexItem,
EuiFormRow,
EuiIconTip,
EuiPage,
EuiPageBody,
EuiScreenReaderOnly,
EuiSelect,
EuiSpacer,
EuiTitle,
} from '@elastic/eui';
import { AnnotationFlyout } from '../components/annotations/annotation_flyout';
@ -87,8 +91,17 @@ function mapSwimlaneOptionsToEuiOptions(options) {
const ExplorerPage = ({ children, jobSelectorProps, resizeRef }) => (
<div ref={resizeRef} data-test-subj="mlPageAnomalyExplorer">
<NavigationMenu tabId="explorer" />
<JobSelector {...jobSelectorProps} />
{children}
<EuiPage style={{ padding: '0px', background: 'none' }}>
<EuiPageBody>
<EuiScreenReaderOnly>
<h1>
<FormattedMessage id="xpack.ml.explorer.pageTitle" defaultMessage="Anomaly Explorer" />
</h1>
</EuiScreenReaderOnly>
<JobSelector {...jobSelectorProps} />
{children}
</EuiPageBody>
</EuiPage>
</div>
);
@ -343,7 +356,7 @@ export class Explorer extends React.Component {
return (
<ExplorerPage jobSelectorProps={jobSelectorProps} resizeRef={this.resizeRef}>
<div className="results-container">
{/* Make sure ChartTooltip is inside this plain wrapping div so positioning can be infered correctly. */}
{/* Make sure ChartTooltip is inside wrapping div with 0px left/right padding so positioning can be inferred correctly. */}
<ChartTooltip />
{noInfluencersConfigured === false && influencers !== undefined && (
@ -372,27 +385,28 @@ export class Explorer extends React.Component {
)}
{noInfluencersConfigured === false && (
<div
className="column col-xs-2 euiText"
data-test-subj="mlAnomalyExplorerInfluencerList"
>
<span className="panel-title">
<FormattedMessage
id="xpack.ml.explorer.topInfuencersTitle"
defaultMessage="Top Influencers"
/>
</span>
<div className="column col-xs-2" data-test-subj="mlAnomalyExplorerInfluencerList">
<EuiTitle className="panel-title">
<h2>
<FormattedMessage
id="xpack.ml.explorer.topInfuencersTitle"
defaultMessage="Top influencers"
/>
</h2>
</EuiTitle>
<InfluencersList influencers={influencers} influencerFilter={this.applyFilter} />
</div>
)}
<div className={mainColumnClasses}>
<span className="panel-title euiText">
<FormattedMessage
id="xpack.ml.explorer.anomalyTimelineTitle"
defaultMessage="Anomaly timeline"
/>
</span>
<EuiTitle className="panel-title">
<h2>
<FormattedMessage
id="xpack.ml.explorer.anomalyTimelineTitle"
defaultMessage="Anomaly timeline"
/>
</h2>
</EuiTitle>
<div
className="ml-explorer-swimlane euiText"
@ -507,12 +521,14 @@ export class Explorer extends React.Component {
{annotationsData.length > 0 && (
<>
<span className="panel-title euiText">
<FormattedMessage
id="xpack.ml.explorer.annotationsTitle"
defaultMessage="Annotations"
/>
</span>
<EuiTitle className="panel-title">
<h2>
<FormattedMessage
id="xpack.ml.explorer.annotationsTitle"
defaultMessage="Annotations"
/>
</h2>
</EuiTitle>
<AnnotationsTable
annotations={annotationsData}
drillDown={true}
@ -523,9 +539,14 @@ export class Explorer extends React.Component {
</>
)}
<span className="panel-title euiText">
<FormattedMessage id="xpack.ml.explorer.anomaliesTitle" defaultMessage="Anomalies" />
</span>
<EuiTitle className="panel-title">
<h2>
<FormattedMessage
id="xpack.ml.explorer.anomaliesTitle"
defaultMessage="Anomalies"
/>
</h2>
</EuiTitle>
<EuiFlexGroup
direction="row"

View file

@ -7,7 +7,16 @@
import React, { Component } from 'react';
import { timefilter } from 'ui/timefilter';
import { FormattedMessage } from '@kbn/i18n/react';
import { EuiFlexGroup, EuiFlexItem, EuiSpacer, EuiTitle } from '@elastic/eui';
import {
EuiFlexGroup,
EuiFlexItem,
EuiPage,
EuiPageBody,
EuiPageHeader,
EuiPageHeaderSection,
EuiSpacer,
EuiTitle,
} from '@elastic/eui';
import { ml } from '../../../../services/ml_api_service';
import { checkForAutoStartDatafeed, filterJobs, loadFullJob } from '../utils';
@ -348,109 +357,18 @@ export class JobsListView extends Component {
renderManagementJobsListComponents() {
const {
isRefreshing,
loading,
itemIdToExpandedRowMap,
jobsSummaryList,
filteredJobsSummaryList,
fullJobsList,
selectedJobs,
} = this.state;
return (
<div className="managementJobsList">
<div>
<JobFilterBar setFilters={this.setFilters} />
</div>
<JobsList
jobsSummaryList={filteredJobsSummaryList}
fullJobsList={fullJobsList}
itemIdToExpandedRowMap={itemIdToExpandedRowMap}
toggleRow={this.toggleRow}
selectJobChange={this.selectJobChange}
selectedJobsCount={selectedJobs.length}
loading={loading}
isManagementTable={true}
isMlEnabledInSpace={this.props.isMlEnabledInSpace}
/>
</div>
);
}
renderJobsListComponents() {
const { loading, jobsSummaryList } = this.state;
const jobIds = jobsSummaryList.map(j => j.id);
return (
<div>
<div className="actions-bar">
<MultiJobActions
selectedJobs={this.state.selectedJobs}
allJobIds={jobIds}
showStartDatafeedModal={this.showStartDatafeedModal}
showDeleteJobModal={this.showDeleteJobModal}
refreshJobs={() => this.refreshJobSummaryList(true)}
/>
<JobFilterBar setFilters={this.setFilters} />
</div>
<JobsList
jobsSummaryList={this.state.filteredJobsSummaryList}
fullJobsList={this.state.fullJobsList}
itemIdToExpandedRowMap={this.state.itemIdToExpandedRowMap}
toggleRow={this.toggleRow}
selectJobChange={this.selectJobChange}
showEditJobFlyout={this.showEditJobFlyout}
showDeleteJobModal={this.showDeleteJobModal}
showStartDatafeedModal={this.showStartDatafeedModal}
refreshJobs={() => this.refreshJobSummaryList(true)}
selectedJobsCount={this.state.selectedJobs.length}
loading={loading}
/>
<EditJobFlyout
setShowFunction={this.setShowEditJobFlyoutFunction}
unsetShowFunction={this.unsetShowEditJobFlyoutFunction}
refreshJobs={() => this.refreshJobSummaryList(true)}
allJobIds={jobIds}
/>
<DeleteJobModal
setShowFunction={this.setShowDeleteJobModalFunction}
unsetShowFunction={this.unsetShowDeleteJobModalFunction}
refreshJobs={() => this.refreshJobSummaryList(true)}
/>
<StartDatafeedModal
setShowFunction={this.setShowStartDatafeedModalFunction}
unsetShowFunction={this.unsetShowDeleteJobModalFunction}
getShowCreateWatchFlyoutFunction={this.getShowCreateWatchFlyoutFunction}
refreshJobs={() => this.refreshJobSummaryList(true)}
/>
<CreateWatchFlyout
setShowFunction={this.setShowCreateWatchFlyoutFunction}
unsetShowFunction={this.unsetShowCreateWatchFlyoutFunction}
/>
</div>
);
}
render() {
const { isRefreshing, jobsSummaryList } = this.state;
const { isManagementTable } = this.props;
return (
<div className="job-management" data-test-subj="ml-jobs-list">
{!isManagementTable && (
<>
<EuiTitle>
<h1>
<FormattedMessage
id="xpack.ml.jobsList.title"
defaultMessage="Anomaly detection jobs"
/>
</h1>
</EuiTitle>
<EuiSpacer size="m" />
</>
)}
<NodeAvailableWarning />
<UpgradeWarning />
<EuiFlexGroup justifyContent="spaceBetween">
<EuiFlexItem grow={false}>
<JobStatsBar jobsSummaryList={jobsSummaryList} />
@ -463,19 +381,133 @@ export class JobsListView extends Component {
isRefreshing={isRefreshing}
/>
</EuiFlexItem>
{!isManagementTable && (
<EuiFlexItem grow={false}>
<NewJobButton />
</EuiFlexItem>
)}
</EuiFlexGroup>
</EuiFlexItem>
</EuiFlexGroup>
<EuiSpacer size="s" />
<div className="managementJobsList">
<div>
<JobFilterBar setFilters={this.setFilters} />
</div>
<JobsList
jobsSummaryList={filteredJobsSummaryList}
fullJobsList={fullJobsList}
itemIdToExpandedRowMap={itemIdToExpandedRowMap}
toggleRow={this.toggleRow}
selectJobChange={this.selectJobChange}
selectedJobsCount={selectedJobs.length}
loading={loading}
isManagementTable={true}
isMlEnabledInSpace={this.props.isMlEnabledInSpace}
/>
</div>
</div>
);
}
{!isManagementTable && this.renderJobsListComponents()}
{isManagementTable && this.renderManagementJobsListComponents()}
renderJobsListComponents() {
const { isRefreshing, loading, jobsSummaryList } = this.state;
const jobIds = jobsSummaryList.map(j => j.id);
return (
<EuiPage data-test-subj="ml-jobs-list">
<EuiPageBody>
<EuiPageHeader>
<EuiPageHeaderSection>
<EuiTitle>
<h1>
<FormattedMessage
id="xpack.ml.jobsList.title"
defaultMessage="Anomaly detection jobs"
/>
</h1>
</EuiTitle>
</EuiPageHeaderSection>
</EuiPageHeader>
<NodeAvailableWarning />
<UpgradeWarning />
<EuiFlexGroup justifyContent="spaceBetween">
<EuiFlexItem grow={false}>
<JobStatsBar jobsSummaryList={jobsSummaryList} />
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiFlexGroup alignItems="center" gutterSize="s">
<EuiFlexItem grow={false}>
<RefreshJobsListButton
onRefreshClick={this.onRefreshClick}
isRefreshing={isRefreshing}
/>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<NewJobButton />
</EuiFlexItem>
</EuiFlexGroup>
</EuiFlexItem>
</EuiFlexGroup>
<EuiSpacer size="s" />
<div>
<div className="actions-bar">
<MultiJobActions
selectedJobs={this.state.selectedJobs}
allJobIds={jobIds}
showStartDatafeedModal={this.showStartDatafeedModal}
showDeleteJobModal={this.showDeleteJobModal}
refreshJobs={() => this.refreshJobSummaryList(true)}
/>
<JobFilterBar setFilters={this.setFilters} />
</div>
<JobsList
jobsSummaryList={this.state.filteredJobsSummaryList}
fullJobsList={this.state.fullJobsList}
itemIdToExpandedRowMap={this.state.itemIdToExpandedRowMap}
toggleRow={this.toggleRow}
selectJobChange={this.selectJobChange}
showEditJobFlyout={this.showEditJobFlyout}
showDeleteJobModal={this.showDeleteJobModal}
showStartDatafeedModal={this.showStartDatafeedModal}
refreshJobs={() => this.refreshJobSummaryList(true)}
selectedJobsCount={this.state.selectedJobs.length}
loading={loading}
/>
<EditJobFlyout
setShowFunction={this.setShowEditJobFlyoutFunction}
unsetShowFunction={this.unsetShowEditJobFlyoutFunction}
refreshJobs={() => this.refreshJobSummaryList(true)}
allJobIds={jobIds}
/>
<DeleteJobModal
setShowFunction={this.setShowDeleteJobModalFunction}
unsetShowFunction={this.unsetShowDeleteJobModalFunction}
refreshJobs={() => this.refreshJobSummaryList(true)}
/>
<StartDatafeedModal
setShowFunction={this.setShowStartDatafeedModalFunction}
unsetShowFunction={this.unsetShowDeleteJobModalFunction}
getShowCreateWatchFlyoutFunction={this.getShowCreateWatchFlyoutFunction}
refreshJobs={() => this.refreshJobSummaryList(true)}
/>
<CreateWatchFlyout
setShowFunction={this.setShowCreateWatchFlyoutFunction}
unsetShowFunction={this.unsetShowCreateWatchFlyoutFunction}
/>
</div>
</EuiPageBody>
</EuiPage>
);
}
render() {
const { isManagementTable } = this.props;
return (
<div>
{!isManagementTable
? this.renderJobsListComponents()
: this.renderManagementJobsListComponents()}
</div>
);
}

View file

@ -174,13 +174,13 @@ export const Page: FC = () => {
<EuiPage data-test-subj="mlPageJobTypeSelection">
<EuiPageBody restrictWidth={1200}>
<EuiTitle size="l">
<h2>
<h1>
<FormattedMessage
id="xpack.ml.newJob.wizard.jobType.createJobFromTitle"
defaultMessage="Create a job from the {pageTitleLabel}"
values={{ pageTitleLabel }}
/>
</h2>
</h1>
</EuiTitle>
<EuiSpacer />
@ -204,16 +204,16 @@ export const Page: FC = () => {
)}
<div hidden={recognizerResultsCount === 0}>
<EuiTitle size="s">
<h2>
<FormattedMessage
id="xpack.ml.newJob.wizard.jobType.useSuppliedConfigurationTitle"
defaultMessage="Use a supplied configuration"
/>
</h2>
</EuiTitle>
<EuiSpacer size="s" />
<EuiText>
<EuiTitle size="s">
<h3>
<FormattedMessage
id="xpack.ml.newJob.wizard.jobType.useSuppliedConfigurationTitle"
defaultMessage="Use a supplied configuration"
/>
</h3>
</EuiTitle>
<p>
<FormattedMessage
id="xpack.ml.newJob.wizard.jobType.useSuppliedConfigurationDescription"
@ -236,16 +236,16 @@ export const Page: FC = () => {
<EuiSpacer size="xxl" />
</div>
<EuiTitle size="s">
<h2>
<FormattedMessage
id="xpack.ml.newJob.wizard.jobType.useWizardTitle"
defaultMessage="Use a wizard"
/>
</h2>
</EuiTitle>
<EuiSpacer size="s" />
<EuiText>
<EuiTitle size="s">
<h3>
<FormattedMessage
id="xpack.ml.newJob.wizard.jobType.useWizardTitle"
defaultMessage="Use a wizard"
/>
</h3>
</EuiTitle>
<p>
<FormattedMessage
id="xpack.ml.newJob.wizard.jobType.useWizardDescription"

View file

@ -200,13 +200,13 @@ export const Page: FC<PageProps> = ({ existingJobsAndGroups, jobType }) => {
<EuiPageContentHeader>
<EuiPageContentHeaderSection>
<EuiTitle>
<h2>
<h1>
<FormattedMessage
id="xpack.ml.newJob.page.createJob"
defaultMessage="Create job"
/>
: {jobCreatorTitle}
</h2>
</h1>
</EuiTitle>
</EuiPageContentHeaderSection>
</EuiPageContentHeader>

View file

@ -144,7 +144,7 @@ const Title: FC<{ 'data-test-subj': string }> = ({ 'data-test-subj': dataTestSub
return (
<Fragment>
<EuiTitle size="s">
<h3 data-test-subj={dataTestSubj}>{children}</h3>
<h2 data-test-subj={dataTestSubj}>{children}</h2>
</EuiTitle>
<EuiSpacer />
</Fragment>

View file

@ -5,7 +5,7 @@
*/
import React, { FC } from 'react';
import { EuiFlexItem, EuiLink, EuiText } from '@elastic/eui';
import { EuiFlexItem, EuiLink, EuiSpacer, EuiText, EuiTitle } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
import chrome from 'ui/chrome';
import { metadata } from 'ui/metadata';
@ -39,13 +39,16 @@ function getCreateJobLink(createAnomalyDetectionJobDisabled: boolean) {
export const OverviewSideBar: FC<Props> = ({ createAnomalyDetectionJobDisabled }) => (
<EuiFlexItem grow={1}>
<EuiText className="mlOverview__sidebar">
<h2>
<EuiTitle size="m">
<h1>
<FormattedMessage
id="xpack.ml.overview.gettingStartedSectionTitle"
defaultMessage="Getting started"
/>
</h2>
</h1>
</EuiTitle>
<EuiSpacer size="s" />
<EuiText className="mlOverview__sidebar">
<p>
<FormattedMessage
id="xpack.ml.overview.gettingStartedSectionText"

View file

@ -8,36 +8,38 @@ exports[`NewCalendar Renders new calendar form 1`] = `
<EuiPage
className="mlCalendarEditForm"
>
<EuiPageContent
className="mlCalendarEditForm__content"
horizontalPosition="center"
verticalPosition="center"
>
<InjectIntl(CalendarForm)
calendarId=""
canCreateCalendar={true}
canDeleteCalendar={true}
description=""
eventsList={Array []}
groupIds={Array []}
isEdit={false}
isNewCalendarIdValid={true}
jobIds={Array []}
onCalendarIdChange={[Function]}
onCreate={[Function]}
onCreateGroupOption={[Function]}
onDescriptionChange={[Function]}
onEdit={[Function]}
onEventDelete={[Function]}
onGroupSelection={[Function]}
onJobSelection={[Function]}
saving={false}
selectedGroupOptions={Array []}
selectedJobOptions={Array []}
showImportModal={[Function]}
showNewEventModal={[Function]}
/>
</EuiPageContent>
<EuiPageBody>
<EuiPageContent
className="mlCalendarEditForm__content"
horizontalPosition="center"
verticalPosition="center"
>
<InjectIntl(CalendarForm)
calendarId=""
canCreateCalendar={true}
canDeleteCalendar={true}
description=""
eventsList={Array []}
groupIds={Array []}
isEdit={false}
isNewCalendarIdValid={true}
jobIds={Array []}
onCalendarIdChange={[Function]}
onCreate={[Function]}
onCreateGroupOption={[Function]}
onDescriptionChange={[Function]}
onEdit={[Function]}
onEventDelete={[Function]}
onGroupSelection={[Function]}
onJobSelection={[Function]}
saving={false}
selectedGroupOptions={Array []}
selectedJobOptions={Array []}
showImportModal={[Function]}
showNewEventModal={[Function]}
/>
</EuiPageContent>
</EuiPageBody>
</EuiPage>
</Fragment>
`;

View file

@ -10,7 +10,7 @@ import { timefilter } from 'ui/timefilter';
import { injectI18n } from '@kbn/i18n/react';
import { EuiPage, EuiPageContent, EuiOverlayMask } from '@elastic/eui';
import { EuiPage, EuiPageBody, EuiPageContent, EuiOverlayMask } from '@elastic/eui';
import { toastNotifications } from 'ui/notify';
@ -334,39 +334,41 @@ export const NewCalendar = injectI18n(
<Fragment>
<NavigationMenu tabId="settings" />
<EuiPage className="mlCalendarEditForm">
<EuiPageContent
className="mlCalendarEditForm__content"
verticalPosition="center"
horizontalPosition="center"
>
<CalendarForm
calendarId={selectedCalendar ? selectedCalendar.calendar_id : formCalendarId}
canCreateCalendar={this.props.canCreateCalendar}
canDeleteCalendar={this.props.canDeleteCalendar}
description={selectedCalendar ? selectedCalendar.description : description}
eventsList={events}
groupIds={groupIdOptions}
isEdit={selectedCalendar !== undefined}
isNewCalendarIdValid={
selectedCalendar || isNewCalendarIdValid === null ? true : isNewCalendarIdValid
}
jobIds={jobIdOptions}
onCalendarIdChange={this.onCalendarIdChange}
onCreate={this.onCreate}
onDescriptionChange={this.onDescriptionChange}
onEdit={this.onEdit}
onEventDelete={this.onEventDelete}
onGroupSelection={this.onGroupSelection}
showImportModal={this.showImportModal}
onJobSelection={this.onJobSelection}
saving={saving}
selectedGroupOptions={selectedGroupOptions}
selectedJobOptions={selectedJobOptions}
onCreateGroupOption={this.onCreateGroupOption}
showNewEventModal={this.showNewEventModal}
/>
</EuiPageContent>
{modal}
<EuiPageBody>
<EuiPageContent
className="mlCalendarEditForm__content"
verticalPosition="center"
horizontalPosition="center"
>
<CalendarForm
calendarId={selectedCalendar ? selectedCalendar.calendar_id : formCalendarId}
canCreateCalendar={this.props.canCreateCalendar}
canDeleteCalendar={this.props.canDeleteCalendar}
description={selectedCalendar ? selectedCalendar.description : description}
eventsList={events}
groupIds={groupIdOptions}
isEdit={selectedCalendar !== undefined}
isNewCalendarIdValid={
selectedCalendar || isNewCalendarIdValid === null ? true : isNewCalendarIdValid
}
jobIds={jobIdOptions}
onCalendarIdChange={this.onCalendarIdChange}
onCreate={this.onCreate}
onDescriptionChange={this.onDescriptionChange}
onEdit={this.onEdit}
onEventDelete={this.onEventDelete}
onGroupSelection={this.onGroupSelection}
showImportModal={this.showImportModal}
onJobSelection={this.onJobSelection}
saving={saving}
selectedGroupOptions={selectedGroupOptions}
selectedJobOptions={selectedJobOptions}
onCreateGroupOption={this.onCreateGroupOption}
showNewEventModal={this.showNewEventModal}
/>
</EuiPageContent>
{modal}
</EuiPageBody>
</EuiPage>
</Fragment>
);

View file

@ -8,65 +8,67 @@ exports[`CalendarsList Renders calendar list with calendars 1`] = `
<EuiPage
className="mlCalendarList"
>
<EuiPageContent
className="mlCalendarList__content"
horizontalPosition="center"
verticalPosition="center"
>
<CalendarsListHeader
refreshCalendars={[Function]}
totalCount={2}
/>
<InjectIntl(CalendarsListTable)
calendarsList={
Array [
Object {
"calendar_id": "farequote-calendar",
"description": "test ",
"events": Array [
Object {
"calendar_id": "farequote-calendar",
"description": "Downtime feb 9 2017 10:10 to 10:30",
"end_time": 1486657800000,
"event_id": "Ee-YgGcBxHgQWEhCO_xj",
"start_time": 1486656600000,
},
],
"events_length": 1,
"job_ids": Array [
"farequote",
],
"job_ids_string": "farequote",
},
Object {
"calendar_id": "this-is-a-new-calendar",
"description": "new calendar",
"events": Array [
Object {
"calendar_id": "this-is-a-new-calendar",
"description": "New event!",
"end_time": 1544162400000,
"event_id": "ehWKhGcBqHkXuWNrIrSV",
"start_time": 1544076000000,
},
],
"events_length": 1,
"job_ids": Array [
"test",
],
"job_ids_string": "test",
},
]
}
canCreateCalendar={true}
canDeleteCalendar={true}
itemsSelected={false}
loading={false}
mlNodesAvailable={true}
onDeleteClick={[Function]}
setSelectedCalendarList={[Function]}
/>
</EuiPageContent>
<EuiPageBody>
<EuiPageContent
className="mlCalendarList__content"
horizontalPosition="center"
verticalPosition="center"
>
<CalendarsListHeader
refreshCalendars={[Function]}
totalCount={2}
/>
<InjectIntl(CalendarsListTable)
calendarsList={
Array [
Object {
"calendar_id": "farequote-calendar",
"description": "test ",
"events": Array [
Object {
"calendar_id": "farequote-calendar",
"description": "Downtime feb 9 2017 10:10 to 10:30",
"end_time": 1486657800000,
"event_id": "Ee-YgGcBxHgQWEhCO_xj",
"start_time": 1486656600000,
},
],
"events_length": 1,
"job_ids": Array [
"farequote",
],
"job_ids_string": "farequote",
},
Object {
"calendar_id": "this-is-a-new-calendar",
"description": "new calendar",
"events": Array [
Object {
"calendar_id": "this-is-a-new-calendar",
"description": "New event!",
"end_time": 1544162400000,
"event_id": "ehWKhGcBqHkXuWNrIrSV",
"start_time": 1544076000000,
},
],
"events_length": 1,
"job_ids": Array [
"test",
],
"job_ids_string": "test",
},
]
}
canCreateCalendar={true}
canDeleteCalendar={true}
itemsSelected={false}
loading={false}
mlNodesAvailable={true}
onDeleteClick={[Function]}
setSelectedCalendarList={[Function]}
/>
</EuiPageContent>
</EuiPageBody>
</EuiPage>
</Fragment>
`;

View file

@ -11,6 +11,7 @@ import {
EuiConfirmModal,
EuiOverlayMask,
EuiPage,
EuiPageBody,
EuiPageContent,
EUI_MODAL_CONFIRM_BUTTON,
} from '@elastic/eui';
@ -149,27 +150,29 @@ export const CalendarsList = injectI18n(
<Fragment>
<NavigationMenu tabId="settings" />
<EuiPage className="mlCalendarList">
<EuiPageContent
className="mlCalendarList__content"
verticalPosition="center"
horizontalPosition="center"
>
<CalendarsListHeader
totalCount={calendars.length}
refreshCalendars={this.loadCalendars}
/>
<CalendarsListTable
loading={loading}
calendarsList={this.addRequiredFieldsToList(calendars)}
onDeleteClick={this.showDestroyModal}
canCreateCalendar={canCreateCalendar}
canDeleteCalendar={canDeleteCalendar}
mlNodesAvailable={nodesAvailable}
setSelectedCalendarList={this.setSelectedCalendarList}
itemsSelected={selectedForDeletion.length > 0}
/>
</EuiPageContent>
{destroyModal}
<EuiPageBody>
<EuiPageContent
className="mlCalendarList__content"
verticalPosition="center"
horizontalPosition="center"
>
<CalendarsListHeader
totalCount={calendars.length}
refreshCalendars={this.loadCalendars}
/>
<CalendarsListTable
loading={loading}
calendarsList={this.addRequiredFieldsToList(calendars)}
onDeleteClick={this.showDestroyModal}
canCreateCalendar={canCreateCalendar}
canDeleteCalendar={canDeleteCalendar}
mlNodesAvailable={nodesAvailable}
setSelectedCalendarList={this.setSelectedCalendarList}
itemsSelected={selectedForDeletion.length > 0}
/>
</EuiPageContent>
{destroyModal}
</EuiPageBody>
</EuiPage>
</Fragment>
);

View file

@ -18,6 +18,7 @@ import {
EuiFlexGroup,
EuiFlexItem,
EuiPage,
EuiPageBody,
EuiPageContent,
EuiSearchBar,
EuiSpacer,
@ -324,68 +325,70 @@ export const EditFilterList = injectI18n(
<Fragment>
<NavigationMenu tabId="settings" />
<EuiPage className="ml-edit-filter-lists">
<EuiPageContent
className="ml-edit-filter-lists-content"
verticalPosition="center"
horizontalPosition="center"
>
<EditFilterListHeader
canCreateFilter={canCreateFilter}
filterId={this.props.filterId}
newFilterId={newFilterId}
isNewFilterIdInvalid={isNewFilterIdInvalid}
updateNewFilterId={this.updateNewFilterId}
description={description}
updateDescription={this.updateDescription}
totalItemCount={totalItemCount}
usedBy={loadedFilter.used_by}
/>
<EditFilterListToolbar
canCreateFilter={canCreateFilter}
canDeleteFilter={canDeleteFilter}
onSearchChange={this.onSearchChange}
addItems={this.addItems}
deleteSelectedItems={this.deleteSelectedItems}
selectedItemCount={selectedItems.length}
/>
<EuiSpacer size="xl" />
<ItemsGrid
totalItemCount={totalItemCount}
items={matchingItems}
selectedItems={selectedItems}
itemsPerPage={itemsPerPage}
setItemsPerPage={this.setItemsPerPage}
setItemSelected={this.setItemSelected}
activePage={activePage}
setActivePage={this.setActivePage}
/>
<EuiFlexGroup justifyContent="flexEnd">
<EuiFlexItem grow={false}>
<EuiButtonEmpty onClick={returnToFiltersList}>
<FormattedMessage
id="xpack.ml.settings.filterLists.editFilterList.cancelButtonLabel"
defaultMessage="Cancel"
/>
</EuiButtonEmpty>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiButton
onClick={this.save}
disabled={
saveInProgress === true ||
isNewFilterIdInvalid === true ||
canCreateFilter === false
}
fill
>
<FormattedMessage
id="xpack.ml.settings.filterLists.editFilterList.saveButtonLabel"
defaultMessage="Save"
/>
</EuiButton>
</EuiFlexItem>
</EuiFlexGroup>
</EuiPageContent>
<EuiPageBody>
<EuiPageContent
className="ml-edit-filter-lists-content"
verticalPosition="center"
horizontalPosition="center"
>
<EditFilterListHeader
canCreateFilter={canCreateFilter}
filterId={this.props.filterId}
newFilterId={newFilterId}
isNewFilterIdInvalid={isNewFilterIdInvalid}
updateNewFilterId={this.updateNewFilterId}
description={description}
updateDescription={this.updateDescription}
totalItemCount={totalItemCount}
usedBy={loadedFilter.used_by}
/>
<EditFilterListToolbar
canCreateFilter={canCreateFilter}
canDeleteFilter={canDeleteFilter}
onSearchChange={this.onSearchChange}
addItems={this.addItems}
deleteSelectedItems={this.deleteSelectedItems}
selectedItemCount={selectedItems.length}
/>
<EuiSpacer size="xl" />
<ItemsGrid
totalItemCount={totalItemCount}
items={matchingItems}
selectedItems={selectedItems}
itemsPerPage={itemsPerPage}
setItemsPerPage={this.setItemsPerPage}
setItemSelected={this.setItemSelected}
activePage={activePage}
setActivePage={this.setActivePage}
/>
<EuiFlexGroup justifyContent="flexEnd">
<EuiFlexItem grow={false}>
<EuiButtonEmpty onClick={returnToFiltersList}>
<FormattedMessage
id="xpack.ml.settings.filterLists.editFilterList.cancelButtonLabel"
defaultMessage="Cancel"
/>
</EuiButtonEmpty>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiButton
onClick={this.save}
disabled={
saveInProgress === true ||
isNewFilterIdInvalid === true ||
canCreateFilter === false
}
fill
>
<FormattedMessage
id="xpack.ml.settings.filterLists.editFilterList.saveButtonLabel"
defaultMessage="Save"
/>
</EuiButton>
</EuiFlexItem>
</EuiFlexGroup>
</EuiPageContent>
</EuiPageBody>
</EuiPage>
</Fragment>
);

View file

@ -8,37 +8,39 @@ exports[`Filter Lists renders a list of filters 1`] = `
<EuiPage
className="ml-list-filter-lists"
>
<EuiPageContent
className="ml-list-filter-lists-content"
horizontalPosition="center"
verticalPosition="center"
>
<FilterListsHeader
refreshFilterLists={[Function]}
totalCount={1}
/>
<FilterListsTable
canCreateFilter={true}
canDeleteFilter={true}
filterLists={
Array [
Object {
"description": "List of known safe domains",
"filter_id": "safe_domains",
"item_count": 500,
"used_by": Object {
"jobs": Array [
"dns_exfiltration",
],
<EuiPageBody>
<EuiPageContent
className="ml-list-filter-lists-content"
horizontalPosition="center"
verticalPosition="center"
>
<FilterListsHeader
refreshFilterLists={[Function]}
totalCount={1}
/>
<FilterListsTable
canCreateFilter={true}
canDeleteFilter={true}
filterLists={
Array [
Object {
"description": "List of known safe domains",
"filter_id": "safe_domains",
"item_count": 500,
"used_by": Object {
"jobs": Array [
"dns_exfiltration",
],
},
},
},
]
}
refreshFilterLists={[Function]}
selectedFilterLists={Array []}
setSelectedFilterLists={[Function]}
/>
</EuiPageContent>
]
}
refreshFilterLists={[Function]}
selectedFilterLists={Array []}
setSelectedFilterLists={[Function]}
/>
</EuiPageContent>
</EuiPageBody>
</EuiPage>
</Fragment>
`;

View file

@ -11,7 +11,7 @@
import React, { Component, Fragment } from 'react';
import { PropTypes } from 'prop-types';
import { EuiPage, EuiPageContent } from '@elastic/eui';
import { EuiPage, EuiPageBody, EuiPageContent } from '@elastic/eui';
import { injectI18n } from '@kbn/i18n/react';
@ -90,24 +90,26 @@ export const FilterLists = injectI18n(
<Fragment>
<NavigationMenu tabId="settings" />
<EuiPage className="ml-list-filter-lists">
<EuiPageContent
className="ml-list-filter-lists-content"
verticalPosition="center"
horizontalPosition="center"
>
<FilterListsHeader
totalCount={filterLists.length}
refreshFilterLists={this.refreshFilterLists}
/>
<FilterListsTable
canCreateFilter={canCreateFilter}
canDeleteFilter={canDeleteFilter}
filterLists={filterLists}
selectedFilterLists={selectedFilterLists}
setSelectedFilterLists={this.setSelectedFilterLists}
refreshFilterLists={this.refreshFilterLists}
/>
</EuiPageContent>
<EuiPageBody>
<EuiPageContent
className="ml-list-filter-lists-content"
verticalPosition="center"
horizontalPosition="center"
>
<FilterListsHeader
totalCount={filterLists.length}
refreshFilterLists={this.refreshFilterLists}
/>
<FilterListsTable
canCreateFilter={canCreateFilter}
canDeleteFilter={canDeleteFilter}
filterLists={filterLists}
selectedFilterLists={selectedFilterLists}
setSelectedFilterLists={this.setSelectedFilterLists}
refreshFilterLists={this.refreshFilterLists}
/>
</EuiPageContent>
</EuiPageBody>
</EuiPage>
</Fragment>
);

View file

@ -35,12 +35,12 @@ export const Settings: FC<Props> = ({ canGetFilters, canGetCalendars }) => {
<EuiPageContent className="mlSettingsPage__content" horizontalPosition="center">
<EuiPageContentHeader>
<EuiTitle>
<h2>
<h1>
<FormattedMessage
id="xpack.ml.settings.jobManagementTitle"
defaultMessage="Job Management"
/>
</h2>
</h1>
</EuiTitle>
</EuiPageContentHeader>

View file

@ -34,7 +34,9 @@
padding: $euiSize;
.panel-title {
color: $euiTitleColor;
font-size: $euiFontSizeM;
font-weight: 400;
color: $euiColorDarkShade;
}
.entity-count-text {
@ -78,7 +80,8 @@
font-family: $euiFontFamily;
}
.axis path, .axis line {
.axis path,
.axis line {
fill: none;
stroke: $euiBorderColor;
shape-rendering: crispEdges;
@ -104,6 +107,7 @@
stroke: $euiColorDarkShade;
stroke-width: 2;
}
.chart-border-highlight:hover {
opacity: 1;
}
@ -191,6 +195,7 @@
}
.forecast {
.metric-value,
.metric-value:hover {
stroke: #cca300;
@ -220,7 +225,9 @@
}
}
a:hover, a:active, a:focus {
a:hover,
a:active,
a:focus {
text-decoration: underline;
}
@ -321,6 +328,7 @@
div.brush-handle-inner-left {
border-radius: $euiBorderRadius 0px 0px $euiBorderRadius;
}
div.brush-handle-inner-right {
border-radius: 0px $euiBorderRadius $euiBorderRadius 0px;
}
@ -342,7 +350,9 @@
of the horizontal bar below the tab menu elements in its inactive state. */
.mlTimeSeriesExplorerProgress {
background-color: $euiColorEmptyShade;
&::-moz-progress-bar, &::-webkit-progress-bar {
&::-moz-progress-bar,
&::-webkit-progress-bar {
background-color: $euiColorEmptyShade;
}
}

View file

@ -61,7 +61,7 @@ const contextChartHeight = 60;
const contextChartLineTopMargin = 3;
const chartSpacing = 25;
const swimlaneHeight = 30;
const margin = { top: 20, right: 10, bottom: 15, left: 40 };
const margin = { top: 10, right: 10, bottom: 15, left: 40 };
const mlAnnotationsEnabled = chrome.getInjected('mlAnnotationsEnabled', false);
const ZOOM_INTERVAL_OPTIONS = [

View file

@ -20,14 +20,14 @@ import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n/react';
import {
EuiCallOut,
EuiCheckbox,
EuiFlexGroup,
EuiFlexItem,
EuiFormRow,
EuiSelect,
EuiSpacer,
EuiText,
EuiCallOut,
EuiTitle,
} from '@elastic/eui';
import chrome from 'ui/chrome';
@ -1209,54 +1209,60 @@ export class TimeSeriesExplorer extends React.Component {
<div>
{/* Make sure ChartTooltip is inside this plain wrapping element without padding so positioning can be inferred correctly. */}
<ChartTooltip />
<EuiText className="results-container">
<span className="panel-title">
{i18n.translate('xpack.ml.timeSeriesExplorer.singleTimeSeriesAnalysisTitle', {
defaultMessage: 'Single time series analysis of {functionLabel}',
values: { functionLabel: chartDetails.functionLabel },
})}
</span>
&nbsp;
{chartDetails.entityData.count === 1 && (
<span className="entity-count-text">
{chartDetails.entityData.entities.length > 0 && '('}
{chartDetails.entityData.entities
.map(entity => {
return `${entity.fieldName}: ${entity.fieldValue}`;
})
.join(', ')}
{chartDetails.entityData.entities.length > 0 && ')'}
</span>
)}
{chartDetails.entityData.count !== 1 && (
<span className="entity-count-text">
{chartDetails.entityData.entities.map((countData, i) => {
return (
<Fragment key={countData.fieldName}>
{i18n.translate(
'xpack.ml.timeSeriesExplorer.countDataInChartDetailsDescription',
{
defaultMessage:
'{openBrace}{cardinalityValue} distinct {fieldName} {cardinality, plural, one {} other { values}}{closeBrace}',
values: {
openBrace: i === 0 ? '(' : '',
closeBrace:
i === chartDetails.entityData.entities.length - 1 ? ')' : '',
cardinalityValue:
countData.cardinality === 0
? allValuesLabel
: countData.cardinality,
cardinality: countData.cardinality,
fieldName: countData.fieldName,
},
}
)}
{i !== chartDetails.entityData.entities.length - 1 ? ', ' : ''}
</Fragment>
);
})}
</span>
)}
<div className="results-container">
<EuiTitle className="panel-title">
<h2 style={{ display: 'inline' }}>
<span>
{i18n.translate('xpack.ml.timeSeriesExplorer.singleTimeSeriesAnalysisTitle', {
defaultMessage: 'Single time series analysis of {functionLabel}',
values: { functionLabel: chartDetails.functionLabel },
})}
</span>
&nbsp;
{chartDetails.entityData.count === 1 && (
<span className="entity-count-text">
{chartDetails.entityData.entities.length > 0 && '('}
{chartDetails.entityData.entities
.map(entity => {
return `${entity.fieldName}: ${entity.fieldValue}`;
})
.join(', ')}
{chartDetails.entityData.entities.length > 0 && ')'}
</span>
)}
{chartDetails.entityData.count !== 1 && (
<span className="entity-count-text">
{chartDetails.entityData.entities.map((countData, i) => {
return (
<Fragment key={countData.fieldName}>
{i18n.translate(
'xpack.ml.timeSeriesExplorer.countDataInChartDetailsDescription',
{
defaultMessage:
'{openBrace}{cardinalityValue} distinct {fieldName} {cardinality, plural, one {} other { values}}{closeBrace}',
values: {
openBrace: i === 0 ? '(' : '',
closeBrace:
i === chartDetails.entityData.entities.length - 1 ? ')' : '',
cardinalityValue:
countData.cardinality === 0
? allValuesLabel
: countData.cardinality,
cardinality: countData.cardinality,
fieldName: countData.fieldName,
},
}
)}
{i !== chartDetails.entityData.entities.length - 1 ? ', ' : ''}
</Fragment>
);
})}
</span>
)}
</h2>
</EuiTitle>
<EuiFlexGroup style={{ float: 'right' }}>
{showModelBoundsCheckbox && (
<EuiFlexItem grow={false}>
@ -1311,11 +1317,14 @@ export class TimeSeriesExplorer extends React.Component {
</div>
{showAnnotations && focusAnnotationData.length > 0 && (
<div>
<span className="panel-title">
{i18n.translate('xpack.ml.timeSeriesExplorer.annotationsTitle', {
defaultMessage: 'Annotations',
})}
</span>
<EuiTitle className="panel-title">
<h2>
<FormattedMessage
id="xpack.ml.timeSeriesExplorer.annotationsTitle"
defaultMessage="Annotations"
/>
</h2>
</EuiTitle>
<AnnotationsTable
annotations={focusAnnotationData}
isSingleMetricViewerLinkVisible={false}
@ -1325,11 +1334,14 @@ export class TimeSeriesExplorer extends React.Component {
</div>
)}
<AnnotationFlyout />
<span className="panel-title">
{i18n.translate('xpack.ml.timeSeriesExplorer.anomaliesTitle', {
defaultMessage: 'Anomalies',
})}
</span>
<EuiTitle className="panel-title">
<h2>
<FormattedMessage
id="xpack.ml.timeSeriesExplorer.anomaliesTitle"
defaultMessage="Anomalies"
/>
</h2>
</EuiTitle>
<EuiFlexGroup
direction="row"
gutterSize="l"
@ -1356,7 +1368,7 @@ export class TimeSeriesExplorer extends React.Component {
</EuiFlexItem>
</EuiFlexGroup>
<EuiSpacer size="m" />
</EuiText>
</div>
</div>
)}
{arePartitioningFieldsProvided && jobs.length > 0 && hasResults === true && (

View file

@ -6,7 +6,9 @@
import React, { FC } from 'react';
import { EuiProgress } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
import { EuiPage, EuiPageBody, EuiProgress, EuiScreenReaderOnly } from '@elastic/eui';
import { JobSelector } from '../components/job_selector';
import { NavigationMenu } from '../components/navigation_menu';
@ -47,7 +49,19 @@ export const TimeSeriesExplorerPage: FC<TimeSeriesExplorerPageProps> = ({
ref={resizeRef}
data-test-subj="mlPageSingleMetricViewer"
>
{children}
<EuiPage style={{ padding: '0px', background: 'none' }}>
<EuiPageBody>
<EuiScreenReaderOnly>
<h1>
<FormattedMessage
id="xpack.ml.timeSeriesExplorer.pageTitle"
defaultMessage="Single Metric Viewer"
/>
</h1>
</EuiScreenReaderOnly>
{children}
</EuiPageBody>
</EuiPage>
</div>
</>
);