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] Transforms: Improves transform list reloading behavior. #164296

Merged

Conversation

walterra
Copy link
Contributor

@walterra walterra commented Aug 21, 2023

Summary

Fixes #164303 (Fix transforms in serverless projects).
Fixes #163145 (Improve transformlist reloading behavior).
Part of #153288 (Migrate snapshot tests using enzyme to use @testing-library/react).

Before:

transform-list-error-no-refresh-0001

After:

transform-list-error-refresh-0001

  • If the transform list fails to load, it does no longer show a non-refreshable full page error. Instead the error is shown in an inline callout and the refresh button is still present.
  • AuthorizationProvider is gone and has been replaced by a custom hook useTransformCapabilities. All client side code no longer relies on privileges being present but makes use of capabilities (like canGetTransform etc.). The custom route to fetch privileges and capabilities is also gone, instead capabilities are retrieved from Kibana's own application.capabilities.transform which we register server side.
  • Refactors all remote data fetching to use react-query. This gets rid of the custom code to refresh the transform list using observables, instead all CRUD actions now make use of react-query's useMutation and trigger a cache invalidation of the transform list data to initiate a refetch. The useApi hook is gone, instead we now have specific hooks for data fetching that wrap useQuery (useGetTransform, useGetTransformStats etc.) and the existing hooks for actions have been refactored to use useMutation (useStartTransforms, useStopTransforms etc.).
  • Toasts for "success" messages have been removed.
  • All tests that made use of toMatchSnapshot have been refactored away from enzyme to react-testing-lib and no longer rely on snapshots, instead we make basic assertions on the rendered components.

Checklist

@walterra walterra self-assigned this Aug 21, 2023
@walterra walterra force-pushed the ml-transform-fix-transform-list-reload branch from f8efbfb to 270b8a2 Compare August 22, 2023 15:01
@kibana-ci
Copy link
Collaborator

💛 Build succeeded, but was flaky

Failed CI Steps

Test Failures

  • [job] [logs] FTR Configs #32 / machine learning basic license - permissions for user with full ML access (ft_ml_poweruser) "after all" hook for "should not allow access to the Stack Management ML page"

Metrics [docs]

Module Count

Fewer modules leads to a faster build time

id before after diff
transform 365 371 +6

Async chunks

Total size of all lazy-loaded chunks that will be downloaded as the user navigates the app

id before after diff
transform 404.7KB 401.5KB -3.2KB

Page load bundle

Size of the bundles that are downloaded on every page load. Target size is below 100kb

id before after diff
transform 17.8KB 18.4KB +690.0B
Unknown metric groups

ESLint disabled in files

id before after diff
transform 3 4 +1

ESLint disabled line counts

id before after diff
transform 31 29 -2

Total ESLint disabled count

id before after diff
transform 34 33 -1

History

  • 💔 Build #152578 failed 3adfd4aacaf0f5fdbd1d7ab423536f37915faa06
  • 💔 Build #152562 failed c1dbc1e646aaba2c084b2587ab67956b6cb46698
  • 💛 Build #152473 was flaky 9272144b1a76a95d1ecd8feae32d93cdcca0a247
  • 💛 Build #152407 was flaky 270b8a214670ab2469d4abc1414dc0a7bc60d94b
  • 💔 Build #152341 failed f8efbfb03a21fc2c074777b4e80b3d8b444c9cc7

To update your PR or re-run it, just comment with:
@elasticmachine merge upstream

cc @walterra

@walterra walterra force-pushed the ml-transform-fix-transform-list-reload branch 2 times, most recently from 8022e8f to 8f76e78 Compare August 24, 2023 09:08
Comment on lines 34 to 36
<EuiFlexGroup justifyContent="spaceAround">
<EuiFlexItem grow={false}>
<EuiPageContent verticalPosition="center" horizontalPosition="center" color="danger">
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you can use EuiPageTemplate.EmptyPrompt instead

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, must have missed it when I merged in your PR that fixed those, updated in 9b02239.

<EuiButtonEmpty onClick={openModal}>
{!inline && (
<>
<pre>{previewText}</pre>{' '}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
<pre>{previewText}</pre>{' '}
<pre>{previewText}</pre>

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated in a47947c.

const { canDeleteIndex: userCanDeleteIndex } = useTransformCapabilities();

const userCanDeleteDataView =
(capabilities.savedObjectsManagement && capabilities.savedObjectsManagement.delete === true) ||
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
(capabilities.savedObjectsManagement && capabilities.savedObjectsManagement.delete === true) ||
(capabilities.savedObjectsManagement?.delete === true) ||

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated in 4efc4bd.


const userCanDeleteDataView =
(capabilities.savedObjectsManagement && capabilities.savedObjectsManagement.delete === true) ||
(capabilities.indexPatterns && capabilities.indexPatterns.save === true);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
(capabilities.indexPatterns && capabilities.indexPatterns.save === true);
capabilities.indexPatterns?.save === true;

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated in 4efc4bd.


return useQuery<string[], IHttpFetchError>(
[TRANSFORM_REACT_QUERY_KEYS.GET_DATA_VIEW_TITLES],
() => data.dataViews.getTitles()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
() => data.dataViews.getTitles()
data.dataViews.getTitles

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would give a TS error because the useQuery callback would pass on incompatible arguments.

Comment on lines 109 to 130
useEffect(() => {
if (dataViewFieldsIsLoading && !dataViewFieldsIsError) {
setErrorMessage('');
setStatus(INDEX_STATUS.LOADING);
} else if (dataViewFieldsError !== null) {
setErrorMessage(getErrorMessage(dataViewFieldsError));
setStatus(INDEX_STATUS.ERROR);
} else if (
!dataViewFieldsIsLoading &&
!dataViewFieldsIsError &&
dataViewFieldsData !== undefined
) {
const isCrossClusterSearch = indexPattern.includes(':');
const isMissingFields = dataViewFieldsData.hits.hits.every(
(d) => typeof d.fields === 'undefined'
);

if (!isEsSearchResponse(resp)) {
setErrorMessage(getErrorMessage(resp));
setStatus(INDEX_STATUS.ERROR);
return;
}
const docs = resp.hits.hits.map((d) => getProcessedFields(d.fields ?? {}));
isMissingFields = resp.hits.hits.every((d) => typeof d.fields === 'undefined');
setCcsWarning(isCrossClusterSearch && isMissingFields);
setStatus(INDEX_STATUS.LOADED);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [dataViewFieldsData, dataViewFieldsError, dataViewFieldsIsError, dataViewFieldsIsLoading]);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The entire effect looks very complex. Essentially it derives error message and status.
Can we get rid of the state and use memo instead? e.g.

const errorMessage = useMemo(() => {...}, [dataViewFieldsIsLoading, dataViewFieldsIsError]);

);

useEffect(() => {
if (dataGridDataIsLoading && !dataGridDataIsError) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same as above

isLoading,
} = useGetTransformsPreview(previewRequest, validationStatus.isValid);

useEffect(() => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I reckon we should avoid such massive effects. It seems like it can be broken down in independent variables


const transformConfigs = await api.getTransform(transformId);
if (isHttpFetchError(transformConfigs)) {
useEffect(() => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same about this effect

@walterra
Copy link
Contributor Author

@darnautov I agree those useEffects are quite complex. The problem is the transform plugin itself doesn't own the callbacks like setErrorMessage/setStatus etc., they are retrieved from the ml-data-grid package which is shared with the ml plugin. The original complexity comes from that data grid component being shared from the ml plugin directly in times when packages were not available. I tried to avoid touching that data grid package in this PR because it would have made refactoring the ml plugin necessary too, so instead I opted for satisfying it's current API. It's definitely something we should try to simplify in follow ups.

@walterra walterra enabled auto-merge (squash) September 1, 2023 18:31
@kibana-ci
Copy link
Collaborator

kibana-ci commented Sep 1, 2023

💔 Build Failed

Failed CI Steps

Metrics [docs]

Module Count

Fewer modules leads to a faster build time

id before after diff
transform 379 383 +4

Async chunks

Total size of all lazy-loaded chunks that will be downloaded as the user navigates the app

id before after diff
transform 405.8KB 396.5KB -9.3KB

Page load bundle

Size of the bundles that are downloaded on every page load. Target size is below 100kb

id before after diff
transform 17.8KB 18.0KB +193.0B
Unknown metric groups

ESLint disabled in files

id before after diff
transform 3 4 +1

References to deprecated APIs

id before after diff
transform 62 33 -29

Total ESLint disabled count

id before after diff
transform 34 35 +1

History

To update your PR or re-run it, just comment with:
@elasticmachine merge upstream

cc @walterra

@walterra walterra merged commit 0b705eb into elastic:main Sep 1, 2023
@kibanamachine kibanamachine added the backport:skip This commit does not require backporting label Sep 1, 2023
sphilipse pushed a commit to sphilipse/kibana that referenced this pull request Sep 4, 2023
…164296)

## Summary

- If the transform list fails to load, it does no longer show a
non-refreshable full page error. Instead the error is shown in an inline
callout and the refresh button is still present.
- `AuthorizationProvider` is gone and has been replaced by a custom
hook `useTransformCapabilities`. All client side code no longer relies
on `privileges` being present but makes use of `capabilities` (like
`canGetTransform` etc.). The custom route to fetch privileges and
capabilities is also gone, instead capabilities are retrieved from
Kibana's own `application.capabilities.transform` which we register
server side.
- Refactors all remote data fetching to use `react-query`. This gets
rid of the custom code to refresh the transform list using observables,
instead all CRUD actions now make use of `react-query`'s `useMutation`
and trigger a cache invalidation of the transform list data to initiate
a refetch. The `useApi` hook is gone, instead we now have specific hooks
for data fetching that wrap `useQuery` (`useGetTransform`,
`useGetTransformStats` etc.) and the existing hooks for actions have
been refactored to use `useMutation` (`useStartTransforms`,
`useStopTransforms` etc.).
- Toasts for "success" messages have been removed.
- All tests that made use of `toMatchSnapshot` have been refactored
away from `enzyme` to `react-testing-lib` and no longer rely on
snapshots, instead we make basic assertions on the rendered components.

### Checklist

- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios
- [x] This was checked for breaking API changes and was [labeled
appropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)
@walterra walterra deleted the ml-transform-fix-transform-list-reload branch September 18, 2023 08:04
@szabosteve szabosteve changed the title [ML] Transforms: Improve transform list reloading behavior. [ML] Transforms: Improves transform list reloading behavior. Oct 12, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backport:skip This commit does not require backporting bug Fixes for quality problems that affect the customer experience Feature:Transforms ML transforms :ml release_note:enhancement v8.11.0
Projects
None yet
7 participants