[ML] Fixing missing advanced job summary items (#48537) (#48622)

* [ML] Fixing missing advanced job summary items

* updating translations
This commit is contained in:
James Gowdy 2019-10-18 11:55:31 +01:00 committed by GitHub
parent b06d553ea0
commit 1d6dcdb6ae
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
21 changed files with 276 additions and 58 deletions

View file

@ -19,5 +19,6 @@ export enum CREATED_BY_LABEL {
export const DEFAULT_MODEL_MEMORY_LIMIT = '10MB';
export const DEFAULT_BUCKET_SPAN = '15m';
export const DEFAULT_QUERY_DELAY = '60s';
export const SHARED_RESULTS_INDEX_NAME = 'shared';

View file

@ -9,8 +9,7 @@ import { EuiFieldText } from '@elastic/eui';
import { JobCreatorContext } from '../../../job_creator_context';
import { Description } from './description';
import { useStringifiedValue } from '../hooks';
const DEFAULT_QUERY_DELAY = '60s';
import { DEFAULT_QUERY_DELAY } from '../../../../../common/job_creator/util/constants';
export const QueryDelayInput: FC = () => {
const { jobCreator, jobCreatorUpdate, jobValidator, jobValidatorUpdated } = useContext(

View file

@ -6,7 +6,7 @@
import React, { FC, useState, useContext, useEffect } from 'react';
import { EuiFieldNumber } from '@elastic/eui';
import { newJobDefaults } from '../../../../../../new_job_new/utils/new_job_defaults';
import { newJobDefaults } from '../../../../../utils/new_job_defaults';
import { JobCreatorContext } from '../../../job_creator_context';
import { Description } from './description';

View file

@ -8,14 +8,16 @@ import React, { Fragment, FC, useEffect, useState } from 'react';
import { EuiHorizontalRule } from '@elastic/eui';
import { AdvancedDetectors } from './metric_selection';
import { AdvancedDetectorsSummary } from './metric_selection_summary';
import { AdvancedSettings } from './settings';
import { ExtraSettings } from './extra';
interface Props {
isActive: boolean;
setCanProceed?: (proceed: boolean) => void;
}
export const AdvancedView: FC<Props> = ({ setCanProceed }) => {
export const AdvancedView: FC<Props> = ({ isActive, setCanProceed }) => {
const [metricsValid, setMetricValid] = useState(false);
const [settingsValid, setSettingsValid] = useState(false);
@ -27,13 +29,17 @@ export const AdvancedView: FC<Props> = ({ setCanProceed }) => {
return (
<Fragment>
<Fragment>
<ExtraSettings />
<EuiHorizontalRule margin="l" />
<AdvancedDetectors setIsValid={setMetricValid} />
<EuiHorizontalRule margin="l" />
<AdvancedSettings setIsValid={setSettingsValid} />
</Fragment>
{isActive === false ? (
<AdvancedDetectorsSummary />
) : (
<Fragment>
<ExtraSettings />
<EuiHorizontalRule margin="l" />
<AdvancedDetectors setIsValid={setMetricValid} />
<EuiHorizontalRule margin="l" />
<AdvancedSettings setIsValid={setSettingsValid} />
</Fragment>
)}
</Fragment>
);
};

View file

@ -25,11 +25,12 @@ import { AdvancedJobCreator } from '../../../../../common/job_creator';
import { detectorToString } from '../../../../../../../util/string_utils';
interface Props {
isActive: boolean;
onEditJob: (i: number) => void;
onDeleteJob: (i: number) => void;
}
export const DetectorList: FC<Props> = ({ onEditJob, onDeleteJob }) => {
export const DetectorList: FC<Props> = ({ isActive, onEditJob, onDeleteJob }) => {
const { jobCreator: jc, jobCreatorUpdated } = useContext(JobCreatorContext);
const jobCreator = jc as AdvancedJobCreator;
const [detectors, setDetectors] = useState(jobCreator.detectors);

View file

@ -85,7 +85,7 @@ export const AdvancedDetectors: FC<Props> = ({ setIsValid }) => {
return (
<Fragment>
<DetectorList onEditJob={onEditJob} onDeleteJob={onDeleteJob} />
<DetectorList isActive={true} onEditJob={onEditJob} onDeleteJob={onDeleteJob} />
<MetricSelector
payload={modalPayload}
fields={fields}

View file

@ -0,0 +1,13 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import React, { FC } from 'react';
import { DetectorList } from './detector_list';
export const AdvancedDetectorsSummary: FC = () => (
<DetectorList isActive={false} onEditJob={() => {}} onDeleteJob={() => {}} />
);

View file

@ -28,9 +28,9 @@ export const MultiMetricView: FC<Props> = ({ isActive, setCanProceed }) => {
return (
<Fragment>
{isActive === false && <MultiMetricDetectorsSummary />}
{isActive === true && (
{isActive === false ? (
<MultiMetricDetectorsSummary />
) : (
<Fragment>
<MultiMetricDetectors setIsValid={setMetricValid} />

View file

@ -28,9 +28,9 @@ export const PopulationView: FC<Props> = ({ isActive, setCanProceed }) => {
return (
<Fragment>
{isActive === false && <PopulationDetectorsSummary />}
{isActive === true && (
{isActive === false ? (
<PopulationDetectorsSummary />
) : (
<Fragment>
<PopulationDetectors setIsValid={setMetricValid} />
{metricsValid && (

View file

@ -28,9 +28,9 @@ export const SingleMetricView: FC<Props> = ({ isActive, setCanProceed }) => {
return (
<Fragment>
{isActive === false && <SingleMetricDetectorsSummary />}
{isActive === true && (
{isActive === false ? (
<SingleMetricDetectorsSummary />
) : (
<Fragment>
<SingleMetricDetectors setIsValid={setMetricValid} />
{metricsValid && (

View file

@ -47,7 +47,9 @@ export const PickFieldsStep: FC<StepProps> = ({ setCurrentStep, isCurrentStep })
{jobType === JOB_TYPE.POPULATION && (
<PopulationView isActive={isCurrentStep} setCanProceed={setNextActive} />
)}
{jobType === JOB_TYPE.ADVANCED && <AdvancedView setCanProceed={setNextActive} />}
{jobType === JOB_TYPE.ADVANCED && (
<AdvancedView isActive={isCurrentStep} setCanProceed={setNextActive} />
)}
<WizardNav
previous={() =>
setCurrentStep(

View file

@ -0,0 +1,51 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import React, { FC } from 'react';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n/react';
import { EuiTitle } from '@elastic/eui';
export interface ListItems {
title: string;
description: string | JSX.Element;
}
export const trueLabel = i18n.translate('xpack.ml.newJob.wizard.summaryStep.trueLabel', {
defaultMessage: 'True',
});
export const falseLabel = i18n.translate('xpack.ml.newJob.wizard.summaryStep.falseLabel', {
defaultMessage: 'False',
});
export const defaultLabel = i18n.translate('xpack.ml.newJob.wizard.summaryStep.defaultString', {
defaultMessage: 'default',
});
export const JobSectionTitle: FC = () => (
<EuiTitle size="s">
<h3>
<FormattedMessage
id="xpack.ml.newJob.wizard.summaryStep.jobConfig.title"
defaultMessage="Job configuration"
/>
</h3>
</EuiTitle>
);
export const DatafeedSectionTitle: FC = () => (
<EuiTitle size="s">
<h3>
<FormattedMessage
id="xpack.ml.newJob.wizard.summaryStep.datafeedConfig.title"
defaultMessage="Datafeed configuration"
/>
</h3>
</EuiTitle>
);
export const Italic: FC = ({ children }) => <span style={{ fontStyle: 'italic' }}>{children}</span>;

View file

@ -0,0 +1,88 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import React, { FC, useContext } from 'react';
import { i18n } from '@kbn/i18n';
import { EuiFlexGroup, EuiFlexItem, EuiDescriptionList, EuiFormRow } from '@elastic/eui';
import { JobCreatorContext } from '../../../job_creator_context';
import { MLJobEditor } from '../../../../../../jobs_list/components/ml_job_editor';
import { calculateDatafeedFrequencyDefaultSeconds } from '../../../../../../../../common/util/job_utils';
import { DEFAULT_QUERY_DELAY } from '../../../../../common/job_creator/util/constants';
import { newJobDefaults } from '../../../../../utils/new_job_defaults';
import { ListItems, defaultLabel, Italic } from '../common';
const EDITOR_HEIGHT = '200px';
export const DatafeedDetails: FC = () => {
const { jobCreator } = useContext(JobCreatorContext);
const { datafeeds } = newJobDefaults();
const queryString = JSON.stringify(jobCreator.query, null, 2);
const defaultFrequency = calculateDatafeedFrequencyDefaultSeconds(jobCreator.bucketSpanMs / 1000);
const scrollSizeDefault = datafeeds.scroll_size || '';
const queryDelay = jobCreator.queryDelay || (
<Italic>{`${DEFAULT_QUERY_DELAY} (${defaultLabel})`}</Italic>
);
const frequency = jobCreator.frequency || (
<Italic>{`${defaultFrequency} (${defaultLabel})`}</Italic>
);
const scrollSize =
jobCreator.scrollSize !== null ? (
`${jobCreator.scrollSize}`
) : (
<Italic>{`${scrollSizeDefault} (${defaultLabel})`}</Italic>
);
const datafeedDetails: ListItems[] = [
{
title: i18n.translate('xpack.ml.newJob.wizard.summaryStep.datafeedDetails.timeField.title', {
defaultMessage: 'Time field',
}),
description: jobCreator.timeFieldName,
},
{
title: i18n.translate('xpack.ml.newJob.wizard.summaryStep.datafeedDetails.queryDelay.title', {
defaultMessage: 'Query delay',
}),
description: queryDelay,
},
{
title: i18n.translate('xpack.ml.newJob.wizard.summaryStep.datafeedDetails.frequency.title', {
defaultMessage: 'Frequency',
}),
description: frequency,
},
{
title: i18n.translate('xpack.ml.newJob.wizard.summaryStep.datafeedDetails.scrollSize.title', {
defaultMessage: 'Scroll size',
}),
description: scrollSize,
},
];
const queryTitle = i18n.translate(
'xpack.ml.newJob.wizard.summaryStep.datafeedDetails.query.title',
{
defaultMessage: 'Scroll size',
}
);
return (
<EuiFlexGroup>
<EuiFlexItem>
<EuiFormRow label={queryTitle} fullWidth={true}>
<MLJobEditor value={queryString} height={EDITOR_HEIGHT} readOnly={true} />
</EuiFormRow>
</EuiFlexItem>
<EuiFlexItem>
<EuiDescriptionList compressed listItems={datafeedDetails} />
</EuiFlexItem>
</EuiFlexGroup>
);
};

View file

@ -0,0 +1,6 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
export { DatafeedDetails } from './datafeed_details';

View file

@ -5,11 +5,12 @@
*/
import React, { Fragment, FC, useContext } from 'react';
import { JobCreatorContext } from '../job_creator_context';
import { JOB_TYPE } from '../../../common/job_creator/util/constants';
import { SingleMetricView } from '../pick_fields_step/components/single_metric_view';
import { MultiMetricView } from '../pick_fields_step/components/multi_metric_view';
import { PopulationView } from '../pick_fields_step/components/population_view';
import { JobCreatorContext } from '../../../job_creator_context';
import { JOB_TYPE } from '../../../../../common/job_creator/util/constants';
import { SingleMetricView } from '../../../pick_fields_step/components/single_metric_view';
import { MultiMetricView } from '../../../pick_fields_step/components/multi_metric_view';
import { PopulationView } from '../../../pick_fields_step/components/population_view';
import { AdvancedView } from '../../../pick_fields_step/components/advanced_view';
export const DetectorChart: FC = () => {
const { jobCreator } = useContext(JobCreatorContext);
@ -19,6 +20,7 @@ export const DetectorChart: FC = () => {
{jobCreator.type === JOB_TYPE.SINGLE_METRIC && <SingleMetricView isActive={false} />}
{jobCreator.type === JOB_TYPE.MULTI_METRIC && <MultiMetricView isActive={false} />}
{jobCreator.type === JOB_TYPE.POPULATION && <PopulationView isActive={false} />}
{jobCreator.type === JOB_TYPE.ADVANCED && <AdvancedView isActive={false} />}
</Fragment>
);
};

View file

@ -0,0 +1,7 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
export { DetectorChart } from './detector_chart';

View file

@ -0,0 +1,6 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
export { JobDetails } from './job_details';

View file

@ -8,16 +8,26 @@ import React, { FC, useContext } from 'react';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n/react';
import { EuiFlexGroup, EuiFlexItem, EuiDescriptionList } from '@elastic/eui';
import { JobCreatorContext } from '../job_creator_context';
import { isMultiMetricJobCreator, isPopulationJobCreator } from '../../../common/job_creator';
import { JobCreatorContext } from '../../../job_creator_context';
import {
isMultiMetricJobCreator,
isPopulationJobCreator,
isAdvancedJobCreator,
} from '../../../../../common/job_creator';
import { newJobDefaults } from '../../../../../utils/new_job_defaults';
import { ListItems, falseLabel, trueLabel, defaultLabel, Italic } from '../common';
export const JobDetails: FC = () => {
const { jobCreator } = useContext(JobCreatorContext);
const { anomaly_detectors: anomalyDetectors } = newJobDefaults();
interface ListItems {
title: string;
description: string | JSX.Element;
}
const modelMemoryLimitDefault = anomalyDetectors.model_memory_limit || '';
const modelMemoryLimit =
jobCreator.modelMemoryLimit !== null ? (
jobCreator.modelMemoryLimit
) : (
<Italic>{`${modelMemoryLimitDefault} (${defaultLabel})`}</Italic>
);
const jobDetails: ListItems[] = [
{
@ -34,12 +44,12 @@ export const JobDetails: FC = () => {
jobCreator.description.length > 0 ? (
jobCreator.description
) : (
<span style={{ fontStyle: 'italic' }}>
<Italic>
<FormattedMessage
id="xpack.ml.newJob.wizard.summaryStep.jobDetails.jobDescription.placeholder"
defaultMessage="No description provided"
/>
</span>
</Italic>
),
},
{
@ -50,12 +60,12 @@ export const JobDetails: FC = () => {
jobCreator.groups.length > 0 ? (
jobCreator.groups.join(', ')
) : (
<span style={{ fontStyle: 'italic' }}>
<Italic>
<FormattedMessage
id="xpack.ml.newJob.wizard.summaryStep.jobDetails.groups.placeholder"
defaultMessage="No groups selected"
/>
</span>
</Italic>
),
},
];
@ -78,12 +88,12 @@ export const JobDetails: FC = () => {
isMultiMetricJobCreator(jobCreator) && jobCreator.splitField !== null ? (
jobCreator.splitField.name
) : (
<span style={{ fontStyle: 'italic' }}>
<Italic>
<FormattedMessage
id="xpack.ml.newJob.wizard.summaryStep.jobDetails.splitField.placeholder"
defaultMessage="No split field selected"
/>
</span>
</Italic>
),
});
}
@ -107,6 +117,30 @@ export const JobDetails: FC = () => {
});
}
if (isAdvancedJobCreator(jobCreator) && jobCreator.categorizationFieldName !== null) {
detectorDetails.push({
title: i18n.translate(
'xpack.ml.newJob.wizard.summaryStep.jobDetails.categorizationField.title',
{
defaultMessage: 'Categorization field',
}
),
description: jobCreator.categorizationFieldName,
});
}
if (isAdvancedJobCreator(jobCreator) && jobCreator.summaryCountFieldName !== null) {
detectorDetails.push({
title: i18n.translate(
'xpack.ml.newJob.wizard.summaryStep.jobDetails.summaryCountField.title',
{
defaultMessage: 'Summary count field',
}
),
description: jobCreator.summaryCountFieldName,
});
}
detectorDetails.push({
title: i18n.translate('xpack.ml.newJob.wizard.summaryStep.jobDetails.influencers.title', {
defaultMessage: 'Influencers',
@ -115,23 +149,15 @@ export const JobDetails: FC = () => {
jobCreator.influencers.length > 0 ? (
jobCreator.influencers.join(', ')
) : (
<span style={{ fontStyle: 'italic' }}>
<Italic>
<FormattedMessage
id="xpack.ml.newJob.wizard.summaryStep.jobDetails.influencers.placeholder"
defaultMessage="No influencers selected"
/>
</span>
</Italic>
),
});
const trueLabel = i18n.translate('xpack.ml.newJob.wizard.summaryStep.jobDetails.trueLabel', {
defaultMessage: 'True',
});
const falseLabel = i18n.translate('xpack.ml.newJob.wizard.summaryStep.jobDetails.falseLabel', {
defaultMessage: 'False',
});
const advancedDetails: ListItems[] = [
{
title: i18n.translate('xpack.ml.newJob.wizard.summaryStep.jobDetails.enableModelPlot.title', {
@ -155,7 +181,7 @@ export const JobDetails: FC = () => {
defaultMessage: 'Model memory limit',
}
),
description: jobCreator.modelMemoryLimit !== null ? jobCreator.modelMemoryLimit : '',
description: modelMemoryLimit,
},
];

View file

@ -24,9 +24,10 @@ import { mlJobService } from '../../../../../services/job_service';
import { JsonEditorFlyout, EDITOR_MODE } from '../common/json_editor_flyout';
import { DatafeedPreviewFlyout } from '../common/datafeed_preview_flyout';
import { JOB_TYPE } from '../../../common/job_creator/util/constants';
import { isSingleMetricJobCreator } from '../../../common/job_creator';
import { JobDetails } from './job_details';
import { DetectorChart } from './detector_chart';
import { isSingleMetricJobCreator, isAdvancedJobCreator } from '../../../common/job_creator';
import { JobDetails } from './components/job_details';
import { DatafeedDetails } from './components/datafeed_details';
import { DetectorChart } from './components/detector_chart';
import { JobProgress } from './components/job_progress';
import { PostSaveOptions } from './components/post_save_options';
import {
@ -34,6 +35,7 @@ import {
resetJob,
advancedStartDatafeed,
} from '../../../common/job_creator/util/general';
import { JobSectionTitle, DatafeedSectionTitle } from './components/common';
export const SummaryStep: FC<StepProps> = ({ setCurrentStep, isCurrentStep }) => {
const { jobCreator, jobValidator, jobValidatorUpdated, resultsLoader } = useContext(
@ -44,6 +46,8 @@ export const SummaryStep: FC<StepProps> = ({ setCurrentStep, isCurrentStep }) =>
const [isValid, setIsValid] = useState(jobValidator.validationSummary.basic);
const [jobRunner, setJobRunner] = useState<JobRunner | null>(null);
const isAdvanced = isAdvancedJobCreator(jobCreator);
useEffect(() => {
jobCreator.subscribeToProgress(setProgress);
}, []);
@ -117,12 +121,22 @@ export const SummaryStep: FC<StepProps> = ({ setCurrentStep, isCurrentStep }) =>
<Fragment>
{isCurrentStep && (
<Fragment>
{isAdvanced && <JobSectionTitle />}
<DetectorChart />
<EuiSpacer size="m" />
<JobProgress progress={progress} />
<EuiSpacer size="m" />
<JobDetails />
{isAdvanced && (
<Fragment>
<EuiHorizontalRule />
<DatafeedSectionTitle />
<EuiSpacer size="m" />
<DatafeedDetails />
</Fragment>
)}
<EuiHorizontalRule />
<EuiFlexGroup>
{progress < 100 && (

View file

@ -6905,7 +6905,6 @@
"xpack.ml.newJob.wizard.summaryStep.createJobError": "ジョブの作成エラー",
"xpack.ml.newJob.wizard.summaryStep.jobDetails.bucketSpan.title": "バケットスパン",
"xpack.ml.newJob.wizard.summaryStep.jobDetails.enableModelPlot.title": "モデルプロットを有効にする",
"xpack.ml.newJob.wizard.summaryStep.jobDetails.falseLabel": "False",
"xpack.ml.newJob.wizard.summaryStep.jobDetails.groups.placeholder": "グループが選択されていません",
"xpack.ml.newJob.wizard.summaryStep.jobDetails.groups.title": "グループ",
"xpack.ml.newJob.wizard.summaryStep.jobDetails.influencers.placeholder": "影響因子が選択されていません",
@ -6918,7 +6917,6 @@
"xpack.ml.newJob.wizard.summaryStep.jobDetails.populationField.title": "集団フィールド",
"xpack.ml.newJob.wizard.summaryStep.jobDetails.splitField.placeholder": "分割フィールドが選択されていません",
"xpack.ml.newJob.wizard.summaryStep.jobDetails.splitField.title": "分割フィールド",
"xpack.ml.newJob.wizard.summaryStep.jobDetails.trueLabel": "True",
"xpack.ml.newJob.wizard.summaryStep.jobDetails.useDedicatedIndex.title": "専用インデックスを使用",
"xpack.ml.newJob.wizard.summaryStep.postSaveOptions.createWatch": "ウォッチを作成",
"xpack.ml.newJob.wizard.summaryStep.postSaveOptions.startJobInRealTime": "リアルタイムで実行中のジョブを開始",

View file

@ -7000,7 +7000,6 @@
"xpack.ml.newJob.wizard.summaryStep.createJobError": "作业创建错误",
"xpack.ml.newJob.wizard.summaryStep.jobDetails.bucketSpan.title": "存储桶跨度",
"xpack.ml.newJob.wizard.summaryStep.jobDetails.enableModelPlot.title": "启用模型绘图",
"xpack.ml.newJob.wizard.summaryStep.jobDetails.falseLabel": "False",
"xpack.ml.newJob.wizard.summaryStep.jobDetails.groups.placeholder": "未选择组",
"xpack.ml.newJob.wizard.summaryStep.jobDetails.groups.title": "组",
"xpack.ml.newJob.wizard.summaryStep.jobDetails.influencers.placeholder": "未选择影响因素",
@ -7013,7 +7012,6 @@
"xpack.ml.newJob.wizard.summaryStep.jobDetails.populationField.title": "群体字段",
"xpack.ml.newJob.wizard.summaryStep.jobDetails.splitField.placeholder": "未选择分割字段",
"xpack.ml.newJob.wizard.summaryStep.jobDetails.splitField.title": "分割字段",
"xpack.ml.newJob.wizard.summaryStep.jobDetails.trueLabel": "True",
"xpack.ml.newJob.wizard.summaryStep.jobDetails.useDedicatedIndex.title": "使用专用索引",
"xpack.ml.newJob.wizard.summaryStep.postSaveOptions.createWatch": "创建监视",
"xpack.ml.newJob.wizard.summaryStep.postSaveOptions.startJobInRealTime": "启动实时运行的作业",