diff --git a/jest.config.js b/jest.config.js index b4b88d210cb..0b4d02caaff 100644 --- a/jest.config.js +++ b/jest.config.js @@ -2,4 +2,8 @@ const merge = require('lodash/merge'); module.exports = merge(require('@centreon/frontend-core/jest'), { roots: ['/www/front_src/src/'], + setupFilesAfterEnv: [ + '@testing-library/jest-dom/extend-expect', + '/setupTest.js', + ], }); diff --git a/package-lock.json b/package-lock.json index 68528247d6b..39dba0cd040 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,9 +13,9 @@ } }, "@babel/compat-data": { - "version": "7.8.5", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.8.5.tgz", - "integrity": "sha512-jWYUqQX/ObOhG1UiEkbH5SANsE/8oKXiQWjj7p7xgj9Zmnt//aUvyz4dBkK0HNsS8/cbyC5NmmH87VekW+mXFg==", + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.8.6.tgz", + "integrity": "sha512-CurCIKPTkS25Mb8mz267vU95vy+TyUpnctEX2lV33xWNmHAfjruztgiPBbXZRh3xZZy1CYvGx6XfxyTVS+sk7Q==", "requires": { "browserslist": "^4.8.5", "invariant": "^2.2.4", @@ -72,11 +72,11 @@ } }, "@babel/generator": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.8.4.tgz", - "integrity": "sha512-PwhclGdRpNAf3IxZb0YVuITPZmmrXz9zf6fH8lT4XbrmfQKr6ryBzhv593P5C6poJRciFCL/eHGW2NuGrgEyxA==", + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.8.6.tgz", + "integrity": "sha512-4bpOR5ZBz+wWcMeVtcf7FbjcFzCp+817z2/gHNncIRcM9MmKzUhtWCYAq27RAfUrAFwb+OCG1s9WEaVxfi6cjg==", "requires": { - "@babel/types": "^7.8.3", + "@babel/types": "^7.8.6", "jsesc": "^2.5.1", "lodash": "^4.17.13", "source-map": "^0.5.0" @@ -119,11 +119,11 @@ } }, "@babel/helper-compilation-targets": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.8.4.tgz", - "integrity": "sha512-3k3BsKMvPp5bjxgMdrFyq0UaEO48HciVrOVF0+lon8pp95cyJ2ujAh0TrBHNMnJGT2rr0iKOJPFFbSqjDyf/Pg==", + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.8.6.tgz", + "integrity": "sha512-UrJdk27hKVJSnibFcUWYLkCL0ZywTUoot8yii1lsHJcvwrypagmYKjHLMWivQPm4s6GdyygCL8fiH5EYLxhQwQ==", "requires": { - "@babel/compat-data": "^7.8.4", + "@babel/compat-data": "^7.8.6", "browserslist": "^4.8.5", "invariant": "^2.2.4", "levenary": "^1.1.1", @@ -138,23 +138,24 @@ } }, "@babel/helper-create-class-features-plugin": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.8.3.tgz", - "integrity": "sha512-qmp4pD7zeTxsv0JNecSBsEmG1ei2MqwJq4YQcK3ZWm/0t07QstWfvuV/vm3Qt5xNMFETn2SZqpMx2MQzbtq+KA==", + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.8.6.tgz", + "integrity": "sha512-klTBDdsr+VFFqaDHm5rR69OpEQtO2Qv8ECxHS1mNhJJvaHArR6a1xTf5K/eZW7eZpJbhCx3NW1Yt/sKsLXLblg==", "requires": { "@babel/helper-function-name": "^7.8.3", "@babel/helper-member-expression-to-functions": "^7.8.3", "@babel/helper-optimise-call-expression": "^7.8.3", "@babel/helper-plugin-utils": "^7.8.3", - "@babel/helper-replace-supers": "^7.8.3", + "@babel/helper-replace-supers": "^7.8.6", "@babel/helper-split-export-declaration": "^7.8.3" } }, "@babel/helper-create-regexp-features-plugin": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.8.3.tgz", - "integrity": "sha512-Gcsm1OHCUr9o9TcJln57xhWHtdXbA2pgQ58S0Lxlks0WMGNXuki4+GLfX0p+L2ZkINUGZvfkz8rzoqJQSthI+Q==", + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.8.6.tgz", + "integrity": "sha512-bPyujWfsHhV/ztUkwGHz/RPV1T1TDEsSZDsN42JPehndA+p1KKTh3npvTadux0ZhCrytx9tvjpWNowKby3tM6A==", "requires": { + "@babel/helper-annotate-as-pure": "^7.8.3", "@babel/helper-regex": "^7.8.3", "regexpu-core": "^4.6.0" } @@ -221,15 +222,16 @@ } }, "@babel/helper-module-transforms": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.8.3.tgz", - "integrity": "sha512-C7NG6B7vfBa/pwCOshpMbOYUmrYQDfCpVL/JCRu0ek8B5p8kue1+BCXpg2vOYs7w5ACB9GTOBYQ5U6NwrMg+3Q==", + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.8.6.tgz", + "integrity": "sha512-RDnGJSR5EFBJjG3deY0NiL0K9TO8SXxS9n/MPsbPK/s9LbQymuLNtlzvDiNS7IpecuL45cMeLVkA+HfmlrnkRg==", "requires": { "@babel/helper-module-imports": "^7.8.3", + "@babel/helper-replace-supers": "^7.8.6", "@babel/helper-simple-access": "^7.8.3", "@babel/helper-split-export-declaration": "^7.8.3", - "@babel/template": "^7.8.3", - "@babel/types": "^7.8.3", + "@babel/template": "^7.8.6", + "@babel/types": "^7.8.6", "lodash": "^4.17.13" } }, @@ -267,14 +269,14 @@ } }, "@babel/helper-replace-supers": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.8.3.tgz", - "integrity": "sha512-xOUssL6ho41U81etpLoT2RTdvdus4VfHamCuAm4AHxGr+0it5fnwoVdwUJ7GFEqCsQYzJUhcbsN9wB9apcYKFA==", + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.8.6.tgz", + "integrity": "sha512-PeMArdA4Sv/Wf4zXwBKPqVj7n9UF/xg6slNRtZW84FM7JpE1CbG8B612FyM4cxrf4fMAMGO0kR7voy1ForHHFA==", "requires": { "@babel/helper-member-expression-to-functions": "^7.8.3", "@babel/helper-optimise-call-expression": "^7.8.3", - "@babel/traverse": "^7.8.3", - "@babel/types": "^7.8.3" + "@babel/traverse": "^7.8.6", + "@babel/types": "^7.8.6" } }, "@babel/helper-simple-access": { @@ -326,9 +328,9 @@ } }, "@babel/parser": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.8.4.tgz", - "integrity": "sha512-0fKu/QqildpXmPVaRBoXOlyBb3MC+J0A66x97qEfLOMkn3u6nfY5esWogQwi/K0BjASYy4DbnsEWnpNL6qT5Mw==" + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.8.6.tgz", + "integrity": "sha512-trGNYSfwq5s0SgM1BMEB8hX3NDmO7EP2wsDGDexiaKMB92BaRpS+qZfpkMqUBhcsOTBwNy9B/jieo4ad/t/z2g==" }, "@babel/plugin-proposal-async-generator-functions": { "version": "7.8.3", @@ -580,16 +582,16 @@ } }, "@babel/plugin-transform-classes": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.8.3.tgz", - "integrity": "sha512-SjT0cwFJ+7Rbr1vQsvphAHwUHvSUPmMjMU/0P59G8U2HLFqSa082JO7zkbDNWs9kH/IUqpHI6xWNesGf8haF1w==", + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.8.6.tgz", + "integrity": "sha512-k9r8qRay/R6v5aWZkrEclEhKO6mc1CCQr2dLsVHBmOQiMpN6I2bpjX3vgnldUWeEI1GHVNByULVxZ4BdP4Hmdg==", "requires": { "@babel/helper-annotate-as-pure": "^7.8.3", "@babel/helper-define-map": "^7.8.3", "@babel/helper-function-name": "^7.8.3", "@babel/helper-optimise-call-expression": "^7.8.3", "@babel/helper-plugin-utils": "^7.8.3", - "@babel/helper-replace-supers": "^7.8.3", + "@babel/helper-replace-supers": "^7.8.6", "@babel/helper-split-export-declaration": "^7.8.3", "globals": "^11.1.0" } @@ -646,9 +648,9 @@ } }, "@babel/plugin-transform-for-of": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.8.4.tgz", - "integrity": "sha512-iAXNlOWvcYUYoV8YIxwS7TxGRJcxyl8eQCfT+A5j8sKUzRFvJdcyjp97jL2IghWSRDaL2PU2O2tX8Cu9dTBq5A==", + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.8.6.tgz", + "integrity": "sha512-M0pw4/1/KI5WAxPsdcUL/w2LJ7o89YHN3yLkzNjg7Yl15GlVGgzHyCU+FMeAxevHGsLVmUqbirlUIKTafPmzdw==", "requires": { "@babel/helper-plugin-utils": "^7.8.3" } @@ -921,12 +923,12 @@ } }, "@babel/preset-env": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.8.4.tgz", - "integrity": "sha512-HihCgpr45AnSOHRbS5cWNTINs0TwaR8BS8xIIH+QwiW8cKL0llV91njQMpeMReEPVs+1Ao0x3RLEBLtt1hOq4w==", + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.8.6.tgz", + "integrity": "sha512-M5u8llV9DIVXBFB/ArIpqJuvXpO+ymxcJ6e8ZAmzeK3sQeBNOD1y+rHvHCGG4TlEmsNpIrdecsHGHT8ZCoOSJg==", "requires": { - "@babel/compat-data": "^7.8.4", - "@babel/helper-compilation-targets": "^7.8.4", + "@babel/compat-data": "^7.8.6", + "@babel/helper-compilation-targets": "^7.8.6", "@babel/helper-module-imports": "^7.8.3", "@babel/helper-plugin-utils": "^7.8.3", "@babel/plugin-proposal-async-generator-functions": "^7.8.3", @@ -949,13 +951,13 @@ "@babel/plugin-transform-async-to-generator": "^7.8.3", "@babel/plugin-transform-block-scoped-functions": "^7.8.3", "@babel/plugin-transform-block-scoping": "^7.8.3", - "@babel/plugin-transform-classes": "^7.8.3", + "@babel/plugin-transform-classes": "^7.8.6", "@babel/plugin-transform-computed-properties": "^7.8.3", "@babel/plugin-transform-destructuring": "^7.8.3", "@babel/plugin-transform-dotall-regex": "^7.8.3", "@babel/plugin-transform-duplicate-keys": "^7.8.3", "@babel/plugin-transform-exponentiation-operator": "^7.8.3", - "@babel/plugin-transform-for-of": "^7.8.4", + "@babel/plugin-transform-for-of": "^7.8.6", "@babel/plugin-transform-function-name": "^7.8.3", "@babel/plugin-transform-literals": "^7.8.3", "@babel/plugin-transform-member-expression-literals": "^7.8.3", @@ -976,7 +978,7 @@ "@babel/plugin-transform-template-literals": "^7.8.3", "@babel/plugin-transform-typeof-symbol": "^7.8.4", "@babel/plugin-transform-unicode-regex": "^7.8.3", - "@babel/types": "^7.8.3", + "@babel/types": "^7.8.6", "browserslist": "^4.8.5", "core-js-compat": "^3.6.2", "invariant": "^2.2.2", @@ -1021,26 +1023,26 @@ } }, "@babel/template": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.3.tgz", - "integrity": "sha512-04m87AcQgAFdvuoyiQ2kgELr2tV8B4fP/xJAVUL3Yb3bkNdMedD3d0rlSQr3PegP0cms3eHjl1F7PWlvWbU8FQ==", + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.6.tgz", + "integrity": "sha512-zbMsPMy/v0PWFZEhQJ66bqjhH+z0JgMoBWuikXybgG3Gkd/3t5oQ1Rw2WQhnSrsOmsKXnZOx15tkC4qON/+JPg==", "requires": { "@babel/code-frame": "^7.8.3", - "@babel/parser": "^7.8.3", - "@babel/types": "^7.8.3" + "@babel/parser": "^7.8.6", + "@babel/types": "^7.8.6" } }, "@babel/traverse": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.8.4.tgz", - "integrity": "sha512-NGLJPZwnVEyBPLI+bl9y9aSnxMhsKz42so7ApAv9D+b4vAFPpY013FTS9LdKxcABoIYFU52HcYga1pPlx454mg==", + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.8.6.tgz", + "integrity": "sha512-2B8l0db/DPi8iinITKuo7cbPznLCEk0kCxDoB9/N6gGNg/gxOXiR/IcymAFPiBwk5w6TtQ27w4wpElgp9btR9A==", "requires": { "@babel/code-frame": "^7.8.3", - "@babel/generator": "^7.8.4", + "@babel/generator": "^7.8.6", "@babel/helper-function-name": "^7.8.3", "@babel/helper-split-export-declaration": "^7.8.3", - "@babel/parser": "^7.8.4", - "@babel/types": "^7.8.3", + "@babel/parser": "^7.8.6", + "@babel/types": "^7.8.6", "debug": "^4.1.0", "globals": "^11.1.0", "lodash": "^4.17.13" @@ -1062,9 +1064,9 @@ } }, "@babel/types": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.3.tgz", - "integrity": "sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==", + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.6.tgz", + "integrity": "sha512-wqz7pgWMIrht3gquyEFPVXeXCti72Rm8ep9b5tQKz9Yg9LzJA3HxosF1SB3Kc81KD1A3XBkkVYtJvCKS2Z/QrA==", "requires": { "esutils": "^2.0.2", "lodash": "^4.17.13", @@ -1078,12 +1080,12 @@ "dev": true }, "@centreon/frontend-core": { - "version": "github:centreon/frontend-core#948abe1f89b8ba12ee7153b3380b12b0bec57af6", + "version": "github:centreon/frontend-core#35a9766ca0e58ad0ed275a31ab24c03a61b2e470", "from": "github:centreon/frontend-core", "dev": true }, "@centreon/ui": { - "version": "github:centreon/centreon-ui#12ef887220f649c1bd0ff83440ba501fa5de6e2d", + "version": "github:centreon/centreon-ui#c14dc35db5c9c2038281e62cdd1d0280aa917224", "from": "github:centreon/centreon-ui", "requires": { "@material-ui/core": "^4.9.3", @@ -1122,9 +1124,9 @@ "integrity": "sha512-ij4wRiunFfaJxjB0BdrYHIH8FxBJpOwNPhhAcunlmPdXudL1WQV1qoP9un6JsEBAgQH+7UXyyjh0g7jTxXK6tg==" }, "@emotion/cache": { - "version": "10.0.27", - "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-10.0.27.tgz", - "integrity": "sha512-Zp8BEpbMunFsTcqAK4D7YTm3MvCp1SekflSLJH8lze2fCcSZ/yMkXHo8kb3t1/1Tdd3hAqf3Fb7z9VZ+FMiC9w==", + "version": "10.0.29", + "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-10.0.29.tgz", + "integrity": "sha512-fU2VtSVlHiF27empSbxi1O2JFdNWZO+2NFHfwO0pxgTep6Xa3uGb+3pVKfLww2l/IBGLNEZl5Xf/++A4wAYDYQ==", "requires": { "@emotion/sheet": "0.9.4", "@emotion/stylis": "0.8.5", @@ -1133,9 +1135,9 @@ } }, "@emotion/core": { - "version": "10.0.27", - "resolved": "https://registry.npmjs.org/@emotion/core/-/core-10.0.27.tgz", - "integrity": "sha512-XbD5R36pVbohQMnKfajHv43g8EbN4NHdF6Zh9zg/C0nr0jqwOw3gYnC07Xj3yG43OYSRyrGsoQ5qPwc8ycvLZw==", + "version": "10.0.28", + "resolved": "https://registry.npmjs.org/@emotion/core/-/core-10.0.28.tgz", + "integrity": "sha512-pH8UueKYO5jgg0Iq+AmCLxBsvuGtvlmiDCOuv8fGNYn3cowFpLN98L8zO56U0H1PjDIyAlXymgL3Wu7u7v6hbA==", "requires": { "@babel/runtime": "^7.5.5", "@emotion/cache": "^10.0.27", @@ -1166,15 +1168,22 @@ "integrity": "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==" }, "@emotion/serialize": { - "version": "0.11.15", - "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-0.11.15.tgz", - "integrity": "sha512-YE+qnrmGwyR+XB5j7Bi+0GT1JWsdcjM/d4POu+TXkcnrRs4RFCCsi3d/Ebf+wSStHqAlTT2+dfd+b9N9EO2KBg==", + "version": "0.11.16", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-0.11.16.tgz", + "integrity": "sha512-G3J4o8by0VRrO+PFeSc3js2myYNOXVJ3Ya+RGVxnshRYgsvErfAOglKAiy1Eo1vhzxqtUvjCyS5gtewzkmvSSg==", "requires": { - "@emotion/hash": "0.7.4", + "@emotion/hash": "0.8.0", "@emotion/memoize": "0.7.4", "@emotion/unitless": "0.7.5", "@emotion/utils": "0.11.3", "csstype": "^2.5.7" + }, + "dependencies": { + "@emotion/hash": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz", + "integrity": "sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==" + } } }, "@emotion/sheet": { @@ -1488,9 +1497,9 @@ } }, "@material-ui/core": { - "version": "4.9.4", - "resolved": "https://registry.npmjs.org/@material-ui/core/-/core-4.9.4.tgz", - "integrity": "sha512-1wqm3jBC8mGpVHu0wVOYBX7LUzkPsWxkkTtKSn0Hz66T6TDJkke72mkSIL7akNdjnxy+bRc2Vi6NiJ4YutkDcw==", + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/@material-ui/core/-/core-4.9.5.tgz", + "integrity": "sha512-hVuUqw6847jcgRsUqzCiYCXcIJYhPUfM3gS9sNehTsbI0SF3tufLNO2B2Cgkuns8uOGy0nicD4p3L7JqhnEElg==", "requires": { "@babel/runtime": "^7.4.4", "@material-ui/styles": "^4.9.0", @@ -1514,6 +1523,18 @@ "@babel/runtime": "^7.4.4" } }, + "@material-ui/lab": { + "version": "4.0.0-alpha.45", + "resolved": "https://registry.npmjs.org/@material-ui/lab/-/lab-4.0.0-alpha.45.tgz", + "integrity": "sha512-zT6kUU87SHsPukiu3tlWg8V6o0tGS38c1b/xst/kPqX6eLbfqrROyxhHn1A8ZtHmqga1AKQdv/1llQoG80Afww==", + "requires": { + "@babel/runtime": "^7.4.4", + "@material-ui/utils": "^4.7.1", + "clsx": "^1.0.4", + "prop-types": "^15.7.2", + "react-is": "^16.8.0" + } + }, "@material-ui/styles": { "version": "4.9.0", "resolved": "https://registry.npmjs.org/@material-ui/styles/-/styles-4.9.0.tgz", @@ -2120,8 +2141,7 @@ "@types/color-name": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", - "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==", - "dev": true + "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==" }, "@types/eslint-visitor-keys": { "version": "1.0.0", @@ -2301,9 +2321,9 @@ "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==" }, "@types/node": { - "version": "13.7.6", - "resolved": "https://registry.npmjs.org/@types/node/-/node-13.7.6.tgz", - "integrity": "sha512-eyK7MWD0R1HqVTp+PtwRgFeIsemzuj4gBFSQxfPHY5iMjS7474e5wq+VFgTcdpyHeNxyKSaetYAjdMLJlKoWqA==" + "version": "13.7.7", + "resolved": "https://registry.npmjs.org/@types/node/-/node-13.7.7.tgz", + "integrity": "sha512-Uo4chgKbnPNlxQwoFmYIwctkQVkMMmsAoGGU4JKwLuvBefF0pCq4FybNSnfkfRCpC7ZW7kttcC/TrRtAJsvGtg==" }, "@types/parse-json": { "version": "4.0.0", @@ -2419,9 +2439,9 @@ } }, "@types/webpack": { - "version": "4.41.6", - "resolved": "https://registry.npmjs.org/@types/webpack/-/webpack-4.41.6.tgz", - "integrity": "sha512-iWRpV5Ej+8uKrgxp6jXz3v7ZTjgtuMXY+rsxQjFNU0hYCnHkpA7vtiNffgxjuxX4feFHBbz0IF76OzX2OqDYPw==", + "version": "4.41.7", + "resolved": "https://registry.npmjs.org/@types/webpack/-/webpack-4.41.7.tgz", + "integrity": "sha512-OQG9viYwO0V1NaNV7d0n79V+n6mjOV30CwgFPIfTzwmk8DHbt+C4f2aBGdCYbo3yFyYD6sjXfqqOjwkl1j+ulA==", "dev": true, "requires": { "@types/anymatch": "*", @@ -2473,11 +2493,11 @@ "integrity": "sha512-FA/BWv8t8ZWJ+gEOnLLd8ygxH/2UFbAvgEonyfN6yWGLKc7zVjbpl2Y4CTjid9h2RfgPP6SEt6uHwEOply00yw==" }, "@typescript-eslint/eslint-plugin": { - "version": "2.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.21.0.tgz", - "integrity": "sha512-b5jjjDMxzcjh/Sbjuo7WyhrQmVJg0WipTHQgXh5Xwx10uYm6nPWqN1WGOsaNq4HR3Zh4wUx4IRQdDkCHwyewyw==", + "version": "2.22.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.22.0.tgz", + "integrity": "sha512-BvxRLaTDVQ3N+Qq8BivLiE9akQLAOUfxNHIEhedOcg8B2+jY8Rc4/D+iVprvuMX1AdezFYautuGDwr9QxqSxBQ==", "requires": { - "@typescript-eslint/experimental-utils": "2.21.0", + "@typescript-eslint/experimental-utils": "2.22.0", "eslint-utils": "^1.4.3", "functional-red-black-tree": "^1.0.1", "regexpp": "^3.0.0", @@ -2485,30 +2505,30 @@ } }, "@typescript-eslint/experimental-utils": { - "version": "2.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-2.21.0.tgz", - "integrity": "sha512-olKw9JP/XUkav4lq0I7S1mhGgONJF9rHNhKFn9wJlpfRVjNo3PPjSvybxEldvCXnvD+WAshSzqH5cEjPp9CsBA==", + "version": "2.22.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-2.22.0.tgz", + "integrity": "sha512-sJt1GYBe6yC0dWOQzXlp+tiuGglNhJC9eXZeC8GBVH98Zv9jtatccuhz0OF5kC/DwChqsNfghHx7OlIDQjNYAQ==", "requires": { "@types/json-schema": "^7.0.3", - "@typescript-eslint/typescript-estree": "2.21.0", + "@typescript-eslint/typescript-estree": "2.22.0", "eslint-scope": "^5.0.0" } }, "@typescript-eslint/parser": { - "version": "2.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-2.21.0.tgz", - "integrity": "sha512-VrmbdrrrvvI6cPPOG7uOgGUFXNYTiSbnRq8ZMyuGa4+qmXJXVLEEz78hKuqupvkpwJQNk1Ucz1TenrRP90gmBg==", + "version": "2.22.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-2.22.0.tgz", + "integrity": "sha512-FaZKC1X+nvD7qMPqKFUYHz3H0TAioSVFGvG29f796Nc5tBluoqfHgLbSFKsh7mKjRoeTm8J9WX2Wo9EyZWjG7w==", "requires": { "@types/eslint-visitor-keys": "^1.0.0", - "@typescript-eslint/experimental-utils": "2.21.0", - "@typescript-eslint/typescript-estree": "2.21.0", + "@typescript-eslint/experimental-utils": "2.22.0", + "@typescript-eslint/typescript-estree": "2.22.0", "eslint-visitor-keys": "^1.1.0" } }, "@typescript-eslint/typescript-estree": { - "version": "2.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-2.21.0.tgz", - "integrity": "sha512-NC/nogZNb9IK2MEFQqyDBAciOT8Lp8O3KgAfvHx2Skx6WBo+KmDqlU3R9KxHONaijfTIKtojRe3SZQyMjr3wBw==", + "version": "2.22.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-2.22.0.tgz", + "integrity": "sha512-2HFZW2FQc4MhIBB8WhDm9lVFaBDy6h9jGrJ4V2Uzxe/ON29HCHBTj3GkgcsgMWfsl2U5as+pTOr30Nibaw7qRQ==", "requires": { "debug": "^4.1.1", "eslint-visitor-keys": "^1.1.0", @@ -2723,9 +2743,9 @@ } }, "acorn": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.1.0.tgz", - "integrity": "sha512-kL5CuoXA/dgxlBbVrflsflzQ3PAas7RYZB52NOm/6839iVYJgKMJ3cQJD+t2i5+qFa8h3MDpEOJiS64E8JLnSQ==" + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.1.1.tgz", + "integrity": "sha512-add7dgA5ppRPxCFJoAGfMDi7PIBXq1RtGo7BhbLaxwrXPOmw8gq48Y9ozT01hUKy9byMjlR20EJhu5zlkErEkg==" }, "acorn-globals": { "version": "4.3.4", @@ -2847,11 +2867,18 @@ "integrity": "sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA==" }, "ansi-escapes": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.0.tgz", - "integrity": "sha512-EiYhwo0v255HUL6eDyuLrXEkTi7WwVCLAw+SeOQ7M7qdun1z1pum4DEm/nuqIVbPvi9RPPc9k9LbyBv6H0DwVg==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.1.tgz", + "integrity": "sha512-JWF7ocqNrp8u9oqpgV+wH5ftbt+cfvv+PTjOvKLT3AdYly/LmORARfEVT1iyjwN+4MqE5UmVKoAdIBqeoCHgLA==", "requires": { - "type-fest": "^0.8.1" + "type-fest": "^0.11.0" + }, + "dependencies": { + "type-fest": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.11.0.tgz", + "integrity": "sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ==" + } } }, "ansi-html": { @@ -3607,20 +3634,27 @@ } }, "babel-plugin-emotion": { - "version": "10.0.27", - "resolved": "https://registry.npmjs.org/babel-plugin-emotion/-/babel-plugin-emotion-10.0.27.tgz", - "integrity": "sha512-SUNYcT4FqhOqvwv0z1oeYhqgheU8qrceLojuHyX17ngo7WtWqN5I9l3IGHzf21Xraj465CVzF4IvOlAF+3ed0A==", + "version": "10.0.29", + "resolved": "https://registry.npmjs.org/babel-plugin-emotion/-/babel-plugin-emotion-10.0.29.tgz", + "integrity": "sha512-7Jpi1OCxjyz0k163lKtqP+LHMg5z3S6A7vMBfHnF06l2unmtsOmFDzZBpGf0CWo1G4m8UACfVcDJiSiRuu/cSw==", "requires": { "@babel/helper-module-imports": "^7.0.0", - "@emotion/hash": "0.7.4", + "@emotion/hash": "0.8.0", "@emotion/memoize": "0.7.4", - "@emotion/serialize": "^0.11.15", + "@emotion/serialize": "^0.11.16", "babel-plugin-macros": "^2.0.0", "babel-plugin-syntax-jsx": "^6.18.0", "convert-source-map": "^1.5.0", "escape-string-regexp": "^1.0.5", "find-root": "^1.1.0", "source-map": "^0.5.7" + }, + "dependencies": { + "@emotion/hash": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz", + "integrity": "sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==" + } } }, "babel-plugin-istanbul": { @@ -3752,6 +3786,77 @@ "@babel/runtime": "7.8.4", "babel-plugin-macros": "2.8.0", "babel-plugin-transform-react-remove-prop-types": "0.4.24" + }, + "dependencies": { + "@babel/preset-env": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.8.4.tgz", + "integrity": "sha512-HihCgpr45AnSOHRbS5cWNTINs0TwaR8BS8xIIH+QwiW8cKL0llV91njQMpeMReEPVs+1Ao0x3RLEBLtt1hOq4w==", + "requires": { + "@babel/compat-data": "^7.8.4", + "@babel/helper-compilation-targets": "^7.8.4", + "@babel/helper-module-imports": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/plugin-proposal-async-generator-functions": "^7.8.3", + "@babel/plugin-proposal-dynamic-import": "^7.8.3", + "@babel/plugin-proposal-json-strings": "^7.8.3", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-proposal-object-rest-spread": "^7.8.3", + "@babel/plugin-proposal-optional-catch-binding": "^7.8.3", + "@babel/plugin-proposal-optional-chaining": "^7.8.3", + "@babel/plugin-proposal-unicode-property-regex": "^7.8.3", + "@babel/plugin-syntax-async-generators": "^7.8.0", + "@babel/plugin-syntax-dynamic-import": "^7.8.0", + "@babel/plugin-syntax-json-strings": "^7.8.0", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.0", + "@babel/plugin-syntax-object-rest-spread": "^7.8.0", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.0", + "@babel/plugin-syntax-optional-chaining": "^7.8.0", + "@babel/plugin-syntax-top-level-await": "^7.8.3", + "@babel/plugin-transform-arrow-functions": "^7.8.3", + "@babel/plugin-transform-async-to-generator": "^7.8.3", + "@babel/plugin-transform-block-scoped-functions": "^7.8.3", + "@babel/plugin-transform-block-scoping": "^7.8.3", + "@babel/plugin-transform-classes": "^7.8.3", + "@babel/plugin-transform-computed-properties": "^7.8.3", + "@babel/plugin-transform-destructuring": "^7.8.3", + "@babel/plugin-transform-dotall-regex": "^7.8.3", + "@babel/plugin-transform-duplicate-keys": "^7.8.3", + "@babel/plugin-transform-exponentiation-operator": "^7.8.3", + "@babel/plugin-transform-for-of": "^7.8.4", + "@babel/plugin-transform-function-name": "^7.8.3", + "@babel/plugin-transform-literals": "^7.8.3", + "@babel/plugin-transform-member-expression-literals": "^7.8.3", + "@babel/plugin-transform-modules-amd": "^7.8.3", + "@babel/plugin-transform-modules-commonjs": "^7.8.3", + "@babel/plugin-transform-modules-systemjs": "^7.8.3", + "@babel/plugin-transform-modules-umd": "^7.8.3", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.8.3", + "@babel/plugin-transform-new-target": "^7.8.3", + "@babel/plugin-transform-object-super": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.8.4", + "@babel/plugin-transform-property-literals": "^7.8.3", + "@babel/plugin-transform-regenerator": "^7.8.3", + "@babel/plugin-transform-reserved-words": "^7.8.3", + "@babel/plugin-transform-shorthand-properties": "^7.8.3", + "@babel/plugin-transform-spread": "^7.8.3", + "@babel/plugin-transform-sticky-regex": "^7.8.3", + "@babel/plugin-transform-template-literals": "^7.8.3", + "@babel/plugin-transform-typeof-symbol": "^7.8.4", + "@babel/plugin-transform-unicode-regex": "^7.8.3", + "@babel/types": "^7.8.3", + "browserslist": "^4.8.5", + "core-js-compat": "^3.6.2", + "invariant": "^2.2.2", + "levenary": "^1.1.1", + "semver": "^5.5.0" + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + } } }, "babel-runtime": { @@ -4114,13 +4219,13 @@ } }, "browserslist": { - "version": "4.8.7", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.8.7.tgz", - "integrity": "sha512-gFOnZNYBHrEyUML0xr5NJ6edFaaKbTFX9S9kQHlYfCP0Rit/boRIz4G+Avq6/4haEKJXdGGUnoolx+5MWW2BoA==", + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.9.1.tgz", + "integrity": "sha512-Q0DnKq20End3raFulq6Vfp1ecB9fh8yUNV55s8sekaDDeqBaCtWlRHCUdaWyUeSSBJM7IbM6HcsyaeYqgeDhnw==", "requires": { - "caniuse-lite": "^1.0.30001027", - "electron-to-chromium": "^1.3.349", - "node-releases": "^1.1.49" + "caniuse-lite": "^1.0.30001030", + "electron-to-chromium": "^1.3.363", + "node-releases": "^1.1.50" } }, "bser": { @@ -4294,9 +4399,9 @@ } }, "caniuse-lite": { - "version": "1.0.30001030", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001030.tgz", - "integrity": "sha512-QGK0W4Ft/Ac+zTjEiRJfwDNATvS3fodDczBXrH42784kcfqcDKpEPfN08N0HQjrAp8He/Jw8QiSS9QRn7XAbUw==" + "version": "1.0.30001031", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001031.tgz", + "integrity": "sha512-DpAP5a1NGRLgYfaNCaXIRyGARi+3tJA2quZXNNA1Du26VyVkqvy2tznNu5ANyN1Y5aX44QDotZSVSUSi2uMGjg==" }, "capture-exit": { "version": "2.0.0", @@ -5234,6 +5339,11 @@ } } }, + "date-fns": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.10.0.tgz", + "integrity": "sha512-EhfEKevYGWhWlZbNeplfhIU/+N+x0iCIx7VzKlXma2EdQyznVlZhCptXUY+BegNpPW2kjdx15Rvq503YcXXrcA==" + }, "debug": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", @@ -5665,9 +5775,9 @@ "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" }, "electron-to-chromium": { - "version": "1.3.361", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.361.tgz", - "integrity": "sha512-OzSVjWpsRhJyr9PSAXkeloSe6e9viU2ToGt1wXlXFsGcxuI9vlsnalL+V/AM59Z2pEo3wRxIddtOGsT7Y6x/sQ==" + "version": "1.3.366", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.366.tgz", + "integrity": "sha512-MWtwlJaX/MqAH4V7j4pFasq2O4OIH7MltGTEVvzyeuUW+CPYsx+fuVg/MSBrTL4PzZjHidOixaELNy75/XFK1g==" }, "elliptic": { "version": "6.5.2", @@ -6253,9 +6363,9 @@ } }, "eslint-plugin-jest": { - "version": "23.8.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-23.8.0.tgz", - "integrity": "sha512-DKXmLxguZ1Lru4u5YM12ko3WLq6gqo7dhV2b63K731+/PNyZ/Ff6NGONQsGUtPLG9zU3kdz/N+2LTbweNZifeg==", + "version": "23.8.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-23.8.1.tgz", + "integrity": "sha512-OycLNqPo/2EfO6kTqnmsu1khz1gTIOxGl3ThIVwL5/oycDF4pm5uNDyvFelNLdpr4COUuM8PVi3963NEG1Efpw==", "dev": true, "requires": { "@typescript-eslint/experimental-utils": "^2.5.0" @@ -6359,12 +6469,12 @@ "integrity": "sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==" }, "espree": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/espree/-/espree-6.1.2.tgz", - "integrity": "sha512-2iUPuuPP+yW1PZaMSDM9eyVf8D5P0Hi8h83YtZ5bPc/zHYjII5khoixIUTMO794NOY8F/ThF1Bo8ncZILarUTA==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-6.2.0.tgz", + "integrity": "sha512-Xs8airJ7RQolnDIbLtRutmfvSsAe0xqMMAantCN/GMoqf81TFbeI1T7Jpd56qYu1uuh32dOG5W/X9uO+ghPXzA==", "requires": { "acorn": "^7.1.0", - "acorn-jsx": "^5.1.0", + "acorn-jsx": "^5.2.0", "eslint-visitor-keys": "^1.1.0" } }, @@ -7567,9 +7677,9 @@ } }, "hosted-git-info": { - "version": "2.8.6", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.6.tgz", - "integrity": "sha512-Kp6rShEsCHhF5dD3EWKdkgVA8ix90oSUJ0VY4g9goxxa0+f4lx63muTftn0mlJ/+8IESGWyKnP//V2D7S4ZbIQ==" + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz", + "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==" }, "hpack.js": { "version": "2.1.6", @@ -8035,23 +8145,77 @@ "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==" }, "inquirer": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.0.4.tgz", - "integrity": "sha512-Bu5Td5+j11sCkqfqmUTiwv+tWisMtP0L7Q8WrqA2C/BbBhy1YTdFrvjjlrKq8oagA/tLQBski2Gcx/Sqyi2qSQ==", + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.0.5.tgz", + "integrity": "sha512-6Z5cP+LAO0rzNE7xWjWtT84jxKa5ScLEGLgegPXeO3dGeU8lNe5Ii7SlXH6KVtLGlDuaEhsvsFjrjWjw8j5lFg==", "requires": { "ansi-escapes": "^4.2.1", - "chalk": "^2.4.2", + "chalk": "^3.0.0", "cli-cursor": "^3.1.0", "cli-width": "^2.0.0", "external-editor": "^3.0.3", "figures": "^3.0.0", "lodash": "^4.17.15", "mute-stream": "0.0.8", - "run-async": "^2.2.0", + "run-async": "^2.4.0", "rxjs": "^6.5.3", "string-width": "^4.1.0", - "strip-ansi": "^5.1.0", + "strip-ansi": "^6.0.0", "through": "^2.3.6" + }, + "dependencies": { + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "requires": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "requires": { + "ansi-regex": "^5.0.0" + } + }, + "supports-color": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "requires": { + "has-flag": "^4.0.0" + } + } } }, "install": { @@ -13883,9 +14047,9 @@ "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==" }, "promise": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/promise/-/promise-8.0.3.tgz", - "integrity": "sha512-HeRDUL1RJiLhyA0/grn+PTShlBAcLuh/1BJGtrvjwbvRDCTLLMEz9rOGCV+R3vHY4MixIuoMEd9Yq/XvsTPcjw==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/promise/-/promise-8.1.0.tgz", + "integrity": "sha512-W04AqnILOL/sPRXziNicCjSNRruLAuIHEOVBazepu0545DDNGYHz7ar9ZgZ1fMU8/MA4mVxp5rkBWRi6OXIy3Q==", "requires": { "asap": "~2.0.6" } @@ -14003,9 +14167,9 @@ "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" }, "query-string": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/query-string/-/query-string-6.11.0.tgz", - "integrity": "sha512-jS+me8X3OEGFTsF6kF+vUUMFG/d3WUCvD7bHhfZP5784nOq1pjj8yau/u86nfOncmcN6ZkSWKWkKAvv/MGxzLA==", + "version": "6.11.1", + "resolved": "https://registry.npmjs.org/query-string/-/query-string-6.11.1.tgz", + "integrity": "sha512-1ZvJOUl8ifkkBxu2ByVM/8GijMIPx+cef7u3yroO3Ogm4DOdZcF5dcrWTIlSHe3Pg/mtlt6/eFjObDfJureZZA==", "requires": { "decode-uri-component": "^0.2.0", "split-on-first": "^1.0.0", @@ -14076,9 +14240,9 @@ } }, "react": { - "version": "16.12.0", - "resolved": "https://registry.npmjs.org/react/-/react-16.12.0.tgz", - "integrity": "sha512-fglqy3k5E+81pA8s+7K0/T3DBCF0ZDOher1elBFzF7O6arXJgzyu/FW+COxFvAWXJoJN9KIZbT2LXlukwphYTA==", + "version": "16.13.0", + "resolved": "https://registry.npmjs.org/react/-/react-16.13.0.tgz", + "integrity": "sha512-TSavZz2iSLkq5/oiE7gnFzmURKZMltmi193rm5HEoUDAXpzT9Kzw6oNZnGoai/4+fUnm7FqS5dwgUL34TujcWQ==", "requires": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1", @@ -14129,6 +14293,11 @@ "text-table": "0.2.0" }, "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" + }, "browserslist": { "version": "4.8.6", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.8.6.tgz", @@ -14168,6 +14337,36 @@ "path-exists": "^4.0.0" } }, + "inquirer": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.0.4.tgz", + "integrity": "sha512-Bu5Td5+j11sCkqfqmUTiwv+tWisMtP0L7Q8WrqA2C/BbBhy1YTdFrvjjlrKq8oagA/tLQBski2Gcx/Sqyi2qSQ==", + "requires": { + "ansi-escapes": "^4.2.1", + "chalk": "^2.4.2", + "cli-cursor": "^3.1.0", + "cli-width": "^2.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.15", + "mute-stream": "0.0.8", + "run-async": "^2.2.0", + "rxjs": "^6.5.3", + "string-width": "^4.1.0", + "strip-ansi": "^5.1.0", + "through": "^2.3.6" + }, + "dependencies": { + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, "json5": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", @@ -14231,6 +14430,13 @@ "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", "requires": { "ansi-regex": "^5.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==" + } } }, "which": { @@ -14244,14 +14450,25 @@ } }, "react-dom": { - "version": "16.12.0", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.12.0.tgz", - "integrity": "sha512-LMxFfAGrcS3kETtQaCkTKjMiifahaMySFDn71fZUNpPHZQEzmk/GiAeIT8JSOrHB23fnuCOMruL2a8NYlw+8Gw==", + "version": "16.13.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.13.0.tgz", + "integrity": "sha512-y09d2c4cG220DzdlFkPTnVvGTszVvNpC73v+AaLGLHbkpy3SSgvYq8x0rNwPJ/Rk/CicTNgk0hbHNw1gMEZAXg==", "requires": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1", "prop-types": "^15.6.2", - "scheduler": "^0.18.0" + "scheduler": "^0.19.0" + }, + "dependencies": { + "scheduler": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.19.0.tgz", + "integrity": "sha512-xowbVaTPe9r7y7RUejcK73/j8tt2jfiyTednOvHbA8JoClvMYCp+r8QegLwK/n8zWQAtZb1fFnER4XLBZXrCxA==", + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1" + } + } } }, "react-error-overlay": { @@ -14302,9 +14519,9 @@ } }, "react-is": { - "version": "16.12.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.12.0.tgz", - "integrity": "sha512-rPCkf/mWBtKc97aLL9/txD8DZdemK0vkA3JMLShjlJB3Pj3s+lpf1KaBzMfQrAmhMQB0n1cU/SUGgKKBCe837Q==" + "version": "16.13.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.0.tgz", + "integrity": "sha512-GFMtL0vHkiBv9HluwNZTggSn/sCyEt9n02aM0dSAjGGyqyNlAyftYm4phPxdvCigG15JreC5biwxCgTAJZ7yAA==" }, "react-lifecycles-compat": { "version": "3.0.4", @@ -16826,9 +17043,9 @@ } }, "svg-parser": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/svg-parser/-/svg-parser-2.0.3.tgz", - "integrity": "sha512-fnCWiifNhK8i2Z7b9R5tbNahpxrRdAaQbnoxKlT2KrSCj9Kq/yBSgulCRgBJRhy1dPnSY5slg5ehPUnzpEcHlg==" + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/svg-parser/-/svg-parser-2.0.4.tgz", + "integrity": "sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==" }, "svgo": { "version": "1.3.2", @@ -16866,9 +17083,9 @@ "integrity": "sha512-6PC+JRGmNjiG3kJ56ZMNWDPL8hjyghF5cMXIFOKg+NiwwEZZIvxTWd0pinWKyD227odg9ygF8xVhhz7gb8Uq7A==" }, "systemjs": { - "version": "6.2.4", - "resolved": "https://registry.npmjs.org/systemjs/-/systemjs-6.2.4.tgz", - "integrity": "sha512-e++CM66/hoVcpWyfj2TVdj4pqMq8PQQLPgQUjb17W0uD7fpRYmO/ahmNfSDwtLoXxF03YUrBcLgg8RahwpZVig==" + "version": "6.2.5", + "resolved": "https://registry.npmjs.org/systemjs/-/systemjs-6.2.5.tgz", + "integrity": "sha512-Jw1FOgzxG+wIi+ewEPyYKsqxR3IQOQWMwFh1o7C0VfLYoBcVDYSg8EFrKCisUD+5+/KecrDC+NSy4exkl7QRdw==" }, "systemjs-plugin-css": { "version": "0.1.37", @@ -16935,9 +17152,9 @@ } }, "terser": { - "version": "4.6.4", - "resolved": "https://registry.npmjs.org/terser/-/terser-4.6.4.tgz", - "integrity": "sha512-5fqgBPLgVHZ/fVvqRhhUp9YUiGXhFJ9ZkrZWD9vQtFBR4QIGTnbsb+/kKqSqfgp3WnBwGWAFnedGTtmX1YTn0w==", + "version": "4.6.6", + "resolved": "https://registry.npmjs.org/terser/-/terser-4.6.6.tgz", + "integrity": "sha512-4lYPyeNmstjIIESr/ysHg2vUPRGf2tzF9z2yYwnowXVuVzLEamPN1Gfrz7f8I9uEPuHcbFlW4PLIAsJoxXyJ1g==", "requires": { "commander": "^2.20.0", "source-map": "~0.6.1", @@ -17269,9 +17486,9 @@ "integrity": "sha512-ti7OGMOUOzo66wLF3liskw6YQIaSsBgc4GOAlWRnIEj8htCxJUxskanMUoJOD6MDCRAXo36goXJZch+nOS0VMA==" }, "tslib": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.11.0.tgz", - "integrity": "sha512-BmndXUtiTn/VDDrJzQE7Mm22Ix3PxgLltW9bSNLoeCY31gnG2OPx0QqJnuc9oMIKioYrz487i6K9o4Pdn0j+Kg==" + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.11.1.tgz", + "integrity": "sha512-aZW88SY8kQbU7gpV19lN24LtXh/yD4ZZg6qieAJDDg+YBsJcSmLGK9QpnUjAKVG/xefmvJGd1WUmfpT/g6AJGA==" }, "tsutils": { "version": "3.17.1", @@ -17347,9 +17564,9 @@ } }, "typescript": { - "version": "3.8.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.8.2.tgz", - "integrity": "sha512-EgOVgL/4xfVrCMbhYKUQTdF37SQn4Iw73H5BgCrF1Abdun7Kwy/QZsE/ssAy0y4LxBbvua3PIbFsbRczWWnDdQ==", + "version": "3.8.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.8.3.tgz", + "integrity": "sha512-MYlEfn5VrLNsgudQTVJeNaQFUAI7DkhnOjdpAp4T+ku1TfQClewlbSuTVHiA+8skNBgaf02TL/kLOvig4y3G8w==", "dev": true }, "typescript-compare": { @@ -18329,9 +18546,9 @@ "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==" }, "webpack": { - "version": "4.41.6", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.41.6.tgz", - "integrity": "sha512-yxXfV0Zv9WMGRD+QexkZzmGIh54bsvEs+9aRWxnN8erLWEOehAKUTeNBoUbA6HPEZPlRo7KDi2ZcNveoZgK9MA==", + "version": "4.42.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.42.0.tgz", + "integrity": "sha512-EzJRHvwQyBiYrYqhyjW9AqM90dE4+s1/XtCfn7uWg6cS72zH+2VPFAlsnW0+W0cDi0XRjNKUMoJtpSi50+Ph6w==", "dev": true, "requires": { "@webassemblyjs/ast": "1.8.5", diff --git a/package.json b/package.json index 31b0c38b5b9..ad5b589f95b 100644 --- a/package.json +++ b/package.json @@ -70,9 +70,11 @@ "@centreon/ui": "centreon/centreon-ui", "@material-ui/core": "^4.9.4", "@material-ui/icons": "^4.9.1", + "@material-ui/lab": "^4.0.0-alpha.45", "axios": "^0.19.2", "classnames": "^2.2.6", "connected-react-router": "^6.7.0", + "date-fns": "^2.10.0", "dom-serializer": "^0.2.2", "install": "^0.13.0", "loaders.css": "^0.1.2", diff --git a/setupTest.js b/setupTest.js new file mode 100644 index 00000000000..a7e699ce8ca --- /dev/null +++ b/setupTest.js @@ -0,0 +1,8 @@ +document.createRange = () => ({ + setStart: () => {}, + setEnd: () => {}, + commonAncestorContainer: { + nodeName: 'BODY', + ownerDocument: document, + }, +}); diff --git a/www/front_src/src/Resources/api/index.ts b/www/front_src/src/Resources/api/index.ts index e2faf94ad08..5c4b4e98395 100644 --- a/www/front_src/src/Resources/api/index.ts +++ b/www/front_src/src/Resources/api/index.ts @@ -7,7 +7,7 @@ const api = axios.create({ baseURL: './api/beta/', }); -const getData = ({ endpoint, requestParams }): Promise => +const getData = ({ endpoint, requestParams }): Promise => api.get(endpoint, requestParams).then(({ data }) => data); const listResources = ( @@ -16,4 +16,4 @@ const listResources = ( ): Promise => getData({ endpoint: buildResourcesEndpoint(endpointParams), requestParams }); -export { listResources }; +export { listResources, getData }; diff --git a/www/front_src/src/Resources/columns/State/DetailsTable/Acknowledgement.tsx b/www/front_src/src/Resources/columns/State/DetailsTable/Acknowledgement.tsx new file mode 100644 index 00000000000..12704cba7df --- /dev/null +++ b/www/front_src/src/Resources/columns/State/DetailsTable/Acknowledgement.tsx @@ -0,0 +1,61 @@ +import React from 'react'; + +import { + labelAuthor, + labelComment, + labelEntryTime, + labelPersistent, + labelSticky, +} from '../../../translatedLabels'; +import DetailsTable, { + getFormattedDate, + DetailsTableProps, + getYesNoLabel, +} from '.'; + +interface AcknoweldgementDetails { + author_name: string; + entry_time: string; + is_persistent_comment: string; + is_sticky: string; + comment: string; +} + +type Props = Pick; + +const AcknowledgementDetailsTable = ({ endpoint }: Props): JSX.Element => { + const columns = [ + { + label: labelAuthor, + getFormattedString: ({ author_name }): string => author_name, + }, + { + label: labelEntryTime, + getFormattedString: ({ entry_time }): string => + getFormattedDate(entry_time), + }, + { + label: labelPersistent, + getFormattedString: ({ is_persistent_comment }): string => + getYesNoLabel(is_persistent_comment), + }, + { + label: labelSticky, + getFormattedString: ({ is_sticky }): string => getYesNoLabel(is_sticky), + }, + + { + label: labelComment, + getFormattedString: ({ comment }): string => comment, + }, + ]; + + return ( + + columns={columns} + endpoint={endpoint} + /> + ); +}; + +export default AcknowledgementDetailsTable; diff --git a/www/front_src/src/Resources/columns/State/DetailsTable/Downtime.tsx b/www/front_src/src/Resources/columns/State/DetailsTable/Downtime.tsx new file mode 100644 index 00000000000..b15a7bca977 --- /dev/null +++ b/www/front_src/src/Resources/columns/State/DetailsTable/Downtime.tsx @@ -0,0 +1,56 @@ +import React from 'react'; + +import { + labelAuthor, + labelFixed, + labelYes, + labelNo, + labelStartTime, + labelEndTime, + labelComment, +} from '../../../translatedLabels'; +import DetailsTable, { getFormattedDate, DetailsTableProps } from '.'; + +interface DowntimeDetails { + author_name: string; + is_fixed: boolean; + start_time: string; + end_time: string; + ccoment: string; +} + +type Props = Pick; + +const DowntimeDetailsTable = ({ endpoint }: Props): JSX.Element => { + const columns = [ + { + label: labelAuthor, + getFormattedString: ({ author_name }): string => author_name, + }, + { + label: labelFixed, + getFormattedString: ({ is_fixed }): string => + is_fixed ? labelYes : labelNo, + }, + { + label: labelStartTime, + getFormattedString: ({ start_time }): string => + getFormattedDate(start_time), + }, + { + label: labelEndTime, + getFormattedString: ({ end_time }): string => getFormattedDate(end_time), + }, + + { + label: labelComment, + getFormattedString: ({ comment }): string => comment, + }, + ]; + + return ( + columns={columns} endpoint={endpoint} /> + ); +}; + +export default DowntimeDetailsTable; diff --git a/www/front_src/src/Resources/columns/State/DetailsTable/index.tsx b/www/front_src/src/Resources/columns/State/DetailsTable/index.tsx new file mode 100644 index 00000000000..bd84ed1a372 --- /dev/null +++ b/www/front_src/src/Resources/columns/State/DetailsTable/index.tsx @@ -0,0 +1,105 @@ +import React, { useState, useEffect } from 'react'; + +import format from 'date-fns/format'; +import parseISO from 'date-fns/parseISO'; + +import { + TableContainer, + TableRow, + Paper, + Table, + TableHead, + TableCell, + TableBody, +} from '@material-ui/core'; +import { Skeleton } from '@material-ui/lab'; + +import { getData } from '../../../api'; +import { + labelSomethingWentWrong, + labelYes, + labelNo, +} from '../../../translatedLabels'; +import useCancelTokenSource from '../../../useCancelTokenSource'; + +const getFormattedDate = (isoDate): string => + format(parseISO(isoDate), 'MM/dd/yyyy H:m'); + +const getYesNoLabel = (value): string => (value ? labelYes : labelNo); + +const columnMaxWidth = 150; + +interface Column { + getFormattedString: (details) => string; + label: string; +} + +export interface DetailsTableProps { + endpoint: string; + columns: Array; +} + +const DetailsTable = ({ + endpoint, + columns, +}: DetailsTableProps): JSX.Element => { + const [details, setDetails] = useState(); + const { cancel, token } = useCancelTokenSource(); + + useEffect(() => { + getData({ endpoint, requestParams: { cancelToken: token } }) + .then((retrievedDetails) => setDetails(retrievedDetails)) + .catch(() => { + setDetails(null); + }); + + return (): void => cancel(); + }, []); + + const loading = details === undefined; + const error = details === null; + const success = !loading && !error; + + const tableMaxWidth = columns.length * columnMaxWidth; + + return ( + + + + + {columns.map(({ label }) => ( + {label} + ))} + + + + + {loading && ( + + + + )} + {success && + columns.map(({ label, getFormattedString }) => ( + + {getFormattedString(details)} + + ))} + {error && ( + + {labelSomethingWentWrong} + + )} + + +
+
+ ); +}; + +export { getFormattedDate, getYesNoLabel }; +export default DetailsTable; diff --git a/www/front_src/src/Resources/columns/State/index.tsx b/www/front_src/src/Resources/columns/State/index.tsx new file mode 100644 index 00000000000..aaed4ca5d72 --- /dev/null +++ b/www/front_src/src/Resources/columns/State/index.tsx @@ -0,0 +1,118 @@ +import React from 'react'; + +import { Grid, Avatar, makeStyles, fade, Tooltip } from '@material-ui/core'; +import { Person as IconAcknowledged } from '@material-ui/icons'; +import { lime, purple } from '@material-ui/core/colors'; + +import IconDowntime from '../icons/Downtime'; +import { ColumnProps } from '..'; +import DowntimeDetailsTable from './DetailsTable/Downtime'; +import AcknowledgementDetailsTable from './DetailsTable/Acknowledgement'; +import { labelInDowntime, labelAcknowledged } from '../../translatedLabels'; +import { Resource } from '../../models'; + +const useStyles = makeStyles((theme) => ({ + stateChip: { + width: theme.spacing(4), + height: theme.spacing(4), + }, + acknowledged: { + backgroundColor: fade(lime[900], 0.1), + color: lime[900], + }, + downtime: { + backgroundColor: fade(purple[500], 0.1), + color: purple[500], + }, + tooltip: { + maxWidth: 'none', + backgroundColor: 'transparent', + }, +})); + +interface StateChipProps { + endpoint: string; + className: string; + Icon: React.SFC; + DetailsTable: React.SFC<{ endpoint: string }>; + ariaLabel: string; +} + +const StateChip = ({ + endpoint, + className, + Icon, + DetailsTable, + ariaLabel, +}: StateChipProps): JSX.Element => { + const classes = useStyles(); + + return ( + } + classes={{ tooltip: classes.tooltip }} + enterDelay={0} + > + + + + + ); +}; + +const DowntimeChip = ({ resource }: { resource: Resource }): JSX.Element => { + const classes = useStyles(); + + return ( + + ); +}; + +const AcknowledgedChip = ({ + resource, +}: { + resource: Resource; +}): JSX.Element => { + const classes = useStyles(); + + return ( + + ); +}; + +const StateColumn = ({ Cell, row }: ColumnProps): JSX.Element => { + return ( + + + {row.in_downtime && ( + + + + )} + {row.acknowledged && ( + + + + )} + + + ); +}; + +export default StateColumn; diff --git a/www/front_src/src/Resources/columns/icons/__mocks__/Downtime.tsx b/www/front_src/src/Resources/columns/icons/__mocks__/Downtime.tsx new file mode 100644 index 00000000000..0d41cc41e18 --- /dev/null +++ b/www/front_src/src/Resources/columns/icons/__mocks__/Downtime.tsx @@ -0,0 +1,5 @@ +import React from 'react'; + +const Downtime = (): JSX.Element => Downtime; + +export default Downtime; diff --git a/www/front_src/src/Resources/columns/icons/downtime.icon.svg b/www/front_src/src/Resources/columns/icons/downtime.icon.svg index f0f314a83e8..c08900b955c 100644 --- a/www/front_src/src/Resources/columns/icons/downtime.icon.svg +++ b/www/front_src/src/Resources/columns/icons/downtime.icon.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/www/front_src/src/Resources/columns/index.tsx b/www/front_src/src/Resources/columns/index.tsx index 6e23fa1333a..8ad9587d321 100644 --- a/www/front_src/src/Resources/columns/index.tsx +++ b/www/front_src/src/Resources/columns/index.tsx @@ -1,7 +1,6 @@ import React from 'react'; -import { Grid, Typography, Avatar, makeStyles, fade } from '@material-ui/core'; -import { Person as IconAcknowledged } from '@material-ui/icons'; +import { Grid, Typography, makeStyles } from '@material-ui/core'; import { TABLE_COLUMN_TYPES, StatusChip, StatusCode } from '@centreon/ui'; @@ -14,11 +13,16 @@ import { labelState, labelLastCheck, } from '../translatedLabels'; - -import IconDowntime from './icons/Downtime'; import { Resource } from '../models'; +import StateColumn from './State'; + +const useStyles = makeStyles((theme) => ({ + resourceDetailsCell: { + padding: theme.spacing(0.5), + }, +})); -interface ColumnProps { +export interface ColumnProps { row: Resource; Cell: ({ children, width }: { children; width? }) => JSX.Element; isRowSelected: boolean; @@ -48,10 +52,12 @@ const StatusColumn = ({ Cell, row }: ColumnProps): JSX.Element => { }; const ResourcesColumn = ({ Cell, row }: ColumnProps): JSX.Element => { + const classes = useStyles(); + return ( - - + + {row.icon ? ( { )} - + {row.name} {row.parent && ( - <> + - + - - {row.parent.name} - - - )} - - - ); -}; - -const useStateChipStyles = makeStyles((theme) => ({ - stateChip: { - width: theme.spacing(4), - height: theme.spacing(4), - }, - acknowledged: { - backgroundColor: fade('#AE9500', 0.1), - color: '#AE9500', - }, - downtime: { - backgroundColor: fade('#C117FF', 0.1), - color: '#C117FF', - }, -})); - -const DowntimeChip = (): JSX.Element => { - const classes = useStateChipStyles(); - - return ( - - - - ); -}; - -const AcknowledgedChip = (): JSX.Element => { - const classes = useStateChipStyles(); - - return ( - - - - ); -}; - -const StateColumn = ({ Cell, row }: ColumnProps): JSX.Element => { - return ( - - - {row.in_downtime && ( - - - - )} - {row.acknowledged && ( - - + {row.parent.name} )} diff --git a/www/front_src/src/Resources/index.test.tsx b/www/front_src/src/Resources/index.test.tsx index 94e8d34436f..ef79b591d46 100644 --- a/www/front_src/src/Resources/index.test.tsx +++ b/www/front_src/src/Resources/index.test.tsx @@ -11,12 +11,16 @@ import { labelAll, labelResourceName, labelSearch, + labelInDowntime, + labelAcknowledged, } from './translatedLabels'; import columns from './columns'; import { Resource } from './models'; const mockedAxios = axios as jest.Mocked; +jest.mock('./columns/icons/Downtime'); + const getEndpoint = ({ state = 'unhandled_problems', sortBy = undefined, @@ -67,8 +71,10 @@ const fillEntities = (): Array => { code: 0, name: 'OK', }, - acknowledged: false, - in_downtime: false, + acknowledged: index % 2 === 0, + acknowledgement_endpoint: `/monitoring/acknowledgement/${index}`, + in_downtime: index % 3 === 0, + downtime_endpoint: `/monitoring/downtime/${index}`, duration: '1m', last_check: '1m', tries: '1', @@ -102,10 +108,10 @@ describe(Resources, () => { }); beforeEach(() => { - mockedAxios.get.mockResolvedValue({ data: retrievedListing }); + mockedAxios.get.mockResolvedValueOnce({ data: retrievedListing }); }); - it('lists with unhnandled_problems state by default', async () => { + it('executes a listing request with unhnandled_problems state by default', async () => { render(); await wait(() => @@ -116,11 +122,13 @@ describe(Resources, () => { ); }); - it('executes a list request with selected state filter when state filter is changed', async () => { + it('executes a listing request with selected state filter when state filter is changed', async () => { const { getByText } = render(); await wait(() => expect(mockedAxios.get).toHaveBeenCalled()); + mockedAxios.get.mockResolvedValueOnce({ data: retrievedListing }); + selectOption(getByText(labelUnhandledProblems), labelResourceProblems); await wait(() => @@ -130,6 +138,8 @@ describe(Resources, () => { ), ); + mockedAxios.get.mockResolvedValueOnce({ data: retrievedListing }); + selectOption(getByText(labelResourceProblems), labelAll); await wait(() => @@ -140,7 +150,7 @@ describe(Resources, () => { ); }); - it('sends a listing request with sort_by param when a sortable column is clicked', async () => { + it('executes a listing request with sort_by param when a sortable column is clicked', async () => { const { getByText } = render(); await wait(() => { @@ -150,6 +160,8 @@ describe(Resources, () => { columns .filter(({ sortable }) => sortable !== false) .forEach(({ id, label }) => { + mockedAxios.get.mockResolvedValueOnce({ data: retrievedListing }); + fireEvent.click(getByText(label)); expect(mockedAxios.get).toHaveBeenCalledWith( @@ -157,6 +169,8 @@ describe(Resources, () => { cancelTokenRequestParam, ); + mockedAxios.get.mockResolvedValueOnce({ data: retrievedListing }); + fireEvent.click(getByText(label)); expect(mockedAxios.get).toHaveBeenCalledWith( @@ -166,15 +180,13 @@ describe(Resources, () => { }); }); - it('sends a listing request with an updated page param when a change page action is clicked', async () => { + it('executes a listing request with an updated page param when a change page action is clicked', async () => { const { getByLabelText } = render(); await wait(() => { expect(mockedAxios.get).toHaveBeenCalled(); }); - mockedAxios.get.mockReset(); - mockedAxios.get.mockResolvedValueOnce({ data: { ...retrievedListing, @@ -235,6 +247,8 @@ describe(Resources, () => { it('executes a listing request with a limit param when the rows per page value is changed', () => { const { getByDisplayValue } = render(); + mockedAxios.get.mockResolvedValueOnce({ data: retrievedListing }); + fireEvent.change(getByDisplayValue('10'), { target: { value: '20' }, }); @@ -246,7 +260,7 @@ describe(Resources, () => { }); searchableFields.forEach((searchableField) => { - it(`executes a listing request with a search param containing ${searchableField} when ${searchableField} is typed in the SearchField`, () => { + it(`executes a listing request with a search param containing ${searchableField} when ${searchableField} is typed in the search field`, () => { const { getByPlaceholderText, getByText } = render(); const fieldSearchValue = 'foobar'; @@ -255,6 +269,8 @@ describe(Resources, () => { target: { value: `${searchableField}:${fieldSearchValue}` }, }); + mockedAxios.get.mockResolvedValueOnce({ data: retrievedListing }); + fireEvent.click(getByText(labelSearch)); expect(mockedAxios.get).toHaveBeenCalledWith( @@ -266,7 +282,7 @@ describe(Resources, () => { }); }); - it('executes a listing request with a search param containing all searchable fields if no searchable field is directly specified', () => { + it('executes a listing request with a search param containing all searchable fields when a string that does not correspond to any searchable field is typed in the search field', () => { const { getByPlaceholderText, getByText } = render(); const searchValue = 'foobar'; @@ -275,6 +291,8 @@ describe(Resources, () => { target: { value: searchValue }, }); + mockedAxios.get.mockResolvedValueOnce({ data: retrievedListing }); + fireEvent.click(getByText(labelSearch)); expect(mockedAxios.get).toHaveBeenCalledWith( @@ -287,4 +305,82 @@ describe(Resources, () => { cancelTokenRequestParam, ); }); + + it('displays downtime details when the downtime state chip is hovered', async () => { + const { getByLabelText, getByText } = render(); + + const entityInDowntime = entities.find(({ in_downtime }) => in_downtime); + + await wait(() => { + expect(mockedAxios.get).toHaveBeenCalled(); + }); + + mockedAxios.get.mockResolvedValueOnce({ + data: { + author_name: 'admin', + start_time: '2020-02-28T09:16:16', + end_time: '2020-02-28T09:18:16', + is_fixed: true, + comment: 'Set by admin', + }, + }); + + const chipLabel = `${entityInDowntime?.name} ${labelInDowntime}`; + + fireEvent.mouseEnter(getByLabelText(chipLabel)); + fireEvent.mouseOver(getByLabelText(chipLabel)); + + await wait(() => expect(mockedAxios.get).toHaveBeenCalled()); + + expect(mockedAxios.get).toHaveBeenLastCalledWith( + entityInDowntime?.downtime_endpoint, + cancelTokenRequestParam, + ); + + expect(getByText('admin')).toBeInTheDocument(); + expect(getByText('Yes')).toBeInTheDocument(); + expect(getByText('02/28/2020 9:16')).toBeInTheDocument(); + expect(getByText('02/28/2020 9:18')).toBeInTheDocument(); + expect(getByText('Set by admin')).toBeInTheDocument(); + }); + + it('displays acknowledgement details when an acknowledged state chip is hovered', async () => { + const { getByLabelText, getByText } = render(); + + const acknowledgedEntity = entities.find( + ({ acknowledged }) => acknowledged, + ); + + await wait(() => { + expect(mockedAxios.get).toHaveBeenCalled(); + }); + + mockedAxios.get.mockResolvedValueOnce({ + data: { + author_name: 'admin', + entry_time: '2020-02-28T09:16:16', + is_persistent_comment: true, + is_sticky: false, + comment: 'Set by admin', + }, + }); + + const chipLabel = `${acknowledgedEntity?.name} ${labelAcknowledged}`; + + fireEvent.mouseEnter(getByLabelText(chipLabel)); + fireEvent.mouseOver(getByLabelText(chipLabel)); + + await wait(() => expect(mockedAxios.get).toHaveBeenCalled()); + + expect(mockedAxios.get).toHaveBeenLastCalledWith( + acknowledgedEntity?.acknowledgement_endpoint, + cancelTokenRequestParam, + ); + + expect(getByText('admin')).toBeInTheDocument(); + expect(getByText('02/28/2020 9:16')).toBeInTheDocument(); + expect(getByText('Yes')).toBeInTheDocument(); + expect(getByText('No')).toBeInTheDocument(); + expect(getByText('Set by admin')).toBeInTheDocument(); + }); }); diff --git a/www/front_src/src/Resources/index.tsx b/www/front_src/src/Resources/index.tsx index 88ba2e16ff4..b07b1f4fe6c 100644 --- a/www/front_src/src/Resources/index.tsx +++ b/www/front_src/src/Resources/index.tsx @@ -3,6 +3,7 @@ import React, { useEffect, useState } from 'react'; import axios from 'axios'; import { Typography, makeStyles, Paper, Grid, Button } from '@material-ui/core'; +import { lime, purple } from '@material-ui/core/colors'; import { Listing, @@ -117,6 +118,19 @@ const Resources = (): JSX.Element => { setSearch(searchFieldValue); }; + const rowColorConditions = [ + { + name: 'inDowntime', + condition: ({ in_downtime }): boolean => in_downtime, + color: purple[500], + }, + { + name: 'acknowledged', + condition: ({ acknowledged }): boolean => acknowledged, + color: lime[900], + }, + ]; + return (
@@ -166,6 +180,7 @@ const Resources = (): JSX.Element => { columnConfiguration={columns} tableData={listing?.result} currentPage={page - 1} + rowColorConditions={rowColorConditions} limit={listing?.meta.limit} onDelete={noOp} onSort={changeSort} diff --git a/www/front_src/src/Resources/models.ts b/www/front_src/src/Resources/models.ts index 32d9a06e629..b88ce55790b 100644 --- a/www/front_src/src/Resources/models.ts +++ b/www/front_src/src/Resources/models.ts @@ -30,7 +30,9 @@ export interface Resource { icon?: Icon; parent?: Parent; status: Status; + downtime_endpoint?: string; acknowledged: boolean; + acknowledgement_endpoint?: string; in_downtime: boolean; duration: string; tries: string; diff --git a/www/front_src/src/Resources/translatedLabels.ts b/www/front_src/src/Resources/translatedLabels.ts index dfb81f5bef6..3403baa9c95 100644 --- a/www/front_src/src/Resources/translatedLabels.ts +++ b/www/front_src/src/Resources/translatedLabels.ts @@ -1,15 +1,25 @@ import { I18n } from 'react-redux-i18n'; +export const labelAcknowledged = I18n.t('acknowledged'); export const labelAll = I18n.t('All'); +export const labelAuthor = I18n.t('Author'); +export const labelComment = I18n.t('Comment'); export const labelDuration = I18n.t('Duration'); +export const labelEndTime = I18n.t('End time'); +export const labelEntryTime = I18n.t('Entry time'); export const labelFilter = I18n.t('Filter'); +export const labelFixed = I18n.t('Fixed'); +export const labelInDowntime = I18n.t('in downtime'); export const labelLastCheck = I18n.t('Last check'); +export const labelNo = I18n.t('No'); +export const labelPersistent = I18n.t('Persistent'); export const labelResourceName = I18n.t('Resource name'); export const labelResourceProblems = I18n.t('Resource problems'); export const labelResources = I18n.t('Resources'); export const labelSearch = I18n.t('Search'); export const labelSeverity = I18n.t('Severity'); export const labelStatus = I18n.t('Status'); +export const labelSticky = I18n.t('Sticky'); export const labelTries = I18n.t('Tries'); export const labelInformation = I18n.t('Information'); export const labelSearchOnFields = I18n.t( @@ -24,9 +34,12 @@ export const labelSearchByHostName = I18n.t( export const labelSearchByServiceStartingWith = I18n.t( "To search services with a description starting with the string 'centreon', you can type:", ); +export const labelStartTime = I18n.t('Start time'); export const labelState = I18n.t('State'); export const labelStateFilter = I18n.t('State filter'); export const labelUnhandledProblems = I18n.t('Unhandled problems'); export const labelUsePartialQuery = I18n.t( "It's also possible to use a partial query for the search value, by using a regular expression, for instance:", ); +export const labelYes = I18n.t('Yes'); +export const labelSomethingWentWrong = I18n.t('Oops, something went wrong'); diff --git a/www/front_src/src/Resources/useCancelTokenSource.ts b/www/front_src/src/Resources/useCancelTokenSource.ts new file mode 100644 index 00000000000..714cf8ac781 --- /dev/null +++ b/www/front_src/src/Resources/useCancelTokenSource.ts @@ -0,0 +1,11 @@ +import { useState } from 'react'; + +import axios, { CancelTokenSource } from 'axios'; + +const useCancelTokenSource = (): CancelTokenSource => { + const [cancelTokenSource] = useState(axios.CancelToken.source()); + + return cancelTokenSource; +}; + +export default useCancelTokenSource;