Compare commits
2 Commits
705b1f5e12
...
cfff6bc46e
Author | SHA1 | Date |
---|---|---|
Martyn | cfff6bc46e | |
Martyn | fcd60fc08a |
|
@ -1163,6 +1163,19 @@
|
|||
"resolved": "https://registry.npmjs.org/@csstools/normalize.css/-/normalize.css-10.1.0.tgz",
|
||||
"integrity": "sha512-ij4wRiunFfaJxjB0BdrYHIH8FxBJpOwNPhhAcunlmPdXudL1WQV1qoP9un6JsEBAgQH+7UXyyjh0g7jTxXK6tg=="
|
||||
},
|
||||
"@date-io/core": {
|
||||
"version": "1.3.13",
|
||||
"resolved": "https://registry.npmjs.org/@date-io/core/-/core-1.3.13.tgz",
|
||||
"integrity": "sha512-AlEKV7TxjeK+jxWVKcCFrfYAk8spX9aCyiToFIiLPtfQbsjmRGLIhb5VZgptQcJdHtLXo7+m0DuurwFgUToQuA=="
|
||||
},
|
||||
"@date-io/date-fns": {
|
||||
"version": "1.3.13",
|
||||
"resolved": "https://registry.npmjs.org/@date-io/date-fns/-/date-fns-1.3.13.tgz",
|
||||
"integrity": "sha512-yXxGzcRUPcogiMj58wVgFjc9qUYrCnnU9eLcyNbsQCmae4jPuZCDoIBR21j8ZURsM7GRtU62VOw5yNd4dDHunA==",
|
||||
"requires": {
|
||||
"@date-io/core": "^1.3.13"
|
||||
}
|
||||
},
|
||||
"@emotion/hash": {
|
||||
"version": "0.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz",
|
||||
|
@ -1420,6 +1433,19 @@
|
|||
"@babel/runtime": "^7.4.4"
|
||||
}
|
||||
},
|
||||
"@material-ui/pickers": {
|
||||
"version": "3.2.10",
|
||||
"resolved": "https://registry.npmjs.org/@material-ui/pickers/-/pickers-3.2.10.tgz",
|
||||
"integrity": "sha512-B8G6Obn5S3RCl7hwahkQj9sKUapwXWFjiaz/Bsw1fhYFdNMnDUolRiWQSoKPb1/oKe37Dtfszoywi1Ynbo3y8w==",
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.6.0",
|
||||
"@date-io/core": "1.x",
|
||||
"@types/styled-jsx": "^2.2.8",
|
||||
"clsx": "^1.0.2",
|
||||
"react-transition-group": "^4.0.0",
|
||||
"rifm": "^0.7.0"
|
||||
}
|
||||
},
|
||||
"@material-ui/styles": {
|
||||
"version": "4.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@material-ui/styles/-/styles-4.10.0.tgz",
|
||||
|
@ -1865,6 +1891,14 @@
|
|||
"resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-1.0.1.tgz",
|
||||
"integrity": "sha512-l42BggppR6zLmpfU6fq9HEa2oGPEI8yrSPL3GITjfRInppYFahObbIQOQK3UGxEnyQpltZLaPe75046NOZQikw=="
|
||||
},
|
||||
"@types/styled-jsx": {
|
||||
"version": "2.2.8",
|
||||
"resolved": "https://registry.npmjs.org/@types/styled-jsx/-/styled-jsx-2.2.8.tgz",
|
||||
"integrity": "sha512-Yjye9VwMdYeXfS71ihueWRSxrruuXTwKCbzue4+5b2rjnQ//AtyM7myZ1BEhNhBQ/nL/RE7bdToUoLln2miKvg==",
|
||||
"requires": {
|
||||
"@types/react": "*"
|
||||
}
|
||||
},
|
||||
"@types/testing-library__dom": {
|
||||
"version": "6.14.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/testing-library__dom/-/testing-library__dom-6.14.0.tgz",
|
||||
|
@ -2572,37 +2606,6 @@
|
|||
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.10.0.tgz",
|
||||
"integrity": "sha512-3YDiu347mtVtjpyV3u5kVqQLP242c06zwDOgpeRnybmXlYYsLbtTrUBUm8i8srONt+FWobl5aibnU1030PeeuA=="
|
||||
},
|
||||
"axios": {
|
||||
"version": "0.19.2",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-0.19.2.tgz",
|
||||
"integrity": "sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA==",
|
||||
"requires": {
|
||||
"follow-redirects": "1.5.10"
|
||||
},
|
||||
"dependencies": {
|
||||
"debug": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
|
||||
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
|
||||
"requires": {
|
||||
"ms": "2.0.0"
|
||||
}
|
||||
},
|
||||
"follow-redirects": {
|
||||
"version": "1.5.10",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz",
|
||||
"integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==",
|
||||
"requires": {
|
||||
"debug": "=3.1.0"
|
||||
}
|
||||
},
|
||||
"ms": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
|
||||
}
|
||||
}
|
||||
},
|
||||
"axobject-query": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz",
|
||||
|
@ -3075,6 +3078,11 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"base64-arraybuffer": {
|
||||
"version": "0.1.5",
|
||||
"resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz",
|
||||
"integrity": "sha1-c5JncZI7Whl0etZmqlzUv5xunOg="
|
||||
},
|
||||
"base64-js": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz",
|
||||
|
@ -3476,6 +3484,103 @@
|
|||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001109.tgz",
|
||||
"integrity": "sha512-4JIXRodHzdS3HdK8nSgIqXYLExOvG+D2/EenSvcub2Kp3QEADjo2v2oUn5g0n0D+UNwG9BtwKOyGcSq2qvQXvQ=="
|
||||
},
|
||||
"canvg": {
|
||||
"version": "1.5.3",
|
||||
"resolved": "https://registry.npmjs.org/canvg/-/canvg-1.5.3.tgz",
|
||||
"integrity": "sha512-7Gn2IuQzvUQWPIuZuFHrzsTM0gkPz2RRT9OcbdmA03jeKk8kltrD8gqUzNX15ghY/4PV5bbe5lmD6yDLDY6Ybg==",
|
||||
"requires": {
|
||||
"jsdom": "^8.1.0",
|
||||
"rgbcolor": "^1.0.1",
|
||||
"stackblur-canvas": "^1.4.1",
|
||||
"xmldom": "^0.1.22"
|
||||
},
|
||||
"dependencies": {
|
||||
"abab": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/abab/-/abab-1.0.4.tgz",
|
||||
"integrity": "sha1-X6rZwsB/YN12dw9xzwJbYqY8/U4="
|
||||
},
|
||||
"acorn": {
|
||||
"version": "2.7.0",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-2.7.0.tgz",
|
||||
"integrity": "sha1-q259nYhqrKiwhbwzEreaGYQz8Oc="
|
||||
},
|
||||
"acorn-globals": {
|
||||
"version": "1.0.9",
|
||||
"resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-1.0.9.tgz",
|
||||
"integrity": "sha1-VbtemGkVB7dFedBRNBMhfDgMVM8=",
|
||||
"requires": {
|
||||
"acorn": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"cssstyle": {
|
||||
"version": "0.2.37",
|
||||
"resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-0.2.37.tgz",
|
||||
"integrity": "sha1-VBCXI0yyUTyDzu06zdwn/yeYfVQ=",
|
||||
"requires": {
|
||||
"cssom": "0.3.x"
|
||||
}
|
||||
},
|
||||
"jsdom": {
|
||||
"version": "8.5.0",
|
||||
"resolved": "https://registry.npmjs.org/jsdom/-/jsdom-8.5.0.tgz",
|
||||
"integrity": "sha1-1Nj12/J2hjW2KmKCO5R89wcevJg=",
|
||||
"requires": {
|
||||
"abab": "^1.0.0",
|
||||
"acorn": "^2.4.0",
|
||||
"acorn-globals": "^1.0.4",
|
||||
"array-equal": "^1.0.0",
|
||||
"cssom": ">= 0.3.0 < 0.4.0",
|
||||
"cssstyle": ">= 0.2.34 < 0.3.0",
|
||||
"escodegen": "^1.6.1",
|
||||
"iconv-lite": "^0.4.13",
|
||||
"nwmatcher": ">= 1.3.7 < 2.0.0",
|
||||
"parse5": "^1.5.1",
|
||||
"request": "^2.55.0",
|
||||
"sax": "^1.1.4",
|
||||
"symbol-tree": ">= 3.1.0 < 4.0.0",
|
||||
"tough-cookie": "^2.2.0",
|
||||
"webidl-conversions": "^3.0.1",
|
||||
"whatwg-url": "^2.0.1",
|
||||
"xml-name-validator": ">= 2.0.1 < 3.0.0"
|
||||
}
|
||||
},
|
||||
"parse5": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/parse5/-/parse5-1.5.1.tgz",
|
||||
"integrity": "sha1-m387DeMr543CQBsXVzzK8Pb1nZQ="
|
||||
},
|
||||
"stackblur-canvas": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/stackblur-canvas/-/stackblur-canvas-1.4.1.tgz",
|
||||
"integrity": "sha1-hJqm+UsnL/JvZHH6QTDtH35HlVs="
|
||||
},
|
||||
"tr46": {
|
||||
"version": "0.0.3",
|
||||
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
|
||||
"integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o="
|
||||
},
|
||||
"webidl-conversions": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
|
||||
"integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE="
|
||||
},
|
||||
"whatwg-url": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-2.0.1.tgz",
|
||||
"integrity": "sha1-U5ayBD8CDub3BNnEXqhRnnJN5lk=",
|
||||
"requires": {
|
||||
"tr46": "~0.0.3",
|
||||
"webidl-conversions": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"xml-name-validator": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-2.0.1.tgz",
|
||||
"integrity": "sha1-TYuPHszTQZqjYgYb7O9RXh5VljU="
|
||||
}
|
||||
}
|
||||
},
|
||||
"capture-exit": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/capture-exit/-/capture-exit-2.0.0.tgz",
|
||||
|
@ -3617,6 +3722,11 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"classnames": {
|
||||
"version": "2.2.6",
|
||||
"resolved": "https://registry.npmjs.org/classnames/-/classnames-2.2.6.tgz",
|
||||
"integrity": "sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q=="
|
||||
},
|
||||
"clean-css": {
|
||||
"version": "4.2.3",
|
||||
"resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.3.tgz",
|
||||
|
@ -4097,6 +4207,14 @@
|
|||
"postcss": "^7.0.5"
|
||||
}
|
||||
},
|
||||
"css-box-model": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/css-box-model/-/css-box-model-1.2.1.tgz",
|
||||
"integrity": "sha512-a7Vr4Q/kd/aw96bnJG332W9V9LkJO69JRcaCYDUqjp6/z0w6VcZjgAcTbgFxEPfBgdnAwlh3iwu+hLopa+flJw==",
|
||||
"requires": {
|
||||
"tiny-invariant": "^1.0.6"
|
||||
}
|
||||
},
|
||||
"css-color-names": {
|
||||
"version": "0.0.4",
|
||||
"resolved": "https://registry.npmjs.org/css-color-names/-/css-color-names-0.0.4.tgz",
|
||||
|
@ -4137,6 +4255,14 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"css-line-break": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/css-line-break/-/css-line-break-1.0.1.tgz",
|
||||
"integrity": "sha1-GfIGOjPpX7KDG4ZEbAuAwYivRQo=",
|
||||
"requires": {
|
||||
"base64-arraybuffer": "^0.1.5"
|
||||
}
|
||||
},
|
||||
"css-loader": {
|
||||
"version": "3.4.2",
|
||||
"resolved": "https://registry.npmjs.org/css-loader/-/css-loader-3.4.2.tgz",
|
||||
|
@ -4399,6 +4525,16 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"date-fns": {
|
||||
"version": "2.15.0",
|
||||
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.15.0.tgz",
|
||||
"integrity": "sha512-ZCPzAMJZn3rNUvvQIMlXhDr4A+Ar07eLeGsGREoWU19a3Pqf5oYa+ccd+B3F6XVtQY6HANMFdOQ8A+ipFnvJdQ=="
|
||||
},
|
||||
"debounce": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/debounce/-/debounce-1.2.0.tgz",
|
||||
"integrity": "sha512-mYtLl1xfZLi1m4RtQYlZgJUNQjl4ZxVnHzIR8nLLgi4q1YT8o/WM+MK/f8yfcc9s5Ir5zRaPZyZU6xs1Syoocg=="
|
||||
},
|
||||
"debug": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
|
||||
|
@ -5876,6 +6012,15 @@
|
|||
"schema-utils": "^2.5.0"
|
||||
}
|
||||
},
|
||||
"file-saver": {
|
||||
"version": "github:eligrey/FileSaver.js#e865e37af9f9947ddcced76b549e27dc45c1cb2e",
|
||||
"from": "github:eligrey/FileSaver.js#1.3.8"
|
||||
},
|
||||
"filefy": {
|
||||
"version": "0.1.10",
|
||||
"resolved": "https://registry.npmjs.org/filefy/-/filefy-0.1.10.tgz",
|
||||
"integrity": "sha512-VgoRVOOY1WkTpWH+KBy8zcU1G7uQTVsXqhWEgzryB9A5hg2aqCyZ6aQ/5PSzlqM5+6cnVrX6oYV0XqD3HZSnmQ=="
|
||||
},
|
||||
"filesize": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/filesize/-/filesize-6.0.1.tgz",
|
||||
|
@ -6584,6 +6729,14 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"html2canvas": {
|
||||
"version": "1.0.0-alpha.12",
|
||||
"resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.0.0-alpha.12.tgz",
|
||||
"integrity": "sha1-OxmS48mz9WBjw1/WIElPN+uohRM=",
|
||||
"requires": {
|
||||
"css-line-break": "1.0.1"
|
||||
}
|
||||
},
|
||||
"htmlparser2": {
|
||||
"version": "3.10.1",
|
||||
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz",
|
||||
|
@ -7889,6 +8042,24 @@
|
|||
"resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz",
|
||||
"integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM="
|
||||
},
|
||||
"jspdf": {
|
||||
"version": "1.5.3",
|
||||
"resolved": "https://registry.npmjs.org/jspdf/-/jspdf-1.5.3.tgz",
|
||||
"integrity": "sha512-J9X76xnncMw+wIqb15HeWfPMqPwYxSpPY8yWPJ7rAZN/ZDzFkjCSZObryCyUe8zbrVRNiuCnIeQteCzMn7GnWw==",
|
||||
"requires": {
|
||||
"canvg": "1.5.3",
|
||||
"file-saver": "github:eligrey/FileSaver.js#1.3.8",
|
||||
"html2canvas": "1.0.0-alpha.12",
|
||||
"omggif": "1.0.7",
|
||||
"promise-polyfill": "8.1.0",
|
||||
"stackblur-canvas": "2.2.0"
|
||||
}
|
||||
},
|
||||
"jspdf-autotable": {
|
||||
"version": "3.5.3",
|
||||
"resolved": "https://registry.npmjs.org/jspdf-autotable/-/jspdf-autotable-3.5.3.tgz",
|
||||
"integrity": "sha512-K+cNWW3x6w0R/1B5m6PYOm6v8CTTDXy/g32lZouc7SuC6zhvzMN2dauhk6dDYxPD0pky0oyPIJFwSJ/tV8PAeg=="
|
||||
},
|
||||
"jsprim": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz",
|
||||
|
@ -8283,6 +8454,32 @@
|
|||
"object-visit": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"material-table": {
|
||||
"version": "1.67.1",
|
||||
"resolved": "https://registry.npmjs.org/material-table/-/material-table-1.67.1.tgz",
|
||||
"integrity": "sha512-cMmzIO601D1b4C+ZYlpiRxBUtvrAVfJ74wcpeF39K4wdfweXyFgQ+bXdfFSIycBv36ZPTFWoku/3bAJiBn5Gzw==",
|
||||
"requires": {
|
||||
"@date-io/date-fns": "^1.1.0",
|
||||
"@material-ui/pickers": "^3.2.2",
|
||||
"classnames": "^2.2.6",
|
||||
"date-fns": "^2.0.0-alpha.27",
|
||||
"debounce": "^1.2.0",
|
||||
"fast-deep-equal": "2.0.1",
|
||||
"filefy": "0.1.10",
|
||||
"jspdf": "1.5.3",
|
||||
"jspdf-autotable": "3.5.3",
|
||||
"prop-types": "^15.6.2",
|
||||
"react-beautiful-dnd": "^13.0.0",
|
||||
"react-double-scrollbar": "0.0.15"
|
||||
},
|
||||
"dependencies": {
|
||||
"fast-deep-equal": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz",
|
||||
"integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk="
|
||||
}
|
||||
}
|
||||
},
|
||||
"md5.js": {
|
||||
"version": "1.3.5",
|
||||
"resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz",
|
||||
|
@ -8313,6 +8510,11 @@
|
|||
"p-is-promise": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"memoize-one": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.1.1.tgz",
|
||||
"integrity": "sha512-HKeeBpWvqiVJD57ZUAsJNm71eHTykffzcLZVYWiVfQeI1rJtuEaS7hQiEpWfVVk18donPwJEcFKIkCmPJNOhHA=="
|
||||
},
|
||||
"memory-fs": {
|
||||
"version": "0.4.1",
|
||||
"resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz",
|
||||
|
@ -8869,6 +9071,11 @@
|
|||
"resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
|
||||
"integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0="
|
||||
},
|
||||
"nwmatcher": {
|
||||
"version": "1.4.4",
|
||||
"resolved": "https://registry.npmjs.org/nwmatcher/-/nwmatcher-1.4.4.tgz",
|
||||
"integrity": "sha512-3iuY4N5dhgMpCUrOVnuAdGrgxVqV2cJpM+XNccjR2DKOB1RUP0aA+wGXEiNziG/UKboFyGBIoKOaNlJxx8bciQ=="
|
||||
},
|
||||
"nwsapi": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.0.tgz",
|
||||
|
@ -9006,6 +9213,11 @@
|
|||
"resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz",
|
||||
"integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg=="
|
||||
},
|
||||
"omggif": {
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/omggif/-/omggif-1.0.7.tgz",
|
||||
"integrity": "sha1-WdLuywJj3oRjWz/riHwMmXPx5J0="
|
||||
},
|
||||
"on-finished": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
|
||||
|
@ -10436,6 +10648,11 @@
|
|||
"resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz",
|
||||
"integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM="
|
||||
},
|
||||
"promise-polyfill": {
|
||||
"version": "8.1.0",
|
||||
"resolved": "https://registry.npmjs.org/promise-polyfill/-/promise-polyfill-8.1.0.tgz",
|
||||
"integrity": "sha512-OzSf6gcCUQ01byV4BgwyUCswlaQQ6gzXc23aLQWhicvfX9kfsUiUhgt3CCQej8jDnl8/PhGF31JdHX2/MzF3WA=="
|
||||
},
|
||||
"prompts": {
|
||||
"version": "2.3.2",
|
||||
"resolved": "https://registry.npmjs.org/prompts/-/prompts-2.3.2.tgz",
|
||||
|
@ -10571,6 +10788,11 @@
|
|||
"performance-now": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"raf-schd": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/raf-schd/-/raf-schd-4.0.2.tgz",
|
||||
"integrity": "sha512-VhlMZmGy6A6hrkJWHLNTGl5gtgMUm+xfGza6wbwnE914yeQ5Ybm18vgM734RZhMgfw4tacUrWseGZlpUrrakEQ=="
|
||||
},
|
||||
"randombytes": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
|
||||
|
@ -10634,6 +10856,20 @@
|
|||
"whatwg-fetch": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"react-beautiful-dnd": {
|
||||
"version": "13.0.0",
|
||||
"resolved": "https://registry.npmjs.org/react-beautiful-dnd/-/react-beautiful-dnd-13.0.0.tgz",
|
||||
"integrity": "sha512-87It8sN0ineoC3nBW0SbQuTFXM6bUqM62uJGY4BtTf0yzPl8/3+bHMWkgIe0Z6m8e+gJgjWxefGRVfpE3VcdEg==",
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.8.4",
|
||||
"css-box-model": "^1.2.0",
|
||||
"memoize-one": "^5.1.1",
|
||||
"raf-schd": "^4.0.2",
|
||||
"react-redux": "^7.1.1",
|
||||
"redux": "^4.0.4",
|
||||
"use-memo-one": "^1.1.1"
|
||||
}
|
||||
},
|
||||
"react-dev-utils": {
|
||||
"version": "10.2.1",
|
||||
"resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-10.2.1.tgz",
|
||||
|
@ -10846,6 +11082,11 @@
|
|||
"scheduler": "^0.19.1"
|
||||
}
|
||||
},
|
||||
"react-double-scrollbar": {
|
||||
"version": "0.0.15",
|
||||
"resolved": "https://registry.npmjs.org/react-double-scrollbar/-/react-double-scrollbar-0.0.15.tgz",
|
||||
"integrity": "sha1-6RWrjLO5WYdwdfSUNt6/2wQoj+Q="
|
||||
},
|
||||
"react-error-overlay": {
|
||||
"version": "6.0.7",
|
||||
"resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.7.tgz",
|
||||
|
@ -10856,6 +11097,18 @@
|
|||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
|
||||
},
|
||||
"react-redux": {
|
||||
"version": "7.2.1",
|
||||
"resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.1.tgz",
|
||||
"integrity": "sha512-T+VfD/bvgGTUA74iW9d2i5THrDQWbweXP0AVNI8tNd1Rk5ch1rnMiJkDD67ejw7YBKM4+REvcvqRuWJb7BLuEg==",
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.5.5",
|
||||
"hoist-non-react-statics": "^3.3.0",
|
||||
"loose-envify": "^1.4.0",
|
||||
"prop-types": "^15.7.2",
|
||||
"react-is": "^16.9.0"
|
||||
}
|
||||
},
|
||||
"react-scripts": {
|
||||
"version": "3.4.1",
|
||||
"resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-3.4.1.tgz",
|
||||
|
@ -10989,6 +11242,15 @@
|
|||
"strip-indent": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"redux": {
|
||||
"version": "4.0.5",
|
||||
"resolved": "https://registry.npmjs.org/redux/-/redux-4.0.5.tgz",
|
||||
"integrity": "sha512-VSz1uMAH24DM6MF72vcojpYPtrTUu3ByVWfPL1nPfVRb5mZVTve5GnNCUV53QM/BZ66xfWrm0CTWoM+Xlz8V1w==",
|
||||
"requires": {
|
||||
"loose-envify": "^1.4.0",
|
||||
"symbol-observable": "^1.2.0"
|
||||
}
|
||||
},
|
||||
"regenerate": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.1.tgz",
|
||||
|
@ -11349,6 +11611,19 @@
|
|||
"resolved": "https://registry.npmjs.org/rgba-regex/-/rgba-regex-1.0.0.tgz",
|
||||
"integrity": "sha1-QzdOLiyglosO8VI0YLfXMP8i7rM="
|
||||
},
|
||||
"rgbcolor": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/rgbcolor/-/rgbcolor-1.0.1.tgz",
|
||||
"integrity": "sha1-1lBezbMEplldom+ktDMHMGd1lF0="
|
||||
},
|
||||
"rifm": {
|
||||
"version": "0.7.0",
|
||||
"resolved": "https://registry.npmjs.org/rifm/-/rifm-0.7.0.tgz",
|
||||
"integrity": "sha512-DSOJTWHD67860I5ojetXdEQRIBvF6YcpNe53j0vn1vp9EUb9N80EiZTxgP+FkDKorWC8PZw052kTF4C1GOivCQ==",
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.3.1"
|
||||
}
|
||||
},
|
||||
"rimraf": {
|
||||
"version": "2.6.3",
|
||||
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz",
|
||||
|
@ -12078,6 +12353,11 @@
|
|||
"resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-1.0.2.tgz",
|
||||
"integrity": "sha512-MTX+MeG5U994cazkjd/9KNAapsHnibjMLnfXodlkXw76JEea0UiNzrqidzo1emMwk7w5Qhc9jd4Bn9TBb1MFwA=="
|
||||
},
|
||||
"stackblur-canvas": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/stackblur-canvas/-/stackblur-canvas-2.2.0.tgz",
|
||||
"integrity": "sha512-5Gf8dtlf8k6NbLzuly2NkGrkS/Ahh+I5VUjO7TnFizdJtgpfpLLEdQlLe9umbcnZlitU84kfYjXE67xlSXfhfQ=="
|
||||
},
|
||||
"static-extend": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz",
|
||||
|
@ -12425,6 +12705,11 @@
|
|||
"util.promisify": "~1.0.0"
|
||||
}
|
||||
},
|
||||
"symbol-observable": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz",
|
||||
"integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ=="
|
||||
},
|
||||
"symbol-tree": {
|
||||
"version": "3.2.4",
|
||||
"resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz",
|
||||
|
@ -12663,6 +12948,11 @@
|
|||
"resolved": "https://registry.npmjs.org/timsort/-/timsort-0.3.0.tgz",
|
||||
"integrity": "sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q="
|
||||
},
|
||||
"tiny-invariant": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.1.0.tgz",
|
||||
"integrity": "sha512-ytxQvrb1cPc9WBEI/HSeYYoGD0kWnGEOR8RY6KomWLBVhqz0RgTwVO9dLrGz7dC+nN9llyI7OKAgRq8Vq4ZBSw=="
|
||||
},
|
||||
"tiny-warning": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz",
|
||||
|
@ -12979,6 +13269,11 @@
|
|||
"resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz",
|
||||
"integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ=="
|
||||
},
|
||||
"use-memo-one": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/use-memo-one/-/use-memo-one-1.1.1.tgz",
|
||||
"integrity": "sha512-oFfsyun+bP7RX8X2AskHNTxu+R3QdE/RC5IefMbqptmACAA/gfol1KDD5KRzPsGMa62sWxGZw+Ui43u6x4ddoQ=="
|
||||
},
|
||||
"util": {
|
||||
"version": "0.10.3",
|
||||
"resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz",
|
||||
|
@ -14020,6 +14315,11 @@
|
|||
"resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz",
|
||||
"integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw=="
|
||||
},
|
||||
"xmldom": {
|
||||
"version": "0.1.31",
|
||||
"resolved": "https://registry.npmjs.org/xmldom/-/xmldom-0.1.31.tgz",
|
||||
"integrity": "sha512-yS2uJflVQs6n+CyjHoaBmVSqIDevTAWrzMmjG1Gc7h1qQ7uVozNhEPJAwZXWyGQ/Gafo3fCwrcaokezLPupVyQ=="
|
||||
},
|
||||
"xregexp": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/xregexp/-/xregexp-4.3.0.tgz",
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
"@testing-library/jest-dom": "^4.2.4",
|
||||
"@testing-library/react": "^9.5.0",
|
||||
"@testing-library/user-event": "^7.2.1",
|
||||
"material-table": "^1.67.1",
|
||||
"react": "^16.13.1",
|
||||
"react-dom": "^16.13.1",
|
||||
"react-scripts": "3.4.1"
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
{"jointime":"0001-01-01T00:00:00Z","hasleft":false,"videoCacheUpdated":"2020-08-02T17:40:13.480470725Z", "commands": [{"command":"card","action":"RandomPrompt"},{"command":"whotosingwith","action":"AgingSinger"}]}
|
|
@ -1,5 +1,21 @@
|
|||
import React, { useEffect } from 'react';
|
||||
import { Container, Typography, Button } from '@material-ui/core';
|
||||
import { AddBox, ArrowDownward } from "@material-ui/icons";
|
||||
import MaterialTable from "material-table";
|
||||
import Check from '@material-ui/icons/Check';
|
||||
import ChevronLeft from '@material-ui/icons/ChevronLeft';
|
||||
import ChevronRight from '@material-ui/icons/ChevronRight';
|
||||
import Clear from '@material-ui/icons/Clear';
|
||||
import DeleteOutline from '@material-ui/icons/DeleteOutline';
|
||||
import Edit from '@material-ui/icons/Edit';
|
||||
import FilterList from '@material-ui/icons/FilterList';
|
||||
import FirstPage from '@material-ui/icons/FirstPage';
|
||||
import LastPage from '@material-ui/icons/LastPage';
|
||||
import Remove from '@material-ui/icons/Remove';
|
||||
import SaveAlt from '@material-ui/icons/SaveAlt';
|
||||
import Search from '@material-ui/icons/Search';
|
||||
import ViewColumn from '@material-ui/icons/ViewColumn';
|
||||
import { forwardRef } from 'react';
|
||||
|
||||
const channelName = window.location.href.split("/")[4]
|
||||
const adminToken = window.location.href.split("/")[5]
|
||||
|
@ -7,11 +23,36 @@ const dataURL = "/botdeets/"+ channelName + "/" + adminToken
|
|||
|
||||
function BotDeets() {
|
||||
|
||||
const [botState, setBotState] = React.useState({loading: true, botData: []})
|
||||
const [botState, setBotState] = React.useState({loading: true, botData: { commands: [{"command":"card","action":"RandomPrompt"},{"command":"whotosingwith","action":"AgingSinger"}]} });
|
||||
|
||||
const tableIcons = {
|
||||
Add: forwardRef((props, ref) => <AddBox {...props} ref={ref} />),
|
||||
Check: forwardRef((props, ref) => <Check {...props} ref={ref} />),
|
||||
Clear: forwardRef((props, ref) => <Clear {...props} ref={ref} />),
|
||||
Delete: forwardRef((props, ref) => <DeleteOutline {...props} ref={ref} />),
|
||||
DetailPanel: forwardRef((props, ref) => <ChevronRight {...props} ref={ref} />),
|
||||
Edit: forwardRef((props, ref) => <Edit {...props} ref={ref} />),
|
||||
Export: forwardRef((props, ref) => <SaveAlt {...props} ref={ref} />),
|
||||
Filter: forwardRef((props, ref) => <FilterList {...props} ref={ref} />),
|
||||
FirstPage: forwardRef((props, ref) => <FirstPage {...props} ref={ref} />),
|
||||
LastPage: forwardRef((props, ref) => <LastPage {...props} ref={ref} />),
|
||||
NextPage: forwardRef((props, ref) => <ChevronRight {...props} ref={ref} />),
|
||||
PreviousPage: forwardRef((props, ref) => <ChevronLeft {...props} ref={ref} />),
|
||||
ResetSearch: forwardRef((props, ref) => <Clear {...props} ref={ref} />),
|
||||
Search: forwardRef((props, ref) => <Search {...props} ref={ref} />),
|
||||
SortArrow: forwardRef((props, ref) => <ArrowDownward {...props} ref={ref} />),
|
||||
ThirdStateCheck: forwardRef((props, ref) => <Remove {...props} ref={ref} />),
|
||||
ViewColumn: forwardRef((props, ref) => <ViewColumn {...props} ref={ref} />)
|
||||
};
|
||||
useEffect(() => {
|
||||
// We should only fetch once!
|
||||
if (botState.loading) {
|
||||
fetch(dataURL).then((res) => res.json().then((data)=>{
|
||||
let actualURL = dataURL
|
||||
if (window.location.href.split("/")[2] === "192.168.1.111:3000") {
|
||||
//Frontend dev mode only
|
||||
actualURL = "/sampleData/bot.json"
|
||||
}
|
||||
fetch(actualURL).then((res) => res.json().then((data)=>{
|
||||
setBotState({botData: data, loading: false })
|
||||
}));
|
||||
}
|
||||
|
@ -20,8 +61,11 @@ function BotDeets() {
|
|||
if (botState.loading) {
|
||||
return <p>Sorry, still loading...</p>
|
||||
}
|
||||
|
||||
return <p>Sorry, still making this... soon soon.</p>
|
||||
|
||||
let dd = botState.botData
|
||||
const dd = botState.botData
|
||||
const cmds = dd.commands
|
||||
if (dd.hasleft) {
|
||||
return (
|
||||
<Container>
|
||||
|
@ -38,13 +82,83 @@ function BotDeets() {
|
|||
)
|
||||
} else {
|
||||
return (
|
||||
|
||||
<Container>
|
||||
<Typography variant="h5" component="h2" gutterBottom>
|
||||
Coming soon! Bot control panel!
|
||||
</Typography>
|
||||
<Typography component="tt" gutterBottom>
|
||||
{dd}
|
||||
</Typography>
|
||||
<div style={{ maxWidth: "100%" }}>
|
||||
<MaterialTable
|
||||
editable={{
|
||||
isEditable: rowData => true,
|
||||
isDeletable: rowData => true,
|
||||
onRowAddCancelled: rowData => console.log('Row adding cancelled'),
|
||||
onRowUpdateCancelled: rowData => console.log('Row editing cancelled'),
|
||||
onRowUpdate: (newData, oldData) =>
|
||||
new Promise((resolve, reject) => {
|
||||
setTimeout(() => {
|
||||
const index = cmds.indexOf(oldData);
|
||||
let newCommands = cmds;
|
||||
let newState = botState;
|
||||
newCommands[index] = newData;
|
||||
newState.botData.commands = newCommands;
|
||||
setBotState(newState);
|
||||
resolve();
|
||||
}, 1000);
|
||||
}),
|
||||
onRowDelete: oldData =>
|
||||
new Promise((resolve, reject) => {
|
||||
setTimeout(() => {
|
||||
const index = cmds.indexOf(oldData);
|
||||
let newCommands = cmds;
|
||||
let newState = botState;
|
||||
newCommands.splice(index, 1);
|
||||
newState.botData.commands = newCommands;
|
||||
setBotState(newState);
|
||||
resolve();
|
||||
}, 1000);
|
||||
}),
|
||||
onRowAdd: newData =>
|
||||
new Promise((resolve, reject) => {
|
||||
setTimeout(() => {
|
||||
let newCommands = cmds;
|
||||
let newState = botState;
|
||||
newCommands[cmds.length] = newData;
|
||||
newState.botData.commands = newCommands;
|
||||
setBotState(newState);
|
||||
resolve();
|
||||
}, 1000);
|
||||
}),
|
||||
}}
|
||||
icons={tableIcons}
|
||||
columns={[
|
||||
{ title: "Command", field: "command" },
|
||||
{
|
||||
title: "Action description",
|
||||
field: "action",
|
||||
lookup: { RandomPrompt: "Random prompt", AgingSinger: "Singer I haven't sung with in ages", AgingSong: "Song I haven't sung in ages"},
|
||||
/* editComponent: tableData =>
|
||||
<Select
|
||||
id="action"
|
||||
className=""
|
||||
optionId="key"
|
||||
optionName="value"
|
||||
value={tableData.rowData.action}
|
||||
dataAutoId={dropdowns('action')}
|
||||
>
|
||||
<MenuItem value="RandomPrompt">Random prompt</MenuItem>
|
||||
<MenuItem value="AgingSinger">Singer I haven't sung with in ages</MenuItem>
|
||||
<MenuItem value="AgingSong">Song I haven't sung in ages</MenuItem>
|
||||
</Select>*/
|
||||
},
|
||||
]}
|
||||
data={cmds}
|
||||
title="Commands"
|
||||
options={{
|
||||
search: false
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,161 +0,0 @@
|
|||
import React, { useEffect } from 'react';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import { Table, TableBody, TableCell, TableContainer, TableHead, TableRow, TableSortLabel, Paper } from '@material-ui/core';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
const channelName = window.location.href.split("/")[4]
|
||||
const adminToken = window.location.href.split("/")[5]
|
||||
const dataURL = "/topsingers/"+ channelName + "/" + adminToken
|
||||
const headCells = [
|
||||
{ id: 'singerName', numeric: false, disablePadding: true, label: 'Singer Name' },
|
||||
{ id: 'singCount', numeric: true, disablePadding: false, label: 'Count' },
|
||||
];
|
||||
|
||||
function descendingComparator(a, b, orderBy) {
|
||||
if (b[orderBy] < a[orderBy]) {
|
||||
return -1;
|
||||
}
|
||||
if (b[orderBy] > a[orderBy]) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
function stableSort(array, comparator) {
|
||||
const stabilizedThis = array.map((el, index) => [el, index]);
|
||||
stabilizedThis.sort((a, b) => {
|
||||
const order = comparator(a[0], b[0]);
|
||||
if (order !== 0) return order;
|
||||
return a[1] - b[1];
|
||||
});
|
||||
return stabilizedThis.map((el) => el[0]);
|
||||
}
|
||||
|
||||
function getComparator(order, orderBy) {
|
||||
return order === 'desc'
|
||||
? (a, b) => descendingComparator(a, b, orderBy)
|
||||
: (a, b) => -descendingComparator(a, b, orderBy);
|
||||
}
|
||||
|
||||
function EnhancedTableHead(props) {
|
||||
const { classes, order, orderBy, onRequestSort } = props;
|
||||
const createSortHandler = (property) => (event) => {
|
||||
onRequestSort(event, property);
|
||||
};
|
||||
|
||||
return (
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
{headCells.map((headCell) => (
|
||||
<TableCell
|
||||
key={headCell.id}
|
||||
align={headCell.numeric ? 'right' : 'left'}
|
||||
padding={headCell.disablePadding ? 'none' : 'default'}
|
||||
sortDirection={orderBy === headCell.id ? order : false}
|
||||
>
|
||||
<TableSortLabel
|
||||
active={orderBy === headCell.id}
|
||||
direction={orderBy === headCell.id ? order : 'asc'}
|
||||
onClick={createSortHandler(headCell.id)}
|
||||
>
|
||||
{headCell.label}
|
||||
{orderBy === headCell.id ? (
|
||||
<span className={classes.visuallyHidden}>
|
||||
{order === 'desc' ? 'sorted descending' : 'sorted ascending'}
|
||||
</span>
|
||||
) : null}
|
||||
</TableSortLabel>
|
||||
</TableCell>
|
||||
))}
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
);
|
||||
}
|
||||
|
||||
EnhancedTableHead.propTypes = {
|
||||
classes: PropTypes.object.isRequired,
|
||||
numSelected: PropTypes.number.isRequired,
|
||||
onRequestSort: PropTypes.func.isRequired,
|
||||
onSelectAllClick: PropTypes.func.isRequired,
|
||||
order: PropTypes.oneOf(['asc', 'desc']).isRequired,
|
||||
orderBy: PropTypes.string.isRequired,
|
||||
rowCount: PropTypes.number.isRequired,
|
||||
};
|
||||
|
||||
|
||||
class TopTenSingers extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.handleClick = this.handleClick.bind(this);
|
||||
this.state = {loading: true, duetData: []};
|
||||
}
|
||||
|
||||
setDuetState(data) {
|
||||
this.setState(data)
|
||||
}
|
||||
|
||||
render() {
|
||||
const useStyles = makeStyles({
|
||||
table: {
|
||||
minWidth: 650,
|
||||
},
|
||||
});
|
||||
|
||||
const [order, setOrder] = React.useState('asc');
|
||||
const [orderBy, setOrderBy] = React.useState('calories');
|
||||
const classes = useStyles();
|
||||
|
||||
const handleRequestSort = (event, property) => {
|
||||
const isAsc = orderBy === property && order === 'asc';
|
||||
setOrder(isAsc ? 'desc' : 'asc');
|
||||
setOrderBy(property);
|
||||
};
|
||||
useEffect(() => {
|
||||
// We should only fetch once!
|
||||
if (this.state.loading || this.props.triggerRefresh) {
|
||||
fetch(dataURL).then((res) => res.json().then((data)=>{
|
||||
this.setDuetState({duetData: data, loading: false })
|
||||
}));
|
||||
}
|
||||
}, [this.setState, this.state.loading, this.props.triggerRefresh]);
|
||||
|
||||
if (this.state.loading) {
|
||||
return <p>Sorry, still loading...</p>
|
||||
}
|
||||
|
||||
let dd = this.state.duetData
|
||||
|
||||
return (
|
||||
<TableContainer component={Paper}
|
||||
order={order}
|
||||
orderBy={orderBy}
|
||||
onRequestSort={handleRequestSort}>
|
||||
<Table className={classes.table} size="small" aria-label="simple table">
|
||||
<EnhancedTableHead onRequestSort={handleRequestSort}>
|
||||
<TableRow>
|
||||
<TableCell>Song Name</TableCell>
|
||||
<TableCell align="right">Sings</TableCell>
|
||||
</TableRow>
|
||||
</EnhancedTableHead>
|
||||
<TableBody>
|
||||
{stableSort(dd, getComparator(order, orderBy))
|
||||
.map((row, index) => {
|
||||
const labelId = `enhanced-table-${index}`;
|
||||
|
||||
return (
|
||||
<TableRow key={row.singerName} >
|
||||
<TableCell component="th" id={labelId} scope="row" padding="none">
|
||||
{row.singerName}
|
||||
</TableCell>
|
||||
<TableCell align="right">{row.singCount}</TableCell>
|
||||
</TableRow>
|
||||
);
|
||||
})}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</TableContainer>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default TopTenSingers.render;
|
|
@ -95,13 +95,37 @@ type SingsVideoStruct struct {
|
|||
LastSungSinger time.Time `json:"LastSungSinger"` // Last time a duet was sung with this SINGER, regardless of song, only Duets have this date initialised
|
||||
}
|
||||
|
||||
// CommandType Kinda an enum
|
||||
type CommandType string
|
||||
|
||||
const (
|
||||
RandomSinger CommandType = "RandomSinger"
|
||||
RandomPrompt CommandType = "RandomPrompt"
|
||||
RandomSong CommandType = "RandomSong"
|
||||
AgingSinger CommandType = "AgingSinger"
|
||||
AgingSong CommandType = "AgingSong"
|
||||
)
|
||||
|
||||
func (ct CommandType) IsValid() error {
|
||||
switch ct {
|
||||
case RandomSinger, RandomPrompt, RandomSong, AgingSinger, AgingSong:
|
||||
return nil
|
||||
}
|
||||
return errors.New("Invalid command type")
|
||||
}
|
||||
|
||||
type CommandStruct struct {
|
||||
CommandName CommandType `json:"commandName"`
|
||||
KeyWord string `json:"keyword"`
|
||||
}
|
||||
|
||||
type ChannelData struct {
|
||||
Name string `json:"name"`
|
||||
AdminKey string `json:"value,omitempty"`
|
||||
Command string `json:"customcommand,omitempty"`
|
||||
ExtraStrings string `json:"extrastrings,omitempty"`
|
||||
JoinTime time.Time `json:"jointime"`
|
||||
ControlChannel bool
|
||||
Name string `json:"name"`
|
||||
AdminKey string `json:"value,omitempty"`
|
||||
Commands []CommandStruct `json:"commands,omitempty"`
|
||||
ExtraStrings string `json:"extrastrings,omitempty"`
|
||||
JoinTime time.Time `json:"jointime"`
|
||||
HasLeft bool `json:"hasleft"`
|
||||
VideoCache []SingsVideoStruct `json:"videoCache"`
|
||||
VideoCacheUpdated time.Time `json:"videoCacheUpdated"`
|
||||
|
@ -199,7 +223,7 @@ func (bb *KardBot) HandleChat() error {
|
|||
if nil != matches {
|
||||
realUserName := matches[1]
|
||||
if bb.ChannelData[realUserName].Name == "" {
|
||||
record := ChannelData{Name: realUserName, JoinTime: time.Now(), Command: "card", ControlChannel: true}
|
||||
record := ChannelData{Name: realUserName, JoinTime: time.Now(), Commands: nil, ControlChannel: true}
|
||||
bb.Database.Write("channelData", realUserName, record)
|
||||
bb.ChannelData[realUserName] = record
|
||||
}
|
||||
|
@ -233,18 +257,25 @@ func (bb *KardBot) HandleChat() error {
|
|||
cmdMatches := CmdRegex.FindStringSubmatch(msg)
|
||||
if nil != cmdMatches {
|
||||
cmd := cmdMatches[1]
|
||||
|
||||
rgb.YPrintf("[%s] Checking cmd %s against %s\n", TimeStamp(), cmd, bb.ChannelData[channel].Command)
|
||||
cardCommand := ""
|
||||
commands := bb.ChannelData[channel].Commands
|
||||
for _, command := range commands {
|
||||
if command.CommandName == RandomPrompt {
|
||||
cardCommand = command.KeyWord
|
||||
}
|
||||
}
|
||||
rgb.YPrintf("[%s] Checking cmd %s against [%s]\n", TimeStamp(), cmd, bb.ChannelData[channel].Commands)
|
||||
switch cmd {
|
||||
case bb.ChannelData[channel].Command:
|
||||
rgb.CPrintf("[%s] Card asked for by %s on %s' channel!\n", TimeStamp(), userName, channel)
|
||||
|
||||
bb.Say("Your prompt is : "+bb.Prompts[rand.Intn(len(bb.Prompts))], channel)
|
||||
case cardCommand:
|
||||
if cardCommand != "" {
|
||||
rgb.CPrintf("[%s] Card asked for by %s on %s' channel!\n", TimeStamp(), userName, channel)
|
||||
bb.Say("Your prompt is : "+bb.Prompts[rand.Intn(len(bb.Prompts))], channel)
|
||||
}
|
||||
case "join":
|
||||
if bb.ChannelData[channel].ControlChannel {
|
||||
rgb.CPrintf("[%s] Join asked for by %s on %s' channel!\n", TimeStamp(), userName, channel)
|
||||
if bb.ChannelData[userName].Name == "" {
|
||||
record := ChannelData{Name: userName, JoinTime: time.Now(), Command: "card", ControlChannel: true}
|
||||
record := ChannelData{Name: userName, JoinTime: time.Now(), Commands: nil, ControlChannel: true}
|
||||
bb.Database.Write("channelData", userName, record)
|
||||
bb.ChannelData[userName] = record
|
||||
}
|
||||
|
@ -460,7 +491,7 @@ func (bb *KardBot) readChannelData() error {
|
|||
records, err := bb.Database.ReadAll("channelData")
|
||||
if err != nil {
|
||||
// no db? initialise one?
|
||||
record := ChannelData{Name: bb.Channel, JoinTime: time.Now(), Command: "card"}
|
||||
record := ChannelData{Name: bb.Channel, JoinTime: time.Now(), Commands: nil}
|
||||
rgb.YPrintf("[%s] No channel table for #%s exists, creating...\n", TimeStamp(), bb.Channel)
|
||||
if err := bb.Database.Write("channelData", bb.Channel, record); err != nil {
|
||||
return err
|
||||
|
@ -476,22 +507,11 @@ func (bb *KardBot) readChannelData() error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if record.Name != "" {
|
||||
if record.Command == "" {
|
||||
record.Command = "card"
|
||||
|
||||
rgb.YPrintf("[%s] Rewriting data for #%s...\n", TimeStamp(), bb.Channel)
|
||||
if err := bb.Database.Write("channelData", record.Name, record); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
bb.ChannelData[record.Name] = record
|
||||
}
|
||||
}
|
||||
// Managed to leave the main channel!?
|
||||
if bb.ChannelData[bb.Channel].Name == "" {
|
||||
rgb.YPrintf("[%s] No channel data for #%s exists, creating...\n", TimeStamp(), bb.Channel)
|
||||
record := ChannelData{Name: bb.Channel, JoinTime: time.Now(), Command: "card"}
|
||||
record := ChannelData{Name: bb.Channel, JoinTime: time.Now(), Commands: nil}
|
||||
bb.ChannelData[bb.Channel] = record
|
||||
if err := bb.Database.Write("channelData", bb.Channel, record); err != nil {
|
||||
return err
|
||||
|
|
|
@ -217,84 +217,6 @@ func AugmentSingsVideoStructSlice(input []irc.SingsVideoStruct) []AugmentedSings
|
|||
return ret
|
||||
}
|
||||
|
||||
func AdminHandler(response http.ResponseWriter, request *http.Request) {
|
||||
vars := mux.Vars(request)
|
||||
if vars["key"] != ircBot.ChannelData[vars["channel"]].AdminKey {
|
||||
UnauthorizedHandler(response, request)
|
||||
return
|
||||
}
|
||||
type TemplateData struct {
|
||||
Channel string
|
||||
Command string
|
||||
ExtraStrings string
|
||||
SinceTime time.Time
|
||||
SinceTimeUTC string
|
||||
Leaving bool
|
||||
HasLeft bool
|
||||
SongData []AugmentedSingsVideoStruct
|
||||
TopNSongs []SongSings
|
||||
TopNSingers []SingerSings
|
||||
ChannelKey string
|
||||
}
|
||||
updateCacheIfNecessary(vars["channel"])
|
||||
channelData := ircBot.ChannelData[vars["channel"]]
|
||||
updateCalculatedFields(channelData.VideoCache)
|
||||
for _, song := range channelData.VideoCache {
|
||||
if song.Duet && song.OtherSinger == "" {
|
||||
fmt.Printf("WARNING: found duet with no other singer! %s", song.SongTitle) // should never happen but debug in case it does!
|
||||
}
|
||||
}
|
||||
topNSongs := calculateTopNSongs(channelData.VideoCache, 10)
|
||||
topNSingers := calculateTopNSingers(channelData.VideoCache, 10)
|
||||
var td = TemplateData{channelData.Name, channelData.Command, channelData.ExtraStrings, channelData.JoinTime, channelData.JoinTime.Format(irc.UTCFormat), false, channelData.HasLeft, AugmentSingsVideoStructSlice(channelData.VideoCache), topNSongs, topNSingers, vars["key"]}
|
||||
|
||||
if request.Method == "POST" {
|
||||
request.ParseForm()
|
||||
if strings.Join(request.PostForm["leave"], ",") == "Leave twitch channel" {
|
||||
td.Leaving = true
|
||||
} else if strings.Join(request.PostForm["reallyleave"], ",") == "Really leave twitch channel" {
|
||||
record := ircBot.ChannelData[vars["channel"]]
|
||||
record.HasLeft = true
|
||||
ircBot.ChannelData[vars["channel"]] = record
|
||||
ircBot.LeaveChannel(vars["channel"])
|
||||
ircBot.Database.Write("channelData", vars["channel"], record)
|
||||
LeaveHandler(response, request)
|
||||
return
|
||||
}
|
||||
if strings.Join(request.PostForm["join"], ",") == "Come on in" {
|
||||
record := ircBot.ChannelData[vars["channel"]]
|
||||
td.HasLeft = false
|
||||
record.Name = vars["channel"]
|
||||
record.JoinTime = time.Now()
|
||||
record.HasLeft = false
|
||||
if record.Command == "" {
|
||||
record.Command = "card"
|
||||
}
|
||||
ircBot.Database.Write("channelData", vars["channel"], record)
|
||||
ircBot.ChannelData[vars["channel"]] = record
|
||||
td = TemplateData{record.Name, record.Command, record.ExtraStrings, record.JoinTime, record.JoinTime.Format(irc.UTCFormat), false, record.HasLeft, AugmentSingsVideoStructSlice(channelData.VideoCache), topNSongs, topNSingers, vars["key"]}
|
||||
ircBot.JoinChannel(record.Name)
|
||||
}
|
||||
sourceData := ircBot.ChannelData[vars["channel"]]
|
||||
if strings.Join(request.PostForm["Command"], ",") != "" {
|
||||
sourceData.Command = strings.Join(request.PostForm["Command"], ",")
|
||||
td.Command = sourceData.Command
|
||||
ircBot.ChannelData[vars["channel"]] = sourceData
|
||||
}
|
||||
if strings.Join(request.PostForm["ExtraStrings"], ",") != sourceData.ExtraStrings {
|
||||
sourceData.ExtraStrings = strings.Join(request.PostForm["ExtraStrings"], ",")
|
||||
td.ExtraStrings = sourceData.ExtraStrings
|
||||
ircBot.ChannelData[vars["channel"]] = sourceData
|
||||
}
|
||||
ircBot.Database.Write("channelData", vars["channel"], sourceData)
|
||||
}
|
||||
tmpl, err := template.New("admin.html").ParseFiles("web/admin.html")
|
||||
if err != nil {
|
||||
panic(err.Error())
|
||||
}
|
||||
tmpl.Execute(response, td)
|
||||
}
|
||||
|
||||
func UnauthorizedHandler(response http.ResponseWriter, request *http.Request) {
|
||||
response.Header().Add("X-Template-File", "html"+request.URL.Path)
|
||||
response.WriteHeader(401)
|
||||
|
@ -318,7 +240,11 @@ func twitchHTTPClient(call string, bearer string) (string, error) {
|
|||
defer resp.Body.Close()
|
||||
|
||||
body, _ := ioutil.ReadAll(resp.Body)
|
||||
return string([]byte(body)), nil
|
||||
if resp.StatusCode != 200 {
|
||||
return string(http.StatusText(resp.StatusCode)), errors.New("HTTP ERROR: " + http.StatusText(resp.StatusCode))
|
||||
} else {
|
||||
return string([]byte(body)), nil
|
||||
}
|
||||
}
|
||||
|
||||
func ValidateTwitchBearerToken(bearer string) (bool, error) {
|
||||
|
@ -479,6 +405,31 @@ func (h *KVHeap) Pop() interface{} {
|
|||
|
||||
var cacheLock sync.Mutex
|
||||
|
||||
type CacheDetails struct {
|
||||
Age time.Duration `json: "cache_age"`
|
||||
AgeStr string `json: "cache_age_nice"`
|
||||
SongCount int `json: "expires_in"`
|
||||
}
|
||||
|
||||
func getCacheDetails(channel string) CacheDetails {
|
||||
var ret CacheDetails
|
||||
channelData := ircBot.ChannelData[channel]
|
||||
ret.Age = time.Now().Sub(channelData.VideoCacheUpdated)
|
||||
ret.AgeStr = humanize.Time(channelData.VideoCacheUpdated)
|
||||
ret.SongCount = len(channelData.VideoCache)
|
||||
return ret
|
||||
}
|
||||
|
||||
func forceUpdateCache(channel string) {
|
||||
fmt.Printf("Forcing cache update!")
|
||||
channelData := ircBot.ChannelData[channel]
|
||||
tenHours := time.Hour * -10
|
||||
videoCacheUpdated := time.Now().Add(tenHours) // Subtract 10 hours from now, cache is 10 hours old.
|
||||
channelData.VideoCacheUpdated = videoCacheUpdated
|
||||
ircBot.ChannelData[channel] = channelData
|
||||
updateCacheIfNecessary(channel)
|
||||
}
|
||||
|
||||
func updateCacheIfNecessary(channel string) {
|
||||
cacheLock.Lock()
|
||||
channelData := ircBot.ChannelData[channel]
|
||||
|
@ -601,9 +552,11 @@ func fetchVoDsPagesRecursive(userID string, bearer string, from string) ([]irc.S
|
|||
func fetchAllVoDs(userID string, bearer string) ([]irc.SingsVideoStruct, error) {
|
||||
tokenValid, err := ValidateTwitchBearerToken(bearer)
|
||||
if err != nil {
|
||||
fmt.Println("Error validating token : " + err.Error())
|
||||
return nil, err
|
||||
}
|
||||
if !tokenValid {
|
||||
fmt.Println("Error validating token (revoked?)")
|
||||
return nil, errors.New("Failed to validate token with twitch (authorization revoked?!)")
|
||||
}
|
||||
titles, err := fetchVoDsPagesRecursive(userID, bearer, "")
|
||||
|
@ -746,7 +699,7 @@ func CSVHandler(response http.ResponseWriter, request *http.Request) {
|
|||
}
|
||||
type TemplateData struct {
|
||||
Channel string
|
||||
Command string
|
||||
Commands []irc.CommandStruct
|
||||
ExtraStrings string
|
||||
SinceTime time.Time
|
||||
SinceTimeUTC string
|
||||
|
@ -760,7 +713,7 @@ func CSVHandler(response http.ResponseWriter, request *http.Request) {
|
|||
channelData := ircBot.ChannelData[vars["channel"]]
|
||||
topNSongs := calculateTopNSongs(channelData.VideoCache, 10)
|
||||
topNSingers := calculateTopNSingers(channelData.VideoCache, 10)
|
||||
var td = TemplateData{channelData.Name, channelData.Command, channelData.ExtraStrings, channelData.JoinTime, channelData.JoinTime.Format(irc.UTCFormat), false, channelData.HasLeft, AugmentSingsVideoStructSliceForCSV(channelData.VideoCache), topNSongs, topNSingers}
|
||||
var td = TemplateData{channelData.Name, channelData.Commands, channelData.ExtraStrings, channelData.JoinTime, channelData.JoinTime.Format(irc.UTCFormat), false, channelData.HasLeft, AugmentSingsVideoStructSliceForCSV(channelData.VideoCache), topNSongs, topNSingers}
|
||||
if request.URL.Path[0:4] == "/csv" {
|
||||
response.Header().Add("Content-Disposition", "attachment; filename=\"duets.csv\"")
|
||||
response.Header().Add("Content-type", "text/csv")
|
||||
|
@ -782,7 +735,7 @@ func JSONHandler(response http.ResponseWriter, request *http.Request) {
|
|||
}
|
||||
type TemplateData struct {
|
||||
Channel string
|
||||
Command string
|
||||
Commands []irc.CommandStruct
|
||||
ExtraStrings string
|
||||
SinceTime time.Time
|
||||
SinceTimeUTC string
|
||||
|
@ -794,9 +747,15 @@ func JSONHandler(response http.ResponseWriter, request *http.Request) {
|
|||
}
|
||||
updateCacheIfNecessary(vars["channel"])
|
||||
channelData := ircBot.ChannelData[vars["channel"]]
|
||||
topNSongs := calculateTopNSongs(channelData.VideoCache, 10)
|
||||
topNSingers := calculateTopNSingers(channelData.VideoCache, 10)
|
||||
var td = TemplateData{channelData.Name, channelData.Command, channelData.ExtraStrings, channelData.JoinTime, channelData.JoinTime.Format(irc.UTCFormat), false, channelData.HasLeft, AugmentSingsVideoStructSlice(channelData.VideoCache), topNSongs, topNSingers}
|
||||
|
||||
var topNSongs []SongSings
|
||||
var topNSingers []SingerSings
|
||||
|
||||
if request.URL.Path[0:4] != "/deb" {
|
||||
topNSongs = calculateTopNSongs(channelData.VideoCache, 10)
|
||||
topNSingers = calculateTopNSingers(channelData.VideoCache, 10)
|
||||
}
|
||||
var td = TemplateData{channelData.Name, channelData.Commands, channelData.ExtraStrings, channelData.JoinTime, channelData.JoinTime.Format(irc.UTCFormat), false, channelData.HasLeft, AugmentSingsVideoStructSlice(channelData.VideoCache), topNSongs, topNSingers}
|
||||
response.Header().Add("Content-type", "application/json")
|
||||
if request.URL.Path[0:5] == "/json" {
|
||||
tmpl := template.Must(template.ParseFiles("web/data.json"))
|
||||
|
@ -810,6 +769,42 @@ func JSONHandler(response http.ResponseWriter, request *http.Request) {
|
|||
}
|
||||
}
|
||||
|
||||
func CacheDetailsHandler(response http.ResponseWriter, request *http.Request) {
|
||||
vars := mux.Vars(request)
|
||||
if vars["key"] != ircBot.ChannelData[vars["channel"]].AdminKey {
|
||||
UnauthorizedHandler(response, request)
|
||||
return
|
||||
}
|
||||
deets := getCacheDetails(vars["channel"])
|
||||
response.Header().Add("Content-type", "application/json")
|
||||
enc := json.NewEncoder(response)
|
||||
enc.Encode(deets)
|
||||
}
|
||||
|
||||
func BotDetailsHandler(response http.ResponseWriter, request *http.Request) {
|
||||
vars := mux.Vars(request)
|
||||
if vars["key"] != ircBot.ChannelData[vars["channel"]].AdminKey {
|
||||
UnauthorizedHandler(response, request)
|
||||
return
|
||||
}
|
||||
type ChannelDataSmaller struct {
|
||||
Commands []irc.CommandStruct `json:"commands,omitempty"`
|
||||
ExtraStrings string `json:"extrastrings,omitempty"`
|
||||
JoinTime time.Time `json:"jointime"`
|
||||
HasLeft bool `json:"hasleft"`
|
||||
VideoCacheUpdated time.Time `json:"videoCacheUpdated"`
|
||||
}
|
||||
var deets ChannelDataSmaller
|
||||
deets.Commands = ircBot.ChannelData[vars["channel"]].Commands
|
||||
deets.ExtraStrings = ircBot.ChannelData[vars["channel"]].ExtraStrings
|
||||
deets.JoinTime = ircBot.ChannelData[vars["channel"]].JoinTime
|
||||
deets.HasLeft = ircBot.ChannelData[vars["channel"]].HasLeft
|
||||
deets.VideoCacheUpdated = ircBot.ChannelData[vars["channel"]].VideoCacheUpdated
|
||||
response.Header().Add("Content-type", "application/json")
|
||||
enc := json.NewEncoder(response)
|
||||
enc.Encode(deets)
|
||||
}
|
||||
|
||||
func ReactIndexHandler(entrypoint string) func(w http.ResponseWriter, r *http.Request) {
|
||||
fn := func(w http.ResponseWriter, r *http.Request) {
|
||||
http.ServeFile(w, r, entrypoint)
|
||||
|
@ -818,6 +813,33 @@ func ReactIndexHandler(entrypoint string) func(w http.ResponseWriter, r *http.Re
|
|||
return http.HandlerFunc(fn)
|
||||
}
|
||||
|
||||
func ForceRefreshHandler(response http.ResponseWriter, request *http.Request) {
|
||||
vars := mux.Vars(request)
|
||||
if vars["key"] != ircBot.ChannelData[vars["channel"]].AdminKey {
|
||||
UnauthorizedHandler(response, request)
|
||||
return
|
||||
}
|
||||
forceUpdateCache(vars["channel"])
|
||||
response.Header().Add("Content-type", "application/json")
|
||||
enc := json.NewEncoder(response)
|
||||
enc.Encode(true)
|
||||
}
|
||||
|
||||
func JoinHandler(response http.ResponseWriter, request *http.Request) {
|
||||
vars := mux.Vars(request)
|
||||
if vars["key"] != ircBot.ChannelData[vars["channel"]].AdminKey {
|
||||
UnauthorizedHandler(response, request)
|
||||
return
|
||||
}
|
||||
record := ircBot.ChannelData[vars["channel"]]
|
||||
record.Name = vars["channel"]
|
||||
record.JoinTime = time.Now()
|
||||
record.HasLeft = false
|
||||
ircBot.Database.Write("channelData", vars["channel"], record)
|
||||
ircBot.ChannelData[vars["channel"]] = record
|
||||
ircBot.JoinChannel(record.Name)
|
||||
}
|
||||
|
||||
func HandleHTTP(passedIrcBot *irc.KardBot) {
|
||||
ircBot = passedIrcBot
|
||||
r := mux.NewRouter()
|
||||
|
@ -825,9 +847,14 @@ func HandleHTTP(passedIrcBot *irc.KardBot) {
|
|||
r.NotFoundHandler = http.HandlerFunc(NotFoundHandler)
|
||||
r.HandleFunc("/healthz", HealthHandler)
|
||||
r.HandleFunc("/web/{.*}", TemplateHandler)
|
||||
r.HandleFunc("/cachedeets/{channel}/{key}", CacheDetailsHandler)
|
||||
r.HandleFunc("/botdeets/{channel}/{key}", BotDetailsHandler)
|
||||
r.HandleFunc("/join/{channel}/{key}", JoinHandler)
|
||||
r.HandleFunc("/force/{channel}/{key}", ForceRefreshHandler)
|
||||
r.HandleFunc("/csv/{channel}/{key}", CSVHandler)
|
||||
r.HandleFunc("/tsv/{channel}/{key}", CSVHandler)
|
||||
r.HandleFunc("/json/{channel}/{key}", JSONHandler)
|
||||
r.HandleFunc("/debug/{channel}/{key}", JSONHandler)
|
||||
r.HandleFunc("/topsongs/{channel}/{key}", JSONHandler)
|
||||
r.HandleFunc("/topsingers/{channel}/{key}", JSONHandler)
|
||||
r.Path("/twitchtobackend").Queries("access_token", "{access_token}", "scope", "{scope}", "token_type", "{token_type}").HandlerFunc(TwitchBackendHandler)
|
||||
|
|
Loading…
Reference in New Issue