From a10f58479a4cbc535a919c921bdad5c9d23f7c02 Mon Sep 17 00:00:00 2001 From: Pavel Strunkin Date: Thu, 25 Jun 2020 22:22:38 +0200 Subject: [PATCH 1/4] DrawArea. Show no image in case image is deleted --- src/components/DrawArea.tsx | 214 ++++++++++++++++++------------------ 1 file changed, 106 insertions(+), 108 deletions(-) diff --git a/src/components/DrawArea.tsx b/src/components/DrawArea.tsx index c0d82ba6..6904166d 100644 --- a/src/components/DrawArea.tsx +++ b/src/components/DrawArea.tsx @@ -75,7 +75,7 @@ export const DrawArea: FunctionComponent = ({ const [isDrawMode, setIsDrawMode] = drawModeState; const [isDrawing, setIsDrawing] = React.useState(isDrawMode); - const [image, loading] = useImage(staticService.getImage(imageName)); + const [image, imageStatus] = useImage(staticService.getImage(imageName)); const handleContentMousedown = (e: any) => { if (!isDrawMode) return; @@ -126,124 +126,122 @@ export const DrawArea: FunctionComponent = ({ - {imageName ? ( - loading === "loading" ? ( - - - - + {imageStatus === "loading" && ( + + + - ) : ( - + + )} + {(!imageName || imageStatus === "failed") && } + {imageName && imageStatus === "loaded" && ( + +
{ + if (!isDrawMode && isDrag && !selectedRectId) { + event.preventDefault(); + setStagePos({ + x: event.clientX - stageInitPos.x, + y: event.clientY - stageInitPos.y, + }); + setStageOffset(stagePos); + } + }} + onMouseUp={(event) => { + setIsDrag(false); + setStageInitPos(stagePos); + }} + onMouseLeave={(event) => { + setIsDrag(false); + setStageInitPos(stagePos); + }} + onMouseDown={(event) => { + setIsDrag(true); + setStageInitPos({ + x: event.clientX - stageOffset.x, + y: event.clientY - stageOffset.y, + }); }} > -
{ - if (!isDrawMode && isDrag && !selectedRectId) { - event.preventDefault(); - setStagePos({ - x: event.clientX - stageInitPos.x, - y: event.clientY - stageInitPos.y, - }); - setStageOffset(stagePos); - } - }} - onMouseUp={(event) => { - setIsDrag(false); - setStageInitPos(stagePos); - }} - onMouseLeave={(event) => { - setIsDrag(false); - setStageInitPos(stagePos); - }} - onMouseDown={(event) => { - setIsDrag(true); - setStageInitPos({ - x: event.clientX - stageOffset.x, - y: event.clientY - stageOffset.y, - }); + transform: `scale(${stageScale})`, + transformOrigin: "top left", }} + onContentMousedown={handleContentMousedown} + onContentMouseup={handleContentMouseup} + onContentMouseMove={handleContentMouseMove} > - - - { - document.body.style.cursor = isDrawMode - ? "crosshair" - : "grab"; - }} - onMouseDown={(event) => { - document.body.style.cursor = "grabbing"; - }} - onMouseUp={(event) => { - document.body.style.cursor = "grab"; - }} - onMouseLeave={(event) => { - document.body.style.cursor = "default"; - }} - /> - {ignoreAreas.map((rect, i) => { - return ( - setSelectedRectId(rect.id)} - onChange={(newAttrs: RectConfig) => { - const rects = ignoreAreas.slice(); + + { + document.body.style.cursor = isDrawMode + ? "crosshair" + : "grab"; + }} + onMouseDown={(event) => { + document.body.style.cursor = "grabbing"; + }} + onMouseUp={(event) => { + document.body.style.cursor = "grab"; + }} + onMouseLeave={(event) => { + document.body.style.cursor = "default"; + }} + /> + {ignoreAreas.map((rect, i) => { + return ( + setSelectedRectId(rect.id)} + onChange={(newAttrs: RectConfig) => { + const rects = ignoreAreas.slice(); - rects[i].x = Math.round(newAttrs.x || 0); - rects[i].y = Math.round(newAttrs.y || 0); - rects[i].width = Math.round( - newAttrs.width || MIN_RECT_SIDE_PIXEL - ); - rects[i].height = Math.round( - newAttrs.height || MIN_RECT_SIDE_PIXEL - ); + rects[i].x = Math.round(newAttrs.x || 0); + rects[i].y = Math.round(newAttrs.y || 0); + rects[i].width = Math.round( + newAttrs.width || MIN_RECT_SIDE_PIXEL + ); + rects[i].height = Math.round( + newAttrs.height || MIN_RECT_SIDE_PIXEL + ); - setIgnoreAreas(rects); - }} - /> - ); - })} - - -
+ setIgnoreAreas(rects); + }} + /> + ); + })} + +
- - ) - ) : ( - +
+
)}
From a138d3e9d977dc27a170da120943f13e00acf548 Mon Sep 17 00:00:00 2001 From: Pavel Strunkin Date: Fri, 26 Jun 2020 23:52:32 +0200 Subject: [PATCH 2/4] material-ui-popup-state added --- package-lock.json | 26 +++++++++++++++ package.json | 1 + src/components/CommentsPopper.tsx | 49 +++++++++++++++++++++++++++++ src/components/TestDetailsModal.tsx | 4 +++ 4 files changed, 80 insertions(+) create mode 100644 src/components/CommentsPopper.tsx diff --git a/package-lock.json b/package-lock.json index 7f6ec13e..e8165d0c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3714,6 +3714,11 @@ } } }, + "classnames": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.2.6.tgz", + "integrity": "sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q==" + }, "clean-css": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.3.tgz", @@ -8868,6 +8873,27 @@ "object-visit": "^1.0.0" } }, + "material-ui-popup-state": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/material-ui-popup-state/-/material-ui-popup-state-1.6.1.tgz", + "integrity": "sha512-I1Cu8hc3RPPTZ7p946q6qQB+n68JuhoiOxclV+wft8bplYGHFLjbNmF59wQMTN6oRZD42QuVtTxDv7LIi0eB8w==", + "requires": { + "@babel/runtime": "^7.1.5", + "@material-ui/types": "^4.1.1", + "classnames": "^2.2.6", + "prop-types": "^15.0.0" + }, + "dependencies": { + "@material-ui/types": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@material-ui/types/-/types-4.1.1.tgz", + "integrity": "sha512-AN+GZNXytX9yxGi0JOfxHrRTbhFybjUJ05rnsBVjcB+16e466Z0Xe5IxawuOayVZgTBNDxmPKo5j4V6OnMtaSQ==", + "requires": { + "@types/react": "*" + } + } + } + }, "md5.js": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", diff --git a/package.json b/package.json index 914345d6..5332f06f 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "@testing-library/react": "^9.5.0", "@testing-library/user-event": "^7.2.1", "konva": "^4.2.2", + "material-ui-popup-state": "^1.6.1", "qs": "^6.9.4", "react": "^16.13.1", "react-debounce-input": "^3.2.2", diff --git a/src/components/CommentsPopper.tsx b/src/components/CommentsPopper.tsx new file mode 100644 index 00000000..76b50601 --- /dev/null +++ b/src/components/CommentsPopper.tsx @@ -0,0 +1,49 @@ +import React from "react"; +import { + Button, + Popper, + Fade, + Paper, + Typography, + Box, + makeStyles, +} from "@material-ui/core"; +import { + usePopupState, + bindToggle, + bindPopper, +} from "material-ui-popup-state/hooks"; + +const useStyles = makeStyles((theme) => ({ + popperContainer: { + zIndex: 1400, + }, +})); + +export const CommentsPopper = () => { + const classes = useStyles(); + const popupState = usePopupState({ + variant: "popper", + popupId: "demoPopper", + }); + return ( + + + + {({ TransitionProps }) => ( + + + The content of the Popper. + + + )} + + + ); +}; diff --git a/src/components/TestDetailsModal.tsx b/src/components/TestDetailsModal.tsx index 6ed53d6c..0f0a8372 100644 --- a/src/components/TestDetailsModal.tsx +++ b/src/components/TestDetailsModal.tsx @@ -37,6 +37,7 @@ import useImage from "use-image"; import { routes } from "../constants"; import { useTestRunDispatch, updateTestRun, selectTestRun } from "../contexts"; import { DrawArea } from "./DrawArea"; +import { CommentsPopper } from "./CommentsPopper"; const useStyles = makeStyles((theme) => ({ imageContainer: { @@ -202,6 +203,9 @@ const TestDetailsModal: React.FunctionComponent<{ Baseline history
+ + + From 761364da00c9e85ca87526d4b1a42234be3beeae Mon Sep 17 00:00:00 2001 From: Pavel Strunkin Date: Sat, 27 Jun 2020 12:56:49 +0200 Subject: [PATCH 3/4] CommentsPopper added --- src/components/CommentsPopper.tsx | 61 ++++++++++++++++++++++++----- src/components/TestDetailsModal.tsx | 2 +- src/types/testRun.ts | 1 + src/types/testVariation.ts | 3 +- 4 files changed, 56 insertions(+), 11 deletions(-) diff --git a/src/components/CommentsPopper.tsx b/src/components/CommentsPopper.tsx index 76b50601..c6aeaf44 100644 --- a/src/components/CommentsPopper.tsx +++ b/src/components/CommentsPopper.tsx @@ -4,42 +4,85 @@ import { Popper, Fade, Paper, - Typography, - Box, makeStyles, + TextField, + Badge, + IconButton, } from "@material-ui/core"; import { usePopupState, bindToggle, bindPopper, } from "material-ui-popup-state/hooks"; +import { Comment } from "@material-ui/icons"; const useStyles = makeStyles((theme) => ({ popperContainer: { zIndex: 1400, }, + contentContainer: { + padding: theme.spacing(2), + }, })); -export const CommentsPopper = () => { +interface IProps { + text: string; +} + +export const CommentsPopper: React.FunctionComponent = ({ text }) => { const classes = useStyles(); const popupState = usePopupState({ variant: "popper", - popupId: "demoPopper", + popupId: "commentPopper", }); + const [comment, setComment] = React.useState(text); + return ( - + + + + + {({ TransitionProps }) => ( - - The content of the Popper. + + + + setComment((event.target as HTMLInputElement).value) + } + inputProps={{ + "data-testid": "comment", + }} + /> + + )} diff --git a/src/components/TestDetailsModal.tsx b/src/components/TestDetailsModal.tsx index 0f0a8372..ef8fde1b 100644 --- a/src/components/TestDetailsModal.tsx +++ b/src/components/TestDetailsModal.tsx @@ -204,7 +204,7 @@ const TestDetailsModal: React.FunctionComponent<{ - + diff --git a/src/types/testRun.ts b/src/types/testRun.ts index 0164bc55..a7bfa0ff 100644 --- a/src/types/testRun.ts +++ b/src/types/testRun.ts @@ -16,4 +16,5 @@ export interface TestRun { viewport: string; device: string; ignoreAreas: string; + comment: string; } diff --git a/src/types/testVariation.ts b/src/types/testVariation.ts index 2a75a30e..4a8846d5 100644 --- a/src/types/testVariation.ts +++ b/src/types/testVariation.ts @@ -10,5 +10,6 @@ export interface TestVariation { device: string; ignoreAreas: string; projectId: string; - baselines: Baseline[] + baselines: Baseline[]; + comment: string; } From 6337a27bf8fcbbf2f2eb4104e7370e6660aac9f1 Mon Sep 17 00:00:00 2001 From: Pavel Strunkin Date: Sat, 27 Jun 2020 15:50:08 +0200 Subject: [PATCH 4/4] save added --- src/components/CommentsPopper.tsx | 14 ++++++++++---- src/components/TestDetailsModal.tsx | 15 +++++++++++++- src/services/testRun.service.ts | 13 +++++++++++++ src/services/testVariation.service.ts | 28 ++++++++++++++++++++++----- src/types/testRun.ts | 2 +- src/types/testVariation.ts | 2 +- 6 files changed, 62 insertions(+), 12 deletions(-) diff --git a/src/components/CommentsPopper.tsx b/src/components/CommentsPopper.tsx index c6aeaf44..bc6cda12 100644 --- a/src/components/CommentsPopper.tsx +++ b/src/components/CommentsPopper.tsx @@ -26,16 +26,22 @@ const useStyles = makeStyles((theme) => ({ })); interface IProps { - text: string; + text: string | undefined; + onSave: (comment: string) => Promise; } -export const CommentsPopper: React.FunctionComponent = ({ text }) => { +export const CommentsPopper: React.FunctionComponent = ({ + text, + onSave, +}) => { const classes = useStyles(); const popupState = usePopupState({ variant: "popper", popupId: "commentPopper", }); - const [comment, setComment] = React.useState(text); + const [comment, setComment] = React.useState(""); + + React.useEffect(() => setComment(text ? text : ""), [text]); return ( @@ -77,7 +83,7 @@ export const CommentsPopper: React.FunctionComponent = ({ text }) => { /> - + + Promise.all([ + // update in test run + testRunService + .setComment(testRun.id, comment) + .then((testRun) => updateTestRun(testRunDispatch, testRun)), + // update in variation + testVariationService + .setComment(testRun.testVariationId, comment), + ]) + } + /> diff --git a/src/services/testRun.service.ts b/src/services/testRun.service.ts index bb1e1f61..ea586081 100644 --- a/src/services/testRun.service.ts +++ b/src/services/testRun.service.ts @@ -12,6 +12,7 @@ export const testRunService = { approve, reject, setIgnoreAreas, + setComment, }; function getList(buildId: string): Promise { @@ -86,3 +87,15 @@ function setIgnoreAreas( requestOptions ).then(handleResponse); } + +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 + ); +} diff --git a/src/services/testVariation.service.ts b/src/services/testVariation.service.ts index 7574fc51..5cd179ab 100644 --- a/src/services/testVariation.service.ts +++ b/src/services/testVariation.service.ts @@ -3,12 +3,13 @@ import { handleResponse, authHeader } from "../_helpers/service.helpers"; import { API_URL } from "../_config/api.config"; import { IgnoreArea } from "../types/ignoreArea"; -const ENDPOINT_URL = "/test-variations" +const ENDPOINT_URL = "/test-variations"; export const testVariationService = { getList, getDetails, - setIgnoreAreas + setIgnoreAreas, + setComment, }; function getList(projectId: String): Promise { @@ -17,7 +18,10 @@ function getList(projectId: String): Promise { headers: authHeader(), }; - return fetch(`${API_URL}${ENDPOINT_URL}?projectId=${projectId}`, requestOptions).then(handleResponse); + return fetch( + `${API_URL}${ENDPOINT_URL}?projectId=${projectId}`, + requestOptions + ).then(handleResponse); } function getDetails(id: String): Promise { @@ -26,7 +30,9 @@ function getDetails(id: String): Promise { headers: authHeader(), }; - return fetch(`${API_URL}${ENDPOINT_URL}/${id}`, requestOptions).then(handleResponse); + return fetch(`${API_URL}${ENDPOINT_URL}/${id}`, requestOptions).then( + handleResponse + ); } function setIgnoreAreas( @@ -43,4 +49,16 @@ function setIgnoreAreas( `${API_URL}${ENDPOINT_URL}/ignoreArea/${variationId}`, requestOptions ).then(handleResponse); -} \ No newline at end of file +} + +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 + ); +} diff --git a/src/types/testRun.ts b/src/types/testRun.ts index a7bfa0ff..9a36171b 100644 --- a/src/types/testRun.ts +++ b/src/types/testRun.ts @@ -16,5 +16,5 @@ export interface TestRun { viewport: string; device: string; ignoreAreas: string; - comment: string; + comment?: string; } diff --git a/src/types/testVariation.ts b/src/types/testVariation.ts index 4a8846d5..400ded41 100644 --- a/src/types/testVariation.ts +++ b/src/types/testVariation.ts @@ -11,5 +11,5 @@ export interface TestVariation { ignoreAreas: string; projectId: string; baselines: Baseline[]; - comment: string; + comment?: string; }