diff --git a/.buildkite/pipeline.yml b/.buildkite/pipeline.yml index 8f86cbadc0..65f15a783a 100644 --- a/.buildkite/pipeline.yml +++ b/.buildkite/pipeline.yml @@ -117,6 +117,10 @@ steps: - "check-frontend-license" - "check-backend-license" command: ./ops/check.sh e2e-container + plugins: + - artifacts#v1.9.0: + upload: "./e2e-reports.tar.gz" + expire_in: "${RETENTION_DAYS} days" - label: ":rocket: Deploy prod" if: build.branch == "main" && (build.message =~ /(?i)\[frontend\]/ || build.message =~ /(?i)\[backend\]/) diff --git a/.trivyignore b/.trivyignore index 58c469a05c..048fbfd363 100644 --- a/.trivyignore +++ b/.trivyignore @@ -11,3 +11,4 @@ CVE-2023-49467 CVE-2023-49468 CVE-2024-0553 CVE-2024-0567 +CVE-2024-22201 diff --git a/frontend/__tests__/containers/MetricsStep/Crews.test.tsx b/frontend/__tests__/containers/MetricsStep/Crews.test.tsx index e7ca40166f..a41474d117 100644 --- a/frontend/__tests__/containers/MetricsStep/Crews.test.tsx +++ b/frontend/__tests__/containers/MetricsStep/Crews.test.tsx @@ -145,7 +145,7 @@ describe('Crew', () => { await userEvent.click(screen.getByRole('radio', { name: assigneeFilterLabels[1] })); await waitFor(() => { - expect(mockedUseAppDispatch).toHaveBeenCalledTimes(2); + expect(mockedUseAppDispatch).toHaveBeenCalledTimes(3); expect(mockedUseAppDispatch).toHaveBeenCalledWith(updateAssigneeFilter(assigneeFilterValues[1])); }); }); diff --git a/frontend/__tests__/containers/MetricsStep/CycleTime.test.tsx b/frontend/__tests__/containers/MetricsStep/CycleTime.test.tsx index fbfb11532c..0bdf860645 100644 --- a/frontend/__tests__/containers/MetricsStep/CycleTime.test.tsx +++ b/frontend/__tests__/containers/MetricsStep/CycleTime.test.tsx @@ -320,7 +320,7 @@ describe('CycleTime', () => { setup(); await userEvent.click(screen.getByRole('radio', { name: cycleTimeTypeLabels[1] })); - expect(mockedUseAppDispatch).toHaveBeenCalledTimes(3); + expect(mockedUseAppDispatch).toHaveBeenCalledTimes(4); expect(mockedUseAppDispatch).toHaveBeenCalledWith(setCycleTimeSettingsType(CYCLE_TIME_SETTINGS_TYPES.BY_STATUS)); expect(mockedUseAppDispatch).toHaveBeenCalledWith( updateCycleTimeSettings( diff --git a/frontend/__tests__/context/metricsSlice.test.ts b/frontend/__tests__/context/metricsSlice.test.ts index 8c19aa160f..e6e187de0f 100644 --- a/frontend/__tests__/context/metricsSlice.test.ts +++ b/frontend/__tests__/context/metricsSlice.test.ts @@ -23,6 +23,7 @@ import { setupStore } from '../utils/setupStoreUtil'; import { store } from '@src/store'; const initState = { + isBoarConfigDirty: false, jiraColumns: [], targetFields: [], users: [], diff --git a/frontend/e2e/fixtures/createNew/boardData.csv b/frontend/e2e/fixtures/createNew/boardData.csv index dae3b55392..3b1b74f835 100644 --- a/frontend/e2e/fixtures/createNew/boardData.csv +++ b/frontend/e2e/fixtures/createNew/boardData.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: DONE","OriginCycleTime: TESTING","OriginCycleTime: WAIT FOR TEST","OriginCycleTime: DOING","OriginCycleTime: REVIEW","OriginCycleTime: FLAG","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","22.29","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","24.09","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","23.29","0.78","0.04","5.14","2.96","0","2.01" -"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","25.99","0.05","2.72","2.83","0.35","0","2.14" -"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","24.06","0","1.99","1.08","2.22","0","7.65" -"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","24.09","1.87","1.35","5.94","0.27","0","0.72" -"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","24.12","1.84","0.10","3.00","0.98","0","3.00" -"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","24.12","1.16","0.02","4.22","1.73","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","26.25","0.78","0.07","2.81","3.19","0","0" -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, -"ADM-813","[FE]add new field 'Advance' in metrics page","Task","Review","2024-02-23","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","3.97","0.27","0.19","0","0","0","4.78","0.27","0","3.97" -"ADM-819","[BE]cache doesn't work in one case","Bug","Blocked","2024-02-23","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","0.08","0","0.84","0","0","0","3.14","0","0","0.08" -"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","9.20","0","38.43","0","0","0","1.05","0","0","9.20" -"ADM-797","[BE]The add flag as block logic is not working","Bug","Blocked","2024-02-20","2.0","heartbeat user","Wenting Yan","ADM","Auto Dora Metrics","High",,"Sprint 30","Stream2,v1.1.5","0","","Impediment","","","None","2.0","","","","0","0","7.13","0","0","4.99","0","2.03","0","0","0","7.13","0","0.09","5.08" -"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","0.06","0","0","0","0","1.17","0","0","0","0.06","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","2.07","0","0","1.03","0","6.67","0","0","0","2.07","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","1.27","0","0","0","0","8.00","0","0","0","1.27","0","0","0" -"ADM-806","[BE]no need to obtain pipeline data twice in backend","Bug","Doing","2024-02-21","2.0","heartbeat user","Yufan Wang","ADM","Auto Dora Metrics","Medium",,"Sprint 30","Stream2,v1.1.5","0","","","","","None","2.0","","","","0","0","1.97","0","0","0","0","8.10","0","0","0","1.97","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","7.08","0","0","1.99","0","0.95","0","0","0","7.08","0","0","1.99" -"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","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","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","0" -"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","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: FLAG","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" +"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" +"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" +"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" +"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" +"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" +"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" diff --git a/frontend/e2e/pages/metrics/ReportStep.ts b/frontend/e2e/pages/metrics/ReportStep.ts index 5f7f446986..5870deb18f 100644 --- a/frontend/e2e/pages/metrics/ReportStep.ts +++ b/frontend/e2e/pages/metrics/ReportStep.ts @@ -8,6 +8,7 @@ import fs from 'fs'; export class ReportStep { readonly page: Page; + readonly pageHeader: Locator; readonly velocityPart: Locator; readonly averageCycleTimeForSP: Locator; readonly averageCycleTimeForCard: Locator; @@ -26,7 +27,8 @@ export class ReportStep { constructor(page: Page) { this.page = page; - this.velocityPart = page.locator('[data-test-id="Velocity"] [data-test-id="report-section"]'); + this.pageHeader = this.page.locator('[data-test-id="Header"]'); + this.velocityPart = this.page.locator('[data-test-id="Velocity"] [data-test-id="report-section"]'); this.averageCycleTimeForSP = this.page.locator('[data-test-id="Cycle Time"] [data-test-id="report-section"]'); this.averageCycleTimeForCard = this.page.locator('[data-test-id="Cycle Time"] [data-test-id="report-section"]'); this.prLeadTime = this.page.locator('[data-test-id="Lead Time For Changes"] [data-test-id="report-section"]'); @@ -55,6 +57,7 @@ export class ReportStep { await this.showMoreLinks.nth(1).click(); await expect(this.page).toHaveScreenshot(snapshotPath, { fullPage: true, + mask: [this.pageHeader], }); await downloadFileAndCheck(this.page, this.exportPipelineDataButton, 'pipelineData.csv', async (fileDataString) => { const localCsvFile = fs.readFileSync(path.resolve(__dirname, '../../fixtures/createNew/pipelineData.csv')); @@ -67,7 +70,7 @@ export class ReportStep { } async confirmGeneratedReport() { - await expect(this.page.getByRole('alert')).toContainText('Help Information', { timeout: E2E_EXPECT_TIMEOUT * 2 }); + await expect(this.page.getByRole('alert')).toContainText('Help Information', { timeout: E2E_EXPECT_TIMEOUT * 3 }); await expect(this.page.getByRole('alert')).toContainText( 'The file will expire in 30 minutes, please download it in time.', ); @@ -85,20 +88,19 @@ export class ReportStep { await expect(this.averageCycleTimeForCard).toContainText(`${averageCycleTimeForCard}Average Cycle Time(Days/Card)`); } - // eslint-disable-next-line @typescript-eslint/no-unused-vars async checkBoardMetricsDetails(snapshotPath: string, csvCompareLines: number) { await this.showMoreLinks.first().click(); await expect(this.page).toHaveScreenshot(snapshotPath, { fullPage: true, + mask: [this.pageHeader], + }); + await downloadFileAndCheck(this.page, this.exportBoardData, 'boardData.csv', async (fileDataString) => { + const localCsvFile = fs.readFileSync(path.resolve(__dirname, '../../fixtures/createNew/boardData.csv')); + const localCsv = parse(localCsvFile, { to: csvCompareLines }); + const downloadCsv = parse(fileDataString, { to: csvCompareLines }); + + expect(localCsv).toStrictEqual(downloadCsv); }); - //FIXME fix csv compare issue - // await downloadFileAndCheck(this.page, this.exportBoardData, 'boardData.csv', async (fileDataString) => { - // const localCsvFile = fs.readFileSync(path.resolve(__dirname, '../../fixtures/createNew/boardData.csv')); - // const localCsv = parse(localCsvFile, { to: csvCompareLines }); - // const downloadCsv = parse(fileDataString, { to: csvCompareLines }); - // - // expect(localCsv).toStrictEqual(downloadCsv); - // }); await this.backButton.click(); } diff --git a/frontend/e2e/specs/create-a-new-project.spec.ts-snapshots/create-a-new-project-Board-Metrics-Google-Chrome-darwin.png b/frontend/e2e/specs/create-a-new-project.spec.ts-snapshots/create-a-new-project-Board-Metrics-Google-Chrome-darwin.png index f2dd37d813..cfbd2ce42f 100644 Binary files a/frontend/e2e/specs/create-a-new-project.spec.ts-snapshots/create-a-new-project-Board-Metrics-Google-Chrome-darwin.png and b/frontend/e2e/specs/create-a-new-project.spec.ts-snapshots/create-a-new-project-Board-Metrics-Google-Chrome-darwin.png differ diff --git a/frontend/e2e/specs/create-a-new-project.spec.ts-snapshots/create-a-new-project-Board-Metrics-Google-Chrome-linux.png b/frontend/e2e/specs/create-a-new-project.spec.ts-snapshots/create-a-new-project-Board-Metrics-Google-Chrome-linux.png index a2f6cecd54..a2c2de3823 100644 Binary files a/frontend/e2e/specs/create-a-new-project.spec.ts-snapshots/create-a-new-project-Board-Metrics-Google-Chrome-linux.png and b/frontend/e2e/specs/create-a-new-project.spec.ts-snapshots/create-a-new-project-Board-Metrics-Google-Chrome-linux.png differ diff --git a/frontend/e2e/specs/create-a-new-project.spec.ts-snapshots/create-a-new-project-Board-Metrics-Microsoft-Edge-linux.png b/frontend/e2e/specs/create-a-new-project.spec.ts-snapshots/create-a-new-project-Board-Metrics-Microsoft-Edge-linux.png index a2f6cecd54..a2c2de3823 100644 Binary files a/frontend/e2e/specs/create-a-new-project.spec.ts-snapshots/create-a-new-project-Board-Metrics-Microsoft-Edge-linux.png and b/frontend/e2e/specs/create-a-new-project.spec.ts-snapshots/create-a-new-project-Board-Metrics-Microsoft-Edge-linux.png differ diff --git a/frontend/e2e/specs/create-a-new-project.spec.ts-snapshots/create-a-new-project-Board-Metrics-Tablet-linux.png b/frontend/e2e/specs/create-a-new-project.spec.ts-snapshots/create-a-new-project-Board-Metrics-Tablet-linux.png index 84905766ca..dcce64c647 100644 Binary files a/frontend/e2e/specs/create-a-new-project.spec.ts-snapshots/create-a-new-project-Board-Metrics-Tablet-linux.png and b/frontend/e2e/specs/create-a-new-project.spec.ts-snapshots/create-a-new-project-Board-Metrics-Tablet-linux.png differ diff --git a/frontend/e2e/specs/create-a-new-project.spec.ts-snapshots/create-a-new-project-Board-Metrics-chromium-darwin.png b/frontend/e2e/specs/create-a-new-project.spec.ts-snapshots/create-a-new-project-Board-Metrics-chromium-darwin.png index 609a4e0487..2508201756 100644 Binary files a/frontend/e2e/specs/create-a-new-project.spec.ts-snapshots/create-a-new-project-Board-Metrics-chromium-darwin.png and b/frontend/e2e/specs/create-a-new-project.spec.ts-snapshots/create-a-new-project-Board-Metrics-chromium-darwin.png differ diff --git a/frontend/e2e/specs/create-a-new-project.spec.ts-snapshots/create-a-new-project-Board-Metrics-chromium-linux.png b/frontend/e2e/specs/create-a-new-project.spec.ts-snapshots/create-a-new-project-Board-Metrics-chromium-linux.png index a2f6cecd54..a2c2de3823 100644 Binary files a/frontend/e2e/specs/create-a-new-project.spec.ts-snapshots/create-a-new-project-Board-Metrics-chromium-linux.png and b/frontend/e2e/specs/create-a-new-project.spec.ts-snapshots/create-a-new-project-Board-Metrics-chromium-linux.png differ diff --git a/frontend/e2e/specs/create-a-new-project.spec.ts-snapshots/create-a-new-project-Board-Metrics-webkit-linux.png b/frontend/e2e/specs/create-a-new-project.spec.ts-snapshots/create-a-new-project-Board-Metrics-webkit-linux.png index 449be1ff60..aa635a5e90 100644 Binary files a/frontend/e2e/specs/create-a-new-project.spec.ts-snapshots/create-a-new-project-Board-Metrics-webkit-linux.png and b/frontend/e2e/specs/create-a-new-project.spec.ts-snapshots/create-a-new-project-Board-Metrics-webkit-linux.png differ diff --git a/frontend/e2e/specs/create-a-new-project.spec.ts-snapshots/create-a-new-project-DORA-Metrics-Google-Chrome-darwin.png b/frontend/e2e/specs/create-a-new-project.spec.ts-snapshots/create-a-new-project-DORA-Metrics-Google-Chrome-darwin.png index 2779039846..de35cbad38 100644 Binary files a/frontend/e2e/specs/create-a-new-project.spec.ts-snapshots/create-a-new-project-DORA-Metrics-Google-Chrome-darwin.png and b/frontend/e2e/specs/create-a-new-project.spec.ts-snapshots/create-a-new-project-DORA-Metrics-Google-Chrome-darwin.png differ diff --git a/frontend/e2e/specs/create-a-new-project.spec.ts-snapshots/create-a-new-project-DORA-Metrics-Google-Chrome-linux.png b/frontend/e2e/specs/create-a-new-project.spec.ts-snapshots/create-a-new-project-DORA-Metrics-Google-Chrome-linux.png index 6156687885..9c004b2a31 100644 Binary files a/frontend/e2e/specs/create-a-new-project.spec.ts-snapshots/create-a-new-project-DORA-Metrics-Google-Chrome-linux.png and b/frontend/e2e/specs/create-a-new-project.spec.ts-snapshots/create-a-new-project-DORA-Metrics-Google-Chrome-linux.png differ diff --git a/frontend/e2e/specs/create-a-new-project.spec.ts-snapshots/create-a-new-project-DORA-Metrics-Microsoft-Edge-linux.png b/frontend/e2e/specs/create-a-new-project.spec.ts-snapshots/create-a-new-project-DORA-Metrics-Microsoft-Edge-linux.png index 6156687885..9c004b2a31 100644 Binary files a/frontend/e2e/specs/create-a-new-project.spec.ts-snapshots/create-a-new-project-DORA-Metrics-Microsoft-Edge-linux.png and b/frontend/e2e/specs/create-a-new-project.spec.ts-snapshots/create-a-new-project-DORA-Metrics-Microsoft-Edge-linux.png differ diff --git a/frontend/e2e/specs/create-a-new-project.spec.ts-snapshots/create-a-new-project-DORA-Metrics-Tablet-linux.png b/frontend/e2e/specs/create-a-new-project.spec.ts-snapshots/create-a-new-project-DORA-Metrics-Tablet-linux.png index a5a0f58ccd..8fe27e0095 100644 Binary files a/frontend/e2e/specs/create-a-new-project.spec.ts-snapshots/create-a-new-project-DORA-Metrics-Tablet-linux.png and b/frontend/e2e/specs/create-a-new-project.spec.ts-snapshots/create-a-new-project-DORA-Metrics-Tablet-linux.png differ diff --git a/frontend/e2e/specs/create-a-new-project.spec.ts-snapshots/create-a-new-project-DORA-Metrics-chromium-linux.png b/frontend/e2e/specs/create-a-new-project.spec.ts-snapshots/create-a-new-project-DORA-Metrics-chromium-linux.png index 6156687885..9c004b2a31 100644 Binary files a/frontend/e2e/specs/create-a-new-project.spec.ts-snapshots/create-a-new-project-DORA-Metrics-chromium-linux.png and b/frontend/e2e/specs/create-a-new-project.spec.ts-snapshots/create-a-new-project-DORA-Metrics-chromium-linux.png differ diff --git a/frontend/e2e/specs/create-a-new-project.spec.ts-snapshots/create-a-new-project-DORA-Metrics-webkit-linux.png b/frontend/e2e/specs/create-a-new-project.spec.ts-snapshots/create-a-new-project-DORA-Metrics-webkit-linux.png index 66694b87cc..b5f894cd1e 100644 Binary files a/frontend/e2e/specs/create-a-new-project.spec.ts-snapshots/create-a-new-project-DORA-Metrics-webkit-linux.png and b/frontend/e2e/specs/create-a-new-project.spec.ts-snapshots/create-a-new-project-DORA-Metrics-webkit-linux.png differ diff --git a/frontend/e2e/specs/import-project-from-file.spec.ts-snapshots/import-project-from-file-Board-Metrics-Google-Chrome-darwin.png b/frontend/e2e/specs/import-project-from-file.spec.ts-snapshots/import-project-from-file-Board-Metrics-Google-Chrome-darwin.png index 609a4e0487..cfbd2ce42f 100644 Binary files a/frontend/e2e/specs/import-project-from-file.spec.ts-snapshots/import-project-from-file-Board-Metrics-Google-Chrome-darwin.png and b/frontend/e2e/specs/import-project-from-file.spec.ts-snapshots/import-project-from-file-Board-Metrics-Google-Chrome-darwin.png differ diff --git a/frontend/e2e/specs/import-project-from-file.spec.ts-snapshots/import-project-from-file-Board-Metrics-Google-Chrome-linux.png b/frontend/e2e/specs/import-project-from-file.spec.ts-snapshots/import-project-from-file-Board-Metrics-Google-Chrome-linux.png index a2f6cecd54..a2c2de3823 100644 Binary files a/frontend/e2e/specs/import-project-from-file.spec.ts-snapshots/import-project-from-file-Board-Metrics-Google-Chrome-linux.png and b/frontend/e2e/specs/import-project-from-file.spec.ts-snapshots/import-project-from-file-Board-Metrics-Google-Chrome-linux.png differ diff --git a/frontend/e2e/specs/import-project-from-file.spec.ts-snapshots/import-project-from-file-Board-Metrics-Microsoft-Edge-linux.png b/frontend/e2e/specs/import-project-from-file.spec.ts-snapshots/import-project-from-file-Board-Metrics-Microsoft-Edge-linux.png index a2f6cecd54..a2c2de3823 100644 Binary files a/frontend/e2e/specs/import-project-from-file.spec.ts-snapshots/import-project-from-file-Board-Metrics-Microsoft-Edge-linux.png and b/frontend/e2e/specs/import-project-from-file.spec.ts-snapshots/import-project-from-file-Board-Metrics-Microsoft-Edge-linux.png differ diff --git a/frontend/e2e/specs/import-project-from-file.spec.ts-snapshots/import-project-from-file-Board-Metrics-Tablet-darwin.png b/frontend/e2e/specs/import-project-from-file.spec.ts-snapshots/import-project-from-file-Board-Metrics-Tablet-darwin.png index 0647c04dec..134befc210 100644 Binary files a/frontend/e2e/specs/import-project-from-file.spec.ts-snapshots/import-project-from-file-Board-Metrics-Tablet-darwin.png and b/frontend/e2e/specs/import-project-from-file.spec.ts-snapshots/import-project-from-file-Board-Metrics-Tablet-darwin.png differ diff --git a/frontend/e2e/specs/import-project-from-file.spec.ts-snapshots/import-project-from-file-Board-Metrics-Tablet-linux.png b/frontend/e2e/specs/import-project-from-file.spec.ts-snapshots/import-project-from-file-Board-Metrics-Tablet-linux.png index 84905766ca..dcce64c647 100644 Binary files a/frontend/e2e/specs/import-project-from-file.spec.ts-snapshots/import-project-from-file-Board-Metrics-Tablet-linux.png and b/frontend/e2e/specs/import-project-from-file.spec.ts-snapshots/import-project-from-file-Board-Metrics-Tablet-linux.png differ diff --git a/frontend/e2e/specs/import-project-from-file.spec.ts-snapshots/import-project-from-file-Board-Metrics-chromium-darwin.png b/frontend/e2e/specs/import-project-from-file.spec.ts-snapshots/import-project-from-file-Board-Metrics-chromium-darwin.png index f2dd37d813..193117a378 100644 Binary files a/frontend/e2e/specs/import-project-from-file.spec.ts-snapshots/import-project-from-file-Board-Metrics-chromium-darwin.png and b/frontend/e2e/specs/import-project-from-file.spec.ts-snapshots/import-project-from-file-Board-Metrics-chromium-darwin.png differ diff --git a/frontend/e2e/specs/import-project-from-file.spec.ts-snapshots/import-project-from-file-Board-Metrics-chromium-linux.png b/frontend/e2e/specs/import-project-from-file.spec.ts-snapshots/import-project-from-file-Board-Metrics-chromium-linux.png index a2f6cecd54..a2c2de3823 100644 Binary files a/frontend/e2e/specs/import-project-from-file.spec.ts-snapshots/import-project-from-file-Board-Metrics-chromium-linux.png and b/frontend/e2e/specs/import-project-from-file.spec.ts-snapshots/import-project-from-file-Board-Metrics-chromium-linux.png differ diff --git a/frontend/e2e/specs/import-project-from-file.spec.ts-snapshots/import-project-from-file-Board-Metrics-webkit-linux.png b/frontend/e2e/specs/import-project-from-file.spec.ts-snapshots/import-project-from-file-Board-Metrics-webkit-linux.png index 449be1ff60..aa635a5e90 100644 Binary files a/frontend/e2e/specs/import-project-from-file.spec.ts-snapshots/import-project-from-file-Board-Metrics-webkit-linux.png and b/frontend/e2e/specs/import-project-from-file.spec.ts-snapshots/import-project-from-file-Board-Metrics-webkit-linux.png differ diff --git a/frontend/e2e/specs/import-project-from-file.spec.ts-snapshots/import-project-from-file-DORA-Metrics-Google-Chrome-darwin.png b/frontend/e2e/specs/import-project-from-file.spec.ts-snapshots/import-project-from-file-DORA-Metrics-Google-Chrome-darwin.png index a5a0bf03ce..de35cbad38 100644 Binary files a/frontend/e2e/specs/import-project-from-file.spec.ts-snapshots/import-project-from-file-DORA-Metrics-Google-Chrome-darwin.png and b/frontend/e2e/specs/import-project-from-file.spec.ts-snapshots/import-project-from-file-DORA-Metrics-Google-Chrome-darwin.png differ diff --git a/frontend/e2e/specs/import-project-from-file.spec.ts-snapshots/import-project-from-file-DORA-Metrics-Google-Chrome-linux.png b/frontend/e2e/specs/import-project-from-file.spec.ts-snapshots/import-project-from-file-DORA-Metrics-Google-Chrome-linux.png index 6156687885..9c004b2a31 100644 Binary files a/frontend/e2e/specs/import-project-from-file.spec.ts-snapshots/import-project-from-file-DORA-Metrics-Google-Chrome-linux.png and b/frontend/e2e/specs/import-project-from-file.spec.ts-snapshots/import-project-from-file-DORA-Metrics-Google-Chrome-linux.png differ diff --git a/frontend/e2e/specs/import-project-from-file.spec.ts-snapshots/import-project-from-file-DORA-Metrics-Microsoft-Edge-linux.png b/frontend/e2e/specs/import-project-from-file.spec.ts-snapshots/import-project-from-file-DORA-Metrics-Microsoft-Edge-linux.png index 6156687885..9c004b2a31 100644 Binary files a/frontend/e2e/specs/import-project-from-file.spec.ts-snapshots/import-project-from-file-DORA-Metrics-Microsoft-Edge-linux.png and b/frontend/e2e/specs/import-project-from-file.spec.ts-snapshots/import-project-from-file-DORA-Metrics-Microsoft-Edge-linux.png differ diff --git a/frontend/e2e/specs/import-project-from-file.spec.ts-snapshots/import-project-from-file-DORA-Metrics-Tablet-darwin.png b/frontend/e2e/specs/import-project-from-file.spec.ts-snapshots/import-project-from-file-DORA-Metrics-Tablet-darwin.png index cb4237536d..eef81143d3 100644 Binary files a/frontend/e2e/specs/import-project-from-file.spec.ts-snapshots/import-project-from-file-DORA-Metrics-Tablet-darwin.png and b/frontend/e2e/specs/import-project-from-file.spec.ts-snapshots/import-project-from-file-DORA-Metrics-Tablet-darwin.png differ diff --git a/frontend/e2e/specs/import-project-from-file.spec.ts-snapshots/import-project-from-file-DORA-Metrics-Tablet-linux.png b/frontend/e2e/specs/import-project-from-file.spec.ts-snapshots/import-project-from-file-DORA-Metrics-Tablet-linux.png index a5a0f58ccd..8fe27e0095 100644 Binary files a/frontend/e2e/specs/import-project-from-file.spec.ts-snapshots/import-project-from-file-DORA-Metrics-Tablet-linux.png and b/frontend/e2e/specs/import-project-from-file.spec.ts-snapshots/import-project-from-file-DORA-Metrics-Tablet-linux.png differ diff --git a/frontend/e2e/specs/import-project-from-file.spec.ts-snapshots/import-project-from-file-DORA-Metrics-chromium-darwin.png b/frontend/e2e/specs/import-project-from-file.spec.ts-snapshots/import-project-from-file-DORA-Metrics-chromium-darwin.png index a5a0bf03ce..f4aa046fb3 100644 Binary files a/frontend/e2e/specs/import-project-from-file.spec.ts-snapshots/import-project-from-file-DORA-Metrics-chromium-darwin.png and b/frontend/e2e/specs/import-project-from-file.spec.ts-snapshots/import-project-from-file-DORA-Metrics-chromium-darwin.png differ diff --git a/frontend/e2e/specs/import-project-from-file.spec.ts-snapshots/import-project-from-file-DORA-Metrics-chromium-linux.png b/frontend/e2e/specs/import-project-from-file.spec.ts-snapshots/import-project-from-file-DORA-Metrics-chromium-linux.png index 6156687885..9c004b2a31 100644 Binary files a/frontend/e2e/specs/import-project-from-file.spec.ts-snapshots/import-project-from-file-DORA-Metrics-chromium-linux.png and b/frontend/e2e/specs/import-project-from-file.spec.ts-snapshots/import-project-from-file-DORA-Metrics-chromium-linux.png differ diff --git a/frontend/e2e/specs/import-project-from-file.spec.ts-snapshots/import-project-from-file-DORA-Metrics-webkit-linux.png b/frontend/e2e/specs/import-project-from-file.spec.ts-snapshots/import-project-from-file-DORA-Metrics-webkit-linux.png index 66694b87cc..b5f894cd1e 100644 Binary files a/frontend/e2e/specs/import-project-from-file.spec.ts-snapshots/import-project-from-file-DORA-Metrics-webkit-linux.png and b/frontend/e2e/specs/import-project-from-file.spec.ts-snapshots/import-project-from-file-DORA-Metrics-webkit-linux.png differ diff --git a/frontend/package.json b/frontend/package.json index 691e7d4941..45b7cfa69b 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -20,12 +20,14 @@ "e2e:major": "pnpm run e2e --project='Google Chrome'", "e2e:ci": "dotenvx run --env-file=./e2e/.env.ci -- pnpm run e2e", "e2e:major-ci": "dotenvx run --env-file=./e2e/.env.ci -- pnpm run e2e:major", - "e2e:local": "dotenvx run --env-file=./e2e/.env.local -- pnpm run e2e", + "e2e:local": "dotenvx run --env-file=./e2e/.env.local -- pnpm run e2e:major", "e2e:with-server": "ts-node --project tsconfig.scripts.json ./scripts/runE2eWithServer.ts 'pnpm run e2e:local'", "e2e:ui": "dotenvx run --env-file=./e2e/.env.local -- pnpm exec playwright test --ui --headed", "e2e:report": "pnpm exec playwright show-report", "e2e:codegen": "pnpm exec playwright codegen 13.215.41.120:4321", + "e2e:build-docker-image": "docker build -t 'heartbeat_e2e:latest' ../ -f ../ops/infra/Dockerfile.e2e", "e2e:updateSnapshots": "pnpm run e2e:local --update-snapshots", + "e2e:updateSnapshots-docker": "docker run --rm --network=host -v $(pwd)/e2e:/app/e2e -w /app -it heartbeat_e2e:latest pnpm run e2e:updateSnapshots", "prepare": "cd .. && husky install frontend/.husky", "license-compliance": "license-compliance -r detailed", "type-check": "tsc --noEmit" diff --git a/frontend/src/containers/ConfigStep/Board/index.tsx b/frontend/src/containers/ConfigStep/Board/index.tsx index 52473863ce..812976cdb3 100644 --- a/frontend/src/containers/ConfigStep/Board/index.tsx +++ b/frontend/src/containers/ConfigStep/Board/index.tsx @@ -5,23 +5,26 @@ import { StyledTextField, StyledTypeSelections, } from '@src/components/Common/ConfigForms'; +import { updateMetricsBoardDirtyStatus } from '@src/context/Metrics/metricsSlice'; import { KEYS, useVerifyBoardEffect } from '@src/hooks/useVerifyBoardEffect'; import { ResetButton, VerifyButton } from '@src/components/Common/Buttons'; +import { useAppSelector, useAppDispatch } from '@src/hooks/useAppDispatch'; import { InputLabel, ListItemText, MenuItem, Select } from '@mui/material'; import { ConfigSelectionTitle } from '@src/containers/MetricsStep/style'; import { selectIsBoardVerified } from '@src/context/config/configSlice'; import { BOARD_TYPES, CONFIG_TITLE } from '@src/constants/resources'; -import { useAppSelector } from '@src/hooks/useAppDispatch'; import { Loading } from '@src/components/Loading'; import { FormEvent, useMemo } from 'react'; export const Board = () => { + const dispatch = useAppDispatch(); const isVerified = useAppSelector(selectIsBoardVerified); const { verifyJira, isLoading, fields, updateField, validateField, resetFields } = useVerifyBoardEffect(); const onSubmit = async (e: FormEvent) => { e.preventDefault(); await verifyJira(); + dispatch(updateMetricsBoardDirtyStatus(false)); }; const isDisableVerifyButton = useMemo( diff --git a/frontend/src/containers/MetricsStep/Classification/index.tsx b/frontend/src/containers/MetricsStep/Classification/index.tsx index 893c160e18..8d7bb7baa8 100644 --- a/frontend/src/containers/MetricsStep/Classification/index.tsx +++ b/frontend/src/containers/MetricsStep/Classification/index.tsx @@ -1,5 +1,9 @@ +import { + saveTargetFields, + selectClassificationWarningMessage, + updateMetricsBoardDirtyStatus, +} from '@src/context/Metrics/metricsSlice'; import { TypedStyledAutocompleted, ITargetFieldType } from '@src/components/Common/MultiAutoComplete/styles'; -import { saveTargetFields, selectClassificationWarningMessage } from '@src/context/Metrics/metricsSlice'; import { MetricsSettingTitle } from '@src/components/Common/MetricsSettingTitle'; import { WarningNotification } from '@src/components/Common/WarningNotification'; import { Checkbox, createFilterOptions, TextField } from '@mui/material'; @@ -37,7 +41,7 @@ export const Classification = ({ targetFields, title, label }: classificationPro ...targetField, flag: !!nextSelectedOptions.find((option) => option.key === targetField.key), })); - + dispatch(updateMetricsBoardDirtyStatus(true)); dispatch(saveTargetFields(updatedTargetFields)); }; diff --git a/frontend/src/containers/MetricsStep/Crews/AssigneeFilter.tsx b/frontend/src/containers/MetricsStep/Crews/AssigneeFilter.tsx index efa3301a8a..76fbee8e15 100644 --- a/frontend/src/containers/MetricsStep/Crews/AssigneeFilter.tsx +++ b/frontend/src/containers/MetricsStep/Crews/AssigneeFilter.tsx @@ -1,4 +1,8 @@ -import { selectAssigneeFilter, updateAssigneeFilter } from '@src/context/Metrics/metricsSlice'; +import { + selectAssigneeFilter, + updateAssigneeFilter, + updateMetricsBoardDirtyStatus, +} from '@src/context/Metrics/metricsSlice'; import { StyledRadioGroup } from '@src/containers/MetricsStep/Crews/style'; import { useAppDispatch } from '@src/hooks/useAppDispatch'; import { FormControlLabel, Radio } from '@mui/material'; @@ -11,6 +15,7 @@ export const AssigneeFilter = () => { const handleChange = (event: React.ChangeEvent) => { dispatch(updateAssigneeFilter(event.target.value)); + dispatch(updateMetricsBoardDirtyStatus(true)); }; return ( diff --git a/frontend/src/containers/MetricsStep/Crews/index.tsx b/frontend/src/containers/MetricsStep/Crews/index.tsx index 5b9c9c4039..d573e94e80 100644 --- a/frontend/src/containers/MetricsStep/Crews/index.tsx +++ b/frontend/src/containers/MetricsStep/Crews/index.tsx @@ -1,4 +1,9 @@ -import { saveUsers, selectMetricsContent, savePipelineCrews } from '@src/context/Metrics/metricsSlice'; +import { + saveUsers, + selectMetricsContent, + savePipelineCrews, + updateMetricsBoardDirtyStatus, +} from '@src/context/Metrics/metricsSlice'; import { AssigneeFilter } from '@src/containers/MetricsStep/Crews/AssigneeFilter'; import { MetricsSettingTitle } from '@src/components/Common/MetricsSettingTitle'; import MultiAutoComplete from '@src/components/Common/MultiAutoComplete'; @@ -18,6 +23,7 @@ interface crewsProps { export const Crews = ({ options, title, label, type = 'board' }: crewsProps) => { const isBoardCrews = type === 'board'; const dispatch = useAppDispatch(); + const [isEmptyCrewData, setIsEmptyCrewData] = useState(false); const { users, pipelineCrews } = useAppSelector(selectMetricsContent); const [selectedCrews, setSelectedCrews] = useState([]); @@ -31,11 +37,14 @@ export const Crews = ({ options, title, label, type = 'board' }: crewsProps) => setIsEmptyCrewData(selectedCrews.length === 0); }, [selectedCrews]); - const handleCrewChange = (event: React.SyntheticEvent, value: string[]) => { + const handleCrewChange = (_: React.SyntheticEvent, value: string[]) => { if (value[value.length - 1] === 'All') { setSelectedCrews(selectedCrews.length === options.length ? [] : options); return; } + if (isBoardCrews) { + dispatch(updateMetricsBoardDirtyStatus(true)); + } setSelectedCrews([...value]); }; diff --git a/frontend/src/containers/MetricsStep/CycleTime/FlagCard.tsx b/frontend/src/containers/MetricsStep/CycleTime/FlagCard.tsx index cf3532ca48..286c52ae64 100644 --- a/frontend/src/containers/MetricsStep/CycleTime/FlagCard.tsx +++ b/frontend/src/containers/MetricsStep/CycleTime/FlagCard.tsx @@ -1,4 +1,8 @@ -import { selectTreatFlagCardAsBlock, updateTreatFlagCardAsBlock } from '@src/context/Metrics/metricsSlice'; +import { + selectTreatFlagCardAsBlock, + updateTreatFlagCardAsBlock, + updateMetricsBoardDirtyStatus, +} from '@src/context/Metrics/metricsSlice'; import { FlagCardItem, ItemCheckbox, ItemText } from '@src/containers/MetricsStep/CycleTime/style'; import { useAppDispatch } from '@src/hooks/useAppDispatch'; import { useAppSelector } from '@src/hooks'; @@ -10,6 +14,7 @@ const FlagCard = () => { const handleFlagCardAsBlock = () => { dispatch(updateTreatFlagCardAsBlock(!flagCardAsBlock)); + dispatch(updateMetricsBoardDirtyStatus(true)); }; return ( diff --git a/frontend/src/containers/MetricsStep/CycleTime/Table/index.tsx b/frontend/src/containers/MetricsStep/CycleTime/Table/index.tsx index 912b314fe8..142f339593 100644 --- a/frontend/src/containers/MetricsStep/CycleTime/Table/index.tsx +++ b/frontend/src/containers/MetricsStep/CycleTime/Table/index.tsx @@ -10,6 +10,7 @@ import { saveDoneColumn, selectMetricsContent, setCycleTimeSettingsType, + updateMetricsBoardDirtyStatus, } from '@src/context/Metrics/metricsSlice'; import { StyledRadioGroup, @@ -56,6 +57,7 @@ const CycleTimeTable = () => { ); isColumnAsKey && resetRealDoneColumn(name, value); dispatch(updateCycleTimeSettings(newCycleTimeSettings)); + dispatch(updateMetricsBoardDirtyStatus(true)); }, [cycleTimeSettings, dispatch, isColumnAsKey, resetRealDoneColumn], ); @@ -87,6 +89,7 @@ const CycleTimeTable = () => { ), ); dispatch(saveDoneColumn([])); + dispatch(updateMetricsBoardDirtyStatus(true)); }; return ( diff --git a/frontend/src/containers/MetricsStep/RealDone/index.tsx b/frontend/src/containers/MetricsStep/RealDone/index.tsx index f54d3a97c2..2605b8609e 100644 --- a/frontend/src/containers/MetricsStep/RealDone/index.tsx +++ b/frontend/src/containers/MetricsStep/RealDone/index.tsx @@ -3,6 +3,7 @@ import { selectCycleTimeSettings, selectMetricsContent, selectRealDoneWarningMessage, + updateMetricsBoardDirtyStatus, } from '@src/context/Metrics/metricsSlice'; import { MetricsSettingTitle } from '@src/components/Common/MetricsSettingTitle'; import { WarningNotification } from '@src/components/Common/WarningNotification'; @@ -40,7 +41,9 @@ export const RealDone = ({ columns, title, label }: realDoneProps) => { dispatch(saveDoneColumn(selectedDoneStatus.length === status.length ? [] : status)); return; } + setSelectedDoneStatus([...value]); + dispatch(updateMetricsBoardDirtyStatus(true)); dispatch(saveDoneColumn([...value])); }; diff --git a/frontend/src/containers/MetricsStep/index.tsx b/frontend/src/containers/MetricsStep/index.tsx index 879f97d56c..9f8f208820 100644 --- a/frontend/src/containers/MetricsStep/index.tsx +++ b/frontend/src/containers/MetricsStep/index.tsx @@ -13,8 +13,8 @@ import { MetricSelectionWrapper, MetricsSelectionTitle, } from '@src/containers/MetricsStep/style'; +import { selectMetricsContent, updateMetricsState, selectMetricsBoardIsDirty } from '@src/context/Metrics/metricsSlice'; import { DeploymentFrequencySettings } from '@src/containers/MetricsStep/DeploymentFrequencySettings'; -import { selectMetricsContent, updateMetricsState } from '@src/context/Metrics/metricsSlice'; import { StyledRetryButton, StyledErrorMessage } from '@src/containers/MetricsStep/style'; import { CYCLE_TIME_SETTINGS_TYPES, DONE, REQUIRED_DATA } from '@src/constants/resources'; import { closeAllNotifications } from '@src/context/notification/NotificationSlice'; @@ -54,6 +54,7 @@ const MetricsStep = () => { cycleTimeSettings.filter((e) => e.value === DONE).length > 1; const { getBoardInfo, isLoading, errorMessage } = useGetBoardInfoEffect(); const shouldLoad = useAppSelector(shouldMetricsLoad); + const isBoarConfigDirty = useAppSelector(selectMetricsBoardIsDirty); const getInfo = useCallback( () => @@ -75,9 +76,9 @@ const MetricsStep = () => { useLayoutEffect(() => { if (!shouldLoad) return; dispatch(closeAllNotifications()); - if (!shouldLoad || !isShowCrewsAndRealDone) return; + if (!shouldLoad || !isShowCrewsAndRealDone || isBoarConfigDirty) return; getInfo(); - }, [shouldLoad, isShowCrewsAndRealDone, dispatch, getInfo]); + }, [shouldLoad, isShowCrewsAndRealDone, isBoarConfigDirty, dispatch, getInfo]); return ( <> diff --git a/frontend/src/containers/MetricsStepper/index.tsx b/frontend/src/containers/MetricsStepper/index.tsx index 239836cde4..203ad98d5e 100644 --- a/frontend/src/containers/MetricsStepper/index.tsx +++ b/frontend/src/containers/MetricsStepper/index.tsx @@ -20,13 +20,6 @@ import { SOURCE_CONTROL_TYPES, TIPS, } from '@src/constants/resources'; -import { - ICycleTimeSetting, - updateCycleTimeSettings, - savedMetricsSettingState, - selectCycleTimeSettings, - selectMetricsContent, -} from '@src/context/Metrics/metricsSlice'; import { BackButton, ButtonContainer, @@ -37,13 +30,19 @@ import { StyledStepLabel, StyledStepper, } from './style'; +import { + ICycleTimeSetting, + savedMetricsSettingState, + selectCycleTimeSettings, + selectMetricsContent, +} from '@src/context/Metrics/metricsSlice'; import { backStep, nextStep, selectStepNumber, updateTimeStamp } from '@src/context/stepper/StepperSlice'; import { useMetricsStepValidationCheckContext } from '@src/hooks/useMetricsStepValidationCheckContext'; import { pipeline } from '@src/context/config/pipelineTool/verifyResponseSlice'; import { COMMON_BUTTONS, METRICS_STEPS, STEPS } from '@src/constants/commons'; import { ConfirmDialog } from '@src/containers/MetricsStepper/ConfirmDialog'; -import React, { lazy, Suspense, useEffect, useMemo, useState } from 'react'; import { useAppDispatch, useAppSelector } from '@src/hooks/useAppDispatch'; +import { lazy, Suspense, useEffect, useMemo, useState } from 'react'; import { getFormMeta } from '@src/context/meta/metaSlice'; import SaveAltIcon from '@mui/icons-material/SaveAlt'; import { exportToJsonFile } from '@src/utils/util'; @@ -263,7 +262,6 @@ const MetricsStepper = () => { branches: [], })); dispatch(updatePipelineList(initPipelineSteps)); - dispatch(updateCycleTimeSettings([])); } }; diff --git a/frontend/src/context/Metrics/metricsSlice.ts b/frontend/src/context/Metrics/metricsSlice.ts index b9841ee3ac..eed395ceaf 100644 --- a/frontend/src/context/Metrics/metricsSlice.ts +++ b/frontend/src/context/Metrics/metricsSlice.ts @@ -34,6 +34,7 @@ export interface ICycleTimeSetting { } export interface savedMetricsSettingState { + isBoarConfigDirty: boolean; jiraColumns: { key: string; value: { name: string; statuses: string[] } }[]; targetFields: { name: string; key: string; flag: boolean }[]; users: string[]; @@ -65,6 +66,7 @@ export interface savedMetricsSettingState { } const initialState: savedMetricsSettingState = { + isBoarConfigDirty: false, jiraColumns: [], targetFields: [], users: [], @@ -130,10 +132,13 @@ const findKeyByValues = (arrayA: { [key: string]: string }[], arrayB: string[]): const setSelectUsers = (users: string[], importedCrews: string[]) => users.filter((item: string) => importedCrews?.includes(item)); -const setPipelineCrews = (pipelineCrews: string[], importedPipelineCrews: string[]) => { +const setPipelineCrews = (isProjectCreated: boolean, pipelineCrews: string[], importedPipelineCrews: string[]) => { if (_.isEmpty(pipelineCrews)) { return []; } + if (isProjectCreated) { + return pipelineCrews; + } return pipelineCrews.filter((item: string) => importedPipelineCrews?.includes(item)); }; @@ -238,6 +243,10 @@ export const metricsSlice = createSlice({ }); }, + updateMetricsBoardDirtyStatus: (state, action) => { + state.isBoarConfigDirty = action.payload; + }, + updateMetricsImportedData: (state, action) => { const { crews, @@ -354,7 +363,8 @@ export const metricsSlice = createSlice({ updatePipelineSettings: (state, action) => { const { pipelineList, isProjectCreated, pipelineCrews } = action.payload; const { importedDeployment, importedPipelineCrews } = state.importedData; - state.pipelineCrews = isProjectCreated ? pipelineCrews : setPipelineCrews(pipelineCrews, importedPipelineCrews); + + state.pipelineCrews = setPipelineCrews(isProjectCreated, pipelineCrews, importedPipelineCrews); const orgNames: Array = _.uniq(pipelineList.map((item: pipeline) => item.orgName)); const filteredPipelineNames = (organization: string) => pipelineList @@ -407,8 +417,7 @@ export const metricsSlice = createSlice({ const updatedImportedPipelineStep = importedDeployment.find((pipeline) => pipeline.id === id)?.step ?? ''; const updatedImportedPipelineBranches = importedDeployment.find((pipeline) => pipeline.id === id)?.branches ?? []; const selectedPipelineStep = state.deploymentFrequencySettings.find((pipeline) => pipeline.id === id)?.step ?? ''; - const validPipelineCrews = _.filter(pipelineCrews, (crew) => importedPipelineCrews.includes(crew)); - state.pipelineCrews = validPipelineCrews; + state.pipelineCrews = _.filter(pipelineCrews, (crew) => importedPipelineCrews.includes(crew)); const stepWarningMessage = (selectedStep: string) => (steps.includes(selectedStep) ? null : MESSAGE.STEP_WARNING); const validStep = (selectedStep: string): string => (steps.includes(selectedStep) ? selectedStep : ''); @@ -488,8 +497,11 @@ export const { setCycleTimeSettingsType, resetMetricData, updateAdvancedSettings, + updateMetricsBoardDirtyStatus, } = metricsSlice.actions; +export const selectMetricsBoardIsDirty = (state: RootState) => state.metrics.isBoarConfigDirty; + export const selectDeploymentFrequencySettings = (state: RootState) => state.metrics.deploymentFrequencySettings; export const selectCycleTimeSettings = (state: RootState) => state.metrics.cycleTimeSettings; diff --git a/ops/check.sh b/ops/check.sh index c29ff98944..73229592d5 100755 --- a/ops/check.sh +++ b/ops/check.sh @@ -157,6 +157,8 @@ dot_star_check() { e2e_container_check() { docker build -t "heartbeat_e2e:latest" ./ -f ./ops/infra/Dockerfile.e2e + set +e + local result docker run \ --name hb_e2e_runner \ -e "APP_ORIGIN=${APP_HTTP_SCHEDULE:-}://${AWS_EC2_IP_E2E:-}:${AWS_EC2_IP_E2E_PORT:-}" \ @@ -166,8 +168,13 @@ e2e_container_check() { -e "CI=${CI:-}" \ heartbeat_e2e:latest \ pnpm run e2e:major-ci + result=$? + set -e + docker cp hb_e2e_runner:/app/e2e/reports ./e2e-reports docker rm hb_e2e_runner + tar -zcvf ./e2e-reports.tar.gz ./e2e-reports + exit $result } e2e_check(){