Skip to content

Commit ab95222

Browse files
Merge branch 'master' into fix/index_management_tests
2 parents 0679427 + 0390251 commit ab95222

File tree

27 files changed

+402
-182
lines changed

27 files changed

+402
-182
lines changed

x-pack/legacy/plugins/apm/public/components/app/ServiceMap/Cytoscape.tsx

Lines changed: 48 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,20 @@ function useCytoscape(options: cytoscape.CytoscapeOptions) {
5757
return [ref, cy] as [React.MutableRefObject<any>, cytoscape.Core | undefined];
5858
}
5959

60+
function rotatePoint(
61+
{ x, y }: { x: number; y: number },
62+
degreesRotated: number
63+
) {
64+
const radiansPerDegree = Math.PI / 180;
65+
const θ = radiansPerDegree * degreesRotated;
66+
const cosθ = Math.cos(θ);
67+
const sinθ = Math.sin(θ);
68+
return {
69+
x: x * cosθ - y * sinθ,
70+
y: x * sinθ + y * cosθ
71+
};
72+
}
73+
6074
function getLayoutOptions(
6175
selectedRoots: string[],
6276
height: number,
@@ -71,10 +85,11 @@ function getLayoutOptions(
7185
animate: true,
7286
animationEasing: animationOptions.easing,
7387
animationDuration: animationOptions.duration,
74-
// Rotate nodes from top -> bottom to display left -> right
7588
// @ts-ignore
76-
transform: (node: any, { x, y }: cytoscape.Position) => ({ x: y, y: -x }),
77-
// swap width/height of boundingBox to compensation for the rotation
89+
// Rotate nodes counter-clockwise to transform layout from top→bottom to left→right.
90+
// The extra 5° achieves the effect of separating overlapping taxi-styled edges.
91+
transform: (node: any, pos: cytoscape.Position) => rotatePoint(pos, -95),
92+
// swap width/height of boundingBox to compensate for the rotation
7893
boundingBox: { x1: 0, y1: 0, w: height, h: width }
7994
};
8095
}
@@ -109,20 +124,31 @@ export function Cytoscape({
109124
// is required and can trigger rendering when changed.
110125
const divStyle = { ...style, height };
111126

112-
const dataHandler = useCallback<cytoscape.EventHandler>(
113-
event => {
127+
const resetConnectedEdgeStyle = useCallback(
128+
(node?: cytoscape.NodeSingular) => {
114129
if (cy) {
115130
cy.edges().removeClass('highlight');
116131

117-
if (serviceName) {
118-
const focusedNode = cy.getElementById(serviceName);
119-
focusedNode.connectedEdges().addClass('highlight');
132+
if (node) {
133+
node.connectedEdges().addClass('highlight');
120134
}
135+
}
136+
},
137+
[cy]
138+
);
121139

122-
// Add the "primary" class to the node if its id matches the serviceName.
123-
if (cy.nodes().length > 0 && serviceName) {
124-
cy.nodes().removeClass('primary');
125-
cy.getElementById(serviceName).addClass('primary');
140+
const dataHandler = useCallback<cytoscape.EventHandler>(
141+
event => {
142+
if (cy) {
143+
if (serviceName) {
144+
resetConnectedEdgeStyle(cy.getElementById(serviceName));
145+
// Add the "primary" class to the node if its id matches the serviceName.
146+
if (cy.nodes().length > 0) {
147+
cy.nodes().removeClass('primary');
148+
cy.getElementById(serviceName).addClass('primary');
149+
}
150+
} else {
151+
resetConnectedEdgeStyle();
126152
}
127153
if (event.cy.elements().length > 0) {
128154
const selectedRoots = selectRoots(event.cy);
@@ -141,7 +167,7 @@ export function Cytoscape({
141167
}
142168
}
143169
},
144-
[cy, serviceName, height, width]
170+
[cy, resetConnectedEdgeStyle, serviceName, height, width]
145171
);
146172

147173
// Trigger a custom "data" event when data changes
@@ -162,12 +188,20 @@ export function Cytoscape({
162188
event.target.removeClass('hover');
163189
event.target.connectedEdges().removeClass('nodeHover');
164190
};
191+
const selectHandler: cytoscape.EventHandler = event => {
192+
resetConnectedEdgeStyle(event.target);
193+
};
194+
const unselectHandler: cytoscape.EventHandler = event => {
195+
resetConnectedEdgeStyle();
196+
};
165197

166198
if (cy) {
167199
cy.on('data', dataHandler);
168200
cy.ready(dataHandler);
169201
cy.on('mouseover', 'edge, node', mouseoverHandler);
170202
cy.on('mouseout', 'edge, node', mouseoutHandler);
203+
cy.on('select', 'node', selectHandler);
204+
cy.on('unselect', 'node', unselectHandler);
171205
}
172206

173207
return () => {
@@ -181,7 +215,7 @@ export function Cytoscape({
181215
cy.removeListener('mouseout', 'edge, node', mouseoutHandler);
182216
}
183217
};
184-
}, [cy, dataHandler, serviceName]);
218+
}, [cy, dataHandler, resetConnectedEdgeStyle, serviceName]);
185219

186220
return (
187221
<CytoscapeContext.Provider value={cy}>

x-pack/legacy/plugins/apm/public/components/app/ServiceMap/cytoscapeOptions.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -121,15 +121,18 @@ const style: cytoscape.Stylesheet[] = [
121121
{
122122
selector: 'edge.nodeHover',
123123
style: {
124-
width: 4,
124+
width: 2,
125125
// @ts-ignore
126-
'z-index': zIndexEdgeHover
126+
'z-index': zIndexEdgeHover,
127+
'line-color': theme.euiColorDarkShade,
128+
'source-arrow-color': theme.euiColorDarkShade,
129+
'target-arrow-color': theme.euiColorDarkShade
127130
}
128131
},
129132
{
130133
selector: 'node.hover',
131134
style: {
132-
'border-width': 4
135+
'border-width': 2
133136
}
134137
},
135138
{

x-pack/legacy/plugins/apm/public/components/shared/KueryBar/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ export function KueryBar() {
7979
const disabled = /\/service-map$/.test(location.pathname);
8080
const disabledPlaceholder = i18n.translate(
8181
'xpack.apm.kueryBar.disabledPlaceholder',
82-
{ defaultMessage: 'Search is not available for service maps' }
82+
{ defaultMessage: 'Search is not available for service map' }
8383
);
8484

8585
async function onChange(inputValue: string, selectionStart: number) {

x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/import_rules_route.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,7 @@ export const importRulesRoute = (router: IRouter, config: LegacyServices['config
234234
references,
235235
note,
236236
version,
237+
lists,
237238
anomalyThreshold,
238239
machineLearningJobId,
239240
});

x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/patch_rules_bulk_route.test.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,32 @@ describe('patch_rules_bulk', () => {
5656
]);
5757
});
5858

59+
test('allows ML Params to be patched', async () => {
60+
const request = requestMock.create({
61+
method: 'patch',
62+
path: `${DETECTION_ENGINE_RULES_URL}/bulk_update`,
63+
body: [
64+
{
65+
rule_id: 'my-rule-id',
66+
anomaly_threshold: 4,
67+
machine_learning_job_id: 'some_job_id',
68+
},
69+
],
70+
});
71+
await server.inject(request, context);
72+
73+
expect(clients.alertsClient.update).toHaveBeenCalledWith(
74+
expect.objectContaining({
75+
data: expect.objectContaining({
76+
params: expect.objectContaining({
77+
anomalyThreshold: 4,
78+
machineLearningJobId: 'some_job_id',
79+
}),
80+
}),
81+
})
82+
);
83+
});
84+
5985
test('returns 404 if alertClient is not available on the route', async () => {
6086
context.alerting!.getAlertsClient = jest.fn();
6187
const response = await server.inject(getPatchBulkRequest(), context);

x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/patch_rules_bulk_route.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@ export const patchRulesBulkRoute = (router: IRouter) => {
7575
references,
7676
note,
7777
version,
78+
anomaly_threshold: anomalyThreshold,
79+
machine_learning_job_id: machineLearningJobId,
7880
} = payloadRule;
7981
const idOrRuleIdOrUnknown = id ?? ruleId ?? '(unknown id)';
8082
try {
@@ -111,6 +113,8 @@ export const patchRulesBulkRoute = (router: IRouter) => {
111113
references,
112114
note,
113115
version,
116+
anomalyThreshold,
117+
machineLearningJobId,
114118
});
115119
if (rule != null) {
116120
const ruleStatuses = await savedObjectsClient.find<

x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/patch_rules_route.test.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,30 @@ describe('patch_rules', () => {
8585
status_code: 500,
8686
});
8787
});
88+
89+
test('allows ML Params to be patched', async () => {
90+
const request = requestMock.create({
91+
method: 'patch',
92+
path: DETECTION_ENGINE_RULES_URL,
93+
body: {
94+
rule_id: 'my-rule-id',
95+
anomaly_threshold: 4,
96+
machine_learning_job_id: 'some_job_id',
97+
},
98+
});
99+
await server.inject(request, context);
100+
101+
expect(clients.alertsClient.update).toHaveBeenCalledWith(
102+
expect.objectContaining({
103+
data: expect.objectContaining({
104+
params: expect.objectContaining({
105+
anomalyThreshold: 4,
106+
machineLearningJobId: 'some_job_id',
107+
}),
108+
}),
109+
})
110+
);
111+
});
88112
});
89113

90114
describe('request validation', () => {

x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/patch_rules_route.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ export const patchRulesRoute = (router: IRouter) => {
5959
references,
6060
note,
6161
version,
62+
anomaly_threshold: anomalyThreshold,
63+
machine_learning_job_id: machineLearningJobId,
6264
} = request.body;
6365
const siemResponse = buildSiemResponse(response);
6466

@@ -108,6 +110,8 @@ export const patchRulesRoute = (router: IRouter) => {
108110
references,
109111
note,
110112
version,
113+
anomalyThreshold,
114+
machineLearningJobId,
111115
});
112116
if (rule != null) {
113117
const ruleStatuses = await savedObjectsClient.find<
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"rule_id": "machine-learning",
3+
"anomaly_threshold": 10
4+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"name": "Query with a machine learning job",
3+
"description": "Query with a machine learning job",
4+
"rule_id": "machine-learning",
5+
"risk_score": 1,
6+
"severity": "high",
7+
"type": "machine_learning",
8+
"machine_learning_job_id": "linux_anomalous_network_activity_ecs",
9+
"anomaly_threshold": 50
10+
}

0 commit comments

Comments
 (0)