Skip to content

Commit

Permalink
[ML] Transforms: Fixes max page search size limit (#159052)
Browse files Browse the repository at this point in the history
Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
  • Loading branch information
qn895 and kibanamachine committed Jun 7, 2023
1 parent 0095c57 commit 87dc7ae
Show file tree
Hide file tree
Showing 12 changed files with 123 additions and 89 deletions.
2 changes: 1 addition & 1 deletion x-pack/plugins/transform/public/app/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import { KibanaContextProvider, KibanaThemeProvider } from '@kbn/kibana-react-pl
import { addInternalBasePath } from '../../common/constants';

import { SectionError } from './components';
import { SECTION_SLUG } from './constants';
import { SECTION_SLUG } from './common/constants';
import { AuthorizationContext, AuthorizationProvider } from './lib/authorization';
import { AppDependencies } from './app_dependencies';

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* 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; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import { i18n } from '@kbn/i18n';

export const numberRangeMinus1To100NotValidErrorMessage = i18n.translate(
'xpack.transform.transformSettingValidations.numberGreaterThanOrEqualToNegativeOneNotValidErrorMessage',
{
defaultMessage: 'Number of retries needs to be between 0 and 100, or -1 for infinite retries.',
}
);

export const numberRange10To10000NotValidErrorMessage = i18n.translate(
'xpack.transform.transformSettingValidations.numberRange10To10000NotValidErrorMessage',
{
defaultMessage: 'Value needs to be an integer between 10 and 10000.',
}
);

export const pageSearchSizeInvalidErrorMessage = i18n.translate(
'xpack.transform.transformSettingValidations.maxPageSearchSizeInvalidMessage',
{
defaultMessage: 'Maximum page search size needs to be an integer between 10 and 65536.',
}
);

// Retention policy max age validator
export const retentionPolicyMaxAgeInvalidErrorMessage = i18n.translate(
'xpack.transform.transformSettingValidations.retentionPolicyMaxAgeInvalidMessage',
{
defaultMessage: 'Invalid max age format. Minimum of 60s required.',
}
);

// xpack.transform.transformList.numberOfRetriesInvalidErrorMessage
export const numberOfRetriesInvalidErrorMessage = i18n.translate(
'xpack.transform.transformSettingsValidations.numberOfRetriesInvalidErrorMessage',
{
defaultMessage: 'Number of retries needs to be between 0 and 100, or -1 for infinite retries.',
}
);
2 changes: 1 addition & 1 deletion x-pack/plugins/transform/public/app/common/navigation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import React, { FC } from 'react';
import { Redirect } from 'react-router-dom';

import { SECTION_SLUG } from '../constants';
import { SECTION_SLUG } from './constants';

export const RedirectToTransformManagement: FC = () => <Redirect to={`/${SECTION_SLUG.HOME}`} />;

Expand Down
40 changes: 36 additions & 4 deletions x-pack/plugins/transform/public/app/common/validators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,14 @@
* 2.0.
*/

import { numberValidator } from '@kbn/ml-agg-utils';
import {
numberOfRetriesInvalidErrorMessage,
numberRange10To10000NotValidErrorMessage,
numberRangeMinus1To100NotValidErrorMessage,
pageSearchSizeInvalidErrorMessage,
} from './constants/validation_messages';

const RETENTION_POLICY_MIN_AGE_SECONDS = 60;
const TIME_UNITS = ['nanos', 'micros', 'ms', 's', 'm', 'h', 'd'];

Expand Down Expand Up @@ -119,14 +127,26 @@ export const transformFrequencyValidator = (value: string): boolean => {
return isValidFrequency({ number, timeUnit });
};

// A Validator function takes in a value to check and returns an array of error messages.
// If no messages (empty array) get returned, the value is valid.
export type Validator = (value: any, isOptional?: boolean) => string[];

/**
* Validates transform max_page_search_size input.
* Must be a number between 10 and 10000.
* Must be a number between 10 and 65536.
* @param value User input value.
*/
export function transformSettingsMaxPageSearchSizeValidator(value: number): boolean {
return value >= 10 && value <= 10000;
}
export const transformSettingsPageSearchSizeValidator: Validator = (value) =>
!(value + '').includes('.') &&
numberValidator({ min: 10, max: 65536, integerOnly: true })(+value) === null
? []
: [pageSearchSizeInvalidErrorMessage];

export const transformSettingsNumberOfRetriesValidator: Validator = (value) =>
!(value + '').includes('.') &&
numberValidator({ min: -1, max: 100, integerOnly: true })(+value) === null
? []
: [numberOfRetriesInvalidErrorMessage];

/**
* Validates whether string input can be parsed as a valid JSON
Expand All @@ -144,3 +164,15 @@ export function jsonStringValidator(value: unknown): boolean {
}
return true;
}

export const integerRangeMinus1To100Validator: Validator = (value) =>
!(value + '').includes('.') &&
numberValidator({ min: -1, max: 100, integerOnly: true })(+value) === null
? []
: [numberRangeMinus1To100NotValidErrorMessage];

export const integerRange10To10000Validator: Validator = (value) =>
!(value + '').includes('.') &&
numberValidator({ min: 10, max: 100001, integerOnly: true })(+value) === null
? []
: [numberRange10To10000NotValidErrorMessage];
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export interface StepDetailsExposedState {
transformId: TransformId;
transformDescription: string;
transformFrequency: string;
transformSettingsMaxPageSearchSize: number;
transformSettingsMaxPageSearchSize?: number;
transformSettingsDocsPerSecond: number | null;
transformSettingsNumFailureRetries?: number;
valid: boolean;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import { KBN_FIELD_TYPES } from '@kbn/field-types';
import { toMountPoint } from '@kbn/kibana-react-plugin/public';

import { isHttpFetchError } from '@kbn/core-http-browser';
import { integerRangeMinus1To100Validator } from '../../../transform_management/components/edit_transform_flyout/use_edit_transform_flyout';
import { retentionPolicyMaxAgeInvalidErrorMessage } from '../../../../common/constants/validation_messages';
import {
isEsIndices,
isEsIngestPipelines,
Expand All @@ -54,9 +54,10 @@ import {
import { EsIndexName, DataViewTitle } from './common';
import {
continuousModeDelayValidator,
integerRangeMinus1To100Validator,
retentionPolicyMaxAgeValidator,
transformFrequencyValidator,
transformSettingsMaxPageSearchSizeValidator,
transformSettingsPageSearchSizeValidator,
} from '../../../../common/validators';
import { StepDefineExposedState } from '../step_define/common';
import { TRANSFORM_FUNCTION } from '../../../../../../common/constants';
Expand Down Expand Up @@ -298,14 +299,16 @@ export const StepDetailsForm: FC<StepDetailsFormProps> = React.memo(
const [transformFrequency, setTransformFrequency] = useState(defaults.transformFrequency);
const isTransformFrequencyValid = transformFrequencyValidator(transformFrequency);

const [transformSettingsMaxPageSearchSize, setTransformSettingsMaxPageSearchSize] = useState(
defaults.transformSettingsMaxPageSearchSize
);
const [transformSettingsMaxPageSearchSize, setTransformSettingsMaxPageSearchSize] = useState<
number | undefined
>(defaults.transformSettingsMaxPageSearchSize);
const [transformSettingsDocsPerSecond] = useState(defaults.transformSettingsDocsPerSecond);

const isTransformSettingsMaxPageSearchSizeValid = transformSettingsMaxPageSearchSizeValidator(
const transformSettingsMaxPageSearchSizeErrors = transformSettingsPageSearchSizeValidator(
transformSettingsMaxPageSearchSize
);
const isTransformSettingsMaxPageSearchSizeValid =
transformSettingsMaxPageSearchSizeErrors.length === 0;

const [transformSettingsNumFailureRetries, setTransformSettingsNumFailureRetries] = useState<
string | number | undefined
Expand Down Expand Up @@ -731,11 +734,7 @@ export const StepDetailsForm: FC<StepDetailsFormProps> = React.memo(
isInvalid={!retentionPolicyMaxAgeEmpty && !isRetentionPolicyMaxAgeValid}
error={
!retentionPolicyMaxAgeEmpty &&
!isRetentionPolicyMaxAgeValid && [
i18n.translate('xpack.transform.stepDetailsForm.retentionPolicyMaxAgeError', {
defaultMessage: 'Invalid max age format. Minimum of 60s required.',
}),
]
!isRetentionPolicyMaxAgeValid && [retentionPolicyMaxAgeInvalidErrorMessage]
}
helpText={i18n.translate(
'xpack.transform.stepDetailsForm.retentionPolicyMaxAgeHelpText',
Expand Down Expand Up @@ -821,14 +820,7 @@ export const StepDetailsForm: FC<StepDetailsFormProps> = React.memo(
defaultMessage: 'Maximum page search size',
})}
isInvalid={!isTransformSettingsMaxPageSearchSizeValid}
error={
!isTransformSettingsMaxPageSearchSizeValid && [
i18n.translate('xpack.transform.stepDetailsForm.maxPageSearchSizeError', {
defaultMessage:
'max_page_search_size needs to be a number between 10 and 10000.',
}),
]
}
error={transformSettingsMaxPageSearchSizeErrors}
helpText={i18n.translate(
'xpack.transform.stepDetailsForm.maxPageSearchSizeHelpText',
{
Expand All @@ -845,10 +837,19 @@ export const StepDetailsForm: FC<StepDetailsFormProps> = React.memo(
values: { defaultValue: 500 },
}
)}
value={transformSettingsMaxPageSearchSize.toString()}
onChange={(e) =>
setTransformSettingsMaxPageSearchSize(parseInt(e.target.value, 10))
value={
transformSettingsMaxPageSearchSize
? transformSettingsMaxPageSearchSize.toString()
: transformSettingsMaxPageSearchSize
}
onChange={(e) => {
if (e.target.value !== '') {
const parsed = parseInt(e.target.value, 10);
setTransformSettingsMaxPageSearchSize(isFinite(parsed) ? parsed : undefined);
} else {
setTransformSettingsMaxPageSearchSize(undefined);
}
}}
aria-label={i18n.translate(
'xpack.transform.stepDetailsForm.maxPageSearchSizeAriaLabel',
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { i18n } from '@kbn/i18n';

import { AuthorizationContext } from '../../../../lib/authorization';
import { TransformListAction, TransformListRow } from '../../../../common';
import { SECTION_SLUG } from '../../../../constants';
import { SECTION_SLUG } from '../../../../common/constants';
import { useSearchItems } from '../../../../hooks/use_search_items';
import { useAppDependencies, useToastNotifications } from '../../../../app_dependencies';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { i18n } from '@kbn/i18n';
import { numberValidator } from '@kbn/ml-agg-utils';
import { getNestedProperty, setNestedProperty } from '@kbn/ml-nested-property';

import { retentionPolicyMaxAgeInvalidErrorMessage } from '../../../../common/constants/validation_messages';
import { PostTransformsUpdateRequestSchema } from '../../../../../../common/api_schemas/update_transforms';
import {
DEFAULT_TRANSFORM_FREQUENCY,
Expand All @@ -24,6 +25,9 @@ import {
isValidFrequency,
isValidRetentionPolicyMaxAge,
ParsedDuration,
transformSettingsNumberOfRetriesValidator,
transformSettingsPageSearchSizeValidator,
Validator,
} from '../../../../common/validators';

// This custom hook uses nested reducers to provide a generic framework to manage form state
Expand Down Expand Up @@ -96,10 +100,6 @@ type EditTransformFlyoutSectionsState = Record<EditTransformFormSections, FormSe
// For example, if the `pipeline` field was changed, it's necessary to make the `index`
// field part of the request, otherwise the update would fail.

// A Validator function takes in a value to check and returns an array of error messages.
// If no messages (empty array) get returned, the value is valid.
type Validator = (value: any, isOptional?: boolean) => string[];

// Note on the form validation and input components used:
// All inputs use `EuiFieldText` which means all form values will be treated as strings.
// This means we cast other formats like numbers coming from the transform config to strings,
Expand All @@ -113,36 +113,11 @@ const numberAboveZeroNotValidErrorMessage = i18n.translate(
}
);

const numberRangeMinus1To100NotValidErrorMessage = i18n.translate(
'xpack.transform.transformList.editFlyoutFormNumberGreaterThanOrEqualToNegativeOneNotValidErrorMessage',
{
defaultMessage: 'Number of retries needs to be between 0 and 100, or -1 for infinite retries.',
}
);

export const integerAboveZeroValidator: Validator = (value) =>
!(value + '').includes('.') && numberValidator({ min: 1, integerOnly: true })(+value) === null
? []
: [numberAboveZeroNotValidErrorMessage];

export const integerRangeMinus1To100Validator: Validator = (value) =>
!(value + '').includes('.') &&
numberValidator({ min: -1, max: 100, integerOnly: true })(+value) === null
? []
: [numberRangeMinus1To100NotValidErrorMessage];

const numberRange10To10000NotValidErrorMessage = i18n.translate(
'xpack.transform.transformList.editFlyoutFormNumberRange10To10000NotValidErrorMessage',
{
defaultMessage: 'Value needs to be an integer between 10 and 10000.',
}
);
export const integerRange10To10000Validator: Validator = (value) =>
!(value + '').includes('.') &&
numberValidator({ min: 10, max: 100001, integerOnly: true })(+value) === null
? []
: [numberRange10To10000NotValidErrorMessage];

const requiredErrorMessage = i18n.translate(
'xpack.transform.transformList.editFlyoutFormRequiredErrorMessage',
{
Expand Down Expand Up @@ -208,30 +183,23 @@ export const frequencyValidator: Validator = (arg) => {
return isValidFrequency(parsedArg) ? [] : [frequencyNotValidErrorMessage];
};

// Retention policy max age validator
const retentionPolicyMaxAgeNotValidErrorMessage = i18n.translate(
'xpack.transform.transformList.editFlyoutFormRetentionPolicyMaxAgeNotValidErrorMessage',
{
defaultMessage: 'Invalid max age format. Minimum of 60s required.',
}
);
export const retentionPolicyMaxAgeValidator: Validator = (arg) => {
const parsedArg = parseDurationAboveZero(arg, retentionPolicyMaxAgeNotValidErrorMessage);
const parsedArg = parseDurationAboveZero(arg, retentionPolicyMaxAgeInvalidErrorMessage);

if (Array.isArray(parsedArg)) {
return parsedArg;
}

return isValidRetentionPolicyMaxAge(parsedArg) ? [] : [retentionPolicyMaxAgeNotValidErrorMessage];
return isValidRetentionPolicyMaxAge(parsedArg) ? [] : [retentionPolicyMaxAgeInvalidErrorMessage];
};

const validate = {
string: stringValidator,
frequency: frequencyValidator,
integerAboveZero: integerAboveZeroValidator,
integerRangeMinus1To100: integerRangeMinus1To100Validator,
integerRange10To10000: integerRange10To10000Validator,
retentionPolicyMaxAge: retentionPolicyMaxAgeValidator,
transformSettingsNumberOfRetriesValidator,
transformSettingsPageSearchSizeValidator,
retentionPolicyMaxAgeValidator,
} as const;

export const initializeField = (
Expand Down Expand Up @@ -424,7 +392,7 @@ export const getDefaultState = (config: TransformConfigUnion): EditTransformFlyo
defaultValue: `${DEFAULT_TRANSFORM_SETTINGS_MAX_PAGE_SEARCH_SIZE}`,
isNullable: true,
isOptional: true,
validator: 'integerRange10To10000',
validator: 'transformSettingsPageSearchSizeValidator',
valueParser: (v) => +v,
}
),
Expand All @@ -436,7 +404,7 @@ export const getDefaultState = (config: TransformConfigUnion): EditTransformFlyo
defaultValue: undefined,
isNullable: true,
isOptional: true,
validator: 'integerRangeMinus1To100',
validator: 'transformSettingsNumberOfRetriesValidator',
valueParser: (v) => +v,
}
),
Expand All @@ -462,7 +430,7 @@ export const getDefaultState = (config: TransformConfigUnion): EditTransformFlyo
isNullable: false,
isOptional: true,
section: 'retentionPolicy',
validator: 'retentionPolicyMaxAge',
validator: 'retentionPolicyMaxAgeValidator',
}
),
},
Expand Down
6 changes: 1 addition & 5 deletions x-pack/plugins/translations/translations/fr-FR.json
Original file line number Diff line number Diff line change
Expand Up @@ -37467,7 +37467,6 @@
"xpack.transform.stepDetailsForm.frequencyHelpText": "L'intervalle de vérification des changements dans les index sources lorsque la transformation fonctionne en continu.",
"xpack.transform.stepDetailsForm.frequencyLabel": "Fréquence",
"xpack.transform.stepDetailsForm.maxPageSearchSizeAriaLabel": "Choisissez une taille maximale de recherche de pages.",
"xpack.transform.stepDetailsForm.maxPageSearchSizeError": "max_page_search_size doit être un nombre compris entre 10 et 10 000.",
"xpack.transform.stepDetailsForm.maxPageSearchSizeHelpText": "La taille de page initiale à utiliser pour l'agrégation imbriquée de chaque point de contrôle.",
"xpack.transform.stepDetailsForm.maxPageSearchSizeLabel": "Taille maximale de recherche de pages",
"xpack.transform.stepDetailsForm.missingBucketCheckboxHelpTextLink": "En savoir plus",
Expand All @@ -37478,7 +37477,6 @@
"xpack.transform.stepDetailsForm.retentionPolicyDateFieldLabel": "Champ de date pour la politique de conservation",
"xpack.transform.stepDetailsForm.retentionPolicyError": "Les paramètres de politique de conservation ne sont pas disponibles pour les index sans champ de date.",
"xpack.transform.stepDetailsForm.retentionPolicyMaxAgeAriaLabel": "Choisissez un âge maximal.",
"xpack.transform.stepDetailsForm.retentionPolicyMaxAgeError": "Format d'âge maximal non valide. Le minimum requis est de 60 s.",
"xpack.transform.stepDetailsForm.retentionPolicyMaxAgeHelpText": "Les documents antérieurs à la valeur configurée seront retirés de l'index de destination.",
"xpack.transform.stepDetailsForm.retentionPolicyMaxAgeLabel": "Âge maximal",
"xpack.transform.stepDetailsForm.transformDescriptionInputAriaLabel": "Choisissez une description de transformation facultative.",
Expand Down Expand Up @@ -37549,15 +37547,13 @@
"xpack.transform.transformList.editFlyoutFormMaxPageSearchSizeHelpText": "La taille de page initiale à utiliser pour l'agrégation imbriquée de chaque point de contrôle.",
"xpack.transform.transformList.editFlyoutFormMaxPageSearchSizeLabel": "Taille maximale de recherche de pages",
"xpack.transform.transformList.editFlyoutFormNumberAboveZeroNotValidErrorMessage": "La valeur doit être un entier supérieur à zéro.",
"xpack.transform.transformList.editFlyoutFormNumberGreaterThanOrEqualToNegativeOneNotValidErrorMessage": "Le nombre de tentatives doit être compris entre 0 et 100, ou égal à -1 pour des tentatives infinies.",
"xpack.transform.transformList.editFlyoutFormNumberRange10To10000NotValidErrorMessage": "La valeur doit être un entier compris entre 10 et 10 000.",
"xpack.transform.transformSettingValidations.numberGreaterThanOrEqualToNegativeOneNotValidErrorMessage": "Le nombre de tentatives doit être compris entre 0 et 100, ou égal à -1 pour des tentatives infinies.",
"xpack.transform.transformList.editFlyoutFormNumFailureRetriesHelpText": "Le nombre de nouvelles tentatives après un échec récupérable avant que la tâche de transformation soit marquée comme ayant échoué. Définissez-le à -1 pour des tentatives infinies.",
"xpack.transform.transformList.editFlyoutFormRequiredErrorMessage": "Champs requis.",
"xpack.transform.transformList.editFlyoutFormRetentionPolicyDateFieldHelpText": "Sélectionnez le champ de date pouvant être utilisé pour identifier les documents obsolètes dans l'index de destination.",
"xpack.transform.transformList.editFlyoutFormRetentionPolicyFieldLabel": "Champ",
"xpack.transform.transformList.editFlyoutFormRetentionPolicyFieldSelectAriaLabel": "Champ de date pour définir la politique de conservation",
"xpack.transform.transformList.editFlyoutFormRetentionPolicyMaxAgeLabel": "Âge maximal",
"xpack.transform.transformList.editFlyoutFormRetentionPolicyMaxAgeNotValidErrorMessage": "Format d'âge maximal non valide. Le minimum requis est de 60 s.",
"xpack.transform.transformList.editFlyoutFormRetentionPolicySwitchLabel": "Politique de conservation",
"xpack.transform.transformList.editFlyoutFormStringNotValidErrorMessage": "La valeur doit être de type chaîne.",
"xpack.transform.transformList.editFlyoutUpdateButtonText": "Mettre à jour",
Expand Down
Loading

0 comments on commit 87dc7ae

Please sign in to comment.