Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ML] Transform: Use redux toolkit for state management for edit transform flyout #173861

Merged
merged 38 commits into from
Jan 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
83816e8
use zustand for state management
walterra Aug 9, 2023
cb1e6dd
fix package.json
walterra Aug 9, 2023
4f9cc86
remove commented code
walterra Aug 9, 2023
6d8ce6d
get rid of reducer and actions boilerplate
walterra Aug 10, 2023
ff8f290
flatten state structure
walterra Aug 10, 2023
469d534
improve action handling
walterra Aug 10, 2023
90d6a42
refactor validators
walterra Aug 10, 2023
03965df
refactor parsers
walterra Aug 10, 2023
5d97178
fix types and state management.
walterra Dec 20, 2023
6618341
fix preview request body
walterra Dec 20, 2023
50f0f4f
use redux toolkit for edit transform flyout state management
walterra Dec 21, 2023
063b5fa
remove zustand from package.json
walterra Dec 21, 2023
4328ceb
refactor to move createSlice to top level of file
walterra Dec 21, 2023
759595b
fix state to be redux compliant
walterra Dec 21, 2023
6b66b51
fix state initialization
walterra Dec 21, 2023
e9c080e
fix dependencies
walterra Dec 21, 2023
d68e43c
fix jest test
walterra Dec 22, 2023
d8c69cf
add comment to custom hook
walterra Dec 22, 2023
753eee5
consolidate code into helper functions for form field and section update
walterra Dec 22, 2023
ee3bda4
cleanup
walterra Dec 22, 2023
66c5e8d
selectors
walterra Jan 3, 2024
eb1506a
renaming
walterra Jan 3, 2024
6e9b88a
renaming
walterra Jan 3, 2024
1b606c5
remove unnecessary state checks
walterra Jan 3, 2024
41b2b9f
break out reducer actions from createSlice
walterra Jan 3, 2024
c8a6c6e
fix types
walterra Jan 3, 2024
3ccbdde
minor cleanup
walterra Jan 3, 2024
344dc4f
minor refactor
walterra Jan 3, 2024
d09f769
rename use_edit_transform_flyout to edit_transform_flyout_state
walterra Jan 4, 2024
1989f7e
update comment
walterra Jan 4, 2024
af818e6
split up state management
walterra Jan 4, 2024
de96784
Merge branch 'main' into ml-transform-edit-redux
walterra Jan 16, 2024
ca3467b
improve selector reuse
walterra Jan 16, 2024
0af53d8
Merge branch 'main' into ml-transform-edit-redux
walterra Jan 17, 2024
b8cc881
add type to imports
walterra Jan 17, 2024
358341c
fix comment typo
walterra Jan 17, 2024
788a4e4
use isDefined
walterra Jan 17, 2024
31d5d15
use useMount
walterra Jan 17, 2024
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 @@ -8,9 +8,6 @@
import { frequencyValidator } from './frequency_validator';

describe('Transform: frequencyValidator()', () => {
// frequencyValidator() returns an array of error messages so
// an array with a length of 0 means a successful validation.

it('should fail when the input is not an integer and valid time unit.', () => {
expect(frequencyValidator('0')).toEqual(['The frequency value is not valid.']);
expect(frequencyValidator('0.1s')).toEqual(['The frequency value is not valid.']);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* 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 React, { type FC } from 'react';

import { EuiCallOut, EuiSpacer } from '@elastic/eui';

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

import { useApiErrorMessage } from '../state_management/selectors/api_error_message';

export const EditTransformApiErrorCallout: FC = () => {
const apiErrorMessage = useApiErrorMessage();

if (apiErrorMessage === undefined) return null;

return (
<>
<EuiSpacer size="m" />
<EuiCallOut
title={i18n.translate('xpack.transform.transformList.editTransformGenericErrorMessage', {
defaultMessage: 'An error occurred calling the API endpoint to update transforms.',
})}
color="danger"
iconType="warning"
>
<p>{apiErrorMessage}</p>
</EuiCallOut>
</>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,16 @@ import {
EuiTitle,
} from '@elastic/eui';

import { isManagedTransform } from '../../../../common/managed_transforms_utils';
import { isManagedTransform } from '../../../common/managed_transforms_utils';

import { ManagedTransformsWarningCallout } from '../managed_transforms_callout/managed_transforms_callout';
import type { EditAction } from '../action_edit';
import { ManagedTransformsWarningCallout } from '../../transform_management/components/managed_transforms_callout/managed_transforms_callout';
import type { EditAction } from '../../transform_management/components/action_edit';

import { EditTransformFlyoutProvider } from '../state_management/edit_transform_flyout_state';

import { EditTransformApiErrorCallout } from './edit_transform_api_error_callout';
import { EditTransformFlyoutCallout } from './edit_transform_flyout_callout';
import { EditTransformFlyoutForm } from './edit_transform_flyout_form';
import { EditTransformFlyoutProvider } from './use_edit_transform_flyout';
import { EditTransformUpdateButton } from './edit_transform_update_button';

export const EditTransformFlyout: FC<EditAction> = ({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import {
EuiTextColor,
} from '@elastic/eui';

import { useDocumentationLinks } from '../../../../hooks/use_documentation_links';
import { useDocumentationLinks } from '../../../hooks/use_documentation_links';
export const EditTransformFlyoutCallout: FC = () => {
const { esTransformUpdate } = useDocumentationLinks();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,13 @@ import { EuiFormRow, EuiTextArea } from '@elastic/eui';

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

import {
useEditTransformFlyout,
type EditTransformHookTextInputSelectors,
} from './use_edit_transform_flyout';
import { capitalizeFirstLetter } from './capitalize_first_letter';
import { useEditTransformFlyoutActions } from '../state_management/edit_transform_flyout_state';
import { useFormField } from '../state_management/selectors/form_field';
import type { FormFields } from '../state_management/form_field';
import { capitalizeFirstLetter } from '../utils/capitalize_first_letter';

interface EditTransformFlyoutFormTextInputProps {
field: EditTransformHookTextInputSelectors;
field: FormFields;
label: string;
helpText?: string;
placeHolder?: boolean;
Expand All @@ -30,8 +29,8 @@ export const EditTransformFlyoutFormTextArea: FC<EditTransformFlyoutFormTextInpu
helpText,
placeHolder = false,
}) => {
const { defaultValue, errorMessages, value } = useEditTransformFlyout(field);
const { formField } = useEditTransformFlyout('actions');
const { defaultValue, errorMessages, value } = useFormField(field);
const { setFormField } = useEditTransformFlyoutActions();
const upperCaseField = capitalizeFirstLetter(field);

return (
Expand All @@ -53,7 +52,7 @@ export const EditTransformFlyoutFormTextArea: FC<EditTransformFlyoutFormTextInpu
}
isInvalid={errorMessages.length > 0}
value={value}
onChange={(e) => formField({ field, value: e.target.value })}
onChange={(e) => setFormField({ field, value: e.target.value })}
aria-label={label}
/>
</EuiFormRow>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,13 @@ import { EuiFieldText, EuiFormRow } from '@elastic/eui';

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

import {
useEditTransformFlyout,
type EditTransformHookTextInputSelectors,
} from './use_edit_transform_flyout';
import { capitalizeFirstLetter } from './capitalize_first_letter';
import { useEditTransformFlyoutActions } from '../state_management/edit_transform_flyout_state';
import { useFormField } from '../state_management/selectors/form_field';
import type { FormFields } from '../state_management/form_field';
import { capitalizeFirstLetter } from '../utils/capitalize_first_letter';

interface EditTransformFlyoutFormTextInputProps {
field: EditTransformHookTextInputSelectors;
field: FormFields;
label: string;
helpText?: string;
placeHolder?: boolean;
Expand All @@ -30,8 +29,8 @@ export const EditTransformFlyoutFormTextInput: FC<EditTransformFlyoutFormTextInp
helpText,
placeHolder = false,
}) => {
const { defaultValue, errorMessages, value } = useEditTransformFlyout(field);
const { formField } = useEditTransformFlyout('actions');
const { defaultValue, errorMessages, value } = useFormField(field);
const { setFormField } = useEditTransformFlyoutActions();
const upperCaseField = capitalizeFirstLetter(field);

return (
Expand All @@ -53,7 +52,7 @@ export const EditTransformFlyoutFormTextInput: FC<EditTransformFlyoutFormTextInp
}
isInvalid={errorMessages.length > 0}
value={value}
onChange={(e) => formField({ field, value: e.target.value })}
onChange={(e) => setFormField({ field, value: e.target.value })}
aria-label={label}
/>
</EuiFormRow>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,12 @@ import { useEuiTheme, EuiComboBox, EuiFormRow, EuiSkeletonRectangle } from '@ela

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

import { useGetEsIngestPipelines } from '../../../../hooks';
import { useGetEsIngestPipelines } from '../../../hooks';

import { useEditTransformFlyoutActions } from '../state_management/edit_transform_flyout_state';
import { useFormField } from '../state_management/selectors/form_field';

import { EditTransformFlyoutFormTextInput } from './edit_transform_flyout_form_text_input';
import { useEditTransformFlyout } from './use_edit_transform_flyout';

const ingestPipelineLabel = i18n.translate(
'xpack.transform.transformList.editFlyoutFormDestinationIngestPipelineLabel',
Expand All @@ -25,8 +27,8 @@ const ingestPipelineLabel = i18n.translate(

export const EditTransformIngestPipeline: FC = () => {
const { euiTheme } = useEuiTheme();
const { errorMessages, value } = useEditTransformFlyout('destinationIngestPipeline');
const { formField } = useEditTransformFlyout('actions');
const { errorMessages, value } = useFormField('destinationIngestPipeline');
const { setFormField } = useEditTransformFlyoutActions();

const { data: esIngestPipelinesData, isLoading } = useGetEsIngestPipelines();
const ingestPipelineNames = esIngestPipelinesData?.map(({ name }) => name) ?? [];
Expand Down Expand Up @@ -66,7 +68,7 @@ export const EditTransformIngestPipeline: FC = () => {
options={ingestPipelineNames.map((label: string) => ({ label }))}
selectedOptions={[{ label: value }]}
onChange={(o) =>
formField({ field: 'destinationIngestPipeline', value: o[0]?.label ?? '' })
setFormField({ field: 'destinationIngestPipeline', value: o[0]?.label ?? '' })
}
/>
</EuiSkeletonRectangle>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,37 +7,45 @@

import React, { useEffect, useMemo, type FC } from 'react';

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

import { EuiFormRow, EuiSelect, EuiSpacer, EuiSwitch } from '@elastic/eui';

import { i18n } from '@kbn/i18n';
import { toMountPoint } from '@kbn/react-kibana-mount';
import { useAppDependencies, useToastNotifications } from '../../../../app_dependencies';
import { ToastNotificationText } from '../../../../components';
import { isLatestTransform, isPivotTransform } from '../../../../../../common/types/transform';
import { useGetTransformsPreview } from '../../../../hooks';

import type { PostTransformsPreviewRequestSchema } from '../../../../../common/api_schemas/transforms';
import { isLatestTransform, isPivotTransform } from '../../../../../common/types/transform';
import { getErrorMessage } from '../../../../../common/utils/errors';

import { useAppDependencies, useToastNotifications } from '../../../app_dependencies';
import { useGetTransformsPreview } from '../../../hooks';
import { ToastNotificationText } from '../../../components';

import {
useEditTransformFlyoutActions,
useEditTransformFlyoutContext,
} from '../state_management/edit_transform_flyout_state';
import { useFormSections } from '../state_management/selectors/form_sections';
import { useRetentionPolicyField } from '../state_management/selectors/retention_policy_field';

import { EditTransformFlyoutFormTextInput } from './edit_transform_flyout_form_text_input';
import { useEditTransformFlyout } from './use_edit_transform_flyout';
import { getErrorMessage } from '../../../../../../common/utils/errors';

export const EditTransformRetentionPolicy: FC = () => {
const { i18n: i18nStart, theme } = useAppDependencies();

const toastNotifications = useToastNotifications();

const dataViewId = useEditTransformFlyout('dataViewId');
const formSections = useEditTransformFlyout('stateFormSection');
const retentionPolicyField = useEditTransformFlyout('retentionPolicyField');
const { formField, formSection } = useEditTransformFlyout('actions');
const requestConfig = useEditTransformFlyout('config');
const { config, dataViewId } = useEditTransformFlyoutContext();
const formSections = useFormSections();
const retentionPolicyField = useRetentionPolicyField();
const { setFormField, setFormSection } = useEditTransformFlyoutActions();

const previewRequest = useMemo(() => {
const previewRequest: PostTransformsPreviewRequestSchema = useMemo(() => {
return {
source: requestConfig.source,
...(isPivotTransform(requestConfig) ? { pivot: requestConfig.pivot } : {}),
...(isLatestTransform(requestConfig) ? { latest: requestConfig.latest } : {}),
source: config.source,
...(isPivotTransform(config) ? { pivot: config.pivot } : {}),
...(isLatestTransform(config) ? { latest: config.latest } : {}),
};
}, [requestConfig]);
}, [config]);

const { error: transformsPreviewError, data: transformPreview } =
useGetTransformsPreview(previewRequest);
Expand Down Expand Up @@ -98,7 +106,7 @@ export const EditTransformRetentionPolicy: FC = () => {
)}
checked={formSections.retentionPolicy.enabled}
onChange={(e) =>
formSection({
setFormSection({
section: 'retentionPolicy',
enabled: e.target.checked,
})
Expand Down Expand Up @@ -142,7 +150,7 @@ export const EditTransformRetentionPolicy: FC = () => {
options={retentionDateFieldOptions}
value={retentionPolicyField.value}
onChange={(e) =>
formField({ field: 'retentionPolicyField', value: e.target.value })
setFormField({ field: 'retentionPolicyField', value: e.target.value })
}
hasNoInitialSelection={
!retentionDateFieldOptions
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,29 +11,38 @@ import { EuiButton } from '@elastic/eui';

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

import { getErrorMessage } from '../../../../../../common/utils/errors';
import { getErrorMessage } from '../../../../../common/utils/errors';

import { useUpdateTransform } from '../../../../hooks';
import { useUpdateTransform } from '../../../hooks';

import { useEditTransformFlyout } from './use_edit_transform_flyout';
import {
useEditTransformFlyoutActions,
useEditTransformFlyoutContext,
} from '../state_management/edit_transform_flyout_state';
import { useIsFormTouched } from '../state_management/selectors/is_form_touched';
import { useIsFormValid } from '../state_management/selectors/is_form_valid';
import { useUpdatedTransformConfig } from '../state_management/selectors/updated_transform_config';

interface EditTransformUpdateButtonProps {
closeFlyout: () => void;
}

export const EditTransformUpdateButton: FC<EditTransformUpdateButtonProps> = ({ closeFlyout }) => {
const requestConfig = useEditTransformFlyout('requestConfig');
const isUpdateButtonDisabled = useEditTransformFlyout('isUpdateButtonDisabled');
const config = useEditTransformFlyout('config');
const { apiError } = useEditTransformFlyout('actions');
const { config } = useEditTransformFlyoutContext();
const isFormValid = useIsFormValid();
const isFormTouched = useIsFormTouched();
const requestConfig = useUpdatedTransformConfig();
const isUpdateButtonDisabled = !isFormValid || !isFormTouched;

const { setApiError } = useEditTransformFlyoutActions();

const updateTransfrom = useUpdateTransform(config.id, requestConfig);

async function submitFormHandler() {
apiError(undefined);
setApiError(undefined);

updateTransfrom(undefined, {
onError: (error) => apiError(getErrorMessage(error)),
onError: (error) => setApiError(getErrorMessage(error)),
onSuccess: () => closeFlyout(),
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@
* 2.0.
*/

export { EditTransformFlyout } from './edit_transform_flyout';
export { EditTransformFlyout } from './components/edit_transform_flyout';
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* 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 { TransformPivotConfig } from '../../../../../../common/types/transform';

export const getTransformConfigMock = (): TransformPivotConfig => ({
id: 'the-transform-id',
source: {
index: ['the-transform-source-index'],
query: {
match_all: {},
},
},
dest: {
index: 'the-transform-destination-index',
},
pivot: {
group_by: {
airline: {
terms: {
field: 'airline',
},
},
},
aggregations: {
'responsetime.avg': {
avg: {
field: 'responsetime',
},
},
},
},
description: 'the-description',
});
Loading