Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ADM-973 [frontend] retry all when retry #1524

Merged
merged 9 commits into from
Jul 12, 2024
30 changes: 30 additions & 0 deletions frontend/__tests__/hooks/useGenerateReportEffect.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -280,3 +280,33 @@ describe('use generate report effect', () => {
expect(result.current.reportInfos[1].timeout4Dora.shouldShow).toEqual(true);
});
});

describe('generateReportId execution', () => {
it('should not call generateReportId when call startToRequestData method given reportId is already generated', async () => {
reportClient.generateReportId = jest.fn().mockResolvedValue({ reportId: 'mockReportId' });
reportClient.polling = jest
.fn()
.mockImplementation(async () => ({ status: HttpStatusCode.Ok, response: MOCK_REPORT_RESPONSE }));
reportClient.retrieveByUrl = jest.fn().mockImplementation(async () => MOCK_RETRIEVE_REPORT_RESPONSE);

const { result } = setup();

await waitFor(() => {
result.current.startToRequestData(MOCK_GENERATE_REPORT_REQUEST_PARAMS_WITH_BOARD_METRIC_TYPE);
});

jest.runOnlyPendingTimers();

await waitFor(() => {
expect(reportClient.generateReportId).toHaveBeenCalledTimes(1);
});

await waitFor(() => {
result.current.startToRequestData(MOCK_GENERATE_REPORT_REQUEST_PARAMS_WITH_BOARD_METRIC_TYPE);
});

await waitFor(() => {
expect(reportClient.generateReportId).toHaveBeenCalledTimes(1);
});
});
});
42 changes: 42 additions & 0 deletions frontend/__tests__/utils/Util.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
sortDateRanges,
sortDisabledOptions,
sortLegend,
sortReportInfos,
transformToCleanedBuildKiteEmoji,
updateResponseCrews,
valueFormatter,
Expand All @@ -33,6 +34,7 @@ import {
import { CleanedBuildKiteEmoji, OriginBuildKiteEmoji } from '@src/constants/emojis/emoji';
import { ICycleTimeSetting, IPipelineConfig } from '@src/context/Metrics/metricsSlice';
import { IPipeline } from '@src/context/config/pipelineTool/verifyResponseSlice';
import { IReportInfo } from '../../src/hooks/useGenerateReportEffect';
import { BoardInfoResponse } from '@src/hooks/useGetBoardInfo';
import { EMPTY_STRING } from '@src/constants/commons';
import { PIPELINE_TOOL_TYPES } from '../fixtures';
Expand Down Expand Up @@ -447,6 +449,46 @@ describe('sortDateRanges function', () => {
});
});

describe('sortReportInfos function', () => {
const reportInfos = [
{
id: '2024-03-19T00:00:00.000+08:00',
reportData: {},
},
{
id: '2024-02-01T00:00:00.000+08:00',
reportData: {},
},
{
id: '2024-04-01T00:00:00.000+08:00',
reportData: {},
},
];
const expectResult = [
{
id: '2024-04-01T00:00:00.000+08:00',
reportData: {},
},
{
id: '2024-03-19T00:00:00.000+08:00',
reportData: {},
},
{
id: '2024-02-01T00:00:00.000+08:00',
reportData: {},
},
];
it('should descend reportInfos', () => {
const sortedReportInfos = sortReportInfos(reportInfos as IReportInfo[]);
expect(sortedReportInfos).toStrictEqual(expectResult);
});

it('should ascend reportInfos', () => {
const sortedReportInfos = sortReportInfos(reportInfos as IReportInfo[], false);
expect(sortedReportInfos).toStrictEqual(expectResult.reverse());
});
});

describe('combineBoardInfo function', () => {
const boardInfoResponses: BoardInfoResponse[] = [
{
Expand Down
5 changes: 1 addition & 4 deletions frontend/src/clients/report/CSVClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { downloadCSV } from '@src/utils/util';
import dayjs from 'dayjs';

export class CSVClient extends HttpClient {
parseTimeStampToHumanDate = (csvTimeStamp: number | undefined): string => dayjs(csvTimeStamp).format('HHmmSSS');
parseCollectionDateToHumanDate = (date: string) => dayjs(date).format('YYYYMMDD');

exportCSVData = async (params: CSVReportRequestDTO) => {
Expand All @@ -19,9 +18,7 @@ export class CSVClient extends HttpClient {
.then((res) => {
const exportedFilename = `${params.dataType}-${this.parseCollectionDateToHumanDate(
params.startDate,
)}-${this.parseCollectionDateToHumanDate(params.endDate)}-${this.parseTimeStampToHumanDate(
params.reportId,
)}.csv`;
)}-${this.parseCollectionDateToHumanDate(params.endDate)}-${params.reportId}.csv`;
downloadCSV(exportedFilename, res.data);
})
.catch((e) => {
Expand Down
32 changes: 10 additions & 22 deletions frontend/src/containers/ReportStep/ReportContent/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
TimeoutErrorKey,
useGenerateReportEffect,
} from '@src/hooks/useGenerateReportEffect';
import { sortDateRanges } from '@src/utils/util';
import { sortDateRanges, sortReportInfos } from '@src/utils/util';

import {
addNotification,
Expand Down Expand Up @@ -54,8 +54,7 @@ import { uniqueId } from 'lodash';
export interface ReportContentProps {
metrics: string[];
dateRanges: DateRangeList;
startToRequestDoraData: () => void;
startToRequestBoardData: () => void;
startToRequestData: () => void;
reportInfos: IReportInfo[];
handleSave?: () => void;
reportId?: number;
Expand All @@ -75,16 +74,8 @@ export interface DateRangeRequestResult {
}

const ReportContent = (props: ReportContentProps) => {
const {
metrics,
dateRanges,
startToRequestDoraData,
startToRequestBoardData,
reportInfos,
handleSave,
reportId,
hideButtons = false,
} = props;
const { metrics, dateRanges, reportInfos, handleSave, reportId, startToRequestData, hideButtons = false } = props;

const dispatch = useAppDispatch();

const descendingDateRanges = sortDateRanges(dateRanges);
Expand All @@ -98,6 +89,7 @@ const ReportContent = (props: ReportContentProps) => {

return `${formattedStart}-${formattedEnd}`;
});
const ascendingReportInfos = sortReportInfos(reportInfos, false);

const [selectedDateRange, setSelectedDateRange] = useState<DateRange>(descendingDateRanges[0]);
const [currentDataInfo, setCurrentDataInfo] = useState<IReportInfo>(initReportInfo());
Expand Down Expand Up @@ -258,7 +250,7 @@ const ReportContent = (props: ReportContentProps) => {
<Box>
{shouldShowBoardMetrics && (
<BoardMetrics
startToRequestBoardData={startToRequestBoardData}
startToRequestBoardData={startToRequestData}
onShowDetail={() => setPageType(REPORT_PAGE_TYPE.BOARD)}
boardReport={currentDataInfo.reportData}
errorMessage={getErrorMessage4Board()}
Expand All @@ -267,7 +259,7 @@ const ReportContent = (props: ReportContentProps) => {
)}
{shouldShowDoraMetrics && (
<DoraMetrics
startToRequestDoraData={startToRequestDoraData}
startToRequestDoraData={startToRequestData}
onShowDetail={() => setPageType(REPORT_PAGE_TYPE.DORA)}
doraReport={currentDataInfo.reportData}
metrics={metrics}
Expand Down Expand Up @@ -383,10 +375,6 @@ const ReportContent = (props: ReportContentProps) => {
setPageType(newValue === CHART_INDEX.BOARD ? REPORT_PAGE_TYPE.BOARD_CHART : REPORT_PAGE_TYPE.DORA_CHART);
};

const handleChartRetry = () => {
pageType === REPORT_PAGE_TYPE.DORA_CHART ? startToRequestDoraData() : startToRequestBoardData();
};

const tabProps = (index: number) => {
return {
id: `simple-tab-${index}`,
Expand All @@ -403,9 +391,9 @@ const ReportContent = (props: ReportContentProps) => {
case REPORT_PAGE_TYPE.DORA:
return !!reportData && showDoraDetail(reportData);
case REPORT_PAGE_TYPE.BOARD_CHART:
return showBoardChart(reportInfos);
return showBoardChart(ascendingReportInfos);
case REPORT_PAGE_TYPE.DORA_CHART:
return showDoraChart(reportInfos.map((infos) => infos.reportData));
return showDoraChart(ascendingReportInfos.map((infos) => infos.reportData));
}
};

Expand All @@ -430,7 +418,7 @@ const ReportContent = (props: ReportContentProps) => {
{startDate && endDate && (
<StyledCalendarWrapper data-testid={'calendarWrapper'} justCalendar={!shouldShowTabs}>
{shouldShowChartRetryButton() && (
<StyledRetry aria-label='chart retry' onClick={handleChartRetry}>
<StyledRetry aria-label='chart retry' onClick={startToRequestData}>
<ReplayIcon />
</StyledRetry>
)}
Expand Down
20 changes: 2 additions & 18 deletions frontend/src/containers/ReportStep/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ import {
selectConfig,
selectDateRange,
} from '@src/context/config/configSlice';
import { BOARD_METRICS, DORA_METRICS, MESSAGE, RequiredData } from '@src/constants/resources';
import { IPipelineConfig, selectMetricsContent } from '@src/context/Metrics/metricsSlice';
import { selectReportId, selectTimeStamp } from '@src/context/stepper/StepperSlice';
import { ReportResponseDTO } from '@src/clients/report/dto/response';
import { MESSAGE, RequiredData } from '@src/constants/resources';
import { useAppDispatch } from '@src/hooks/useAppDispatch';
import { MetricTypes } from '@src/constants/commons';
import ReportContent from './ReportContent';
Expand Down Expand Up @@ -170,21 +170,6 @@ const ReportStep = ({ handleSave }: ReportStepProps) => {
...(shouldShowDoraMetrics ? getDoraSetting() : {}),
};

const boardReportRequestBody = {
...basicReportRequestBody,
metrics: metrics.filter((metric) => BOARD_METRICS.includes(metric)),
metricTypes: [MetricTypes.Board],
buildKiteSetting: undefined,
codebaseSetting: undefined,
};

const doraReportRequestBody = {
...basicReportRequestBody,
metrics: metrics.filter((metric) => DORA_METRICS.includes(metric)),
metricTypes: [MetricTypes.DORA],
jiraBoardSetting: undefined,
};

useEffect(() => {
exportValidityTimeMin &&
isCsvFileGeneratedAtEnd &&
Expand Down Expand Up @@ -242,8 +227,7 @@ const ReportStep = ({ handleSave }: ReportStepProps) => {
<ReportContent
metrics={metrics}
dateRanges={dateRanges}
startToRequestDoraData={() => startToRequestData(doraReportRequestBody)}
startToRequestBoardData={() => startToRequestData(boardReportRequestBody)}
startToRequestData={() => startToRequestData(basicReportRequestBody)}
reportInfos={reportInfos}
handleSave={handleSave}
reportId={reportId}
Expand Down
3 changes: 1 addition & 2 deletions frontend/src/containers/ShareReport/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,7 @@ const ShareReport = () => {
metrics={metrics}
dateRanges={dateRanges}
reportInfos={reportInfos}
startToRequestBoardData={getData}
startToRequestDoraData={getData}
startToRequestData={getData}
hideButtons
/>
</StyledPageContentWrapper>
Expand Down
17 changes: 13 additions & 4 deletions frontend/src/hooks/useGenerateReportEffect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ export const useGenerateReportEffect = (): IUseGenerateReportEffect => {
dateRangeList.map((dateRange) => ({ ...initReportInfo(), id: dateRange.startDate as string })),
);
const [hasPollingStarted, setHasPollingStarted] = useState<boolean>(false);
const [reportId, setReportId] = useState<string>('');
let nextHasPollingStarted = false;

const startToRequestData = async (params: ReportRequestDTO) => {
Expand All @@ -115,8 +116,17 @@ export const useGenerateReportEffect = (): IUseGenerateReportEffect => {

resetReportPageLoadingStatus(dateRangeList);

const reportIdRes = await reportClient.generateReportId();
if (!reportId) {
const reportIdRes = await reportClient.generateReportId();
setReportId(reportIdRes.reportId);
dispatch(updateReportId(reportIdRes.reportId));
await retrieveUrlAndPolling(params, reportIdRes.reportId);
} else {
await retrieveUrlAndPolling(params, reportId);
}
};

const retrieveUrlAndPolling = async (params: ReportRequestDTO, reportId: string) => {
const res: PromiseSettledResult<ReportCallbackResponse>[] = await Promise.allSettled(
dateRangeList.map(({ startDate, endDate }) =>
reportClient.retrieveByUrl(
Expand All @@ -125,16 +135,15 @@ export const useGenerateReportEffect = (): IUseGenerateReportEffect => {
startTime: formatDateToTimestampString(startDate!),
endTime: formatDateToTimestampString(endDate!),
},
`${reportPath}/${reportIdRes.reportId}`,
`${reportPath}/${reportId}`,
),
),
);

updateErrorAfterFetchReport(res, metricTypes);
updateErrorAfterFetchReport(res, params.metricTypes);

const { pollingInfos, pollingInterval } = assemblePollingParams(res);

dispatch(updateReportId(reportIdRes.reportId));
resetPollingLoadingStatusBeforePolling(pollingInfos.map((item) => item.id));
await pollingReport({ pollingInfos, interval: pollingInterval });
};
Expand Down
1 change: 1 addition & 0 deletions frontend/src/layouts/ShareReportTrigger/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ const ShareReportTrigger = () => {
const handleClick = (event: React.MouseEvent<HTMLElement>) => {
if (canShare) {
setAnchorEl(anchorEl ? null : event.currentTarget);
setShowAlert(false);
}
};

Expand Down
3 changes: 2 additions & 1 deletion frontend/src/layouts/ShareReportTrigger/style.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ export const LinkLine = styled.div({
display: 'flex',
alignItems: 'center',
margin: '1.5rem 0',
height: '2.125rem',
a: {
cursor: 'pointer',
marginRight: '0.625rem',
Expand All @@ -59,7 +60,7 @@ export const LinkLine = styled.div({

export const ShareIconWrapper = styled.span(({ disabled }: { disabled: boolean }) => ({
padding: '0.5rem',
cursor: disabled ? 'unset !important' : 'pointer',
cursor: disabled ? 'not-allowed !important' : 'pointer',
marginLeft: '0.2rem',
'> svg': {
color: disabled ? theme.main.errorMessage.color : 'white',
Expand Down
10 changes: 9 additions & 1 deletion frontend/src/utils/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { IPipeline } from '@src/context/config/pipelineTool/verifyResponseSlice'
import { ITrendInfo } from '@src/containers/ReportStep/ChartAndTitleWrapper';
import { includes, isEqual, sortBy, uniq, uniqBy } from 'lodash';
import { DateRangeList } from '@src/context/config/configSlice';
import { IReportInfo } from '../hooks/useGenerateReportEffect';
import { BoardInfoResponse } from '@src/hooks/useGetBoardInfo';
import { DATE_FORMAT_TEMPLATE } from '@src/constants/template';
import duration from 'dayjs/plugin/duration';
Expand Down Expand Up @@ -115,7 +116,14 @@ export const formatDateToTimestampString = (date: string) => {

export const sortDateRanges = (dateRanges: DateRangeList, descending = true) => {
const result = [...dateRanges].sort((a, b) => {
return dayjs(b.startDate as string).diff(dayjs(a.startDate as string));
return dayjs(b.startDate).diff(dayjs(a.startDate));
});
return descending ? result : result.reverse();
};

export const sortReportInfos = (reportInfos: IReportInfo[], descending = true) => {
const result = [...reportInfos].sort((a, b) => {
return dayjs(b.id).diff(dayjs(a.id));
});
return descending ? result : result.reverse();
};
Expand Down
Loading