diff --git a/frontend/__tests__/components/Common/DateRangeViewer/DateRangeViewer.test.tsx b/frontend/__tests__/components/Common/DateRangeViewer/DateRangeViewer.test.tsx index 4b401164a..10ed03165 100644 --- a/frontend/__tests__/components/Common/DateRangeViewer/DateRangeViewer.test.tsx +++ b/frontend/__tests__/components/Common/DateRangeViewer/DateRangeViewer.test.tsx @@ -1,7 +1,7 @@ import { nextStep, - updateMetricsPageFailedTimeRangeInfos, - updateReportPageFailedTimeRangeInfos, + updateMetricsPageLoadingStatus, + updateReportPageLoadingStatus, } from '@src/context/stepper/StepperSlice'; import { formatDateToTimestampString, sortDateRanges } from '@src/utils/util'; import DateRangeViewer from '@src/components/Common/DateRangeViewer'; @@ -13,6 +13,19 @@ import { Provider } from 'react-redux'; import React from 'react'; const changeDateRange = jest.fn(); +const loadedSuccess = { isLoading: false, isLoaded: true, isLoadedWithError: false }; +const allMetricsPageDataLoadedSuccess = { + boardInfo: loadedSuccess, + pipelineInfo: loadedSuccess, + pipelineStep: loadedSuccess, +}; +const allReportPageDataLoadedSuccess = { + gainPollingUrl: loadedSuccess, + polling: loadedSuccess, + boardMetrics: loadedSuccess, + pipelineMetrics: loadedSuccess, + sourceControlMetrics: loadedSuccess, +}; describe('DateRangeViewer', () => { let store = setupStore(); @@ -77,18 +90,30 @@ describe('DateRangeViewer', () => { const failedTimeRangeList = [ { startDate: formatDateToTimestampString('2024-02-01T00:00:00.000+08:00'), - errors: { isBoardInfoError: true, isPipelineInfoError: false, isPipelineStepError: false }, + loadingStatus: { + boardInfo: { isLoading: false, isLoaded: true, isLoadedWithError: true }, + pipelineInfo: loadedSuccess, + pipelineStep: loadedSuccess, + }, }, { startDate: formatDateToTimestampString('2024-03-19T00:00:00.000+08:00'), - errors: { isBoardInfoError: false, isPipelineInfoError: false, isPipelineStepError: false }, + loadingStatus: { + boardInfo: loadedSuccess, + pipelineInfo: loadedSuccess, + pipelineStep: loadedSuccess, + }, }, { startDate: formatDateToTimestampString('2024-04-01T00:00:00.000+08:00'), - errors: { isBoardInfoError: false, isPipelineInfoError: false, isPipelineStepError: false }, + loadingStatus: { + boardInfo: loadedSuccess, + pipelineInfo: loadedSuccess, + pipelineStep: loadedSuccess, + }, }, ]; - store.dispatch(updateMetricsPageFailedTimeRangeInfos(failedTimeRangeList)); + store.dispatch(updateMetricsPageLoadingStatus(failedTimeRangeList)); const { getByLabelText } = setup(mockDateRanges); expect(screen.getByTestId('PriorityHighIcon')).toBeInTheDocument(); @@ -100,18 +125,30 @@ describe('DateRangeViewer', () => { const failedTimeRangeList = [ { startDate: formatDateToTimestampString('2024-02-01T00:00:00.000+08:00'), - errors: { isBoardInfoError: undefined, isPipelineInfoError: false, isPipelineStepError: false }, + loadingStatus: { + boardInfo: { isLoading: true, isLoaded: false, isLoadedWithError: false }, + pipelineInfo: loadedSuccess, + pipelineStep: loadedSuccess, + }, }, { startDate: formatDateToTimestampString('2024-03-19T00:00:00.000+08:00'), - errors: { isBoardInfoError: false, isPipelineInfoError: false, isPipelineStepError: false }, + loadingStatus: { + boardInfo: loadedSuccess, + pipelineInfo: loadedSuccess, + pipelineStep: loadedSuccess, + }, }, { startDate: formatDateToTimestampString('2024-04-01T00:00:00.000+08:00'), - errors: { isBoardInfoError: false, isPipelineInfoError: false, isPipelineStepError: false }, + loadingStatus: { + boardInfo: loadedSuccess, + pipelineInfo: loadedSuccess, + pipelineStep: loadedSuccess, + }, }, ]; - store.dispatch(updateMetricsPageFailedTimeRangeInfos(failedTimeRangeList)); + store.dispatch(updateMetricsPageLoadingStatus(failedTimeRangeList)); const { getByLabelText } = setup(mockDateRanges); expect(screen.getByLabelText('loading icon in date')).toBeInTheDocument(); @@ -124,18 +161,18 @@ describe('DateRangeViewer', () => { const failedTimeRangeList = [ { startDate: formatDateToTimestampString('2024-02-01T00:00:00.000+08:00'), - errors: { isBoardInfoError: false, isPipelineInfoError: false, isPipelineStepError: false }, + loadingStatus: allMetricsPageDataLoadedSuccess, }, { startDate: formatDateToTimestampString('2024-03-19T00:00:00.000+08:00'), - errors: { isBoardInfoError: false, isPipelineInfoError: false, isPipelineStepError: false }, + loadingStatus: allMetricsPageDataLoadedSuccess, }, { startDate: formatDateToTimestampString('2024-04-01T00:00:00.000+08:00'), - errors: { isBoardInfoError: false, isPipelineInfoError: false, isPipelineStepError: false }, + loadingStatus: allMetricsPageDataLoadedSuccess, }, ]; - store.dispatch(updateMetricsPageFailedTimeRangeInfos(failedTimeRangeList)); + store.dispatch(updateMetricsPageLoadingStatus(failedTimeRangeList)); const { getByLabelText } = setup(mockDateRanges); expect(screen.getByTestId('CheckIcon')).toBeInTheDocument(); @@ -179,15 +216,15 @@ describe('DateRangeViewer', () => { const failedTimeRangeList = [ { startDate: formatDateToTimestampString('2024-02-01T00:00:00.000+08:00'), - errors: { isGainPollingUrlError: false }, + loadingStatus: allReportPageDataLoadedSuccess, }, { startDate: formatDateToTimestampString('2024-03-19T00:00:00.000+08:00'), - errors: { isPollingError: false }, + loadingStatus: allReportPageDataLoadedSuccess, }, ]; - store.dispatch(updateReportPageFailedTimeRangeInfos(failedTimeRangeList)); + store.dispatch(updateReportPageLoadingStatus(failedTimeRangeList)); const { getByLabelText } = setup(mockDateRanges); await userEvent.click(getByLabelText('expandMore')); @@ -214,66 +251,56 @@ describe('DateRangeViewer', () => { const failedTimeRangeList = [ { startDate: formatDateToTimestampString('2024-02-01T00:00:00.000+08:00'), - errors: { - isBoardMetricsError: true, - isGainPollingUrlError: false, - isPipelineMetricsError: false, - isPollingError: false, - isSourceControlMetricsError: false, + loadingStatus: { + gainPollingUrl: loadedSuccess, + polling: loadedSuccess, + boardMetrics: { isLoading: false, isLoaded: true, isLoadedWithError: true }, + pipelineMetrics: loadedSuccess, + sourceControlMetrics: loadedSuccess, }, }, { startDate: formatDateToTimestampString('2024-03-19T00:00:00.000+08:00'), - errors: { - isBoardMetricsError: false, - isGainPollingUrlError: true, - isPipelineMetricsError: false, - isPollingError: false, - isSourceControlMetricsError: false, + loadingStatus: { + gainPollingUrl: { isLoading: false, isLoaded: true, isLoadedWithError: true }, }, }, { startDate: formatDateToTimestampString('2024-04-01T00:00:00.000+08:00'), - errors: { - isBoardMetricsError: false, - isGainPollingUrlError: false, - isPipelineMetricsError: true, - isPollingError: false, - isSourceControlMetricsError: false, + loadingStatus: { + gainPollingUrl: loadedSuccess, + polling: loadedSuccess, + boardMetrics: loadedSuccess, + pipelineMetrics: { isLoading: false, isLoaded: true, isLoadedWithError: true }, + sourceControlMetrics: loadedSuccess, }, }, { startDate: formatDateToTimestampString('2023-02-01T00:00:00.000+08:00'), - errors: { - isBoardMetricsError: false, - isGainPollingUrlError: false, - isPipelineMetricsError: false, - isPollingError: true, - isSourceControlMetricsError: false, + loadingStatus: { + gainPollingUrl: loadedSuccess, + polling: { isLoading: false, isLoaded: true, isLoadedWithError: true }, + boardMetrics: { isLoading: false, isLoaded: true, isLoadedWithError: true }, + pipelineMetrics: { isLoading: false, isLoaded: true, isLoadedWithError: true }, + sourceControlMetrics: { isLoading: false, isLoaded: true, isLoadedWithError: true }, }, }, { startDate: formatDateToTimestampString('2023-03-19T00:00:00.000+08:00'), - errors: { - isBoardMetricsError: false, - isGainPollingUrlError: false, - isPipelineMetricsError: false, - isPollingError: false, - isSourceControlMetricsError: true, + loadingStatus: { + gainPollingUrl: loadedSuccess, + polling: loadedSuccess, + boardMetrics: loadedSuccess, + pipelineMetrics: loadedSuccess, + sourceControlMetrics: { isLoading: false, isLoaded: true, isLoadedWithError: true }, }, }, { startDate: formatDateToTimestampString('2023-04-01T00:00:00.000+08:00'), - errors: { - isBoardMetricsError: false, - isGainPollingUrlError: false, - isPipelineMetricsError: false, - isPollingError: false, - isSourceControlMetricsError: false, - }, + loadingStatus: allReportPageDataLoadedSuccess, }, ]; - store.dispatch(updateReportPageFailedTimeRangeInfos(failedTimeRangeList)); + store.dispatch(updateReportPageLoadingStatus(failedTimeRangeList)); const { getByLabelText } = setup(dateRangeList); expect(screen.getByTestId('PriorityHighIcon')).toBeInTheDocument(); diff --git a/frontend/__tests__/context/stepperSlice.test.ts b/frontend/__tests__/context/stepperSlice.test.ts index 9f0bec180..87be03999 100644 --- a/frontend/__tests__/context/stepperSlice.test.ts +++ b/frontend/__tests__/context/stepperSlice.test.ts @@ -21,8 +21,8 @@ describe('stepper reducer', () => { stepNumber: 0, timeStamp: 0, shouldMetricsLoaded: true, - metricsPageFailedTimeRangeInfos: {}, - reportPageFailedTimeRangeInfos: {}, + metricsPageTimeRangeLoadingStatus: {}, + reportPageTimeRangeLoadingStatus: {}, }, nextStep(), ); @@ -36,8 +36,8 @@ describe('stepper reducer', () => { stepNumber: 0, timeStamp: 0, shouldMetricsLoaded: true, - metricsPageFailedTimeRangeInfos: {}, - reportPageFailedTimeRangeInfos: {}, + metricsPageTimeRangeLoadingStatus: {}, + reportPageTimeRangeLoadingStatus: {}, }, backStep(), ); @@ -51,8 +51,8 @@ describe('stepper reducer', () => { stepNumber: 2, timeStamp: 0, shouldMetricsLoaded: true, - metricsPageFailedTimeRangeInfos: {}, - reportPageFailedTimeRangeInfos: {}, + metricsPageTimeRangeLoadingStatus: {}, + reportPageTimeRangeLoadingStatus: {}, }, backStep(), ); @@ -67,8 +67,8 @@ describe('stepper reducer', () => { stepNumber: 2, timeStamp: 0, shouldMetricsLoaded: true, - metricsPageFailedTimeRangeInfos: {}, - reportPageFailedTimeRangeInfos: {}, + metricsPageTimeRangeLoadingStatus: {}, + reportPageTimeRangeLoadingStatus: {}, }, updateTimeStamp(mockTime), ); diff --git a/frontend/src/components/Common/DateRangeViewer/index.tsx b/frontend/src/components/Common/DateRangeViewer/index.tsx index cd2c7c6d3..f0726aa1c 100644 --- a/frontend/src/components/Common/DateRangeViewer/index.tsx +++ b/frontend/src/components/Common/DateRangeViewer/index.tsx @@ -11,8 +11,8 @@ import { StyledExpandMoreIcon, } from './style'; import { - IMetricsPageFailedDateRange, - IReportPageFailedDateRange, + IMetricsPageLoadingStatus, + IReportPageLoadingStatus, selectMetricsPageFailedTimeRangeInfos, selectReportPageFailedTimeRangeInfos, selectStepNumber, @@ -42,8 +42,8 @@ const DateRangeViewer = ({ }: Props) => { const [showMoreDateRange, setShowMoreDateRange] = useState(false); const DateRangeExpandRef = useRef(null); - const metricsPageFailedTimeRangeInfos = useAppSelector(selectMetricsPageFailedTimeRangeInfos); - const reportPageFailedTimeRangeInfos = useAppSelector(selectReportPageFailedTimeRangeInfos); + const metricsPageTimeRangeLoadingStatus = useAppSelector(selectMetricsPageFailedTimeRangeInfos); + const reportPageTimeRangeLoadingStatus = useAppSelector(selectReportPageFailedTimeRangeInfos); const stepNumber = useAppSelector(selectStepNumber); const currentDateRange: DateRange = selectedDateRange || dateRangeList[0]; const isMetricsPage = stepNumber === STEP_NUMBER.METRICS_PAGE; @@ -87,31 +87,18 @@ const DateRangeViewer = ({ }, [handleClickOutside]); function getDateRangeStatus(startDate: string) { - let errorInfo: IMetricsPageFailedDateRange | IReportPageFailedDateRange; - const dateRangeStatus: { isLoading: boolean; isFailed: boolean } = { isLoading: false, isFailed: false }; + let errorInfo: IMetricsPageLoadingStatus | IReportPageLoadingStatus; + if (isMetricsPage) { - errorInfo = metricsPageFailedTimeRangeInfos[startDate] || {}; - if ( - errorInfo.isBoardInfoError === undefined || - errorInfo.isPipelineInfoError === undefined || - errorInfo.isPipelineStepError === undefined - ) { - dateRangeStatus.isLoading = true; - } + errorInfo = metricsPageTimeRangeLoadingStatus[startDate] || {}; } else { - errorInfo = reportPageFailedTimeRangeInfos[startDate] || {}; - if ( - errorInfo.isBoardMetricsError === undefined || - errorInfo.isGainPollingUrlError === undefined || - errorInfo.isPipelineMetricsError === undefined || - errorInfo.isPollingError === undefined || - errorInfo.isSourceControlMetricsError === undefined - ) { - dateRangeStatus.isLoading = true; - } + errorInfo = reportPageTimeRangeLoadingStatus[startDate] || {}; } - dateRangeStatus.isFailed = Object.values(errorInfo).some((value) => value); - return dateRangeStatus; + + return { + isLoading: Object.values(errorInfo).some(({ isLoading }) => isLoading), + isFailed: Object.values(errorInfo).some(({ isLoaded, isLoadedWithError }) => isLoaded && isLoadedWithError), + }; } function getTotalDateRangeStatus() { diff --git a/frontend/src/context/stepper/StepperSlice.tsx b/frontend/src/context/stepper/StepperSlice.tsx index 5553f171c..b7eb905a3 100644 --- a/frontend/src/context/stepper/StepperSlice.tsx +++ b/frontend/src/context/stepper/StepperSlice.tsx @@ -2,39 +2,45 @@ import { STEP_NUMBER } from '@src/constants/commons'; import { createSlice } from '@reduxjs/toolkit'; import type { RootState } from '@src/store'; -export interface IMetricsPageFailedDateRange { - isBoardInfoError?: boolean; - isPipelineInfoError?: boolean; - isPipelineStepError?: boolean; +interface LoadingStatus { + isLoading: boolean; + isLoaded: boolean; + isLoadedWithError: boolean; } -export interface IReportPageFailedDateRange { - isGainPollingUrlError?: boolean; - isPollingError?: boolean; - isBoardMetricsError?: boolean; - isPipelineMetricsError?: boolean; - isSourceControlMetricsError?: boolean; +export interface IMetricsPageLoadingStatus { + boardInfo?: LoadingStatus; + pipelineInfo?: LoadingStatus; + pipelineStep?: LoadingStatus; } -export interface IPageFailedDateRangePayload { +export interface IReportPageLoadingStatus { + gainPollingUrl?: LoadingStatus; + polling?: LoadingStatus; + boardMetrics?: LoadingStatus; + pipelineMetrics?: LoadingStatus; + sourceControlMetrics?: LoadingStatus; +} + +export interface IPageLoadingStatusPayload { startDate: string; - errors: T; + loadingStatus: T; } export interface StepState { stepNumber: number; timeStamp: number; shouldMetricsLoaded: boolean; - metricsPageFailedTimeRangeInfos: Record; - reportPageFailedTimeRangeInfos: Record; + metricsPageTimeRangeLoadingStatus: Record; + reportPageTimeRangeLoadingStatus: Record; } const initialState: StepState = { stepNumber: STEP_NUMBER.CONFIG_PAGE, timeStamp: 0, shouldMetricsLoaded: true, - metricsPageFailedTimeRangeInfos: {}, - reportPageFailedTimeRangeInfos: {}, + metricsPageTimeRangeLoadingStatus: {}, + reportPageTimeRangeLoadingStatus: {}, }; export const stepperSlice = createSlice({ @@ -47,10 +53,10 @@ export const stepperSlice = createSlice({ }, nextStep: (state) => { if (state.shouldMetricsLoaded && state.stepNumber === STEP_NUMBER.CONFIG_PAGE) { - state.metricsPageFailedTimeRangeInfos = {}; + state.metricsPageTimeRangeLoadingStatus = {}; } if (state.stepNumber === STEP_NUMBER.METRICS_PAGE) { - state.reportPageFailedTimeRangeInfos = {}; + state.reportPageTimeRangeLoadingStatus = {}; } state.shouldMetricsLoaded = true; state.stepNumber += 1; @@ -65,30 +71,30 @@ export const stepperSlice = createSlice({ updateTimeStamp: (state, action) => { state.timeStamp = action.payload; }, - updateMetricsPageFailedTimeRangeInfos: (state, action) => { - const errorInfoList: IPageFailedDateRangePayload[] = action.payload; + updateMetricsPageLoadingStatus: (state, action) => { + const loadingStatusList: IPageLoadingStatusPayload[] = action.payload; - errorInfoList.forEach((singleTimeRangeInfo) => updateInfo(singleTimeRangeInfo)); + loadingStatusList.forEach((singleTimeRangeInfo) => updateInfo(singleTimeRangeInfo)); - function updateInfo(errorInfo: IPageFailedDateRangePayload) { - const { startDate, errors } = errorInfo; - state.metricsPageFailedTimeRangeInfos[startDate] = { - ...state.metricsPageFailedTimeRangeInfos[startDate], - ...errors, + function updateInfo(loadingInfo: IPageLoadingStatusPayload) { + const { startDate, loadingStatus } = loadingInfo; + state.metricsPageTimeRangeLoadingStatus[startDate] = { + ...state.metricsPageTimeRangeLoadingStatus[startDate], + ...loadingStatus, }; } }, - updateReportPageFailedTimeRangeInfos: (state, action) => { - const errorInfoList: IPageFailedDateRangePayload[] = action.payload; + updateReportPageLoadingStatus: (state, action) => { + const loadingStatusList: IPageLoadingStatusPayload[] = action.payload; - errorInfoList.forEach((singleTimeRangeInfo) => updateInfo(singleTimeRangeInfo)); + loadingStatusList.forEach((singleTimeRangeInfo) => updateInfo(singleTimeRangeInfo)); - function updateInfo(errorInfo: IPageFailedDateRangePayload) { - const { startDate, errors } = errorInfo; - state.reportPageFailedTimeRangeInfos[startDate] = { - ...state.reportPageFailedTimeRangeInfos[startDate], - ...errors, + function updateInfo(loadingInfo: IPageLoadingStatusPayload) { + const { startDate, loadingStatus } = loadingInfo; + state.reportPageTimeRangeLoadingStatus[startDate] = { + ...state.reportPageTimeRangeLoadingStatus[startDate], + ...loadingStatus, }; } }, @@ -101,16 +107,17 @@ export const { backStep, updateShouldMetricsLoaded, updateTimeStamp, - updateMetricsPageFailedTimeRangeInfos, - updateReportPageFailedTimeRangeInfos, + updateMetricsPageLoadingStatus, + updateReportPageLoadingStatus, } = stepperSlice.actions; export const selectStepNumber = (state: RootState) => state.stepper.stepNumber; export const selectTimeStamp = (state: RootState) => state.stepper.timeStamp; export const shouldMetricsLoaded = (state: RootState) => state.stepper.shouldMetricsLoaded; export const selectMetricsPageFailedTimeRangeInfos = (state: RootState) => - state.stepper.metricsPageFailedTimeRangeInfos; + state.stepper.metricsPageTimeRangeLoadingStatus; -export const selectReportPageFailedTimeRangeInfos = (state: RootState) => state.stepper.reportPageFailedTimeRangeInfos; +export const selectReportPageFailedTimeRangeInfos = (state: RootState) => + state.stepper.reportPageTimeRangeLoadingStatus; export default stepperSlice.reducer; diff --git a/frontend/src/hooks/useGenerateReportEffect.ts b/frontend/src/hooks/useGenerateReportEffect.ts index 493ab027e..7b4d741ea 100644 --- a/frontend/src/hooks/useGenerateReportEffect.ts +++ b/frontend/src/hooks/useGenerateReportEffect.ts @@ -1,7 +1,7 @@ import { - IPageFailedDateRangePayload, - IReportPageFailedDateRange, - updateReportPageFailedTimeRangeInfos, + IPageLoadingStatusPayload, + IReportPageLoadingStatus, + updateReportPageLoadingStatus, } from '@src/context/stepper/StepperSlice'; import { ReportCallbackResponse, ReportResponseDTO } from '@src/clients/report/dto/response'; import { exportValidityTimeMapper } from '@src/hooks/reportMapper/exportValidityTime'; @@ -106,7 +106,7 @@ export const useGenerateReportEffect = (): IUseGenerateReportEffect => { nextHasPollingStarted = true; setHasPollingStarted(nextHasPollingStarted); - resetReportPageFailedTimeRangeInfos(dateRangeList); + resetReportPageLoadingStatus(dateRangeList); const res: PromiseSettledResult[] = await Promise.allSettled( dateRangeList.map(({ startDate, endDate }) => @@ -125,6 +125,7 @@ export const useGenerateReportEffect = (): IUseGenerateReportEffect => { const { pollingInfos, pollingInterval } = assemblePollingParams(res); + resetPollingLoadingStatusBeforePolling(pollingInfos.map((item) => item.id)); await pollingReport({ pollingInfos, interval: pollingInterval }); }; @@ -167,7 +168,7 @@ export const useGenerateReportEffect = (): IUseGenerateReportEffect => { const pollingResponsesWithId = assemblePollingResWithId(pollingResponses, pollingInfos); setReportInfos((preReportInfos) => getReportInfosAfterPolling(preReportInfos, pollingResponsesWithId)); - updateReportPageFailedTimeRangeInfosAfterPolling(pollingResponsesWithId); + updateReportPageLoadingStatusAfterPolling(pollingResponsesWithId); const nextPollingInfos = getNextPollingInfos(pollingResponsesWithId, pollingInfos); if (nextPollingInfos.length === 0) { @@ -204,25 +205,48 @@ export const useGenerateReportEffect = (): IUseGenerateReportEffect => { }); }; - const resetReportPageFailedTimeRangeInfos = (dateRangeList: DateRangeList) => { + const resetReportPageLoadingStatus = (dateRangeList: DateRangeList) => { + const loadingStatus = { + isLoading: false, + isLoaded: false, + isLoadedWithError: false, + }; const payload = dateRangeList.map(({ startDate }) => ({ startDate: formatDateToTimestampString(startDate!), - errors: { - isGainPollingUrlError: undefined, - isPollingError: undefined, - isBoardMetricsError: undefined, - isPipelineMetricsError: undefined, - isSourceControlMetricsError: undefined, + loadingStatus: { + gainPollingUrl: { isLoading: false, isLoaded: false, isLoadedWithError: false }, + polling: { ...loadingStatus }, + boardMetrics: { ...loadingStatus }, + pipelineMetrics: { ...loadingStatus }, + sourceControlMetrics: { ...loadingStatus }, }, })); - dispatch(updateReportPageFailedTimeRangeInfos(payload)); + dispatch(updateReportPageLoadingStatus(payload)); }; + function resetPollingLoadingStatusBeforePolling(dates: string[]) { + const loadingStatus = { + isLoading: true, + isLoaded: false, + isLoadedWithError: false, + }; + const payload = dates.map((date) => ({ + startDate: formatDateToTimestampString(date), + loadingStatus: { + polling: { ...loadingStatus }, + boardMetrics: { ...loadingStatus }, + pipelineMetrics: { ...loadingStatus }, + sourceControlMetrics: { ...loadingStatus }, + }, + })); + dispatch(updateReportPageLoadingStatus(payload)); + } + const updateErrorAfterFetchReport = ( res: PromiseSettledResult[], metricTypes: MetricTypes[], ) => { - updateReportPageFailedTimeRangeInfosAfterReport(res); + updateReportPageLoadingStatusAfterReport(res); if (res.filter(({ status }) => status === REJECTED).length === 0) return; @@ -239,37 +263,59 @@ export const useGenerateReportEffect = (): IUseGenerateReportEffect => { }); }; - function updateReportPageFailedTimeRangeInfosAfterPolling( + function updateReportPageLoadingStatusAfterPolling( pollingResponsesWithId: PromiseSettledResultWithId[], ) { - const updateReportPageFailedTimeRangeInfosPayload: IPageFailedDateRangePayload[] = []; + const updateReportPageFailedTimeRangeInfosPayload: IPageLoadingStatusPayload[] = []; pollingResponsesWithId.forEach((currentRes) => { const isRejected = currentRes.status === REJECTED; if (isRejected || currentRes.value.response.allMetricsCompleted) { updateReportPageFailedTimeRangeInfosPayload.push({ startDate: formatDateToTimestampString(currentRes.id), - errors: { - isPollingError: isRejected, - isBoardMetricsError: !isRejected && !!currentRes.value.response.reportMetricsError.boardMetricsError, - isSourceControlMetricsError: - !isRejected && !!currentRes.value.response.reportMetricsError.sourceControlMetricsError, - isPipelineMetricsError: !isRejected && !!currentRes.value.response.reportMetricsError.pipelineMetricsError, + loadingStatus: { + polling: { + isLoading: false, + isLoaded: true, + isLoadedWithError: isRejected, + }, + boardMetrics: { + isLoading: false, + isLoaded: true, + isLoadedWithError: !isRejected && !!currentRes.value.response.reportMetricsError.boardMetricsError, + }, + pipelineMetrics: { + isLoading: false, + isLoaded: true, + isLoadedWithError: !isRejected && !!currentRes.value.response.reportMetricsError.pipelineMetricsError, + }, + sourceControlMetrics: { + isLoading: false, + isLoaded: true, + isLoadedWithError: + !isRejected && !!currentRes.value.response.reportMetricsError.sourceControlMetricsError, + }, }, }); } }); - dispatch(updateReportPageFailedTimeRangeInfos(updateReportPageFailedTimeRangeInfosPayload)); + dispatch(updateReportPageLoadingStatus(updateReportPageFailedTimeRangeInfosPayload)); } - function updateReportPageFailedTimeRangeInfosAfterReport(res: PromiseSettledResult[]) { - const updateReportPageFailedTimeRangeInfosPayload: IPageFailedDateRangePayload[] = []; + function updateReportPageLoadingStatusAfterReport(res: PromiseSettledResult[]) { + const updateReportPageFailedTimeRangeInfosPayload: IPageLoadingStatusPayload[] = []; res.forEach((currentRes, index) => { updateReportPageFailedTimeRangeInfosPayload.push({ startDate: formatDateToTimestampString(reportInfos[index].id), - errors: { isGainPollingUrlError: currentRes.status === REJECTED }, + loadingStatus: { + gainPollingUrl: { + isLoading: false, + isLoaded: true, + isLoadedWithError: currentRes.status === REJECTED, + }, + }, }); }); - dispatch(updateReportPageFailedTimeRangeInfos(updateReportPageFailedTimeRangeInfosPayload)); + dispatch(updateReportPageLoadingStatus(updateReportPageFailedTimeRangeInfosPayload)); } const assemblePollingParams = (res: PromiseSettledResult[]) => { diff --git a/frontend/src/hooks/useGetBoardInfo.ts b/frontend/src/hooks/useGetBoardInfo.ts index b71532640..ab630caee 100644 --- a/frontend/src/hooks/useGetBoardInfo.ts +++ b/frontend/src/hooks/useGetBoardInfo.ts @@ -1,5 +1,5 @@ import { AxiosRequestErrorCode, BOARD_CONFIG_INFO_ERROR, BOARD_CONFIG_INFO_TITLE } from '@src/constants/resources'; -import { updateMetricsPageFailedTimeRangeInfos } from '@src/context/stepper/StepperSlice'; +import { updateMetricsPageLoadingStatus } from '@src/context/stepper/StepperSlice'; import { boardInfoClient } from '@src/clients/board/BoardInfoClient'; import { BoardInfoConfigDTO } from '@src/clients/board/dto/request'; import { MetricsDataFailStatus } from '@src/constants/commons'; @@ -121,11 +121,15 @@ export const useGetBoardInfoEffect = (): useGetBoardInfoInterface => { }); dispatch( - updateMetricsPageFailedTimeRangeInfos( + updateMetricsPageLoadingStatus( dateRangeCopy.map((dateRange) => ({ startDate: formatDateToTimestampString(dateRange.startDate!), - errors: { - isBoardInfoError: undefined, + loadingStatus: { + boardInfo: { + isLoading: true, + isLoaded: false, + isLoadedWithError: false, + }, }, })), ), @@ -150,13 +154,17 @@ export const useGetBoardInfoEffect = (): useGetBoardInfoInterface => { .finally(() => { setIsLoading(false); dispatch( - updateMetricsPageFailedTimeRangeInfos( + updateMetricsPageLoadingStatus( dateRangeCopy.map((dateRange) => ({ startDate: formatDateToTimestampString(dateRange.startDate!), - errors: { - isBoardInfoError: localFailedTimeRangeList.includes( - formatDateToTimestampString(dateRange.startDate!), - ), + loadingStatus: { + boardInfo: { + isLoading: false, + isLoaded: true, + isLoadedWithError: localFailedTimeRangeList.includes( + formatDateToTimestampString(dateRange.startDate!), + ), + }, }, })), ), diff --git a/frontend/src/hooks/useGetMetricsStepsEffect.ts b/frontend/src/hooks/useGetMetricsStepsEffect.ts index 4c5c61cc1..bc7ad8fed 100644 --- a/frontend/src/hooks/useGetMetricsStepsEffect.ts +++ b/frontend/src/hooks/useGetMetricsStepsEffect.ts @@ -1,6 +1,6 @@ -import { updateMetricsPageFailedTimeRangeInfos } from '@src/context/stepper/StepperSlice'; import { updateShouldRetryPipelineConfig } from '@src/context/Metrics/metricsSlice'; import { IStepsParams, IStepsRes, metricsClient } from '@src/clients/MetricsClient'; +import { updateMetricsPageLoadingStatus } from '@src/context/stepper/StepperSlice'; import { MetricsDataFailStatus, DURATION } from '@src/constants/commons'; import { FULFILLED, MESSAGE, REJECTED } from '@src/constants/resources'; import { useAppDispatch } from '@src/hooks/useAppDispatch'; @@ -44,11 +44,17 @@ export const useGetMetricsStepsEffect = (): useGetMetricsStepsEffectInterface => setIsLoading(true); dispatch( - updateMetricsPageFailedTimeRangeInfos( + updateMetricsPageLoadingStatus( params.map((param) => { return { startDate: param.startTime, - errors: { isPipelineStepError: undefined }, + loadingStatus: { + pipelineStep: { + isLoading: true, + isLoaded: false, + isLoadedWithError: false, + }, + }, }; }), ), @@ -63,11 +69,17 @@ export const useGetMetricsStepsEffect = (): useGetMetricsStepsEffectInterface => const hasFulfilled = allStepsRes.some((stepInfo) => stepInfo.status === FULFILLED); dispatch( - updateMetricsPageFailedTimeRangeInfos( + updateMetricsPageLoadingStatus( params.map((param, index) => { return { startDate: param.startTime, - errors: { isPipelineStepError: allStepsRes[index].status === REJECTED }, + loadingStatus: { + pipelineStep: { + isLoading: false, + isLoaded: true, + isLoadedWithError: allStepsRes[index].status === REJECTED, + }, + }, }; }), ), diff --git a/frontend/src/hooks/useGetPipelineToolInfoEffect.ts b/frontend/src/hooks/useGetPipelineToolInfoEffect.ts index 0156a201b..ebf18674b 100644 --- a/frontend/src/hooks/useGetPipelineToolInfoEffect.ts +++ b/frontend/src/hooks/useGetPipelineToolInfoEffect.ts @@ -4,9 +4,9 @@ import { selectPipelineTool, selectDateRange, } from '@src/context/config/configSlice'; -import { shouldMetricsLoaded, updateMetricsPageFailedTimeRangeInfos } from '@src/context/stepper/StepperSlice'; import { pipelineToolClient, IGetPipelineToolInfoResult } from '@src/clients/pipeline/PipelineToolClient'; import { selectShouldGetPipelineConfig, updatePipelineSettings } from '@src/context/Metrics/metricsSlice'; +import { shouldMetricsLoaded, updateMetricsPageLoadingStatus } from '@src/context/stepper/StepperSlice'; import { clearMetricsPipelineFormMeta } from '@src/context/meta/metaSlice'; import { useEffect, useState, useRef, useCallback } from 'react'; import { formatDateToTimestampString } from '@src/utils/util'; @@ -44,11 +44,15 @@ export const useGetPipelineToolInfoEffect = (): IUseVerifyPipeLineToolStateInter }; setIsLoading(true); dispatch( - updateMetricsPageFailedTimeRangeInfos( + updateMetricsPageLoadingStatus( dateRangeList.map((dateRange) => ({ startDate: formatDateToTimestampString(dateRange.startDate!), - errors: { - isPipelineInfoError: undefined, + loadingStatus: { + pipelineInfo: { + isLoading: true, + isLoaded: false, + isLoadedWithError: false, + }, }, })), ), @@ -62,11 +66,15 @@ export const useGetPipelineToolInfoEffect = (): IUseVerifyPipeLineToolStateInter dispatch(updatePipelineSettings({ ...response.data, isProjectCreated })); } dispatch( - updateMetricsPageFailedTimeRangeInfos( + updateMetricsPageLoadingStatus( dateRangeList.map((dateRange) => ({ startDate: formatDateToTimestampString(dateRange.startDate!), - errors: { - isPipelineInfoError: response.code !== HttpStatusCode.Ok, + loadingStatus: { + pipelineInfo: { + isLoading: false, + isLoaded: true, + isLoadedWithError: response.code !== HttpStatusCode.Ok, + }, }, })), ),