"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.useFetchStream = useFetchStream; var _react = require("react"); var _useThrottle = _interopRequireDefault(require("react-use/lib/useThrottle")); var _mlIsPopulatedObject = require("@kbn/ml-is-populated-object"); var _fetch_stream = require("./fetch_stream"); var _string_reducer = require("./string_reducer"); /* * 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. */ // Type guard for custom reducer hook argument function isReducerOptions(arg) { return (0, _mlIsPopulatedObject.isPopulatedObject)(arg, ['reducer', 'initialState']); } /** * Custom hook to receive streaming data. * * Note on the use of `any`: * The generic `R` extends from `Reducer` * to match the definition in React itself. * * @param http Kibana HTTP client. * @param endpoint API endpoint including Kibana base path. * @param apiVersion Optional API version. * @param body Optional API request body. * @param customReducer Optional custom reducer and initial state. * @returns An object with streaming data and methods to act on the stream. */ function useFetchStream(http, endpoint, apiVersion, body, customReducer) { const [errors, setErrors] = (0, _react.useState)([]); const [isCancelled, setIsCancelled] = (0, _react.useState)(false); const [isRunning, setIsRunning] = (0, _react.useState)(false); const reducerWithFallback = isReducerOptions(customReducer) ? customReducer : { reducer: _string_reducer.stringReducer, initialState: '' }; const [data, dispatch] = (0, _react.useReducer)(reducerWithFallback.reducer, reducerWithFallback.initialState); const dataThrottled = (0, _useThrottle.default)(data, 100); const abortCtrl = (0, _react.useRef)(new AbortController()); const addError = error => { setErrors(prevErrors => [...prevErrors, error]); }; const start = async () => { if (isRunning) { addError('Instant restart while running not supported yet.'); return; } setErrors([]); setIsRunning(true); setIsCancelled(false); abortCtrl.current = new AbortController(); for await (const [fetchStreamError, actions] of (0, _fetch_stream.fetchStream)(http, endpoint, apiVersion, abortCtrl, body, customReducer !== undefined)) { if (fetchStreamError !== null) { addError(fetchStreamError); } else if (Array.isArray(actions) && actions.length > 0) { dispatch(actions); } } setIsRunning(false); }; const cancel = () => { abortCtrl.current.abort(); setIsCancelled(true); setIsRunning(false); }; // If components using this custom hook get unmounted, cancel any ongoing request. (0, _react.useEffect)(() => { return () => abortCtrl.current.abort(); }, []); return { cancel, // To avoid a race condition where the stream already ended but `useThrottle` would // yet have to trigger another update within the throttling interval, we'll return // the unthrottled data once the stream is complete. data: isRunning ? dataThrottled : data, dispatch, errors, isCancelled, isRunning, start }; }