From 777a3dd15fb20bc7f6b345aaeb689c45b9517a68 Mon Sep 17 00:00:00 2001 From: Surat Das Date: Fri, 18 Jun 2021 14:01:55 -0700 Subject: [PATCH 1/2] Issue #276: Enable to bulk clear/apply ignore area for test runs --- src/components/TestRunList/BulkOperation.tsx | 109 +++++++++++++++---- src/services/testRun.service.ts | 13 +++ 2 files changed, 103 insertions(+), 19 deletions(-) diff --git a/src/components/TestRunList/BulkOperation.tsx b/src/components/TestRunList/BulkOperation.tsx index 5ac55650..b563c06b 100644 --- a/src/components/TestRunList/BulkOperation.tsx +++ b/src/components/TestRunList/BulkOperation.tsx @@ -1,11 +1,12 @@ import React from "react"; -import { Typography, IconButton, Tooltip } from "@material-ui/core"; -import { BaseComponentProps, RowModel } from "@material-ui/data-grid"; +import { Typography, IconButton, Tooltip, LinearProgress } from "@material-ui/core"; +import { BaseComponentProps, InternalRowsState, RowModel } from "@material-ui/data-grid"; import { BaseModal } from "../BaseModal"; import { useSnackbar } from "notistack"; -import { Delete, ThumbDown, ThumbUp } from "@material-ui/icons"; +import { Collections, Delete, LayersClear, ThumbDown, ThumbUp } from "@material-ui/icons"; import { testRunService } from "../../services"; import { TestStatus } from "../../types"; +import { IgnoreArea } from "../../types/ignoreArea"; export const BulkOperation: React.FunctionComponent = ( props: BaseComponentProps @@ -14,9 +15,13 @@ export const BulkOperation: React.FunctionComponent = ( const [approveDialogOpen, setApproveDialogOpen] = React.useState(false); const [rejectDialogOpen, setRejectDialogOpen] = React.useState(false); const [deleteDialogOpen, setDeleteDialogOpen] = React.useState(false); + const [applyIgnoreDialogOpen, setApplyIgnoreDialogOpen] = React.useState(false); + const [clearIgnoreDialogOpen, setClearIgnoreDialogOpen] = React.useState(false); + const [isProcessing, setIsProcessing] = React.useState(false); - const rows: Record = props.state.selection; - const count = Object.keys(rows).length; + const allRows: InternalRowsState = props.state.rows; + const selectedRows: Record = props.state.selection; + const count = Object.keys(selectedRows).length; const toggleApproveDialogOpen = () => { setApproveDialogOpen(!approveDialogOpen); @@ -27,21 +32,39 @@ export const BulkOperation: React.FunctionComponent = ( const toggleDeleteDialogOpen = () => { setDeleteDialogOpen(!deleteDialogOpen); }; + const toggleApplyIgnoreDialogOpen = () => { + setApplyIgnoreDialogOpen(!applyIgnoreDialogOpen); + }; + const toggleClearIgnoreDialogOpen = () => { + setClearIgnoreDialogOpen(!clearIgnoreDialogOpen); + }; const getTitle = () => { + if (applyIgnoreDialogOpen) { + return "Apply Selected Ignore Area To All Images"; + } + if (clearIgnoreDialogOpen) { + return "Clear Ignore Area For Selected Items"; + } return submitButtonText() + " Test Runs"; }; const submitButtonText = (): string => { - if (deleteDialogOpen) { - return "Delete"; - } if (approveDialogOpen) { return "Approve"; } if (rejectDialogOpen) { return "Reject"; } + if (deleteDialogOpen) { + return "Delete"; + } + if (applyIgnoreDialogOpen) { + return "Apply"; + } + if (clearIgnoreDialogOpen) { + return "Clear"; + } return ""; }; @@ -55,6 +78,12 @@ export const BulkOperation: React.FunctionComponent = ( if (rejectDialogOpen) { return toggleRejectDialogOpen(); } + if (applyIgnoreDialogOpen) { + return toggleApplyIgnoreDialogOpen(); + } + if (clearIgnoreDialogOpen) { + return toggleClearIgnoreDialogOpen(); + } }; const isRowEligibleForApproveOrReject = (id: string) => { @@ -72,6 +101,23 @@ export const BulkOperation: React.FunctionComponent = ( if (isRowEligibleForApproveOrReject(id)) { processApproveReject(id); } + if (clearIgnoreDialogOpen) { + testRunService.setIgnoreAreas(id, []); + } + if (applyIgnoreDialogOpen) { + const testRun = testRunService.getTestRunDetails(id); + let runningNumber = 0; + allRows.allRows.forEach(async (eachRow) => { + const ignoreAreaToSet: IgnoreArea[] = JSON.parse((await testRun).ignoreAreas); + if (ignoreAreaToSet.length > 0) { + //Add a running number to make id unique. + ignoreAreaToSet.forEach((e) => { + e.id = (Date.now() + (++runningNumber)).toString().slice(0, 13); + }); + testRunService.setIgnoreAreas(eachRow.toString(), ignoreAreaToSet); + } + }); + } }; const processApproveReject = (id: string) => { @@ -90,9 +136,22 @@ export const BulkOperation: React.FunctionComponent = ( if (approveDialogOpen) { return toggleApproveDialogOpen(); } + if (applyIgnoreDialogOpen) { + return toggleApplyIgnoreDialogOpen(); + } + if (clearIgnoreDialogOpen) { + return toggleClearIgnoreDialogOpen(); + } return toggleRejectDialogOpen(); }; + const getProcessSuccessMessage = () => { + if (applyIgnoreDialogOpen) { + return "Selected image ignore area has been applied to all images."; + } + return `${count} test runs processed.`; + }; + return ( <> @@ -116,28 +175,39 @@ export const BulkOperation: React.FunctionComponent = ( + + + + + + + + + + + + + + {`Are you sure you want to ${submitButtonText().toLowerCase()} ${count} items?`} + {applyIgnoreDialogOpen + ? `Are you sure you want to apply ignore area to all images? Works well if images are of same resolution.` + : `Are you sure you want to ${submitButtonText().toLowerCase()} ${count} items?`} } onSubmit={() => { - enqueueSnackbar( - "Wait for the confirmation message until operation is completed.", - { - variant: "info", - } - ); - + setIsProcessing(true); Promise.all( - Object.keys(rows).map((id: string) => processAction(id)) + Object.keys(selectedRows).map((id: string) => processAction(id)) ) .then(() => { - enqueueSnackbar(`${count} test runs processed.`, { + setIsProcessing(false); + enqueueSnackbar(getProcessSuccessMessage(), { variant: "success", }); }) @@ -149,6 +219,7 @@ export const BulkOperation: React.FunctionComponent = ( closeModal(); }} /> + { isProcessing && } ); }; diff --git a/src/services/testRun.service.ts b/src/services/testRun.service.ts index 93062102..a3ef9a8a 100644 --- a/src/services/testRun.service.ts +++ b/src/services/testRun.service.ts @@ -67,6 +67,18 @@ async function setIgnoreAreas( ).then(handleResponse); } +async function getTestRunDetails(id: string): Promise { + const requestOptions = { + method: "GET", + headers: authHeader(), + }; + + return fetch( + `${API_URL}${ENDPOINT_URL}/${id}`, + requestOptions + ).then(handleResponse); +} + async function setComment(id: string, comment: string): Promise { const requestOptions = { method: "PUT", @@ -84,6 +96,7 @@ export const testRunService = { remove, approve, reject, + getTestRunDetails, setIgnoreAreas, setComment, }; From d1b59ea455bd99d8a6272899736e5446cfc06bbc Mon Sep 17 00:00:00 2001 From: Surat Das Date: Sat, 19 Jun 2021 19:32:30 -0700 Subject: [PATCH 2/2] Added clear ignroe from details view and removed bulk apply logic --- src/components/TestDetailsModal.tsx | 16 ++++- src/components/TestRunList/BulkOperation.tsx | 66 +++++--------------- src/services/testRun.service.ts | 13 ---- 3 files changed, 28 insertions(+), 67 deletions(-) diff --git a/src/components/TestDetailsModal.tsx b/src/components/TestDetailsModal.tsx index 8631ab59..c6dced5b 100644 --- a/src/components/TestDetailsModal.tsx +++ b/src/components/TestDetailsModal.tsx @@ -25,7 +25,7 @@ import { TestStatus } from "../types/testStatus"; import { useHistory, Prompt } from "react-router-dom"; import { IgnoreArea } from "../types/ignoreArea"; import { KonvaEventObject } from "konva/types/Node"; -import { Close, Add, Delete, Save, WarningRounded } from "@material-ui/icons"; +import { Close, Add, Delete, Save, WarningRounded, LayersClear } from "@material-ui/icons"; import { TestRunDetails } from "./TestRunDetails"; import useImage from "use-image"; import { routes } from "../constants"; @@ -330,7 +330,7 @@ const TestDetailsModal: React.FunctionComponent<{ selectedRectId && deleteIgnoreArea(selectedRectId) } @@ -338,6 +338,18 @@ const TestDetailsModal: React.FunctionComponent<{ + + + + setIgnoreAreas([]) + } + > + + + + = ( const [approveDialogOpen, setApproveDialogOpen] = React.useState(false); const [rejectDialogOpen, setRejectDialogOpen] = React.useState(false); const [deleteDialogOpen, setDeleteDialogOpen] = React.useState(false); - const [applyIgnoreDialogOpen, setApplyIgnoreDialogOpen] = React.useState(false); const [clearIgnoreDialogOpen, setClearIgnoreDialogOpen] = React.useState(false); const [isProcessing, setIsProcessing] = React.useState(false); @@ -32,17 +31,11 @@ export const BulkOperation: React.FunctionComponent = ( const toggleDeleteDialogOpen = () => { setDeleteDialogOpen(!deleteDialogOpen); }; - const toggleApplyIgnoreDialogOpen = () => { - setApplyIgnoreDialogOpen(!applyIgnoreDialogOpen); - }; const toggleClearIgnoreDialogOpen = () => { setClearIgnoreDialogOpen(!clearIgnoreDialogOpen); }; const getTitle = () => { - if (applyIgnoreDialogOpen) { - return "Apply Selected Ignore Area To All Images"; - } if (clearIgnoreDialogOpen) { return "Clear Ignore Area For Selected Items"; } @@ -59,9 +52,6 @@ export const BulkOperation: React.FunctionComponent = ( if (deleteDialogOpen) { return "Delete"; } - if (applyIgnoreDialogOpen) { - return "Apply"; - } if (clearIgnoreDialogOpen) { return "Clear"; } @@ -78,9 +68,6 @@ export const BulkOperation: React.FunctionComponent = ( if (rejectDialogOpen) { return toggleRejectDialogOpen(); } - if (applyIgnoreDialogOpen) { - return toggleApplyIgnoreDialogOpen(); - } if (clearIgnoreDialogOpen) { return toggleClearIgnoreDialogOpen(); } @@ -104,20 +91,6 @@ export const BulkOperation: React.FunctionComponent = ( if (clearIgnoreDialogOpen) { testRunService.setIgnoreAreas(id, []); } - if (applyIgnoreDialogOpen) { - const testRun = testRunService.getTestRunDetails(id); - let runningNumber = 0; - allRows.allRows.forEach(async (eachRow) => { - const ignoreAreaToSet: IgnoreArea[] = JSON.parse((await testRun).ignoreAreas); - if (ignoreAreaToSet.length > 0) { - //Add a running number to make id unique. - ignoreAreaToSet.forEach((e) => { - e.id = (Date.now() + (++runningNumber)).toString().slice(0, 13); - }); - testRunService.setIgnoreAreas(eachRow.toString(), ignoreAreaToSet); - } - }); - } }; const processApproveReject = (id: string) => { @@ -136,22 +109,12 @@ export const BulkOperation: React.FunctionComponent = ( if (approveDialogOpen) { return toggleApproveDialogOpen(); } - if (applyIgnoreDialogOpen) { - return toggleApplyIgnoreDialogOpen(); - } if (clearIgnoreDialogOpen) { return toggleClearIgnoreDialogOpen(); } return toggleRejectDialogOpen(); }; - const getProcessSuccessMessage = () => { - if (applyIgnoreDialogOpen) { - return "Selected image ignore area has been applied to all images."; - } - return `${count} test runs processed.`; - }; - return ( <> @@ -175,30 +138,29 @@ export const BulkOperation: React.FunctionComponent = ( - - - - - - - - + - + {applyIgnoreDialogOpen - ? `Are you sure you want to apply ignore area to all images? Works well if images are of same resolution.` - : `Are you sure you want to ${submitButtonText().toLowerCase()} ${count} items?`} + + {`Are you sure you want to ${submitButtonText().toLowerCase()} ${count} items?`} + } onSubmit={() => { setIsProcessing(true); @@ -207,7 +169,7 @@ export const BulkOperation: React.FunctionComponent = ( ) .then(() => { setIsProcessing(false); - enqueueSnackbar(getProcessSuccessMessage(), { + enqueueSnackbar(`${count} test runs processed.`, { variant: "success", }); }) diff --git a/src/services/testRun.service.ts b/src/services/testRun.service.ts index a3ef9a8a..93062102 100644 --- a/src/services/testRun.service.ts +++ b/src/services/testRun.service.ts @@ -67,18 +67,6 @@ async function setIgnoreAreas( ).then(handleResponse); } -async function getTestRunDetails(id: string): Promise { - const requestOptions = { - method: "GET", - headers: authHeader(), - }; - - return fetch( - `${API_URL}${ENDPOINT_URL}/${id}`, - requestOptions - ).then(handleResponse); -} - async function setComment(id: string, comment: string): Promise { const requestOptions = { method: "PUT", @@ -96,7 +84,6 @@ export const testRunService = { remove, approve, reject, - getTestRunDetails, setIgnoreAreas, setComment, };