[ML] Adding missing detector descriptions to advanced wizard (#48440) (#48615)

* [ML] Adding detector descriptions to advanced wizard

* renaming things

* reverting accidentally added refactor
This commit is contained in:
James Gowdy 2019-10-18 10:50:39 +01:00 committed by GitHub
parent bc375cacab
commit 567288216b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 143 additions and 39 deletions

View file

@ -12,6 +12,9 @@ import 'uiExports/savedObjectTypes';
import 'ui/courier';
import 'ui/autoload/all';
// needed to make syntax highlighting work in ace editors
import 'ace';
import 'plugins/ml/access_denied';
import 'plugins/ml/jobs';
import 'plugins/ml/overview';

View file

@ -23,6 +23,7 @@ export interface RichDetector {
overField: SplitField;
partitionField: SplitField;
excludeFrequent: string | null;
description: string | null;
}
export class AdvancedJobCreator extends JobCreator {
@ -43,7 +44,8 @@ export class AdvancedJobCreator extends JobCreator {
byField: SplitField,
overField: SplitField,
partitionField: SplitField,
excludeFrequent: string | null
excludeFrequent: string | null,
description: string | null
) {
const { detector, richDetector } = this._createDetector(
agg,
@ -51,7 +53,8 @@ export class AdvancedJobCreator extends JobCreator {
byField,
overField,
partitionField,
excludeFrequent
excludeFrequent,
description
);
this._addDetector(detector, agg, field);
@ -65,6 +68,7 @@ export class AdvancedJobCreator extends JobCreator {
overField: SplitField,
partitionField: SplitField,
excludeFrequent: string | null,
description: string | null,
index: number
) {
const { detector, richDetector } = this._createDetector(
@ -73,7 +77,8 @@ export class AdvancedJobCreator extends JobCreator {
byField,
overField,
partitionField,
excludeFrequent
excludeFrequent,
description
);
this._editDetector(detector, agg, field, index);
@ -89,7 +94,8 @@ export class AdvancedJobCreator extends JobCreator {
byField: SplitField,
overField: SplitField,
partitionField: SplitField,
excludeFrequent: string | null
excludeFrequent: string | null,
description: string | null
): { detector: Detector; richDetector: RichDetector } {
const detector: Detector = createBasicDetector(agg, field);
@ -105,6 +111,9 @@ export class AdvancedJobCreator extends JobCreator {
if (excludeFrequent !== null) {
detector.exclude_frequent = excludeFrequent;
}
if (description !== null) {
detector.detector_description = description;
}
const richDetector: RichDetector = {
agg,
@ -113,6 +122,7 @@ export class AdvancedJobCreator extends JobCreator {
overField,
partitionField,
excludeFrequent,
description,
};
return { detector, richDetector };
@ -170,7 +180,8 @@ export class AdvancedJobCreator extends JobCreator {
dtr.byField,
dtr.overField,
dtr.partitionField,
dtr.excludeFrequent
dtr.excludeFrequent,
dtr.description
);
}
});

View file

@ -32,6 +32,7 @@ export function getRichDetectors(job: Job, datafeed: Datafeed, advanced: boolean
? newJobCapsService.getFieldById(d.partition_field_name)
: null,
excludeFrequent: d.exclude_frequent || null,
description: d.detector_description || null,
};
});
}

View file

@ -12,6 +12,7 @@ import {
EuiFlexGrid,
EuiComboBoxOptionProps,
EuiHorizontalRule,
EuiTextArea,
} from '@elastic/eui';
import { JobCreatorContext } from '../../../job_creator_context';
import { AdvancedJobCreator, JobCreatorType } from '../../../../../common/job_creator';
@ -24,6 +25,8 @@ import { RichDetector } from '../../../../../common/job_creator/advanced_job_cre
import { ES_FIELD_TYPES } from '../../../../../../../../../../../../src/plugins/data/public';
import { ModalWrapper } from './modal_wrapper';
import { MLCATEGORY } from '../../../../../../../../common/constants/field_types';
import { detectorToString } from '../../../../../../../util/string_utils';
import { createBasicDetector } from '../../../../../common/job_creator/util/default_configs';
import {
AggDescription,
@ -32,6 +35,7 @@ import {
OverFieldDescription,
PartitionFieldDescription,
ExcludeFrequentDescription,
DescriptionDescription,
} from './descriptions';
interface Props {
@ -81,8 +85,10 @@ export const AdvancedDetectorModal: FC<Props> = ({
const [excludeFrequentOption, setExcludeFrequentOption] = useState(
createExcludeFrequentOption(detector.excludeFrequent)
);
const [descriptionOption, setDescriptionOption] = useState(detector.description || '');
const [fieldsEnabled, setFieldsEnabled] = useState(true);
const [fieldOptionEnabled, setFieldOptionEnabled] = useState(true);
const { descriptionPlaceholder, setDescriptionPlaceholder } = useDetectorPlaceholder(detector);
const aggOptions: EuiComboBoxOptionProps[] = aggs.map(createAggOption);
const fieldOptions: EuiComboBoxOptionProps[] = fields
@ -132,8 +138,10 @@ export const AdvancedDetectorModal: FC<Props> = ({
overField: getField(overFieldOption.label),
partitionField: getField(partitionFieldOption.label),
excludeFrequent: excludeFrequentOption.label !== '' ? excludeFrequentOption.label : null,
description: descriptionOption !== '' ? descriptionOption : null,
};
setDetector(dtr);
setDescriptionPlaceholder(dtr);
}, [
aggOption,
fieldOption,
@ -141,6 +149,7 @@ export const AdvancedDetectorModal: FC<Props> = ({
overFieldOption,
partitionFieldOption,
excludeFrequentOption,
descriptionOption,
]);
useEffect(() => {
@ -228,9 +237,6 @@ export const AdvancedDetectorModal: FC<Props> = ({
/>
</PartitionFieldDescription>
</EuiFlexItem>
</EuiFlexGrid>
<EuiHorizontalRule margin="l" />
<EuiFlexGroup>
<EuiFlexItem>
<ExcludeFrequentDescription>
<EuiComboBox
@ -243,7 +249,19 @@ export const AdvancedDetectorModal: FC<Props> = ({
/>
</ExcludeFrequentDescription>
</EuiFlexItem>
<EuiFlexItem />
</EuiFlexGrid>
<EuiHorizontalRule margin="l" />
<EuiFlexGroup>
<EuiFlexItem>
<DescriptionDescription>
<EuiTextArea
rows={2}
placeholder={descriptionPlaceholder}
value={descriptionOption}
onChange={e => setDescriptionOption(e.target.value)}
/>
</DescriptionDescription>
</EuiFlexItem>
</EuiFlexGroup>
</Fragment>
</ModalWrapper>
@ -291,3 +309,27 @@ function createMlcategoryField(jobCreator: JobCreatorType): EuiComboBoxOptionPro
},
];
}
function useDetectorPlaceholder(detector: RichDetector) {
const [descriptionPlaceholder, setDescriptionPlaceholderString] = useState(
createDefaultDescription(detector)
);
function setDescriptionPlaceholder(dtr: RichDetector) {
setDescriptionPlaceholderString(createDefaultDescription(dtr));
}
return { descriptionPlaceholder, setDescriptionPlaceholder };
}
function createDefaultDescription(dtr: RichDetector) {
if (dtr.agg === null || dtr.field === null) {
return '';
}
const basicDetector = createBasicDetector(dtr.agg, dtr.field);
basicDetector.by_field_name = dtr.byField ? dtr.byField.id : undefined;
basicDetector.over_field_name = dtr.overField ? dtr.overField.id : undefined;
basicDetector.partition_field_name = dtr.partitionField ? dtr.partitionField.id : undefined;
basicDetector.exclude_frequent = dtr.excludeFrequent ? dtr.excludeFrequent : undefined;
return detectorToString(basicDetector);
}

View file

@ -158,3 +158,28 @@ export const ExcludeFrequentDescription: FC = memo(({ children }) => {
</EuiDescribedFormGroup>
);
});
export const DescriptionDescription: FC = memo(({ children }) => {
const title = i18n.translate(
'xpack.ml.newJob.wizard.pickFieldsStep.advancedDetectorModal.description.title',
{
defaultMessage: 'Description',
}
);
return (
<EuiDescribedFormGroup
idAria="description"
title={<h3>{title}</h3>}
description={
<FormattedMessage
id="xpack.ml.newJob.wizard.pickFieldsStep.advancedDetectorModal.description.description"
defaultMessage="Override the default detector description with a meaningful description of what the detector is analyzing."
/>
}
>
<EuiFormRow label={title} describedByIds={['description']}>
<>{children}</>
</EuiFormRow>
</EuiDescribedFormGroup>
);
});

View file

@ -17,6 +17,7 @@ import {
EuiButtonIcon,
EuiSpacer,
EuiCallOut,
EuiHorizontalRule,
} from '@elastic/eui';
import { JobCreatorContext } from '../../../job_creator_context';
@ -37,6 +38,39 @@ export const DetectorList: FC<Props> = ({ onEditJob, onDeleteJob }) => {
setDetectors(jobCreator.detectors);
}, [jobCreatorUpdated]);
const Buttons: FC<{ index: number }> = ({ index }) => {
return (
<EuiFlexGroup gutterSize="s">
<EuiFlexItem>
<EuiButtonIcon
color="primary"
onClick={() => onEditJob(index)}
iconType="pencil"
aria-label={i18n.translate(
'xpack.ml.newJob.wizard.pickFieldsStep.advancedDetectorList.editButton',
{
defaultMessage: 'Edit',
}
)}
/>
</EuiFlexItem>
<EuiFlexItem>
<EuiButtonIcon
color="danger"
onClick={() => onDeleteJob(index)}
iconType="trash"
aria-label={i18n.translate(
'xpack.ml.newJob.wizard.pickFieldsStep.advancedDetectorList.deleteButton',
{
defaultMessage: 'Delete',
}
)}
/>
</EuiFlexItem>
</EuiFlexGroup>
);
};
return (
<Fragment>
<EuiTitle size="xs">
@ -57,38 +91,23 @@ export const DetectorList: FC<Props> = ({ onEditJob, onDeleteJob }) => {
<EuiFlexItem key={i}>
<EuiPanel paddingSize="m">
<EuiFlexGroup>
<EuiFlexItem>{detectorToString(d)}</EuiFlexItem>
<EuiFlexItem>
{d.detector_description !== undefined ? (
<div style={{ fontWeight: 'bold' }}>{d.detector_description}</div>
) : (
detectorToString(d)
)}
</EuiFlexItem>
<EuiFlexItem grow={false} style={{ margin: '8px' }}>
<EuiFlexGroup gutterSize="s">
<EuiFlexItem>
<EuiButtonIcon
color="primary"
onClick={() => onEditJob(i)}
iconType="pencil"
aria-label={i18n.translate(
'xpack.ml.newJob.wizard.pickFieldsStep.advancedDetectorList.editButton',
{
defaultMessage: 'Edit',
}
)}
/>
</EuiFlexItem>
<EuiFlexItem>
<EuiButtonIcon
color="danger"
onClick={() => onDeleteJob(i)}
iconType="trash"
aria-label={i18n.translate(
'xpack.ml.newJob.wizard.pickFieldsStep.advancedDetectorList.deleteButton',
{
defaultMessage: 'Delete',
}
)}
/>
</EuiFlexItem>
</EuiFlexGroup>
<Buttons index={i} />
</EuiFlexItem>
</EuiFlexGroup>
{d.detector_description !== undefined && (
<Fragment>
<EuiHorizontalRule margin="s" />
{detectorToString(d)}
</Fragment>
)}
</EuiPanel>
</EuiFlexItem>
))}

View file

@ -26,6 +26,7 @@ const emptyRichDetector: RichDetector = {
overField: null,
partitionField: null,
excludeFrequent: null,
description: null,
};
export const AdvancedDetectors: FC<Props> = ({ setIsValid }) => {
@ -47,7 +48,8 @@ export const AdvancedDetectors: FC<Props> = ({ setIsValid }) => {
dtr.byField,
dtr.overField,
dtr.partitionField,
dtr.excludeFrequent
dtr.excludeFrequent,
dtr.description
);
} else {
jobCreator.editDetector(
@ -57,6 +59,7 @@ export const AdvancedDetectors: FC<Props> = ({ setIsValid }) => {
dtr.overField,
dtr.partitionField,
dtr.excludeFrequent,
dtr.description,
index
);
}