mirror of
https://github.com/elastic/kibana.git
synced 2025-04-25 02:09:32 -04:00
[ResponseOps] Bring back EuiThemeProvider to fix o11y and stack monitoring rules in stack management (#188724)
Related to https://github.com/elastic/kibana/issues/186969 and elastic/response-ops-team#218 ## Summary This PR brings back EuiThemeProvider to fix o11y and stack monitoring rules in stack management. ## To check/do - [x] Add an APM test that fails without this fix - [x] Check if this solves the related SDH for [CPU Usage](https://github.com/elastic/sdh-kibana/issues/4829) - Yes, it will solve that issue ([comment](https://github.com/elastic/sdh-kibana/issues/4829#issuecomment-2242509680)) - [x] Smoke test **ALL** rule types in stack management - Can we load the rule form? - Can we adjust all the input fields without error? - Does it work both with and without data in the preview chart?
This commit is contained in:
parent
11e81d15ec
commit
ed32c98072
4 changed files with 107 additions and 22 deletions
|
@ -14,10 +14,11 @@ interface Props {
|
||||||
value: React.ReactNode;
|
value: React.ReactNode;
|
||||||
children?: React.ReactNode;
|
children?: React.ReactNode;
|
||||||
color?: ExpressionColor;
|
color?: ExpressionColor;
|
||||||
|
dataTestSubj?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function PopoverExpression(props: Props) {
|
export function PopoverExpression(props: Props) {
|
||||||
const { title, value, children, color } = props;
|
const { title, value, children, color, dataTestSubj } = props;
|
||||||
const [popoverOpen, setPopoverOpen] = useState(false);
|
const [popoverOpen, setPopoverOpen] = useState(false);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -27,6 +28,7 @@ export function PopoverExpression(props: Props) {
|
||||||
closePopover={() => setPopoverOpen(false)}
|
closePopover={() => setPopoverOpen(false)}
|
||||||
button={
|
button={
|
||||||
<EuiExpression
|
<EuiExpression
|
||||||
|
data-test-subj={dataTestSubj}
|
||||||
description={title}
|
description={title}
|
||||||
value={value}
|
value={value}
|
||||||
isActive={popoverOpen}
|
isActive={popoverOpen}
|
||||||
|
|
|
@ -34,6 +34,7 @@ export function ServiceField({
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<PopoverExpression
|
<PopoverExpression
|
||||||
|
dataTestSubj="apmServiceField"
|
||||||
value={currentValue || allOptionText}
|
value={currentValue || allOptionText}
|
||||||
title={i18n.translate('xpack.apm.alerting.fields.service', {
|
title={i18n.translate('xpack.apm.alerting.fields.service', {
|
||||||
defaultMessage: 'Service',
|
defaultMessage: 'Service',
|
||||||
|
@ -68,6 +69,7 @@ export function EnvironmentField({
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<PopoverExpression
|
<PopoverExpression
|
||||||
|
dataTestSubj="apmEnvironmentField"
|
||||||
value={getEnvironmentLabel(currentValue)}
|
value={getEnvironmentLabel(currentValue)}
|
||||||
title={i18n.translate('xpack.apm.alerting.fields.environment', {
|
title={i18n.translate('xpack.apm.alerting.fields.environment', {
|
||||||
defaultMessage: 'Environment',
|
defaultMessage: 'Environment',
|
||||||
|
@ -106,7 +108,11 @@ export function TransactionNameField({
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PopoverExpression value={currentValue || allOptionText} title={label}>
|
<PopoverExpression
|
||||||
|
dataTestSubj="apmTransactionNameField"
|
||||||
|
value={currentValue || allOptionText}
|
||||||
|
title={label}
|
||||||
|
>
|
||||||
<SuggestionsSelect
|
<SuggestionsSelect
|
||||||
customOptions={[{ label: allOptionText, value: undefined }]}
|
customOptions={[{ label: allOptionText, value: undefined }]}
|
||||||
customOptionText={i18n.translate('xpack.apm.alerting.transaction.name.custom.text', {
|
customOptionText={i18n.translate('xpack.apm.alerting.transaction.name.custom.text', {
|
||||||
|
@ -139,7 +145,11 @@ export function TransactionTypeField({
|
||||||
defaultMessage: 'Type',
|
defaultMessage: 'Type',
|
||||||
});
|
});
|
||||||
return (
|
return (
|
||||||
<PopoverExpression value={currentValue || allOptionText} title={label}>
|
<PopoverExpression
|
||||||
|
dataTestSubj="apmTransactionTypeField"
|
||||||
|
value={currentValue || allOptionText}
|
||||||
|
title={label}
|
||||||
|
>
|
||||||
<SuggestionsSelect
|
<SuggestionsSelect
|
||||||
customOptions={[{ label: allOptionText, value: undefined }]}
|
customOptions={[{ label: allOptionText, value: undefined }]}
|
||||||
customOptionText={i18n.translate('xpack.apm.transactionTypesSelectCustomOptionText', {
|
customOptionText={i18n.translate('xpack.apm.transactionTypesSelectCustomOptionText', {
|
||||||
|
@ -172,7 +182,11 @@ export function ErrorGroupingKeyField({
|
||||||
defaultMessage: 'Error grouping key',
|
defaultMessage: 'Error grouping key',
|
||||||
});
|
});
|
||||||
return (
|
return (
|
||||||
<PopoverExpression value={currentValue || allOptionText} title={label}>
|
<PopoverExpression
|
||||||
|
dataTestSubj="apmErrorGroupingKeyField"
|
||||||
|
value={currentValue || allOptionText}
|
||||||
|
title={label}
|
||||||
|
>
|
||||||
<SuggestionsSelect
|
<SuggestionsSelect
|
||||||
customOptions={[{ label: allOptionText, value: undefined }]}
|
customOptions={[{ label: allOptionText, value: undefined }]}
|
||||||
customOptionText={i18n.translate('xpack.apm.errorKeySelectCustomOptionText', {
|
customOptionText={i18n.translate('xpack.apm.errorKeySelectCustomOptionText', {
|
||||||
|
|
|
@ -43,7 +43,10 @@ import {
|
||||||
EuiToolTip,
|
EuiToolTip,
|
||||||
EuiCallOut,
|
EuiCallOut,
|
||||||
EuiAccordion,
|
EuiAccordion,
|
||||||
|
useEuiTheme,
|
||||||
|
COLOR_MODES_STANDARD,
|
||||||
} from '@elastic/eui';
|
} from '@elastic/eui';
|
||||||
|
import { EuiThemeProvider } from '@kbn/kibana-react-plugin/common';
|
||||||
import { capitalize } from 'lodash';
|
import { capitalize } from 'lodash';
|
||||||
import { KibanaFeature } from '@kbn/features-plugin/public';
|
import { KibanaFeature } from '@kbn/features-plugin/public';
|
||||||
import {
|
import {
|
||||||
|
@ -199,6 +202,7 @@ export const RuleForm = ({
|
||||||
dataViews,
|
dataViews,
|
||||||
} = useKibana().services;
|
} = useKibana().services;
|
||||||
const canShowActions = hasShowActionsCapability(capabilities);
|
const canShowActions = hasShowActionsCapability(capabilities);
|
||||||
|
const { colorMode } = useEuiTheme();
|
||||||
|
|
||||||
const [ruleTypeModel, setRuleTypeModel] = useState<RuleTypeModel | null>(null);
|
const [ruleTypeModel, setRuleTypeModel] = useState<RuleTypeModel | null>(null);
|
||||||
const flyoutBodyOverflowRef = useRef<HTMLDivElement | HTMLSpanElement | null>(null);
|
const flyoutBodyOverflowRef = useRef<HTMLDivElement | HTMLSpanElement | null>(null);
|
||||||
|
@ -765,24 +769,26 @@ export const RuleForm = ({
|
||||||
</SectionLoading>
|
</SectionLoading>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<RuleParamsExpressionComponent
|
<EuiThemeProvider darkMode={colorMode === COLOR_MODES_STANDARD.dark}>
|
||||||
id={rule.id}
|
<RuleParamsExpressionComponent
|
||||||
ruleParams={rule.params}
|
id={rule.id}
|
||||||
ruleInterval={`${ruleInterval ?? 1}${ruleIntervalUnit}`}
|
ruleParams={rule.params}
|
||||||
ruleThrottle={''}
|
ruleInterval={`${ruleInterval ?? 1}${ruleIntervalUnit}`}
|
||||||
alertNotifyWhen={rule.notifyWhen ?? 'onActionGroupChange'}
|
ruleThrottle={''}
|
||||||
errors={errors}
|
alertNotifyWhen={rule.notifyWhen ?? 'onActionGroupChange'}
|
||||||
setRuleParams={setRuleParams}
|
errors={errors}
|
||||||
setRuleProperty={setRuleProperty}
|
setRuleParams={setRuleParams}
|
||||||
defaultActionGroupId={defaultActionGroupId}
|
setRuleProperty={setRuleProperty}
|
||||||
actionGroups={selectedRuleType.actionGroups}
|
defaultActionGroupId={defaultActionGroupId}
|
||||||
metadata={metadata}
|
actionGroups={selectedRuleType.actionGroups}
|
||||||
charts={charts}
|
metadata={metadata}
|
||||||
data={data}
|
charts={charts}
|
||||||
dataViews={dataViews}
|
data={data}
|
||||||
unifiedSearch={unifiedSearch}
|
dataViews={dataViews}
|
||||||
onChangeMetaData={onChangeMetaData}
|
unifiedSearch={unifiedSearch}
|
||||||
/>
|
onChangeMetaData={onChangeMetaData}
|
||||||
|
/>
|
||||||
|
</EuiThemeProvider>
|
||||||
</Suspense>
|
</Suspense>
|
||||||
</EuiErrorBoundary>
|
</EuiErrorBoundary>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
|
@ -8,6 +8,9 @@
|
||||||
import expect from '@kbn/expect';
|
import expect from '@kbn/expect';
|
||||||
import { asyncForEach } from '@kbn/std';
|
import { asyncForEach } from '@kbn/std';
|
||||||
import { omit } from 'lodash';
|
import { omit } from 'lodash';
|
||||||
|
import { apm, timerange } from '@kbn/apm-synthtrace-client';
|
||||||
|
import { ApmSynthtraceEsClient } from '@kbn/apm-synthtrace';
|
||||||
|
import { getApmSynthtraceEsClient } from '../../../common/utils/synthtrace/apm_es_client';
|
||||||
import { FtrProviderContext } from '../../ftr_provider_context';
|
import { FtrProviderContext } from '../../ftr_provider_context';
|
||||||
import { generateUniqueKey } from '../../lib/get_test_data';
|
import { generateUniqueKey } from '../../lib/get_test_data';
|
||||||
|
|
||||||
|
@ -20,6 +23,8 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
|
||||||
const retry = getService('retry');
|
const retry = getService('retry');
|
||||||
const rules = getService('rules');
|
const rules = getService('rules');
|
||||||
const toasts = getService('toasts');
|
const toasts = getService('toasts');
|
||||||
|
const esClient = getService('es');
|
||||||
|
const apmSynthtraceKibanaClient = getService('apmSynthtraceKibanaClient');
|
||||||
|
|
||||||
async function getAlertsByName(name: string) {
|
async function getAlertsByName(name: string) {
|
||||||
const {
|
const {
|
||||||
|
@ -71,6 +76,12 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
|
||||||
await nameInput.click();
|
await nameInput.click();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function defineAPMErrorCountRule(ruleName: string) {
|
||||||
|
await pageObjects.triggersActionsUI.clickCreateAlertButton();
|
||||||
|
await testSubjects.click(`apm.error_rate-SelectOption`);
|
||||||
|
await testSubjects.setValue('ruleNameInput', ruleName);
|
||||||
|
}
|
||||||
|
|
||||||
async function defineAlwaysFiringAlert(alertName: string) {
|
async function defineAlwaysFiringAlert(alertName: string) {
|
||||||
await pageObjects.triggersActionsUI.clickCreateAlertButton();
|
await pageObjects.triggersActionsUI.clickCreateAlertButton();
|
||||||
await testSubjects.click('test.always-firing-SelectOption');
|
await testSubjects.click('test.always-firing-SelectOption');
|
||||||
|
@ -82,6 +93,45 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
describe('create alert', function () {
|
describe('create alert', function () {
|
||||||
|
let apmSynthtraceEsClient: ApmSynthtraceEsClient;
|
||||||
|
before(async () => {
|
||||||
|
const version = (await apmSynthtraceKibanaClient.installApmPackage()).version;
|
||||||
|
apmSynthtraceEsClient = await getApmSynthtraceEsClient({
|
||||||
|
client: esClient,
|
||||||
|
packageVersion: version,
|
||||||
|
});
|
||||||
|
const opbeansJava = apm
|
||||||
|
.service({ name: 'opbeans-java', environment: 'production', agentName: 'java' })
|
||||||
|
.instance('instance');
|
||||||
|
|
||||||
|
const opbeansNode = apm
|
||||||
|
.service({ name: 'opbeans-node', environment: 'production', agentName: 'node' })
|
||||||
|
.instance('instance');
|
||||||
|
|
||||||
|
const events = timerange('now-15m', 'now')
|
||||||
|
.ratePerMinute(1)
|
||||||
|
.generator((timestamp) => {
|
||||||
|
return [
|
||||||
|
opbeansJava
|
||||||
|
.transaction({ transactionName: 'tx-java' })
|
||||||
|
.timestamp(timestamp)
|
||||||
|
.duration(100)
|
||||||
|
.failure()
|
||||||
|
.errors(opbeansJava.error({ message: 'a java error' }).timestamp(timestamp + 50)),
|
||||||
|
|
||||||
|
opbeansNode
|
||||||
|
.transaction({ transactionName: 'tx-node' })
|
||||||
|
.timestamp(timestamp)
|
||||||
|
.duration(100)
|
||||||
|
.success(),
|
||||||
|
];
|
||||||
|
});
|
||||||
|
|
||||||
|
return Promise.all([apmSynthtraceEsClient.index(events)]);
|
||||||
|
});
|
||||||
|
|
||||||
|
after(() => apmSynthtraceEsClient.clean());
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await pageObjects.common.navigateToApp('triggersActions');
|
await pageObjects.common.navigateToApp('triggersActions');
|
||||||
await testSubjects.click('rulesTab');
|
await testSubjects.click('rulesTab');
|
||||||
|
@ -321,6 +371,19 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
|
||||||
await discardNewRuleCreation();
|
await discardNewRuleCreation();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Related issue that this test is trying to prevent:
|
||||||
|
// https://github.com/elastic/kibana/issues/186969
|
||||||
|
it('should successfully show the APM error count rule flyout', async () => {
|
||||||
|
const ruleName = generateUniqueKey();
|
||||||
|
await defineAPMErrorCountRule(ruleName);
|
||||||
|
|
||||||
|
await testSubjects.existOrFail('apmServiceField');
|
||||||
|
await testSubjects.existOrFail('apmEnvironmentField');
|
||||||
|
await testSubjects.existOrFail('apmErrorGroupingKeyField');
|
||||||
|
|
||||||
|
await discardNewRuleCreation();
|
||||||
|
});
|
||||||
|
|
||||||
it('should successfully test valid es_query alert', async () => {
|
it('should successfully test valid es_query alert', async () => {
|
||||||
const alertName = generateUniqueKey();
|
const alertName = generateUniqueKey();
|
||||||
await defineEsQueryAlert(alertName);
|
await defineEsQueryAlert(alertName);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue