Skip to content

Commit

Permalink
refactor IndexService into custom hooks using react-query
Browse files Browse the repository at this point in the history
  • Loading branch information
walterra committed Aug 22, 2023
1 parent c1dbc1e commit 3adfd4a
Show file tree
Hide file tree
Showing 6 changed files with 117 additions and 89 deletions.
2 changes: 2 additions & 0 deletions x-pack/plugins/transform/common/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down
33 changes: 33 additions & 0 deletions x-pack/plugins/transform/public/app/hooks/use_can_delete_index.ts
Original file line number Diff line number Diff line change
@@ -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<boolean, IHttpFetchError>(
[TRANSFORM_REACT_QUERY_KEYS.CAN_DELETE_INDEX],
async ({ signal }) => {
const resp = await http.get<PrivilegesAndCapabilities>(addInternalBasePath('privileges'), {
version: '1',
signal,
});
if (!resp) {
return false;
}
return resp.privileges.hasAllPrivileges;
}
);
};
32 changes: 32 additions & 0 deletions x-pack/plugins/transform/public/app/hooks/use_data_view_exists.ts
Original file line number Diff line number Diff line change
@@ -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<boolean, ErrorType>(
[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 }
);
};
108 changes: 49 additions & 59 deletions x-pack/plugins/transform/public/app/hooks/use_delete_transform.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -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<boolean>(true);
const [deleteDataView, setDeleteDataView] = useState<boolean>(true);
const [userCanDeleteIndex, setUserCanDeleteIndex] = useState<boolean>(false);
const [dataViewExists, setDataViewExists] = useState<boolean>(false);
const [userCanDeleteDataView, setUserCanDeleteDataView] = useState<boolean>(false);
const [deleteDataView, setDeleteDataView] = useState<boolean>(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),
Expand All @@ -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<string | undefined>(() => {
// 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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export type DeleteAction = ReturnType<typeof useDeleteAction>;
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<TransformListRow[]>([]);
Expand Down
29 changes: 0 additions & 29 deletions x-pack/plugins/transform/public/app/services/es_index_service.ts

This file was deleted.

0 comments on commit 3adfd4a

Please sign in to comment.