Getting a feel for desired multi-language approach #424

This commit is contained in:
James Barnsley
2020-07-04 21:39:30 +12:00
parent 4e44e31136
commit 78ec0eff26
17 changed files with 2491 additions and 272 deletions

4
.eslintrc.json Normal file → Executable file
View File

@ -9,7 +9,9 @@
"no-console": 0,
"no-underscore-dangle": 0,
"react/prop-types": 0,
"linebreak-style": 0
"linebreak-style": 0,
"no-case-declarations": 0,
"camelcase": 0
},
"globals": {
"fetch": true

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -100,7 +100,7 @@
// Release details
// These are automatically injected to built HTML
var build = "1592960481";
var build = "1593854017";
var version = "3.50.0";
// Construct the script tag

222
package-lock.json generated
View File

@ -1,6 +1,6 @@
{
"name": "mopidy-iris",
"version": "3.49.0",
"version": "3.50.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@ -4339,13 +4339,13 @@
"@types/events": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@types/events/-/events-3.0.0.tgz",
"integrity": "sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g==",
"integrity": "sha1-KGLz9Yqaf3w+eNefEw3U1xwlwqc=",
"dev": true
},
"@types/glob": {
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.1.tgz",
"integrity": "sha512-1Bh06cbWJUHMC97acuD6UMG29nMt0Aqz1vF3guLfG+kHHJhy3AyohZFFxYk2f7Q1SQIrNwvncxAE0N/9s70F2w==",
"integrity": "sha1-qlmhxuP7xCHgfM0xqUTDDrpSFXU=",
"dev": true,
"requires": {
"@types/events": "*",
@ -4381,7 +4381,7 @@
"@types/minimatch": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz",
"integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==",
"integrity": "sha1-PcoOPzOyAPx9ETnAzZbBJoyt/Z0=",
"dev": true
},
"@types/node": {
@ -4607,13 +4607,13 @@
"abbrev": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
"integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==",
"integrity": "sha1-+PLIh60Qv2f2NPAFtph/7TF5qsg=",
"dev": true
},
"accepts": {
"version": "1.3.7",
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz",
"integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==",
"integrity": "sha1-UxvHJlF6OytB+FACHGzBXqq1B80=",
"dev": true,
"requires": {
"mime-types": "~2.1.24",
@ -4621,9 +4621,9 @@
}
},
"acorn": {
"version": "5.7.3",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz",
"integrity": "sha1-Z6ojG/iBKXS4UjWpZ3Hra9B+onk=",
"version": "5.7.4",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.4.tgz",
"integrity": "sha512-1D++VG7BhrtvQpNbBzovKNc1FLGGEE/oGe7b9xJm/RFHMBeUaUGpluV9RLjZa47YFdPcDAenEYuq9pQPcMdLJg==",
"dev": true
},
"acorn-globals": {
@ -4721,7 +4721,7 @@
"ansi-colors": {
"version": "3.2.4",
"resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.4.tgz",
"integrity": "sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA==",
"integrity": "sha1-46PaS/uubIapwoViXeEkojQCb78=",
"dev": true
},
"ansi-escapes": {
@ -4767,7 +4767,7 @@
"are-we-there-yet": {
"version": "1.1.5",
"resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz",
"integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==",
"integrity": "sha1-SzXClE8GKov82mZBB2A1D+nd/CE=",
"dev": true,
"requires": {
"delegates": "^1.0.0",
@ -4864,7 +4864,7 @@
"array-flatten": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz",
"integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==",
"integrity": "sha1-JO+AoowaiTYX4hSbDG0NeIKTsJk=",
"dev": true
},
"array-includes": {
@ -5098,7 +5098,7 @@
"async": {
"version": "2.6.3",
"resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz",
"integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==",
"integrity": "sha1-1yYl4jRKNlbjo61Pp0n6gymdgv8=",
"dev": true,
"requires": {
"lodash": "^4.17.14"
@ -6557,8 +6557,7 @@
"big.js": {
"version": "5.2.2",
"resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz",
"integrity": "sha1-ZfCvOC9Xi83HQr2cKB6cstd2gyg=",
"dev": true
"integrity": "sha1-ZfCvOC9Xi83HQr2cKB6cstd2gyg="
},
"binary-extensions": {
"version": "1.13.1",
@ -6590,7 +6589,7 @@
"body-parser": {
"version": "1.19.0",
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz",
"integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==",
"integrity": "sha1-lrJwnlfJxOCab9Zqj9l5hE9p8Io=",
"dev": true,
"requires": {
"bytes": "3.1.0",
@ -6608,13 +6607,13 @@
"bytes": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz",
"integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==",
"integrity": "sha1-9s95M6Ng4FiPqf3oVlHNx/gF0fY=",
"dev": true
},
"qs": {
"version": "6.7.0",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz",
"integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==",
"integrity": "sha1-QdwaAV49WB8WIXdr4xr7KHapsbw=",
"dev": true
}
}
@ -6825,7 +6824,7 @@
"buffer-indexof": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/buffer-indexof/-/buffer-indexof-1.1.1.tgz",
"integrity": "sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g==",
"integrity": "sha1-Uvq8xqYG0aADAoAmSO9o9jnaJow=",
"dev": true
},
"buffer-xor": {
@ -7338,7 +7337,7 @@
"compression": {
"version": "1.7.4",
"resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz",
"integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==",
"integrity": "sha1-lVI+/xcMpXwpoMpB5v4TH0Hlu48=",
"dev": true,
"requires": {
"accepts": "~1.3.5",
@ -7409,7 +7408,7 @@
"connect-history-api-fallback": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz",
"integrity": "sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==",
"integrity": "sha1-izIIk1kwjRERFdgcrT/Oq4iPl7w=",
"dev": true
},
"console-browserify": {
@ -7439,7 +7438,7 @@
"content-disposition": {
"version": "0.5.3",
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz",
"integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==",
"integrity": "sha1-4TDK9+cnkIfFYWwgB9BIVpiYT70=",
"dev": true,
"requires": {
"safe-buffer": "5.1.2"
@ -7448,7 +7447,7 @@
"content-type": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
"integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==",
"integrity": "sha1-4TjMdeBAxyexlm/l5fjJruJW/js=",
"dev": true
},
"convert-source-map": {
@ -7463,7 +7462,7 @@
"cookie": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz",
"integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==",
"integrity": "sha1-vrQ35wIrO21JAZ0IhmUwPr6cFLo=",
"dev": true
},
"cookie-signature": {
@ -7849,7 +7848,7 @@
"deep-equal": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz",
"integrity": "sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g==",
"integrity": "sha1-tcmMlCzv+vfLBR4k4UNKJaLmB2o=",
"dev": true,
"requires": {
"is-arguments": "^1.0.4",
@ -7869,7 +7868,7 @@
"default-gateway": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-4.2.0.tgz",
"integrity": "sha512-h6sMrVB1VMWVrW13mSc6ia/DwYYw5MN6+exNu1OaJeFac5aSAvwM7lZ0NVfTABuSkQelr4h5oebg3KB1XPdjgA==",
"integrity": "sha1-FnEEx1AMIRX23WmwpTa7jtcgVSs=",
"dev": true,
"requires": {
"execa": "^1.0.0",
@ -7935,7 +7934,7 @@
"del": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/del/-/del-4.1.1.tgz",
"integrity": "sha512-QwGuEUouP2kVwQenAsOof5Fv8K9t3D8Ca8NxcXKrIpEHjTXK5J2nXLdP+ALI1cgv8wj7KuwBhTwBkOZSJKM5XQ==",
"integrity": "sha1-no8RciLqRKMf86FWwEm5kFKp8LQ=",
"dev": true,
"requires": {
"@types/glob": "^7.1.1",
@ -7950,7 +7949,7 @@
"pify": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz",
"integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==",
"integrity": "sha1-SyzSXFDVmHNcUCkiJP2MbfQeMjE=",
"dev": true
}
}
@ -8013,7 +8012,7 @@
"detect-node": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.0.4.tgz",
"integrity": "sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw==",
"integrity": "sha1-AU7o+PZpxcWAI9pkuBecCDooxGw=",
"dev": true
},
"diff-sequences": {
@ -8048,7 +8047,7 @@
"dns-packet": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-1.3.1.tgz",
"integrity": "sha512-0UxfQkMhYAUaZI+xrNZOz/as5KgDU0M/fQ9b6SpkyLbk3GEswDi6PADJVaYJradtRVsRIlF1zLyOodbcTCDzUg==",
"integrity": "sha1-EqpCaYEHW+UAuRDu3NC0fdfe2lo=",
"dev": true,
"requires": {
"ip": "^1.1.0",
@ -9064,7 +9063,7 @@
"eventsource": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/eventsource/-/eventsource-1.0.7.tgz",
"integrity": "sha512-4Ln17+vVT0k8aWq+t/bF5arcS3EpT9gYtW66EPacdj/mAFevznsnyoHLPy2BA8gbIQeIHoPsvwmfBftfcG//BQ==",
"integrity": "sha1-j7xyyT/NNAiAkLwKTmT0tc7m2NA=",
"dev": true,
"requires": {
"original": "^1.0.0"
@ -9185,7 +9184,7 @@
"express": {
"version": "4.17.1",
"resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz",
"integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==",
"integrity": "sha1-RJH8OGBc9R+GKdOcK10Cb5ikwTQ=",
"dev": true,
"requires": {
"accepts": "~1.3.7",
@ -9235,7 +9234,7 @@
"qs": {
"version": "6.7.0",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz",
"integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==",
"integrity": "sha1-QdwaAV49WB8WIXdr4xr7KHapsbw=",
"dev": true
}
}
@ -9455,7 +9454,7 @@
"finalhandler": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
"integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==",
"integrity": "sha1-t+fQAP/RGTjQ/bBTUG9uur6fWH0=",
"dev": true,
"requires": {
"debug": "2.6.9",
@ -9576,7 +9575,7 @@
"debug": {
"version": "3.2.6",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
"integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
"integrity": "sha1-6D0X3hbYp++3cX7b5fsQE17uYps=",
"dev": true,
"requires": {
"ms": "^2.1.1"
@ -10286,7 +10285,7 @@
"fstream": {
"version": "1.0.12",
"resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz",
"integrity": "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==",
"integrity": "sha1-Touo7i1Ivk99DeUFRVVI6uWTIEU=",
"dev": true,
"requires": {
"graceful-fs": "^4.1.2",
@ -10418,7 +10417,7 @@
"gaze": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/gaze/-/gaze-1.1.3.tgz",
"integrity": "sha512-BRdNm8hbWzFzWHERTrejLqwHDfS4GibPoq5wjTPIoJHoBtKGPg3xAFfxmM+9ztbXelxcf2hwQcaz1PtmFeue8g==",
"integrity": "sha1-xEFzPhO5J6yMD/C0w7Az8ogSkko=",
"dev": true,
"requires": {
"globule": "^1.0.0"
@ -10870,7 +10869,7 @@
"http-errors": {
"version": "1.7.2",
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz",
"integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==",
"integrity": "sha1-T1ApzxMjnzEDblsuVSkrz7zIXI8=",
"dev": true,
"requires": {
"depd": "~1.1.2",
@ -10899,7 +10898,7 @@
"http-proxy-middleware": {
"version": "0.19.1",
"resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-0.19.1.tgz",
"integrity": "sha512-yHYTgWMQO8VvwNS22eLLloAkvungsKdKTLO8AJlftYIKNfJr3GK3zK0ZCfzDDGUBttdGc8xFy1mCitvNKQtC3Q==",
"integrity": "sha1-GDx9xKoUeRUDBkmMIQza+WCApDo=",
"dev": true,
"requires": {
"http-proxy": "^1.17.0",
@ -11270,7 +11269,7 @@
"internal-ip": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/internal-ip/-/internal-ip-4.3.0.tgz",
"integrity": "sha512-S1zBo1D6zcsyuC6PMmY5+55YMILQ9av8lotMx447Bq6SAgo/sDK6y6uUKmuYhW7eacnIhFfsPmCNYdDzsnnDCg==",
"integrity": "sha1-hFRSuq2dLKO2nGNaE3rLmg2tCQc=",
"dev": true,
"requires": {
"default-gateway": "^4.2.0",
@ -11403,7 +11402,7 @@
"is-arguments": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.0.4.tgz",
"integrity": "sha512-xPh0Rmt8NE65sNzvyUmWgI1tz3mKq74lGA0mL8LYZcoIzKOzDh6HmrYm3d18k60nHerC8A9Km8kYu87zfSFnLA==",
"integrity": "sha1-P6+WbHy6D/Q3+zH2JQCC/PBEjPM=",
"dev": true
},
"is-arrayish": {
@ -11564,13 +11563,13 @@
"is-path-cwd": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz",
"integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==",
"integrity": "sha1-Z9Q7gmZKe1GR/ZEZEn6zAASKn9s=",
"dev": true
},
"is-path-in-cwd": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-2.1.0.tgz",
"integrity": "sha512-rNocXHgipO+rvnP6dk3zI20RpOtrAM/kzbB258Uw5BWr3TpXi861yzjo16Dn4hUox07iw5AyeMLHWsujkjzvRQ==",
"integrity": "sha1-v+Lcomxp85cmWkAJljYCk1oFOss=",
"dev": true,
"requires": {
"is-path-inside": "^2.1.0"
@ -11579,7 +11578,7 @@
"is-path-inside": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-2.1.0.tgz",
"integrity": "sha512-wiyhTzfDWsvwAW53OBWF5zuvaOGlZ6PwYxAbPVDhpm+gM09xKQGjBq/8uYN12aDvMxnAnq3dxTyoSoRNmg5YFg==",
"integrity": "sha1-fJgQWH1lmkDSe8201WFuqwWUlLI=",
"dev": true,
"requires": {
"path-is-inside": "^1.0.2"
@ -12937,7 +12936,7 @@
"json3": {
"version": "3.3.3",
"resolved": "https://registry.npmjs.org/json3/-/json3-3.3.3.tgz",
"integrity": "sha512-c7/8mbUsKigAbLkD5B010BK4D9LZm7A1pNItkEwiUZRpIN66exu/e7YQWysGun+TRKaJp8MhemM+VkfWv42aCA==",
"integrity": "sha1-f8EON1/FrkLEcFpcwKpvYr4wW4E=",
"dev": true
},
"json5": {
@ -12971,7 +12970,7 @@
"killable": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/killable/-/killable-1.0.1.tgz",
"integrity": "sha512-LzqtLKlUwirEUyl/nicirVmNiPvYs7l5n8wOPP7fyJVpUPkvCnW/vuiXGpylGUlnPDnB7311rARzAt3Mhswpjg==",
"integrity": "sha1-TIzkQRh6Bhx0dPuHygjipjgZSJI=",
"dev": true
},
"kind-of": {
@ -13076,8 +13075,7 @@
"lodash": {
"version": "4.17.15",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
"integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==",
"dev": true
"integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A=="
},
"lodash.camelcase": {
"version": "4.3.0",
@ -13153,7 +13151,7 @@
"lru-cache": {
"version": "4.1.5",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz",
"integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==",
"integrity": "sha1-i75Q6oW+1ZvJ4z3KuCNe6bz0Q80=",
"dev": true,
"requires": {
"pseudomap": "^1.0.2",
@ -13553,8 +13551,7 @@
"minimist": {
"version": "1.2.5",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
"dev": true
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
},
"mississippi": {
"version": "3.0.0",
@ -13649,7 +13646,7 @@
"multicast-dns": {
"version": "6.2.3",
"resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-6.2.3.tgz",
"integrity": "sha512-ji6J5enbMyGRHIAkAOu3WdV8nggqviKCEKtXcOqfphZZtQrmHKycfynJ2V7eVPUA4NhJ6V7Wf4TmGbTwKE9B6g==",
"integrity": "sha1-oOx72QVcQoL3kMPIL04o2zsxsik=",
"dev": true,
"requires": {
"dns-packet": "^1.3.1",
@ -13715,7 +13712,7 @@
"negotiator": {
"version": "0.6.2",
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz",
"integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==",
"integrity": "sha1-/qz3zPUlp3rpY0Q2pkiD/+yjRvs=",
"dev": true
},
"neo-async": {
@ -13733,13 +13730,13 @@
"node-forge": {
"version": "0.9.0",
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.9.0.tgz",
"integrity": "sha512-7ASaDa3pD+lJ3WvXFsxekJQelBKRpne+GOVbLbtHYdd7pFspyeuJHnWfLplGf3SwKGbfs/aYl5V/JCIaHVUKKQ==",
"integrity": "sha1-1iQFDtu0SHStyhK7mlLsY8t4JXk=",
"dev": true
},
"node-gyp": {
"version": "3.8.0",
"resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-3.8.0.tgz",
"integrity": "sha512-3g8lYefrRRzvGeSowdJKAKyks8oUpLEd/DyPV4eMhVlhJ0aNaZqIrNUIPuEWWTAoPqyFkfGrM67MC69baqn6vA==",
"integrity": "sha1-VAMEJhwzDoDQ1e3OJTpoyzlkIYw=",
"dev": true,
"requires": {
"fstream": "^1.0.0",
@ -13963,7 +13960,7 @@
"npmlog": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz",
"integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==",
"integrity": "sha1-CKfyqL9zRgR3mp76StXMcXq7lUs=",
"dev": true,
"requires": {
"are-we-there-yet": "~1.1.2",
@ -14354,7 +14351,7 @@
"obuf": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz",
"integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==",
"integrity": "sha1-Cb6jND1BhZ69RGKS0RydTbYZCE4=",
"dev": true
},
"on-finished": {
@ -14369,7 +14366,7 @@
"on-headers": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz",
"integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==",
"integrity": "sha1-dysK5qqlJcOZ5Imt+tkMQD6zwo8=",
"dev": true
},
"once": {
@ -14393,7 +14390,7 @@
"opn": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/opn/-/opn-5.5.0.tgz",
"integrity": "sha512-PqHpggC9bLV0VeWcdKhkpxY+3JTzetLSqTCWL/z/tFIbI6G8JCjondXklT1JinczLz2Xib62sSp0T/gKT4KksA==",
"integrity": "sha1-/HFk+rVtI1kExRw7J9pnWMo7m/w=",
"dev": true,
"requires": {
"is-wsl": "^1.1.0"
@ -14424,7 +14421,7 @@
"original": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/original/-/original-1.0.2.tgz",
"integrity": "sha512-hyBVl6iqqUOJ8FqRe+l/gS8H+kKYjrEndd5Pm1MfBtsEKA038HkkdbAl/72EAXGyonD/PFsvmVG+EvcIpliMBg==",
"integrity": "sha1-5EKmHP/hxf0gpl8yYcJmY7MD8l8=",
"dev": true,
"requires": {
"url-parse": "^1.4.3"
@ -14451,7 +14448,7 @@
"osenv": {
"version": "0.1.5",
"resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz",
"integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==",
"integrity": "sha1-hc36+uso6Gd/QW4odZK18/SepBA=",
"dev": true,
"requires": {
"os-homedir": "^1.0.0",
@ -14506,7 +14503,7 @@
"p-map": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz",
"integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==",
"integrity": "sha1-MQko/u+cnsxltosXaTAYpmXOoXU=",
"dev": true
},
"p-reduce": {
@ -14518,7 +14515,7 @@
"p-retry": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/p-retry/-/p-retry-3.0.1.tgz",
"integrity": "sha512-XE6G4+YTTkT2a0UWb2kjZe8xNwf8bIbnqpc/IS/idOBVhyves0mK5OJgeocjx7q5pvX/6m23xuzVPYT1uGM73w==",
"integrity": "sha1-MWtMiJPiyNwc+okfQGxLQivr8yg=",
"dev": true,
"requires": {
"retry": "^0.12.0"
@ -14630,7 +14627,7 @@
"parseurl": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
"integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
"integrity": "sha1-naGee+6NEt/wUT7Vt2lXeTvC6NQ=",
"dev": true
},
"pascalcase": {
@ -15599,7 +15596,7 @@
"querystringify": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.1.1.tgz",
"integrity": "sha512-w7fLxIRCRT7U8Qu53jQnJyPkYZIaR4n5151KMfcJlO/A9397Wxb1amJvROTK6TOnp7PfoAmg/qXiNHI+08jRfA==",
"integrity": "sha1-YOWl/WSn+L+k0qsu1v30yFutFU4=",
"dev": true
},
"raf": {
@ -15649,13 +15646,13 @@
"range-parser": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
"integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
"integrity": "sha1-PPNwI9GZ4cJNGlW4SADC8+ZGgDE=",
"dev": true
},
"raw-body": {
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz",
"integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==",
"integrity": "sha1-oc5vucm8NWylLoklarWQWeE9AzI=",
"dev": true,
"requires": {
"bytes": "3.1.0",
@ -15667,7 +15664,7 @@
"bytes": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz",
"integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==",
"integrity": "sha1-9s95M6Ng4FiPqf3oVlHNx/gF0fY=",
"dev": true
}
}
@ -16635,7 +16632,7 @@
"selfsigned": {
"version": "1.10.7",
"resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-1.10.7.tgz",
"integrity": "sha512-8M3wBCzeWIJnQfl43IKwOmC4H/RAp50S8DF60znzjW5GVqTcSe2vWclt7hmYVPkKPlHWOu5EaWOMZ2Y6W8ZXTA==",
"integrity": "sha1-2lgZ/QSdVXTyjoipvMbbxubzkGs=",
"dev": true,
"requires": {
"node-forge": "0.9.0"
@ -16650,7 +16647,7 @@
"send": {
"version": "0.17.1",
"resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz",
"integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==",
"integrity": "sha1-wdiwWfeQD3Rm3Uk4vcROEd2zdsg=",
"dev": true,
"requires": {
"debug": "2.6.9",
@ -16671,7 +16668,7 @@
"ms": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
"integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==",
"integrity": "sha1-MKWGTrPrsKZvLr5tcnrwagnYbgo=",
"dev": true
}
}
@ -16712,7 +16709,7 @@
"setprototypeof": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz",
"integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==",
"integrity": "sha1-0L2FU2iHtv58DYGMuWLZ2RxU5lY=",
"dev": true
}
}
@ -16720,7 +16717,7 @@
"serve-static": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz",
"integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==",
"integrity": "sha1-Zm5jbcTwEPfvKZcKiKZ0MgiYsvk=",
"dev": true,
"requires": {
"encodeurl": "~1.0.2",
@ -16767,7 +16764,7 @@
"setprototypeof": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz",
"integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==",
"integrity": "sha1-fpWsskqpL1iF4KvvW6ExMw1K5oM=",
"dev": true
},
"sha.js": {
@ -17060,7 +17057,7 @@
"sockjs-client": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/sockjs-client/-/sockjs-client-1.4.0.tgz",
"integrity": "sha512-5zaLyO8/nri5cua0VtOrFXBPK1jbL4+1cebT/mmKA1E1ZXOvJrII75bPu0l0k843G/+iAbhEqzyKr0w/eCCj7g==",
"integrity": "sha1-yfJWjhnI/YFztJl+o0IOC7MGx9U=",
"dev": true,
"requires": {
"debug": "^3.2.5",
@ -17074,7 +17071,7 @@
"debug": {
"version": "3.2.6",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
"integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
"integrity": "sha1-6D0X3hbYp++3cX7b5fsQE17uYps=",
"dev": true,
"requires": {
"ms": "^2.1.1"
@ -17083,7 +17080,7 @@
"faye-websocket": {
"version": "0.11.3",
"resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.3.tgz",
"integrity": "sha512-D2y4bovYpzziGgbHYtGCMjlJM36vAl/y+xUyn1C+FVx8szd1E+86KwVw6XvYSzOP8iMpm1X0I4xJD+QtUb36OA==",
"integrity": "sha1-XA6aiWjokSwoZjn96XeosgnyUI4=",
"dev": true,
"requires": {
"websocket-driver": ">=0.5.1"
@ -17217,7 +17214,7 @@
"spdy-transport": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz",
"integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==",
"integrity": "sha1-ANSGOmQArXXfkzYaFghgXl3NzzE=",
"dev": true,
"requires": {
"debug": "^4.1.0",
@ -17322,7 +17319,7 @@
"stdout-stream": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/stdout-stream/-/stdout-stream-1.4.1.tgz",
"integrity": "sha512-j4emi03KXqJWcIeF8eIXkjMFN1Cmb8gUlDYGeBALLPo5qdyTfA9bOtl8m33lRoC+vFMkP3gl0WsDr6+gzxbbTA==",
"integrity": "sha1-WsF0zdXNcmEEqgwLK9g4FdjVNd4=",
"dev": true,
"requires": {
"readable-stream": "^2.0.1"
@ -18096,7 +18093,7 @@
"tar": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/tar/-/tar-2.2.2.tgz",
"integrity": "sha512-FCEhQ/4rE1zYv9rYXJw/msRqsnmlje5jHP6huWeBZ704jUTy02c5AZyWujpMR1ax6mVw9NyJMfuK2CMDWVIfgA==",
"integrity": "sha1-DKiEhWLHKZuLRG/2pNYM27I+3EA=",
"dev": true,
"requires": {
"block-stream": "*",
@ -18322,7 +18319,7 @@
"thunky": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz",
"integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==",
"integrity": "sha1-Wrr3FKlAXbBQRzK7zNLO3Z75U30=",
"dev": true
},
"timers-browserify": {
@ -18416,7 +18413,7 @@
"toidentifier": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz",
"integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==",
"integrity": "sha1-fhvjRw8ed5SLxD2Uo8j013UrpVM=",
"dev": true
},
"tough-cookie": {
@ -18453,7 +18450,7 @@
"true-case-path": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/true-case-path/-/true-case-path-1.0.3.tgz",
"integrity": "sha512-m6s2OdQe5wgpFMC+pAJ+q9djG82O2jcHPOI6RNg1yy9rCYR+WD6Nbpl32fDpfC56nirdRy+opFa/Vk7HYhqaew==",
"integrity": "sha1-+BO1qMhrQNpZYGcisUTjIleZ9H0=",
"dev": true,
"requires": {
"glob": "^7.1.2"
@ -18503,7 +18500,7 @@
"type-is": {
"version": "1.6.18",
"resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
"integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
"integrity": "sha1-TlUs0F3wlGfcvE73Od6J8s83wTE=",
"dev": true,
"requires": {
"media-typer": "0.3.0",
@ -18719,7 +18716,7 @@
"url-parse": {
"version": "1.4.7",
"resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.4.7.tgz",
"integrity": "sha512-d3uaVyzDB9tQoSXFvuSUNFibTd9zxd2bkVrDRvF5TmvWWQwqE4lgYJ5m+x1DbecWkw+LK4RNl2CU1hHuOKPVlg==",
"integrity": "sha1-qKg1NejACjFuQDpdtKwbm4U64ng=",
"dev": true,
"requires": {
"querystringify": "^2.1.1",
@ -18970,7 +18967,7 @@
"wbuf": {
"version": "1.7.3",
"resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz",
"integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==",
"integrity": "sha1-wdjRSTFtPqhShIiVy2oL/oh7h98=",
"dev": true,
"requires": {
"minimalistic-assert": "^1.0.0"
@ -19293,7 +19290,7 @@
"webpack-dev-middleware": {
"version": "3.7.2",
"resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-3.7.2.tgz",
"integrity": "sha512-1xC42LxbYoqLNAhV6YzTYacicgMZQTqRd27Sim9wn5hJrX3I5nxYy1SxSd4+gjUFsz1dQFj+yEe6zEVmSkeJjw==",
"integrity": "sha1-ABnD23FuP6XOy/ZPKriKdLqzMfM=",
"dev": true,
"requires": {
"memory-fs": "^0.4.1",
@ -19385,7 +19382,7 @@
"is-absolute-url": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-3.0.3.tgz",
"integrity": "sha512-opmNIX7uFnS96NtPmhWQgQx6/NYFgsUXYMllcfzwWKUMwfo8kku1TvE6hkNcH+Q1ts5cMVrsY7j0bxXQDciu9Q==",
"integrity": "sha1-lsaiK2ojkpsR6gr7GDbDatSl1pg=",
"dev": true
},
"locate-path": {
@ -19431,7 +19428,7 @@
"semver": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
"integrity": "sha1-7gpkyK9ejO6mdoexM3YeG+y9HT0=",
"dev": true
},
"string-width": {
@ -19459,7 +19456,7 @@
"supports-color": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz",
"integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==",
"integrity": "sha1-B2Srxpxj1ayELdSGfo0CXogN+PM=",
"dev": true,
"requires": {
"has-flag": "^3.0.0"
@ -19468,7 +19465,7 @@
"ws": {
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/ws/-/ws-6.2.1.tgz",
"integrity": "sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA==",
"integrity": "sha1-RC/fCkftZPWbal2P8TD0dI7VJPs=",
"dev": true,
"requires": {
"async-limiter": "~1.0.0"
@ -19497,7 +19494,7 @@
"webpack-log": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/webpack-log/-/webpack-log-2.0.0.tgz",
"integrity": "sha512-cX8G2vR/85UYG59FgkoMamwHUIkSSlV3bBMRsbxVXVUk2j6NleCKjQ/WE9eYg9WY4w25O9w8wKP4rzNZFmUcUg==",
"integrity": "sha1-W3ko4GN1k/EZ0y9iJ8HgrDHhtH8=",
"dev": true,
"requires": {
"ansi-colors": "^3.0.0",
@ -19620,7 +19617,7 @@
"wide-align": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz",
"integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==",
"integrity": "sha1-rgdOa9wMFKQx6ATmJFScYzsABFc=",
"dev": true,
"requires": {
"string-width": "^1.0.2 || 2"
@ -19742,6 +19739,45 @@
"integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=",
"dev": true
},
"yaml": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.0.tgz",
"integrity": "sha512-yr2icI4glYaNG+KWONODapy2/jDdMSDnrONSjblABjD9B4Z5LgiircSt8m8sRZFNi08kG9Sm0uSHtEmP3zaEGg=="
},
"yaml-loader": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/yaml-loader/-/yaml-loader-0.6.0.tgz",
"integrity": "sha512-1bNiLelumURyj+zvVHOv8Y3dpCri0F2S+DCcmps0pA1zWRLjS+FhZQg4o3aUUDYESh73+pKZNI18bj7stpReow==",
"requires": {
"loader-utils": "^1.4.0",
"yaml": "^1.8.3"
},
"dependencies": {
"emojis-list": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz",
"integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q=="
},
"json5": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
"integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
"requires": {
"minimist": "^1.2.0"
}
},
"loader-utils": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz",
"integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==",
"requires": {
"big.js": "^5.2.2",
"emojis-list": "^3.0.0",
"json5": "^1.0.1"
}
}
}
},
"yargs": {
"version": "13.3.0",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.0.tgz",

9
package.json Normal file → Executable file
View File

@ -11,9 +11,9 @@
"main": "app.js",
"dependencies": {
"@sentry/browser": "^5.15.5",
"fast-average-color": "^6.0.2",
"history": "^4.10.1",
"jquery": "^3.5.0",
"lodash": "^4.17.15",
"logrocket": "^1.0.7",
"mopidy": "^0.5",
"react": "^16.13.1",
@ -24,7 +24,10 @@
"react-redux": "^7",
"react-router": "^5",
"react-router-dom": "^5.1.2",
"react-sortablejs": "^1.5.0"
"react-sortablejs": "^1.5.0",
"redux": "^4.0.5",
"redux-thunk": "^2.3.0",
"yaml-loader": "^0.6.0"
},
"devDependencies": {
"@babel/plugin-proposal-class-properties": "^7.8.3",
@ -55,8 +58,6 @@
"mini-css-extract-plugin": "^0.6.0",
"node-sass": "^4.14.1",
"react-test-renderer": "^16.13.1",
"redux": "^4.0.5",
"redux-thunk": "^2.3.0",
"sass-loader": "^7.3.1",
"sortablejs": "^1.10.2",
"style-loader": "^0.23",

View File

@ -8,6 +8,7 @@ import Icon from './Icon';
import Dropzones from './Fields/Dropzones';
import * as uiActions from '../services/ui/actions';
import * as mopidyActions from '../services/mopidy/actions';
import { content, Content } from '../locale';
class Sidebar extends React.Component {
renderStatusIcon() {
@ -43,9 +44,21 @@ class Sidebar extends React.Component {
<span className="status tooltip tooltip--right">
<Icon name="warning" className="red-text" />
<span className="tooltip__content">
{!mopidy_connected && (<span>Mopidy not connected<br /></span>)}
{!pusher_connected && (<span>Pusher not connected<br /></span>)}
{!snapcast_connected && snapcast_enabled && (<span>Snapcast not connected<br /></span>)}
{!mopidy_connected && (
<Content path="sidebar.not_connected" params={{ name: 'Mopidy' }}>
<br />
</Content>
)}
{!pusher_connected && (
<Content path="sidebar.not_connected" params={{ name: 'Pusher' }}>
<br />
</Content>
)}
{!snapcast_connected && snapcast_enabled && (
<Content path="sidebar.not_connected" params={{ name: 'Snapcast' }}>
<br />
</Content>
)}
</span>
</span>
);
@ -69,64 +82,68 @@ class Sidebar extends React.Component {
<section className="sidebar__menu__section">
<Link to="/queue" history={history} className="sidebar__menu__item" activeClassName="sidebar__menu__item--active">
<Icon name="play_arrow" type="material" />
Now playing
<Content path="sidebar.now_playing" />
</Link>
<Link to="/search" history={history} className="sidebar__menu__item" activeClassName="sidebar__menu__item--active">
<Icon name="search" type="material" />
Search
<Content path="sidebar.search" />
</Link>
</section>
{spotify_available && (
<section className="sidebar__menu__section">
<title className="sidebar__menu__section__title">Discover</title>
<title className="sidebar__menu__section__title">
{content('sidebar.discover')}
</title>
<Link to="/discover/recommendations" history={history} className="sidebar__menu__item" activeClassName="sidebar__menu__item--active">
<Icon name="explore" type="material" />
Discover
{content('sidebar.discover')}
</Link>
<Link to="/discover/categories" history={history} className="sidebar__menu__item" activeClassName="sidebar__menu__item--active">
<Icon name="mood" type="material" />
Genre / Mood
{content('sidebar.genre')}
</Link>
<Link to="/discover/featured" history={history} className="sidebar__menu__item" activeClassName="sidebar__menu__item--active">
<Icon name="star" type="material" />
Featured playlists
{content('sidebar.featured_playlists')}
</Link>
<Link to="/discover/new-releases" history={history} className="sidebar__menu__item" activeClassName="sidebar__menu__item--active">
<Icon name="new_releases" type="material" />
New releases
{content('sidebar.new_releases')}
</Link>
</section>
)}
<section className="sidebar__menu__section">
<title className="sidebar__menu__section__title">My Music</title>
<title className="sidebar__menu__section__title">
{content('sidebar.my_music')}
</title>
<Link to="/library/playlists" history={history} className="sidebar__menu__item" activeClassName="sidebar__menu__item--active">
<Icon name="queue_music" type="material" />
Playlists
{content('sidebar.playlists')}
</Link>
<Link to="/library/artists" history={history} className="sidebar__menu__item" activeClassName="sidebar__menu__item--active">
<Icon name="recent_actors" type="material" />
Artists
{content('sidebar.artists')}
</Link>
<Link to="/library/albums" history={history} className="sidebar__menu__item" activeClassName="sidebar__menu__item--active">
<Icon name="album" type="material" />
Albums
{content('sidebar.albums')}
</Link>
<Link to="/library/tracks" history={history} className="sidebar__menu__item" activeClassName="sidebar__menu__item--active">
<Icon name="music_note" type="material" />
Tracks
{content('sidebar.tracks')}
</Link>
<Link to="/library/browse" history={history} className="sidebar__menu__item" activeClassName="sidebar__menu__item--active">
<Icon name="folder" type="material" />
Browse
{content('sidebar.browse')}
</Link>
</section>
<section className="sidebar__menu__section">
<Link to="/settings" history={history} className="sidebar__menu__item" activeClassName="sidebar__menu__item--active">
<Icon name="settings" type="material" />
Settings
{content('sidebar.settings')}
{this.renderStatusIcon()}
</Link>
</section>

3
src/js/locale/de.yaml Executable file
View File

@ -0,0 +1,3 @@
sidebar:
now_playing: GERMAN
search: GERMAN

12
src/js/locale/dictionaries.js Executable file
View File

@ -0,0 +1,12 @@
import en from './en.yaml';
import de from './de.yaml';
export default {
en,
de,
};
export {
en,
de,
};

25
src/js/locale/en.yaml Executable file
View File

@ -0,0 +1,25 @@
sidebar:
now_playing: Now playing
search: Search
discover: Discover
genre: Genre / Mood
featured_playlists: Featured playlists
new_releases: New releases
my_music: My music
playlists: Playlists
artists: Artists
albums: Albums
tracks: Tracks
browse: Browse
settings: Settings
not_connected: %{name} not connected
now_playing:
title: Now playing
context_actions:
radio: Radio
history: History
add_uri: Add URI
current_track:
playing_from: Playling from
shuffle: Shuffle
clear: Clear

54
src/js/locale/index.js Executable file
View File

@ -0,0 +1,54 @@
import React, { Fragment } from 'react';
import { useSelector } from 'react-redux';
import get from 'lodash/get';
import dictionaries from './dictionaries';
import { titleCase } from '../util/helpers';
const PARAMS_REG_EXP = '%{(.*?)}';
const paramsRegExp = new RegExp(PARAMS_REG_EXP, 'g');
const content = (path, params = {}, transform, dictionary) => {
let value = get((dictionary || dictionaries.en), path, '');
value = value.replace(
paramsRegExp,
(replaceText, key) => params.hasOwnProperty(key) ? params[key] : '',
);
switch (transform) {
case 'upper':
value = value.toUpperCase();
break;
case 'lower':
value = value.toLowerCase();
break;
case 'title':
value = titleCase(value);
break;
default:
break;
}
return value;
};
const Content = ({ path, params = {}, transform, children }) => {
const language = useSelector((state) => state.ui.language);
const dictionary = dictionaries[language];
return (
<Fragment>
{content(path, params, transform, dictionary)}
{children}
</Fragment>
);
}
export default {
Content,
content,
};
export {
Content,
content,
};

View File

@ -268,6 +268,7 @@ export function reorderPlaylistTracks(uri, indexes, insert_before, snapshot_id =
};
case 'm3u':
case 'gmusic':
return {
type: 'MOPIDY_REORDER_PLAYLIST_TRACKS',
key: uri,
@ -275,6 +276,12 @@ export function reorderPlaylistTracks(uri, indexes, insert_before, snapshot_id =
range_length: range.length,
insert_before,
};
default:
return {
type: 'UNSUPPORTED_ACTION',
name: 'reorderPlaylistTracks',
};
}
}
@ -292,13 +299,19 @@ export function savePlaylist(uri, name, description = '', is_public = false, is_
};
case 'm3u':
case 'gmusic':
return {
type: 'MOPIDY_SAVE_PLAYLIST',
key: uri,
name,
};
default:
return {
type: 'UNSUPPORTED_ACTION',
name: 'savePlaylist',
};
}
return false;
}
export function createPlaylist(scheme, name, description = '', is_public = false, is_collaborative = false) {
@ -312,7 +325,6 @@ export function createPlaylist(scheme, name, description = '', is_public = false
default:
return mopidyActions.createPlaylist(name, scheme);
}
return false;
}
export function deletePlaylist(uri) {
@ -323,7 +335,6 @@ export function deletePlaylist(uri) {
default:
return mopidyActions.deletePlaylist(uri);
}
return false;
}
export function removeTracksFromPlaylist(uri, tracks_indexes) {
@ -336,11 +347,18 @@ export function removeTracksFromPlaylist(uri, tracks_indexes) {
};
case 'm3u':
case 'gmusic':
return {
type: 'MOPIDY_REMOVE_PLAYLIST_TRACKS',
key: uri,
tracks_indexes,
};
default:
return {
type: 'UNSUPPORTED_ACTION',
name: 'removeTracksFromPlaylist',
};
}
}
@ -354,11 +372,18 @@ export function addTracksToPlaylist(uri, tracks_uris) {
};
case 'm3u':
case 'gmusic':
return {
type: 'MOPIDY_ADD_PLAYLIST_TRACKS',
key: uri,
tracks_uris,
};
default:
return {
type: 'UNSUPPORTED_ACTION',
name: 'addTracksToPlaylist',
};
}
}

View File

@ -13,6 +13,7 @@ import {
formatPlaylist,
formatUser,
} from '../../util/format';
import { handleException } from './actions';
const coreActions = require('./actions.js');
const uiActions = require('../ui/actions.js');
@ -24,35 +25,38 @@ const CoreMiddleware = (function () {
* The actual middleware inteceptor
* */
return (store) => (next) => (action = {}) => {
const { core } = store.getState();
const {
core,
ui,
mopidy,
spotify,
} = store.getState();
switch (action.type) {
case 'HANDLE_EXCEPTION':
// Construct meaningful message and description
var { message } = action;
if (action.description) {
var { description } = action;
} else if (action.data.xhr && action.data.xhr.responseText) {
const xhr_response = JSON.parse(action.data.xhr.responseText);
if (xhr_response.error && xhr_response.error.message) {
var description = xhr_response.error.message;
}
} else if (action.data.xhr) {
var description = `${action.data.xhr.status} ${action.data.xhr.statusText}`;
} else {
var description = null;
}
// Prepare a summary dump of our state
var state = store.getState();
var exported_state = {
const state = store.getState();
const exported_state = {
core: { ...state.core },
ui: { ...state.ui },
spotify: { ...state.spotify },
mopidy: { ...state.mopidy },
pusher: { ...state.pusher },
};
const { message } = action;
let { description } = action;
// Construct meaningful message and description
if (!description) {
if (action.data.xhr && action.data.xhr.responseText) {
const xhr_response = JSON.parse(action.data.xhr.responseText);
if (xhr_response.error && xhr_response.error.message) {
description = xhr_response.error.message;
}
} else if (action.data.xhr) {
description = `${action.data.xhr.status} ${action.data.xhr.statusText}`;
}
}
// Strip out non-essential store info
delete exported_state.core.albums;
@ -69,7 +73,7 @@ const CoreMiddleware = (function () {
delete exported_state.mopidy.library_artists;
delete exported_state.mopidy.library_playlists;
let data = {
const data = {
...action.data,
message,
description,
@ -77,7 +81,7 @@ const CoreMiddleware = (function () {
};
// Log with Analytics
if (store.getState().ui.allow_reporting) {
if (ui.allow_reporting) {
ReactGA.event({
category: 'Error',
action: message,
@ -94,88 +98,85 @@ const CoreMiddleware = (function () {
break;
case 'UNSUPPORTED_ACTION':
store.dispatch(handleException(
`Action failed (${action.name})`,
{ description: 'Not supported on this type of object' },
));
break;
case 'PLAY_PLAYLIST':
if (store.getState().ui.allow_reporting) {
if (ui.allow_reporting) {
ReactGA.event({ category: 'Playlist', action: 'Play', label: action.uri });
}
next(action);
break;
case 'SAVE_PLAYLIST':
if (store.getState().ui.allow_reporting) {
if (ui.allow_reporting) {
ReactGA.event({ category: 'Playlist', action: 'Save', label: action.key });
}
next(action);
break;
case 'CREATE_PLAYLIST':
if (store.getState().ui.allow_reporting) {
if (ui.allow_reporting) {
ReactGA.event({ category: 'Playlist', action: 'Create', label: +action.name });
}
next(action);
break;
case 'REORDER_PLAYLIST_TRACKS':
if (store.getState().ui.allow_reporting) {
if (ui.allow_reporting) {
ReactGA.event({ category: 'Playlist', action: 'Reorder tracks', label: action.key });
}
next(action);
break;
case 'ADD_PLAYLIST_TRACKS':
if (store.getState().ui.allow_reporting) {
if (ui.allow_reporting) {
ReactGA.event({ category: 'Playlist', action: 'Add tracks', label: action.playlist_uri });
}
next(action);
break;
case 'REMOVE_PLAYLIST_TRACKS':
if (store.getState().ui.allow_reporting) {
if (ui.allow_reporting) {
ReactGA.event({ category: 'Playlist', action: 'Remove tracks', label: action.playlist_uri });
}
next(action);
break;
case 'DELETE_PLAYLIST':
if (store.getState().ui.allow_reporting) {
if (ui.allow_reporting) {
ReactGA.event({ category: 'Playlist', action: 'Delete', label: action.uri });
}
next(action);
break;
case 'SEARCH_STARTED':
if (store.getState().ui.allow_reporting) {
if (ui.allow_reporting) {
ReactGA.event({ category: 'Search', action: 'Started', label: `${action.type}: ${action.query}` });
}
next(action);
var state = store.getState();
if (state.ui.search_uri_schemes) {
var uri_schemes = state.ui.search_uri_schemes;
} else {
var { uri_schemes } = state.mopidy;
}
// backends that can handle more than just track results
// make sure they are available and respect our settings
var available_full_uri_schemes = ['local:', 'file:', 'gmusic:'];
var full_uri_schemes = [];
for (var i = 0; i < available_full_uri_schemes.length; i++) {
const index = uri_schemes.indexOf(available_full_uri_schemes[i]);
if (index > -1) {
full_uri_schemes.push(available_full_uri_schemes[i]);
}
}
const uri_schemes = ui.search_uri_schemes || mopidy.uri_schemes;
const available_full_uri_schemes = ['local:', 'file:', 'gmusic:'];
const full_uri_schemes = available_full_uri_schemes.filter(
(full_uri_scheme) => uri_schemes.indexOf(full_uri_scheme) > -1
);
// initiate spotify searching
if (!action.only_mopidy) {
if (!state.ui.search_settings || state.ui.search_settings.spotify) {
if (!ui.search_settings || ui.search_settings.spotify) {
store.dispatch(spotifyActions.getSearchResults(action.query));
}
}
// backend searching (mopidy)
if (state.mopidy.connected) {
if (mopidy.connected) {
store.dispatch(
mopidyActions.getSearchResults(action.search_type, action.query, 100, full_uri_schemes),
);
@ -185,7 +186,7 @@ const CoreMiddleware = (function () {
// Get assets from all of our providers
case 'GET_LIBRARY_PLAYLISTS':
if (store.getState().spotify.connected) {
if (spotify.connected) {
store.dispatch(spotifyActions.getLibraryPlaylists());
}
if (store.getState().mopidy.connected) {
@ -196,7 +197,7 @@ const CoreMiddleware = (function () {
// Get assets from all of our providers
case 'GET_LIBRARY_ALBUMS':
if (store.getState().spotify.connected) {
if (spotify.connected) {
store.dispatch(spotifyActions.getLibraryAlbums());
}
if (store.getState().mopidy.connected) {
@ -207,7 +208,7 @@ const CoreMiddleware = (function () {
// Get assets from all of our providers
case 'GET_LIBRARY_ARTISTS':
if (store.getState().spotify.connected) {
if (spotify.connected) {
store.dispatch(spotifyActions.getLibraryArtists());
}
if (store.getState().mopidy.connected) {
@ -224,15 +225,14 @@ const CoreMiddleware = (function () {
* Playlist manipulation
* */
case 'PLAYLIST_TRACKS':
var tracks = formatTracks(action.tracks);
action.tracks_uris = arrayOf('uri', tracks);
const tracks = formatTracks(action.tracks);
store.dispatch({
type: 'TRACKS_LOADED',
tracks,
});
next(action);
next({ ...action, tracks_uris: arrayOf('uri', tracks) });
break;
case 'PLAYLIST_TRACKS_ADDED':
@ -334,7 +334,7 @@ const CoreMiddleware = (function () {
case 'spotify':
store.dispatch(spotifyActions.getTrack(action.uri));
if (store.getState().spotify.me) {
if (spotify.me) {
store.dispatch(spotifyActions.following(action.uri));
}
break;
@ -362,7 +362,7 @@ const CoreMiddleware = (function () {
case 'spotify':
store.dispatch(spotifyActions.getAlbum(action.uri));
if (store.getState().spotify.me) {
if (spotify.me) {
store.dispatch(spotifyActions.following(action.uri));
}
break;
@ -391,7 +391,7 @@ const CoreMiddleware = (function () {
case 'spotify':
store.dispatch(spotifyActions.getArtist(action.uri, true));
if (store.getState().spotify.me) {
if (spotify.me) {
store.dispatch(spotifyActions.following(action.uri));
}
break;
@ -420,7 +420,7 @@ const CoreMiddleware = (function () {
case 'spotify':
store.dispatch(spotifyActions.getPlaylist(action.uri));
if (store.getState().spotify.me) {
if (spotify.me) {
store.dispatch(spotifyActions.following(action.uri));
}
break;
@ -448,7 +448,7 @@ const CoreMiddleware = (function () {
case 'spotify':
store.dispatch(spotifyActions.getUser(action.uri));
if (store.getState().spotify.me) {
if (spotify.me) {
store.dispatch(spotifyActions.following(action.uri));
}
break;
@ -667,8 +667,8 @@ const CoreMiddleware = (function () {
break;
case 'spotify':
if (store.getState().spotify.authorization && store.getState().spotify.me) {
playlist.can_edit = (playlist.owner.id == store.getState().spotify.me.id);
if (spotify.authorization && spotify.me) {
playlist.can_edit = (playlist.owner.id == spotify.me.id);
}
}

View File

@ -43,6 +43,7 @@ let state = {
http_streaming_url: `http://${window.location.hostname}:8000/mopidy`,
},
ui: {
language: 'en',
theme: 'auto',
smooth_scrolling_enabled: true,
hotkeys_enabled: true,

View File

@ -20,6 +20,7 @@ import {
getFromUri,
uriType,
} from '../util/helpers';
import { content } from '../locale';
class Queue extends React.Component {
constructor(props) {
@ -243,7 +244,7 @@ class Queue extends React.Component {
<div className="view queue-view preserve-3d">
<Header options={options} uiActions={this.props.uiActions}>
<Icon name="play_arrow" type="material" />
Now playing
{content('now_playing.title')}
</Header>
{theme === 'dark' && <Parallax image={current_track_image} blur />}
<div className="content-wrapper">

View File

@ -8,6 +8,7 @@ import PusherConnectionList from '../components/PusherConnectionList';
import SourcesPriority from '../components/Fields/SourcesPriority';
import Commands from '../components/Fields/Commands';
import TextField from '../components/Fields/TextField';
import SelectField from '../components/Fields/SelectField';
import Header from '../components/Header';
import Icon from '../components/Icon';
import Services from '../components/Services';
@ -49,6 +50,11 @@ class Settings extends React.Component {
if (new_username) this.setState({ pusher_username: new_username });
}
onLanguageChange = (language) => {
const { uiActions: { set } } = this.props;
set({ language });
}
resetAllSettings() {
localStorage.clear();
window.location = '#';
@ -178,6 +184,20 @@ class Settings extends React.Component {
Interface
<a name="interface" />
</h4>
<div className="field dropdown">
<div className="name">Language</div>
<div className="input">
<SelectField
onChange={this.onLanguageChange}
options={[
{ value: 'en', label: 'English (EN)' },
{ value: 'de', label: 'German (DE)' },
]}
value={ui.language}
/>
</div>
</div>
<div className="field radio">
<div className="name">

View File

@ -56,6 +56,11 @@ const config = {
]
},
{
test: /\.ya?ml$/,
type: 'json',
use: 'yaml-loader'
},
{
// load external resources (ie Google fonts)
test: /.(gif|png|woff(2)?|eot|ttf|svg)(\?[a-z0-9=\.]+)?$/,
use: [