No news.
: null;
return (
diff --git a/web/package-lock.json b/web/package-lock.json
index 29c9b28f0..24797132a 100644
--- a/web/package-lock.json
+++ b/web/package-lock.json
@@ -132,9 +132,9 @@
}
},
"@hapi/boom": {
- "version": "9.1.2",
- "resolved": "https://registry.npmjs.org/@hapi/boom/-/boom-9.1.2.tgz",
- "integrity": "sha512-uJEJtiNHzKw80JpngDGBCGAmWjBtzxDCz17A9NO2zCi8LLBlb5Frpq4pXwyN+2JQMod4pKz5BALwyneCgDg89Q==",
+ "version": "9.1.3",
+ "resolved": "https://registry.npmjs.org/@hapi/boom/-/boom-9.1.3.tgz",
+ "integrity": "sha512-RlrGyZ603hE/eRTZtTltocRm50HHmrmL3kGOP0SQ9MasazlW1mt/fkv4C5P/6rnpFXjwld/POFX1C8tMZE3ldg==",
"requires": {
"@hapi/hoek": "9.x.x"
}
@@ -162,9 +162,9 @@
"dev": true
},
"@next/env": {
- "version": "10.2.3",
- "resolved": "https://registry.npmjs.org/@next/env/-/env-10.2.3.tgz",
- "integrity": "sha512-uBOjRBjsWC4C8X3DfmWWP6ekwLnf2JCCwQX9KVnJtJkqfDsv1yQPakdOEwvJzXQc3JC/v5KKffYPVmV2wHXCgQ=="
+ "version": "11.0.1",
+ "resolved": "https://registry.npmjs.org/@next/env/-/env-11.0.1.tgz",
+ "integrity": "sha512-yZfKh2U6R9tEYyNUrs2V3SBvCMufkJ07xMH5uWy8wqcl5gAXoEw6A/1LDqwX3j7pUutF9d1ZxpdGDA3Uag+aQQ=="
},
"@next/eslint-plugin-next": {
"version": "11.0.1",
@@ -173,14 +173,14 @@
"dev": true
},
"@next/polyfill-module": {
- "version": "10.2.3",
- "resolved": "https://registry.npmjs.org/@next/polyfill-module/-/polyfill-module-10.2.3.tgz",
- "integrity": "sha512-OkeY4cLhzfYbXxM4fd+6V4s5pTPuyfKSlavItfNRA6PpS7t1/R6YjO7S7rB8tu1pbTGuDHGIdE1ioDv15bAbDQ=="
+ "version": "11.0.1",
+ "resolved": "https://registry.npmjs.org/@next/polyfill-module/-/polyfill-module-11.0.1.tgz",
+ "integrity": "sha512-Cjs7rrKCg4CF4Jhri8PCKlBXhszTfOQNl9AjzdNy4K5jXFyxyoSzuX2rK4IuoyE+yGp5A3XJCBEmOQ4xbUp9Mg=="
},
"@next/react-dev-overlay": {
- "version": "10.2.3",
- "resolved": "https://registry.npmjs.org/@next/react-dev-overlay/-/react-dev-overlay-10.2.3.tgz",
- "integrity": "sha512-E6g2jws4YW94l0lMMopBVKIZK2mEHfSBvM0d9dmzKG9L/A/kEq6LZCB4SiwGJbNsAdlk2y3USDa0oNbpA+m5Kw==",
+ "version": "11.0.1",
+ "resolved": "https://registry.npmjs.org/@next/react-dev-overlay/-/react-dev-overlay-11.0.1.tgz",
+ "integrity": "sha512-lvUjMVpLsgzADs9Q8wtC5LNqvfdN+M0BDMSrqr04EDWAyyX0vURHC9hkvLbyEYWyh+WW32pwjKBXdkMnJhoqMg==",
"requires": {
"@babel/code-frame": "7.12.11",
"anser": "1.4.9",
@@ -233,9 +233,9 @@
}
},
"@next/react-refresh-utils": {
- "version": "10.2.3",
- "resolved": "https://registry.npmjs.org/@next/react-refresh-utils/-/react-refresh-utils-10.2.3.tgz",
- "integrity": "sha512-qtBF56vPC6d6a8p7LYd0iRjW89fhY80kAIzmj+VonvIGjK/nymBjcFUhbKiMFqlhsarCksnhwX+Zmn95Dw9qvA=="
+ "version": "11.0.1",
+ "resolved": "https://registry.npmjs.org/@next/react-refresh-utils/-/react-refresh-utils-11.0.1.tgz",
+ "integrity": "sha512-K347DM6Z7gBSE+TfUaTTceWvbj0B6iNAsFZXbFZOlfg3uyz2sbKpzPYYFocCc27yjLaS8OfR8DEdS2mZXi8Saw=="
},
"@nodelib/fs.scandir": {
"version": "2.1.3",
@@ -263,19 +263,6 @@
"fastq": "^1.6.0"
}
},
- "@opentelemetry/api": {
- "version": "0.14.0",
- "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-0.14.0.tgz",
- "integrity": "sha512-L7RMuZr5LzMmZiQSQDy9O1jo0q+DaLy6XpYJfIGfYSfoJA5qzYwUP3sP1uMIQ549DvxAgM3ng85EaPTM/hUHwQ==",
- "requires": {
- "@opentelemetry/context-base": "^0.14.0"
- }
- },
- "@opentelemetry/context-base": {
- "version": "0.14.0",
- "resolved": "https://registry.npmjs.org/@opentelemetry/context-base/-/context-base-0.14.0.tgz",
- "integrity": "sha512-sDOAZcYwynHFTbLo6n8kIbLiVF3a3BLkrmehJUyEbT9F+Smbi47kLGS2gG2g0fjBLR/Lr1InPD7kXL7FaTqEkw=="
- },
"@rushstack/eslint-patch": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.0.6.tgz",
@@ -721,101 +708,6 @@
"integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
"dev": true
},
- "array.prototype.filter": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/array.prototype.filter/-/array.prototype.filter-1.0.0.tgz",
- "integrity": "sha512-TfO1gz+tLm+Bswq0FBOXPqAchtCr2Rn48T8dLJoRFl8NoEosjZmzptmuo1X8aZBzZcqsR1W8U761tjACJtngTQ==",
- "requires": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.3",
- "es-abstract": "^1.18.0",
- "es-array-method-boxes-properly": "^1.0.0",
- "is-string": "^1.0.5"
- },
- "dependencies": {
- "es-abstract": {
- "version": "1.18.0",
- "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0.tgz",
- "integrity": "sha512-LJzK7MrQa8TS0ja2w3YNLzUgJCGPdPOV1yVvezjNnS89D+VR08+Szt2mz3YB2Dck/+w5tfIq/RoUAFqJJGM2yw==",
- "requires": {
- "call-bind": "^1.0.2",
- "es-to-primitive": "^1.2.1",
- "function-bind": "^1.1.1",
- "get-intrinsic": "^1.1.1",
- "has": "^1.0.3",
- "has-symbols": "^1.0.2",
- "is-callable": "^1.2.3",
- "is-negative-zero": "^2.0.1",
- "is-regex": "^1.1.2",
- "is-string": "^1.0.5",
- "object-inspect": "^1.9.0",
- "object-keys": "^1.1.1",
- "object.assign": "^4.1.2",
- "string.prototype.trimend": "^1.0.4",
- "string.prototype.trimstart": "^1.0.4",
- "unbox-primitive": "^1.0.0"
- }
- },
- "has-symbols": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz",
- "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw=="
- },
- "is-callable": {
- "version": "1.2.3",
- "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.3.tgz",
- "integrity": "sha512-J1DcMe8UYTBSrKezuIUTUwjXsho29693unXM2YhJUTR2txK/eG47bvNa/wipPFmZFgr/N6f1GA66dv0mEyTIyQ=="
- },
- "is-negative-zero": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz",
- "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w=="
- },
- "is-regex": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.3.tgz",
- "integrity": "sha512-qSVXFz28HM7y+IWX6vLCsexdlvzT1PJNFSBuaQLQ5o0IEw8UDYW6/2+eCMVyIsbM8CNLX2a/QWmSpyxYEHY7CQ==",
- "requires": {
- "call-bind": "^1.0.2",
- "has-symbols": "^1.0.2"
- }
- },
- "object-inspect": {
- "version": "1.10.3",
- "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.10.3.tgz",
- "integrity": "sha512-e5mCJlSH7poANfC8z8S9s9S2IN5/4Zb3aZ33f5s8YqoazCFzNLloLU8r5VCG+G7WoqLvAAZoVMcy3tp/3X0Plw=="
- },
- "object.assign": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz",
- "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==",
- "requires": {
- "call-bind": "^1.0.0",
- "define-properties": "^1.1.3",
- "has-symbols": "^1.0.1",
- "object-keys": "^1.1.1"
- }
- },
- "string.prototype.trimend": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz",
- "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==",
- "requires": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.3"
- }
- },
- "string.prototype.trimstart": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz",
- "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==",
- "requires": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.3"
- }
- }
- }
- },
"array.prototype.flat": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.4.tgz",
@@ -891,12 +783,9 @@
"integrity": "sha512-8eLCg00W9pIRZSB781UUX/H6Oskmm8xloZfr09lz5bikRpBVDlJ3hRVuxxP1SxcwsEYfJ4IU8Q19Y8/893r3rQ=="
},
"available-typed-arrays": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.3.tgz",
- "integrity": "sha512-CuPhFULixV/d89POo1UG4GqGbR7dmrefY2ZdmsYakeR4gOSJXoF7tfeaiqMHGOMrlTiJoeEs87fpLsBYmE2BMw==",
- "requires": {
- "array.prototype.filter": "^1.0.0"
- }
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.4.tgz",
+ "integrity": "sha512-SA5mXJWrId1TaQjfxUYghbqQ/hYioKmLJvPJyDuYRtXXenFNMjj4hSSt1Cf1xsuXSXrtxrVC5Ot4eU6cOtBDdA=="
},
"axe-core": {
"version": "4.1.2",
@@ -1088,9 +977,9 @@
"dev": true
},
"caniuse-lite": {
- "version": "1.0.30001228",
- "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001228.tgz",
- "integrity": "sha512-QQmLOGJ3DEgokHbMSA8cj2a+geXqmnpyOFT0lhQV6P3/YOJvGDEwoedcwxEQ30gJIwIIunHIicunJ2rzK5gB2A=="
+ "version": "1.0.30001243",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001243.tgz",
+ "integrity": "sha512-vNxw9mkTBtkmLFnJRv/2rhs1yufpDfCkBZexG3Y0xdOH2Z/eE/85E4Dl5j1YUN34nZVsSp6vVRFQRrez9wJMRA=="
},
"chalk": {
"version": "2.4.2",
@@ -1139,21 +1028,13 @@
"optional": true
},
"chartkick": {
- "version": "4.0.3",
- "resolved": "https://registry.npmjs.org/chartkick/-/chartkick-4.0.3.tgz",
- "integrity": "sha512-e2WhXYE0VsevyTxol2J4WaHz26iuuSpduK9BVkvIIVrIt6TFlDw7Vm4iXSYIAsDMdC9/UsIV2ZtYIldMMXpvlA==",
+ "version": "4.0.5",
+ "resolved": "https://registry.npmjs.org/chartkick/-/chartkick-4.0.5.tgz",
+ "integrity": "sha512-xKak4Fsgfvp1hj/LykRKkniDMaZASx2A4TdVc/sfsiNFFNf1m+D7PGwP1vgj1UsbsCjOCSfGWWyJpOYxkUCBug==",
"requires": {
"chart.js": ">=3.0.2",
"chartjs-adapter-date-fns": ">=2.0.0",
"date-fns": ">=2.0.0"
- },
- "dependencies": {
- "chart.js": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-3.1.0.tgz",
- "integrity": "sha512-bKJi2VbC4fqZXlLbK7LKVvmG9crjoG9anfp96utZLyIGPuCx+YN+5/HDXy98QGt3lf74T8gKUPISUZL222tDJQ==",
- "optional": true
- }
}
},
"chokidar": {
@@ -1469,9 +1350,9 @@
"integrity": "sha512-fRA+BaAWOR/yr/t7T9E9GJztHPeFjj8U35ajyAjCDtAAnTn1Rc1f6W6VGPJrO1tkQv9zWu+JRof7z6oQtiYVFQ=="
},
"electron-to-chromium": {
- "version": "1.3.736",
- "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.736.tgz",
- "integrity": "sha512-DY8dA7gR51MSo66DqitEQoUMQ0Z+A2DSXFi7tK304bdTVqczCAfUuyQw6Wdg8hIoo5zIxkU1L24RQtUce1Ioig=="
+ "version": "1.3.771",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.771.tgz",
+ "integrity": "sha512-zHMomTqkpnAD9W5rhXE1aiU3ogGFrqWzdvM4C6222SREiqsWQb2w0S7P2Ii44qCaGimmAP1z+OydllM438uJyA=="
},
"elliptic": {
"version": "6.5.4",
@@ -1555,11 +1436,6 @@
"string.prototype.trimstart": "^1.0.1"
}
},
- "es-array-method-boxes-properly": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz",
- "integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA=="
- },
"es-to-primitive": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz",
@@ -2850,6 +2726,14 @@
"integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==",
"dev": true
},
+ "image-size": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/image-size/-/image-size-1.0.0.tgz",
+ "integrity": "sha512-JLJ6OwBfO1KcA+TvJT+v8gbE6iWbj24LyDNFgFEN0lzegn6cC6a/p3NIDaepMsJjQjlUWqIC7wJv8lBFxPNjcw==",
+ "requires": {
+ "queue": "6.0.2"
+ }
+ },
"import-fresh": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
@@ -3067,9 +2951,9 @@
},
"dependencies": {
"es-abstract": {
- "version": "1.18.0",
- "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0.tgz",
- "integrity": "sha512-LJzK7MrQa8TS0ja2w3YNLzUgJCGPdPOV1yVvezjNnS89D+VR08+Szt2mz3YB2Dck/+w5tfIq/RoUAFqJJGM2yw==",
+ "version": "1.18.3",
+ "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.3.tgz",
+ "integrity": "sha512-nQIr12dxV7SSxE6r6f1l3DtAeEYdsGpps13dR0TwJg1S8gyp4ZPgy3FZcHBgbiQqnoqSTb+oC+kO4UQ0C/J8vw==",
"requires": {
"call-bind": "^1.0.2",
"es-to-primitive": "^1.2.1",
@@ -3079,14 +2963,14 @@
"has-symbols": "^1.0.2",
"is-callable": "^1.2.3",
"is-negative-zero": "^2.0.1",
- "is-regex": "^1.1.2",
- "is-string": "^1.0.5",
- "object-inspect": "^1.9.0",
+ "is-regex": "^1.1.3",
+ "is-string": "^1.0.6",
+ "object-inspect": "^1.10.3",
"object-keys": "^1.1.1",
"object.assign": "^4.1.2",
"string.prototype.trimend": "^1.0.4",
"string.prototype.trimstart": "^1.0.4",
- "unbox-primitive": "^1.0.0"
+ "unbox-primitive": "^1.0.1"
},
"dependencies": {
"has-symbols": {
@@ -3122,6 +3006,11 @@
}
}
},
+ "is-string": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.6.tgz",
+ "integrity": "sha512-2gdzbKUuqtQ3lYNrUTQYoClPhm7oQu4UdpSZMp1/DGgkHBT8E2Z1l0yMdb6D4zNAxwDiMv8MdulKROJGNl0Q0w=="
+ },
"object-inspect": {
"version": "1.10.3",
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.10.3.tgz",
@@ -3673,17 +3562,16 @@
"dev": true
},
"next": {
- "version": "10.2.3",
- "resolved": "https://registry.npmjs.org/next/-/next-10.2.3.tgz",
- "integrity": "sha512-dkM1mIfnORtGyzw/Yme8RdqNxlCMZyi4Lqj56F01/yHbe1ZtOaJ0cyqqRB4RGiPhjGGh0319f8ddjDyO1605Ow==",
+ "version": "11.0.1",
+ "resolved": "https://registry.npmjs.org/next/-/next-11.0.1.tgz",
+ "integrity": "sha512-yR7be7asNbvpVNpi6xxEg28wZ7Gqmj1nOt0sABH9qORmF3+pms2KZ7Cng33oK5nqPIzEEFJD0pp2PCe3/ueMIg==",
"requires": {
"@babel/runtime": "7.12.5",
"@hapi/accept": "5.0.2",
- "@next/env": "10.2.3",
- "@next/polyfill-module": "10.2.3",
- "@next/react-dev-overlay": "10.2.3",
- "@next/react-refresh-utils": "10.2.3",
- "@opentelemetry/api": "0.14.0",
+ "@next/env": "11.0.1",
+ "@next/polyfill-module": "11.0.1",
+ "@next/react-dev-overlay": "11.0.1",
+ "@next/react-refresh-utils": "11.0.1",
"assert": "2.0.0",
"ast-types": "0.13.2",
"browserify-zlib": "0.2.0",
@@ -3701,6 +3589,7 @@
"find-cache-dir": "3.3.1",
"get-orientation": "1.1.2",
"https-browserify": "1.0.0",
+ "image-size": "1.0.0",
"jest-worker": "27.0.0-next.5",
"native-url": "0.3.4",
"node-fetch": "2.6.1",
@@ -3715,7 +3604,7 @@
"prop-types": "15.7.2",
"querystring-es3": "0.2.1",
"raw-body": "2.4.1",
- "react-is": "16.13.1",
+ "react-is": "17.0.2",
"react-refresh": "0.8.3",
"stream-browserify": "3.0.0",
"stream-http": "3.1.1",
@@ -3736,6 +3625,11 @@
"requires": {
"regenerator-runtime": "^0.13.4"
}
+ },
+ "react-is": {
+ "version": "17.0.2",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
+ "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w=="
}
}
},
@@ -3909,9 +3803,9 @@
}
},
"node-releases": {
- "version": "1.1.72",
- "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.72.tgz",
- "integrity": "sha512-LLUo+PpH3dU6XizX3iVoubUNheF/owjXCZZ5yACDxNnPtgFuludV1ZL3ayK1kVep42Rmm0+R9/Y60NQbZ2bifw=="
+ "version": "1.1.73",
+ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.73.tgz",
+ "integrity": "sha512-uW7fodD6pyW2FZNZnp/Z3hvWKeEW1Y8R1+1CnErE8cXFXzl5blBOoVB41CvMer6P6Q0S5FXDwcHgFd1Wj0U9zg=="
},
"normalize-package-data": {
"version": "2.5.0",
@@ -4593,6 +4487,14 @@
"resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz",
"integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM="
},
+ "queue": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/queue/-/queue-6.0.2.tgz",
+ "integrity": "sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==",
+ "requires": {
+ "inherits": "~2.0.3"
+ }
+ },
"randombytes": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
@@ -6005,14 +5907,21 @@
"integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA=="
},
"unbox-primitive": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.0.tgz",
- "integrity": "sha512-P/51NX+JXyxK/aigg1/ZgyccdAxm5K1+n8+tvqSntjOivPt19gvm1VC49RWYetsiub8WViUchdxl/KWHHB0kzA==",
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz",
+ "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==",
"requires": {
"function-bind": "^1.1.1",
- "has-bigints": "^1.0.0",
- "has-symbols": "^1.0.0",
- "which-boxed-primitive": "^1.0.1"
+ "has-bigints": "^1.0.1",
+ "has-symbols": "^1.0.2",
+ "which-boxed-primitive": "^1.0.2"
+ },
+ "dependencies": {
+ "has-symbols": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz",
+ "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw=="
+ }
}
},
"unified": {
diff --git a/web/package.json b/web/package.json
index ab51b6f41..8b09d066a 100644
--- a/web/package.json
+++ b/web/package.json
@@ -12,10 +12,11 @@
"@ant-design/icons": "^4.6.2",
"antd": "^4.16.6",
"chart.js": "^3.4.1",
+ "chartkick": "^4.0.5",
"classnames": "^2.3.1",
"date-fns": "^2.22.1",
"markdown-it": "^12.1.0",
- "next": "^10.2.3",
+ "next": "^11.0.1",
"prop-types": "^15.7.2",
"rc-util": "^5.13.2",
"react": "^17.0.2",
diff --git a/web/pages/access-tokens.tsx b/web/pages/access-tokens.tsx
index 76c0e33e8..514ca45ed 100644
--- a/web/pages/access-tokens.tsx
+++ b/web/pages/access-tokens.tsx
@@ -1,5 +1,17 @@
import React, { useState, useEffect } from 'react';
-import { Table, Tag, Space, Button, Modal, Checkbox, Input, Typography, Tooltip, Row, Col } from 'antd';
+import {
+ Table,
+ Tag,
+ Space,
+ Button,
+ Modal,
+ Checkbox,
+ Input,
+ Typography,
+ Tooltip,
+ Row,
+ Col,
+} from 'antd';
import { DeleteOutlined } from '@ant-design/icons';
import format from 'date-fns/format';
@@ -26,7 +38,7 @@ const availableScopes = {
},
};
-function convertScopeStringToTag(scopeString) {
+function convertScopeStringToTag(scopeString: string) {
if (!scopeString || !availableScopes[scopeString]) {
return null;
}
@@ -50,9 +62,10 @@ function NewTokenModal(props: Props) {
const [selectedScopes, setSelectedScopes] = useState([]);
const [name, setName] = useState('');
- const scopes = Object.keys(availableScopes).map(key => {
- return { value: key, label: availableScopes[key].description };
- });
+ const scopes = Object.keys(availableScopes).map(key => ({
+ value: key,
+ label: availableScopes[key].description,
+ }));
function onChange(checkedValues) {
setSelectedScopes(checkedValues);
@@ -73,9 +86,11 @@ function NewTokenModal(props: Props) {
function selectAll() {
setSelectedScopes(Object.keys(availableScopes));
}
- const checkboxes = scopes.map(function (singleEvent) {
- return (
-
- {checkboxes}
-
+ {checkboxes}
@@ -182,13 +195,7 @@ export default function AccessTokens() {
title: 'Scopes',
dataIndex: 'scopes',
key: 'scopes',
- render: scopes => (
- <>
- {scopes.map(scope => {
- return convertScopeStringToTag(scope);
- })}
- >
- ),
+ render: ({ map }: string[]) => <>{map(scope => convertScopeStringToTag(scope))}>,
},
{
title: 'Last Used',
diff --git a/web/pages/actions.tsx b/web/pages/actions.tsx
index 4c5e489ed..52915826c 100644
--- a/web/pages/actions.tsx
+++ b/web/pages/actions.tsx
@@ -1,24 +1,15 @@
-// comment
-
-import React, { useState, useEffect, useContext } from 'react';
-import { Table, Space, Button, Modal, Checkbox, Input, Typography } from 'antd';
-import { ServerStatusContext } from '../utils/server-status-context';
import { DeleteOutlined } from '@ant-design/icons';
-import isValidUrl, { DEFAULT_TEXTFIELD_URL_PATTERN } from '../utils/urls';
+import { Button, Checkbox, Input, Modal, Space, Table, Typography } from 'antd';
+import React, { useContext, useEffect, useState } from 'react';
import FormStatusIndicator from '../components/config/form-status-indicator';
import {
- createInputStatus,
- StatusState,
- STATUS_ERROR,
- STATUS_PROCESSING,
- STATUS_SUCCESS,
-} from '../utils/input-statuses';
-
-import {
- postConfigUpdateToAPI,
API_EXTERNAL_ACTIONS,
+ postConfigUpdateToAPI,
RESET_TIMEOUT,
} from '../utils/config-constants';
+import { createInputStatus, STATUS_ERROR, STATUS_SUCCESS } from '../utils/input-statuses';
+import { ServerStatusContext } from '../utils/server-status-context';
+import isValidUrl, { DEFAULT_TEXTFIELD_URL_PATTERN } from '../utils/urls';
const { Title, Paragraph } = Typography;
let resetTimer = null;
@@ -156,6 +147,81 @@ export default function Actions() {
setActions(externalActions || []);
}, [externalActions]);
+ async function save(actionsData) {
+ await postConfigUpdateToAPI({
+ apiPath: API_EXTERNAL_ACTIONS,
+ data: { value: actionsData },
+ onSuccess: () => {
+ setFieldInConfigState({ fieldName: 'externalActions', value: actionsData, path: '' });
+ setSubmitStatus(createInputStatus(STATUS_SUCCESS, 'Updated.'));
+ resetTimer = setTimeout(resetStates, RESET_TIMEOUT);
+ },
+ onError: (message: string) => {
+ console.log(message);
+ setSubmitStatus(createInputStatus(STATUS_ERROR, message));
+ resetTimer = setTimeout(resetStates, RESET_TIMEOUT);
+ },
+ });
+ }
+
+ async function handleDelete(action) {
+ const actionsData = [...actions];
+ const index = actions.findIndex(item => item.url === action.url);
+ actionsData.splice(index, 1);
+
+ try {
+ setActions(actionsData);
+ save(actionsData);
+ } catch (error) {
+ console.error(error);
+ }
+ }
+
+ async function handleSave(
+ url: string,
+ title: string,
+ description: string,
+ icon: string,
+ color: string,
+ openExternally: boolean,
+ ) {
+ try {
+ const actionsData = [...actions];
+ const updatedActions = actionsData.concat({
+ url,
+ title,
+ description,
+ icon,
+ color,
+ openExternally,
+ });
+ setActions(updatedActions);
+ await save(updatedActions);
+ } catch (error) {
+ console.error(error);
+ }
+ }
+
+ const showCreateModal = () => {
+ setIsModalVisible(true);
+ };
+
+ const handleModalSaveButton = (
+ actionUrl: string,
+ actionTitle: string,
+ actionDescription: string,
+ actionIcon: string,
+ actionColor: string,
+ openExternally: boolean,
+ ) => {
+ setIsModalVisible(false);
+ handleSave(actionUrl, actionTitle, actionDescription, actionIcon, actionColor, openExternally);
+ };
+
+ const handleModalCancelButton = () => {
+ setIsModalVisible(false);
+ };
+
const columns = [
{
title: '',
@@ -185,103 +251,23 @@ export default function Actions() {
title: 'Icon',
dataIndex: 'icon',
key: 'icon',
- render: (url: string) => {
- return url ? : null;
- },
+ render: (url: string) => (url ? : null),
},
{
title: 'Color',
dataIndex: 'color',
key: 'color',
- render: (color: string) => {
- return color ?
{color}
: null;
- },
+ render: (color: string) =>
+ color ? {color}
: null,
},
{
title: 'Opens',
dataIndex: 'openExternally',
key: 'openExternally',
- render: (openExternally: boolean) => {
- return openExternally ? 'In a new tab' : 'In a modal';
- },
+ render: (openExternally: boolean) => (openExternally ? 'In a new tab' : 'In a modal'),
},
];
- async function handleDelete(action) {
- let actionsData = [...actions];
- const index = actions.findIndex(item => item.url === action.url);
- actionsData.splice(index, 1);
-
- setActions(actionsData);
- save(actionsData);
- try {
- } catch (error) {
- console.error(error);
- }
- }
-
- async function handleSave(
- url: string,
- title: string,
- description: string,
- icon: string,
- color: string,
- openExternally: boolean,
- ) {
- try {
- let actionsData = [...actions];
- const updatedActions = actionsData.concat({
- url,
- title,
- description,
- icon,
- color,
- openExternally,
- });
- setActions(updatedActions);
- await save(updatedActions);
- } catch (error) {
- console.error(error);
- }
- }
-
- async function save(actionsData) {
- await postConfigUpdateToAPI({
- apiPath: API_EXTERNAL_ACTIONS,
- data: { value: actionsData },
- onSuccess: () => {
- setFieldInConfigState({ fieldName: 'externalActions', value: actionsData, path: '' });
- setSubmitStatus(createInputStatus(STATUS_SUCCESS, 'Updated.'));
- resetTimer = setTimeout(resetStates, RESET_TIMEOUT);
- },
- onError: (message: string) => {
- console.log(message);
- setSubmitStatus(createInputStatus(STATUS_ERROR, message));
- resetTimer = setTimeout(resetStates, RESET_TIMEOUT);
- },
- });
- }
-
- const showCreateModal = () => {
- setIsModalVisible(true);
- };
-
- const handleModalSaveButton = (
- actionUrl: string,
- actionTitle: string,
- actionDescription: string,
- actionIcon: string,
- actionColor: string,
- openExternally: boolean,
- ) => {
- setIsModalVisible(false);
- handleSave(actionUrl, actionTitle, actionDescription, actionIcon, actionColor, openExternally);
- };
-
- const handleModalCancelButton = () => {
- setIsModalVisible(false);
- };
-
return (
External Actions
diff --git a/web/pages/config-chat.tsx b/web/pages/config-chat.tsx
index c6381bfaf..cbecd0ec6 100644
--- a/web/pages/config-chat.tsx
+++ b/web/pages/config-chat.tsx
@@ -1,14 +1,14 @@
-import React, { useState, useContext, useEffect } from 'react';
import { Typography } from 'antd';
+import React, { useContext, useEffect, useState } from 'react';
+import { TEXTFIELD_TYPE_TEXTAREA } from '../components/config/form-textfield';
+import TextFieldWithSubmit from '../components/config/form-textfield-with-submit';
+import ToggleSwitch from '../components/config/form-toggleswitch';
+import { UpdateArgs } from '../types/config-section';
import {
FIELD_PROPS_DISABLE_CHAT,
TEXTFIELD_PROPS_CHAT_USERNAME_BLOCKLIST,
} from '../utils/config-constants';
import { ServerStatusContext } from '../utils/server-status-context';
-import ToggleSwitch from '../components/config/form-toggleswitch';
-import { UpdateArgs } from '../types/config-section';
-import { TEXTFIELD_TYPE_TEXTAREA } from '../components/config/form-textfield';
-import TextFieldWithSubmit from '../components/config/form-textfield-with-submit';
export default function ConfigChat() {
const { Title } = Typography;
@@ -19,6 +19,13 @@ export default function ConfigChat() {
const { chatDisabled } = serverConfig;
const { usernameBlocklist } = serverConfig;
+ const handleFieldChange = ({ fieldName, value }: UpdateArgs) => {
+ setFormDataValues({
+ ...formDataValues,
+ [fieldName]: value,
+ });
+ };
+
function handleChatDisableChange(disabled: boolean) {
handleFieldChange({ fieldName: 'chatDisabled', value: disabled });
}
@@ -38,13 +45,6 @@ export default function ConfigChat() {
return null;
}
- const handleFieldChange = ({ fieldName, value }: UpdateArgs) => {
- setFormDataValues({
- ...formDataValues,
- [fieldName]: value,
- });
- };
-
return (
Chat Settings
diff --git a/web/pages/config-video.tsx b/web/pages/config-video.tsx
index 560d94d0d..770b9955b 100644
--- a/web/pages/config-video.tsx
+++ b/web/pages/config-video.tsx
@@ -1,11 +1,10 @@
+import { Col, Collapse, Row, Typography } from 'antd';
import React from 'react';
-import { Typography, Row, Col, Collapse } from 'antd';
-
-import VideoVariantsTable from '../components/config/video-variants-table';
-import VideoLatency from '../components/config/video-latency';
import VideoCodecSelector from '../components/config/video-codec-selector';
-const { Panel } = Collapse;
+import VideoLatency from '../components/config/video-latency';
+import VideoVariantsTable from '../components/config/video-variants-table';
+const { Panel } = Collapse;
const { Title } = Typography;
export default function ConfigVideoSettings() {
diff --git a/web/pages/offline-notice.tsx b/web/pages/offline-notice.tsx
index f96dc5b45..d56a85ab5 100644
--- a/web/pages/offline-notice.tsx
+++ b/web/pages/offline-notice.tsx
@@ -1,28 +1,34 @@
-import Link from 'next/link';
-import { Card, Row, Col, Input, Collapse, Typography } from 'antd';
import {
- MessageTwoTone,
- QuestionCircleTwoTone,
BookTwoTone,
+ MessageTwoTone,
PlaySquareTwoTone,
ProfileTwoTone,
+ QuestionCircleTwoTone,
} from '@ant-design/icons';
-import OwncastLogo from '../components/logo';
-import LogTable from '../components/log-table';
-import NewsFeed from '../components/news-feed';
+import { Card, Col, Row, Typography } from 'antd';
+import Link from 'next/link';
import { useContext } from 'react';
+import LogTable from '../components/log-table';
+import OwncastLogo from '../components/logo';
+import NewsFeed from '../components/news-feed';
+import { ConfigDetails } from '../types/config-section';
import { ServerStatusContext } from '../utils/server-status-context';
+
const { Paragraph, Text } = Typography;
const { Title } = Typography;
const { Meta } = Card;
-const { Panel } = Collapse;
function generateStreamURL(serverURL, rtmpServerPort) {
return `rtmp://${serverURL.replace(/(^\w+:|^)\/\//, '')}:${rtmpServerPort}/live/`;
}
-export default function Offline({ logs = [], config }) {
+type OfflineProps = {
+ logs: any[];
+ config: ConfigDetails;
+};
+
+export default function Offline({ logs = [], config }: OfflineProps) {
const serverStatusData = useContext(ServerStatusContext);
const { serverConfig } = serverStatusData || {};
diff --git a/web/pages/webhooks.tsx b/web/pages/webhooks.tsx
index d508fe203..6c504513c 100644
--- a/web/pages/webhooks.tsx
+++ b/web/pages/webhooks.tsx
@@ -1,22 +1,21 @@
-import React, { useState, useEffect } from 'react';
+import { DeleteOutlined } from '@ant-design/icons';
import {
+ Button,
+ Checkbox,
+ Col,
+ Input,
+ Modal,
+ Row,
+ Space,
Table,
Tag,
- Space,
- Button,
- Modal,
- Checkbox,
- Input,
- Typography,
Tooltip,
- Row,
- Col,
+ Typography,
} from 'antd';
-import { DeleteOutlined } from '@ant-design/icons';
+import React, { useEffect, useState } from 'react';
+import { CREATE_WEBHOOK, DELETE_WEBHOOK, fetchData, WEBHOOKS } from '../utils/apis';
import isValidUrl, { DEFAULT_TEXTFIELD_URL_PATTERN } from '../utils/urls';
-import { fetchData, DELETE_WEBHOOK, CREATE_WEBHOOK, WEBHOOKS } from '../utils/apis';
-
const { Title, Paragraph } = Typography;
const availableEvents = {
@@ -36,7 +35,7 @@ const availableEvents = {
STREAM_STOPPED: { name: 'Stream stopped', description: 'When a stream stops', color: 'cyan' },
};
-function convertEventStringToTag(eventString) {
+function convertEventStringToTag(eventString: string) {
if (!eventString || !availableEvents[eventString]) {
return null;
}
@@ -61,9 +60,10 @@ function NewWebhookModal(props: Props) {
const [selectedEvents, setSelectedEvents] = useState([]);
const [webhookUrl, setWebhookUrl] = useState('');
- const events = Object.keys(availableEvents).map(key => {
- return { value: key, label: availableEvents[key].description };
- });
+ const events = Object.keys(availableEvents).map(key => ({
+ value: key,
+ label: availableEvents[key].description,
+ }));
function onChange(checkedValues) {
setSelectedEvents(checkedValues);
@@ -85,13 +85,11 @@ function NewWebhookModal(props: Props) {
disabled: selectedEvents?.length === 0 || !isValidUrl(webhookUrl),
};
- const checkboxes = events.map(function (singleEvent) {
- return (
-
-
{singleEvent.label}
-
- );
- });
+ const checkboxes = events.map(singleEvent => (
+
+
{singleEvent.label}
+
+ ));
return (
(
-
- handleDelete(record.id)} icon={ } />
-
- ),
- },
- {
- title: 'URL',
- dataIndex: 'url',
- key: 'url',
- },
- {
- title: 'Events',
- dataIndex: 'events',
- key: 'events',
- render: events => (
- <>
- {events.map(event => {
- return convertEventStringToTag(event);
- })}
- >
- ),
- },
- ];
-
function handleError(error) {
console.error('error', error);
alert(error);
@@ -209,6 +178,29 @@ export default function Webhooks() {
setIsModalVisible(false);
};
+ const columns = [
+ {
+ title: '',
+ key: 'delete',
+ render: (text, record) => (
+
+ handleDelete(record.id)} icon={ } />
+
+ ),
+ },
+ {
+ title: 'URL',
+ dataIndex: 'url',
+ key: 'url',
+ },
+ {
+ title: 'Events',
+ dataIndex: 'events',
+ key: 'events',
+ render: ({ map }: string[]) => <>{map(event => convertEventStringToTag(event))}>,
+ },
+ ];
+
return (
Webhooks
diff --git a/web/types/config-section.ts b/web/types/config-section.ts
index 5b6fd511f..e9e043e16 100644
--- a/web/types/config-section.ts
+++ b/web/types/config-section.ts
@@ -82,7 +82,7 @@ export interface S3Field {
}
export interface ExternalAction {
- title: string,
+ title: string;
description: string;
url: string;
openExternally: boolean;