From d8c1e96e59cb7fa329a8ace0b782985dc8e7acc8 Mon Sep 17 00:00:00 2001 From: Pavel Strunkin Date: Wed, 30 Jun 2021 15:07:00 +0300 Subject: [PATCH 1/3] bulk --- src/components/ApproveRejectButtons.tsx | 4 +- src/components/TestDetailsModal.tsx | 28 ++---- src/components/TestRunList/BulkOperation.tsx | 93 +++++++++++++------- src/services/testRun.service.ts | 66 ++++++++------ src/services/testVariation.service.ts | 31 ------- src/types/ignoreArea.ts | 5 ++ 6 files changed, 115 insertions(+), 112 deletions(-) diff --git a/src/components/ApproveRejectButtons.tsx b/src/components/ApproveRejectButtons.tsx index ab6c28d2..1a4cfd75 100644 --- a/src/components/ApproveRejectButtons.tsx +++ b/src/components/ApproveRejectButtons.tsx @@ -12,7 +12,7 @@ export const ApproveRejectButtons: React.FunctionComponent<{ const approve = () => { testRunService - .approve(testRun.id, testRun.merge) + .approveBulk([testRun.id], testRun.merge) .then(() => enqueueSnackbar("Approved", { variant: "success", @@ -27,7 +27,7 @@ export const ApproveRejectButtons: React.FunctionComponent<{ const reject = () => { testRunService - .reject(testRun.id) + .rejectBulk([testRun.id]) .then(() => enqueueSnackbar("Rejected", { variant: "success", diff --git a/src/components/TestDetailsModal.tsx b/src/components/TestDetailsModal.tsx index 41b28e34..d984fb9d 100644 --- a/src/components/TestDetailsModal.tsx +++ b/src/components/TestDetailsModal.tsx @@ -16,11 +16,7 @@ import { import { ToggleButton } from "@material-ui/lab"; import { useHotkeys } from "react-hotkeys-hook"; import { TestRun } from "../types"; -import { - testRunService, - testVariationService, - staticService, -} from "../services"; +import { testRunService, staticService } from "../services"; import { TestStatus } from "../types/testStatus"; import { useHistory, Prompt } from "react-router-dom"; import { IgnoreArea } from "../types/ignoreArea"; @@ -112,12 +108,11 @@ const TestDetailsModal: React.FunctionComponent<{ }; const saveTestRun = (ignoreAreas: IgnoreArea[], successMessage: string) => { - Promise.all([ - // update in test run - testRunService.setIgnoreAreas(testRun.id, ignoreAreas), - // update in variation - testVariationService.setIgnoreAreas(testRun.testVariationId, ignoreAreas), - ]) + testRunService + .updateIgnoreAreas({ + ids: [testRun.id], + ignoreAreas: ignoreAreas, + }) .then(() => { enqueueSnackbar(successMessage, { variant: "success", @@ -349,15 +344,8 @@ const TestDetailsModal: React.FunctionComponent<{ - Promise.all([ - // update in test run - testRunService.setComment(testRun.id, comment), - // update in variation - testVariationService.setComment( - testRun.testVariationId, - comment - ), - ]) + testRunService + .setComment(testRun.id, comment) .then(() => enqueueSnackbar("Comment updated", { variant: "success", diff --git a/src/components/TestRunList/BulkOperation.tsx b/src/components/TestRunList/BulkOperation.tsx index d72e7838..85bbc276 100644 --- a/src/components/TestRunList/BulkOperation.tsx +++ b/src/components/TestRunList/BulkOperation.tsx @@ -1,12 +1,17 @@ import React from "react"; -import { Typography, IconButton, Tooltip, LinearProgress } from "@material-ui/core"; -import { BaseComponentProps, InternalRowsState, RowModel } from "@material-ui/data-grid"; +import { + Typography, + IconButton, + Tooltip, + LinearProgress, +} from "@material-ui/core"; +import { BaseComponentProps, RowModel } from "@material-ui/data-grid"; import { BaseModal } from "../BaseModal"; import { useSnackbar } from "notistack"; import { Delete, LayersClear, ThumbDown, ThumbUp } from "@material-ui/icons"; import { testRunService } from "../../services"; import { TestStatus } from "../../types"; -import { IgnoreArea } from "../../types/ignoreArea"; +import { head } from "lodash"; export const BulkOperation: React.FunctionComponent = ( props: BaseComponentProps @@ -15,10 +20,39 @@ export const BulkOperation: React.FunctionComponent = ( const [approveDialogOpen, setApproveDialogOpen] = React.useState(false); const [rejectDialogOpen, setRejectDialogOpen] = React.useState(false); const [deleteDialogOpen, setDeleteDialogOpen] = React.useState(false); - const [clearIgnoreDialogOpen, setClearIgnoreDialogOpen] = React.useState(false); + const [clearIgnoreDialogOpen, setClearIgnoreDialogOpen] = React.useState( + false + ); const [isProcessing, setIsProcessing] = React.useState(false); + const ids: string[] = React.useMemo( + () => Object.keys(props.state.selection), + [props.state.selection] + ); + const isMerge: boolean = React.useMemo( + () => + !!head( + props.rows.filter((value: RowModel) => + ids.includes(value.id.toString()) + ) + )?.merge, + // eslint-disable-next-line + [ids] + ); + const idsEligibleForApproveOrReject: string[] = React.useMemo( + () => + props.rows + .filter( + (value: RowModel) => + ids.includes(value.id.toString()) && + [TestStatus.new, TestStatus.unresolved].includes( + value.status.toString() + ) + ) + .map((value: RowModel) => value.id.toString()), + // eslint-disable-next-line + [ids] + ); - const allRows: InternalRowsState = props.state.rows; const selectedRows: Record = props.state.selection; const count = Object.keys(selectedRows).length; @@ -73,33 +107,20 @@ export const BulkOperation: React.FunctionComponent = ( } }; - const isRowEligibleForApproveOrReject = (id: string) => { - //Find the test status of the current row - let currentRow: any = props.rows.find((value: RowModel) => value.id.toString().includes(id)); - let currentRowStatus = JSON.stringify(currentRow.status); - //In line with how we can approve/reject only new and unresolved from details modal. - return (currentRowStatus.includes(TestStatus.new) || currentRowStatus.includes(TestStatus.unresolved)); - }; - - const processAction = (id: string) => { + const getBulkAction = () => { if (deleteDialogOpen) { - testRunService.remove(id); + return testRunService.removeBulk(ids); } - if (isRowEligibleForApproveOrReject(id)) { - processApproveReject(id); - } - if (clearIgnoreDialogOpen) { - testRunService.setIgnoreAreas(id, []); + if (rejectDialogOpen) { + return testRunService.rejectBulk(idsEligibleForApproveOrReject); } - }; - - const processApproveReject = (id: string) => { if (approveDialogOpen) { - testRunService.approve(id, false); - } - if (rejectDialogOpen) { - testRunService.reject(id); + return testRunService.approveBulk(idsEligibleForApproveOrReject, isMerge); } + return testRunService.updateIgnoreAreas({ + ids, + ignoreAreas: [], + }); }; const dismissDialog = () => { @@ -117,7 +138,10 @@ export const BulkOperation: React.FunctionComponent = ( return ( <> - + @@ -153,7 +177,12 @@ export const BulkOperation: React.FunctionComponent = ( = ( } onSubmit={() => { setIsProcessing(true); - Promise.all( - Object.keys(selectedRows).map((id: string) => processAction(id)) - ) + getBulkAction() .then(() => { setIsProcessing(false); enqueueSnackbar(`${count} test runs processed.`, { @@ -181,7 +208,7 @@ export const BulkOperation: React.FunctionComponent = ( closeModal(); }} /> - { isProcessing && } + {isProcessing && } ); }; diff --git a/src/services/testRun.service.ts b/src/services/testRun.service.ts index 93062102..e8063bfe 100644 --- a/src/services/testRun.service.ts +++ b/src/services/testRun.service.ts @@ -1,7 +1,7 @@ import { TestRun } from "../types"; import { handleResponse, authHeader } from "../_helpers/service.helpers"; import { API_URL } from "../_config/env.config"; -import { IgnoreArea } from "../types/ignoreArea"; +import { UpdateIgnoreAreaDto } from "../types/ignoreArea"; const ENDPOINT_URL = "/test-runs"; @@ -17,52 +17,65 @@ async function getList(buildId: string): Promise { ).then(handleResponse); } -async function remove(id: string): Promise { +async function removeBulk(ids: string[]): Promise { const requestOptions = { - method: "DELETE", - headers: authHeader(), + method: "POST", + headers: { "Content-Type": "application/json", ...authHeader() }, + body: JSON.stringify(ids), }; - return fetch(`${API_URL}${ENDPOINT_URL}/${id}`, requestOptions).then( + return fetch(`${API_URL}${ENDPOINT_URL}/delete`, requestOptions).then( handleResponse ); } -async function approve(id: string, merge: boolean): Promise { +async function rejectBulk(ids: string[]): Promise { const requestOptions = { - method: "GET", - headers: authHeader(), + method: "POST", + headers: { "Content-Type": "application/json", ...authHeader() }, + body: JSON.stringify(ids), + }; + + return fetch(`${API_URL}${ENDPOINT_URL}/reject`, requestOptions).then( + handleResponse + ); +} + +async function approveBulk(ids: string[], merge: boolean): Promise { + const requestOptions = { + method: "POST", + headers: { "Content-Type": "application/json", ...authHeader() }, + body: JSON.stringify(ids), }; return fetch( - `${API_URL}${ENDPOINT_URL}/approve?id=${id}&merge=${merge}`, + `${API_URL}${ENDPOINT_URL}/approve?merge=${merge}`, requestOptions ).then(handleResponse); } -async function reject(id: string): Promise { +async function updateIgnoreAreas(data: UpdateIgnoreAreaDto): Promise { const requestOptions = { - method: "GET", - headers: authHeader(), + method: "POST", + headers: { "Content-Type": "application/json", ...authHeader() }, + body: JSON.stringify(data), }; - return fetch(`${API_URL}${ENDPOINT_URL}/reject/${id}`, requestOptions).then( - handleResponse - ); + return fetch( + `${API_URL}${ENDPOINT_URL}/ignoreAreas/update`, + requestOptions + ).then(handleResponse); } -async function setIgnoreAreas( - id: string, - ignoreAreas: IgnoreArea[] -): Promise { +async function addIgnoreAreas(data: UpdateIgnoreAreaDto): Promise { const requestOptions = { - method: "PUT", + method: "POST", headers: { "Content-Type": "application/json", ...authHeader() }, - body: JSON.stringify(ignoreAreas), + body: JSON.stringify(data), }; return fetch( - `${API_URL}${ENDPOINT_URL}/ignoreArea/${id}`, + `${API_URL}${ENDPOINT_URL}/ignoreAreas/add`, requestOptions ).then(handleResponse); } @@ -81,9 +94,10 @@ async function setComment(id: string, comment: string): Promise { export const testRunService = { getList, - remove, - approve, - reject, - setIgnoreAreas, + removeBulk, + rejectBulk, + approveBulk, + updateIgnoreAreas, + addIgnoreAreas, setComment, }; diff --git a/src/services/testVariation.service.ts b/src/services/testVariation.service.ts index 7c4ab06a..c704f872 100644 --- a/src/services/testVariation.service.ts +++ b/src/services/testVariation.service.ts @@ -1,7 +1,6 @@ import { TestVariation, Build } from "../types"; import { handleResponse, authHeader } from "../_helpers/service.helpers"; import { API_URL } from "../_config/env.config"; -import { IgnoreArea } from "../types/ignoreArea"; const ENDPOINT_URL = "/test-variations"; @@ -28,34 +27,6 @@ async function getDetails(id: String): Promise { ); } -async function setIgnoreAreas( - variationId: string, - ignoreAreas: IgnoreArea[] -): Promise { - const requestOptions = { - method: "PUT", - headers: { "Content-Type": "application/json", ...authHeader() }, - body: JSON.stringify(ignoreAreas), - }; - - return fetch( - `${API_URL}${ENDPOINT_URL}/ignoreArea/${variationId}`, - requestOptions - ).then(handleResponse); -} - -async function setComment(id: string, comment: string): Promise { - const requestOptions = { - method: "PUT", - headers: { "Content-Type": "application/json", ...authHeader() }, - body: JSON.stringify({ comment }), - }; - - return fetch(`${API_URL}${ENDPOINT_URL}/comment/${id}`, requestOptions).then( - handleResponse - ); -} - async function merge(projectId: String, branchName: String): Promise { const requestOptions = { method: "GET", @@ -82,8 +53,6 @@ async function remove(id: String): Promise { export const testVariationService = { getList, getDetails, - setIgnoreAreas, - setComment, merge, remove, }; diff --git a/src/types/ignoreArea.ts b/src/types/ignoreArea.ts index 7f9377ca..a17aafca 100644 --- a/src/types/ignoreArea.ts +++ b/src/types/ignoreArea.ts @@ -5,3 +5,8 @@ export interface IgnoreArea { width: number; height: number; } + +export interface UpdateIgnoreAreaDto { + ids: string[]; + ignoreAreas: IgnoreArea[]; +} From 1571045abbdafcd5690ee28267034975f5dad568 Mon Sep 17 00:00:00 2001 From: Pavlo Strunkin Date: Thu, 1 Jul 2021 12:09:59 +0300 Subject: [PATCH 2/3] updated --- src/components/TestDetailsModal.tsx | 2 +- src/services/testRun.service.ts | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/TestDetailsModal.tsx b/src/components/TestDetailsModal.tsx index d984fb9d..2944bafd 100644 --- a/src/components/TestDetailsModal.tsx +++ b/src/components/TestDetailsModal.tsx @@ -345,7 +345,7 @@ const TestDetailsModal: React.FunctionComponent<{ text={testRun.comment} onSave={(comment) => testRunService - .setComment(testRun.id, comment) + .update(testRun.id, { comment }) .then(() => enqueueSnackbar("Comment updated", { variant: "success", diff --git a/src/services/testRun.service.ts b/src/services/testRun.service.ts index e8063bfe..69bb6085 100644 --- a/src/services/testRun.service.ts +++ b/src/services/testRun.service.ts @@ -80,11 +80,11 @@ async function addIgnoreAreas(data: UpdateIgnoreAreaDto): Promise { ).then(handleResponse); } -async function setComment(id: string, comment: string): Promise { +async function update(id: string, data: { comment: string }): Promise { const requestOptions = { method: "PUT", headers: { "Content-Type": "application/json", ...authHeader() }, - body: JSON.stringify({ comment }), + body: JSON.stringify(data), }; return fetch(`${API_URL}${ENDPOINT_URL}/comment/${id}`, requestOptions).then( @@ -99,5 +99,5 @@ export const testRunService = { approveBulk, updateIgnoreAreas, addIgnoreAreas, - setComment, + update, }; From 06bb127e72eaf37263f3a6be9ed3be6fd73db507 Mon Sep 17 00:00:00 2001 From: Pavlo Strunkin Date: Thu, 1 Jul 2021 12:19:19 +0300 Subject: [PATCH 3/3] Update TestDetailsModal.tsx --- src/components/TestDetailsModal.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/TestDetailsModal.tsx b/src/components/TestDetailsModal.tsx index 2944bafd..2b88a6aa 100644 --- a/src/components/TestDetailsModal.tsx +++ b/src/components/TestDetailsModal.tsx @@ -111,7 +111,7 @@ const TestDetailsModal: React.FunctionComponent<{ testRunService .updateIgnoreAreas({ ids: [testRun.id], - ignoreAreas: ignoreAreas, + ignoreAreas, }) .then(() => { enqueueSnackbar(successMessage, {