Skip to content

Commit

Permalink
Merge branch 'master' into fix/http-kibana-change-side-effect
Browse files Browse the repository at this point in the history
  • Loading branch information
shahzad31 committed Mar 22, 2020
2 parents a287758 + 33af1c1 commit 3646e9e
Show file tree
Hide file tree
Showing 130 changed files with 3,783 additions and 545 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,20 @@ function useCytoscape(options: cytoscape.CytoscapeOptions) {
return [ref, cy] as [React.MutableRefObject<any>, cytoscape.Core | undefined];
}

function rotatePoint(
{ x, y }: { x: number; y: number },
degreesRotated: number
) {
const radiansPerDegree = Math.PI / 180;
const θ = radiansPerDegree * degreesRotated;
const cosθ = Math.cos(θ);
const sinθ = Math.sin(θ);
return {
x: x * cosθ - y * sinθ,
y: x * sinθ + y * cosθ
};
}

function getLayoutOptions(
selectedRoots: string[],
height: number,
Expand All @@ -71,10 +85,11 @@ function getLayoutOptions(
animate: true,
animationEasing: animationOptions.easing,
animationDuration: animationOptions.duration,
// Rotate nodes from top -> bottom to display left -> right
// @ts-ignore
transform: (node: any, { x, y }: cytoscape.Position) => ({ x: y, y: -x }),
// swap width/height of boundingBox to compensation for the rotation
// Rotate nodes counter-clockwise to transform layout from top→bottom to left→right.
// The extra 5° achieves the effect of separating overlapping taxi-styled edges.
transform: (node: any, pos: cytoscape.Position) => rotatePoint(pos, -95),
// swap width/height of boundingBox to compensate for the rotation
boundingBox: { x1: 0, y1: 0, w: height, h: width }
};
}
Expand Down Expand Up @@ -109,20 +124,31 @@ export function Cytoscape({
// is required and can trigger rendering when changed.
const divStyle = { ...style, height };

const dataHandler = useCallback<cytoscape.EventHandler>(
event => {
const resetConnectedEdgeStyle = useCallback(
(node?: cytoscape.NodeSingular) => {
if (cy) {
cy.edges().removeClass('highlight');

if (serviceName) {
const focusedNode = cy.getElementById(serviceName);
focusedNode.connectedEdges().addClass('highlight');
if (node) {
node.connectedEdges().addClass('highlight');
}
}
},
[cy]
);

// Add the "primary" class to the node if its id matches the serviceName.
if (cy.nodes().length > 0 && serviceName) {
cy.nodes().removeClass('primary');
cy.getElementById(serviceName).addClass('primary');
const dataHandler = useCallback<cytoscape.EventHandler>(
event => {
if (cy) {
if (serviceName) {
resetConnectedEdgeStyle(cy.getElementById(serviceName));
// Add the "primary" class to the node if its id matches the serviceName.
if (cy.nodes().length > 0) {
cy.nodes().removeClass('primary');
cy.getElementById(serviceName).addClass('primary');
}
} else {
resetConnectedEdgeStyle();
}
if (event.cy.elements().length > 0) {
const selectedRoots = selectRoots(event.cy);
Expand All @@ -141,7 +167,7 @@ export function Cytoscape({
}
}
},
[cy, serviceName, height, width]
[cy, resetConnectedEdgeStyle, serviceName, height, width]
);

// Trigger a custom "data" event when data changes
Expand All @@ -162,12 +188,20 @@ export function Cytoscape({
event.target.removeClass('hover');
event.target.connectedEdges().removeClass('nodeHover');
};
const selectHandler: cytoscape.EventHandler = event => {
resetConnectedEdgeStyle(event.target);
};
const unselectHandler: cytoscape.EventHandler = event => {
resetConnectedEdgeStyle();
};

if (cy) {
cy.on('data', dataHandler);
cy.ready(dataHandler);
cy.on('mouseover', 'edge, node', mouseoverHandler);
cy.on('mouseout', 'edge, node', mouseoutHandler);
cy.on('select', 'node', selectHandler);
cy.on('unselect', 'node', unselectHandler);
}

return () => {
Expand All @@ -181,7 +215,7 @@ export function Cytoscape({
cy.removeListener('mouseout', 'edge, node', mouseoutHandler);
}
};
}, [cy, dataHandler, serviceName]);
}, [cy, dataHandler, resetConnectedEdgeStyle, serviceName]);

return (
<CytoscapeContext.Provider value={cy}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,15 +121,18 @@ const style: cytoscape.Stylesheet[] = [
{
selector: 'edge.nodeHover',
style: {
width: 4,
width: 2,
// @ts-ignore
'z-index': zIndexEdgeHover
'z-index': zIndexEdgeHover,
'line-color': theme.euiColorDarkShade,
'source-arrow-color': theme.euiColorDarkShade,
'target-arrow-color': theme.euiColorDarkShade
}
},
{
selector: 'node.hover',
style: {
'border-width': 4
'border-width': 2
}
},
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
import theme from '@elastic/eui/dist/eui_theme_light.json';
import React from 'react';
import { isValidPlatinumLicense } from '../../../../../../../plugins/apm/common/service_map';
import { useDeepObjectIdentity } from '../../../hooks/useDeepObjectIdentity';
import { useFetcher } from '../../../hooks/useFetcher';
import { useLicense } from '../../../hooks/useLicense';
import { useUrlParams } from '../../../hooks/useUrlParams';
Expand All @@ -28,33 +27,27 @@ interface ServiceMapProps {
export function ServiceMap({ serviceName }: ServiceMapProps) {
const license = useLicense();
const { urlParams, uiFilters } = useUrlParams();
const params = useDeepObjectIdentity({
start: urlParams.start,
end: urlParams.end,
environment: urlParams.environment,
serviceName,
uiFilters: {
...uiFilters,
environment: undefined
}
});

const { data } = useFetcher(() => {
const { start, end } = params;
const { start, end, environment } = urlParams;
if (start && end) {
return callApmApi({
pathname: '/api/apm/service-map',
params: {
query: {
...params,
start,
end,
uiFilters: JSON.stringify(params.uiFilters)
environment,
serviceName,
uiFilters: JSON.stringify({
...uiFilters,
environment: undefined
})
}
}
});
}
}, [params]);
}, [serviceName, uiFilters, urlParams]);

const { ref, height, width } = useRefDimensions();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ export function KueryBar() {
const disabled = /\/service-map$/.test(location.pathname);
const disabledPlaceholder = i18n.translate(
'xpack.apm.kueryBar.disabledPlaceholder',
{ defaultMessage: 'Search is not available for service maps' }
{ defaultMessage: 'Search is not available for service map' }
);

async function onChange(inputValue: string, selectionStart: number) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,7 @@ export const importRulesRoute = (router: IRouter, config: LegacyServices['config
references,
note,
version,
lists,
anomalyThreshold,
machineLearningJobId,
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,32 @@ describe('patch_rules_bulk', () => {
]);
});

test('allows ML Params to be patched', async () => {
const request = requestMock.create({
method: 'patch',
path: `${DETECTION_ENGINE_RULES_URL}/bulk_update`,
body: [
{
rule_id: 'my-rule-id',
anomaly_threshold: 4,
machine_learning_job_id: 'some_job_id',
},
],
});
await server.inject(request, context);

expect(clients.alertsClient.update).toHaveBeenCalledWith(
expect.objectContaining({
data: expect.objectContaining({
params: expect.objectContaining({
anomalyThreshold: 4,
machineLearningJobId: 'some_job_id',
}),
}),
})
);
});

test('returns 404 if alertClient is not available on the route', async () => {
context.alerting!.getAlertsClient = jest.fn();
const response = await server.inject(getPatchBulkRequest(), context);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ export const patchRulesBulkRoute = (router: IRouter) => {
references,
note,
version,
anomaly_threshold: anomalyThreshold,
machine_learning_job_id: machineLearningJobId,
} = payloadRule;
const idOrRuleIdOrUnknown = id ?? ruleId ?? '(unknown id)';
try {
Expand Down Expand Up @@ -111,6 +113,8 @@ export const patchRulesBulkRoute = (router: IRouter) => {
references,
note,
version,
anomalyThreshold,
machineLearningJobId,
});
if (rule != null) {
const ruleStatuses = await savedObjectsClient.find<
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,30 @@ describe('patch_rules', () => {
status_code: 500,
});
});

test('allows ML Params to be patched', async () => {
const request = requestMock.create({
method: 'patch',
path: DETECTION_ENGINE_RULES_URL,
body: {
rule_id: 'my-rule-id',
anomaly_threshold: 4,
machine_learning_job_id: 'some_job_id',
},
});
await server.inject(request, context);

expect(clients.alertsClient.update).toHaveBeenCalledWith(
expect.objectContaining({
data: expect.objectContaining({
params: expect.objectContaining({
anomalyThreshold: 4,
machineLearningJobId: 'some_job_id',
}),
}),
})
);
});
});

describe('request validation', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ export const patchRulesRoute = (router: IRouter) => {
references,
note,
version,
anomaly_threshold: anomalyThreshold,
machine_learning_job_id: machineLearningJobId,
} = request.body;
const siemResponse = buildSiemResponse(response);

Expand Down Expand Up @@ -108,6 +110,8 @@ export const patchRulesRoute = (router: IRouter) => {
references,
note,
version,
anomalyThreshold,
machineLearningJobId,
});
if (rule != null) {
const ruleStatuses = await savedObjectsClient.find<
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"rule_id": "machine-learning",
"anomaly_threshold": 10
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"name": "Query with a machine learning job",
"description": "Query with a machine learning job",
"rule_id": "machine-learning",
"risk_score": 1,
"severity": "high",
"type": "machine_learning",
"machine_learning_job_id": "linux_anomalous_network_activity_ecs",
"anomaly_threshold": 50
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"name": "Query with a machine learning job",
"description": "Query with a machine learning job",
"rule_id": "machine-learning",
"risk_score": 1,
"severity": "high",
"type": "machine_learning",
"machine_learning_job_id": "linux_anomalous_network_activity_ecs",
"anomaly_threshold": 100
}
2 changes: 2 additions & 0 deletions x-pack/legacy/plugins/uptime/common/constants/ui.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ export const MONITOR_ROUTE = '/monitor/:monitorId?';

export const OVERVIEW_ROUTE = '/';

export const SETTINGS_ROUTE = '/settings';

export enum STATUS {
UP = 'up',
DOWN = 'down',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
* 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 * as t from 'io-ts';

export const DynamicSettingsType = t.type({
heartbeatIndices: t.string,
});

export const DynamicSettingsSaveType = t.intersection([
t.type({
success: t.boolean,
}),
t.partial({
error: t.string,
}),
]);

export type DynamicSettings = t.TypeOf<typeof DynamicSettingsType>;
export type DynamicSettingsSaveResponse = t.TypeOf<typeof DynamicSettingsSaveType>;

export const defaultDynamicSettings: DynamicSettings = {
heartbeatIndices: 'heartbeat-8*',
};
1 change: 1 addition & 0 deletions x-pack/legacy/plugins/uptime/common/runtime_types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ export * from './common';
export * from './monitor';
export * from './overview_filters';
export * from './snapshot';
export * from './dynamic_settings';

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 3646e9e

Please sign in to comment.