Skip to content

Commit

Permalink
Merge branch 'main' into fix-bulk-delete-tags-functional-test
Browse files Browse the repository at this point in the history
  • Loading branch information
sebelga authored Aug 21, 2023
2 parents 923b9be + c1d2834 commit b9e5035
Show file tree
Hide file tree
Showing 38 changed files with 363 additions and 568 deletions.
3 changes: 2 additions & 1 deletion .backportrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"repoName": "kibana",
"targetBranchChoices": [
"main",
"8.10",
"8.9",
"8.8",
"8.7",
Expand Down Expand Up @@ -46,7 +47,7 @@
"backport"
],
"branchLabelMapping": {
"^v8.10.0$": "main",
"^v8.11.0$": "main",
"^v(\\d+).(\\d+).\\d+$": "$1.$2"
},
"autoMerge": true,
Expand Down
2 changes: 0 additions & 2 deletions docs/CHANGELOG.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,6 @@ Review important information about the {kib} 8.x releases.
[[release-notes-8.9.1]]
== {kib} 8.9.1

coming::[8.9.1]

Review the following information about the {kib} 8.9.1 release.

[float]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2475,15 +2475,15 @@ Any modifications made to this file will be overwritten.
<div class='model-description'></div>
<div class="field-items">
<div class="param">name </div><div class="param-desc"><span class="param-type"><a href="#string">String</a></span> The display name for the connector. </div>
<div class="param">secrets </div><div class="param-desc"><span class="param-type"><a href="#">secrets_properties_slack_api</a></span> </div>
<div class="param">secrets </div><div class="param-desc"><span class="param-type"><a href="#secrets_properties_slack_api">secrets_properties_slack_api</a></span> </div>
</div> <!-- field-items -->
</div>
<div class="model">
<h3><a name="update_connector_request_slack_webhook"><code>update_connector_request_slack_webhook</code> - Update Slack connector request</a> <a class="up" href="#__Models">Up</a></h3>
<div class='model-description'></div>
<div class="field-items">
<div class="param">name </div><div class="param-desc"><span class="param-type"><a href="#string">String</a></span> The display name for the connector. </div>
<div class="param">secrets </div><div class="param-desc"><span class="param-type"><a href="#">secrets_properties_slack_webhook</a></span> </div>
<div class="param">secrets </div><div class="param-desc"><span class="param-type"><a href="#secrets_properties_slack_webhook">secrets_properties_slack_webhook</a></span> </div>
</div> <!-- field-items -->
</div>
<div class="model">
Expand Down
8 changes: 8 additions & 0 deletions docs/user/ml/index.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -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
Expand All @@ -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);
});
Expand All @@ -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('');
Expand Down
Loading

0 comments on commit b9e5035

Please sign in to comment.