Implement useAsyncPolling

This commit is contained in:
Nikita Nek Dudnik
2020-05-14 17:15:16 +02:00
parent ab9f48ab10
commit 9949ee6880
8 changed files with 82 additions and 49 deletions
+1
View File
@@ -20,6 +20,7 @@
"@material-ui/lab": "4.0.0-alpha.45",
"@types/react-lazylog": "^4.5.0",
"circleci-api": "^4.0.0",
"fast-deep-equal": "^3.1.1",
"moment": "^2.25.3",
"react": "16.13.1",
"react-dom": "16.13.1",
+15
View File
@@ -1,3 +1,18 @@
/*
* Copyright 2020 Spotify AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import React from 'react';
import { Switch, Route } from 'react-router';
import { BuildsPage } from '../pages/BuildsPage';
+2
View File
@@ -17,6 +17,7 @@ import React, { FC, useReducer, Dispatch, Reducer } from 'react';
import { circleCIApiRef } from '../api';
import { State, Action, SettingsState } from './types';
export { SettingsState };
import equal from 'fast-deep-equal';
export const AppContext = React.createContext<[State, Dispatch<Action>]>(
[] as any,
@@ -41,6 +42,7 @@ const reducer: Reducer<State, Action> = (state, action) => {
settings: { ...state.settings, ...action.payload },
};
case 'setBuilds':
if (equal(action.payload, state.builds)) return state;
return {
...state,
builds: action.payload,
+15
View File
@@ -1,3 +1,18 @@
/*
* Copyright 2020 Spotify AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { BuildSummary, BuildWithSteps } from '../api';
export type SettingsState = {
@@ -0,0 +1,37 @@
/*
* Copyright 2020 Spotify AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { useRef } from 'react';
export const useAsyncPolling = (
pollingFn: () => Promise<any>,
interval: number,
) => {
const isPolling = useRef<boolean>(false);
const startPolling = async () => {
if (isPolling.current === true) return;
isPolling.current = true;
while (isPolling.current === true) {
await pollingFn();
await new Promise((resolve) => setTimeout(resolve, interval));
}
};
const stopPolling = () => {
isPolling.current = false;
};
return { isPolling, startPolling, stopPolling };
};
@@ -14,21 +14,25 @@
* limitations under the License.
*/
import { errorApiRef, useApi } from '@backstage/core';
import { useContext, useRef } from 'react';
import { useContext } from 'react';
import { circleCIApiRef, GitType } from '../api/index';
import { AppContext } from '.';
import { useSettings } from './useSettings';
import { useAsyncPolling } from './useAsyncPolling';
const INTERVAL_AMOUNT = 3000;
export function useBuildWithSteps(buildId: number) {
const [settings] = useSettings();
const [{ buildsWithSteps }, dispatch] = useContext(AppContext);
const intervalId = useRef<number | null>(null);
const isPolling = intervalId !== null;
const api = useApi(circleCIApiRef);
const errorApi = useApi(errorApiRef);
const {isPolling, startPolling, stopPolling} = useAsyncPolling(() => getBuildWithSteps(), INTERVAL_AMOUNT);
const getBuildWithSteps = async () => {
try {
const options = {
@@ -61,19 +65,6 @@ export function useBuildWithSteps(buildId: number) {
}
};
const startPolling = () => {
stopPolling();
intervalId.current = (setInterval(
() => getBuildWithSteps(),
INTERVAL_AMOUNT,
) as any) as number;
};
const stopPolling = () => {
const currentIntervalId = intervalId.current;
if (currentIntervalId) clearInterval(currentIntervalId);
};
const build = buildsWithSteps[buildId];
return [
+5 -14
View File
@@ -15,17 +15,19 @@
*/
import { errorApiRef, useApi } from '@backstage/core';
import { GitType } from 'circleci-api';
import { useContext, useRef } from 'react';
import { useContext } from 'react';
import { circleCIApiRef } from '../api/index';
import { AppContext } from '.';
import { useAsyncPolling } from './useAsyncPolling';
const INTERVAL_AMOUNT = 3000;
export function useBuilds() {
const [{ builds, settings }, dispatch] = useContext(AppContext);
const intervalId = useRef<number | null>(null);
const api = useApi(circleCIApiRef);
const errorApi = useApi(errorApiRef);
const {isPolling, startPolling, stopPolling} = useAsyncPolling(() => getBuilds(), INTERVAL_AMOUNT);
const getBuilds = async () => {
if (settings.owner === '' || settings.repo === '') return;
@@ -38,7 +40,7 @@ export function useBuilds() {
type: GitType.GITHUB,
},
});
dispatch({
if (isPolling) dispatch({
type: 'setBuilds',
payload: newBuilds,
});
@@ -62,18 +64,7 @@ export function useBuilds() {
}
};
const startPolling = () => {
stopPolling();
intervalId.current = (setInterval(
() => getBuilds(),
INTERVAL_AMOUNT,
) as unknown) as number;
};
const stopPolling = () => {
const currentIntervalId = intervalId.current;
if (currentIntervalId) clearInterval(currentIntervalId);
};
return [
builds,
-19
View File
@@ -17,28 +17,9 @@ import { useContext, useEffect } from 'react';
import { AppContext, STORAGE_KEY, SettingsState } from '.';
import { useApi, errorApiRef } from '@backstage/core';
// type Effect = {
// type: 'rehydrate',
// payload: any
// };
// const effects = [];
// pushEffect, popEffect
export function useSettings() {
const [{ settings }, dispatch] = useContext(AppContext);
// const interpret = eff => {
// return {
// async rehydrate() {},
// }[eff.type](eff.payload)
// }
// useEffect(() => {
// const effectToInterpret = effects[0];
// removeEffect(0);
// interpret(effectToInterpret)
// },[effects])
const errorApi = useApi(errorApiRef);