Skip to content

Commit

Permalink
Merge branch 'main' into kbnArchiverDrillDowns
Browse files Browse the repository at this point in the history
  • Loading branch information
bhavyarm authored Jun 21, 2022
2 parents 9e7003b + ee1bbf2 commit 78e06c2
Show file tree
Hide file tree
Showing 11 changed files with 214 additions and 61 deletions.
6 changes: 4 additions & 2 deletions x-pack/plugins/ml/common/types/results.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
import type { LineAnnotationDatum, RectAnnotationDatum } from '@elastic/charts';
import type { ErrorType } from '../util/errors';
import type { EntityField } from '../util/anomaly_utils';
import type { Datafeed, JobId } from './anomaly_detection_jobs';
import type { Datafeed, JobId, ModelSnapshot } from './anomaly_detection_jobs';
import { ES_AGGREGATION, ML_JOB_AGGREGATION } from '../constants/aggregation_types';
import type { RecordForInfluencer } from './anomalies';

Expand All @@ -20,12 +20,14 @@ export interface GetStoppedPartitionResult {
export interface MLRectAnnotationDatum extends RectAnnotationDatum {
header: number;
}
export interface LineAnnotationDatumWithModelSnapshot extends LineAnnotationDatum {
modelSnapshot?: ModelSnapshot;
}
export interface GetDatafeedResultsChartDataResult {
bucketResults: number[][];
datafeedResults: number[][];
annotationResultsRect: MLRectAnnotationDatum[];
annotationResultsLine: LineAnnotationDatum[];
modelSnapshotResultsLine: LineAnnotationDatum[];
}

export interface DatafeedResultsChartDataParams {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,17 @@ import {
ScaleType,
Settings,
timeFormatter,
RectAnnotationEvent,
LineAnnotationEvent,
} from '@elastic/charts';

import { DATAFEED_STATE } from '../../../../../../common/constants/states';
import { CombinedJobWithStats } from '../../../../../../common/types/anomaly_detection_jobs';
import {
CombinedJobWithStats,
ModelSnapshot,
} from '../../../../../../common/types/anomaly_detection_jobs';
import { JobMessage } from '../../../../../../common/types/audit_message';
import { LineAnnotationDatumWithModelSnapshot } from '../../../../../../common/types/results';
import { useToastNotificationService } from '../../../../services/toast_notification_service';
import { useMlApiContext } from '../../../../contexts/kibana';
import { useCurrentEuiTheme } from '../../../../components/color_range_legend';
Expand All @@ -58,14 +64,23 @@ import { checkPermission } from '../../../../capabilities/check_capabilities';

const dateFormatter = timeFormatter('MM-DD HH:mm:ss');
const MAX_CHART_POINTS = 480;
const revertSnapshotMessage = i18n.translate(
'xpack.ml.jobsList.datafeedChart.revertSnapshotMessage',
{
defaultMessage: 'Click to revert to this model snapshot.',
}
);

interface DatafeedChartFlyoutProps {
jobId: string;
end: number;
onClose: () => void;
onModelSnapshotAnnotationClick: (modelSnapshot: ModelSnapshot) => void;
}

function setLineAnnotationHeader(lineDatum: LineAnnotationDatum) {
function setLineAnnotationHeader(
lineDatum: LineAnnotationDatum | LineAnnotationDatumWithModelSnapshot
) {
lineDatum.header = dateFormatter(lineDatum.dataValue);
return lineDatum;
}
Expand All @@ -78,28 +93,44 @@ const customTooltip: CustomAnnotationTooltip = ({ details, datum }) => (
</div>
);

export const DatafeedChartFlyout: FC<DatafeedChartFlyoutProps> = ({ jobId, end, onClose }) => {
export const DatafeedChartFlyout: FC<DatafeedChartFlyoutProps> = ({
jobId,
end,
onClose,
onModelSnapshotAnnotationClick,
}) => {
const [data, setData] = useState<{
datafeedConfig: CombinedJobWithStats['datafeed_config'] | undefined;
bucketSpan: string | undefined;
isInitialized: boolean;
}>({ datafeedConfig: undefined, bucketSpan: undefined, isInitialized: false });
modelSnapshotData: LineAnnotationDatumWithModelSnapshot[];
}>({
datafeedConfig: undefined,
bucketSpan: undefined,
isInitialized: false,
modelSnapshotData: [],
});
const [endDate, setEndDate] = useState<any>(moment(end));
const [isLoadingChartData, setIsLoadingChartData] = useState<boolean>(false);
const [bucketData, setBucketData] = useState<number[][]>([]);
const [annotationData, setAnnotationData] = useState<{
rect: RectAnnotationDatum[];
line: LineAnnotationDatum[];
}>({ rect: [], line: [] });
const [modelSnapshotData, setModelSnapshotData] = useState<LineAnnotationDatum[]>([]);
const [modelSnapshotDataForTimeRange, setModelSnapshotDataForTimeRange] = useState<
LineAnnotationDatumWithModelSnapshot[]
>([]);
const [messageData, setMessageData] = useState<LineAnnotationDatum[]>([]);
const [sourceData, setSourceData] = useState<number[][]>([]);
const [showAnnotations, setShowAnnotations] = useState<boolean>(true);
const [showModelSnapshots, setShowModelSnapshots] = useState<boolean>(true);
const [range, setRange] = useState<{ start: string; end: string } | undefined>();
const canUpdateDatafeed = useMemo(() => checkPermission('canUpdateDatafeed'), []);
const canCreateJob = useMemo(() => checkPermission('canCreateJob'), []);
const canStartStopDatafeed = useMemo(() => checkPermission('canStartStopDatafeed'), []);

const {
getModelSnapshots,
results: { getDatafeedResultChartData },
} = useMlApiContext();
const { displayErrorToast } = useToastNotificationService();
Expand Down Expand Up @@ -144,7 +175,11 @@ export const DatafeedChartFlyout: FC<DatafeedChartFlyoutProps> = ({ jobId, end,
rect: chartData.annotationResultsRect,
line: chartData.annotationResultsLine.map(setLineAnnotationHeader),
});
setModelSnapshotData(chartData.modelSnapshotResultsLine.map(setLineAnnotationHeader));
setModelSnapshotDataForTimeRange(
data.modelSnapshotData.filter(
(datum) => datum.dataValue >= startTimestamp && datum.dataValue <= endTimestamp
)
);
} catch (error) {
const title = i18n.translate('xpack.ml.jobsList.datafeedChart.errorToastTitle', {
defaultMessage: 'Error fetching data',
Expand All @@ -154,21 +189,37 @@ export const DatafeedChartFlyout: FC<DatafeedChartFlyoutProps> = ({ jobId, end,
setIsLoadingChartData(false);
}, [endDate, data.bucketSpan]);

const getJobData = useCallback(async () => {
const getJobAndSnapshotData = useCallback(async () => {
try {
const job: CombinedJobWithStats = await loadFullJob(jobId);
const modelSnapshotResultsLine: LineAnnotationDatumWithModelSnapshot[] = [];
const modelSnapshotsResp = await getModelSnapshots(jobId);
const modelSnapshots = modelSnapshotsResp.model_snapshots ?? [];
modelSnapshots.forEach((modelSnapshot) => {
const timestamp = Number(modelSnapshot.latest_record_time_stamp);

modelSnapshotResultsLine.push({
dataValue: timestamp,
details: `${modelSnapshot.description}. ${
canCreateJob && canStartStopDatafeed ? revertSnapshotMessage : ''
}`,
modelSnapshot,
});
});

setData({
datafeedConfig: job.datafeed_config,
bucketSpan: job.analysis_config.bucket_span,
isInitialized: true,
modelSnapshotData: modelSnapshotResultsLine.map(setLineAnnotationHeader),
});
} catch (error) {
displayErrorToast(error);
}
}, [jobId]);

useEffect(function loadJobWithDatafeed() {
getJobData();
useEffect(function loadInitialData() {
getJobAndSnapshotData();
}, []);

useEffect(
Expand Down Expand Up @@ -323,6 +374,24 @@ export const DatafeedChartFlyout: FC<DatafeedChartFlyoutProps> = ({ jobId, end,
<Settings
showLegend
legendPosition={Position.Bottom}
onAnnotationClick={(annotations: {
rects: RectAnnotationEvent[];
lines: LineAnnotationEvent[];
}) => {
// If it's not a line annotation or if it's not a model snapshot annotation then do nothing
if (
!(canCreateJob && canStartStopDatafeed) ||
annotations.lines?.length === 0 ||
(annotations.lines &&
!annotations.lines[0].id.includes('Model snapshots'))
)
return;

onModelSnapshotAnnotationClick(
// @ts-expect-error property 'modelSnapshot' does not exist on type
annotations.lines[0].datum.modelSnapshot
);
}}
// TODO use the EUI charts theme see src/plugins/charts/public/services/theme/README.md
theme={{
lineSeriesStyle: {
Expand All @@ -349,28 +418,6 @@ export const DatafeedChartFlyout: FC<DatafeedChartFlyoutProps> = ({ jobId, end,
})}
position={Position.Left}
/>
{showModelSnapshots ? (
<LineAnnotation
id={i18n.translate(
'xpack.ml.jobsList.datafeedChart.modelSnapshotsLineSeriesId',
{
defaultMessage: 'Model snapshots',
}
)}
key="model-snapshots-results-line"
domainType={AnnotationDomainType.XDomain}
dataValues={modelSnapshotData}
marker={<EuiIcon type="asterisk" />}
markerPosition={Position.Top}
style={{
line: {
strokeWidth: 3,
stroke: euiTheme.euiColorVis1,
opacity: 0.5,
},
}}
/>
) : null}
{showAnnotations ? (
<>
<LineAnnotation
Expand Down Expand Up @@ -407,6 +454,28 @@ export const DatafeedChartFlyout: FC<DatafeedChartFlyoutProps> = ({ jobId, end,
/>
</>
) : null}
{showModelSnapshots ? (
<LineAnnotation
id={i18n.translate(
'xpack.ml.jobsList.datafeedChart.modelSnapshotsLineSeriesId',
{
defaultMessage: 'Model snapshots',
}
)}
key="model-snapshots-results-line"
domainType={AnnotationDomainType.XDomain}
dataValues={modelSnapshotDataForTimeRange}
marker={<EuiIcon type="asterisk" />}
markerPosition={Position.Top}
style={{
line: {
strokeWidth: 3,
stroke: euiTheme.euiColorVis1,
opacity: 0.5,
},
}}
/>
) : null}
{messageData.length > 0 ? (
<>
<LineAnnotation
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { DatafeedPreviewPane } from './datafeed_preview_tab';
import { AnnotationsTable } from '../../../../components/annotations/annotations_table';
import { DatafeedChartFlyout } from '../datafeed_chart_flyout';
import { AnnotationFlyout } from '../../../../components/annotations/annotation_flyout';
import { RevertModelSnapshotFlyout } from '../../../../components/model_snapshots/revert_model_snapshot_flyout';
import { ModelSnapshotTable } from '../../../../components/model_snapshots';
import { ForecastsTable } from './forecasts_table';
import { JobDetailsPane } from './job_details_pane';
Expand All @@ -29,6 +30,8 @@ export class JobDetailsUI extends Component {

this.state = {
datafeedChartFlyoutVisible: false,
modelSnapshot: null,
revertSnapshotFlyoutVisible: false,
};
if (this.props.addYourself) {
this.props.addYourself(props.jobId, (j) => this.updateJob(j));
Expand Down Expand Up @@ -151,10 +154,31 @@ export class JobDetailsUI extends Component {
datafeedChartFlyoutVisible: false,
});
}}
onModelSnapshotAnnotationClick={(modelSnapshot) => {
this.setState({
modelSnapshot,
revertSnapshotFlyoutVisible: true,
datafeedChartFlyoutVisible: false,
});
}}
end={job.data_counts.latest_bucket_timestamp}
jobId={this.props.jobId}
/>
) : null}
{this.state.revertSnapshotFlyoutVisible === true &&
this.state.modelSnapshot !== null ? (
<RevertModelSnapshotFlyout
snapshot={this.state.modelSnapshot}
snapshots={[this.state.modelSnapshot]}
job={job}
closeFlyout={() => {
this.setState({
revertSnapshotFlyoutVisible: false,
});
}}
refresh={refreshJobList}
/>
) : null}
</>
),
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -657,7 +657,6 @@ export function resultsServiceProvider(mlClient: MlClient, client?: IScopedClust
datafeedResults: [],
annotationResultsRect: [],
annotationResultsLine: [],
modelSnapshotResultsLine: [],
};

const { getDatafeedByJobId } = datafeedsProvider(client!, mlClient);
Expand Down Expand Up @@ -739,7 +738,7 @@ export function resultsServiceProvider(mlClient: MlClient, client?: IScopedClust

const { getAnnotations } = annotationServiceProvider(client!);

const [bucketResp, annotationResp, modelSnapshotsResp] = await Promise.all([
const [bucketResp, annotationResp] = await Promise.all([
mlClient.getBuckets({
job_id: jobId,
body: { desc: true, start: String(start), end: String(end), page: { from: 0, size: 1000 } },
Expand All @@ -750,11 +749,6 @@ export function resultsServiceProvider(mlClient: MlClient, client?: IScopedClust
latestMs: end,
maxAnnotations: 1000,
}),
mlClient.getModelSnapshots({
job_id: jobId,
start: String(start),
end: String(end),
}),
]);

const bucketResults = bucketResp?.buckets ?? [];
Expand Down Expand Up @@ -786,16 +780,6 @@ export function resultsServiceProvider(mlClient: MlClient, client?: IScopedClust
}
});

const modelSnapshots = modelSnapshotsResp?.model_snapshots ?? [];
modelSnapshots.forEach((modelSnapshot) => {
const timestamp = Number(modelSnapshot?.timestamp);

finalResults.modelSnapshotResultsLine.push({
dataValue: timestamp,
details: modelSnapshot.description,
});
});

return finalResults;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,13 @@ export const policyFactoryWithoutPaidFeatures = (
...policy,
windows: {
...policy.windows,
advanced:
policy.windows.advanced === undefined
? undefined
: {
...policy.windows.advanced,
rollback: undefined,
},
ransomware: {
mode: ProtectionModes.off,
supported: false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -911,7 +911,10 @@ type KbnConfigSchemaNonOptionalProps<Props extends Record<string, unknown>> = Pi
*/
export interface PolicyConfig {
windows: {
advanced?: {};
advanced?: {
[key: string]: unknown;
rollback?: string | boolean;
};
events: {
dll_and_driver_load: boolean;
dns: boolean;
Expand Down
Loading

0 comments on commit 78e06c2

Please sign in to comment.