Skip to content

Commit

Permalink
Merge branch 'main' into test/page_template
Browse files Browse the repository at this point in the history
  • Loading branch information
kibanamachine authored Sep 7, 2022
2 parents 62d884d + 0e9845f commit ce90eec
Show file tree
Hide file tree
Showing 77 changed files with 3,039 additions and 931 deletions.
20 changes: 20 additions & 0 deletions docs/user/alerting/troubleshooting/alerting-common-issues.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -266,3 +266,23 @@ This error happens when the `xpack.encryptedSavedObjects.encryptionKey` value us
| Generate a new API key for the rule by disabling then enabling the rule.

|===

[float]
[[known-issue-upgrade-rule]]
==== Rules stop running after upgrade

*Problem*:

Alerting rules that were created or edited in 8.2 stop running after you upgrade
to later releases. The following error occurs:

[source,text]
----
<rule-type>:<UUID>: execution failed - security_exception: [security_exception] Reason: missing authentication credentials for REST request [/_security/user/_has_privileges], caused by: ""
----

*Solution*:

Upgrade to 8.3.2 or later releases, then go to *{stack-manage-app} > {rules-ui}* and multi-select the failed rules. Choose
**Manage rules > Update API Keys** to generate new API keys. For more details
about API key authorization, refer to <<alerting-authorization>>.
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ const dockerServerSchema = () =>
port: requiredWhenEnabled(Joi.number()),
portInContainer: requiredWhenEnabled(Joi.number()),
waitForLogLine: Joi.alternatives(Joi.object().instance(RegExp), Joi.string()).optional(),
waitForLogLineTimeoutMs: Joi.number().integer().optional(),
waitFor: Joi.func().optional(),
args: Joi.array().items(Joi.string()).optional(),
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export interface DockerServerSpec {
port: number;
image: string;
waitForLogLine?: RegExp | string;
waitForLogLineTimeoutMs?: number;
/** a function that should return an observable that will allow the tests to execute as soon as it emits anything */
waitFor?: (server: DockerServer, logLine$: Rx.Observable<string>) => Rx.Observable<unknown>;
/* additional command line arguments passed to docker run */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ export class DockerServersService {

private async startServer(server: DockerServer) {
const { log, lifecycle } = this;
const { image, name, waitFor, waitForLogLine } = server;
const { image, name, waitFor, waitForLogLine, waitForLogLineTimeoutMs } = server;

// pull image from registry
log.info(`[docker:${name}] pulling docker image "${image}"`);
Expand Down Expand Up @@ -200,7 +200,8 @@ export class DockerServersService {
: line.includes(waitForLogLine)
)
),
`waitForLogLine didn't emit anything`
`waitForLogLine didn't emit anything`,
waitForLogLineTimeoutMs
)
).toPromise();
}
Expand Down
1 change: 1 addition & 0 deletions src/plugins/controls/common/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,4 @@ export {
// Control Type exports
export { OPTIONS_LIST_CONTROL, type OptionsListEmbeddableInput } from './options_list/types';
export { type RangeSliderEmbeddableInput, RANGE_SLIDER_CONTROL } from './range_slider/types';
export { TIME_SLIDER_CONTROL } from './time_slider/types';
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

import {
EmbeddableStateWithType,
EmbeddablePersistableStateService,
} from '@kbn/embeddable-plugin/common';
import { SavedObjectReference } from '@kbn/core/types';
import { TimeSliderControlEmbeddableInput } from './types';

type TimeSliderInputWithType = Partial<TimeSliderControlEmbeddableInput> & { type: string };

export const createTimeSliderInject = (): EmbeddablePersistableStateService['inject'] => {
return (state: EmbeddableStateWithType, references: SavedObjectReference[]) => {
const workingState = { ...state } as EmbeddableStateWithType | TimeSliderInputWithType;
return workingState as EmbeddableStateWithType;
};
};

export const createTimeSliderExtract = (): EmbeddablePersistableStateService['extract'] => {
return (state: EmbeddableStateWithType) => {
const workingState = { ...state } as EmbeddableStateWithType | TimeSliderInputWithType;
const references: SavedObjectReference[] = [];

return { state: workingState as EmbeddableStateWithType, references };
};
};
17 changes: 17 additions & 0 deletions src/plugins/controls/common/time_slider/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

import type { ControlInput } from '../types';

export const TIME_SLIDER_CONTROL = 'timeSlider';

export interface TimeSliderControlEmbeddableInput extends ControlInput {
// Encode value as percentage of time range to support relative time ranges.
timesliceStartAsPercentageOfTimeRange?: number;
timesliceEndAsPercentageOfTimeRange?: number;
}
1 change: 1 addition & 0 deletions src/plugins/controls/common/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export type ControlInput = EmbeddableInput & {
query?: Query;
filters?: Filter[];
timeRange?: TimeRange;
timeslice?: [number, number];
controlStyle?: ControlStyle;
ignoreParentSettings?: ParentIgnoreSettings;
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

import { OptionsListEmbeddableFactory } from '../options_list';
import { RangeSliderEmbeddableFactory } from '../range_slider';
import { TimeSliderEmbeddableFactory } from '../time_slider';
import { ControlsServiceType } from '../services/controls/types';
import { ControlFactory } from '..';

Expand All @@ -25,4 +26,9 @@ export const populateStorybookControlFactories = (controlsServiceStub: ControlsS
const rangeSliderControlFactory = rangeSliderFactoryStub as unknown as ControlFactory;
rangeSliderControlFactory.getDefaultInput = () => ({});
controlsServiceStub.registerControlType(rangeSliderControlFactory);

const timesliderFactoryStub = new TimeSliderEmbeddableFactory();
const timeSliderControlFactory = timesliderFactoryStub as unknown as ControlFactory;
timeSliderControlFactory.getDefaultInput = () => ({});
controlsServiceStub.registerControlType(timeSliderControlFactory);
};
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { pluginServices } from '../../services';
import { EditControlButton } from '../editor/edit_control';
import { ControlGroupStrings } from '../control_group_strings';
import { useChildEmbeddable } from '../../hooks/use_child_embeddable';
import { TIME_SLIDER_CONTROL } from '../../../common';

export interface ControlFrameProps {
customPrepend?: JSX.Element;
Expand Down Expand Up @@ -87,7 +88,7 @@ export const ControlFrame = ({
'controlFrameFloatingActions--oneLine': !usingTwoLineLayout,
})}
>
{!hasFatalError && (
{!hasFatalError && embeddableType !== TIME_SLIDER_CONTROL && (
<EuiToolTip content={ControlGroupStrings.floatingActions.getEditButtonTitle()}>
<EditControlButton embeddableId={embeddableId} />
</EuiToolTip>
Expand Down Expand Up @@ -121,6 +122,20 @@ export const ControlFrame = ({
'controlFrame--fatalError': hasFatalError,
});

function renderEmbeddablePrepend() {
if (typeof embeddable?.renderPrepend === 'function') {
return embeddable.renderPrepend();
}

return usingTwoLineLayout ? undefined : (
<EuiToolTip anchorClassName="controlFrame__labelToolTip" content={title}>
<EuiFormLabel className="controlFrame__formControlLayoutLabel" htmlFor={embeddableId}>
{title}
</EuiFormLabel>
</EuiToolTip>
);
}

const form = (
<EuiFormControlLayout
className={classNames('controlFrame__formControlLayout', {
Expand All @@ -130,13 +145,7 @@ export const ControlFrame = ({
prepend={
<>
{(embeddable && customPrepend) ?? null}
{usingTwoLineLayout ? undefined : (
<EuiToolTip anchorClassName="controlFrame__labelToolTip" content={title}>
<EuiFormLabel className="controlFrame__formControlLayoutLabel" htmlFor={embeddableId}>
{title}
</EuiFormLabel>
</EuiToolTip>
)}
{renderEmbeddablePrepend()}
</>
}
>
Expand Down
12 changes: 1 addition & 11 deletions src/plugins/controls/public/control_group/control_group.scss
Original file line number Diff line number Diff line change
Expand Up @@ -228,17 +228,7 @@ $controlMinWidth: $euiSize * 14;
opacity: 0;
}
.controlFrame__formControlLayout {
background-color: tintOrShade($euiColorSuccess, 90%, 70%);
color: transparent !important;
box-shadow: none;

.euiFormLabel {
opacity: 0;
}

.controlFrame__control {
opacity: 0;
}
opacity: 0; // hide dragged control, while control is dragged its replaced with ControlClone component
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

import { i18n } from '@kbn/i18n';
import React from 'react';
import { EuiContextMenuItem } from '@elastic/eui';
import type { ControlInput } from '../../types';
import { TIME_SLIDER_CONTROL } from '../../time_slider/types';

interface Props {
addNewEmbeddable: (type: string, input: Omit<ControlInput, 'id'>) => void;
closePopover?: () => void;
hasTimeSliderControl: boolean;
}

export const CreateTimeSliderControlButton = ({
addNewEmbeddable,
closePopover,
hasTimeSliderControl,
}: Props) => {
return (
<EuiContextMenuItem
icon="plusInCircle"
onClick={() => {
addNewEmbeddable(TIME_SLIDER_CONTROL, {
title: i18n.translate('controls.controlGroup.timeSlider.title', {
defaultMessage: 'Time slider',
}),
});
if (closePopover) {
closePopover();
}
}}
data-test-subj="controls-create-timeslider-button"
disabled={hasTimeSliderControl}
toolTipContent={
hasTimeSliderControl
? i18n.translate('controls.controlGroup.onlyOneTimeSliderControlMsg', {
defaultMessage: 'Control group already contains time slider control.',
})
: null
}
>
{i18n.translate('controls.controlGroup.addTimeSliderControlButtonTitle', {
defaultMessage: 'Add time slider control',
})}
</EuiContextMenuItem>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@ interface ChainingSystem {
getContainerSettings: (
initialInput: ControlGroupInput
) => EmbeddableContainerSettings | undefined;
getPrecedingFilters: (props: GetPrecedingFiltersProps) => Filter[] | undefined;
getPrecedingFilters: (
props: GetPrecedingFiltersProps
) => { filters: Filter[]; timeslice?: [number, number] } | undefined;
onChildChange: (props: OnChildChangedProps) => void;
}

Expand Down Expand Up @@ -84,14 +86,19 @@ export const ControlGroupChainingSystems: {
}),
getPrecedingFilters: ({ id, childOrder, getChild }) => {
let filters: Filter[] = [];
let timeslice;
const order = childOrder.IdsToOrder?.[id];
if (!order || order === 0) return filters;
if (!order || order === 0) return { filters, timeslice };
for (let i = 0; i < order; i++) {
const embeddable = getChild(childOrder.idsInOrder[i]);
if (!embeddable || isErrorEmbeddable(embeddable)) return filters;
filters = [...filters, ...(embeddable.getOutput().filters ?? [])];
if (!embeddable || isErrorEmbeddable(embeddable)) return { filters, timeslice };
const embeddableOutput = embeddable.getOutput();
if (embeddableOutput.timeslice) {
timeslice = embeddableOutput.timeslice;
}
filters = [...filters, ...(embeddableOutput.filters ?? [])];
}
return filters;
return { filters, timeslice };
},
onChildChange: ({ childOutputChangedId, childOrder, recalculateFilters$, getChild }) => {
if (childOutputChangedId === childOrder.lastChildId) {
Expand All @@ -100,13 +107,28 @@ export const ControlGroupChainingSystems: {
return;
}

// when output changes on a child which isn't the last - make the next embeddable updateInputFromParent
const nextOrder = childOrder.IdsToOrder[childOutputChangedId] + 1;
if (nextOrder >= childOrder.idsInOrder.length) return;
setTimeout(
() => getChild(childOrder.idsInOrder[nextOrder])?.refreshInputFromParent(),
1 // run on next tick
);
// when output changes on a child which isn't the last
let nextOrder = childOrder.IdsToOrder[childOutputChangedId] + 1;
while (nextOrder < childOrder.idsInOrder.length) {
const nextControl = getChild(childOrder.idsInOrder[nextOrder]);

// make the next chained embeddable updateInputFromParent
if (nextControl?.isChained?.()) {
setTimeout(
() => nextControl.refreshInputFromParent(),
1 // run on next tick
);
return;
}

// recalculate filters when there are no chained controls to the right of the updated control
if (nextControl.id === childOrder.lastChildId) {
recalculateFilters$.next(null);
return;
}

nextOrder += 1;
}
},
},
NONE: {
Expand Down
Loading

0 comments on commit ce90eec

Please sign in to comment.