mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
[ML] Converting single to multi metric job (#42532)
* [ML] Converting single to multi metric job * removing summary_count_field_name from copied job * changes based on review
This commit is contained in:
parent
042307e48d
commit
516b25c458
10 changed files with 83 additions and 35 deletions
|
@ -149,7 +149,14 @@ function showResults(resp, action) {
|
|||
export function cloneJob(jobId) {
|
||||
loadFullJob(jobId)
|
||||
.then((job) => {
|
||||
mlJobService.currentJob = job;
|
||||
if(job.custom_settings && job.custom_settings.created_by) {
|
||||
// if the job is from a wizards, i.e. contains a created_by property
|
||||
// use tempJobCloningObjects to temporarily store the job
|
||||
mlJobService.tempJobCloningObjects.job = job;
|
||||
} else {
|
||||
// otherwise use the currentJob
|
||||
mlJobService.currentJob = job;
|
||||
}
|
||||
window.location.href = `#/jobs/new_job`;
|
||||
})
|
||||
.catch((error) => {
|
||||
|
|
|
@ -23,7 +23,12 @@ export function preConfiguredJobRedirect(AppState, Private, courier) {
|
|||
let redirectUrl = getWizardUrlFromAppState(appState);
|
||||
if (redirectUrl === null) {
|
||||
// no settings in appState
|
||||
const job = mlJobService.currentJob;
|
||||
let job;
|
||||
if(mlJobService.currentJob !== undefined) {
|
||||
job = mlJobService.currentJob;
|
||||
} else if(mlJobService.tempJobCloningObjects.job !== undefined) {
|
||||
job = mlJobService.tempJobCloningObjects.job;
|
||||
}
|
||||
if (job) {
|
||||
loadIndexPatterns(Private, courier)
|
||||
.then(() => {
|
||||
|
|
|
@ -12,7 +12,7 @@ import { Aggregation, Field } from '../../../../../common/types/fields';
|
|||
import { createEmptyJob, createEmptyDatafeed } from './util/default_configs';
|
||||
import { mlJobService } from '../../../../services/job_service';
|
||||
import { JobRunner, ProgressSubscriber } from '../job_runner';
|
||||
import { JOB_TYPE } from './util/constants';
|
||||
import { JOB_TYPE, CREATED_BY_LABEL } from './util/constants';
|
||||
|
||||
export class JobCreator {
|
||||
protected _type: JOB_TYPE = JOB_TYPE.SINGLE_METRIC;
|
||||
|
@ -341,12 +341,12 @@ export class JobCreator {
|
|||
return null;
|
||||
}
|
||||
|
||||
public set createdBy(createdBy: string | null) {
|
||||
public set createdBy(createdBy: CREATED_BY_LABEL | null) {
|
||||
this._setCustomSetting('created_by', createdBy);
|
||||
}
|
||||
|
||||
public get createdBy(): string | null {
|
||||
return this._getCustomSetting('created_by') as string | null;
|
||||
public get createdBy(): CREATED_BY_LABEL | null {
|
||||
return this._getCustomSetting('created_by') as CREATED_BY_LABEL | null;
|
||||
}
|
||||
|
||||
public get formattedJobJson() {
|
||||
|
|
|
@ -5,9 +5,14 @@
|
|||
*/
|
||||
|
||||
import React, { Fragment, FC, useContext, useEffect, useState } from 'react';
|
||||
import { EuiFlexGroup, EuiFlexItem, EuiButtonEmpty } from '@elastic/eui';
|
||||
|
||||
import { JobCreatorContext } from '../../../job_creator_context';
|
||||
import { BucketSpan } from '../bucket_span';
|
||||
|
||||
import { CREATED_BY_LABEL } from '../../../../../common/job_creator/util/constants';
|
||||
import { mlJobService } from '../../../../../../../services/job_service';
|
||||
|
||||
interface Props {
|
||||
isActive: boolean;
|
||||
setIsValid: (proceed: boolean) => void;
|
||||
|
@ -27,5 +32,37 @@ export const SingleMetricSettings: FC<Props> = ({ isActive, setIsValid }) => {
|
|||
setBucketSpan(jobCreator.bucketSpan);
|
||||
}, [jobCreatorUpdated]);
|
||||
|
||||
return <Fragment>{isActive && <BucketSpan />}</Fragment>;
|
||||
const convertToMultiMetricJob = () => {
|
||||
jobCreator.createdBy = CREATED_BY_LABEL.MULTI_METRIC;
|
||||
mlJobService.tempJobCloningObjects.job = {
|
||||
...jobCreator.jobConfig,
|
||||
datafeed_config: jobCreator.datafeedConfig,
|
||||
};
|
||||
delete mlJobService.tempJobCloningObjects.job.datafeed_config.aggregations;
|
||||
delete mlJobService.tempJobCloningObjects.job.analysis_config.summary_count_field_name;
|
||||
|
||||
mlJobService.tempJobCloningObjects.skipTimeRangeStep = true;
|
||||
window.location.href = window.location.href.replace('single_metric', 'multi_metric');
|
||||
};
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
{isActive && (
|
||||
<Fragment>
|
||||
<EuiFlexGroup gutterSize="xl">
|
||||
<EuiFlexItem>
|
||||
<BucketSpan />
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
<EuiFlexGroup>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiButtonEmpty onClick={convertToMultiMetricJob}>
|
||||
Convert to multi metric job
|
||||
</EuiButtonEmpty>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</Fragment>
|
||||
)}
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -65,7 +65,7 @@ export const SplitCards: FC<Props> = memo(
|
|||
marginBottom: `-${SPACING}px`,
|
||||
marginLeft: `${sideMargin}px`,
|
||||
marginRight: `${sideMargin}px`,
|
||||
...(animate ? { transition: 'margin 0.2s' } : {}),
|
||||
...(animate ? { transition: 'margin 0.5s' } : {}),
|
||||
};
|
||||
return (
|
||||
<div key={fieldName} ref={ref => storePanels(ref, marginBottom)} style={style}>
|
||||
|
|
|
@ -18,8 +18,6 @@ import { EventRateChart } from '../charts/event_rate_chart';
|
|||
import { LineChartPoint } from '../../../common/chart_loader';
|
||||
import { TimeRangePicker } from './time_range_picker';
|
||||
import { GetTimeFieldRangeResponse } from '../../../../../services/ml_api_service';
|
||||
import { mlJobService } from '../../../../../services/job_service';
|
||||
import { ml } from '../../../../../services/ml_api_service';
|
||||
|
||||
export interface TimeRange {
|
||||
start: number;
|
||||
|
@ -82,28 +80,6 @@ export const TimeRangeStep: FC<StepProps> = ({ setCurrentStep, isCurrentStep })
|
|||
});
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (mlJobService.currentJob !== undefined) {
|
||||
(async (index: string, timeFieldName: string | undefined, query: object) => {
|
||||
const resp = await ml.getTimeFieldRange({
|
||||
index,
|
||||
timeFieldName,
|
||||
query,
|
||||
});
|
||||
setTimeRange({
|
||||
start: resp.start.epoch,
|
||||
end: resp.end.epoch,
|
||||
});
|
||||
// wipe the cloning job
|
||||
mlJobService.currentJob = undefined;
|
||||
})(
|
||||
kibanaContext.currentIndexPattern.title,
|
||||
kibanaContext.currentIndexPattern.timeFieldName,
|
||||
kibanaContext.combinedQuery
|
||||
);
|
||||
}
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
{isCurrentStep && (
|
||||
|
|
|
@ -51,10 +51,16 @@ export const Page: FC<PageProps> = ({ existingJobsAndGroups, jobType }) => {
|
|||
const { from, to } = getTimeFilterRange();
|
||||
jobCreator.setTimeRange(from, to);
|
||||
|
||||
if (mlJobService.currentJob !== undefined) {
|
||||
const clonedJob = mlJobService.cloneJob(mlJobService.currentJob);
|
||||
let skipTimeRangeStep = false;
|
||||
|
||||
if (mlJobService.tempJobCloningObjects.job !== undefined) {
|
||||
const clonedJob = mlJobService.cloneJob(mlJobService.tempJobCloningObjects.job);
|
||||
const { job, datafeed } = expandCombinedJobConfig(clonedJob);
|
||||
jobCreator.cloneFromExistingJob(job, datafeed);
|
||||
|
||||
skipTimeRangeStep = mlJobService.tempJobCloningObjects.skipTimeRangeStep;
|
||||
mlJobService.tempJobCloningObjects.skipTimeRangeStep = false;
|
||||
mlJobService.tempJobCloningObjects.job = undefined;
|
||||
} else {
|
||||
jobCreator.bucketSpan = DEFAULT_BUCKET_SPAN;
|
||||
|
||||
|
@ -89,7 +95,6 @@ export const Page: FC<PageProps> = ({ existingJobsAndGroups, jobType }) => {
|
|||
useEffect(() => {
|
||||
return () => {
|
||||
jobCreator.forceStopRefreshPolls();
|
||||
mlJobService.currentJob = undefined;
|
||||
};
|
||||
});
|
||||
|
||||
|
@ -105,6 +110,7 @@ export const Page: FC<PageProps> = ({ existingJobsAndGroups, jobType }) => {
|
|||
chartInterval={chartInterval}
|
||||
jobValidator={jobValidator}
|
||||
existingJobsAndGroups={existingJobsAndGroups}
|
||||
skipTimeRangeStep={skipTimeRangeStep}
|
||||
/>
|
||||
</EuiPageContentBody>
|
||||
</EuiPageBody>
|
||||
|
|
|
@ -39,6 +39,7 @@ interface Props {
|
|||
chartInterval: MlTimeBuckets;
|
||||
jobValidator: JobValidator;
|
||||
existingJobsAndGroups: ExistingJobsAndGroups;
|
||||
skipTimeRangeStep: boolean;
|
||||
}
|
||||
|
||||
export const Wizard: FC<Props> = ({
|
||||
|
@ -48,6 +49,7 @@ export const Wizard: FC<Props> = ({
|
|||
chartInterval,
|
||||
jobValidator,
|
||||
existingJobsAndGroups,
|
||||
skipTimeRangeStep = false,
|
||||
}) => {
|
||||
const [jobCreatorUpdated, setJobCreatorUpdate] = useReducer<(s: number) => number>(s => s + 1, 0);
|
||||
const jobCreatorUpdate = () => setJobCreatorUpdate(jobCreatorUpdated);
|
||||
|
@ -102,6 +104,10 @@ export const Wizard: FC<Props> = ({
|
|||
|
||||
useEffect(() => {
|
||||
jobCreator.subscribeToProgress(setProgress);
|
||||
|
||||
if (skipTimeRangeStep) {
|
||||
setCurrentStep(WIZARD_STEPS.PICK_FIELDS);
|
||||
}
|
||||
}, []);
|
||||
|
||||
// disable the step links if the job is running
|
||||
|
|
|
@ -11,6 +11,11 @@ export interface ExistingJobsAndGroups {
|
|||
|
||||
declare interface JobService {
|
||||
currentJob: any;
|
||||
tempJobCloningObjects: {
|
||||
job: any;
|
||||
skipTimeRangeStep: boolean;
|
||||
};
|
||||
skipTimeRangeStep: boolean;
|
||||
saveNewJob(job: any): Promise<any>;
|
||||
cloneJob(job: any): any;
|
||||
openJob(jobId: string): Promise<any>;
|
||||
|
|
|
@ -30,6 +30,12 @@ class JobService {
|
|||
// if populated when loading the job management page, the start datafeed modal
|
||||
// is automatically opened.
|
||||
this.currentJob = undefined;
|
||||
|
||||
this.tempJobCloningObjects = {
|
||||
job: undefined,
|
||||
skipTimeRangeStep: false,
|
||||
};
|
||||
|
||||
this.jobs = [];
|
||||
|
||||
// Provide ready access to widely used basic job properties.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue