in x-pack/platform/plugins/private/transform/public/app/sections/create_transform/components/step_details/step_details_form.tsx [243:500]
text: toMountPoint(
<ToastNotificationText text={getErrorMessage(dataViewTitlesError)} />,
startServices
),
});
}
}, [dataViewTitlesError]);
const sourceIndexDateFieldNames = searchItems.dataView.fields
.filter((f) => f.type === KBN_FIELD_TYPES.DATE)
.map((f) => f.name)
.sort();
// Continuous Mode
const isContinuousModeAvailable = sourceIndexDateFieldNames.length > 0;
const [isContinuousModeEnabled, setContinuousModeEnabled] = useState(
defaults.isContinuousModeEnabled
);
const [continuousModeDateField, setContinuousModeDateField] = useState(
isContinuousModeAvailable ? sourceIndexDateFieldNames[0] : ''
);
const [continuousModeDelay, setContinuousModeDelay] = useState(defaults.continuousModeDelay);
const isContinuousModeDelayValid = isContinuousModeDelay(continuousModeDelay);
// Retention Policy
const isRetentionPolicyAvailable = destIndexAvailableTimeFields.length > 0;
const [isRetentionPolicyEnabled, setRetentionPolicyEnabled] = useState(
defaults.isRetentionPolicyEnabled
);
const [retentionPolicyDateField, setRetentionPolicyDateField] = useState(
isRetentionPolicyAvailable ? defaults.retentionPolicyDateField : ''
);
const [retentionPolicyMaxAge, setRetentionPolicyMaxAge] = useState(
defaults.retentionPolicyMaxAge
);
const retentionPolicyMaxAgeEmpty = retentionPolicyMaxAge === '';
const isRetentionPolicyMaxAgeValid = isRetentionPolicyMaxAge(retentionPolicyMaxAge);
useEffect(() => {
// Reset retention policy settings when the user disables the whole option
if (!isRetentionPolicyEnabled) {
setRetentionPolicyDateField(
isRetentionPolicyAvailable ? destIndexAvailableTimeFields[0] : ''
);
setRetentionPolicyMaxAge('');
}
// When retention policy is first enabled, pick a default option
if (
isRetentionPolicyAvailable &&
isRetentionPolicyEnabled &&
retentionPolicyDateField === ''
) {
// If a time field '@timestamp' exists, prioritize that
const prioritizeTimestamp = destIndexAvailableTimeFields.find((d) => d === '@timestamp');
// else pick the first available option
setRetentionPolicyDateField(prioritizeTimestamp ?? destIndexAvailableTimeFields[0]);
}
}, [isRetentionPolicyEnabled, isRetentionPolicyAvailable, destIndexAvailableTimeFields]);
const transformIdExists = transformIds.some((id) => transformId === id);
const transformIdEmpty = transformId === '';
const transformIdValid = isTransformIdValid(transformId);
const indexNameExists = indexNames.some((name) => destinationIndex === name);
const indexNameEmpty = destinationIndex === '';
const indexNameValid = isValidIndexName(destinationIndex);
const dataViewTitleExists = dataViewTitles?.some((name) => destinationIndex === name) ?? false;
const [transformFrequency, setTransformFrequency] = useState(defaults.transformFrequency);
const isTransformFrequencyValid = isTransformWizardFrequency(transformFrequency);
const [transformSettingsMaxPageSearchSize, setTransformSettingsMaxPageSearchSize] = useState<
number | undefined
>(defaults.transformSettingsMaxPageSearchSize);
const [transformSettingsDocsPerSecond] = useState(defaults.transformSettingsDocsPerSecond);
const transformSettingsMaxPageSearchSizeErrors = transformSettingsPageSearchSizeValidator(
transformSettingsMaxPageSearchSize
);
const isTransformSettingsMaxPageSearchSizeValid =
transformSettingsMaxPageSearchSizeErrors.length === 0;
const [transformSettingsNumFailureRetries, setTransformSettingsNumFailureRetries] = useState<
string | number | undefined
>(defaults.transformSettingsNumFailureRetries);
const isTransformSettingsNumFailureRetriesValid =
transformSettingsNumFailureRetries === undefined ||
transformSettingsNumFailureRetries === '-' ||
integerRangeMinus1To100Validator(transformSettingsNumFailureRetries).length === 0;
const valid =
!transformIdEmpty &&
transformIdValid &&
!transformIdExists &&
isTransformFrequencyValid &&
isTransformSettingsMaxPageSearchSizeValid &&
!indexNameEmpty &&
indexNameValid &&
(!dataViewTitleExists || !createDataView) &&
(!isContinuousModeAvailable || (isContinuousModeAvailable && isContinuousModeDelayValid)) &&
(!isRetentionPolicyAvailable ||
!isRetentionPolicyEnabled ||
(isRetentionPolicyAvailable &&
isRetentionPolicyEnabled &&
!retentionPolicyMaxAgeEmpty &&
isRetentionPolicyMaxAgeValid));
// expose state to wizard
useEffect(() => {
onChange({
continuousModeDateField,
continuousModeDelay,
createDataView,
isContinuousModeEnabled,
isRetentionPolicyEnabled,
retentionPolicyDateField,
retentionPolicyMaxAge,
transformId,
transformDescription,
transformFrequency,
transformSettingsMaxPageSearchSize,
transformSettingsDocsPerSecond,
transformSettingsNumFailureRetries:
transformSettingsNumFailureRetries === undefined ||
transformSettingsNumFailureRetries === ''
? undefined
: typeof transformSettingsNumFailureRetries === 'number'
? transformSettingsNumFailureRetries
: parseInt(transformSettingsNumFailureRetries, 10),
destinationIndex,
destinationIngestPipeline,
touched: true,
valid,
dataViewTimeField,
_meta: defaults._meta,
});
// custom comparison
/* eslint-disable react-hooks/exhaustive-deps */
}, [
continuousModeDateField,
continuousModeDelay,
createDataView,
isContinuousModeEnabled,
isRetentionPolicyEnabled,
retentionPolicyDateField,
retentionPolicyMaxAge,
transformId,
transformDescription,
transformFrequency,
transformSettingsMaxPageSearchSize,
transformSettingsNumFailureRetries,
destinationIndex,
destinationIngestPipeline,
valid,
dataViewTimeField,
/* eslint-enable react-hooks/exhaustive-deps */
]);
useEffect(() => {
if (destIndexSameAsId === true && !transformIdEmpty && transformIdValid) {
setDestinationIndex(transformId);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [destIndexSameAsId, transformId]);
return (
<div data-test-subj="transformStepDetailsForm">
<EuiForm>
<EuiFormRow
label={i18n.translate('xpack.transform.stepDetailsForm.transformIdLabel', {
defaultMessage: 'Transform ID',
})}
isInvalid={(!transformIdEmpty && !transformIdValid) || transformIdExists}
error={[
...(!transformIdEmpty && !transformIdValid
? [
i18n.translate('xpack.transform.stepDetailsForm.transformIdInvalidError', {
defaultMessage:
'Must contain lowercase alphanumeric characters (a-z and 0-9), hyphens, and underscores only and must start and end with alphanumeric characters.',
}),
]
: []),
...(transformIdExists
? [
i18n.translate('xpack.transform.stepDetailsForm.transformIdExistsError', {
defaultMessage: 'A transform with this ID already exists.',
}),
]
: []),
]}
>
<EuiFieldText
value={transformId}
onChange={(e) => setTransformId(e.target.value)}
aria-label={i18n.translate(
'xpack.transform.stepDetailsForm.transformIdInputAriaLabel',
{
defaultMessage: 'Choose a unique transform ID.',
}
)}
isInvalid={(!transformIdEmpty && !transformIdValid) || transformIdExists}
data-test-subj="transformIdInput"
/>
</EuiFormRow>
<EuiFormRow
label={i18n.translate('xpack.transform.stepDetailsForm.transformDescriptionLabel', {
defaultMessage: 'Transform description',
})}
>
<EuiTextArea
placeholder={i18n.translate(
'xpack.transform.stepDetailsForm.transformDescriptionPlaceholderText',
{ defaultMessage: 'Description (optional)' }
)}
value={transformDescription}
onChange={(e) => setTransformDescription(e.target.value)}
aria-label={i18n.translate(
'xpack.transform.stepDetailsForm.transformDescriptionInputAriaLabel',
{
defaultMessage: 'Choose an optional transform description.',
}
)}
data-test-subj="transformDescriptionInput"
/>
</EuiFormRow>
<DestinationIndexForm
createIndexLink={esIndicesCreateIndex}
destinationIndex={destinationIndex}
destinationIndexNameEmpty={indexNameEmpty}
destinationIndexNameExists={indexNameExists}
destinationIndexNameValid={indexNameValid}
destIndexSameAsId={destIndexSameAsId}
fullWidth={false}
indexNameExistsMessage={i18n.translate(
'xpack.transform.stepDetailsForm.destinationIndexHelpText',
{
defaultMessage:
'An index with this name already exists. Be aware that running this transform will modify this destination index.',
}
)}
isJobCreated={transformIdExists}
onDestinationIndexChange={setDestinationIndex}
setDestIndexSameAsId={setDestIndexSameAsId}
switchLabel={i18n.translate(
'xpack.transform.stepDetailsForm.destinationIndexFormSwitchLabel',
{
defaultMessage: 'Use transform ID as destination index name',
}
)}
/>
{ingestPipelineNames.length > 0 && (
<EuiFormRow
label={i18n.translate(
'xpack.transform.stepDetailsForm.destinationIngestPipelineLabel',
{