Implement Redux
This commit is contained in:
parent
228e7b58dd
commit
699b99bdd5
11 changed files with 273 additions and 115 deletions
152
ui/package-lock.json
generated
152
ui/package-lock.json
generated
|
|
@ -7,8 +7,7 @@
|
|||
"@sindresorhus/is": {
|
||||
"version": "0.7.0",
|
||||
"resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.7.0.tgz",
|
||||
"integrity": "sha512-ONhaKPIufzzrlNbqtWFFd+jlnemX6lJAgq9ZeiZtS7I1PIf/la7CW4m83rTXRnVnsMbW2k56pGYu7AUFJD9Pow==",
|
||||
"dev": true
|
||||
"integrity": "sha512-ONhaKPIufzzrlNbqtWFFd+jlnemX6lJAgq9ZeiZtS7I1PIf/la7CW4m83rTXRnVnsMbW2k56pGYu7AUFJD9Pow=="
|
||||
},
|
||||
"accepts": {
|
||||
"version": "1.3.5",
|
||||
|
|
@ -1500,7 +1499,6 @@
|
|||
"version": "2.1.4",
|
||||
"resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-2.1.4.tgz",
|
||||
"integrity": "sha1-DYCIAbY0KtM8kd+dC0TcCbkeXD0=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"clone-response": "1.0.2",
|
||||
"get-stream": "3.0.0",
|
||||
|
|
@ -1562,6 +1560,39 @@
|
|||
"integrity": "sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I=",
|
||||
"dev": true
|
||||
},
|
||||
"chart.js": {
|
||||
"version": "2.7.2",
|
||||
"resolved": "https://registry.npmjs.org/chart.js/-/chart.js-2.7.2.tgz",
|
||||
"integrity": "sha512-90wl3V9xRZ8tnMvMlpcW+0Yg13BelsGS9P9t0ClaDxv/hdypHDr/YAGf+728m11P5ljwyB0ZHfPKCapZFqSqYA==",
|
||||
"requires": {
|
||||
"chartjs-color": "2.2.0",
|
||||
"moment": "2.21.0"
|
||||
}
|
||||
},
|
||||
"chartjs-color": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/chartjs-color/-/chartjs-color-2.2.0.tgz",
|
||||
"integrity": "sha1-hKL7dVeH7YXDndbdjHsdiEKbrq4=",
|
||||
"requires": {
|
||||
"chartjs-color-string": "0.5.0",
|
||||
"color-convert": "0.5.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"color-convert": {
|
||||
"version": "0.5.3",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-0.5.3.tgz",
|
||||
"integrity": "sha1-vbbGnOZg+t/+CwAHzER+G59ygr0="
|
||||
}
|
||||
}
|
||||
},
|
||||
"chartjs-color-string": {
|
||||
"version": "0.5.0",
|
||||
"resolved": "https://registry.npmjs.org/chartjs-color-string/-/chartjs-color-string-0.5.0.tgz",
|
||||
"integrity": "sha512-amWNvCOXlOUYxZVDSa0YOab5K/lmEhbFNKI55PWc4mlv28BDzA7zaoQTGxSBgJMHIW+hGX8YUrvw/FH4LyhwSQ==",
|
||||
"requires": {
|
||||
"color-name": "1.1.3"
|
||||
}
|
||||
},
|
||||
"chokidar": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.0.2.tgz",
|
||||
|
|
@ -1821,7 +1852,6 @@
|
|||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz",
|
||||
"integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"mimic-response": "1.0.0"
|
||||
}
|
||||
|
|
@ -1891,8 +1921,7 @@
|
|||
"color-name": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
|
||||
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
|
||||
"dev": true
|
||||
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
|
||||
},
|
||||
"color-string": {
|
||||
"version": "0.3.0",
|
||||
|
|
@ -2068,8 +2097,7 @@
|
|||
"core-util-is": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
|
||||
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
|
||||
"dev": true
|
||||
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
|
||||
},
|
||||
"cosmiconfig": {
|
||||
"version": "2.2.2",
|
||||
|
|
@ -2443,14 +2471,12 @@
|
|||
"decode-uri-component": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz",
|
||||
"integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=",
|
||||
"dev": true
|
||||
"integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU="
|
||||
},
|
||||
"decompress-response": {
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz",
|
||||
"integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"mimic-response": "1.0.0"
|
||||
}
|
||||
|
|
@ -2601,8 +2627,7 @@
|
|||
"duplexer3": {
|
||||
"version": "0.1.4",
|
||||
"resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz",
|
||||
"integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=",
|
||||
"dev": true
|
||||
"integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI="
|
||||
},
|
||||
"duplexify": {
|
||||
"version": "3.5.4",
|
||||
|
|
@ -3310,7 +3335,6 @@
|
|||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz",
|
||||
"integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"inherits": "2.0.3",
|
||||
"readable-stream": "2.3.5"
|
||||
|
|
@ -4259,8 +4283,7 @@
|
|||
"get-stream": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz",
|
||||
"integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=",
|
||||
"dev": true
|
||||
"integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ="
|
||||
},
|
||||
"get-value": {
|
||||
"version": "2.0.6",
|
||||
|
|
@ -4494,7 +4517,6 @@
|
|||
"version": "8.3.0",
|
||||
"resolved": "https://registry.npmjs.org/got/-/got-8.3.0.tgz",
|
||||
"integrity": "sha512-kBNy/S2CGwrYgDSec5KTWGKUvupwkkTVAjIsVFF2shXO13xpZdFP4d4kxa//CLX2tN/rV0aYwK8vY6UKWGn2vQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@sindresorhus/is": "0.7.0",
|
||||
"cacheable-request": "2.1.4",
|
||||
|
|
@ -4569,14 +4591,12 @@
|
|||
"has-symbol-support-x": {
|
||||
"version": "1.4.2",
|
||||
"resolved": "https://registry.npmjs.org/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz",
|
||||
"integrity": "sha512-3ToOva++HaW+eCpgqZrCfN51IPB+7bJNVT6CUATzueB5Heb8o6Nam0V3HG5dlDvZU1Gn5QLcbahiKw/XVk5JJw==",
|
||||
"dev": true
|
||||
"integrity": "sha512-3ToOva++HaW+eCpgqZrCfN51IPB+7bJNVT6CUATzueB5Heb8o6Nam0V3HG5dlDvZU1Gn5QLcbahiKw/XVk5JJw=="
|
||||
},
|
||||
"has-to-string-tag-x": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/has-to-string-tag-x/-/has-to-string-tag-x-1.4.1.tgz",
|
||||
"integrity": "sha512-vdbKfmw+3LoOYVr+mtxHaX5a96+0f3DljYd8JOqvOLsf5mw2Otda2qCDT9qRqLAhrjyQ0h7ual5nOiASpsGNFw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"has-symbol-support-x": "1.4.2"
|
||||
}
|
||||
|
|
@ -4707,8 +4727,7 @@
|
|||
"http-cache-semantics": {
|
||||
"version": "3.8.1",
|
||||
"resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz",
|
||||
"integrity": "sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w==",
|
||||
"dev": true
|
||||
"integrity": "sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w=="
|
||||
},
|
||||
"http-deceiver": {
|
||||
"version": "1.2.7",
|
||||
|
|
@ -4969,8 +4988,7 @@
|
|||
"inherits": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
|
||||
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
|
||||
"dev": true
|
||||
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
|
||||
},
|
||||
"ini": {
|
||||
"version": "1.3.5",
|
||||
|
|
@ -5035,7 +5053,6 @@
|
|||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/into-stream/-/into-stream-3.1.0.tgz",
|
||||
"integrity": "sha1-lvsKk2wSur1v8XUqF9BWFqvQlMY=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"from2": "2.3.0",
|
||||
"p-is-promise": "1.1.0"
|
||||
|
|
@ -5228,8 +5245,7 @@
|
|||
"is-object": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/is-object/-/is-object-1.0.1.tgz",
|
||||
"integrity": "sha1-iVJojF7C/9awPsyF52ngKQMINHA=",
|
||||
"dev": true
|
||||
"integrity": "sha1-iVJojF7C/9awPsyF52ngKQMINHA="
|
||||
},
|
||||
"is-observable": {
|
||||
"version": "0.2.0",
|
||||
|
|
@ -5292,8 +5308,7 @@
|
|||
"is-plain-obj": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz",
|
||||
"integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=",
|
||||
"dev": true
|
||||
"integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4="
|
||||
},
|
||||
"is-plain-object": {
|
||||
"version": "2.0.4",
|
||||
|
|
@ -5334,8 +5349,7 @@
|
|||
"is-retry-allowed": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz",
|
||||
"integrity": "sha1-EaBgVotnM5REAz0BJaYaINVk+zQ=",
|
||||
"dev": true
|
||||
"integrity": "sha1-EaBgVotnM5REAz0BJaYaINVk+zQ="
|
||||
},
|
||||
"is-scoped": {
|
||||
"version": "1.0.0",
|
||||
|
|
@ -5388,8 +5402,7 @@
|
|||
"isarray": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
|
||||
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
|
||||
"dev": true
|
||||
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
|
||||
},
|
||||
"isexe": {
|
||||
"version": "2.0.0",
|
||||
|
|
@ -5418,7 +5431,6 @@
|
|||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/isurl/-/isurl-1.0.0.tgz",
|
||||
"integrity": "sha512-1P/yWsxPlDtn7QeRD+ULKQPaIaN6yF368GZ2vDfv0AL0NwpStafjWCDDdn0k8wgFMWpVAqG7oJhxHnlud42i9w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"has-to-string-tag-x": "1.4.1",
|
||||
"is-object": "1.0.1"
|
||||
|
|
@ -5574,8 +5586,7 @@
|
|||
"json-buffer": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz",
|
||||
"integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=",
|
||||
"dev": true
|
||||
"integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg="
|
||||
},
|
||||
"json-parse-better-errors": {
|
||||
"version": "1.0.1",
|
||||
|
|
@ -5605,7 +5616,6 @@
|
|||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/keyv/-/keyv-3.0.0.tgz",
|
||||
"integrity": "sha512-eguHnq22OE3uVoSYG0LVWNP+4ppamWr9+zWBe1bsNcovIMy6huUJFPgy4mGwCd/rnl3vOLGW1MTlu4c57CT1xA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"json-buffer": "3.0.0"
|
||||
}
|
||||
|
|
@ -6008,8 +6018,7 @@
|
|||
"lowercase-keys": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.0.tgz",
|
||||
"integrity": "sha1-TjNms55/VFfjXxMkvfb4jQv8cwY=",
|
||||
"dev": true
|
||||
"integrity": "sha1-TjNms55/VFfjXxMkvfb4jQv8cwY="
|
||||
},
|
||||
"lru-cache": {
|
||||
"version": "4.1.2",
|
||||
|
|
@ -6272,8 +6281,7 @@
|
|||
"mimic-response": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.0.tgz",
|
||||
"integrity": "sha1-3z02Uqc/3ta5sLJBRub9BSNTRY4=",
|
||||
"dev": true
|
||||
"integrity": "sha1-3z02Uqc/3ta5sLJBRub9BSNTRY4="
|
||||
},
|
||||
"minimalistic-assert": {
|
||||
"version": "1.0.0",
|
||||
|
|
@ -6350,6 +6358,11 @@
|
|||
"minimist": "0.0.8"
|
||||
}
|
||||
},
|
||||
"moment": {
|
||||
"version": "2.21.0",
|
||||
"resolved": "https://registry.npmjs.org/moment/-/moment-2.21.0.tgz",
|
||||
"integrity": "sha512-TCZ36BjURTeFTM/CwRcViQlfkMvL1/vFISuNLO5GkcVm1+QHfbSiNqZuWeMFjj1/3+uAjXswgRk30j1kkLYJBQ=="
|
||||
},
|
||||
"move-concurrently": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz",
|
||||
|
|
@ -6558,7 +6571,6 @@
|
|||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-2.0.1.tgz",
|
||||
"integrity": "sha512-D6MUW4K/VzoJ4rJ01JFKxDrtY1v9wrgzCX5f2qj/lzH1m/lW6MhUZFKerVsnyjOhOsYzI9Kqqak+10l4LvLpMw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"prepend-http": "2.0.0",
|
||||
"query-string": "5.1.1",
|
||||
|
|
@ -6589,8 +6601,7 @@
|
|||
"object-assign": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
||||
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
|
||||
"dev": true
|
||||
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
|
||||
},
|
||||
"object-copy": {
|
||||
"version": "0.1.0",
|
||||
|
|
@ -6859,8 +6870,7 @@
|
|||
"p-cancelable": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-0.4.0.tgz",
|
||||
"integrity": "sha512-/AodqPe1y/GYbhSlnMjxukLGQfQIgsmjSy2CXCNB96kg4ozKvmlovuHEKICToOO/yS3LLWgrWI1dFtFfrePS1g==",
|
||||
"dev": true
|
||||
"integrity": "sha512-/AodqPe1y/GYbhSlnMjxukLGQfQIgsmjSy2CXCNB96kg4ozKvmlovuHEKICToOO/yS3LLWgrWI1dFtFfrePS1g=="
|
||||
},
|
||||
"p-each-series": {
|
||||
"version": "1.0.0",
|
||||
|
|
@ -6874,14 +6884,12 @@
|
|||
"p-finally": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz",
|
||||
"integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=",
|
||||
"dev": true
|
||||
"integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4="
|
||||
},
|
||||
"p-is-promise": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-1.1.0.tgz",
|
||||
"integrity": "sha1-nJRWmJ6fZYgBewQ01WCXZ1w9oF4=",
|
||||
"dev": true
|
||||
"integrity": "sha1-nJRWmJ6fZYgBewQ01WCXZ1w9oF4="
|
||||
},
|
||||
"p-lazy": {
|
||||
"version": "1.0.0",
|
||||
|
|
@ -6923,7 +6931,6 @@
|
|||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-2.0.1.tgz",
|
||||
"integrity": "sha512-88em58dDVB/KzPEx1X0N3LwFfYZPyDc4B6eF38M1rk9VTZMbxXXgjugz8mmwpS9Ox4BDZ+t6t3QP5+/gazweIA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"p-finally": "1.0.0"
|
||||
}
|
||||
|
|
@ -7103,8 +7110,7 @@
|
|||
"pify": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
|
||||
"integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=",
|
||||
"dev": true
|
||||
"integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY="
|
||||
},
|
||||
"pinkie": {
|
||||
"version": "2.0.4",
|
||||
|
|
@ -8961,8 +8967,7 @@
|
|||
"prepend-http": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz",
|
||||
"integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=",
|
||||
"dev": true
|
||||
"integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc="
|
||||
},
|
||||
"preserve": {
|
||||
"version": "0.2.0",
|
||||
|
|
@ -8997,8 +9002,7 @@
|
|||
"process-nextick-args": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz",
|
||||
"integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==",
|
||||
"dev": true
|
||||
"integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw=="
|
||||
},
|
||||
"promise-inflight": {
|
||||
"version": "1.0.1",
|
||||
|
|
@ -9084,7 +9088,6 @@
|
|||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/query-string/-/query-string-5.1.1.tgz",
|
||||
"integrity": "sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"decode-uri-component": "0.2.0",
|
||||
"object-assign": "4.1.1",
|
||||
|
|
@ -9223,7 +9226,6 @@
|
|||
"version": "2.3.5",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.5.tgz",
|
||||
"integrity": "sha512-tK0yDhrkygt/knjowCUiWP9YdV7c5R+8cR0r/kt9ZhBU906Fs6RpQJCEilamRJj1Nx2rWI6LkW9gKqjTkshhEw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"core-util-is": "1.0.2",
|
||||
"inherits": "2.0.3",
|
||||
|
|
@ -9490,7 +9492,6 @@
|
|||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz",
|
||||
"integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"lowercase-keys": "1.0.0"
|
||||
}
|
||||
|
|
@ -9575,8 +9576,7 @@
|
|||
"safe-buffer": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz",
|
||||
"integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==",
|
||||
"dev": true
|
||||
"integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg=="
|
||||
},
|
||||
"safe-regex": {
|
||||
"version": "1.1.0",
|
||||
|
|
@ -9965,7 +9965,6 @@
|
|||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-2.0.0.tgz",
|
||||
"integrity": "sha1-ZYU1WEhh7JfXMNbPQYIuH1ZoQSg=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"is-plain-obj": "1.1.0"
|
||||
}
|
||||
|
|
@ -10230,8 +10229,7 @@
|
|||
"strict-uri-encode": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz",
|
||||
"integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=",
|
||||
"dev": true
|
||||
"integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM="
|
||||
},
|
||||
"string-template": {
|
||||
"version": "0.2.1",
|
||||
|
|
@ -10276,7 +10274,6 @@
|
|||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz",
|
||||
"integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"safe-buffer": "5.1.1"
|
||||
}
|
||||
|
|
@ -10449,8 +10446,7 @@
|
|||
"timed-out": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz",
|
||||
"integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=",
|
||||
"dev": true
|
||||
"integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8="
|
||||
},
|
||||
"timers-browserify": {
|
||||
"version": "2.0.6",
|
||||
|
|
@ -10809,7 +10805,6 @@
|
|||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz",
|
||||
"integrity": "sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"prepend-http": "2.0.0"
|
||||
}
|
||||
|
|
@ -10817,8 +10812,7 @@
|
|||
"url-to-options": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/url-to-options/-/url-to-options-1.0.1.tgz",
|
||||
"integrity": "sha1-FQWgOiiaSMvXpDTvuu7FBV9WM6k=",
|
||||
"dev": true
|
||||
"integrity": "sha1-FQWgOiiaSMvXpDTvuu7FBV9WM6k="
|
||||
},
|
||||
"use": {
|
||||
"version": "3.1.0",
|
||||
|
|
@ -10849,8 +10843,7 @@
|
|||
"util-deprecate": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
||||
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
|
||||
"dev": true
|
||||
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
|
||||
},
|
||||
"utils-merge": {
|
||||
"version": "1.0.1",
|
||||
|
|
@ -10974,6 +10967,14 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"vue-resource": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/vue-resource/-/vue-resource-1.5.0.tgz",
|
||||
"integrity": "sha512-em+Ihe+duUWQv4uKO8aFTGK+e/lvNtk5EBEmWaBYcfQzBmHhKR4jJAeVIHcG6otugmsme/DmYrOEPfbss+2XfQ==",
|
||||
"requires": {
|
||||
"got": "8.3.0"
|
||||
}
|
||||
},
|
||||
"vue-router": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/vue-router/-/vue-router-3.0.1.tgz",
|
||||
|
|
@ -11005,6 +11006,11 @@
|
|||
"integrity": "sha512-x3LV3wdmmERhVCYy3quqA57NJW7F3i6faas++pJQWtknWT+n7k30F4TVdHvCLn48peTJFRvCpxs3UuFPqgeELg==",
|
||||
"dev": true
|
||||
},
|
||||
"vuex": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/vuex/-/vuex-3.0.1.tgz",
|
||||
"integrity": "sha512-wLoqz0B7DSZtgbWL1ShIBBCjv22GV5U+vcBFox658g6V0s4wZV9P4YjCNyoHSyIBpj1f29JBoNQIqD82cR4O3w=="
|
||||
},
|
||||
"watchpack": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.5.0.tgz",
|
||||
|
|
|
|||
|
|
@ -19,10 +19,14 @@
|
|||
"sideEffects": false,
|
||||
"dependencies": {
|
||||
"bootstrap": "^4.0.0",
|
||||
"chart.js": "^2.7.2",
|
||||
"font-awesome": "^4.7.0",
|
||||
"jquery": "^3.3.1",
|
||||
"moment": "^2.21.0",
|
||||
"vue": "^2.5.16",
|
||||
"vue-router": "^3.0.1"
|
||||
"vue-resource": "^1.5.0",
|
||||
"vue-router": "^3.0.1",
|
||||
"vuex": "^3.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-loader": "^7.1.4",
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@
|
|||
</li>
|
||||
</ul>
|
||||
<hr class="hideable" />
|
||||
<p class="hideable">
|
||||
<p class="hideable" id="copyright">
|
||||
Copyright © Cosmic Pi Inc. 2018. <br />All Rights Reserved. <br />
|
||||
</p>
|
||||
</div>
|
||||
|
|
@ -45,6 +45,8 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import moment from 'moment';
|
||||
|
||||
export default {
|
||||
name: '',
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,6 +37,10 @@ hr {
|
|||
border-right: 1px solid #111;
|
||||
}
|
||||
|
||||
#sidebar #copyright {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
#sidebar ul {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
|
|
@ -59,7 +63,7 @@ hr {
|
|||
width: 100%;
|
||||
display: block;
|
||||
color: #ddd;
|
||||
font-size: 18px;
|
||||
font-size: 16px;
|
||||
transition: padding 0.2s;
|
||||
}
|
||||
|
||||
|
|
@ -75,8 +79,6 @@ hr {
|
|||
|
||||
#sidebar #logo {
|
||||
width: 100%;
|
||||
padding: 5px 10px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
#sidebar p {
|
||||
|
|
@ -94,10 +96,6 @@ hr {
|
|||
background-color: white;
|
||||
}
|
||||
|
||||
.component-content {
|
||||
padding: 4px 20px;
|
||||
}
|
||||
|
||||
@media(max-width:768px) {
|
||||
#sidebar {
|
||||
width: var(--mobile-sidebar-width);
|
||||
|
|
|
|||
|
|
@ -1,22 +1,33 @@
|
|||
<template>
|
||||
<div class="row">
|
||||
<LiveValue value="NA" icon="fa-thermometer-quarter"></LiveValue>
|
||||
<Value :value=lastTemperature icon="fa-thermometer-quarter" title="Temperature"></Value>
|
||||
<Value :value=lastHumidity icon="fa-thermometer-quarter" title="Humidity"></Value>
|
||||
|
||||
<TimeSeries title="Temperature (C)" dkey="TemperatureC"></TimeSeries>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import LiveValue from './LiveValue.vue'
|
||||
|
||||
import Value from './Value.vue'
|
||||
import TimeSeries from './TimeSeries.vue'
|
||||
|
||||
export default {
|
||||
name: 'Dashboard',
|
||||
components: {
|
||||
LiveValue
|
||||
components: { Value, TimeSeries },
|
||||
computed: {
|
||||
times() {
|
||||
return this.$store.getters.getTimeSeries();
|
||||
},
|
||||
lastTemperature() {
|
||||
return this.$store.getters.getLastValue('TemperatureC');
|
||||
},
|
||||
lastHumidity() {
|
||||
let value = this.$store.getters.getLastValue('Humidity');
|
||||
return (!isNaN(value)) ? value.toFixed(2) : value;
|
||||
},
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
temperatureValue: 'NA',
|
||||
}
|
||||
beforeCreate() {
|
||||
this.$store.dispatch('requestSeries');
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -1,22 +0,0 @@
|
|||
<template>
|
||||
<div class="card bg-primary col-bg-3 col-md-4 col-sm-6 col-xs-12">
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-3">
|
||||
<i class="fa fa-thermometer-quarter fa-5x"></i>
|
||||
</div>
|
||||
<div class="col-9 text-center">
|
||||
<div class="huge">{{ value }}</div>
|
||||
<div class="card-title">Temperature</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'LiveValue',
|
||||
props: ['value', 'icon'],
|
||||
}
|
||||
</script>
|
||||
64
ui/src/components/TimeSeries.vue
Normal file
64
ui/src/components/TimeSeries.vue
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
<template>
|
||||
<div class="col-lg-6">
|
||||
<div class="card card-default">
|
||||
<div class="card-header">
|
||||
<h5>{{ title }}</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<canvas ref="canvas" style="height:300px"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Chart from 'chart.js'
|
||||
|
||||
|
||||
export default {
|
||||
name: 'TimeSeries',
|
||||
props: ['title', 'dkey'],
|
||||
data() {
|
||||
return {
|
||||
chart: null,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
times() {
|
||||
return this.$store.getters.getTimeSeries();
|
||||
},
|
||||
values() {
|
||||
return this.$store.getters.getSeries(this.dkey);
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
'times': function() {
|
||||
this.chart.data.datasets[0].data = this.values;
|
||||
this.chart.data.labels = this.times
|
||||
this.chart.update();
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.chart = new Chart(this.$refs.canvas, {
|
||||
type: 'line',
|
||||
data: {
|
||||
labels: this.times,
|
||||
datasets: [{
|
||||
label: this.title,
|
||||
data: this.values,
|
||||
backgroundColor: "rgba(153,51,255,0.4)"
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
animation: false,
|
||||
},
|
||||
});
|
||||
|
||||
/*
|
||||
setInterval(() => {
|
||||
this.$store.dispatch('addRandomValues');
|
||||
}, 1000);
|
||||
*/
|
||||
},
|
||||
}
|
||||
</script>
|
||||
30
ui/src/components/Value.vue
Normal file
30
ui/src/components/Value.vue
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
<template>
|
||||
<div class="col-bg-3 col-md-4 col-sm-6 col-xs-12 item">
|
||||
<div class="card card-default bg-primary">
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-3">
|
||||
<i :class="[ ['fa', icon, 'fa-5x'].join(' ') ]"></i>
|
||||
</div>
|
||||
<div class="col-9 text-right">
|
||||
<div class="huge">{{ value }}</div>
|
||||
<div class="card-title">{{ title }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'Value',
|
||||
props: ['value', 'icon', 'title'],
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.item {
|
||||
padding-bottom: 20px;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,17 +1,27 @@
|
|||
import Vue from 'vue'
|
||||
import VueResource from 'vue-resource';
|
||||
import router from './router.js'
|
||||
import store from './store.js';
|
||||
import App from './App.vue'
|
||||
import $ from 'jquery';
|
||||
import './assets/css/main.css'
|
||||
import '../node_modules/bootstrap/dist/css/bootstrap.css'
|
||||
import '../node_modules/font-awesome/css/font-awesome.css'
|
||||
|
||||
/*
|
||||
import $ from 'jquery';
|
||||
window.jQuery = $;
|
||||
window.$ = $;
|
||||
*/
|
||||
|
||||
Vue.use(VueResource);
|
||||
Vue.http.options.root = 'http://192.168.1.26:5000/api/';
|
||||
|
||||
Vue.prototype.$bus = new Vue();
|
||||
|
||||
new Vue({
|
||||
el: '#app',
|
||||
router,
|
||||
store,
|
||||
template: '<App/>',
|
||||
components: { App }
|
||||
})
|
||||
|
|
|
|||
55
ui/src/store.js
Normal file
55
ui/src/store.js
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
import Vue from 'vue';
|
||||
import Vuex from 'vuex';
|
||||
import moment from 'moment';
|
||||
|
||||
|
||||
const SERIES_MAX_SIZE = 30;
|
||||
Vue.use(Vuex);
|
||||
|
||||
|
||||
const state = {
|
||||
series: [],
|
||||
}
|
||||
|
||||
const getters = {
|
||||
getSeries: (state) => (key, max=SERIES_MAX_SIZE) => {
|
||||
let values = state.series.map(x => x[key]);
|
||||
return values.slice(-max);
|
||||
},
|
||||
getTimeSeries: (state) => (format='LTS', max=SERIES_MAX_SIZE) => {
|
||||
let values = state.series.map(x => moment(x.UTCUnixTime * 1000).format(format));
|
||||
return values.slice(-max);
|
||||
},
|
||||
getLastValue: (state) => (key) => {
|
||||
if (state.series.length > 0) {
|
||||
let last = state.series.reduce((l, e) => e.UTCUnixTime > l.UTCUnixTime ? e : l);
|
||||
return last[key];
|
||||
}
|
||||
return 'NA';
|
||||
}
|
||||
}
|
||||
|
||||
const actions = {
|
||||
requestSeries({ commit }) {
|
||||
Vue.http.get('data?format=json').then(response => {
|
||||
commit('setSeries', response.body);
|
||||
});
|
||||
},
|
||||
addRandomValues({ commit }) {
|
||||
commit('setSeries', [ { 'UTCUnixTime': 123123, 'TemperatureC': 26.0 } ]);
|
||||
}
|
||||
}
|
||||
|
||||
const mutations = {
|
||||
setSeries(state, data) {
|
||||
state.series.push(...data);
|
||||
state.series = state.series.slice(-SERIES_MAX_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
export default new Vuex.Store({
|
||||
state,
|
||||
getters,
|
||||
actions,
|
||||
mutations
|
||||
});
|
||||
Loading…
Reference in a new issue