Implement Redux

This commit is contained in:
Darko Lukic 2018-03-22 23:45:04 +01:00
parent 228e7b58dd
commit 699b99bdd5
11 changed files with 273 additions and 115 deletions

View file

@ -9,4 +9,4 @@
<div id="app"></div>
<script src="/dist/build.js"></script>
</body>
</html>
</html>

152
ui/package-lock.json generated
View file

@ -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",

View file

@ -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",

View file

@ -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: '',
}

View file

@ -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);

View file

@ -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>

View file

@ -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>

View 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>

View 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>

View file

@ -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
View 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
});