From 2fd5b1560d19aa8992b260fe71f2994488596e65 Mon Sep 17 00:00:00 2001 From: Pavel Strunkin Date: Sun, 7 Jun 2020 23:54:35 +0200 Subject: [PATCH 1/5] socket added --- package-lock.json | 232 +++++++++++++++++++++++++++- package.json | 4 +- src/components/TestDetailsModal.tsx | 4 - src/contexts/build.context.tsx | 93 ++--------- src/pages/ProjectPage.tsx | 21 ++- 5 files changed, 263 insertions(+), 91 deletions(-) diff --git a/package-lock.json b/package-lock.json index c8d8fe26..0bed57f3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "vrt-frontend", - "version": "0.0.3", + "version": "1.2.0", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -1944,6 +1944,12 @@ "@types/react": "*" } }, + "@types/socket.io-client": { + "version": "1.4.33", + "resolved": "https://registry.npmjs.org/@types/socket.io-client/-/socket.io-client-1.4.33.tgz", + "integrity": "sha512-m4LnxkljsI9fMsjwpW5QhRpMixo2BeeLpFmg0AE+sS4H1pzAd/cs/ftTiL60FLZgfFa8PFRPx5KsHu8O0bADKQ==", + "dev": true + }, "@types/stack-utils": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-1.0.1.tgz", @@ -2363,6 +2369,11 @@ } } }, + "after": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz", + "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=" + }, "aggregate-error": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.0.1.tgz", @@ -2535,6 +2546,11 @@ "es-abstract": "^1.17.0-next.1" } }, + "arraybuffer.slice": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz", + "integrity": "sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog==" + }, "arrify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", @@ -3051,6 +3067,11 @@ "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==" }, + "backo2": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", + "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=" + }, "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", @@ -3111,6 +3132,11 @@ } } }, + "base64-arraybuffer": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz", + "integrity": "sha1-c5JncZI7Whl0etZmqlzUv5xunOg=" + }, "base64-js": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz", @@ -3129,6 +3155,14 @@ "tweetnacl": "^0.14.3" } }, + "better-assert": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz", + "integrity": "sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI=", + "requires": { + "callsite": "1.0.0" + } + }, "big.js": { "version": "5.2.2", "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", @@ -3148,6 +3182,11 @@ "file-uri-to-path": "1.0.0" } }, + "blob": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.5.tgz", + "integrity": "sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig==" + }, "bluebird": { "version": "3.7.2", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", @@ -3470,6 +3509,11 @@ "caller-callsite": "^2.0.0" } }, + "callsite": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz", + "integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA=" + }, "callsites": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", @@ -3811,11 +3855,21 @@ "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=" }, + "component-bind": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz", + "integrity": "sha1-AMYIq33Nk4l8AAllGx06jh5zu9E=" + }, "component-emitter": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==" }, + "component-inherit": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz", + "integrity": "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM=" + }, "compose-function": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/compose-function/-/compose-function-3.0.3.tgz", @@ -4863,6 +4917,46 @@ "once": "^1.4.0" } }, + "engine.io-client": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.4.3.tgz", + "integrity": "sha512-0NGY+9hioejTEJCaSJZfWZLk4FPI9dN+1H1C4+wj2iuFba47UgZbJzfWs4aNFajnX/qAaYKbe2lLTfEEWzCmcw==", + "requires": { + "component-emitter": "~1.3.0", + "component-inherit": "0.0.3", + "debug": "~4.1.0", + "engine.io-parser": "~2.2.0", + "has-cors": "1.1.0", + "indexof": "0.0.1", + "parseqs": "0.0.5", + "parseuri": "0.0.5", + "ws": "~6.1.0", + "xmlhttprequest-ssl": "~1.5.4", + "yeast": "0.1.2" + }, + "dependencies": { + "ws": { + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/ws/-/ws-6.1.4.tgz", + "integrity": "sha512-eqZfL+NE/YQc1/ZynhojeV8q+H050oR8AZ2uIev7RU10svA9ZnJUddHcOUZTJLinZ9yEfdA2kSATS2qZK5fhJA==", + "requires": { + "async-limiter": "~1.0.0" + } + } + } + }, + "engine.io-parser": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.2.0.tgz", + "integrity": "sha512-6I3qD9iUxotsC5HEMuuGsKA0cXerGz+4uGcXQEkfBidgKf0amsjrrtwcbwK/nzpZBxclXlV7gGl9dgWvu4LF6w==", + "requires": { + "after": "0.8.2", + "arraybuffer.slice": "~0.0.7", + "base64-arraybuffer": "0.1.5", + "blob": "0.0.5", + "has-binary2": "~1.0.2" + } + }, "enhanced-resolve": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.1.1.tgz", @@ -5414,9 +5508,9 @@ "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" }, "eventemitter3": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.0.tgz", - "integrity": "sha512-qerSRB0p+UDEssxTtm6EDKcE7W4OaoisfIMl4CngyEhjpYglocpNg6UEqCvemdGhosAsg4sO2dXJOdyBifPGCg==" + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.4.tgz", + "integrity": "sha512-rlaVLnVxtxvoyLsQQFBx53YmXHDxRIzzTLbdfxqi4yocpSjAxXwkU0cScM5JgSKMqEhrZpnvQ2D9gjylR0AimQ==" }, "events": { "version": "3.1.0", @@ -6318,6 +6412,26 @@ } } }, + "has-binary2": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.3.tgz", + "integrity": "sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw==", + "requires": { + "isarray": "2.0.1" + }, + "dependencies": { + "isarray": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", + "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=" + } + } + }, + "has-cors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz", + "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=" + }, "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", @@ -6584,9 +6698,9 @@ "integrity": "sha1-ksnBN0w1CF912zWexWzCV8u5P6Q=" }, "http-proxy": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.0.tgz", - "integrity": "sha512-84I2iJM/n1d4Hdgc6y2+qY5mDaz2PUVjlg9znE9byl+q0uC3DeByqBGReQu5tpLK0TAqTIXScRUV+dg7+bUPpQ==", + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", "requires": { "eventemitter3": "^4.0.0", "follow-redirects": "^1.0.0", @@ -6717,6 +6831,11 @@ "resolved": "https://registry.npmjs.org/indexes-of/-/indexes-of-1.0.1.tgz", "integrity": "sha1-8w9xbI4r00bHtn0985FVZqfAVgc=" }, + "indexof": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", + "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=" + }, "infer-owner": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", @@ -9330,6 +9449,11 @@ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" }, + "object-component": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/object-component/-/object-component-0.0.3.tgz", + "integrity": "sha1-8MaapQ78lbhmwYb0AKM3acsvEpE=" + }, "object-copy": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", @@ -9716,6 +9840,22 @@ "resolved": "https://registry.npmjs.org/parse5/-/parse5-4.0.0.tgz", "integrity": "sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA==" }, + "parseqs": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.5.tgz", + "integrity": "sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0=", + "requires": { + "better-assert": "~1.0.0" + } + }, + "parseuri": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.5.tgz", + "integrity": "sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo=", + "requires": { + "better-assert": "~1.0.0" + } + }, "parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", @@ -12542,6 +12682,69 @@ "kind-of": "^3.2.0" } }, + "socket.io-client": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.3.0.tgz", + "integrity": "sha512-cEQQf24gET3rfhxZ2jJ5xzAOo/xhZwK+mOqtGRg5IowZsMgwvHwnf/mCRapAAkadhM26y+iydgwsXGObBB5ZdA==", + "requires": { + "backo2": "1.0.2", + "base64-arraybuffer": "0.1.5", + "component-bind": "1.0.0", + "component-emitter": "1.2.1", + "debug": "~4.1.0", + "engine.io-client": "~3.4.0", + "has-binary2": "~1.0.2", + "has-cors": "1.1.0", + "indexof": "0.0.1", + "object-component": "0.0.3", + "parseqs": "0.0.5", + "parseuri": "0.0.5", + "socket.io-parser": "~3.3.0", + "to-array": "0.1.4" + }, + "dependencies": { + "component-emitter": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=" + } + } + }, + "socket.io-parser": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.3.0.tgz", + "integrity": "sha512-hczmV6bDgdaEbVqhAeVMM/jfUfzuEZHsQg6eOmLgJht6G3mPKMxYm75w2+qhAQZ+4X+1+ATZ+QFKeOZD5riHng==", + "requires": { + "component-emitter": "1.2.1", + "debug": "~3.1.0", + "isarray": "2.0.1" + }, + "dependencies": { + "component-emitter": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=" + }, + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + }, + "isarray": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", + "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=" + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, "sockjs": { "version": "0.3.19", "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.19.tgz", @@ -13375,6 +13578,11 @@ "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.4.tgz", "integrity": "sha1-I2QN17QtAEM5ERQIIOXPRA5SHdE=" }, + "to-array": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz", + "integrity": "sha1-F+bBH3PdTz10zaek/zI46a2b+JA=" + }, "to-arraybuffer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz", @@ -15696,6 +15904,11 @@ "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==" }, + "xmlhttprequest-ssl": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz", + "integrity": "sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4=" + }, "xregexp": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/xregexp/-/xregexp-4.3.0.tgz", @@ -15812,6 +16025,11 @@ "camelcase": "^5.0.0", "decamelize": "^1.2.0" } + }, + "yeast": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", + "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk=" } } } diff --git a/package.json b/package.json index 28a4dd82..aa7ba3c1 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "react-konva": "^16.13.0-0", "react-router-dom": "^5.1.2", "react-scripts": "3.4.1", + "socket.io-client": "^2.3.0", "typescript": "^3.8.3", "use-image": "^1.0.5" }, @@ -44,6 +45,7 @@ "@types/qs": "^6.9.2", "@types/react": "^16.9.34", "@types/react-dom": "^16.9.6", - "@types/react-router-dom": "^5.1.4" + "@types/react-router-dom": "^5.1.4", + "@types/socket.io-client": "^1.4.33" } } diff --git a/src/components/TestDetailsModal.tsx b/src/components/TestDetailsModal.tsx index fe759a82..cab908a7 100644 --- a/src/components/TestDetailsModal.tsx +++ b/src/components/TestDetailsModal.tsx @@ -37,7 +37,6 @@ import { TestRunDetails } from "./TestRunDetails"; import useImage from "use-image"; import { routes } from "../constants"; import { NoImagePlaceholder } from "./NoImageAvailable"; -import { useBuildDispatch, updateBuild } from "../contexts/build.context"; const useStyles = makeStyles((theme) => ({ imageContainer: { @@ -66,7 +65,6 @@ const TestDetailsModal: React.FunctionComponent<{ }> = ({ testRun, updateTestRun }) => { const classes = useStyles(); const history = useHistory(); - const buildDispatch = useBuildDispatch(); const stageWidth = (window.innerWidth / 2) * 0.9; const stageHeigth = window.innerHeight; @@ -174,7 +172,6 @@ const TestDetailsModal: React.FunctionComponent<{ onClick={() => testRunService.approve(testRun.id).then((testRun) => { updateTestRun(testRun); - updateBuild(buildDispatch, testRun); }) } > @@ -185,7 +182,6 @@ const TestDetailsModal: React.FunctionComponent<{ onClick={() => testRunService.reject(testRun.id).then((testRun) => { updateTestRun(testRun); - updateBuild(buildDispatch, testRun); }) } > diff --git a/src/contexts/build.context.tsx b/src/contexts/build.context.tsx index f87b6f94..6f475630 100644 --- a/src/contexts/build.context.tsx +++ b/src/contexts/build.context.tsx @@ -1,8 +1,6 @@ import React from "react"; -import { Build, TestRun } from "../types"; +import { Build } from "../types"; import { buildsService } from "../services"; -import { TestStatus } from "../types/testStatus"; -import { BuildStatus } from "../types/buildStatus"; interface IRequestAction { type: "request"; @@ -24,23 +22,17 @@ interface IDeleteAction { payload: string; } -interface IUpdateAction { - type: "update"; - payload: TestRun; -} - -interface IStatsAction { - type: "stats"; - payload: string; +interface IAddAction { + type: "add"; + payload: Build; } type IAction = | IRequestAction | IGetAction | IDeleteAction - | ISelectAction - | IStatsAction - | IUpdateAction; + | IAddAction + | ISelectAction; type Dispatch = (action: IAction) => void; type State = { @@ -67,65 +59,6 @@ function buildReducer(state: State, action: IAction): State { ...state, selectedBuildId: action.payload, }; - case "stats": - return { - ...state, - buildList: state.buildList.map((build) => { - if (build.id === action.payload) { - // reset stats - build.status = BuildStatus.passed; - build.passedCount = 0; - build.unresolvedCount = 0; - build.failedCount = 0; - - // calculate stats - build.testRuns.forEach((testRun) => { - switch (testRun.status) { - case TestStatus.approved: - case TestStatus.ok: { - build.passedCount += 1; - break; - } - case TestStatus.unresolved: - case TestStatus.new: { - build.unresolvedCount += 1; - break; - } - case TestStatus.failed: { - build.failedCount += 1; - break; - } - } - }); - - if (build.failedCount > 0) { - build.status = BuildStatus.failed; - } - if (build.unresolvedCount > 0) { - build.status = BuildStatus.unresolved; - } - } - return build; - }), - }; - case "update": - return { - ...state, - buildList: state.buildList.map((build) => { - if (build.id === action.payload.buildId) { - return { - ...build, - testRuns: build.testRuns.map((testRun) => { - if (testRun.id === action.payload.id) { - return action.payload; - } - return testRun; - }), - }; - } - return build; - }), - }; case "get": return { ...state, @@ -136,6 +69,12 @@ function buildReducer(state: State, action: IAction): State { ...state, buildList: state.buildList.filter((p) => p.id !== action.payload), }; + case "add": + console.log(action.payload); + return { + ...state, + buildList: [action.payload, ...state.buildList], + }; default: return state; } @@ -176,7 +115,6 @@ async function getBuildList(dispatch: Dispatch, id: string) { .getList(id) .then((items) => { dispatch({ type: "get", payload: items }); - items.forEach((build) => dispatch({ type: "stats", payload: build.id })); }) .catch((error) => { console.log(error.toString()); @@ -202,9 +140,8 @@ async function selectBuild(dispatch: Dispatch, id: string) { dispatch({ type: "select", payload: id }); } -async function updateBuild(dispatch: Dispatch, testRun: TestRun) { - dispatch({ type: "update", payload: testRun }); - dispatch({ type: "stats", payload: testRun.buildId }); +async function addBuild(dispatch: Dispatch, build: Build) { + dispatch({ type: "add", payload: build }); } export { @@ -214,5 +151,5 @@ export { getBuildList, deleteBuild, selectBuild, - updateBuild, + addBuild, }; diff --git a/src/pages/ProjectPage.tsx b/src/pages/ProjectPage.tsx index 15af777d..ec4014b0 100644 --- a/src/pages/ProjectPage.tsx +++ b/src/pages/ProjectPage.tsx @@ -8,7 +8,7 @@ import { makeStyles, } from "@material-ui/core"; import { useParams, useLocation, useHistory } from "react-router-dom"; -import { TestRun } from "../types"; +import { TestRun, Build } from "../types"; import { testRunService } from "../services"; import BuildList from "../components/BuildList"; import ProjectSelect from "../components/ProjectSelect"; @@ -22,8 +22,10 @@ import { useBuildState, useBuildDispatch, getBuildList, + addBuild, selectBuild, } from "../contexts/build.context"; +import socketIOClient from "socket.io-client"; const getQueryParams = (guery: string) => { const queryParams = qs.parse(guery, { ignoreQueryPrefix: true }); @@ -79,6 +81,23 @@ const ProjectPage = () => { const [testStatus, setTestStatus] = React.useState(""); const [filteredTestRuns, setFilteredTestRuns] = React.useState([]); + useEffect(() => { + const socket = socketIOClient("http://127.0.0.1:4201"); + socket.on("connect", (data: string) => { + console.log("Socket connected"); + }); + + socket.on("build_created", function (build: Build) { + // console.log(build) + addBuild(buildDispatch, build); + }); + + socket.on("testRun_created", function (testRun: TestRun) { + // console.log(testRun) + }); + // eslint-disable-next-line + }, []); + useEffect(() => { const queryParams = getQueryParams(location.search); if (!selectedBuildId) { From 65cedb3a02afa04f59cec2aaeccccb6cf4d56df8 Mon Sep 17 00:00:00 2001 From: Pavel Strunkin Date: Mon, 8 Jun 2020 23:20:41 +0200 Subject: [PATCH 2/5] TestRun context added --- src/App.jsx | 7 +- src/components/TestDetailsModal.tsx | 18 ++- src/components/TestRunList.tsx | 21 ++- src/contexts/build.context.tsx | 1 - src/contexts/testRun.context.tsx | 210 ++++++++++++++++++++++++++++ src/pages/ProjectPage.tsx | 71 ++++------ 6 files changed, 271 insertions(+), 57 deletions(-) create mode 100644 src/contexts/testRun.context.tsx diff --git a/src/App.jsx b/src/App.jsx index 86429ec4..9a5f9062 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -5,6 +5,7 @@ import { AuthProvider } from "./contexts/auth.context"; import { ProjectProvider } from "./contexts/project.context"; import Router from "./Router"; import { BuildProvider } from "./contexts/build.context"; +import { TestRunProvider } from "./contexts/testRun.context"; function App() { return ( @@ -12,8 +13,10 @@ function App() { -
- + +
+ + diff --git a/src/components/TestDetailsModal.tsx b/src/components/TestDetailsModal.tsx index cab908a7..b0523284 100644 --- a/src/components/TestDetailsModal.tsx +++ b/src/components/TestDetailsModal.tsx @@ -37,6 +37,11 @@ import { TestRunDetails } from "./TestRunDetails"; import useImage from "use-image"; import { routes } from "../constants"; import { NoImagePlaceholder } from "./NoImageAvailable"; +import { + useTestRunDispatch, + updateTestRun, + selectTestRun, +} from "../contexts/testRun.context"; const useStyles = makeStyles((theme) => ({ imageContainer: { @@ -61,10 +66,10 @@ const defaultStagePos = { const TestDetailsModal: React.FunctionComponent<{ testRun: TestRun; - updateTestRun: (testRun: TestRun) => void; -}> = ({ testRun, updateTestRun }) => { +}> = ({ testRun }) => { const classes = useStyles(); const history = useHistory(); + const testRunDispatch = useTestRunDispatch(); const stageWidth = (window.innerWidth / 2) * 0.9; const stageHeigth = window.innerHeight; @@ -108,6 +113,7 @@ const TestDetailsModal: React.FunctionComponent<{ history.push({ search: `buildId=${testRun.buildId}`, }); + selectTestRun(testRunDispatch, undefined); }; const isIgnoreAreasSaved = () => { @@ -171,7 +177,7 @@ const TestDetailsModal: React.FunctionComponent<{ color="inherit" onClick={() => testRunService.approve(testRun.id).then((testRun) => { - updateTestRun(testRun); + updateTestRun(testRunDispatch, testRun); }) } > @@ -181,7 +187,7 @@ const TestDetailsModal: React.FunctionComponent<{ color="secondary" onClick={() => testRunService.reject(testRun.id).then((testRun) => { - updateTestRun(testRun); + updateTestRun(testRunDispatch, testRun); }) } > @@ -249,7 +255,9 @@ const TestDetailsModal: React.FunctionComponent<{ // recalculate diff testRunService .recalculateDiff(testRun.id) - .then((testRun) => updateTestRun(testRun)) + .then((testRun) => + updateTestRun(testRunDispatch, testRun) + ) ); // update in variation diff --git a/src/components/TestRunList.tsx b/src/components/TestRunList.tsx index 8d45a879..e9f1d6cd 100644 --- a/src/components/TestRunList.tsx +++ b/src/components/TestRunList.tsx @@ -16,12 +16,18 @@ import { useHistory } from "react-router-dom"; import { TestRun } from "../types"; import TestStatusChip from "./TestStatusChip"; import { buildTestRunLocation } from "../_helpers/route.helpers"; +import { + useTestRunState, + useTestRunDispatch, + deleteTestRun, + selectTestRun, +} from "../contexts/testRun.context"; const TestRunList: React.FunctionComponent<{ items: TestRun[]; - selectedId: string | undefined; - handleRemove: (id: string) => {}; -}> = ({ items, selectedId, handleRemove }) => { +}> = ({ items }) => { + const { selectedTestRunId } = useTestRunState(); + const testRunDispatch = useTestRunDispatch(); const history = useHistory(); const [anchorEl, setAnchorEl] = React.useState(null); const [selectedTestRun, setSelectedTestRun] = React.useState< @@ -58,10 +64,15 @@ const TestRunList: React.FunctionComponent<{ {items.map((test) => ( - + { history.push(buildTestRunLocation(test)); + selectTestRun(testRunDispatch, test.id) }} > {test.name} @@ -107,7 +118,7 @@ const TestRunList: React.FunctionComponent<{ { - handleRemove(selectedTestRun.id); + deleteTestRun(testRunDispatch, selectedTestRun.id); handleClose(); }} > diff --git a/src/contexts/build.context.tsx b/src/contexts/build.context.tsx index 6f475630..b10943d4 100644 --- a/src/contexts/build.context.tsx +++ b/src/contexts/build.context.tsx @@ -70,7 +70,6 @@ function buildReducer(state: State, action: IAction): State { buildList: state.buildList.filter((p) => p.id !== action.payload), }; case "add": - console.log(action.payload); return { ...state, buildList: [action.payload, ...state.buildList], diff --git a/src/contexts/testRun.context.tsx b/src/contexts/testRun.context.tsx new file mode 100644 index 00000000..498429ea --- /dev/null +++ b/src/contexts/testRun.context.tsx @@ -0,0 +1,210 @@ +import React from "react"; +import { TestRun } from "../types"; +import { testRunService } from "../services"; + +interface IRequestAction { + type: "request"; + payload?: undefined; +} + +interface IGetAction { + type: "get"; + payload: TestRun[]; +} + +interface ISelectAction { + type: "select"; + payload: string | undefined; +} + +interface IIndexAction { + type: "index"; + payload: string | undefined; +} + +interface IDeleteAction { + type: "delete"; + payload: string; +} + +interface IAddAction { + type: "add"; + payload: TestRun; +} + +interface IUpdateAction { + type: "update"; + payload: TestRun; +} + +interface IApproveAction { + type: "approve"; + payload: TestRun; +} + +interface IRejectAction { + type: "reject"; + payload: TestRun; +} + +type IAction = + | IRequestAction + | IIndexAction + | IGetAction + | IDeleteAction + | IAddAction + | IUpdateAction + | IApproveAction + | IRejectAction + | ISelectAction; + +type Dispatch = (action: IAction) => void; +type State = { + selectedTestRunId: string | undefined; + selectedTestRunIndex: number | undefined; + testRuns: TestRun[]; +}; + +type TestRunProviderProps = { children: React.ReactNode }; + +const TestRunStateContext = React.createContext(undefined); +const TestRunDispatchContext = React.createContext( + undefined +); + +const initialState: State = { + selectedTestRunId: undefined, + selectedTestRunIndex: undefined, + testRuns: [], +}; + +function testRunReducer(state: State, action: IAction): State { + switch (action.type) { + case "select": + return { + ...state, + selectedTestRunId: action.payload, + }; + case "index": + return { + ...state, + selectedTestRunIndex: state.testRuns.findIndex( + (t) => t.id === action.payload + ), + }; + case "get": + return { + ...state, + testRuns: action.payload, + }; + case "delete": + return { + ...state, + testRuns: state.testRuns.filter((p) => p.id !== action.payload), + }; + case "add": + return { + ...state, + testRuns: [...state.testRuns, action.payload], + }; + case "update": + return { + ...state, + testRuns: state.testRuns.map((t) => { + if (t.id === action.payload.id) { + return action.payload; + } + return t; + }), + }; + default: + return state; + } +} + +function TestRunProvider({ children }: TestRunProviderProps) { + const [state, dispatch] = React.useReducer(testRunReducer, initialState); + + React.useEffect(() => { + setTestRunIndex(dispatch, state.selectedTestRunId); + }, [state.selectedTestRunId, state.testRuns]); + + return ( + + + {children} + + + ); +} + +function useTestRunState() { + const context = React.useContext(TestRunStateContext); + if (context === undefined) { + throw new Error("must be used within a TestRunProvider"); + } + return context; +} + +function useTestRunDispatch() { + const context = React.useContext(TestRunDispatchContext); + if (context === undefined) { + throw new Error("must be used within a TestRunProvider"); + } + return context; +} + +async function getTestRunList(dispatch: Dispatch, buildId: string) { + dispatch({ type: "request" }); + + testRunService + .getList(buildId) + .then((items) => { + dispatch({ type: "get", payload: items }); + }) + .catch((error) => { + console.log(error.toString()); + }); +} + +async function deleteTestRun(dispatch: Dispatch, id: string) { + dispatch({ type: "request" }); + + testRunService + .remove(id) + .then((isDeleted) => { + if (isDeleted) { + dispatch({ type: "delete", payload: id }); + } + }) + .catch((error) => { + console.log(error.toString()); + }); +} + +async function selectTestRun(dispatch: Dispatch, id: string | undefined) { + dispatch({ type: "select", payload: id }); +} + +async function setTestRunIndex(dispatch: Dispatch, index: string | undefined) { + dispatch({ type: "index", payload: index }); +} + +async function addTestRun(dispatch: Dispatch, testRun: TestRun) { + dispatch({ type: "add", payload: testRun }); +} + +async function updateTestRun(dispatch: Dispatch, testRun: TestRun) { + dispatch({ type: "update", payload: testRun }); +} + +export { + TestRunProvider, + useTestRunState, + useTestRunDispatch, + getTestRunList, + deleteTestRun, + selectTestRun, + addTestRun, + updateTestRun, +}; diff --git a/src/pages/ProjectPage.tsx b/src/pages/ProjectPage.tsx index ec4014b0..4fad5023 100644 --- a/src/pages/ProjectPage.tsx +++ b/src/pages/ProjectPage.tsx @@ -1,4 +1,4 @@ -import React, { useEffect, useState } from "react"; +import React, { useEffect } from "react"; import { Grid, Dialog, @@ -9,7 +9,6 @@ import { } from "@material-ui/core"; import { useParams, useLocation, useHistory } from "react-router-dom"; import { TestRun, Build } from "../types"; -import { testRunService } from "../services"; import BuildList from "../components/BuildList"; import ProjectSelect from "../components/ProjectSelect"; import qs from "qs"; @@ -26,6 +25,13 @@ import { selectBuild, } from "../contexts/build.context"; import socketIOClient from "socket.io-client"; +import { + useTestRunState, + addTestRun, + useTestRunDispatch, + selectTestRun, + getTestRunList, +} from "../contexts/testRun.context"; const getQueryParams = (guery: string) => { const queryParams = qs.parse(guery, { ignoreQueryPrefix: true }); @@ -68,9 +74,12 @@ const ProjectPage = () => { const history = useHistory(); const { buildList, selectedBuildId } = useBuildState(); const buildDispatch = useBuildDispatch(); - const [testRuns, setTestRuns] = useState([]); - const [selectedTestdId, setSelectedTestId] = useState(); - const [selectedTestRunIndex, setSelectedTestRunIndex] = useState(); + const { + testRuns, + selectedTestRunId, + selectedTestRunIndex, + } = useTestRunState(); + const testRunDispatch = useTestRunDispatch(); // filter const [query, setQuery] = React.useState(""); @@ -88,12 +97,14 @@ const ProjectPage = () => { }); socket.on("build_created", function (build: Build) { - // console.log(build) addBuild(buildDispatch, build); }); socket.on("testRun_created", function (testRun: TestRun) { - // console.log(testRun) + console.log(selectedBuildId) + if (testRun.buildId === selectedBuildId) { + addTestRun(testRunDispatch, testRun); + } }); // eslint-disable-next-line }, []); @@ -112,15 +123,10 @@ const ProjectPage = () => { useEffect(() => { const queryParams = getQueryParams(location.search); - if (queryParams.testId) { - setSelectedTestId(queryParams.testId); - const index = testRuns.findIndex((t) => t.id === queryParams.testId); - setSelectedTestRunIndex(index); - } else { - setSelectedTestId(undefined); - setSelectedTestRunIndex(undefined); + if (!selectedTestRunId && queryParams.testId) { + selectTestRun(testRunDispatch, queryParams.testId); } - }, [location.search, testRuns]); + }, [location.search, testRuns, selectedTestRunId, testRunDispatch]); useEffect(() => { if (projectId) { @@ -130,11 +136,9 @@ const ProjectPage = () => { useEffect(() => { if (selectedBuildId) { - testRunService.getList(selectedBuildId).then((testRuns) => { - setTestRuns(testRuns); - }); + getTestRunList(testRunDispatch, selectedBuildId); } - }, [selectedBuildId]); + }, [selectedBuildId, testRunDispatch]); useEffect(() => { setFilteredTestRuns( @@ -150,16 +154,6 @@ const ProjectPage = () => { ); }, [query, os, device, browser, viewport, testStatus, testRuns]); - const updateTestRun = (testRun: TestRun) => { - const updated = testRuns.map((t) => { - if (t.id === testRun.id) { - return testRun; - } - return t; - }); - setTestRuns(updated); - }; - return ( @@ -189,24 +183,11 @@ const ProjectPage = () => { - - testRunService.remove(id).then((isRemoved) => { - if (isRemoved) { - setTestRuns(testRuns.filter((item) => item.id !== id)); - } - }) - } - /> + {selectedTestRunIndex !== undefined && testRuns[selectedTestRunIndex] && ( - + {selectedTestRunIndex + 1 < testRuns.length && ( { onClick={() => { const next = testRuns[selectedTestRunIndex + 1]; history.push(buildTestRunLocation(next)); + selectTestRun(testRunDispatch, next.id); }} > @@ -232,6 +214,7 @@ const ProjectPage = () => { onClick={() => { const prev = testRuns[selectedTestRunIndex - 1]; history.push(buildTestRunLocation(prev)); + selectTestRun(testRunDispatch, prev.id); }} > From 2dbffd020f09c097a57c583df92cf200455c7763 Mon Sep 17 00:00:00 2001 From: Pavel Strunkin Date: Tue, 9 Jun 2020 00:22:30 +0200 Subject: [PATCH 3/5] refactoring --- src/App.jsx | 10 ++-- src/components/BuildList.tsx | 2 +- src/components/Header.tsx | 2 +- src/components/LoginForm.tsx | 2 +- src/components/PrivateRoute.tsx | 2 +- src/components/ProjectSelect.tsx | 2 +- src/components/RegisterForm.tsx | 2 +- src/components/TestDetailsModal.tsx | 17 +++---- src/components/TestRunList.tsx | 2 +- src/contexts/index.ts | 4 ++ src/pages/LoginPage.tsx | 2 +- src/pages/ProfilePage.tsx | 2 +- src/pages/ProjectListPage.tsx | 2 +- src/pages/ProjectPage.tsx | 69 ++++++++++++++------------ src/pages/RegisterPage.tsx | 2 +- src/pages/TestVariationDetailsPage.tsx | 34 ++++++++----- 16 files changed, 87 insertions(+), 69 deletions(-) create mode 100644 src/contexts/index.ts diff --git a/src/App.jsx b/src/App.jsx index 9a5f9062..f7830f22 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -1,11 +1,13 @@ import React from "react"; import "./App.css"; import Header from "./components/Header"; -import { AuthProvider } from "./contexts/auth.context"; -import { ProjectProvider } from "./contexts/project.context"; +import { + AuthProvider, + ProjectProvider, + BuildProvider, + TestRunProvider, +} from "./contexts"; import Router from "./Router"; -import { BuildProvider } from "./contexts/build.context"; -import { TestRunProvider } from "./contexts/testRun.context"; function App() { return ( diff --git a/src/components/BuildList.tsx b/src/components/BuildList.tsx index 0586a0b5..2cdd8ecd 100644 --- a/src/components/BuildList.tsx +++ b/src/components/BuildList.tsx @@ -19,7 +19,7 @@ import { useBuildDispatch, deleteBuild, selectBuild, -} from "../contexts/build.context"; +} from "../contexts"; import { BuildStatusChip } from "./BuildStatusChip"; const useStyles = makeStyles((theme: Theme) => diff --git a/src/components/Header.tsx b/src/components/Header.tsx index bdd0c4c7..2873a80d 100644 --- a/src/components/Header.tsx +++ b/src/components/Header.tsx @@ -13,7 +13,7 @@ import { useAuthState, useAuthDispatch, logout, -} from "../contexts/auth.context"; +} from "../contexts"; import { routes } from "../constants"; const Header: FunctionComponent = () => { diff --git a/src/components/LoginForm.tsx b/src/components/LoginForm.tsx index bc21263d..b1c41a85 100644 --- a/src/components/LoginForm.tsx +++ b/src/components/LoginForm.tsx @@ -9,7 +9,7 @@ import { CardActions, Typography, } from "@material-ui/core"; -import { useAuthDispatch, login } from "../contexts/auth.context"; +import { useAuthDispatch, login } from "../contexts"; import { routes } from "../constants"; const LoginForm = () => { diff --git a/src/components/PrivateRoute.tsx b/src/components/PrivateRoute.tsx index f2e36b92..383b3d46 100644 --- a/src/components/PrivateRoute.tsx +++ b/src/components/PrivateRoute.tsx @@ -1,6 +1,6 @@ import React from "react"; import { Redirect, Route, RouteProps } from "react-router-dom"; -import { useAuthState } from "../contexts/auth.context"; +import { useAuthState } from "../contexts"; import { routes } from "../constants"; const PrivateRoute: React.SFC = ({ diff --git a/src/components/ProjectSelect.tsx b/src/components/ProjectSelect.tsx index cd12bd9f..107a7640 100644 --- a/src/components/ProjectSelect.tsx +++ b/src/components/ProjectSelect.tsx @@ -1,6 +1,6 @@ import React, { FunctionComponent } from "react"; import { MenuItem, Select } from "@material-ui/core"; -import { useProjectState } from "../contexts/project.context"; +import { useProjectState } from "../contexts"; import { useHistory } from "react-router-dom"; const ProjectSelect: FunctionComponent<{ diff --git a/src/components/RegisterForm.tsx b/src/components/RegisterForm.tsx index b02317fe..50830347 100644 --- a/src/components/RegisterForm.tsx +++ b/src/components/RegisterForm.tsx @@ -7,7 +7,7 @@ import { CardContent, CardActions, } from "@material-ui/core"; -import { useAuthDispatch, login } from "../contexts/auth.context"; +import { useAuthDispatch, login } from "../contexts"; import { usersService } from "../services"; const RegisterForm = () => { diff --git a/src/components/TestDetailsModal.tsx b/src/components/TestDetailsModal.tsx index b0523284..2dd8287a 100644 --- a/src/components/TestDetailsModal.tsx +++ b/src/components/TestDetailsModal.tsx @@ -41,7 +41,7 @@ import { useTestRunDispatch, updateTestRun, selectTestRun, -} from "../contexts/testRun.context"; +} from "../contexts"; const useStyles = makeStyles((theme) => ({ imageContainer: { @@ -366,14 +366,13 @@ const TestDetailsModal: React.FunctionComponent<{ {testRun.diffName ? ( - -
+ +
{ diff --git a/src/pages/ProfilePage.tsx b/src/pages/ProfilePage.tsx index 459a95ae..02868f50 100644 --- a/src/pages/ProfilePage.tsx +++ b/src/pages/ProfilePage.tsx @@ -12,7 +12,7 @@ import { useAuthState, useAuthDispatch, update, -} from "../contexts/auth.context"; +} from "../contexts"; import { usersService } from "../services"; const ProfilePage = () => { diff --git a/src/pages/ProjectListPage.tsx b/src/pages/ProjectListPage.tsx index 958607b5..bdaa83e8 100644 --- a/src/pages/ProjectListPage.tsx +++ b/src/pages/ProjectListPage.tsx @@ -23,7 +23,7 @@ import { getProjectList, deleteProject, createProject, -} from "../contexts/project.context"; +} from "../contexts"; import { Link } from "react-router-dom"; import { Delete, Add } from "@material-ui/icons"; import { routes } from "../constants"; diff --git a/src/pages/ProjectPage.tsx b/src/pages/ProjectPage.tsx index 4fad5023..bf816048 100644 --- a/src/pages/ProjectPage.tsx +++ b/src/pages/ProjectPage.tsx @@ -23,15 +23,13 @@ import { getBuildList, addBuild, selectBuild, -} from "../contexts/build.context"; -import socketIOClient from "socket.io-client"; -import { useTestRunState, addTestRun, useTestRunDispatch, selectTestRun, getTestRunList, -} from "../contexts/testRun.context"; +} from "../contexts"; +import socketIOClient from "socket.io-client"; const getQueryParams = (guery: string) => { const queryParams = qs.parse(guery, { ignoreQueryPrefix: true }); @@ -81,6 +79,8 @@ const ProjectPage = () => { } = useTestRunState(); const testRunDispatch = useTestRunDispatch(); + const [socket, setSocket] = React.useState(); + // filter const [query, setQuery] = React.useState(""); const [os, setOs] = React.useState(""); @@ -90,25 +90,41 @@ const ProjectPage = () => { const [testStatus, setTestStatus] = React.useState(""); const [filteredTestRuns, setFilteredTestRuns] = React.useState([]); + // init socket connection useEffect(() => { const socket = socketIOClient("http://127.0.0.1:4201"); - socket.on("connect", (data: string) => { - console.log("Socket connected"); - }); - - socket.on("build_created", function (build: Build) { - addBuild(buildDispatch, build); - }); - - socket.on("testRun_created", function (testRun: TestRun) { - console.log(selectedBuildId) - if (testRun.buildId === selectedBuildId) { - addTestRun(testRunDispatch, testRun); - } - }); - // eslint-disable-next-line + setSocket(socket); }, []); + // subscribe on socket events + useEffect(() => { + if (socket) { + socket.removeAllListeners(); + + socket.on("build_created", function (build: Build) { + addBuild(buildDispatch, build); + }); + + socket.on(`testRun_created`, function (testRun: TestRun) { + if (testRun.buildId === selectedBuildId) { + addTestRun(testRunDispatch, testRun); + } + }); + } + }, [socket, selectedBuildId, buildDispatch, testRunDispatch]); + + useEffect(() => { + if (projectId) { + getBuildList(buildDispatch, projectId); + } + }, [projectId, buildDispatch]); + + useEffect(() => { + if (selectedBuildId) { + getTestRunList(testRunDispatch, selectedBuildId); + } + }, [selectedBuildId, testRunDispatch]); + useEffect(() => { const queryParams = getQueryParams(location.search); if (!selectedBuildId) { @@ -118,8 +134,7 @@ const ProjectPage = () => { selectBuild(buildDispatch, buildList[0].id); } } - // eslint-disable-next-line - }, []); + }, [buildDispatch, buildList, location.search, selectedBuildId]); useEffect(() => { const queryParams = getQueryParams(location.search); @@ -128,18 +143,6 @@ const ProjectPage = () => { } }, [location.search, testRuns, selectedTestRunId, testRunDispatch]); - useEffect(() => { - if (projectId) { - getBuildList(buildDispatch, projectId); - } - }, [projectId, buildDispatch]); - - useEffect(() => { - if (selectedBuildId) { - getTestRunList(testRunDispatch, selectedBuildId); - } - }, [selectedBuildId, testRunDispatch]); - useEffect(() => { setFilteredTestRuns( testRuns.filter( diff --git a/src/pages/RegisterPage.tsx b/src/pages/RegisterPage.tsx index aac7be0d..ee0e4cb8 100644 --- a/src/pages/RegisterPage.tsx +++ b/src/pages/RegisterPage.tsx @@ -2,7 +2,7 @@ import React, { useEffect } from "react"; import { Grid } from "@material-ui/core"; import RegisterForm from "../components/RegisterForm"; import { useHistory } from "react-router-dom"; -import { useAuthState } from "../contexts/auth.context"; +import { useAuthState } from "../contexts"; import { routes } from "../constants"; const RegisterPage = () => { diff --git a/src/pages/TestVariationDetailsPage.tsx b/src/pages/TestVariationDetailsPage.tsx index 76aab31c..b4641fb0 100644 --- a/src/pages/TestVariationDetailsPage.tsx +++ b/src/pages/TestVariationDetailsPage.tsx @@ -1,5 +1,5 @@ import React from "react"; -import { useParams, Link } from "react-router-dom"; +import { useParams, useHistory } from "react-router-dom"; import { TestVariation } from "../types"; import { testVariationService, staticService } from "../services"; import { @@ -14,7 +14,12 @@ import { } from "@material-ui/core"; import { buildTestRunUrl } from "../_helpers/route.helpers"; import { TestVariationDetails } from "../components/TestVariationDetails"; -import { selectBuild, useBuildDispatch } from "../contexts/build.context"; +import { + selectBuild, + useBuildDispatch, + useTestRunDispatch, + selectTestRun, +} from "../contexts"; const useStyles = makeStyles({ media: { @@ -25,7 +30,9 @@ const useStyles = makeStyles({ const TestVariationDetailsPage: React.FunctionComponent = () => { const classes = useStyles(); + const history = useHistory(); const buildDispatch = useBuildDispatch(); + const testRunDispatch = useTestRunDispatch(); const { testVariationId } = useParams(); const [testVariation, setTestVariation] = React.useState(); @@ -52,17 +59,20 @@ const TestVariationDetailsPage: React.FunctionComponent = () => { From 6db8873652126bb26bf521a12057eb40036006e1 Mon Sep 17 00:00:00 2001 From: Pavel Strunkin Date: Tue, 9 Jun 2020 22:18:46 +0200 Subject: [PATCH 4/5] socket moved to context --- src/App.jsx | 7 ++- src/contexts/socket.context.tsx | 99 ++++++++++++++++++++++++++++++++ src/contexts/testRun.context.tsx | 1 + src/pages/ProjectPage.tsx | 30 +--------- 4 files changed, 106 insertions(+), 31 deletions(-) create mode 100644 src/contexts/socket.context.tsx diff --git a/src/App.jsx b/src/App.jsx index f7830f22..00482241 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -8,6 +8,7 @@ import { TestRunProvider, } from "./contexts"; import Router from "./Router"; +import { SocketProvider } from "./contexts/socket.context"; function App() { return ( @@ -16,8 +17,10 @@ function App() { -
- + +
+ + diff --git a/src/contexts/socket.context.tsx b/src/contexts/socket.context.tsx new file mode 100644 index 00000000..2767f94e --- /dev/null +++ b/src/contexts/socket.context.tsx @@ -0,0 +1,99 @@ +import * as React from "react"; +import socketIOClient from "socket.io-client"; +import { useBuildState, useBuildDispatch, addBuild } from "./build.context"; +import { Build, TestRun } from "../types"; +import { useTestRunDispatch, addTestRun } from "./testRun.context"; + +interface IConnectAction { + type: "connect"; + payload: SocketIOClient.Socket; +} + +interface IClearAction { + type: "clear"; +} + +type IAction = IConnectAction | IClearAction; + +type Dispatch = (action: IAction) => void; +type State = { socket: SocketIOClient.Socket | undefined }; + +type SocketProviderProps = { children: React.ReactNode }; + +const SocketStateContext = React.createContext(undefined); +const SocketDispatchContext = React.createContext( + undefined +); + +const initialState: State = { + socket: undefined, +}; + +function socketReducer(state: State, action: IAction): State { + switch (action.type) { + case "connect": { + return { socket: action.payload }; + } + default: + return state; + } +} + +function SocketProvider({ children }: SocketProviderProps) { + const [state, dispatch] = React.useReducer(socketReducer, initialState); + const { selectedBuildId } = useBuildState(); + const testRunDispatch = useTestRunDispatch(); + const buildDispatch = useBuildDispatch(); + + React.useEffect(() => { + connect(dispatch); + }, []); + + React.useEffect(() => { + if (state.socket) { + state.socket.removeAllListeners(); + + state.socket.on("build_created", function (build: Build) { + addBuild(buildDispatch, build); + }); + + state.socket.on(`testRun_created`, function (testRun: TestRun) { + if (testRun.buildId === selectedBuildId) { + addTestRun(testRunDispatch, testRun); + } + }); + } + }, [state.socket, selectedBuildId, buildDispatch, testRunDispatch]); + + return ( + + + {children} + + + ); +} + +function useSocketState() { + const context = React.useContext(SocketStateContext); + if (context === undefined) { + throw new Error("must be used within a SocketProvider"); + } + return context; +} + +function useSocketDispatch() { + const context = React.useContext(SocketDispatchContext); + if (context === undefined) { + throw new Error("must be used within a SocketProvider"); + } + return context; +} + +function connect(dispatch: Dispatch) { + const socket = socketIOClient("http://127.0.0.1:4201"); + dispatch({ type: "connect", payload: socket }); + console.log("Socket connected"); +} + +export { SocketProvider, useSocketState, useSocketDispatch, connect }; diff --git a/src/contexts/testRun.context.tsx b/src/contexts/testRun.context.tsx index 498429ea..68915c9f 100644 --- a/src/contexts/testRun.context.tsx +++ b/src/contexts/testRun.context.tsx @@ -191,6 +191,7 @@ async function setTestRunIndex(dispatch: Dispatch, index: string | undefined) { } async function addTestRun(dispatch: Dispatch, testRun: TestRun) { + dispatch({ type: "delete", payload: testRun.id }); dispatch({ type: "add", payload: testRun }); } diff --git a/src/pages/ProjectPage.tsx b/src/pages/ProjectPage.tsx index bf816048..6635c49a 100644 --- a/src/pages/ProjectPage.tsx +++ b/src/pages/ProjectPage.tsx @@ -8,7 +8,7 @@ import { makeStyles, } from "@material-ui/core"; import { useParams, useLocation, useHistory } from "react-router-dom"; -import { TestRun, Build } from "../types"; +import { TestRun } from "../types"; import BuildList from "../components/BuildList"; import ProjectSelect from "../components/ProjectSelect"; import qs from "qs"; @@ -21,15 +21,12 @@ import { useBuildState, useBuildDispatch, getBuildList, - addBuild, selectBuild, useTestRunState, - addTestRun, useTestRunDispatch, selectTestRun, getTestRunList, } from "../contexts"; -import socketIOClient from "socket.io-client"; const getQueryParams = (guery: string) => { const queryParams = qs.parse(guery, { ignoreQueryPrefix: true }); @@ -79,8 +76,6 @@ const ProjectPage = () => { } = useTestRunState(); const testRunDispatch = useTestRunDispatch(); - const [socket, setSocket] = React.useState(); - // filter const [query, setQuery] = React.useState(""); const [os, setOs] = React.useState(""); @@ -90,29 +85,6 @@ const ProjectPage = () => { const [testStatus, setTestStatus] = React.useState(""); const [filteredTestRuns, setFilteredTestRuns] = React.useState([]); - // init socket connection - useEffect(() => { - const socket = socketIOClient("http://127.0.0.1:4201"); - setSocket(socket); - }, []); - - // subscribe on socket events - useEffect(() => { - if (socket) { - socket.removeAllListeners(); - - socket.on("build_created", function (build: Build) { - addBuild(buildDispatch, build); - }); - - socket.on(`testRun_created`, function (testRun: TestRun) { - if (testRun.buildId === selectedBuildId) { - addTestRun(testRunDispatch, testRun); - } - }); - } - }, [socket, selectedBuildId, buildDispatch, testRunDispatch]); - useEffect(() => { if (projectId) { getBuildList(buildDispatch, projectId); From 82431dd9ec3f1ae97f935a57d4fb254ce41a10c2 Mon Sep 17 00:00:00 2001 From: Pavel Strunkin Date: Wed, 10 Jun 2020 00:09:05 +0200 Subject: [PATCH 5/5] hardcoded url removed --- src/contexts/socket.context.tsx | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/contexts/socket.context.tsx b/src/contexts/socket.context.tsx index 2767f94e..d32c54a7 100644 --- a/src/contexts/socket.context.tsx +++ b/src/contexts/socket.context.tsx @@ -91,9 +91,14 @@ function useSocketDispatch() { } function connect(dispatch: Dispatch) { - const socket = socketIOClient("http://127.0.0.1:4201"); - dispatch({ type: "connect", payload: socket }); - console.log("Socket connected"); + const apiUrl = process.env.REACT_APP_API_URL; + if (apiUrl) { + const socket = socketIOClient(apiUrl); + dispatch({ type: "connect", payload: socket }); + console.log("Socket connected"); + } else { + console.log("API url is not provided: " + apiUrl); + } } export { SocketProvider, useSocketState, useSocketDispatch, connect };