From 3919a8bb049b185912db52e5388ecac75e4c8e28 Mon Sep 17 00:00:00 2001 From: Walter Rafelsberger Date: Mon, 21 Aug 2023 14:33:45 +0200 Subject: [PATCH 01/53] migrate transform list to use react-query --- .../common/api_schemas/transforms.ts | 2 +- x-pack/plugins/transform/common/constants.ts | 5 + .../transform/public/app/common/index.ts | 7 +- .../transform/public/app/common/transform.ts | 68 +------ .../public/app/hooks/use_delete_transform.tsx | 5 +- .../public/app/hooks/use_get_transforms.ts | 139 ++++++------- .../app/hooks/use_reauthorize_transform.tsx | 5 +- .../public/app/hooks/use_reset_transform.tsx | 5 +- .../app/hooks/use_schedule_now_transform.tsx | 5 +- .../public/app/hooks/use_start_transform.tsx | 5 +- .../public/app/hooks/use_stop_transform.tsx | 5 +- .../components/authorization_provider.tsx | 3 +- .../edit_transform_update_button.tsx | 5 +- .../transform_list.test.tsx.snap | 96 +++++---- .../expanded_row_messages_pane.tsx | 112 +++++------ .../transform_list/transform_list.test.tsx | 18 +- .../transform_list/transform_list.tsx | 46 ++++- .../transform_list/use_actions.test.tsx | 11 +- .../transform_list/use_columns.test.tsx | 10 +- .../transform_list/use_refresh_interval.ts | 28 --- .../transform_management_section.tsx | 183 +++++++----------- 21 files changed, 339 insertions(+), 424 deletions(-) delete mode 100644 x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/use_refresh_interval.ts diff --git a/x-pack/plugins/transform/common/api_schemas/transforms.ts b/x-pack/plugins/transform/common/api_schemas/transforms.ts index 5b300a613be94..65e0433a81264 100644 --- a/x-pack/plugins/transform/common/api_schemas/transforms.ts +++ b/x-pack/plugins/transform/common/api_schemas/transforms.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { schema, TypeOf } from '@kbn/config-schema'; +import { schema, type TypeOf } from '@kbn/config-schema'; import type { ES_FIELD_TYPES } from '@kbn/field-types'; diff --git a/x-pack/plugins/transform/common/constants.ts b/x-pack/plugins/transform/common/constants.ts index 633f0dc7849ac..1076f1d6530d6 100644 --- a/x-pack/plugins/transform/common/constants.ts +++ b/x-pack/plugins/transform/common/constants.ts @@ -32,6 +32,11 @@ const EXTERNAL_API_BASE_PATH = '/api/transform/'; export const addInternalBasePath = (uri: string): string => `${INTERNAL_API_BASE_PATH}${uri}`; export const addExternalBasePath = (uri: string): string => `${EXTERNAL_API_BASE_PATH}${uri}`; +export const TRANSFORM_REACT_QUERY_KEYS = { + PRIVILEGES: 'transform.privileges', + TRANSFORMS_LIST: 'transform.transforms_list', +} as const; + // In order to create a transform, the API requires the following privileges: // - transform_admin (builtin) // - cluster privileges: manage_transform diff --git a/x-pack/plugins/transform/public/app/common/index.ts b/x-pack/plugins/transform/public/app/common/index.ts index c7656974ec569..42701de487adb 100644 --- a/x-pack/plugins/transform/public/app/common/index.ts +++ b/x-pack/plugins/transform/public/app/common/index.ts @@ -19,12 +19,7 @@ export { toggleSelectedField, } from './fields'; export type { DropDownLabel, DropDownOption, Label } from './dropdown'; -export { - isTransformIdValid, - refreshTransformList$, - useRefreshTransformList, - REFRESH_TRANSFORM_LIST_STATE, -} from './transform'; +export { isTransformIdValid, useRefreshTransformList } from './transform'; export type { TransformListAction, TransformListRow } from './transform_list'; export { TRANSFORM_LIST_COLUMN } from './transform_list'; export { getTransformProgress, isCompletedBatchTransform } from './transform_stats'; diff --git a/x-pack/plugins/transform/public/app/common/transform.ts b/x-pack/plugins/transform/public/app/common/transform.ts index 35ead5691a866..34bbb82805c50 100644 --- a/x-pack/plugins/transform/public/app/common/transform.ts +++ b/x-pack/plugins/transform/public/app/common/transform.ts @@ -5,12 +5,12 @@ * 2.0. */ -import { useEffect } from 'react'; -import { BehaviorSubject } from 'rxjs'; -import { filter, distinctUntilChanged } from 'rxjs/operators'; -import { Subscription } from 'rxjs'; import { cloneDeep } from 'lodash'; +import { useCallback } from 'react'; +import { useQueryClient } from '@tanstack/react-query'; + import type { TransformConfigUnion, TransformId } from '../../../common/types/transform'; +import { TRANSFORM_REACT_QUERY_KEYS } from '../../../common/constants'; // Via https://github.com/elastic/elasticsearch/blob/master/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/transform/utils/TransformStrings.java#L24 // Matches a string that contains lowercase characters, digits, hyphens, underscores or dots. @@ -23,63 +23,13 @@ export function isTransformIdValid(transformId: TransformId) { export const TRANSFORM_ERROR_TYPE = { DANGLING_TASK: 'dangling_task', } as const; -export enum REFRESH_TRANSFORM_LIST_STATE { - ERROR = 'error', - IDLE = 'idle', - LOADING = 'loading', - REFRESH = 'refresh', -} -export const refreshTransformList$ = new BehaviorSubject( - REFRESH_TRANSFORM_LIST_STATE.IDLE -); - -export const useRefreshTransformList = ( - callback: { - isLoading?(d: boolean): void; - onRefresh?(): void; - } = {} -) => { - useEffect(() => { - const distinct$ = refreshTransformList$.pipe(distinctUntilChanged()); - - const subscriptions: Subscription[] = []; - - if (typeof callback.onRefresh === 'function') { - // initial call to refresh - callback.onRefresh(); - - subscriptions.push( - distinct$ - .pipe(filter((state) => state === REFRESH_TRANSFORM_LIST_STATE.REFRESH)) - .subscribe(() => typeof callback.onRefresh === 'function' && callback.onRefresh()) - ); - } - - if (typeof callback.isLoading === 'function') { - subscriptions.push( - distinct$.subscribe( - (state) => - typeof callback.isLoading === 'function' && - callback.isLoading(state === REFRESH_TRANSFORM_LIST_STATE.LOADING) - ) - ); - } - return () => { - subscriptions.map((sub) => sub.unsubscribe()); - }; - // The effect should only be called once. - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); +export const useRefreshTransformList = () => { + const queryClient = useQueryClient(); - return { - refresh: () => { - // A refresh is followed immediately by setting the state to loading - // to trigger data fetching and loading indicators in one go. - refreshTransformList$.next(REFRESH_TRANSFORM_LIST_STATE.REFRESH); - refreshTransformList$.next(REFRESH_TRANSFORM_LIST_STATE.LOADING); - }, - }; + return useCallback(() => { + queryClient.invalidateQueries([TRANSFORM_REACT_QUERY_KEYS.TRANSFORMS_LIST]); + }, [queryClient]); }; export const overrideTransformForCloning = (originalConfig: TransformConfigUnion) => { diff --git a/x-pack/plugins/transform/public/app/hooks/use_delete_transform.tsx b/x-pack/plugins/transform/public/app/hooks/use_delete_transform.tsx index 25318fc9e2903..d4e078d285ca9 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_delete_transform.tsx +++ b/x-pack/plugins/transform/public/app/hooks/use_delete_transform.tsx @@ -16,7 +16,7 @@ import type { import { isDeleteTransformsResponseSchema } from '../../../common/api_schemas/type_guards'; import { getErrorMessage } from '../../../common/utils/errors'; import { useAppDependencies, useToastNotifications } from '../app_dependencies'; -import { REFRESH_TRANSFORM_LIST_STATE, refreshTransformList$, TransformListRow } from '../common'; +import { useRefreshTransformList, type TransformListRow } from '../common'; import { ToastNotificationText } from '../components'; import { useApi } from './use_api'; import { indexService } from '../services/es_index_service'; @@ -120,6 +120,7 @@ type SuccessCountField = keyof Omit; export const useDeleteTransforms = () => { const { overlays, theme } = useAppDependencies(); + const refreshTransformList = useRefreshTransformList(); const toastNotifications = useToastNotifications(); const api = useApi(); @@ -293,6 +294,6 @@ export const useDeleteTransforms = () => { } } - refreshTransformList$.next(REFRESH_TRANSFORM_LIST_STATE.REFRESH); + refreshTransformList(); }; }; diff --git a/x-pack/plugins/transform/public/app/hooks/use_get_transforms.ts b/x-pack/plugins/transform/public/app/hooks/use_get_transforms.ts index 55e3bc40360cf..e31f30fd790f1 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_get_transforms.ts +++ b/x-pack/plugins/transform/public/app/hooks/use_get_transforms.ts @@ -5,75 +5,70 @@ * 2.0. */ +import { useQuery } from '@tanstack/react-query'; + import type { IHttpFetchError } from '@kbn/core-http-browser'; import { isDefined } from '@kbn/ml-is-defined'; +import { isGetTransformsStatsResponseSchema } from '../../../common/api_schemas/type_guards'; +import type { + GetTransformNodesResponseSchema, + GetTransformsResponseSchema, +} from '../../../common/api_schemas/transforms'; import { - isGetTransformNodesResponseSchema, - isGetTransformsResponseSchema, - isGetTransformsStatsResponseSchema, -} from '../../../common/api_schemas/type_guards'; -import { TRANSFORM_MODE } from '../../../common/constants'; + addInternalBasePath, + DEFAULT_REFRESH_INTERVAL_MS, + TRANSFORM_REACT_QUERY_KEYS, + TRANSFORM_MODE, +} from '../../../common/constants'; import { isTransformStats } from '../../../common/types/transform_stats'; -import { - type TransformListRow, - refreshTransformList$, - REFRESH_TRANSFORM_LIST_STATE, -} from '../common'; +import { type TransformListRow } from '../common'; +import { useAppDependencies } from '../app_dependencies'; -import { useApi } from './use_api'; import { TRANSFORM_ERROR_TYPE } from '../common/transform'; export type GetTransforms = (forceRefresh?: boolean) => void; -export const useGetTransforms = ( - setTransforms: React.Dispatch>, - setTransformNodes: React.Dispatch>, - setErrorMessage: React.Dispatch>, - setTransformIdsWithoutConfig: React.Dispatch>, - setIsInitialized: React.Dispatch>, - blockRefresh: boolean -): GetTransforms => { - const api = useApi(); - - let concurrentLoads = 0; - - const getTransforms = async (forceRefresh = false) => { - if (forceRefresh === true || blockRefresh === false) { - refreshTransformList$.next(REFRESH_TRANSFORM_LIST_STATE.LOADING); - concurrentLoads++; - - if (concurrentLoads > 1) { - return; - } - - const fetchOptions = { asSystemRequest: true }; - const transformNodes = await api.getTransformNodes(); - const transformConfigs = await api.getTransforms(fetchOptions); - const transformStats = await api.getTransformsStats(fetchOptions); - - if ( - !isGetTransformsResponseSchema(transformConfigs) || - !isGetTransformsStatsResponseSchema(transformStats) || - !isGetTransformNodesResponseSchema(transformNodes) - ) { - // An error is followed immediately by setting the state to idle. - // This way we're able to treat ERROR as a one-time-event like REFRESH. - refreshTransformList$.next(REFRESH_TRANSFORM_LIST_STATE.ERROR); - refreshTransformList$.next(REFRESH_TRANSFORM_LIST_STATE.IDLE); - setTransformNodes(0); - setTransforms([]); - - setIsInitialized(true); - - if (!isGetTransformsResponseSchema(transformConfigs)) { - setErrorMessage(transformConfigs); - } else if (!isGetTransformsStatsResponseSchema(transformStats)) { - setErrorMessage(transformStats); +interface UseGetTransformsResponse { + tableRows: TransformListRow[]; + transformIdsWithoutConfig?: string[]; + transformNodes: number; +} + +export const useGetTransforms = () => { + const { http } = useAppDependencies(); + + return useQuery( + [TRANSFORM_REACT_QUERY_KEYS.TRANSFORMS_LIST], + async ({ signal }) => { + const update: UseGetTransformsResponse = { + tableRows: [], + transformNodes: 0, + }; + + const transformNodes = await http.get( + addInternalBasePath('transforms/_nodes'), + { + version: '1', + signal, } + ); - return; - } + update.transformNodes = transformNodes.count; + + const transformConfigs = await http.get( + addInternalBasePath('transforms'), + { + version: '1', + asSystemRequest: true, + signal, + } + ); + const transformStats = await http.get(addInternalBasePath(`transforms/_stats`), { + version: '1', + asSystemRequest: true, + signal, + }); // There might be some errors with fetching certain transforms // For example, when task exists and is running but the config is deleted @@ -87,14 +82,11 @@ export const useGetTransforms = ( }) .filter(isDefined); - setTransformIdsWithoutConfig( - danglingTaskIdMatches.length > 0 ? danglingTaskIdMatches : undefined - ); - } else { - setTransformIdsWithoutConfig(undefined); + update.transformIdsWithoutConfig = + danglingTaskIdMatches.length > 0 ? danglingTaskIdMatches : undefined; } - const tableRows = transformConfigs.transforms.reduce((reducedtableRows, config) => { + update.tableRows = transformConfigs.transforms.reduce((reducedtableRows, config) => { const stats = isGetTransformsStatsResponseSchema(transformStats) ? transformStats.transforms.find((d) => config.id === d.id) : undefined; @@ -117,21 +109,10 @@ export const useGetTransforms = ( return reducedtableRows; }, [] as TransformListRow[]); - setTransformNodes(transformNodes.count); - setTransforms(tableRows); - setErrorMessage(undefined); - setIsInitialized(true); - refreshTransformList$.next(REFRESH_TRANSFORM_LIST_STATE.IDLE); - - concurrentLoads--; - - if (concurrentLoads > 0) { - concurrentLoads = 0; - getTransforms(true); - return; - } + return update; + }, + { + refetchInterval: DEFAULT_REFRESH_INTERVAL_MS, } - }; - - return getTransforms; + ); }; diff --git a/x-pack/plugins/transform/public/app/hooks/use_reauthorize_transform.tsx b/x-pack/plugins/transform/public/app/hooks/use_reauthorize_transform.tsx index af6018c35cecc..3b907aa915128 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_reauthorize_transform.tsx +++ b/x-pack/plugins/transform/public/app/hooks/use_reauthorize_transform.tsx @@ -17,13 +17,14 @@ import { isStartTransformsResponseSchema } from '../../../common/api_schemas/typ import { getErrorMessage } from '../../../common/utils/errors'; import { useAppDependencies, useToastNotifications } from '../app_dependencies'; -import { refreshTransformList$, REFRESH_TRANSFORM_LIST_STATE } from '../common'; +import { useRefreshTransformList } from '../common'; import { ToastNotificationText } from '../components'; import { useApi } from './use_api'; export const useReauthorizeTransforms = () => { const { overlays, theme } = useAppDependencies(); + const refreshTransformList = useRefreshTransformList(); const toastNotifications = useToastNotifications(); const api = useApi(); @@ -76,6 +77,6 @@ export const useReauthorizeTransforms = () => { } } - refreshTransformList$.next(REFRESH_TRANSFORM_LIST_STATE.REFRESH); + refreshTransformList(); }; }; diff --git a/x-pack/plugins/transform/public/app/hooks/use_reset_transform.tsx b/x-pack/plugins/transform/public/app/hooks/use_reset_transform.tsx index c33cec3f5b93f..d64301ee37522 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_reset_transform.tsx +++ b/x-pack/plugins/transform/public/app/hooks/use_reset_transform.tsx @@ -15,7 +15,7 @@ import type { import { isResetTransformsResponseSchema } from '../../../common/api_schemas/type_guards'; import { getErrorMessage } from '../../../common/utils/errors'; import { useAppDependencies, useToastNotifications } from '../app_dependencies'; -import { REFRESH_TRANSFORM_LIST_STATE, refreshTransformList$ } from '../common'; +import { useRefreshTransformList } from '../common'; import { ToastNotificationText } from '../components'; import { useApi } from './use_api'; @@ -23,6 +23,7 @@ type SuccessCountField = keyof Omit; export const useResetTransforms = () => { const { overlays, theme } = useAppDependencies(); + const refreshTransformList = useRefreshTransformList(); const toastNotifications = useToastNotifications(); const api = useApi(); @@ -107,6 +108,6 @@ export const useResetTransforms = () => { } } - refreshTransformList$.next(REFRESH_TRANSFORM_LIST_STATE.REFRESH); + refreshTransformList(); }; }; diff --git a/x-pack/plugins/transform/public/app/hooks/use_schedule_now_transform.tsx b/x-pack/plugins/transform/public/app/hooks/use_schedule_now_transform.tsx index 8454580867391..b0a15f1635c44 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_schedule_now_transform.tsx +++ b/x-pack/plugins/transform/public/app/hooks/use_schedule_now_transform.tsx @@ -17,13 +17,14 @@ import { isScheduleNowTransformsResponseSchema } from '../../../common/api_schem import { getErrorMessage } from '../../../common/utils/errors'; import { useAppDependencies, useToastNotifications } from '../app_dependencies'; -import { refreshTransformList$, REFRESH_TRANSFORM_LIST_STATE } from '../common'; +import { useRefreshTransformList } from '../common'; import { ToastNotificationText } from '../components'; import { useApi } from './use_api'; export const useScheduleNowTransforms = () => { const { overlays, theme } = useAppDependencies(); + const refreshTransformList = useRefreshTransformList(); const toastNotifications = useToastNotifications(); const api = useApi(); @@ -79,6 +80,6 @@ export const useScheduleNowTransforms = () => { } } - refreshTransformList$.next(REFRESH_TRANSFORM_LIST_STATE.REFRESH); + refreshTransformList(); }; }; diff --git a/x-pack/plugins/transform/public/app/hooks/use_start_transform.tsx b/x-pack/plugins/transform/public/app/hooks/use_start_transform.tsx index e4d9bdfe431a9..a3bd5b29d5e57 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_start_transform.tsx +++ b/x-pack/plugins/transform/public/app/hooks/use_start_transform.tsx @@ -17,13 +17,14 @@ import { isStartTransformsResponseSchema } from '../../../common/api_schemas/typ import { getErrorMessage } from '../../../common/utils/errors'; import { useAppDependencies, useToastNotifications } from '../app_dependencies'; -import { refreshTransformList$, REFRESH_TRANSFORM_LIST_STATE } from '../common'; +import { useRefreshTransformList } from '../common'; import { ToastNotificationText } from '../components'; import { useApi } from './use_api'; export const useStartTransforms = () => { const { overlays, theme } = useAppDependencies(); + const refreshTransformList = useRefreshTransformList(); const toastNotifications = useToastNotifications(); const api = useApi(); @@ -73,6 +74,6 @@ export const useStartTransforms = () => { } } - refreshTransformList$.next(REFRESH_TRANSFORM_LIST_STATE.REFRESH); + refreshTransformList(); }; }; diff --git a/x-pack/plugins/transform/public/app/hooks/use_stop_transform.tsx b/x-pack/plugins/transform/public/app/hooks/use_stop_transform.tsx index 39d009e471180..d89ee1a0118f1 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_stop_transform.tsx +++ b/x-pack/plugins/transform/public/app/hooks/use_stop_transform.tsx @@ -17,13 +17,14 @@ import { isStopTransformsResponseSchema } from '../../../common/api_schemas/type import { getErrorMessage } from '../../../common/utils/errors'; import { useAppDependencies, useToastNotifications } from '../app_dependencies'; -import { refreshTransformList$, REFRESH_TRANSFORM_LIST_STATE } from '../common'; +import { useRefreshTransformList } from '../common'; import { ToastNotificationText } from '../components'; import { useApi } from './use_api'; export const useStopTransforms = () => { const { overlays, theme } = useAppDependencies(); + const refreshTransformList = useRefreshTransformList(); const toastNotifications = useToastNotifications(); const api = useApi(); @@ -71,6 +72,6 @@ export const useStopTransforms = () => { } } - refreshTransformList$.next(REFRESH_TRANSFORM_LIST_STATE.REFRESH); + refreshTransformList(); }; }; diff --git a/x-pack/plugins/transform/public/app/lib/authorization/components/authorization_provider.tsx b/x-pack/plugins/transform/public/app/lib/authorization/components/authorization_provider.tsx index 02bbe4e40a969..9e73582b13d91 100644 --- a/x-pack/plugins/transform/public/app/lib/authorization/components/authorization_provider.tsx +++ b/x-pack/plugins/transform/public/app/lib/authorization/components/authorization_provider.tsx @@ -10,6 +10,7 @@ import { useQuery } from '@tanstack/react-query'; import type { IHttpFetchError } from '@kbn/core-http-browser'; +import { TRANSFORM_REACT_QUERY_KEYS } from '../../../../../common/constants'; import type { Privileges } from '../../../../../common/types/privileges'; import { @@ -54,7 +55,7 @@ export const AuthorizationProvider = ({ privilegesEndpoint, children }: Props) = error, data: privilegesData, } = useQuery( - ['transform-privileges-and-capabilities'], + [TRANSFORM_REACT_QUERY_KEYS.PRIVILEGES], async ({ signal }) => { return await http.fetch(path, { version, diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/edit_transform_flyout/edit_transform_update_button.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/edit_transform_flyout/edit_transform_update_button.tsx index 06e30d584de46..59bacf76fd39f 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/edit_transform_flyout/edit_transform_update_button.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/edit_transform_flyout/edit_transform_update_button.tsx @@ -14,7 +14,7 @@ import { i18n } from '@kbn/i18n'; import { isPostTransformsUpdateResponseSchema } from '../../../../../../common/api_schemas/type_guards'; import { getErrorMessage } from '../../../../../../common/utils/errors'; -import { refreshTransformList$, REFRESH_TRANSFORM_LIST_STATE } from '../../../../common'; +import { useRefreshTransformList } from '../../../../common'; import { useToastNotifications } from '../../../../app_dependencies'; import { useApi } from '../../../../hooks/use_api'; @@ -26,6 +26,7 @@ interface EditTransformUpdateButtonProps { export const EditTransformUpdateButton: FC = ({ closeFlyout }) => { const api = useApi(); + const refreshTransformList = useRefreshTransformList(); const toastNotifications = useToastNotifications(); const requestConfig = useEditTransformFlyout('requestConfig'); @@ -51,7 +52,7 @@ export const EditTransformUpdateButton: FC = ({ }) ); closeFlyout(); - refreshTransformList$.next(REFRESH_TRANSFORM_LIST_STATE.REFRESH); + refreshTransformList(); } return ( diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/__snapshots__/transform_list.test.tsx.snap b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/__snapshots__/transform_list.test.tsx.snap index 2e80f1deb8b2e..a24e252578041 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/__snapshots__/transform_list.test.tsx.snap +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/__snapshots__/transform_list.test.tsx.snap @@ -1,43 +1,67 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Transform: Transform List Minimal initialization 1`] = ` - - - - - - Create your first transform - , - ] - } - data-test-subj="transformNoTransformsFound" - title={ -

- No transforms found -

- } - /> -
-
-
+ + `; diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row_messages_pane.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row_messages_pane.tsx index 4cf387ad2973b..8178ee43dc809 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row_messages_pane.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row_messages_pane.tsx @@ -6,6 +6,7 @@ */ import React, { MouseEvent, useState, type FC } from 'react'; +import { useQuery } from '@tanstack/react-query'; import { formatDate, @@ -15,15 +16,21 @@ import { EuiToolTip, EuiButtonIcon, } from '@elastic/eui'; -import { euiLightVars as theme } from '@kbn/ui-theme'; +import type { IHttpFetchError } from '@kbn/core-http-browser'; +import { euiLightVars as theme } from '@kbn/ui-theme'; import { i18n } from '@kbn/i18n'; -import { DEFAULT_MAX_AUDIT_MESSAGE_SIZE, TIME_FORMAT } from '../../../../../../common/constants'; -import { isGetTransformsAuditMessagesResponseSchema } from '../../../../../../common/api_schemas/type_guards'; +import type { GetTransformsAuditMessagesResponseSchema } from '../../../../../../common/api_schemas/audit_messages'; +import { + addInternalBasePath, + DEFAULT_MAX_AUDIT_MESSAGE_SIZE, + TIME_FORMAT, + TRANSFORM_REACT_QUERY_KEYS, +} from '../../../../../../common/constants'; import { TransformMessage } from '../../../../../../common/types/messages'; -import { useApi } from '../../../../hooks/use_api'; +import { useAppDependencies } from '../../../../app_dependencies'; import { JobIcon } from '../../../../components/job_icon'; import { useRefreshTransformList } from '../../../../common'; @@ -37,11 +44,7 @@ interface Sorting { } export const ExpandedRowMessagesPane: FC = ({ transformId }) => { - const [messages, setMessages] = useState([]); - const [msgCount, setMsgCount] = useState(0); - - const [isLoading, setIsLoading] = useState(false); - const [errorMessage, setErrorMessage] = useState(''); + const { http } = useAppDependencies(); const [pageIndex, setPageIndex] = useState(0); const [pageSize, setPageSize] = useState(10); @@ -52,58 +55,43 @@ export const ExpandedRowMessagesPane: FC = ({ tran }, }); - const api = useApi(); - - const getMessagesFactory = ( - sortField: keyof TransformMessage = 'timestamp', - sortDirection: 'asc' | 'desc' = 'desc' - ) => { - let concurrentLoads = 0; - - return async function getMessages() { - concurrentLoads++; - - if (concurrentLoads > 1) { - return; - } - - setIsLoading(true); - const messagesResp = await api.getTransformAuditMessages( - transformId, - sortField, - sortDirection - ); - - if (!isGetTransformsAuditMessagesResponseSchema(messagesResp)) { - setIsLoading(false); - setErrorMessage( - i18n.translate( - 'xpack.transform.transformList.transformDetails.messagesPane.errorMessage', - { - defaultMessage: 'Messages could not be loaded', - } - ) - ); - return; - } - - setIsLoading(false); - setMessages(messagesResp.messages); - setMsgCount(messagesResp.total); - - concurrentLoads--; - - if (concurrentLoads > 0) { - concurrentLoads = 0; - getMessages(); - } - }; - }; - const { refresh: refreshMessage } = useRefreshTransformList({ onRefresh: getMessagesFactory() }); + const { isLoading, error, data } = useQuery< + GetTransformsAuditMessagesResponseSchema, + IHttpFetchError + >( + [ + TRANSFORM_REACT_QUERY_KEYS.TRANSFORMS_LIST, + transformId, + sorting.sort.field, + sorting.sort.direction, + ], + async ({ signal }) => + await http.get( + addInternalBasePath(`transforms/${transformId}/messages`), + { + query: { + sortField: sorting.sort.field, + sortDirection: sorting.sort.direction, + }, + version: '1', + signal, + } + ) + ); + const messages = data?.messages ?? []; + const msgCount = data?.total ?? 0; + const errorMessage = + error !== null + ? i18n.translate('xpack.transform.transformList.transformDetails.messagesPane.errorMessage', { + defaultMessage: 'Messages could not be loaded', + }) + : ''; + + const refreshTransformList = useRefreshTransformList(); const columns = [ { - name: refreshMessage ? ( + name: refreshTransformList ? ( = ({ tran // TODO: Replace this with ML's blurButtonOnClick when it's moved to a shared package onClick={(e: MouseEvent) => { (e.currentTarget as HTMLButtonElement).blur(); - refreshMessage(); + refreshTransformList(); }} iconType="refresh" aria-label={i18n.translate('xpack.transform.transformList.refreshAriaLabel', { @@ -192,12 +180,6 @@ export const ExpandedRowMessagesPane: FC = ({ tran setPageSize(size); if (sort) { setSorting({ sort }); - - // Since we only show 500 messages, if user wants oldest messages first - // we need to make sure we fetch them from elasticsearch - if (msgCount > DEFAULT_MAX_AUDIT_MESSAGE_SIZE) { - getMessagesFactory(sort.field, sort.direction)(); - } } }; diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_list.test.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_list.test.tsx index 430fa9478f60a..c4fc1cbc65c27 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_list.test.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_list.test.tsx @@ -7,6 +7,7 @@ import { shallow } from 'enzyme'; import React from 'react'; +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { TransformList } from './transform_list'; @@ -15,13 +16,18 @@ jest.mock('../../../../app_dependencies'); describe('Transform: Transform List ', () => { test('Minimal initialization', () => { + const queryClient = new QueryClient(); const wrapper = shallow( - + + + ); expect(wrapper).toMatchSnapshot(); diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_list.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_list.tsx index e6c279e56f3c3..f008cf33ce638 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_list.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_list.tsx @@ -5,14 +5,16 @@ * 2.0. */ -import React, { MouseEventHandler, FC, useContext, useState } from 'react'; +import React, { type MouseEventHandler, type FC, useContext, useState } from 'react'; import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n-react'; import { EuiButton, EuiButtonEmpty, EuiButtonIcon, + EuiCallOut, EuiEmptyPrompt, EuiFlexGroup, EuiFlexItem, @@ -34,7 +36,7 @@ import type { TransformId } from '../../../../../../common/types/transform'; import { useRefreshTransformList, - TransformListRow, + type TransformListRow, TRANSFORM_LIST_COLUMN, } from '../../../../common'; import { AuthorizationContext } from '../../../../lib/authorization'; @@ -74,6 +76,29 @@ import { useAlertRuleFlyout } from '../../../../../alerting/transform_alerting_f import { TransformHealthAlertRule } from '../../../../../../common/types/alerting'; import { StopActionModal } from '../action_stop/stop_action_modal'; +const ErrorMessage: FC<{ errorMessage: any }> = ({ errorMessage }) => ( + <> + + + } + color="danger" + iconType="error" + > +

+ +

{JSON.stringify(errorMessage)}
+ +

+
+ + +); + type ItemIdToExpandedRowMap = Record; function getItemIdToExpandedRowMap( @@ -91,6 +116,8 @@ function getItemIdToExpandedRowMap( } interface TransformListProps { + errorMessage: any; + isLoading: boolean; onCreateTransform: MouseEventHandler; transformNodes: number; transforms: TransformListRow[]; @@ -98,13 +125,14 @@ interface TransformListProps { } export const TransformList: FC = ({ + errorMessage, + isLoading, onCreateTransform, transformNodes, transforms, transformsLoading, }) => { - const [isLoading, setIsLoading] = useState(false); - const { refresh } = useRefreshTransformList({ isLoading: setIsLoading }); + const refreshTransformList = useRefreshTransformList(); const { setEditAlertRule } = useAlertRuleFlyout(); const [query, setQuery] = useState>[0]>(); @@ -142,11 +170,10 @@ export const TransformList: FC = ({ const filteredTransforms = clauses.length > 0 ? filterTransforms(transforms, clauses) : transforms; - if (transforms.length === 0 && transformNodes === 0) { - return null; - } + const errorMessageInsert = + errorMessage !== null ? : null; - if (transforms.length === 0) { + if (transforms.length === 0 && errorMessage === null) { return ( @@ -319,7 +346,7 @@ export const TransformList: FC = ({ const toolsRight = ( - + @@ -355,6 +382,7 @@ export const TransformList: FC = ({ {/* Single Action Modals */} {singleActionModals} + {errorMessage !== null && errorMessageInsert} { test('useActions()', async () => { - const { result, waitForNextUpdate } = renderHook(() => - useActions({ forceDisable: false, transformNodes: 1 }) + const queryClient = new QueryClient(); + const wrapper: FC = ({ children }) => ( + {children} + ); + const { result, waitForNextUpdate } = renderHook( + () => useActions({ forceDisable: false, transformNodes: 1 }), + { wrapper } ); await waitForNextUpdate(); diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/use_columns.test.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/use_columns.test.tsx index 521bd745e8692..87f550e433bc2 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/use_columns.test.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/use_columns.test.tsx @@ -5,6 +5,8 @@ * 2.0. */ +import React, { type FC } from 'react'; +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { renderHook } from '@testing-library/react-hooks'; import { useColumns } from './use_columns'; @@ -14,7 +16,13 @@ jest.mock('../../../../app_dependencies'); describe('Transform: Job List Columns', () => { test('useColumns()', async () => { - const { result, waitForNextUpdate } = renderHook(() => useColumns([], () => {}, 1, [])); + const queryClient = new QueryClient(); + const wrapper: FC = ({ children }) => ( + {children} + ); + const { result, waitForNextUpdate } = renderHook(() => useColumns([], () => {}, 1, []), { + wrapper, + }); await waitForNextUpdate(); diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/use_refresh_interval.ts b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/use_refresh_interval.ts deleted file mode 100644 index c1f4c3d4f7d5c..0000000000000 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/use_refresh_interval.ts +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 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, { useEffect } from 'react'; - -import { DEFAULT_REFRESH_INTERVAL_MS } from '../../../../../../common/constants'; - -import { useRefreshTransformList } from '../../../../common'; - -export const useRefreshInterval = ( - setBlockRefresh: React.Dispatch> -) => { - const { refresh } = useRefreshTransformList(); - useEffect(() => { - const interval = setInterval(refresh, DEFAULT_REFRESH_INTERVAL_MS); - - // useEffect cleanup - return () => { - clearInterval(interval); - }; - // custom comparison - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); // [] as comparator makes sure this only runs once -}; diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/transform_management_section.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/transform_management_section.tsx index 3c74cf450b4b9..829233680a2f9 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/transform_management_section.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/transform_management_section.tsx @@ -11,12 +11,8 @@ import { FormattedMessage } from '@kbn/i18n-react'; import { EuiButtonEmpty, - EuiEmptyPrompt, - EuiFlexGroup, - EuiFlexItem, EuiSkeletonText, EuiModal, - EuiPageContent_Deprecated as EuiPageContent, EuiPageContentBody_Deprecated as EuiPageContentBody, EuiPageHeader, EuiSpacer, @@ -30,14 +26,12 @@ import { TRANSFORM_STATE, } from '../../../../common/constants'; -import { useRefreshTransformList, TransformListRow } from '../../common'; import { useDocumentationLinks } from '../../hooks/use_documentation_links'; import { useDeleteTransforms, useGetTransforms } from '../../hooks'; import { RedirectToCreateTransform } from '../../common/navigation'; import { AuthorizationContext, PrivilegesWrapper } from '../../lib/authorization'; import { breadcrumbService, docTitleService, BREADCRUMB_SECTION } from '../../services/navigation'; -import { useRefreshInterval } from './components/transform_list/use_refresh_interval'; import { SearchSelection } from './components/search_selection'; import { TransformList } from './components/transform_list'; import { TransformStatsBar } from './components/transform_list/transforms_stats_bar'; @@ -50,34 +44,18 @@ import { export const TransformManagement: FC = () => { const { esTransform } = useDocumentationLinks(); - const [transformsLoading, setTransformsLoading] = useState(false); - const [isInitialized, setIsInitialized] = useState(false); - const [blockRefresh, setBlockRefresh] = useState(false); - const [transforms, setTransforms] = useState([]); - const [transformNodes, setTransformNodes] = useState(0); - const [errorMessage, setErrorMessage] = useState(undefined); - const [transformIdsWithoutConfig, setTransformIdsWithoutConfig] = useState< - string[] | undefined - >(); - const deleteTransforms = useDeleteTransforms(); - const getTransforms = useGetTransforms( - setTransforms, - setTransformNodes, - setErrorMessage, - setTransformIdsWithoutConfig, - setIsInitialized, - blockRefresh - ); - - // Subscribe to the refresh observable to trigger reloading the transform list. - useRefreshTransformList({ - isLoading: setTransformsLoading, - onRefresh: () => getTransforms(true), - }); - // Call useRefreshInterval() after the subscription above is set up. - useRefreshInterval(setBlockRefresh); + const { + isInitialLoading, + isLoading: transformsLoading, + error: errorMessage, + data, + } = useGetTransforms(); + const isInitialized = !isInitialLoading; + const transforms = useMemo(() => data?.tableRows ?? [], [data]); + const transformNodes = data?.transformNodes ?? 0; + const transformIdsWithoutConfig = data?.transformIdsWithoutConfig; const { canStartStopTransform } = useContext(AuthorizationContext).capabilities; @@ -180,92 +158,63 @@ export const TransformManagement: FC = () => { - {typeof errorMessage !== 'undefined' && ( - - - - - - - - } - body={ -

-

{JSON.stringify(errorMessage)}
-

- } - actions={[]} - /> -
-
-
- )} - {typeof errorMessage === 'undefined' && ( - - {transformIdsWithoutConfig ? ( - <> - -

- -

- { - await deleteTransforms( - // If transform task doesn't have any corresponding config - // we won't know what the destination index or data view would be - // and should be force deleted - { - transformsInfo: transformIdsWithoutConfig.map((id) => ({ - id, - state: TRANSFORM_STATE.FAILED, - })), - deleteDestIndex: false, - deleteDestDataView: false, - forceDelete: true, - } - ); + + + {transformIdsWithoutConfig ? ( + <> + +

+ +

+ { + await deleteTransforms( + // If transform task doesn't have any corresponding config + // we won't know what the destination index or data view would be + // and should be force deleted + { + transformsInfo: transformIdsWithoutConfig.map((id) => ({ + id, + state: TRANSFORM_STATE.FAILED, + })), + deleteDestIndex: false, + deleteDestDataView: false, + forceDelete: true, + } + ); + }} + > + - - -
- - - ) : null} - - -
- )} + /> +
+
+ + + ) : null} + + +
)} From ec2bd1c264c50417cf3fad3f370be18c2c28328b Mon Sep 17 00:00:00 2001 From: Walter Rafelsberger Date: Mon, 21 Aug 2023 16:12:18 +0200 Subject: [PATCH 02/53] refactor inline useQuery to custom hook. cleanup useApi. --- .../transform_health_rule_trigger.tsx | 50 ++++++----------- .../public/app/hooks/__mocks__/use_api.ts | 13 ----- .../transform/public/app/hooks/index.ts | 2 + .../transform/public/app/hooks/use_api.ts | 56 ------------------- .../hooks/use_get_transform_audit_messages.ts | 39 +++++++++++++ .../public/app/hooks/use_get_transforms.ts | 2 - .../step_details/step_details_form.tsx | 44 +++++++-------- .../expanded_row_messages_pane.tsx | 40 ++----------- .../transform_management_section.tsx | 2 +- 9 files changed, 88 insertions(+), 160 deletions(-) create mode 100644 x-pack/plugins/transform/public/app/hooks/use_get_transform_audit_messages.ts diff --git a/x-pack/plugins/transform/public/alerting/transform_health_rule_type/transform_health_rule_trigger.tsx b/x-pack/plugins/transform/public/alerting/transform_health_rule_type/transform_health_rule_trigger.tsx index 56bd9a2db877e..f691c6a986020 100644 --- a/x-pack/plugins/transform/public/alerting/transform_health_rule_type/transform_health_rule_trigger.tsx +++ b/x-pack/plugins/transform/public/alerting/transform_health_rule_type/transform_health_rule_trigger.tsx @@ -6,16 +6,15 @@ */ import { EuiForm, EuiSpacer } from '@elastic/eui'; -import React, { FC, useCallback, useEffect, useMemo, useState } from 'react'; +import React, { FC, useCallback, useEffect, useMemo } from 'react'; import { FormattedMessage } from '@kbn/i18n-react'; import { i18n } from '@kbn/i18n'; import type { RuleTypeParamsExpressionProps } from '@kbn/triggers-actions-ui-plugin/public'; import type { TransformHealthRuleParams } from '../../../common/types/alerting'; import { TestsSelectionControl } from './tests_selection_control'; import { TransformSelectorControl } from './transform_selector_control'; -import { useApi } from '../../app/hooks'; +import { useGetTransforms } from '../../app/hooks'; import { useToastNotifications } from '../../app/app_dependencies'; -import { GetTransformsResponseSchema } from '../../../common/api_schemas/transforms'; import { ALL_TRANSFORMS_SELECTION } from '../../../common/constants'; export type TransformHealthRuleTriggerProps = @@ -29,9 +28,12 @@ const TransformHealthRuleTrigger: FC = ({ const formErrors = Object.values(errors).flat(); const isFormInvalid = formErrors.length > 0; - const api = useApi(); const toast = useToastNotifications(); - const [transformOptions, setTransformOptions] = useState([]); + const { error, data } = useGetTransforms(); + const transformOptions = useMemo( + () => data?.tableRows.filter((v) => v.config.sync).map((v) => v.id) ?? [], + [data] + ); const onAlertParamChange = useCallback( (param: T) => @@ -41,34 +43,18 @@ const TransformHealthRuleTrigger: FC = ({ [setRuleParams] ); - useEffect( - function fetchTransforms() { - let unmounted = false; - api - .getTransforms() - .then((r) => { - if (!unmounted) { - setTransformOptions( - (r as GetTransformsResponseSchema).transforms.filter((v) => v.sync).map((v) => v.id) - ); + useEffect(() => { + if (error !== null) { + toast.addError(error, { + title: i18n.translate( + 'xpack.transform.alertingRuleTypes.transformHealth.fetchErrorMessage', + { + defaultMessage: 'Unable to fetch transforms', } - }) - .catch((e) => { - toast.addError(e, { - title: i18n.translate( - 'xpack.transform.alertingRuleTypes.transformHealth.fetchErrorMessage', - { - defaultMessage: 'Unable to fetch transforms', - } - ), - }); - }); - return () => { - unmounted = true; - }; - }, - [api, toast] - ); + ), + }); + } + }, [error, toast]); const excludeTransformOptions = useMemo(() => { if (ruleParams.includeTransforms?.some((v) => v === ALL_TRANSFORMS_SELECTION)) { diff --git a/x-pack/plugins/transform/public/app/hooks/__mocks__/use_api.ts b/x-pack/plugins/transform/public/app/hooks/__mocks__/use_api.ts index 2e0407b0ac974..a2f30a6c256b9 100644 --- a/x-pack/plugins/transform/public/app/hooks/__mocks__/use_api.ts +++ b/x-pack/plugins/transform/public/app/hooks/__mocks__/use_api.ts @@ -12,7 +12,6 @@ import { DEFAULT_SAMPLER_SHARD_SIZE } from '@kbn/ml-agg-utils'; import type { TransformId } from '../../../../common/types/transform'; import type { FieldHistogramsResponseSchema } from '../../../../common/api_schemas/field_histograms'; -import type { GetTransformsAuditMessagesResponseSchema } from '../../../../common/api_schemas/audit_messages'; import type { DeleteTransformsRequestSchema, DeleteTransformsResponseSchema, @@ -53,17 +52,11 @@ const apiFactory = () => ({ ): Promise { return Promise.resolve({ count: 0, transforms: [] }); }, - async getTransforms(): Promise { - return Promise.resolve({ count: 0, transforms: [] }); - }, async getTransformStats( transformId: TransformId ): Promise { return Promise.resolve({ count: 0, transforms: [] }); }, - async getTransformsStats(): Promise { - return Promise.resolve({ count: 0, transforms: [] }); - }, async createTransform( transformId: TransformId, transformConfig: PutTransformsRequestSchema @@ -126,12 +119,6 @@ const apiFactory = () => ({ ): Promise { return Promise.resolve({}); }, - async getTransformAuditMessages( - transformId: TransformId - ): Promise { - return Promise.resolve({ messages: [], total: 0 }); - }, - async getEsIndices(): Promise { return Promise.resolve([]); }, diff --git a/x-pack/plugins/transform/public/app/hooks/index.ts b/x-pack/plugins/transform/public/app/hooks/index.ts index f6a4c72b39a44..91730ec067aeb 100644 --- a/x-pack/plugins/transform/public/app/hooks/index.ts +++ b/x-pack/plugins/transform/public/app/hooks/index.ts @@ -6,6 +6,8 @@ */ export { useApi } from './use_api'; +export { useDocumentationLinks } from './use_documentation_links'; +export { useGetTransformAuditMessages } from './use_get_transform_audit_messages'; export { useGetTransforms } from './use_get_transforms'; export { useDeleteTransforms, useDeleteIndexAndTargetIndex } from './use_delete_transform'; export { useResetTransforms } from './use_reset_transform'; diff --git a/x-pack/plugins/transform/public/app/hooks/use_api.ts b/x-pack/plugins/transform/public/app/hooks/use_api.ts index 066977fb841df..a72e249d7b944 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_api.ts +++ b/x-pack/plugins/transform/public/app/hooks/use_api.ts @@ -16,7 +16,6 @@ import { ReauthorizeTransformsRequestSchema, ReauthorizeTransformsResponseSchema, } from '../../../common/api_schemas/reauthorize_transforms'; -import type { GetTransformsAuditMessagesResponseSchema } from '../../../common/api_schemas/audit_messages'; import type { DeleteTransformsRequestSchema, DeleteTransformsResponseSchema, @@ -42,7 +41,6 @@ import type { ScheduleNowTransformsResponseSchema, } from '../../../common/api_schemas/schedule_now_transforms'; import type { - GetTransformNodesResponseSchema, GetTransformsResponseSchema, PostTransformsPreviewRequestSchema, PostTransformsPreviewResponseSchema, @@ -68,22 +66,11 @@ export interface FieldHistogramRequestConfig { type?: KBN_FIELD_TYPES; } -interface FetchOptions { - asSystemRequest?: boolean; -} - export const useApi = () => { const { http } = useAppDependencies(); return useMemo( () => ({ - async getTransformNodes(): Promise { - try { - return await http.get(addInternalBasePath(`transforms/_nodes`), { version: '1' }); - } catch (e) { - return e; - } - }, async getTransform( transformId: TransformId ): Promise { @@ -95,18 +82,6 @@ export const useApi = () => { return e; } }, - async getTransforms( - fetchOptions: FetchOptions = {} - ): Promise { - try { - return await http.get(addInternalBasePath(`transforms`), { - ...fetchOptions, - version: '1', - }); - } catch (e) { - return e; - } - }, async getTransformStats( transformId: TransformId ): Promise { @@ -118,18 +93,6 @@ export const useApi = () => { return e; } }, - async getTransformsStats( - fetchOptions: FetchOptions = {} - ): Promise { - try { - return await http.get(addInternalBasePath(`transforms/_stats`), { - ...fetchOptions, - version: '1', - }); - } catch (e) { - return e; - } - }, async createTransform( transformId: TransformId, transformConfig: PutTransformsRequestSchema @@ -241,25 +204,6 @@ export const useApi = () => { return e; } }, - async getTransformAuditMessages( - transformId: TransformId, - sortField: string, - sortDirection: 'asc' | 'desc' - ): Promise< - { messages: GetTransformsAuditMessagesResponseSchema; total: number } | IHttpFetchError - > { - try { - return await http.get(addInternalBasePath(`transforms/${transformId}/messages`), { - query: { - sortField, - sortDirection, - }, - version: '1', - }); - } catch (e) { - return e; - } - }, async getEsIndices(): Promise { try { return await http.get(`/api/index_management/indices`, { version: '1' }); diff --git a/x-pack/plugins/transform/public/app/hooks/use_get_transform_audit_messages.ts b/x-pack/plugins/transform/public/app/hooks/use_get_transform_audit_messages.ts new file mode 100644 index 0000000000000..09e0bdf23571d --- /dev/null +++ b/x-pack/plugins/transform/public/app/hooks/use_get_transform_audit_messages.ts @@ -0,0 +1,39 @@ +/* + * 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 { useQuery } from '@tanstack/react-query'; + +import type { IHttpFetchError } from '@kbn/core-http-browser'; + +import type { GetTransformsAuditMessagesResponseSchema } from '../../../common/api_schemas/audit_messages'; +import { addInternalBasePath, TRANSFORM_REACT_QUERY_KEYS } from '../../../common/constants'; +import { TransformMessage } from '../../../common/types/messages'; + +import { useAppDependencies } from '../app_dependencies'; + +export const useGetTransformAuditMessages = ( + transformId: string, + sortField: keyof TransformMessage, + sortDirection: 'asc' | 'desc' +) => { + const { http } = useAppDependencies(); + + const query = { sortField, sortDirection }; + + return useQuery( + [TRANSFORM_REACT_QUERY_KEYS.TRANSFORMS_LIST, transformId, query], + async ({ signal }) => + await http.get( + addInternalBasePath(`transforms/${transformId}/messages`), + { + query, + version: '1', + signal, + } + ) + ); +}; diff --git a/x-pack/plugins/transform/public/app/hooks/use_get_transforms.ts b/x-pack/plugins/transform/public/app/hooks/use_get_transforms.ts index e31f30fd790f1..ee644f9dd8d32 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_get_transforms.ts +++ b/x-pack/plugins/transform/public/app/hooks/use_get_transforms.ts @@ -27,8 +27,6 @@ import { useAppDependencies } from '../app_dependencies'; import { TRANSFORM_ERROR_TYPE } from '../common/transform'; -export type GetTransforms = (forceRefresh?: boolean) => void; - interface UseGetTransformsResponse { tableRows: TransformListRow[]; transformIdsWithoutConfig?: string[]; diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_details/step_details_form.tsx b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_details/step_details_form.tsx index 4e8104a7645ee..f2c6a448943e5 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_details/step_details_form.tsx +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_details/step_details_form.tsx @@ -42,7 +42,7 @@ import { getErrorMessage } from '../../../../../../common/utils/errors'; import { useAppDependencies, useToastNotifications } from '../../../../app_dependencies'; import { ToastNotificationText } from '../../../../components'; -import { useDocumentationLinks } from '../../../../hooks/use_documentation_links'; +import { useDocumentationLinks, useGetTransforms } from '../../../../hooks'; import { SearchItems } from '../../../../hooks/use_search_items'; import { useApi } from '../../../../hooks/use_api'; import { StepDetailsTimeField } from './step_details_time_field'; @@ -90,7 +90,6 @@ export const StepDetailsForm: FC = React.memo( const [destinationIngestPipeline, setDestinationIngestPipeline] = useState( defaults.destinationIngestPipeline ); - const [transformIds, setTransformIds] = useState([]); const [indexNames, setIndexNames] = useState([]); const [ingestPipelineNames, setIngestPipelineNames] = useState([]); @@ -128,6 +127,27 @@ export const StepDetailsForm: FC = React.memo( const { overlays, theme } = useAppDependencies(); const api = useApi(); + const { error, data } = useGetTransforms(); + const transformIds = data?.tableRows.map((d) => d.id) ?? []; + + useEffect(() => { + if (isHttpFetchError(error)) { + toastNotifications.addDanger({ + title: i18n.translate('xpack.transform.stepDetailsForm.errorGettingTransformList', { + defaultMessage: 'An error occurred getting the existing transform IDs:', + }), + text: toMountPoint( + , + { theme$: theme.theme$ } + ), + }); + } + }, [error, overlays, theme, toastNotifications]); + // fetch existing transform IDs and indices once for form validation useEffect(() => { // use an IIFE to avoid returning a Promise to useEffect. @@ -167,26 +187,6 @@ export const StepDetailsForm: FC = React.memo( }); } - const resp = await api.getTransforms(); - - if (isHttpFetchError(resp)) { - toastNotifications.addDanger({ - title: i18n.translate('xpack.transform.stepDetailsForm.errorGettingTransformList', { - defaultMessage: 'An error occurred getting the existing transform IDs:', - }), - text: toMountPoint( - , - { theme$: theme.theme$ } - ), - }); - } else { - setTransformIds(resp.transforms.map((transform) => transform.id)); - } - const [indices, ingestPipelines] = await Promise.all([ api.getEsIndices(), api.getEsIngestPipelines(), diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row_messages_pane.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row_messages_pane.tsx index 8178ee43dc809..fb435679d2185 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row_messages_pane.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row_messages_pane.tsx @@ -6,7 +6,6 @@ */ import React, { MouseEvent, useState, type FC } from 'react'; -import { useQuery } from '@tanstack/react-query'; import { formatDate, @@ -17,22 +16,15 @@ import { EuiButtonIcon, } from '@elastic/eui'; -import type { IHttpFetchError } from '@kbn/core-http-browser'; import { euiLightVars as theme } from '@kbn/ui-theme'; import { i18n } from '@kbn/i18n'; -import type { GetTransformsAuditMessagesResponseSchema } from '../../../../../../common/api_schemas/audit_messages'; -import { - addInternalBasePath, - DEFAULT_MAX_AUDIT_MESSAGE_SIZE, - TIME_FORMAT, - TRANSFORM_REACT_QUERY_KEYS, -} from '../../../../../../common/constants'; +import { DEFAULT_MAX_AUDIT_MESSAGE_SIZE, TIME_FORMAT } from '../../../../../../common/constants'; import { TransformMessage } from '../../../../../../common/types/messages'; -import { useAppDependencies } from '../../../../app_dependencies'; import { JobIcon } from '../../../../components/job_icon'; import { useRefreshTransformList } from '../../../../common'; +import { useGetTransformAuditMessages } from '../../../../hooks'; interface ExpandedRowMessagesPaneProps { transformId: string; @@ -44,8 +36,6 @@ interface Sorting { } export const ExpandedRowMessagesPane: FC = ({ transformId }) => { - const { http } = useAppDependencies(); - const [pageIndex, setPageIndex] = useState(0); const [pageSize, setPageSize] = useState(10); const [sorting, setSorting] = useState<{ sort: Sorting }>({ @@ -55,28 +45,10 @@ export const ExpandedRowMessagesPane: FC = ({ tran }, }); - const { isLoading, error, data } = useQuery< - GetTransformsAuditMessagesResponseSchema, - IHttpFetchError - >( - [ - TRANSFORM_REACT_QUERY_KEYS.TRANSFORMS_LIST, - transformId, - sorting.sort.field, - sorting.sort.direction, - ], - async ({ signal }) => - await http.get( - addInternalBasePath(`transforms/${transformId}/messages`), - { - query: { - sortField: sorting.sort.field, - sortDirection: sorting.sort.direction, - }, - version: '1', - signal, - } - ) + const { isLoading, error, data } = useGetTransformAuditMessages( + transformId, + sorting.sort.field, + sorting.sort.direction ); const messages = data?.messages ?? []; const msgCount = data?.total ?? 0; diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/transform_management_section.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/transform_management_section.tsx index 829233680a2f9..045f1bdbc38e0 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/transform_management_section.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/transform_management_section.tsx @@ -26,7 +26,7 @@ import { TRANSFORM_STATE, } from '../../../../common/constants'; -import { useDocumentationLinks } from '../../hooks/use_documentation_links'; +import { useDocumentationLinks } from '../../hooks'; import { useDeleteTransforms, useGetTransforms } from '../../hooks'; import { RedirectToCreateTransform } from '../../common/navigation'; import { AuthorizationContext, PrivilegesWrapper } from '../../lib/authorization'; From 04ae3c043f981b0ff1a2bf836c08b41dbf97db17 Mon Sep 17 00:00:00 2001 From: Walter Rafelsberger Date: Tue, 22 Aug 2023 14:02:51 +0200 Subject: [PATCH 03/53] migrate wizard to use react-query --- .../common/api_schemas/transforms_stats.ts | 2 +- x-pack/plugins/transform/common/constants.ts | 1 + .../public/app/hooks/__mocks__/use_api.ts | 26 -- .../transform/public/app/hooks/index.ts | 2 + .../transform/public/app/hooks/use_api.ts | 47 --- .../public/app/hooks/use_create_transform.tsx | 84 +++++ .../public/app/hooks/use_delete_transform.tsx | 296 +++++++++--------- .../app/hooks/use_get_transform_stats.ts | 37 +++ .../public/app/hooks/use_start_transform.tsx | 86 ++--- .../step_create/step_create_form.test.tsx | 8 +- .../step_create/step_create_form.tsx | 234 ++++++-------- .../action_start/use_start_action.tsx | 2 +- .../transform_management_section.tsx | 8 +- 13 files changed, 427 insertions(+), 406 deletions(-) create mode 100644 x-pack/plugins/transform/public/app/hooks/use_create_transform.tsx create mode 100644 x-pack/plugins/transform/public/app/hooks/use_get_transform_stats.ts diff --git a/x-pack/plugins/transform/common/api_schemas/transforms_stats.ts b/x-pack/plugins/transform/common/api_schemas/transforms_stats.ts index 459d37414e244..a9d177a341e21 100644 --- a/x-pack/plugins/transform/common/api_schemas/transforms_stats.ts +++ b/x-pack/plugins/transform/common/api_schemas/transforms_stats.ts @@ -13,7 +13,7 @@ import { getTransformsRequestSchema } from './transforms'; export const getTransformsStatsRequestSchema = getTransformsRequestSchema; -export type GetTransformsRequestSchema = TypeOf; +export type GetTransformsStatsRequestSchema = TypeOf; export interface GetTransformsStatsResponseSchema { node_failures?: object; diff --git a/x-pack/plugins/transform/common/constants.ts b/x-pack/plugins/transform/common/constants.ts index 1076f1d6530d6..eb4943f2e6706 100644 --- a/x-pack/plugins/transform/common/constants.ts +++ b/x-pack/plugins/transform/common/constants.ts @@ -35,6 +35,7 @@ export const addExternalBasePath = (uri: string): string => `${EXTERNAL_API_BASE export const TRANSFORM_REACT_QUERY_KEYS = { PRIVILEGES: 'transform.privileges', TRANSFORMS_LIST: 'transform.transforms_list', + TRANSFORM_STATS: 'transform.transform_stats', } as const; // In order to create a transform, the API requires the following privileges: diff --git a/x-pack/plugins/transform/public/app/hooks/__mocks__/use_api.ts b/x-pack/plugins/transform/public/app/hooks/__mocks__/use_api.ts index a2f30a6c256b9..f76de90a1259a 100644 --- a/x-pack/plugins/transform/public/app/hooks/__mocks__/use_api.ts +++ b/x-pack/plugins/transform/public/app/hooks/__mocks__/use_api.ts @@ -12,14 +12,6 @@ import { DEFAULT_SAMPLER_SHARD_SIZE } from '@kbn/ml-agg-utils'; import type { TransformId } from '../../../../common/types/transform'; import type { FieldHistogramsResponseSchema } from '../../../../common/api_schemas/field_histograms'; -import type { - DeleteTransformsRequestSchema, - DeleteTransformsResponseSchema, -} from '../../../../common/api_schemas/delete_transforms'; -import type { - StartTransformsRequestSchema, - StartTransformsResponseSchema, -} from '../../../../common/api_schemas/start_transforms'; import type { StopTransformsRequestSchema, StopTransformsResponseSchema, @@ -28,8 +20,6 @@ import type { GetTransformsResponseSchema, PostTransformsPreviewRequestSchema, PostTransformsPreviewResponseSchema, - PutTransformsRequestSchema, - PutTransformsResponseSchema, } from '../../../../common/api_schemas/transforms'; import type { GetTransformsStatsResponseSchema } from '../../../../common/api_schemas/transforms_stats'; import type { @@ -57,12 +47,6 @@ const apiFactory = () => ({ ): Promise { return Promise.resolve({ count: 0, transforms: [] }); }, - async createTransform( - transformId: TransformId, - transformConfig: PutTransformsRequestSchema - ): Promise { - return Promise.resolve({ transformsCreated: [], errors: [] }); - }, async updateTransform( transformId: TransformId, transformConfig: PostTransformsUpdateRequestSchema @@ -82,11 +66,6 @@ const apiFactory = () => ({ create_time: 1598860879097, }); }, - async deleteTransforms( - reqBody: DeleteTransformsRequestSchema - ): Promise { - return Promise.resolve({}); - }, async getTransformsPreview( obj: PostTransformsPreviewRequestSchema ): Promise { @@ -109,11 +88,6 @@ const apiFactory = () => ({ preview: [], }); }, - async startTransforms( - reqBody: StartTransformsRequestSchema - ): Promise { - return Promise.resolve({}); - }, async stopTransforms( transformsInfo: StopTransformsRequestSchema ): Promise { diff --git a/x-pack/plugins/transform/public/app/hooks/index.ts b/x-pack/plugins/transform/public/app/hooks/index.ts index 91730ec067aeb..d77f60439609b 100644 --- a/x-pack/plugins/transform/public/app/hooks/index.ts +++ b/x-pack/plugins/transform/public/app/hooks/index.ts @@ -6,9 +6,11 @@ */ export { useApi } from './use_api'; +export { useCreateTransform } from './use_create_transform'; export { useDocumentationLinks } from './use_documentation_links'; export { useGetTransformAuditMessages } from './use_get_transform_audit_messages'; export { useGetTransforms } from './use_get_transforms'; +export { useGetTransformStats } from './use_get_transform_stats'; export { useDeleteTransforms, useDeleteIndexAndTargetIndex } from './use_delete_transform'; export { useResetTransforms } from './use_reset_transform'; export { useScheduleNowTransforms } from './use_schedule_now_transform'; diff --git a/x-pack/plugins/transform/public/app/hooks/use_api.ts b/x-pack/plugins/transform/public/app/hooks/use_api.ts index a72e249d7b944..14547f0dd834a 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_api.ts +++ b/x-pack/plugins/transform/public/app/hooks/use_api.ts @@ -16,10 +16,6 @@ import { ReauthorizeTransformsRequestSchema, ReauthorizeTransformsResponseSchema, } from '../../../common/api_schemas/reauthorize_transforms'; -import type { - DeleteTransformsRequestSchema, - DeleteTransformsResponseSchema, -} from '../../../common/api_schemas/delete_transforms'; import type { FieldHistogramsRequestSchema, FieldHistogramsResponseSchema, @@ -28,10 +24,6 @@ import type { ResetTransformsRequestSchema, ResetTransformsResponseSchema, } from '../../../common/api_schemas/reset_transforms'; -import type { - StartTransformsRequestSchema, - StartTransformsResponseSchema, -} from '../../../common/api_schemas/start_transforms'; import type { StopTransformsRequestSchema, StopTransformsResponseSchema, @@ -44,8 +36,6 @@ import type { GetTransformsResponseSchema, PostTransformsPreviewRequestSchema, PostTransformsPreviewResponseSchema, - PutTransformsRequestSchema, - PutTransformsResponseSchema, } from '../../../common/api_schemas/transforms'; import type { PostTransformsUpdateRequestSchema, @@ -93,19 +83,6 @@ export const useApi = () => { return e; } }, - async createTransform( - transformId: TransformId, - transformConfig: PutTransformsRequestSchema - ): Promise { - try { - return await http.put(addInternalBasePath(`transforms/${transformId}`), { - body: JSON.stringify(transformConfig), - version: '1', - }); - } catch (e) { - return e; - } - }, async updateTransform( transformId: TransformId, transformConfig: PostTransformsUpdateRequestSchema @@ -119,18 +96,6 @@ export const useApi = () => { return e; } }, - async deleteTransforms( - reqBody: DeleteTransformsRequestSchema - ): Promise { - try { - return await http.post(addInternalBasePath(`delete_transforms`), { - body: JSON.stringify(reqBody), - version: '1', - }); - } catch (e) { - return e; - } - }, async getTransformsPreview( obj: PostTransformsPreviewRequestSchema ): Promise { @@ -168,18 +133,6 @@ export const useApi = () => { return e; } }, - async startTransforms( - reqBody: StartTransformsRequestSchema - ): Promise { - try { - return await http.post(addInternalBasePath(`start_transforms`), { - body: JSON.stringify(reqBody), - version: '1', - }); - } catch (e) { - return e; - } - }, async stopTransforms( transformsInfo: StopTransformsRequestSchema ): Promise { diff --git a/x-pack/plugins/transform/public/app/hooks/use_create_transform.tsx b/x-pack/plugins/transform/public/app/hooks/use_create_transform.tsx new file mode 100644 index 0000000000000..f44f0f234559f --- /dev/null +++ b/x-pack/plugins/transform/public/app/hooks/use_create_transform.tsx @@ -0,0 +1,84 @@ +/* + * 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 from 'react'; +import { useMutation } from '@tanstack/react-query'; + +import { i18n } from '@kbn/i18n'; +import { toMountPoint } from '@kbn/kibana-react-plugin/public'; + +import type { + PutTransformsRequestSchema, + PutTransformsResponseSchema, +} from '../../../common/api_schemas/transforms'; +import { isPutTransformsResponseSchema } from '../../../common/api_schemas/type_guards'; +import { addInternalBasePath } from '../../../common/constants'; +import type { TransformId } from '../../../common/types/transform'; +import { getErrorMessage } from '../../../common/utils/errors'; + +import { useAppDependencies, useToastNotifications } from '../app_dependencies'; +import { useRefreshTransformList } from '../common'; +import { ToastNotificationText } from '../components'; + +export const useCreateTransform = ( + transformId: TransformId, + transformConfig: PutTransformsRequestSchema +) => { + const { http, overlays, theme } = useAppDependencies(); + const refreshTransformList = useRefreshTransformList(); + const toastNotifications = useToastNotifications(); + + const mutation = useMutation({ + mutationFn: () => { + return http.put( + addInternalBasePath(`transforms/${transformId}`), + { + body: JSON.stringify(transformConfig), + version: '1', + } + ); + }, + onError: (resp) => { + if (!isPutTransformsResponseSchema(resp) || resp.errors.length > 0) { + let respErrors: + | PutTransformsResponseSchema['errors'] + | PutTransformsResponseSchema['errors'][number] + | undefined; + + if (isPutTransformsResponseSchema(resp) && resp.errors.length > 0) { + respErrors = resp.errors.length === 1 ? resp.errors[0] : resp.errors; + } + + toastNotifications.addDanger({ + title: i18n.translate('xpack.transform.stepCreateForm.createTransformErrorMessage', { + defaultMessage: 'An error occurred creating the transform {transformId}:', + values: { transformId }, + }), + text: toMountPoint( + , + { theme$: theme.theme$ } + ), + }); + } + }, + onSuccess: (results) => { + toastNotifications.addSuccess( + i18n.translate('xpack.transform.stepCreateForm.createTransformSuccessMessage', { + defaultMessage: 'Request to create transform {transformId} acknowledged.', + values: { transformId }, + }) + ); + refreshTransformList(); + }, + }); + + return mutation; +}; diff --git a/x-pack/plugins/transform/public/app/hooks/use_delete_transform.tsx b/x-pack/plugins/transform/public/app/hooks/use_delete_transform.tsx index d4e078d285ca9..453a9bd912c07 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_delete_transform.tsx +++ b/x-pack/plugins/transform/public/app/hooks/use_delete_transform.tsx @@ -6,19 +6,22 @@ */ import React, { useCallback, useEffect, useState } from 'react'; +import { useMutation } from '@tanstack/react-query'; + import { i18n } from '@kbn/i18n'; import { toMountPoint } from '@kbn/kibana-react-plugin/public'; import { extractErrorMessage } from '@kbn/ml-error-utils'; + +import { addInternalBasePath } from '../../../common/constants'; import type { DeleteTransformStatus, DeleteTransformsRequestSchema, + DeleteTransformsResponseSchema, } from '../../../common/api_schemas/delete_transforms'; -import { isDeleteTransformsResponseSchema } from '../../../common/api_schemas/type_guards'; import { getErrorMessage } from '../../../common/utils/errors'; import { useAppDependencies, useToastNotifications } from '../app_dependencies'; import { useRefreshTransformList, type TransformListRow } from '../common'; import { ToastNotificationText } from '../components'; -import { useApi } from './use_api'; import { indexService } from '../services/es_index_service'; export const useDeleteIndexAndTargetIndex = (items: TransformListRow[]) => { @@ -119,15 +122,18 @@ export const useDeleteIndexAndTargetIndex = (items: TransformListRow[]) => { type SuccessCountField = keyof Omit; export const useDeleteTransforms = () => { - const { overlays, theme } = useAppDependencies(); + const { http, overlays, theme } = useAppDependencies(); const refreshTransformList = useRefreshTransformList(); const toastNotifications = useToastNotifications(); - const api = useApi(); - return async (reqBody: DeleteTransformsRequestSchema) => { - const results = await api.deleteTransforms(reqBody); - - if (!isDeleteTransformsResponseSchema(results)) { + const mutation = useMutation({ + mutationFn: (reqBody: DeleteTransformsRequestSchema) => { + return http.post(addInternalBasePath('delete_transforms'), { + body: JSON.stringify(reqBody), + version: '1', + }); + }, + onError: (error) => { toastNotifications.addDanger({ title: i18n.translate('xpack.transform.transformList.deleteTransformGenericErrorMessage', { defaultMessage: 'An error occurred calling the API endpoint to delete transforms.', @@ -137,163 +143,165 @@ export const useDeleteTransforms = () => { previewTextLength={50} overlays={overlays} theme={theme} - text={getErrorMessage(results)} + text={getErrorMessage(error)} />, { theme$: theme.theme$ } ), }); - return; - } - - const isBulk = Object.keys(results).length > 1; - const successCount: Record = { - transformDeleted: 0, - destIndexDeleted: 0, - destDataViewDeleted: 0, - }; - for (const transformId in results) { - // hasOwnProperty check to ensure only properties on object itself, and not its prototypes - if (results.hasOwnProperty(transformId)) { - const status = results[transformId]; - const destinationIndex = status.destinationIndex; + }, + onSuccess: (results) => { + const isBulk = Object.keys(results).length > 1; + const successCount: Record = { + transformDeleted: 0, + destIndexDeleted: 0, + destDataViewDeleted: 0, + }; + for (const transformId in results) { + // hasOwnProperty check to ensure only properties on object itself, and not its prototypes + if (results.hasOwnProperty(transformId)) { + const status = results[transformId]; + const destinationIndex = status.destinationIndex; - // if we are only deleting one transform, show the success toast messages - if (!isBulk && status.transformDeleted) { - if (status.transformDeleted?.success) { - toastNotifications.addSuccess( - i18n.translate('xpack.transform.transformList.deleteTransformSuccessMessage', { - defaultMessage: 'Request to delete transform {transformId} acknowledged.', + // if we are only deleting one transform, show the success toast messages + if (!isBulk && status.transformDeleted) { + if (status.transformDeleted?.success) { + toastNotifications.addSuccess( + i18n.translate('xpack.transform.transformList.deleteTransformSuccessMessage', { + defaultMessage: 'Request to delete transform {transformId} acknowledged.', + values: { transformId }, + }) + ); + } + if (status.destIndexDeleted?.success) { + toastNotifications.addSuccess( + i18n.translate( + 'xpack.transform.deleteTransform.deleteAnalyticsWithIndexSuccessMessage', + { + defaultMessage: + 'Request to delete destination index {destinationIndex} acknowledged.', + values: { destinationIndex }, + } + ) + ); + } + if (status.destDataViewDeleted?.success) { + toastNotifications.addSuccess( + i18n.translate( + 'xpack.transform.deleteTransform.deleteAnalyticsWithDataViewSuccessMessage', + { + defaultMessage: 'Request to delete data view {destinationIndex} acknowledged.', + values: { destinationIndex }, + } + ) + ); + } + } else { + (Object.keys(successCount) as SuccessCountField[]).forEach((key) => { + if (status[key]?.success) { + successCount[key] = successCount[key] + 1; + } + }); + } + if (status.transformDeleted?.error) { + const error = status.transformDeleted.error.reason; + toastNotifications.addDanger({ + title: i18n.translate('xpack.transform.transformList.deleteTransformErrorMessage', { + defaultMessage: 'An error occurred deleting the transform {transformId}', values: { transformId }, - }) - ); + }), + text: toMountPoint( + , + { theme$: theme.theme$ } + ), + }); } - if (status.destIndexDeleted?.success) { - toastNotifications.addSuccess( - i18n.translate( - 'xpack.transform.deleteTransform.deleteAnalyticsWithIndexSuccessMessage', + + if (status.destIndexDeleted?.error) { + const error = status.destIndexDeleted.error.reason; + toastNotifications.addDanger({ + title: i18n.translate( + 'xpack.transform.deleteTransform.deleteAnalyticsWithIndexErrorMessage', { - defaultMessage: - 'Request to delete destination index {destinationIndex} acknowledged.', + defaultMessage: 'An error occurred deleting destination index {destinationIndex}', values: { destinationIndex }, } - ) - ); + ), + text: toMountPoint( + , + { theme$: theme.theme$ } + ), + }); } - if (status.destDataViewDeleted?.success) { - toastNotifications.addSuccess( - i18n.translate( - 'xpack.transform.deleteTransform.deleteAnalyticsWithDataViewSuccessMessage', + + if (status.destDataViewDeleted?.error) { + const error = status.destDataViewDeleted.error.reason; + toastNotifications.addDanger({ + title: i18n.translate( + 'xpack.transform.deleteTransform.deleteAnalyticsWithDataViewErrorMessage', { - defaultMessage: 'Request to delete data view {destinationIndex} acknowledged.', + defaultMessage: 'An error occurred deleting data view {destinationIndex}', values: { destinationIndex }, } - ) - ); + ), + text: toMountPoint( + , + { theme$: theme.theme$ } + ), + }); } - } else { - (Object.keys(successCount) as SuccessCountField[]).forEach((key) => { - if (status[key]?.success) { - successCount[key] = successCount[key] + 1; - } - }); - } - if (status.transformDeleted?.error) { - const error = status.transformDeleted.error.reason; - toastNotifications.addDanger({ - title: i18n.translate('xpack.transform.transformList.deleteTransformErrorMessage', { - defaultMessage: 'An error occurred deleting the transform {transformId}', - values: { transformId }, - }), - text: toMountPoint( - , - { theme$: theme.theme$ } - ), - }); } + } - if (status.destIndexDeleted?.error) { - const error = status.destIndexDeleted.error.reason; - toastNotifications.addDanger({ - title: i18n.translate( - 'xpack.transform.deleteTransform.deleteAnalyticsWithIndexErrorMessage', - { - defaultMessage: 'An error occurred deleting destination index {destinationIndex}', - values: { destinationIndex }, - } - ), - text: toMountPoint( - , - { theme$: theme.theme$ } - ), - }); + // if we are deleting multiple transforms, combine the success messages + if (isBulk) { + if (successCount.transformDeleted > 0) { + toastNotifications.addSuccess( + i18n.translate('xpack.transform.transformList.bulkDeleteTransformSuccessMessage', { + defaultMessage: + 'Successfully deleted {count} {count, plural, one {transform} other {transforms}}.', + values: { count: successCount.transformDeleted }, + }) + ); } - if (status.destDataViewDeleted?.error) { - const error = status.destDataViewDeleted.error.reason; - toastNotifications.addDanger({ - title: i18n.translate( - 'xpack.transform.deleteTransform.deleteAnalyticsWithDataViewErrorMessage', - { - defaultMessage: 'An error occurred deleting data view {destinationIndex}', - values: { destinationIndex }, - } - ), - text: toMountPoint( - , - { theme$: theme.theme$ } - ), - }); + if (successCount.destIndexDeleted > 0) { + toastNotifications.addSuccess( + i18n.translate('xpack.transform.transformList.bulkDeleteDestIndexSuccessMessage', { + defaultMessage: + 'Successfully deleted {count} destination {count, plural, one {index} other {indices}}.', + values: { count: successCount.destIndexDeleted }, + }) + ); + } + if (successCount.destDataViewDeleted > 0) { + toastNotifications.addSuccess( + i18n.translate('xpack.transform.transformList.bulkDeleteDestDataViewSuccessMessage', { + defaultMessage: + 'Successfully deleted {count} destination data {count, plural, one {view} other {views}}.', + values: { count: successCount.destDataViewDeleted }, + }) + ); } - } - } - - // if we are deleting multiple transforms, combine the success messages - if (isBulk) { - if (successCount.transformDeleted > 0) { - toastNotifications.addSuccess( - i18n.translate('xpack.transform.transformList.bulkDeleteTransformSuccessMessage', { - defaultMessage: - 'Successfully deleted {count} {count, plural, one {transform} other {transforms}}.', - values: { count: successCount.transformDeleted }, - }) - ); } - if (successCount.destIndexDeleted > 0) { - toastNotifications.addSuccess( - i18n.translate('xpack.transform.transformList.bulkDeleteDestIndexSuccessMessage', { - defaultMessage: - 'Successfully deleted {count} destination {count, plural, one {index} other {indices}}.', - values: { count: successCount.destIndexDeleted }, - }) - ); - } - if (successCount.destDataViewDeleted > 0) { - toastNotifications.addSuccess( - i18n.translate('xpack.transform.transformList.bulkDeleteDestDataViewSuccessMessage', { - defaultMessage: - 'Successfully deleted {count} destination data {count, plural, one {view} other {views}}.', - values: { count: successCount.destDataViewDeleted }, - }) - ); - } - } + refreshTransformList(); + }, + }); - refreshTransformList(); - }; + return (reqBody: DeleteTransformsRequestSchema) => mutation.mutate(reqBody); }; diff --git a/x-pack/plugins/transform/public/app/hooks/use_get_transform_stats.ts b/x-pack/plugins/transform/public/app/hooks/use_get_transform_stats.ts new file mode 100644 index 0000000000000..a5df06f2ece59 --- /dev/null +++ b/x-pack/plugins/transform/public/app/hooks/use_get_transform_stats.ts @@ -0,0 +1,37 @@ +/* + * 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 { useQuery } from '@tanstack/react-query'; + +import type { IHttpFetchError } from '@kbn/core-http-browser'; + +import type { GetTransformsStatsResponseSchema } from '../../../common/api_schemas/transforms_stats'; +import { addInternalBasePath, TRANSFORM_REACT_QUERY_KEYS } from '../../../common/constants'; +import type { TransformId } from '../../../common/types/transform'; + +import { useAppDependencies } from '../app_dependencies'; + +export const useGetTransformStats = ( + transformId: TransformId, + enabled?: boolean, + refetchInterval?: number | false +) => { + const { http } = useAppDependencies(); + + return useQuery( + [TRANSFORM_REACT_QUERY_KEYS.TRANSFORM_STATS, transformId], + async ({ signal }) => + await http.get( + addInternalBasePath(`transforms/${transformId}/_stats`), + { + version: '1', + signal, + } + ), + { enabled, refetchInterval } + ); +}; diff --git a/x-pack/plugins/transform/public/app/hooks/use_start_transform.tsx b/x-pack/plugins/transform/public/app/hooks/use_start_transform.tsx index a3bd5b29d5e57..84dc80ef64e47 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_start_transform.tsx +++ b/x-pack/plugins/transform/public/app/hooks/use_start_transform.tsx @@ -6,13 +6,17 @@ */ import React from 'react'; +import { useMutation } from '@tanstack/react-query'; import { i18n } from '@kbn/i18n'; import { toMountPoint } from '@kbn/kibana-react-plugin/public'; -import type { StartTransformsRequestSchema } from '../../../common/api_schemas/start_transforms'; -import { isStartTransformsResponseSchema } from '../../../common/api_schemas/type_guards'; +import { addInternalBasePath } from '../../../common/constants'; +import type { + StartTransformsRequestSchema, + StartTransformsResponseSchema, +} from '../../../common/api_schemas/start_transforms'; import { getErrorMessage } from '../../../common/utils/errors'; @@ -20,18 +24,19 @@ import { useAppDependencies, useToastNotifications } from '../app_dependencies'; import { useRefreshTransformList } from '../common'; import { ToastNotificationText } from '../components'; -import { useApi } from './use_api'; - export const useStartTransforms = () => { - const { overlays, theme } = useAppDependencies(); + const { http, overlays, theme } = useAppDependencies(); const refreshTransformList = useRefreshTransformList(); const toastNotifications = useToastNotifications(); - const api = useApi(); - - return async (transformsInfo: StartTransformsRequestSchema) => { - const results = await api.startTransforms(transformsInfo); - if (!isStartTransformsResponseSchema(results)) { + const mutation = useMutation({ + mutationFn: (reqBody: StartTransformsRequestSchema) => { + return http.post(addInternalBasePath(`start_transforms`), { + body: JSON.stringify(reqBody), + version: '1', + }); + }, + onError: (error) => { toastNotifications.addDanger({ title: i18n.translate( 'xpack.transform.stepCreateForm.startTransformResponseSchemaErrorMessage', @@ -40,40 +45,41 @@ export const useStartTransforms = () => { } ), text: toMountPoint( - , + , { theme$: theme.theme$ } ), }); - return; - } - - for (const transformId in results) { - // hasOwnProperty check to ensure only properties on object itself, and not its prototypes - if (results.hasOwnProperty(transformId)) { - const result = results[transformId]; - if (result.success === true) { - toastNotifications.addSuccess( - i18n.translate('xpack.transform.transformList.startTransformSuccessMessage', { - defaultMessage: 'Request to start transform {transformId} acknowledged.', - values: { transformId }, - }) - ); - } else { - toastNotifications.addError(new Error(JSON.stringify(result.error!.caused_by, null, 2)), { - title: i18n.translate('xpack.transform.transformList.startTransformErrorMessage', { - defaultMessage: 'An error occurred starting the transform {transformId}', - values: { transformId }, - }), - toastMessage: result.error!.reason, - }); + }, + onSuccess: (results) => { + for (const transformId in results) { + // hasOwnProperty check to ensure only properties on object itself, and not its prototypes + if (results.hasOwnProperty(transformId)) { + const result = results[transformId]; + if (result.success === true) { + toastNotifications.addSuccess( + i18n.translate('xpack.transform.transformList.startTransformSuccessMessage', { + defaultMessage: 'Request to start transform {transformId} acknowledged.', + values: { transformId }, + }) + ); + } else { + toastNotifications.addError( + new Error(JSON.stringify(result.error!.caused_by, null, 2)), + { + title: i18n.translate('xpack.transform.transformList.startTransformErrorMessage', { + defaultMessage: 'An error occurred starting the transform {transformId}', + values: { transformId }, + }), + toastMessage: result.error!.reason, + } + ); + } } } - } - refreshTransformList(); - }; + refreshTransformList(); + }, + }); + + return mutation; }; diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_create/step_create_form.test.tsx b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_create/step_create_form.test.tsx index 2e785c2d6680b..e2fa8912fc932 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_create/step_create_form.test.tsx +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_create/step_create_form.test.tsx @@ -7,6 +7,7 @@ import React from 'react'; import { render } from '@testing-library/react'; +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { StepCreateForm, StepCreateFormProps } from './step_create_form'; @@ -16,6 +17,7 @@ jest.mock('../../../../app_dependencies'); describe('Transform: ', () => { test('Minimal initialization', () => { // Arrange + const queryClient = new QueryClient(); const props: StepCreateFormProps = { createDataView: false, transformId: 'the-transform-id', @@ -35,7 +37,11 @@ describe('Transform: ', () => { onChange() {}, }; - const { getByText } = render(); + const { getByText } = render( + + + + ); // Act // Assert diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_create/step_create_form.tsx b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_create/step_create_form.tsx index d61b18632cef4..b0391c85c1146 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_create/step_create_form.tsx +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_create/step_create_form.tsx @@ -31,10 +31,8 @@ import { DISCOVER_APP_LOCATOR } from '@kbn/discover-plugin/common'; import { DuplicateDataViewError } from '@kbn/data-plugin/public'; import type { RuntimeField } from '@kbn/data-views-plugin/common'; import { isPopulatedObject } from '@kbn/ml-is-populated-object'; -import type { PutTransformsResponseSchema } from '../../../../../../common/api_schemas/transforms'; import { isGetTransformsStatsResponseSchema, - isPutTransformsResponseSchema, isStartTransformsResponseSchema, } from '../../../../../../common/api_schemas/type_guards'; import { PROGRESS_REFRESH_INTERVAL_MS } from '../../../../../../common/constants'; @@ -42,7 +40,7 @@ import { PROGRESS_REFRESH_INTERVAL_MS } from '../../../../../../common/constants import { getErrorMessage } from '../../../../../../common/utils/errors'; import { getTransformProgress } from '../../../../common'; -import { useApi } from '../../../../hooks/use_api'; +import { useCreateTransform, useGetTransformStats, useStartTransforms } from '../../../../hooks'; import { useAppDependencies, useToastNotifications } from '../../../../app_dependencies'; import { RedirectToTransformManagement } from '../../../../common/navigation'; import { ToastNotificationText } from '../../../../components'; @@ -129,103 +127,45 @@ export const StepCreateForm: FC = React.memo( }, [created, started, dataViewId]); const { overlays, theme } = useAppDependencies(); - const api = useApi(); + const { mutate: startTransforms } = useStartTransforms(); + const { mutate: createTransform } = useCreateTransform(transformId, transformConfig); - async function createTransform() { + function createTransformHandler(startAfterCreation = false) { setLoading(true); - const resp = await api.createTransform(transformId, transformConfig); - - if (!isPutTransformsResponseSchema(resp) || resp.errors.length > 0) { - let respErrors: - | PutTransformsResponseSchema['errors'] - | PutTransformsResponseSchema['errors'][number] - | undefined; - - if (isPutTransformsResponseSchema(resp) && resp.errors.length > 0) { - respErrors = resp.errors.length === 1 ? resp.errors[0] : resp.errors; - } - - toastNotifications.addDanger({ - title: i18n.translate('xpack.transform.stepCreateForm.createTransformErrorMessage', { - defaultMessage: 'An error occurred creating the transform {transformId}:', - values: { transformId }, - }), - text: toMountPoint( - , - { theme$: theme.theme$ } - ), - }); - setCreated(false); - setLoading(false); - return false; - } - - toastNotifications.addSuccess( - i18n.translate('xpack.transform.stepCreateForm.createTransformSuccessMessage', { - defaultMessage: 'Request to create transform {transformId} acknowledged.', - values: { transformId }, - }) - ); - setCreated(true); - setLoading(false); - - if (createDataView) { - createKibanaDataView(); - } - - return true; + createTransform(undefined, { + onError: () => { + setCreated(false); + }, + onSuccess: () => { + setCreated(true); + if (createDataView) { + createKibanaDataView(); + } + if (startAfterCreation) { + startTransform(); + } + }, + onSettled: () => { + setLoading(false); + }, + }); } - async function startTransform() { + function startTransform() { setLoading(true); - const resp = await api.startTransforms([{ id: transformId }]); - - if (isStartTransformsResponseSchema(resp) && resp[transformId]?.success === true) { - toastNotifications.addSuccess( - i18n.translate('xpack.transform.stepCreateForm.startTransformSuccessMessage', { - defaultMessage: 'Request to start transform {transformId} acknowledged.', - values: { transformId }, - }) - ); - setStarted(true); - setLoading(false); - return; - } - - const errorMessage = - isStartTransformsResponseSchema(resp) && resp[transformId]?.success === false - ? resp[transformId].error - : resp; - - toastNotifications.addDanger({ - title: i18n.translate('xpack.transform.stepCreateForm.startTransformErrorMessage', { - defaultMessage: 'An error occurred starting the transform {transformId}:', - values: { transformId }, - }), - text: toMountPoint( - , - { theme$: theme.theme$ } - ), + startTransforms([{ id: transformId }], { + onError: () => { + setStarted(false); + }, + onSuccess: (resp) => { + setStarted(isStartTransformsResponseSchema(resp) && resp[transformId]?.success === true); + }, + onSettled: () => { + setLoading(false); + }, }); - setStarted(false); - setLoading(false); - } - - async function createAndStartTransform() { - const acknowledged = await createTransform(); - if (acknowledged) { - await startTransform(); - } } const createKibanaDataView = async () => { @@ -288,57 +228,67 @@ export const StepCreateForm: FC = React.memo( const isBatchTransform = typeof transformConfig.sync === 'undefined'; - if ( - loading === false && - started === true && - progressPercentComplete === undefined && - isBatchTransform - ) { - // wrapping in function so we can keep the interval id in local scope - function startProgressBar() { - const interval = setInterval(async () => { - const stats = await api.getTransformStats(transformId); - - if ( - isGetTransformsStatsResponseSchema(stats) && - Array.isArray(stats.transforms) && - stats.transforms.length > 0 - ) { - const percent = - getTransformProgress({ - id: transformId, - config: { - ...transformConfig, - id: transformId, - }, - stats: stats.transforms[0], - }) || 0; - setProgressPercentComplete(percent); - if (percent >= 100) { - clearInterval(interval); - } - } else { - toastNotifications.addDanger({ - title: i18n.translate('xpack.transform.stepCreateForm.progressErrorMessage', { - defaultMessage: 'An error occurred getting the progress percentage:', - }), - text: toMountPoint( - , - { theme$: theme.theme$ } - ), - }); - clearInterval(interval); - } - }, PROGRESS_REFRESH_INTERVAL_MS); + useEffect(() => { + if ( + loading === false && + started === true && + progressPercentComplete === undefined && + isBatchTransform + ) { setProgressPercentComplete(0); } + }, [loading, started, progressPercentComplete, isBatchTransform]); + + const progressBarRefetchEnabled = + isBatchTransform && + typeof progressPercentComplete === 'number' && + progressPercentComplete < 100; + const progressBarRefetchInterval = progressBarRefetchEnabled + ? PROGRESS_REFRESH_INTERVAL_MS + : false; + + const { data: stats } = useGetTransformStats( + transformId, + progressBarRefetchEnabled, + progressBarRefetchInterval + ); - startProgressBar(); - } + useEffect(() => { + if (stats === undefined) { + return; + } + + if ( + isGetTransformsStatsResponseSchema(stats) && + Array.isArray(stats.transforms) && + stats.transforms.length > 0 + ) { + const percent = + getTransformProgress({ + id: transformId, + config: { + ...transformConfig, + id: transformId, + }, + stats: stats.transforms[0], + }) || 0; + setProgressPercentComplete(percent); + } else { + toastNotifications.addDanger({ + title: i18n.translate('xpack.transform.stepCreateForm.progressErrorMessage', { + defaultMessage: 'An error occurred getting the progress percentage:', + }), + text: toMountPoint( + , + { theme$: theme.theme$ } + ), + }); + } + }, [overlays, stats, theme, toastNotifications, transformConfig, transformId]); function getTransformConfigDevConsoleStatement() { return `PUT _transform/${transformId}\n${JSON.stringify(transformConfig, null, 2)}\n\n`; @@ -362,7 +312,7 @@ export const StepCreateForm: FC = React.memo( createTransformHandler(true)} data-test-subj="transformWizardCreateAndStartButton" > {i18n.translate('xpack.transform.stepCreateForm.createAndStartTransformButton', { @@ -436,7 +386,7 @@ export const StepCreateForm: FC = React.memo( createTransformHandler()} data-test-subj="transformWizardCreateButton" > {i18n.translate('xpack.transform.stepCreateForm.createTransformButton', { diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_start/use_start_action.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_start/use_start_action.tsx index 20910cf5fa0a5..b033cb514cbf2 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_start/use_start_action.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_start/use_start_action.tsx @@ -19,7 +19,7 @@ export type StartAction = ReturnType; export const useStartAction = (forceDisable: boolean, transformNodes: number) => { const { canStartStopTransform } = useContext(AuthorizationContext).capabilities; - const startTransforms = useStartTransforms(); + const { mutate: startTransforms } = useStartTransforms(); const [isModalVisible, setModalVisible] = useState(false); const [items, setItems] = useState([]); diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/transform_management_section.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/transform_management_section.tsx index 045f1bdbc38e0..1a8db994e0fec 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/transform_management_section.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/transform_management_section.tsx @@ -176,8 +176,8 @@ export const TransformManagement: FC = () => { { - await deleteTransforms( + onClick={() => + deleteTransforms( // If transform task doesn't have any corresponding config // we won't know what the destination index or data view would be // and should be force deleted @@ -190,8 +190,8 @@ export const TransformManagement: FC = () => { deleteDestDataView: false, forceDelete: true, } - ); - }} + ) + } > Date: Tue, 22 Aug 2023 14:37:31 +0200 Subject: [PATCH 04/53] fix i18n --- x-pack/plugins/translations/translations/fr-FR.json | 2 -- x-pack/plugins/translations/translations/ja-JP.json | 2 -- x-pack/plugins/translations/translations/zh-CN.json | 2 -- 3 files changed, 6 deletions(-) diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index 147738ec2eda0..9f0b2ff73b908 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -37794,8 +37794,6 @@ "xpack.transform.stepCreateForm.createTransformErrorMessage": "Une erreur s'est produite lors de la création de la transformation {transformId} :", "xpack.transform.stepCreateForm.createTransformSuccessMessage": "La requête pour créer la transformation {transformId} a été reconnue.", "xpack.transform.stepCreateForm.duplicateDataViewErrorMessage": "Une erreur est survenue lors de la création de la vue de données Kibana {dataViewName} : La vue de données existe déjà.", - "xpack.transform.stepCreateForm.startTransformErrorMessage": "Une erreur s'est produite lors du démarrage de la transformation {transformId} :", - "xpack.transform.stepCreateForm.startTransformSuccessMessage": "La requête pour démarrer la transformation {transformId} a été reconnue.", "xpack.transform.stepDefineForm.invalidKuerySyntaxErrorMessageQueryBar": "Requête non valide : {queryErrorMessage}", "xpack.transform.stepDefineForm.queryPlaceholderKql": "Par exemple, {example}", "xpack.transform.stepDefineForm.queryPlaceholderLucene": "Par exemple, {example}", diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index ba3c415751725..e1129d3faa9d1 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -37793,8 +37793,6 @@ "xpack.transform.stepCreateForm.createTransformErrorMessage": "変換 {transformId} の取得中にエラーが発生しました。", "xpack.transform.stepCreateForm.createTransformSuccessMessage": "変換 {transformId} の作成リクエストが受け付けられました。", "xpack.transform.stepCreateForm.duplicateDataViewErrorMessage": "Kibanaデータビュー{dataViewName}の作成中にエラーが発生しました:データビューはすでに存在します。", - "xpack.transform.stepCreateForm.startTransformErrorMessage": "変換 {transformId} の開始中にエラーが発生しました。", - "xpack.transform.stepCreateForm.startTransformSuccessMessage": "変換 {transformId} の開始リクエストが受け付けられました。", "xpack.transform.stepDefineForm.invalidKuerySyntaxErrorMessageQueryBar": "無効なクエリ:{queryErrorMessage}", "xpack.transform.stepDefineForm.queryPlaceholderKql": "例: {example}.", "xpack.transform.stepDefineForm.queryPlaceholderLucene": "例: {example}.", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index be39a446a11a8..a7195f24d0c46 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -37787,8 +37787,6 @@ "xpack.transform.stepCreateForm.createTransformErrorMessage": "创建转换 {transformId} 时出错:", "xpack.transform.stepCreateForm.createTransformSuccessMessage": "创建转换 {transformId} 的请求已确认。", "xpack.transform.stepCreateForm.duplicateDataViewErrorMessage": "创建 Kibana 数据视图 {dataViewName} 时发生错误:数据视图已存在。", - "xpack.transform.stepCreateForm.startTransformErrorMessage": "启动转换 {transformId} 时发生错误:", - "xpack.transform.stepCreateForm.startTransformSuccessMessage": "启动转换 {transformId} 的请求已确认。", "xpack.transform.stepDefineForm.invalidKuerySyntaxErrorMessageQueryBar": "无效查询:{queryErrorMessage}", "xpack.transform.stepDefineForm.queryPlaceholderKql": "例如,{example}", "xpack.transform.stepDefineForm.queryPlaceholderLucene": "例如,{example}", From c23dc685d68b26b031d688b140aa968efad9e5e9 Mon Sep 17 00:00:00 2001 From: Walter Rafelsberger Date: Tue, 22 Aug 2023 14:48:44 +0200 Subject: [PATCH 05/53] migrate cloning to use react-query --- x-pack/plugins/transform/common/constants.ts | 6 +- .../transform/public/app/common/transform.ts | 3 +- .../public/app/hooks/__mocks__/use_api.ts | 6 -- .../transform/public/app/hooks/index.ts | 1 + .../transform/public/app/hooks/use_api.ts | 12 --- .../public/app/hooks/use_get_transform.tsx | 40 ++++++++++ .../hooks/use_get_transform_audit_messages.ts | 2 +- .../app/hooks/use_get_transform_stats.ts | 2 +- .../public/app/hooks/use_get_transforms.ts | 2 +- .../clone_transform_section.tsx | 73 ++++++++++--------- 10 files changed, 87 insertions(+), 60 deletions(-) create mode 100644 x-pack/plugins/transform/public/app/hooks/use_get_transform.tsx diff --git a/x-pack/plugins/transform/common/constants.ts b/x-pack/plugins/transform/common/constants.ts index eb4943f2e6706..b6518c1fa241d 100644 --- a/x-pack/plugins/transform/common/constants.ts +++ b/x-pack/plugins/transform/common/constants.ts @@ -34,8 +34,10 @@ export const addExternalBasePath = (uri: string): string => `${EXTERNAL_API_BASE export const TRANSFORM_REACT_QUERY_KEYS = { PRIVILEGES: 'transform.privileges', - TRANSFORMS_LIST: 'transform.transforms_list', - TRANSFORM_STATS: 'transform.transform_stats', + GET_TRANSFORM: 'transform.get_transform', + GET_TRANSFORM_AUDIT_MESSAGES: 'transform.get_transform_audit_messages', + GET_TRANSFORM_STATS: 'transform.get_transform_stats', + GET_TRANSFORMS: 'transform.get_transforms', } as const; // In order to create a transform, the API requires the following privileges: diff --git a/x-pack/plugins/transform/public/app/common/transform.ts b/x-pack/plugins/transform/public/app/common/transform.ts index 34bbb82805c50..6339917a41db3 100644 --- a/x-pack/plugins/transform/public/app/common/transform.ts +++ b/x-pack/plugins/transform/public/app/common/transform.ts @@ -28,7 +28,8 @@ export const useRefreshTransformList = () => { const queryClient = useQueryClient(); return useCallback(() => { - queryClient.invalidateQueries([TRANSFORM_REACT_QUERY_KEYS.TRANSFORMS_LIST]); + queryClient.invalidateQueries([TRANSFORM_REACT_QUERY_KEYS.GET_TRANSFORMS]); + queryClient.invalidateQueries([TRANSFORM_REACT_QUERY_KEYS.GET_TRANSFORM_AUDIT_MESSAGES]); }, [queryClient]); }; diff --git a/x-pack/plugins/transform/public/app/hooks/__mocks__/use_api.ts b/x-pack/plugins/transform/public/app/hooks/__mocks__/use_api.ts index f76de90a1259a..763e754bc4aa8 100644 --- a/x-pack/plugins/transform/public/app/hooks/__mocks__/use_api.ts +++ b/x-pack/plugins/transform/public/app/hooks/__mocks__/use_api.ts @@ -17,7 +17,6 @@ import type { StopTransformsResponseSchema, } from '../../../../common/api_schemas/stop_transforms'; import type { - GetTransformsResponseSchema, PostTransformsPreviewRequestSchema, PostTransformsPreviewResponseSchema, } from '../../../../common/api_schemas/transforms'; @@ -37,11 +36,6 @@ export interface FieldHistogramRequestConfig { } const apiFactory = () => ({ - async getTransform( - transformId: TransformId - ): Promise { - return Promise.resolve({ count: 0, transforms: [] }); - }, async getTransformStats( transformId: TransformId ): Promise { diff --git a/x-pack/plugins/transform/public/app/hooks/index.ts b/x-pack/plugins/transform/public/app/hooks/index.ts index d77f60439609b..b3283da96a65a 100644 --- a/x-pack/plugins/transform/public/app/hooks/index.ts +++ b/x-pack/plugins/transform/public/app/hooks/index.ts @@ -9,6 +9,7 @@ export { useApi } from './use_api'; export { useCreateTransform } from './use_create_transform'; export { useDocumentationLinks } from './use_documentation_links'; export { useGetTransformAuditMessages } from './use_get_transform_audit_messages'; +export { useGetTransform } from './use_get_transform'; export { useGetTransforms } from './use_get_transforms'; export { useGetTransformStats } from './use_get_transform_stats'; export { useDeleteTransforms, useDeleteIndexAndTargetIndex } from './use_delete_transform'; diff --git a/x-pack/plugins/transform/public/app/hooks/use_api.ts b/x-pack/plugins/transform/public/app/hooks/use_api.ts index 14547f0dd834a..edd839b447805 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_api.ts +++ b/x-pack/plugins/transform/public/app/hooks/use_api.ts @@ -33,7 +33,6 @@ import type { ScheduleNowTransformsResponseSchema, } from '../../../common/api_schemas/schedule_now_transforms'; import type { - GetTransformsResponseSchema, PostTransformsPreviewRequestSchema, PostTransformsPreviewResponseSchema, } from '../../../common/api_schemas/transforms'; @@ -61,17 +60,6 @@ export const useApi = () => { return useMemo( () => ({ - async getTransform( - transformId: TransformId - ): Promise { - try { - return await http.get(addInternalBasePath(`transforms/${transformId}`), { - version: '1', - }); - } catch (e) { - return e; - } - }, async getTransformStats( transformId: TransformId ): Promise { diff --git a/x-pack/plugins/transform/public/app/hooks/use_get_transform.tsx b/x-pack/plugins/transform/public/app/hooks/use_get_transform.tsx new file mode 100644 index 0000000000000..e3038706758a4 --- /dev/null +++ b/x-pack/plugins/transform/public/app/hooks/use_get_transform.tsx @@ -0,0 +1,40 @@ +/* + * 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. + */ + +/* + * 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 { useQuery } from '@tanstack/react-query'; + +import type { IHttpFetchError } from '@kbn/core-http-browser'; + +import type { GetTransformsResponseSchema } from '../../../common/api_schemas/transforms'; +import { addInternalBasePath, TRANSFORM_REACT_QUERY_KEYS } from '../../../common/constants'; +import type { TransformId } from '../../../common/types/transform'; + +import { useAppDependencies } from '../app_dependencies'; + +export const useGetTransform = (transformId: TransformId, enabled?: boolean) => { + const { http } = useAppDependencies(); + + return useQuery( + [TRANSFORM_REACT_QUERY_KEYS.GET_TRANSFORM, transformId], + async ({ signal }) => + await http.get( + addInternalBasePath(`transforms/${transformId}`), + { + version: '1', + signal, + } + ), + { enabled } + ); +}; diff --git a/x-pack/plugins/transform/public/app/hooks/use_get_transform_audit_messages.ts b/x-pack/plugins/transform/public/app/hooks/use_get_transform_audit_messages.ts index 09e0bdf23571d..fec306f455417 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_get_transform_audit_messages.ts +++ b/x-pack/plugins/transform/public/app/hooks/use_get_transform_audit_messages.ts @@ -25,7 +25,7 @@ export const useGetTransformAuditMessages = ( const query = { sortField, sortDirection }; return useQuery( - [TRANSFORM_REACT_QUERY_KEYS.TRANSFORMS_LIST, transformId, query], + [TRANSFORM_REACT_QUERY_KEYS.GET_TRANSFORM_AUDIT_MESSAGES, transformId, query], async ({ signal }) => await http.get( addInternalBasePath(`transforms/${transformId}/messages`), diff --git a/x-pack/plugins/transform/public/app/hooks/use_get_transform_stats.ts b/x-pack/plugins/transform/public/app/hooks/use_get_transform_stats.ts index a5df06f2ece59..c6f1951b85819 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_get_transform_stats.ts +++ b/x-pack/plugins/transform/public/app/hooks/use_get_transform_stats.ts @@ -23,7 +23,7 @@ export const useGetTransformStats = ( const { http } = useAppDependencies(); return useQuery( - [TRANSFORM_REACT_QUERY_KEYS.TRANSFORM_STATS, transformId], + [TRANSFORM_REACT_QUERY_KEYS.GET_TRANSFORM_STATS, transformId], async ({ signal }) => await http.get( addInternalBasePath(`transforms/${transformId}/_stats`), diff --git a/x-pack/plugins/transform/public/app/hooks/use_get_transforms.ts b/x-pack/plugins/transform/public/app/hooks/use_get_transforms.ts index ee644f9dd8d32..f97eaf671fb97 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_get_transforms.ts +++ b/x-pack/plugins/transform/public/app/hooks/use_get_transforms.ts @@ -37,7 +37,7 @@ export const useGetTransforms = () => { const { http } = useAppDependencies(); return useQuery( - [TRANSFORM_REACT_QUERY_KEYS.TRANSFORMS_LIST], + [TRANSFORM_REACT_QUERY_KEYS.GET_TRANSFORMS], async ({ signal }) => { const update: UseGetTransformsResponse = { tableRows: [], diff --git a/x-pack/plugins/transform/public/app/sections/clone_transform/clone_transform_section.tsx b/x-pack/plugins/transform/public/app/sections/clone_transform/clone_transform_section.tsx index 2131ae616553d..04e04f4e47b81 100644 --- a/x-pack/plugins/transform/public/app/sections/clone_transform/clone_transform_section.tsx +++ b/x-pack/plugins/transform/public/app/sections/clone_transform/clone_transform_section.tsx @@ -23,7 +23,7 @@ import { isHttpFetchError } from '@kbn/core-http-browser'; import { APP_CREATE_TRANSFORM_CLUSTER_PRIVILEGES } from '../../../../common/constants'; import { TransformConfigUnion } from '../../../../common/types/transform'; -import { useApi } from '../../hooks/use_api'; +import { useGetTransform } from '../../hooks'; import { useDocumentationLinks } from '../../hooks/use_documentation_links'; import { useSearchItems } from '../../hooks/use_search_items'; @@ -45,8 +45,6 @@ export const CloneTransformSection: FC = ({ match, location }) => { docTitleService.setTitle('createTransform'); }, []); - const api = useApi(); - const { esTransform } = useDocumentationLinks(); const transformId = match.params.transformId; @@ -56,52 +54,55 @@ export const CloneTransformSection: FC = ({ match, location }) => { const [isInitialized, setIsInitialized] = useState(false); const { error: searchItemsError, searchItems, setSavedObjectId } = useSearchItems(undefined); - const fetchTransformConfig = async () => { + useEffect(() => { + if (dataViewId === undefined) { + setErrorMessage( + i18n.translate('xpack.transform.clone.fetchErrorPromptText', { + defaultMessage: 'Could not fetch the Kibana data view ID.', + }) + ); + } else { + setSavedObjectId(dataViewId); + } + }, [dataViewId, setSavedObjectId]); + + useEffect(() => { if (searchItemsError !== undefined) { setTransformConfig(undefined); setErrorMessage(searchItemsError); setIsInitialized(true); - return; } + }, [searchItemsError]); + + const { data: transformConfigs, error } = useGetTransform( + transformId, + searchItemsError === undefined + ); - const transformConfigs = await api.getTransform(transformId); - if (isHttpFetchError(transformConfigs)) { + useEffect(() => { + if (isHttpFetchError(error) && error.message !== errorMessage) { setTransformConfig(undefined); - setErrorMessage(transformConfigs.message); + setErrorMessage(error.message); setIsInitialized(true); return; } - try { - if (dataViewId === undefined) { - throw new Error( - i18n.translate('xpack.transform.clone.fetchErrorPromptText', { - defaultMessage: 'Could not fetch the Kibana data view ID.', - }) - ); - } - - setSavedObjectId(dataViewId); - - setTransformConfig(overrideTransformForCloning(transformConfigs.transforms[0])); - setErrorMessage(undefined); - setIsInitialized(true); - } catch (e) { - setTransformConfig(undefined); - if (e.message !== undefined) { - setErrorMessage(e.message); - } else { - setErrorMessage(JSON.stringify(e, null, 2)); + if (transformConfigs !== undefined) { + try { + setTransformConfig(overrideTransformForCloning(transformConfigs.transforms[0])); + setErrorMessage(undefined); + setIsInitialized(true); + } catch (e) { + setTransformConfig(undefined); + if (e.message !== undefined) { + setErrorMessage(e.message); + } else { + setErrorMessage(JSON.stringify(e, null, 2)); + } + setIsInitialized(true); } - setIsInitialized(true); } - }; - - useEffect(() => { - fetchTransformConfig(); - // The effect should only be called once. - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); + }, [error, errorMessage, transformConfigs]); const docsLink = ( Date: Tue, 22 Aug 2023 14:52:24 +0200 Subject: [PATCH 06/53] remove getTransformStats from useApi --- .../transform/public/app/hooks/__mocks__/use_api.ts | 6 ------ x-pack/plugins/transform/public/app/hooks/use_api.ts | 12 ------------ 2 files changed, 18 deletions(-) diff --git a/x-pack/plugins/transform/public/app/hooks/__mocks__/use_api.ts b/x-pack/plugins/transform/public/app/hooks/__mocks__/use_api.ts index 763e754bc4aa8..f278460c637b9 100644 --- a/x-pack/plugins/transform/public/app/hooks/__mocks__/use_api.ts +++ b/x-pack/plugins/transform/public/app/hooks/__mocks__/use_api.ts @@ -20,7 +20,6 @@ import type { PostTransformsPreviewRequestSchema, PostTransformsPreviewResponseSchema, } from '../../../../common/api_schemas/transforms'; -import type { GetTransformsStatsResponseSchema } from '../../../../common/api_schemas/transforms_stats'; import type { PostTransformsUpdateRequestSchema, PostTransformsUpdateResponseSchema, @@ -36,11 +35,6 @@ export interface FieldHistogramRequestConfig { } const apiFactory = () => ({ - async getTransformStats( - transformId: TransformId - ): Promise { - return Promise.resolve({ count: 0, transforms: [] }); - }, async updateTransform( transformId: TransformId, transformConfig: PostTransformsUpdateRequestSchema diff --git a/x-pack/plugins/transform/public/app/hooks/use_api.ts b/x-pack/plugins/transform/public/app/hooks/use_api.ts index edd839b447805..fab00296f73f9 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_api.ts +++ b/x-pack/plugins/transform/public/app/hooks/use_api.ts @@ -40,7 +40,6 @@ import type { PostTransformsUpdateRequestSchema, PostTransformsUpdateResponseSchema, } from '../../../common/api_schemas/update_transforms'; -import type { GetTransformsStatsResponseSchema } from '../../../common/api_schemas/transforms_stats'; import type { TransformId } from '../../../common/types/transform'; import { addInternalBasePath } from '../../../common/constants'; import type { EsIndex } from '../../../common/types/es_index'; @@ -60,17 +59,6 @@ export const useApi = () => { return useMemo( () => ({ - async getTransformStats( - transformId: TransformId - ): Promise { - try { - return await http.get(addInternalBasePath(`transforms/${transformId}/_stats`), { - version: '1', - }); - } catch (e) { - return e; - } - }, async updateTransform( transformId: TransformId, transformConfig: PostTransformsUpdateRequestSchema From a2978b2ad7eab64d41b86e6ccb3e087facc5656d Mon Sep 17 00:00:00 2001 From: Walter Rafelsberger Date: Tue, 22 Aug 2023 15:11:40 +0200 Subject: [PATCH 07/53] migrate update to use react-query --- .../public/app/hooks/__mocks__/use_api.ts | 24 --------- .../transform/public/app/hooks/index.ts | 1 + .../transform/public/app/hooks/use_api.ts | 18 ------- .../public/app/hooks/use_update_transform.ts | 52 +++++++++++++++++++ .../edit_transform_update_button.tsx | 35 ++++--------- 5 files changed, 64 insertions(+), 66 deletions(-) create mode 100644 x-pack/plugins/transform/public/app/hooks/use_update_transform.ts diff --git a/x-pack/plugins/transform/public/app/hooks/__mocks__/use_api.ts b/x-pack/plugins/transform/public/app/hooks/__mocks__/use_api.ts index f278460c637b9..4e3035ea7da6f 100644 --- a/x-pack/plugins/transform/public/app/hooks/__mocks__/use_api.ts +++ b/x-pack/plugins/transform/public/app/hooks/__mocks__/use_api.ts @@ -10,7 +10,6 @@ import type { IHttpFetchError } from '@kbn/core-http-browser'; import { KBN_FIELD_TYPES } from '@kbn/field-types'; import { DEFAULT_SAMPLER_SHARD_SIZE } from '@kbn/ml-agg-utils'; -import type { TransformId } from '../../../../common/types/transform'; import type { FieldHistogramsResponseSchema } from '../../../../common/api_schemas/field_histograms'; import type { StopTransformsRequestSchema, @@ -20,10 +19,6 @@ import type { PostTransformsPreviewRequestSchema, PostTransformsPreviewResponseSchema, } from '../../../../common/api_schemas/transforms'; -import type { - PostTransformsUpdateRequestSchema, - PostTransformsUpdateResponseSchema, -} from '../../../../common/api_schemas/update_transforms'; import type { EsIndex } from '../../../../common/types/es_index'; @@ -35,25 +30,6 @@ export interface FieldHistogramRequestConfig { } const apiFactory = () => ({ - async updateTransform( - transformId: TransformId, - transformConfig: PostTransformsUpdateRequestSchema - ): Promise { - return Promise.resolve({ - id: 'the-test-id', - source: { index: ['the-index-name'], query: { match_all: {} } }, - dest: { index: 'user-the-destination-index-name' }, - frequency: '10m', - pivot: { - group_by: { the_group: { terms: { field: 'the-group-by-field' } } }, - aggregations: { the_agg: { value_count: { field: 'the-agg-field' } } }, - }, - description: 'the-description', - settings: { docs_per_second: null }, - version: '8.0.0', - create_time: 1598860879097, - }); - }, async getTransformsPreview( obj: PostTransformsPreviewRequestSchema ): Promise { diff --git a/x-pack/plugins/transform/public/app/hooks/index.ts b/x-pack/plugins/transform/public/app/hooks/index.ts index b3283da96a65a..5d44385247434 100644 --- a/x-pack/plugins/transform/public/app/hooks/index.ts +++ b/x-pack/plugins/transform/public/app/hooks/index.ts @@ -17,3 +17,4 @@ export { useResetTransforms } from './use_reset_transform'; export { useScheduleNowTransforms } from './use_schedule_now_transform'; export { useStartTransforms } from './use_start_transform'; export { useStopTransforms } from './use_stop_transform'; +export { useUpdateTransform } from './use_update_transform'; diff --git a/x-pack/plugins/transform/public/app/hooks/use_api.ts b/x-pack/plugins/transform/public/app/hooks/use_api.ts index fab00296f73f9..45a2579078e7f 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_api.ts +++ b/x-pack/plugins/transform/public/app/hooks/use_api.ts @@ -36,11 +36,6 @@ import type { PostTransformsPreviewRequestSchema, PostTransformsPreviewResponseSchema, } from '../../../common/api_schemas/transforms'; -import type { - PostTransformsUpdateRequestSchema, - PostTransformsUpdateResponseSchema, -} from '../../../common/api_schemas/update_transforms'; -import type { TransformId } from '../../../common/types/transform'; import { addInternalBasePath } from '../../../common/constants'; import type { EsIndex } from '../../../common/types/es_index'; import type { EsIngestPipeline } from '../../../common/types/es_ingest_pipeline'; @@ -59,19 +54,6 @@ export const useApi = () => { return useMemo( () => ({ - async updateTransform( - transformId: TransformId, - transformConfig: PostTransformsUpdateRequestSchema - ): Promise { - try { - return await http.post(addInternalBasePath(`transforms/${transformId}/_update`), { - body: JSON.stringify(transformConfig), - version: '1', - }); - } catch (e) { - return e; - } - }, async getTransformsPreview( obj: PostTransformsPreviewRequestSchema ): Promise { diff --git a/x-pack/plugins/transform/public/app/hooks/use_update_transform.ts b/x-pack/plugins/transform/public/app/hooks/use_update_transform.ts new file mode 100644 index 0000000000000..ec1c572a66b86 --- /dev/null +++ b/x-pack/plugins/transform/public/app/hooks/use_update_transform.ts @@ -0,0 +1,52 @@ +/* + * 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 { useMutation } from '@tanstack/react-query'; + +import { i18n } from '@kbn/i18n'; + +import type { + PostTransformsUpdateRequestSchema, + PostTransformsUpdateResponseSchema, +} from '../../../common/api_schemas/update_transforms'; +import { addInternalBasePath } from '../../../common/constants'; +import type { TransformId } from '../../../common/types/transform'; + +import { useAppDependencies, useToastNotifications } from '../app_dependencies'; +import { useRefreshTransformList } from '../common'; + +export const useUpdateTransform = ( + transformId: TransformId, + transformConfig: PostTransformsUpdateRequestSchema +) => { + const { http } = useAppDependencies(); + const refreshTransformList = useRefreshTransformList(); + const toastNotifications = useToastNotifications(); + + const mutation = useMutation({ + mutationFn: () => { + return http.post( + addInternalBasePath(`transforms/${transformId}/_update`), + { + body: JSON.stringify(transformConfig), + version: '1', + } + ); + }, + onSuccess: () => { + toastNotifications.addSuccess( + i18n.translate('xpack.transform.transformList.editTransformSuccessMessage', { + defaultMessage: 'Transform {transformId} updated.', + values: { transformId }, + }) + ); + refreshTransformList(); + }, + }); + + return mutation; +}; diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/edit_transform_flyout/edit_transform_update_button.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/edit_transform_flyout/edit_transform_update_button.tsx index 59bacf76fd39f..7b00ce29bf8f3 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/edit_transform_flyout/edit_transform_update_button.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/edit_transform_flyout/edit_transform_update_button.tsx @@ -11,12 +11,9 @@ import { EuiButton } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { isPostTransformsUpdateResponseSchema } from '../../../../../../common/api_schemas/type_guards'; import { getErrorMessage } from '../../../../../../common/utils/errors'; -import { useRefreshTransformList } from '../../../../common'; -import { useToastNotifications } from '../../../../app_dependencies'; -import { useApi } from '../../../../hooks/use_api'; +import { useUpdateTransform } from '../../../../hooks'; import { useEditTransformFlyout } from './use_edit_transform_flyout'; @@ -25,34 +22,24 @@ interface EditTransformUpdateButtonProps { } export const EditTransformUpdateButton: FC = ({ closeFlyout }) => { - const api = useApi(); - const refreshTransformList = useRefreshTransformList(); - const toastNotifications = useToastNotifications(); - const requestConfig = useEditTransformFlyout('requestConfig'); const isUpdateButtonDisabled = useEditTransformFlyout('isUpdateButtonDisabled'); const config = useEditTransformFlyout('config'); const { apiError } = useEditTransformFlyout('actions'); + const { mutate: updateTransfrom } = useUpdateTransform(config.id, requestConfig); + async function submitFormHandler() { apiError(undefined); - const transformId = config.id; - - const resp = await api.updateTransform(transformId, requestConfig); - - if (!isPostTransformsUpdateResponseSchema(resp)) { - apiError(getErrorMessage(resp)); - return; - } - toastNotifications.addSuccess( - i18n.translate('xpack.transform.transformList.editTransformSuccessMessage', { - defaultMessage: 'Transform {transformId} updated.', - values: { transformId }, - }) - ); - closeFlyout(); - refreshTransformList(); + updateTransfrom(undefined, { + onError: (error) => { + apiError(getErrorMessage(error)); + }, + onSuccess: () => { + closeFlyout(); + }, + }); } return ( From 1f55030b999ac354afd16c1dec9884f96c5c9d77 Mon Sep 17 00:00:00 2001 From: Walter Rafelsberger Date: Tue, 22 Aug 2023 16:43:54 +0200 Subject: [PATCH 08/53] migrate preview to use react-query --- x-pack/plugins/transform/common/constants.ts | 1 + .../public/app/hooks/__mocks__/use_api.ts | 26 --- .../transform/public/app/hooks/index.ts | 1 + .../transform/public/app/hooks/use_api.ts | 16 -- .../public/app/hooks/use_get_transform.tsx | 7 - .../app/hooks/use_get_transforms_preview.ts | 39 ++++ .../app/hooks/use_transform_config_data.ts | 167 +++++++++--------- .../step_define/step_define_form.test.tsx | 18 +- .../step_define/step_define_summary.test.tsx | 10 +- .../step_details/step_details_form.tsx | 92 +++++----- 10 files changed, 194 insertions(+), 183 deletions(-) create mode 100644 x-pack/plugins/transform/public/app/hooks/use_get_transforms_preview.ts diff --git a/x-pack/plugins/transform/common/constants.ts b/x-pack/plugins/transform/common/constants.ts index b6518c1fa241d..367459e566019 100644 --- a/x-pack/plugins/transform/common/constants.ts +++ b/x-pack/plugins/transform/common/constants.ts @@ -38,6 +38,7 @@ export const TRANSFORM_REACT_QUERY_KEYS = { GET_TRANSFORM_AUDIT_MESSAGES: 'transform.get_transform_audit_messages', GET_TRANSFORM_STATS: 'transform.get_transform_stats', GET_TRANSFORMS: 'transform.get_transforms', + GET_TRANSFORMS_PREVIEW: 'transform.get_transforms_preview', } as const; // In order to create a transform, the API requires the following privileges: diff --git a/x-pack/plugins/transform/public/app/hooks/__mocks__/use_api.ts b/x-pack/plugins/transform/public/app/hooks/__mocks__/use_api.ts index 4e3035ea7da6f..249198b2e600f 100644 --- a/x-pack/plugins/transform/public/app/hooks/__mocks__/use_api.ts +++ b/x-pack/plugins/transform/public/app/hooks/__mocks__/use_api.ts @@ -15,10 +15,6 @@ import type { StopTransformsRequestSchema, StopTransformsResponseSchema, } from '../../../../common/api_schemas/stop_transforms'; -import type { - PostTransformsPreviewRequestSchema, - PostTransformsPreviewResponseSchema, -} from '../../../../common/api_schemas/transforms'; import type { EsIndex } from '../../../../common/types/es_index'; @@ -30,28 +26,6 @@ export interface FieldHistogramRequestConfig { } const apiFactory = () => ({ - async getTransformsPreview( - obj: PostTransformsPreviewRequestSchema - ): Promise { - return Promise.resolve({ - generated_dest_index: { - mappings: { - _meta: { - _transform: { - transform: 'the-transform', - version: { create: 'the-version' }, - creation_date_in_millis: 0, - }, - created_by: 'mock', - }, - properties: {}, - }, - settings: { index: { number_of_shards: '1', auto_expand_replicas: '0-1' } }, - aliases: {}, - }, - preview: [], - }); - }, async stopTransforms( transformsInfo: StopTransformsRequestSchema ): Promise { diff --git a/x-pack/plugins/transform/public/app/hooks/index.ts b/x-pack/plugins/transform/public/app/hooks/index.ts index 5d44385247434..71789989ba5ff 100644 --- a/x-pack/plugins/transform/public/app/hooks/index.ts +++ b/x-pack/plugins/transform/public/app/hooks/index.ts @@ -11,6 +11,7 @@ export { useDocumentationLinks } from './use_documentation_links'; export { useGetTransformAuditMessages } from './use_get_transform_audit_messages'; export { useGetTransform } from './use_get_transform'; export { useGetTransforms } from './use_get_transforms'; +export { useGetTransformsPreview } from './use_get_transforms_preview'; export { useGetTransformStats } from './use_get_transform_stats'; export { useDeleteTransforms, useDeleteIndexAndTargetIndex } from './use_delete_transform'; export { useResetTransforms } from './use_reset_transform'; diff --git a/x-pack/plugins/transform/public/app/hooks/use_api.ts b/x-pack/plugins/transform/public/app/hooks/use_api.ts index 45a2579078e7f..e6fd8542f9ba6 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_api.ts +++ b/x-pack/plugins/transform/public/app/hooks/use_api.ts @@ -32,10 +32,6 @@ import type { ScheduleNowTransformsRequestSchema, ScheduleNowTransformsResponseSchema, } from '../../../common/api_schemas/schedule_now_transforms'; -import type { - PostTransformsPreviewRequestSchema, - PostTransformsPreviewResponseSchema, -} from '../../../common/api_schemas/transforms'; import { addInternalBasePath } from '../../../common/constants'; import type { EsIndex } from '../../../common/types/es_index'; import type { EsIngestPipeline } from '../../../common/types/es_ingest_pipeline'; @@ -54,18 +50,6 @@ export const useApi = () => { return useMemo( () => ({ - async getTransformsPreview( - obj: PostTransformsPreviewRequestSchema - ): Promise { - try { - return await http.post(addInternalBasePath(`transforms/_preview`), { - body: JSON.stringify(obj), - version: '1', - }); - } catch (e) { - return e; - } - }, async reauthorizeTransforms( reqBody: ReauthorizeTransformsRequestSchema ): Promise { diff --git a/x-pack/plugins/transform/public/app/hooks/use_get_transform.tsx b/x-pack/plugins/transform/public/app/hooks/use_get_transform.tsx index e3038706758a4..4cccc76295d52 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_get_transform.tsx +++ b/x-pack/plugins/transform/public/app/hooks/use_get_transform.tsx @@ -5,13 +5,6 @@ * 2.0. */ -/* - * 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 { useQuery } from '@tanstack/react-query'; import type { IHttpFetchError } from '@kbn/core-http-browser'; diff --git a/x-pack/plugins/transform/public/app/hooks/use_get_transforms_preview.ts b/x-pack/plugins/transform/public/app/hooks/use_get_transforms_preview.ts new file mode 100644 index 0000000000000..096c966e53311 --- /dev/null +++ b/x-pack/plugins/transform/public/app/hooks/use_get_transforms_preview.ts @@ -0,0 +1,39 @@ +/* + * 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 { useQuery } from '@tanstack/react-query'; + +import type { IHttpFetchError } from '@kbn/core-http-browser'; + +import type { + PostTransformsPreviewRequestSchema, + PostTransformsPreviewResponseSchema, +} from '../../../common/api_schemas/transforms'; +import { addInternalBasePath, TRANSFORM_REACT_QUERY_KEYS } from '../../../common/constants'; + +import { useAppDependencies } from '../app_dependencies'; + +export const useGetTransformsPreview = ( + obj: PostTransformsPreviewRequestSchema, + enabled?: boolean +) => { + const { http } = useAppDependencies(); + + return useQuery( + [TRANSFORM_REACT_QUERY_KEYS.GET_TRANSFORMS_PREVIEW, obj], + async ({ signal }) => + await http.post( + addInternalBasePath('transforms/_preview'), + { + body: JSON.stringify(obj), + version: '1', + signal, + } + ), + { enabled } + ); +}; diff --git a/x-pack/plugins/transform/public/app/hooks/use_transform_config_data.ts b/x-pack/plugins/transform/public/app/hooks/use_transform_config_data.ts index f96a0f72194c6..0871dd7877c14 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_transform_config_data.ts +++ b/x-pack/plugins/transform/public/app/hooks/use_transform_config_data.ts @@ -29,14 +29,13 @@ import { } from '@kbn/ml-data-grid'; import type { PreviewMappingsProperties } from '../../../common/api_schemas/transforms'; -import { isPostTransformsPreviewResponseSchema } from '../../../common/api_schemas/type_guards'; import { getErrorMessage } from '../../../common/utils/errors'; import { getPreviewTransformRequestBody, type TransformConfigQuery } from '../common'; import { SearchItems } from './use_search_items'; -import { useApi } from './use_api'; +import { useGetTransformsPreview } from './use_get_transforms_preview'; import { StepDefineExposedState } from '../sections/create_transform/components/step_define'; import { isLatestPartialRequest, @@ -111,7 +110,6 @@ export const useTransformConfigData = ( ): UseIndexDataReturnType => { const [previewMappingsProperties, setPreviewMappingsProperties] = useState({}); - const api = useApi(); // Filters mapping properties of type `object`, which get returned for nested field parents. const columnKeys = Object.keys(previewMappingsProperties).filter( @@ -147,84 +145,100 @@ export const useTransformConfigData = ( tableItems, } = dataGrid; - const getPreviewData = async () => { - if (!validationStatus.isValid) { + const previewRequest = useMemo( + () => + getPreviewTransformRequestBody( + dataView, + query, + requestPayload, + combinedRuntimeMappings, + timeRangeMs + ), + [dataView, query, requestPayload, combinedRuntimeMappings, timeRangeMs] + ); + + const { + error: previewError, + data: previewData, + isError, + isLoading, + } = useGetTransformsPreview(previewRequest, validationStatus.isValid); + + useEffect(() => { + if (isLoading) { + setErrorMessage(''); + setNoDataMessage(''); + setStatus(INDEX_STATUS.LOADING); + } else if (isError) { + setErrorMessage(getErrorMessage(previewError)); setTableItems([]); setRowCountInfo({ rowCount: 0, rowCountRelation: ES_CLIENT_TOTAL_HITS_RELATION.EQ, }); - setNoDataMessage(validationStatus.errorMessage!); - return; + setPreviewMappingsProperties({}); + setStatus(INDEX_STATUS.ERROR); + } else if (!isLoading && !isError && previewData !== undefined) { + // To improve UI performance with a latest configuration for indices with a large number + // of fields, we reduce the number of available columns to those populated with values. + + // 1. Flatten the returned object structure object documents to match mapping properties + const docs = previewData.preview.map(getFlattenedObject); + + // 2. Get all field names for each returned doc and flatten it + // to a list of unique field names used across all docs. + const populatedFields = [...new Set(docs.map(Object.keys).flat(1))]; + + // 3. Filter mapping properties by populated fields + let populatedProperties: PreviewMappingsProperties = Object.entries( + previewData.generated_dest_index.mappings.properties + ) + .filter(([key]) => populatedFields.includes(key)) + .reduce( + (p, [key, value]) => ({ + ...p, + [key]: value, + }), + {} + ); + + populatedProperties = getCombinedProperties(populatedProperties, docs); + + setTableItems(docs); + setRowCountInfo({ + rowCount: docs.length, + rowCountRelation: ES_CLIENT_TOTAL_HITS_RELATION.EQ, + }); + setPreviewMappingsProperties(populatedProperties); + setStatus(INDEX_STATUS.LOADED); + + if (docs.length === 0) { + setNoDataMessage( + i18n.translate('xpack.transform.pivotPreview.PivotPreviewNoDataCalloutBody', { + defaultMessage: + 'The preview request did not return any data. Please ensure the optional query returns data and that values exist for the field used by group-by and aggregation fields.', + }) + ); + } else { + setNoDataMessage(''); + } } + // custom comparison + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [isError, isLoading, previewData]); - setErrorMessage(''); - setNoDataMessage(''); - setStatus(INDEX_STATUS.LOADING); - - const previewRequest = getPreviewTransformRequestBody( - dataView, - query, - requestPayload, - combinedRuntimeMappings, - timeRangeMs - ); - const resp = await api.getTransformsPreview(previewRequest); - - if (!isPostTransformsPreviewResponseSchema(resp)) { - setErrorMessage(getErrorMessage(resp)); + useEffect(() => { + if (!validationStatus.isValid) { setTableItems([]); setRowCountInfo({ rowCount: 0, rowCountRelation: ES_CLIENT_TOTAL_HITS_RELATION.EQ, }); - setPreviewMappingsProperties({}); - setStatus(INDEX_STATUS.ERROR); - return; - } - - // To improve UI performance with a latest configuration for indices with a large number - // of fields, we reduce the number of available columns to those populated with values. - - // 1. Flatten the returned object structure object documents to match mapping properties - const docs = resp.preview.map(getFlattenedObject); - - // 2. Get all field names for each returned doc and flatten it - // to a list of unique field names used across all docs. - const populatedFields = [...new Set(docs.map(Object.keys).flat(1))]; - - // 3. Filter mapping properties by populated fields - let populatedProperties: PreviewMappingsProperties = Object.entries( - resp.generated_dest_index.mappings.properties - ) - .filter(([key]) => populatedFields.includes(key)) - .reduce( - (p, [key, value]) => ({ - ...p, - [key]: value, - }), - {} - ); - - populatedProperties = getCombinedProperties(populatedProperties, docs); - - setTableItems(docs); - setRowCountInfo({ - rowCount: docs.length, - rowCountRelation: ES_CLIENT_TOTAL_HITS_RELATION.EQ, - }); - setPreviewMappingsProperties(populatedProperties); - setStatus(INDEX_STATUS.LOADED); - - if (docs.length === 0) { - setNoDataMessage( - i18n.translate('xpack.transform.pivotPreview.PivotPreviewNoDataCalloutBody', { - defaultMessage: - 'The preview request did not return any data. Please ensure the optional query returns data and that values exist for the field used by group-by and aggregation fields.', - }) - ); + setNoDataMessage(validationStatus.errorMessage!); } - }; + // custom comparison + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [validationStatus.isValid]); useEffect(() => { resetPagination(); @@ -232,15 +246,6 @@ export const useTransformConfigData = ( // eslint-disable-next-line react-hooks/exhaustive-deps }, [JSON.stringify(query)]); - useEffect(() => { - getPreviewData(); - // custom comparison - /* eslint-disable react-hooks/exhaustive-deps */ - }, [ - dataView.getIndexPattern(), - JSON.stringify([requestPayload, query, combinedRuntimeMappings, timeRangeMs]), - ]); - if (sortingColumns.length > 0) { const sortingColumnsWithTypes = sortingColumns.map((c) => { // Since items might contain undefined/null values, we want to accurate find the data type @@ -291,13 +296,7 @@ export const useTransformConfigData = ( return cellValue; }; - }, [ - pageData, - pagination.pageIndex, - pagination.pageSize, - previewMappingsProperties, - formatHumanReadableDateTimeSeconds, - ]); + }, [pageData, pagination.pageIndex, pagination.pageSize, previewMappingsProperties]); return { ...dataGrid, diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/step_define_form.test.tsx b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/step_define_form.test.tsx index 6d5d6d0ea6fc9..3470cf5706a2e 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/step_define_form.test.tsx +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/step_define_form.test.tsx @@ -7,6 +7,7 @@ import React from 'react'; import { render, waitFor } from '@testing-library/react'; +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { I18nProvider } from '@kbn/i18n-react'; import { DatePickerContextProvider, type DatePickerDependencies } from '@kbn/ml-date-picker'; @@ -66,6 +67,7 @@ const createMockStorage = () => ({ describe('Transform: ', () => { test('Minimal initialization', async () => { // Arrange + const queryClient = new QueryClient(); const mlSharedImports = await getMlSharedImports(); const searchItems = { @@ -87,13 +89,15 @@ describe('Transform: ', () => { const { getByText } = render( - - - - - - - + + + + + + + + + ); diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/step_define_summary.test.tsx b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/step_define_summary.test.tsx index 85cef1fb2958e..4f378d4394da0 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/step_define_summary.test.tsx +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/step_define_summary.test.tsx @@ -7,6 +7,7 @@ import React from 'react'; import { render, waitFor } from '@testing-library/react'; +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { PIVOT_SUPPORTED_AGGS } from '../../../../../../common/types/pivot_aggs'; @@ -30,6 +31,7 @@ describe('Transform: ', () => { // Using the async/await wait()/done() pattern to avoid act() errors. test('Minimal initialization', async () => { // Arrange + const queryClient = new QueryClient(); const mlSharedImports = await getMlSharedImports(); const searchItems = { @@ -78,9 +80,11 @@ describe('Transform: ', () => { }; const { queryByText } = render( - - - + + + + + ); // Act diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_details/step_details_form.tsx b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_details/step_details_form.tsx index f2c6a448943e5..9c7f20197c33b 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_details/step_details_form.tsx +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_details/step_details_form.tsx @@ -42,7 +42,11 @@ import { getErrorMessage } from '../../../../../../common/utils/errors'; import { useAppDependencies, useToastNotifications } from '../../../../app_dependencies'; import { ToastNotificationText } from '../../../../components'; -import { useDocumentationLinks, useGetTransforms } from '../../../../hooks'; +import { + useDocumentationLinks, + useGetTransforms, + useGetTransformsPreview, +} from '../../../../hooks'; import { SearchItems } from '../../../../hooks/use_search_items'; import { useApi } from '../../../../hooks/use_api'; import { StepDetailsTimeField } from './step_details_time_field'; @@ -127,11 +131,11 @@ export const StepDetailsForm: FC = React.memo( const { overlays, theme } = useAppDependencies(); const api = useApi(); - const { error, data } = useGetTransforms(); - const transformIds = data?.tableRows.map((d) => d.id) ?? []; + const { error: transformsError, data: transforms } = useGetTransforms(); + const transformIds = transforms?.tableRows.map((d) => d.id) ?? []; useEffect(() => { - if (isHttpFetchError(error)) { + if (isHttpFetchError(transformsError)) { toastNotifications.addDanger({ title: i18n.translate('xpack.transform.stepDetailsForm.errorGettingTransformList', { defaultMessage: 'An error occurred getting the existing transform IDs:', @@ -140,53 +144,61 @@ export const StepDetailsForm: FC = React.memo( , { theme$: theme.theme$ } ), }); } - }, [error, overlays, theme, toastNotifications]); + }, [transformsError, overlays, theme, toastNotifications]); + + const previewRequest = useMemo(() => { + const { searchQuery, previewRequest: partialPreviewRequest } = stepDefineState; + const transformConfigQuery = getTransformConfigQuery(searchQuery); + return getPreviewTransformRequestBody( + searchItems.dataView, + transformConfigQuery, + partialPreviewRequest, + stepDefineState.runtimeMappings + ); + }, [searchItems.dataView, stepDefineState]); + const { error: transformsPreviewError, data: transformPreview } = + useGetTransformsPreview(previewRequest); - // fetch existing transform IDs and indices once for form validation useEffect(() => { - // use an IIFE to avoid returning a Promise to useEffect. - (async function () { - const { searchQuery, previewRequest: partialPreviewRequest } = stepDefineState; - const transformConfigQuery = getTransformConfigQuery(searchQuery); - const previewRequest = getPreviewTransformRequestBody( - searchItems.dataView, - transformConfigQuery, - partialPreviewRequest, - stepDefineState.runtimeMappings + if (isPostTransformsPreviewResponseSchema(transformPreview)) { + const properties = transformPreview.generated_dest_index.mappings.properties; + const timeFields: string[] = Object.keys(properties).filter( + (col) => properties[col].type === 'date' ); - const transformPreview = await api.getTransformsPreview(previewRequest); - - if (isPostTransformsPreviewResponseSchema(transformPreview)) { - const properties = transformPreview.generated_dest_index.mappings.properties; - const timeFields: string[] = Object.keys(properties).filter( - (col) => properties[col].type === 'date' - ); + setDataViewAvailableTimeFields(timeFields); + setDataViewTimeField(timeFields[0]); + } + }, [transformPreview]); - setDataViewAvailableTimeFields(timeFields); - setDataViewTimeField(timeFields[0]); - } else { - toastNotifications.addDanger({ - title: i18n.translate('xpack.transform.stepDetailsForm.errorGettingTransformPreview', { - defaultMessage: 'An error occurred fetching the transform preview', - }), - text: toMountPoint( - , - { theme$: theme.theme$ } - ), - }); - } + useEffect(() => { + if (transformsPreviewError !== null) { + toastNotifications.addDanger({ + title: i18n.translate('xpack.transform.stepDetailsForm.errorGettingTransformPreview', { + defaultMessage: 'An error occurred fetching the transform preview', + }), + text: toMountPoint( + , + { theme$: theme.theme$ } + ), + }); + } + }, [overlays, theme, toastNotifications, transformsPreviewError]); + // fetch existing transform IDs and indices once for form validation + useEffect(() => { + // use an IIFE to avoid returning a Promise to useEffect. + (async function () { const [indices, ingestPipelines] = await Promise.all([ api.getEsIndices(), api.getEsIngestPipelines(), From 7d5107b2aff53dcabea8747ff89818cb5378a5cb Mon Sep 17 00:00:00 2001 From: Walter Rafelsberger Date: Tue, 22 Aug 2023 16:52:47 +0200 Subject: [PATCH 09/53] migrate reauthorize to use react-query --- .../transform/public/app/hooks/use_api.ts | 17 ---- .../app/hooks/use_reauthorize_transform.tsx | 92 ++++++++++--------- .../use_reauthorize_action.tsx | 2 +- 3 files changed, 51 insertions(+), 60 deletions(-) diff --git a/x-pack/plugins/transform/public/app/hooks/use_api.ts b/x-pack/plugins/transform/public/app/hooks/use_api.ts index e6fd8542f9ba6..b6a766ceb0752 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_api.ts +++ b/x-pack/plugins/transform/public/app/hooks/use_api.ts @@ -12,10 +12,6 @@ import type { IHttpFetchError } from '@kbn/core-http-browser'; import { KBN_FIELD_TYPES } from '@kbn/field-types'; import { DEFAULT_SAMPLER_SHARD_SIZE } from '@kbn/ml-agg-utils'; -import { - ReauthorizeTransformsRequestSchema, - ReauthorizeTransformsResponseSchema, -} from '../../../common/api_schemas/reauthorize_transforms'; import type { FieldHistogramsRequestSchema, FieldHistogramsResponseSchema, @@ -50,19 +46,6 @@ export const useApi = () => { return useMemo( () => ({ - async reauthorizeTransforms( - reqBody: ReauthorizeTransformsRequestSchema - ): Promise { - try { - return await http.post(addInternalBasePath(`reauthorize_transforms`), { - body: JSON.stringify(reqBody), - version: '1', - }); - } catch (e) { - return e; - } - }, - async resetTransforms( reqBody: ResetTransformsRequestSchema ): Promise { diff --git a/x-pack/plugins/transform/public/app/hooks/use_reauthorize_transform.tsx b/x-pack/plugins/transform/public/app/hooks/use_reauthorize_transform.tsx index 3b907aa915128..34a18acfaafe9 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_reauthorize_transform.tsx +++ b/x-pack/plugins/transform/public/app/hooks/use_reauthorize_transform.tsx @@ -6,32 +6,39 @@ */ import React from 'react'; +import { useMutation } from '@tanstack/react-query'; import { i18n } from '@kbn/i18n'; import { toMountPoint } from '@kbn/kibana-react-plugin/public'; -import type { StartTransformsRequestSchema } from '../../../common/api_schemas/start_transforms'; -import { isStartTransformsResponseSchema } from '../../../common/api_schemas/type_guards'; - +import { addInternalBasePath } from '../../../common/constants'; import { getErrorMessage } from '../../../common/utils/errors'; +import { + ReauthorizeTransformsRequestSchema, + ReauthorizeTransformsResponseSchema, +} from '../../../common/api_schemas/reauthorize_transforms'; import { useAppDependencies, useToastNotifications } from '../app_dependencies'; import { useRefreshTransformList } from '../common'; import { ToastNotificationText } from '../components'; -import { useApi } from './use_api'; - export const useReauthorizeTransforms = () => { - const { overlays, theme } = useAppDependencies(); + const { http, overlays, theme } = useAppDependencies(); const refreshTransformList = useRefreshTransformList(); const toastNotifications = useToastNotifications(); - const api = useApi(); - - return async (transformsInfo: StartTransformsRequestSchema) => { - const results = await api.reauthorizeTransforms(transformsInfo); - if (!isStartTransformsResponseSchema(results)) { + const mutation = useMutation({ + mutationFn: (reqBody: ReauthorizeTransformsRequestSchema) => { + return http.post( + addInternalBasePath('reauthorize_transforms'), + { + body: JSON.stringify(reqBody), + version: '1', + } + ); + }, + onError: (error) => { toastNotifications.addDanger({ title: i18n.translate( 'xpack.transform.stepCreateForm.reauthorizeTransformResponseSchemaErrorMessage', @@ -40,43 +47,44 @@ export const useReauthorizeTransforms = () => { } ), text: toMountPoint( - , + , { theme$: theme.theme$ } ), }); - return; - } - - for (const transformId in results) { - // hasOwnProperty check to ensure only properties on object itself, and not its prototypes - if (results.hasOwnProperty(transformId)) { - const result = results[transformId]; - if (result.success === true) { - toastNotifications.addSuccess( - i18n.translate('xpack.transform.transformList.reauthorizeTransformSuccessMessage', { - defaultMessage: 'Request to reauthorize transform {transformId} acknowledged.', - values: { transformId }, - }) - ); - } else { - toastNotifications.addError(new Error(JSON.stringify(result.error!.caused_by, null, 2)), { - title: i18n.translate( - 'xpack.transform.transformList.reauthorizeTransformErrorMessage', - { - defaultMessage: 'An error occurred reauthorizing the transform {transformId}', + }, + onSuccess: (results) => { + for (const transformId in results) { + // hasOwnProperty check to ensure only properties on object itself, and not its prototypes + if (results.hasOwnProperty(transformId)) { + const result = results[transformId]; + if (result.success === true) { + toastNotifications.addSuccess( + i18n.translate('xpack.transform.transformList.reauthorizeTransformSuccessMessage', { + defaultMessage: 'Request to reauthorize transform {transformId} acknowledged.', values: { transformId }, + }) + ); + } else { + toastNotifications.addError( + new Error(JSON.stringify(result.error!.caused_by, null, 2)), + { + title: i18n.translate( + 'xpack.transform.transformList.reauthorizeTransformErrorMessage', + { + defaultMessage: 'An error occurred reauthorizing the transform {transformId}', + values: { transformId }, + } + ), + toastMessage: result.error!.reason, } - ), - toastMessage: result.error!.reason, - }); + ); + } } } - } - refreshTransformList(); - }; + refreshTransformList(); + }, + }); + + return mutation; }; diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_reauthorize/use_reauthorize_action.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_reauthorize/use_reauthorize_action.tsx index 086f5451d53be..b3c11971fb750 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_reauthorize/use_reauthorize_action.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_reauthorize/use_reauthorize_action.tsx @@ -23,7 +23,7 @@ export type ReauthorizeAction = ReturnType; export const useReauthorizeAction = (forceDisable: boolean, transformNodes: number) => { const { canStartStopTransform } = useContext(AuthorizationContext).capabilities; - const reauthorizeTransforms = useReauthorizeTransforms(); + const { mutate: reauthorizeTransforms } = useReauthorizeTransforms(); const [isModalVisible, setModalVisible] = useState(false); const [items, setItems] = useState([]); From e7d1c0e880bbaa7be48014446e38be948b6f66d0 Mon Sep 17 00:00:00 2001 From: Walter Rafelsberger Date: Tue, 22 Aug 2023 17:11:42 +0200 Subject: [PATCH 10/53] migrate reset to use react-query --- .../transform/public/app/hooks/use_api.ts | 16 -- .../public/app/hooks/use_reset_transform.tsx | 140 +++++++++--------- .../action_reset/use_reset_action.tsx | 2 +- 3 files changed, 75 insertions(+), 83 deletions(-) diff --git a/x-pack/plugins/transform/public/app/hooks/use_api.ts b/x-pack/plugins/transform/public/app/hooks/use_api.ts index b6a766ceb0752..e64240893a7d7 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_api.ts +++ b/x-pack/plugins/transform/public/app/hooks/use_api.ts @@ -16,10 +16,6 @@ import type { FieldHistogramsRequestSchema, FieldHistogramsResponseSchema, } from '../../../common/api_schemas/field_histograms'; -import type { - ResetTransformsRequestSchema, - ResetTransformsResponseSchema, -} from '../../../common/api_schemas/reset_transforms'; import type { StopTransformsRequestSchema, StopTransformsResponseSchema, @@ -46,18 +42,6 @@ export const useApi = () => { return useMemo( () => ({ - async resetTransforms( - reqBody: ResetTransformsRequestSchema - ): Promise { - try { - return await http.post(addInternalBasePath(`reset_transforms`), { - body: JSON.stringify(reqBody), - version: '1', - }); - } catch (e) { - return e; - } - }, async stopTransforms( transformsInfo: StopTransformsRequestSchema ): Promise { diff --git a/x-pack/plugins/transform/public/app/hooks/use_reset_transform.tsx b/x-pack/plugins/transform/public/app/hooks/use_reset_transform.tsx index d64301ee37522..d91ddaf142306 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_reset_transform.tsx +++ b/x-pack/plugins/transform/public/app/hooks/use_reset_transform.tsx @@ -6,31 +6,37 @@ */ import React from 'react'; +import { useMutation } from '@tanstack/react-query'; + import { i18n } from '@kbn/i18n'; import { toMountPoint } from '@kbn/kibana-react-plugin/public'; + import type { ResetTransformStatus, ResetTransformsRequestSchema, + ResetTransformsResponseSchema, } from '../../../common/api_schemas/reset_transforms'; -import { isResetTransformsResponseSchema } from '../../../common/api_schemas/type_guards'; +import { addInternalBasePath } from '../../../common/constants'; import { getErrorMessage } from '../../../common/utils/errors'; import { useAppDependencies, useToastNotifications } from '../app_dependencies'; import { useRefreshTransformList } from '../common'; import { ToastNotificationText } from '../components'; -import { useApi } from './use_api'; type SuccessCountField = keyof Omit; export const useResetTransforms = () => { - const { overlays, theme } = useAppDependencies(); + const { http, overlays, theme } = useAppDependencies(); const refreshTransformList = useRefreshTransformList(); const toastNotifications = useToastNotifications(); - const api = useApi(); - - return async (reqBody: ResetTransformsRequestSchema) => { - const results = await api.resetTransforms(reqBody); - if (!isResetTransformsResponseSchema(results)) { + const mutation = useMutation({ + mutationFn: (reqBody: ResetTransformsRequestSchema) => { + return http.post(addInternalBasePath('reset_transforms'), { + body: JSON.stringify(reqBody), + version: '1', + }); + }, + onError: (error) => { toastNotifications.addDanger({ title: i18n.translate('xpack.transform.transformList.resetTransformGenericErrorMessage', { defaultMessage: 'An error occurred calling the API endpoint to reset transforms.', @@ -40,74 +46,76 @@ export const useResetTransforms = () => { previewTextLength={50} overlays={overlays} theme={theme} - text={getErrorMessage(results)} + text={getErrorMessage(error)} />, { theme$: theme.theme$ } ), }); - return; - } - - const isBulk = Object.keys(results).length > 1; - const successCount: Record = { - transformReset: 0, - }; - for (const transformId in results) { - // hasOwnProperty check to ensure only properties on object itself, and not its prototypes - if (results.hasOwnProperty(transformId)) { - const status = results[transformId]; + }, + onSuccess: (results) => { + const isBulk = Object.keys(results).length > 1; + const successCount: Record = { + transformReset: 0, + }; + for (const transformId in results) { + // hasOwnProperty check to ensure only properties on object itself, and not its prototypes + if (results.hasOwnProperty(transformId)) { + const status = results[transformId]; - // if we are only resetting one transform, show the success toast messages - if (!isBulk && status.transformReset) { - if (status.transformReset?.success) { - toastNotifications.addSuccess( - i18n.translate('xpack.transform.transformList.resetTransformSuccessMessage', { - defaultMessage: 'Request to reset transform {transformId} acknowledged.', + // if we are only resetting one transform, show the success toast messages + if (!isBulk && status.transformReset) { + if (status.transformReset?.success) { + toastNotifications.addSuccess( + i18n.translate('xpack.transform.transformList.resetTransformSuccessMessage', { + defaultMessage: 'Request to reset transform {transformId} acknowledged.', + values: { transformId }, + }) + ); + } + } else { + (Object.keys(successCount) as SuccessCountField[]).forEach((key) => { + if (status[key]?.success) { + successCount[key] = successCount[key] + 1; + } + }); + } + if (status.transformReset?.error) { + const error = status.transformReset.error.reason; + toastNotifications.addDanger({ + title: i18n.translate('xpack.transform.transformList.resetTransformErrorMessage', { + defaultMessage: 'An error occurred resetting the transform {transformId}', values: { transformId }, - }) - ); + }), + text: toMountPoint( + , + { theme$: theme.theme$ } + ), + }); } - } else { - (Object.keys(successCount) as SuccessCountField[]).forEach((key) => { - if (status[key]?.success) { - successCount[key] = successCount[key] + 1; - } - }); - } - if (status.transformReset?.error) { - const error = status.transformReset.error.reason; - toastNotifications.addDanger({ - title: i18n.translate('xpack.transform.transformList.resetTransformErrorMessage', { - defaultMessage: 'An error occurred resetting the transform {transformId}', - values: { transformId }, - }), - text: toMountPoint( - , - { theme$: theme.theme$ } - ), - }); } } - } - // if we are deleting multiple transforms, combine the success messages - if (isBulk) { - if (successCount.transformReset > 0) { - toastNotifications.addSuccess( - i18n.translate('xpack.transform.transformList.bulkResetTransformSuccessMessage', { - defaultMessage: - 'Successfully reset {count} {count, plural, one {transform} other {transforms}}.', - values: { count: successCount.transformReset }, - }) - ); + // if we are deleting multiple transforms, combine the success messages + if (isBulk) { + if (successCount.transformReset > 0) { + toastNotifications.addSuccess( + i18n.translate('xpack.transform.transformList.bulkResetTransformSuccessMessage', { + defaultMessage: + 'Successfully reset {count} {count, plural, one {transform} other {transforms}}.', + values: { count: successCount.transformReset }, + }) + ); + } } - } - refreshTransformList(); - }; + refreshTransformList(); + }, + }); + + return mutation; }; diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_reset/use_reset_action.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_reset/use_reset_action.tsx index 70164bc22a63c..45dcf5b4ba3da 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_reset/use_reset_action.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_reset/use_reset_action.tsx @@ -19,7 +19,7 @@ export type ResetAction = ReturnType; export const useResetAction = (forceDisable: boolean) => { const { canResetTransform } = useContext(AuthorizationContext).capabilities; - const resetTransforms = useResetTransforms(); + const { mutate: resetTransforms } = useResetTransforms(); const [isModalVisible, setModalVisible] = useState(false); const [items, setItems] = useState([]); From 9c47fe6ffdc8ee2c731013175eb664b39273e794 Mon Sep 17 00:00:00 2001 From: Walter Rafelsberger Date: Tue, 22 Aug 2023 17:18:15 +0200 Subject: [PATCH 11/53] migrate stop to use react-query --- .../public/app/hooks/__mocks__/use_api.ts | 9 --- .../transform/public/app/hooks/use_api.ts | 16 ---- .../public/app/hooks/use_start_transform.tsx | 2 +- .../public/app/hooks/use_stop_transform.tsx | 80 ++++++++++--------- .../action_stop/use_stop_action.tsx | 2 +- 5 files changed, 43 insertions(+), 66 deletions(-) diff --git a/x-pack/plugins/transform/public/app/hooks/__mocks__/use_api.ts b/x-pack/plugins/transform/public/app/hooks/__mocks__/use_api.ts index 249198b2e600f..69e056ffdfb6c 100644 --- a/x-pack/plugins/transform/public/app/hooks/__mocks__/use_api.ts +++ b/x-pack/plugins/transform/public/app/hooks/__mocks__/use_api.ts @@ -11,10 +11,6 @@ import { KBN_FIELD_TYPES } from '@kbn/field-types'; import { DEFAULT_SAMPLER_SHARD_SIZE } from '@kbn/ml-agg-utils'; import type { FieldHistogramsResponseSchema } from '../../../../common/api_schemas/field_histograms'; -import type { - StopTransformsRequestSchema, - StopTransformsResponseSchema, -} from '../../../../common/api_schemas/stop_transforms'; import type { EsIndex } from '../../../../common/types/es_index'; @@ -26,11 +22,6 @@ export interface FieldHistogramRequestConfig { } const apiFactory = () => ({ - async stopTransforms( - transformsInfo: StopTransformsRequestSchema - ): Promise { - return Promise.resolve({}); - }, async getEsIndices(): Promise { return Promise.resolve([]); }, diff --git a/x-pack/plugins/transform/public/app/hooks/use_api.ts b/x-pack/plugins/transform/public/app/hooks/use_api.ts index e64240893a7d7..5b741e50b39e5 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_api.ts +++ b/x-pack/plugins/transform/public/app/hooks/use_api.ts @@ -16,10 +16,6 @@ import type { FieldHistogramsRequestSchema, FieldHistogramsResponseSchema, } from '../../../common/api_schemas/field_histograms'; -import type { - StopTransformsRequestSchema, - StopTransformsResponseSchema, -} from '../../../common/api_schemas/stop_transforms'; import type { ScheduleNowTransformsRequestSchema, ScheduleNowTransformsResponseSchema, @@ -42,18 +38,6 @@ export const useApi = () => { return useMemo( () => ({ - async stopTransforms( - transformsInfo: StopTransformsRequestSchema - ): Promise { - try { - return await http.post(addInternalBasePath(`stop_transforms`), { - body: JSON.stringify(transformsInfo), - version: '1', - }); - } catch (e) { - return e; - } - }, async scheduleNowTransforms( transformsInfo: ScheduleNowTransformsRequestSchema ): Promise { diff --git a/x-pack/plugins/transform/public/app/hooks/use_start_transform.tsx b/x-pack/plugins/transform/public/app/hooks/use_start_transform.tsx index 84dc80ef64e47..2f0e7a28e1e28 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_start_transform.tsx +++ b/x-pack/plugins/transform/public/app/hooks/use_start_transform.tsx @@ -31,7 +31,7 @@ export const useStartTransforms = () => { const mutation = useMutation({ mutationFn: (reqBody: StartTransformsRequestSchema) => { - return http.post(addInternalBasePath(`start_transforms`), { + return http.post(addInternalBasePath('start_transforms'), { body: JSON.stringify(reqBody), version: '1', }); diff --git a/x-pack/plugins/transform/public/app/hooks/use_stop_transform.tsx b/x-pack/plugins/transform/public/app/hooks/use_stop_transform.tsx index d89ee1a0118f1..004ee40389200 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_stop_transform.tsx +++ b/x-pack/plugins/transform/public/app/hooks/use_stop_transform.tsx @@ -6,32 +6,36 @@ */ import React from 'react'; +import { useMutation } from '@tanstack/react-query'; import { i18n } from '@kbn/i18n'; import { toMountPoint } from '@kbn/kibana-react-plugin/public'; -import type { StopTransformsRequestSchema } from '../../../common/api_schemas/stop_transforms'; -import { isStopTransformsResponseSchema } from '../../../common/api_schemas/type_guards'; - +import { addInternalBasePath } from '../../../common/constants'; +import type { + StopTransformsRequestSchema, + StopTransformsResponseSchema, +} from '../../../common/api_schemas/stop_transforms'; import { getErrorMessage } from '../../../common/utils/errors'; import { useAppDependencies, useToastNotifications } from '../app_dependencies'; import { useRefreshTransformList } from '../common'; import { ToastNotificationText } from '../components'; -import { useApi } from './use_api'; - export const useStopTransforms = () => { - const { overlays, theme } = useAppDependencies(); + const { http, overlays, theme } = useAppDependencies(); const refreshTransformList = useRefreshTransformList(); const toastNotifications = useToastNotifications(); - const api = useApi(); - return async (transformsInfo: StopTransformsRequestSchema) => { - const results = await api.stopTransforms(transformsInfo); - - if (!isStopTransformsResponseSchema(results)) { + const mutation = useMutation({ + mutationFn: (reqBody: StopTransformsRequestSchema) => { + return http.post(addInternalBasePath('stop_transforms'), { + body: JSON.stringify(reqBody), + version: '1', + }); + }, + onError: (error) => { toastNotifications.addDanger({ title: i18n.translate( 'xpack.transform.transformList.stopTransformResponseSchemaErrorMessage', @@ -40,38 +44,36 @@ export const useStopTransforms = () => { } ), text: toMountPoint( - , + , { theme$: theme.theme$ } ), }); - return; - } - - for (const transformId in results) { - // hasOwnProperty check to ensure only properties on object itself, and not its prototypes - if (results.hasOwnProperty(transformId)) { - if (results[transformId].success === true) { - toastNotifications.addSuccess( - i18n.translate('xpack.transform.transformList.stopTransformSuccessMessage', { - defaultMessage: 'Request to stop data frame transform {transformId} acknowledged.', - values: { transformId }, - }) - ); - } else { - toastNotifications.addDanger( - i18n.translate('xpack.transform.transformList.stopTransformErrorMessage', { - defaultMessage: 'An error occurred stopping the data frame transform {transformId}', - values: { transformId }, - }) - ); + }, + onSuccess: (results) => { + for (const transformId in results) { + // hasOwnProperty check to ensure only properties on object itself, and not its prototypes + if (results.hasOwnProperty(transformId)) { + if (results[transformId].success === true) { + toastNotifications.addSuccess( + i18n.translate('xpack.transform.transformList.stopTransformSuccessMessage', { + defaultMessage: 'Request to stop data frame transform {transformId} acknowledged.', + values: { transformId }, + }) + ); + } else { + toastNotifications.addDanger( + i18n.translate('xpack.transform.transformList.stopTransformErrorMessage', { + defaultMessage: 'An error occurred stopping the data frame transform {transformId}', + values: { transformId }, + }) + ); + } } } - } - refreshTransformList(); - }; + refreshTransformList(); + }, + }); + + return mutation; }; diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_stop/use_stop_action.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_stop/use_stop_action.tsx index ac53ee83f6f65..e09d5cc4888d0 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_stop/use_stop_action.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_stop/use_stop_action.tsx @@ -18,7 +18,7 @@ export type StopAction = ReturnType; export const useStopAction = (forceDisable: boolean) => { const { canStartStopTransform } = useContext(AuthorizationContext).capabilities; - const stopTransforms = useStopTransforms(); + const { mutate: stopTransforms } = useStopTransforms(); const [isModalVisible, setModalVisible] = useState(false); const [items, setItems] = useState([]); From cb904c056f9c73b8c1e7a05eb047a4284b3c6687 Mon Sep 17 00:00:00 2001 From: Walter Rafelsberger Date: Tue, 22 Aug 2023 17:23:58 +0200 Subject: [PATCH 12/53] migrate schedule now to use react-query --- .../transform/public/app/hooks/use_api.ts | 16 ---- .../app/hooks/use_schedule_now_transform.tsx | 95 ++++++++++--------- .../public/app/hooks/use_start_transform.tsx | 2 - .../use_schedule_now_action.tsx | 2 +- 4 files changed, 52 insertions(+), 63 deletions(-) diff --git a/x-pack/plugins/transform/public/app/hooks/use_api.ts b/x-pack/plugins/transform/public/app/hooks/use_api.ts index 5b741e50b39e5..6956d7fa7b084 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_api.ts +++ b/x-pack/plugins/transform/public/app/hooks/use_api.ts @@ -16,10 +16,6 @@ import type { FieldHistogramsRequestSchema, FieldHistogramsResponseSchema, } from '../../../common/api_schemas/field_histograms'; -import type { - ScheduleNowTransformsRequestSchema, - ScheduleNowTransformsResponseSchema, -} from '../../../common/api_schemas/schedule_now_transforms'; import { addInternalBasePath } from '../../../common/constants'; import type { EsIndex } from '../../../common/types/es_index'; import type { EsIngestPipeline } from '../../../common/types/es_ingest_pipeline'; @@ -38,18 +34,6 @@ export const useApi = () => { return useMemo( () => ({ - async scheduleNowTransforms( - transformsInfo: ScheduleNowTransformsRequestSchema - ): Promise { - try { - return await http.post(addInternalBasePath(`schedule_now_transforms`), { - body: JSON.stringify(transformsInfo), - version: '1', - }); - } catch (e) { - return e; - } - }, async getEsIndices(): Promise { try { return await http.get(`/api/index_management/indices`, { version: '1' }); diff --git a/x-pack/plugins/transform/public/app/hooks/use_schedule_now_transform.tsx b/x-pack/plugins/transform/public/app/hooks/use_schedule_now_transform.tsx index b0a15f1635c44..398bd42629167 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_schedule_now_transform.tsx +++ b/x-pack/plugins/transform/public/app/hooks/use_schedule_now_transform.tsx @@ -6,32 +6,38 @@ */ import React from 'react'; +import { useMutation } from '@tanstack/react-query'; import { i18n } from '@kbn/i18n'; - import { toMountPoint } from '@kbn/kibana-react-plugin/public'; -import type { ScheduleNowTransformsRequestSchema } from '../../../common/api_schemas/schedule_now_transforms'; -import { isScheduleNowTransformsResponseSchema } from '../../../common/api_schemas/type_guards'; - +import { addInternalBasePath } from '../../../common/constants'; +import type { + ScheduleNowTransformsRequestSchema, + ScheduleNowTransformsResponseSchema, +} from '../../../common/api_schemas/schedule_now_transforms'; import { getErrorMessage } from '../../../common/utils/errors'; import { useAppDependencies, useToastNotifications } from '../app_dependencies'; import { useRefreshTransformList } from '../common'; import { ToastNotificationText } from '../components'; -import { useApi } from './use_api'; - export const useScheduleNowTransforms = () => { - const { overlays, theme } = useAppDependencies(); + const { http, overlays, theme } = useAppDependencies(); const refreshTransformList = useRefreshTransformList(); const toastNotifications = useToastNotifications(); - const api = useApi(); - return async (transformsInfo: ScheduleNowTransformsRequestSchema) => { - const results = await api.scheduleNowTransforms(transformsInfo); - - if (!isScheduleNowTransformsResponseSchema(results)) { + const mutation = useMutation({ + mutationFn: (reqBody: ScheduleNowTransformsRequestSchema) => { + return http.post( + addInternalBasePath('schedule_now_transforms'), + { + body: JSON.stringify(reqBody), + version: '1', + } + ); + }, + onError: (error) => { toastNotifications.addDanger({ title: i18n.translate( 'xpack.transform.stepCreateForm.scheduleNowTransformResponseSchemaErrorMessage', @@ -41,45 +47,46 @@ export const useScheduleNowTransforms = () => { } ), text: toMountPoint( - , + , { theme$: theme.theme$ } ), }); - return; - } - - for (const transformId in results) { - // hasOwnProperty check to ensure only properties on object itself, and not its prototypes - if (results.hasOwnProperty(transformId)) { - const result = results[transformId]; - if (result.success === true) { - toastNotifications.addSuccess( - i18n.translate('xpack.transform.transformList.scheduleNowTransformSuccessMessage', { - defaultMessage: - 'Request to schedule transform {transformId} to process data instantly acknowledged.', - values: { transformId }, - }) - ); - } else { - toastNotifications.addError(new Error(JSON.stringify(result.error!.caused_by, null, 2)), { - title: i18n.translate( - 'xpack.transform.transformList.scheduleNowTransformErrorMessage', - { + }, + onSuccess: (results) => { + for (const transformId in results) { + // hasOwnProperty check to ensure only properties on object itself, and not its prototypes + if (results.hasOwnProperty(transformId)) { + const result = results[transformId]; + if (result.success === true) { + toastNotifications.addSuccess( + i18n.translate('xpack.transform.transformList.scheduleNowTransformSuccessMessage', { defaultMessage: - 'An error occurred scheduling transform {transformId} to process data instantly.', + 'Request to schedule transform {transformId} to process data instantly acknowledged.', values: { transformId }, + }) + ); + } else { + toastNotifications.addError( + new Error(JSON.stringify(result.error!.caused_by, null, 2)), + { + title: i18n.translate( + 'xpack.transform.transformList.scheduleNowTransformErrorMessage', + { + defaultMessage: + 'An error occurred scheduling transform {transformId} to process data instantly.', + values: { transformId }, + } + ), + toastMessage: result.error!.reason, } - ), - toastMessage: result.error!.reason, - }); + ); + } } } - } - refreshTransformList(); - }; + refreshTransformList(); + }, + }); + + return mutation; }; diff --git a/x-pack/plugins/transform/public/app/hooks/use_start_transform.tsx b/x-pack/plugins/transform/public/app/hooks/use_start_transform.tsx index 2f0e7a28e1e28..65defb8a5dbee 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_start_transform.tsx +++ b/x-pack/plugins/transform/public/app/hooks/use_start_transform.tsx @@ -9,7 +9,6 @@ import React from 'react'; import { useMutation } from '@tanstack/react-query'; import { i18n } from '@kbn/i18n'; - import { toMountPoint } from '@kbn/kibana-react-plugin/public'; import { addInternalBasePath } from '../../../common/constants'; @@ -17,7 +16,6 @@ import type { StartTransformsRequestSchema, StartTransformsResponseSchema, } from '../../../common/api_schemas/start_transforms'; - import { getErrorMessage } from '../../../common/utils/errors'; import { useAppDependencies, useToastNotifications } from '../app_dependencies'; diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_schedule_now/use_schedule_now_action.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_schedule_now/use_schedule_now_action.tsx index dda70deb225a6..1d9fb7417dc04 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_schedule_now/use_schedule_now_action.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_schedule_now/use_schedule_now_action.tsx @@ -23,7 +23,7 @@ export type ScheduleNowAction = ReturnType; export const useScheduleNowAction = (forceDisable: boolean, transformNodes: number) => { const { canScheduleNowTransform } = useContext(AuthorizationContext).capabilities; - const scheduleNowTransforms = useScheduleNowTransforms(); + const { mutate: scheduleNowTransforms } = useScheduleNowTransforms(); const action: TransformListAction = useMemo( () => ({ From 1526d624ea73433d7c5abb0caeedbf848742c408 Mon Sep 17 00:00:00 2001 From: Walter Rafelsberger Date: Tue, 22 Aug 2023 18:29:16 +0200 Subject: [PATCH 13/53] migrate more to react-query --- x-pack/plugins/transform/common/constants.ts | 5 +- .../public/app/hooks/__mocks__/use_api.ts | 5 - .../transform/public/app/hooks/index.ts | 3 + .../transform/public/app/hooks/use_api.ts | 16 -- .../app/hooks/use_get_data_view_titles.ts | 23 +++ .../public/app/hooks/use_get_es_indices.ts | 28 ++++ .../app/hooks/use_get_es_ingest_pipelines.ts | 28 ++++ .../public/app/hooks/use_get_transform.tsx | 13 +- .../hooks/use_get_transform_audit_messages.ts | 4 +- .../app/hooks/use_get_transform_stats.ts | 4 +- .../app/hooks/use_get_transforms_preview.ts | 15 +- .../components/authorization_provider.tsx | 9 +- .../step_details/step_details_form.tsx | 141 +++++++++--------- .../edit_transform_ingest_pipeline.tsx | 37 +---- 14 files changed, 178 insertions(+), 153 deletions(-) create mode 100644 x-pack/plugins/transform/public/app/hooks/use_get_data_view_titles.ts create mode 100644 x-pack/plugins/transform/public/app/hooks/use_get_es_indices.ts create mode 100644 x-pack/plugins/transform/public/app/hooks/use_get_es_ingest_pipelines.ts diff --git a/x-pack/plugins/transform/common/constants.ts b/x-pack/plugins/transform/common/constants.ts index 367459e566019..19bf3512d40d7 100644 --- a/x-pack/plugins/transform/common/constants.ts +++ b/x-pack/plugins/transform/common/constants.ts @@ -33,7 +33,10 @@ export const addInternalBasePath = (uri: string): string => `${INTERNAL_API_BASE export const addExternalBasePath = (uri: string): string => `${EXTERNAL_API_BASE_PATH}${uri}`; export const TRANSFORM_REACT_QUERY_KEYS = { - PRIVILEGES: 'transform.privileges', + GET_DATA_VIEW_TITLES: 'transform.get_data_view_titles', + GET_ES_INDICES: 'transform.get_es_indices', + GET_ES_INGEST_PIPELINES: 'transform.get_es_ingest_pipelines', + GET_PRIVILEGES: 'transform.get_privileges', GET_TRANSFORM: 'transform.get_transform', GET_TRANSFORM_AUDIT_MESSAGES: 'transform.get_transform_audit_messages', GET_TRANSFORM_STATS: 'transform.get_transform_stats', diff --git a/x-pack/plugins/transform/public/app/hooks/__mocks__/use_api.ts b/x-pack/plugins/transform/public/app/hooks/__mocks__/use_api.ts index 69e056ffdfb6c..1bcd2e8cd0506 100644 --- a/x-pack/plugins/transform/public/app/hooks/__mocks__/use_api.ts +++ b/x-pack/plugins/transform/public/app/hooks/__mocks__/use_api.ts @@ -12,8 +12,6 @@ import { DEFAULT_SAMPLER_SHARD_SIZE } from '@kbn/ml-agg-utils'; import type { FieldHistogramsResponseSchema } from '../../../../common/api_schemas/field_histograms'; -import type { EsIndex } from '../../../../common/types/es_index'; - import type { SavedSearchQuery } from '../use_search_items'; export interface FieldHistogramRequestConfig { @@ -22,9 +20,6 @@ export interface FieldHistogramRequestConfig { } const apiFactory = () => ({ - async getEsIndices(): Promise { - return Promise.resolve([]); - }, async getHistogramsForFields( dataViewTitle: string, fields: FieldHistogramRequestConfig[], diff --git a/x-pack/plugins/transform/public/app/hooks/index.ts b/x-pack/plugins/transform/public/app/hooks/index.ts index 71789989ba5ff..03a90d3b89042 100644 --- a/x-pack/plugins/transform/public/app/hooks/index.ts +++ b/x-pack/plugins/transform/public/app/hooks/index.ts @@ -8,6 +8,9 @@ export { useApi } from './use_api'; export { useCreateTransform } from './use_create_transform'; export { useDocumentationLinks } from './use_documentation_links'; +export { useGetDataViewTitles } from './use_get_data_view_titles'; +export { useGetEsIndices } from './use_get_es_indices'; +export { useGetEsIngestPipelines } from './use_get_es_ingest_pipelines'; export { useGetTransformAuditMessages } from './use_get_transform_audit_messages'; export { useGetTransform } from './use_get_transform'; export { useGetTransforms } from './use_get_transforms'; diff --git a/x-pack/plugins/transform/public/app/hooks/use_api.ts b/x-pack/plugins/transform/public/app/hooks/use_api.ts index 6956d7fa7b084..f50af871368f1 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_api.ts +++ b/x-pack/plugins/transform/public/app/hooks/use_api.ts @@ -17,8 +17,6 @@ import type { FieldHistogramsResponseSchema, } from '../../../common/api_schemas/field_histograms'; import { addInternalBasePath } from '../../../common/constants'; -import type { EsIndex } from '../../../common/types/es_index'; -import type { EsIngestPipeline } from '../../../common/types/es_ingest_pipeline'; import { useAppDependencies } from '../app_dependencies'; @@ -34,20 +32,6 @@ export const useApi = () => { return useMemo( () => ({ - async getEsIndices(): Promise { - try { - return await http.get(`/api/index_management/indices`, { version: '1' }); - } catch (e) { - return e; - } - }, - async getEsIngestPipelines(): Promise { - try { - return await http.get('/api/ingest_pipelines', { version: '1' }); - } catch (e) { - return e; - } - }, async getHistogramsForFields( dataViewTitle: string, fields: FieldHistogramRequestConfig[], diff --git a/x-pack/plugins/transform/public/app/hooks/use_get_data_view_titles.ts b/x-pack/plugins/transform/public/app/hooks/use_get_data_view_titles.ts new file mode 100644 index 0000000000000..449ac30b9f513 --- /dev/null +++ b/x-pack/plugins/transform/public/app/hooks/use_get_data_view_titles.ts @@ -0,0 +1,23 @@ +/* + * 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 { useQuery } from '@tanstack/react-query'; + +import type { IHttpFetchError } from '@kbn/core-http-browser'; + +import { TRANSFORM_REACT_QUERY_KEYS } from '../../../common/constants'; + +import { useAppDependencies } from '../app_dependencies'; + +export const useGetDataViewTitles = () => { + const { data } = useAppDependencies(); + + return useQuery( + [TRANSFORM_REACT_QUERY_KEYS.GET_DATA_VIEW_TITLES], + () => data.dataViews.getTitles() + ); +}; diff --git a/x-pack/plugins/transform/public/app/hooks/use_get_es_indices.ts b/x-pack/plugins/transform/public/app/hooks/use_get_es_indices.ts new file mode 100644 index 0000000000000..7da50c155d1be --- /dev/null +++ b/x-pack/plugins/transform/public/app/hooks/use_get_es_indices.ts @@ -0,0 +1,28 @@ +/* + * 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 { useQuery } from '@tanstack/react-query'; + +import type { IHttpFetchError } from '@kbn/core-http-browser'; + +import { TRANSFORM_REACT_QUERY_KEYS } from '../../../common/constants'; +import type { EsIndex } from '../../../common/types/es_index'; + +import { useAppDependencies } from '../app_dependencies'; + +export const useGetEsIndices = () => { + const { http } = useAppDependencies(); + + return useQuery( + [TRANSFORM_REACT_QUERY_KEYS.GET_ES_INDICES], + ({ signal }) => + http.get('/api/index_management/indices', { + version: '1', + signal, + }) + ); +}; diff --git a/x-pack/plugins/transform/public/app/hooks/use_get_es_ingest_pipelines.ts b/x-pack/plugins/transform/public/app/hooks/use_get_es_ingest_pipelines.ts new file mode 100644 index 0000000000000..3f9784c64b652 --- /dev/null +++ b/x-pack/plugins/transform/public/app/hooks/use_get_es_ingest_pipelines.ts @@ -0,0 +1,28 @@ +/* + * 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 { useQuery } from '@tanstack/react-query'; + +import type { IHttpFetchError } from '@kbn/core-http-browser'; + +import { TRANSFORM_REACT_QUERY_KEYS } from '../../../common/constants'; +import type { EsIngestPipeline } from '../../../common/types/es_ingest_pipeline'; + +import { useAppDependencies } from '../app_dependencies'; + +export const useGetEsIngestPipelines = () => { + const { http } = useAppDependencies(); + + return useQuery( + [TRANSFORM_REACT_QUERY_KEYS.GET_ES_INGEST_PIPELINES], + ({ signal }) => + http.get('/api/ingest_pipelines', { + version: '1', + signal, + }) + ); +}; diff --git a/x-pack/plugins/transform/public/app/hooks/use_get_transform.tsx b/x-pack/plugins/transform/public/app/hooks/use_get_transform.tsx index 4cccc76295d52..b9e3d977c71bd 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_get_transform.tsx +++ b/x-pack/plugins/transform/public/app/hooks/use_get_transform.tsx @@ -20,14 +20,11 @@ export const useGetTransform = (transformId: TransformId, enabled?: boolean) => return useQuery( [TRANSFORM_REACT_QUERY_KEYS.GET_TRANSFORM, transformId], - async ({ signal }) => - await http.get( - addInternalBasePath(`transforms/${transformId}`), - { - version: '1', - signal, - } - ), + ({ signal }) => + http.get(addInternalBasePath(`transforms/${transformId}`), { + version: '1', + signal, + }), { enabled } ); }; diff --git a/x-pack/plugins/transform/public/app/hooks/use_get_transform_audit_messages.ts b/x-pack/plugins/transform/public/app/hooks/use_get_transform_audit_messages.ts index fec306f455417..3f7559a251275 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_get_transform_audit_messages.ts +++ b/x-pack/plugins/transform/public/app/hooks/use_get_transform_audit_messages.ts @@ -26,8 +26,8 @@ export const useGetTransformAuditMessages = ( return useQuery( [TRANSFORM_REACT_QUERY_KEYS.GET_TRANSFORM_AUDIT_MESSAGES, transformId, query], - async ({ signal }) => - await http.get( + ({ signal }) => + http.get( addInternalBasePath(`transforms/${transformId}/messages`), { query, diff --git a/x-pack/plugins/transform/public/app/hooks/use_get_transform_stats.ts b/x-pack/plugins/transform/public/app/hooks/use_get_transform_stats.ts index c6f1951b85819..d2b9d32f25853 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_get_transform_stats.ts +++ b/x-pack/plugins/transform/public/app/hooks/use_get_transform_stats.ts @@ -24,8 +24,8 @@ export const useGetTransformStats = ( return useQuery( [TRANSFORM_REACT_QUERY_KEYS.GET_TRANSFORM_STATS, transformId], - async ({ signal }) => - await http.get( + ({ signal }) => + http.get( addInternalBasePath(`transforms/${transformId}/_stats`), { version: '1', diff --git a/x-pack/plugins/transform/public/app/hooks/use_get_transforms_preview.ts b/x-pack/plugins/transform/public/app/hooks/use_get_transforms_preview.ts index 096c966e53311..ae671912b9267 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_get_transforms_preview.ts +++ b/x-pack/plugins/transform/public/app/hooks/use_get_transforms_preview.ts @@ -25,15 +25,12 @@ export const useGetTransformsPreview = ( return useQuery( [TRANSFORM_REACT_QUERY_KEYS.GET_TRANSFORMS_PREVIEW, obj], - async ({ signal }) => - await http.post( - addInternalBasePath('transforms/_preview'), - { - body: JSON.stringify(obj), - version: '1', - signal, - } - ), + ({ signal }) => + http.post(addInternalBasePath('transforms/_preview'), { + body: JSON.stringify(obj), + version: '1', + signal, + }), { enabled } ); }; diff --git a/x-pack/plugins/transform/public/app/lib/authorization/components/authorization_provider.tsx b/x-pack/plugins/transform/public/app/lib/authorization/components/authorization_provider.tsx index 9e73582b13d91..34760269772d1 100644 --- a/x-pack/plugins/transform/public/app/lib/authorization/components/authorization_provider.tsx +++ b/x-pack/plugins/transform/public/app/lib/authorization/components/authorization_provider.tsx @@ -55,14 +55,13 @@ export const AuthorizationProvider = ({ privilegesEndpoint, children }: Props) = error, data: privilegesData, } = useQuery( - [TRANSFORM_REACT_QUERY_KEYS.PRIVILEGES], - async ({ signal }) => { - return await http.fetch(path, { + [TRANSFORM_REACT_QUERY_KEYS.GET_PRIVILEGES], + ({ signal }) => + http.fetch(path, { version, method: 'GET', signal, - }); - } + }) ); const value = { diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_details/step_details_form.tsx b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_details/step_details_form.tsx index 9c7f20197c33b..bb10abbeb8c3b 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_details/step_details_form.tsx +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_details/step_details_form.tsx @@ -29,11 +29,7 @@ import { toMountPoint } from '@kbn/kibana-react-plugin/public'; import { isHttpFetchError } from '@kbn/core-http-browser'; import { retentionPolicyMaxAgeInvalidErrorMessage } from '../../../../common/constants/validation_messages'; -import { - isEsIndices, - isEsIngestPipelines, - isPostTransformsPreviewResponseSchema, -} from '../../../../../../common/api_schemas/type_guards'; +import { isPostTransformsPreviewResponseSchema } from '../../../../../../common/api_schemas/type_guards'; import { DEFAULT_TRANSFORM_FREQUENCY } from '../../../../../../common/constants'; import { TransformId } from '../../../../../../common/types/transform'; import { isValidIndexName } from '../../../../../../common/utils/es_utils'; @@ -44,18 +40,20 @@ import { useAppDependencies, useToastNotifications } from '../../../../app_depen import { ToastNotificationText } from '../../../../components'; import { useDocumentationLinks, + useGetDataViewTitles, + useGetEsIndices, + useGetEsIngestPipelines, useGetTransforms, useGetTransformsPreview, } from '../../../../hooks'; import { SearchItems } from '../../../../hooks/use_search_items'; -import { useApi } from '../../../../hooks/use_api'; import { StepDetailsTimeField } from './step_details_time_field'; import { getTransformConfigQuery, getPreviewTransformRequestBody, isTransformIdValid, } from '../../../../common'; -import { EsIndexName, DataViewTitle } from './common'; +import { EsIndexName } from './common'; import { continuousModeDelayValidator, integerRangeMinus1To100Validator, @@ -94,8 +92,6 @@ export const StepDetailsForm: FC = React.memo( const [destinationIngestPipeline, setDestinationIngestPipeline] = useState( defaults.destinationIngestPipeline ); - const [indexNames, setIndexNames] = useState([]); - const [ingestPipelineNames, setIngestPipelineNames] = useState([]); const canCreateDataView = useMemo( () => @@ -105,7 +101,6 @@ export const StepDetailsForm: FC = React.memo( ); // Index pattern state - const [dataViewTitles, setDataViewTitles] = useState([]); const [createDataView, setCreateDataView] = useState( canCreateDataView === false ? false : defaults.createDataView ); @@ -129,7 +124,6 @@ export const StepDetailsForm: FC = React.memo( ); const { overlays, theme } = useAppDependencies(); - const api = useApi(); const { error: transformsError, data: transforms } = useGetTransforms(); const transformIds = transforms?.tableRows.map((d) => d.id) ?? []; @@ -195,68 +189,72 @@ export const StepDetailsForm: FC = React.memo( } }, [overlays, theme, toastNotifications, transformsPreviewError]); - // fetch existing transform IDs and indices once for form validation + const { error: esIndicesError, data: esIndicesData } = useGetEsIndices(); + const indexNames = esIndicesData?.map((index) => index.name) ?? []; + useEffect(() => { - // use an IIFE to avoid returning a Promise to useEffect. - (async function () { - const [indices, ingestPipelines] = await Promise.all([ - api.getEsIndices(), - api.getEsIngestPipelines(), - ]); - - if (isEsIndices(indices)) { - setIndexNames(indices.map((index) => index.name)); - } else { - toastNotifications.addDanger({ - title: i18n.translate('xpack.transform.stepDetailsForm.errorGettingIndexNames', { - defaultMessage: 'An error occurred getting the existing index names:', - }), - text: toMountPoint( - , - { theme$: theme.theme$ } - ), - }); - } + if (esIndicesError !== null) { + toastNotifications.addDanger({ + title: i18n.translate('xpack.transform.stepDetailsForm.errorGettingIndexNames', { + defaultMessage: 'An error occurred getting the existing index names:', + }), + text: toMountPoint( + , + { theme$: theme.theme$ } + ), + }); + } + // custom comparison + /* eslint-disable react-hooks/exhaustive-deps */ + }, [esIndicesError]); - if (isEsIngestPipelines(ingestPipelines)) { - setIngestPipelineNames(ingestPipelines.map(({ name }) => name)); - } else { - toastNotifications.addDanger({ - title: i18n.translate('xpack.transform.stepDetailsForm.errorGettingIngestPipelines', { - defaultMessage: 'An error occurred getting the existing ingest pipeline names:', - }), - text: toMountPoint( - , - { theme$: theme.theme$ } - ), - }); - } + const { error: esIngestPipelinesError, data: esIngestPipelinesData } = + useGetEsIngestPipelines(); + const ingestPipelineNames = esIngestPipelinesData?.map(({ name }) => name) ?? []; - try { - setDataViewTitles(await deps.data.dataViews.getTitles()); - } catch (e) { - toastNotifications.addDanger({ - title: i18n.translate('xpack.transform.stepDetailsForm.errorGettingDataViewTitles', { - defaultMessage: 'An error occurred getting the existing data view titles:', - }), - text: toMountPoint( - , - { theme$: theme.theme$ } - ), - }); - } - })(); - // run once - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); + useEffect(() => { + if (esIngestPipelinesError !== null) { + toastNotifications.addDanger({ + title: i18n.translate('xpack.transform.stepDetailsForm.errorGettingIngestPipelines', { + defaultMessage: 'An error occurred getting the existing ingest pipeline names:', + }), + text: toMountPoint( + , + { theme$: theme.theme$ } + ), + }); + } + // custom comparison + /* eslint-disable react-hooks/exhaustive-deps */ + }, [esIngestPipelinesError]); + + const { error: dataViewTitlesError, data: dataViewTitles } = useGetDataViewTitles(); + + useEffect(() => { + if (dataViewTitlesError !== null) { + toastNotifications.addDanger({ + title: i18n.translate('xpack.transform.stepDetailsForm.errorGettingDataViewTitles', { + defaultMessage: 'An error occurred getting the existing data view titles:', + }), + text: toMountPoint( + , + { theme$: theme.theme$ } + ), + }); + } + }, [dataViewTitlesError]); const dateFieldNames = searchItems.dataView.fields .filter((f) => f.type === KBN_FIELD_TYPES.DATE) @@ -296,7 +294,6 @@ export const StepDetailsForm: FC = React.memo( ); setRetentionPolicyMaxAge(''); } - // eslint-disable-next-line react-hooks/exhaustive-deps }, [isRetentionPolicyEnabled]); const transformIdExists = transformIds.some((id) => transformId === id); @@ -306,7 +303,7 @@ export const StepDetailsForm: FC = React.memo( const indexNameExists = indexNames.some((name) => destinationIndex === name); const indexNameEmpty = destinationIndex === ''; const indexNameValid = isValidIndexName(destinationIndex); - const dataViewTitleExists = dataViewTitles.some((name) => destinationIndex === name); + const dataViewTitleExists = dataViewTitles?.some((name) => destinationIndex === name) ?? false; const [transformFrequency, setTransformFrequency] = useState(defaults.transformFrequency); const isTransformFrequencyValid = transformFrequencyValidator(transformFrequency); diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/edit_transform_flyout/edit_transform_ingest_pipeline.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/edit_transform_flyout/edit_transform_ingest_pipeline.tsx index b5bb7f3fb258f..519bdc94011e1 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/edit_transform_flyout/edit_transform_ingest_pipeline.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/edit_transform_flyout/edit_transform_ingest_pipeline.tsx @@ -5,15 +5,13 @@ * 2.0. */ -import React, { useEffect, useState, type FC } from 'react'; +import React, { type FC } from 'react'; import { useEuiTheme, EuiComboBox, EuiFormRow, EuiSkeletonRectangle } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { isEsIngestPipelines } from '../../../../../../common/api_schemas/type_guards'; - -import { useApi } from '../../../../hooks/use_api'; +import { useGetEsIngestPipelines } from '../../../../hooks'; import { EditTransformFlyoutFormTextInput } from './edit_transform_flyout_form_text_input'; import { useEditTransformFlyout } from './use_edit_transform_flyout'; @@ -30,35 +28,8 @@ export const EditTransformIngestPipeline: FC = () => { const { errorMessages, value } = useEditTransformFlyout('destinationIngestPipeline'); const { formField } = useEditTransformFlyout('actions'); - const api = useApi(); - - const [ingestPipelineNames, setIngestPipelineNames] = useState([]); - const [isLoading, setIsLoading] = useState(true); - - useEffect(function fetchPipelinesOnMount() { - let unmounted = false; - - async function getIngestPipelineNames() { - try { - const ingestPipelines = await api.getEsIngestPipelines(); - - if (!unmounted && isEsIngestPipelines(ingestPipelines)) { - setIngestPipelineNames(ingestPipelines.map(({ name }) => name)); - } - } finally { - if (!unmounted) { - setIsLoading(false); - } - } - } - - getIngestPipelineNames(); - - return () => { - unmounted = true; - }; - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); + const { data: esIngestPipelinesData, isLoading } = useGetEsIngestPipelines(); + const ingestPipelineNames = esIngestPipelinesData?.map(({ name }) => name) ?? []; return ( <> From 8cade10233ad0da793133a380ef8394e9aee750a Mon Sep 17 00:00:00 2001 From: Walter Rafelsberger Date: Tue, 22 Aug 2023 19:18:32 +0200 Subject: [PATCH 14/53] migrate rest of useApi to react-query --- x-pack/plugins/transform/common/constants.ts | 1 + .../public/app/hooks/__mocks__/use_api.ts | 35 -------- .../transform/public/app/hooks/index.ts | 1 - .../transform/public/app/hooks/use_api.ts | 59 ------------- .../hooks/use_get_histograms_for_fields.ts | 66 +++++++++++++++ .../public/app/hooks/use_index_data.test.tsx | 39 +++++---- .../public/app/hooks/use_index_data.ts | 82 +++++++++---------- 7 files changed, 127 insertions(+), 156 deletions(-) delete mode 100644 x-pack/plugins/transform/public/app/hooks/__mocks__/use_api.ts delete mode 100644 x-pack/plugins/transform/public/app/hooks/use_api.ts create mode 100644 x-pack/plugins/transform/public/app/hooks/use_get_histograms_for_fields.ts diff --git a/x-pack/plugins/transform/common/constants.ts b/x-pack/plugins/transform/common/constants.ts index 19bf3512d40d7..2c7adcaaae1ec 100644 --- a/x-pack/plugins/transform/common/constants.ts +++ b/x-pack/plugins/transform/common/constants.ts @@ -36,6 +36,7 @@ export const TRANSFORM_REACT_QUERY_KEYS = { GET_DATA_VIEW_TITLES: 'transform.get_data_view_titles', GET_ES_INDICES: 'transform.get_es_indices', GET_ES_INGEST_PIPELINES: 'transform.get_es_ingest_pipelines', + GET_HISTOGRAMS_FOR_FIELDS: 'transform.get_histograms_for_fields', GET_PRIVILEGES: 'transform.get_privileges', GET_TRANSFORM: 'transform.get_transform', GET_TRANSFORM_AUDIT_MESSAGES: 'transform.get_transform_audit_messages', diff --git a/x-pack/plugins/transform/public/app/hooks/__mocks__/use_api.ts b/x-pack/plugins/transform/public/app/hooks/__mocks__/use_api.ts deleted file mode 100644 index 1bcd2e8cd0506..0000000000000 --- a/x-pack/plugins/transform/public/app/hooks/__mocks__/use_api.ts +++ /dev/null @@ -1,35 +0,0 @@ -/* - * 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 type { IHttpFetchError } from '@kbn/core-http-browser'; - -import { KBN_FIELD_TYPES } from '@kbn/field-types'; -import { DEFAULT_SAMPLER_SHARD_SIZE } from '@kbn/ml-agg-utils'; - -import type { FieldHistogramsResponseSchema } from '../../../../common/api_schemas/field_histograms'; - -import type { SavedSearchQuery } from '../use_search_items'; - -export interface FieldHistogramRequestConfig { - fieldName: string; - type?: KBN_FIELD_TYPES; -} - -const apiFactory = () => ({ - async getHistogramsForFields( - dataViewTitle: string, - fields: FieldHistogramRequestConfig[], - query: string | SavedSearchQuery, - samplerShardSize = DEFAULT_SAMPLER_SHARD_SIZE - ): Promise { - return Promise.resolve([]); - }, -}); - -export const useApi = () => { - return apiFactory(); -}; diff --git a/x-pack/plugins/transform/public/app/hooks/index.ts b/x-pack/plugins/transform/public/app/hooks/index.ts index 03a90d3b89042..f3e619e2364ce 100644 --- a/x-pack/plugins/transform/public/app/hooks/index.ts +++ b/x-pack/plugins/transform/public/app/hooks/index.ts @@ -5,7 +5,6 @@ * 2.0. */ -export { useApi } from './use_api'; export { useCreateTransform } from './use_create_transform'; export { useDocumentationLinks } from './use_documentation_links'; export { useGetDataViewTitles } from './use_get_data_view_titles'; diff --git a/x-pack/plugins/transform/public/app/hooks/use_api.ts b/x-pack/plugins/transform/public/app/hooks/use_api.ts deleted file mode 100644 index f50af871368f1..0000000000000 --- a/x-pack/plugins/transform/public/app/hooks/use_api.ts +++ /dev/null @@ -1,59 +0,0 @@ -/* - * 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 { useMemo } from 'react'; - -import type { IHttpFetchError } from '@kbn/core-http-browser'; - -import { KBN_FIELD_TYPES } from '@kbn/field-types'; -import { DEFAULT_SAMPLER_SHARD_SIZE } from '@kbn/ml-agg-utils'; - -import type { - FieldHistogramsRequestSchema, - FieldHistogramsResponseSchema, -} from '../../../common/api_schemas/field_histograms'; -import { addInternalBasePath } from '../../../common/constants'; - -import { useAppDependencies } from '../app_dependencies'; - -import type { SavedSearchQuery } from './use_search_items'; - -export interface FieldHistogramRequestConfig { - fieldName: string; - type?: KBN_FIELD_TYPES; -} - -export const useApi = () => { - const { http } = useAppDependencies(); - - return useMemo( - () => ({ - async getHistogramsForFields( - dataViewTitle: string, - fields: FieldHistogramRequestConfig[], - query: string | SavedSearchQuery, - runtimeMappings?: FieldHistogramsRequestSchema['runtimeMappings'], - samplerShardSize = DEFAULT_SAMPLER_SHARD_SIZE - ): Promise { - try { - return await http.post(addInternalBasePath(`field_histograms/${dataViewTitle}`), { - body: JSON.stringify({ - query, - fields, - samplerShardSize, - ...(runtimeMappings !== undefined ? { runtimeMappings } : {}), - }), - version: '1', - }); - } catch (e) { - return e; - } - }, - }), - [http] - ); -}; diff --git a/x-pack/plugins/transform/public/app/hooks/use_get_histograms_for_fields.ts b/x-pack/plugins/transform/public/app/hooks/use_get_histograms_for_fields.ts new file mode 100644 index 0000000000000..63ce23dba6214 --- /dev/null +++ b/x-pack/plugins/transform/public/app/hooks/use_get_histograms_for_fields.ts @@ -0,0 +1,66 @@ +/* + * 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 { useQuery } from '@tanstack/react-query'; + +import type { IHttpFetchError } from '@kbn/core-http-browser'; +import { KBN_FIELD_TYPES } from '@kbn/field-types'; +import { DEFAULT_SAMPLER_SHARD_SIZE } from '@kbn/ml-agg-utils'; + +import { addInternalBasePath, TRANSFORM_REACT_QUERY_KEYS } from '../../../common/constants'; +import type { + FieldHistogramsRequestSchema, + FieldHistogramsResponseSchema, +} from '../../../common/api_schemas/field_histograms'; + +import { useAppDependencies } from '../app_dependencies'; + +import type { SavedSearchQuery } from './use_search_items'; + +export interface FieldHistogramRequestConfig { + fieldName: string; + type?: KBN_FIELD_TYPES; +} + +export const useGetHistogramsForFields = ( + dataViewTitle: string, + fields: FieldHistogramRequestConfig[], + query: string | SavedSearchQuery, + runtimeMappings?: FieldHistogramsRequestSchema['runtimeMappings'], + enabled?: boolean, + samplerShardSize = DEFAULT_SAMPLER_SHARD_SIZE +) => { + const { http } = useAppDependencies(); + + return useQuery( + [ + TRANSFORM_REACT_QUERY_KEYS.GET_HISTOGRAMS_FOR_FIELDS, + { + dataViewTitle, + fields, + query, + runtimeMappings, + samplerShardSize, + }, + ], + ({ signal }) => + http.post( + addInternalBasePath(`field_histograms/${dataViewTitle}`), + { + body: JSON.stringify({ + query, + fields, + samplerShardSize, + ...(runtimeMappings !== undefined ? { runtimeMappings } : {}), + }), + version: '1', + signal, + } + ), + { enabled } + ); +}; diff --git a/x-pack/plugins/transform/public/app/hooks/use_index_data.test.tsx b/x-pack/plugins/transform/public/app/hooks/use_index_data.test.tsx index 9da9fa8e5e782..c64d2eb09ee54 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_index_data.test.tsx +++ b/x-pack/plugins/transform/public/app/hooks/use_index_data.test.tsx @@ -6,12 +6,12 @@ */ import React, { FC } from 'react'; -import { __IntlProvider as IntlProvider } from '@kbn/i18n-react'; - +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import '@testing-library/jest-dom/extend-expect'; import { render, screen, waitFor } from '@testing-library/react'; import { renderHook } from '@testing-library/react-hooks'; +import { __IntlProvider as IntlProvider } from '@kbn/i18n-react'; import { CoreSetup } from '@kbn/core/public'; import { DataGrid, type UseIndexDataReturnType } from '@kbn/ml-data-grid'; import type { RuntimeMappings } from '@kbn/ml-runtime-field-utils'; @@ -25,7 +25,6 @@ import { useIndexData } from './use_index_data'; jest.mock('../../shared_imports'); jest.mock('../app_dependencies'); -jest.mock('./use_api'); import { MlSharedContext } from '../__mocks__/shared_context'; @@ -45,13 +44,17 @@ const runtimeMappings: RuntimeMappings = { }, }; +const queryClient = new QueryClient(); + describe('Transform: useIndexData()', () => { test('dataView set triggers loading', async () => { const mlShared = await getMlSharedImports(); const wrapper: FC = ({ children }) => ( - - {children} - + + + {children} + + ); const { result, waitForNextUpdate } = renderHook( @@ -102,11 +105,13 @@ describe('Transform: with useIndexData()', () => { }; render( - - - - - + + + + + + + ); // Act @@ -142,11 +147,13 @@ describe('Transform: with useIndexData()', () => { }; render( - - - - - + + + + + + + ); // Act diff --git a/x-pack/plugins/transform/public/app/hooks/use_index_data.ts b/x-pack/plugins/transform/public/app/hooks/use_index_data.ts index 7b6911636c600..1f42394fb0fdb 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_index_data.ts +++ b/x-pack/plugins/transform/public/app/hooks/use_index_data.ts @@ -28,10 +28,7 @@ import { } from '@kbn/ml-data-grid'; import type { TimeRange as TimeRangeMs } from '@kbn/ml-date-picker'; -import { - isEsSearchResponse, - isFieldHistogramsResponseSchema, -} from '../../../common/api_schemas/type_guards'; +import { isEsSearchResponse } from '../../../common/api_schemas/type_guards'; import { hasKeywordDuplicate, isKeywordDuplicate, @@ -44,7 +41,7 @@ import { useToastNotifications, useAppDependencies } from '../app_dependencies'; import type { StepDefineExposedState } from '../sections/create_transform/components/step_define/common'; import { SearchItems } from './use_search_items'; -import { useApi } from './use_api'; +import { useGetHistogramsForFields } from './use_get_histograms_for_fields'; import { useDataSearch } from './use_data_search'; export const useIndexData = ( @@ -61,7 +58,6 @@ export const useIndexData = ( const indexPattern = useMemo(() => dataView.getIndexPattern(), [dataView]); - const api = useApi(); const dataSearch = useDataSearch(); const toastNotifications = useToastNotifications(); @@ -273,58 +269,54 @@ export const useIndexData = ( ]), ]); - useEffect(() => { - const fetchColumnChartsData = async function () { - const allDataViewFieldNames = new Set(dataView.fields.map((f) => f.name)); - const columnChartsData = await api.getHistogramsForFields( - indexPattern, - columns - .filter((cT) => dataGrid.visibleColumns.includes(cT.id)) - .map((cT) => { - // If a column field name has a corresponding keyword field, - // fetch the keyword field instead to be able to do aggregations. - const fieldName = cT.id; - return hasKeywordDuplicate(fieldName, allDataViewFieldNames) - ? { - fieldName: `${fieldName}.keyword`, - type: getFieldType(undefined), - } - : { - fieldName, - type: getFieldType(cT.schema), - }; - }), - isDefaultQuery(query) ? defaultQuery : queryWithBaseFilterCriteria, - combinedRuntimeMappings - ); + const allDataViewFieldNames = new Set(dataView.fields.map((f) => f.name)); + const { error: histogramsForFieldsError, data: histogramsForFieldsData } = + useGetHistogramsForFields( + indexPattern, + columns + .filter((cT) => dataGrid.visibleColumns.includes(cT.id)) + .map((cT) => { + // If a column field name has a corresponding keyword field, + // fetch the keyword field instead to be able to do aggregations. + const fieldName = cT.id; + return hasKeywordDuplicate(fieldName, allDataViewFieldNames) + ? { + fieldName: `${fieldName}.keyword`, + type: getFieldType(undefined), + } + : { + fieldName, + type: getFieldType(cT.schema), + }; + }), + isDefaultQuery(query) ? defaultQuery : queryWithBaseFilterCriteria, + combinedRuntimeMappings, + chartsVisible + ); - if (!isFieldHistogramsResponseSchema(columnChartsData)) { - showDataGridColumnChartErrorMessageToast(columnChartsData, toastNotifications); - return; - } + useEffect(() => { + if (histogramsForFieldsError !== null) { + showDataGridColumnChartErrorMessageToast(histogramsForFieldsError, toastNotifications); + } + // custom comparison + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [histogramsForFieldsError]); + useEffect(() => { + if (histogramsForFieldsData) { setColumnCharts( // revert field names with `.keyword` used to do aggregations to their original column name - columnChartsData.map((d) => ({ + histogramsForFieldsData.map((d) => ({ ...d, ...(isKeywordDuplicate(d.id, allDataViewFieldNames) ? { id: removeKeywordPostfix(d.id) } : {}), })) ); - }; - - if (chartsVisible) { - fetchColumnChartsData(); } // custom comparison // eslint-disable-next-line react-hooks/exhaustive-deps - }, [ - chartsVisible, - indexPattern, - // eslint-disable-next-line react-hooks/exhaustive-deps - JSON.stringify([query, dataGrid.visibleColumns, combinedRuntimeMappings, timeRangeMs]), - ]); + }, [histogramsForFieldsData]); const renderCellValue = useRenderCellValue(dataView, pagination, tableItems); From 0614d002266a3259b061038ab764430c87e7ec84 Mon Sep 17 00:00:00 2001 From: Walter Rafelsberger Date: Tue, 22 Aug 2023 19:35:26 +0200 Subject: [PATCH 15/53] remove unnecessary type guards --- .../common/api_schemas/type_guards.ts | 125 ------------------ .../public/app/hooks/use_create_transform.tsx | 59 ++++----- .../public/app/hooks/use_get_transforms.ts | 21 +-- .../step_create/step_create_form.tsx | 22 +-- .../step_details/step_details_form.tsx | 3 +- 5 files changed, 42 insertions(+), 188 deletions(-) diff --git a/x-pack/plugins/transform/common/api_schemas/type_guards.ts b/x-pack/plugins/transform/common/api_schemas/type_guards.ts index d5dbad0056c35..08b12144aec35 100644 --- a/x-pack/plugins/transform/common/api_schemas/type_guards.ts +++ b/x-pack/plugins/transform/common/api_schemas/type_guards.ts @@ -9,74 +9,6 @@ import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { isPopulatedObject } from '@kbn/ml-is-populated-object'; -import type { EsIndex } from '../types/es_index'; -import type { EsIngestPipeline } from '../types/es_ingest_pipeline'; - -// To be able to use the type guards on the client side, we need to make sure we don't import -// the code of '@kbn/config-schema' but just its types, otherwise the client side code will -// fail to build. -import type { FieldHistogramsResponseSchema } from './field_histograms'; -import type { GetTransformsAuditMessagesResponseSchema } from './audit_messages'; -import type { DeleteTransformsResponseSchema } from './delete_transforms'; -import type { ResetTransformsResponseSchema } from './reset_transforms'; -import type { StartTransformsResponseSchema } from './start_transforms'; -import type { StopTransformsResponseSchema } from './stop_transforms'; -import type { ScheduleNowTransformsResponseSchema } from './schedule_now_transforms'; -import type { - GetTransformNodesResponseSchema, - GetTransformsResponseSchema, - PostTransformsPreviewResponseSchema, - PutTransformsResponseSchema, -} from './transforms'; -import type { GetTransformsStatsResponseSchema } from './transforms_stats'; -import type { PostTransformsUpdateResponseSchema } from './update_transforms'; - -const isGenericResponseSchema = (arg: any): arg is T => { - return isPopulatedObject(arg, ['count', 'transforms']) && Array.isArray(arg.transforms); -}; - -export const isGetTransformNodesResponseSchema = ( - arg: unknown -): arg is GetTransformNodesResponseSchema => { - return isPopulatedObject(arg, ['count']) && typeof arg.count === 'number'; -}; - -export const isGetTransformsResponseSchema = (arg: unknown): arg is GetTransformsResponseSchema => { - return isGenericResponseSchema(arg); -}; - -export const isGetTransformsStatsResponseSchema = ( - arg: unknown -): arg is GetTransformsStatsResponseSchema => { - return isGenericResponseSchema(arg); -}; - -export const isDeleteTransformsResponseSchema = ( - arg: unknown -): arg is DeleteTransformsResponseSchema => { - return ( - isPopulatedObject(arg) && - Object.values(arg).every((d) => isPopulatedObject(d, ['transformDeleted'])) - ); -}; - -export const isResetTransformsResponseSchema = ( - arg: unknown -): arg is ResetTransformsResponseSchema => { - return ( - isPopulatedObject(arg) && - Object.values(arg).every((d) => isPopulatedObject(d, ['transformReset'])) - ); -}; - -export const isEsIndices = (arg: unknown): arg is EsIndex[] => { - return Array.isArray(arg); -}; - -export const isEsIngestPipelines = (arg: unknown): arg is EsIngestPipeline[] => { - return Array.isArray(arg) && arg.every((d) => isPopulatedObject(d, ['name'])); -}; - export const isEsSearchResponse = (arg: unknown): arg is estypes.SearchResponse => { return isPopulatedObject(arg, ['hits']); }; @@ -88,60 +20,3 @@ export const isEsSearchResponseWithAggregations = ( ): arg is SearchResponseWithAggregations => { return isEsSearchResponse(arg) && {}.hasOwnProperty.call(arg, 'aggregations'); }; - -export const isFieldHistogramsResponseSchema = ( - arg: unknown -): arg is FieldHistogramsResponseSchema => { - return Array.isArray(arg); -}; - -export const isGetTransformsAuditMessagesResponseSchema = ( - arg: unknown -): arg is GetTransformsAuditMessagesResponseSchema => { - return isPopulatedObject(arg, ['messages', 'total']); -}; - -export const isPostTransformsPreviewResponseSchema = ( - arg: unknown -): arg is PostTransformsPreviewResponseSchema => { - return ( - isPopulatedObject(arg, ['generated_dest_index', 'preview']) && - typeof arg.generated_dest_index !== undefined && - Array.isArray(arg.preview) - ); -}; - -export const isPostTransformsUpdateResponseSchema = ( - arg: unknown -): arg is PostTransformsUpdateResponseSchema => { - return isPopulatedObject(arg, ['id']) && typeof arg.id === 'string'; -}; - -export const isPutTransformsResponseSchema = (arg: unknown): arg is PutTransformsResponseSchema => { - return ( - isPopulatedObject(arg, ['transformsCreated', 'errors']) && - Array.isArray(arg.transformsCreated) && - Array.isArray(arg.errors) - ); -}; - -const isGenericSuccessResponseSchema = (arg: unknown) => - isPopulatedObject(arg) && Object.values(arg).every((d) => isPopulatedObject(d, ['success'])); - -export const isStartTransformsResponseSchema = ( - arg: unknown -): arg is StartTransformsResponseSchema => { - return isGenericSuccessResponseSchema(arg); -}; - -export const isStopTransformsResponseSchema = ( - arg: unknown -): arg is StopTransformsResponseSchema => { - return isGenericSuccessResponseSchema(arg); -}; - -export const isScheduleNowTransformsResponseSchema = ( - arg: unknown -): arg is ScheduleNowTransformsResponseSchema => { - return isGenericSuccessResponseSchema(arg); -}; diff --git a/x-pack/plugins/transform/public/app/hooks/use_create_transform.tsx b/x-pack/plugins/transform/public/app/hooks/use_create_transform.tsx index f44f0f234559f..d97508ed3a009 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_create_transform.tsx +++ b/x-pack/plugins/transform/public/app/hooks/use_create_transform.tsx @@ -15,7 +15,6 @@ import type { PutTransformsRequestSchema, PutTransformsResponseSchema, } from '../../../common/api_schemas/transforms'; -import { isPutTransformsResponseSchema } from '../../../common/api_schemas/type_guards'; import { addInternalBasePath } from '../../../common/constants'; import type { TransformId } from '../../../common/types/transform'; import { getErrorMessage } from '../../../common/utils/errors'; @@ -32,6 +31,19 @@ export const useCreateTransform = ( const refreshTransformList = useRefreshTransformList(); const toastNotifications = useToastNotifications(); + function errorToast(error: unknown) { + toastNotifications.addDanger({ + title: i18n.translate('xpack.transform.stepCreateForm.createTransformErrorMessage', { + defaultMessage: 'An error occurred creating the transform {transformId}:', + values: { transformId }, + }), + text: toMountPoint( + , + { theme$: theme.theme$ } + ), + }); + } + const mutation = useMutation({ mutationFn: () => { return http.put( @@ -42,40 +54,21 @@ export const useCreateTransform = ( } ); }, - onError: (resp) => { - if (!isPutTransformsResponseSchema(resp) || resp.errors.length > 0) { - let respErrors: - | PutTransformsResponseSchema['errors'] - | PutTransformsResponseSchema['errors'][number] - | undefined; - - if (isPutTransformsResponseSchema(resp) && resp.errors.length > 0) { - respErrors = resp.errors.length === 1 ? resp.errors[0] : resp.errors; - } - - toastNotifications.addDanger({ - title: i18n.translate('xpack.transform.stepCreateForm.createTransformErrorMessage', { - defaultMessage: 'An error occurred creating the transform {transformId}:', + onError: (error) => { + errorToast(error); + }, + onSuccess: (resp) => { + if (resp.errors.length > 0) { + errorToast(resp.errors.length === 1 ? resp.errors[0] : resp.errors); + } else { + toastNotifications.addSuccess( + i18n.translate('xpack.transform.stepCreateForm.createTransformSuccessMessage', { + defaultMessage: 'Request to create transform {transformId} acknowledged.', values: { transformId }, - }), - text: toMountPoint( - , - { theme$: theme.theme$ } - ), - }); + }) + ); } - }, - onSuccess: (results) => { - toastNotifications.addSuccess( - i18n.translate('xpack.transform.stepCreateForm.createTransformSuccessMessage', { - defaultMessage: 'Request to create transform {transformId} acknowledged.', - values: { transformId }, - }) - ); + refreshTransformList(); }, }); diff --git a/x-pack/plugins/transform/public/app/hooks/use_get_transforms.ts b/x-pack/plugins/transform/public/app/hooks/use_get_transforms.ts index f97eaf671fb97..04a0d09219095 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_get_transforms.ts +++ b/x-pack/plugins/transform/public/app/hooks/use_get_transforms.ts @@ -9,11 +9,12 @@ import { useQuery } from '@tanstack/react-query'; import type { IHttpFetchError } from '@kbn/core-http-browser'; import { isDefined } from '@kbn/ml-is-defined'; -import { isGetTransformsStatsResponseSchema } from '../../../common/api_schemas/type_guards'; + import type { GetTransformNodesResponseSchema, GetTransformsResponseSchema, } from '../../../common/api_schemas/transforms'; +import type { GetTransformsStatsResponseSchema } from '../../../common/api_schemas/transforms_stats'; import { addInternalBasePath, DEFAULT_REFRESH_INTERVAL_MS, @@ -24,7 +25,6 @@ import { isTransformStats } from '../../../common/types/transform_stats'; import { type TransformListRow } from '../common'; import { useAppDependencies } from '../app_dependencies'; - import { TRANSFORM_ERROR_TYPE } from '../common/transform'; interface UseGetTransformsResponse { @@ -62,11 +62,14 @@ export const useGetTransforms = () => { signal, } ); - const transformStats = await http.get(addInternalBasePath(`transforms/_stats`), { - version: '1', - asSystemRequest: true, - signal, - }); + const transformStats = await http.get( + addInternalBasePath(`transforms/_stats`), + { + version: '1', + asSystemRequest: true, + signal, + } + ); // There might be some errors with fetching certain transforms // For example, when task exists and is running but the config is deleted @@ -85,9 +88,7 @@ export const useGetTransforms = () => { } update.tableRows = transformConfigs.transforms.reduce((reducedtableRows, config) => { - const stats = isGetTransformsStatsResponseSchema(transformStats) - ? transformStats.transforms.find((d) => config.id === d.id) - : undefined; + const stats = transformStats.transforms.find((d) => config.id === d.id); // A newly created transform might not have corresponding stats yet. // If that's the case we just skip the transform and don't add it to the transform list yet. diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_create/step_create_form.tsx b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_create/step_create_form.tsx index b0391c85c1146..2bca8ec8072e1 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_create/step_create_form.tsx +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_create/step_create_form.tsx @@ -31,10 +31,6 @@ import { DISCOVER_APP_LOCATOR } from '@kbn/discover-plugin/common'; import { DuplicateDataViewError } from '@kbn/data-plugin/public'; import type { RuntimeField } from '@kbn/data-views-plugin/common'; import { isPopulatedObject } from '@kbn/ml-is-populated-object'; -import { - isGetTransformsStatsResponseSchema, - isStartTransformsResponseSchema, -} from '../../../../../../common/api_schemas/type_guards'; import { PROGRESS_REFRESH_INTERVAL_MS } from '../../../../../../common/constants'; import { getErrorMessage } from '../../../../../../common/utils/errors'; @@ -156,15 +152,9 @@ export const StepCreateForm: FC = React.memo( setLoading(true); startTransforms([{ id: transformId }], { - onError: () => { - setStarted(false); - }, - onSuccess: (resp) => { - setStarted(isStartTransformsResponseSchema(resp) && resp[transformId]?.success === true); - }, - onSettled: () => { - setLoading(false); - }, + onError: () => setStarted(false), + onSuccess: (resp) => setStarted(resp[transformId]?.success === true), + onSettled: () => setLoading(false), }); } @@ -258,11 +248,7 @@ export const StepCreateForm: FC = React.memo( return; } - if ( - isGetTransformsStatsResponseSchema(stats) && - Array.isArray(stats.transforms) && - stats.transforms.length > 0 - ) { + if (stats && Array.isArray(stats.transforms) && stats.transforms.length > 0) { const percent = getTransformProgress({ id: transformId, diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_details/step_details_form.tsx b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_details/step_details_form.tsx index bb10abbeb8c3b..a234795ebe788 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_details/step_details_form.tsx +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_details/step_details_form.tsx @@ -29,7 +29,6 @@ import { toMountPoint } from '@kbn/kibana-react-plugin/public'; import { isHttpFetchError } from '@kbn/core-http-browser'; import { retentionPolicyMaxAgeInvalidErrorMessage } from '../../../../common/constants/validation_messages'; -import { isPostTransformsPreviewResponseSchema } from '../../../../../../common/api_schemas/type_guards'; import { DEFAULT_TRANSFORM_FREQUENCY } from '../../../../../../common/constants'; import { TransformId } from '../../../../../../common/types/transform'; import { isValidIndexName } from '../../../../../../common/utils/es_utils'; @@ -160,7 +159,7 @@ export const StepDetailsForm: FC = React.memo( useGetTransformsPreview(previewRequest); useEffect(() => { - if (isPostTransformsPreviewResponseSchema(transformPreview)) { + if (transformPreview) { const properties = transformPreview.generated_dest_index.mappings.properties; const timeFields: string[] = Object.keys(properties).filter( (col) => properties[col].type === 'date' From 5f04ab7e38da32338ef5932257da9efe9e6c9ca8 Mon Sep 17 00:00:00 2001 From: Walter Rafelsberger Date: Tue, 22 Aug 2023 22:56:40 +0200 Subject: [PATCH 16/53] remove unnecessary type guards --- .../common/api_schemas/type_guards.ts | 22 -- x-pack/plugins/transform/common/constants.ts | 1 + .../public/app/hooks/use_data_search.ts | 46 ++-- .../public/app/hooks/use_index_data.ts | 212 ++++++++---------- .../components/filter_term_form.tsx | 128 +++++------ 5 files changed, 174 insertions(+), 235 deletions(-) delete mode 100644 x-pack/plugins/transform/common/api_schemas/type_guards.ts diff --git a/x-pack/plugins/transform/common/api_schemas/type_guards.ts b/x-pack/plugins/transform/common/api_schemas/type_guards.ts deleted file mode 100644 index 08b12144aec35..0000000000000 --- a/x-pack/plugins/transform/common/api_schemas/type_guards.ts +++ /dev/null @@ -1,22 +0,0 @@ -/* - * 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 type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; - -import { isPopulatedObject } from '@kbn/ml-is-populated-object'; - -export const isEsSearchResponse = (arg: unknown): arg is estypes.SearchResponse => { - return isPopulatedObject(arg, ['hits']); -}; - -type SearchResponseWithAggregations = Required> & - estypes.SearchResponse; -export const isEsSearchResponseWithAggregations = ( - arg: unknown -): arg is SearchResponseWithAggregations => { - return isEsSearchResponse(arg) && {}.hasOwnProperty.call(arg, 'aggregations'); -}; diff --git a/x-pack/plugins/transform/common/constants.ts b/x-pack/plugins/transform/common/constants.ts index 2c7adcaaae1ec..1584811c0df6b 100644 --- a/x-pack/plugins/transform/common/constants.ts +++ b/x-pack/plugins/transform/common/constants.ts @@ -33,6 +33,7 @@ export const addInternalBasePath = (uri: string): string => `${INTERNAL_API_BASE export const addExternalBasePath = (uri: string): string => `${EXTERNAL_API_BASE_PATH}${uri}`; export const TRANSFORM_REACT_QUERY_KEYS = { + DATA_SEARCH: 'transform.data_search', GET_DATA_VIEW_TITLES: 'transform.get_data_view_titles', GET_ES_INDICES: 'transform.get_es_indices', GET_ES_INGEST_PIPELINES: 'transform.get_es_ingest_pipelines', diff --git a/x-pack/plugins/transform/public/app/hooks/use_data_search.ts b/x-pack/plugins/transform/public/app/hooks/use_data_search.ts index af4bb440f9e24..f691cb7a0d8b6 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_data_search.ts +++ b/x-pack/plugins/transform/public/app/hooks/use_data_search.ts @@ -5,37 +5,37 @@ * 2.0. */ -import { useCallback } from 'react'; +import { useQuery } from '@tanstack/react-query'; import { lastValueFrom } from 'rxjs'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; + import type { IKibanaSearchRequest } from '@kbn/data-plugin/common'; +import { TRANSFORM_REACT_QUERY_KEYS } from '../../../common/constants'; + import { useAppDependencies } from '../app_dependencies'; -export const useDataSearch = () => { +export const useDataSearch = ( + esSearchRequestParams: IKibanaSearchRequest['params'], + enabled?: boolean +) => { const { data } = useAppDependencies(); - return useCallback( - async (esSearchRequestParams: IKibanaSearchRequest['params'], abortSignal?: AbortSignal) => { - try { - const { rawResponse: resp } = await lastValueFrom( - data.search.search( - { - params: esSearchRequestParams, - }, - { abortSignal } - ) - ); - - return resp; - } catch (error) { - if (error.name === 'AbortError') { - // ignore abort errors - } else { - return error; - } - } + return useQuery( + [TRANSFORM_REACT_QUERY_KEYS.DATA_SEARCH, esSearchRequestParams], + async ({ signal }) => { + const { rawResponse: resp } = await lastValueFrom( + data.search.search( + { + params: esSearchRequestParams, + }, + { abortSignal: signal } + ) + ); + + return resp; }, - [data] + { enabled } ); }; diff --git a/x-pack/plugins/transform/public/app/hooks/use_index_data.ts b/x-pack/plugins/transform/public/app/hooks/use_index_data.ts index 1f42394fb0fdb..5fca52ae9c6f8 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_index_data.ts +++ b/x-pack/plugins/transform/public/app/hooks/use_index_data.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { useEffect, useMemo, useRef, useState } from 'react'; +import { useEffect, useMemo, useRef } from 'react'; import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import type { EuiDataGridColumn } from '@elastic/eui'; @@ -28,7 +28,6 @@ import { } from '@kbn/ml-data-grid'; import type { TimeRange as TimeRangeMs } from '@kbn/ml-date-picker'; -import { isEsSearchResponse } from '../../../common/api_schemas/type_guards'; import { hasKeywordDuplicate, isKeywordDuplicate, @@ -57,12 +56,8 @@ export const useIndexData = ( const loadIndexDataStartTime = useRef(window.performance.now()); const indexPattern = useMemo(() => dataView.getIndexPattern(), [dataView]); - - const dataSearch = useDataSearch(); const toastNotifications = useToastNotifications(); - const [dataViewFields, setDataViewFields] = useState(); - const baseFilterCriteria = buildBaseFilterCriteria( dataView.timeFieldName, timeRangeMs?.from, @@ -81,67 +76,69 @@ export const useIndexData = ( }, }; - useEffect(() => { - if (dataView.timeFieldName !== undefined && timeRangeMs === undefined) { - return; - } - const abortController = new AbortController(); - - // Fetch 500 random documents to determine populated fields. - // This is a workaround to avoid passing potentially thousands of unpopulated fields - // (for example, as part of filebeat/metricbeat/ECS based indices) - // to the data grid component which would significantly slow down the page. - const fetchDataGridSampleDocuments = async function () { - setErrorMessage(''); - setStatus(INDEX_STATUS.LOADING); - - const esSearchRequest = { - index: indexPattern, - body: { - fields: ['*'], - _source: false, - query: { - function_score: { - query: defaultQuery, - random_score: {}, - }, + // Fetch 500 random documents to determine populated fields. + // This is a workaround to avoid passing potentially thousands of unpopulated fields + // (for example, as part of filebeat/metricbeat/ECS based indices) + // to the data grid component which would significantly slow down the page. + const { + error: dataViewFieldsError, + data: dataViewFieldsData, + isError: dataViewFieldsIsError, + isLoading: dataViewFieldsIsLoading, + } = useDataSearch( + { + index: indexPattern, + body: { + fields: ['*'], + _source: false, + query: { + function_score: { + query: defaultQuery, + random_score: {}, }, - size: 500, }, - }; - - const resp = await dataSearch(esSearchRequest, abortController.signal); - - if (!isEsSearchResponse(resp)) { - setErrorMessage(getErrorMessage(resp)); - setStatus(INDEX_STATUS.ERROR); - return; - } + size: 500, + }, + }, + // Check whether fetching should be enabled + !(dataView.timeFieldName !== undefined && timeRangeMs === undefined) + ); + 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 = resp.hits.hits.every((d) => typeof d.fields === 'undefined'); + const isMissingFields = dataViewFieldsData.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]); - const docs = resp.hits.hits.map((d) => getProcessedFields(d.fields ?? {})); + const dataViewFields = useMemo(() => { + if (dataViewFieldsData) { + const docs = dataViewFieldsData.hits.hits.map((d) => getProcessedFields(d.fields ?? {})); // Get all field names for each returned doc and flatten it // to a list of unique field names used across all docs. const allDataViewFields = getFieldsFromKibanaIndexPattern(dataView); - const populatedFields = [...new Set(docs.map(Object.keys).flat(1))] + return [...new Set(docs.map(Object.keys).flat(1))] .filter((d) => allDataViewFields.includes(d)) .sort(); - - setCcsWarning(isCrossClusterSearch && isMissingFields); - setStatus(INDEX_STATUS.LOADED); - setDataViewFields(populatedFields); - }; - - fetchDataGridSampleDocuments(); - - return () => { - abortController.abort(); - }; - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [timeRangeMs]); + } + }, [dataView, dataViewFieldsData]); const columns: EuiDataGridColumn[] = useMemo(() => { if (typeof dataViewFields === 'undefined') { @@ -195,79 +192,64 @@ export const useIndexData = ( // eslint-disable-next-line react-hooks/exhaustive-deps }, [JSON.stringify([query, timeRangeMs])]); - useEffect(() => { - if (typeof dataViewFields === 'undefined') { - return; - } - const abortController = new AbortController(); + const sort: EsSorting = sortingColumns.reduce((s, column) => { + s[column.id] = { order: column.direction }; + return s; + }, {} as EsSorting); + + const { + error: dataGridDataError, + data: dataGridData, + isError: dataGridDataIsError, + isLoading: dataGridDataIsLoading, + } = useDataSearch( + { + index: indexPattern, + body: { + fields: ['*'], + _source: false, + query: isDefaultQuery(query) ? defaultQuery : queryWithBaseFilterCriteria, + from: pagination.pageIndex * pagination.pageSize, + size: pagination.pageSize, + ...(Object.keys(sort).length > 0 ? { sort } : {}), + ...(isRuntimeMappings(combinedRuntimeMappings) + ? { runtime_mappings: combinedRuntimeMappings } + : {}), + }, + }, + // Check whether fetching should be enabled + dataViewFields !== undefined + ); - const fetchDataGridData = async function () { + useEffect(() => { + if (dataGridDataIsLoading && !dataGridDataIsError) { setErrorMessage(''); setStatus(INDEX_STATUS.LOADING); - - const sort: EsSorting = sortingColumns.reduce((s, column) => { - s[column.id] = { order: column.direction }; - return s; - }, {} as EsSorting); - - const esSearchRequest = { - index: indexPattern, - body: { - fields: ['*'], - _source: false, - query: isDefaultQuery(query) ? defaultQuery : queryWithBaseFilterCriteria, - from: pagination.pageIndex * pagination.pageSize, - size: pagination.pageSize, - ...(Object.keys(sort).length > 0 ? { sort } : {}), - ...(isRuntimeMappings(combinedRuntimeMappings) - ? { runtime_mappings: combinedRuntimeMappings } - : {}), - }, - }; - const resp = await dataSearch(esSearchRequest, abortController.signal); - - if (!isEsSearchResponse(resp)) { - setErrorMessage(getErrorMessage(resp)); - setStatus(INDEX_STATUS.ERROR); - return; - } - + } else if (dataGridDataError !== null) { + setErrorMessage(getErrorMessage(dataGridDataError)); + setStatus(INDEX_STATUS.ERROR); + } else if (!dataGridDataIsLoading && !dataGridDataIsError && dataGridData !== undefined) { const isCrossClusterSearch = indexPattern.includes(':'); - const isMissingFields = resp.hits.hits.every((d) => typeof d.fields === 'undefined'); + const isMissingFields = dataGridData.hits.hits.every((d) => typeof d.fields === 'undefined'); - const docs = resp.hits.hits.map((d) => getProcessedFields(d.fields ?? {})); + const docs = dataGridData.hits.hits.map((d) => getProcessedFields(d.fields ?? {})); setCcsWarning(isCrossClusterSearch && isMissingFields); setRowCountInfo({ - rowCount: typeof resp.hits.total === 'number' ? resp.hits.total : resp.hits.total!.value, + rowCount: + typeof dataGridData.hits.total === 'number' + ? dataGridData.hits.total + : dataGridData.hits.total!.value, rowCountRelation: - typeof resp.hits.total === 'number' + typeof dataGridData.hits.total === 'number' ? ('eq' as estypes.SearchTotalHitsRelation) - : resp.hits.total!.relation, + : dataGridData.hits.total!.relation, }); setTableItems(docs); setStatus(INDEX_STATUS.LOADED); - }; - - fetchDataGridData(); - - return () => { - abortController.abort(); - }; - // custom comparison - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [ - indexPattern, + } // eslint-disable-next-line react-hooks/exhaustive-deps - JSON.stringify([ - query, - pagination, - sortingColumns, - dataViewFields, - combinedRuntimeMappings, - timeRangeMs, - ]), - ]); + }, [dataGridDataError, dataGridDataIsError, dataGridDataIsLoading]); const allDataViewFieldNames = new Set(dataView.fields.map((f) => f.name)); const { error: histogramsForFieldsError, data: histogramsForFieldsData } = diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/common/filter_agg/components/filter_term_form.tsx b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/common/filter_agg/components/filter_term_form.tsx index 0c6fae30fd1f0..c35cca74c72ac 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/common/filter_agg/components/filter_term_form.tsx +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/common/filter_agg/components/filter_term_form.tsx @@ -6,7 +6,7 @@ */ import { debounce } from 'lodash'; -import React, { useCallback, useContext, useEffect, useState } from 'react'; +import React, { useCallback, useContext, useEffect, useMemo, useState } from 'react'; import useUpdateEffect from 'react-use/lib/useUpdateEffect'; import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; @@ -18,7 +18,6 @@ import { i18n } from '@kbn/i18n'; import { isMultiBucketAggregate } from '@kbn/ml-agg-utils'; import { useDataSearch } from '../../../../../../../hooks/use_data_search'; -import { isEsSearchResponseWithAggregations } from '../../../../../../../../../common/api_schemas/type_guards'; import { CreateTransformWizardContext } from '../../../../wizard/wizard'; import { useToastNotifications } from '../../../../../../../app_dependencies'; @@ -33,16 +32,22 @@ export const FilterTermForm: FilterAggConfigTerm['aggTypeConfig']['FilterAggForm selectedField, }) => { const { dataView, runtimeMappings } = useContext(CreateTransformWizardContext); - const dataSearch = useDataSearch(); const toastNotifications = useToastNotifications(); - const [options, setOptions] = useState([]); - const [isLoading, setIsLoading] = useState(true); const [searchValue, setSearchValue] = useState(''); + const debouncedOnSearchChange = useMemo( + () => debounce((d: string) => setSearchValue(d), 600), + [] + ); - const onSearchChange = (newSearchValue: string) => { - setSearchValue(newSearchValue); - }; + useEffect(() => { + // Simulate initial load. + debouncedOnSearchChange(''); + // Cancel debouncing when unmounting + return () => debouncedOnSearchChange.cancel(); + // Only call on mount + /* eslint-disable-next-line react-hooks/exhaustive-deps */ + }, []); const updateConfig = useCallback( (update) => { @@ -56,80 +61,53 @@ export const FilterTermForm: FilterAggConfigTerm['aggTypeConfig']['FilterAggForm [config, onChange] ); - useEffect(() => { - const abortController = new AbortController(); - - const fetchOptions = debounce(async () => { - if (selectedField === undefined) return; - - setIsLoading(true); - setOptions([]); - - const esSearchRequest = { - index: dataView!.title, - body: { - ...(runtimeMappings !== undefined ? { runtime_mappings: runtimeMappings } : {}), - query: { - wildcard: { - [selectedField!]: { - value: `*${searchValue}*`, - }, + const { data, isError, isLoading } = useDataSearch( + { + index: dataView!.title, + body: { + ...(runtimeMappings !== undefined ? { runtime_mappings: runtimeMappings } : {}), + query: { + wildcard: { + [selectedField!]: { + value: `*${searchValue}*`, }, }, - aggs: { - field_values: { - terms: { - field: selectedField, - size: 10, - }, + }, + aggs: { + field_values: { + terms: { + field: selectedField, + size: 10, }, }, - size: 0, }, - }; - - const response = await dataSearch(esSearchRequest, abortController.signal); - - setIsLoading(false); - - if ( - !( - isEsSearchResponseWithAggregations(response) && - isMultiBucketAggregate( - response.aggregations.field_values - ) - ) - ) { - toastNotifications.addWarning( - i18n.translate('xpack.transform.agg.popoverForm.filerAgg.term.errorFetchSuggestions', { - defaultMessage: 'Unable to fetch suggestions', - }) - ); - return; - } + size: 0, + }, + }, + // Check whether fetching should be enabled + selectedField !== undefined + ); - setOptions( - ( - response.aggregations.field_values - .buckets as estypes.AggregationsSignificantLongTermsBucket[] - ).map((value) => ({ label: value.key + '' })) + useEffect(() => { + if (isError) { + toastNotifications.addWarning( + i18n.translate('xpack.transform.agg.popoverForm.filerAgg.term.errorFetchSuggestions', { + defaultMessage: 'Unable to fetch suggestions', + }) ); - }, 600); - - fetchOptions(); - - return () => { - // make sure the ongoing request is canceled - fetchOptions.cancel(); - abortController.abort(); - }; + } /* eslint-disable-next-line react-hooks/exhaustive-deps */ - }, [selectedField]); - - useEffect(() => { - // Simulate initial load. - onSearchChange(''); - }, []); + }, [isError]); + + const options: EuiComboBoxOptionOption[] = + isMultiBucketAggregate( + data?.aggregations?.field_values + ) + ? ( + data?.aggregations?.field_values + .buckets as estypes.AggregationsSignificantLongTermsBucket[] + ).map((value) => ({ label: value.key + '' })) + : []; useUpdateEffect(() => { // Reset value control on field change @@ -168,7 +146,7 @@ export const FilterTermForm: FilterAggConfigTerm['aggTypeConfig']['FilterAggForm onCreateOption={(value) => { updateConfig({ value }); }} - onSearchChange={onSearchChange} + onSearchChange={debouncedOnSearchChange} data-test-subj="transformFilterTermValueSelector" /> From c4b4d53cb0465bacef1fd74883fcdaf98eb00dfd Mon Sep 17 00:00:00 2001 From: Walter Rafelsberger Date: Tue, 22 Aug 2023 23:08:14 +0200 Subject: [PATCH 17/53] cleanup --- .../public/app/hooks/use_create_transform.tsx | 18 ++++++------------ .../public/app/hooks/use_delete_transform.tsx | 14 ++++++-------- .../app/hooks/use_reauthorize_transform.tsx | 12 +++++------- .../public/app/hooks/use_reset_transform.tsx | 12 +++++------- .../app/hooks/use_schedule_now_transform.tsx | 12 +++++------- .../public/app/hooks/use_start_transform.tsx | 12 +++++------- .../public/app/hooks/use_stop_transform.tsx | 12 +++++------- .../public/app/hooks/use_update_transform.ts | 7 +++---- .../transform_management_section.tsx | 2 +- 9 files changed, 41 insertions(+), 60 deletions(-) diff --git a/x-pack/plugins/transform/public/app/hooks/use_create_transform.tsx b/x-pack/plugins/transform/public/app/hooks/use_create_transform.tsx index d97508ed3a009..7f7d397d0baee 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_create_transform.tsx +++ b/x-pack/plugins/transform/public/app/hooks/use_create_transform.tsx @@ -45,18 +45,12 @@ export const useCreateTransform = ( } const mutation = useMutation({ - mutationFn: () => { - return http.put( - addInternalBasePath(`transforms/${transformId}`), - { - body: JSON.stringify(transformConfig), - version: '1', - } - ); - }, - onError: (error) => { - errorToast(error); - }, + mutationFn: () => + http.put(addInternalBasePath(`transforms/${transformId}`), { + body: JSON.stringify(transformConfig), + version: '1', + }), + onError: (error) => errorToast(error), onSuccess: (resp) => { if (resp.errors.length > 0) { errorToast(resp.errors.length === 1 ? resp.errors[0] : resp.errors); diff --git a/x-pack/plugins/transform/public/app/hooks/use_delete_transform.tsx b/x-pack/plugins/transform/public/app/hooks/use_delete_transform.tsx index 453a9bd912c07..99fb593b4d165 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_delete_transform.tsx +++ b/x-pack/plugins/transform/public/app/hooks/use_delete_transform.tsx @@ -127,13 +127,12 @@ export const useDeleteTransforms = () => { const toastNotifications = useToastNotifications(); const mutation = useMutation({ - mutationFn: (reqBody: DeleteTransformsRequestSchema) => { - return http.post(addInternalBasePath('delete_transforms'), { + mutationFn: (reqBody: DeleteTransformsRequestSchema) => + http.post(addInternalBasePath('delete_transforms'), { body: JSON.stringify(reqBody), version: '1', - }); - }, - onError: (error) => { + }), + onError: (error) => toastNotifications.addDanger({ title: i18n.translate('xpack.transform.transformList.deleteTransformGenericErrorMessage', { defaultMessage: 'An error occurred calling the API endpoint to delete transforms.', @@ -147,8 +146,7 @@ export const useDeleteTransforms = () => { />, { theme$: theme.theme$ } ), - }); - }, + }), onSuccess: (results) => { const isBulk = Object.keys(results).length > 1; const successCount: Record = { @@ -303,5 +301,5 @@ export const useDeleteTransforms = () => { }, }); - return (reqBody: DeleteTransformsRequestSchema) => mutation.mutate(reqBody); + return mutation; }; diff --git a/x-pack/plugins/transform/public/app/hooks/use_reauthorize_transform.tsx b/x-pack/plugins/transform/public/app/hooks/use_reauthorize_transform.tsx index 34a18acfaafe9..c226d82fc0410 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_reauthorize_transform.tsx +++ b/x-pack/plugins/transform/public/app/hooks/use_reauthorize_transform.tsx @@ -29,16 +29,15 @@ export const useReauthorizeTransforms = () => { const toastNotifications = useToastNotifications(); const mutation = useMutation({ - mutationFn: (reqBody: ReauthorizeTransformsRequestSchema) => { - return http.post( + mutationFn: (reqBody: ReauthorizeTransformsRequestSchema) => + http.post( addInternalBasePath('reauthorize_transforms'), { body: JSON.stringify(reqBody), version: '1', } - ); - }, - onError: (error) => { + ), + onError: (error) => toastNotifications.addDanger({ title: i18n.translate( 'xpack.transform.stepCreateForm.reauthorizeTransformResponseSchemaErrorMessage', @@ -50,8 +49,7 @@ export const useReauthorizeTransforms = () => { , { theme$: theme.theme$ } ), - }); - }, + }), onSuccess: (results) => { for (const transformId in results) { // hasOwnProperty check to ensure only properties on object itself, and not its prototypes diff --git a/x-pack/plugins/transform/public/app/hooks/use_reset_transform.tsx b/x-pack/plugins/transform/public/app/hooks/use_reset_transform.tsx index d91ddaf142306..e3147f0578ea5 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_reset_transform.tsx +++ b/x-pack/plugins/transform/public/app/hooks/use_reset_transform.tsx @@ -30,13 +30,12 @@ export const useResetTransforms = () => { const toastNotifications = useToastNotifications(); const mutation = useMutation({ - mutationFn: (reqBody: ResetTransformsRequestSchema) => { - return http.post(addInternalBasePath('reset_transforms'), { + mutationFn: (reqBody: ResetTransformsRequestSchema) => + http.post(addInternalBasePath('reset_transforms'), { body: JSON.stringify(reqBody), version: '1', - }); - }, - onError: (error) => { + }), + onError: (error) => toastNotifications.addDanger({ title: i18n.translate('xpack.transform.transformList.resetTransformGenericErrorMessage', { defaultMessage: 'An error occurred calling the API endpoint to reset transforms.', @@ -50,8 +49,7 @@ export const useResetTransforms = () => { />, { theme$: theme.theme$ } ), - }); - }, + }), onSuccess: (results) => { const isBulk = Object.keys(results).length > 1; const successCount: Record = { diff --git a/x-pack/plugins/transform/public/app/hooks/use_schedule_now_transform.tsx b/x-pack/plugins/transform/public/app/hooks/use_schedule_now_transform.tsx index 398bd42629167..ac37b25c9478b 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_schedule_now_transform.tsx +++ b/x-pack/plugins/transform/public/app/hooks/use_schedule_now_transform.tsx @@ -28,16 +28,15 @@ export const useScheduleNowTransforms = () => { const toastNotifications = useToastNotifications(); const mutation = useMutation({ - mutationFn: (reqBody: ScheduleNowTransformsRequestSchema) => { - return http.post( + mutationFn: (reqBody: ScheduleNowTransformsRequestSchema) => + http.post( addInternalBasePath('schedule_now_transforms'), { body: JSON.stringify(reqBody), version: '1', } - ); - }, - onError: (error) => { + ), + onError: (error) => toastNotifications.addDanger({ title: i18n.translate( 'xpack.transform.stepCreateForm.scheduleNowTransformResponseSchemaErrorMessage', @@ -50,8 +49,7 @@ export const useScheduleNowTransforms = () => { , { theme$: theme.theme$ } ), - }); - }, + }), onSuccess: (results) => { for (const transformId in results) { // hasOwnProperty check to ensure only properties on object itself, and not its prototypes diff --git a/x-pack/plugins/transform/public/app/hooks/use_start_transform.tsx b/x-pack/plugins/transform/public/app/hooks/use_start_transform.tsx index 65defb8a5dbee..ddb3b1a0e0ef3 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_start_transform.tsx +++ b/x-pack/plugins/transform/public/app/hooks/use_start_transform.tsx @@ -28,13 +28,12 @@ export const useStartTransforms = () => { const toastNotifications = useToastNotifications(); const mutation = useMutation({ - mutationFn: (reqBody: StartTransformsRequestSchema) => { - return http.post(addInternalBasePath('start_transforms'), { + mutationFn: (reqBody: StartTransformsRequestSchema) => + http.post(addInternalBasePath('start_transforms'), { body: JSON.stringify(reqBody), version: '1', - }); - }, - onError: (error) => { + }), + onError: (error) => toastNotifications.addDanger({ title: i18n.translate( 'xpack.transform.stepCreateForm.startTransformResponseSchemaErrorMessage', @@ -46,8 +45,7 @@ export const useStartTransforms = () => { , { theme$: theme.theme$ } ), - }); - }, + }), onSuccess: (results) => { for (const transformId in results) { // hasOwnProperty check to ensure only properties on object itself, and not its prototypes diff --git a/x-pack/plugins/transform/public/app/hooks/use_stop_transform.tsx b/x-pack/plugins/transform/public/app/hooks/use_stop_transform.tsx index 004ee40389200..35f58302a256d 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_stop_transform.tsx +++ b/x-pack/plugins/transform/public/app/hooks/use_stop_transform.tsx @@ -29,13 +29,12 @@ export const useStopTransforms = () => { const toastNotifications = useToastNotifications(); const mutation = useMutation({ - mutationFn: (reqBody: StopTransformsRequestSchema) => { - return http.post(addInternalBasePath('stop_transforms'), { + mutationFn: (reqBody: StopTransformsRequestSchema) => + http.post(addInternalBasePath('stop_transforms'), { body: JSON.stringify(reqBody), version: '1', - }); - }, - onError: (error) => { + }), + onError: (error) => toastNotifications.addDanger({ title: i18n.translate( 'xpack.transform.transformList.stopTransformResponseSchemaErrorMessage', @@ -47,8 +46,7 @@ export const useStopTransforms = () => { , { theme$: theme.theme$ } ), - }); - }, + }), onSuccess: (results) => { for (const transformId in results) { // hasOwnProperty check to ensure only properties on object itself, and not its prototypes diff --git a/x-pack/plugins/transform/public/app/hooks/use_update_transform.ts b/x-pack/plugins/transform/public/app/hooks/use_update_transform.ts index ec1c572a66b86..23c295d7c7be9 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_update_transform.ts +++ b/x-pack/plugins/transform/public/app/hooks/use_update_transform.ts @@ -28,15 +28,14 @@ export const useUpdateTransform = ( const toastNotifications = useToastNotifications(); const mutation = useMutation({ - mutationFn: () => { - return http.post( + mutationFn: () => + http.post( addInternalBasePath(`transforms/${transformId}/_update`), { body: JSON.stringify(transformConfig), version: '1', } - ); - }, + ), onSuccess: () => { toastNotifications.addSuccess( i18n.translate('xpack.transform.transformList.editTransformSuccessMessage', { diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/transform_management_section.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/transform_management_section.tsx index 1a8db994e0fec..12e85a9232b84 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/transform_management_section.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/transform_management_section.tsx @@ -44,7 +44,7 @@ import { export const TransformManagement: FC = () => { const { esTransform } = useDocumentationLinks(); - const deleteTransforms = useDeleteTransforms(); + const { mutate: deleteTransforms } = useDeleteTransforms(); const { isInitialLoading, From be3e0fcda240f583e0e80a6c279084e19e29520d Mon Sep 17 00:00:00 2001 From: Walter Rafelsberger Date: Tue, 22 Aug 2023 23:18:24 +0200 Subject: [PATCH 18/53] cleanup --- .../transform/public/app/hooks/use_create_transform.tsx | 2 +- .../app/sections/clone_transform/clone_transform_section.tsx | 4 ++-- .../components/step_details/step_details_form.tsx | 3 +-- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/x-pack/plugins/transform/public/app/hooks/use_create_transform.tsx b/x-pack/plugins/transform/public/app/hooks/use_create_transform.tsx index 7f7d397d0baee..7d404ef2c66bb 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_create_transform.tsx +++ b/x-pack/plugins/transform/public/app/hooks/use_create_transform.tsx @@ -50,7 +50,7 @@ export const useCreateTransform = ( body: JSON.stringify(transformConfig), version: '1', }), - onError: (error) => errorToast(error), + onError: errorToast, onSuccess: (resp) => { if (resp.errors.length > 0) { errorToast(resp.errors.length === 1 ? resp.errors[0] : resp.errors); diff --git a/x-pack/plugins/transform/public/app/sections/clone_transform/clone_transform_section.tsx b/x-pack/plugins/transform/public/app/sections/clone_transform/clone_transform_section.tsx index 04e04f4e47b81..269adfd3eb266 100644 --- a/x-pack/plugins/transform/public/app/sections/clone_transform/clone_transform_section.tsx +++ b/x-pack/plugins/transform/public/app/sections/clone_transform/clone_transform_section.tsx @@ -19,7 +19,7 @@ import { EuiPageHeader, EuiSpacer, } from '@elastic/eui'; -import { isHttpFetchError } from '@kbn/core-http-browser'; + import { APP_CREATE_TRANSFORM_CLUSTER_PRIVILEGES } from '../../../../common/constants'; import { TransformConfigUnion } from '../../../../common/types/transform'; @@ -80,7 +80,7 @@ export const CloneTransformSection: FC = ({ match, location }) => { ); useEffect(() => { - if (isHttpFetchError(error) && error.message !== errorMessage) { + if (error !== null && error.message !== errorMessage) { setTransformConfig(undefined); setErrorMessage(error.message); setIsInitialized(true); diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_details/step_details_form.tsx b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_details/step_details_form.tsx index a234795ebe788..9fda641d16f65 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_details/step_details_form.tsx +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_details/step_details_form.tsx @@ -27,7 +27,6 @@ import { import { KBN_FIELD_TYPES } from '@kbn/field-types'; import { toMountPoint } from '@kbn/kibana-react-plugin/public'; -import { isHttpFetchError } from '@kbn/core-http-browser'; import { retentionPolicyMaxAgeInvalidErrorMessage } from '../../../../common/constants/validation_messages'; import { DEFAULT_TRANSFORM_FREQUENCY } from '../../../../../../common/constants'; import { TransformId } from '../../../../../../common/types/transform'; @@ -128,7 +127,7 @@ export const StepDetailsForm: FC = React.memo( const transformIds = transforms?.tableRows.map((d) => d.id) ?? []; useEffect(() => { - if (isHttpFetchError(transformsError)) { + if (transformsError !== null) { toastNotifications.addDanger({ title: i18n.translate('xpack.transform.stepDetailsForm.errorGettingTransformList', { defaultMessage: 'An error occurred getting the existing transform IDs:', From 30801503d07cf35e44c823c2a850d7d6683249ff Mon Sep 17 00:00:00 2001 From: Walter Rafelsberger Date: Wed, 23 Aug 2023 00:40:17 +0200 Subject: [PATCH 19/53] refactor IndexService into custom hooks using react-query --- x-pack/plugins/transform/common/constants.ts | 2 + .../public/app/hooks/use_can_delete_index.ts | 33 ++++++ .../public/app/hooks/use_data_view_exists.ts | 32 ++++++ .../public/app/hooks/use_delete_transform.tsx | 108 ++++++++---------- .../action_delete/use_delete_action.tsx | 2 +- .../public/app/services/es_index_service.ts | 29 ----- 6 files changed, 117 insertions(+), 89 deletions(-) create mode 100644 x-pack/plugins/transform/public/app/hooks/use_can_delete_index.ts create mode 100644 x-pack/plugins/transform/public/app/hooks/use_data_view_exists.ts delete mode 100644 x-pack/plugins/transform/public/app/services/es_index_service.ts diff --git a/x-pack/plugins/transform/common/constants.ts b/x-pack/plugins/transform/common/constants.ts index 1584811c0df6b..1bf6a81167124 100644 --- a/x-pack/plugins/transform/common/constants.ts +++ b/x-pack/plugins/transform/common/constants.ts @@ -33,7 +33,9 @@ export const addInternalBasePath = (uri: string): string => `${INTERNAL_API_BASE export const addExternalBasePath = (uri: string): string => `${EXTERNAL_API_BASE_PATH}${uri}`; export const TRANSFORM_REACT_QUERY_KEYS = { + CAN_DELETE_INDEX: 'transform.can_delete_index', DATA_SEARCH: 'transform.data_search', + DATA_VIEW_EXISTS: 'transform.data_view_exists', GET_DATA_VIEW_TITLES: 'transform.get_data_view_titles', GET_ES_INDICES: 'transform.get_es_indices', GET_ES_INGEST_PIPELINES: 'transform.get_es_ingest_pipelines', diff --git a/x-pack/plugins/transform/public/app/hooks/use_can_delete_index.ts b/x-pack/plugins/transform/public/app/hooks/use_can_delete_index.ts new file mode 100644 index 0000000000000..d198daa9ab26f --- /dev/null +++ b/x-pack/plugins/transform/public/app/hooks/use_can_delete_index.ts @@ -0,0 +1,33 @@ +/* + * 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 { useQuery } from '@tanstack/react-query'; + +import type { IHttpFetchError } from '@kbn/core-http-browser'; + +import type { PrivilegesAndCapabilities } from '../../../common/privilege/has_privilege_factory'; +import { addInternalBasePath, TRANSFORM_REACT_QUERY_KEYS } from '../../../common/constants'; + +import { useAppDependencies } from '../app_dependencies'; + +export const useCanDeleteIndex = () => { + const { http } = useAppDependencies(); + + return useQuery( + [TRANSFORM_REACT_QUERY_KEYS.CAN_DELETE_INDEX], + async ({ signal }) => { + const resp = await http.get(addInternalBasePath('privileges'), { + version: '1', + signal, + }); + if (!resp) { + return false; + } + return resp.privileges.hasAllPrivileges; + } + ); +}; diff --git a/x-pack/plugins/transform/public/app/hooks/use_data_view_exists.ts b/x-pack/plugins/transform/public/app/hooks/use_data_view_exists.ts new file mode 100644 index 0000000000000..7f2a2b48af1c1 --- /dev/null +++ b/x-pack/plugins/transform/public/app/hooks/use_data_view_exists.ts @@ -0,0 +1,32 @@ +/* + * 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 { useQuery } from '@tanstack/react-query'; + +import type { ErrorType } from '@kbn/ml-error-utils'; + +import { TRANSFORM_REACT_QUERY_KEYS } from '../../../common/constants'; + +import { useAppDependencies } from '../app_dependencies'; + +export const useDataViewExists = (indexName?: string, enabled?: boolean, initialData?: boolean) => { + const { + data: { dataViews: dataViewsContract }, + } = useAppDependencies(); + + return useQuery( + [TRANSFORM_REACT_QUERY_KEYS.DATA_VIEW_EXISTS, indexName], + async () => { + if (indexName === undefined) { + return false; + } + + return (await dataViewsContract.find(indexName)).some(({ title }) => title === indexName); + }, + { enabled, initialData } + ); +}; diff --git a/x-pack/plugins/transform/public/app/hooks/use_delete_transform.tsx b/x-pack/plugins/transform/public/app/hooks/use_delete_transform.tsx index 99fb593b4d165..58e3db4e7cd22 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_delete_transform.tsx +++ b/x-pack/plugins/transform/public/app/hooks/use_delete_transform.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { useCallback, useEffect, useState } from 'react'; +import React, { useCallback, useEffect, useMemo, useState } from 'react'; import { useMutation } from '@tanstack/react-query'; import { i18n } from '@kbn/i18n'; @@ -19,24 +19,42 @@ import type { DeleteTransformsResponseSchema, } from '../../../common/api_schemas/delete_transforms'; import { getErrorMessage } from '../../../common/utils/errors'; + import { useAppDependencies, useToastNotifications } from '../app_dependencies'; +import { useCanDeleteIndex } from './use_can_delete_index'; +import { useDataViewExists } from './use_data_view_exists'; import { useRefreshTransformList, type TransformListRow } from '../common'; import { ToastNotificationText } from '../components'; -import { indexService } from '../services/es_index_service'; export const useDeleteIndexAndTargetIndex = (items: TransformListRow[]) => { const { - http, - data: { dataViews: dataViewsContract }, application: { capabilities }, } = useAppDependencies(); const toastNotifications = useToastNotifications(); + const userCanDeleteDataView = + capabilities.savedObjectsManagement.delete === true || capabilities.indexPatterns.save === true; + const [deleteDestIndex, setDeleteDestIndex] = useState(true); - const [deleteDataView, setDeleteDataView] = useState(true); - const [userCanDeleteIndex, setUserCanDeleteIndex] = useState(false); - const [dataViewExists, setDataViewExists] = useState(false); - const [userCanDeleteDataView, setUserCanDeleteDataView] = useState(false); + const [deleteDataView, setDeleteDataView] = useState(userCanDeleteDataView); + + const { error: canDeleteIndexError, data: canDeleteIndex } = useCanDeleteIndex(); + const userCanDeleteIndex = canDeleteIndex === true; + + useEffect(() => { + if (canDeleteIndexError !== null) { + toastNotifications.addDanger( + i18n.translate( + 'xpack.transform.transformList.errorWithCheckingIfUserCanDeleteIndexNotificationErrorMessage', + { + defaultMessage: 'An error occurred checking if user can delete destination index', + } + ) + ); + } + // custom comparison + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [canDeleteIndexError]); const toggleDeleteIndex = useCallback( () => setDeleteDestIndex(!deleteDestIndex), @@ -46,67 +64,39 @@ export const useDeleteIndexAndTargetIndex = (items: TransformListRow[]) => { () => setDeleteDataView(!deleteDataView), [deleteDataView] ); - const checkDataViewExists = useCallback( - async (indexName: string) => { - try { - const dvExists = await indexService.dataViewExists(dataViewsContract, indexName); - setDataViewExists(dvExists); - } catch (e) { - const error = extractErrorMessage(e); - toastNotifications.addDanger( - i18n.translate( - 'xpack.transform.deleteTransform.errorWithCheckingIfDataViewExistsNotificationErrorMessage', - { - defaultMessage: 'An error occurred checking if data view {dataView} exists: {error}', - values: { dataView: indexName, error }, - } - ) - ); - } - }, - [dataViewsContract, toastNotifications] + const indexName = useMemo(() => { + // if user only deleting one transform + if (items.length === 1) { + const config = items[0].config; + return Array.isArray(config.dest.index) ? config.dest.index[0] : config.dest.index; + } + }, [items]); + + const { error: dataViewExistsError, data: dataViewExists } = useDataViewExists( + indexName, + items.length === 1, + items.length !== 1 ); - const checkUserIndexPermission = useCallback(async () => { - try { - const userCanDelete = await indexService.canDeleteIndex(http); - if (userCanDelete) { - setUserCanDeleteIndex(true); - } - const canDeleteDataView = - capabilities.savedObjectsManagement.delete === true || - capabilities.indexPatterns.save === true; - setUserCanDeleteDataView(canDeleteDataView); - if (canDeleteDataView === false) { - setDeleteDataView(false); - } - } catch (e) { + useEffect(() => { + if (dataViewExistsError !== null) { toastNotifications.addDanger( i18n.translate( - 'xpack.transform.transformList.errorWithCheckingIfUserCanDeleteIndexNotificationErrorMessage', + 'xpack.transform.deleteTransform.errorWithCheckingIfDataViewExistsNotificationErrorMessage', { - defaultMessage: 'An error occurred checking if user can delete destination index', + defaultMessage: 'An error occurred checking if data view {dataView} exists: {error}', + values: { + dataView: indexName, + error: extractErrorMessage(dataViewExistsError), + }, } ) ); } - }, [http, toastNotifications, capabilities]); - - useEffect(() => { - checkUserIndexPermission(); - - // if user only deleting one transform - if (items.length === 1) { - const config = items[0].config; - const destinationIndex = Array.isArray(config.dest.index) - ? config.dest.index[0] - : config.dest.index; - checkDataViewExists(destinationIndex); - } else { - setDataViewExists(true); - } - }, [checkDataViewExists, checkUserIndexPermission, items]); + // custom comparison + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [dataViewExistsError]); return { userCanDeleteIndex, diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_delete/use_delete_action.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_delete/use_delete_action.tsx index 357809b54746b..e81612fe77bac 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_delete/use_delete_action.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_delete/use_delete_action.tsx @@ -23,7 +23,7 @@ export type DeleteAction = ReturnType; export const useDeleteAction = (forceDisable: boolean) => { const { canDeleteTransform } = useContext(AuthorizationContext).capabilities; - const deleteTransforms = useDeleteTransforms(); + const { mutate: deleteTransforms } = useDeleteTransforms(); const [isModalVisible, setModalVisible] = useState(false); const [items, setItems] = useState([]); diff --git a/x-pack/plugins/transform/public/app/services/es_index_service.ts b/x-pack/plugins/transform/public/app/services/es_index_service.ts deleted file mode 100644 index d8d058b731a74..0000000000000 --- a/x-pack/plugins/transform/public/app/services/es_index_service.ts +++ /dev/null @@ -1,29 +0,0 @@ -/* - * 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 type { HttpSetup } from '@kbn/core/public'; -import type { DataViewsContract } from '@kbn/data-views-plugin/public'; -import { addInternalBasePath } from '../../../common/constants'; - -export class IndexService { - async canDeleteIndex(http: HttpSetup) { - const privilege = await http.get<{ hasAllPrivileges: boolean }>( - addInternalBasePath(`privileges`), - { version: '1' } - ); - if (!privilege) { - return false; - } - return privilege.hasAllPrivileges; - } - - async dataViewExists(dataViewsContract: DataViewsContract, indexName: string) { - return (await dataViewsContract.find(indexName)).some(({ title }) => title === indexName); - } -} - -export const indexService = new IndexService(); From d302856712c4a7742fb08381837b0832fb166b95 Mon Sep 17 00:00:00 2001 From: Walter Rafelsberger Date: Wed, 23 Aug 2023 08:39:51 +0200 Subject: [PATCH 20/53] fix tests --- .../transform/public/app/hooks/use_delete_transform.tsx | 3 ++- .../api_integration/apis/transform/stop_transforms.ts | 8 -------- x-pack/test/api_integration/apis/transform/transforms.ts | 5 ----- .../api_integration/apis/transform/transforms_nodes.ts | 3 --- .../api_integration/apis/transform/transforms_stats.ts | 2 -- 5 files changed, 2 insertions(+), 19 deletions(-) diff --git a/x-pack/plugins/transform/public/app/hooks/use_delete_transform.tsx b/x-pack/plugins/transform/public/app/hooks/use_delete_transform.tsx index 58e3db4e7cd22..55925a86cee85 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_delete_transform.tsx +++ b/x-pack/plugins/transform/public/app/hooks/use_delete_transform.tsx @@ -33,7 +33,8 @@ export const useDeleteIndexAndTargetIndex = (items: TransformListRow[]) => { const toastNotifications = useToastNotifications(); const userCanDeleteDataView = - capabilities.savedObjectsManagement.delete === true || capabilities.indexPatterns.save === true; + (capabilities.savedObjectsManagement && capabilities.savedObjectsManagement.delete === true) || + (capabilities.indexPatterns && capabilities.indexPatterns.save === true); const [deleteDestIndex, setDeleteDestIndex] = useState(true); const [deleteDataView, setDeleteDataView] = useState(userCanDeleteDataView); diff --git a/x-pack/test/api_integration/apis/transform/stop_transforms.ts b/x-pack/test/api_integration/apis/transform/stop_transforms.ts index 7811432e7417a..c982c6b45f1c9 100644 --- a/x-pack/test/api_integration/apis/transform/stop_transforms.ts +++ b/x-pack/test/api_integration/apis/transform/stop_transforms.ts @@ -9,7 +9,6 @@ import expect from '@kbn/expect'; import type { PutTransformsRequestSchema } from '@kbn/transform-plugin/common/api_schemas/transforms'; import type { StopTransformsRequestSchema } from '@kbn/transform-plugin/common/api_schemas/stop_transforms'; -import { isStopTransformsResponseSchema } from '@kbn/transform-plugin/common/api_schemas/type_guards'; import { TRANSFORM_STATE } from '@kbn/transform-plugin/common/constants'; @@ -76,7 +75,6 @@ export default ({ getService }: FtrProviderContext) => { .send(reqBody); transform.api.assertResponseStatusCode(200, status, body); - expect(isStopTransformsResponseSchema(body)).to.eql(true); expect(body[transformId].success).to.eql(true); expect(typeof body[transformId].error).to.eql('undefined'); await transform.api.waitForTransformState(transformId, TRANSFORM_STATE.STOPPED); @@ -97,7 +95,6 @@ export default ({ getService }: FtrProviderContext) => { .send(reqBody); transform.api.assertResponseStatusCode(200, status, body); - expect(isStopTransformsResponseSchema(body)).to.eql(true); expect(body[transformId].success).to.eql(false); expect(typeof body[transformId].error).to.eql('object'); @@ -121,7 +118,6 @@ export default ({ getService }: FtrProviderContext) => { .send(reqBody); transform.api.assertResponseStatusCode(200, status, body); - expect(isStopTransformsResponseSchema(body)).to.eql(true); expect(body.invalid_transform_id.success).to.eql(false); expect(body.invalid_transform_id).to.have.property('error'); }); @@ -158,8 +154,6 @@ export default ({ getService }: FtrProviderContext) => { .send(reqBody); transform.api.assertResponseStatusCode(200, status, body); - expect(isStopTransformsResponseSchema(body)).to.eql(true); - await asyncForEach(reqBody, async ({ id: transformId }: { id: string }, idx: number) => { expect(body[transformId].success).to.eql(true); await transform.api.waitForTransformState(transformId, TRANSFORM_STATE.STOPPED); @@ -183,8 +177,6 @@ export default ({ getService }: FtrProviderContext) => { ]); transform.api.assertResponseStatusCode(200, status, body); - expect(isStopTransformsResponseSchema(body)).to.eql(true); - await asyncForEach(reqBody, async ({ id: transformId }: { id: string }, idx: number) => { expect(body[transformId].success).to.eql(true); await transform.api.waitForTransformState(transformId, TRANSFORM_STATE.STOPPED); diff --git a/x-pack/test/api_integration/apis/transform/transforms.ts b/x-pack/test/api_integration/apis/transform/transforms.ts index 4c3d1641d6d5f..2016876ba93a6 100644 --- a/x-pack/test/api_integration/apis/transform/transforms.ts +++ b/x-pack/test/api_integration/apis/transform/transforms.ts @@ -8,7 +8,6 @@ import expect from '@kbn/expect'; import type { GetTransformsResponseSchema } from '@kbn/transform-plugin/common/api_schemas/transforms'; -import { isGetTransformsResponseSchema } from '@kbn/transform-plugin/common/api_schemas/type_guards'; import { getCommonRequestHeader } from '../../../functional/services/ml/common_api'; import { USER } from '../../../functional/services/transform/security_common'; @@ -43,8 +42,6 @@ export default ({ getService }: FtrProviderContext) => { } function assertTransformsResponseBody(body: GetTransformsResponseSchema) { - expect(isGetTransformsResponseSchema(body)).to.eql(true); - expect(body.count).to.eql(expected.apiTransformTransforms.count); expect(body.transforms).to.have.length(expected.apiTransformTransforms.count); @@ -62,8 +59,6 @@ export default ({ getService }: FtrProviderContext) => { } function assertSingleTransformResponseBody(body: GetTransformsResponseSchema) { - expect(isGetTransformsResponseSchema(body)).to.eql(true); - expect(body.count).to.eql(expected.apiTransformTransformsTransformId.count); expect(body.transforms).to.have.length(expected.apiTransformTransformsTransformId.count); diff --git a/x-pack/test/api_integration/apis/transform/transforms_nodes.ts b/x-pack/test/api_integration/apis/transform/transforms_nodes.ts index bf3e91df69684..10f4413a8f85f 100644 --- a/x-pack/test/api_integration/apis/transform/transforms_nodes.ts +++ b/x-pack/test/api_integration/apis/transform/transforms_nodes.ts @@ -8,7 +8,6 @@ import expect from '@kbn/expect'; import type { GetTransformNodesResponseSchema } from '@kbn/transform-plugin/common/api_schemas/transforms'; -import { isGetTransformNodesResponseSchema } from '@kbn/transform-plugin/common/api_schemas/type_guards'; import { getCommonRequestHeader } from '../../../functional/services/ml/common_api'; import { USER } from '../../../functional/services/transform/security_common'; @@ -25,8 +24,6 @@ export default ({ getService }: FtrProviderContext) => { }; function assertTransformsNodesResponseBody(body: GetTransformNodesResponseSchema) { - expect(isGetTransformNodesResponseSchema(body)).to.eql(true); - expect(body.count).to.not.be.lessThan(expected.apiTransformTransformsNodes.minCount); } diff --git a/x-pack/test/api_integration/apis/transform/transforms_stats.ts b/x-pack/test/api_integration/apis/transform/transforms_stats.ts index 41cdafd0c058f..aea5c049343e9 100644 --- a/x-pack/test/api_integration/apis/transform/transforms_stats.ts +++ b/x-pack/test/api_integration/apis/transform/transforms_stats.ts @@ -8,7 +8,6 @@ import expect from '@kbn/expect'; import type { GetTransformsStatsResponseSchema } from '@kbn/transform-plugin/common/api_schemas/transforms_stats'; -import { isGetTransformsStatsResponseSchema } from '@kbn/transform-plugin/common/api_schemas/type_guards'; import { TRANSFORM_STATE } from '@kbn/transform-plugin/common/constants'; import { getCommonRequestHeader } from '../../../functional/services/ml/common_api'; @@ -39,7 +38,6 @@ export default ({ getService }: FtrProviderContext) => { } function assertTransformsStatsResponseBody(body: GetTransformsStatsResponseSchema) { - expect(isGetTransformsStatsResponseSchema(body)).to.eql(true); expect(body.count).to.eql(expected.apiTransformTransforms.count); expect(body.transforms).to.have.length(expected.apiTransformTransforms.count); From 5fbaec275dd7ab35a2f3582b345353c97f081a16 Mon Sep 17 00:00:00 2001 From: Walter Rafelsberger Date: Wed, 23 Aug 2023 14:07:33 +0200 Subject: [PATCH 21/53] remove success toasts --- .../public/app/hooks/use_create_transform.tsx | 7 -- .../public/app/hooks/use_delete_transform.tsx | 81 ------------------- .../app/hooks/use_reauthorize_transform.tsx | 9 +-- .../public/app/hooks/use_reset_transform.tsx | 37 --------- .../app/hooks/use_schedule_now_transform.tsx | 10 +-- .../public/app/hooks/use_start_transform.tsx | 9 +-- .../public/app/hooks/use_stop_transform.tsx | 9 +-- .../public/app/hooks/use_update_transform.ts | 15 +--- .../step_create/step_create_form.tsx | 7 -- .../edit_transform_update_button.tsx | 8 +- 10 files changed, 8 insertions(+), 184 deletions(-) diff --git a/x-pack/plugins/transform/public/app/hooks/use_create_transform.tsx b/x-pack/plugins/transform/public/app/hooks/use_create_transform.tsx index 7d404ef2c66bb..0b01bc95c8fe8 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_create_transform.tsx +++ b/x-pack/plugins/transform/public/app/hooks/use_create_transform.tsx @@ -54,13 +54,6 @@ export const useCreateTransform = ( onSuccess: (resp) => { if (resp.errors.length > 0) { errorToast(resp.errors.length === 1 ? resp.errors[0] : resp.errors); - } else { - toastNotifications.addSuccess( - i18n.translate('xpack.transform.stepCreateForm.createTransformSuccessMessage', { - defaultMessage: 'Request to create transform {transformId} acknowledged.', - values: { transformId }, - }) - ); } refreshTransformList(); diff --git a/x-pack/plugins/transform/public/app/hooks/use_delete_transform.tsx b/x-pack/plugins/transform/public/app/hooks/use_delete_transform.tsx index 55925a86cee85..2d057c11c4a16 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_delete_transform.tsx +++ b/x-pack/plugins/transform/public/app/hooks/use_delete_transform.tsx @@ -14,7 +14,6 @@ import { extractErrorMessage } from '@kbn/ml-error-utils'; import { addInternalBasePath } from '../../../common/constants'; import type { - DeleteTransformStatus, DeleteTransformsRequestSchema, DeleteTransformsResponseSchema, } from '../../../common/api_schemas/delete_transforms'; @@ -110,8 +109,6 @@ export const useDeleteIndexAndTargetIndex = (items: TransformListRow[]) => { }; }; -type SuccessCountField = keyof Omit; - export const useDeleteTransforms = () => { const { http, overlays, theme } = useAppDependencies(); const refreshTransformList = useRefreshTransformList(); @@ -139,58 +136,12 @@ export const useDeleteTransforms = () => { ), }), onSuccess: (results) => { - const isBulk = Object.keys(results).length > 1; - const successCount: Record = { - transformDeleted: 0, - destIndexDeleted: 0, - destDataViewDeleted: 0, - }; for (const transformId in results) { // hasOwnProperty check to ensure only properties on object itself, and not its prototypes if (results.hasOwnProperty(transformId)) { const status = results[transformId]; const destinationIndex = status.destinationIndex; - // if we are only deleting one transform, show the success toast messages - if (!isBulk && status.transformDeleted) { - if (status.transformDeleted?.success) { - toastNotifications.addSuccess( - i18n.translate('xpack.transform.transformList.deleteTransformSuccessMessage', { - defaultMessage: 'Request to delete transform {transformId} acknowledged.', - values: { transformId }, - }) - ); - } - if (status.destIndexDeleted?.success) { - toastNotifications.addSuccess( - i18n.translate( - 'xpack.transform.deleteTransform.deleteAnalyticsWithIndexSuccessMessage', - { - defaultMessage: - 'Request to delete destination index {destinationIndex} acknowledged.', - values: { destinationIndex }, - } - ) - ); - } - if (status.destDataViewDeleted?.success) { - toastNotifications.addSuccess( - i18n.translate( - 'xpack.transform.deleteTransform.deleteAnalyticsWithDataViewSuccessMessage', - { - defaultMessage: 'Request to delete data view {destinationIndex} acknowledged.', - values: { destinationIndex }, - } - ) - ); - } - } else { - (Object.keys(successCount) as SuccessCountField[]).forEach((key) => { - if (status[key]?.success) { - successCount[key] = successCount[key] + 1; - } - }); - } if (status.transformDeleted?.error) { const error = status.transformDeleted.error.reason; toastNotifications.addDanger({ @@ -256,38 +207,6 @@ export const useDeleteTransforms = () => { } } - // if we are deleting multiple transforms, combine the success messages - if (isBulk) { - if (successCount.transformDeleted > 0) { - toastNotifications.addSuccess( - i18n.translate('xpack.transform.transformList.bulkDeleteTransformSuccessMessage', { - defaultMessage: - 'Successfully deleted {count} {count, plural, one {transform} other {transforms}}.', - values: { count: successCount.transformDeleted }, - }) - ); - } - - if (successCount.destIndexDeleted > 0) { - toastNotifications.addSuccess( - i18n.translate('xpack.transform.transformList.bulkDeleteDestIndexSuccessMessage', { - defaultMessage: - 'Successfully deleted {count} destination {count, plural, one {index} other {indices}}.', - values: { count: successCount.destIndexDeleted }, - }) - ); - } - if (successCount.destDataViewDeleted > 0) { - toastNotifications.addSuccess( - i18n.translate('xpack.transform.transformList.bulkDeleteDestDataViewSuccessMessage', { - defaultMessage: - 'Successfully deleted {count} destination data {count, plural, one {view} other {views}}.', - values: { count: successCount.destDataViewDeleted }, - }) - ); - } - } - refreshTransformList(); }, }); diff --git a/x-pack/plugins/transform/public/app/hooks/use_reauthorize_transform.tsx b/x-pack/plugins/transform/public/app/hooks/use_reauthorize_transform.tsx index c226d82fc0410..7eae534d6f0eb 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_reauthorize_transform.tsx +++ b/x-pack/plugins/transform/public/app/hooks/use_reauthorize_transform.tsx @@ -55,14 +55,7 @@ export const useReauthorizeTransforms = () => { // hasOwnProperty check to ensure only properties on object itself, and not its prototypes if (results.hasOwnProperty(transformId)) { const result = results[transformId]; - if (result.success === true) { - toastNotifications.addSuccess( - i18n.translate('xpack.transform.transformList.reauthorizeTransformSuccessMessage', { - defaultMessage: 'Request to reauthorize transform {transformId} acknowledged.', - values: { transformId }, - }) - ); - } else { + if (!result.success) { toastNotifications.addError( new Error(JSON.stringify(result.error!.caused_by, null, 2)), { diff --git a/x-pack/plugins/transform/public/app/hooks/use_reset_transform.tsx b/x-pack/plugins/transform/public/app/hooks/use_reset_transform.tsx index e3147f0578ea5..f470a2e0f3698 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_reset_transform.tsx +++ b/x-pack/plugins/transform/public/app/hooks/use_reset_transform.tsx @@ -12,7 +12,6 @@ import { i18n } from '@kbn/i18n'; import { toMountPoint } from '@kbn/kibana-react-plugin/public'; import type { - ResetTransformStatus, ResetTransformsRequestSchema, ResetTransformsResponseSchema, } from '../../../common/api_schemas/reset_transforms'; @@ -22,8 +21,6 @@ import { useAppDependencies, useToastNotifications } from '../app_dependencies'; import { useRefreshTransformList } from '../common'; import { ToastNotificationText } from '../components'; -type SuccessCountField = keyof Omit; - export const useResetTransforms = () => { const { http, overlays, theme } = useAppDependencies(); const refreshTransformList = useRefreshTransformList(); @@ -51,32 +48,11 @@ export const useResetTransforms = () => { ), }), onSuccess: (results) => { - const isBulk = Object.keys(results).length > 1; - const successCount: Record = { - transformReset: 0, - }; for (const transformId in results) { // hasOwnProperty check to ensure only properties on object itself, and not its prototypes if (results.hasOwnProperty(transformId)) { const status = results[transformId]; - // if we are only resetting one transform, show the success toast messages - if (!isBulk && status.transformReset) { - if (status.transformReset?.success) { - toastNotifications.addSuccess( - i18n.translate('xpack.transform.transformList.resetTransformSuccessMessage', { - defaultMessage: 'Request to reset transform {transformId} acknowledged.', - values: { transformId }, - }) - ); - } - } else { - (Object.keys(successCount) as SuccessCountField[]).forEach((key) => { - if (status[key]?.success) { - successCount[key] = successCount[key] + 1; - } - }); - } if (status.transformReset?.error) { const error = status.transformReset.error.reason; toastNotifications.addDanger({ @@ -98,19 +74,6 @@ export const useResetTransforms = () => { } } - // if we are deleting multiple transforms, combine the success messages - if (isBulk) { - if (successCount.transformReset > 0) { - toastNotifications.addSuccess( - i18n.translate('xpack.transform.transformList.bulkResetTransformSuccessMessage', { - defaultMessage: - 'Successfully reset {count} {count, plural, one {transform} other {transforms}}.', - values: { count: successCount.transformReset }, - }) - ); - } - } - refreshTransformList(); }, }); diff --git a/x-pack/plugins/transform/public/app/hooks/use_schedule_now_transform.tsx b/x-pack/plugins/transform/public/app/hooks/use_schedule_now_transform.tsx index ac37b25c9478b..6ffc2bf6308d3 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_schedule_now_transform.tsx +++ b/x-pack/plugins/transform/public/app/hooks/use_schedule_now_transform.tsx @@ -55,15 +55,7 @@ export const useScheduleNowTransforms = () => { // hasOwnProperty check to ensure only properties on object itself, and not its prototypes if (results.hasOwnProperty(transformId)) { const result = results[transformId]; - if (result.success === true) { - toastNotifications.addSuccess( - i18n.translate('xpack.transform.transformList.scheduleNowTransformSuccessMessage', { - defaultMessage: - 'Request to schedule transform {transformId} to process data instantly acknowledged.', - values: { transformId }, - }) - ); - } else { + if (!result.success) { toastNotifications.addError( new Error(JSON.stringify(result.error!.caused_by, null, 2)), { diff --git a/x-pack/plugins/transform/public/app/hooks/use_start_transform.tsx b/x-pack/plugins/transform/public/app/hooks/use_start_transform.tsx index ddb3b1a0e0ef3..63e62276e0d76 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_start_transform.tsx +++ b/x-pack/plugins/transform/public/app/hooks/use_start_transform.tsx @@ -51,14 +51,7 @@ export const useStartTransforms = () => { // hasOwnProperty check to ensure only properties on object itself, and not its prototypes if (results.hasOwnProperty(transformId)) { const result = results[transformId]; - if (result.success === true) { - toastNotifications.addSuccess( - i18n.translate('xpack.transform.transformList.startTransformSuccessMessage', { - defaultMessage: 'Request to start transform {transformId} acknowledged.', - values: { transformId }, - }) - ); - } else { + if (!result.success) { toastNotifications.addError( new Error(JSON.stringify(result.error!.caused_by, null, 2)), { diff --git a/x-pack/plugins/transform/public/app/hooks/use_stop_transform.tsx b/x-pack/plugins/transform/public/app/hooks/use_stop_transform.tsx index 35f58302a256d..506f8c04bf8a4 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_stop_transform.tsx +++ b/x-pack/plugins/transform/public/app/hooks/use_stop_transform.tsx @@ -51,14 +51,7 @@ export const useStopTransforms = () => { for (const transformId in results) { // hasOwnProperty check to ensure only properties on object itself, and not its prototypes if (results.hasOwnProperty(transformId)) { - if (results[transformId].success === true) { - toastNotifications.addSuccess( - i18n.translate('xpack.transform.transformList.stopTransformSuccessMessage', { - defaultMessage: 'Request to stop data frame transform {transformId} acknowledged.', - values: { transformId }, - }) - ); - } else { + if (!results[transformId].success) { toastNotifications.addDanger( i18n.translate('xpack.transform.transformList.stopTransformErrorMessage', { defaultMessage: 'An error occurred stopping the data frame transform {transformId}', diff --git a/x-pack/plugins/transform/public/app/hooks/use_update_transform.ts b/x-pack/plugins/transform/public/app/hooks/use_update_transform.ts index 23c295d7c7be9..1c1469ab1a5ba 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_update_transform.ts +++ b/x-pack/plugins/transform/public/app/hooks/use_update_transform.ts @@ -7,8 +7,6 @@ import { useMutation } from '@tanstack/react-query'; -import { i18n } from '@kbn/i18n'; - import type { PostTransformsUpdateRequestSchema, PostTransformsUpdateResponseSchema, @@ -16,7 +14,7 @@ import type { import { addInternalBasePath } from '../../../common/constants'; import type { TransformId } from '../../../common/types/transform'; -import { useAppDependencies, useToastNotifications } from '../app_dependencies'; +import { useAppDependencies } from '../app_dependencies'; import { useRefreshTransformList } from '../common'; export const useUpdateTransform = ( @@ -25,7 +23,6 @@ export const useUpdateTransform = ( ) => { const { http } = useAppDependencies(); const refreshTransformList = useRefreshTransformList(); - const toastNotifications = useToastNotifications(); const mutation = useMutation({ mutationFn: () => @@ -36,15 +33,7 @@ export const useUpdateTransform = ( version: '1', } ), - onSuccess: () => { - toastNotifications.addSuccess( - i18n.translate('xpack.transform.transformList.editTransformSuccessMessage', { - defaultMessage: 'Transform {transformId} updated.', - values: { transformId }, - }) - ); - refreshTransformList(); - }, + onSuccess: () => refreshTransformList(), }); return mutation; diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_create/step_create_form.tsx b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_create/step_create_form.tsx index 2bca8ec8072e1..ff3ae39844289 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_create/step_create_form.tsx +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_create/step_create_form.tsx @@ -180,13 +180,6 @@ export const StepCreateForm: FC = React.memo( true ); - toastNotifications.addSuccess( - i18n.translate('xpack.transform.stepCreateForm.createDataViewSuccessMessage', { - defaultMessage: 'Kibana data view {dataViewName} created successfully.', - values: { dataViewName }, - }) - ); - setDataViewId(newDataView.id); setLoading(false); return true; diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/edit_transform_flyout/edit_transform_update_button.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/edit_transform_flyout/edit_transform_update_button.tsx index 7b00ce29bf8f3..3279b761a954b 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/edit_transform_flyout/edit_transform_update_button.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/edit_transform_flyout/edit_transform_update_button.tsx @@ -33,12 +33,8 @@ export const EditTransformUpdateButton: FC = ({ apiError(undefined); updateTransfrom(undefined, { - onError: (error) => { - apiError(getErrorMessage(error)); - }, - onSuccess: () => { - closeFlyout(); - }, + onError: (error) => apiError(getErrorMessage(error)), + onSuccess: () => closeFlyout(), }); } From b986a42e2a1c8ec4e2d10538d0c96b1a6772a628 Mon Sep 17 00:00:00 2001 From: Walter Rafelsberger Date: Wed, 23 Aug 2023 14:44:55 +0200 Subject: [PATCH 22/53] fix i18n --- .../plugins/translations/translations/fr-FR.json | 15 --------------- .../plugins/translations/translations/ja-JP.json | 15 --------------- .../plugins/translations/translations/zh-CN.json | 15 --------------- 3 files changed, 45 deletions(-) diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index 9f0b2ff73b908..ad1003a6f7cf9 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -37781,18 +37781,14 @@ "xpack.transform.clone.noDataViewErrorPromptText": "Impossible de cloner la transformation {transformId}. Il n'existe aucune vue de données pour {dataViewTitle}.", "xpack.transform.danglingTasksError": "{count} {count, plural, one {transformation n'a pas de} many {transformations n'ont pas de} other {transformations n'ont pas de}} détails de configuration : [{transformIds}] {count, plural, one {Elle ne peut pas être récupérée et doit être supprimée} many {Elles ne peuvent pas être récupérées et doivent être supprimées} other {Elles ne peuvent pas être récupérées et doivent être supprimées}}.", "xpack.transform.deleteTransform.deleteAnalyticsWithDataViewErrorMessage": "Une erreur est survenue lors de la suppression de la vue de données {destinationIndex}", - "xpack.transform.deleteTransform.deleteAnalyticsWithDataViewSuccessMessage": "Requête de suppression de la vue de données {destinationIndex} reconnue.", "xpack.transform.deleteTransform.deleteAnalyticsWithIndexErrorMessage": "Une erreur s'est produite lors de la suppression de l'index de destination {destinationIndex}", - "xpack.transform.deleteTransform.deleteAnalyticsWithIndexSuccessMessage": "Requête de suppression de l'index de destination {destinationIndex} reconnue.", "xpack.transform.deleteTransform.errorWithCheckingIfDataViewExistsNotificationErrorMessage": "Une erreur s'est produite lors de la vérification de l'existence de la vue de données {dataView} : {error}", "xpack.transform.edit.noDataViewErrorPromptText": "Impossible d'obtenir la vue de données pour la transformation {transformId}. Il n'existe aucune vue de données pour {dataViewTitle}.", "xpack.transform.forceDeleteTransformMessage": "Supprimer {count} {count, plural, one {transformation} many {transformations} other {transformations}}", "xpack.transform.managedTransformsWarningCallout": "{count, plural, one {Cette transformation} many {Au moins l'une de ces transformations} other {Au moins l'une de ces transformations}} est préconfigurée par Elastic. Le fait de {action} {count, plural, one {la} many {les} other {les}} avec une heure de fin spécifique peut avoir un impact sur d'autres éléments du produit.", "xpack.transform.multiTransformActionsMenu.transformsCount": "Sélection effectuée de {count} {count, plural, one {transformation} many {transformations} other {transformations}}", "xpack.transform.stepCreateForm.createDataViewErrorMessage": "Une erreur est survenue lors de la création de la vue de données Kibana {dataViewName} :", - "xpack.transform.stepCreateForm.createDataViewSuccessMessage": "La vue de données Kibana {dataViewName} a bien été créée.", "xpack.transform.stepCreateForm.createTransformErrorMessage": "Une erreur s'est produite lors de la création de la transformation {transformId} :", - "xpack.transform.stepCreateForm.createTransformSuccessMessage": "La requête pour créer la transformation {transformId} a été reconnue.", "xpack.transform.stepCreateForm.duplicateDataViewErrorMessage": "Une erreur est survenue lors de la création de la vue de données Kibana {dataViewName} : La vue de données existe déjà.", "xpack.transform.stepDefineForm.invalidKuerySyntaxErrorMessageQueryBar": "Requête non valide : {queryErrorMessage}", "xpack.transform.stepDefineForm.queryPlaceholderKql": "Par exemple, {example}", @@ -37805,41 +37801,30 @@ "xpack.transform.stepDetailsForm.retentionPolicyMaxAgePlaceholderText": "max_age, par exemple {exampleValue}", "xpack.transform.transformForm.sizeNotationPlaceholder": "Exemples : {example1}, {example2}, {example3}, {example4}", "xpack.transform.transformList.alertingRules.tooltipContent": "La transformation a {rulesCount} {rulesCount, plural, one { règle} many { règles} other { règles}} d'alerte associée(s)", - "xpack.transform.transformList.bulkDeleteDestDataViewSuccessMessage": "Suppression réussie de {count} {count, plural, one {vue} many {vues} other {vues}} de données de destination.", - "xpack.transform.transformList.bulkDeleteDestIndexSuccessMessage": "Suppression réussie de {count} {count, plural, one {index} many {index système non migrés} other {index}} de destination.", "xpack.transform.transformList.bulkDeleteModalTitle": "Supprimer {count} {count, plural, one {transformation} many {transformations} other {transformations}} ?", - "xpack.transform.transformList.bulkDeleteTransformSuccessMessage": "Suppression réussie de {count} {count, plural, one {transformation} many {transformations} other {transformations}}.", "xpack.transform.transformList.bulkReauthorizeModalTitle": "Réautoriser {count} {count, plural, one {transformation} many {transformations} other {transformations}} ?", "xpack.transform.transformList.bulkResetModalTitle": "Réinitialiser {count} {count, plural, one {transformation} many {transformations} other {transformations}} ?", - "xpack.transform.transformList.bulkResetTransformSuccessMessage": "Réinitialisation effectuée avec succès de {count} {count, plural, one {transformation} many {transformations} other {transformations}}.", "xpack.transform.transformList.bulkStartModalTitle": "Démarrer {count} {count, plural, one {transformation} many {transformations} other {transformations}} ?", "xpack.transform.transformList.bulkStopModalTitle": "Arrêter {count} {count, plural, one {transformation} many {transformations} other {transformations}} ?", "xpack.transform.transformList.cannotRestartCompleteBatchTransformToolTip": "{transformId} est une transformation par lots terminée et ne peut pas être redémarrée.", "xpack.transform.transformList.cannotScheduleNowCompleteBatchTransformToolTip": "{transformId} est une transformation par lots terminée qui ne peut pas être planifiée pour traiter les données instantanément.", "xpack.transform.transformList.deleteModalTitle": "Supprimer {transformId} ?", "xpack.transform.transformList.deleteTransformErrorMessage": "Une erreur s'est produite lors de la suppression de la transformation {transformId}", - "xpack.transform.transformList.deleteTransformSuccessMessage": "La requête pour supprimer la transformation {transformId} a été reconnue.", "xpack.transform.transformList.editFlyoutFormPlaceholderText": "Par défaut : {defaultValue}", "xpack.transform.transformList.editFlyoutTitle": "Modifier {transformId}", - "xpack.transform.transformList.editTransformSuccessMessage": "Transformation {transformId} mise à jour.", "xpack.transform.transformList.reauthorizeModalTitle": "Réautoriser {transformId} ?", "xpack.transform.transformList.reauthorizeTransformErrorMessage": "Une erreur s'est produite lors de la réautorisation de la transformation {transformId}", - "xpack.transform.transformList.reauthorizeTransformSuccessMessage": "La requête pour réautoriser la transformation {transformId} a été reconnue.", "xpack.transform.transformList.resetModalTitle": "Réinitialiser {transformId} ?", "xpack.transform.transformList.resetTransformErrorMessage": "Une erreur s'est produite lors de la réinitialisation de la transformation {transformId}", - "xpack.transform.transformList.resetTransformSuccessMessage": "La requête pour réinitialiser la transformation {transformId} a été reconnue.", "xpack.transform.transformList.rowCollapse": "Masquer les détails pour {transformId}", "xpack.transform.transformList.rowExpand": "Afficher les détails pour {transformId}", "xpack.transform.transformList.scheduleNowTransformErrorMessage": "Une erreur s'est produite lors de la planification de la transformation {transformId} pour traiter les données instantanément.", - "xpack.transform.transformList.scheduleNowTransformSuccessMessage": "La demande de planification de transformation {transformId} pour traiter les données immédiatement a été reconnue.", "xpack.transform.transformList.startedTransformToolTip": "{transformId} a déjà démarré.", "xpack.transform.transformList.startModalTitle": "Démarrer {transformId} ?", "xpack.transform.transformList.startTransformErrorMessage": "Une erreur s'est produite lors du démarrage de la transformation {transformId}", - "xpack.transform.transformList.startTransformSuccessMessage": "La requête pour démarrer la transformation {transformId} a été reconnue.", "xpack.transform.transformList.stopModalTitle": "Arrêter {transformId} ?", "xpack.transform.transformList.stoppedTransformToolTip": "{transformId} est déjà arrêtée.", "xpack.transform.transformList.stopTransformErrorMessage": "Une erreur s'est produite lors de l'arrêt de la transformation du cadre de données {transformId}", - "xpack.transform.transformList.stopTransformSuccessMessage": "La requête pour arrêter la transformation du cadre de données {transformId} a été reconnue.", "xpack.transform.transformList.unauthorizedTransformsCallout.insufficientPermissionsMsg": "{unauthorizedCnt, plural, one {Une transformation a été créée avec des autorisations insuffisantes.} many {# transformations ont été créées avec des autorisations insuffisantes.} other {# transformations ont été créées avec des autorisations insuffisantes.}}", "xpack.transform.transformList.unauthorizedTransformsCallout.reauthorizeMsg": "Réautorisez pour démarrer {unauthorizedCnt, plural, one {la transformation} many {# transformations} other {# transformations}}.", "xpack.transform.transformNodes.noTransformNodesCallOutBody": "Vous ne pourrez ni créer ni exécuter de transformations. {learnMoreLink}", diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index e1129d3faa9d1..38725eebe2427 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -37780,18 +37780,14 @@ "xpack.transform.clone.noDataViewErrorPromptText": "トランスフォーム{transformId}を複製できません。{dataViewTitle}のデータビューは存在しません。", "xpack.transform.danglingTasksError": "{count}個の{count, plural, other {変換}}に構成の詳細がありません:[{transformIds}]。{count, plural, other {それら}}回復できないため、削除してください。", "xpack.transform.deleteTransform.deleteAnalyticsWithDataViewErrorMessage": "データビュー{destinationIndex}の削除中にエラーが発生しました", - "xpack.transform.deleteTransform.deleteAnalyticsWithDataViewSuccessMessage": "データビュー {destinationIndex} の削除リクエストが受け付けられました。", "xpack.transform.deleteTransform.deleteAnalyticsWithIndexErrorMessage": "ディスティネーションインデックス{destinationIndex}の削除中にエラーが発生しました", - "xpack.transform.deleteTransform.deleteAnalyticsWithIndexSuccessMessage": "ディスティネーションインデックス{destinationIndex}を削除する要求が確認されました。", "xpack.transform.deleteTransform.errorWithCheckingIfDataViewExistsNotificationErrorMessage": "データビュー{dataView}が存在するかどうかを確認するときにエラーが発生しました:{error}", "xpack.transform.edit.noDataViewErrorPromptText": "変換{transformId}のデータビューを取得できません。{dataViewTitle}のデータビューは存在しません。", "xpack.transform.forceDeleteTransformMessage": "{count}{count, plural, other {変換}}の削除", "xpack.transform.managedTransformsWarningCallout": "{count, plural, other {これらの変換のうちの少なくとも1個の変換}}はElasticによってあらかじめ構成されています。{count, plural, other {それらを}}{action}すると、製品の他の部分に影響する可能性があります。", "xpack.transform.multiTransformActionsMenu.transformsCount": "{count}個の{count, plural, other {変換}}を選択済み", "xpack.transform.stepCreateForm.createDataViewErrorMessage": "Kibanaデータビュー{dataViewName}の作成中にエラーが発生しました:", - "xpack.transform.stepCreateForm.createDataViewSuccessMessage": "Kibanaデータビュー{dataViewName}が正常に作成されました。", "xpack.transform.stepCreateForm.createTransformErrorMessage": "変換 {transformId} の取得中にエラーが発生しました。", - "xpack.transform.stepCreateForm.createTransformSuccessMessage": "変換 {transformId} の作成リクエストが受け付けられました。", "xpack.transform.stepCreateForm.duplicateDataViewErrorMessage": "Kibanaデータビュー{dataViewName}の作成中にエラーが発生しました:データビューはすでに存在します。", "xpack.transform.stepDefineForm.invalidKuerySyntaxErrorMessageQueryBar": "無効なクエリ:{queryErrorMessage}", "xpack.transform.stepDefineForm.queryPlaceholderKql": "例: {example}.", @@ -37804,41 +37800,30 @@ "xpack.transform.stepDetailsForm.retentionPolicyMaxAgePlaceholderText": "max_age 例:{exampleValue}", "xpack.transform.transformForm.sizeNotationPlaceholder": "例:{example1}, {example2}, {example3}, {example4}", "xpack.transform.transformList.alertingRules.tooltipContent": "変換には{rulesCount}個の関連付けられたアラート{rulesCount, plural, other { ルール}}があります", - "xpack.transform.transformList.bulkDeleteDestDataViewSuccessMessage": "{count}個のディスティネーションデータ{count, plural, other {ビュー}}が正常に削除されました。", - "xpack.transform.transformList.bulkDeleteDestIndexSuccessMessage": "{count}個のディスティネーション{count, plural, other {インデックス}}が正常に削除されました。", "xpack.transform.transformList.bulkDeleteModalTitle": "{count}{count, plural, other {変換}}を削除しますか?", - "xpack.transform.transformList.bulkDeleteTransformSuccessMessage": "{count}個の{count, plural, other {トランスフォーム}}が正常に削除されました。", "xpack.transform.transformList.bulkReauthorizeModalTitle": "{count} {count, plural, other {トランスフォーム}}をもう一度認可しますか?", "xpack.transform.transformList.bulkResetModalTitle": "{count}個の{count, plural, other {変換}}をリセットしますか?", - "xpack.transform.transformList.bulkResetTransformSuccessMessage": "{count}個の{count, plural, other {変換}}が正常にリセットされました。", "xpack.transform.transformList.bulkStartModalTitle": "{count}個の{count, plural, other {変換}}を開始しますか?", "xpack.transform.transformList.bulkStopModalTitle": "{count}個のを{count, plural, other {変換}}停止しますか?", "xpack.transform.transformList.cannotRestartCompleteBatchTransformToolTip": "{transformId} は完了済みの一斉変換で、再度開始できません。", "xpack.transform.transformList.cannotScheduleNowCompleteBatchTransformToolTip": "{transformId}は完了済みのバッチ変換であるため、データの即時処理のスケジュールを設定できません。", "xpack.transform.transformList.deleteModalTitle": "{transformId}を削除しますか?", "xpack.transform.transformList.deleteTransformErrorMessage": "変換 {transformId} の削除中にエラーが発生しました", - "xpack.transform.transformList.deleteTransformSuccessMessage": "変換 {transformId} の削除リクエストが受け付けられました。", "xpack.transform.transformList.editFlyoutFormPlaceholderText": "デフォルト:{defaultValue}", "xpack.transform.transformList.editFlyoutTitle": "{transformId}の編集", - "xpack.transform.transformList.editTransformSuccessMessage": "変換{transformId}が更新されました。", "xpack.transform.transformList.reauthorizeModalTitle": "{transformId}をもう一度許可しますか?", "xpack.transform.transformList.reauthorizeTransformErrorMessage": "変換{transformId}の再認可中にエラーが発生しました", - "xpack.transform.transformList.reauthorizeTransformSuccessMessage": "変換{transformId}の再認可リクエストが受け付けられました。", "xpack.transform.transformList.resetModalTitle": "{transformId}をリセットしますか?", "xpack.transform.transformList.resetTransformErrorMessage": "変換{transformId}のリセット中にエラーが発生しました", - "xpack.transform.transformList.resetTransformSuccessMessage": "変換{transformId}のリセットリクエストが受け付けられました。", "xpack.transform.transformList.rowCollapse": "{transformId} の詳細を非表示", "xpack.transform.transformList.rowExpand": "{transformId} の詳細を表示", "xpack.transform.transformList.scheduleNowTransformErrorMessage": "変換{transformId}でデータの即時処理のスケジュールの設定中にエラーが発生しました。", - "xpack.transform.transformList.scheduleNowTransformSuccessMessage": "変換{transformId}でデータの即時処理のスケジュールを設定するリクエストが受け付けられました。", "xpack.transform.transformList.startedTransformToolTip": "{transformId} はすでに開始済みです。", "xpack.transform.transformList.startModalTitle": "{transformId}を開始しますか?", "xpack.transform.transformList.startTransformErrorMessage": "変換 {transformId} の開始中にエラーが発生しました", - "xpack.transform.transformList.startTransformSuccessMessage": "変換 {transformId} の開始リクエストが受け付けられました。", "xpack.transform.transformList.stopModalTitle": "{transformId}を終了しますか?", "xpack.transform.transformList.stoppedTransformToolTip": "{transformId} はすでに停止済みです。", "xpack.transform.transformList.stopTransformErrorMessage": "データフレーム変換 {transformId} の停止中にエラーが発生しました", - "xpack.transform.transformList.stopTransformSuccessMessage": "データフレーム変換 {transformId} の停止リクエストが受け付けられました。", "xpack.transform.transformList.unauthorizedTransformsCallout.insufficientPermissionsMsg": "{unauthorizedCnt, plural, other {十分な権限がない状態で#個の変換が作成されました。}}", "xpack.transform.transformList.unauthorizedTransformsCallout.reauthorizeMsg": "もう一度認可して、{unauthorizedCnt, plural, other {#個の変換}}を開始してください。", "xpack.transform.transformNodes.noTransformNodesCallOutBody": "変換の作成または実行はできません。{learnMoreLink}。", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index a7195f24d0c46..25f2c6216187a 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -37774,18 +37774,14 @@ "xpack.transform.clone.noDataViewErrorPromptText": "无法克隆转换 {transformId}。对于 {dataViewTitle},不存在数据视图。", "xpack.transform.danglingTasksError": "{count} 个{count, plural, other {转换}}缺少配置详情:[{transformIds}] 无法将{count, plural, other {其}}恢复,应予以删除。", "xpack.transform.deleteTransform.deleteAnalyticsWithDataViewErrorMessage": "删除数据视图 {destinationIndex} 时出错", - "xpack.transform.deleteTransform.deleteAnalyticsWithDataViewSuccessMessage": "删除数据视图 {destinationIndex} 的请求已确认。", "xpack.transform.deleteTransform.deleteAnalyticsWithIndexErrorMessage": "删除目标索引 {destinationIndex} 时发生错误", - "xpack.transform.deleteTransform.deleteAnalyticsWithIndexSuccessMessage": "删除目标索引 {destinationIndex} 的请求已确认。", "xpack.transform.deleteTransform.errorWithCheckingIfDataViewExistsNotificationErrorMessage": "检查数据视图 {dataView} 是否存在时发生错误:{error}", "xpack.transform.edit.noDataViewErrorPromptText": "无法获取转换 {transformId} 的数据视图。对于 {dataViewTitle},不存在数据视图。", "xpack.transform.forceDeleteTransformMessage": "删除 {count} {count, plural, other {转换}}", "xpack.transform.managedTransformsWarningCallout": "{count, plural, other {至少一个此类转换}}由 Elastic 预配置;{action} {count, plural, other {这些转换}}可能会影响该产品的其他部分。", "xpack.transform.multiTransformActionsMenu.transformsCount": "已选定 {count} 个{count, plural, other {转换}}", "xpack.transform.stepCreateForm.createDataViewErrorMessage": "创建 Kibana 数据视图 {dataViewName} 时发生错误:", - "xpack.transform.stepCreateForm.createDataViewSuccessMessage": "已成功创建 Kibana 数据视图 {dataViewName}。", "xpack.transform.stepCreateForm.createTransformErrorMessage": "创建转换 {transformId} 时出错:", - "xpack.transform.stepCreateForm.createTransformSuccessMessage": "创建转换 {transformId} 的请求已确认。", "xpack.transform.stepCreateForm.duplicateDataViewErrorMessage": "创建 Kibana 数据视图 {dataViewName} 时发生错误:数据视图已存在。", "xpack.transform.stepDefineForm.invalidKuerySyntaxErrorMessageQueryBar": "无效查询:{queryErrorMessage}", "xpack.transform.stepDefineForm.queryPlaceholderKql": "例如,{example}", @@ -37798,41 +37794,30 @@ "xpack.transform.stepDetailsForm.retentionPolicyMaxAgePlaceholderText": "max_age,例如 {exampleValue}", "xpack.transform.transformForm.sizeNotationPlaceholder": "示例:{example1}、{example2}、{example3}、{example4}", "xpack.transform.transformList.alertingRules.tooltipContent": "转换具有 {rulesCount} 个关联的告警{rulesCount, plural, other { 规则}}", - "xpack.transform.transformList.bulkDeleteDestDataViewSuccessMessage": "已成功删除 {count} 个目标数据{count, plural, other {视图}}。", - "xpack.transform.transformList.bulkDeleteDestIndexSuccessMessage": "已成功删除 {count} 个目标数据{count, plural, other {索引}}。", "xpack.transform.transformList.bulkDeleteModalTitle": "删除 {count} 个 {count, plural, other {转换}}?", - "xpack.transform.transformList.bulkDeleteTransformSuccessMessage": "已成功删除 {count} 个{count, plural, other {转换}}。", "xpack.transform.transformList.bulkReauthorizeModalTitle": "重新授权 {count} 个{count, plural, other {转换}}?", "xpack.transform.transformList.bulkResetModalTitle": "重置 {count} 个{count, plural, other {转换}}?", - "xpack.transform.transformList.bulkResetTransformSuccessMessage": "已成功重置 {count} 个{count, plural, other {转换}}。", "xpack.transform.transformList.bulkStartModalTitle": "启动 {count} 个{count, plural, other {转换}}?", "xpack.transform.transformList.bulkStopModalTitle": "停止 {count} 个{count, plural, other {转换}}?", "xpack.transform.transformList.cannotRestartCompleteBatchTransformToolTip": "{transformId} 为已完成批量转换,无法重新启动。", "xpack.transform.transformList.cannotScheduleNowCompleteBatchTransformToolTip": "{transformId} 为已完成的批量转换,无法安排其立即处理数据。", "xpack.transform.transformList.deleteModalTitle": "删除 {transformId}?", "xpack.transform.transformList.deleteTransformErrorMessage": "删除转换 {transformId} 时发生错误", - "xpack.transform.transformList.deleteTransformSuccessMessage": "删除转换 {transformId} 的请求已确认。", "xpack.transform.transformList.editFlyoutFormPlaceholderText": "默认值:{defaultValue}", "xpack.transform.transformList.editFlyoutTitle": "编辑 {transformId}", - "xpack.transform.transformList.editTransformSuccessMessage": "转换 {transformId} 已更新。", "xpack.transform.transformList.reauthorizeModalTitle": "重新授权 {transformId}?", "xpack.transform.transformList.reauthorizeTransformErrorMessage": "重新授权转换 {transformId} 时出错", - "xpack.transform.transformList.reauthorizeTransformSuccessMessage": "重新授权转换 {transformId} 的请求已确认。", "xpack.transform.transformList.resetModalTitle": "重置 {transformId}?", "xpack.transform.transformList.resetTransformErrorMessage": "重置转换 {transformId} 时出错", - "xpack.transform.transformList.resetTransformSuccessMessage": "重置转换 {transformId} 的请求已确认。", "xpack.transform.transformList.rowCollapse": "隐藏 {transformId} 的详情", "xpack.transform.transformList.rowExpand": "显示 {transformId} 的详情", "xpack.transform.transformList.scheduleNowTransformErrorMessage": "计划转换 {transformId} 以立即处理数据时出错。", - "xpack.transform.transformList.scheduleNowTransformSuccessMessage": "计划转换 {transformId} 以立即处理数据的请求已确认。", "xpack.transform.transformList.startedTransformToolTip": "{transformId} 已启动。", "xpack.transform.transformList.startModalTitle": "启动 {transformId}?", "xpack.transform.transformList.startTransformErrorMessage": "启动转换 {transformId} 时发生错误", - "xpack.transform.transformList.startTransformSuccessMessage": "启动转换 {transformId} 的请求已确认。", "xpack.transform.transformList.stopModalTitle": "停止 {transformId}?", "xpack.transform.transformList.stoppedTransformToolTip": "{transformId} 已停止。", "xpack.transform.transformList.stopTransformErrorMessage": "停止数据帧转换 {transformId} 时发生错误", - "xpack.transform.transformList.stopTransformSuccessMessage": "停止数据帧转换 {transformId} 的请求已确认。", "xpack.transform.transformList.unauthorizedTransformsCallout.insufficientPermissionsMsg": "{unauthorizedCnt, plural, other {已创建 # 个转换,但权限不足。}}", "xpack.transform.transformList.unauthorizedTransformsCallout.reauthorizeMsg": "重新授权以启动{unauthorizedCnt, plural, other {# 个转换}}。", "xpack.transform.transformNodes.noTransformNodesCallOutBody": "您将无法创建或运行转换。{learnMoreLink}", From 32c12ebddf2fb8e7ee0ce9be7de2a9e842f6256e Mon Sep 17 00:00:00 2001 From: Walter Rafelsberger Date: Thu, 24 Aug 2023 10:39:26 +0200 Subject: [PATCH 23/53] refactor AuthorizationProvider into useAuthorization hook. --- x-pack/plugins/transform/public/app/app.tsx | 22 ++- .../public/app/common/navigation.tsx | 3 +- .../public/app/components/job_icon.tsx | 2 +- .../components/toast_notification_text.tsx | 2 +- .../transform/public/app/hooks/index.ts | 2 + .../public/app/hooks/use_authorization.ts | 63 ++++++++ .../public/app/hooks/use_index_data.test.tsx | 3 +- .../components/authorization_provider.tsx | 83 ----------- .../app/lib/authorization/components/index.ts | 1 - .../components/with_privileges.tsx | 6 +- .../advanced_pivot_editor_switch.tsx | 2 +- .../advanced_query_editor_switch.tsx | 2 +- ...dvanced_runtime_mappings_editor_switch.tsx | 3 +- .../switch_modal.tsx | 3 +- .../advanced_runtime_mappings_settings.tsx | 3 +- .../advanced_source_editor.tsx | 2 +- .../date_picker_apply_switch.tsx | 2 +- .../source_search_bar/source_search_bar.tsx | 2 +- .../step_create/step_create_summary.tsx | 2 +- .../step_define/latest_function_form.tsx | 3 +- .../step_define/pivot_function_form.tsx | 2 +- .../transform_function_selector.tsx | 3 +- .../step_details/step_details_summary.tsx | 2 +- .../step_details/step_details_time_field.tsx | 3 +- .../components/switch_modal/switch_modal.tsx | 3 +- .../components/wizard_nav/wizard_nav.tsx | 2 +- .../action_clone/clone_action_name.tsx | 3 +- .../action_clone/use_clone_action.tsx | 7 +- .../create_alert_rule_action_name.tsx | 3 +- .../use_create_alert_rule_action.tsx | 6 +- .../action_delete/delete_action_name.tsx | 3 +- .../action_delete/use_delete_action.tsx | 11 +- .../action_discover/discover_action_name.tsx | 3 +- .../action_edit/edit_action_name.tsx | 10 +- .../action_edit/use_edit_action.tsx | 6 +- .../reauthorize_action_modal.tsx | 3 +- .../reauthorize_action_name.tsx | 10 +- .../use_reauthorize_action.tsx | 6 +- .../action_reset/reset_action_name.tsx | 3 +- .../action_reset/use_reset_action.tsx | 7 +- .../schedule_now_action_name.tsx | 10 +- .../use_schedule_now_action.tsx | 6 +- .../start_action_name.test.tsx.snap | 136 +++++++++++++++++- .../action_start/start_action_modal.tsx | 3 +- .../action_start/start_action_name.test.tsx | 9 +- .../action_start/start_action_name.tsx | 10 +- .../action_start/use_start_action.tsx | 7 +- .../stop_action_name.test.tsx.snap | 135 ++++++++++++++++- .../action_stop/stop_action_name.test.tsx | 9 +- .../action_stop/stop_action_name.tsx | 10 +- .../action_stop/use_stop_action.tsx | 7 +- .../create_transform_button.test.tsx.snap | 75 +++++++--- .../create_transform_button.test.tsx | 9 +- .../create_transform_button.tsx | 10 +- .../edit_transform_flyout_callout.tsx | 2 +- .../edit_transform_flyout_form_text_input.tsx | 2 +- .../refresh_transform_list_button.tsx | 2 +- .../search_selection/search_selection.tsx | 3 +- .../components/stats_bar/stat.tsx | 2 +- .../components/stats_bar/stats_bar.tsx | 3 +- .../transform_list/expanded_row_json_pane.tsx | 2 +- .../transform_list/transform_list.tsx | 6 +- .../transform_list/transforms_stats_bar.tsx | 2 +- .../components/transform_list/use_columns.tsx | 6 +- .../transform_management_section.tsx | 8 +- 65 files changed, 531 insertions(+), 250 deletions(-) create mode 100644 x-pack/plugins/transform/public/app/hooks/use_authorization.ts delete mode 100644 x-pack/plugins/transform/public/app/lib/authorization/components/authorization_provider.tsx diff --git a/x-pack/plugins/transform/public/app/app.tsx b/x-pack/plugins/transform/public/app/app.tsx index ba4a43bfa0876..3321a9483c910 100644 --- a/x-pack/plugins/transform/public/app/app.tsx +++ b/x-pack/plugins/transform/public/app/app.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { useContext, FC } from 'react'; +import React, { type FC } from 'react'; import { render, unmountComponentAtNode } from 'react-dom'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; @@ -16,19 +16,17 @@ import { ScopedHistory } from '@kbn/core/public'; import { FormattedMessage } from '@kbn/i18n-react'; import { KibanaContextProvider, KibanaThemeProvider } from '@kbn/kibana-react-plugin/public'; -import { addInternalBasePath } from '../../common/constants'; - import { SectionError } from './components'; import { SECTION_SLUG } from './common/constants'; -import { AuthorizationContext, AuthorizationProvider } from './lib/authorization'; import { AppDependencies } from './app_dependencies'; +import { useAuthorization } from './hooks'; import { CloneTransformSection } from './sections/clone_transform'; import { CreateTransformSection } from './sections/create_transform'; import { TransformManagementSection } from './sections/transform_management'; export const App: FC<{ history: ScopedHistory }> = ({ history }) => { - const { apiError } = useContext(AuthorizationContext); - if (apiError !== null) { + const { error } = useAuthorization(); + if (error !== null) { return ( = ({ history }) => { defaultMessage="Error fetching user privileges from the server" /> } - error={apiError} + error={error} /> ); } @@ -68,13 +66,9 @@ export const renderApp = (element: HTMLElement, appDependencies: AppDependencies - - - - - + + + diff --git a/x-pack/plugins/transform/public/app/common/navigation.tsx b/x-pack/plugins/transform/public/app/common/navigation.tsx index 601e701c7f16d..ef6696d3e757a 100644 --- a/x-pack/plugins/transform/public/app/common/navigation.tsx +++ b/x-pack/plugins/transform/public/app/common/navigation.tsx @@ -5,7 +5,8 @@ * 2.0. */ -import React, { FC } from 'react'; +import React, { type FC } from 'react'; + import { Redirect } from 'react-router-dom'; import { SECTION_SLUG } from './constants'; diff --git a/x-pack/plugins/transform/public/app/components/job_icon.tsx b/x-pack/plugins/transform/public/app/components/job_icon.tsx index 09db5a1c52377..12a5687156611 100644 --- a/x-pack/plugins/transform/public/app/components/job_icon.tsx +++ b/x-pack/plugins/transform/public/app/components/job_icon.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { FC } from 'react'; +import React, { type FC } from 'react'; import { EuiIcon, EuiToolTip } from '@elastic/eui'; import { AuditMessageBase } from '../../../common/types/messages'; diff --git a/x-pack/plugins/transform/public/app/components/toast_notification_text.tsx b/x-pack/plugins/transform/public/app/components/toast_notification_text.tsx index 6409a8fcf3b45..ca9079745fe3d 100644 --- a/x-pack/plugins/transform/public/app/components/toast_notification_text.tsx +++ b/x-pack/plugins/transform/public/app/components/toast_notification_text.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { FC } from 'react'; +import React, { type FC } from 'react'; import { EuiButtonEmpty, diff --git a/x-pack/plugins/transform/public/app/hooks/index.ts b/x-pack/plugins/transform/public/app/hooks/index.ts index f3e619e2364ce..f83574101ea9c 100644 --- a/x-pack/plugins/transform/public/app/hooks/index.ts +++ b/x-pack/plugins/transform/public/app/hooks/index.ts @@ -10,6 +10,7 @@ export { useDocumentationLinks } from './use_documentation_links'; export { useGetDataViewTitles } from './use_get_data_view_titles'; export { useGetEsIndices } from './use_get_es_indices'; export { useGetEsIngestPipelines } from './use_get_es_ingest_pipelines'; +export { useAuthorization } from './use_authorization'; export { useGetTransformAuditMessages } from './use_get_transform_audit_messages'; export { useGetTransform } from './use_get_transform'; export { useGetTransforms } from './use_get_transforms'; @@ -17,6 +18,7 @@ export { useGetTransformsPreview } from './use_get_transforms_preview'; export { useGetTransformStats } from './use_get_transform_stats'; export { useDeleteTransforms, useDeleteIndexAndTargetIndex } from './use_delete_transform'; export { useResetTransforms } from './use_reset_transform'; +export { useSearchItems } from './use_search_items'; export { useScheduleNowTransforms } from './use_schedule_now_transform'; export { useStartTransforms } from './use_start_transform'; export { useStopTransforms } from './use_stop_transform'; diff --git a/x-pack/plugins/transform/public/app/hooks/use_authorization.ts b/x-pack/plugins/transform/public/app/hooks/use_authorization.ts new file mode 100644 index 0000000000000..7fbc6cfe0ad8e --- /dev/null +++ b/x-pack/plugins/transform/public/app/hooks/use_authorization.ts @@ -0,0 +1,63 @@ +/* + * 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 { useQuery } from '@tanstack/react-query'; + +import type { IHttpFetchError } from '@kbn/core-http-browser'; + +import { addInternalBasePath, TRANSFORM_REACT_QUERY_KEYS } from '../../../common/constants'; +import type { Privileges } from '../../../common/types/privileges'; +import { + type PrivilegesAndCapabilities, + type TransformCapabilities, + INITIAL_CAPABILITIES, +} from '../../../common/privilege/has_privilege_factory'; + +import { useAppDependencies } from '../app_dependencies'; + +interface Authorization { + isLoading: boolean; + error: Error | null; + privileges: Privileges; + capabilities: TransformCapabilities; +} + +const initialData: Authorization = { + isLoading: true, + error: null, + privileges: { + hasAllPrivileges: false, + missingPrivileges: {}, + }, + capabilities: INITIAL_CAPABILITIES, +}; + +export const useAuthorization = (): Authorization => { + const { http } = useAppDependencies(); + + const { + isLoading, + error, + data: privilegesData, + } = useQuery( + [TRANSFORM_REACT_QUERY_KEYS.GET_PRIVILEGES], + ({ signal }) => + http.fetch(addInternalBasePath(`privileges`), { + version: '1', + method: 'GET', + signal, + }), + { initialData } + ); + + return { + isLoading, + privileges: privilegesData.privileges, + capabilities: privilegesData.capabilities, + error, + }; +}; diff --git a/x-pack/plugins/transform/public/app/hooks/use_index_data.test.tsx b/x-pack/plugins/transform/public/app/hooks/use_index_data.test.tsx index c64d2eb09ee54..640f16f78a0b4 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_index_data.test.tsx +++ b/x-pack/plugins/transform/public/app/hooks/use_index_data.test.tsx @@ -5,7 +5,8 @@ * 2.0. */ -import React, { FC } from 'react'; +import React, { type FC } from 'react'; + import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import '@testing-library/jest-dom/extend-expect'; import { render, screen, waitFor } from '@testing-library/react'; diff --git a/x-pack/plugins/transform/public/app/lib/authorization/components/authorization_provider.tsx b/x-pack/plugins/transform/public/app/lib/authorization/components/authorization_provider.tsx deleted file mode 100644 index 34760269772d1..0000000000000 --- a/x-pack/plugins/transform/public/app/lib/authorization/components/authorization_provider.tsx +++ /dev/null @@ -1,83 +0,0 @@ -/* - * 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, { createContext } from 'react'; -import { useQuery } from '@tanstack/react-query'; - -import type { IHttpFetchError } from '@kbn/core-http-browser'; - -import { TRANSFORM_REACT_QUERY_KEYS } from '../../../../../common/constants'; -import type { Privileges } from '../../../../../common/types/privileges'; - -import { - type PrivilegesAndCapabilities, - type TransformCapabilities, - INITIAL_CAPABILITIES, -} from '../../../../../common/privilege/has_privilege_factory'; - -import { useAppDependencies } from '../../../app_dependencies'; - -interface Authorization { - isLoading: boolean; - apiError: Error | null; - privileges: Privileges; - capabilities: TransformCapabilities; -} - -const initialValue: Authorization = { - isLoading: true, - apiError: null, - privileges: { - hasAllPrivileges: false, - missingPrivileges: {}, - }, - capabilities: INITIAL_CAPABILITIES, -}; - -export const AuthorizationContext = createContext({ ...initialValue }); - -interface Props { - privilegesEndpoint: { path: string; version: string }; - children: React.ReactNode; -} - -export const AuthorizationProvider = ({ privilegesEndpoint, children }: Props) => { - const { http } = useAppDependencies(); - - const { path, version } = privilegesEndpoint; - - const { - isLoading, - error, - data: privilegesData, - } = useQuery( - [TRANSFORM_REACT_QUERY_KEYS.GET_PRIVILEGES], - ({ signal }) => - http.fetch(path, { - version, - method: 'GET', - signal, - }) - ); - - const value = { - isLoading, - privileges: - isLoading || privilegesData === undefined - ? { ...initialValue.privileges } - : privilegesData.privileges, - capabilities: - isLoading || privilegesData === undefined - ? { ...INITIAL_CAPABILITIES } - : privilegesData.capabilities, - apiError: error ? error : null, - }; - - return ( - {children} - ); -}; diff --git a/x-pack/plugins/transform/public/app/lib/authorization/components/index.ts b/x-pack/plugins/transform/public/app/lib/authorization/components/index.ts index cb0f248efc165..1b04f9287f2c4 100644 --- a/x-pack/plugins/transform/public/app/lib/authorization/components/index.ts +++ b/x-pack/plugins/transform/public/app/lib/authorization/components/index.ts @@ -6,6 +6,5 @@ */ export { createCapabilityFailureMessage } from '../../../../../common/privilege/has_privilege_factory'; -export { AuthorizationProvider, AuthorizationContext } from './authorization_provider'; export { PrivilegesWrapper } from './with_privileges'; export { NotAuthorizedSection } from './not_authorized_section'; diff --git a/x-pack/plugins/transform/public/app/lib/authorization/components/with_privileges.tsx b/x-pack/plugins/transform/public/app/lib/authorization/components/with_privileges.tsx index 2117591142b26..2623a6429da94 100644 --- a/x-pack/plugins/transform/public/app/lib/authorization/components/with_privileges.tsx +++ b/x-pack/plugins/transform/public/app/lib/authorization/components/with_privileges.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { useContext, FC } from 'react'; +import React, { type FC } from 'react'; import { EuiFlexItem, @@ -19,7 +19,7 @@ import { MissingPrivileges } from '../../../../../common/types/privileges'; import { SectionLoading } from '../../../components'; -import { AuthorizationContext } from './authorization_provider'; +import { useAuthorization } from '../../../hooks'; import { NotAuthorizedSection } from './not_authorized_section'; import { hasPrivilegeFactory, @@ -42,7 +42,7 @@ interface Props { } export const WithPrivileges = ({ privileges: requiredPrivileges, children }: Props) => { - const { isLoading, privileges } = useContext(AuthorizationContext); + const { isLoading, privileges } = useAuthorization(); const privilegesToArray: Privilege[] = toArray(requiredPrivileges).map((p) => { const [section, privilege] = p.split('.'); diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/advanced_pivot_editor_switch/advanced_pivot_editor_switch.tsx b/x-pack/plugins/transform/public/app/sections/create_transform/components/advanced_pivot_editor_switch/advanced_pivot_editor_switch.tsx index 900af603266b8..a125da52b0cae 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/advanced_pivot_editor_switch/advanced_pivot_editor_switch.tsx +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/advanced_pivot_editor_switch/advanced_pivot_editor_switch.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { FC } from 'react'; +import React, { type FC } from 'react'; import { EuiFlexGroup, EuiFlexItem, EuiFormRow, EuiSwitch } from '@elastic/eui'; diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/advanced_query_editor_switch/advanced_query_editor_switch.tsx b/x-pack/plugins/transform/public/app/sections/create_transform/components/advanced_query_editor_switch/advanced_query_editor_switch.tsx index 43c6684a5a2bc..cb21e7026f27b 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/advanced_query_editor_switch/advanced_query_editor_switch.tsx +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/advanced_query_editor_switch/advanced_query_editor_switch.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { FC } from 'react'; +import React, { type FC } from 'react'; import { EuiSwitch } from '@elastic/eui'; diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/advanced_runtime_mappings_editor_switch/advanced_runtime_mappings_editor_switch.tsx b/x-pack/plugins/transform/public/app/sections/create_transform/components/advanced_runtime_mappings_editor_switch/advanced_runtime_mappings_editor_switch.tsx index 2ee8bc9995df6..c53c5dae0b4ad 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/advanced_runtime_mappings_editor_switch/advanced_runtime_mappings_editor_switch.tsx +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/advanced_runtime_mappings_editor_switch/advanced_runtime_mappings_editor_switch.tsx @@ -5,7 +5,8 @@ * 2.0. */ -import React, { FC } from 'react'; +import React, { type FC } from 'react'; + import { EuiSwitch } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { SwitchModal } from './switch_modal'; diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/advanced_runtime_mappings_editor_switch/switch_modal.tsx b/x-pack/plugins/transform/public/app/sections/create_transform/components/advanced_runtime_mappings_editor_switch/switch_modal.tsx index ff08ab37bb3e6..37dd6dd01f98e 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/advanced_runtime_mappings_editor_switch/switch_modal.tsx +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/advanced_runtime_mappings_editor_switch/switch_modal.tsx @@ -5,7 +5,8 @@ * 2.0. */ -import React, { FC } from 'react'; +import React, { type FC } from 'react'; + import { EuiConfirmModal } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/advanced_runtime_mappings_settings/advanced_runtime_mappings_settings.tsx b/x-pack/plugins/transform/public/app/sections/create_transform/components/advanced_runtime_mappings_settings/advanced_runtime_mappings_settings.tsx index db617690efc5f..8b76b8d7d7e1a 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/advanced_runtime_mappings_settings/advanced_runtime_mappings_settings.tsx +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/advanced_runtime_mappings_settings/advanced_runtime_mappings_settings.tsx @@ -5,7 +5,8 @@ * 2.0. */ -import React, { FC } from 'react'; +import React, { type FC } from 'react'; + import { EuiButton, EuiButtonIcon, diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/advanced_source_editor/advanced_source_editor.tsx b/x-pack/plugins/transform/public/app/sections/create_transform/components/advanced_source_editor/advanced_source_editor.tsx index 665c9986e6e69..4fea2f43bd5db 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/advanced_source_editor/advanced_source_editor.tsx +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/advanced_source_editor/advanced_source_editor.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { FC } from 'react'; +import React, { type FC } from 'react'; import { i18n } from '@kbn/i18n'; diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/date_picker_apply_switch/date_picker_apply_switch.tsx b/x-pack/plugins/transform/public/app/sections/create_transform/components/date_picker_apply_switch/date_picker_apply_switch.tsx index a57d83b75aa10..2f5672d3ec592 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/date_picker_apply_switch/date_picker_apply_switch.tsx +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/date_picker_apply_switch/date_picker_apply_switch.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { FC } from 'react'; +import React, { type FC } from 'react'; import { EuiSwitch } from '@elastic/eui'; diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/source_search_bar/source_search_bar.tsx b/x-pack/plugins/transform/public/app/sections/create_transform/components/source_search_bar/source_search_bar.tsx index e0a52978c0b4a..42b9d556f9dc2 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/source_search_bar/source_search_bar.tsx +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/source_search_bar/source_search_bar.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { FC } from 'react'; +import React, { type FC } from 'react'; import { EuiCode, EuiInputPopover } from '@elastic/eui'; diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_create/step_create_summary.tsx b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_create/step_create_summary.tsx index b7704044fe0b3..2be067c777a1e 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_create/step_create_summary.tsx +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_create/step_create_summary.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { FC } from 'react'; +import React, { type FC } from 'react'; export const StepCreateSummary: FC = React.memo(() => { return null; diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/latest_function_form.tsx b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/latest_function_form.tsx index a83c7c7a5871c..ba0d9e93e2cce 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/latest_function_form.tsx +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/latest_function_form.tsx @@ -5,7 +5,8 @@ * 2.0. */ -import React, { FC } from 'react'; +import React, { type FC } from 'react'; + import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; import { EuiButtonIcon, EuiCallOut, EuiComboBox, EuiCopy, EuiFormRow } from '@elastic/eui'; diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/pivot_function_form.tsx b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/pivot_function_form.tsx index efa28de596a18..861aeb778af74 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/pivot_function_form.tsx +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/pivot_function_form.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { FC } from 'react'; +import React, { type FC } from 'react'; import { EuiButton, diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/transform_function_selector.tsx b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/transform_function_selector.tsx index 3aec137a3adf8..441e18ebb43d2 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/transform_function_selector.tsx +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/transform_function_selector.tsx @@ -5,7 +5,8 @@ * 2.0. */ -import React, { FC } from 'react'; +import React, { type FC } from 'react'; + import { i18n } from '@kbn/i18n'; import { EuiCard, EuiFlexGroup, EuiFlexItem, EuiIcon, EuiSpacer } from '@elastic/eui'; import { TRANSFORM_FUNCTION, TransformFunction } from '../../../../../../common/constants'; diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_details/step_details_summary.tsx b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_details/step_details_summary.tsx index 80203af34e105..b3b11a6e4764e 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_details/step_details_summary.tsx +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_details/step_details_summary.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { FC } from 'react'; +import React, { type FC } from 'react'; import { i18n } from '@kbn/i18n'; diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_details/step_details_time_field.tsx b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_details/step_details_time_field.tsx index d750bf6c7e1fd..76ce803bdb415 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_details/step_details_time_field.tsx +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_details/step_details_time_field.tsx @@ -5,7 +5,8 @@ * 2.0. */ -import React, { FC } from 'react'; +import React, { type FC } from 'react'; + import { EuiFormRow, EuiSelect } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; import { i18n } from '@kbn/i18n'; diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/switch_modal/switch_modal.tsx b/x-pack/plugins/transform/public/app/sections/create_transform/components/switch_modal/switch_modal.tsx index 2d2a5b1fcad93..cbc53383541ed 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/switch_modal/switch_modal.tsx +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/switch_modal/switch_modal.tsx @@ -5,7 +5,8 @@ * 2.0. */ -import React, { FC } from 'react'; +import React, { type FC } from 'react'; + import { i18n } from '@kbn/i18n'; import { EuiConfirmModal } from '@elastic/eui'; diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/wizard_nav/wizard_nav.tsx b/x-pack/plugins/transform/public/app/sections/create_transform/components/wizard_nav/wizard_nav.tsx index 103b8378cef7f..2ffb8437d4861 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/wizard_nav/wizard_nav.tsx +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/wizard_nav/wizard_nav.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { FC } from 'react'; +import React, { type FC } from 'react'; import { i18n } from '@kbn/i18n'; diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_clone/clone_action_name.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_clone/clone_action_name.tsx index e6f3eeb4a9064..9af861aaf5c40 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_clone/clone_action_name.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_clone/clone_action_name.tsx @@ -5,7 +5,8 @@ * 2.0. */ -import React, { FC } from 'react'; +import React, { type FC } from 'react'; + import { i18n } from '@kbn/i18n'; import { EuiToolTip } from '@elastic/eui'; diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_clone/use_clone_action.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_clone/use_clone_action.tsx index 35d5e9f05c315..08e698672be76 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_clone/use_clone_action.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_clone/use_clone_action.tsx @@ -5,14 +5,13 @@ * 2.0. */ -import React, { useCallback, useContext, useMemo } from 'react'; +import React, { useCallback, useMemo } from 'react'; import { useHistory } from 'react-router-dom'; import { i18n } from '@kbn/i18n'; -import { AuthorizationContext } from '../../../../lib/authorization'; import { TransformListAction, TransformListRow } from '../../../../common'; import { SECTION_SLUG } from '../../../../common/constants'; -import { useSearchItems } from '../../../../hooks/use_search_items'; +import { useAuthorization, useSearchItems } from '../../../../hooks'; import { useAppDependencies, useToastNotifications } from '../../../../app_dependencies'; import { cloneActionNameText, CloneActionName } from './clone_action_name'; @@ -26,7 +25,7 @@ export const useCloneAction = (forceDisable: boolean, transformNodes: number) => const { getDataViewIdByTitle, loadDataViews } = useSearchItems(undefined); - const { canCreateTransform } = useContext(AuthorizationContext).capabilities; + const { canCreateTransform } = useAuthorization().capabilities; const clickHandler = useCallback( async (item: TransformListRow) => { diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_create_alert/create_alert_rule_action_name.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_create_alert/create_alert_rule_action_name.tsx index c8d67a86d579a..dde62aa8cbfda 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_create_alert/create_alert_rule_action_name.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_create_alert/create_alert_rule_action_name.tsx @@ -5,7 +5,8 @@ * 2.0. */ -import React, { FC } from 'react'; +import React, { type FC } from 'react'; + import { EuiToolTip } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_create_alert/use_create_alert_rule_action.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_create_alert/use_create_alert_rule_action.tsx index 070f1eb08ac60..7c2efa8cc645a 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_create_alert/use_create_alert_rule_action.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_create_alert/use_create_alert_rule_action.tsx @@ -5,8 +5,8 @@ * 2.0. */ -import React, { useCallback, useContext, useMemo } from 'react'; -import { AuthorizationContext } from '../../../../lib/authorization'; +import React, { useCallback, useMemo } from 'react'; +import { useAuthorization } from '../../../../hooks'; import { TransformListAction, TransformListRow } from '../../../../common'; import { crateAlertRuleActionNameText, @@ -17,7 +17,7 @@ import { isContinuousTransform } from '../../../../../../common/types/transform' export type CreateAlertRuleAction = ReturnType; export const useCreateAlertRuleAction = (forceDisable: boolean) => { - const { canCreateTransformAlerts } = useContext(AuthorizationContext).capabilities; + const { canCreateTransformAlerts } = useAuthorization().capabilities; const { setCreateAlertRule } = useAlertRuleFlyout(); const clickHandler = useCallback( diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_delete/delete_action_name.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_delete/delete_action_name.tsx index fa1142938efe7..24488ec60dcf2 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_delete/delete_action_name.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_delete/delete_action_name.tsx @@ -5,7 +5,8 @@ * 2.0. */ -import React, { FC } from 'react'; +import React, { type FC } from 'react'; + import { i18n } from '@kbn/i18n'; import { EuiToolTip } from '@elastic/eui'; import { TransformState, TRANSFORM_STATE } from '../../../../../../common/constants'; diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_delete/use_delete_action.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_delete/use_delete_action.tsx index e81612fe77bac..ddae1b1578d34 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_delete/use_delete_action.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_delete/use_delete_action.tsx @@ -5,13 +5,16 @@ * 2.0. */ -import React, { useContext, useMemo, useState } from 'react'; +import React, { useMemo, useState } from 'react'; import { TRANSFORM_STATE } from '../../../../../../common/constants'; import { TransformListAction, TransformListRow } from '../../../../common'; -import { useDeleteIndexAndTargetIndex, useDeleteTransforms } from '../../../../hooks'; -import { AuthorizationContext } from '../../../../lib/authorization'; +import { + useDeleteIndexAndTargetIndex, + useDeleteTransforms, + useAuthorization, +} from '../../../../hooks'; import { deleteActionNameText, @@ -21,7 +24,7 @@ import { export type DeleteAction = ReturnType; export const useDeleteAction = (forceDisable: boolean) => { - const { canDeleteTransform } = useContext(AuthorizationContext).capabilities; + const { canDeleteTransform } = useAuthorization().capabilities; const { mutate: deleteTransforms } = useDeleteTransforms(); diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_discover/discover_action_name.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_discover/discover_action_name.tsx index f7cc72c2236b0..c3d359e648c28 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_discover/discover_action_name.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_discover/discover_action_name.tsx @@ -5,7 +5,8 @@ * 2.0. */ -import React, { FC } from 'react'; +import React, { type FC } from 'react'; + import { i18n } from '@kbn/i18n'; import { EuiToolTip } from '@elastic/eui'; diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_edit/edit_action_name.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_edit/edit_action_name.tsx index 3bf5ee8e611f6..5a95a9dfa7601 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_edit/edit_action_name.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_edit/edit_action_name.tsx @@ -5,16 +5,14 @@ * 2.0. */ -import React, { useContext, FC } from 'react'; +import React, { type FC } from 'react'; import { i18n } from '@kbn/i18n'; import { EuiToolTip } from '@elastic/eui'; -import { - createCapabilityFailureMessage, - AuthorizationContext, -} from '../../../../lib/authorization'; +import { createCapabilityFailureMessage } from '../../../../lib/authorization'; +import { useAuthorization } from '../../../../hooks'; export const editActionNameText = i18n.translate( 'xpack.transform.transformList.editActionNameText', @@ -24,7 +22,7 @@ export const editActionNameText = i18n.translate( ); export const EditActionName: FC = () => { - const { canCreateTransform } = useContext(AuthorizationContext).capabilities; + const { canCreateTransform } = useAuthorization().capabilities; if (!canCreateTransform) { return ( diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_edit/use_edit_action.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_edit/use_edit_action.tsx index 19d60b8b64381..e2da5262d9d28 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_edit/use_edit_action.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_edit/use_edit_action.tsx @@ -5,12 +5,12 @@ * 2.0. */ -import React, { useCallback, useContext, useMemo, useState } from 'react'; +import React, { useCallback, useMemo, useState } from 'react'; import { i18n } from '@kbn/i18n'; import { TransformListAction, TransformListRow } from '../../../../common'; -import { AuthorizationContext } from '../../../../lib/authorization'; +import { useAuthorization } from '../../../../hooks'; import { editActionNameText, EditActionName } from './edit_action_name'; import { useSearchItems } from '../../../../hooks/use_search_items'; @@ -19,7 +19,7 @@ import { TransformConfigUnion } from '../../../../../../common/types/transform'; export type EditAction = ReturnType; export const useEditAction = (forceDisable: boolean, transformNodes: number) => { - const { canCreateTransform } = useContext(AuthorizationContext).capabilities; + const { canCreateTransform } = useAuthorization().capabilities; const [config, setConfig] = useState(); const [isFlyoutVisible, setIsFlyoutVisible] = useState(false); diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_reauthorize/reauthorize_action_modal.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_reauthorize/reauthorize_action_modal.tsx index 9e848fdd8323e..edfde117abbd7 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_reauthorize/reauthorize_action_modal.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_reauthorize/reauthorize_action_modal.tsx @@ -5,7 +5,8 @@ * 2.0. */ -import React, { FC } from 'react'; +import React, { type FC } from 'react'; + import { i18n } from '@kbn/i18n'; import { EUI_MODAL_CONFIRM_BUTTON, EuiConfirmModal } from '@elastic/eui'; import type { ReauthorizeAction } from './use_reauthorize_action'; diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_reauthorize/reauthorize_action_name.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_reauthorize/reauthorize_action_name.tsx index e07ae03ec46b0..5e47fbc64c87b 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_reauthorize/reauthorize_action_name.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_reauthorize/reauthorize_action_name.tsx @@ -5,14 +5,12 @@ * 2.0. */ -import React, { FC, useContext } from 'react'; +import React, { type FC } from 'react'; import { i18n } from '@kbn/i18n'; import { EuiToolTip, EuiText } from '@elastic/eui'; import { needsReauthorization } from '../../../../common/reauthorization_utils'; -import { - AuthorizationContext, - createCapabilityFailureMessage, -} from '../../../../lib/authorization'; +import { createCapabilityFailureMessage } from '../../../../lib/authorization'; +import { useAuthorization } from '../../../../hooks'; import { TransformListRow } from '../../../../common'; export const reauthorizeActionNameText = i18n.translate( @@ -45,7 +43,7 @@ export const ReauthorizeActionName: FC = ({ forceDisable, transformNodes, }) => { - const { canStartStopTransform } = useContext(AuthorizationContext).capabilities; + const { canStartStopTransform } = useAuthorization().capabilities; // Disable start for batch transforms which have completed. const someNeedsReauthorization = items.some(needsReauthorization); diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_reauthorize/use_reauthorize_action.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_reauthorize/use_reauthorize_action.tsx index b3c11971fb750..f42aaf5a0c6aa 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_reauthorize/use_reauthorize_action.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_reauthorize/use_reauthorize_action.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { useContext, useMemo, useState } from 'react'; +import React, { useMemo, useState } from 'react'; import { sortTransformsToReauthorize } from './sort_transforms_to_reauthorize'; import { needsReauthorization } from '../../../../common/reauthorization_utils'; @@ -17,11 +17,11 @@ import { } from './reauthorize_action_name'; import { TransformListAction, TransformListRow } from '../../../../common'; -import { AuthorizationContext } from '../../../../lib/authorization'; +import { useAuthorization } from '../../../../hooks'; export type ReauthorizeAction = ReturnType; export const useReauthorizeAction = (forceDisable: boolean, transformNodes: number) => { - const { canStartStopTransform } = useContext(AuthorizationContext).capabilities; + const { canStartStopTransform } = useAuthorization().capabilities; const { mutate: reauthorizeTransforms } = useReauthorizeTransforms(); diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_reset/reset_action_name.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_reset/reset_action_name.tsx index c6ea0f5f7270d..030b1cad14c65 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_reset/reset_action_name.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_reset/reset_action_name.tsx @@ -5,7 +5,8 @@ * 2.0. */ -import React, { FC } from 'react'; +import React, { type FC } from 'react'; + import { i18n } from '@kbn/i18n'; import { EuiToolTip } from '@elastic/eui'; import { TransformState, TRANSFORM_STATE } from '../../../../../../common/constants'; diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_reset/use_reset_action.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_reset/use_reset_action.tsx index 45dcf5b4ba3da..e5f2ea62b984d 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_reset/use_reset_action.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_reset/use_reset_action.tsx @@ -5,19 +5,18 @@ * 2.0. */ -import React, { useContext, useMemo, useState } from 'react'; +import React, { useMemo, useState } from 'react'; import { TRANSFORM_STATE } from '../../../../../../common/constants'; import { TransformListAction, TransformListRow } from '../../../../common'; -import { useResetTransforms } from '../../../../hooks'; -import { AuthorizationContext } from '../../../../lib/authorization'; +import { useAuthorization, useResetTransforms } from '../../../../hooks'; import { resetActionNameText, isResetActionDisabled, ResetActionName } from './reset_action_name'; export type ResetAction = ReturnType; export const useResetAction = (forceDisable: boolean) => { - const { canResetTransform } = useContext(AuthorizationContext).capabilities; + const { canResetTransform } = useAuthorization().capabilities; const { mutate: resetTransforms } = useResetTransforms(); diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_schedule_now/schedule_now_action_name.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_schedule_now/schedule_now_action_name.tsx index 71b6a055c0d94..ca3931603df4c 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_schedule_now/schedule_now_action_name.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_schedule_now/schedule_now_action_name.tsx @@ -5,14 +5,12 @@ * 2.0. */ -import React, { FC, useContext } from 'react'; +import React, { type FC } from 'react'; import { i18n } from '@kbn/i18n'; import { EuiToolTip } from '@elastic/eui'; -import { - createCapabilityFailureMessage, - AuthorizationContext, -} from '../../../../lib/authorization'; +import { createCapabilityFailureMessage } from '../../../../lib/authorization'; +import { useAuthorization } from '../../../../hooks'; import { TransformListRow, isCompletedBatchTransform } from '../../../../common'; export const scheduleNowActionNameText = i18n.translate( @@ -48,7 +46,7 @@ export const ScheduleNowActionName: FC = ({ forceDisable, transformNodes, }) => { - const { canScheduleNowTransform } = useContext(AuthorizationContext).capabilities; + const { canScheduleNowTransform } = useAuthorization().capabilities; const isBulkAction = items.length > 1; // Disable schedule-now for batch transforms which have completed. diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_schedule_now/use_schedule_now_action.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_schedule_now/use_schedule_now_action.tsx index 1d9fb7417dc04..8f5fb462bb28d 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_schedule_now/use_schedule_now_action.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_schedule_now/use_schedule_now_action.tsx @@ -5,11 +5,11 @@ * 2.0. */ -import React, { useContext, useMemo } from 'react'; +import React, { useMemo } from 'react'; import { TRANSFORM_STATE } from '../../../../../../common/constants'; -import { AuthorizationContext } from '../../../../lib/authorization'; +import { useAuthorization } from '../../../../hooks'; import { TransformListAction, TransformListRow } from '../../../../common'; import { useScheduleNowTransforms } from '../../../../hooks'; @@ -21,7 +21,7 @@ import { export type ScheduleNowAction = ReturnType; export const useScheduleNowAction = (forceDisable: boolean, transformNodes: number) => { - const { canScheduleNowTransform } = useContext(AuthorizationContext).capabilities; + const { canScheduleNowTransform } = useAuthorization().capabilities; const { mutate: scheduleNowTransforms } = useScheduleNowTransforms(); diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_start/__snapshots__/start_action_name.test.tsx.snap b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_start/__snapshots__/start_action_name.test.tsx.snap index 20b0691b55bf9..466afc71a4811 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_start/__snapshots__/start_action_name.test.tsx.snap +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_start/__snapshots__/start_action_name.test.tsx.snap @@ -1,12 +1,134 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Transform: Transform List Actions Minimal initialization 1`] = ` - - Start - + + + + `; diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_start/start_action_modal.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_start/start_action_modal.tsx index 7ad6897034e10..ab98f36222957 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_start/start_action_modal.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_start/start_action_modal.tsx @@ -5,7 +5,8 @@ * 2.0. */ -import React, { FC } from 'react'; +import React, { type FC } from 'react'; + import { i18n } from '@kbn/i18n'; import { EuiConfirmModal, EUI_MODAL_CONFIRM_BUTTON } from '@elastic/eui'; import { StartAction } from './use_start_action'; diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_start/start_action_name.test.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_start/start_action_name.test.tsx index ba4619b022620..f609dd21325a9 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_start/start_action_name.test.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_start/start_action_name.test.tsx @@ -7,6 +7,7 @@ import { shallow } from 'enzyme'; import React from 'react'; +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { TransformListRow } from '../../../../common'; import { StartActionName, StartActionNameProps } from './start_action_name'; @@ -16,6 +17,8 @@ import transformListRow from '../../../../common/__mocks__/transform_list_row.js jest.mock('../../../../../shared_imports'); jest.mock('../../../../app_dependencies'); +const queryClient = new QueryClient(); + describe('Transform: Transform List Actions ', () => { test('Minimal initialization', () => { // @ts-expect-error mock data is too loosely typed @@ -26,7 +29,11 @@ describe('Transform: Transform List Actions ', () => { transformNodes: 1, }; - const wrapper = shallow(); + const wrapper = shallow( + + + + ); expect(wrapper).toMatchSnapshot(); }); diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_start/start_action_name.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_start/start_action_name.tsx index 844d9755d7073..2a4fa01d63084 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_start/start_action_name.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_start/start_action_name.tsx @@ -5,16 +5,14 @@ * 2.0. */ -import React, { FC, useContext } from 'react'; +import React, { type FC } from 'react'; import { i18n } from '@kbn/i18n'; import { EuiToolTip } from '@elastic/eui'; import { TRANSFORM_STATE } from '../../../../../../common/constants'; -import { - createCapabilityFailureMessage, - AuthorizationContext, -} from '../../../../lib/authorization'; +import { createCapabilityFailureMessage } from '../../../../lib/authorization'; +import { useAuthorization } from '../../../../hooks'; import { TransformListRow, isCompletedBatchTransform } from '../../../../common'; export const startActionNameText = i18n.translate( @@ -55,7 +53,7 @@ export const StartActionName: FC = ({ forceDisable, transformNodes, }) => { - const { canStartStopTransform } = useContext(AuthorizationContext).capabilities; + const { canStartStopTransform } = useAuthorization().capabilities; const isBulkAction = items.length > 1; // Disable start for batch transforms which have completed. diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_start/use_start_action.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_start/use_start_action.tsx index b033cb514cbf2..bbb08854a8cff 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_start/use_start_action.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_start/use_start_action.tsx @@ -5,19 +5,18 @@ * 2.0. */ -import React, { useContext, useMemo, useState } from 'react'; +import React, { useMemo, useState } from 'react'; import { TRANSFORM_STATE } from '../../../../../../common/constants'; -import { AuthorizationContext } from '../../../../lib/authorization'; import { TransformListAction, TransformListRow } from '../../../../common'; -import { useStartTransforms } from '../../../../hooks'; +import { useAuthorization, useStartTransforms } from '../../../../hooks'; import { isStartActionDisabled, startActionNameText, StartActionName } from './start_action_name'; export type StartAction = ReturnType; export const useStartAction = (forceDisable: boolean, transformNodes: number) => { - const { canStartStopTransform } = useContext(AuthorizationContext).capabilities; + const { canStartStopTransform } = useAuthorization().capabilities; const { mutate: startTransforms } = useStartTransforms(); diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_stop/__snapshots__/stop_action_name.test.tsx.snap b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_stop/__snapshots__/stop_action_name.test.tsx.snap index fd97412fa1875..ec4b06334060f 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_stop/__snapshots__/stop_action_name.test.tsx.snap +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_stop/__snapshots__/stop_action_name.test.tsx.snap @@ -1,12 +1,133 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Transform: Transform List Actions Minimal initialization 1`] = ` - - Stop - + + + + `; diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_stop/stop_action_name.test.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_stop/stop_action_name.test.tsx index 9496dbd82c70d..316142d4b6c73 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_stop/stop_action_name.test.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_stop/stop_action_name.test.tsx @@ -7,6 +7,7 @@ import { shallow } from 'enzyme'; import React from 'react'; +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { TransformListRow } from '../../../../common'; import { StopActionName, StopActionNameProps } from './stop_action_name'; @@ -16,6 +17,8 @@ import transformListRow from '../../../../common/__mocks__/transform_list_row.js jest.mock('../../../../../shared_imports'); jest.mock('../../../../app_dependencies'); +const queryClient = new QueryClient(); + describe('Transform: Transform List Actions ', () => { test('Minimal initialization', () => { // @ts-expect-error mock data is too loosely typed @@ -25,7 +28,11 @@ describe('Transform: Transform List Actions ', () => { items: [item], }; - const wrapper = shallow(); + const wrapper = shallow( + + + + ); expect(wrapper).toMatchSnapshot(); }); diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_stop/stop_action_name.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_stop/stop_action_name.tsx index 1c729555f7df3..71b98a825b6ba 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_stop/stop_action_name.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_stop/stop_action_name.tsx @@ -5,17 +5,15 @@ * 2.0. */ -import React, { FC, useContext } from 'react'; +import React, { type FC } from 'react'; import { i18n } from '@kbn/i18n'; import { EuiToolTip } from '@elastic/eui'; import { TRANSFORM_STATE } from '../../../../../../common/constants'; import { TransformListRow } from '../../../../common'; -import { - createCapabilityFailureMessage, - AuthorizationContext, -} from '../../../../lib/authorization'; +import { createCapabilityFailureMessage } from '../../../../lib/authorization'; +import { useAuthorization } from '../../../../hooks'; export const stopActionNameText = i18n.translate( 'xpack.transform.transformList.stopActionNameText', @@ -43,7 +41,7 @@ export interface StopActionNameProps { } export const StopActionName: FC = ({ items, forceDisable }) => { const isBulkAction = items.length > 1; - const { canStartStopTransform } = useContext(AuthorizationContext).capabilities; + const { canStartStopTransform } = useAuthorization().capabilities; // Disable stop action if one of the transforms is stopped already const stoppedTransform = items.some( diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_stop/use_stop_action.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_stop/use_stop_action.tsx index e09d5cc4888d0..b3a4a4b4e909a 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_stop/use_stop_action.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_stop/use_stop_action.tsx @@ -5,18 +5,17 @@ * 2.0. */ -import React, { useCallback, useContext, useMemo, useState } from 'react'; +import React, { useCallback, useMemo, useState } from 'react'; import { TRANSFORM_STATE } from '../../../../../../common/constants'; -import { AuthorizationContext } from '../../../../lib/authorization'; import { TransformListAction, TransformListRow } from '../../../../common'; -import { useStopTransforms } from '../../../../hooks'; +import { useAuthorization, useStopTransforms } from '../../../../hooks'; import { isStopActionDisabled, stopActionNameText, StopActionName } from './stop_action_name'; import { isManagedTransform } from '../../../../common/managed_transforms_utils'; export type StopAction = ReturnType; export const useStopAction = (forceDisable: boolean) => { - const { canStartStopTransform } = useContext(AuthorizationContext).capabilities; + const { canStartStopTransform } = useAuthorization().capabilities; const { mutate: stopTransforms } = useStopTransforms(); const [isModalVisible, setModalVisible] = useState(false); diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/create_transform_button/__snapshots__/create_transform_button.test.tsx.snap b/x-pack/plugins/transform/public/app/sections/transform_management/components/create_transform_button/__snapshots__/create_transform_button.test.tsx.snap index a529ef04f9230..e8428dbefb43c 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/create_transform_button/__snapshots__/create_transform_button.test.tsx.snap +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/create_transform_button/__snapshots__/create_transform_button.test.tsx.snap @@ -1,26 +1,63 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Transform: Transform List Minimal initialization 1`] = ` - - - - - + + `; diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/create_transform_button/create_transform_button.test.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/create_transform_button/create_transform_button.test.tsx index 0a7324fd09ffc..4e8c09958c3e7 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/create_transform_button/create_transform_button.test.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/create_transform_button/create_transform_button.test.tsx @@ -7,14 +7,21 @@ import { shallow } from 'enzyme'; import React from 'react'; +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { CreateTransformButton } from './create_transform_button'; jest.mock('../../../../../shared_imports'); +const queryClient = new QueryClient(); + describe('Transform: Transform List ', () => { test('Minimal initialization', () => { - const wrapper = shallow(); + const wrapper = shallow( + + + + ); expect(wrapper).toMatchSnapshot(); }); diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/create_transform_button/create_transform_button.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/create_transform_button/create_transform_button.tsx index 14697f9af4080..3340dc10a0d02 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/create_transform_button/create_transform_button.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/create_transform_button/create_transform_button.tsx @@ -5,16 +5,14 @@ * 2.0. */ -import React, { useContext, FC, MouseEventHandler } from 'react'; +import React, { type FC, type MouseEventHandler } from 'react'; import { EuiButton, EuiToolTip } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; -import { - createCapabilityFailureMessage, - AuthorizationContext, -} from '../../../../lib/authorization'; +import { createCapabilityFailureMessage } from '../../../../lib/authorization'; +import { useAuthorization } from '../../../../hooks'; interface CreateTransformButtonProps { onClick: MouseEventHandler; @@ -25,7 +23,7 @@ export const CreateTransformButton: FC = ({ onClick, transformNodes, }) => { - const { capabilities } = useContext(AuthorizationContext); + const { capabilities } = useAuthorization(); const disabled = !capabilities.canCreateTransform || diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/edit_transform_flyout/edit_transform_flyout_callout.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/edit_transform_flyout/edit_transform_flyout_callout.tsx index 75f333960fa54..cdaabb3a3b200 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/edit_transform_flyout/edit_transform_flyout_callout.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/edit_transform_flyout/edit_transform_flyout_callout.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { FC } from 'react'; +import React, { type FC } from 'react'; import { i18n } from '@kbn/i18n'; diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/edit_transform_flyout/edit_transform_flyout_form_text_input.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/edit_transform_flyout/edit_transform_flyout_form_text_input.tsx index a337d73ca54b3..d9310762ef3e0 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/edit_transform_flyout/edit_transform_flyout_form_text_input.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/edit_transform_flyout/edit_transform_flyout_form_text_input.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { FC } from 'react'; +import React, { type FC } from 'react'; import { EuiFieldText, EuiFormRow } from '@elastic/eui'; diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/refresh_transform_list_button/refresh_transform_list_button.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/refresh_transform_list_button/refresh_transform_list_button.tsx index d0ea13ec11df1..efd4fb1d500af 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/refresh_transform_list_button/refresh_transform_list_button.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/refresh_transform_list_button/refresh_transform_list_button.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { FC } from 'react'; +import React, { type FC } from 'react'; import { EuiButton } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/search_selection/search_selection.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/search_selection/search_selection.tsx index 5647060ee7a72..3f2bd7fb70c0c 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/search_selection/search_selection.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/search_selection/search_selection.tsx @@ -8,7 +8,8 @@ import { EuiModalBody, EuiModalHeader, EuiModalHeaderTitle } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; -import React, { FC } from 'react'; +import React, { type FC } from 'react'; + import { SavedObjectFinder } from '@kbn/saved-objects-finder-plugin/public'; import { useAppDependencies } from '../../../../app_dependencies'; diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/stats_bar/stat.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/stats_bar/stat.tsx index 810d60f3b8fd7..cfd0d112ba90b 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/stats_bar/stat.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/stats_bar/stat.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { FC } from 'react'; +import React, { type FC } from 'react'; export interface StatsBarStat { label: string; diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/stats_bar/stats_bar.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/stats_bar/stats_bar.tsx index 21674ae24301c..849c651b37ea0 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/stats_bar/stats_bar.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/stats_bar/stats_bar.tsx @@ -5,7 +5,8 @@ * 2.0. */ -import React, { FC } from 'react'; +import React, { type FC } from 'react'; + import { Stat, StatsBarStat } from './stat'; interface Stats { diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row_json_pane.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row_json_pane.tsx index c68a57ea12109..48e17d9157226 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row_json_pane.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row_json_pane.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { FC } from 'react'; +import React, { type FC } from 'react'; import { EuiCodeBlock, EuiFlexGroup, EuiFlexItem, EuiSpacer } from '@elastic/eui'; diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_list.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_list.tsx index f008cf33ce638..c48d6f1affe69 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_list.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_list.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { type MouseEventHandler, type FC, useContext, useState } from 'react'; +import React, { type MouseEventHandler, type FC, useState } from 'react'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; @@ -39,7 +39,7 @@ import { type TransformListRow, TRANSFORM_LIST_COLUMN, } from '../../../../common'; -import { AuthorizationContext } from '../../../../lib/authorization'; +import { useAuthorization } from '../../../../hooks'; import { CreateTransformButton } from '../create_transform_button'; import { RefreshTransformListButton } from '../refresh_transform_list_button'; @@ -147,7 +147,7 @@ export const TransformList: FC = ({ const bulkStopAction = useStopAction(false); const bulkScheduleNowAction = useScheduleNowAction(false, transformNodes); - const { capabilities } = useContext(AuthorizationContext); + const { capabilities } = useAuthorization(); const disabled = !capabilities.canCreateTransform || !capabilities.canPreviewTransform || diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transforms_stats_bar.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transforms_stats_bar.tsx index 8ad53c64c2f1e..554b82c1fd3fe 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transforms_stats_bar.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transforms_stats_bar.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { FC } from 'react'; +import React, { type FC } from 'react'; import { EuiCallOut, EuiLink, EuiSpacer } from '@elastic/eui'; diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/use_columns.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/use_columns.tsx index db77b3e306da2..7c743da1e7f3d 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/use_columns.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/use_columns.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { useContext } from 'react'; +import React from 'react'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; import { @@ -24,7 +24,7 @@ import { EuiIcon, } from '@elastic/eui'; -import { AuthorizationContext } from '../../../../lib/authorization'; +import { useAuthorization } from '../../../../hooks'; import { needsReauthorization } from '../../../../common/reauthorization_utils'; import { isLatestTransform, @@ -52,7 +52,7 @@ export const useColumns = ( transformNodes: number, transformSelection: TransformListRow[] ) => { - const { canStartStopTransform } = useContext(AuthorizationContext).capabilities; + const { canStartStopTransform } = useAuthorization().capabilities; const { actions, modals } = useActions({ forceDisable: transformSelection.length > 0, diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/transform_management_section.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/transform_management_section.tsx index 12e85a9232b84..f5e37fbe24b2c 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/transform_management_section.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/transform_management_section.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { FC, useContext, useEffect, useMemo, useState } from 'react'; +import React, { FC, useEffect, useMemo, useState } from 'react'; import { FormattedMessage } from '@kbn/i18n-react'; @@ -27,9 +27,9 @@ import { } from '../../../../common/constants'; import { useDocumentationLinks } from '../../hooks'; -import { useDeleteTransforms, useGetTransforms } from '../../hooks'; +import { useDeleteTransforms, useAuthorization, useGetTransforms } from '../../hooks'; import { RedirectToCreateTransform } from '../../common/navigation'; -import { AuthorizationContext, PrivilegesWrapper } from '../../lib/authorization'; +import { PrivilegesWrapper } from '../../lib/authorization'; import { breadcrumbService, docTitleService, BREADCRUMB_SECTION } from '../../services/navigation'; import { SearchSelection } from './components/search_selection'; @@ -57,7 +57,7 @@ export const TransformManagement: FC = () => { const transformNodes = data?.transformNodes ?? 0; const transformIdsWithoutConfig = data?.transformIdsWithoutConfig; - const { canStartStopTransform } = useContext(AuthorizationContext).capabilities; + const { canStartStopTransform } = useAuthorization().capabilities; const unauthorizedTransformsWarning = useMemo(() => { const unauthorizedCnt = transforms.filter((t) => needsReauthorization(t)).length; From 27233be6ba77a6462c4cb90278e1d46a66f98da1 Mon Sep 17 00:00:00 2001 From: Walter Rafelsberger Date: Thu, 24 Aug 2023 10:58:30 +0200 Subject: [PATCH 24/53] fix react-query caching --- x-pack/plugins/transform/common/constants.ts | 1 + x-pack/plugins/transform/public/app/app.tsx | 15 ++++++++++++++- .../public/app/hooks/use_authorization.ts | 16 ++++++++++------ 3 files changed, 25 insertions(+), 7 deletions(-) diff --git a/x-pack/plugins/transform/common/constants.ts b/x-pack/plugins/transform/common/constants.ts index 1bf6a81167124..04cf9c86c08dc 100644 --- a/x-pack/plugins/transform/common/constants.ts +++ b/x-pack/plugins/transform/common/constants.ts @@ -10,6 +10,7 @@ import { i18n } from '@kbn/i18n'; import { LicenseType } from '@kbn/licensing-plugin/common/types'; import { TransformHealthTests } from './types/alerting'; +export const REACT_QUERY_STALE_TIME = 10000; export const DEFAULT_REFRESH_INTERVAL_MS = 30000; export const MINIMUM_REFRESH_INTERVAL_MS = 1000; export const PROGRESS_REFRESH_INTERVAL_MS = 2000; diff --git a/x-pack/plugins/transform/public/app/app.tsx b/x-pack/plugins/transform/public/app/app.tsx index 3321a9483c910..1dc2190b0ebb6 100644 --- a/x-pack/plugins/transform/public/app/app.tsx +++ b/x-pack/plugins/transform/public/app/app.tsx @@ -16,6 +16,8 @@ import { ScopedHistory } from '@kbn/core/public'; import { FormattedMessage } from '@kbn/i18n-react'; import { KibanaContextProvider, KibanaThemeProvider } from '@kbn/kibana-react-plugin/public'; +import { REACT_QUERY_STALE_TIME } from '../../common/constants'; + import { SectionError } from './components'; import { SECTION_SLUG } from './common/constants'; import { AppDependencies } from './app_dependencies'; @@ -59,7 +61,18 @@ export const App: FC<{ history: ScopedHistory }> = ({ history }) => { export const renderApp = (element: HTMLElement, appDependencies: AppDependencies) => { const I18nContext = appDependencies.i18n.Context; - const queryClient = new QueryClient(); + + const queryClient = new QueryClient({ + defaultOptions: { + queries: { + // This combo of options makes sure that we cache actual queries for + // the specified stale time, but treat provided default values as + // outdated immediately to trigger an initial fetch. + initialDataUpdatedAt: 0, + staleTime: REACT_QUERY_STALE_TIME, + }, + }, + }); render( diff --git a/x-pack/plugins/transform/public/app/hooks/use_authorization.ts b/x-pack/plugins/transform/public/app/hooks/use_authorization.ts index 7fbc6cfe0ad8e..24d169c50b736 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_authorization.ts +++ b/x-pack/plugins/transform/public/app/hooks/use_authorization.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { useMemo } from 'react'; import { useQuery } from '@tanstack/react-query'; import type { IHttpFetchError } from '@kbn/core-http-browser'; @@ -54,10 +55,13 @@ export const useAuthorization = (): Authorization => { { initialData } ); - return { - isLoading, - privileges: privilegesData.privileges, - capabilities: privilegesData.capabilities, - error, - }; + return useMemo( + () => ({ + isLoading, + privileges: privilegesData.privileges, + capabilities: privilegesData.capabilities, + error, + }), + [isLoading, privilegesData.privileges, privilegesData.capabilities, error] + ); }; From 6a00eef25daa2c8295f2afb14065e017e0943021 Mon Sep 17 00:00:00 2001 From: Walter Rafelsberger Date: Thu, 24 Aug 2023 11:13:08 +0200 Subject: [PATCH 25/53] cleanup --- x-pack/plugins/transform/common/constants.ts | 1 - .../public/app/hooks/use_can_delete_index.ts | 33 ------------------- .../public/app/hooks/use_delete_transform.tsx | 6 ++-- 3 files changed, 3 insertions(+), 37 deletions(-) delete mode 100644 x-pack/plugins/transform/public/app/hooks/use_can_delete_index.ts diff --git a/x-pack/plugins/transform/common/constants.ts b/x-pack/plugins/transform/common/constants.ts index 04cf9c86c08dc..74bed69c8facc 100644 --- a/x-pack/plugins/transform/common/constants.ts +++ b/x-pack/plugins/transform/common/constants.ts @@ -34,7 +34,6 @@ export const addInternalBasePath = (uri: string): string => `${INTERNAL_API_BASE export const addExternalBasePath = (uri: string): string => `${EXTERNAL_API_BASE_PATH}${uri}`; export const TRANSFORM_REACT_QUERY_KEYS = { - CAN_DELETE_INDEX: 'transform.can_delete_index', DATA_SEARCH: 'transform.data_search', DATA_VIEW_EXISTS: 'transform.data_view_exists', GET_DATA_VIEW_TITLES: 'transform.get_data_view_titles', diff --git a/x-pack/plugins/transform/public/app/hooks/use_can_delete_index.ts b/x-pack/plugins/transform/public/app/hooks/use_can_delete_index.ts deleted file mode 100644 index d198daa9ab26f..0000000000000 --- a/x-pack/plugins/transform/public/app/hooks/use_can_delete_index.ts +++ /dev/null @@ -1,33 +0,0 @@ -/* - * 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 { useQuery } from '@tanstack/react-query'; - -import type { IHttpFetchError } from '@kbn/core-http-browser'; - -import type { PrivilegesAndCapabilities } from '../../../common/privilege/has_privilege_factory'; -import { addInternalBasePath, TRANSFORM_REACT_QUERY_KEYS } from '../../../common/constants'; - -import { useAppDependencies } from '../app_dependencies'; - -export const useCanDeleteIndex = () => { - const { http } = useAppDependencies(); - - return useQuery( - [TRANSFORM_REACT_QUERY_KEYS.CAN_DELETE_INDEX], - async ({ signal }) => { - const resp = await http.get(addInternalBasePath('privileges'), { - version: '1', - signal, - }); - if (!resp) { - return false; - } - return resp.privileges.hasAllPrivileges; - } - ); -}; diff --git a/x-pack/plugins/transform/public/app/hooks/use_delete_transform.tsx b/x-pack/plugins/transform/public/app/hooks/use_delete_transform.tsx index 2d057c11c4a16..0201d94816d8f 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_delete_transform.tsx +++ b/x-pack/plugins/transform/public/app/hooks/use_delete_transform.tsx @@ -20,7 +20,7 @@ import type { import { getErrorMessage } from '../../../common/utils/errors'; import { useAppDependencies, useToastNotifications } from '../app_dependencies'; -import { useCanDeleteIndex } from './use_can_delete_index'; +import { useAuthorization } from './use_authorization'; import { useDataViewExists } from './use_data_view_exists'; import { useRefreshTransformList, type TransformListRow } from '../common'; import { ToastNotificationText } from '../components'; @@ -38,8 +38,8 @@ export const useDeleteIndexAndTargetIndex = (items: TransformListRow[]) => { const [deleteDestIndex, setDeleteDestIndex] = useState(true); const [deleteDataView, setDeleteDataView] = useState(userCanDeleteDataView); - const { error: canDeleteIndexError, data: canDeleteIndex } = useCanDeleteIndex(); - const userCanDeleteIndex = canDeleteIndex === true; + const { error: canDeleteIndexError, privileges } = useAuthorization(); + const userCanDeleteIndex = privileges.hasAllPrivileges; useEffect(() => { if (canDeleteIndexError !== null) { From 4802a9af538898351dfd6a270ce3dd849f4d1a4e Mon Sep 17 00:00:00 2001 From: Walter Rafelsberger Date: Thu, 24 Aug 2023 11:29:44 +0200 Subject: [PATCH 26/53] fix authorization hooks --- .../transform/public/app/common/transform.ts | 5 +- .../public/app/hooks/use_authorization.ts | 46 ++++++------------- 2 files changed, 15 insertions(+), 36 deletions(-) diff --git a/x-pack/plugins/transform/public/app/common/transform.ts b/x-pack/plugins/transform/public/app/common/transform.ts index 6339917a41db3..ca60600fc40bf 100644 --- a/x-pack/plugins/transform/public/app/common/transform.ts +++ b/x-pack/plugins/transform/public/app/common/transform.ts @@ -6,7 +6,6 @@ */ import { cloneDeep } from 'lodash'; -import { useCallback } from 'react'; import { useQueryClient } from '@tanstack/react-query'; import type { TransformConfigUnion, TransformId } from '../../../common/types/transform'; @@ -27,10 +26,10 @@ export const TRANSFORM_ERROR_TYPE = { export const useRefreshTransformList = () => { const queryClient = useQueryClient(); - return useCallback(() => { + return () => { queryClient.invalidateQueries([TRANSFORM_REACT_QUERY_KEYS.GET_TRANSFORMS]); queryClient.invalidateQueries([TRANSFORM_REACT_QUERY_KEYS.GET_TRANSFORM_AUDIT_MESSAGES]); - }, [queryClient]); + }; }; export const overrideTransformForCloning = (originalConfig: TransformConfigUnion) => { diff --git a/x-pack/plugins/transform/public/app/hooks/use_authorization.ts b/x-pack/plugins/transform/public/app/hooks/use_authorization.ts index 24d169c50b736..faa07e6bf428e 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_authorization.ts +++ b/x-pack/plugins/transform/public/app/hooks/use_authorization.ts @@ -11,40 +11,17 @@ import { useQuery } from '@tanstack/react-query'; import type { IHttpFetchError } from '@kbn/core-http-browser'; import { addInternalBasePath, TRANSFORM_REACT_QUERY_KEYS } from '../../../common/constants'; -import type { Privileges } from '../../../common/types/privileges'; import { type PrivilegesAndCapabilities, - type TransformCapabilities, INITIAL_CAPABILITIES, } from '../../../common/privilege/has_privilege_factory'; import { useAppDependencies } from '../app_dependencies'; -interface Authorization { - isLoading: boolean; - error: Error | null; - privileges: Privileges; - capabilities: TransformCapabilities; -} - -const initialData: Authorization = { - isLoading: true, - error: null, - privileges: { - hasAllPrivileges: false, - missingPrivileges: {}, - }, - capabilities: INITIAL_CAPABILITIES, -}; - -export const useAuthorization = (): Authorization => { +export const useAuthorization = () => { const { http } = useAppDependencies(); - const { - isLoading, - error, - data: privilegesData, - } = useQuery( + const { error, isLoading, data } = useQuery( [TRANSFORM_REACT_QUERY_KEYS.GET_PRIVILEGES], ({ signal }) => http.fetch(addInternalBasePath(`privileges`), { @@ -52,16 +29,19 @@ export const useAuthorization = (): Authorization => { method: 'GET', signal, }), - { initialData } + { + initialData: { + privileges: { + hasAllPrivileges: false, + missingPrivileges: {}, + }, + capabilities: INITIAL_CAPABILITIES, + }, + } ); return useMemo( - () => ({ - isLoading, - privileges: privilegesData.privileges, - capabilities: privilegesData.capabilities, - error, - }), - [isLoading, privilegesData.privileges, privilegesData.capabilities, error] + () => ({ error, isLoading, capabilities: data.capabilities, privileges: data.privileges }), + [error, isLoading, data.capabilities, data.privileges] ); }; From 9acea75847c5ad955b8f84b3d16715e8d7f5d710 Mon Sep 17 00:00:00 2001 From: Walter Rafelsberger Date: Thu, 24 Aug 2023 11:43:41 +0200 Subject: [PATCH 27/53] cleanup --- .../public/app/hooks/use_get_transform_audit_messages.ts | 3 ++- .../components/step_create/step_create_form.tsx | 8 ++------ .../transform_list/expanded_row_messages_pane.tsx | 5 ++--- 3 files changed, 6 insertions(+), 10 deletions(-) diff --git a/x-pack/plugins/transform/public/app/hooks/use_get_transform_audit_messages.ts b/x-pack/plugins/transform/public/app/hooks/use_get_transform_audit_messages.ts index 3f7559a251275..07f8034f2ecf0 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_get_transform_audit_messages.ts +++ b/x-pack/plugins/transform/public/app/hooks/use_get_transform_audit_messages.ts @@ -34,6 +34,7 @@ export const useGetTransformAuditMessages = ( version: '1', signal, } - ) + ), + { initialData: { messages: [], total: 0 } } ); }; diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_create/step_create_form.tsx b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_create/step_create_form.tsx index ff3ae39844289..f49d9ea60e2ed 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_create/step_create_form.tsx +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_create/step_create_form.tsx @@ -130,9 +130,7 @@ export const StepCreateForm: FC = React.memo( setLoading(true); createTransform(undefined, { - onError: () => { - setCreated(false); - }, + onError: () => setCreated(false), onSuccess: () => { setCreated(true); if (createDataView) { @@ -142,9 +140,7 @@ export const StepCreateForm: FC = React.memo( startTransform(); } }, - onSettled: () => { - setLoading(false); - }, + onSettled: () => setLoading(false), }); } diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row_messages_pane.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row_messages_pane.tsx index fb435679d2185..69e7f5462764f 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row_messages_pane.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row_messages_pane.tsx @@ -50,8 +50,7 @@ export const ExpandedRowMessagesPane: FC = ({ tran sorting.sort.field, sorting.sort.direction ); - const messages = data?.messages ?? []; - const msgCount = data?.total ?? 0; + const { messages, total } = data; const errorMessage = error !== null ? i18n.translate('xpack.transform.transformList.transformDetails.messagesPane.errorMessage', { @@ -122,7 +121,7 @@ export const ExpandedRowMessagesPane: FC = ({ tran const getPageOfMessages = ({ index, size }: { index: number; size: number }) => { let list = messages; - if (msgCount <= DEFAULT_MAX_AUDIT_MESSAGE_SIZE) { + if (total <= DEFAULT_MAX_AUDIT_MESSAGE_SIZE) { const sortField = sorting.sort.field ?? 'timestamp'; list = messages.sort((a: TransformMessage, b: TransformMessage) => { const prev = a[sortField] as any; From c135c9589b2f90c8ab1fcc291535496f7246c0fe Mon Sep 17 00:00:00 2001 From: Walter Rafelsberger Date: Thu, 24 Aug 2023 12:05:42 +0200 Subject: [PATCH 28/53] cleanup --- .../transform_health_rule_trigger.tsx | 2 +- .../public/app/hooks/use_get_transforms.ts | 18 ++++++++++++------ .../step_details/step_details_form.tsx | 6 ++++-- .../transform_management_section.tsx | 10 +++------- 4 files changed, 20 insertions(+), 16 deletions(-) diff --git a/x-pack/plugins/transform/public/alerting/transform_health_rule_type/transform_health_rule_trigger.tsx b/x-pack/plugins/transform/public/alerting/transform_health_rule_type/transform_health_rule_trigger.tsx index f691c6a986020..49b8ee1a684fb 100644 --- a/x-pack/plugins/transform/public/alerting/transform_health_rule_type/transform_health_rule_trigger.tsx +++ b/x-pack/plugins/transform/public/alerting/transform_health_rule_type/transform_health_rule_trigger.tsx @@ -31,7 +31,7 @@ const TransformHealthRuleTrigger: FC = ({ const toast = useToastNotifications(); const { error, data } = useGetTransforms(); const transformOptions = useMemo( - () => data?.tableRows.filter((v) => v.config.sync).map((v) => v.id) ?? [], + () => data?.transforms.filter((v) => v.config.sync).map((v) => v.id) ?? [], [data] ); diff --git a/x-pack/plugins/transform/public/app/hooks/use_get_transforms.ts b/x-pack/plugins/transform/public/app/hooks/use_get_transforms.ts index 04a0d09219095..fb8582cd78c28 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_get_transforms.ts +++ b/x-pack/plugins/transform/public/app/hooks/use_get_transforms.ts @@ -28,21 +28,25 @@ import { useAppDependencies } from '../app_dependencies'; import { TRANSFORM_ERROR_TYPE } from '../common/transform'; interface UseGetTransformsResponse { - tableRows: TransformListRow[]; + transforms: TransformListRow[]; + transformIds: string[]; transformIdsWithoutConfig?: string[]; transformNodes: number; } +const getInitialData = (): UseGetTransformsResponse => ({ + transforms: [], + transformIds: [], + transformNodes: 0, +}); + export const useGetTransforms = () => { const { http } = useAppDependencies(); return useQuery( [TRANSFORM_REACT_QUERY_KEYS.GET_TRANSFORMS], async ({ signal }) => { - const update: UseGetTransformsResponse = { - tableRows: [], - transformNodes: 0, - }; + const update = getInitialData(); const transformNodes = await http.get( addInternalBasePath('transforms/_nodes'), @@ -87,7 +91,7 @@ export const useGetTransforms = () => { danglingTaskIdMatches.length > 0 ? danglingTaskIdMatches : undefined; } - update.tableRows = transformConfigs.transforms.reduce((reducedtableRows, config) => { + update.transforms = transformConfigs.transforms.reduce((reducedtableRows, config) => { const stats = transformStats.transforms.find((d) => config.id === d.id); // A newly created transform might not have corresponding stats yet. @@ -107,10 +111,12 @@ export const useGetTransforms = () => { }); return reducedtableRows; }, [] as TransformListRow[]); + update.transformIds = update.transforms.map(({ id }) => id); return update; }, { + initialData: getInitialData(), refetchInterval: DEFAULT_REFRESH_INTERVAL_MS, } ); diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_details/step_details_form.tsx b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_details/step_details_form.tsx index 9fda641d16f65..41cf150f47bc6 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_details/step_details_form.tsx +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_details/step_details_form.tsx @@ -123,8 +123,10 @@ export const StepDetailsForm: FC = React.memo( const { overlays, theme } = useAppDependencies(); - const { error: transformsError, data: transforms } = useGetTransforms(); - const transformIds = transforms?.tableRows.map((d) => d.id) ?? []; + const { + error: transformsError, + data: { transformIds }, + } = useGetTransforms(); useEffect(() => { if (transformsError !== null) { diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/transform_management_section.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/transform_management_section.tsx index f5e37fbe24b2c..c4b2ffa2b0a9e 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/transform_management_section.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/transform_management_section.tsx @@ -50,12 +50,8 @@ export const TransformManagement: FC = () => { isInitialLoading, isLoading: transformsLoading, error: errorMessage, - data, + data: { transforms, transformNodes, transformIdsWithoutConfig }, } = useGetTransforms(); - const isInitialized = !isInitialLoading; - const transforms = useMemo(() => data?.tableRows ?? [], [data]); - const transformNodes = data?.transformNodes ?? 0; - const transformIdsWithoutConfig = data?.transformIdsWithoutConfig; const { canStartStopTransform } = useAuthorization().capabilities; @@ -151,8 +147,8 @@ export const TransformManagement: FC = () => { - {!isInitialized && } - {isInitialized && ( + {isInitialLoading && } + {!isInitialLoading && ( <> {unauthorizedTransformsWarning} From 70a8d63ca4b86bb2d50eb0a397b1bdb134dfe9a5 Mon Sep 17 00:00:00 2001 From: Walter Rafelsberger Date: Thu, 24 Aug 2023 12:11:59 +0200 Subject: [PATCH 29/53] return mutate only instead of whole mutation from custom hooks --- .../transform/public/app/hooks/use_create_transform.tsx | 2 +- .../transform/public/app/hooks/use_delete_transform.tsx | 2 +- .../transform/public/app/hooks/use_reauthorize_transform.tsx | 2 +- .../transform/public/app/hooks/use_reset_transform.tsx | 2 +- .../public/app/hooks/use_schedule_now_transform.tsx | 2 +- .../transform/public/app/hooks/use_start_transform.tsx | 2 +- .../transform/public/app/hooks/use_stop_transform.tsx | 2 +- .../transform/public/app/hooks/use_update_transform.ts | 2 +- .../components/step_create/step_create_form.tsx | 4 ++-- .../components/action_delete/use_delete_action.tsx | 2 +- .../components/action_reauthorize/use_reauthorize_action.tsx | 2 +- .../components/action_reset/use_reset_action.tsx | 2 +- .../action_schedule_now/use_schedule_now_action.tsx | 3 +-- .../components/action_start/use_start_action.tsx | 2 +- .../components/action_stop/use_stop_action.tsx | 5 +---- .../edit_transform_flyout/edit_transform_update_button.tsx | 2 +- .../transform_management/transform_management_section.tsx | 2 +- 17 files changed, 18 insertions(+), 22 deletions(-) diff --git a/x-pack/plugins/transform/public/app/hooks/use_create_transform.tsx b/x-pack/plugins/transform/public/app/hooks/use_create_transform.tsx index 0b01bc95c8fe8..06d90a50d04f0 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_create_transform.tsx +++ b/x-pack/plugins/transform/public/app/hooks/use_create_transform.tsx @@ -60,5 +60,5 @@ export const useCreateTransform = ( }, }); - return mutation; + return mutation.mutate; }; diff --git a/x-pack/plugins/transform/public/app/hooks/use_delete_transform.tsx b/x-pack/plugins/transform/public/app/hooks/use_delete_transform.tsx index 0201d94816d8f..e473ccb0be6ea 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_delete_transform.tsx +++ b/x-pack/plugins/transform/public/app/hooks/use_delete_transform.tsx @@ -211,5 +211,5 @@ export const useDeleteTransforms = () => { }, }); - return mutation; + return mutation.mutate; }; diff --git a/x-pack/plugins/transform/public/app/hooks/use_reauthorize_transform.tsx b/x-pack/plugins/transform/public/app/hooks/use_reauthorize_transform.tsx index 7eae534d6f0eb..8de8318df5794 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_reauthorize_transform.tsx +++ b/x-pack/plugins/transform/public/app/hooks/use_reauthorize_transform.tsx @@ -77,5 +77,5 @@ export const useReauthorizeTransforms = () => { }, }); - return mutation; + return mutation.mutate; }; diff --git a/x-pack/plugins/transform/public/app/hooks/use_reset_transform.tsx b/x-pack/plugins/transform/public/app/hooks/use_reset_transform.tsx index f470a2e0f3698..6bfde68a99ba1 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_reset_transform.tsx +++ b/x-pack/plugins/transform/public/app/hooks/use_reset_transform.tsx @@ -78,5 +78,5 @@ export const useResetTransforms = () => { }, }); - return mutation; + return mutation.mutate; }; diff --git a/x-pack/plugins/transform/public/app/hooks/use_schedule_now_transform.tsx b/x-pack/plugins/transform/public/app/hooks/use_schedule_now_transform.tsx index 6ffc2bf6308d3..ff75f34fcc716 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_schedule_now_transform.tsx +++ b/x-pack/plugins/transform/public/app/hooks/use_schedule_now_transform.tsx @@ -78,5 +78,5 @@ export const useScheduleNowTransforms = () => { }, }); - return mutation; + return mutation.mutate; }; diff --git a/x-pack/plugins/transform/public/app/hooks/use_start_transform.tsx b/x-pack/plugins/transform/public/app/hooks/use_start_transform.tsx index 63e62276e0d76..1413aa278edfd 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_start_transform.tsx +++ b/x-pack/plugins/transform/public/app/hooks/use_start_transform.tsx @@ -70,5 +70,5 @@ export const useStartTransforms = () => { }, }); - return mutation; + return mutation.mutate; }; diff --git a/x-pack/plugins/transform/public/app/hooks/use_stop_transform.tsx b/x-pack/plugins/transform/public/app/hooks/use_stop_transform.tsx index 506f8c04bf8a4..b2c4826cae292 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_stop_transform.tsx +++ b/x-pack/plugins/transform/public/app/hooks/use_stop_transform.tsx @@ -66,5 +66,5 @@ export const useStopTransforms = () => { }, }); - return mutation; + return mutation.mutate; }; diff --git a/x-pack/plugins/transform/public/app/hooks/use_update_transform.ts b/x-pack/plugins/transform/public/app/hooks/use_update_transform.ts index 1c1469ab1a5ba..144a930c7e5d0 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_update_transform.ts +++ b/x-pack/plugins/transform/public/app/hooks/use_update_transform.ts @@ -36,5 +36,5 @@ export const useUpdateTransform = ( onSuccess: () => refreshTransformList(), }); - return mutation; + return mutation.mutate; }; diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_create/step_create_form.tsx b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_create/step_create_form.tsx index f49d9ea60e2ed..2b0487beb8b2d 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_create/step_create_form.tsx +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_create/step_create_form.tsx @@ -123,8 +123,8 @@ export const StepCreateForm: FC = React.memo( }, [created, started, dataViewId]); const { overlays, theme } = useAppDependencies(); - const { mutate: startTransforms } = useStartTransforms(); - const { mutate: createTransform } = useCreateTransform(transformId, transformConfig); + const startTransforms = useStartTransforms(); + const createTransform = useCreateTransform(transformId, transformConfig); function createTransformHandler(startAfterCreation = false) { setLoading(true); diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_delete/use_delete_action.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_delete/use_delete_action.tsx index ddae1b1578d34..520428ca52a57 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_delete/use_delete_action.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_delete/use_delete_action.tsx @@ -26,7 +26,7 @@ export type DeleteAction = ReturnType; export const useDeleteAction = (forceDisable: boolean) => { const { canDeleteTransform } = useAuthorization().capabilities; - const { mutate: deleteTransforms } = useDeleteTransforms(); + const deleteTransforms = useDeleteTransforms(); const [isModalVisible, setModalVisible] = useState(false); const [items, setItems] = useState([]); diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_reauthorize/use_reauthorize_action.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_reauthorize/use_reauthorize_action.tsx index f42aaf5a0c6aa..fcfc0da7564bd 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_reauthorize/use_reauthorize_action.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_reauthorize/use_reauthorize_action.tsx @@ -23,7 +23,7 @@ export type ReauthorizeAction = ReturnType; export const useReauthorizeAction = (forceDisable: boolean, transformNodes: number) => { const { canStartStopTransform } = useAuthorization().capabilities; - const { mutate: reauthorizeTransforms } = useReauthorizeTransforms(); + const reauthorizeTransforms = useReauthorizeTransforms(); const [isModalVisible, setModalVisible] = useState(false); const [items, setItems] = useState([]); diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_reset/use_reset_action.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_reset/use_reset_action.tsx index e5f2ea62b984d..a1f10bb801cdf 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_reset/use_reset_action.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_reset/use_reset_action.tsx @@ -18,7 +18,7 @@ export type ResetAction = ReturnType; export const useResetAction = (forceDisable: boolean) => { const { canResetTransform } = useAuthorization().capabilities; - const { mutate: resetTransforms } = useResetTransforms(); + const resetTransforms = useResetTransforms(); const [isModalVisible, setModalVisible] = useState(false); const [items, setItems] = useState([]); diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_schedule_now/use_schedule_now_action.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_schedule_now/use_schedule_now_action.tsx index 8f5fb462bb28d..858cadc246f5e 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_schedule_now/use_schedule_now_action.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_schedule_now/use_schedule_now_action.tsx @@ -22,8 +22,7 @@ import { export type ScheduleNowAction = ReturnType; export const useScheduleNowAction = (forceDisable: boolean, transformNodes: number) => { const { canScheduleNowTransform } = useAuthorization().capabilities; - - const { mutate: scheduleNowTransforms } = useScheduleNowTransforms(); + const scheduleNowTransforms = useScheduleNowTransforms(); const action: TransformListAction = useMemo( () => ({ diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_start/use_start_action.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_start/use_start_action.tsx index bbb08854a8cff..31b5a555cd333 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_start/use_start_action.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_start/use_start_action.tsx @@ -18,7 +18,7 @@ export type StartAction = ReturnType; export const useStartAction = (forceDisable: boolean, transformNodes: number) => { const { canStartStopTransform } = useAuthorization().capabilities; - const { mutate: startTransforms } = useStartTransforms(); + const startTransforms = useStartTransforms(); const [isModalVisible, setModalVisible] = useState(false); const [items, setItems] = useState([]); diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_stop/use_stop_action.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_stop/use_stop_action.tsx index b3a4a4b4e909a..8d7d4251a4802 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_stop/use_stop_action.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_stop/use_stop_action.tsx @@ -16,20 +16,17 @@ export type StopAction = ReturnType; export const useStopAction = (forceDisable: boolean) => { const { canStartStopTransform } = useAuthorization().capabilities; - - const { mutate: stopTransforms } = useStopTransforms(); + const stopTransforms = useStopTransforms(); const [isModalVisible, setModalVisible] = useState(false); const [items, setItems] = useState([]); const closeModal = () => setModalVisible(false); - const openModal = (newItems: TransformListRow[]) => { if (Array.isArray(newItems)) { setItems(newItems); setModalVisible(true); } }; - const stopAndCloseModal = useCallback( (transformSelection: TransformListRow[]) => { setModalVisible(false); diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/edit_transform_flyout/edit_transform_update_button.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/edit_transform_flyout/edit_transform_update_button.tsx index 3279b761a954b..b55b6f90a0aa3 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/edit_transform_flyout/edit_transform_update_button.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/edit_transform_flyout/edit_transform_update_button.tsx @@ -27,7 +27,7 @@ export const EditTransformUpdateButton: FC = ({ const config = useEditTransformFlyout('config'); const { apiError } = useEditTransformFlyout('actions'); - const { mutate: updateTransfrom } = useUpdateTransform(config.id, requestConfig); + const updateTransfrom = useUpdateTransform(config.id, requestConfig); async function submitFormHandler() { apiError(undefined); diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/transform_management_section.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/transform_management_section.tsx index c4b2ffa2b0a9e..39dbc8b0f10f5 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/transform_management_section.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/transform_management_section.tsx @@ -44,7 +44,7 @@ import { export const TransformManagement: FC = () => { const { esTransform } = useDocumentationLinks(); - const { mutate: deleteTransforms } = useDeleteTransforms(); + const deleteTransforms = useDeleteTransforms(); const { isInitialLoading, From 61b300a73f58ea374adee361149ec010e0197527 Mon Sep 17 00:00:00 2001 From: Walter Rafelsberger Date: Thu, 24 Aug 2023 12:47:48 +0200 Subject: [PATCH 30/53] cleanup --- x-pack/plugins/transform/public/app/app.tsx | 4 ---- .../public/app/hooks/use_authorization.ts | 23 ++++++++++--------- .../public/app/hooks/use_data_view_exists.ts | 14 +++++++---- .../public/app/hooks/use_delete_transform.tsx | 22 ++++++------------ .../hooks/use_get_transform_audit_messages.ts | 3 +-- .../public/app/hooks/use_get_transforms.ts | 5 ++-- .../expanded_row_messages_pane.tsx | 10 ++++---- 7 files changed, 38 insertions(+), 43 deletions(-) diff --git a/x-pack/plugins/transform/public/app/app.tsx b/x-pack/plugins/transform/public/app/app.tsx index 1dc2190b0ebb6..689026689192e 100644 --- a/x-pack/plugins/transform/public/app/app.tsx +++ b/x-pack/plugins/transform/public/app/app.tsx @@ -65,10 +65,6 @@ export const renderApp = (element: HTMLElement, appDependencies: AppDependencies const queryClient = new QueryClient({ defaultOptions: { queries: { - // This combo of options makes sure that we cache actual queries for - // the specified stale time, but treat provided default values as - // outdated immediately to trigger an initial fetch. - initialDataUpdatedAt: 0, staleTime: REACT_QUERY_STALE_TIME, }, }, diff --git a/x-pack/plugins/transform/public/app/hooks/use_authorization.ts b/x-pack/plugins/transform/public/app/hooks/use_authorization.ts index faa07e6bf428e..bbb1bae7142bf 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_authorization.ts +++ b/x-pack/plugins/transform/public/app/hooks/use_authorization.ts @@ -21,23 +21,24 @@ import { useAppDependencies } from '../app_dependencies'; export const useAuthorization = () => { const { http } = useAppDependencies(); - const { error, isLoading, data } = useQuery( + const { + error, + isLoading, + data = { + privileges: { + hasAllPrivileges: false, + missingPrivileges: {}, + }, + capabilities: INITIAL_CAPABILITIES, + }, + } = useQuery( [TRANSFORM_REACT_QUERY_KEYS.GET_PRIVILEGES], ({ signal }) => http.fetch(addInternalBasePath(`privileges`), { version: '1', method: 'GET', signal, - }), - { - initialData: { - privileges: { - hasAllPrivileges: false, - missingPrivileges: {}, - }, - capabilities: INITIAL_CAPABILITIES, - }, - } + }) ); return useMemo( diff --git a/x-pack/plugins/transform/public/app/hooks/use_data_view_exists.ts b/x-pack/plugins/transform/public/app/hooks/use_data_view_exists.ts index 7f2a2b48af1c1..d74fa9c909a5d 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_data_view_exists.ts +++ b/x-pack/plugins/transform/public/app/hooks/use_data_view_exists.ts @@ -12,21 +12,27 @@ import type { ErrorType } from '@kbn/ml-error-utils'; import { TRANSFORM_REACT_QUERY_KEYS } from '../../../common/constants'; import { useAppDependencies } from '../app_dependencies'; +import type { TransformListRow } from '../common'; -export const useDataViewExists = (indexName?: string, enabled?: boolean, initialData?: boolean) => { +export const useDataViewExists = (items: TransformListRow[]) => { const { data: { dataViews: dataViewsContract }, } = useAppDependencies(); return useQuery( - [TRANSFORM_REACT_QUERY_KEYS.DATA_VIEW_EXISTS, indexName], + [TRANSFORM_REACT_QUERY_KEYS.DATA_VIEW_EXISTS, items], async () => { + if (items.length !== 1) { + return false; + } + const config = items[0].config; + const indexName = Array.isArray(config.dest.index) ? config.dest.index[0] : config.dest.index; + if (indexName === undefined) { return false; } return (await dataViewsContract.find(indexName)).some(({ title }) => title === indexName); - }, - { enabled, initialData } + } ); }; diff --git a/x-pack/plugins/transform/public/app/hooks/use_delete_transform.tsx b/x-pack/plugins/transform/public/app/hooks/use_delete_transform.tsx index e473ccb0be6ea..f5d3bbfa6e9f4 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_delete_transform.tsx +++ b/x-pack/plugins/transform/public/app/hooks/use_delete_transform.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { useCallback, useEffect, useMemo, useState } from 'react'; +import React, { useCallback, useEffect, useState } from 'react'; import { useMutation } from '@tanstack/react-query'; import { i18n } from '@kbn/i18n'; @@ -65,22 +65,14 @@ export const useDeleteIndexAndTargetIndex = (items: TransformListRow[]) => { [deleteDataView] ); - const indexName = useMemo(() => { - // if user only deleting one transform - if (items.length === 1) { - const config = items[0].config; - return Array.isArray(config.dest.index) ? config.dest.index[0] : config.dest.index; - } - }, [items]); - - const { error: dataViewExistsError, data: dataViewExists } = useDataViewExists( - indexName, - items.length === 1, - items.length !== 1 - ); + const { error: dataViewExistsError, data: dataViewExists = items.length !== 1 } = + useDataViewExists(items); useEffect(() => { - if (dataViewExistsError !== null) { + if (dataViewExistsError !== null && items.length === 1) { + const config = items[0].config; + const indexName = Array.isArray(config.dest.index) ? config.dest.index[0] : config.dest.index; + toastNotifications.addDanger( i18n.translate( 'xpack.transform.deleteTransform.errorWithCheckingIfDataViewExistsNotificationErrorMessage', diff --git a/x-pack/plugins/transform/public/app/hooks/use_get_transform_audit_messages.ts b/x-pack/plugins/transform/public/app/hooks/use_get_transform_audit_messages.ts index 07f8034f2ecf0..3f7559a251275 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_get_transform_audit_messages.ts +++ b/x-pack/plugins/transform/public/app/hooks/use_get_transform_audit_messages.ts @@ -34,7 +34,6 @@ export const useGetTransformAuditMessages = ( version: '1', signal, } - ), - { initialData: { messages: [], total: 0 } } + ) ); }; diff --git a/x-pack/plugins/transform/public/app/hooks/use_get_transforms.ts b/x-pack/plugins/transform/public/app/hooks/use_get_transforms.ts index fb8582cd78c28..d08fe50f679a3 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_get_transforms.ts +++ b/x-pack/plugins/transform/public/app/hooks/use_get_transforms.ts @@ -43,7 +43,7 @@ const getInitialData = (): UseGetTransformsResponse => ({ export const useGetTransforms = () => { const { http } = useAppDependencies(); - return useQuery( + const { data = getInitialData(), ...rest } = useQuery( [TRANSFORM_REACT_QUERY_KEYS.GET_TRANSFORMS], async ({ signal }) => { const update = getInitialData(); @@ -116,8 +116,9 @@ export const useGetTransforms = () => { return update; }, { - initialData: getInitialData(), refetchInterval: DEFAULT_REFRESH_INTERVAL_MS, } ); + + return { data, ...rest }; }; diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row_messages_pane.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row_messages_pane.tsx index 69e7f5462764f..3ed38727086d5 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row_messages_pane.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row_messages_pane.tsx @@ -45,11 +45,11 @@ export const ExpandedRowMessagesPane: FC = ({ tran }, }); - const { isLoading, error, data } = useGetTransformAuditMessages( - transformId, - sorting.sort.field, - sorting.sort.direction - ); + const { + isLoading, + error, + data = { messages: [], total: 0 }, + } = useGetTransformAuditMessages(transformId, sorting.sort.field, sorting.sort.direction); const { messages, total } = data; const errorMessage = error !== null From bfbb3dcff14bc05bf82657b2c65e9a6c7352ce57 Mon Sep 17 00:00:00 2001 From: Walter Rafelsberger Date: Thu, 24 Aug 2023 15:46:15 +0200 Subject: [PATCH 31/53] migrate enzyme-snapshots to react-testing-lib --- .../public/app/hooks/use_index_data.test.tsx | 1 - .../agg_label_form.test.tsx.snap | 72 ------ .../__snapshots__/list_form.test.tsx.snap | 28 --- .../__snapshots__/list_summary.test.tsx.snap | 18 -- .../__snapshots__/popover_form.test.tsx.snap | 48 ---- .../aggregation_list/agg_label_form.test.tsx | 6 +- .../aggregation_list/list_form.test.tsx | 6 +- .../aggregation_list/list_summary.test.tsx | 6 +- .../aggregation_list/popover_form.test.tsx | 6 +- .../group_by_label_form.test.tsx.snap | 234 ------------------ .../group_by_label_summary.test.tsx.snap | 77 ------ .../__snapshots__/list_form.test.tsx.snap | 28 --- .../__snapshots__/list_summary.test.tsx.snap | 24 -- .../__snapshots__/popover_form.test.tsx.snap | 18 -- .../group_by_label_form.test.tsx | 14 +- .../group_by_label_summary.test.tsx | 14 +- .../group_by_list/list_form.test.tsx | 6 +- .../group_by_list/list_summary.test.tsx | 6 +- .../group_by_list/popover_form.test.tsx | 7 +- ...transform_management_section.test.tsx.snap | 14 -- .../delete_action_name.test.tsx.snap | 7 - .../action_delete/delete_action_name.test.tsx | 6 +- .../start_action_name.test.tsx.snap | 134 ---------- .../action_start/start_action_name.test.tsx | 7 +- .../stop_action_name.test.tsx.snap | 133 ---------- .../action_stop/stop_action_name.test.tsx | 7 +- .../create_transform_button.test.tsx.snap | 63 ----- .../create_transform_button.test.tsx | 7 +- .../expanded_row_details_pane.test.tsx.snap | 66 ----- .../expanded_row_json_pane.test.tsx.snap | 66 ----- .../transform_list.test.tsx.snap | 67 ----- .../expanded_row_details_pane.test.tsx | 14 +- .../expanded_row_json_pane.test.tsx | 7 +- .../transform_list/transform_list.test.tsx | 64 +++-- .../transform_management_section.test.tsx | 14 +- 35 files changed, 119 insertions(+), 1176 deletions(-) delete mode 100644 x-pack/plugins/transform/public/app/sections/create_transform/components/aggregation_list/__snapshots__/agg_label_form.test.tsx.snap delete mode 100644 x-pack/plugins/transform/public/app/sections/create_transform/components/aggregation_list/__snapshots__/list_form.test.tsx.snap delete mode 100644 x-pack/plugins/transform/public/app/sections/create_transform/components/aggregation_list/__snapshots__/list_summary.test.tsx.snap delete mode 100644 x-pack/plugins/transform/public/app/sections/create_transform/components/aggregation_list/__snapshots__/popover_form.test.tsx.snap delete mode 100644 x-pack/plugins/transform/public/app/sections/create_transform/components/group_by_list/__snapshots__/group_by_label_form.test.tsx.snap delete mode 100644 x-pack/plugins/transform/public/app/sections/create_transform/components/group_by_list/__snapshots__/group_by_label_summary.test.tsx.snap delete mode 100644 x-pack/plugins/transform/public/app/sections/create_transform/components/group_by_list/__snapshots__/list_form.test.tsx.snap delete mode 100644 x-pack/plugins/transform/public/app/sections/create_transform/components/group_by_list/__snapshots__/list_summary.test.tsx.snap delete mode 100644 x-pack/plugins/transform/public/app/sections/create_transform/components/group_by_list/__snapshots__/popover_form.test.tsx.snap delete mode 100644 x-pack/plugins/transform/public/app/sections/transform_management/__snapshots__/transform_management_section.test.tsx.snap delete mode 100644 x-pack/plugins/transform/public/app/sections/transform_management/components/action_delete/__snapshots__/delete_action_name.test.tsx.snap delete mode 100644 x-pack/plugins/transform/public/app/sections/transform_management/components/action_start/__snapshots__/start_action_name.test.tsx.snap delete mode 100644 x-pack/plugins/transform/public/app/sections/transform_management/components/action_stop/__snapshots__/stop_action_name.test.tsx.snap delete mode 100644 x-pack/plugins/transform/public/app/sections/transform_management/components/create_transform_button/__snapshots__/create_transform_button.test.tsx.snap delete mode 100644 x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/__snapshots__/expanded_row_details_pane.test.tsx.snap delete mode 100644 x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/__snapshots__/expanded_row_json_pane.test.tsx.snap delete mode 100644 x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/__snapshots__/transform_list.test.tsx.snap diff --git a/x-pack/plugins/transform/public/app/hooks/use_index_data.test.tsx b/x-pack/plugins/transform/public/app/hooks/use_index_data.test.tsx index 640f16f78a0b4..ced29e2f8c17c 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_index_data.test.tsx +++ b/x-pack/plugins/transform/public/app/hooks/use_index_data.test.tsx @@ -6,7 +6,6 @@ */ import React, { type FC } from 'react'; - import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import '@testing-library/jest-dom/extend-expect'; import { render, screen, waitFor } from '@testing-library/react'; diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/aggregation_list/__snapshots__/agg_label_form.test.tsx.snap b/x-pack/plugins/transform/public/app/sections/create_transform/components/aggregation_list/__snapshots__/agg_label_form.test.tsx.snap deleted file mode 100644 index 09056b8529f16..0000000000000 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/aggregation_list/__snapshots__/agg_label_form.test.tsx.snap +++ /dev/null @@ -1,72 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Transform: Date histogram aggregation 1`] = ` - - - - - the-group-by-agg-name - - - - - } - closePopover={[Function]} - display="inline-block" - hasArrow={true} - id="transformFormPopover" - isOpen={false} - ownFocus={true} - panelPaddingSize="m" - > - - - - - - - - -`; diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/aggregation_list/__snapshots__/list_form.test.tsx.snap b/x-pack/plugins/transform/public/app/sections/create_transform/components/aggregation_list/__snapshots__/list_form.test.tsx.snap deleted file mode 100644 index 89b54e6d0a22f..0000000000000 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/aggregation_list/__snapshots__/list_form.test.tsx.snap +++ /dev/null @@ -1,28 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Transform: Minimal initialization 1`] = ` - - - - - - -`; diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/aggregation_list/__snapshots__/list_summary.test.tsx.snap b/x-pack/plugins/transform/public/app/sections/create_transform/components/aggregation_list/__snapshots__/list_summary.test.tsx.snap deleted file mode 100644 index f08d7fab7c829..0000000000000 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/aggregation_list/__snapshots__/list_summary.test.tsx.snap +++ /dev/null @@ -1,18 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Transform: Minimal initialization 1`] = ` - - -
- the-agg -
-
- -
-`; diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/aggregation_list/__snapshots__/popover_form.test.tsx.snap b/x-pack/plugins/transform/public/app/sections/create_transform/components/aggregation_list/__snapshots__/popover_form.test.tsx.snap deleted file mode 100644 index f7b4e836ee784..0000000000000 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/aggregation_list/__snapshots__/popover_form.test.tsx.snap +++ /dev/null @@ -1,48 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Transform: Aggregation Minimal initialization 1`] = ` - - - - - - - Apply - - - -`; diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/aggregation_list/agg_label_form.test.tsx b/x-pack/plugins/transform/public/app/sections/create_transform/components/aggregation_list/agg_label_form.test.tsx index fc9f91f96b3ff..b036016314754 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/aggregation_list/agg_label_form.test.tsx +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/aggregation_list/agg_label_form.test.tsx @@ -5,8 +5,8 @@ * 2.0. */ -import { shallow } from 'enzyme'; import React from 'react'; +import { render } from '@testing-library/react'; import { AggName } from '../../../../../../common/types/aggregations'; import { PIVOT_SUPPORTED_AGGS } from '../../../../../../common/types/pivot_aggs'; @@ -31,8 +31,8 @@ describe('Transform: ', () => { onChange() {}, }; - const wrapper = shallow(); + const { container } = render(); - expect(wrapper).toMatchSnapshot(); + expect(container.textContent).toBe('the-group-by-agg-name'); }); }); diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/aggregation_list/list_form.test.tsx b/x-pack/plugins/transform/public/app/sections/create_transform/components/aggregation_list/list_form.test.tsx index 1525aa1a3320b..205fb93479339 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/aggregation_list/list_form.test.tsx +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/aggregation_list/list_form.test.tsx @@ -5,8 +5,8 @@ * 2.0. */ -import { shallow } from 'enzyme'; import React from 'react'; +import { render } from '@testing-library/react'; import { PIVOT_SUPPORTED_AGGS } from '../../../../../../common/types/pivot_aggs'; @@ -29,8 +29,8 @@ describe('Transform: ', () => { onChange() {}, }; - const wrapper = shallow(); + const { container } = render(); - expect(wrapper).toMatchSnapshot(); + expect(container.textContent).toBe('the-group-by-agg-name'); }); }); diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/aggregation_list/list_summary.test.tsx b/x-pack/plugins/transform/public/app/sections/create_transform/components/aggregation_list/list_summary.test.tsx index 71d728798c8fb..d1078f4d5a87a 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/aggregation_list/list_summary.test.tsx +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/aggregation_list/list_summary.test.tsx @@ -5,8 +5,8 @@ * 2.0. */ -import { shallow } from 'enzyme'; import React from 'react'; +import { render } from '@testing-library/react'; import { PIVOT_SUPPORTED_AGGS } from '../../../../../../common/types/pivot_aggs'; @@ -26,8 +26,8 @@ describe('Transform: ', () => { list: { 'the-agg': item }, }; - const wrapper = shallow(); + const { container } = render(); - expect(wrapper).toMatchSnapshot(); + expect(container.textContent).toBe('the-agg'); }); }); diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/aggregation_list/popover_form.test.tsx b/x-pack/plugins/transform/public/app/sections/create_transform/components/aggregation_list/popover_form.test.tsx index 0587d4f0e1c46..88cdad407bd62 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/aggregation_list/popover_form.test.tsx +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/aggregation_list/popover_form.test.tsx @@ -5,7 +5,6 @@ * 2.0. */ -import { shallow } from 'enzyme'; import { fireEvent, render } from '@testing-library/react'; import React from 'react'; import { AggName } from '../../../../../../common/types/aggregations'; @@ -29,7 +28,7 @@ describe('Transform: Aggregation ', () => { const otherAggNames: AggName[] = []; const onChange = (item: PivotAggsConfig) => {}; - const wrapper = shallow( + const { getByTestId } = render( ', () => { /> ); - expect(wrapper).toMatchSnapshot(); + const input = getByTestId('transformAggName'); + expect(input).toHaveValue('the-group-by-agg-name'); }); test('preserves the field for unsupported aggs', async () => { diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/group_by_list/__snapshots__/group_by_label_form.test.tsx.snap b/x-pack/plugins/transform/public/app/sections/create_transform/components/group_by_list/__snapshots__/group_by_label_form.test.tsx.snap deleted file mode 100644 index 0bb11827655e0..0000000000000 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/group_by_list/__snapshots__/group_by_label_form.test.tsx.snap +++ /dev/null @@ -1,234 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Transform: Date histogram aggregation 1`] = ` - - - - the-group-by-agg-name - - - - - 1m - - - - - } - closePopover={[Function]} - display="inline-block" - hasArrow={true} - id="transformIntervalFormPopover" - isOpen={false} - ownFocus={true} - panelPaddingSize="m" - > - - - - - - - -`; - -exports[`Transform: Histogram aggregation 1`] = ` - - - - the-group-by-agg-name - - - - - 100 - - - - - } - closePopover={[Function]} - display="inline-block" - hasArrow={true} - id="transformIntervalFormPopover" - isOpen={false} - ownFocus={true} - panelPaddingSize="m" - > - - - - - - - -`; - -exports[`Transform: Terms aggregation 1`] = ` - - - - the-group-by-agg-name - - - - - } - closePopover={[Function]} - display="inline-block" - hasArrow={true} - id="transformIntervalFormPopover" - isOpen={false} - ownFocus={true} - panelPaddingSize="m" - > - - - - - - - -`; diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/group_by_list/__snapshots__/group_by_label_summary.test.tsx.snap b/x-pack/plugins/transform/public/app/sections/create_transform/components/group_by_list/__snapshots__/group_by_label_summary.test.tsx.snap deleted file mode 100644 index b1d3afeff412c..0000000000000 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/group_by_list/__snapshots__/group_by_label_summary.test.tsx.snap +++ /dev/null @@ -1,77 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Transform: Date histogram aggregation 1`] = ` - - - - the-options-data-id - - - - - 1m - - - -`; - -exports[`Transform: Histogram aggregation 1`] = ` - - - - the-options-data-id - - - - - 100 - - - -`; - -exports[`Transform: Terms aggregation 1`] = ` - - - - the-options-data-id - - - -`; diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/group_by_list/__snapshots__/list_form.test.tsx.snap b/x-pack/plugins/transform/public/app/sections/create_transform/components/group_by_list/__snapshots__/list_form.test.tsx.snap deleted file mode 100644 index da1e9a79680ad..0000000000000 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/group_by_list/__snapshots__/list_form.test.tsx.snap +++ /dev/null @@ -1,28 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Transform: Minimal initialization 1`] = ` - - - - - - -`; diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/group_by_list/__snapshots__/list_summary.test.tsx.snap b/x-pack/plugins/transform/public/app/sections/create_transform/components/group_by_list/__snapshots__/list_summary.test.tsx.snap deleted file mode 100644 index 724433a80d3a8..0000000000000 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/group_by_list/__snapshots__/list_summary.test.tsx.snap +++ /dev/null @@ -1,24 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Transform: Minimal initialization 1`] = ` - - - - - - -`; diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/group_by_list/__snapshots__/popover_form.test.tsx.snap b/x-pack/plugins/transform/public/app/sections/create_transform/components/group_by_list/__snapshots__/popover_form.test.tsx.snap deleted file mode 100644 index 9c9fb59eea4b1..0000000000000 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/group_by_list/__snapshots__/popover_form.test.tsx.snap +++ /dev/null @@ -1,18 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Transform: Group By Minimal initialization 1`] = ` - -`; diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/group_by_list/group_by_label_form.test.tsx b/x-pack/plugins/transform/public/app/sections/create_transform/components/group_by_list/group_by_label_form.test.tsx index 09ec34f90d751..2edcfc7a9bd2c 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/group_by_list/group_by_label_form.test.tsx +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/group_by_list/group_by_label_form.test.tsx @@ -5,8 +5,8 @@ * 2.0. */ -import { shallow } from 'enzyme'; import React from 'react'; +import { render } from '@testing-library/react'; import { PivotGroupByConfig, PIVOT_SUPPORTED_GROUP_BY_AGGS } from '../../../../common'; @@ -29,9 +29,9 @@ describe('Transform: ', () => { onChange() {}, }; - const wrapper = shallow(); + const { container } = render(); - expect(wrapper).toMatchSnapshot(); + expect(container.textContent).toContain('the-group-by-agg-name'); }); test('Histogram aggregation', () => { @@ -50,9 +50,9 @@ describe('Transform: ', () => { onChange() {}, }; - const wrapper = shallow(); + const { container } = render(); - expect(wrapper).toMatchSnapshot(); + expect(container.textContent).toContain('the-group-by-agg-name'); }); test('Terms aggregation', () => { @@ -70,8 +70,8 @@ describe('Transform: ', () => { onChange() {}, }; - const wrapper = shallow(); + const { container } = render(); - expect(wrapper).toMatchSnapshot(); + expect(container.textContent).toContain('the-group-by-agg-name'); }); }); diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/group_by_list/group_by_label_summary.test.tsx b/x-pack/plugins/transform/public/app/sections/create_transform/components/group_by_list/group_by_label_summary.test.tsx index 689c27f5f81be..5c03d3bc8f320 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/group_by_list/group_by_label_summary.test.tsx +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/group_by_list/group_by_label_summary.test.tsx @@ -5,8 +5,8 @@ * 2.0. */ -import { shallow } from 'enzyme'; import React from 'react'; +import { render } from '@testing-library/react'; import { PivotGroupByConfig, PIVOT_SUPPORTED_GROUP_BY_AGGS } from '../../../../common'; @@ -26,9 +26,9 @@ describe('Transform: ', () => { optionsDataId: 'the-options-data-id', }; - const wrapper = shallow(); + const { container } = render(); - expect(wrapper).toMatchSnapshot(); + expect(container.textContent).toContain('the-options-data-id'); }); test('Histogram aggregation', () => { @@ -44,9 +44,9 @@ describe('Transform: ', () => { optionsDataId: 'the-options-data-id', }; - const wrapper = shallow(); + const { container } = render(); - expect(wrapper).toMatchSnapshot(); + expect(container.textContent).toContain('the-options-data-id'); }); test('Terms aggregation', () => { @@ -61,8 +61,8 @@ describe('Transform: ', () => { optionsDataId: 'the-options-data-id', }; - const wrapper = shallow(); + const { container } = render(); - expect(wrapper).toMatchSnapshot(); + expect(container.textContent).toContain('the-options-data-id'); }); }); diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/group_by_list/list_form.test.tsx b/x-pack/plugins/transform/public/app/sections/create_transform/components/group_by_list/list_form.test.tsx index 61a11a8b551b3..eb942cad63b01 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/group_by_list/list_form.test.tsx +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/group_by_list/list_form.test.tsx @@ -5,8 +5,8 @@ * 2.0. */ -import { shallow } from 'enzyme'; import React from 'react'; +import { render } from '@testing-library/react'; import { PivotGroupByConfig, PIVOT_SUPPORTED_GROUP_BY_AGGS } from '../../../../common'; @@ -27,8 +27,8 @@ describe('Transform: ', () => { onChange() {}, }; - const wrapper = shallow(); + const { container } = render(); - expect(wrapper).toMatchSnapshot(); + expect(container.textContent).toContain('the-group-by-agg-name'); }); }); diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/group_by_list/list_summary.test.tsx b/x-pack/plugins/transform/public/app/sections/create_transform/components/group_by_list/list_summary.test.tsx index 201b36a41b09c..eadddd8356e42 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/group_by_list/list_summary.test.tsx +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/group_by_list/list_summary.test.tsx @@ -5,8 +5,8 @@ * 2.0. */ -import { shallow } from 'enzyme'; import React from 'react'; +import { render } from '@testing-library/react'; import { PivotGroupByConfig, PIVOT_SUPPORTED_GROUP_BY_AGGS } from '../../../../common'; @@ -24,8 +24,8 @@ describe('Transform: ', () => { list: { 'the-options-data-id': item }, }; - const wrapper = shallow(); + const { container } = render(); - expect(wrapper).toMatchSnapshot(); + expect(container.textContent).toContain('the-options-data-id'); }); }); diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/group_by_list/popover_form.test.tsx b/x-pack/plugins/transform/public/app/sections/create_transform/components/group_by_list/popover_form.test.tsx index d5b1139e6cdae..4ef6cbbaf51be 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/group_by_list/popover_form.test.tsx +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/group_by_list/popover_form.test.tsx @@ -5,8 +5,8 @@ * 2.0. */ -import { shallow } from 'enzyme'; import React from 'react'; +import { render } from '@testing-library/react'; import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; @@ -101,7 +101,7 @@ describe('Transform: Group By ', () => { appName: 'the-test-app', }; - const wrapper = shallow( + const { getByDisplayValue } = render( ', () => { ); - expect(wrapper.find(PopoverForm)).toMatchSnapshot(); + expect(getByDisplayValue('the-agg-name')).toBeInTheDocument(); + expect(getByDisplayValue('1m')).toBeInTheDocument(); }); }); diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/__snapshots__/transform_management_section.test.tsx.snap b/x-pack/plugins/transform/public/app/sections/transform_management/__snapshots__/transform_management_section.test.tsx.snap deleted file mode 100644 index 8348f93b32140..0000000000000 --- a/x-pack/plugins/transform/public/app/sections/transform_management/__snapshots__/transform_management_section.test.tsx.snap +++ /dev/null @@ -1,14 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Transform: Minimal initialization 1`] = ` - - - -`; diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_delete/__snapshots__/delete_action_name.test.tsx.snap b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_delete/__snapshots__/delete_action_name.test.tsx.snap deleted file mode 100644 index fe1e813ca9843..0000000000000 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_delete/__snapshots__/delete_action_name.test.tsx.snap +++ /dev/null @@ -1,7 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Transform: Transform List Actions Minimal initialization 1`] = ` - - Delete - -`; diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_delete/delete_action_name.test.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_delete/delete_action_name.test.tsx index 1fb0d69682cda..37daeeb75e138 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_delete/delete_action_name.test.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_delete/delete_action_name.test.tsx @@ -5,8 +5,8 @@ * 2.0. */ -import { shallow } from 'enzyme'; import React from 'react'; +import { render } from '@testing-library/react'; import { DeleteActionName, DeleteActionNameProps } from './delete_action_name'; @@ -21,7 +21,7 @@ describe('Transform: Transform List Actions ', () => { isBulkAction: false, }; - const wrapper = shallow(); - expect(wrapper).toMatchSnapshot(); + const { container } = render(); + expect(container.textContent).toBe('Delete'); }); }); diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_start/__snapshots__/start_action_name.test.tsx.snap b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_start/__snapshots__/start_action_name.test.tsx.snap deleted file mode 100644 index 466afc71a4811..0000000000000 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_start/__snapshots__/start_action_name.test.tsx.snap +++ /dev/null @@ -1,134 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Transform: Transform List Actions Minimal initialization 1`] = ` - - - - - -`; diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_start/start_action_name.test.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_start/start_action_name.test.tsx index f609dd21325a9..6ef0a995186c7 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_start/start_action_name.test.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_start/start_action_name.test.tsx @@ -5,8 +5,8 @@ * 2.0. */ -import { shallow } from 'enzyme'; import React from 'react'; +import { render } from '@testing-library/react'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { TransformListRow } from '../../../../common'; @@ -29,12 +29,11 @@ describe('Transform: Transform List Actions ', () => { transformNodes: 1, }; - const wrapper = shallow( + const { container } = render( ); - - expect(wrapper).toMatchSnapshot(); + expect(container.textContent).toBe('Start'); }); }); diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_stop/__snapshots__/stop_action_name.test.tsx.snap b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_stop/__snapshots__/stop_action_name.test.tsx.snap deleted file mode 100644 index ec4b06334060f..0000000000000 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_stop/__snapshots__/stop_action_name.test.tsx.snap +++ /dev/null @@ -1,133 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Transform: Transform List Actions Minimal initialization 1`] = ` - - - - - -`; diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_stop/stop_action_name.test.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_stop/stop_action_name.test.tsx index 316142d4b6c73..e32bf043a2221 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_stop/stop_action_name.test.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_stop/stop_action_name.test.tsx @@ -5,8 +5,8 @@ * 2.0. */ -import { shallow } from 'enzyme'; import React from 'react'; +import { render } from '@testing-library/react'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { TransformListRow } from '../../../../common'; @@ -28,12 +28,11 @@ describe('Transform: Transform List Actions ', () => { items: [item], }; - const wrapper = shallow( + const { container } = render( ); - - expect(wrapper).toMatchSnapshot(); + expect(container.textContent).toBe('Stop'); }); }); diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/create_transform_button/__snapshots__/create_transform_button.test.tsx.snap b/x-pack/plugins/transform/public/app/sections/transform_management/components/create_transform_button/__snapshots__/create_transform_button.test.tsx.snap deleted file mode 100644 index e8428dbefb43c..0000000000000 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/create_transform_button/__snapshots__/create_transform_button.test.tsx.snap +++ /dev/null @@ -1,63 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Transform: Transform List Minimal initialization 1`] = ` - - - - - -`; diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/create_transform_button/create_transform_button.test.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/create_transform_button/create_transform_button.test.tsx index 4e8c09958c3e7..da84ef2faa8e3 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/create_transform_button/create_transform_button.test.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/create_transform_button/create_transform_button.test.tsx @@ -5,8 +5,8 @@ * 2.0. */ -import { shallow } from 'enzyme'; import React from 'react'; +import { render } from '@testing-library/react'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { CreateTransformButton } from './create_transform_button'; @@ -17,12 +17,11 @@ const queryClient = new QueryClient(); describe('Transform: Transform List ', () => { test('Minimal initialization', () => { - const wrapper = shallow( + const { container } = render( ); - - expect(wrapper).toMatchSnapshot(); + expect(container.textContent).toBe('Create a transform'); }); }); diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/__snapshots__/expanded_row_details_pane.test.tsx.snap b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/__snapshots__/expanded_row_details_pane.test.tsx.snap deleted file mode 100644 index 39964399f66db..0000000000000 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/__snapshots__/expanded_row_details_pane.test.tsx.snap +++ /dev/null @@ -1,66 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Transform: Job List Expanded Row Minimal initialization 1`] = ` -
- - - -
- - - -
-`; - -exports[`Transform: Job List Expanded Row
Minimal initialization 1`] = ` - - - - the-section-title - - - - -`; diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/__snapshots__/expanded_row_json_pane.test.tsx.snap b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/__snapshots__/expanded_row_json_pane.test.tsx.snap deleted file mode 100644 index 19a5055954d84..0000000000000 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/__snapshots__/expanded_row_json_pane.test.tsx.snap +++ /dev/null @@ -1,66 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Transform: Transform List Expanded Row Minimal initialization 1`] = ` -
- - - - - { - "id": "fq_date_histogram_1m_1441", - "source": { - "index": [ - "farequote-2019" - ], - "query": { - "match_all": {} - } - }, - "dest": { - "index": "fq_date_histogram_1m_1441" - }, - "pivot": { - "group_by": { - "@timestamp": { - "date_histogram": { - "field": "@timestamp", - "calendar_interval": "1m" - } - } - }, - "aggregations": { - "responsetime.avg": { - "avg": { - "field": "responsetime" - } - } - } - }, - "version": "8.0.0", - "create_time": 1564388146667 -} - - - -   - - -
-`; diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/__snapshots__/transform_list.test.tsx.snap b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/__snapshots__/transform_list.test.tsx.snap deleted file mode 100644 index a24e252578041..0000000000000 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/__snapshots__/transform_list.test.tsx.snap +++ /dev/null @@ -1,67 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Transform: Transform List Minimal initialization 1`] = ` - - - - - -`; diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row_details_pane.test.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row_details_pane.test.tsx index a4c8a497d2202..ad375d47ce4cc 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row_details_pane.test.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row_details_pane.test.tsx @@ -5,8 +5,8 @@ * 2.0. */ -import { shallow } from 'enzyme'; import React from 'react'; +import { render } from '@testing-library/react'; import { ExpandedRowDetailsPane, Section, SectionConfig } from './expanded_row_details_pane'; @@ -23,16 +23,20 @@ const section: SectionConfig = { describe('Transform: Job List Expanded Row ', () => { test('Minimal initialization', () => { - const wrapper = shallow(); + const { container } = render(); - expect(wrapper).toMatchSnapshot(); + expect(container.textContent).toContain('the-section-title'); + expect(container.textContent).toContain('the-item-title'); + expect(container.textContent).toContain('the-item-description'); }); }); describe('Transform: Job List Expanded Row
', () => { test('Minimal initialization', () => { - const wrapper = shallow(
); + const { container } = render(
); - expect(wrapper).toMatchSnapshot(); + expect(container.textContent).toContain('the-section-title'); + expect(container.textContent).toContain('the-item-title'); + expect(container.textContent).toContain('the-item-description'); }); }); diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row_json_pane.test.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row_json_pane.test.tsx index 7b1a5de79fae5..ff69aab3aa3eb 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row_json_pane.test.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row_json_pane.test.tsx @@ -5,8 +5,8 @@ * 2.0. */ -import { shallow } from 'enzyme'; import React from 'react'; +import { render } from '@testing-library/react'; import transformListRow from '../../../../common/__mocks__/transform_list_row.json'; @@ -14,8 +14,7 @@ import { ExpandedRowJsonPane } from './expanded_row_json_pane'; describe('Transform: Transform List Expanded Row ', () => { test('Minimal initialization', () => { - const wrapper = shallow(); - - expect(wrapper).toMatchSnapshot(); + const { container } = render(); + expect(container.textContent).toContain(JSON.stringify(transformListRow.config, null, 2)); }); }); diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_list.test.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_list.test.tsx index c4fc1cbc65c27..c9ab7234a6d74 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_list.test.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_list.test.tsx @@ -5,31 +5,63 @@ * 2.0. */ -import { shallow } from 'enzyme'; import React from 'react'; -import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; +import { render, waitFor } from '@testing-library/react'; +import { QueryClient, QueryClientProvider, type UseQueryResult } from '@tanstack/react-query'; +import * as ReactQuery from '@tanstack/react-query'; + +import { __IntlProvider as IntlProvider } from '@kbn/i18n-react'; + +import { INITIAL_CAPABILITIES } from '../../../../../../common/privilege/has_privilege_factory'; import { TransformList } from './transform_list'; +const useQueryMock = jest.spyOn(ReactQuery, 'useQuery').mockImplementation((queryKey) => { + switch (queryKey[0]) { + case 'transform.data_view_exists': + return { error: null, data: true } as UseQueryResult; + case 'transform.get_privileges': + return { + error: null, + isLoading: false, + data: { + privileges: { + hasAllPrivileges: true, + missingPrivileges: {}, + }, + capabilities: INITIAL_CAPABILITIES, + }, + } as UseQueryResult; + } + + return { error: null, data: undefined } as UseQueryResult; +}); + +const queryClient = new QueryClient(); + jest.mock('../../../../../shared_imports'); jest.mock('../../../../app_dependencies'); describe('Transform: Transform List ', () => { - test('Minimal initialization', () => { - const queryClient = new QueryClient(); - const wrapper = shallow( - - - + test('Minimal initialization', async () => { + const { container } = render( + + + + + ); - expect(wrapper).toMatchSnapshot(); + await waitFor(() => { + expect(useQueryMock).toHaveBeenCalledTimes(22); + expect(container.textContent).toContain('Reload'); + }); }); }); diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/transform_management_section.test.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/transform_management_section.test.tsx index 3e4cee609c75b..61e268aeb25ff 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/transform_management_section.test.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/transform_management_section.test.tsx @@ -5,17 +5,25 @@ * 2.0. */ -import { shallow } from 'enzyme'; import React from 'react'; +import { render } from '@testing-library/react'; +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { TransformManagementSection } from './transform_management_section'; jest.mock('../../../shared_imports'); +jest.mock('../../services/navigation'); + +const queryClient = new QueryClient(); describe('Transform: ', () => { test('Minimal initialization', () => { - const wrapper = shallow(); + const { container } = render( + + + + ); - expect(wrapper).toMatchSnapshot(); + expect(container.textContent).toBe('Checking privileges…'); }); }); From a6a7c701fb3138c74593d3fca8dcce69e3d5d681 Mon Sep 17 00:00:00 2001 From: Walter Rafelsberger Date: Fri, 25 Aug 2023 10:11:28 +0200 Subject: [PATCH 32/53] client side code no longer relies on privileges --- x-pack/plugins/transform/common/constants.ts | 17 -- .../common/privilege/has_privilege_factory.ts | 217 ------------------ .../transform/common/types/capabilities.ts | 39 ++++ .../transform/common/types/privileges.ts | 15 -- .../create_capability_failure_message.ts | 85 +++++++ .../index.ts => common/utils/to_array.ts} | 2 +- x-pack/plugins/transform/public/app/app.tsx | 48 ++-- .../app/components/capabilities_wrapper.tsx | 64 ++++++ .../transform/public/app/components/index.ts | 2 - .../public/app/components/section_error.tsx | 39 ---- .../public/app/components/section_loading.tsx | 48 ---- .../transform/public/app/hooks/index.ts | 2 +- .../public/app/hooks/use_authorization.ts | 48 ---- .../public/app/hooks/use_delete_transform.tsx | 21 +- .../app/hooks/use_transform_capabilities.ts | 16 ++ .../app/lib/authorization/components/index.ts | 10 - .../components/not_authorized_section.tsx | 18 -- .../components/with_privileges.tsx | 141 ------------ .../clone_transform_section.tsx | 14 +- .../create_transform_section.tsx | 15 +- .../action_clone/clone_action_name.tsx | 2 +- .../action_clone/use_clone_action.tsx | 4 +- .../create_alert_rule_action_name.tsx | 3 +- .../use_create_alert_rule_action.tsx | 4 +- .../action_delete/delete_action_name.tsx | 5 +- .../action_delete/use_delete_action.tsx | 4 +- .../action_edit/edit_action_name.tsx | 7 +- .../action_edit/use_edit_action.tsx | 4 +- .../reauthorize_action_name.tsx | 12 +- .../use_reauthorize_action.tsx | 4 +- .../action_reset/reset_action_name.tsx | 7 +- .../action_reset/use_reset_action.tsx | 4 +- .../schedule_now_action_name.tsx | 11 +- .../use_schedule_now_action.tsx | 4 +- .../action_start/start_action_name.tsx | 6 +- .../action_start/use_start_action.tsx | 4 +- .../action_stop/stop_action_name.tsx | 6 +- .../action_stop/use_stop_action.tsx | 4 +- .../create_transform_button.tsx | 7 +- .../transform_list/transform_list.test.tsx | 14 -- .../transform_list/transform_list.tsx | 4 +- .../components/transform_list/use_columns.tsx | 4 +- .../transform_management_section.tsx | 15 +- .../plugins/transform/server/capabilities.ts | 120 +++++++++- .../capabiltiies.test.ts} | 2 +- .../transform/server/routes/api/privileges.ts | 84 ------- .../plugins/transform/server/routes/index.ts | 2 - 47 files changed, 422 insertions(+), 786 deletions(-) delete mode 100644 x-pack/plugins/transform/common/privilege/has_privilege_factory.ts create mode 100644 x-pack/plugins/transform/common/types/capabilities.ts delete mode 100644 x-pack/plugins/transform/common/types/privileges.ts create mode 100644 x-pack/plugins/transform/common/utils/create_capability_failure_message.ts rename x-pack/plugins/transform/{public/app/lib/authorization/index.ts => common/utils/to_array.ts} (73%) create mode 100644 x-pack/plugins/transform/public/app/components/capabilities_wrapper.tsx delete mode 100644 x-pack/plugins/transform/public/app/components/section_error.tsx delete mode 100644 x-pack/plugins/transform/public/app/components/section_loading.tsx delete mode 100644 x-pack/plugins/transform/public/app/hooks/use_authorization.ts create mode 100644 x-pack/plugins/transform/public/app/hooks/use_transform_capabilities.ts delete mode 100644 x-pack/plugins/transform/public/app/lib/authorization/components/index.ts delete mode 100644 x-pack/plugins/transform/public/app/lib/authorization/components/not_authorized_section.tsx delete mode 100644 x-pack/plugins/transform/public/app/lib/authorization/components/with_privileges.tsx rename x-pack/plugins/transform/{common/privilege/has_privilege_factory.test.ts => server/capabiltiies.test.ts} (99%) delete mode 100644 x-pack/plugins/transform/server/routes/api/privileges.ts diff --git a/x-pack/plugins/transform/common/constants.ts b/x-pack/plugins/transform/common/constants.ts index 74bed69c8facc..e7acb401f6282 100644 --- a/x-pack/plugins/transform/common/constants.ts +++ b/x-pack/plugins/transform/common/constants.ts @@ -40,7 +40,6 @@ export const TRANSFORM_REACT_QUERY_KEYS = { GET_ES_INDICES: 'transform.get_es_indices', GET_ES_INGEST_PIPELINES: 'transform.get_es_ingest_pipelines', GET_HISTOGRAMS_FOR_FIELDS: 'transform.get_histograms_for_fields', - GET_PRIVILEGES: 'transform.get_privileges', GET_TRANSFORM: 'transform.get_transform', GET_TRANSFORM_AUDIT_MESSAGES: 'transform.get_transform_audit_messages', GET_TRANSFORM_STATS: 'transform.get_transform_stats', @@ -87,22 +86,6 @@ export const APP_CLUSTER_PRIVILEGES = [ // Minimum privileges required to return transform node count export const NODES_INFO_PRIVILEGES = ['cluster:monitor/transform/get']; -// Equivalent of capabilities.canGetTransform -export const APP_GET_TRANSFORM_CLUSTER_PRIVILEGES = [ - 'cluster.cluster:monitor/transform/get', - 'cluster.cluster:monitor/transform/stats/get', -]; - -// Equivalent of capabilities.canCreateTransform -export const APP_CREATE_TRANSFORM_CLUSTER_PRIVILEGES = [ - 'cluster.cluster:monitor/transform/get', - 'cluster.cluster:monitor/transform/stats/get', - 'cluster.cluster:admin/transform/preview', - 'cluster.cluster:admin/transform/put', - 'cluster.cluster:admin/transform/start', - 'cluster.cluster:admin/transform/start_task', -]; - export const APP_INDEX_PRIVILEGES = ['monitor']; // reflects https://github.com/elastic/elasticsearch/blob/master/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/transform/transforms/TransformStats.java#L214 diff --git a/x-pack/plugins/transform/common/privilege/has_privilege_factory.ts b/x-pack/plugins/transform/common/privilege/has_privilege_factory.ts deleted file mode 100644 index 9dee0c1a73cf1..0000000000000 --- a/x-pack/plugins/transform/common/privilege/has_privilege_factory.ts +++ /dev/null @@ -1,217 +0,0 @@ -/* - * 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'; -import { isPopulatedObject } from '@kbn/ml-is-populated-object'; - -import { cloneDeep } from 'lodash'; -import { APP_INDEX_PRIVILEGES } from '../constants'; -import { Privileges } from '../types/privileges'; - -export interface PrivilegesAndCapabilities { - privileges: Privileges; - capabilities: Capabilities; -} - -export interface TransformCapabilities { - canGetTransform: boolean; - canDeleteTransform: boolean; - canPreviewTransform: boolean; - canCreateTransform: boolean; - canReauthorizeTransform: boolean; - canScheduleNowTransform: boolean; - canStartStopTransform: boolean; - canCreateTransformAlerts: boolean; - canUseTransformAlerts: boolean; - canResetTransform: boolean; -} -export type Capabilities = { [k in keyof TransformCapabilities]: boolean }; - -export const INITIAL_CAPABILITIES = Object.freeze({ - canGetTransform: false, - canDeleteTransform: false, - canPreviewTransform: false, - canCreateTransform: false, - canReauthorizeTransform: false, - canScheduleNowTransform: false, - canStartStopTransform: false, - canCreateTransformAlerts: false, - canUseTransformAlerts: false, - canResetTransform: false, -}); - -export type Privilege = [string, string]; - -function isPrivileges(arg: unknown): arg is Privileges { - return ( - isPopulatedObject(arg, ['hasAllPrivileges', 'missingPrivileges']) && - typeof arg.hasAllPrivileges === 'boolean' && - typeof arg.missingPrivileges === 'object' && - arg.missingPrivileges !== null - ); -} - -export const toArray = (value: string | string[]): string[] => - Array.isArray(value) ? value : [value]; - -export const hasPrivilegeFactory = - (privileges: Privileges | undefined | null) => (privilege: Privilege) => { - const [section, requiredPrivilege] = privilege; - if (isPrivileges(privileges) && !privileges.missingPrivileges[section]) { - // if the section does not exist in our missingPrivileges, everything is OK - return true; - } - if (isPrivileges(privileges) && privileges.missingPrivileges[section]!.length === 0) { - return true; - } - if (requiredPrivilege === '*') { - // If length > 0 and we require them all... KO - return false; - } - // If we require _some_ privilege, we make sure that the one - // we require is *not* in the missingPrivilege array - return ( - isPrivileges(privileges) && - !privileges.missingPrivileges[section]!.includes(requiredPrivilege) - ); - }; - -export const extractMissingPrivileges = ( - privilegesObject: { [key: string]: boolean } = {} -): string[] => - Object.keys(privilegesObject).reduce((privileges: string[], privilegeName: string): string[] => { - if (!privilegesObject[privilegeName]) { - privileges.push(privilegeName); - } - return privileges; - }, []); - -export const getPrivilegesAndCapabilities = ( - clusterPrivileges: Record, - hasOneIndexWithAllPrivileges: boolean, - hasAllPrivileges: boolean -): PrivilegesAndCapabilities => { - const privilegesResult: Privileges = { - hasAllPrivileges: true, - missingPrivileges: { - cluster: [], - index: [], - }, - }; - - // Find missing cluster privileges and set overall app privileges - privilegesResult.missingPrivileges.cluster = extractMissingPrivileges(clusterPrivileges); - privilegesResult.hasAllPrivileges = hasAllPrivileges; - - if (!hasOneIndexWithAllPrivileges) { - privilegesResult.missingPrivileges.index = [...APP_INDEX_PRIVILEGES]; - } - - const hasPrivilege = hasPrivilegeFactory(privilegesResult); - - const capabilities = cloneDeep(INITIAL_CAPABILITIES); - capabilities.canGetTransform = - hasPrivilege(['cluster', 'cluster:monitor/transform/get']) && - hasPrivilege(['cluster', 'cluster:monitor/transform/stats/get']); - - capabilities.canCreateTransform = hasPrivilege(['cluster', 'cluster:admin/transform/put']); - - capabilities.canDeleteTransform = hasPrivilege(['cluster', 'cluster:admin/transform/delete']); - - capabilities.canResetTransform = hasPrivilege(['cluster', 'cluster:admin/transform/reset']); - - capabilities.canPreviewTransform = hasPrivilege(['cluster', 'cluster:admin/transform/preview']); - - capabilities.canStartStopTransform = - hasPrivilege(['cluster', 'cluster:admin/transform/start']) && - hasPrivilege(['cluster', 'cluster:admin/transform/start_task']) && - hasPrivilege(['cluster', 'cluster:admin/transform/stop']); - - capabilities.canCreateTransformAlerts = capabilities.canCreateTransform; - - capabilities.canUseTransformAlerts = capabilities.canGetTransform; - - capabilities.canScheduleNowTransform = capabilities.canStartStopTransform; - - capabilities.canReauthorizeTransform = capabilities.canStartStopTransform; - - return { privileges: privilegesResult, capabilities }; -}; -// create the text for button's tooltips if the user -// doesn't have the permission to press that button -export function createCapabilityFailureMessage( - capability: keyof TransformCapabilities | 'noTransformNodes' -) { - let message = ''; - - switch (capability) { - case 'canCreateTransform': - message = i18n.translate('xpack.transform.capability.noPermission.createTransformTooltip', { - defaultMessage: 'You do not have permission to create transforms.', - }); - break; - case 'canCreateTransformAlerts': - message = i18n.translate( - 'xpack.transform.capability.noPermission.canCreateTransformAlertsTooltip', - { - defaultMessage: 'You do not have permission to create transform alert rules.', - } - ); - break; - case 'canScheduleNowTransform': - message = i18n.translate( - 'xpack.transform.capability.noPermission.scheduleNowTransformTooltip', - { - defaultMessage: - 'You do not have permission to schedule transforms to process data instantly.', - } - ); - break; - case 'canStartStopTransform': - message = i18n.translate( - 'xpack.transform.capability.noPermission.startOrStopTransformTooltip', - { - defaultMessage: 'You do not have permission to start or stop transforms.', - } - ); - break; - - case 'canReauthorizeTransform': - message = i18n.translate( - 'xpack.transform.capability.noPermission.reauthorizeTransformTooltip', - { - defaultMessage: 'You do not have permission to reauthorize transforms.', - } - ); - break; - - case 'canDeleteTransform': - message = i18n.translate('xpack.transform.capability.noPermission.deleteTransformTooltip', { - defaultMessage: 'You do not have permission to delete transforms.', - }); - break; - - case 'canResetTransform': - message = i18n.translate('xpack.transform.capability.noPermission.resetTransformTooltip', { - defaultMessage: 'You do not have permission to reset transforms.', - }); - break; - - case 'noTransformNodes': - message = i18n.translate('xpack.transform.capability.noPermission.noTransformNodesTooltip', { - defaultMessage: 'There are no transform nodes available.', - }); - break; - } - - return i18n.translate('xpack.transform.capability.pleaseContactAdministratorTooltip', { - defaultMessage: '{message} Please contact your administrator.', - values: { - message, - }, - }); -} diff --git a/x-pack/plugins/transform/common/types/capabilities.ts b/x-pack/plugins/transform/common/types/capabilities.ts new file mode 100644 index 0000000000000..a790fd563327c --- /dev/null +++ b/x-pack/plugins/transform/common/types/capabilities.ts @@ -0,0 +1,39 @@ +/* + * 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. + */ + +export const getInitialTransformCapabilities = (initialSetting = false) => ({ + canCreateTransform: initialSetting, + canCreateTransformAlerts: initialSetting, + canDeleteIndex: initialSetting, + canDeleteTransform: initialSetting, + canGetTransform: initialSetting, + canPreviewTransform: initialSetting, + canReauthorizeTransform: initialSetting, + canResetTransform: initialSetting, + canScheduleNowTransform: initialSetting, + canStartStopTransform: initialSetting, + canUseTransformAlerts: initialSetting, +}); + +export type TransformCapabilities = ReturnType; +export type TransformCapability = keyof TransformCapabilities; + +export interface PrivilegesAndCapabilities { + privileges: Privileges; + capabilities: TransformCapabilities; +} + +export type Privilege = [string, string]; + +export interface MissingPrivileges { + [key: string]: string[] | undefined; +} + +export interface Privileges { + hasAllPrivileges: boolean; + missingPrivileges: MissingPrivileges; +} diff --git a/x-pack/plugins/transform/common/types/privileges.ts b/x-pack/plugins/transform/common/types/privileges.ts deleted file mode 100644 index 702b62210d062..0000000000000 --- a/x-pack/plugins/transform/common/types/privileges.ts +++ /dev/null @@ -1,15 +0,0 @@ -/* - * 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. - */ - -export interface MissingPrivileges { - [key: string]: string[] | undefined; -} - -export interface Privileges { - hasAllPrivileges: boolean; - missingPrivileges: MissingPrivileges; -} diff --git a/x-pack/plugins/transform/common/utils/create_capability_failure_message.ts b/x-pack/plugins/transform/common/utils/create_capability_failure_message.ts new file mode 100644 index 0000000000000..7f0f660bd2514 --- /dev/null +++ b/x-pack/plugins/transform/common/utils/create_capability_failure_message.ts @@ -0,0 +1,85 @@ +/* + * 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'; + +import type { TransformCapabilities } from '../types/capabilities'; + +// create the text for button's tooltips if the user +// doesn't have the permission to press that button +export function createCapabilityFailureMessage( + capability: keyof TransformCapabilities | 'noTransformNodes' +) { + let message = ''; + + switch (capability) { + case 'canCreateTransform': + message = i18n.translate('xpack.transform.capability.noPermission.createTransformTooltip', { + defaultMessage: 'You do not have permission to create transforms.', + }); + break; + case 'canCreateTransformAlerts': + message = i18n.translate( + 'xpack.transform.capability.noPermission.canCreateTransformAlertsTooltip', + { + defaultMessage: 'You do not have permission to create transform alert rules.', + } + ); + break; + case 'canScheduleNowTransform': + message = i18n.translate( + 'xpack.transform.capability.noPermission.scheduleNowTransformTooltip', + { + defaultMessage: + 'You do not have permission to schedule transforms to process data instantly.', + } + ); + break; + case 'canStartStopTransform': + message = i18n.translate( + 'xpack.transform.capability.noPermission.startOrStopTransformTooltip', + { + defaultMessage: 'You do not have permission to start or stop transforms.', + } + ); + break; + + case 'canReauthorizeTransform': + message = i18n.translate( + 'xpack.transform.capability.noPermission.reauthorizeTransformTooltip', + { + defaultMessage: 'You do not have permission to reauthorize transforms.', + } + ); + break; + + case 'canDeleteTransform': + message = i18n.translate('xpack.transform.capability.noPermission.deleteTransformTooltip', { + defaultMessage: 'You do not have permission to delete transforms.', + }); + break; + + case 'canResetTransform': + message = i18n.translate('xpack.transform.capability.noPermission.resetTransformTooltip', { + defaultMessage: 'You do not have permission to reset transforms.', + }); + break; + + case 'noTransformNodes': + message = i18n.translate('xpack.transform.capability.noPermission.noTransformNodesTooltip', { + defaultMessage: 'There are no transform nodes available.', + }); + break; + } + + return i18n.translate('xpack.transform.capability.pleaseContactAdministratorTooltip', { + defaultMessage: '{message} Please contact your administrator.', + values: { + message, + }, + }); +} diff --git a/x-pack/plugins/transform/public/app/lib/authorization/index.ts b/x-pack/plugins/transform/common/utils/to_array.ts similarity index 73% rename from x-pack/plugins/transform/public/app/lib/authorization/index.ts rename to x-pack/plugins/transform/common/utils/to_array.ts index e78d12e73a8ea..f41ceea9fc180 100644 --- a/x-pack/plugins/transform/public/app/lib/authorization/index.ts +++ b/x-pack/plugins/transform/common/utils/to_array.ts @@ -5,4 +5,4 @@ * 2.0. */ -export * from './components'; +export const toArray = (value: T | T[]): T[] => (Array.isArray(value) ? value : [value]); diff --git a/x-pack/plugins/transform/public/app/app.tsx b/x-pack/plugins/transform/public/app/app.tsx index 689026689192e..8e13f45df1c04 100644 --- a/x-pack/plugins/transform/public/app/app.tsx +++ b/x-pack/plugins/transform/public/app/app.tsx @@ -13,51 +13,31 @@ import { EuiErrorBoundary } from '@elastic/eui'; import { Router, Routes, Route } from '@kbn/shared-ux-router'; import { ScopedHistory } from '@kbn/core/public'; -import { FormattedMessage } from '@kbn/i18n-react'; import { KibanaContextProvider, KibanaThemeProvider } from '@kbn/kibana-react-plugin/public'; import { REACT_QUERY_STALE_TIME } from '../../common/constants'; -import { SectionError } from './components'; import { SECTION_SLUG } from './common/constants'; import { AppDependencies } from './app_dependencies'; -import { useAuthorization } from './hooks'; import { CloneTransformSection } from './sections/clone_transform'; import { CreateTransformSection } from './sections/create_transform'; import { TransformManagementSection } from './sections/transform_management'; -export const App: FC<{ history: ScopedHistory }> = ({ history }) => { - const { error } = useAuthorization(); - if (error !== null) { - return ( - - } - error={error} +export const App: FC<{ history: ScopedHistory }> = ({ history }) => ( + + + - ); - } - - return ( - - - - - - - - ); -}; + + + + +); export const renderApp = (element: HTMLElement, appDependencies: AppDependencies) => { const I18nContext = appDependencies.i18n.Context; diff --git a/x-pack/plugins/transform/public/app/components/capabilities_wrapper.tsx b/x-pack/plugins/transform/public/app/components/capabilities_wrapper.tsx new file mode 100644 index 0000000000000..df50691963648 --- /dev/null +++ b/x-pack/plugins/transform/public/app/components/capabilities_wrapper.tsx @@ -0,0 +1,64 @@ +/* + * 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 { + EuiFlexItem, + EuiFlexGroup, + EuiPageContent_Deprecated as EuiPageContent, + EuiEmptyPrompt, +} from '@elastic/eui'; + +import { FormattedMessage } from '@kbn/i18n-react'; + +import type { TransformCapability } from '../../../common/types/capabilities'; +import { toArray } from '../../../common/utils/to_array'; + +import { useTransformCapabilities } from '../hooks'; + +interface Props { + title: React.ReactNode; + message: React.ReactNode | string; +} + +export const NotAuthorizedSection = ({ title, message }: Props) => ( + {title}} body={

{message}

} /> +); + +const MissingCapabilities: FC = () => ( + + + + + } + message={ + + } + /> + + + +); + +export const CapabilitiesWrapper: FC<{ + requiredCapabilities: TransformCapability | TransformCapability[]; +}> = ({ children, requiredCapabilities }) => { + const capabilities = useTransformCapabilities(); + + const hasCapabilities = toArray(requiredCapabilities).every((c) => capabilities[c]); + + return hasCapabilities ? <>{children} : ; +}; diff --git a/x-pack/plugins/transform/public/app/components/index.ts b/x-pack/plugins/transform/public/app/components/index.ts index 7c3cb454aecb3..2edcf498e5832 100644 --- a/x-pack/plugins/transform/public/app/components/index.ts +++ b/x-pack/plugins/transform/public/app/components/index.ts @@ -5,6 +5,4 @@ * 2.0. */ -export { SectionError } from './section_error'; -export { SectionLoading } from './section_loading'; export { ToastNotificationText } from './toast_notification_text'; diff --git a/x-pack/plugins/transform/public/app/components/section_error.tsx b/x-pack/plugins/transform/public/app/components/section_error.tsx deleted file mode 100644 index fc7f6bbc14d72..0000000000000 --- a/x-pack/plugins/transform/public/app/components/section_error.tsx +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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 { EuiEmptyPrompt, EuiPageContent_Deprecated as EuiPageContent } from '@elastic/eui'; -import React from 'react'; - -interface Props { - title: React.ReactNode; - error: Error | null; - actions?: JSX.Element; -} - -export const SectionError: React.FunctionComponent = ({ - title, - error, - actions, - ...rest -}) => { - const errorMessage = error?.message ?? JSON.stringify(error, null, 2); - - return ( - - {title}} - body={ -

-

{errorMessage}
- {actions ? actions : null} -

- } - /> -
- ); -}; diff --git a/x-pack/plugins/transform/public/app/components/section_loading.tsx b/x-pack/plugins/transform/public/app/components/section_loading.tsx deleted file mode 100644 index c1548ad960bb0..0000000000000 --- a/x-pack/plugins/transform/public/app/components/section_loading.tsx +++ /dev/null @@ -1,48 +0,0 @@ -/* - * 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 from 'react'; - -import { - EuiEmptyPrompt, - EuiLoadingSpinner, - EuiText, - EuiFlexGroup, - EuiFlexItem, - EuiTextColor, -} from '@elastic/eui'; - -interface Props { - inline?: boolean; - children: React.ReactNode; - [key: string]: any; -} - -export const SectionLoading: React.FunctionComponent = ({ inline, children, ...rest }) => { - if (inline) { - return ( - - - - - - - {children} - - - - ); - } - - return ( - } - body={{children}} - data-test-subj="sectionLoading" - /> - ); -}; diff --git a/x-pack/plugins/transform/public/app/hooks/index.ts b/x-pack/plugins/transform/public/app/hooks/index.ts index f83574101ea9c..540ea7356e7aa 100644 --- a/x-pack/plugins/transform/public/app/hooks/index.ts +++ b/x-pack/plugins/transform/public/app/hooks/index.ts @@ -10,7 +10,6 @@ export { useDocumentationLinks } from './use_documentation_links'; export { useGetDataViewTitles } from './use_get_data_view_titles'; export { useGetEsIndices } from './use_get_es_indices'; export { useGetEsIngestPipelines } from './use_get_es_ingest_pipelines'; -export { useAuthorization } from './use_authorization'; export { useGetTransformAuditMessages } from './use_get_transform_audit_messages'; export { useGetTransform } from './use_get_transform'; export { useGetTransforms } from './use_get_transforms'; @@ -22,4 +21,5 @@ export { useSearchItems } from './use_search_items'; export { useScheduleNowTransforms } from './use_schedule_now_transform'; export { useStartTransforms } from './use_start_transform'; export { useStopTransforms } from './use_stop_transform'; +export { useTransformCapabilities } from './use_transform_capabilities'; export { useUpdateTransform } from './use_update_transform'; diff --git a/x-pack/plugins/transform/public/app/hooks/use_authorization.ts b/x-pack/plugins/transform/public/app/hooks/use_authorization.ts deleted file mode 100644 index bbb1bae7142bf..0000000000000 --- a/x-pack/plugins/transform/public/app/hooks/use_authorization.ts +++ /dev/null @@ -1,48 +0,0 @@ -/* - * 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 { useMemo } from 'react'; -import { useQuery } from '@tanstack/react-query'; - -import type { IHttpFetchError } from '@kbn/core-http-browser'; - -import { addInternalBasePath, TRANSFORM_REACT_QUERY_KEYS } from '../../../common/constants'; -import { - type PrivilegesAndCapabilities, - INITIAL_CAPABILITIES, -} from '../../../common/privilege/has_privilege_factory'; - -import { useAppDependencies } from '../app_dependencies'; - -export const useAuthorization = () => { - const { http } = useAppDependencies(); - - const { - error, - isLoading, - data = { - privileges: { - hasAllPrivileges: false, - missingPrivileges: {}, - }, - capabilities: INITIAL_CAPABILITIES, - }, - } = useQuery( - [TRANSFORM_REACT_QUERY_KEYS.GET_PRIVILEGES], - ({ signal }) => - http.fetch(addInternalBasePath(`privileges`), { - version: '1', - method: 'GET', - signal, - }) - ); - - return useMemo( - () => ({ error, isLoading, capabilities: data.capabilities, privileges: data.privileges }), - [error, isLoading, data.capabilities, data.privileges] - ); -}; diff --git a/x-pack/plugins/transform/public/app/hooks/use_delete_transform.tsx b/x-pack/plugins/transform/public/app/hooks/use_delete_transform.tsx index f5d3bbfa6e9f4..89bb3f5532b7a 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_delete_transform.tsx +++ b/x-pack/plugins/transform/public/app/hooks/use_delete_transform.tsx @@ -20,7 +20,7 @@ import type { import { getErrorMessage } from '../../../common/utils/errors'; import { useAppDependencies, useToastNotifications } from '../app_dependencies'; -import { useAuthorization } from './use_authorization'; +import { useTransformCapabilities } from './use_transform_capabilities'; import { useDataViewExists } from './use_data_view_exists'; import { useRefreshTransformList, type TransformListRow } from '../common'; import { ToastNotificationText } from '../components'; @@ -30,6 +30,7 @@ export const useDeleteIndexAndTargetIndex = (items: TransformListRow[]) => { application: { capabilities }, } = useAppDependencies(); const toastNotifications = useToastNotifications(); + const { canDeleteIndex: userCanDeleteIndex } = useTransformCapabilities(); const userCanDeleteDataView = (capabilities.savedObjectsManagement && capabilities.savedObjectsManagement.delete === true) || @@ -38,24 +39,6 @@ export const useDeleteIndexAndTargetIndex = (items: TransformListRow[]) => { const [deleteDestIndex, setDeleteDestIndex] = useState(true); const [deleteDataView, setDeleteDataView] = useState(userCanDeleteDataView); - const { error: canDeleteIndexError, privileges } = useAuthorization(); - const userCanDeleteIndex = privileges.hasAllPrivileges; - - useEffect(() => { - if (canDeleteIndexError !== null) { - toastNotifications.addDanger( - i18n.translate( - 'xpack.transform.transformList.errorWithCheckingIfUserCanDeleteIndexNotificationErrorMessage', - { - defaultMessage: 'An error occurred checking if user can delete destination index', - } - ) - ); - } - // custom comparison - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [canDeleteIndexError]); - const toggleDeleteIndex = useCallback( () => setDeleteDestIndex(!deleteDestIndex), [deleteDestIndex] diff --git a/x-pack/plugins/transform/public/app/hooks/use_transform_capabilities.ts b/x-pack/plugins/transform/public/app/hooks/use_transform_capabilities.ts new file mode 100644 index 0000000000000..482309ad2eac7 --- /dev/null +++ b/x-pack/plugins/transform/public/app/hooks/use_transform_capabilities.ts @@ -0,0 +1,16 @@ +/* + * 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 type { PrivilegesAndCapabilities } from '../../../common/types/capabilities'; + +import { useAppDependencies } from '../app_dependencies'; + +export const useTransformCapabilities = () => { + const { application } = useAppDependencies(); + + return application.capabilities.transform as PrivilegesAndCapabilities['capabilities']; +}; diff --git a/x-pack/plugins/transform/public/app/lib/authorization/components/index.ts b/x-pack/plugins/transform/public/app/lib/authorization/components/index.ts deleted file mode 100644 index 1b04f9287f2c4..0000000000000 --- a/x-pack/plugins/transform/public/app/lib/authorization/components/index.ts +++ /dev/null @@ -1,10 +0,0 @@ -/* - * 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. - */ - -export { createCapabilityFailureMessage } from '../../../../../common/privilege/has_privilege_factory'; -export { PrivilegesWrapper } from './with_privileges'; -export { NotAuthorizedSection } from './not_authorized_section'; diff --git a/x-pack/plugins/transform/public/app/lib/authorization/components/not_authorized_section.tsx b/x-pack/plugins/transform/public/app/lib/authorization/components/not_authorized_section.tsx deleted file mode 100644 index 4b0942276c028..0000000000000 --- a/x-pack/plugins/transform/public/app/lib/authorization/components/not_authorized_section.tsx +++ /dev/null @@ -1,18 +0,0 @@ -/* - * 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 from 'react'; -import { EuiEmptyPrompt } from '@elastic/eui'; - -interface Props { - title: React.ReactNode; - message: React.ReactNode | string; -} - -export const NotAuthorizedSection = ({ title, message }: Props) => ( - {title}} body={

{message}

} /> -); diff --git a/x-pack/plugins/transform/public/app/lib/authorization/components/with_privileges.tsx b/x-pack/plugins/transform/public/app/lib/authorization/components/with_privileges.tsx deleted file mode 100644 index 2623a6429da94..0000000000000 --- a/x-pack/plugins/transform/public/app/lib/authorization/components/with_privileges.tsx +++ /dev/null @@ -1,141 +0,0 @@ -/* - * 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 { - EuiFlexItem, - EuiFlexGroup, - EuiPageContent_Deprecated as EuiPageContent, -} from '@elastic/eui'; - -import { FormattedMessage } from '@kbn/i18n-react'; - -import { MissingPrivileges } from '../../../../../common/types/privileges'; - -import { SectionLoading } from '../../../components'; - -import { useAuthorization } from '../../../hooks'; -import { NotAuthorizedSection } from './not_authorized_section'; -import { - hasPrivilegeFactory, - toArray, - Privilege, -} from '../../../../../common/privilege/has_privilege_factory'; - -interface Props { - /** - * Each required privilege must have the format "section.privilege". - * To indicate that *all* privileges from a section are required, we can use the asterix - * e.g. "index.*" - */ - privileges: string | string[]; - children: (childrenProps: { - isLoading: boolean; - hasPrivileges: boolean; - privilegesMissing: MissingPrivileges; - }) => JSX.Element; -} - -export const WithPrivileges = ({ privileges: requiredPrivileges, children }: Props) => { - const { isLoading, privileges } = useAuthorization(); - - const privilegesToArray: Privilege[] = toArray(requiredPrivileges).map((p) => { - const [section, privilege] = p.split('.'); - if (!privilege) { - // Oh! we forgot to use the dot "." notation. - throw new Error('Required privilege must have the format "section.privilege"'); - } - return [section, privilege]; - }); - - const hasPrivilege = hasPrivilegeFactory(privileges); - const hasPrivileges = isLoading ? false : privilegesToArray.every(hasPrivilege); - - const privilegesMissing = privilegesToArray.reduce((acc, [section, privilege]) => { - if (privilege === '*') { - acc[section] = privileges.missingPrivileges[section] || []; - } else if ( - privileges.missingPrivileges[section] && - privileges.missingPrivileges[section]!.includes(privilege) - ) { - const missing: string[] = acc[section] || []; - acc[section] = [...missing, privilege]; - } - - return acc; - }, {} as MissingPrivileges); - - return children({ isLoading, hasPrivileges, privilegesMissing }); -}; - -interface MissingClusterPrivilegesProps { - missingPrivileges: string; - privilegesCount: number; -} - -const MissingClusterPrivileges: FC = ({ - missingPrivileges, - privilegesCount, -}) => ( - - - - - } - message={ - - } - /> - - - -); - -export const PrivilegesWrapper: FC<{ privileges: string | string[] }> = ({ - children, - privileges, -}) => ( - - {({ isLoading, hasPrivileges, privilegesMissing }) => { - if (isLoading) { - return ( - - - - ); - } - - if (!hasPrivileges) { - return ( - - ); - } - - return <>{children}; - }} - -); diff --git a/x-pack/plugins/transform/public/app/sections/clone_transform/clone_transform_section.tsx b/x-pack/plugins/transform/public/app/sections/clone_transform/clone_transform_section.tsx index 269adfd3eb266..7552c0da82895 100644 --- a/x-pack/plugins/transform/public/app/sections/clone_transform/clone_transform_section.tsx +++ b/x-pack/plugins/transform/public/app/sections/clone_transform/clone_transform_section.tsx @@ -20,7 +20,6 @@ import { EuiSpacer, } from '@elastic/eui'; -import { APP_CREATE_TRANSFORM_CLUSTER_PRIVILEGES } from '../../../../common/constants'; import { TransformConfigUnion } from '../../../../common/types/transform'; import { useGetTransform } from '../../hooks'; @@ -28,7 +27,7 @@ import { useDocumentationLinks } from '../../hooks/use_documentation_links'; import { useSearchItems } from '../../hooks/use_search_items'; import { breadcrumbService, docTitleService, BREADCRUMB_SECTION } from '../../services/navigation'; -import { PrivilegesWrapper } from '../../lib/authorization'; +import { CapabilitiesWrapper } from '../../components/capabilities_wrapper'; import { Wizard } from '../create_transform/components/wizard'; import { overrideTransformForCloning } from '../../common/transform'; @@ -119,7 +118,14 @@ export const CloneTransformSection: FC = ({ match, location }) => { ); return ( - + = ({ match, location }) => { )} - + ); }; diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/create_transform_section.tsx b/x-pack/plugins/transform/public/app/sections/create_transform/create_transform_section.tsx index a5c674a70745c..c09d7941f7ded 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/create_transform_section.tsx +++ b/x-pack/plugins/transform/public/app/sections/create_transform/create_transform_section.tsx @@ -18,12 +18,10 @@ import { EuiSpacer, } from '@elastic/eui'; -import { APP_CREATE_TRANSFORM_CLUSTER_PRIVILEGES } from '../../../../common/constants'; - import { useDocumentationLinks } from '../../hooks/use_documentation_links'; import { useSearchItems } from '../../hooks/use_search_items'; import { breadcrumbService, docTitleService, BREADCRUMB_SECTION } from '../../services/navigation'; -import { PrivilegesWrapper } from '../../lib/authorization'; +import { CapabilitiesWrapper } from '../../components/capabilities_wrapper'; import { Wizard } from './components/wizard'; @@ -54,7 +52,14 @@ export const CreateTransformSection: FC = ({ match }) => { ); return ( - + = ({ match }) => { )} {searchItems !== undefined && } - + ); }; diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_clone/clone_action_name.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_clone/clone_action_name.tsx index 9af861aaf5c40..21c33361e398b 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_clone/clone_action_name.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_clone/clone_action_name.tsx @@ -10,7 +10,7 @@ import React, { type FC } from 'react'; import { i18n } from '@kbn/i18n'; import { EuiToolTip } from '@elastic/eui'; -import { createCapabilityFailureMessage } from '../../../../lib/authorization'; +import { createCapabilityFailureMessage } from '../../../../../../common/utils/create_capability_failure_message'; export const cloneActionNameText = i18n.translate( 'xpack.transform.transformList.cloneActionNameText', diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_clone/use_clone_action.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_clone/use_clone_action.tsx index 08e698672be76..d78211e19bdb4 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_clone/use_clone_action.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_clone/use_clone_action.tsx @@ -11,7 +11,7 @@ import { i18n } from '@kbn/i18n'; import { TransformListAction, TransformListRow } from '../../../../common'; import { SECTION_SLUG } from '../../../../common/constants'; -import { useAuthorization, useSearchItems } from '../../../../hooks'; +import { useTransformCapabilities, useSearchItems } from '../../../../hooks'; import { useAppDependencies, useToastNotifications } from '../../../../app_dependencies'; import { cloneActionNameText, CloneActionName } from './clone_action_name'; @@ -25,7 +25,7 @@ export const useCloneAction = (forceDisable: boolean, transformNodes: number) => const { getDataViewIdByTitle, loadDataViews } = useSearchItems(undefined); - const { canCreateTransform } = useAuthorization().capabilities; + const { canCreateTransform } = useTransformCapabilities(); const clickHandler = useCallback( async (item: TransformListRow) => { diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_create_alert/create_alert_rule_action_name.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_create_alert/create_alert_rule_action_name.tsx index dde62aa8cbfda..fec35288d80b5 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_create_alert/create_alert_rule_action_name.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_create_alert/create_alert_rule_action_name.tsx @@ -10,7 +10,8 @@ import React, { type FC } from 'react'; import { EuiToolTip } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { createCapabilityFailureMessage } from '../../../../lib/authorization'; + +import { createCapabilityFailureMessage } from '../../../../../../common/utils/create_capability_failure_message'; interface CreateAlertRuleActionProps { disabled: boolean; diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_create_alert/use_create_alert_rule_action.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_create_alert/use_create_alert_rule_action.tsx index 7c2efa8cc645a..af75222fa85e7 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_create_alert/use_create_alert_rule_action.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_create_alert/use_create_alert_rule_action.tsx @@ -6,7 +6,7 @@ */ import React, { useCallback, useMemo } from 'react'; -import { useAuthorization } from '../../../../hooks'; +import { useTransformCapabilities } from '../../../../hooks'; import { TransformListAction, TransformListRow } from '../../../../common'; import { crateAlertRuleActionNameText, @@ -17,7 +17,7 @@ import { isContinuousTransform } from '../../../../../../common/types/transform' export type CreateAlertRuleAction = ReturnType; export const useCreateAlertRuleAction = (forceDisable: boolean) => { - const { canCreateTransformAlerts } = useAuthorization().capabilities; + const { canCreateTransformAlerts } = useTransformCapabilities(); const { setCreateAlertRule } = useAlertRuleFlyout(); const clickHandler = useCallback( diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_delete/delete_action_name.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_delete/delete_action_name.tsx index 24488ec60dcf2..93e346e6c7a1d 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_delete/delete_action_name.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_delete/delete_action_name.tsx @@ -8,9 +8,12 @@ import React, { type FC } from 'react'; import { i18n } from '@kbn/i18n'; + import { EuiToolTip } from '@elastic/eui'; + import { TransformState, TRANSFORM_STATE } from '../../../../../../common/constants'; -import { createCapabilityFailureMessage } from '../../../../lib/authorization'; +import { createCapabilityFailureMessage } from '../../../../../../common/utils/create_capability_failure_message'; + import { TransformListRow } from '../../../../common'; export const deleteActionNameText = i18n.translate( diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_delete/use_delete_action.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_delete/use_delete_action.tsx index 520428ca52a57..5996e271604e3 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_delete/use_delete_action.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_delete/use_delete_action.tsx @@ -13,7 +13,7 @@ import { TransformListAction, TransformListRow } from '../../../../common'; import { useDeleteIndexAndTargetIndex, useDeleteTransforms, - useAuthorization, + useTransformCapabilities, } from '../../../../hooks'; import { @@ -24,7 +24,7 @@ import { export type DeleteAction = ReturnType; export const useDeleteAction = (forceDisable: boolean) => { - const { canDeleteTransform } = useAuthorization().capabilities; + const { canDeleteTransform } = useTransformCapabilities(); const deleteTransforms = useDeleteTransforms(); diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_edit/edit_action_name.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_edit/edit_action_name.tsx index 5a95a9dfa7601..7fc16ebfff278 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_edit/edit_action_name.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_edit/edit_action_name.tsx @@ -11,8 +11,9 @@ import { i18n } from '@kbn/i18n'; import { EuiToolTip } from '@elastic/eui'; -import { createCapabilityFailureMessage } from '../../../../lib/authorization'; -import { useAuthorization } from '../../../../hooks'; +import { createCapabilityFailureMessage } from '../../../../../../common/utils/create_capability_failure_message'; + +import { useTransformCapabilities } from '../../../../hooks'; export const editActionNameText = i18n.translate( 'xpack.transform.transformList.editActionNameText', @@ -22,7 +23,7 @@ export const editActionNameText = i18n.translate( ); export const EditActionName: FC = () => { - const { canCreateTransform } = useAuthorization().capabilities; + const { canCreateTransform } = useTransformCapabilities(); if (!canCreateTransform) { return ( diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_edit/use_edit_action.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_edit/use_edit_action.tsx index e2da5262d9d28..40e7334197b0c 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_edit/use_edit_action.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_edit/use_edit_action.tsx @@ -10,7 +10,7 @@ import React, { useCallback, useMemo, useState } from 'react'; import { i18n } from '@kbn/i18n'; import { TransformListAction, TransformListRow } from '../../../../common'; -import { useAuthorization } from '../../../../hooks'; +import { useTransformCapabilities } from '../../../../hooks'; import { editActionNameText, EditActionName } from './edit_action_name'; import { useSearchItems } from '../../../../hooks/use_search_items'; @@ -19,7 +19,7 @@ import { TransformConfigUnion } from '../../../../../../common/types/transform'; export type EditAction = ReturnType; export const useEditAction = (forceDisable: boolean, transformNodes: number) => { - const { canCreateTransform } = useAuthorization().capabilities; + const { canCreateTransform } = useTransformCapabilities(); const [config, setConfig] = useState(); const [isFlyoutVisible, setIsFlyoutVisible] = useState(false); diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_reauthorize/reauthorize_action_name.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_reauthorize/reauthorize_action_name.tsx index 5e47fbc64c87b..ee883a3e7e77b 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_reauthorize/reauthorize_action_name.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_reauthorize/reauthorize_action_name.tsx @@ -6,11 +6,15 @@ */ import React, { type FC } from 'react'; -import { i18n } from '@kbn/i18n'; + import { EuiToolTip, EuiText } from '@elastic/eui'; + +import { i18n } from '@kbn/i18n'; + +import { createCapabilityFailureMessage } from '../../../../../../common/utils/create_capability_failure_message'; + import { needsReauthorization } from '../../../../common/reauthorization_utils'; -import { createCapabilityFailureMessage } from '../../../../lib/authorization'; -import { useAuthorization } from '../../../../hooks'; +import { useTransformCapabilities } from '../../../../hooks'; import { TransformListRow } from '../../../../common'; export const reauthorizeActionNameText = i18n.translate( @@ -43,7 +47,7 @@ export const ReauthorizeActionName: FC = ({ forceDisable, transformNodes, }) => { - const { canStartStopTransform } = useAuthorization().capabilities; + const { canStartStopTransform } = useTransformCapabilities(); // Disable start for batch transforms which have completed. const someNeedsReauthorization = items.some(needsReauthorization); diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_reauthorize/use_reauthorize_action.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_reauthorize/use_reauthorize_action.tsx index fcfc0da7564bd..67e618765e42e 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_reauthorize/use_reauthorize_action.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_reauthorize/use_reauthorize_action.tsx @@ -17,11 +17,11 @@ import { } from './reauthorize_action_name'; import { TransformListAction, TransformListRow } from '../../../../common'; -import { useAuthorization } from '../../../../hooks'; +import { useTransformCapabilities } from '../../../../hooks'; export type ReauthorizeAction = ReturnType; export const useReauthorizeAction = (forceDisable: boolean, transformNodes: number) => { - const { canStartStopTransform } = useAuthorization().capabilities; + const { canStartStopTransform } = useTransformCapabilities(); const reauthorizeTransforms = useReauthorizeTransforms(); diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_reset/reset_action_name.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_reset/reset_action_name.tsx index 030b1cad14c65..6d5f56d3e7297 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_reset/reset_action_name.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_reset/reset_action_name.tsx @@ -7,10 +7,13 @@ import React, { type FC } from 'react'; -import { i18n } from '@kbn/i18n'; import { EuiToolTip } from '@elastic/eui'; + +import { i18n } from '@kbn/i18n'; + import { TransformState, TRANSFORM_STATE } from '../../../../../../common/constants'; -import { createCapabilityFailureMessage } from '../../../../lib/authorization'; +import { createCapabilityFailureMessage } from '../../../../../../common/utils/create_capability_failure_message'; + import { TransformListRow } from '../../../../common'; export const resetActionNameText = i18n.translate( diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_reset/use_reset_action.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_reset/use_reset_action.tsx index a1f10bb801cdf..23a399fdb9086 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_reset/use_reset_action.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_reset/use_reset_action.tsx @@ -10,13 +10,13 @@ import React, { useMemo, useState } from 'react'; import { TRANSFORM_STATE } from '../../../../../../common/constants'; import { TransformListAction, TransformListRow } from '../../../../common'; -import { useAuthorization, useResetTransforms } from '../../../../hooks'; +import { useTransformCapabilities, useResetTransforms } from '../../../../hooks'; import { resetActionNameText, isResetActionDisabled, ResetActionName } from './reset_action_name'; export type ResetAction = ReturnType; export const useResetAction = (forceDisable: boolean) => { - const { canResetTransform } = useAuthorization().capabilities; + const { canResetTransform } = useTransformCapabilities(); const resetTransforms = useResetTransforms(); diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_schedule_now/schedule_now_action_name.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_schedule_now/schedule_now_action_name.tsx index ca3931603df4c..0c3be1cdad70b 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_schedule_now/schedule_now_action_name.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_schedule_now/schedule_now_action_name.tsx @@ -6,11 +6,14 @@ */ import React, { type FC } from 'react'; -import { i18n } from '@kbn/i18n'; + import { EuiToolTip } from '@elastic/eui'; -import { createCapabilityFailureMessage } from '../../../../lib/authorization'; -import { useAuthorization } from '../../../../hooks'; +import { i18n } from '@kbn/i18n'; + +import { createCapabilityFailureMessage } from '../../../../../../common/utils/create_capability_failure_message'; + +import { useTransformCapabilities } from '../../../../hooks'; import { TransformListRow, isCompletedBatchTransform } from '../../../../common'; export const scheduleNowActionNameText = i18n.translate( @@ -46,7 +49,7 @@ export const ScheduleNowActionName: FC = ({ forceDisable, transformNodes, }) => { - const { canScheduleNowTransform } = useAuthorization().capabilities; + const { canScheduleNowTransform } = useTransformCapabilities(); const isBulkAction = items.length > 1; // Disable schedule-now for batch transforms which have completed. diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_schedule_now/use_schedule_now_action.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_schedule_now/use_schedule_now_action.tsx index 858cadc246f5e..a13d3da89f677 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_schedule_now/use_schedule_now_action.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_schedule_now/use_schedule_now_action.tsx @@ -9,7 +9,7 @@ import React, { useMemo } from 'react'; import { TRANSFORM_STATE } from '../../../../../../common/constants'; -import { useAuthorization } from '../../../../hooks'; +import { useTransformCapabilities } from '../../../../hooks'; import { TransformListAction, TransformListRow } from '../../../../common'; import { useScheduleNowTransforms } from '../../../../hooks'; @@ -21,7 +21,7 @@ import { export type ScheduleNowAction = ReturnType; export const useScheduleNowAction = (forceDisable: boolean, transformNodes: number) => { - const { canScheduleNowTransform } = useAuthorization().capabilities; + const { canScheduleNowTransform } = useTransformCapabilities(); const scheduleNowTransforms = useScheduleNowTransforms(); const action: TransformListAction = useMemo( diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_start/start_action_name.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_start/start_action_name.tsx index 2a4fa01d63084..c50c83d25edc5 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_start/start_action_name.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_start/start_action_name.tsx @@ -10,9 +10,9 @@ import { i18n } from '@kbn/i18n'; import { EuiToolTip } from '@elastic/eui'; import { TRANSFORM_STATE } from '../../../../../../common/constants'; +import { createCapabilityFailureMessage } from '../../../../../../common/utils/create_capability_failure_message'; -import { createCapabilityFailureMessage } from '../../../../lib/authorization'; -import { useAuthorization } from '../../../../hooks'; +import { useTransformCapabilities } from '../../../../hooks'; import { TransformListRow, isCompletedBatchTransform } from '../../../../common'; export const startActionNameText = i18n.translate( @@ -53,7 +53,7 @@ export const StartActionName: FC = ({ forceDisable, transformNodes, }) => { - const { canStartStopTransform } = useAuthorization().capabilities; + const { canStartStopTransform } = useTransformCapabilities(); const isBulkAction = items.length > 1; // Disable start for batch transforms which have completed. diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_start/use_start_action.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_start/use_start_action.tsx index 31b5a555cd333..168174730b706 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_start/use_start_action.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_start/use_start_action.tsx @@ -10,13 +10,13 @@ import React, { useMemo, useState } from 'react'; import { TRANSFORM_STATE } from '../../../../../../common/constants'; import { TransformListAction, TransformListRow } from '../../../../common'; -import { useAuthorization, useStartTransforms } from '../../../../hooks'; +import { useTransformCapabilities, useStartTransforms } from '../../../../hooks'; import { isStartActionDisabled, startActionNameText, StartActionName } from './start_action_name'; export type StartAction = ReturnType; export const useStartAction = (forceDisable: boolean, transformNodes: number) => { - const { canStartStopTransform } = useAuthorization().capabilities; + const { canStartStopTransform } = useTransformCapabilities(); const startTransforms = useStartTransforms(); diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_stop/stop_action_name.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_stop/stop_action_name.tsx index 71b98a825b6ba..e5bc1425cdd99 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_stop/stop_action_name.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_stop/stop_action_name.tsx @@ -10,10 +10,10 @@ import { i18n } from '@kbn/i18n'; import { EuiToolTip } from '@elastic/eui'; import { TRANSFORM_STATE } from '../../../../../../common/constants'; +import { createCapabilityFailureMessage } from '../../../../../../common/utils/create_capability_failure_message'; import { TransformListRow } from '../../../../common'; -import { createCapabilityFailureMessage } from '../../../../lib/authorization'; -import { useAuthorization } from '../../../../hooks'; +import { useTransformCapabilities } from '../../../../hooks'; export const stopActionNameText = i18n.translate( 'xpack.transform.transformList.stopActionNameText', @@ -41,7 +41,7 @@ export interface StopActionNameProps { } export const StopActionName: FC = ({ items, forceDisable }) => { const isBulkAction = items.length > 1; - const { canStartStopTransform } = useAuthorization().capabilities; + const { canStartStopTransform } = useTransformCapabilities(); // Disable stop action if one of the transforms is stopped already const stoppedTransform = items.some( diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_stop/use_stop_action.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_stop/use_stop_action.tsx index 8d7d4251a4802..e410704341177 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_stop/use_stop_action.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_stop/use_stop_action.tsx @@ -8,14 +8,14 @@ import React, { useCallback, useMemo, useState } from 'react'; import { TRANSFORM_STATE } from '../../../../../../common/constants'; import { TransformListAction, TransformListRow } from '../../../../common'; -import { useAuthorization, useStopTransforms } from '../../../../hooks'; +import { useTransformCapabilities, useStopTransforms } from '../../../../hooks'; import { isStopActionDisabled, stopActionNameText, StopActionName } from './stop_action_name'; import { isManagedTransform } from '../../../../common/managed_transforms_utils'; export type StopAction = ReturnType; export const useStopAction = (forceDisable: boolean) => { - const { canStartStopTransform } = useAuthorization().capabilities; + const { canStartStopTransform } = useTransformCapabilities(); const stopTransforms = useStopTransforms(); const [isModalVisible, setModalVisible] = useState(false); const [items, setItems] = useState([]); diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/create_transform_button/create_transform_button.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/create_transform_button/create_transform_button.tsx index 3340dc10a0d02..9c1fa4be8c101 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/create_transform_button/create_transform_button.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/create_transform_button/create_transform_button.tsx @@ -11,8 +11,9 @@ import { EuiButton, EuiToolTip } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; -import { createCapabilityFailureMessage } from '../../../../lib/authorization'; -import { useAuthorization } from '../../../../hooks'; +import { createCapabilityFailureMessage } from '../../../../../../common/utils/create_capability_failure_message'; + +import { useTransformCapabilities } from '../../../../hooks'; interface CreateTransformButtonProps { onClick: MouseEventHandler; @@ -23,7 +24,7 @@ export const CreateTransformButton: FC = ({ onClick, transformNodes, }) => { - const { capabilities } = useAuthorization(); + const capabilities = useTransformCapabilities(); const disabled = !capabilities.canCreateTransform || diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_list.test.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_list.test.tsx index c9ab7234a6d74..10b8dc747db36 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_list.test.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_list.test.tsx @@ -12,26 +12,12 @@ import * as ReactQuery from '@tanstack/react-query'; import { __IntlProvider as IntlProvider } from '@kbn/i18n-react'; -import { INITIAL_CAPABILITIES } from '../../../../../../common/privilege/has_privilege_factory'; - import { TransformList } from './transform_list'; const useQueryMock = jest.spyOn(ReactQuery, 'useQuery').mockImplementation((queryKey) => { switch (queryKey[0]) { case 'transform.data_view_exists': return { error: null, data: true } as UseQueryResult; - case 'transform.get_privileges': - return { - error: null, - isLoading: false, - data: { - privileges: { - hasAllPrivileges: true, - missingPrivileges: {}, - }, - capabilities: INITIAL_CAPABILITIES, - }, - } as UseQueryResult; } return { error: null, data: undefined } as UseQueryResult; diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_list.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_list.tsx index c48d6f1affe69..93a60c484a47e 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_list.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_list.tsx @@ -39,7 +39,7 @@ import { type TransformListRow, TRANSFORM_LIST_COLUMN, } from '../../../../common'; -import { useAuthorization } from '../../../../hooks'; +import { useTransformCapabilities } from '../../../../hooks'; import { CreateTransformButton } from '../create_transform_button'; import { RefreshTransformListButton } from '../refresh_transform_list_button'; @@ -147,7 +147,7 @@ export const TransformList: FC = ({ const bulkStopAction = useStopAction(false); const bulkScheduleNowAction = useScheduleNowAction(false, transformNodes); - const { capabilities } = useAuthorization(); + const capabilities = useTransformCapabilities(); const disabled = !capabilities.canCreateTransform || !capabilities.canPreviewTransform || diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/use_columns.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/use_columns.tsx index 7c743da1e7f3d..2ae8edf30a1de 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/use_columns.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/use_columns.tsx @@ -24,7 +24,7 @@ import { EuiIcon, } from '@elastic/eui'; -import { useAuthorization } from '../../../../hooks'; +import { useTransformCapabilities } from '../../../../hooks'; import { needsReauthorization } from '../../../../common/reauthorization_utils'; import { isLatestTransform, @@ -52,7 +52,7 @@ export const useColumns = ( transformNodes: number, transformSelection: TransformListRow[] ) => { - const { canStartStopTransform } = useAuthorization().capabilities; + const { canStartStopTransform } = useTransformCapabilities(); const { actions, modals } = useActions({ forceDisable: transformSelection.length > 0, diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/transform_management_section.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/transform_management_section.tsx index 39dbc8b0f10f5..ad0e791ddef07 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/transform_management_section.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/transform_management_section.tsx @@ -21,15 +21,12 @@ import { } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { needsReauthorization } from '../../common/reauthorization_utils'; -import { - APP_GET_TRANSFORM_CLUSTER_PRIVILEGES, - TRANSFORM_STATE, -} from '../../../../common/constants'; +import { TRANSFORM_STATE } from '../../../../common/constants'; import { useDocumentationLinks } from '../../hooks'; -import { useDeleteTransforms, useAuthorization, useGetTransforms } from '../../hooks'; +import { useDeleteTransforms, useTransformCapabilities, useGetTransforms } from '../../hooks'; import { RedirectToCreateTransform } from '../../common/navigation'; -import { PrivilegesWrapper } from '../../lib/authorization'; +import { CapabilitiesWrapper } from '../../components/capabilities_wrapper'; import { breadcrumbService, docTitleService, BREADCRUMB_SECTION } from '../../services/navigation'; import { SearchSelection } from './components/search_selection'; @@ -53,7 +50,7 @@ export const TransformManagement: FC = () => { data: { transforms, transformNodes, transformIdsWithoutConfig }, } = useGetTransforms(); - const { canStartStopTransform } = useAuthorization().capabilities; + const { canStartStopTransform } = useTransformCapabilities(); const unauthorizedTransformsWarning = useMemo(() => { const unauthorizedCnt = transforms.filter((t) => needsReauthorization(t)).length; @@ -236,8 +233,8 @@ export const TransformManagementSection: FC = () => { }, []); return ( - + - + ); }; diff --git a/x-pack/plugins/transform/server/capabilities.ts b/x-pack/plugins/transform/server/capabilities.ts index 73889a0808359..5fd542d428a70 100644 --- a/x-pack/plugins/transform/server/capabilities.ts +++ b/x-pack/plugins/transform/server/capabilities.ts @@ -7,22 +7,123 @@ import type { CoreSetup } from '@kbn/core-lifecycle-server'; import { SecurityPluginSetup } from '@kbn/security-plugin/server'; +import { isPopulatedObject } from '@kbn/ml-is-populated-object'; + import { - getPrivilegesAndCapabilities, - INITIAL_CAPABILITIES, -} from '../common/privilege/has_privilege_factory'; -import { APP_CLUSTER_PRIVILEGES } from '../common/constants'; + getInitialTransformCapabilities, + type Privilege, + type Privileges, + type PrivilegesAndCapabilities, +} from '../common/types/capabilities'; +import { APP_CLUSTER_PRIVILEGES, APP_INDEX_PRIVILEGES } from '../common/constants'; + import type { PluginStartDependencies } from './types'; export const TRANSFORM_PLUGIN_ID = 'transform' as const; +function isPrivileges(arg: unknown): arg is Privileges { + return ( + isPopulatedObject(arg, ['hasAllPrivileges', 'missingPrivileges']) && + typeof arg.hasAllPrivileges === 'boolean' && + typeof arg.missingPrivileges === 'object' && + arg.missingPrivileges !== null + ); +} + +export const hasPrivilegeFactory = + (privileges: Privileges | undefined | null) => (privilege: Privilege) => { + const [section, requiredPrivilege] = privilege; + if (isPrivileges(privileges) && !privileges.missingPrivileges[section]) { + // if the section does not exist in our missingPrivileges, everything is OK + return true; + } + if (isPrivileges(privileges) && privileges.missingPrivileges[section]!.length === 0) { + return true; + } + if (requiredPrivilege === '*') { + // If length > 0 and we require them all... KO + return false; + } + // If we require _some_ privilege, we make sure that the one + // we require is *not* in the missingPrivilege array + return ( + isPrivileges(privileges) && + !privileges.missingPrivileges[section]!.includes(requiredPrivilege) + ); + }; + +export const extractMissingPrivileges = ( + privilegesObject: { [key: string]: boolean } = {} +): string[] => + Object.keys(privilegesObject).reduce((privileges: string[], privilegeName: string): string[] => { + if (!privilegesObject[privilegeName]) { + privileges.push(privilegeName); + } + return privileges; + }, []); + +export const getPrivilegesAndCapabilities = ( + clusterPrivileges: Record, + hasOneIndexWithAllPrivileges: boolean, + hasAllPrivileges: boolean +): PrivilegesAndCapabilities => { + const privilegesResult: Privileges = { + hasAllPrivileges: true, + missingPrivileges: { + cluster: [], + index: [], + }, + }; + + // Find missing cluster privileges and set overall app privileges + privilegesResult.missingPrivileges.cluster = extractMissingPrivileges(clusterPrivileges); + privilegesResult.hasAllPrivileges = hasAllPrivileges; + + if (!hasOneIndexWithAllPrivileges) { + privilegesResult.missingPrivileges.index = [...APP_INDEX_PRIVILEGES]; + } + + const hasPrivilege = hasPrivilegeFactory(privilegesResult); + + const capabilities = getInitialTransformCapabilities(); + + capabilities.canGetTransform = + hasPrivilege(['cluster', 'cluster:monitor/transform/get']) && + hasPrivilege(['cluster', 'cluster:monitor/transform/stats/get']); + + capabilities.canCreateTransform = hasPrivilege(['cluster', 'cluster:admin/transform/put']); + + capabilities.canDeleteTransform = hasPrivilege(['cluster', 'cluster:admin/transform/delete']); + + capabilities.canResetTransform = hasPrivilege(['cluster', 'cluster:admin/transform/reset']); + + capabilities.canPreviewTransform = hasPrivilege(['cluster', 'cluster:admin/transform/preview']); + + capabilities.canStartStopTransform = + hasPrivilege(['cluster', 'cluster:admin/transform/start']) && + hasPrivilege(['cluster', 'cluster:admin/transform/start_task']) && + hasPrivilege(['cluster', 'cluster:admin/transform/stop']); + + capabilities.canCreateTransformAlerts = capabilities.canCreateTransform; + + capabilities.canUseTransformAlerts = capabilities.canGetTransform; + + capabilities.canScheduleNowTransform = capabilities.canStartStopTransform; + + capabilities.canReauthorizeTransform = capabilities.canStartStopTransform; + + capabilities.canDeleteIndex = hasAllPrivileges; + + return { privileges: privilegesResult, capabilities }; +}; + export const setupCapabilities = ( core: Pick, 'capabilities' | 'getStartServices'>, securitySetup?: SecurityPluginSetup ) => { core.capabilities.registerProvider(() => { return { - transform: INITIAL_CAPABILITIES, + transform: getInitialTransformCapabilities(), }; }); @@ -38,10 +139,7 @@ export const setupCapabilities = ( // If security is not enabled or not available, transform should have full permission if (!isSecurityPluginEnabled || !securityStart) { return { - transform: Object.keys(INITIAL_CAPABILITIES).reduce>((acc, p) => { - acc[p] = true; - return acc; - }, {}), + transform: getInitialTransformCapabilities(true), }; } @@ -71,6 +169,8 @@ export const setupCapabilities = ( hasAllRequested ).capabilities; - return { transform: transformCapabilities }; + return { + transform: transformCapabilities as Record>, + }; }); }; diff --git a/x-pack/plugins/transform/common/privilege/has_privilege_factory.test.ts b/x-pack/plugins/transform/server/capabiltiies.test.ts similarity index 99% rename from x-pack/plugins/transform/common/privilege/has_privilege_factory.test.ts rename to x-pack/plugins/transform/server/capabiltiies.test.ts index e9fa6cd7bc6d7..0523be0846917 100644 --- a/x-pack/plugins/transform/common/privilege/has_privilege_factory.test.ts +++ b/x-pack/plugins/transform/server/capabiltiies.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { extractMissingPrivileges, getPrivilegesAndCapabilities } from './has_privilege_factory'; +import { extractMissingPrivileges, getPrivilegesAndCapabilities } from './capabilities'; describe('has_privilege_factory', () => { const fullClusterPrivileges = { diff --git a/x-pack/plugins/transform/server/routes/api/privileges.ts b/x-pack/plugins/transform/server/routes/api/privileges.ts deleted file mode 100644 index 0b93c8e503fc6..0000000000000 --- a/x-pack/plugins/transform/server/routes/api/privileges.ts +++ /dev/null @@ -1,84 +0,0 @@ -/* - * 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 type { IKibanaResponse, IScopedClusterClient } from '@kbn/core/server'; -import type { SecurityHasPrivilegesResponse } from '@elastic/elasticsearch/lib/api/types'; -import { - getPrivilegesAndCapabilities, - type PrivilegesAndCapabilities, -} from '../../../common/privilege/has_privilege_factory'; -import { - addInternalBasePath, - APP_CLUSTER_PRIVILEGES, - APP_INDEX_PRIVILEGES, -} from '../../../common/constants'; - -import type { RouteDependencies } from '../../types'; - -export function registerPrivilegesRoute({ router, license }: RouteDependencies) { - router.versioned - .get({ - path: addInternalBasePath('privileges'), - access: 'internal', - }) - .addVersion( - { - version: '1', - validate: false, - }, - license.guardApiRoute( - async (ctx, req, res): Promise> => { - if (license.getStatus().isSecurityEnabled === false) { - // If security isn't enabled, let the user use app. - return res.ok({ - body: getPrivilegesAndCapabilities({}, true, true), - }); - } - - const esClient: IScopedClusterClient = (await ctx.core).elasticsearch.client; - - const esClusterPrivilegesReq: Promise = - esClient.asCurrentUser.security.hasPrivileges({ - body: { - cluster: APP_CLUSTER_PRIVILEGES, - }, - }); - const [esClusterPrivileges, userPrivileges] = await Promise.all([ - // Get cluster privileges - esClusterPrivilegesReq, - // // Get all index privileges the user has - esClient.asCurrentUser.security.getUserPrivileges(), - ]); - - const { has_all_requested: hasAllPrivileges, cluster } = esClusterPrivileges; - const { indices } = userPrivileges; - - // Check if they have all the required index privileges for at least one index - const hasOneIndexWithAllPrivileges = - indices.find(({ privileges }: { privileges: string[] }) => { - if (privileges.includes('all')) { - return true; - } - - const indexHasAllPrivileges = APP_INDEX_PRIVILEGES.every((privilege) => - privileges.includes(privilege) - ); - - return indexHasAllPrivileges; - }) !== undefined; - - return res.ok({ - body: getPrivilegesAndCapabilities( - cluster, - hasOneIndexWithAllPrivileges, - hasAllPrivileges - ), - }); - } - ) - ); -} diff --git a/x-pack/plugins/transform/server/routes/index.ts b/x-pack/plugins/transform/server/routes/index.ts index 0a8539c7683de..aec4417f2a421 100644 --- a/x-pack/plugins/transform/server/routes/index.ts +++ b/x-pack/plugins/transform/server/routes/index.ts @@ -8,11 +8,9 @@ import { RouteDependencies } from '../types'; import { registerFieldHistogramsRoutes } from './api/field_histograms'; -import { registerPrivilegesRoute } from './api/privileges'; import { registerTransformsRoutes } from './api/transforms'; export function registerRoutes(dependencies: RouteDependencies) { registerFieldHistogramsRoutes(dependencies); - registerPrivilegesRoute(dependencies); registerTransformsRoutes(dependencies); } From 9d44654919c4a1bed668100237fdec6edc948445 Mon Sep 17 00:00:00 2001 From: Walter Rafelsberger Date: Fri, 25 Aug 2023 10:56:16 +0200 Subject: [PATCH 33/53] fix jest tests --- .../plugins/transform/common/types/capabilities.ts | 9 +++++++++ .../public/app/hooks/use_transform_capabilities.ts | 12 ++++++++++-- .../transform_list/transform_list.test.tsx | 2 +- .../transform_management_section.test.tsx | 2 +- .../{capabiltiies.test.ts => capabilities.test.ts} | 11 ++++++++--- 5 files changed, 29 insertions(+), 7 deletions(-) rename x-pack/plugins/transform/server/{capabiltiies.test.ts => capabilities.test.ts} (94%) diff --git a/x-pack/plugins/transform/common/types/capabilities.ts b/x-pack/plugins/transform/common/types/capabilities.ts index a790fd563327c..ae5e241e3b0fe 100644 --- a/x-pack/plugins/transform/common/types/capabilities.ts +++ b/x-pack/plugins/transform/common/types/capabilities.ts @@ -5,6 +5,8 @@ * 2.0. */ +import { isPopulatedObject } from '@kbn/ml-is-populated-object'; + export const getInitialTransformCapabilities = (initialSetting = false) => ({ canCreateTransform: initialSetting, canCreateTransformAlerts: initialSetting, @@ -19,6 +21,13 @@ export const getInitialTransformCapabilities = (initialSetting = false) => ({ canUseTransformAlerts: initialSetting, }); +export const isTransformCapabilities = (arg: unknown): arg is TransformCapabilities => { + return ( + isPopulatedObject(arg, Object.keys(getInitialTransformCapabilities())) && + Object.values(arg).every((d) => typeof d === 'boolean') + ); +}; + export type TransformCapabilities = ReturnType; export type TransformCapability = keyof TransformCapabilities; diff --git a/x-pack/plugins/transform/public/app/hooks/use_transform_capabilities.ts b/x-pack/plugins/transform/public/app/hooks/use_transform_capabilities.ts index 482309ad2eac7..4483568bb85c1 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_transform_capabilities.ts +++ b/x-pack/plugins/transform/public/app/hooks/use_transform_capabilities.ts @@ -5,12 +5,20 @@ * 2.0. */ -import type { PrivilegesAndCapabilities } from '../../../common/types/capabilities'; +import { + getInitialTransformCapabilities, + isTransformCapabilities, + type TransformCapabilities, +} from '../../../common/types/capabilities'; import { useAppDependencies } from '../app_dependencies'; export const useTransformCapabilities = () => { const { application } = useAppDependencies(); - return application.capabilities.transform as PrivilegesAndCapabilities['capabilities']; + if (isTransformCapabilities(application?.capabilities?.transform)) { + return application.capabilities.transform as TransformCapabilities; + } + + return getInitialTransformCapabilities(); }; diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_list.test.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_list.test.tsx index 10b8dc747db36..9ba5f8abaa36d 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_list.test.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_list.test.tsx @@ -46,7 +46,7 @@ describe('Transform: Transform List ', () => { ); await waitFor(() => { - expect(useQueryMock).toHaveBeenCalledTimes(22); + expect(useQueryMock).toHaveBeenCalledTimes(4); expect(container.textContent).toContain('Reload'); }); }); diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/transform_management_section.test.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/transform_management_section.test.tsx index 61e268aeb25ff..3782bc9e9dfb3 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/transform_management_section.test.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/transform_management_section.test.tsx @@ -24,6 +24,6 @@ describe('Transform: ', () => { ); - expect(container.textContent).toBe('Checking privileges…'); + expect(container.textContent).toContain('Missing permission'); }); }); diff --git a/x-pack/plugins/transform/server/capabiltiies.test.ts b/x-pack/plugins/transform/server/capabilities.test.ts similarity index 94% rename from x-pack/plugins/transform/server/capabiltiies.test.ts rename to x-pack/plugins/transform/server/capabilities.test.ts index 0523be0846917..5cf194d6e84e3 100644 --- a/x-pack/plugins/transform/server/capabiltiies.test.ts +++ b/x-pack/plugins/transform/server/capabilities.test.ts @@ -5,6 +5,8 @@ * 2.0. */ +import { type TransformCapabilities } from '../common/types/capabilities'; + import { extractMissingPrivileges, getPrivilegesAndCapabilities } from './capabilities'; describe('has_privilege_factory', () => { @@ -65,9 +67,10 @@ describe('has_privilege_factory', () => { describe('getPrivilegesAndCapabilities', () => { it('returns full capabilities if provided both monitor and admin cluster privileges', () => { - const fullCapabilities = { + const fullCapabilities: TransformCapabilities = { canCreateTransform: true, canCreateTransformAlerts: true, + canDeleteIndex: true, canDeleteTransform: true, canGetTransform: true, canPreviewTransform: true, @@ -91,9 +94,10 @@ describe('has_privilege_factory', () => { }); }); it('returns view only capabilities if provided only monitor cluster privileges', () => { - const viewOnlyCapabilities = { + const viewOnlyCapabilities: TransformCapabilities = { canCreateTransform: false, canCreateTransformAlerts: false, + canDeleteIndex: false, canDeleteTransform: false, canGetTransform: true, canPreviewTransform: false, @@ -119,9 +123,10 @@ describe('has_privilege_factory', () => { }); }); it('returns no capabilities and all the missing privileges if no cluster privileges', () => { - const noCapabilities = { + const noCapabilities: TransformCapabilities = { canCreateTransform: false, canCreateTransformAlerts: false, + canDeleteIndex: false, canDeleteTransform: false, canGetTransform: false, canPreviewTransform: false, From 6beaef4d53b113a549c56821622a0ce0ee075f5f Mon Sep 17 00:00:00 2001 From: Walter Rafelsberger Date: Fri, 25 Aug 2023 10:58:34 +0200 Subject: [PATCH 34/53] fix i18n --- x-pack/plugins/translations/translations/fr-FR.json | 5 ----- x-pack/plugins/translations/translations/ja-JP.json | 5 ----- x-pack/plugins/translations/translations/zh-CN.json | 5 ----- 3 files changed, 15 deletions(-) diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index ad1003a6f7cf9..2c6931c58e50b 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -37776,7 +37776,6 @@ "xpack.transform.alertTypes.transformHealth.healthCheckRecoveryMessage": "La/les {count, plural, one {Transformer} many {Transformations} other {Transformations}} {transformsString} {count, plural, one {est} many {sont} other {sont}} saine(s).", "xpack.transform.alertTypes.transformHealth.notStartedMessage": "La/les {count, plural, one {Transformer} many {Transformer} other {Transformer}} {transformsString} {count, plural, one {est} many {sont} other {ne sont pas démarrées}}.", "xpack.transform.alertTypes.transformHealth.notStartedRecoveryMessage": "La/les {count, plural, one {Transformer} many {Transformer} other {Transformer}} {transformsString} {count, plural, one {est} many {sont} other {sont}} lancée(s).", - "xpack.transform.app.deniedPrivilegeDescription": "Pour utiliser cette section des transformations, vous devez avoir {privilegesCount, plural, one {ce privilège de cluster} many {ces privilèges de cluster} other {ces privilèges de cluster}} : {missingPrivileges}.", "xpack.transform.capability.pleaseContactAdministratorTooltip": "{message} Veuillez contacter votre administrateur.", "xpack.transform.clone.noDataViewErrorPromptText": "Impossible de cloner la transformation {transformId}. Il n'existe aucune vue de données pour {dataViewTitle}.", "xpack.transform.danglingTasksError": "{count} {count, plural, one {transformation n'a pas de} many {transformations n'ont pas de} other {transformations n'ont pas de}} détails de configuration : [{transformIds}] {count, plural, one {Elle ne peut pas être récupérée et doit être supprimée} many {Elles ne peuvent pas être récupérées et doivent être supprimées} other {Elles ne peuvent pas être récupérées et doivent être supprimées}}.", @@ -37870,9 +37869,6 @@ "xpack.transform.alertTypes.transformHealth.notStartedCheckName": "La transformation n'a pas démarré", "xpack.transform.alertTypes.transformHealth.testsConfigTransforms.errorMessage": "Au moins une vérification d'intégrité doit être sélectionnée", "xpack.transform.alertTypes.transformHealth.testsSelection.enableTestLabel": "Activer", - "xpack.transform.app.checkingPrivilegesDescription": "Vérification des privilèges…", - "xpack.transform.app.checkingPrivilegesErrorMessage": "Erreur lors de la récupération des privilèges utilisateur depuis le serveur", - "xpack.transform.app.deniedPrivilegeTitle": "Vous ne disposez pas de privilèges de cluster", "xpack.transform.appName": "Transformations", "xpack.transform.appTitle": "Transformations", "xpack.transform.capability.noPermission.canCreateTransformAlertsTooltip": "Vous ne disposez pas d'autorisation pour créer des règles d'alerte de transformation.", @@ -38150,7 +38146,6 @@ "xpack.transform.transformList.editFlyoutUpdateButtonText": "Mettre à jour", "xpack.transform.transformList.editManagedTransformsDescription": "modification", "xpack.transform.transformList.editTransformGenericErrorMessage": "Une erreur s'est produite lors de l'appel du point de terminaison de l'API pour mettre à jour les transformations.", - "xpack.transform.transformList.errorWithCheckingIfUserCanDeleteIndexNotificationErrorMessage": "Une erreur s'est produite lors de la vérification de la possibilité pour un utilisateur de supprimer l'index de destination", "xpack.transform.transformList.managedBadgeLabel": "Géré", "xpack.transform.transformList.managedBadgeTooltip": "Cette transformation est préconfigurée et gérée par Elastic. Les autres éléments du produit peuvent dépendre de ce comportement.", "xpack.transform.transformList.needsReauthorizationBadge.contactAdminTooltip": "Contactez votre administrateur pour demander les autorisations requises.", diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 38725eebe2427..403ec0becfce9 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -37775,7 +37775,6 @@ "xpack.transform.alertTypes.transformHealth.healthCheckRecoveryMessage": "{count, plural, other {トランスフォーム}} {transformsString} {count, plural, other {あります}}は正常です。", "xpack.transform.alertTypes.transformHealth.notStartedMessage": "{count, plural, other {トランスフォーム}}\"{transformsString}\"{count, plural, other {あります}}開始されていません。", "xpack.transform.alertTypes.transformHealth.notStartedRecoveryMessage": "{count, plural, other {トランスフォーム}}\"{transformsString}\"{count, plural, other {あります}}開始しました。", - "xpack.transform.app.deniedPrivilegeDescription": "変換のこのセクションを使用するには、{privilegesCount, plural, other {これらのクラスター権限}}が必要です:{missingPrivileges}", "xpack.transform.capability.pleaseContactAdministratorTooltip": "{message} 管理者にお問い合わせください。", "xpack.transform.clone.noDataViewErrorPromptText": "トランスフォーム{transformId}を複製できません。{dataViewTitle}のデータビューは存在しません。", "xpack.transform.danglingTasksError": "{count}個の{count, plural, other {変換}}に構成の詳細がありません:[{transformIds}]。{count, plural, other {それら}}回復できないため、削除してください。", @@ -37869,9 +37868,6 @@ "xpack.transform.alertTypes.transformHealth.notStartedCheckName": "トランスフォームが開始していません", "xpack.transform.alertTypes.transformHealth.testsConfigTransforms.errorMessage": "1つ以上の正常性チェックを選択する必要があります", "xpack.transform.alertTypes.transformHealth.testsSelection.enableTestLabel": "有効にする", - "xpack.transform.app.checkingPrivilegesDescription": "権限を確認中…", - "xpack.transform.app.checkingPrivilegesErrorMessage": "サーバーからユーザー特権を取得しているときにエラーが発生しました", - "xpack.transform.app.deniedPrivilegeTitle": "クラスター特権が足りません", "xpack.transform.appName": "トランスフォーム", "xpack.transform.appTitle": "トランスフォーム", "xpack.transform.capability.noPermission.canCreateTransformAlertsTooltip": "トランスフォームアラートルールを作成するアクセス権がありません。", @@ -38149,7 +38145,6 @@ "xpack.transform.transformList.editFlyoutUpdateButtonText": "更新", "xpack.transform.transformList.editManagedTransformsDescription": "編集中", "xpack.transform.transformList.editTransformGenericErrorMessage": "トランスフォームを削除するためのAPIエンドポイントの呼び出し中にエラーが発生しました。", - "xpack.transform.transformList.errorWithCheckingIfUserCanDeleteIndexNotificationErrorMessage": "ユーザーがディスティネーションインデックスを削除できるかどうかを確認するときにエラーが発生しました。", "xpack.transform.transformList.managedBadgeLabel": "管理中", "xpack.transform.transformList.managedBadgeTooltip": "このトランスフォームはElasticによってあらかじめ構成および管理されています。製品の他の部分はその動作に依存関係が存在している場合があります。", "xpack.transform.transformList.needsReauthorizationBadge.contactAdminTooltip": "必要な権限をリクエストするには、管理者に問い合わせてください。", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 25f2c6216187a..da2c3259c2fec 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -37769,7 +37769,6 @@ "xpack.transform.alertTypes.transformHealth.healthCheckRecoveryMessage": "{count, plural, other {转换}} {transformsString}{count, plural, other {有}}运行正常。", "xpack.transform.alertTypes.transformHealth.notStartedMessage": "{count, plural, other {转换}} {transformsString}{count, plural, other {有}}未启动。", "xpack.transform.alertTypes.transformHealth.notStartedRecoveryMessage": "{count, plural, other {转换}} {transformsString}{count, plural, other {有}}已启动。", - "xpack.transform.app.deniedPrivilegeDescription": "要使用“转换”部分,必须具有{privilegesCount, plural, other {以下集群权限}}:{missingPrivileges}。", "xpack.transform.capability.pleaseContactAdministratorTooltip": "{message}请联系您的管理员。", "xpack.transform.clone.noDataViewErrorPromptText": "无法克隆转换 {transformId}。对于 {dataViewTitle},不存在数据视图。", "xpack.transform.danglingTasksError": "{count} 个{count, plural, other {转换}}缺少配置详情:[{transformIds}] 无法将{count, plural, other {其}}恢复,应予以删除。", @@ -37863,9 +37862,6 @@ "xpack.transform.alertTypes.transformHealth.notStartedCheckName": "转换未启动", "xpack.transform.alertTypes.transformHealth.testsConfigTransforms.errorMessage": "必须至少选择一次运行状况检查", "xpack.transform.alertTypes.transformHealth.testsSelection.enableTestLabel": "启用", - "xpack.transform.app.checkingPrivilegesDescription": "正在检查权限……", - "xpack.transform.app.checkingPrivilegesErrorMessage": "从服务器获取用户权限时出错", - "xpack.transform.app.deniedPrivilegeTitle": "您缺少集群权限", "xpack.transform.appName": "转换", "xpack.transform.appTitle": "转换", "xpack.transform.capability.noPermission.canCreateTransformAlertsTooltip": "您无权创建转换告警规则。", @@ -38143,7 +38139,6 @@ "xpack.transform.transformList.editFlyoutUpdateButtonText": "更新", "xpack.transform.transformList.editManagedTransformsDescription": "正在编辑", "xpack.transform.transformList.editTransformGenericErrorMessage": "调用用于更新转换的 API 终端时发生错误。", - "xpack.transform.transformList.errorWithCheckingIfUserCanDeleteIndexNotificationErrorMessage": "检查用户是否可以删除目标索引时发生错误", "xpack.transform.transformList.managedBadgeLabel": "托管", "xpack.transform.transformList.managedBadgeTooltip": "此转换由 Elastic 预配置和管理;该产品的其他部分可能依赖于其行为。", "xpack.transform.transformList.needsReauthorizationBadge.contactAdminTooltip": "请联系管理员请求所需权限。", From b4da48b1f228685f51c499a1bc6f7db72124f5b4 Mon Sep 17 00:00:00 2001 From: Walter Rafelsberger Date: Fri, 25 Aug 2023 15:40:11 +0200 Subject: [PATCH 35/53] error modal --- .../components/toast_notification_text.tsx | 24 ++++++-- .../transform_list/transform_list.test.tsx | 1 - .../transform_list/transform_list.tsx | 33 +---------- .../transform_management_section.tsx | 58 +++++++++++++++++-- 4 files changed, 73 insertions(+), 43 deletions(-) diff --git a/x-pack/plugins/transform/public/app/components/toast_notification_text.tsx b/x-pack/plugins/transform/public/app/components/toast_notification_text.tsx index ca9079745fe3d..75559ba561ed9 100644 --- a/x-pack/plugins/transform/public/app/components/toast_notification_text.tsx +++ b/x-pack/plugins/transform/public/app/components/toast_notification_text.tsx @@ -32,6 +32,8 @@ interface ToastNotificationTextProps { theme: CoreStart['theme']; text: any; previewTextLength?: number; + inline?: boolean; + forceModal?: boolean; } export const ToastNotificationText: FC = ({ @@ -39,12 +41,15 @@ export const ToastNotificationText: FC = ({ text, theme, previewTextLength, + inline = false, + forceModal = false, }) => { - if (typeof text === 'string' && text.length <= MAX_SIMPLE_MESSAGE_LENGTH) { + if (!forceModal && typeof text === 'string' && text.length <= MAX_SIMPLE_MESSAGE_LENGTH) { return text; } if ( + !forceModal && typeof text === 'object' && typeof text.message === 'string' && text.message.length <= MAX_SIMPLE_MESSAGE_LENGTH @@ -52,8 +57,9 @@ export const ToastNotificationText: FC = ({ return text.message; } - const unformattedText = text.message ? text.message : text; - const formattedText = typeof unformattedText === 'object' ? JSON.stringify(text, null, 2) : text; + const unformattedText = typeof text === 'object' && text.message ? text.message : text; + const formattedText = + typeof unformattedText === 'object' ? JSON.stringify(text, null, 2) : unformattedText; const textLength = previewTextLength ?? 140; const previewText = `${formattedText.substring(0, textLength)}${ formattedText.length > textLength ? ' ...' : '' @@ -90,8 +96,16 @@ export const ToastNotificationText: FC = ({ return ( <> -
{previewText}
- + {!inline && ( + <> +
{previewText}
{' '} + + )} + {i18n.translate('xpack.transform.toastText.openModalButtonText', { defaultMessage: 'View details', })} diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_list.test.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_list.test.tsx index 9ba5f8abaa36d..efa34261d3731 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_list.test.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_list.test.tsx @@ -34,7 +34,6 @@ describe('Transform: Transform List ', () => { = ({ errorMessage }) => ( - <> - - - } - color="danger" - iconType="error" - > -

- -

{JSON.stringify(errorMessage)}
- -

-
- - -); - type ItemIdToExpandedRowMap = Record; function getItemIdToExpandedRowMap( @@ -116,7 +91,6 @@ function getItemIdToExpandedRowMap( } interface TransformListProps { - errorMessage: any; isLoading: boolean; onCreateTransform: MouseEventHandler; transformNodes: number; @@ -125,7 +99,6 @@ interface TransformListProps { } export const TransformList: FC = ({ - errorMessage, isLoading, onCreateTransform, transformNodes, @@ -170,10 +143,7 @@ export const TransformList: FC = ({ const filteredTransforms = clauses.length > 0 ? filterTransforms(transforms, clauses) : transforms; - const errorMessageInsert = - errorMessage !== null ? : null; - - if (transforms.length === 0 && errorMessage === null) { + if (transforms.length === 0) { return ( @@ -382,7 +352,6 @@ export const TransformList: FC = ({ {/* Single Action Modals */} {singleActionModals} - {errorMessage !== null && errorMessageInsert} | null }> = ({ + errorMessage, +}) => { + const { overlays, theme } = useAppDependencies(); + const [isModalVisible, setIsModalVisible] = useState(false); + + return ( + <> + + + {' '} + {errorMessage !== null && ( + + )} + + } + color="danger" + iconType="error" + /> + {isModalVisible && ( + setIsModalVisible(false)} + className="transformListErrorMessageModal" + data-test-subj="transformSelectSourceModal" + > +
{JSON.stringify(errorMessage)}
+
+ )} + + ); +}; + export const TransformManagement: FC = () => { const { esTransform } = useDocumentationLinks(); @@ -141,14 +189,15 @@ export const TransformManagement: FC = () => { bottomBorder /> - - {isInitialLoading && } {!isInitialLoading && ( <> {unauthorizedTransformsWarning} + {errorMessage !== null && } + + @@ -199,7 +248,6 @@ export const TransformManagement: FC = () => { ) : null} Date: Fri, 25 Aug 2023 16:08:35 +0200 Subject: [PATCH 36/53] migrate to updated toMountPoint --- .../components/toast_notification_text.tsx | 14 ++-- .../public/app/hooks/use_create_transform.tsx | 12 ++-- .../public/app/hooks/use_delete_transform.tsx | 52 +++++---------- .../app/hooks/use_reauthorize_transform.tsx | 12 ++-- .../public/app/hooks/use_reset_transform.tsx | 29 ++++----- .../app/hooks/use_schedule_now_transform.tsx | 12 ++-- .../public/app/hooks/use_start_transform.tsx | 12 ++-- .../public/app/hooks/use_stop_transform.tsx | 12 ++-- .../step_create/step_create_form.tsx | 32 ++++------ .../step_details/step_details_form.tsx | 64 +++++++------------ 10 files changed, 98 insertions(+), 153 deletions(-) diff --git a/x-pack/plugins/transform/public/app/components/toast_notification_text.tsx b/x-pack/plugins/transform/public/app/components/toast_notification_text.tsx index 75559ba561ed9..c94666b244094 100644 --- a/x-pack/plugins/transform/public/app/components/toast_notification_text.tsx +++ b/x-pack/plugins/transform/public/app/components/toast_notification_text.tsx @@ -19,17 +19,13 @@ import { import { i18n } from '@kbn/i18n'; -import { CoreStart } from '@kbn/core/public'; +import { toMountPoint } from '@kbn/react-kibana-mount'; -import { toMountPoint } from '@kbn/kibana-react-plugin/public'; +import { useAppDependencies } from '../app_dependencies'; const MAX_SIMPLE_MESSAGE_LENGTH = 140; -// Because of the use of `toMountPoint`, `useKibanaContext` doesn't work via `useAppDependencies`. -// That's why we need to pass in `overlays` as a prop cannot get it via context. interface ToastNotificationTextProps { - overlays: CoreStart['overlays']; - theme: CoreStart['theme']; text: any; previewTextLength?: number; inline?: boolean; @@ -37,13 +33,13 @@ interface ToastNotificationTextProps { } export const ToastNotificationText: FC = ({ - overlays, text, - theme, previewTextLength, inline = false, forceModal = false, }) => { + const { overlays, theme, i18n: i18nStart } = useAppDependencies(); + if (!forceModal && typeof text === 'string' && text.length <= MAX_SIMPLE_MESSAGE_LENGTH) { return text; } @@ -89,7 +85,7 @@ export const ToastNotificationText: FC = ({
, - { theme$: theme.theme$ } + { theme, i18n: i18nStart } ) ); }; diff --git a/x-pack/plugins/transform/public/app/hooks/use_create_transform.tsx b/x-pack/plugins/transform/public/app/hooks/use_create_transform.tsx index 06d90a50d04f0..064f6fa6450e2 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_create_transform.tsx +++ b/x-pack/plugins/transform/public/app/hooks/use_create_transform.tsx @@ -9,7 +9,7 @@ import React from 'react'; import { useMutation } from '@tanstack/react-query'; import { i18n } from '@kbn/i18n'; -import { toMountPoint } from '@kbn/kibana-react-plugin/public'; +import { toMountPoint } from '@kbn/react-kibana-mount'; import type { PutTransformsRequestSchema, @@ -27,7 +27,7 @@ export const useCreateTransform = ( transformId: TransformId, transformConfig: PutTransformsRequestSchema ) => { - const { http, overlays, theme } = useAppDependencies(); + const { http, i18n: i18nStart, theme } = useAppDependencies(); const refreshTransformList = useRefreshTransformList(); const toastNotifications = useToastNotifications(); @@ -37,10 +37,10 @@ export const useCreateTransform = ( defaultMessage: 'An error occurred creating the transform {transformId}:', values: { transformId }, }), - text: toMountPoint( - , - { theme$: theme.theme$ } - ), + text: toMountPoint(, { + theme, + i18n: i18nStart, + }), }); } diff --git a/x-pack/plugins/transform/public/app/hooks/use_delete_transform.tsx b/x-pack/plugins/transform/public/app/hooks/use_delete_transform.tsx index 89bb3f5532b7a..ba70a9470fd1e 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_delete_transform.tsx +++ b/x-pack/plugins/transform/public/app/hooks/use_delete_transform.tsx @@ -9,7 +9,7 @@ import React, { useCallback, useEffect, useState } from 'react'; import { useMutation } from '@tanstack/react-query'; import { i18n } from '@kbn/i18n'; -import { toMountPoint } from '@kbn/kibana-react-plugin/public'; +import { toMountPoint } from '@kbn/react-kibana-mount'; import { extractErrorMessage } from '@kbn/ml-error-utils'; import { addInternalBasePath } from '../../../common/constants'; @@ -85,7 +85,7 @@ export const useDeleteIndexAndTargetIndex = (items: TransformListRow[]) => { }; export const useDeleteTransforms = () => { - const { http, overlays, theme } = useAppDependencies(); + const { http, i18n: i18nStart, theme } = useAppDependencies(); const refreshTransformList = useRefreshTransformList(); const toastNotifications = useToastNotifications(); @@ -101,13 +101,8 @@ export const useDeleteTransforms = () => { defaultMessage: 'An error occurred calling the API endpoint to delete transforms.', }), text: toMountPoint( - , - { theme$: theme.theme$ } + , + { theme, i18n: i18nStart } ), }), onSuccess: (results) => { @@ -124,15 +119,10 @@ export const useDeleteTransforms = () => { defaultMessage: 'An error occurred deleting the transform {transformId}', values: { transformId }, }), - text: toMountPoint( - , - { theme$: theme.theme$ } - ), + text: toMountPoint(, { + theme, + i18n: i18nStart, + }), }); } @@ -146,15 +136,10 @@ export const useDeleteTransforms = () => { values: { destinationIndex }, } ), - text: toMountPoint( - , - { theme$: theme.theme$ } - ), + text: toMountPoint(, { + theme, + i18n: i18nStart, + }), }); } @@ -168,15 +153,10 @@ export const useDeleteTransforms = () => { values: { destinationIndex }, } ), - text: toMountPoint( - , - { theme$: theme.theme$ } - ), + text: toMountPoint(, { + theme, + i18n: i18nStart, + }), }); } } diff --git a/x-pack/plugins/transform/public/app/hooks/use_reauthorize_transform.tsx b/x-pack/plugins/transform/public/app/hooks/use_reauthorize_transform.tsx index 8de8318df5794..6bf0157591e6d 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_reauthorize_transform.tsx +++ b/x-pack/plugins/transform/public/app/hooks/use_reauthorize_transform.tsx @@ -10,7 +10,7 @@ import { useMutation } from '@tanstack/react-query'; import { i18n } from '@kbn/i18n'; -import { toMountPoint } from '@kbn/kibana-react-plugin/public'; +import { toMountPoint } from '@kbn/react-kibana-mount'; import { addInternalBasePath } from '../../../common/constants'; import { getErrorMessage } from '../../../common/utils/errors'; @@ -24,7 +24,7 @@ import { useRefreshTransformList } from '../common'; import { ToastNotificationText } from '../components'; export const useReauthorizeTransforms = () => { - const { http, overlays, theme } = useAppDependencies(); + const { http, i18n: i18nStart, theme } = useAppDependencies(); const refreshTransformList = useRefreshTransformList(); const toastNotifications = useToastNotifications(); @@ -45,10 +45,10 @@ export const useReauthorizeTransforms = () => { defaultMessage: 'An error occurred calling the reauthorize transforms request.', } ), - text: toMountPoint( - , - { theme$: theme.theme$ } - ), + text: toMountPoint(, { + theme, + i18n: i18nStart, + }), }), onSuccess: (results) => { for (const transformId in results) { diff --git a/x-pack/plugins/transform/public/app/hooks/use_reset_transform.tsx b/x-pack/plugins/transform/public/app/hooks/use_reset_transform.tsx index 6bfde68a99ba1..8c717c76f7a66 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_reset_transform.tsx +++ b/x-pack/plugins/transform/public/app/hooks/use_reset_transform.tsx @@ -9,7 +9,7 @@ import React from 'react'; import { useMutation } from '@tanstack/react-query'; import { i18n } from '@kbn/i18n'; -import { toMountPoint } from '@kbn/kibana-react-plugin/public'; +import { toMountPoint } from '@kbn/react-kibana-mount'; import type { ResetTransformsRequestSchema, @@ -22,7 +22,7 @@ import { useRefreshTransformList } from '../common'; import { ToastNotificationText } from '../components'; export const useResetTransforms = () => { - const { http, overlays, theme } = useAppDependencies(); + const { http, i18n: i18nStart, theme } = useAppDependencies(); const refreshTransformList = useRefreshTransformList(); const toastNotifications = useToastNotifications(); @@ -38,13 +38,11 @@ export const useResetTransforms = () => { defaultMessage: 'An error occurred calling the API endpoint to reset transforms.', }), text: toMountPoint( - , - { theme$: theme.theme$ } + , + { + theme, + i18n: i18nStart, + } ), }), onSuccess: (results) => { @@ -60,15 +58,10 @@ export const useResetTransforms = () => { defaultMessage: 'An error occurred resetting the transform {transformId}', values: { transformId }, }), - text: toMountPoint( - , - { theme$: theme.theme$ } - ), + text: toMountPoint(, { + theme, + i18n: i18nStart, + }), }); } } diff --git a/x-pack/plugins/transform/public/app/hooks/use_schedule_now_transform.tsx b/x-pack/plugins/transform/public/app/hooks/use_schedule_now_transform.tsx index ff75f34fcc716..2e0c220781725 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_schedule_now_transform.tsx +++ b/x-pack/plugins/transform/public/app/hooks/use_schedule_now_transform.tsx @@ -9,7 +9,7 @@ import React from 'react'; import { useMutation } from '@tanstack/react-query'; import { i18n } from '@kbn/i18n'; -import { toMountPoint } from '@kbn/kibana-react-plugin/public'; +import { toMountPoint } from '@kbn/react-kibana-mount'; import { addInternalBasePath } from '../../../common/constants'; import type { @@ -23,7 +23,7 @@ import { useRefreshTransformList } from '../common'; import { ToastNotificationText } from '../components'; export const useScheduleNowTransforms = () => { - const { http, overlays, theme } = useAppDependencies(); + const { http, i18n: i18nStart, theme } = useAppDependencies(); const refreshTransformList = useRefreshTransformList(); const toastNotifications = useToastNotifications(); @@ -45,10 +45,10 @@ export const useScheduleNowTransforms = () => { 'An error occurred calling the request to schedule the transform to process data instantly.', } ), - text: toMountPoint( - , - { theme$: theme.theme$ } - ), + text: toMountPoint(, { + theme, + i18n: i18nStart, + }), }), onSuccess: (results) => { for (const transformId in results) { diff --git a/x-pack/plugins/transform/public/app/hooks/use_start_transform.tsx b/x-pack/plugins/transform/public/app/hooks/use_start_transform.tsx index 1413aa278edfd..8f81bb5b479c7 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_start_transform.tsx +++ b/x-pack/plugins/transform/public/app/hooks/use_start_transform.tsx @@ -9,7 +9,7 @@ import React from 'react'; import { useMutation } from '@tanstack/react-query'; import { i18n } from '@kbn/i18n'; -import { toMountPoint } from '@kbn/kibana-react-plugin/public'; +import { toMountPoint } from '@kbn/react-kibana-mount'; import { addInternalBasePath } from '../../../common/constants'; import type { @@ -23,7 +23,7 @@ import { useRefreshTransformList } from '../common'; import { ToastNotificationText } from '../components'; export const useStartTransforms = () => { - const { http, overlays, theme } = useAppDependencies(); + const { http, i18n: i18nStart, theme } = useAppDependencies(); const refreshTransformList = useRefreshTransformList(); const toastNotifications = useToastNotifications(); @@ -41,10 +41,10 @@ export const useStartTransforms = () => { defaultMessage: 'An error occurred calling the start transforms request.', } ), - text: toMountPoint( - , - { theme$: theme.theme$ } - ), + text: toMountPoint(, { + theme, + i18n: i18nStart, + }), }), onSuccess: (results) => { for (const transformId in results) { diff --git a/x-pack/plugins/transform/public/app/hooks/use_stop_transform.tsx b/x-pack/plugins/transform/public/app/hooks/use_stop_transform.tsx index b2c4826cae292..69a258f28a86d 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_stop_transform.tsx +++ b/x-pack/plugins/transform/public/app/hooks/use_stop_transform.tsx @@ -10,7 +10,7 @@ import { useMutation } from '@tanstack/react-query'; import { i18n } from '@kbn/i18n'; -import { toMountPoint } from '@kbn/kibana-react-plugin/public'; +import { toMountPoint } from '@kbn/react-kibana-mount'; import { addInternalBasePath } from '../../../common/constants'; import type { @@ -24,7 +24,7 @@ import { useRefreshTransformList } from '../common'; import { ToastNotificationText } from '../components'; export const useStopTransforms = () => { - const { http, overlays, theme } = useAppDependencies(); + const { http, i18n: i18nStart, theme } = useAppDependencies(); const refreshTransformList = useRefreshTransformList(); const toastNotifications = useToastNotifications(); @@ -42,10 +42,10 @@ export const useStopTransforms = () => { defaultMessage: 'An error occurred called the stop transforms request.', } ), - text: toMountPoint( - , - { theme$: theme.theme$ } - ), + text: toMountPoint(, { + theme, + i18n: i18nStart, + }), }), onSuccess: (results) => { for (const transformId in results) { diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_create/step_create_form.tsx b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_create/step_create_form.tsx index 2b0487beb8b2d..a51dfffa7e77a 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_create/step_create_form.tsx +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_create/step_create_form.tsx @@ -24,7 +24,7 @@ import { } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; -import { toMountPoint } from '@kbn/kibana-react-plugin/public'; +import { toMountPoint } from '@kbn/react-kibana-mount'; import { DISCOVER_APP_LOCATOR } from '@kbn/discover-plugin/common'; @@ -86,11 +86,10 @@ export const StepCreateForm: FC = React.memo( ); const [discoverLink, setDiscoverLink] = useState(); - const deps = useAppDependencies(); - const { share } = deps; - const dataViews = deps.data.dataViews; const toastNotifications = useToastNotifications(); - const isDiscoverAvailable = deps.application.capabilities.discover?.show ?? false; + const { application, data, i18n: i18nStart, share, theme } = useAppDependencies(); + const dataViews = data.dataViews; + const isDiscoverAvailable = application.capabilities.discover?.show ?? false; useEffect(() => { let unmounted = false; @@ -122,7 +121,6 @@ export const StepCreateForm: FC = React.memo( // eslint-disable-next-line react-hooks/exhaustive-deps }, [created, started, dataViewId]); - const { overlays, theme } = useAppDependencies(); const startTransforms = useStartTransforms(); const createTransform = useCreateTransform(transformId, transformConfig); @@ -194,10 +192,10 @@ export const StepCreateForm: FC = React.memo( defaultMessage: 'An error occurred creating the Kibana data view {dataViewName}:', values: { dataViewName }, }), - text: toMountPoint( - , - { theme$: theme.theme$ } - ), + text: toMountPoint(, { + theme, + i18n: i18nStart, + }), }); setLoading(false); return false; @@ -253,17 +251,13 @@ export const StepCreateForm: FC = React.memo( title: i18n.translate('xpack.transform.stepCreateForm.progressErrorMessage', { defaultMessage: 'An error occurred getting the progress percentage:', }), - text: toMountPoint( - , - { theme$: theme.theme$ } - ), + text: toMountPoint(, { + theme, + i18n: i18nStart, + }), }); } - }, [overlays, stats, theme, toastNotifications, transformConfig, transformId]); + }, [i18nStart, stats, theme, toastNotifications, transformConfig, transformId]); function getTransformConfigDevConsoleStatement() { return `PUT _transform/${transformId}\n${JSON.stringify(transformConfig, null, 2)}\n\n`; diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_details/step_details_form.tsx b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_details/step_details_form.tsx index 41cf150f47bc6..48fa750db7113 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_details/step_details_form.tsx +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_details/step_details_form.tsx @@ -25,7 +25,7 @@ import { } from '@elastic/eui'; import { KBN_FIELD_TYPES } from '@kbn/field-types'; -import { toMountPoint } from '@kbn/kibana-react-plugin/public'; +import { toMountPoint } from '@kbn/react-kibana-mount'; import { retentionPolicyMaxAgeInvalidErrorMessage } from '../../../../common/constants/validation_messages'; import { DEFAULT_TRANSFORM_FREQUENCY } from '../../../../../../common/constants'; @@ -73,8 +73,8 @@ interface StepDetailsFormProps { export const StepDetailsForm: FC = React.memo( ({ overrides = {}, onChange, searchItems, stepDefineState }) => { - const deps = useAppDependencies(); - const { capabilities } = deps.application; + const { application, i18n: i18nStart, theme } = useAppDependencies(); + const { capabilities } = application; const toastNotifications = useToastNotifications(); const { esIndicesCreateIndex } = useDocumentationLinks(); @@ -121,8 +121,6 @@ export const StepDetailsForm: FC = React.memo( [setDataViewTimeField, dataViewAvailableTimeFields] ); - const { overlays, theme } = useAppDependencies(); - const { error: transformsError, data: { transformIds }, @@ -134,17 +132,15 @@ export const StepDetailsForm: FC = React.memo( title: i18n.translate('xpack.transform.stepDetailsForm.errorGettingTransformList', { defaultMessage: 'An error occurred getting the existing transform IDs:', }), - text: toMountPoint( - , - { theme$: theme.theme$ } - ), + text: toMountPoint(, { + theme, + i18n: i18nStart, + }), }); } - }, [transformsError, overlays, theme, toastNotifications]); + // custom comparison + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [transformsError]); const previewRequest = useMemo(() => { const { searchQuery, previewRequest: partialPreviewRequest } = stepDefineState; @@ -178,16 +174,14 @@ export const StepDetailsForm: FC = React.memo( defaultMessage: 'An error occurred fetching the transform preview', }), text: toMountPoint( - , - { theme$: theme.theme$ } + , + { theme, i18n: i18nStart } ), }); } - }, [overlays, theme, toastNotifications, transformsPreviewError]); + // custom comparison + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [transformsPreviewError]); const { error: esIndicesError, data: esIndicesData } = useGetEsIndices(); const indexNames = esIndicesData?.map((index) => index.name) ?? []; @@ -198,14 +192,10 @@ export const StepDetailsForm: FC = React.memo( title: i18n.translate('xpack.transform.stepDetailsForm.errorGettingIndexNames', { defaultMessage: 'An error occurred getting the existing index names:', }), - text: toMountPoint( - , - { theme$: theme.theme$ } - ), + text: toMountPoint(, { + theme, + i18n: i18nStart, + }), }); } // custom comparison @@ -223,12 +213,8 @@ export const StepDetailsForm: FC = React.memo( defaultMessage: 'An error occurred getting the existing ingest pipeline names:', }), text: toMountPoint( - , - { theme$: theme.theme$ } + , + { theme, i18n: i18nStart } ), }); } @@ -245,12 +231,8 @@ export const StepDetailsForm: FC = React.memo( defaultMessage: 'An error occurred getting the existing data view titles:', }), text: toMountPoint( - , - { theme$: theme.theme$ } + , + { theme, i18n: i18nStart } ), }); } From c4d181181f1c0b7344df1c5c2e140038100a71a1 Mon Sep 17 00:00:00 2001 From: Walter Rafelsberger Date: Fri, 25 Aug 2023 16:56:10 +0200 Subject: [PATCH 37/53] linting --- x-pack/plugins/transform/tsconfig.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/transform/tsconfig.json b/x-pack/plugins/transform/tsconfig.json index 9c9ef2299c60d..2d0cdf45c554d 100644 --- a/x-pack/plugins/transform/tsconfig.json +++ b/x-pack/plugins/transform/tsconfig.json @@ -67,7 +67,8 @@ "@kbn/saved-search-plugin", "@kbn/unified-field-list", "@kbn/ebt-tools", - "@kbn/content-management-plugin" + "@kbn/content-management-plugin", + "@kbn/react-kibana-mount" ], "exclude": [ "target/**/*", From ed56944422f00daf0e4fd019416168a51d930014 Mon Sep 17 00:00:00 2001 From: Walter Rafelsberger Date: Fri, 25 Aug 2023 16:56:59 +0200 Subject: [PATCH 38/53] tweak react-query default settings --- x-pack/plugins/transform/common/constants.ts | 1 - x-pack/plugins/transform/public/app/app.tsx | 5 ++--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/x-pack/plugins/transform/common/constants.ts b/x-pack/plugins/transform/common/constants.ts index e7acb401f6282..fd073c5f474f4 100644 --- a/x-pack/plugins/transform/common/constants.ts +++ b/x-pack/plugins/transform/common/constants.ts @@ -10,7 +10,6 @@ import { i18n } from '@kbn/i18n'; import { LicenseType } from '@kbn/licensing-plugin/common/types'; import { TransformHealthTests } from './types/alerting'; -export const REACT_QUERY_STALE_TIME = 10000; export const DEFAULT_REFRESH_INTERVAL_MS = 30000; export const MINIMUM_REFRESH_INTERVAL_MS = 1000; export const PROGRESS_REFRESH_INTERVAL_MS = 2000; diff --git a/x-pack/plugins/transform/public/app/app.tsx b/x-pack/plugins/transform/public/app/app.tsx index 8e13f45df1c04..505009784d26e 100644 --- a/x-pack/plugins/transform/public/app/app.tsx +++ b/x-pack/plugins/transform/public/app/app.tsx @@ -15,8 +15,6 @@ import { Router, Routes, Route } from '@kbn/shared-ux-router'; import { ScopedHistory } from '@kbn/core/public'; import { KibanaContextProvider, KibanaThemeProvider } from '@kbn/kibana-react-plugin/public'; -import { REACT_QUERY_STALE_TIME } from '../../common/constants'; - import { SECTION_SLUG } from './common/constants'; import { AppDependencies } from './app_dependencies'; import { CloneTransformSection } from './sections/clone_transform'; @@ -45,7 +43,8 @@ export const renderApp = (element: HTMLElement, appDependencies: AppDependencies const queryClient = new QueryClient({ defaultOptions: { queries: { - staleTime: REACT_QUERY_STALE_TIME, + staleTime: Infinity, + retry: false, }, }, }); From cc7426d8d3489d9681ccb92001f1524d259faaef Mon Sep 17 00:00:00 2001 From: Walter Rafelsberger Date: Fri, 25 Aug 2023 16:59:14 +0200 Subject: [PATCH 39/53] move useRefreshTransformList to hooks folder --- .../transform/public/app/common/index.ts | 2 +- .../transform/public/app/common/transform.ts | 11 ----------- .../toast_notification_text.test.tsx | 2 +- .../transform/public/app/hooks/index.ts | 1 + .../public/app/hooks/use_create_transform.tsx | 3 ++- .../public/app/hooks/use_delete_transform.tsx | 6 ++++-- .../app/hooks/use_reauthorize_transform.tsx | 5 +++-- .../app/hooks/use_refresh_transform_list.ts | 19 +++++++++++++++++++ .../public/app/hooks/use_reset_transform.tsx | 4 +++- .../app/hooks/use_schedule_now_transform.tsx | 3 ++- .../public/app/hooks/use_start_transform.tsx | 3 ++- .../public/app/hooks/use_stop_transform.tsx | 3 ++- .../public/app/hooks/use_update_transform.ts | 3 ++- .../expanded_row_messages_pane.tsx | 3 +-- .../transform_list/transform_list.tsx | 8 ++------ 15 files changed, 45 insertions(+), 31 deletions(-) create mode 100644 x-pack/plugins/transform/public/app/hooks/use_refresh_transform_list.ts diff --git a/x-pack/plugins/transform/public/app/common/index.ts b/x-pack/plugins/transform/public/app/common/index.ts index 42701de487adb..2bea1421277ef 100644 --- a/x-pack/plugins/transform/public/app/common/index.ts +++ b/x-pack/plugins/transform/public/app/common/index.ts @@ -19,7 +19,7 @@ export { toggleSelectedField, } from './fields'; export type { DropDownLabel, DropDownOption, Label } from './dropdown'; -export { isTransformIdValid, useRefreshTransformList } from './transform'; +export { isTransformIdValid } from './transform'; export type { TransformListAction, TransformListRow } from './transform_list'; export { TRANSFORM_LIST_COLUMN } from './transform_list'; export { getTransformProgress, isCompletedBatchTransform } from './transform_stats'; diff --git a/x-pack/plugins/transform/public/app/common/transform.ts b/x-pack/plugins/transform/public/app/common/transform.ts index ca60600fc40bf..b689ee8096983 100644 --- a/x-pack/plugins/transform/public/app/common/transform.ts +++ b/x-pack/plugins/transform/public/app/common/transform.ts @@ -6,10 +6,8 @@ */ import { cloneDeep } from 'lodash'; -import { useQueryClient } from '@tanstack/react-query'; import type { TransformConfigUnion, TransformId } from '../../../common/types/transform'; -import { TRANSFORM_REACT_QUERY_KEYS } from '../../../common/constants'; // Via https://github.com/elastic/elasticsearch/blob/master/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/transform/utils/TransformStrings.java#L24 // Matches a string that contains lowercase characters, digits, hyphens, underscores or dots. @@ -23,15 +21,6 @@ export const TRANSFORM_ERROR_TYPE = { DANGLING_TASK: 'dangling_task', } as const; -export const useRefreshTransformList = () => { - const queryClient = useQueryClient(); - - return () => { - queryClient.invalidateQueries([TRANSFORM_REACT_QUERY_KEYS.GET_TRANSFORMS]); - queryClient.invalidateQueries([TRANSFORM_REACT_QUERY_KEYS.GET_TRANSFORM_AUDIT_MESSAGES]); - }; -}; - export const overrideTransformForCloning = (originalConfig: TransformConfigUnion) => { // 'Managed' means job is preconfigured and deployed by other solutions // we should not clone this setting diff --git a/x-pack/plugins/transform/public/app/components/toast_notification_text.test.tsx b/x-pack/plugins/transform/public/app/components/toast_notification_text.test.tsx index 266091f5420b8..4afed870a6f6c 100644 --- a/x-pack/plugins/transform/public/app/components/toast_notification_text.test.tsx +++ b/x-pack/plugins/transform/public/app/components/toast_notification_text.test.tsx @@ -35,7 +35,7 @@ describe('ToastNotificationText', () => { }; const { container } = render(); expect(container.textContent).toBe( - 'a text message that is longer than 140 characters. a text message that is longer than 140 characters. a text message that is longer than 140 ...View details' + 'a text message that is longer than 140 characters. a text message that is longer than 140 characters. a text message that is longer than 140 ... View details' ); }); }); diff --git a/x-pack/plugins/transform/public/app/hooks/index.ts b/x-pack/plugins/transform/public/app/hooks/index.ts index 540ea7356e7aa..1dcf42108faae 100644 --- a/x-pack/plugins/transform/public/app/hooks/index.ts +++ b/x-pack/plugins/transform/public/app/hooks/index.ts @@ -16,6 +16,7 @@ export { useGetTransforms } from './use_get_transforms'; export { useGetTransformsPreview } from './use_get_transforms_preview'; export { useGetTransformStats } from './use_get_transform_stats'; export { useDeleteTransforms, useDeleteIndexAndTargetIndex } from './use_delete_transform'; +export { useRefreshTransformList } from './use_refresh_transform_list'; export { useResetTransforms } from './use_reset_transform'; export { useSearchItems } from './use_search_items'; export { useScheduleNowTransforms } from './use_schedule_now_transform'; diff --git a/x-pack/plugins/transform/public/app/hooks/use_create_transform.tsx b/x-pack/plugins/transform/public/app/hooks/use_create_transform.tsx index 064f6fa6450e2..7e40efcf94c56 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_create_transform.tsx +++ b/x-pack/plugins/transform/public/app/hooks/use_create_transform.tsx @@ -20,9 +20,10 @@ import type { TransformId } from '../../../common/types/transform'; import { getErrorMessage } from '../../../common/utils/errors'; import { useAppDependencies, useToastNotifications } from '../app_dependencies'; -import { useRefreshTransformList } from '../common'; import { ToastNotificationText } from '../components'; +import { useRefreshTransformList } from './use_refresh_transform_list'; + export const useCreateTransform = ( transformId: TransformId, transformConfig: PutTransformsRequestSchema diff --git a/x-pack/plugins/transform/public/app/hooks/use_delete_transform.tsx b/x-pack/plugins/transform/public/app/hooks/use_delete_transform.tsx index ba70a9470fd1e..ffdffcad488c5 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_delete_transform.tsx +++ b/x-pack/plugins/transform/public/app/hooks/use_delete_transform.tsx @@ -20,10 +20,12 @@ import type { import { getErrorMessage } from '../../../common/utils/errors'; import { useAppDependencies, useToastNotifications } from '../app_dependencies'; +import { type TransformListRow } from '../common'; +import { ToastNotificationText } from '../components'; + import { useTransformCapabilities } from './use_transform_capabilities'; import { useDataViewExists } from './use_data_view_exists'; -import { useRefreshTransformList, type TransformListRow } from '../common'; -import { ToastNotificationText } from '../components'; +import { useRefreshTransformList } from './use_refresh_transform_list'; export const useDeleteIndexAndTargetIndex = (items: TransformListRow[]) => { const { diff --git a/x-pack/plugins/transform/public/app/hooks/use_reauthorize_transform.tsx b/x-pack/plugins/transform/public/app/hooks/use_reauthorize_transform.tsx index 6bf0157591e6d..9ecd1b8717243 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_reauthorize_transform.tsx +++ b/x-pack/plugins/transform/public/app/hooks/use_reauthorize_transform.tsx @@ -14,15 +14,16 @@ import { toMountPoint } from '@kbn/react-kibana-mount'; import { addInternalBasePath } from '../../../common/constants'; import { getErrorMessage } from '../../../common/utils/errors'; -import { +import type { ReauthorizeTransformsRequestSchema, ReauthorizeTransformsResponseSchema, } from '../../../common/api_schemas/reauthorize_transforms'; import { useAppDependencies, useToastNotifications } from '../app_dependencies'; -import { useRefreshTransformList } from '../common'; import { ToastNotificationText } from '../components'; +import { useRefreshTransformList } from './use_refresh_transform_list'; + export const useReauthorizeTransforms = () => { const { http, i18n: i18nStart, theme } = useAppDependencies(); const refreshTransformList = useRefreshTransformList(); diff --git a/x-pack/plugins/transform/public/app/hooks/use_refresh_transform_list.ts b/x-pack/plugins/transform/public/app/hooks/use_refresh_transform_list.ts new file mode 100644 index 0000000000000..50b77a6e09f81 --- /dev/null +++ b/x-pack/plugins/transform/public/app/hooks/use_refresh_transform_list.ts @@ -0,0 +1,19 @@ +/* + * 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 { useQueryClient } from '@tanstack/react-query'; + +import { TRANSFORM_REACT_QUERY_KEYS } from '../../../common/constants'; + +export const useRefreshTransformList = () => { + const queryClient = useQueryClient(); + + return () => { + queryClient.invalidateQueries([TRANSFORM_REACT_QUERY_KEYS.GET_TRANSFORMS]); + queryClient.invalidateQueries([TRANSFORM_REACT_QUERY_KEYS.GET_TRANSFORM_AUDIT_MESSAGES]); + }; +}; diff --git a/x-pack/plugins/transform/public/app/hooks/use_reset_transform.tsx b/x-pack/plugins/transform/public/app/hooks/use_reset_transform.tsx index 8c717c76f7a66..1f415eae1ad20 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_reset_transform.tsx +++ b/x-pack/plugins/transform/public/app/hooks/use_reset_transform.tsx @@ -17,10 +17,12 @@ import type { } from '../../../common/api_schemas/reset_transforms'; import { addInternalBasePath } from '../../../common/constants'; import { getErrorMessage } from '../../../common/utils/errors'; + import { useAppDependencies, useToastNotifications } from '../app_dependencies'; -import { useRefreshTransformList } from '../common'; import { ToastNotificationText } from '../components'; +import { useRefreshTransformList } from './use_refresh_transform_list'; + export const useResetTransforms = () => { const { http, i18n: i18nStart, theme } = useAppDependencies(); const refreshTransformList = useRefreshTransformList(); diff --git a/x-pack/plugins/transform/public/app/hooks/use_schedule_now_transform.tsx b/x-pack/plugins/transform/public/app/hooks/use_schedule_now_transform.tsx index 2e0c220781725..bb568673a5758 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_schedule_now_transform.tsx +++ b/x-pack/plugins/transform/public/app/hooks/use_schedule_now_transform.tsx @@ -19,9 +19,10 @@ import type { import { getErrorMessage } from '../../../common/utils/errors'; import { useAppDependencies, useToastNotifications } from '../app_dependencies'; -import { useRefreshTransformList } from '../common'; import { ToastNotificationText } from '../components'; +import { useRefreshTransformList } from './use_refresh_transform_list'; + export const useScheduleNowTransforms = () => { const { http, i18n: i18nStart, theme } = useAppDependencies(); const refreshTransformList = useRefreshTransformList(); diff --git a/x-pack/plugins/transform/public/app/hooks/use_start_transform.tsx b/x-pack/plugins/transform/public/app/hooks/use_start_transform.tsx index 8f81bb5b479c7..104c3145fc259 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_start_transform.tsx +++ b/x-pack/plugins/transform/public/app/hooks/use_start_transform.tsx @@ -19,9 +19,10 @@ import type { import { getErrorMessage } from '../../../common/utils/errors'; import { useAppDependencies, useToastNotifications } from '../app_dependencies'; -import { useRefreshTransformList } from '../common'; import { ToastNotificationText } from '../components'; +import { useRefreshTransformList } from './use_refresh_transform_list'; + export const useStartTransforms = () => { const { http, i18n: i18nStart, theme } = useAppDependencies(); const refreshTransformList = useRefreshTransformList(); diff --git a/x-pack/plugins/transform/public/app/hooks/use_stop_transform.tsx b/x-pack/plugins/transform/public/app/hooks/use_stop_transform.tsx index 69a258f28a86d..564b17feac3f9 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_stop_transform.tsx +++ b/x-pack/plugins/transform/public/app/hooks/use_stop_transform.tsx @@ -20,9 +20,10 @@ import type { import { getErrorMessage } from '../../../common/utils/errors'; import { useAppDependencies, useToastNotifications } from '../app_dependencies'; -import { useRefreshTransformList } from '../common'; import { ToastNotificationText } from '../components'; +import { useRefreshTransformList } from './use_refresh_transform_list'; + export const useStopTransforms = () => { const { http, i18n: i18nStart, theme } = useAppDependencies(); const refreshTransformList = useRefreshTransformList(); diff --git a/x-pack/plugins/transform/public/app/hooks/use_update_transform.ts b/x-pack/plugins/transform/public/app/hooks/use_update_transform.ts index 144a930c7e5d0..3859f9a8353f0 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_update_transform.ts +++ b/x-pack/plugins/transform/public/app/hooks/use_update_transform.ts @@ -15,7 +15,8 @@ import { addInternalBasePath } from '../../../common/constants'; import type { TransformId } from '../../../common/types/transform'; import { useAppDependencies } from '../app_dependencies'; -import { useRefreshTransformList } from '../common'; + +import { useRefreshTransformList } from './use_refresh_transform_list'; export const useUpdateTransform = ( transformId: TransformId, diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row_messages_pane.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row_messages_pane.tsx index 3ed38727086d5..2ec73e4485dd1 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row_messages_pane.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row_messages_pane.tsx @@ -23,8 +23,7 @@ import { DEFAULT_MAX_AUDIT_MESSAGE_SIZE, TIME_FORMAT } from '../../../../../../c import { TransformMessage } from '../../../../../../common/types/messages'; import { JobIcon } from '../../../../components/job_icon'; -import { useRefreshTransformList } from '../../../../common'; -import { useGetTransformAuditMessages } from '../../../../hooks'; +import { useGetTransformAuditMessages, useRefreshTransformList } from '../../../../hooks'; interface ExpandedRowMessagesPaneProps { transformId: string; diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_list.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_list.tsx index ee19874175903..57e7cbdb47697 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_list.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_list.tsx @@ -32,12 +32,8 @@ import { } from '../action_reauthorize'; import type { TransformId } from '../../../../../../common/types/transform'; -import { - useRefreshTransformList, - type TransformListRow, - TRANSFORM_LIST_COLUMN, -} from '../../../../common'; -import { useTransformCapabilities } from '../../../../hooks'; +import { type TransformListRow, TRANSFORM_LIST_COLUMN } from '../../../../common'; +import { useRefreshTransformList, useTransformCapabilities } from '../../../../hooks'; import { CreateTransformButton } from '../create_transform_button'; import { RefreshTransformListButton } from '../refresh_transform_list_button'; From 95ff5c062b112e6267d68f996a5998176e206029 Mon Sep 17 00:00:00 2001 From: Walter Rafelsberger Date: Fri, 25 Aug 2023 17:00:11 +0200 Subject: [PATCH 40/53] remove ununused code. tweak empty list state --- .../transform_management_section.tsx | 44 +++++++------------ 1 file changed, 16 insertions(+), 28 deletions(-) diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/transform_management_section.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/transform_management_section.tsx index c690d6b3efd91..86deb7a385ef6 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/transform_management_section.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/transform_management_section.tsx @@ -25,7 +25,6 @@ import type { IHttpFetchError } from '@kbn/core-http-browser'; import { needsReauthorization } from '../../common/reauthorization_utils'; import { TRANSFORM_STATE } from '../../../../common/constants'; -import { useAppDependencies } from '../../app_dependencies'; import { useDocumentationLinks } from '../../hooks'; import { useDeleteTransforms, useTransformCapabilities, useGetTransforms } from '../../hooks'; import { RedirectToCreateTransform } from '../../common/navigation'; @@ -45,9 +44,6 @@ import { const ErrorMessageCallout: FC<{ errorMessage: IHttpFetchError | null }> = ({ errorMessage, }) => { - const { overlays, theme } = useAppDependencies(); - const [isModalVisible, setIsModalVisible] = useState(false); - return ( <> @@ -60,28 +56,13 @@ const ErrorMessageCallout: FC<{ errorMessage: IHttpFetchError | null }> defaultMessage="An error occurred getting the transform list." />{' '} {errorMessage !== null && ( - + )} } color="danger" iconType="error" /> - {isModalVisible && ( - setIsModalVisible(false)} - className="transformListErrorMessageModal" - data-test-subj="transformSelectSourceModal" - > -
{JSON.stringify(errorMessage)}
-
- )} ); }; @@ -190,7 +171,12 @@ export const TransformManagement: FC = () => { /> - {isInitialLoading && } + {isInitialLoading && ( + <> + + + + )} {!isInitialLoading && ( <> {unauthorizedTransformsWarning} @@ -247,13 +233,15 @@ export const TransformManagement: FC = () => { ) : null} - + {(transformNodes > 0 || transforms.length > 0) && ( + + )} From 1c4c3c2a099dd626129dcecb2200d8a756e694b4 Mon Sep 17 00:00:00 2001 From: Walter Rafelsberger Date: Fri, 25 Aug 2023 17:12:34 +0200 Subject: [PATCH 41/53] adds retry button to warning callout for no transform nodes. --- .../transform_list/transforms_stats_bar.tsx | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transforms_stats_bar.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transforms_stats_bar.tsx index 554b82c1fd3fe..a041466eb5434 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transforms_stats_bar.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transforms_stats_bar.tsx @@ -7,7 +7,7 @@ import React, { type FC } from 'react'; -import { EuiCallOut, EuiLink, EuiSpacer } from '@elastic/eui'; +import { EuiButton, EuiCallOut, EuiLink, EuiSpacer } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; @@ -16,7 +16,7 @@ import { TRANSFORM_MODE, TRANSFORM_STATE } from '../../../../../../common/consta import { TransformListRow } from '../../../../common'; -import { useDocumentationLinks } from '../../../../hooks/use_documentation_links'; +import { useDocumentationLinks, useRefreshTransformList } from '../../../../hooks'; import { StatsBar, TransformStatsBarStats } from '../stats_bar'; @@ -109,6 +109,7 @@ export const TransformStatsBar: FC = ({ transformNodes, transformsList, }) => { + const refreshTransformList = useRefreshTransformList(); const { esNodeRoles } = useDocumentationLinks(); const transformStats: TransformStatsBarStats = createTranformStats( @@ -118,10 +119,8 @@ export const TransformStatsBar: FC = ({ return ( <> - {transformNodes === 0 && ( <> - = ({ }} />

+ refreshTransformList()} size="s"> + +
+ )} + ); }; From 4ce95262c88e0960a7b1eea8879f55d833899129 Mon Sep 17 00:00:00 2001 From: Walter Rafelsberger Date: Fri, 25 Aug 2023 18:17:28 +0200 Subject: [PATCH 42/53] fix jest test --- .../components/transform_list/transform_list.test.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_list.test.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_list.test.tsx index efa34261d3731..fc4bf0e24d14d 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_list.test.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_list.test.tsx @@ -46,7 +46,7 @@ describe('Transform: Transform List ', () => { await waitFor(() => { expect(useQueryMock).toHaveBeenCalledTimes(4); - expect(container.textContent).toContain('Reload'); + expect(container.textContent).toContain('Create your first transform'); }); }); }); From f25ea75b32ee4e8d3c0864d7d94afb38dcfee41c Mon Sep 17 00:00:00 2001 From: Walter Rafelsberger Date: Thu, 31 Aug 2023 09:09:39 +0200 Subject: [PATCH 43/53] add null checks --- .../public/app/components/toast_notification_text.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/transform/public/app/components/toast_notification_text.tsx b/x-pack/plugins/transform/public/app/components/toast_notification_text.tsx index c94666b244094..eab82bf1d4c83 100644 --- a/x-pack/plugins/transform/public/app/components/toast_notification_text.tsx +++ b/x-pack/plugins/transform/public/app/components/toast_notification_text.tsx @@ -47,13 +47,15 @@ export const ToastNotificationText: FC = ({ if ( !forceModal && typeof text === 'object' && + text !== null && typeof text.message === 'string' && text.message.length <= MAX_SIMPLE_MESSAGE_LENGTH ) { return text.message; } - const unformattedText = typeof text === 'object' && text.message ? text.message : text; + const unformattedText = + typeof text === 'object' && text !== null && text.message ? text.message : text; const formattedText = typeof unformattedText === 'object' ? JSON.stringify(text, null, 2) : unformattedText; const textLength = previewTextLength ?? 140; From c6b72a697dfde222d2c6adbfe25ecdc9a3fa74ae Mon Sep 17 00:00:00 2001 From: Walter Rafelsberger Date: Thu, 31 Aug 2023 09:17:41 +0200 Subject: [PATCH 44/53] cleanup types --- .../transform/public/app/hooks/use_transform_capabilities.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/x-pack/plugins/transform/public/app/hooks/use_transform_capabilities.ts b/x-pack/plugins/transform/public/app/hooks/use_transform_capabilities.ts index 4483568bb85c1..f497da3bd51de 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_transform_capabilities.ts +++ b/x-pack/plugins/transform/public/app/hooks/use_transform_capabilities.ts @@ -8,7 +8,6 @@ import { getInitialTransformCapabilities, isTransformCapabilities, - type TransformCapabilities, } from '../../../common/types/capabilities'; import { useAppDependencies } from '../app_dependencies'; @@ -17,7 +16,7 @@ export const useTransformCapabilities = () => { const { application } = useAppDependencies(); if (isTransformCapabilities(application?.capabilities?.transform)) { - return application.capabilities.transform as TransformCapabilities; + return application.capabilities.transform; } return getInitialTransformCapabilities(); From ee46ca26d8ac8a6df3d53b5cebbb006fff243a15 Mon Sep 17 00:00:00 2001 From: Walter Rafelsberger Date: Thu, 31 Aug 2023 11:06:24 +0200 Subject: [PATCH 45/53] fix passing on populated fields --- .../plugins/transform/public/app/hooks/use_index_data.ts | 9 +++++---- .../components/step_define/step_define_form.tsx | 7 ++++++- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/x-pack/plugins/transform/public/app/hooks/use_index_data.ts b/x-pack/plugins/transform/public/app/hooks/use_index_data.ts index f6d148fe02922..e0f4847f04281 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_index_data.ts +++ b/x-pack/plugins/transform/public/app/hooks/use_index_data.ts @@ -48,7 +48,7 @@ export const useIndexData = ( query: TransformConfigQuery, combinedRuntimeMappings?: StepDefineExposedState['runtimeMappings'], timeRangeMs?: TimeRangeMs, - populatedFields?: Set | null + populatedFields?: string[] ): UseIndexDataReturnType => { const { analytics } = useAppDependencies(); @@ -103,7 +103,8 @@ export const useIndexData = ( }, // Check whether fetching should be enabled // If populatedFields are not provided, make own request to calculate - !!populatedFields && !(dataView.timeFieldName !== undefined && timeRangeMs === undefined) + !Array.isArray(populatedFields) && + !(dataView.timeFieldName !== undefined && timeRangeMs === undefined) ); useEffect(() => { @@ -130,8 +131,8 @@ export const useIndexData = ( }, [dataViewFieldsData, dataViewFieldsError, dataViewFieldsIsError, dataViewFieldsIsLoading]); const dataViewFields = useMemo(() => { - if (populatedFields) { - return [...populatedFields]; + if (Array.isArray(populatedFields)) { + return populatedFields; } if (dataViewFieldsData) { diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/step_define_form.tsx b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/step_define_form.tsx index 81bdb47735a37..246460d11d3ee 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/step_define_form.tsx +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/step_define_form.tsx @@ -78,6 +78,9 @@ const ALLOW_TIME_RANGE_ON_TRANSFORM_CONFIG = false; const advancedEditorsSidebarWidth = '220px'; +type PopulatedFields = Set; +const isPopulatedFields = (arg: unknown): arg is PopulatedFields => arg instanceof Set; + export const ConfigSectionTitle: FC<{ title: string }> = ({ title }) => ( <> @@ -132,7 +135,9 @@ export const StepDefineForm: FC = React.memo((props) => { transformConfigQuery, runtimeMappings, timeRangeMs, - fieldStatsContext?.populatedFields ?? null + isPopulatedFields(fieldStatsContext?.populatedFields) + ? [...fieldStatsContext.populatedFields] + : [] ), dataTestSubj: 'transformIndexPreview', toastNotifications, From 1fa7a2e84e38f3ce8c52a316ed8be92880a392cd Mon Sep 17 00:00:00 2001 From: Walter Rafelsberger Date: Thu, 31 Aug 2023 11:19:22 +0200 Subject: [PATCH 46/53] refactor useCreateTransform for consistency --- .../public/app/hooks/use_create_transform.tsx | 30 +++++++++++------- .../step_create/step_create_form.tsx | 31 ++++++++++--------- 2 files changed, 35 insertions(+), 26 deletions(-) diff --git a/x-pack/plugins/transform/public/app/hooks/use_create_transform.tsx b/x-pack/plugins/transform/public/app/hooks/use_create_transform.tsx index 7e40efcf94c56..272e815c42eb4 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_create_transform.tsx +++ b/x-pack/plugins/transform/public/app/hooks/use_create_transform.tsx @@ -24,15 +24,17 @@ import { ToastNotificationText } from '../components'; import { useRefreshTransformList } from './use_refresh_transform_list'; -export const useCreateTransform = ( - transformId: TransformId, - transformConfig: PutTransformsRequestSchema -) => { +interface CreateTransformArgs { + transformId: TransformId; + transformConfig: PutTransformsRequestSchema; +} + +export const useCreateTransform = () => { const { http, i18n: i18nStart, theme } = useAppDependencies(); const refreshTransformList = useRefreshTransformList(); const toastNotifications = useToastNotifications(); - function errorToast(error: unknown) { + function errorToast(error: unknown, { transformId }: CreateTransformArgs) { toastNotifications.addDanger({ title: i18n.translate('xpack.transform.stepCreateForm.createTransformErrorMessage', { defaultMessage: 'An error occurred creating the transform {transformId}:', @@ -46,15 +48,19 @@ export const useCreateTransform = ( } const mutation = useMutation({ - mutationFn: () => - http.put(addInternalBasePath(`transforms/${transformId}`), { - body: JSON.stringify(transformConfig), - version: '1', - }), + mutationFn: ({ transformId, transformConfig }: CreateTransformArgs) => { + return http.put( + addInternalBasePath(`transforms/${transformId}`), + { + body: JSON.stringify(transformConfig), + version: '1', + } + ); + }, onError: errorToast, - onSuccess: (resp) => { + onSuccess: (resp, options) => { if (resp.errors.length > 0) { - errorToast(resp.errors.length === 1 ? resp.errors[0] : resp.errors); + errorToast(resp.errors.length === 1 ? resp.errors[0] : resp.errors, options); } refreshTransformList(); diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_create/step_create_form.tsx b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_create/step_create_form.tsx index a51dfffa7e77a..3c78757a6f257 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_create/step_create_form.tsx +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_create/step_create_form.tsx @@ -122,24 +122,27 @@ export const StepCreateForm: FC = React.memo( }, [created, started, dataViewId]); const startTransforms = useStartTransforms(); - const createTransform = useCreateTransform(transformId, transformConfig); + const createTransform = useCreateTransform(); function createTransformHandler(startAfterCreation = false) { setLoading(true); - createTransform(undefined, { - onError: () => setCreated(false), - onSuccess: () => { - setCreated(true); - if (createDataView) { - createKibanaDataView(); - } - if (startAfterCreation) { - startTransform(); - } - }, - onSettled: () => setLoading(false), - }); + createTransform( + { transformId, transformConfig }, + { + onError: () => setCreated(false), + onSuccess: () => { + setCreated(true); + if (createDataView) { + createKibanaDataView(); + } + if (startAfterCreation) { + startTransform(); + } + }, + onSettled: () => setLoading(false), + } + ); } function startTransform() { From 493f52d10eb69eda3d5594eefe620b15ea633208 Mon Sep 17 00:00:00 2001 From: Walter Rafelsberger Date: Thu, 31 Aug 2023 12:25:56 +0200 Subject: [PATCH 47/53] move fetching transform nodes to its own hook --- x-pack/plugins/transform/common/constants.ts | 1 + .../transform/public/app/hooks/index.ts | 1 + .../app/hooks/use_get_transform_nodes.ts | 41 +++++++++++++ .../public/app/hooks/use_get_transforms.ts | 25 +++----- .../app/hooks/use_refresh_transform_list.ts | 1 + .../transform_management_section.tsx | 61 ++++++++++++++----- 6 files changed, 99 insertions(+), 31 deletions(-) create mode 100644 x-pack/plugins/transform/public/app/hooks/use_get_transform_nodes.ts diff --git a/x-pack/plugins/transform/common/constants.ts b/x-pack/plugins/transform/common/constants.ts index fd073c5f474f4..a1ba2d8277af9 100644 --- a/x-pack/plugins/transform/common/constants.ts +++ b/x-pack/plugins/transform/common/constants.ts @@ -40,6 +40,7 @@ export const TRANSFORM_REACT_QUERY_KEYS = { GET_ES_INGEST_PIPELINES: 'transform.get_es_ingest_pipelines', GET_HISTOGRAMS_FOR_FIELDS: 'transform.get_histograms_for_fields', GET_TRANSFORM: 'transform.get_transform', + GET_TRANSFORM_NODES: 'transform.get_transform_nodes', GET_TRANSFORM_AUDIT_MESSAGES: 'transform.get_transform_audit_messages', GET_TRANSFORM_STATS: 'transform.get_transform_stats', GET_TRANSFORMS: 'transform.get_transforms', diff --git a/x-pack/plugins/transform/public/app/hooks/index.ts b/x-pack/plugins/transform/public/app/hooks/index.ts index 1dcf42108faae..749706f97cd70 100644 --- a/x-pack/plugins/transform/public/app/hooks/index.ts +++ b/x-pack/plugins/transform/public/app/hooks/index.ts @@ -12,6 +12,7 @@ export { useGetEsIndices } from './use_get_es_indices'; export { useGetEsIngestPipelines } from './use_get_es_ingest_pipelines'; export { useGetTransformAuditMessages } from './use_get_transform_audit_messages'; export { useGetTransform } from './use_get_transform'; +export { useGetTransformNodes } from './use_get_transform_nodes'; export { useGetTransforms } from './use_get_transforms'; export { useGetTransformsPreview } from './use_get_transforms_preview'; export { useGetTransformStats } from './use_get_transform_stats'; diff --git a/x-pack/plugins/transform/public/app/hooks/use_get_transform_nodes.ts b/x-pack/plugins/transform/public/app/hooks/use_get_transform_nodes.ts new file mode 100644 index 0000000000000..2d3d7cfa9defd --- /dev/null +++ b/x-pack/plugins/transform/public/app/hooks/use_get_transform_nodes.ts @@ -0,0 +1,41 @@ +/* + * 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 { useQuery } from '@tanstack/react-query'; + +import type { IHttpFetchError } from '@kbn/core-http-browser'; + +import type { GetTransformNodesResponseSchema } from '../../../common/api_schemas/transforms'; +import { + addInternalBasePath, + DEFAULT_REFRESH_INTERVAL_MS, + TRANSFORM_REACT_QUERY_KEYS, +} from '../../../common/constants'; + +import { useAppDependencies } from '../app_dependencies'; + +export const useGetTransformNodes = () => { + const { http } = useAppDependencies(); + + return useQuery( + [TRANSFORM_REACT_QUERY_KEYS.GET_TRANSFORM_NODES], + async ({ signal }) => { + const transformNodes = await http.get( + addInternalBasePath('transforms/_nodes'), + { + version: '1', + signal, + } + ); + + return transformNodes.count; + }, + { + refetchInterval: DEFAULT_REFRESH_INTERVAL_MS, + } + ); +}; diff --git a/x-pack/plugins/transform/public/app/hooks/use_get_transforms.ts b/x-pack/plugins/transform/public/app/hooks/use_get_transforms.ts index d08fe50f679a3..f29267fa309a9 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_get_transforms.ts +++ b/x-pack/plugins/transform/public/app/hooks/use_get_transforms.ts @@ -10,10 +10,7 @@ import { useQuery } from '@tanstack/react-query'; import type { IHttpFetchError } from '@kbn/core-http-browser'; import { isDefined } from '@kbn/ml-is-defined'; -import type { - GetTransformNodesResponseSchema, - GetTransformsResponseSchema, -} from '../../../common/api_schemas/transforms'; +import type { GetTransformsResponseSchema } from '../../../common/api_schemas/transforms'; import type { GetTransformsStatsResponseSchema } from '../../../common/api_schemas/transforms_stats'; import { addInternalBasePath, @@ -31,16 +28,18 @@ interface UseGetTransformsResponse { transforms: TransformListRow[]; transformIds: string[]; transformIdsWithoutConfig?: string[]; - transformNodes: number; } const getInitialData = (): UseGetTransformsResponse => ({ transforms: [], transformIds: [], - transformNodes: 0, }); -export const useGetTransforms = () => { +interface UseGetTransformsOptions { + enabled?: boolean; +} + +export const useGetTransforms = ({ enabled }: UseGetTransformsOptions) => { const { http } = useAppDependencies(); const { data = getInitialData(), ...rest } = useQuery( @@ -48,16 +47,6 @@ export const useGetTransforms = () => { async ({ signal }) => { const update = getInitialData(); - const transformNodes = await http.get( - addInternalBasePath('transforms/_nodes'), - { - version: '1', - signal, - } - ); - - update.transformNodes = transformNodes.count; - const transformConfigs = await http.get( addInternalBasePath('transforms'), { @@ -111,11 +100,13 @@ export const useGetTransforms = () => { }); return reducedtableRows; }, [] as TransformListRow[]); + update.transformIds = update.transforms.map(({ id }) => id); return update; }, { + enabled, refetchInterval: DEFAULT_REFRESH_INTERVAL_MS, } ); diff --git a/x-pack/plugins/transform/public/app/hooks/use_refresh_transform_list.ts b/x-pack/plugins/transform/public/app/hooks/use_refresh_transform_list.ts index 50b77a6e09f81..651886ba76f7b 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_refresh_transform_list.ts +++ b/x-pack/plugins/transform/public/app/hooks/use_refresh_transform_list.ts @@ -13,6 +13,7 @@ export const useRefreshTransformList = () => { const queryClient = useQueryClient(); return () => { + queryClient.invalidateQueries([TRANSFORM_REACT_QUERY_KEYS.GET_TRANSFORM_NODES]); queryClient.invalidateQueries([TRANSFORM_REACT_QUERY_KEYS.GET_TRANSFORMS]); queryClient.invalidateQueries([TRANSFORM_REACT_QUERY_KEYS.GET_TRANSFORM_AUDIT_MESSAGES]); }; diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/transform_management_section.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/transform_management_section.tsx index 4b91715df5cd7..8cfb7ebb5240c 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/transform_management_section.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/transform_management_section.tsx @@ -24,8 +24,13 @@ import type { IHttpFetchError } from '@kbn/core-http-browser'; import { needsReauthorization } from '../../common/reauthorization_utils'; import { TRANSFORM_STATE } from '../../../../common/constants'; -import { useDocumentationLinks } from '../../hooks'; -import { useDeleteTransforms, useTransformCapabilities, useGetTransforms } from '../../hooks'; +import { + useDocumentationLinks, + useDeleteTransforms, + useTransformCapabilities, + useGetTransforms, + useGetTransformNodes, +} from '../../hooks'; import { RedirectToCreateTransform } from '../../common/navigation'; import { CapabilitiesWrapper } from '../../components/capabilities_wrapper'; import { ToastNotificationText } from '../../components/toast_notification_text'; @@ -40,9 +45,10 @@ import { TransformAlertFlyoutWrapper, } from '../../../alerting/transform_alerting_flyout'; -const ErrorMessageCallout: FC<{ errorMessage: IHttpFetchError | null }> = ({ - errorMessage, -}) => { +const ErrorMessageCallout: FC<{ + text: JSX.Element; + errorMessage: IHttpFetchError | null; +}> = ({ text, errorMessage }) => { return ( <> @@ -50,10 +56,7 @@ const ErrorMessageCallout: FC<{ errorMessage: IHttpFetchError | null }> size="s" title={ <> - {' '} + {text}{' '} {errorMessage !== null && ( )} @@ -72,11 +75,20 @@ export const TransformManagement: FC = () => { const deleteTransforms = useDeleteTransforms(); const { - isInitialLoading, + isInitialLoading: transformNodesInitialLoading, + error: transformNodesErrorMessage, + data: transformNodesData = 0, + } = useGetTransformNodes(); + const transformNodes = transformNodesErrorMessage === null ? transformNodesData : 0; + + const { + isInitialLoading: transformsInitialLoading, isLoading: transformsLoading, - error: errorMessage, - data: { transforms, transformNodes, transformIdsWithoutConfig }, - } = useGetTransforms(); + error: transformsErrorMessage, + data: { transforms, transformIdsWithoutConfig }, + } = useGetTransforms({ enabled: !transformNodesInitialLoading && transformNodes > 0 }); + + const isInitialLoading = transformNodesInitialLoading || transformsInitialLoading; const { canStartStopTransform } = useTransformCapabilities(); @@ -181,7 +193,28 @@ export const TransformManagement: FC = () => { <> {unauthorizedTransformsWarning} - {errorMessage !== null && } + {transformNodesErrorMessage !== null && ( + + } + errorMessage={transformNodesErrorMessage} + /> + )} + {transformsErrorMessage !== null && ( + + } + errorMessage={transformsErrorMessage} + /> + )} From 9b02239b20ca8289d3e768aa2d0db5b38f7e599c Mon Sep 17 00:00:00 2001 From: Walter Rafelsberger Date: Thu, 31 Aug 2023 12:32:32 +0200 Subject: [PATCH 48/53] refactor EuiPageContent_Deprecated --- .../public/app/components/capabilities_wrapper.tsx | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/x-pack/plugins/transform/public/app/components/capabilities_wrapper.tsx b/x-pack/plugins/transform/public/app/components/capabilities_wrapper.tsx index df50691963648..ce850aa2ffc6c 100644 --- a/x-pack/plugins/transform/public/app/components/capabilities_wrapper.tsx +++ b/x-pack/plugins/transform/public/app/components/capabilities_wrapper.tsx @@ -7,12 +7,7 @@ import React, { type FC } from 'react'; -import { - EuiFlexItem, - EuiFlexGroup, - EuiPageContent_Deprecated as EuiPageContent, - EuiEmptyPrompt, -} from '@elastic/eui'; +import { EuiFlexItem, EuiFlexGroup, EuiPageTemplate, EuiEmptyPrompt } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; @@ -33,7 +28,7 @@ export const NotAuthorizedSection = ({ title, message }: Props) => ( const MissingCapabilities: FC = () => ( - + ( /> } /> - + ); From a47947c7a375bc687eac4bd1fdaa15aadaaa3f54 Mon Sep 17 00:00:00 2001 From: Walter Rafelsberger Date: Thu, 31 Aug 2023 12:37:45 +0200 Subject: [PATCH 49/53] revert space after preview text --- .../public/app/components/toast_notification_text.test.tsx | 2 +- .../public/app/components/toast_notification_text.tsx | 6 +----- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/x-pack/plugins/transform/public/app/components/toast_notification_text.test.tsx b/x-pack/plugins/transform/public/app/components/toast_notification_text.test.tsx index 4afed870a6f6c..266091f5420b8 100644 --- a/x-pack/plugins/transform/public/app/components/toast_notification_text.test.tsx +++ b/x-pack/plugins/transform/public/app/components/toast_notification_text.test.tsx @@ -35,7 +35,7 @@ describe('ToastNotificationText', () => { }; const { container } = render(); expect(container.textContent).toBe( - 'a text message that is longer than 140 characters. a text message that is longer than 140 characters. a text message that is longer than 140 ... View details' + 'a text message that is longer than 140 characters. a text message that is longer than 140 characters. a text message that is longer than 140 ...View details' ); }); }); diff --git a/x-pack/plugins/transform/public/app/components/toast_notification_text.tsx b/x-pack/plugins/transform/public/app/components/toast_notification_text.tsx index eab82bf1d4c83..8b2f154e8124e 100644 --- a/x-pack/plugins/transform/public/app/components/toast_notification_text.tsx +++ b/x-pack/plugins/transform/public/app/components/toast_notification_text.tsx @@ -94,11 +94,7 @@ export const ToastNotificationText: FC = ({ return ( <> - {!inline && ( - <> -
{previewText}
{' '} - - )} + {!inline &&
{previewText}
} Date: Thu, 31 Aug 2023 12:41:51 +0200 Subject: [PATCH 50/53] tweak capabilities checks --- .../transform/public/app/hooks/use_delete_transform.tsx | 4 ++-- .../components/step_details/step_details_form.tsx | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/x-pack/plugins/transform/public/app/hooks/use_delete_transform.tsx b/x-pack/plugins/transform/public/app/hooks/use_delete_transform.tsx index ffdffcad488c5..a7ed779c47cc7 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_delete_transform.tsx +++ b/x-pack/plugins/transform/public/app/hooks/use_delete_transform.tsx @@ -35,8 +35,8 @@ export const useDeleteIndexAndTargetIndex = (items: TransformListRow[]) => { const { canDeleteIndex: userCanDeleteIndex } = useTransformCapabilities(); const userCanDeleteDataView = - (capabilities.savedObjectsManagement && capabilities.savedObjectsManagement.delete === true) || - (capabilities.indexPatterns && capabilities.indexPatterns.save === true); + capabilities.savedObjectsManagement?.delete === true || + capabilities.indexPatterns?.save === true; const [deleteDestIndex, setDeleteDestIndex] = useState(true); const [deleteDataView, setDeleteDataView] = useState(userCanDeleteDataView); diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_details/step_details_form.tsx b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_details/step_details_form.tsx index 48fa750db7113..da9ebbf9b2ef7 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_details/step_details_form.tsx +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_details/step_details_form.tsx @@ -93,8 +93,8 @@ export const StepDetailsForm: FC = React.memo( const canCreateDataView = useMemo( () => - capabilities.savedObjectsManagement.edit === true || - capabilities.indexPatterns.save === true, + capabilities.savedObjectsManagement?.edit === true || + capabilities.indexPatterns?.save === true, [capabilities] ); From 0a26dafb651f579c2dd84a76d89f2abd64286da3 Mon Sep 17 00:00:00 2001 From: Walter Rafelsberger Date: Thu, 31 Aug 2023 12:46:55 +0200 Subject: [PATCH 51/53] fix i18n --- x-pack/plugins/translations/translations/fr-FR.json | 1 - x-pack/plugins/translations/translations/ja-JP.json | 1 - x-pack/plugins/translations/translations/zh-CN.json | 1 - 3 files changed, 3 deletions(-) diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index 3cf5682882be4..100309f24dea8 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -37888,7 +37888,6 @@ "xpack.transform.licenseCheckErrorMessage": "La vérification de la licence a échoué", "xpack.transform.list.emptyPromptButtonText": "Créez votre première transformation", "xpack.transform.list.emptyPromptTitle": "Aucune transformation n'a été trouvée", - "xpack.transform.list.errorPromptTitle": "Une erreur s'est produite lors de l'obtention de la liste de transformations", "xpack.transform.mode": "Mode", "xpack.transform.modeFilter": "Mode", "xpack.transform.models.transformService.allOtherRequestsCancelledDescription": "Toutes les autres requêtes ont été annulées.", diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 09c5109747e44..dc8051cf6a4b6 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -37887,7 +37887,6 @@ "xpack.transform.licenseCheckErrorMessage": "ライセンス確認失敗", "xpack.transform.list.emptyPromptButtonText": "初めてのトランスフォームを作成", "xpack.transform.list.emptyPromptTitle": "トランスフォームが見つかりません", - "xpack.transform.list.errorPromptTitle": "トランスフォームリストの取得中にエラーが発生しました", "xpack.transform.mode": "モード", "xpack.transform.modeFilter": "モード", "xpack.transform.models.transformService.allOtherRequestsCancelledDescription": "他のすべてのリクエストはキャンセルされました。", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 99e195d0990d7..767cf36bff48d 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -37881,7 +37881,6 @@ "xpack.transform.licenseCheckErrorMessage": "许可证检查失败", "xpack.transform.list.emptyPromptButtonText": "创建您的首个转换", "xpack.transform.list.emptyPromptTitle": "找不到转换", - "xpack.transform.list.errorPromptTitle": "获取转换列表时发生错误", "xpack.transform.mode": "模式", "xpack.transform.modeFilter": "模式", "xpack.transform.models.transformService.allOtherRequestsCancelledDescription": "所有其他请求已取消。", From 279e526e37c9510054cd4aed45718db13f140656 Mon Sep 17 00:00:00 2001 From: Walter Rafelsberger Date: Thu, 31 Aug 2023 13:16:09 +0200 Subject: [PATCH 52/53] fix handling options default --- x-pack/plugins/transform/public/app/hooks/use_get_transforms.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/transform/public/app/hooks/use_get_transforms.ts b/x-pack/plugins/transform/public/app/hooks/use_get_transforms.ts index f29267fa309a9..f74f7a5774ded 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_get_transforms.ts +++ b/x-pack/plugins/transform/public/app/hooks/use_get_transforms.ts @@ -39,7 +39,7 @@ interface UseGetTransformsOptions { enabled?: boolean; } -export const useGetTransforms = ({ enabled }: UseGetTransformsOptions) => { +export const useGetTransforms = ({ enabled }: UseGetTransformsOptions = {}) => { const { http } = useAppDependencies(); const { data = getInitialData(), ...rest } = useQuery( From f0e555f68111030032ff911d3e05d7d43d882c60 Mon Sep 17 00:00:00 2001 From: Walter Rafelsberger Date: Fri, 1 Sep 2023 09:08:33 +0200 Subject: [PATCH 53/53] fix populated fields cleanup --- .../public/app/hooks/use_index_data.ts | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/x-pack/plugins/transform/public/app/hooks/use_index_data.ts b/x-pack/plugins/transform/public/app/hooks/use_index_data.ts index e0f4847f04281..4534552f6b405 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_index_data.ts +++ b/x-pack/plugins/transform/public/app/hooks/use_index_data.ts @@ -131,20 +131,17 @@ export const useIndexData = ( }, [dataViewFieldsData, dataViewFieldsError, dataViewFieldsIsError, dataViewFieldsIsLoading]); const dataViewFields = useMemo(() => { - if (Array.isArray(populatedFields)) { - return populatedFields; - } - - if (dataViewFieldsData) { - const docs = dataViewFieldsData.hits.hits.map((d) => getProcessedFields(d.fields ?? {})); + let allPopulatedFields = Array.isArray(populatedFields) ? populatedFields : []; + if (populatedFields === undefined && dataViewFieldsData) { // Get all field names for each returned doc and flatten it // to a list of unique field names used across all docs. - const allDataViewFields = getFieldsFromKibanaIndexPattern(dataView); - return [...new Set(docs.map(Object.keys).flat(1))] - .filter((d) => allDataViewFields.includes(d)) - .sort(); + const docs = dataViewFieldsData.hits.hits.map((d) => getProcessedFields(d.fields ?? {})); + allPopulatedFields = [...new Set(docs.map(Object.keys).flat(1))]; } + + const allDataViewFields = getFieldsFromKibanaIndexPattern(dataView); + return allPopulatedFields.filter((d) => allDataViewFields.includes(d)).sort(); // eslint-disable-next-line react-hooks/exhaustive-deps }, [dataViewFieldsData, populatedFields]);