Skip to content

Commit 2277737

Browse files
authored
Merge branch 'main' into siem-explore-163462
2 parents 9f4728e + 5f310f7 commit 2277737

26 files changed

Lines changed: 283 additions & 502 deletions

File tree

.backportrc.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
"repoName": "kibana",
44
"targetBranchChoices": [
55
"main",
6+
"8.10",
67
"8.9",
78
"8.8",
89
"8.7",
@@ -46,7 +47,7 @@
4647
"backport"
4748
],
4849
"branchLabelMapping": {
49-
"^v8.10.0$": "main",
50+
"^v8.11.0$": "main",
5051
"^v(\\d+).(\\d+).\\d+$": "$1.$2"
5152
},
5253
"autoMerge": true,

docs/user/ml/index.asciidoc

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,3 +223,11 @@ point type selector to filter the results by specific types of change points.
223223

224224
[role="screenshot"]
225225
image::user/ml/images/ml-change-point-detection-selected.png[Selected change points]
226+
227+
228+
You can attach change point charts to a dashboard or a case by using the context
229+
menu. If the split field is selected, you can either select specific charts
230+
(partitions) or set the maximum number of top change points to plot. It's
231+
possible to preserve the applied time range or use the time bound from the page
232+
date picker. You can also add or edit change point charts directly from the
233+
**Dashboard** app.

packages/kbn-securitysolution-utils/src/path_validations/index.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,11 @@ export type TrustedAppConditionEntryField =
3333
| 'process.hash.*'
3434
| 'process.executable.caseless'
3535
| 'process.Ext.code_signature';
36-
export type BlocklistConditionEntryField = 'file.hash.*' | 'file.path' | 'file.Ext.code_signature';
36+
export type BlocklistConditionEntryField =
37+
| 'file.hash.*'
38+
| 'file.path'
39+
| 'file.Ext.code_signature'
40+
| 'file.path.caseless';
3741
export type AllConditionEntryFields =
3842
| TrustedAppConditionEntryField
3943
| BlocklistConditionEntryField

src/plugins/dashboard/public/dashboard_actions/clone_panel_action.test.tsx

Lines changed: 54 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,21 @@ import {
1616
import { CoreStart } from '@kbn/core/public';
1717
import { coreMock } from '@kbn/core/public/mocks';
1818
import { embeddablePluginMock } from '@kbn/embeddable-plugin/public/mocks';
19-
import { ErrorEmbeddable, IContainer, isErrorEmbeddable } from '@kbn/embeddable-plugin/public';
19+
import {
20+
ErrorEmbeddable,
21+
IContainer,
22+
isErrorEmbeddable,
23+
ReferenceOrValueEmbeddable,
24+
} from '@kbn/embeddable-plugin/public';
2025

21-
import { DashboardPanelState } from '../../common';
2226
import { ClonePanelAction } from './clone_panel_action';
2327
import { pluginServices } from '../services/plugin_services';
2428
import { buildMockDashboard, getSampleDashboardPanel } from '../mocks';
2529
import { DashboardContainer } from '../dashboard_container/embeddable/dashboard_container';
2630

2731
let container: DashboardContainer;
28-
let byRefOrValEmbeddable: ContactCardEmbeddable;
2932
let genericEmbeddable: ContactCardEmbeddable;
33+
let byRefOrValEmbeddable: ContactCardEmbeddable & ReferenceOrValueEmbeddable;
3034
let coreStart: CoreStart;
3135
beforeEach(async () => {
3236
coreStart = coreMock.createStart();
@@ -58,20 +62,22 @@ beforeEach(async () => {
5862
>(CONTACT_CARD_EMBEDDABLE, {
5963
firstName: 'RefOrValEmbeddable',
6064
});
61-
const genericContactCardEmbeddable = await container.addNewEmbeddable<
65+
66+
const nonRefOrValueContactCard = await container.addNewEmbeddable<
6267
ContactCardEmbeddableInput,
6368
ContactCardEmbeddableOutput,
6469
ContactCardEmbeddable
6570
>(CONTACT_CARD_EMBEDDABLE, {
66-
firstName: 'NotRefOrValEmbeddable',
71+
firstName: 'Not a refOrValEmbeddable',
6772
});
6873

6974
if (
7075
isErrorEmbeddable(refOrValContactCardEmbeddable) ||
71-
isErrorEmbeddable(genericContactCardEmbeddable)
76+
isErrorEmbeddable(nonRefOrValueContactCard)
7277
) {
7378
throw new Error('Failed to create embeddables');
7479
} else {
80+
genericEmbeddable = nonRefOrValueContactCard;
7581
byRefOrValEmbeddable = embeddablePluginMock.mockRefOrValEmbeddable<
7682
ContactCardEmbeddable,
7783
ContactCardEmbeddableInput
@@ -80,14 +86,14 @@ beforeEach(async () => {
8086
savedObjectId: 'testSavedObjectId',
8187
id: refOrValContactCardEmbeddable.id,
8288
},
83-
mockedByValueInput: { firstName: 'Kibanana', id: refOrValContactCardEmbeddable.id },
89+
mockedByValueInput: { firstName: 'RefOrValEmbeddable', id: refOrValContactCardEmbeddable.id },
8490
});
85-
genericEmbeddable = genericContactCardEmbeddable;
91+
jest.spyOn(byRefOrValEmbeddable, 'getInputAsValueType');
8692
}
8793
});
8894

8995
test('Clone is incompatible with Error Embeddables', async () => {
90-
const action = new ClonePanelAction(coreStart.savedObjects);
96+
const action = new ClonePanelAction();
9197
const errorEmbeddable = new ErrorEmbeddable('Wow what an awful error', { id: ' 404' }, container);
9298
expect(await action.isCompatible({ embeddable: errorEmbeddable })).toBe(false);
9399
});
@@ -96,134 +102,65 @@ test('Clone adds a new embeddable', async () => {
96102
const dashboard = byRefOrValEmbeddable.getRoot() as IContainer;
97103
const originalPanelCount = Object.keys(dashboard.getInput().panels).length;
98104
const originalPanelKeySet = new Set(Object.keys(dashboard.getInput().panels));
99-
const action = new ClonePanelAction(coreStart.savedObjects);
105+
const action = new ClonePanelAction();
100106
await action.execute({ embeddable: byRefOrValEmbeddable });
107+
101108
expect(Object.keys(container.getInput().panels).length).toEqual(originalPanelCount + 1);
102109
const newPanelId = Object.keys(container.getInput().panels).find(
103110
(key) => !originalPanelKeySet.has(key)
104111
);
105112
expect(newPanelId).toBeDefined();
106113
const newPanel = container.getInput().panels[newPanelId!];
107-
expect(newPanel.type).toEqual('placeholder');
108-
// let the placeholder load
109-
await dashboard.untilEmbeddableLoaded(newPanelId!);
110-
await new Promise((r) => process.nextTick(r)); // Allow the current loop of the event loop to run to completion
111-
// now wait for the full embeddable to replace it
112-
const loadedPanel = await dashboard.untilEmbeddableLoaded(newPanelId!);
113-
expect(loadedPanel.type).toEqual(byRefOrValEmbeddable.type);
114+
expect(newPanel.type).toEqual(byRefOrValEmbeddable.type);
114115
});
115116

116117
test('Clones a RefOrVal embeddable by value', async () => {
117118
const dashboard = byRefOrValEmbeddable.getRoot() as IContainer;
118-
const panel = dashboard.getInput().panels[byRefOrValEmbeddable.id] as DashboardPanelState;
119-
const action = new ClonePanelAction(coreStart.savedObjects);
120-
// @ts-ignore
121-
const newPanel = await action.cloneEmbeddable(panel, byRefOrValEmbeddable);
122-
expect(coreStart.savedObjects.client.get).toHaveBeenCalledTimes(0);
123-
expect(coreStart.savedObjects.client.find).toHaveBeenCalledTimes(0);
124-
expect(coreStart.savedObjects.client.create).toHaveBeenCalledTimes(0);
125-
expect(newPanel.type).toEqual(byRefOrValEmbeddable.type);
126-
});
119+
const originalPanelKeySet = new Set(Object.keys(dashboard.getInput().panels));
120+
const action = new ClonePanelAction();
121+
await action.execute({ embeddable: byRefOrValEmbeddable });
122+
const newPanelId = Object.keys(container.getInput().panels).find(
123+
(key) => !originalPanelKeySet.has(key)
124+
);
127125

128-
test('Clones a non-RefOrVal embeddable by value if the panel does not have a savedObjectId', async () => {
129-
const dashboard = genericEmbeddable.getRoot() as IContainer;
130-
const panel = dashboard.getInput().panels[genericEmbeddable.id] as DashboardPanelState;
131-
const action = new ClonePanelAction(coreStart.savedObjects);
132-
// @ts-ignore
133-
const newPanelWithoutId = await action.cloneEmbeddable(panel, genericEmbeddable);
134-
expect(coreStart.savedObjects.client.get).toHaveBeenCalledTimes(0);
135-
expect(coreStart.savedObjects.client.find).toHaveBeenCalledTimes(0);
136-
expect(coreStart.savedObjects.client.create).toHaveBeenCalledTimes(0);
137-
expect(newPanelWithoutId.type).toEqual(genericEmbeddable.type);
138-
});
126+
const originalFirstName = (
127+
container.getInput().panels[byRefOrValEmbeddable.id].explicitInput as ContactCardEmbeddableInput
128+
).firstName;
139129

140-
test('Clones a non-RefOrVal embeddable by reference if the panel has a savedObjectId', async () => {
141-
const dashboard = genericEmbeddable.getRoot() as IContainer;
142-
const panel = dashboard.getInput().panels[genericEmbeddable.id] as DashboardPanelState;
143-
panel.explicitInput.savedObjectId = 'holySavedObjectBatman';
144-
const action = new ClonePanelAction(coreStart.savedObjects);
145-
// @ts-ignore
146-
const newPanel = await action.cloneEmbeddable(panel, genericEmbeddable);
147-
expect(coreStart.savedObjects.client.get).toHaveBeenCalledTimes(1);
148-
expect(coreStart.savedObjects.client.find).toHaveBeenCalledTimes(1);
149-
expect(coreStart.savedObjects.client.create).toHaveBeenCalledTimes(1);
150-
expect(newPanel.type).toEqual(genericEmbeddable.type);
130+
const newFirstName = (
131+
container.getInput().panels[newPanelId!].explicitInput as ContactCardEmbeddableInput
132+
).firstName;
133+
134+
expect(byRefOrValEmbeddable.getInputAsValueType).toHaveBeenCalled();
135+
136+
expect(originalFirstName).toEqual(newFirstName);
137+
expect(container.getInput().panels[newPanelId!].type).toEqual(byRefOrValEmbeddable.type);
151138
});
152139

153-
test('Gets a unique title from the saved objects library', async () => {
140+
test('Clones a non RefOrVal embeddable by value', async () => {
154141
const dashboard = genericEmbeddable.getRoot() as IContainer;
155-
const panel = dashboard.getInput().panels[genericEmbeddable.id] as DashboardPanelState;
156-
panel.explicitInput.savedObjectId = 'holySavedObjectBatman';
157-
coreStart.savedObjects.client.find = jest.fn().mockImplementation(({ search }) => {
158-
if (search === '"testFirstClone"') {
159-
return {
160-
savedObjects: [
161-
{
162-
attributes: { title: 'testFirstClone' },
163-
get: jest.fn().mockReturnValue('testFirstClone'),
164-
},
165-
],
166-
total: 1,
167-
};
168-
} else if (search === '"testBeforePageLimit"') {
169-
return {
170-
savedObjects: [
171-
{
172-
attributes: { title: 'testBeforePageLimit (copy 9)' },
173-
get: jest.fn().mockReturnValue('testBeforePageLimit (copy 9)'),
174-
},
175-
],
176-
total: 10,
177-
};
178-
} else if (search === '"testMaxLogic"') {
179-
return {
180-
savedObjects: [
181-
{
182-
attributes: { title: 'testMaxLogic (copy 10000)' },
183-
get: jest.fn().mockReturnValue('testMaxLogic (copy 10000)'),
184-
},
185-
],
186-
total: 2,
187-
};
188-
} else if (search === '"testAfterPageLimit"') {
189-
return { total: 11 };
190-
}
191-
});
192-
193-
const action = new ClonePanelAction(coreStart.savedObjects);
194-
// @ts-ignore
195-
expect(await action.getCloneTitle(genericEmbeddable, 'testFirstClone')).toEqual(
196-
'testFirstClone (copy)'
197-
);
198-
// @ts-ignore
199-
expect(await action.getCloneTitle(genericEmbeddable, 'testBeforePageLimit')).toEqual(
200-
'testBeforePageLimit (copy 10)'
201-
);
202-
// @ts-ignore
203-
expect(await action.getCloneTitle(genericEmbeddable, 'testBeforePageLimit (copy 9)')).toEqual(
204-
'testBeforePageLimit (copy 10)'
205-
);
206-
// @ts-ignore
207-
expect(await action.getCloneTitle(genericEmbeddable, 'testMaxLogic')).toEqual(
208-
'testMaxLogic (copy 10001)'
209-
);
210-
// @ts-ignore
211-
expect(await action.getCloneTitle(genericEmbeddable, 'testAfterPageLimit')).toEqual(
212-
'testAfterPageLimit (copy 11)'
213-
);
214-
// @ts-ignore
215-
expect(await action.getCloneTitle(genericEmbeddable, 'testAfterPageLimit (copy 10)')).toEqual(
216-
'testAfterPageLimit (copy 11)'
217-
);
218-
// @ts-ignore
219-
expect(await action.getCloneTitle(genericEmbeddable, 'testAfterPageLimit (copy 10000)')).toEqual(
220-
'testAfterPageLimit (copy 11)'
142+
const originalPanelKeySet = new Set(Object.keys(dashboard.getInput().panels));
143+
const action = new ClonePanelAction();
144+
await action.execute({ embeddable: genericEmbeddable });
145+
const newPanelId = Object.keys(container.getInput().panels).find(
146+
(key) => !originalPanelKeySet.has(key)
221147
);
148+
149+
const originalFirstName = (
150+
container.getInput().panels[genericEmbeddable.id].explicitInput as ContactCardEmbeddableInput
151+
).firstName;
152+
153+
const newFirstName = (
154+
container.getInput().panels[newPanelId!].explicitInput as ContactCardEmbeddableInput
155+
).firstName;
156+
157+
expect(originalFirstName).toEqual(newFirstName);
158+
expect(container.getInput().panels[newPanelId!].type).toEqual(genericEmbeddable.type);
222159
});
223160

224161
test('Gets a unique title from the dashboard', async () => {
225-
const dashboard = genericEmbeddable.getRoot() as DashboardContainer;
226-
const action = new ClonePanelAction(coreStart.savedObjects);
162+
const dashboard = byRefOrValEmbeddable.getRoot() as DashboardContainer;
163+
const action = new ClonePanelAction();
227164

228165
// @ts-ignore
229166
expect(await action.getCloneTitle(byRefOrValEmbeddable, '')).toEqual('');

0 commit comments

Comments
 (0)