Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { AlertDelayField } from './alert_delay_field';
import { RecoveryDelayField } from './recovery_delay_field';
import type { FormValues } from '../types';
import { mapFormValuesToUpdateRequest } from '../utils/rule_request_mappers';
import { createFormWrapper } from '../../test_utils';
import { createFormWrapper, createMockServices } from '../../test_utils';

let getFormValues: (() => FormValues) | undefined;

Expand Down Expand Up @@ -117,6 +117,14 @@ describe('AlertDelayField', () => {
expect(screen.getByTestId('stateTransitionDelayMode')).toBeInTheDocument();
});

it('renders correctly in flyout layout', () => {
render(<AlertDelayField />, {
wrapper: createFormWrapper({ kind: 'alert' }, createMockServices(), { layout: 'flyout' }),
});

expect(screen.getByTestId('stateTransitionDelayMode')).toBeInTheDocument();
});

it('clears alert delay (pending) when switching to immediate while recovery delay stays on breaches', () => {
getFormValues = undefined;
render(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import type { FormValues } from '../types';
import { deriveAlertDelayModeFromStateTransition } from '../utils/rule_request_mappers';
import { StateTransitionCountField } from './state_transition_count_field';
import { StateTransitionTimeframeField } from './state_transition_timeframe_field';
import { useRuleFormMeta } from '../contexts';

type DelayMode = 'immediate' | 'breaches' | 'duration';

Expand Down Expand Up @@ -60,6 +61,7 @@ const DEFAULT_PENDING_TIMEFRAME = '2m';

export const AlertDelayField = () => {
const { control, getValues, setValue } = useFormContext<FormValues>();
const { layout } = useRuleFormMeta();
const stateTransition = useWatch({ control, name: 'stateTransition' });
const selectedMode = useWatch({ control, name: 'stateTransitionAlertDelayMode' });
const displayMode: DelayMode =
Expand Down Expand Up @@ -121,7 +123,7 @@ export const AlertDelayField = () => {
>
<>
<EuiButtonGroup
buttonSize="s"
buttonSize={layout === 'flyout' ? 'compressed' : 's'}
legend={i18n.translate('xpack.alertingV2.ruleForm.alertDelay.delayModeLegend', {
defaultMessage: 'Alert delay mode',
})}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import React from 'react';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { DescriptionField } from './description_field';
import { createFormWrapper } from '../../test_utils';
import { createFormWrapper, createMockServices } from '../../test_utils';

describe('DescriptionField', () => {
it('renders "Add description" button when no description value exists', () => {
Expand Down Expand Up @@ -73,6 +73,17 @@ describe('DescriptionField', () => {
expect(textarea).toHaveValue('My new description');
});

it('renders correctly in flyout layout', async () => {
const user = userEvent.setup();
render(<DescriptionField />, {
wrapper: createFormWrapper({}, createMockServices(), { layout: 'flyout' }),
});

await user.click(screen.getByTestId('addDescriptionButton'));

expect(screen.getByTestId('ruleDescriptionInput')).toBeInTheDocument();
});

it('keeps textarea visible after clearing the value', async () => {
const user = userEvent.setup();
render(<DescriptionField />, { wrapper: createFormWrapper() });
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,13 @@ import { i18n } from '@kbn/i18n';
import { EuiFormRow, EuiTextArea, EuiButtonEmpty, EuiSpacer } from '@elastic/eui';
import { Controller, useFormContext } from 'react-hook-form';
import type { FormValues } from '../types';
import { useRuleFormMeta } from '../contexts';

const DESCRIPTION_ROW_ID = 'ruleV2FormDescriptionField';

export const DescriptionField = () => {
const { control, watch } = useFormContext<FormValues>();
const { layout } = useRuleFormMeta();
const descriptionValue = watch('metadata.description');

// Show the input if there's already a description value
Expand Down Expand Up @@ -71,6 +73,7 @@ export const DescriptionField = () => {
rows={2}
fullWidth
isInvalid={!!error}
compressed={layout === 'flyout'}
placeholder={i18n.translate('xpack.alertingV2.ruleForm.descriptionPlaceholder', {
defaultMessage: 'Add an optional description for this rule...',
})}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export interface DurationInputProps {
unitAriaLabel: string;
dataTestSubj: string;
idPrefix: string;
compressed?: boolean;
}

/**
Expand All @@ -32,7 +33,17 @@ export interface DurationInputProps {
*/
export const DurationInput = React.forwardRef<HTMLInputElement, DurationInputProps>(
(
{ value, onChange, fallback, errors, numberLabel, unitAriaLabel, dataTestSubj, idPrefix },
{
value,
onChange,
fallback,
errors,
numberLabel,
unitAriaLabel,
dataTestSubj,
idPrefix,
compressed,
},
ref
) => {
const effectiveValue = value || fallback || '1m';
Expand Down Expand Up @@ -77,6 +88,7 @@ export const DurationInput = React.forwardRef<HTMLInputElement, DurationInputPro
prepend={numberLabel ? [numberLabel] : undefined}
isInvalid={!!errors}
name="interval"
compressed={compressed}
data-test-subj={`${idPrefix}NumberInput`}
id={`${idPrefix}NumberInput`}
aria-label={numberLabel || undefined}
Expand All @@ -88,6 +100,7 @@ export const DurationInput = React.forwardRef<HTMLInputElement, DurationInputPro
value={intervalUnit}
options={getTimeOptions(intervalNumber ?? 1)}
onChange={onIntervalUnitChange}
compressed={compressed}
data-test-subj={`${idPrefix}UnitInput`}
aria-label={unitAriaLabel}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,16 @@ describe('GroupFieldSelect', () => {
});
});

it('renders correctly in flyout layout', () => {
render(<GroupFieldSelect />, {
wrapper: createFormWrapper({ evaluation: { query: { base: defaultQuery } } }, mockServices, {
layout: 'flyout',
}),
});

expect(screen.getByRole('combobox')).toBeInTheDocument();
});

it('renders empty when no columns available', () => {
mockUseQueryColumns.mockReturnValue({
data: [],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,11 @@ import { EuiComboBox, EuiFormRow } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import type { FormValues } from '../types';
import { useQueryColumns, type QueryColumn } from '../hooks/use_query_columns';
import { useRuleFormServices } from '../contexts';
import { useRuleFormServices, useRuleFormMeta } from '../contexts';

export const GroupFieldSelect = () => {
const { data } = useRuleFormServices();
const { layout } = useRuleFormMeta();
const { control, setValue, getValues } = useFormContext<FormValues>();
const query = useWatch({ name: 'evaluation.query.base', control });
const groupByRowId = 'ruleV2FormGroupByField';
Expand Down Expand Up @@ -77,6 +78,7 @@ export const GroupFieldSelect = () => {
isInvalid={!!error}
isLoading={isLoading}
fullWidth
compressed={layout === 'flyout'}
/>
</EuiFormRow>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ interface Props {
value: string;
onChange: (value: string) => void;
errors?: string;
compressed?: boolean;
}

export const LookbackWindow = React.forwardRef<HTMLInputElement, Props>((props, ref) => (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import React from 'react';
import { render, screen, fireEvent } from '@testing-library/react';
import { LookbackWindowField } from './lookback_window_field';
import { createFormWrapper } from '../../test_utils';
import { createFormWrapper, createMockServices } from '../../test_utils';

describe('LookbackWindowField', () => {
it('renders the lookback window label', () => {
Expand Down Expand Up @@ -41,6 +41,15 @@ describe('LookbackWindowField', () => {
expect(screen.getByTestId('lookbackWindowUnitInput')).toBeInTheDocument();
});

it('renders correctly in flyout layout', () => {
render(<LookbackWindowField />, {
wrapper: createFormWrapper({}, createMockServices(), { layout: 'flyout' }),
});

expect(screen.getByText('Lookback Window')).toBeInTheDocument();
expect(screen.getByTestId('lookbackWindowNumberInput')).toBeInTheDocument();
});

it('allows clearing the number input and typing a new value', () => {
render(<LookbackWindowField />, {
wrapper: createFormWrapper({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { EuiFormRow } from '@elastic/eui';
import { Controller, useFormContext, useWatch } from 'react-hook-form';
import type { FormValues } from '../types';
import { LookbackWindow } from './lookback_window';
import { useRuleFormMeta } from '../contexts';

const LOOKBACK_WINDOW_ROW_ID = 'ruleV2FormLookbackWindowField';

Expand All @@ -25,6 +26,7 @@ const LOOKBACK_LESS_THAN_INTERVAL_WARNING = i18n.translate(

export const LookbackWindowField = () => {
const { control } = useFormContext<FormValues>();
const { layout } = useRuleFormMeta();
const scheduleEvery = useWatch({ control, name: 'schedule.every' });

return (
Expand Down Expand Up @@ -62,7 +64,7 @@ export const LookbackWindowField = () => {
isInvalid={!!error}
fullWidth
>
<LookbackWindow {...field} errors={error?.message} />
<LookbackWindow {...field} errors={error?.message} compressed={layout === 'flyout'} />
</EuiFormRow>
);
}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export interface NumberInputProps {
max?: number;
step?: number;
prepend?: string | React.ReactElement | Array<string | React.ReactElement>;
compressed?: boolean;
'data-test-subj'?: string;
id?: string;
name?: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { RecoveryDelayField } from './recovery_delay_field';
import { AlertDelayField } from './alert_delay_field';
import type { FormValues } from '../types';
import { mapFormValuesToUpdateRequest } from '../utils/rule_request_mappers';
import { createFormWrapper } from '../../test_utils';
import { createFormWrapper, createMockServices } from '../../test_utils';

let getFormValues: (() => FormValues) | undefined;

Expand Down Expand Up @@ -117,6 +117,14 @@ describe('RecoveryDelayField', () => {
expect(screen.getByTestId('recoveryDelayMode')).toBeInTheDocument();
});

it('renders correctly in flyout layout', () => {
render(<RecoveryDelayField />, {
wrapper: createFormWrapper({ kind: 'alert' }, createMockServices(), { layout: 'flyout' }),
});

expect(screen.getByTestId('recoveryDelayMode')).toBeInTheDocument();
});

it('clears recovery delay (recovering) when switching to immediate while alert delay stays on breaches', () => {
getFormValues = undefined;
render(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import type { FormValues } from '../types';
import { deriveRecoveryDelayModeFromStateTransition } from '../utils/rule_request_mappers';
import { StateTransitionCountField } from './state_transition_count_field';
import { StateTransitionTimeframeField } from './state_transition_timeframe_field';
import { useRuleFormMeta } from '../contexts';

type DelayMode = 'immediate' | 'breaches' | 'duration';

Expand Down Expand Up @@ -60,6 +61,7 @@ const DEFAULT_RECOVERING_TIMEFRAME = '2m';

export const RecoveryDelayField = () => {
const { control, getValues, setValue } = useFormContext<FormValues>();
const { layout } = useRuleFormMeta();
const stateTransition = useWatch({ control, name: 'stateTransition' });
const selectedMode = useWatch({ control, name: 'stateTransitionRecoveryDelayMode' });
const displayMode: DelayMode =
Expand Down Expand Up @@ -121,7 +123,7 @@ export const RecoveryDelayField = () => {
>
<>
<EuiButtonGroup
buttonSize="s"
buttonSize={layout === 'flyout' ? 'compressed' : 's'}
legend={i18n.translate('xpack.alertingV2.ruleForm.recoveryDelay.delayModeLegend', {
defaultMessage: 'Recovery delay mode',
})}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import React from 'react';
import { render, screen, fireEvent } from '@testing-library/react';
import { RecoveryTypeField } from './recovery_type_field';
import { createFormWrapper } from '../../test_utils';
import { createFormWrapper, createMockServices } from '../../test_utils';

describe('RecoveryTypeField', () => {
it('renders the recovery label', () => {
Expand Down Expand Up @@ -63,6 +63,14 @@ describe('RecoveryTypeField', () => {
expect(select.value).toBe('query');
});

it('renders correctly in flyout layout', () => {
render(<RecoveryTypeField />, {
wrapper: createFormWrapper({}, createMockServices(), { layout: 'flyout' }),
});

expect(screen.getByTestId('recoveryTypeSelect')).toBeInTheDocument();
});

it('updates value back to no_breach', () => {
render(<RecoveryTypeField />, {
wrapper: createFormWrapper({ recoveryPolicy: { type: 'query' } }),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { Controller, useFormContext } from 'react-hook-form';
import { i18n } from '@kbn/i18n';
import type { RecoveryPolicyType } from '@kbn/alerting-v2-schemas';
import type { FormValues } from '../types';
import { useRuleFormMeta } from '../contexts';

const RECOVERY_TYPE_OPTIONS: Array<{ value: RecoveryPolicyType; text: string }> = [
{
Expand All @@ -36,6 +37,7 @@ const RECOVERY_TYPE_OPTIONS: Array<{ value: RecoveryPolicyType; text: string }>
*/
export const RecoveryTypeField = () => {
const { control } = useFormContext<FormValues>();
const { layout } = useRuleFormMeta();

return (
<Controller
Expand All @@ -56,6 +58,7 @@ export const RecoveryTypeField = () => {
value={field.value}
onChange={(e) => field.onChange(e.target.value)}
fullWidth
compressed={layout === 'flyout'}
data-test-subj="recoveryTypeSelect"
/>
</EuiFormRow>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ interface Props {
value: string;
onChange: (value: string) => void;
errors?: string;
compressed?: boolean;
}

export const RuleSchedule = React.forwardRef<HTMLInputElement, Props>((props, ref) => (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import React from 'react';
import { render, screen } from '@testing-library/react';
import { ScheduleField } from './schedule_field';
import { createFormWrapper } from '../../test_utils';
import { createFormWrapper, createMockServices } from '../../test_utils';

describe('ScheduleField', () => {
it('renders the schedule label', () => {
Expand All @@ -30,6 +30,14 @@ describe('ScheduleField', () => {
expect(screen.getByText('Info')).toBeInTheDocument();
});

it('renders correctly in flyout layout', () => {
render(<ScheduleField />, {
wrapper: createFormWrapper({}, createMockServices(), { layout: 'flyout' }),
});

expect(screen.getByText('Schedule')).toBeInTheDocument();
});

it('displays initial schedule value', () => {
render(<ScheduleField />, {
wrapper: createFormWrapper({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,13 @@ import { EuiFormRow, EuiIconTip } from '@elastic/eui';
import { Controller, useFormContext } from 'react-hook-form';
import type { FormValues } from '../types';
import { RuleSchedule } from './rule_schedule';
import { useRuleFormMeta } from '../contexts';

const SCHEDULE_ROW_ID = 'ruleV2FormScheduleField';

export const ScheduleField = () => {
const { control } = useFormContext<FormValues>();
const { layout } = useRuleFormMeta();

return (
<Controller
Expand Down Expand Up @@ -72,7 +74,7 @@ export const ScheduleField = () => {
}
isInvalid={!!error}
>
<RuleSchedule {...field} errors={error?.message} />
<RuleSchedule {...field} errors={error?.message} compressed={layout === 'flyout'} />
</EuiFormRow>
)}
/>
Expand Down
Loading
Loading