[9.0] [Synthetics] Fix issue when selecting monitor frequency (#215823) (#215871)

# Backport

This will backport the following commits from `main` to `9.0`:
- [[Synthetics] Fix issue when selecting monitor frequency
(#215823)](https://github.com/elastic/kibana/pull/215823)

<!--- Backport version: 9.6.6 -->

### Questions ?
Please refer to the [Backport tool
documentation](https://github.com/sorenlouv/backport)

<!--BACKPORT [{"author":{"name":"Francesco
Fagnani","email":"fagnani.francesco@gmail.com"},"sourceCommit":{"committedDate":"2025-03-25T13:16:37Z","message":"[Synthetics]
Fix issue when selecting monitor frequency (#215823)\n\nThis PR closes
issue #209188.\n\nIf the frequency is set to seconds, when setting it
back to minutes the\ntime unit is correctly
changed.\n\n\n\nhttps://github.com/user-attachments/assets/1a65b130-9740-41f1-94dc-f97cf887ff1a\n\n---------\n\nCo-authored-by:
Shahzad
<shahzad31comp@gmail.com>","sha":"7429c29522579f9c3e9d5c76df8ea58dca583d97","branchLabelMapping":{"^v9.1.0$":"main","^v8.19.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:fix","Team:obs-ux-management","backport:version","v9.1.0","v8.19.0","v8.18.1","v8.17.4","v9.0.1"],"title":"[Synthetics]
Fix issue when selecting monitor
frequency","number":215823,"url":"https://github.com/elastic/kibana/pull/215823","mergeCommit":{"message":"[Synthetics]
Fix issue when selecting monitor frequency (#215823)\n\nThis PR closes
issue #209188.\n\nIf the frequency is set to seconds, when setting it
back to minutes the\ntime unit is correctly
changed.\n\n\n\nhttps://github.com/user-attachments/assets/1a65b130-9740-41f1-94dc-f97cf887ff1a\n\n---------\n\nCo-authored-by:
Shahzad
<shahzad31comp@gmail.com>","sha":"7429c29522579f9c3e9d5c76df8ea58dca583d97"}},"sourceBranch":"main","suggestedTargetBranches":["8.x","8.18","8.17","9.0"],"targetPullRequestStates":[{"branch":"main","label":"v9.1.0","branchLabelMappingKey":"^v9.1.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/215823","number":215823,"mergeCommit":{"message":"[Synthetics]
Fix issue when selecting monitor frequency (#215823)\n\nThis PR closes
issue #209188.\n\nIf the frequency is set to seconds, when setting it
back to minutes the\ntime unit is correctly
changed.\n\n\n\nhttps://github.com/user-attachments/assets/1a65b130-9740-41f1-94dc-f97cf887ff1a\n\n---------\n\nCo-authored-by:
Shahzad
<shahzad31comp@gmail.com>","sha":"7429c29522579f9c3e9d5c76df8ea58dca583d97"}},{"branch":"8.x","label":"v8.19.0","branchLabelMappingKey":"^v8.19.0$","isSourceBranch":false,"state":"NOT_CREATED"},{"branch":"8.18","label":"v8.18.1","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"},{"branch":"8.17","label":"v8.17.4","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"},{"branch":"9.0","label":"v9.0.1","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"}]}]
BACKPORT-->

Co-authored-by: Francesco Fagnani <fagnani.francesco@gmail.com>
This commit is contained in:
Kibana Machine 2025-03-25 16:10:11 +01:00 committed by GitHub
parent dbf34e58ef
commit e541bb29e5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 88 additions and 19 deletions

View file

@ -380,4 +380,18 @@ describe('format', () => {
}, {})
);
});
it('sets the schedule unit to seconds if the number ends with the letter s', () => {
formValues.schedule = { number: '10s', unit: 'm' };
expect(format(formValues)).toEqual(
expect.objectContaining({ schedule: { number: '10', unit: 's' } })
);
});
it('changes schedule unit back to minutes when it is changed from seconds to minutes', () => {
formValues.schedule = { number: '3', unit: 's' };
expect(format(formValues)).toEqual(
expect.objectContaining({ schedule: { number: '3', unit: 'm' } })
);
});
});

View file

@ -5,13 +5,7 @@
* 2.0.
*/
import { get, pick } from 'lodash';
import {
ConfigKey,
MonitorTypeEnum,
FormMonitorType,
MonitorFields,
SyntheticsMonitorSchedule,
} from '../types';
import { ConfigKey, MonitorTypeEnum, FormMonitorType, MonitorFields, ScheduleUnit } from '../types';
import { DEFAULT_FIELDS } from '../constants';
export const serializeNestedFormField = (fields: Record<string, any>) => {
@ -28,6 +22,14 @@ export const serializeNestedFormField = (fields: Record<string, any>) => {
export const ALLOWED_FIELDS = [ConfigKey.ENABLED, ConfigKey.ALERT_CONFIG];
const formatSchedule = (schedule: { number: string; unit: ScheduleUnit }) => {
const isFrequencyInSeconds = schedule.number.endsWith('s');
return {
number: isFrequencyInSeconds ? schedule.number.slice(0, -1) : schedule.number,
unit: isFrequencyInSeconds ? ScheduleUnit.SECONDS : ScheduleUnit.MINUTES,
};
};
export const format = (fields: Record<string, unknown>, readOnly: boolean = false) => {
const formattedFields = serializeNestedFormField(fields) as MonitorFields;
const textAssertion = formattedFields[ConfigKey.TEXT_ASSERTION]
@ -35,13 +37,7 @@ export const format = (fields: Record<string, unknown>, readOnly: boolean = fals
await page.getByText('${formattedFields[ConfigKey.TEXT_ASSERTION]}').first().waitFor();`
: ``;
const schedule = formattedFields[ConfigKey.SCHEDULE];
if (schedule.number.endsWith('s')) {
formattedFields[ConfigKey.SCHEDULE] = {
number: `${schedule.number.slice(0, -1)}`,
unit: 's' as SyntheticsMonitorSchedule['unit'],
};
}
formattedFields[ConfigKey.SCHEDULE] = formatSchedule(formattedFields[ConfigKey.SCHEDULE]);
const formattedMap = {
[FormMonitorType.SINGLE]: {

View file

@ -8,7 +8,10 @@ import { schema } from '@kbn/config-schema';
import { SavedObjectsErrorHelpers } from '@kbn/core/server';
import { i18n } from '@kbn/i18n';
import { validatePermissions } from './edit_monitor';
import { InvalidLocationError } from '../../synthetics_service/project_monitor/normalizers/common_fields';
import {
InvalidLocationError,
InvalidScheduleError,
} from '../../synthetics_service/project_monitor/normalizers/common_fields';
import { AddEditMonitorAPI, CreateMonitorPayLoad } from './add_monitor/add_monitor_api';
import { SyntheticsRestApiRouteFactory } from '../types';
import { SYNTHETICS_API_URLS } from '../../../common/constants';
@ -121,7 +124,7 @@ export const addSyntheticsMonitorRoute: SyntheticsRestApiRouteFactory = () => ({
return mapSavedObjectToMonitor({ monitor: newMonitor, internal });
} catch (getErr) {
server.logger.error(getErr);
if (getErr instanceof InvalidLocationError) {
if (getErr instanceof InvalidLocationError || getErr instanceof InvalidScheduleError) {
return response.badRequest({ body: { message: getErr.message } });
}
if (SavedObjectsErrorHelpers.isForbiddenError(getErr)) {

View file

@ -9,7 +9,10 @@ import { SavedObjectsUpdateResponse, SavedObject } from '@kbn/core/server';
import { SavedObjectsErrorHelpers } from '@kbn/core/server';
import { isEmpty } from 'lodash';
import { invalidOriginError } from './add_monitor';
import { InvalidLocationError } from '../../synthetics_service/project_monitor/normalizers/common_fields';
import {
InvalidLocationError,
InvalidScheduleError,
} from '../../synthetics_service/project_monitor/normalizers/common_fields';
import { AddEditMonitorAPI, CreateMonitorPayLoad } from './add_monitor/add_monitor_api';
import { ELASTIC_MANAGED_LOCATIONS_DISABLED } from './project_monitor/add_monitor_project';
import { getDecryptedMonitor } from '../../saved_objects/synthetics_monitor';
@ -185,7 +188,7 @@ export const editSyntheticsMonitorRoute: SyntheticsRestApiRouteFactory = () => (
if (SavedObjectsErrorHelpers.isNotFoundError(updateErr)) {
return getMonitorNotFoundResponse(response, monitorId);
}
if (updateErr instanceof InvalidLocationError) {
if (updateErr instanceof InvalidLocationError || updateErr instanceof InvalidScheduleError) {
return response.badRequest({ body: { message: updateErr.message } });
}
if (updateErr instanceof MonitorValidationError) {

View file

@ -5,10 +5,13 @@
* 2.0.
*/
import { ScheduleUnit } from '../../../../common/runtime_types';
import {
flattenAndFormatObject,
getMonitorSchedule,
getNormalizeCommonFields,
getUrlsField,
InvalidScheduleError,
isValidURL,
NormalizedProjectProps,
} from './common_fields';
@ -242,3 +245,33 @@ describe('getNormalizeCommonFields', () => {
});
});
});
describe('getMonitorSchedule', () => {
it('should return default value if schedule is falsy', () => {
const defaultValue = { number: '5', unit: ScheduleUnit.MINUTES };
expect(getMonitorSchedule(null as any, defaultValue)).toEqual(defaultValue);
expect(getMonitorSchedule(undefined as any, defaultValue)).toEqual(defaultValue);
});
it('should return a schedule object with minutes if schedule is a number', () => {
expect(getMonitorSchedule(5)).toEqual({ number: '5', unit: ScheduleUnit.MINUTES });
});
it('should return a schedule object with minutes if schedule is a string without seconds', () => {
expect(getMonitorSchedule('10')).toEqual({ number: '10', unit: ScheduleUnit.MINUTES });
});
it('should return a schedule object with seconds if schedule is allowed', () => {
expect(getMonitorSchedule('10s')).toEqual({ number: '10', unit: ScheduleUnit.SECONDS });
expect(getMonitorSchedule('30s')).toEqual({ number: '30', unit: ScheduleUnit.SECONDS });
});
it('should throw InvalidScheduleError if schedule in seconds is not allowed', () => {
expect(() => getMonitorSchedule('20s')).toThrow(InvalidScheduleError);
});
it('should return the schedule object if schedule is already in the correct format', () => {
const existingSchedule = { number: '15', unit: ScheduleUnit.MINUTES };
expect(getMonitorSchedule(existingSchedule)).toEqual(existingSchedule);
});
});

View file

@ -5,6 +5,8 @@
* 2.0.
*/
/* eslint-disable max-classes-per-file */
import { omit, uniqBy } from 'lodash';
import { i18n } from '@kbn/i18n';
import { isValidNamespace } from '@kbn/fleet-plugin/common';
@ -22,7 +24,10 @@ import {
MonitorFields,
type SyntheticsPrivateLocations,
} from '../../../../common/runtime_types';
import { DEFAULT_FIELDS } from '../../../../common/constants/monitor_defaults';
import {
ALLOWED_SCHEDULES_IN_SECONDS,
DEFAULT_FIELDS,
} from '../../../../common/constants/monitor_defaults';
import { DEFAULT_COMMON_FIELDS } from '../../../../common/constants/monitor_defaults';
import { formatKibanaNamespace } from '../../formatters/private_formatters';
@ -165,6 +170,14 @@ export const getMonitorSchedule = (
};
}
if (schedule.includes('s')) {
if (!ALLOWED_SCHEDULES_IN_SECONDS.includes(schedule)) {
throw new InvalidScheduleError(
i18n.translate('xpack.synthetics.projectMonitorApi.validation.invalidSchedule', {
defaultMessage: 'Invalid schedule. Allowed schedules in seconds are {allowedSchedules}',
values: { allowedSchedules: ALLOWED_SCHEDULES_IN_SECONDS.join(', ') },
})
);
}
return {
number: schedule.replace('s', ''),
unit: ScheduleUnit.SECONDS,
@ -257,6 +270,13 @@ export class InvalidLocationError extends Error {
}
}
export class InvalidScheduleError extends Error {
constructor(message: string) {
super(message);
this.name = 'InvalidScheduleError';
}
}
const UNSUPPORTED_OPTION_TITLE = i18n.translate(
'xpack.synthetics.projectMonitorApi.validation.unsupportedOption.title',
{