diff --git a/backend/src/main/java/heartbeat/service/board/jira/JiraService.java b/backend/src/main/java/heartbeat/service/board/jira/JiraService.java index b22b29a3dd..27e77de786 100644 --- a/backend/src/main/java/heartbeat/service/board/jira/JiraService.java +++ b/backend/src/main/java/heartbeat/service/board/jira/JiraService.java @@ -844,7 +844,8 @@ private CycleTimeInfoDTO getCycleTime(CardHistoryResponseDTO cardHistoryResponse keyFlagged); List cycleTimeInfos = boardUtil.getCycleTimeInfos(statusChangedArray, realDoneStatus, treatFlagCardAsBlock); - List originCycleTimeInfos = boardUtil.getOriginCycleTimeInfos(statusChangedArray); + List originCycleTimeInfos = boardUtil.getOriginCycleTimeInfos(statusChangedArray, + treatFlagCardAsBlock); return CycleTimeInfoDTO.builder() .cycleTimeInfos(cycleTimeInfos) diff --git a/backend/src/main/java/heartbeat/util/BoardUtil.java b/backend/src/main/java/heartbeat/util/BoardUtil.java index c974755051..fd316d5e6c 100644 --- a/backend/src/main/java/heartbeat/util/BoardUtil.java +++ b/backend/src/main/java/heartbeat/util/BoardUtil.java @@ -20,10 +20,12 @@ public class BoardUtil { private final WorkDay workDay; - public List getOriginCycleTimeInfos(List statusChangedArray) { + public List getOriginCycleTimeInfos(List statusChangedArray, + Boolean treatFlagCardAsBlock) { List flagTimeStamp = getFlagTimeStamps(statusChangedArray); List columnTimeStamp = getColumnTimeStamps(statusChangedArray); - List originCycleTimeInfos = calculateOriginCycleTime(flagTimeStamp, columnTimeStamp); + List originCycleTimeInfos = calculateOriginCycleTime(flagTimeStamp, columnTimeStamp, + treatFlagCardAsBlock); return getCollectRemovedDuplicates(originCycleTimeInfos); } @@ -50,7 +52,7 @@ public List getCycleTimeInfos(List statusChang } private List calculateOriginCycleTime(List flagTimeStamp, - List columnTimeStamp) { + List columnTimeStamp, Boolean treatFlagCardAsBlock) { List originCycleTimeInfos = new ArrayList<>(); for (StatusTimeStamp columnTimeStampItem : columnTimeStamp) { @@ -62,9 +64,11 @@ private List calculateOriginCycleTime(List flagT .build()); } - double totalFlagTimeInDays = calculateTotalFlagCycleTime(flagTimeStamp); - originCycleTimeInfos - .add(CycleTimeInfo.builder().day(totalFlagTimeInDays).column(CardStepsEnum.FLAG.getValue()).build()); + if (Boolean.TRUE.equals(treatFlagCardAsBlock)) { + double totalFlagTimeInDays = calculateTotalFlagCycleTime(flagTimeStamp); + originCycleTimeInfos + .add(CycleTimeInfo.builder().day(totalFlagTimeInDays).column(CardStepsEnum.FLAG.getValue()).build()); + } return originCycleTimeInfos; } @@ -101,10 +105,8 @@ private List calculateCycleTime(List realDoneStatus, List } if (!isBlockColumnExisted(columnTimeStamp) && totalFlagTimeInDays > 0) { double blockDays = totalFlagTimeInDays - totalFlagAndRealDoneOverlapTime; - cycleTimeInfos.add(CycleTimeInfo.builder() - .day(blockDays) - .column(CardStepsEnum.BLOCK.getValue().toUpperCase()) - .build()); + cycleTimeInfos.add( + CycleTimeInfo.builder().day(blockDays).column(CardStepsEnum.FLAG.getValue().toUpperCase()).build()); } return cycleTimeInfos; diff --git a/backend/src/test/java/heartbeat/service/jira/JiraServiceTest.java b/backend/src/test/java/heartbeat/service/jira/JiraServiceTest.java index f404d6525e..b08f514373 100644 --- a/backend/src/test/java/heartbeat/service/jira/JiraServiceTest.java +++ b/backend/src/test/java/heartbeat/service/jira/JiraServiceTest.java @@ -1166,7 +1166,7 @@ public void shouldProcessCustomFieldsForCardsWhenCallGetStoryPointsAndCycleTime( when(jiraFeignClient.getJiraCardHistoryByCount(any(), any(), anyInt(), anyInt(), any())) .thenReturn(CARD_HISTORY_MULTI_RESPONSE_BUILDER().build()); when(boardUtil.getCycleTimeInfos(any(), any(), any())).thenReturn(CYCLE_TIME_INFO_LIST()); - when(boardUtil.getOriginCycleTimeInfos(any())).thenReturn(CYCLE_TIME_INFO_LIST()); + when(boardUtil.getOriginCycleTimeInfos(any(), any())).thenReturn(CYCLE_TIME_INFO_LIST()); CardCollection doneCards = jiraService.getStoryPointsAndCycleTimeAndReworkInfoForDoneCards( storyPointsAndCycleTimeRequest, jiraBoardSetting.getBoardColumns(), List.of("Zhang San"), ""); diff --git a/backend/src/test/java/heartbeat/util/BoardUtilTest.java b/backend/src/test/java/heartbeat/util/BoardUtilTest.java index f676888c5b..65bfbd565f 100644 --- a/backend/src/test/java/heartbeat/util/BoardUtilTest.java +++ b/backend/src/test/java/heartbeat/util/BoardUtilTest.java @@ -81,7 +81,7 @@ void calculateCycleTimeWhenTreatFlagCardAsBlockIsFalse() { } @Test - void calculateOriginCycleTimeOfColumn() { + void shouldCalculateOriginCycleTimeGivenTreatFlagCardAsBlockIsTrue() { List statusChangedItems = StatusChangedItemsListAndCycleTimeInfosListFixture .STATUS_CHANGED_ITEMS_LIST_OF_ORIGIN(); List statusChangedItemsExpect = StatusChangedItemsListAndCycleTimeInfosListFixture @@ -89,8 +89,22 @@ void calculateOriginCycleTimeOfColumn() { when(workDay.calculateWorkDaysBy24Hours(anyLong(), anyLong())) .thenReturn(StatusChangedItemsListAndCycleTimeInfosListFixture.EXPECT_DAYS); - List result = boardUtil.getOriginCycleTimeInfos(statusChangedItems); + + List result = boardUtil.getOriginCycleTimeInfos(statusChangedItems, Boolean.TRUE); Assertions.assertEquals(statusChangedItemsExpect, result); } + @Test + void shouldCalculateOriginCycleTimeGivenTreatFlagCardAsBlockIsFalse() { + List statusChangedItems = StatusChangedItemsListAndCycleTimeInfosListFixture + .STATUS_CHANGED_ITEMS_LIST_OF_ORIGIN(); + List statusChangedItemsWithoutFlagExpect = StatusChangedItemsListAndCycleTimeInfosListFixture + .CYCLE_TIME_INFOS_LIST_OF_ORIGIN_WITHOUT_FLAG(); + + when(workDay.calculateWorkDaysBy24Hours(anyLong(), anyLong())) + .thenReturn(StatusChangedItemsListAndCycleTimeInfosListFixture.EXPECT_DAYS); + List result = boardUtil.getOriginCycleTimeInfos(statusChangedItems, Boolean.FALSE); + Assertions.assertEquals(statusChangedItemsWithoutFlagExpect, result); + } + } diff --git a/backend/src/test/java/heartbeat/util/StatusChangedItemsListAndCycleTimeInfosListFixture.java b/backend/src/test/java/heartbeat/util/StatusChangedItemsListAndCycleTimeInfosListFixture.java index 8e0c8126ed..f2cbdc7fed 100644 --- a/backend/src/test/java/heartbeat/util/StatusChangedItemsListAndCycleTimeInfosListFixture.java +++ b/backend/src/test/java/heartbeat/util/StatusChangedItemsListAndCycleTimeInfosListFixture.java @@ -9,6 +9,14 @@ public class StatusChangedItemsListAndCycleTimeInfosListFixture { public static double EXPECT_DAYS = 4.0; + public static final String DONE = "DONE"; + + public static final String BLOCK = "BLOCK"; + + public static final String IN_PROGRESS = "IN PROGRESS"; + + public static final String FLAG = "FLAG"; + public static List STATUS_CHANGED_ITEMS_LIST_OF_REAL_DONE_COLUMN() { return List.of(StatusChangedItem.builder().timestamp(1000000L).status("In Progress").build(), StatusChangedItem.builder().timestamp(2000000L).status("DONE").build(), @@ -17,9 +25,9 @@ public static List STATUS_CHANGED_ITEMS_LIST_OF_REAL_DONE_COL } public static List CYCLE_TIME_INFOS_LIST_OF_REAL_DONE_COLUMN() { - return List.of(CycleTimeInfo.builder().column("DONE").day(EXPECT_DAYS).build(), - CycleTimeInfo.builder().column("BLOCK").day(0.0).build(), - CycleTimeInfo.builder().column("IN PROGRESS").day(EXPECT_DAYS).build()); + return List.of(CycleTimeInfo.builder().column(DONE).day(EXPECT_DAYS).build(), + CycleTimeInfo.builder().column(IN_PROGRESS).day(EXPECT_DAYS).build(), + CycleTimeInfo.builder().column(FLAG).day(0.0).build()); } public static List STATUS_CHANGED_ITEMS_LIST_OF_BLOCK_COLUMN() { @@ -31,9 +39,9 @@ public static List STATUS_CHANGED_ITEMS_LIST_OF_BLOCK_COLUMN( } public static List CYCLE_TIME_INFOS_LIST_OF_BLOCK_COLUMN() { - return List.of(CycleTimeInfo.builder().column("DONE").day(EXPECT_DAYS).build(), - CycleTimeInfo.builder().column("BLOCK").day(EXPECT_DAYS).build(), - CycleTimeInfo.builder().column("IN PROGRESS").day(EXPECT_DAYS).build()); + return List.of(CycleTimeInfo.builder().column(DONE).day(EXPECT_DAYS).build(), + CycleTimeInfo.builder().column(BLOCK).day(EXPECT_DAYS).build(), + CycleTimeInfo.builder().column(IN_PROGRESS).day(EXPECT_DAYS).build()); } public static List STATUS_CHANGED_ITEMS_LIST_OF_OTHER_COLUMN() { @@ -45,9 +53,9 @@ public static List STATUS_CHANGED_ITEMS_LIST_OF_OTHER_COLUMN( } public static List CYCLE_TIME_INFOS_LIST_OF_OTHER_COLUMN() { - return List.of(CycleTimeInfo.builder().column("DONE").day(EXPECT_DAYS).build(), - CycleTimeInfo.builder().column("BLOCK").day(8.0).build(), - CycleTimeInfo.builder().column("IN PROGRESS").day(0.0).build()); + return List.of(CycleTimeInfo.builder().column(DONE).day(EXPECT_DAYS).build(), + CycleTimeInfo.builder().column(BLOCK).day(8.0).build(), + CycleTimeInfo.builder().column(IN_PROGRESS).day(0.0).build()); } public static List STATUS_CHANGED_ITEMS_LIST_WHEN_NOT_TREAT_FLAG_AS_BLOCK() { @@ -59,9 +67,9 @@ public static List STATUS_CHANGED_ITEMS_LIST_WHEN_NOT_TREAT_F } public static List CYCLE_TIME_INFOS_LIST_WHEN_NOT_TREAT_FLAG_AS_BLOCK() { - return List.of(CycleTimeInfo.builder().column("DONE").day(EXPECT_DAYS).build(), - CycleTimeInfo.builder().column("BLOCK").day(EXPECT_DAYS).build(), - CycleTimeInfo.builder().column("IN PROGRESS").day(EXPECT_DAYS).build()); + return List.of(CycleTimeInfo.builder().column(DONE).day(EXPECT_DAYS).build(), + CycleTimeInfo.builder().column(BLOCK).day(EXPECT_DAYS).build(), + CycleTimeInfo.builder().column(IN_PROGRESS).day(EXPECT_DAYS).build()); } public static List STATUS_CHANGED_ITEMS_LIST_OF_ORIGIN() { @@ -73,10 +81,16 @@ public static List STATUS_CHANGED_ITEMS_LIST_OF_ORIGIN() { } public static List CYCLE_TIME_INFOS_LIST_OF_ORIGIN() { - return List.of(CycleTimeInfo.builder().column("DONE").day(EXPECT_DAYS).build(), - CycleTimeInfo.builder().column("BLOCK").day(EXPECT_DAYS).build(), - CycleTimeInfo.builder().column("IN PROGRESS").day(EXPECT_DAYS).build(), - CycleTimeInfo.builder().column("FLAG").day(EXPECT_DAYS).build()); + return List.of(CycleTimeInfo.builder().column(DONE).day(EXPECT_DAYS).build(), + CycleTimeInfo.builder().column(BLOCK).day(EXPECT_DAYS).build(), + CycleTimeInfo.builder().column(IN_PROGRESS).day(EXPECT_DAYS).build(), + CycleTimeInfo.builder().column(FLAG).day(EXPECT_DAYS).build()); + } + + public static List CYCLE_TIME_INFOS_LIST_OF_ORIGIN_WITHOUT_FLAG() { + return List.of(CycleTimeInfo.builder().column(DONE).day(EXPECT_DAYS).build(), + CycleTimeInfo.builder().column(BLOCK).day(EXPECT_DAYS).build(), + CycleTimeInfo.builder().column(IN_PROGRESS).day(EXPECT_DAYS).build()); } } diff --git a/frontend/__tests__/containers/MetricsStep/CycleTime.test.tsx b/frontend/__tests__/containers/MetricsStep/CycleTime.test.tsx index 52f70410c1..ef27fad62d 100644 --- a/frontend/__tests__/containers/MetricsStep/CycleTime.test.tsx +++ b/frontend/__tests__/containers/MetricsStep/CycleTime.test.tsx @@ -6,7 +6,7 @@ import { updateTreatFlagCardAsBlock, } from '@src/context/Metrics/metricsSlice'; import { BOARD_MAPPING, ERROR_MESSAGE_TIME_DURATION, LIST_OPEN, NO_RESULT_DASH } from '../../fixtures'; -import { CYCLE_TIME_SETTINGS_TYPES, METRICS_CONSTANTS } from '@src/constants/resources'; +import { CYCLE_TIME_SETTINGS_TYPES, MESSAGE, METRICS_CONSTANTS } from '@src/constants/resources'; import { act, render, screen, waitFor, within } from '@testing-library/react'; import { CycleTime } from '@src/containers/MetricsStep/CycleTime'; import { setupStore } from '../../utils/setupStoreUtil'; @@ -406,4 +406,23 @@ describe('CycleTime', () => { expect(mockedUseAppDispatch).not.toHaveBeenCalledWith(saveDoneColumn([])); }); }); + + [CYCLE_TIME_SETTINGS_TYPES.BY_STATUS, CYCLE_TIME_SETTINGS_TYPES.BY_COLUMN].forEach((cycleTimeSettingsType) => { + it('should show warning message given both mapping block column and add flag as block', () => { + (selectMetricsContent as jest.Mock).mockReturnValue({ + cycleTimeSettingsType, + cycleTimeSettings: [ + ...cycleTimeSettings, + { + column: 'Blocked', + status: 'BLOCKED', + value: 'Block', + }, + ], + }); + setup(); + + expect(screen.getByText(MESSAGE.FLAG_CARD_DROPPED_WARNING)).toBeVisible(); + }); + }); }); diff --git a/frontend/__tests__/containers/MetricsStep/MetricsStep.test.tsx b/frontend/__tests__/containers/MetricsStep/MetricsStep.test.tsx index 49346b1642..b2d074360d 100644 --- a/frontend/__tests__/containers/MetricsStep/MetricsStep.test.tsx +++ b/frontend/__tests__/containers/MetricsStep/MetricsStep.test.tsx @@ -217,7 +217,7 @@ describe('MetricsStep', () => { await userEvent.click(doneSelectTrigger as HTMLInputElement); - const noneOption = within(screen.getByRole('presentation')).getByText('----'); + const noneOption = within(screen.getAllByRole('presentation')[1]).getByText('----'); await userEvent.click(noneOption); expect(realDoneSettingSection).toHaveTextContent(SELECT_CONSIDER_AS_DONE_MESSAGE); diff --git a/frontend/__tests__/context/metricsSlice.test.ts b/frontend/__tests__/context/metricsSlice.test.ts index 8f9d4a80f9..8cfc3c9797 100644 --- a/frontend/__tests__/context/metricsSlice.test.ts +++ b/frontend/__tests__/context/metricsSlice.test.ts @@ -61,6 +61,7 @@ const initState = { classification: [], treatFlagCardAsBlock: true, assigneeFilter: ASSIGNEE_FILTER_TYPES.LAST_ASSIGNEE, + displayFlagCardDropWarning: true, importedData: { importedCrews: [], importedAssigneeFilter: ASSIGNEE_FILTER_TYPES.LAST_ASSIGNEE, @@ -304,6 +305,32 @@ describe('saveMetricsSetting reducer', () => { expect(savedMetricsSetting.doneColumn).toEqual(['DONE']); }); + it('should not be able to show conflict warning and check the flag card as block', () => { + const mockUpdateMetricsStateArguments = { + ...mockJiraResponse, + isProjectCreated: true, + }; + const savedMetricsSetting = saveMetricsSettingReducer( + { + ...initState, + cycleTimeSettingsType: CYCLE_TIME_SETTINGS_TYPES.BY_STATUS, + importedData: { + ...initState.importedData, + importedCrews: ['User B', 'User C'], + importedClassification: ['issuetype'], + importedCycleTime: { + importedCycleTimeSettings: [{ DOING: 'Doing' }, { TESTING: 'Testing' }, { DONE: 'Done' }], + importedTreatFlagCardAsBlock: false, + }, + importedDoneStatus: ['DONE'], + }, + }, + updateMetricsState(mockUpdateMetricsStateArguments), + ); + expect(savedMetricsSetting.displayFlagCardDropWarning).toEqual(false); + expect(savedMetricsSetting.treatFlagCardAsBlock).toEqual(true); + }); + it('should update metricsState given cycleTimeSettingsType is by status', () => { const mockUpdateMetricsStateArguments = { ...mockJiraResponse, @@ -336,6 +363,7 @@ describe('saveMetricsSetting reducer', () => { { column: 'Testing', status: 'TESTING', value: 'Testing' }, ]); expect(savedMetricsSetting.doneColumn).toEqual(['DONE']); + expect(savedMetricsSetting.displayFlagCardDropWarning).toEqual(true); }); it('should update metricsState given its value changed given isProjectCreated is false and selectedDoneColumns and cycleTimeSettingsType is byStatus', () => { diff --git a/frontend/__tests__/fixtures.ts b/frontend/__tests__/fixtures.ts index b88860ccac..4cfa77c67c 100644 --- a/frontend/__tests__/fixtures.ts +++ b/frontend/__tests__/fixtures.ts @@ -467,7 +467,6 @@ export const MOCK_REPORT_RESPONSE: ReportResponseDTO = { fromAnalysis: null, fromInDev: null, fromBlock: 111, - fromFlag: null, fromReview: 111, fromWaitingForTesting: 111, fromTesting: null, diff --git a/frontend/__tests__/hooks/reportMapper/report.test.tsx b/frontend/__tests__/hooks/reportMapper/report.test.tsx index e78629a51b..6a9b084fb3 100644 --- a/frontend/__tests__/hooks/reportMapper/report.test.tsx +++ b/frontend/__tests__/hooks/reportMapper/report.test.tsx @@ -171,7 +171,7 @@ export const EXPECTED_REPORT_VALUES = { ], }, { - id: 5, + id: 4, name: ( From review to in dev @@ -185,7 +185,7 @@ export const EXPECTED_REPORT_VALUES = { ], }, { - id: 6, + id: 5, name: ( From waiting for testing to in dev @@ -199,7 +199,7 @@ export const EXPECTED_REPORT_VALUES = { ], }, { - id: 8, + id: 7, name: ( From done to in dev @@ -213,7 +213,7 @@ export const EXPECTED_REPORT_VALUES = { ], }, { - id: 9, + id: 8, name: Total rework cards, valueList: [ { @@ -223,7 +223,7 @@ export const EXPECTED_REPORT_VALUES = { ], }, { - id: 10, + id: 9, name: Rework cards ratio, valueList: [ { diff --git a/frontend/e2e/fixtures/create-new/board-data-without-block-column.csv b/frontend/e2e/fixtures/create-new/board-data-without-block-column.csv new file mode 100644 index 0000000000..4e27e05de3 --- /dev/null +++ b/frontend/e2e/fixtures/create-new/board-data-without-block-column.csv @@ -0,0 +1,4 @@ +"Issue key","Summary","Issue Type","Status","Status Date","Story Points","assignee","Reporter","Project Key","Project Name","Priority","Parent Summary","Sprint","Labels","Cycle Time","Cycle Time / Story Points","Analysis Days","In Dev Days","Waiting Days","Testing Days","Block Days","Review Days","OriginCycleTime: TESTING","OriginCycleTime: WAITING FOR TESTING","OriginCycleTime: TO DO","OriginCycleTime: IN DEV","OriginCycleTime: REVIEW","OriginCycleTime: FLAG","Rework: total - In dev","Rework: from Block","Rework: from Waiting for testing","Rework: from Done" +"TNB-1","ADM-898-card1","Task","Done","2024-04-08","0.0","Shiqi Yuan","heartbeat user","TNB","Test-no-block","Medium",,,"","0","","0","0","0","0","0","0","0","0","0","0.01","0","0.01","1","1","0","0" +"TNB-2","ADM-898-card2","Task","Done","2024-04-08","0.0","Shiqi Yuan","heartbeat user","TNB","Test-no-block","Medium",,,"","0","","0","0","0","0","0","0","0","0","0","0.01","0","0.01","2","1","0","1" +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, diff --git a/frontend/e2e/fixtures/create-new/board-data.csv b/frontend/e2e/fixtures/create-new/board-data.csv index 9cce0e14a2..da5ffc9569 100644 --- a/frontend/e2e/fixtures/create-new/board-data.csv +++ b/frontend/e2e/fixtures/create-new/board-data.csv @@ -1,24 +1,24 @@ -"Issue key","Summary","Issue Type","Status","Status Date","Story Points","assignee","Reporter","Project Key","Project Name","Priority","Parent Summary","Sprint","Labels","Cycle Time","Story testing-1","Flagged","Fix versions","Partner","Time tracking","Story point estimate","QA","Feature/Operation","Story testing-2","Cycle Time / Story Points","Analysis Days","In Dev Days","Waiting Days","Testing Days","Block Days","Review Days","OriginCycleTime: TODO","OriginCycleTime: TESTING","OriginCycleTime: WAIT FOR TEST","OriginCycleTime: DOING","OriginCycleTime: REVIEW","OriginCycleTime: FLAG","OriginCycleTime: BLOCKED",Rework: total - In dev,Rework: from Block,Rework: from Review,Rework: from Waiting for testing,Rework: from Testing,Rework: from Done -"ADM-735","[backend]identify the source of the error when generate reports encounter exception","Task","Done","2024-01-19","1.0","Yunsong Yang","Yunsong Yang","ADM","Auto Dora Metrics","Medium","Precise on Metrics","Sprint 28","Stream2","7.70","1.0","","","","None","1.0","","","","7.70","0","2.02","1.81","0","0","3.87","3.03","0","1.81","2.02","3.87","0","0","0","0","0","0","0","0" -"ADM-708","[Backend] Verify board and obtain board data with new API","Task","Done","2024-01-19","3.0","Weiran Sun","heartbeat user","ADM","Auto Dora Metrics","Medium","easy to use","Sprint 28","Stream1","9.95","1.0","","","","None","3.0","","","","3.32","0","4.00","0.93","1.04","0.98","3.00","7.10","1.04","0.93","4.00","3.00","0","0.98","2","2","0","0","0","0" -"ADM-699","[Frontend] Optimize the 4xx&504 error display of report overview","Task","Done","2024-01-18","2.0","heartbeat user","heartbeat user","ADM","Auto Dora Metrics","Medium","Performance Improvement","Sprint 28","Stream2","10.93","1.0","","","","None","2.0","","","","5.46","0","5.14","0.04","0.78","2.01","2.96","10.75","0.78","0.04","5.14","2.96","0","2.01","2","2","0","0","0","0" -"ADM-717","[Backend] Verify github and obtain github data with new API","Task","Done","2024-01-17","2.0","Junbo Dai","Yufan Wang","ADM","Auto Dora Metrics","Medium","easy to use","Sprint 28","Stream1","8.09","1.0","","","","None","2.0","Weiran Sun","","","4.04","0","2.83","2.72","0.05","2.14","0.35","6.00","0.05","2.72","2.83","0.35","0","2.14","3","3","0","0","0","0" -"ADM-724","[Spike] redesign board verify API to meet business requirements","Spike","Done","2024-01-17","1.0","heartbeat user","Yufan Wang","ADM","Auto Dora Metrics","Medium","easy to use","Sprint 28","Stream1","12.94","","","","","None","1.0","","","","12.94","0","1.08","1.99","0","7.65","2.22","0.27","0","1.99","1.08","2.22","0","7.65","2","2","0","0","0","0" -"ADM-652","[Frontend]Generate the separate modules detail report","Task","Done","2024-01-17","3.0","Xuebing Li","heartbeat user","ADM","Auto Dora Metrics","Medium","Performance Improvement","Sprint 28","Stream2","10.15","1.0","","","","None","3.0","","","","3.38","0","5.94","1.35","1.87","0.72","0.27","22.87","1.87","1.35","5.94","0.27","0","0.72","1","1","0","0","0","0" -"ADM-683","[Frontend] UI refine for the date picker in report page","Task","Done","2024-01-17","1.0","heartbeat user","heartbeat user","ADM","Auto Dora Metrics","Medium","easy to use","Sprint 28","Stream2","8.92","1.0","","","","None","1.0","","","","8.92","0","3.00","0.10","1.84","3.00","0.98","15.05","1.84","0.10","3.00","0.98","0","3.00","1","1","0","0","0","0" -"ADM-669","[Frontend] UI refine for notification pop up change in report page","Task","Done","2024-01-17","1.0","heartbeat user","heartbeat user","ADM","Auto Dora Metrics","Medium","easy to use","Sprint 28","Stream2","7.13","1.0","","","","None","1.0","","","","7.13","0","4.22","0.02","1.16","0","1.73","17.80","1.16","0.02","4.22","1.73","0","0","0","0","0","0","0","0" -"ADM-709","[Backend] Verify buildkite and obtain buildkite data with new API","Task","Done","2024-01-15","3.0","Xinyi Wang","heartbeat user","ADM","Auto Dora Metrics","Medium","easy to use","Sprint 27","Stream1","6.85","1.0","","","","None","3.0","","","","2.28","0","2.81","0.07","0.78","0","3.19","8.03","0.78","0.07","2.81","3.19","0","0",,,,,, -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, -"ADM-806","[BE]no need to obtain pipeline data twice in backend","Bug","Review","2024-02-26","2.0","heartbeat user","Yufan Wang","ADM","Auto Dora Metrics","Medium",,"Sprint 30","Stream2,v1.1.5","0","","","","","None","2.0","","","","0","0","2.89","0","0","0","0.04","8.10","0","0","2.89","0.04","0","0",,,,,, -"ADM-813","[FE]add new field 'Advance' in metrics page","Task","Review","2024-02-26","2.0","heartbeat user","Yufan Wang","ADM","Auto Dora Metrics","Medium",,"Sprint 30","Stream2,v1.1.5","0","1.0","","","","None","2.0","","","","0","0","4.78","0","0","4.68","0.53","0.19","0","0","4.78","0.53","0","4.68",,,,,, -"ADM-677","[Spike]Investigate Github graphQL API about replacing existing REST API","Spike","Blocked","2024-02-21","2.0","Junbo Dai","Yichen Wang","ADM","Auto Dora Metrics","Medium","Performance Improvement","Sprint 30","Stream1","0","","","","","None","2.0","","","","0","0","1.05","0","0","10.17","0","38.43","0","0","1.05","0","0","10.17",,,,,, -"ADM-819","[BE]cache doesn't work in one case","Bug","Doing","2024-02-26","2.0","Shiqi Yuan","Yufan Wang","ADM","Auto Dora Metrics","Medium",,"Sprint 30","Stream2,v1.1.5","0","","","","","None","2.0","","","","0","0","3.14","0","0","1.05","0","0.84","0","0","3.14","0","0","1.05",,,,,, -"ADM-797","[BE]The add flag as block logic is not working","Bug","Doing","2024-02-26","2.0","heartbeat user","Wenting Yan","ADM","Auto Dora Metrics","High",,"Sprint 30","Stream2,v1.1.5","0","","","","","None","2.0","","","","0","0","7.13","0","0","5.00","0","2.03","0","0","7.38","0","1.05","5.80",,,,,, -"ADM-829","jump home page when user click next button in config page","Bug","Doing","2024-02-23","2.0","Junbo Dai","Yufan Wang","ADM","Auto Dora Metrics","High",,"Sprint 30","Stream1,v1.1.5","0","","","","","None","2.0","","","","0","0","1.03","0","0","0","0","1.17","0","0","1.03","0","0","0",,,,,, -"ADM-812","[FE]metrics page needs to retain the modified data","Bug","Doing","2024-02-23","2.0","heartbeat user","Yufan Wang","ADM","Auto Dora Metrics","Medium",,"Sprint 30","Stream1","0","","","","","None","2.0","","","","0","0","3.04","0","0","1.03","0","6.67","0","0","3.04","0","0","1.03",,,,,, -"ADM-809","[E2E] build ""import a new project"" scenario","Task","Doing","2024-02-22","2.0","heartbeat user","Xingmeng Tao","ADM","Auto Dora Metrics","High",,"Sprint 30","Stream1,v1.1.5","0","1.0","","","","None","2.0","","","","0","0","2.24","0","0","0","0","8.00","0","0","2.24","0","0","0",,,,,, -"ADM-808","[E2E] build ""Create a new Project"" scenario","Task","Doing","2024-02-19","3.5","heartbeat user","Xingmeng Tao","ADM","Auto Dora Metrics","High",,"Sprint 30","Stream1,v1.1.5","0","1.0","","","","None","3.5","","","","0","0","8.04","0","0","1.99","0","0.95","0","0","8.04","0","0","1.99",,,,,, -"ADM-825","[E2E] build ""page jumps"" scenario","Task","TODO",,"2.0",,"Yufan Wang","ADM","Auto Dora Metrics","High",,"Sprint 30","Stream1,v1.1.5","0","1.0","","","","None","2.0","","","","0","0","0","0","0","0","0","0","0","0","0","0","0","0",,,,,, -"ADM-820","user was misguided to home page when they want to enter metrics page","Bug","TODO",,"0.0","heartbeat user","Yufan Wang","ADM","Auto Dora Metrics","Medium",,"Sprint 30","Stream2","0","","","","","None","","","","","","0","0","0","0","0","0","0","0","0","0","0","0","0",,,,,, -"ADM-833","[E2E] build ""unhappy path"" scenario","Task","TODO",,"0.0",,"heartbeat user","ADM","Auto Dora Metrics","Medium",,"Sprint 30","Stream1","0","1.0","","","","None","","","","","","0","0","0","0","0","0","0","0","0","0","0","0","0",,,,,, -"ADM-789","refactor E2E-step2","Task","TODO",,"1.0",,"Yufan Wang","ADM","Auto Dora Metrics","High",,"Sprint 30","Stream2","0","1.0","","","","None","1.0","","","","0","0","0","0","0","0","0","0","0","0","0","0","0","0",,,,,, +Issue key,Summary,Issue Type,Status,Status Date,Story Points,assignee,Reporter,Project Key,Project Name,Priority,Parent Summary,Sprint,Labels,Cycle Time,Story testing-1,Flagged,Fix versions,Partner,Time tracking,Story point estimate,QA,Feature/Operation,Story testing-2,Cycle Time / Story Points,Analysis Days,In Dev Days,Waiting Days,Testing Days,Block Days,Review Days,OriginCycleTime: TODO,OriginCycleTime: TESTING,OriginCycleTime: WAIT FOR TEST,OriginCycleTime: DOING,OriginCycleTime: REVIEW,OriginCycleTime: BLOCKED,Rework: total - In dev,Rework: from Block,Rework: from Review,Rework: from Waiting for testing,Rework: from Testing,Rework: from Done +ADM-735,[backend]identify the source of the error when generate reports encounter exception,Task,Done,2024-01-19,1.0,Yunsong Yang,Yunsong Yang,ADM,Auto Dora Metrics,Medium,Precise on Metrics,Sprint 28,Stream2,7.70,1.0,"","","",None,1.0,"","","",7.70,0,2.02,1.81,0,0,3.87,3.03,0,1.81,2.02,3.87,0,0,0,0,0,0,0 +ADM-708,[Backend] Verify board and obtain board data with new API,Task,Done,2024-01-19,3.0,Weiran Sun,heartbeat user,ADM,Auto Dora Metrics,Medium,easy to use,Sprint 28,Stream1,9.95,1.0,"","","",None,3.0,"","","",3.32,0,4.00,0.93,1.04,0.98,3.00,7.10,1.04,0.93,4.00,3.00,0.98,2,2,0,0,0,0 +ADM-699,[Frontend] Optimize the 4xx&504 error display of report overview,Task,Done,2024-01-18,2.0,heartbeat user,heartbeat user,ADM,Auto Dora Metrics,Medium,Performance Improvement,Sprint 28,Stream2,10.93,1.0,"","","",None,2.0,"","","",5.46,0,5.14,0.04,0.78,2.01,2.96,10.75,0.78,0.04,5.14,2.96,2.01,2,2,0,0,0,0 +ADM-717,[Backend] Verify github and obtain github data with new API,Task,Done,2024-01-17,2.0,Junbo Dai,Yufan Wang,ADM,Auto Dora Metrics,Medium,easy to use,Sprint 28,Stream1,8.09,1.0,"","","",None,2.0,Weiran Sun,"","",4.04,0,2.83,2.72,0.05,2.14,0.35,6.00,0.05,2.72,2.83,0.35,2.14,3,3,0,0,0,0 +ADM-724,[Spike] redesign board verify API to meet business requirements,Spike,Done,2024-01-17,1.0,heartbeat user,Yufan Wang,ADM,Auto Dora Metrics,Medium,easy to use,Sprint 28,Stream1,12.94,"","","","",None,1.0,"","","",12.94,0,1.08,1.99,0,7.65,2.22,0.27,0,1.99,1.08,2.22,7.65,2,2,0,0,0,0 +ADM-652,[Frontend]Generate the separate modules detail report,Task,Done,2024-01-17,3.0,Xuebing Li,heartbeat user,ADM,Auto Dora Metrics,Medium,Performance Improvement,Sprint 28,Stream2,10.15,1.0,"","","",None,3.0,"","","",3.38,0,5.94,1.35,1.87,0.72,0.27,22.87,1.87,1.35,5.94,0.27,0.72,1,1,0,0,0,0 +ADM-683,[Frontend] UI refine for the date picker in report page,Task,Done,2024-01-17,1.0,heartbeat user,heartbeat user,ADM,Auto Dora Metrics,Medium,easy to use,Sprint 28,Stream2,8.92,1.0,"","","",None,1.0,"","","",8.92,0,3.00,0.10,1.84,3.00,0.98,15.05,1.84,0.10,3.00,0.98,3.00,1,1,0,0,0,0 +ADM-669,[Frontend] UI refine for notification pop up change in report page,Task,Done,2024-01-17,1.0,heartbeat user,heartbeat user,ADM,Auto Dora Metrics,Medium,easy to use,Sprint 28,Stream2,7.13,1.0,"","","",None,1.0,"","","",7.13,0,4.22,0.02,1.16,0,1.73,17.80,1.16,0.02,4.22,1.73,0,0,0,0,0,0,0 +ADM-709,[Backend] Verify buildkite and obtain buildkite data with new API,Task,Done,2024-01-15,3.0,Xinyi Wang,heartbeat user,ADM,Auto Dora Metrics,Medium,easy to use,Sprint 27,Stream1,6.85,1.0,"","","",None,3.0,"","","",2.28,0,2.81,0.07,0.78,0,3.19,8.03,0.78,0.07,2.81,3.19,0,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +ADM-806,[BE]no need to obtain pipeline data twice in backend,Bug,Review,2024-02-26,2.0,heartbeat user,Yufan Wang,ADM,Auto Dora Metrics,Medium,,Sprint 30,"Stream2,v1.1.5",0,"","","","",None,2.0,"","","",0,0,2.89,0,0,0,0.04,8.10,0,0,2.89,0.04,0,,,,,, +ADM-813,[FE]add new field 'Advance' in metrics page,Task,Review,2024-02-26,2.0,heartbeat user,Yufan Wang,ADM,Auto Dora Metrics,Medium,,Sprint 30,"Stream2,v1.1.5",0,1.0,"","","",None,2.0,"","","",0,0,4.78,0,0,4.68,0.53,0.19,0,0,4.78,0.53,4.68,,,,,, +ADM-677,[Spike]Investigate Github graphQL API about replacing existing REST API,Spike,Blocked,2024-02-21,2.0,Junbo Dai,Yichen Wang,ADM,Auto Dora Metrics,Medium,Performance Improvement,Sprint 30,Stream1,0,"","","","",None,2.0,"","","",0,0,1.05,0,0,10.17,0,38.43,0,0,1.05,0,10.17,,,,,, +ADM-819,[BE]cache doesn't work in one case,Bug,Doing,2024-02-26,2.0,Shiqi Yuan,Yufan Wang,ADM,Auto Dora Metrics,Medium,,Sprint 30,"Stream2,v1.1.5",0,"","","","",None,2.0,"","","",0,0,3.14,0,0,1.05,0,0.84,0,0,3.14,0,1.05,,,,,, +ADM-797,[BE]The add flag as block logic is not working,Bug,Doing,2024-02-26,2.0,heartbeat user,Wenting Yan,ADM,Auto Dora Metrics,High,,Sprint 30,"Stream2,v1.1.5",0,"","","","",None,2.0,"","","",0,0,7.13,0,0,5.00,0,2.03,0,0,7.38,0,5.80,,,,,, +ADM-829,jump home page when user click next button in config page,Bug,Doing,2024-02-23,2.0,Junbo Dai,Yufan Wang,ADM,Auto Dora Metrics,High,,Sprint 30,"Stream1,v1.1.5",0,"","","","",None,2.0,"","","",0,0,1.03,0,0,0,0,1.17,0,0,1.03,0,0,,,,,, +ADM-812,[FE]metrics page needs to retain the modified data,Bug,Doing,2024-02-23,2.0,heartbeat user,Yufan Wang,ADM,Auto Dora Metrics,Medium,,Sprint 30,Stream1,0,"","","","",None,2.0,"","","",0,0,3.04,0,0,1.03,0,6.67,0,0,3.04,0,1.03,,,,,, +ADM-809,"[E2E] build ""import a new project"" scenario",Task,Doing,2024-02-22,2.0,heartbeat user,Xingmeng Tao,ADM,Auto Dora Metrics,High,,Sprint 30,"Stream1,v1.1.5",0,1.0,"","","",None,2.0,"","","",0,0,2.24,0,0,0,0,8.00,0,0,2.24,0,0,,,,,, +ADM-808,"[E2E] build ""Create a new Project"" scenario",Task,Doing,2024-02-19,3.5,heartbeat user,Xingmeng Tao,ADM,Auto Dora Metrics,High,,Sprint 30,"Stream1,v1.1.5",0,1.0,"","","",None,3.5,"","","",0,0,8.04,0,0,1.99,0,0.95,0,0,8.04,0,1.99,,,,,, +ADM-825,"[E2E] build ""page jumps"" scenario",Task,TODO,,2.0,,Yufan Wang,ADM,Auto Dora Metrics,High,,Sprint 30,"Stream1,v1.1.5",0,1.0,"","","",None,2.0,"","","",0,0,0,0,0,0,0,0,0,0,0,0,0,,,,,, +ADM-820,user was misguided to home page when they want to enter metrics page,Bug,TODO,,0.0,heartbeat user,Yufan Wang,ADM,Auto Dora Metrics,Medium,,Sprint 30,Stream2,0,"","","","",None,"","","","","",0,0,0,0,0,0,0,0,0,0,0,0,,,,,, +ADM-833,"[E2E] build ""unhappy path"" scenario",Task,TODO,,0.0,,heartbeat user,ADM,Auto Dora Metrics,Medium,,Sprint 30,Stream1,0,1.0,"","","",None,"","","","","",0,0,0,0,0,0,0,0,0,0,0,0,,,,,, +ADM-789,refactor E2E-step2,Task,TODO,,1.0,,Yufan Wang,ADM,Auto Dora Metrics,High,,Sprint 30,Stream2,0,1.0,"","","",None,1.0,"","","",0,0,0,0,0,0,0,0,0,0,0,0,0,,,,,, diff --git a/frontend/e2e/fixtures/create-new/config-step.ts b/frontend/e2e/fixtures/create-new/config-step.ts index 4333ed331d..82c45c54c1 100644 --- a/frontend/e2e/fixtures/create-new/config-step.ts +++ b/frontend/e2e/fixtures/create-new/config-step.ts @@ -33,3 +33,22 @@ export const config = { token: process.env.E2E_TOKEN_GITHUB as string, }, }; + +export const configWithoutBlockColumn = { + projectName: 'Heartbeat Metrics', + dateRange: [ + { + startDate: '2024-04-07T00:00:00.000+08:00', + endDate: '2024-04-08T23:59:59.999+08:00', + }, + ], + calendarType: 'Calendar with Chinese Holiday', + metrics: ['Cycle time'], + board: { + type: 'Jira', + boardId: '33', + email: 'heartbeatuser2023@gmail.com', + site: 'dorametrics', + token: process.env.E2E_TOKEN_JIRA as string, + }, +}; diff --git a/frontend/e2e/fixtures/create-new/metrics-step.ts b/frontend/e2e/fixtures/create-new/metrics-step.ts index 9420861234..c0857167b2 100644 --- a/frontend/e2e/fixtures/create-new/metrics-step.ts +++ b/frontend/e2e/fixtures/create-new/metrics-step.ts @@ -73,7 +73,7 @@ export const config = { Done: 'Done', }, ], - treatFlagCardAsBlock: true, + treatFlagCardAsBlock: false, }, doneStatus: ['DONE'], classification: [ @@ -177,3 +177,25 @@ export const modifiedConfig = { }, ], }; + +export const configWithoutBlockColumn = { + crews: ['Shiqi Yuan'], + cycleTime: { + type: 'byColumn', + jiraColumns: [ + { + 'TO DO': 'To do', + }, + { + 'IN DEV': 'In Dev', + }, + { + 'WAITING FOR TESTING': 'Waiting for testing', + }, + { + Done: 'Done', + }, + ], + }, + reworkTimesSettings: { excludeStates: [], reworkState: 'In Dev' }, +}; diff --git a/frontend/e2e/fixtures/create-new/report-result.ts b/frontend/e2e/fixtures/create-new/report-result.ts index ed25741be1..f65517c11b 100644 --- a/frontend/e2e/fixtures/create-new/report-result.ts +++ b/frontend/e2e/fixtures/create-new/report-result.ts @@ -12,8 +12,8 @@ export const BOARD_METRICS_RESULT = { export const FLAG_AS_BLOCK_PROJECT_BOARD_METRICS_RESULT = { Velocity: '7.5', Throughput: '5', - AverageCycleTime4SP: '0.50', - AverageCycleTime4Card: '0.75', + AverageCycleTime4SP: '0.55', + AverageCycleTime4Card: '0.83', totalReworkTimes: '3', totalReworkCards: '3', reworkCardsRatio: '0.6000', diff --git a/frontend/e2e/fixtures/cycle-time-by-status/board-data-by-status.csv b/frontend/e2e/fixtures/cycle-time-by-status/board-data-by-status.csv index 29fd87d1ea..ebdbc9c4bb 100644 --- a/frontend/e2e/fixtures/cycle-time-by-status/board-data-by-status.csv +++ b/frontend/e2e/fixtures/cycle-time-by-status/board-data-by-status.csv @@ -1,5 +1,5 @@ -"Issue key","Summary","Issue Type","Status","Status Date","Story Points","assignee","Reporter","Project Key","Project Name","Priority","Parent Summary","Sprint","Labels","Cycle Time","story point","Flagged","Story point estimate","Design","Cycle Time / Story Points","Analysis Days","In Dev Days","Waiting Days","Testing Days","Block Days","Review Days","OriginCycleTime: TO DO","OriginCycleTime: IN PROGRESS","OriginCycleTime: REVIEW","OriginCycleTime: FLAG","OriginCycleTime: ANALYSIS","OriginCycleTime: READY FOR TESTING","OriginCycleTime: DOING" -"ST-5","card5","Task","done","2024-03-29","3.0","Junbo Dai","heartbeat user","ST","status-test","Medium",,,"","1.17","","","3.0","","0.39","0","1.12","0","0","0","0.05","0.78","1.12","0.05","0","0","0","0" -"ST-6","card6","Task","done","2024-03-29","2.0","Chao Wang","heartbeat user","ST","status-test","Medium",,,"","0.98","","","2.0","","0.49","0","0.93","0.05","0","0","0","0.78","0","0","0","0.93","0.05","0" -"ST-4","card4","Task","done","2024-03-29","2.0","heartbeat user","heartbeat user","ST","status-test","Medium",,,"","0.99","","","2.0","","0.49","0","0.99","0","0","0","0","0.78","0","0","0","0","0","0.99" -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +Issue key,Summary,Issue Type,Status,Status Date,Story Points,assignee,Reporter,Project Key,Project Name,Priority,Parent Summary,Sprint,Labels,Cycle Time,story point,Flagged,Story point estimate,Design,Cycle Time / Story Points,Analysis Days,In Dev Days,Waiting Days,Testing Days,Block Days,Review Days,OriginCycleTime: TO DO,OriginCycleTime: IN PROGRESS,OriginCycleTime: REVIEW,OriginCycleTime: ANALYSIS,OriginCycleTime: READY FOR TESTING,OriginCycleTime: DOING +ST-5,card5,Task,done,2024-03-29,3.0,Junbo Dai,heartbeat user,ST,status-test,Medium,,,"",1.17,"","",3.0,"",0.39,0,1.12,0,0,0,0.05,0.78,1.12,0.05,0,0,0 +ST-6,card6,Task,done,2024-03-29,2.0,Chao Wang,heartbeat user,ST,status-test,Medium,,,"",0.98,"","",2.0,"",0.49,0,0.93,0.05,0,0,0,0.78,0,0,0.93,0.05,0 +ST-4,card4,Task,done,2024-03-29,2.0,heartbeat user,heartbeat user,ST,status-test,Medium,,,"",0.99,"","",2.0,"",0.49,0,0.99,0,0,0,0,0.78,0,0,0,0,0.99 +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, diff --git a/frontend/e2e/fixtures/cycle-time-by-status/cycle-time-by-column-fixture.ts b/frontend/e2e/fixtures/cycle-time-by-status/cycle-time-by-column-fixture.ts index a8103adeee..864ef55cf0 100644 --- a/frontend/e2e/fixtures/cycle-time-by-status/cycle-time-by-column-fixture.ts +++ b/frontend/e2e/fixtures/cycle-time-by-status/cycle-time-by-column-fixture.ts @@ -60,7 +60,7 @@ export const cycleTimeByColumnFixture = { Done: 'Done', }, ], - treatFlagCardAsBlock: true, + treatFlagCardAsBlock: false, }, doneStatus: ['DONE'], classification: [ diff --git a/frontend/e2e/fixtures/import-file/board-data-without-block-column.csv b/frontend/e2e/fixtures/import-file/board-data-without-block-column.csv new file mode 100644 index 0000000000..098a9b4e3d --- /dev/null +++ b/frontend/e2e/fixtures/import-file/board-data-without-block-column.csv @@ -0,0 +1,7 @@ +"Issue key","Summary","Issue Type","Status","Status Date","Story Points","assignee","Reporter","Project Key","Project Name","Priority","Parent Summary","Sprint","Labels","Cycle Time","Cycle Time / Story Points","Analysis Days","In Dev Days","Waiting Days","Testing Days","Block Days","Review Days","OriginCycleTime: TESTING","OriginCycleTime: TO DO","OriginCycleTime: IN PROGRESS","OriginCycleTime: REVIEW","OriginCycleTime: FLAG","Rework: total - In dev","Rework: from Block","Rework: from Review","Rework: from Testing","Rework: from Done" +"TFB-6","test - 1","Task","Done","2024-04-09","1.5","heartbeat user","heartbeat user","TFB","E2E-Test-For-Flag-As-Block","Medium",,,"","0.70","0.47","0","0.70","0","0","0","0","0","0","0.86","0","0.16","1","1","0","0","0" +"TFB-7","test - 2","Task","Done","2024-04-09","2.0","heartbeat user","heartbeat user","TFB","E2E-Test-For-Flag-As-Block","Medium",,,"","0.75","0.38","0","0.73","0","0","0","0.02","0","0","0.84","0.02","0.11","1","1","0","0","0" +"TFB-8","test - 3","Task","Done","2024-04-09","1.0","heartbeat user","heartbeat user","TFB","E2E-Test-For-Flag-As-Block","Medium",,,"","0.70","0.70","0","0.70","0","0","0","0","0","0","0.81","0","0.11","1","1","0","0","0" +"TFB-10","test - 5","Task","Done","2024-04-09","2.0","heartbeat user","heartbeat user","TFB","E2E-Test-For-Flag-As-Block","Medium",,,"","0.81","0.41","0","0.81","0","0","0","0","0","0","0.81","0","0","0","0","0","0","0" +"TFB-9","test - 4","Task","Done","2024-04-09","1.0","heartbeat user","heartbeat user","TFB","E2E-Test-For-Flag-As-Block","Medium",,,"","0.81","0.81","0","0.81","0","0","0","0","0","0","0.81","0","0","0","0","0","0","0" +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, diff --git a/frontend/e2e/fixtures/import-file/board-data.csv b/frontend/e2e/fixtures/import-file/board-data.csv index 13aca7665b..e1910f5730 100644 --- a/frontend/e2e/fixtures/import-file/board-data.csv +++ b/frontend/e2e/fixtures/import-file/board-data.csv @@ -1,4 +1,4 @@ -"Issue key","Summary","Issue Type","Status","Status Date","Story Points","assignee","Reporter","Project Key","Project Name","Priority","Parent Summary","Sprint","Labels","Cycle Time","Story testing-1","Flagged","Fix versions","Partner","Time tracking","Story point estimate","QA","Feature/Operation","Story testing-2","Cycle Time / Story Points","Analysis Days","In Dev Days","Waiting Days","Testing Days","Block Days","Review Days","OriginCycleTime: TODO","OriginCycleTime: TESTING","OriginCycleTime: WAIT FOR TEST","OriginCycleTime: DOING","OriginCycleTime: REVIEW","OriginCycleTime: FLAG","OriginCycleTime: BLOCKED" +"Issue key","Summary","Issue Type","Status","Status Date","Story Points","assignee","Reporter","Project Key","Project Name","Priority","Parent Summary","Sprint","Labels","Cycle Time","Story testing-1","Flagged","Fix versions","Partner","Time tracking","Story point estimate","QA","Feature/Operation","Story testing-2","Cycle Time / Story Points","Analysis Days","In Dev Days","Waiting Days","Testing Days","Block Days","Review Days","OriginCycleTime: TODO","OriginCycleTime: TESTING","OriginCycleTime: WAIT FOR TEST","OriginCycleTime: DOING","OriginCycleTime: REVIEW","OriginCycleTime: BLOCKED" "ADM-735","[backend]identify the source of the error when generate reports encounter exception","Task","Done","2024-01-19","1.0","Yunsong Yang","Yunsong Yang","ADM","Auto Dora Metrics","Medium","Precise on Metrics","Sprint 28","Stream2","7.70","1.0","","","","None","1.0","","","","7.70","0","2.02","1.81","0","0","3.87","3.03","0","1.81","2.02","3.87","0","0" "ADM-708","[Backend] Verify board and obtain board data with new API","Task","Done","2024-01-19","3.0","Weiran Sun","heartbeat user","ADM","Auto Dora Metrics","Medium","easy to use","Sprint 28","Stream1","9.95","1.0","","","","None","3.0","","","","3.32","0","4.00","0.93","1.04","0.98","3.00","7.10","1.04","0.93","4.00","3.00","0","0.98" "ADM-699","[Frontend] Optimize the 4xx&504 error display of report overview","Task","Done","2024-01-18","2.0","heartbeat user","heartbeat user","ADM","Auto Dora Metrics","Medium","Performance Improvement","Sprint 28","Stream2","10.93","1.0","","","","None","2.0","","","","5.46","0","5.14","0.04","0.78","2.01","2.96","10.75","0.78","0.04","5.14","2.96","0","2.01" diff --git a/frontend/e2e/pages/metrics/config-step.ts b/frontend/e2e/pages/metrics/config-step.ts index 8fe53851cf..bc03e04b3e 100644 --- a/frontend/e2e/pages/metrics/config-step.ts +++ b/frontend/e2e/pages/metrics/config-step.ts @@ -47,11 +47,11 @@ export class ConfigStep { readonly requiredMetricsVelocityOption: Locator; readonly requiredMetricsCycleTimeOption: Locator; readonly requiredMetricsClassificationOption: Locator; - readonly requiredMetricsReworkTimesOption: Locator; readonly requiredMetricsLeadTimeForChangesOption: Locator; readonly requiredMetricsDeploymentFrequencyOption: Locator; readonly requiredMetricsChangeFailureRateOption: Locator; readonly requiredMetricsMeanTimeToRecoveryOption: Locator; + readonly requiredMetricsReworkTimesOption: Locator; readonly boardContainer: Locator; readonly boardTypeSelect: Locator; readonly boardIdInput: Locator; @@ -121,6 +121,7 @@ export class ConfigStep { this.requiredMetricsDeploymentFrequencyOption = page.getByRole('option', { name: 'Deployment frequency' }); this.requiredMetricsChangeFailureRateOption = page.getByRole('option', { name: 'Change failure rate' }); this.requiredMetricsMeanTimeToRecoveryOption = page.getByRole('option', { name: 'Mean time to recovery' }); + this.requiredMetricsReworkTimesOption = page.getByRole('option', { name: 'Rework times' }); this.boardContainer = page.getByLabel('Board Config'); this.boardTypeSelect = this.boardContainer.getByLabel('Board *'); diff --git a/frontend/e2e/pages/metrics/metrics-step.ts b/frontend/e2e/pages/metrics/metrics-step.ts index 8d4b346586..cd1cad57b1 100644 --- a/frontend/e2e/pages/metrics/metrics-step.ts +++ b/frontend/e2e/pages/metrics/metrics-step.ts @@ -25,20 +25,24 @@ export class MetricsStep { readonly boardByColumnRadioBox: Locator; readonly boardByStatusRadioBox: Locator; readonly boardCycleTimeSelectForTODO: Locator; - readonly boardCycleTimeSelectForTO_DO_BYSTATUS: Locator; + readonly boardCycleTimeSelectForTO_DO: Locator; readonly boardCycleTimeSelectForDoing: Locator; + readonly boardCycleTimeSelectForIN_DEV: Locator; readonly boardCycleTimeSelectForInProgress: Locator; readonly boardCycleTimeSelectForAnalysis: Locator; readonly boardCycleTimeSelectForBlocked: Locator; readonly boardCycleTimeSelectForReview: Locator; readonly boardCycleTimeSelectForREADY: Locator; readonly boardCycleTimeSelectForWAITFORTESTING: Locator; + readonly boardCycleTimeSelectForWAIT_FOR_TESTING: Locator; readonly boardCycleTimeSelectForTesting: Locator; + readonly boardCycleTimeSelectForTESTING: Locator; readonly boardCycleTimeSelectForDone: Locator; readonly boardCycleTimeInputForTODO: Locator; readonly boardCycleTimeInputForDoing: Locator; readonly boardCycleTimeInputForBlocked: Locator; readonly boardCycleTimeInputForReview: Locator; + readonly boardCycleTimeInputForREVIEW: Locator; readonly boardCycleTimeInputForREADY: Locator; readonly boardCycleTimeInputForTesting: Locator; readonly boardCycleTimeInputForDone: Locator; @@ -102,12 +106,15 @@ export class MetricsStep { this.boardCycleTimeSelectForTODO = this.boardCycleTimeSection .getByLabel('Cycle time select for TODO') .getByLabel('Open'); - this.boardCycleTimeSelectForTO_DO_BYSTATUS = this.boardCycleTimeSection + this.boardCycleTimeSelectForTO_DO = this.boardCycleTimeSection .getByLabel('Cycle time select for TO DO') .getByLabel('Open'); this.boardCycleTimeSelectForDoing = this.boardCycleTimeSection .getByLabel('Cycle time select for Doing') .getByLabel('Open'); + this.boardCycleTimeSelectForIN_DEV = this.boardCycleTimeSection + .getByLabel('Cycle time select for IN DEV') + .getByLabel('Open'); this.boardCycleTimeSelectForInProgress = this.boardCycleTimeSection .getByLabel('Cycle time select for IN PROGRESS') .getByLabel('Open'); @@ -126,9 +133,15 @@ export class MetricsStep { this.boardCycleTimeSelectForWAITFORTESTING = this.boardCycleTimeSection .getByLabel('Cycle time select for WAIT FOR TEST') .getByLabel('Open'); + this.boardCycleTimeSelectForWAIT_FOR_TESTING = this.boardCycleTimeSection + .getByLabel('Cycle time select for WAITING FOR TESTING') + .getByLabel('Open'); this.boardCycleTimeSelectForTesting = this.boardCycleTimeSection .getByLabel('Cycle time select for Testing') .getByLabel('Open'); + this.boardCycleTimeSelectForTESTING = this.boardCycleTimeSection + .getByLabel('Cycle time select for TESTING') + .getByLabel('Open'); this.boardCycleTimeSelectForDone = this.boardCycleTimeSection .getByLabel('Cycle time select for Done') .getByLabel('Open'); @@ -144,6 +157,9 @@ export class MetricsStep { this.boardCycleTimeInputForReview = this.boardCycleTimeSection .getByLabel('Cycle time select for Review') .getByRole('combobox'); + this.boardCycleTimeInputForREVIEW = this.boardCycleTimeSection + .getByLabel('Cycle time select for REVIEW') + .getByRole('combobox'); this.boardCycleTimeInputForREADY = this.boardCycleTimeSection .getByLabel('Cycle time select for WAIT FOR TEST') .getByRole('combobox'); @@ -398,7 +414,7 @@ export class MetricsStep { [todoOption, doingOption, blockOption, reviewOption, forReadyOption, testingOption, doneOption]: string[], isByColumn: boolean, ) { - await this.boardCycleTimeSelectForTO_DO_BYSTATUS.click(); + await this.boardCycleTimeSelectForTO_DO.click(); await this.page.getByRole('option', { name: todoOption }).click(); await this.boardCycleTimeSelectForDoing.click(); @@ -428,6 +444,20 @@ export class MetricsStep { await this.page.getByRole('option', { name: doneOption }).click(); } + async selectHeartbeatStateWithoutBlock([todoOption, inDevOption, waitForTestingOption, doneOption]: string[]) { + await this.boardCycleTimeSelectForTO_DO.click(); + await this.page.getByRole('option', { name: todoOption }).click(); + + await this.boardCycleTimeSelectForIN_DEV.click(); + await this.page.getByRole('option', { name: inDevOption }).click(); + + await this.boardCycleTimeSelectForWAIT_FOR_TESTING.click(); + await this.page.getByRole('option', { name: waitForTestingOption }).click(); + + await this.boardCycleTimeSelectForDone.click(); + await this.page.getByRole('option', { name: doneOption }).click(); + } + async checkHeartbeatStateIsSet( [todoOption, doingOption, blockOption, reviewOption, forReadyOption, testingOption, doneOption]: string[], isByColumn: boolean, diff --git a/frontend/e2e/pages/metrics/report-step.ts b/frontend/e2e/pages/metrics/report-step.ts index 904c75f863..28d5c890d2 100644 --- a/frontend/e2e/pages/metrics/report-step.ts +++ b/frontend/e2e/pages/metrics/report-step.ts @@ -356,6 +356,21 @@ export class ReportStep { await this.backButton.click(); } + async checkBoardDownloadDataWithoutBlock(fileName: string) { + await downloadFileAndCheck( + this.page, + this.exportBoardData, + 'board-data-without-block-column.csv', + async (fileDataString) => { + const localCsvFile = fs.readFileSync(path.resolve(__dirname, fileName)); + const localCsv = parse(localCsvFile); + const downloadCsv = parse(fileDataString); + + expect(localCsv).toStrictEqual(downloadCsv); + }, + ); + } + async checkDoraMetrics( prLeadTime: string, pipelineLeadTime: string, diff --git a/frontend/e2e/specs/major-path/create-a-new-project.spec.ts b/frontend/e2e/specs/major-path/create-a-new-project.spec.ts index 018291b331..9784022991 100644 --- a/frontend/e2e/specs/major-path/create-a-new-project.spec.ts +++ b/frontend/e2e/specs/major-path/create-a-new-project.spec.ts @@ -1,3 +1,5 @@ +import { configWithoutBlockColumn as metricsStepWithoutBlockColumnData } from '../../fixtures/create-new/metrics-step'; +import { configWithoutBlockColumn as configWithoutBlockColumnData } from '../../fixtures/create-new/config-step'; import { cycleTimeByStatusFixture } from '../../fixtures/cycle-time-by-status/cycle-time-by-status-fixture'; import { BOARD_METRICS_RESULT, DORA_METRICS_RESULT } from '../../fixtures/create-new/report-result'; import { config as metricsStepData } from '../../fixtures/create-new/metrics-step'; @@ -50,7 +52,6 @@ test('Create a new project', async ({ homePage, configStep, metricsStep, reportS await metricsStep.checkBoardConfigurationVisible(); await metricsStep.checkPipelineConfigurationVisible(); await metricsStep.checkLastAssigneeCrewFilterChecked(); - await metricsStep.checkCycleTimeConsiderCheckboxChecked(); await metricsStep.checkCycleTimeSettingIsByColumn(); await metricsStep.waitForHiddenLoading(); await metricsStep.selectCrews(metricsStepData.crews); @@ -97,3 +98,46 @@ test('Create a new project', async ({ homePage, configStep, metricsStep, reportS await reportStep.checkDoraMetricsDetails(ProjectCreationType.CREATE_A_NEW_PROJECT); await reportStep.checkMetricDownloadData(); }); + +test('Create a new project without block column in boarding mapping', async ({ + homePage, + configStep, + metricsStep, + reportStep, +}) => { + const dateRange = { + startDate: format(configWithoutBlockColumnData.dateRange[0].startDate), + endDate: format(configWithoutBlockColumnData.dateRange[0].endDate), + }; + + await homePage.goto(); + await homePage.createANewProject(); + await configStep.waitForShown(); + await configStep.typeInProjectName(configWithoutBlockColumnData.projectName); + await configStep.selectRegularCalendar(configWithoutBlockColumnData.calendarType); + await configStep.typeInDateRange(dateRange); + await configStep.selectReworkTimesRequiredMetrics(); + await configStep.checkBoardFormVisible(); + await configStep.checkPipelineToolFormInvisible(); + await configStep.checkSourceControlFormInvisible(); + await configStep.fillAndVerifyBoardConfig(configWithoutBlockColumnData.board); + await configStep.validateNextButtonClickable(); + await configStep.goToMetrics(); + + await metricsStep.checkBoardConfigurationVisible(); + await metricsStep.checkPipelineConfigurationInvisible(); + await metricsStep.checkClassificationSettingInvisible(); + await metricsStep.selectCrews(metricsStepWithoutBlockColumnData.crews); + await metricsStep.selectCycleTimeSettingsType(metricsStepWithoutBlockColumnData.cycleTime.type); + await metricsStep.checkCycleTimeConsiderCheckboxChecked(); + await metricsStep.selectHeartbeatStateWithoutBlock( + metricsStepWithoutBlockColumnData.cycleTime.jiraColumns.map( + (jiraToHBSingleMap) => Object.values(jiraToHBSingleMap)[0], + ), + ); + await metricsStep.selectReworkSettings(metricsStepWithoutBlockColumnData.reworkTimesSettings); + + await metricsStep.goToReportPage(); + await reportStep.confirmGeneratedReport(); + await reportStep.checkBoardDownloadDataWithoutBlock('../../fixtures/create-new/board-data-without-block-column.csv'); +}); diff --git a/frontend/e2e/specs/major-path/cycle-time-by-status-test.spec.ts b/frontend/e2e/specs/major-path/cycle-time-by-status-test.spec.ts index 0bb40ef345..d75bf914a5 100644 --- a/frontend/e2e/specs/major-path/cycle-time-by-status-test.spec.ts +++ b/frontend/e2e/specs/major-path/cycle-time-by-status-test.spec.ts @@ -27,7 +27,6 @@ test('Create a new project with cycle time by status', async ({ homePage, config await metricsStep.waitForShown(); await metricsStep.validateNextButtonNotClickable(); await metricsStep.checkLastAssigneeCrewFilterChecked(); - await metricsStep.checkCycleTimeConsiderCheckboxChecked(); await metricsStep.checkCycleTimeSettingIsByColumn(); await metricsStep.waitForHiddenLoading(); await metricsStep.selectCrews(cycleTimeByStatusFixture.crews); @@ -65,7 +64,6 @@ test('Create a new project with cycle time by status', async ({ homePage, config await metricsStep.waitForShown(); await metricsStep.validateNextButtonNotClickable(); await metricsStep.checkLastAssigneeCrewFilterChecked(); - await metricsStep.checkCycleTimeConsiderCheckboxChecked(); await metricsStep.checkCycleTimeSettingIsByColumn(); await metricsStep.waitForHiddenLoading(); await metricsStep.selectCrews(cycleTimeByColumnFixture.crews); diff --git a/frontend/e2e/specs/major-path/import-project-from-file.spec.ts b/frontend/e2e/specs/major-path/import-project-from-file.spec.ts index 16cbf741a6..7f69a111eb 100644 --- a/frontend/e2e/specs/major-path/import-project-from-file.spec.ts +++ b/frontend/e2e/specs/major-path/import-project-from-file.spec.ts @@ -68,15 +68,22 @@ test('Import project from file', async ({ homePage, configStep, metricsStep, rep await reportStep.checkDownloadReports(); }); -test('Import project from flag as block', async ({ homePage, configStep, metricsStep, reportStep }) => { +test('Import project from flag as block and without block column', async ({ + homePage, + configStep, + metricsStep, + reportStep, +}) => { await homePage.goto(); await homePage.importProjectFromFile('../fixtures/input-files/add-flag-as-block-config-file.json'); await configStep.verifyBoardConfig(); await configStep.goToMetrics(); await metricsStep.waitForShown(); + await metricsStep.checkCycleTimeConsiderCheckboxChecked(); await metricsStep.goToReportPage(); + await reportStep.confirmGeneratedReport(); await reportStep.checkBoardMetrics( FLAG_AS_BLOCK_PROJECT_BOARD_METRICS_RESULT.Velocity, FLAG_AS_BLOCK_PROJECT_BOARD_METRICS_RESULT.Throughput, @@ -87,4 +94,5 @@ test('Import project from flag as block', async ({ homePage, configStep, metrics FLAG_AS_BLOCK_PROJECT_BOARD_METRICS_RESULT.reworkCardsRatio, FLAG_AS_BLOCK_PROJECT_BOARD_METRICS_RESULT.throughput, ); + await reportStep.checkBoardDownloadDataWithoutBlock('../../fixtures/import-file/board-data-without-block-column.csv'); }); diff --git a/frontend/e2e/specs/major-path/page-jumps.spec.ts b/frontend/e2e/specs/major-path/page-jumps.spec.ts index b319037ae3..08c4fc1dcb 100644 --- a/frontend/e2e/specs/major-path/page-jumps.spec.ts +++ b/frontend/e2e/specs/major-path/page-jumps.spec.ts @@ -28,7 +28,6 @@ test('Page jump for import', async ({ homePage, configStep, metricsStep, reportS await metricsStep.selectCrews(modifiedMetricsStepData.crews); await metricsStep.selectCycleTimeSettingsType(modifiedMetricsStepData.cycleTime.type); await metricsStep.selectModifiedHeartbeatState(modifiedHbStateData); - await metricsStep.selectCycleTimeConsiderAsBlockCheckbox(); await metricsStep.selectClassifications(modifiedMetricsStepData.classification); await metricsStep.selectReworkSettings(metricsStepData.reworkTimesSettings); await metricsStep.goToReportPage(); @@ -38,7 +37,6 @@ test('Page jump for import', async ({ homePage, configStep, metricsStep, reportS await metricsStep.checkCrews(modifiedMetricsStepData.crews); await metricsStep.checkBoardByStatusRadioBoxChecked(); await metricsStep.checkModifiedHeartbeatState(modifiedHbStateData); - await metricsStep.checkCycleTimeConsiderAsBlockUnchecked(); await metricsStep.checkClassifications(modifiedMetricsStepData.classification); await metricsStep.checkReworkSettings(metricsStepData.reworkTimesSettings); diff --git a/frontend/src/clients/report/ReportClient.ts b/frontend/src/clients/report/ReportClient.ts index 7d7127fc30..811352c415 100644 --- a/frontend/src/clients/report/ReportClient.ts +++ b/frontend/src/clients/report/ReportClient.ts @@ -31,7 +31,6 @@ export class ReportClient extends HttpClient { reworkState: 'Done', fromAnalysis: 0, fromInDev: 0, - fromFlag: 0, fromBlock: 0, fromWaitingForTesting: 0, fromTesting: 0, diff --git a/frontend/src/clients/report/dto/response.ts b/frontend/src/clients/report/dto/response.ts index 4219fae83c..c9b1b7e64f 100644 --- a/frontend/src/clients/report/dto/response.ts +++ b/frontend/src/clients/report/dto/response.ts @@ -49,7 +49,6 @@ export interface ReworkTimeResponse { fromAnalysis: number | null; fromInDev: number | null; fromBlock: number | null; - fromFlag: number | null; fromWaitingForTesting: number | null; fromTesting: number | null; fromReview: number | null; diff --git a/frontend/src/constants/resources.ts b/frontend/src/constants/resources.ts index 1efe24ee53..34e1041d09 100644 --- a/frontend/src/constants/resources.ts +++ b/frontend/src/constants/resources.ts @@ -218,7 +218,6 @@ export const REWORK_TIME_MAPPING = { fromAnalysis: 'analysis', fromInDev: 'in dev', fromBlock: 'block', - fromFlag: 'flag', fromReview: 'review', fromWaitingForTesting: 'waiting for testing', fromTesting: 'testing', @@ -231,7 +230,6 @@ export const REWORK_BOARD_STATUS: string[] = [ REWORK_TIME_MAPPING.fromAnalysis, REWORK_TIME_MAPPING.fromInDev, REWORK_TIME_MAPPING.fromBlock, - REWORK_TIME_MAPPING.fromFlag, REWORK_TIME_MAPPING.fromWaitingForTesting, REWORK_TIME_MAPPING.fromTesting, REWORK_TIME_MAPPING.fromReview, @@ -268,6 +266,7 @@ export const MESSAGE = { HOME_VERIFY_IMPORT_WARNING: 'The content of the imported JSON file is empty. Please confirm carefully', CONFIG_PAGE_VERIFY_IMPORT_ERROR: 'Imported data is not perfectly matched. Please review carefully before going next!', CLASSIFICATION_WARNING: 'Some classifications in import data might be removed.', + FLAG_CARD_DROPPED_WARNING: 'Please note: ’consider the “Flag” as “Block” ‘ has been dropped!', REAL_DONE_WARNING: 'Some selected doneStatus in import data might be removed', ORGANIZATION_WARNING: 'This organization in import data might be removed', PIPELINE_NAME_WARNING: 'This Pipeline in import data might be removed', @@ -427,3 +426,5 @@ export const REMOVE_BUTTON_TEXT = 'Remove'; export const MAX_TIME_RANGE_AMOUNT = 6; export const START_DATE_INVALID_TEXT = 'Start date is invalid'; export const END_DATE_INVALID_TEXT = 'End date is invalid'; + +export const BLOCK_COLUMN_NAME = ['BLOCKED', 'BLOCK']; diff --git a/frontend/src/containers/MetricsStep/CycleTime/index.tsx b/frontend/src/containers/MetricsStep/CycleTime/index.tsx index 2152dbc3e5..1fcf12999d 100644 --- a/frontend/src/containers/MetricsStep/CycleTime/index.tsx +++ b/frontend/src/containers/MetricsStep/CycleTime/index.tsx @@ -1,20 +1,50 @@ +import { + selectCycleTimeWarningMessage, + selectDisplayFlagCardDropWarning, + selectMetricsContent, + selectTreatFlagCardAsBlock, + updateDisplayFlagCardDropWarning, + updateTreatFlagCardAsBlock, +} from '@src/context/Metrics/metricsSlice'; import SectionTitleWithTooltip from '@src/components/Common/SectionTitleWithTooltip'; -import { selectCycleTimeWarningMessage } from '@src/context/Metrics/metricsSlice'; import { WarningNotification } from '@src/components/Common/WarningNotification'; import CycleTimeTable from '@src/containers/MetricsStep/CycleTime/Table'; import FlagCard from '@src/containers/MetricsStep/CycleTime/FlagCard'; -import { TIPS } from '@src/constants/resources'; +import { useAppDispatch } from '@src/hooks/useAppDispatch'; +import { MESSAGE, TIPS } from '@src/constants/resources'; +import { useEffect, useMemo, useState } from 'react'; +import { existBlockColumn } from '@src/utils/util'; import { useAppSelector } from '@src/hooks'; export const CycleTime = () => { + const dispatch = useAppDispatch(); + const flagCardAsBlock = useAppSelector(selectTreatFlagCardAsBlock); + const displayFlagCardDropWarning = useAppSelector(selectDisplayFlagCardDropWarning); const warningMessage = useAppSelector(selectCycleTimeWarningMessage); + const { cycleTimeSettings, cycleTimeSettingsType } = useAppSelector(selectMetricsContent); + const hasBlockColumn = useMemo(() => { + return existBlockColumn(cycleTimeSettingsType, cycleTimeSettings); + }, [cycleTimeSettingsType, cycleTimeSettings]); + const [shouldShowConflictMessage, setShouldShowConflictMessage] = useState(false); + + useEffect(() => { + if (hasBlockColumn && displayFlagCardDropWarning) { + setShouldShowConflictMessage(true); + dispatch(updateDisplayFlagCardDropWarning(false)); + } + + if (hasBlockColumn && flagCardAsBlock) { + dispatch(updateTreatFlagCardAsBlock(false)); + } + }, [dispatch, flagCardAsBlock, displayFlagCardDropWarning, hasBlockColumn]); return (
+ {shouldShowConflictMessage && } {warningMessage && } - + {hasBlockColumn || }
); }; diff --git a/frontend/src/context/Metrics/metricsSlice.ts b/frontend/src/context/Metrics/metricsSlice.ts index 2b6316b564..9fb44e60fb 100644 --- a/frontend/src/context/Metrics/metricsSlice.ts +++ b/frontend/src/context/Metrics/metricsSlice.ts @@ -5,7 +5,7 @@ import { MESSAGE, METRICS_CONSTANTS, } from '@src/constants/resources'; -import { convertCycleTimeSettings, getSortedAndDeduplicationBoardingMapping } from '@src/utils/util'; +import { convertCycleTimeSettings, existBlockColumn, getSortedAndDeduplicationBoardingMapping } from '@src/utils/util'; import { pipeline } from '@src/context/config/pipelineTool/verifyResponseSlice'; import { createSlice } from '@reduxjs/toolkit'; import camelCase from 'lodash.camelcase'; @@ -51,6 +51,7 @@ export interface ISavedMetricsSettingState { deploymentFrequencySettings: IPipelineConfig[]; leadTimeForChanges: IPipelineConfig[]; treatFlagCardAsBlock: boolean; + displayFlagCardDropWarning: boolean; assigneeFilter: string; firstTimeRoadMetricData: boolean; importedData: { @@ -86,6 +87,7 @@ const initialState: ISavedMetricsSettingState = { deploymentFrequencySettings: [], leadTimeForChanges: [{ id: 0, organization: '', pipelineName: '', step: '', branches: [] }], treatFlagCardAsBlock: true, + displayFlagCardDropWarning: true, assigneeFilter: ASSIGNEE_FILTER_TYPES.LAST_ASSIGNEE, firstTimeRoadMetricData: true, importedData: { @@ -290,6 +292,20 @@ function resetReworkTimeSettingWhenMappingModified(preJiraColumnsValue: string[] }; } +function initTreatFlagCardAsBlock( + preTreatFlagCardAsBlock: boolean, + preHasBlockColumn: boolean, + state: ISavedMetricsSettingState, +) { + if ( + !preTreatFlagCardAsBlock && + preHasBlockColumn && + !existBlockColumn(state.cycleTimeSettingsType, state.cycleTimeSettings) + ) { + state.treatFlagCardAsBlock = true; + } +} + export const metricsSlice = createSlice({ name: 'metrics', initialState, @@ -380,6 +396,11 @@ export const metricsSlice = createSlice({ const preJiraColumnsValue = getSortedAndDeduplicationBoardingMapping(state.cycleTimeSettings).filter( (item) => item !== METRICS_CONSTANTS.cycleTimeEmptyStr, ); + const preHasBlockColumn = existBlockColumn(state.cycleTimeSettingsType, state.cycleTimeSettings); + const preTreatFlagCardAsBlock = state.treatFlagCardAsBlock; + + state.displayFlagCardDropWarning = + state.displayFlagCardDropWarning && !isProjectCreated && importedCycleTime.importedTreatFlagCardAsBlock; state.users = isProjectCreated ? setCreateSelectUsers(state, users) : setImportSelectUsers(state, users, importedCrews); @@ -442,6 +463,7 @@ export const metricsSlice = createSlice({ ? getCycleTimeSettingsByColumn(state, jiraColumns) : getCycleTimeSettingsByStatus(state, jiraColumns); } + initTreatFlagCardAsBlock(preTreatFlagCardAsBlock, preHasBlockColumn, state); resetReworkTimeSettingWhenMappingModified(preJiraColumnsValue, state); if (!isProjectCreated && importedDoneStatus.length > 0) { @@ -457,11 +479,6 @@ export const metricsSlice = createSlice({ importedAssigneeFilter === ASSIGNEE_FILTER_TYPES.HISTORICAL_ASSIGNEE ? importedAssigneeFilter : ASSIGNEE_FILTER_TYPES.LAST_ASSIGNEE; - - state.treatFlagCardAsBlock = - typeof importedCycleTime.importedTreatFlagCardAsBlock === 'boolean' - ? importedCycleTime.importedTreatFlagCardAsBlock - : true; }, updatePipelineSettings: (state, action) => { @@ -575,6 +592,10 @@ export const metricsSlice = createSlice({ state.treatFlagCardAsBlock = action.payload; }, + updateDisplayFlagCardDropWarning: (state, action) => { + state.displayFlagCardDropWarning = action.payload; + }, + updateAssigneeFilter: (state, action) => { state.assigneeFilter = action.payload; }, @@ -607,6 +628,7 @@ export const { updateMetricsImportedData, initDeploymentFrequencySettings, updateTreatFlagCardAsBlock, + updateDisplayFlagCardDropWarning, updateAssigneeFilter, updateMetricsState, updatePipelineSettings, @@ -630,6 +652,7 @@ export const selectCycleTimeSettings = (state: RootState) => state.metrics.cycle export const selectMetricsContent = (state: RootState) => state.metrics; export const selectAdvancedSettings = (state: RootState) => state.metrics.importedData.importedAdvancedSettings; export const selectTreatFlagCardAsBlock = (state: RootState) => state.metrics.treatFlagCardAsBlock; +export const selectDisplayFlagCardDropWarning = (state: RootState) => state.metrics.displayFlagCardDropWarning; export const selectAssigneeFilter = (state: RootState) => state.metrics.assigneeFilter; export const selectCycleTimeWarningMessage = (state: RootState) => state.metrics.cycleTimeWarningMessage; export const selectClassificationWarningMessage = (state: RootState) => state.metrics.classificationWarningMessage; diff --git a/frontend/src/hooks/useVerifyBoardEffect.ts b/frontend/src/hooks/useVerifyBoardEffect.ts index d97a3a6d17..d44643a4f2 100644 --- a/frontend/src/hooks/useVerifyBoardEffect.ts +++ b/frontend/src/hooks/useVerifyBoardEffect.ts @@ -1,6 +1,5 @@ import { BOARD_TYPES, AXIOS_REQUEST_ERROR_CODE, MESSAGE, UNKNOWN_ERROR_TITLE } from '@src/constants/resources'; import { selectBoard, updateBoard, updateBoardVerifyState } from '@src/context/config/configSlice'; -import { updateTreatFlagCardAsBlock } from '@src/context/Metrics/metricsSlice'; import { findCaseInsensitiveType, getJiraBoardToken } from '@src/utils/util'; import { useAppDispatch, useAppSelector } from '@src/hooks/useAppDispatch'; import { DEFAULT_HELPER_TEXT, EMPTY_STRING } from '@src/constants/commons'; @@ -187,7 +186,6 @@ export const useVerifyBoardEffect = (): useVerifyBoardStateInterface => { const verifyJira = async () => { setIsLoading(true); - dispatch(updateTreatFlagCardAsBlock(true)); const boardInfo = getBoardInfo(fields) as BoardRequestDTO; try { const res: { response: Record } = await boardClient.getVerifyBoard({ diff --git a/frontend/src/utils/util.ts b/frontend/src/utils/util.ts index 0d62c6c58e..65f08103a5 100644 --- a/frontend/src/utils/util.ts +++ b/frontend/src/utils/util.ts @@ -1,4 +1,9 @@ -import { CYCLE_TIME_LIST, CYCLE_TIME_SETTINGS_TYPES, METRICS_CONSTANTS } from '@src/constants/resources'; +import { + BLOCK_COLUMN_NAME, + CYCLE_TIME_LIST, + CYCLE_TIME_SETTINGS_TYPES, + METRICS_CONSTANTS, +} from '@src/constants/resources'; import { CleanedBuildKiteEmoji, OriginBuildKiteEmoji } from '@src/constants/emojis/emoji'; import { ICycleTimeSetting, IPipelineConfig } from '@src/context/Metrics/metricsSlice'; import { ITargetFieldType } from '@src/components/Common/MultiAutoComplete/styles'; @@ -156,3 +161,12 @@ export function convertCycleTimeSettings( } return cycleTimeSettings?.map(({ status, value }: ICycleTimeSetting) => ({ [status]: value })); } + +export function existBlockColumn( + cycleTimeSettingsType: CYCLE_TIME_SETTINGS_TYPES, + cycleTimeSettings: ICycleTimeSetting[], +) { + return cycleTimeSettingsType === CYCLE_TIME_SETTINGS_TYPES.BY_COLUMN + ? cycleTimeSettings.some(({ column }) => BLOCK_COLUMN_NAME.includes(column.toUpperCase())) + : cycleTimeSettings.some(({ status }) => BLOCK_COLUMN_NAME.includes(status.toUpperCase())); +}