Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'main' into siem-explore-163462
Browse files Browse the repository at this point in the history
machadoum authored Aug 21, 2023

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
2 parents 9f4728e + 5f310f7 commit 2277737
Showing 26 changed files with 283 additions and 502 deletions.
3 changes: 2 additions & 1 deletion .backportrc.json
Original file line number Diff line number Diff line change
@@ -3,6 +3,7 @@
"repoName": "kibana",
"targetBranchChoices": [
"main",
"8.10",
"8.9",
"8.8",
"8.7",
@@ -46,7 +47,7 @@
"backport"
],
"branchLabelMapping": {
"^v8.10.0$": "main",
"^v8.11.0$": "main",
"^v(\\d+).(\\d+).\\d+$": "$1.$2"
},
"autoMerge": true,
8 changes: 8 additions & 0 deletions docs/user/ml/index.asciidoc
Original file line number Diff line number Diff line change
@@ -223,3 +223,11 @@ point type selector to filter the results by specific types of change points.

[role="screenshot"]
image::user/ml/images/ml-change-point-detection-selected.png[Selected change points]


You can attach change point charts to a dashboard or a case by using the context
menu. If the split field is selected, you can either select specific charts
(partitions) or set the maximum number of top change points to plot. It's
possible to preserve the applied time range or use the time bound from the page
date picker. You can also add or edit change point charts directly from the
**Dashboard** app.
Original file line number Diff line number Diff line change
@@ -33,7 +33,11 @@ export type TrustedAppConditionEntryField =
| 'process.hash.*'
| 'process.executable.caseless'
| 'process.Ext.code_signature';
export type BlocklistConditionEntryField = 'file.hash.*' | 'file.path' | 'file.Ext.code_signature';
export type BlocklistConditionEntryField =
| 'file.hash.*'
| 'file.path'
| 'file.Ext.code_signature'
| 'file.path.caseless';
export type AllConditionEntryFields =
| TrustedAppConditionEntryField
| BlocklistConditionEntryField
Original file line number Diff line number Diff line change
@@ -16,17 +16,21 @@ import {
import { CoreStart } from '@kbn/core/public';
import { coreMock } from '@kbn/core/public/mocks';
import { embeddablePluginMock } from '@kbn/embeddable-plugin/public/mocks';
import { ErrorEmbeddable, IContainer, isErrorEmbeddable } from '@kbn/embeddable-plugin/public';
import {
ErrorEmbeddable,
IContainer,
isErrorEmbeddable,
ReferenceOrValueEmbeddable,
} from '@kbn/embeddable-plugin/public';

import { DashboardPanelState } from '../../common';
import { ClonePanelAction } from './clone_panel_action';
import { pluginServices } from '../services/plugin_services';
import { buildMockDashboard, getSampleDashboardPanel } from '../mocks';
import { DashboardContainer } from '../dashboard_container/embeddable/dashboard_container';

let container: DashboardContainer;
let byRefOrValEmbeddable: ContactCardEmbeddable;
let genericEmbeddable: ContactCardEmbeddable;
let byRefOrValEmbeddable: ContactCardEmbeddable & ReferenceOrValueEmbeddable;
let coreStart: CoreStart;
beforeEach(async () => {
coreStart = coreMock.createStart();
@@ -58,20 +62,22 @@ beforeEach(async () => {
>(CONTACT_CARD_EMBEDDABLE, {
firstName: 'RefOrValEmbeddable',
});
const genericContactCardEmbeddable = await container.addNewEmbeddable<

const nonRefOrValueContactCard = await container.addNewEmbeddable<
ContactCardEmbeddableInput,
ContactCardEmbeddableOutput,
ContactCardEmbeddable
>(CONTACT_CARD_EMBEDDABLE, {
firstName: 'NotRefOrValEmbeddable',
firstName: 'Not a refOrValEmbeddable',
});

if (
isErrorEmbeddable(refOrValContactCardEmbeddable) ||
isErrorEmbeddable(genericContactCardEmbeddable)
isErrorEmbeddable(nonRefOrValueContactCard)
) {
throw new Error('Failed to create embeddables');
} else {
genericEmbeddable = nonRefOrValueContactCard;
byRefOrValEmbeddable = embeddablePluginMock.mockRefOrValEmbeddable<
ContactCardEmbeddable,
ContactCardEmbeddableInput
@@ -80,14 +86,14 @@ beforeEach(async () => {
savedObjectId: 'testSavedObjectId',
id: refOrValContactCardEmbeddable.id,
},
mockedByValueInput: { firstName: 'Kibanana', id: refOrValContactCardEmbeddable.id },
mockedByValueInput: { firstName: 'RefOrValEmbeddable', id: refOrValContactCardEmbeddable.id },
});
genericEmbeddable = genericContactCardEmbeddable;
jest.spyOn(byRefOrValEmbeddable, 'getInputAsValueType');
}
});

test('Clone is incompatible with Error Embeddables', async () => {
const action = new ClonePanelAction(coreStart.savedObjects);
const action = new ClonePanelAction();
const errorEmbeddable = new ErrorEmbeddable('Wow what an awful error', { id: ' 404' }, container);
expect(await action.isCompatible({ embeddable: errorEmbeddable })).toBe(false);
});
@@ -96,134 +102,65 @@ test('Clone adds a new embeddable', async () => {
const dashboard = byRefOrValEmbeddable.getRoot() as IContainer;
const originalPanelCount = Object.keys(dashboard.getInput().panels).length;
const originalPanelKeySet = new Set(Object.keys(dashboard.getInput().panels));
const action = new ClonePanelAction(coreStart.savedObjects);
const action = new ClonePanelAction();
await action.execute({ embeddable: byRefOrValEmbeddable });

expect(Object.keys(container.getInput().panels).length).toEqual(originalPanelCount + 1);
const newPanelId = Object.keys(container.getInput().panels).find(
(key) => !originalPanelKeySet.has(key)
);
expect(newPanelId).toBeDefined();
const newPanel = container.getInput().panels[newPanelId!];
expect(newPanel.type).toEqual('placeholder');
// let the placeholder load
await dashboard.untilEmbeddableLoaded(newPanelId!);
await new Promise((r) => process.nextTick(r)); // Allow the current loop of the event loop to run to completion
// now wait for the full embeddable to replace it
const loadedPanel = await dashboard.untilEmbeddableLoaded(newPanelId!);
expect(loadedPanel.type).toEqual(byRefOrValEmbeddable.type);
expect(newPanel.type).toEqual(byRefOrValEmbeddable.type);
});

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

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

test('Clones a non-RefOrVal embeddable by reference if the panel has a savedObjectId', async () => {
const dashboard = genericEmbeddable.getRoot() as IContainer;
const panel = dashboard.getInput().panels[genericEmbeddable.id] as DashboardPanelState;
panel.explicitInput.savedObjectId = 'holySavedObjectBatman';
const action = new ClonePanelAction(coreStart.savedObjects);
// @ts-ignore
const newPanel = await action.cloneEmbeddable(panel, genericEmbeddable);
expect(coreStart.savedObjects.client.get).toHaveBeenCalledTimes(1);
expect(coreStart.savedObjects.client.find).toHaveBeenCalledTimes(1);
expect(coreStart.savedObjects.client.create).toHaveBeenCalledTimes(1);
expect(newPanel.type).toEqual(genericEmbeddable.type);
const newFirstName = (
container.getInput().panels[newPanelId!].explicitInput as ContactCardEmbeddableInput
).firstName;

expect(byRefOrValEmbeddable.getInputAsValueType).toHaveBeenCalled();

expect(originalFirstName).toEqual(newFirstName);
expect(container.getInput().panels[newPanelId!].type).toEqual(byRefOrValEmbeddable.type);
});

test('Gets a unique title from the saved objects library', async () => {
test('Clones a non RefOrVal embeddable by value', async () => {
const dashboard = genericEmbeddable.getRoot() as IContainer;
const panel = dashboard.getInput().panels[genericEmbeddable.id] as DashboardPanelState;
panel.explicitInput.savedObjectId = 'holySavedObjectBatman';
coreStart.savedObjects.client.find = jest.fn().mockImplementation(({ search }) => {
if (search === '"testFirstClone"') {
return {
savedObjects: [
{
attributes: { title: 'testFirstClone' },
get: jest.fn().mockReturnValue('testFirstClone'),
},
],
total: 1,
};
} else if (search === '"testBeforePageLimit"') {
return {
savedObjects: [
{
attributes: { title: 'testBeforePageLimit (copy 9)' },
get: jest.fn().mockReturnValue('testBeforePageLimit (copy 9)'),
},
],
total: 10,
};
} else if (search === '"testMaxLogic"') {
return {
savedObjects: [
{
attributes: { title: 'testMaxLogic (copy 10000)' },
get: jest.fn().mockReturnValue('testMaxLogic (copy 10000)'),
},
],
total: 2,
};
} else if (search === '"testAfterPageLimit"') {
return { total: 11 };
}
});

const action = new ClonePanelAction(coreStart.savedObjects);
// @ts-ignore
expect(await action.getCloneTitle(genericEmbeddable, 'testFirstClone')).toEqual(
'testFirstClone (copy)'
);
// @ts-ignore
expect(await action.getCloneTitle(genericEmbeddable, 'testBeforePageLimit')).toEqual(
'testBeforePageLimit (copy 10)'
);
// @ts-ignore
expect(await action.getCloneTitle(genericEmbeddable, 'testBeforePageLimit (copy 9)')).toEqual(
'testBeforePageLimit (copy 10)'
);
// @ts-ignore
expect(await action.getCloneTitle(genericEmbeddable, 'testMaxLogic')).toEqual(
'testMaxLogic (copy 10001)'
);
// @ts-ignore
expect(await action.getCloneTitle(genericEmbeddable, 'testAfterPageLimit')).toEqual(
'testAfterPageLimit (copy 11)'
);
// @ts-ignore
expect(await action.getCloneTitle(genericEmbeddable, 'testAfterPageLimit (copy 10)')).toEqual(
'testAfterPageLimit (copy 11)'
);
// @ts-ignore
expect(await action.getCloneTitle(genericEmbeddable, 'testAfterPageLimit (copy 10000)')).toEqual(
'testAfterPageLimit (copy 11)'
const originalPanelKeySet = new Set(Object.keys(dashboard.getInput().panels));
const action = new ClonePanelAction();
await action.execute({ embeddable: genericEmbeddable });
const newPanelId = Object.keys(container.getInput().panels).find(
(key) => !originalPanelKeySet.has(key)
);

const originalFirstName = (
container.getInput().panels[genericEmbeddable.id].explicitInput as ContactCardEmbeddableInput
).firstName;

const newFirstName = (
container.getInput().panels[newPanelId!].explicitInput as ContactCardEmbeddableInput
).firstName;

expect(originalFirstName).toEqual(newFirstName);
expect(container.getInput().panels[newPanelId!].type).toEqual(genericEmbeddable.type);
});

test('Gets a unique title from the dashboard', async () => {
const dashboard = genericEmbeddable.getRoot() as DashboardContainer;
const action = new ClonePanelAction(coreStart.savedObjects);
const dashboard = byRefOrValEmbeddable.getRoot() as DashboardContainer;
const action = new ClonePanelAction();

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

0 comments on commit 2277737

Please sign in to comment.