diff --git a/Dockerfile b/Dockerfile
index c5f6459de..44f59e2b9 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -24,7 +24,7 @@ ARG PREDATOR_DOCS_URL
# Build UI from sources
WORKDIR /usr/ui
RUN npm ci --silent
-RUN BUCKET_PATH=$BUCKET_PATH PREDATOR_DOCS_URL=$PREDATOR_DOCS_URL npm run build
+RUN VERSION=$(node -p -e "require('/usr/package.json').version") && BUCKET_PATH=$BUCKET_PATH PREDATOR_DOCS_URL=$PREDATOR_DOCS_URL VERSION=$VERSION npm run build
# Clean up
RUN mv /usr/ui/dist /tmp/dist && rm -rf /usr/ui/* && mv /tmp/dist /usr/ui/dist
diff --git a/package-lock.json b/package-lock.json
index b3ba8da66..7a50d39ce 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -52,7 +52,7 @@
},
"@babel/generator": {
"version": "7.9.4",
- "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.9.4.tgz",
+ "resolved": "http://npm.zooz.co:8083/@babel%2fgenerator/-/generator-7.9.4.tgz",
"integrity": "sha512-rjP8ahaDy/ouhrvCoU1E5mqaitWrxwuNGU+dy1EpaoK48jZay4MdkskKGIMHLZNewg8sAsqpGSREJwP0zH3YQA==",
"dev": true,
"requires": {
@@ -101,7 +101,7 @@
},
"@babel/helper-validator-identifier": {
"version": "7.9.0",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.9.0.tgz",
+ "resolved": "http://npm.zooz.co:8083/@babel%2fhelper-validator-identifier/-/helper-validator-identifier-7.9.0.tgz",
"integrity": "sha512-6G8bQKjOh+of4PV/ThDm/rRqlU7+IGoJuofpagU5GlEl29Vv0RGqqt86ZGRV8ZuSOY3o+8yXl5y782SMcG7SHw==",
"dev": true
},
@@ -149,7 +149,7 @@
},
"@babel/parser": {
"version": "7.9.4",
- "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.9.4.tgz",
+ "resolved": "http://npm.zooz.co:8083/@babel%2fparser/-/parser-7.9.4.tgz",
"integrity": "sha512-bC49otXX6N0/VYhgOMh4gnP26E9xnDZK3TmbNpxYzzz9BQLBosQwfyOe9/cXUU3txYhTzLCbcqd5c8y/OmCjHA==",
"dev": true
},
@@ -172,7 +172,7 @@
},
"@babel/template": {
"version": "7.8.6",
- "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.6.tgz",
+ "resolved": "http://npm.zooz.co:8083/@babel%2ftemplate/-/template-7.8.6.tgz",
"integrity": "sha512-zbMsPMy/v0PWFZEhQJ66bqjhH+z0JgMoBWuikXybgG3Gkd/3t5oQ1Rw2WQhnSrsOmsKXnZOx15tkC4qON/+JPg==",
"dev": true,
"requires": {
@@ -183,7 +183,7 @@
},
"@babel/traverse": {
"version": "7.9.0",
- "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.9.0.tgz",
+ "resolved": "http://npm.zooz.co:8083/@babel%2ftraverse/-/traverse-7.9.0.tgz",
"integrity": "sha512-jAZQj0+kn4WTHO5dUZkZKhbFrqZE7K5LAQ5JysMnmvGij+wOdr+8lWqPeW0BcF4wFwrEXXtdGO7wcV6YPJcf3w==",
"dev": true,
"requires": {
@@ -217,7 +217,7 @@
},
"@babel/types": {
"version": "7.9.0",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.9.0.tgz",
+ "resolved": "http://npm.zooz.co:8083/@babel%2ftypes/-/types-7.9.0.tgz",
"integrity": "sha512-BS9JKfXkzzJl8RluW4JGknzpiUV7ZrvTayM6yfqLTVBEnFtyowVIOu6rqxRd5cVO6yGoWf4T8u8dgK9oB+GCng==",
"dev": true,
"requires": {
@@ -682,7 +682,7 @@
},
"@types/color-name": {
"version": "1.1.1",
- "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz",
+ "resolved": "http://npm.zooz.co:8083/@types%2fcolor-name/-/color-name-1.1.1.tgz",
"integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ=="
},
"@types/long": {
@@ -746,7 +746,7 @@
},
"acorn": {
"version": "7.1.1",
- "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.1.1.tgz",
+ "resolved": "http://npm.zooz.co:8083/acorn/-/acorn-7.1.1.tgz",
"integrity": "sha512-add7dgA5ppRPxCFJoAGfMDi7PIBXq1RtGo7BhbLaxwrXPOmw8gq48Y9ozT01hUKy9byMjlR20EJhu5zlkErEkg==",
"dev": true
},
@@ -821,7 +821,7 @@
},
"ansi-colors": {
"version": "3.2.3",
- "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.3.tgz",
+ "resolved": "http://npm.zooz.co:8083/ansi-colors/-/ansi-colors-3.2.3.tgz",
"integrity": "sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw==",
"dev": true
},
@@ -864,7 +864,7 @@
},
"anymatch": {
"version": "3.1.1",
- "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz",
+ "resolved": "http://npm.zooz.co:8083/anymatch/-/anymatch-3.1.1.tgz",
"integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==",
"dev": true,
"requires": {
@@ -874,7 +874,7 @@
"dependencies": {
"normalize-path": {
"version": "3.0.0",
- "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
+ "resolved": "http://npm.zooz.co:8083/normalize-path/-/normalize-path-3.0.0.tgz",
"integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
"dev": true
}
@@ -1363,7 +1363,7 @@
},
"binary-extensions": {
"version": "2.0.0",
- "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.0.0.tgz",
+ "resolved": "http://npm.zooz.co:8083/binary-extensions/-/binary-extensions-2.0.0.tgz",
"integrity": "sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow==",
"dev": true
},
@@ -1511,7 +1511,7 @@
},
"braces": {
"version": "3.0.2",
- "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
+ "resolved": "http://npm.zooz.co:8083/braces/-/braces-3.0.2.tgz",
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
"dev": true,
"requires": {
@@ -1574,7 +1574,7 @@
},
"bunyan": {
"version": "1.8.12",
- "resolved": "https://registry.npmjs.org/bunyan/-/bunyan-1.8.12.tgz",
+ "resolved": "http://npm.zooz.co:8083/bunyan/-/bunyan-1.8.12.tgz",
"integrity": "sha1-8VDw9nSKvdcq6uhPBEA74u8RN5c=",
"requires": {
"dtrace-provider": "~0.8",
@@ -1585,7 +1585,7 @@
},
"busboy": {
"version": "0.3.1",
- "resolved": "https://registry.npmjs.org/busboy/-/busboy-0.3.1.tgz",
+ "resolved": "http://npm.zooz.co:8083/busboy/-/busboy-0.3.1.tgz",
"integrity": "sha512-y7tTxhGKXcyBxRKAni+awqx8uqaJKrSFSNFSeRG5CsWNdmy2BIK+6VGWEW7TZnIO/533mtMEA4rOevQV815YJw==",
"requires": {
"dicer": "0.3.0"
@@ -1825,7 +1825,7 @@
},
"chokidar": {
"version": "3.3.0",
- "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.3.0.tgz",
+ "resolved": "http://npm.zooz.co:8083/chokidar/-/chokidar-3.3.0.tgz",
"integrity": "sha512-dGmKLDdT3Gdl7fBUe8XK+gAtGmzy5Fn0XkkWQuYxGIgWVPPse2CxFA5mtrlD0TOHaHjEUqkWNyP1XdHoJES/4A==",
"dev": true,
"requires": {
@@ -1841,13 +1841,13 @@
"dependencies": {
"is-extglob": {
"version": "2.1.1",
- "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+ "resolved": "http://npm.zooz.co:8083/is-extglob/-/is-extglob-2.1.1.tgz",
"integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=",
"dev": true
},
"is-glob": {
"version": "4.0.1",
- "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz",
+ "resolved": "http://npm.zooz.co:8083/is-glob/-/is-glob-4.0.1.tgz",
"integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==",
"dev": true,
"requires": {
@@ -1856,7 +1856,7 @@
},
"normalize-path": {
"version": "3.0.0",
- "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
+ "resolved": "http://npm.zooz.co:8083/normalize-path/-/normalize-path-3.0.0.tgz",
"integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
"dev": true
}
@@ -3871,7 +3871,7 @@
},
"dicer": {
"version": "0.3.0",
- "resolved": "https://registry.npmjs.org/dicer/-/dicer-0.3.0.tgz",
+ "resolved": "http://npm.zooz.co:8083/dicer/-/dicer-0.3.0.tgz",
"integrity": "sha512-MdceRRWqltEG2dZqO769g27N/3PXfcKl04VhYnBlo2YhH7zPi88VebsjTKclaOyiuMaGU72hTfw3VkUitGcVCA==",
"requires": {
"streamsearch": "0.1.2"
@@ -5026,7 +5026,7 @@
},
"fill-range": {
"version": "7.0.1",
- "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
+ "resolved": "http://npm.zooz.co:8083/fill-range/-/fill-range-7.0.1.tgz",
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
"dev": true,
"requires": {
@@ -5351,7 +5351,7 @@
},
"fsevents": {
"version": "2.1.2",
- "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.2.tgz",
+ "resolved": "http://npm.zooz.co:8083/fsevents/-/fsevents-2.1.2.tgz",
"integrity": "sha512-R4wDiBwZ0KzpgOWetKDug1FZcYhqYnUYKtfZYt4mD5SBz76q0KR4Q9o7GIPamsVPGmW3EYPPJ0dOOjvx32ldZA==",
"dev": true,
"optional": true
@@ -6114,7 +6114,7 @@
},
"he": {
"version": "1.2.0",
- "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
+ "resolved": "http://npm.zooz.co:8083/he/-/he-1.2.0.tgz",
"integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==",
"dev": true
},
@@ -6573,7 +6573,7 @@
},
"is-binary-path": {
"version": "2.1.0",
- "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
+ "resolved": "http://npm.zooz.co:8083/is-binary-path/-/is-binary-path-2.1.0.tgz",
"integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
"dev": true,
"requires": {
@@ -6666,7 +6666,7 @@
},
"is-finite": {
"version": "1.1.0",
- "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.1.0.tgz",
+ "resolved": "http://npm.zooz.co:8083/is-finite/-/is-finite-1.1.0.tgz",
"integrity": "sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w==",
"dev": true
},
@@ -6707,7 +6707,7 @@
},
"is-number": {
"version": "7.0.0",
- "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+ "resolved": "http://npm.zooz.co:8083/is-number/-/is-number-7.0.0.tgz",
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
"dev": true
},
@@ -7168,7 +7168,7 @@
},
"kind-of": {
"version": "6.0.3",
- "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
+ "resolved": "http://npm.zooz.co:8083/kind-of/-/kind-of-6.0.3.tgz",
"integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw=="
},
"latest-version": {
@@ -7849,7 +7849,7 @@
},
"minimist": {
"version": "1.2.5",
- "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
+ "resolved": "http://npm.zooz.co:8083/minimist/-/minimist-1.2.5.tgz",
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
},
"minimist-options": {
@@ -7931,7 +7931,7 @@
},
"mocha": {
"version": "7.1.1",
- "resolved": "https://registry.npmjs.org/mocha/-/mocha-7.1.1.tgz",
+ "resolved": "http://npm.zooz.co:8083/mocha/-/mocha-7.1.1.tgz",
"integrity": "sha512-3qQsu3ijNS3GkWcccT5Zw0hf/rWvu1fTN9sPvEd81hlwsr30GX2GcDSSoBxo24IR8FelmrAydGC6/1J5QQP4WA==",
"dev": true,
"requires": {
@@ -7963,7 +7963,7 @@
"dependencies": {
"ansi-styles": {
"version": "3.2.1",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+ "resolved": "http://npm.zooz.co:8083/ansi-styles/-/ansi-styles-3.2.1.tgz",
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
"dev": true,
"requires": {
@@ -7972,7 +7972,7 @@
},
"chalk": {
"version": "2.4.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "resolved": "http://npm.zooz.co:8083/chalk/-/chalk-2.4.2.tgz",
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
"dev": true,
"requires": {
@@ -7983,7 +7983,7 @@
"dependencies": {
"supports-color": {
"version": "5.5.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+ "resolved": "http://npm.zooz.co:8083/supports-color/-/supports-color-5.5.0.tgz",
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
"dev": true,
"requires": {
@@ -7994,7 +7994,7 @@
},
"debug": {
"version": "3.2.6",
- "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
+ "resolved": "http://npm.zooz.co:8083/debug/-/debug-3.2.6.tgz",
"integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
"dev": true,
"requires": {
@@ -8003,7 +8003,7 @@
},
"glob": {
"version": "7.1.3",
- "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz",
+ "resolved": "http://npm.zooz.co:8083/glob/-/glob-7.1.3.tgz",
"integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==",
"dev": true,
"requires": {
@@ -8017,7 +8017,7 @@
},
"log-symbols": {
"version": "3.0.0",
- "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-3.0.0.tgz",
+ "resolved": "http://npm.zooz.co:8083/log-symbols/-/log-symbols-3.0.0.tgz",
"integrity": "sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ==",
"dev": true,
"requires": {
@@ -8026,7 +8026,7 @@
},
"mkdirp": {
"version": "0.5.3",
- "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.3.tgz",
+ "resolved": "http://npm.zooz.co:8083/mkdirp/-/mkdirp-0.5.3.tgz",
"integrity": "sha512-P+2gwrFqx8lhew375MQHHeTlY8AuOJSrGf0R5ddkEndUkmwpgUob/vQuBD1V22/Cw1/lJr4x+EjllSezBThzBg==",
"dev": true,
"requires": {
@@ -8035,13 +8035,13 @@
},
"ms": {
"version": "2.1.1",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
+ "resolved": "http://npm.zooz.co:8083/ms/-/ms-2.1.1.tgz",
"integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==",
"dev": true
},
"supports-color": {
"version": "6.0.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz",
+ "resolved": "http://npm.zooz.co:8083/supports-color/-/supports-color-6.0.0.tgz",
"integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==",
"dev": true,
"requires": {
@@ -8460,7 +8460,7 @@
},
"node-environment-flags": {
"version": "1.0.6",
- "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.6.tgz",
+ "resolved": "http://npm.zooz.co:8083/node-environment-flags/-/node-environment-flags-1.0.6.tgz",
"integrity": "sha512-5Evy2epuL+6TM0lCQGpFIj6KwiEsGh1SrHUhTbNX+sLbBtjidPZFAnVK9y5yU1+h//RitLbRHTIMyxQPtxMdHw==",
"dev": true,
"requires": {
@@ -8772,7 +8772,7 @@
},
"object.getownpropertydescriptors": {
"version": "2.1.0",
- "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.0.tgz",
+ "resolved": "http://npm.zooz.co:8083/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.0.tgz",
"integrity": "sha512-Z53Oah9A3TdLoblT7VKJaTDdXdT+lQO+cNpKVnya5JDe9uLvzu1YyY1yFDFrcxrlRgWrEFH0jJtD/IbuwjcEVg==",
"dev": true,
"requires": {
@@ -9172,7 +9172,7 @@
},
"picomatch": {
"version": "2.2.2",
- "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz",
+ "resolved": "http://npm.zooz.co:8083/picomatch/-/picomatch-2.2.2.tgz",
"integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==",
"dev": true
},
@@ -9572,7 +9572,7 @@
},
"readdirp": {
"version": "3.2.0",
- "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.2.0.tgz",
+ "resolved": "http://npm.zooz.co:8083/readdirp/-/readdirp-3.2.0.tgz",
"integrity": "sha512-crk4Qu3pmXwgxdSgGhgA/eXiJAPQiX4GMOZZMXnqKxHX7TaoL+3gQVo/WeuAiogr07DpnfjIMpXXa+PAIvwPGQ==",
"dev": true,
"requires": {
@@ -10000,7 +10000,7 @@
},
"rewire": {
"version": "5.0.0",
- "resolved": "https://registry.npmjs.org/rewire/-/rewire-5.0.0.tgz",
+ "resolved": "http://npm.zooz.co:8083/rewire/-/rewire-5.0.0.tgz",
"integrity": "sha512-1zfitNyp9RH5UDyGGLe9/1N0bMlPQ0WrX0Tmg11kMHBpqwPJI4gfPpP7YngFyLbFmhXh19SToAG0sKKEFcOIJA==",
"dev": true,
"requires": {
@@ -11067,7 +11067,7 @@
},
"streamsearch": {
"version": "0.1.2",
- "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-0.1.2.tgz",
+ "resolved": "http://npm.zooz.co:8083/streamsearch/-/streamsearch-0.1.2.tgz",
"integrity": "sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo="
},
"string-width": {
@@ -11613,7 +11613,7 @@
},
"to-regex-range": {
"version": "5.0.1",
- "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+ "resolved": "http://npm.zooz.co:8083/to-regex-range/-/to-regex-range-5.0.1.tgz",
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
"dev": true,
"requires": {
@@ -12212,7 +12212,7 @@
},
"yargs-unparser": {
"version": "1.6.0",
- "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-1.6.0.tgz",
+ "resolved": "http://npm.zooz.co:8083/yargs-unparser/-/yargs-unparser-1.6.0.tgz",
"integrity": "sha512-W9tKgmSn0DpSatfri0nx52Joq5hVXgeLiqR/5G0sZNDoLZFOr/xjBUDcShCOGNsBnEMNo1KAMBkTej1Hm62HTw==",
"dev": true,
"requires": {
diff --git a/ui/config/webpack.config.js b/ui/config/webpack.config.js
index eb0aa4471..584d07161 100755
--- a/ui/config/webpack.config.js
+++ b/ui/config/webpack.config.js
@@ -34,7 +34,7 @@ module.exports = {
BUCKET_PATH: env.BUCKET_PATH || '/',
}),
new webpack.NamedModulesPlugin(),
- new webpack.EnvironmentPlugin(['NODE_ENV', 'BUCKET_PATH', 'PREDATOR_URL', 'PREDATOR_DOCS_URL']),
+ new webpack.EnvironmentPlugin(['NODE_ENV', 'BUCKET_PATH', 'PREDATOR_URL', 'PREDATOR_DOCS_URL','VERSION']),
new MonacoWebpackPlugin()
]
};
diff --git a/ui/src/App/common/env.js b/ui/src/App/common/env.js
index b43b9f449..124bce55f 100644
--- a/ui/src/App/common/env.js
+++ b/ui/src/App/common/env.js
@@ -1,7 +1,8 @@
module.exports = {
PREDATOR_URL: generatePredatorUrl(),
PREDATOR_DOCS_URL: generatePredatorDocsUrl(),
- BUCKET_PATH: generateBucketPath()
+ BUCKET_PATH: generateBucketPath(),
+ VERSION: process.env.VERSION || 'dev-mode'
};
function generatePredatorUrl() {
diff --git a/ui/src/features/components/DrawerE/index.js b/ui/src/features/components/DrawerE/index.js
index 70f73334b..60ebf74f5 100644
--- a/ui/src/features/components/DrawerE/index.js
+++ b/ui/src/features/components/DrawerE/index.js
@@ -5,7 +5,8 @@ import {connect} from 'react-redux'
import history from '../../../store/history';
import logo from '../../../images/logo.png';
import {FontAwesomeIcon} from '@fortawesome/react-fontawesome';
-
+import {VERSION} from '../../../App/common/env';
+import {faPoll} from "@fortawesome/free-solid-svg-icons";
const Logo = () => {
@@ -56,7 +57,7 @@ class DrawerE extends Component {
flex: 'initial'
}
- const appLogoInnerStyle={
+ const appLogoInnerStyle = {
display: 'flex',
paddingLeft: '0px',
paddingRight: '0',
@@ -66,13 +67,22 @@ class DrawerE extends Component {
return (
} titleStyle={style['appbar-logo']}
titleStyle={appLogoTitleStyle} style={appLogoInnerStyle} className={style.appbar}/>
-
+
{listItemData.map((listItem) => {
@@ -94,7 +104,7 @@ class DrawerE extends Component {
// className={url.includes(nestedItem.navigateTo) ? style['menu-selected'] : undefined}
primaryText={nestedItem.primaryText}
onClick={nestedItem.linkUrl ? () => window.open(nestedItem.linkUrl, '_blank') : () => this.apiClick(`/${nestedItem.navigateTo}`)}
- iconStyle={{fontSize:'5px'}}
+ iconStyle={{fontSize: '5px'}}
leftIcon={nestedItem.icon &&
}
@@ -107,6 +117,15 @@ class DrawerE extends Component {
})}
+
+
+
Predator}
@@ -123,10 +142,34 @@ class DrawerE extends Component {
}
}
+
+const Bottom = () => {
+ return (
+
+
window.open("https://docs.google.com/forms/d/15dozkkA2xBUV7T7ls5XMyBj-JDg5Tj-TXNMp9PkdFsM/viewform?edit_requested=true")}/>
+ v{VERSION}
+
+ )
+}
+
+
function mapStateToProps(state) {
return {
url: state.router.location.pathname
}
}
+
export default connect(mapStateToProps)(DrawerE);
diff --git a/ui/src/features/components/Report/Charts.js b/ui/src/features/components/Report/Charts.js
index 9f7ad3b10..ceb708c85 100644
--- a/ui/src/features/components/Report/Charts.js
+++ b/ui/src/features/components/Report/Charts.js
@@ -21,7 +21,7 @@ const COLORS = [{stroke: "#8884d8", fill: "#8884d8"},
{stroke: "#395B56", fill: "#395B56"},
{stroke: "#617A70", fill: "#617A70"},
{stroke: "#CCC39F", fill: "#CCC39F"},
- {stroke: "#FFFAD1", fill: "#FFFAD1"},
+ {stroke: "#827e5b", fill: "#827e5b"},
];
const COLOR_FAMILY = {
p95: [{stroke: "#BBDEF0", fill: "#BBDEF0"}, {stroke: "#00A6A6", fill: "#00A6A6"}, {
@@ -54,10 +54,10 @@ const getColor = (key, index) => {
};
const filterKeysFromArrayOfObject = (data, graphType, filteredKeys) => {
- const keysToFilter = Object.keys(_.pickBy(filteredKeys, (value) => value));
+ const keysToFilter = Object.keys(_.pickBy(filteredKeys[graphType] || {}, (value) => value));
const filteredData = data.reduce((acc, cur) => {
acc.push(_.omitBy(cur, (value, key) => {
- return keysToFilter.includes(`${graphType}${key}`)
+ return keysToFilter.includes(`${key}`)
}));
return acc;
}, []);
@@ -100,7 +100,6 @@ export const BarChartPredator = ({data = [], keys=[], graphType, onSelectedGraph
export const LineChartPredator = ({data = [], keys = [], labelY, graphType, onSelectedGraphPropertyFilter, filteredKeys}) => {
const filteredData = filterKeysFromArrayOfObject(data, graphType, filteredKeys);
-
return (
{
style={{margin: '5px', display: 'flex', flexDirection: 'row', alignItems: 'center'}}>
{
onSelectedGraphPropertyFilter(graphType, entry.value, value)
diff --git a/ui/src/features/components/Report/compareReports.js b/ui/src/features/components/Report/compareReports.js
index 53d552364..a9e9f31d1 100644
--- a/ui/src/features/components/Report/compareReports.js
+++ b/ui/src/features/components/Report/compareReports.js
@@ -13,19 +13,27 @@ import Snackbar from "material-ui/Snackbar";
import Checkbox from "../../../components/Checkbox/Checkbox";
import Button from "../../../components/Button";
-
class CompareReports extends React.Component {
constructor(props) {
super(props);
this.state = {
reportsList: [],
mergedReports: this.mergeGraphs([]),
- filteredKeys: {}
+ filteredKeys: {
+ latency: {benchmark_p99: true, benchmark_p95: true, benchmark_median: true},
+ rps: {
+ benchmark_mean: true
+ },
+ status_codes_errors: {
+ benchmark_count: true
+ }
+ },
+ enableBenchmark: false
};
}
componentDidUpdate(prevProps, prevState, snapshot) {
- if (prevProps.aggregateReports !== this.props.aggregateReports) {
+ if (prevProps.aggregateReports !== this.props.aggregateReports || prevProps.benchmark !== this.props.benchmark) {
const reportsList = this.props.aggregateReports.map((report) => ({
name: report.alias,
startTime: report.startTime,
@@ -38,16 +46,16 @@ class CompareReports extends React.Component {
const keysToDefaultFilter = reportsList.flatMap((reportInfo) => [`${reportInfo.name}_p95`, `${reportInfo.name}_p99`]);
this.onSelectedGraphPropertyFilter('latency', keysToDefaultFilter, false);
this.setState({reportsList});
- this.setMergedReports(reportsList)
+ this.setMergedReports(reportsList, this.props.benchmark)
}
}
- setMergedReports = (reportsList) => {
+ setMergedReports = (reportsList, benchmark) => {
const reportsNames = reportsList.filter(cur => cur.show).map(cur => cur.name);
const {aggregateReports} = this.props;
const filteredData = aggregateReports.filter((report) => reportsNames.includes(report.alias));
- const mergedReports = this.mergeGraphs(filteredData);
+ const mergedReports = this.mergeGraphs(filteredData, benchmark);
this.setState({mergedReports});
};
@@ -62,23 +70,25 @@ class CompareReports extends React.Component {
this.setState({reportsList: [...reportsList]});
this.setMergedReports(reportsList);
};
+
onSelectedGraphPropertyFilter = (graphType, keys, value) => {
- const {filteredKeys} = this.state;
+ const {filteredKeys = {}} = this.state;
let newFilteredKeys = {...filteredKeys};
if (_.isArray(keys)) {
newFilteredKeys = keys.reduce((acc, cur) => {
- acc[`${graphType}${cur}`] = !value;
+ _.set(acc, `${graphType}.${cur}`, !value);
return acc;
}, filteredKeys)
} else {
- newFilteredKeys[`${graphType}${keys}`] = !value;
+ _.set(newFilteredKeys, `${graphType}.${keys}`, !value);
}
this.setState({filteredKeys: {...newFilteredKeys}});
};
+
render() {
- const {reportsList, mergedReports, filteredKeys} = this.state;
- const {onClose} = this.props;
+ const {reportsList, mergedReports, filteredKeys, enableBenchmark} = this.state;
+ const {onClose, benchmark} = this.props;
return (
Compare reports
+ {
+ benchmark &&
+
+
Enable benchmark
+
{
+ this.onSelectedGraphPropertyFilter('latency', ['benchmark_p99', 'benchmark_p95', 'benchmark_median'], value);
+ this.onSelectedGraphPropertyFilter('rps', ['benchmark_mean'], value);
+ this.onSelectedGraphPropertyFilter('status_codes_errors', ['benchmark_count'], value);
+ this.setState({enableBenchmark: value});
+ }}
+ />
+
+
+ }
Overall Latency
{
- const {getAggregateReports, selectedReports} = this.props;
- const selectedReportsAsList = Object.entries(selectedReports)
- .flatMap(selectedReport => {
- const testId = selectedReport[0];
- const selectedList = Object.entries(selectedReport[1])
- .filter((isSelected) => isSelected[1])
- .map((pairs) => pairs[0]);
- return selectedList.map((reportId) => {
- return {
- testId,
- reportId
- }
- })
- });
- getAggregateReports(selectedReportsAsList);
+ const {getAggregateReports, selectedReportsAsArray, getBenchmark} = this.props;
+ const firstSelected = selectedReportsAsArray[0];
+ const isAllSelectedReportsBelongToSameTest = _.every(selectedReportsAsArray, (data) => data.testId === firstSelected.testId);
+ getAggregateReports(selectedReportsAsArray);
+ if (isAllSelectedReportsBelongToSameTest) {
+ getBenchmark(firstSelected.testId);
+ }
};
- mergeGraphs = (data) => {
+ mergeGraphs = (data, benchmark) => {
const initial = {
latencyGraph: [],
latencyGraphKeys: [],
@@ -166,7 +190,6 @@ class CompareReports extends React.Component {
if (data.length === 0) {
return initial;
}
-
//merged sorted data by time
const result = data.reduce((acc, cur) => {
acc.latencyGraph = mergeSortedArraysByStartTime(acc.latencyGraph, cur.latencyGraph);
@@ -178,15 +201,35 @@ class CompareReports extends React.Component {
acc.rps = mergeSortedArraysByStartTime(acc.rps, cur.rps);
acc.rpsKeys = acc.rpsKeys.concat(cur.rpsKeys);
- acc.errorsBar = acc.errorsBar.concat(cur.errorsBar);
+ acc.errorsBar = mergeArrayOfObjectsPropsByParameter(acc.errorsBar, cur.errorsBar, 'name');
acc.errorsBarKeys = acc.errorsBarKeys.concat(cur.errorsBarKeys);
acc.scenarios = acc.scenarios.concat(cur.scenarios);
return acc;
}, initial);
+ //assign benchmark;
+ if (benchmark) {
+ result.latencyGraph.forEach(function (data) {
+ Object.assign(data, benchmark.latency);
+ });
+ result.rps.forEach(function (data) {
+ Object.assign(data, benchmark.rps);
+ });
+ result.latencyGraphKeys.push(...benchmark.latencyKeys);
+ result.rpsKeys.push(...benchmark.rpsKeys);
+
+ const benchmarkCodeAndErrors = Object.entries({...benchmark.codes, ...benchmark.errors})
+ .map(function ([key, value]) {
+ return {name: key, benchmark_count: value}
+ });
+
+ result.errorsBarKeys.push('benchmark_count');
+ result.errorsBar.push(...benchmarkCodeAndErrors);
+ result.errorsBar = mergeArrayOfObjectsPropsByParameter(result.errorsBar, benchmarkCodeAndErrors, 'name');
+ }
return result;
- }
+ };
componentDidMount() {
@@ -194,7 +237,8 @@ class CompareReports extends React.Component {
}
componentWillUnmount() {
- this.props.getAggregateReportSuccess([])
+ this.props.getAggregateReportSuccess([]);
+ this.props.clearAggregateReportAndBenchmark();
}
};
@@ -203,14 +247,17 @@ function mapStateToProps(state) {
return {
aggregateReports: selectors.getAggregateReportsForCompare(state),
createBenchmarkSucceed: selectors.createBenchmarkSuccess(state),
+ benchmark: selectors.benchmarkWithKeys(state),
}
}
const mapDispatchToProps = {
getAggregateReports: Actions.getAggregateReports,
+ getBenchmark: Actions.getBenchmark,
createBenchmark: Actions.createBenchmark,
createBenchmarkSuccess: Actions.createBenchmarkSuccess,
getAggregateReportSuccess: Actions.getAggregateReportSuccess,
+ clearAggregateReportAndBenchmark: Actions.clearAggregateReportAndBenchmark,
};
const Block = ({header, dataList, style = {}}) => {
@@ -272,22 +319,22 @@ const ReportsList = ({list = [], onChange}) => {
export default connect(mapStateToProps, mapDispatchToProps)(CompareReports);
-function mergeSortedArraysByStartTime(arr1, arr2) {
+function mergeSortedArraysByStartTime(arr1, arr2, assignProps = {}) {
const arr3 = [];
let i = 0, j = 0;
while (i < arr1.length && j < arr2.length) {
if (arr1[i].timeMills < arr2[j].timeMills) {
- arr3.push(arr1[i]);
+ arr3.push(Object.assign({}, arr1[i], assignProps));
i++;
} else if (arr1[i].timeMills === arr2[j].timeMills) {
- const newData = {...arr1[i], ...arr2[j]};
+ const newData = {...arr1[i], ...arr2[j], ...assignProps};
arr3.push(newData);
i++;
j++;
} else {
- arr3.push(arr2[j]);
+ arr3.push(Object.assign({}, arr2[j], assignProps));
j++;
}
@@ -303,3 +350,20 @@ function mergeSortedArraysByStartTime(arr1, arr2) {
return arr3;
}
+
+function mergeArrayOfObjectsPropsByParameter(arr1, arr2, propName) {
+ const resultAsObject = _.groupBy(arr1.concat(arr2), function (data) {
+ return data[propName];
+ });
+
+ return Object.entries(resultAsObject).map(function ([key, value]) {
+ const props = value.reduce((acc, cur) => {
+ return Object.assign(acc, cur);
+ }, {});
+
+ return {
+ [propName]: key,
+ ...props
+ }
+ })
+}
diff --git a/ui/src/features/components/Report/index.js b/ui/src/features/components/Report/index.js
index 87e58fe7e..0cdec7344 100644
--- a/ui/src/features/components/Report/index.js
+++ b/ui/src/features/components/Report/index.js
@@ -12,12 +12,9 @@ import Button from '../../../components/Button';
import Snackbar from "material-ui/Snackbar";
import {BarChartPredator, LineChartPredator} from "./Charts";
import _ from "lodash";
+import Checkbox from "../../../components/Checkbox/Checkbox";
const REFRESH_DATA_INTERVAL = 30000;
-const COLORS = [{stroke: "#8884d8", fill: "#8884d8"},
- {stroke: "#82ca9d", fill: "#82ca9d"},
- {stroke: "#ffc658", fill: "#ffc658"}
-];
class Report extends React.Component {
@@ -25,7 +22,16 @@ class Report extends React.Component {
super(props);
this.state = {
disabledCreateBenchmark: false,
- filteredKeys: {}
+ filteredKeys: {
+ latency: {benchmark_p99: true, benchmark_p95: true, benchmark_median: true},
+ rps: {
+ benchmark_mean: true
+ },
+ status_codes_errors: {
+ benchmark_count: true
+ }
+ },
+ enableBenchmark: false
}
}
@@ -34,34 +40,63 @@ class Report extends React.Component {
this.props.createBenchmark(report.test_id, aggregateReport.benchMark);
this.setState({disabledCreateBenchmark: true})
};
+
+
onSelectedGraphPropertyFilter = (graphType, keys, value) => {
- const {filteredKeys} = this.state;
+ const {filteredKeys = {}} = this.state;
let newFilteredKeys = {...filteredKeys};
if (_.isArray(keys)) {
newFilteredKeys = keys.reduce((acc, cur) => {
- acc[`${graphType}${cur}`] = !value;
+ _.set(acc, `${graphType}.${cur}`, !value);
return acc;
}, filteredKeys)
} else {
- newFilteredKeys[`${graphType}${keys}`] = !value;
+ _.set(newFilteredKeys, `${graphType}.${keys}`, !value);
}
this.setState({filteredKeys: {...newFilteredKeys}});
};
+
+ onExitReport = () => {
+ const {clearAggregateReportAndBenchmark, onClose} = this.props;
+ clearAggregateReportAndBenchmark();
+ onClose();
+ };
+
render() {
- const {report, onClose, aggregateReport} = this.props;
- const {disabledCreateBenchmark,filteredKeys} = this.state;
+ const {report, aggregateReport} = this.props;
+ const {disabledCreateBenchmark, filteredKeys, enableBenchmark} = this.state;
return (
-
+
-
{report.test_name}
+ {report.test_name}
Started at {dateFormat(new Date(report.start_time), "dddd, mmmm dS, yyyy, h:MM:ss TT")}
+ {
+ aggregateReport.isBenchmarkExist &&
+
Enable benchmark
+
{
+ this.onSelectedGraphPropertyFilter('latency', ['benchmark_p99', 'benchmark_p95', 'benchmark_median'], value);
+ this.onSelectedGraphPropertyFilter('rps', ['benchmark_mean'], value);
+ this.onSelectedGraphPropertyFilter('status_codes_errors', ['benchmark_count'], value);
+ this.setState({enableBenchmark: value});
+ }}
+ />
+
+
+ }
Status Codes
RPS
@@ -103,7 +138,7 @@ class Report extends React.Component {
-
+
{
- const {getAggregateReports, report} = this.props;
- getAggregateReports([{testId:report.test_id, reportId:report.report_id}]);
-
- }
+ const {getAggregateReports, getBenchmark, report} = this.props;
+ getAggregateReports([{testId: report.test_id, reportId: report.report_id}]);
+ getBenchmark(report.test_id);
+ };
componentDidMount() {
this.loadData();
@@ -132,6 +167,7 @@ class Report extends React.Component {
componentWillUnmount() {
clearInterval(this.refreshDataInterval);
+ this.props.clearAggregateReportAndBenchmark();
}
};
@@ -148,12 +184,14 @@ const mapDispatchToProps = {
getAggregateReports: Actions.getAggregateReports,
createBenchmark: Actions.createBenchmark,
createBenchmarkSuccess: Actions.createBenchmarkSuccess,
+ getBenchmark: Actions.getBenchmark,
+ clearAggregateReportAndBenchmark: Actions.clearAggregateReportAndBenchmark,
};
const SummeryTable = ({report = {}}) => {
return (
-
+
diff --git a/ui/src/features/configurationColumn.js b/ui/src/features/configurationColumn.js
index e91c9e5f4..ca2a81a31 100644
--- a/ui/src/features/configurationColumn.js
+++ b/ui/src/features/configurationColumn.js
@@ -531,7 +531,7 @@ const Notes = ({data, onEditNote}) => {
const [editMode, setEditMode] = useState(false);
const [editValue, setEditValue] = useState(notes);
const id = uuid();
- const cell = notes.split('\n').map((row) => ({row}
));
+ const cell = notes.split('\n').map((row,index) => ({row}
));
function onKeyDown(e) {
if (e.key === 'Enter') {
diff --git a/ui/src/features/get-last-reports.js b/ui/src/features/get-last-reports.js
index 24ccb7c9b..8f897cbe0 100644
--- a/ui/src/features/get-last-reports.js
+++ b/ui/src/features/get-last-reports.js
@@ -2,7 +2,6 @@ import React from 'react';
import {connect} from 'react-redux';
import * as selectors from './redux/selectors/reportsSelector';
import {createJobSuccess, errorOnStopRunningJob, stopRunningJobSuccess} from './redux/selectors/jobsSelector';
-import {tests} from './redux/selectors/testsSelector';
import Snackbar from 'material-ui/Snackbar';
import style from './style.scss';
import Dialog from './components/Dialog';
@@ -16,9 +15,9 @@ import {createJobRequest} from './requestBuilder';
import {ReactTableComponent} from './../components/ReactTable';
import {getColumns} from './configurationColumn'
import ErrorDialog from "./components/ErrorDialog";
-import FormWrapper from "../components/FormWrapper";
import Button from "../components/Button";
import Loader from "./components/Loader";
+import DeleteDialog from "./components/DeleteDialog";
const REFRESH_DATA_INTERVAL = 30000;
@@ -35,7 +34,8 @@ class getReports extends React.Component {
sortedReports: [],
sortHeader: '',
rerunJob: null,
- showCompareReports: false
+ showCompareReports: false,
+ showDeleteReportWarning: false
};
}
@@ -44,6 +44,11 @@ class getReports extends React.Component {
if (prevProps.reports !== this.props.reports) {
this.setState({sortedReports: [...this.props.reports]})
}
+
+ if (prevProps.deleteReportSuccess === false && this.props.deleteReportSuccess) {
+ this.loadPageData();
+ }
+
}
@@ -89,14 +94,13 @@ class getReports extends React.Component {
this.setState({showReport: null})
}
loadPageData = () => {
- this.props.getTests();
- this.props.getAllReports();
+ this.props.getLastReports();
};
componentWillUnmount() {
this.props.clearSelectedReport();
clearInterval(this.refreshDataInterval);
- this.props.clearReportForCompare();
+ this.props.clearSelectedReports();
}
onSort = (field) => {
@@ -135,10 +139,18 @@ class getReports extends React.Component {
onReportSelected = (testId, reportId, value) => {
this.props.addReportForCompare(testId, reportId, value);
};
+
loader() {
return this.props.processingGetReports ? : 'There is no data'
}
+ onDeleteSelectedReports = () => {
+ this.setState({showDeleteReportWarning: false})
+ this.props.deleteReports(this.props.selectedReportsAsArray)
+
+ };
+
+
render() {
const {showReport, sortHeader, sortedReports, showCompareReports} = this.state;
const {
@@ -147,7 +159,9 @@ class getReports extends React.Component {
errorOnStopRunningJob,
errorCreateBenchmark,
errorEditReport,
- selectedReports
+ deleteReportFailure,
+ selectedReports,
+ selectedReportsAsArray
} = this.props;
const columns = getColumns({
columnsNames,
@@ -159,25 +173,32 @@ class getReports extends React.Component {
onRunTest: this.onRunTest,
onEditNote: this.onEditNote,
onReportSelected: this.onReportSelected,
- selectedReports: this.props.selectedReports
+ selectedReports: selectedReports
});
const feedbackMessage = this.generateFeedbackMessage();
- const error = errorOnGetReports || errorOnGetReport || errorOnStopRunningJob || errorCreateBenchmark || errorEditReport;
-
+ const error = errorOnGetReports || errorOnGetReport || errorOnStopRunningJob || errorCreateBenchmark || errorEditReport || deleteReportFailure;
return (
{showReport &&
}
-
+
+
+
+
+
: null}
+
+ {
+ this.state.showDeleteReportWarning && {
+ this.setState({showDeleteReportWarning: false})
+ }}/>
+ }
{
showCompareReports &&
-
+
}
{feedbackMessage && {
- this.props.getAllReports();
+ this.props.getLastReports();
this.props.clearStopJobSuccess();
this.props.createJobSuccess(undefined);
this.props.editNotesSuccess(false);
+ this.props.setDeleteReportSuccess(false);
this.setState({
rerunJob: null
});
@@ -229,13 +260,18 @@ class getReports extends React.Component {
return `Job created successfully: ${this.props.jobSuccess.id}`;
}
if (this.props.noteSuccess) {
- return `report notes edited successfully`;
+ return `Successfully updated note`;
}
+ if (this.props.deleteReportSuccess) {
+ return `Successfully deleted ${this.props.deleteReportSuccess} reports`;
+ }
+
}
}
+
function mapStateToProps(state) {
return {
reports: selectors.reports(state),
@@ -245,32 +281,34 @@ function mapStateToProps(state) {
errorOnGetReport: selectors.errorOnGetReport(state),
errorOnStopRunningJob: errorOnStopRunningJob(state),
stopRunningJobSuccess: stopRunningJobSuccess(state),
- tests: tests(state),
jobSuccess: createJobSuccess(state),
noteSuccess: selectors.editNotesSuccess(state),
errorEditReport: selectors.editReportFailure(state),
errorCreateBenchmark: selectors.createBenchmarkFailure(state),
selectedReports: selectors.selectedReports(state),
+ selectedReportsAsArray: selectors.selectedReportsAsArray(state),
isAtLeastOneReportSelected: selectors.isAtLeastOneReportSelected(state),
+ deleteReportSuccess: selectors.deleteReportSuccess(state),
+ deleteReportFailure: selectors.deleteReportFailure(state)
}
}
const mapDispatchToProps = {
clearSelectedReport: Actions.clearSelectedReport,
- getAllReports: Actions.getLastReports,
+ getLastReports: Actions.getLastReports,
getReport: Actions.getReport,
stopRunningJob: Actions.stopRunningJob,
clearStopJobSuccess: Actions.clearStopJobSuccess,
createJob: Actions.createJob,
- getTests: Actions.getTests,
createJobSuccess: Actions.createJobSuccess,
editReport: Actions.editReport,
editNotesSuccess: Actions.editReportSuccess,
cleanAllReportsErrors: Actions.cleanAllReportsErrors,
clearErrorOnStopJob: Actions.clearErrorOnStopJob,
addReportForCompare: Actions.addReportForCompare,
- clearReportForCompare: Actions.clearReportForCompare,
-
+ clearSelectedReports: Actions.clearSelectedReports,
+ deleteReports: Actions.deleteReports,
+ setDeleteReportSuccess: Actions.deleteReportSuccess,
};
export default connect(mapStateToProps, mapDispatchToProps)(getReports);
diff --git a/ui/src/features/get-test-reports.js b/ui/src/features/get-test-reports.js
index a37d34754..dc47b4caf 100644
--- a/ui/src/features/get-test-reports.js
+++ b/ui/src/features/get-test-reports.js
@@ -16,6 +16,7 @@ import {createJobSuccess} from "./redux/selectors/jobsSelector";
import Snackbar from 'material-ui/Snackbar';
import ErrorDialog from "./components/ErrorDialog";
import Button from "../components/Button";
+import DeleteDialog from "./components/DeleteDialog";
const noDataMsg = 'There is no data to display.';
const errorMsgGetReports = 'Error occurred while trying to get all reports for test.';
@@ -53,6 +54,9 @@ class getTests extends React.Component {
if (prevProps.reports !== this.props.reports) {
this.setState({sortedReports: [...this.props.reports]})
}
+ if (prevProps.deleteReportSuccess === false && this.props.deleteReportSuccess) {
+ this.props.getReports(this.testId);
+ }
}
onEditNote = (testId, reportId, notes) => {
@@ -113,7 +117,7 @@ class getTests extends React.Component {
this.props.clearErrorOnGetReports();
this.props.clearSelectedReport();
this.props.clearSelectedTest();
- this.props.clearReportForCompare();
+ this.props.clearSelectedReports();
}
loader() {
@@ -130,9 +134,22 @@ class getTests extends React.Component {
this.props.addReportForCompare(testId, reportId, value);
};
+ onDeleteSelectedReports = () => {
+ this.setState({showDeleteReportWarning: false})
+ this.props.deleteReports(this.props.selectedReportsAsArray)
+ };
+
render() {
const noDataText = this.props.errorOnGetReports ? errorMsgGetReports : this.loader();
const {sortHeader, sortedReports} = this.state;
+ const {
+ errorCreateBenchmark,
+ errorEditReport,
+ selectedReports,
+ selectedReportsAsArray,
+ deleteReportFailure,
+ } = this.props;
+
const columns = getColumns({
columnsNames,
sortHeader,
@@ -143,29 +160,34 @@ class getTests extends React.Component {
onRunTest: this.onRunTest,
onEditNote: this.onEditNote,
onReportSelected: this.onReportSelected,
- selectedReports: this.props.selectedReports
+ selectedReports: selectedReports,
});
const {showReport, showCompareReports} = this.state;
- const {
- errorCreateBenchmark,
- errorEditReport,
- selectedReports,
- } = this.props;
+
const feedbackMessage = this.generateFeedbackMessage();
- const error = errorCreateBenchmark || errorEditReport;
+ const error = errorCreateBenchmark || errorEditReport || deleteReportFailure;
return (
0 && `${this.props.reports[0].test_name} Reports`}
description={DESCRIPTION}>
-
+
+
+
+
+
+
}
{this.state.openViewReport ?