diff --git a/webapp_frontend/package-lock.json b/webapp_frontend/package-lock.json
index 3409c4ab..c2431845 100644
--- a/webapp_frontend/package-lock.json
+++ b/webapp_frontend/package-lock.json
@@ -1782,6 +1782,12 @@
"resolved": "https://registry.npmjs.org/@sheerun/mutationobserver-shim/-/mutationobserver-shim-0.3.3.tgz",
"integrity": "sha512-DetpxZw1fzPD5xUBrIAoplLChO2VB8DlL5Gg+I1IR9b2wPqYIca2WSUxL5g1vLeR4MsQq1NeWriXAVffV+U1Fw=="
},
+ "@sindresorhus/is": {
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.7.0.tgz",
+ "integrity": "sha512-ONhaKPIufzzrlNbqtWFFd+jlnemX6lJAgq9ZeiZtS7I1PIf/la7CW4m83rTXRnVnsMbW2k56pGYu7AUFJD9Pow==",
+ "dev": true
+ },
"@storybook/addon-actions": {
"version": "6.0.28",
"resolved": "https://registry.npmjs.org/@storybook/addon-actions/-/addon-actions-6.0.28.tgz",
@@ -6558,6 +6564,15 @@
}
}
},
+ "ansi-gray": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/ansi-gray/-/ansi-gray-0.1.1.tgz",
+ "integrity": "sha1-KWLPVOyXksSFEKPetSRDaGHvclE=",
+ "dev": true,
+ "requires": {
+ "ansi-wrap": "0.1.0"
+ }
+ },
"ansi-html": {
"version": "0.0.7",
"resolved": "https://registry.npmjs.org/ansi-html/-/ansi-html-0.0.7.tgz",
@@ -6593,6 +6608,12 @@
}
}
},
+ "ansi-wrap": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/ansi-wrap/-/ansi-wrap-0.1.0.tgz",
+ "integrity": "sha1-qCJQ3bABXponyoLoLqYDu/pF768=",
+ "dev": true
+ },
"anymatch": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz",
@@ -6613,6 +6634,23 @@
"resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz",
"integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw=="
},
+ "archive-type": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/archive-type/-/archive-type-4.0.0.tgz",
+ "integrity": "sha1-+S5yIzBW38aWlHJ0nCZ72wRrHXA=",
+ "dev": true,
+ "requires": {
+ "file-type": "^4.2.0"
+ },
+ "dependencies": {
+ "file-type": {
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/file-type/-/file-type-4.4.0.tgz",
+ "integrity": "sha1-G2AOX8ofvcboDApwxxyNul95BsU=",
+ "dev": true
+ }
+ }
+ },
"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",
@@ -7740,6 +7778,16 @@
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.1.0.tgz",
"integrity": "sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ=="
},
+ "bl": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.3.tgz",
+ "integrity": "sha512-pvcNpa0UU69UT341rO6AYy4FVAIkUHuZXRIWbq+zHnsVcRzDDjIAhGuuYoi0d//cwIwtt4pkpKycWEfjdV+vww==",
+ "dev": true,
+ "requires": {
+ "readable-stream": "^2.3.5",
+ "safe-buffer": "^5.1.1"
+ }
+ },
"block-stream": {
"version": "0.0.9",
"resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz",
@@ -8109,6 +8157,34 @@
"isarray": "^1.0.0"
}
},
+ "buffer-alloc": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz",
+ "integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==",
+ "dev": true,
+ "requires": {
+ "buffer-alloc-unsafe": "^1.1.0",
+ "buffer-fill": "^1.0.0"
+ }
+ },
+ "buffer-alloc-unsafe": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz",
+ "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==",
+ "dev": true
+ },
+ "buffer-crc32": {
+ "version": "0.2.13",
+ "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz",
+ "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=",
+ "dev": true
+ },
+ "buffer-fill": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz",
+ "integrity": "sha1-+PeLdniYiO858gXNY39o5wISKyw=",
+ "dev": true
+ },
"buffer-from": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
@@ -8190,6 +8266,72 @@
"unset-value": "^1.0.0"
}
},
+ "cacheable-request": {
+ "version": "2.1.4",
+ "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-2.1.4.tgz",
+ "integrity": "sha1-DYCIAbY0KtM8kd+dC0TcCbkeXD0=",
+ "dev": true,
+ "requires": {
+ "clone-response": "1.0.2",
+ "get-stream": "3.0.0",
+ "http-cache-semantics": "3.8.1",
+ "keyv": "3.0.0",
+ "lowercase-keys": "1.0.0",
+ "normalize-url": "2.0.1",
+ "responselike": "1.0.2"
+ },
+ "dependencies": {
+ "get-stream": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz",
+ "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=",
+ "dev": true
+ },
+ "lowercase-keys": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.0.tgz",
+ "integrity": "sha1-TjNms55/VFfjXxMkvfb4jQv8cwY=",
+ "dev": true
+ },
+ "normalize-url": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-2.0.1.tgz",
+ "integrity": "sha512-D6MUW4K/VzoJ4rJ01JFKxDrtY1v9wrgzCX5f2qj/lzH1m/lW6MhUZFKerVsnyjOhOsYzI9Kqqak+10l4LvLpMw==",
+ "dev": true,
+ "requires": {
+ "prepend-http": "^2.0.0",
+ "query-string": "^5.0.1",
+ "sort-keys": "^2.0.0"
+ }
+ },
+ "prepend-http": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz",
+ "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=",
+ "dev": true
+ },
+ "query-string": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/query-string/-/query-string-5.1.1.tgz",
+ "integrity": "sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw==",
+ "dev": true,
+ "requires": {
+ "decode-uri-component": "^0.2.0",
+ "object-assign": "^4.1.0",
+ "strict-uri-encode": "^1.0.0"
+ }
+ },
+ "sort-keys": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-2.0.0.tgz",
+ "integrity": "sha1-ZYU1WEhh7JfXMNbPQYIuH1ZoQSg=",
+ "dev": true,
+ "requires": {
+ "is-plain-obj": "^1.0.0"
+ }
+ }
+ }
+ },
"call-bind": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.0.tgz",
@@ -8288,6 +8430,18 @@
"resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
"integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw="
},
+ "caw": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/caw/-/caw-2.0.1.tgz",
+ "integrity": "sha512-Cg8/ZSBEa8ZVY9HspcGUYaK63d/bN7rqS3CYCzEGUxuYv6UlmcjzDUz2fCFFHyTvUW5Pk0I+3hkA3iXlIj6guA==",
+ "dev": true,
+ "requires": {
+ "get-proxy": "^2.0.0",
+ "isurl": "^1.0.0-alpha5",
+ "tunnel-agent": "^0.6.0",
+ "url-to-options": "^1.0.1"
+ }
+ },
"ccount": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/ccount/-/ccount-1.1.0.tgz",
@@ -8582,6 +8736,15 @@
"shallow-clone": "^0.1.2"
}
},
+ "clone-response": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz",
+ "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=",
+ "dev": true,
+ "requires": {
+ "mimic-response": "^1.0.0"
+ }
+ },
"clsx": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/clsx/-/clsx-1.1.1.tgz",
@@ -8653,6 +8816,12 @@
"simple-swizzle": "^0.2.2"
}
},
+ "color-support": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz",
+ "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==",
+ "dev": true
+ },
"colorette": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.1.tgz",
@@ -8760,6 +8929,16 @@
"typedarray": "^0.0.6"
}
},
+ "config-chain": {
+ "version": "1.1.12",
+ "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.12.tgz",
+ "integrity": "sha512-a1eOIcu8+7lUInge4Rpf/n4Krkf3Dd9lqhljRzII1/Zno/kRtUWnznPO3jOKBmTEktkt3fkxisUcivoj0ebzoA==",
+ "dev": true,
+ "requires": {
+ "ini": "^1.3.4",
+ "proto-list": "~1.2.1"
+ }
+ },
"confusing-browser-globals": {
"version": "1.0.10",
"resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.10.tgz",
@@ -9310,6 +9489,139 @@
"resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz",
"integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU="
},
+ "decompress": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/decompress/-/decompress-4.2.1.tgz",
+ "integrity": "sha512-e48kc2IjU+2Zw8cTb6VZcJQ3lgVbS4uuB1TfCHbiZIP/haNXm+SVyhu+87jts5/3ROpd82GSVCoNs/z8l4ZOaQ==",
+ "dev": true,
+ "requires": {
+ "decompress-tar": "^4.0.0",
+ "decompress-tarbz2": "^4.0.0",
+ "decompress-targz": "^4.0.0",
+ "decompress-unzip": "^4.0.1",
+ "graceful-fs": "^4.1.10",
+ "make-dir": "^1.0.0",
+ "pify": "^2.3.0",
+ "strip-dirs": "^2.0.0"
+ },
+ "dependencies": {
+ "make-dir": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz",
+ "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==",
+ "dev": true,
+ "requires": {
+ "pify": "^3.0.0"
+ },
+ "dependencies": {
+ "pify": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
+ "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=",
+ "dev": true
+ }
+ }
+ }
+ }
+ },
+ "decompress-response": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz",
+ "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=",
+ "dev": true,
+ "requires": {
+ "mimic-response": "^1.0.0"
+ }
+ },
+ "decompress-tar": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/decompress-tar/-/decompress-tar-4.1.1.tgz",
+ "integrity": "sha512-JdJMaCrGpB5fESVyxwpCx4Jdj2AagLmv3y58Qy4GE6HMVjWz1FeVQk1Ct4Kye7PftcdOo/7U7UKzYBJgqnGeUQ==",
+ "dev": true,
+ "requires": {
+ "file-type": "^5.2.0",
+ "is-stream": "^1.1.0",
+ "tar-stream": "^1.5.2"
+ },
+ "dependencies": {
+ "file-type": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/file-type/-/file-type-5.2.0.tgz",
+ "integrity": "sha1-LdvqfHP/42No365J3DOMBYwritY=",
+ "dev": true
+ }
+ }
+ },
+ "decompress-tarbz2": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/decompress-tarbz2/-/decompress-tarbz2-4.1.1.tgz",
+ "integrity": "sha512-s88xLzf1r81ICXLAVQVzaN6ZmX4A6U4z2nMbOwobxkLoIIfjVMBg7TeguTUXkKeXni795B6y5rnvDw7rxhAq9A==",
+ "dev": true,
+ "requires": {
+ "decompress-tar": "^4.1.0",
+ "file-type": "^6.1.0",
+ "is-stream": "^1.1.0",
+ "seek-bzip": "^1.0.5",
+ "unbzip2-stream": "^1.0.9"
+ },
+ "dependencies": {
+ "file-type": {
+ "version": "6.2.0",
+ "resolved": "https://registry.npmjs.org/file-type/-/file-type-6.2.0.tgz",
+ "integrity": "sha512-YPcTBDV+2Tm0VqjybVd32MHdlEGAtuxS3VAYsumFokDSMG+ROT5wawGlnHDoz7bfMcMDt9hxuXvXwoKUx2fkOg==",
+ "dev": true
+ }
+ }
+ },
+ "decompress-targz": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/decompress-targz/-/decompress-targz-4.1.1.tgz",
+ "integrity": "sha512-4z81Znfr6chWnRDNfFNqLwPvm4db3WuZkqV+UgXQzSngG3CEKdBkw5jrv3axjjL96glyiiKjsxJG3X6WBZwX3w==",
+ "dev": true,
+ "requires": {
+ "decompress-tar": "^4.1.1",
+ "file-type": "^5.2.0",
+ "is-stream": "^1.1.0"
+ },
+ "dependencies": {
+ "file-type": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/file-type/-/file-type-5.2.0.tgz",
+ "integrity": "sha1-LdvqfHP/42No365J3DOMBYwritY=",
+ "dev": true
+ }
+ }
+ },
+ "decompress-unzip": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/decompress-unzip/-/decompress-unzip-4.0.1.tgz",
+ "integrity": "sha1-3qrM39FK6vhVePczroIQ+bSEj2k=",
+ "dev": true,
+ "requires": {
+ "file-type": "^3.8.0",
+ "get-stream": "^2.2.0",
+ "pify": "^2.3.0",
+ "yauzl": "^2.4.2"
+ },
+ "dependencies": {
+ "file-type": {
+ "version": "3.9.0",
+ "resolved": "https://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz",
+ "integrity": "sha1-JXoHg4TR24CHvESdEH1SpSZyuek=",
+ "dev": true
+ },
+ "get-stream": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-2.3.1.tgz",
+ "integrity": "sha1-Xzj5PzRgCWZu4BUKBUFn+Rvdld4=",
+ "dev": true,
+ "requires": {
+ "object-assign": "^4.0.1",
+ "pinkie-promise": "^2.0.0"
+ }
+ }
+ }
+ },
"dedent": {
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz",
@@ -9737,11 +10049,60 @@
"dotenv-defaults": "^1.0.2"
}
},
+ "download": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/download/-/download-7.1.0.tgz",
+ "integrity": "sha512-xqnBTVd/E+GxJVrX5/eUJiLYjCGPwMpdL+jGhGU57BvtcA7wwhtHVbXBeUk51kOpW3S7Jn3BQbN9Q1R1Km2qDQ==",
+ "dev": true,
+ "requires": {
+ "archive-type": "^4.0.0",
+ "caw": "^2.0.1",
+ "content-disposition": "^0.5.2",
+ "decompress": "^4.2.0",
+ "ext-name": "^5.0.0",
+ "file-type": "^8.1.0",
+ "filenamify": "^2.0.0",
+ "get-stream": "^3.0.0",
+ "got": "^8.3.1",
+ "make-dir": "^1.2.0",
+ "p-event": "^2.1.0",
+ "pify": "^3.0.0"
+ },
+ "dependencies": {
+ "get-stream": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz",
+ "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=",
+ "dev": true
+ },
+ "make-dir": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz",
+ "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==",
+ "dev": true,
+ "requires": {
+ "pify": "^3.0.0"
+ }
+ },
+ "pify": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
+ "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=",
+ "dev": true
+ }
+ }
+ },
"duplexer": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz",
"integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg=="
},
+ "duplexer3": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz",
+ "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=",
+ "dev": true
+ },
"duplexify": {
"version": "3.7.1",
"resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz",
@@ -10455,9 +10816,9 @@
}
},
"eslint-plugin-react-hooks": {
- "version": "1.7.0",
- "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-1.7.0.tgz",
- "integrity": "sha512-iXTCFcOmlWvw4+TOE8CLWj6yX1GwzT0Y6cUfHHZqWnSk144VmVIRcVGtUAzrLES7C798lmvnt02C7rxaOX1HNA=="
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.2.0.tgz",
+ "integrity": "sha512-623WEiZJqxR7VdxFCKLI6d6LLpwJkGPYKODnkH3D7WpOG5KM8yWueBd8TLsNAetEJNF5iJmolaAKO3F8yzyVBQ=="
},
"eslint-scope": {
"version": "5.1.1",
@@ -10741,6 +11102,25 @@
}
}
},
+ "ext-list": {
+ "version": "2.2.2",
+ "resolved": "https://registry.npmjs.org/ext-list/-/ext-list-2.2.2.tgz",
+ "integrity": "sha512-u+SQgsubraE6zItfVA0tBuCBhfU9ogSRnsvygI7wht9TS510oLkBRXBsqopeUG/GBOIQyKZO9wjTqIu/sf5zFA==",
+ "dev": true,
+ "requires": {
+ "mime-db": "^1.28.0"
+ }
+ },
+ "ext-name": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/ext-name/-/ext-name-5.0.0.tgz",
+ "integrity": "sha512-yblEwXAbGv1VQDmow7s38W77hzAgJAO50ztBLMcUyUBfxv1HC+LGwtiEN+Co6LtlqT/5uwVOxsD4TNIilWhwdQ==",
+ "dev": true,
+ "requires": {
+ "ext-list": "^2.0.0",
+ "sort-keys-length": "^1.0.0"
+ }
+ },
"extend": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
@@ -10844,6 +11224,18 @@
"resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
"integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU="
},
+ "fancy-log": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/fancy-log/-/fancy-log-1.3.3.tgz",
+ "integrity": "sha512-k9oEhlyc0FrVh25qYuSELjr8oxsCoc4/LEZfg2iJJrfEk/tZL9bCoJE47gqAvI2m/AUjluCS4+3I0eTx8n3AEw==",
+ "dev": true,
+ "requires": {
+ "ansi-gray": "^0.1.1",
+ "color-support": "^1.1.3",
+ "parse-node-version": "^1.0.0",
+ "time-stamp": "^1.0.0"
+ }
+ },
"fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
@@ -10924,6 +11316,15 @@
"bser": "2.1.1"
}
},
+ "fd-slicer": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz",
+ "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=",
+ "dev": true,
+ "requires": {
+ "pend": "~1.2.0"
+ }
+ },
"figgy-pudding": {
"version": "3.5.2",
"resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.2.tgz",
@@ -10989,6 +11390,12 @@
}
}
},
+ "file-type": {
+ "version": "8.1.0",
+ "resolved": "https://registry.npmjs.org/file-type/-/file-type-8.1.0.tgz",
+ "integrity": "sha512-qyQ0pzAy78gVoJsmYeNgl8uH8yKhr1lVhW7JbzJmnlRi0I4R2eEDEJZVKG8agpDnLpacwNbDhLNG/LMdxHD2YQ==",
+ "dev": true
+ },
"filelist": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.1.tgz",
@@ -10998,6 +11405,23 @@
"minimatch": "^3.0.4"
}
},
+ "filename-reserved-regex": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-2.0.0.tgz",
+ "integrity": "sha1-q/c9+rc10EVECr/qLZHzieu/oik=",
+ "dev": true
+ },
+ "filenamify": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/filenamify/-/filenamify-2.1.0.tgz",
+ "integrity": "sha512-ICw7NTT6RsDp2rnYKVd8Fu4cr6ITzGy3+u4vUujPkabyaz+03F24NWEX7fs5fp+kBonlaqPH8fAO2NM+SXt/JA==",
+ "dev": true,
+ "requires": {
+ "filename-reserved-regex": "^2.0.0",
+ "strip-outer": "^1.0.0",
+ "trim-repeated": "^1.0.0"
+ }
+ },
"filesize": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/filesize/-/filesize-6.0.1.tgz",
@@ -11198,6 +11622,12 @@
"readable-stream": "^2.0.0"
}
},
+ "fs-constants": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
+ "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==",
+ "dev": true
+ },
"fs-extra": {
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz",
@@ -11336,6 +11766,15 @@
"integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==",
"dev": true
},
+ "get-proxy": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/get-proxy/-/get-proxy-2.1.0.tgz",
+ "integrity": "sha512-zmZIaQTWnNQb4R4fJUEp/FC51eZsc6EkErspy3xtIYStaq8EB/hDIWipxsal+E8rz0qD7f2sL/NA9Xee4RInJw==",
+ "dev": true,
+ "requires": {
+ "npm-conf": "^1.1.0"
+ }
+ },
"get-stdin": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz",
@@ -11550,6 +11989,45 @@
"delegate": "^3.1.2"
}
},
+ "got": {
+ "version": "8.3.2",
+ "resolved": "https://registry.npmjs.org/got/-/got-8.3.2.tgz",
+ "integrity": "sha512-qjUJ5U/hawxosMryILofZCkm3C84PLJS/0grRIpjAwu+Lkxxj5cxeCU25BG0/3mDSpXKTyZr8oh8wIgLaH0QCw==",
+ "dev": true,
+ "requires": {
+ "@sindresorhus/is": "^0.7.0",
+ "cacheable-request": "^2.1.1",
+ "decompress-response": "^3.3.0",
+ "duplexer3": "^0.1.4",
+ "get-stream": "^3.0.0",
+ "into-stream": "^3.1.0",
+ "is-retry-allowed": "^1.1.0",
+ "isurl": "^1.0.0-alpha5",
+ "lowercase-keys": "^1.0.0",
+ "mimic-response": "^1.0.0",
+ "p-cancelable": "^0.4.0",
+ "p-timeout": "^2.0.1",
+ "pify": "^3.0.0",
+ "safe-buffer": "^5.1.1",
+ "timed-out": "^4.0.1",
+ "url-parse-lax": "^3.0.0",
+ "url-to-options": "^1.0.1"
+ },
+ "dependencies": {
+ "get-stream": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz",
+ "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=",
+ "dev": true
+ },
+ "pify": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
+ "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=",
+ "dev": true
+ }
+ }
+ },
"graceful-fs": {
"version": "4.2.4",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz",
@@ -11634,11 +12112,26 @@
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
"integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0="
},
+ "has-symbol-support-x": {
+ "version": "1.4.2",
+ "resolved": "https://registry.npmjs.org/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz",
+ "integrity": "sha512-3ToOva++HaW+eCpgqZrCfN51IPB+7bJNVT6CUATzueB5Heb8o6Nam0V3HG5dlDvZU1Gn5QLcbahiKw/XVk5JJw==",
+ "dev": true
+ },
"has-symbols": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz",
"integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg=="
},
+ "has-to-string-tag-x": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/has-to-string-tag-x/-/has-to-string-tag-x-1.4.1.tgz",
+ "integrity": "sha512-vdbKfmw+3LoOYVr+mtxHaX5a96+0f3DljYd8JOqvOLsf5mw2Otda2qCDT9qRqLAhrjyQ0h7ual5nOiASpsGNFw==",
+ "dev": true,
+ "requires": {
+ "has-symbol-support-x": "^1.4.1"
+ }
+ },
"has-unicode": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
@@ -12000,6 +12493,12 @@
}
}
},
+ "http-cache-semantics": {
+ "version": "3.8.1",
+ "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz",
+ "integrity": "sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w==",
+ "dev": true
+ },
"http-deceiver": {
"version": "1.2.7",
"resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz",
@@ -12311,6 +12810,16 @@
"integrity": "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==",
"dev": true
},
+ "into-stream": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/into-stream/-/into-stream-3.1.0.tgz",
+ "integrity": "sha1-lvsKk2wSur1v8XUqF9BWFqvQlMY=",
+ "dev": true,
+ "requires": {
+ "from2": "^2.1.1",
+ "p-is-promise": "^1.1.0"
+ }
+ },
"invariant": {
"version": "2.2.4",
"resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
@@ -12530,6 +13039,12 @@
"integrity": "sha512-T/S49scO8plUiAOA2DBTBG3JHpn1yiw0kRp6dgiZ0v2/6twi5eiB0rHtHFH9ZIrvlWc6+4O+m4zg5+Z833aXgw==",
"dev": true
},
+ "is-natural-number": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/is-natural-number/-/is-natural-number-4.0.1.tgz",
+ "integrity": "sha1-q5124dtM7VHjXeDHLr7PCfc0zeg=",
+ "dev": true
+ },
"is-negative-zero": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.0.tgz",
@@ -12606,6 +13121,12 @@
"resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz",
"integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg=="
},
+ "is-retry-allowed": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz",
+ "integrity": "sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg==",
+ "dev": true
+ },
"is-root": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/is-root/-/is-root-2.1.0.tgz",
@@ -12767,6 +13288,16 @@
"html-escaper": "^2.0.0"
}
},
+ "isurl": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/isurl/-/isurl-1.0.0.tgz",
+ "integrity": "sha512-1P/yWsxPlDtn7QeRD+ULKQPaIaN6yF368GZ2vDfv0AL0NwpStafjWCDDdn0k8wgFMWpVAqG7oJhxHnlud42i9w==",
+ "dev": true,
+ "requires": {
+ "has-to-string-tag-x": "^1.2.0",
+ "is-object": "^1.0.1"
+ }
+ },
"iterate-iterator": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/iterate-iterator/-/iterate-iterator-1.0.1.tgz",
@@ -13875,6 +14406,12 @@
"resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz",
"integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA=="
},
+ "json-buffer": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz",
+ "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=",
+ "dev": true
+ },
"json-parse-better-errors": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz",
@@ -13959,6 +14496,15 @@
"object.assign": "^4.1.0"
}
},
+ "keyv": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.0.0.tgz",
+ "integrity": "sha512-eguHnq22OE3uVoSYG0LVWNP+4ppamWr9+zWBe1bsNcovIMy6huUJFPgy4mGwCd/rnl3vOLGW1MTlu4c57CT1xA==",
+ "dev": true,
+ "requires": {
+ "json-buffer": "3.0.0"
+ }
+ },
"killable": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/killable/-/killable-1.0.1.tgz",
@@ -14142,6 +14688,12 @@
"resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz",
"integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0="
},
+ "lodash.get": {
+ "version": "4.4.2",
+ "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz",
+ "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=",
+ "dev": true
+ },
"lodash.memoize": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz",
@@ -14223,6 +14775,12 @@
"tslib": "^1.10.0"
}
},
+ "lowercase-keys": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz",
+ "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==",
+ "dev": true
+ },
"lowlight": {
"version": "1.12.1",
"resolved": "https://registry.npmjs.org/lowlight/-/lowlight-1.12.1.tgz",
@@ -14546,6 +15104,12 @@
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
"integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg=="
},
+ "mimic-response": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz",
+ "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==",
+ "dev": true
+ },
"min-document": {
"version": "2.19.0",
"resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.0.tgz",
@@ -15047,6 +15611,24 @@
"sort-keys": "^1.0.0"
}
},
+ "npm-conf": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/npm-conf/-/npm-conf-1.1.3.tgz",
+ "integrity": "sha512-Yic4bZHJOt9RCFbRP3GgpqhScOY4HH3V2P8yBj6CeYq118Qr+BLXqT2JvpJ00mryLESpgOxf5XlFv4ZjXxLScw==",
+ "dev": true,
+ "requires": {
+ "config-chain": "^1.1.11",
+ "pify": "^3.0.0"
+ },
+ "dependencies": {
+ "pify": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
+ "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=",
+ "dev": true
+ }
+ }
+ },
"npm-run-path": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz",
@@ -15296,6 +15878,11 @@
}
}
},
+ "opencollective-postinstall": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/opencollective-postinstall/-/opencollective-postinstall-2.0.3.tgz",
+ "integrity": "sha512-8AV/sCtuzUeTo8gQK5qDZzARrulB3egtLzFgteqB2tcT4Mw7B8Kt7JcDHmltjz6FOAHsvTevk70gZEbhM4ZS9Q=="
+ },
"opn": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/opn/-/opn-5.5.0.tgz",
@@ -15364,6 +15951,12 @@
"integrity": "sha512-p8oHrMeRAKxXDMPI/EBNITj/zTVHKNnAnM59Im+xnoZUlV07FyTg46wom2286jJlXGGfcPFG/ba5NUiCwWNd4w==",
"dev": true
},
+ "p-cancelable": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-0.4.1.tgz",
+ "integrity": "sha512-HNa1A8LvB1kie7cERyy21VNeHb2CWJJYqyyC2o3klWFfMGlFmWv2Z7sFgZH8ZiaYL95ydToKTFVXgMV/Os0bBQ==",
+ "dev": true
+ },
"p-each-series": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-1.0.0.tgz",
@@ -15372,11 +15965,26 @@
"p-reduce": "^1.0.0"
}
},
+ "p-event": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/p-event/-/p-event-2.3.1.tgz",
+ "integrity": "sha512-NQCqOFhbpVTMX4qMe8PF8lbGtzZ+LCiN7pcNrb/413Na7+TRoe1xkKUzuWa/YEJdGQ0FvKtj35EEbDoVPO2kbA==",
+ "dev": true,
+ "requires": {
+ "p-timeout": "^2.0.1"
+ }
+ },
"p-finally": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz",
"integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4="
},
+ "p-is-promise": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-1.1.0.tgz",
+ "integrity": "sha1-nJRWmJ6fZYgBewQ01WCXZ1w9oF4=",
+ "dev": true
+ },
"p-limit": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
@@ -15414,6 +16022,15 @@
"retry": "^0.12.0"
}
},
+ "p-timeout": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-2.0.1.tgz",
+ "integrity": "sha512-88em58dDVB/KzPEx1X0N3LwFfYZPyDc4B6eF38M1rk9VTZMbxXXgjugz8mmwpS9Ox4BDZ+t6t3QP5+/gazweIA==",
+ "dev": true,
+ "requires": {
+ "p-finally": "^1.0.0"
+ }
+ },
"p-try": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
@@ -15492,6 +16109,12 @@
"error-ex": "^1.2.0"
}
},
+ "parse-node-version": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz",
+ "integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==",
+ "dev": true
+ },
"parse5": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/parse5/-/parse5-4.0.0.tgz",
@@ -15581,6 +16204,12 @@
"sha.js": "^2.4.8"
}
},
+ "pend": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
+ "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=",
+ "dev": true
+ },
"performance-now": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
@@ -16792,6 +17421,12 @@
"xtend": "^4.0.0"
}
},
+ "proto-list": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz",
+ "integrity": "sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk=",
+ "dev": true
+ },
"proxy-addr": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz",
@@ -17672,6 +18307,11 @@
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
"integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg=="
},
+ "eslint-plugin-react-hooks": {
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-1.7.0.tgz",
+ "integrity": "sha512-iXTCFcOmlWvw4+TOE8CLWj6yX1GwzT0Y6cUfHHZqWnSk144VmVIRcVGtUAzrLES7C798lmvnt02C7rxaOX1HNA=="
+ },
"resolve": {
"version": "1.15.0",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.15.0.tgz",
@@ -18384,6 +19024,15 @@
}
}
},
+ "responselike": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz",
+ "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=",
+ "dev": true,
+ "requires": {
+ "lowercase-keys": "^1.0.0"
+ }
+ },
"restore-cursor": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz",
@@ -18620,6 +19269,15 @@
}
}
},
+ "seek-bzip": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/seek-bzip/-/seek-bzip-1.0.6.tgz",
+ "integrity": "sha512-e1QtP3YL5tWww8uKaOCQ18UxIT2laNBXHjV/S2WYCiK4udiv8lkG89KRIoCjUagnAmCBurjF4zEVX2ByBbnCjQ==",
+ "dev": true,
+ "requires": {
+ "commander": "^2.8.1"
+ }
+ },
"select": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/select/-/select-1.1.2.tgz",
@@ -18984,6 +19642,12 @@
}
}
},
+ "slugify": {
+ "version": "1.4.6",
+ "resolved": "https://registry.npmjs.org/slugify/-/slugify-1.4.6.tgz",
+ "integrity": "sha512-ZdJIgv9gdrYwhXqxsH9pv7nXxjUEyQ6nqhngRxoAAOlmMGA28FDq5O4/5US4G2/Nod7d1ovNcgURQJ7kHq50KQ==",
+ "dev": true
+ },
"snapdragon": {
"version": "0.8.2",
"resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz",
@@ -19135,6 +19799,69 @@
}
}
},
+ "sonarqube-scanner": {
+ "version": "2.8.0",
+ "resolved": "https://registry.npmjs.org/sonarqube-scanner/-/sonarqube-scanner-2.8.0.tgz",
+ "integrity": "sha512-zZtJsxY2+LIC1h7mRa7tZ+HjHBvNtCHLpQpVvUrhHsTVLdo+eEfgG0Au/Db9lY6GexnImHgiQJXnS9b21/effg==",
+ "dev": true,
+ "requires": {
+ "download": "^7.1.0",
+ "extend": "3.0.2",
+ "fancy-log": "^1.3.3",
+ "lodash.get": "^4.4.2",
+ "lodash.uniq": "^4.5.0",
+ "mkdirp": "^1.0.3",
+ "progress": "^2.0.3",
+ "read-pkg": "2.0.0",
+ "slugify": "^1.4.0"
+ },
+ "dependencies": {
+ "load-json-file": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz",
+ "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=",
+ "dev": true,
+ "requires": {
+ "graceful-fs": "^4.1.2",
+ "parse-json": "^2.2.0",
+ "pify": "^2.0.0",
+ "strip-bom": "^3.0.0"
+ }
+ },
+ "mkdirp": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
+ "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
+ "dev": true
+ },
+ "path-type": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz",
+ "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=",
+ "dev": true,
+ "requires": {
+ "pify": "^2.0.0"
+ }
+ },
+ "read-pkg": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz",
+ "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=",
+ "dev": true,
+ "requires": {
+ "load-json-file": "^2.0.0",
+ "normalize-package-data": "^2.3.2",
+ "path-type": "^2.0.0"
+ }
+ },
+ "strip-bom": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
+ "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=",
+ "dev": true
+ }
+ }
+ },
"sort-keys": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz",
@@ -19143,6 +19870,15 @@
"is-plain-obj": "^1.0.0"
}
},
+ "sort-keys-length": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/sort-keys-length/-/sort-keys-length-1.0.1.tgz",
+ "integrity": "sha1-nLb09OnkgVWmqgZx7dM2/xR5oYg=",
+ "dev": true,
+ "requires": {
+ "sort-keys": "^1.0.0"
+ }
+ },
"source-list-map": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz",
@@ -19581,6 +20317,15 @@
"babel-plugin-transform-object-rest-spread": "^6.26.0"
}
},
+ "strip-dirs": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/strip-dirs/-/strip-dirs-2.1.0.tgz",
+ "integrity": "sha512-JOCxOeKLm2CAS73y/U4ZeZPTkE+gNVCzKt7Eox84Iej1LT/2pTWYpZKJuxwQpvX1LiZb1xokNR7RLfuBAa7T3g==",
+ "dev": true,
+ "requires": {
+ "is-natural-number": "^4.0.1"
+ }
+ },
"strip-eof": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz",
@@ -19599,6 +20344,15 @@
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
"integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig=="
},
+ "strip-outer": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/strip-outer/-/strip-outer-1.0.1.tgz",
+ "integrity": "sha512-k55yxKHwaXnpYGsOzg4Vl8+tDrWylxDEpknGjhTiZB8dFRU5rTo9CAzeycivxV3s+zlTKwrs6WxMxR95n26kwg==",
+ "dev": true,
+ "requires": {
+ "escape-string-regexp": "^1.0.2"
+ }
+ },
"style-loader": {
"version": "0.23.1",
"resolved": "https://registry.npmjs.org/style-loader/-/style-loader-0.23.1.tgz",
@@ -19651,6 +20405,14 @@
}
}
},
+ "super-tiny-icons": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/super-tiny-icons/-/super-tiny-icons-0.4.0.tgz",
+ "integrity": "sha512-PEHlUQsSdEtQNeP4pNOBCDU9cJe6bsrMmG3yV62icvMDgjCC+srl9AfJ5RGwfKbyvGNbYRUtcmkka+k7yhZxOA==",
+ "requires": {
+ "opencollective-postinstall": "^2.0.2"
+ }
+ },
"supports-color": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
@@ -19755,6 +20517,21 @@
"inherits": "2"
}
},
+ "tar-stream": {
+ "version": "1.6.2",
+ "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.2.tgz",
+ "integrity": "sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A==",
+ "dev": true,
+ "requires": {
+ "bl": "^1.0.0",
+ "buffer-alloc": "^1.2.0",
+ "end-of-stream": "^1.0.0",
+ "fs-constants": "^1.0.0",
+ "readable-stream": "^2.3.0",
+ "to-buffer": "^1.1.1",
+ "xtend": "^4.0.0"
+ }
+ },
"telejson": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/telejson/-/telejson-5.1.0.tgz",
@@ -20009,6 +20786,18 @@
"resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz",
"integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA=="
},
+ "time-stamp": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/time-stamp/-/time-stamp-1.1.0.tgz",
+ "integrity": "sha1-dkpaEa9QVhkhsTPztE5hhofg9cM=",
+ "dev": true
+ },
+ "timed-out": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz",
+ "integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=",
+ "dev": true
+ },
"timers-browserify": {
"version": "2.0.12",
"resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.12.tgz",
@@ -20063,6 +20852,12 @@
"resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz",
"integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M="
},
+ "to-buffer": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.1.1.tgz",
+ "integrity": "sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg==",
+ "dev": true
+ },
"to-fast-properties": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
@@ -20135,6 +20930,15 @@
"resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz",
"integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM="
},
+ "trim-repeated": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/trim-repeated/-/trim-repeated-1.0.0.tgz",
+ "integrity": "sha1-42RqLqTokTEr9+rObPsFOAvAHCE=",
+ "dev": true,
+ "requires": {
+ "escape-string-regexp": "^1.0.2"
+ }
+ },
"trim-trailing-lines": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/trim-trailing-lines/-/trim-trailing-lines-1.1.4.tgz",
@@ -20255,6 +21059,28 @@
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.7.tgz",
"integrity": "sha512-BLbiRkiBzAwsjut4x/dsibSTB6yWpwT5qWmC2OfuCg3GgVQCSgMs4vEctYPhsaGtd0AeuuHMkjZ2h2WG8MSzRw=="
},
+ "unbzip2-stream": {
+ "version": "1.4.3",
+ "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz",
+ "integrity": "sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==",
+ "dev": true,
+ "requires": {
+ "buffer": "^5.2.1",
+ "through": "^2.3.8"
+ },
+ "dependencies": {
+ "buffer": {
+ "version": "5.7.1",
+ "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
+ "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
+ "dev": true,
+ "requires": {
+ "base64-js": "^1.3.1",
+ "ieee754": "^1.1.13"
+ }
+ }
+ }
+ },
"uncontrollable": {
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/uncontrollable/-/uncontrollable-7.1.1.tgz",
@@ -20547,6 +21373,29 @@
"requires-port": "^1.0.0"
}
},
+ "url-parse-lax": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz",
+ "integrity": "sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=",
+ "dev": true,
+ "requires": {
+ "prepend-http": "^2.0.0"
+ },
+ "dependencies": {
+ "prepend-http": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz",
+ "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=",
+ "dev": true
+ }
+ }
+ },
+ "url-to-options": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/url-to-options/-/url-to-options-1.0.1.tgz",
+ "integrity": "sha1-FQWgOiiaSMvXpDTvuu7FBV9WM6k=",
+ "dev": true
+ },
"use": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz",
@@ -21681,6 +22530,16 @@
}
}
},
+ "yauzl": {
+ "version": "2.10.0",
+ "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz",
+ "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=",
+ "dev": true,
+ "requires": {
+ "buffer-crc32": "~0.2.3",
+ "fd-slicer": "~1.1.0"
+ }
+ },
"zwitch": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/zwitch/-/zwitch-1.0.5.tgz",
diff --git a/webapp_frontend/package.json b/webapp_frontend/package.json
index fa985817..b05ebeb5 100644
--- a/webapp_frontend/package.json
+++ b/webapp_frontend/package.json
@@ -16,6 +16,7 @@
"@types/react-router-dom": "^5.1.6",
"axios": "^0.20.0",
"bootstrap": "^4.5.3",
+ "eslint-plugin-react-hooks": "^4.2.0",
"node-sass": "^4.14.1",
"react": "^16.13.1",
"react-bootstrap": "^1.4.0",
@@ -26,6 +27,7 @@
"react-toastify": "^6.1.0",
"redux": "^4.0.5",
"redux-types": "^2.0.3",
+ "super-tiny-icons": "^0.4.0",
"typescript": "^3.8.3"
},
"scripts": {
@@ -35,7 +37,7 @@
"eject": "react-scripts eject",
"storybook": "start-storybook -p 6006 -s public --no-dll",
"build-storybook": "build-storybook -s public --no-dll",
- "sonar": "SONAR_LOGIN=$SONAR_LOGIN SONAR_PASSWORD=$SONAR_PASSWORD node src/sonar-scanner.js"
+ "sonar": "SONAR_LOGIN=$SONAR_LOGIN SONAR_PASSWORD=$SONAR_PASSWORD node src/sonar-scanner.js"
},
"eslintConfig": {
"extends": "react-app"
diff --git a/webapp_frontend/public/favicon.ico b/webapp_frontend/public/favicon.ico
index bcd5dfd6..e0a96e5e 100644
Binary files a/webapp_frontend/public/favicon.ico and b/webapp_frontend/public/favicon.ico differ
diff --git a/webapp_frontend/public/index.html b/webapp_frontend/public/index.html
index aa069f27..f654b812 100644
--- a/webapp_frontend/public/index.html
+++ b/webapp_frontend/public/index.html
@@ -1,5 +1,5 @@
-
+
@@ -24,20 +24,25 @@
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
- React App
+ FileFighter
-
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/webapp_frontend/public/logo192.png b/webapp_frontend/public/logo192.png
index fc44b0a3..6f131e0d 100644
Binary files a/webapp_frontend/public/logo192.png and b/webapp_frontend/public/logo192.png differ
diff --git a/webapp_frontend/public/logo512.png b/webapp_frontend/public/logo512.png
index a4e47a65..d082d9f7 100644
Binary files a/webapp_frontend/public/logo512.png and b/webapp_frontend/public/logo512.png differ
diff --git a/webapp_frontend/src/assets/images/logos/adventurer-run.gif b/webapp_frontend/src/assets/images/logos/adventurer-run.gif
new file mode 100644
index 00000000..5c4196f2
Binary files /dev/null and b/webapp_frontend/src/assets/images/logos/adventurer-run.gif differ
diff --git a/webapp_frontend/src/assets/images/logos/logo.png b/webapp_frontend/src/assets/images/logos/logo.png
index 07f2b0ec..74bea3c9 100644
Binary files a/webapp_frontend/src/assets/images/logos/logo.png and b/webapp_frontend/src/assets/images/logos/logo.png differ
diff --git a/webapp_frontend/src/background/api/api.ts b/webapp_frontend/src/background/api/api.ts
index 2d156f5e..9e5cd615 100644
--- a/webapp_frontend/src/background/api/api.ts
+++ b/webapp_frontend/src/background/api/api.ts
@@ -5,6 +5,10 @@ export const hostname:string =constants.url.API_URL+'/api';
export const userPath:string='/v1/users';
+export const filesytemPath:string='/v1/filesystem';
+
+
+
interface BackendHealthData {
uptimeInSeconds: number;
diff --git a/webapp_frontend/src/background/api/auth.ts b/webapp_frontend/src/background/api/auth.ts
index a76d8d4e..3b965be6 100644
--- a/webapp_frontend/src/background/api/auth.ts
+++ b/webapp_frontend/src/background/api/auth.ts
@@ -28,6 +28,7 @@ export const checkForCookie=()=>{
if (refreshTokenCookieValue){
store.dispatch(addRefreshToken(refreshTokenCookieValue))
getAccessTokenWithRefreshToken();
+
}
store.dispatch(checkedCookies(true))
@@ -78,22 +79,31 @@ export const getAccessTokenWithRefreshToken = () => {
},
};
+
+
Axios.get(hostname + userPath + '/auth', config)
.then((data) => {
setAuthHeaderToAxios(data.data.tokenValue)
store.dispatch(addAccessToken({token: data.data.tokenValue, timestamp: data.data.validUntil}as AccessToken));
+ //TODO: also get User data here
+
+
})
.catch(((error) => {
store.dispatch(removeTokens()as RemoveTokens);
console.log(error)
//you probably want to notify the user, maybe with a toast or similar
+
}));
}
+
+
+
export const logout=()=>{
store.dispatch(removeTokens());
deleteCookie(cookieName);
@@ -102,4 +112,4 @@ export const logout=()=>{
function setAuthHeaderToAxios(accessToken: string) {
Axios.defaults.headers.common['Authorization'] =
`Bearer ${accessToken}`;
-}
\ No newline at end of file
+}
diff --git a/webapp_frontend/src/background/api/filesystem.ts b/webapp_frontend/src/background/api/filesystem.ts
new file mode 100644
index 00000000..875c852f
--- /dev/null
+++ b/webapp_frontend/src/background/api/filesystem.ts
@@ -0,0 +1,457 @@
+import {BackendFolderContentsData} from "./filesystemTypes";
+import {hostname, filesytemPath} from "./api";
+import Axios from "axios";
+
+export const getFolderContents = (path: string) => new Promise((resolve, reject) => {
+
+
+ let config = {
+ headers: {
+ "X-FF-PATH": path
+ },
+ };
+
+
+ console.log(`[filesytem api] request folder content of ${path}`);
+
+ Axios.get(hostname + filesytemPath + '/contents',config)
+ .then(response=>resolve(response.data))
+ .catch(error=>reject(error))
+
+
+ // resolve(exampleValue(path))
+})
+
+/*
+const exampleValue = (path: string): BackendFolderContentsData => {
+ if (path === "/") return exampleFileSystem
+ else if (path === "/fasel") return exampleFileSystem
+ else if (path === "/bla") return {
+ "files": [
+ {
+ "createdByUserId": 0,
+ "id": 0,
+ "lastUpdated": 153354,
+ "name": "inBLA",
+ "permissionSet": {
+ "editableForGroups": [
+ "ADMIN"
+ ],
+ "editableForUsers": [
+ {
+ "groups": [
+ "ADMIN"
+ ],
+ "id": 0,
+ "username": "string"
+ }
+ ],
+ "visibleForGroups": [
+ "ADMIN"
+ ],
+ "visibleForUsers": [
+ {
+ "groups": [
+ "ADMIN"
+ ],
+ "id": 0,
+ "username": "string"
+ }
+ ]
+ },
+ "size": 546,
+ "type": "file"
+ },
+ {
+ "createdByUserId": 1,
+ "id": 0,
+ "lastUpdated": 1597177368,
+ "name": "text.txt",
+ "permissionSet": {
+ "editableForGroups": [
+ "ADMIN"
+ ],
+ "editableForUsers": [
+ {
+ "groups": [
+ "ADMIN"
+ ],
+ "id": 0,
+ "username": "string"
+ }
+ ],
+ "visibleForGroups": [
+ "ADMIN"
+ ],
+ "visibleForUsers": [
+ {
+ "groups": [
+ "ADMIN"
+ ],
+ "id": 0,
+ "username": "string"
+ }
+ ]
+ },
+ "size": 1332,
+ "type": "file"
+ },
+ {
+ "createdByUserId": 2,
+ "id": 0,
+ "lastUpdated": 1599147368,
+ "name": "sound.mp3",
+ "permissionSet": {
+ "editableForGroups": [
+ "ADMIN"
+ ],
+ "editableForUsers": [
+ {
+ "groups": [
+ "ADMIN"
+ ],
+ "id": 0,
+ "username": "string"
+ }
+ ],
+ "visibleForGroups": [
+ "ADMIN"
+ ],
+ "visibleForUsers": [
+ {
+ "groups": [
+ "ADMIN"
+ ],
+ "id": 0,
+ "username": "string"
+ }
+ ]
+ },
+ "size": 27565846,
+ "type": "file"
+ },
+ {
+ "createdByUserId": 1,
+ "id": 0,
+ "lastUpdated": 1602047368,
+ "name": "movie.mp4",
+ "permissionSet": {
+ "editableForGroups": [
+ "ADMIN"
+ ],
+ "editableForUsers": [
+ {
+ "groups": [
+ "ADMIN"
+ ],
+ "id": 0,
+ "username": "string"
+ }
+ ],
+ "visibleForGroups": [
+ "ADMIN"
+ ],
+ "visibleForUsers": [
+ {
+ "groups": [
+ "ADMIN"
+ ],
+ "id": 0,
+ "username": "string"
+ }
+ ]
+ },
+ "size": 224850446,
+ "type": "file"
+ },
+ {
+ "createdByUserId": 2,
+ "id": 0,
+ "lastUpdated": 1599949968,
+ "name": "image.jpg",
+ "permissionSet": {
+ "editableForGroups": [
+ "ADMIN"
+ ],
+ "editableForUsers": [
+ {
+ "groups": [
+ "ADMIN"
+ ],
+ "id": 0,
+ "username": "string"
+ }
+ ],
+ "visibleForGroups": [
+ "ADMIN"
+ ],
+ "visibleForUsers": [
+ {
+ "groups": [
+ "ADMIN"
+ ],
+ "id": 0,
+ "username": "string"
+ }
+ ]
+ },
+ "size": 4866848,
+ "type": "file"
+ },
+ {
+ "createdByUserId": 1313,
+ "id": 0,
+ "lastUpdated": 1599992468,
+ "name": "importantFile.md",
+ "permissionSet": {
+ "editableForGroups": [
+ "ADMIN"
+ ],
+ "editableForUsers": [
+ {
+ "groups": [
+ "ADMIN"
+ ],
+ "id": 0,
+ "username": "string"
+ }
+ ],
+ "visibleForGroups": [
+ "ADMIN"
+ ],
+ "visibleForUsers": [
+ {
+ "groups": [
+ "ADMIN"
+ ],
+ "id": 0,
+ "username": "string"
+ }
+ ]
+ },
+ "size": 96643,
+ "type": "file"
+ },
+ {
+ "createdByUserId": 2,
+ "id": 0,
+ "lastUpdated": 1601584968,
+ "name": "likeMe.html",
+ "permissionSet": {
+ "editableForGroups": [
+ "ADMIN"
+ ],
+ "editableForUsers": [
+ {
+ "groups": [
+ "ADMIN"
+ ],
+ "id": 0,
+ "username": "string"
+ }
+ ],
+ "visibleForGroups": [
+ "ADMIN"
+ ],
+ "visibleForUsers": [
+ {
+ "groups": [
+ "ADMIN"
+ ],
+ "id": 0,
+ "username": "string"
+ }
+ ]
+ },
+ "size": 861858,
+ "type": "file"
+ }
+ ],
+ "folders": [{
+ "createdByUserId": 0,
+ "id": 0,
+ "lastUpdated": 1601148846,
+ "name": "unterBla",
+ "path": "/bla/unterBla",
+ "permissionSet": {
+ "editableForGroups": [
+ "ADMIN"
+ ],
+ "editableForUsers": [
+ {
+ "groups": [
+ "ADMIN"
+ ],
+ "id": 0,
+ "username": "string"
+ }
+ ],
+ "visibleForGroups": [
+ "ADMIN"
+ ],
+ "visibleForUsers": [
+ {
+ "groups": [
+ "ADMIN"
+ ],
+ "id": 0,
+ "username": "string"
+ }
+ ]
+ },
+ "size": 18975576,
+ "type": "FOLDER"
+ }]
+ }
+ else if (path === "/bla/unterBla") return {
+ "files": [
+ {
+ "createdByUserId": 0,
+ "id": 0,
+ "lastUpdated": 0,
+ "name": "inBLA",
+ "permissionSet": {
+ "editableForGroups": [
+ "ADMIN"
+ ],
+ "editableForUsers": [
+ {
+ "groups": [
+ "ADMIN"
+ ],
+ "id": 0,
+ "username": "string"
+ }
+ ],
+ "visibleForGroups": [
+ "ADMIN"
+ ],
+ "visibleForUsers": [
+ {
+ "groups": [
+ "ADMIN"
+ ],
+ "id": 0,
+ "username": "string"
+ }
+ ]
+ },
+ "size": 5489,
+ "type": "file"
+ }
+ ],
+ "folders": []
+ }
+ return {"files": [], "folders": []}
+}
+
+const exampleFileSystem = {
+ "files": [
+ {
+ "createdByUserId": 0,
+ "id": 0,
+ "lastUpdated": 0,
+ "name": "string",
+ "permissionSet": {
+ "editableForGroups": [
+ "ADMIN"
+ ],
+ "editableForUsers": [
+ {
+ "groups": [
+ "ADMIN"
+ ],
+ "id": 0,
+ "username": "string"
+ }
+ ],
+ "visibleForGroups": [
+ "ADMIN"
+ ],
+ "visibleForUsers": [
+ {
+ "groups": [
+ "ADMIN"
+ ],
+ "id": 0,
+ "username": "string"
+ }
+ ]
+ },
+ "size": 13,
+ "type": "FOLDER"
+ }
+ ],
+ "folders": [
+ {
+ "createdByUserId": 0,
+ "id": 0,
+ "lastUpdated": 0,
+ "name": "bla",
+ "path": "/bla",
+ "permissionSet": {
+ "editableForGroups": [
+ "ADMIN"
+ ],
+ "editableForUsers": [
+ {
+ "groups": [
+ "ADMIN"
+ ],
+ "id": 0,
+ "username": "string"
+ }
+ ],
+ "visibleForGroups": [
+ "ADMIN"
+ ],
+ "visibleForUsers": [
+ {
+ "groups": [
+ "ADMIN"
+ ],
+ "id": 0,
+ "username": "string"
+ }
+ ]
+ },
+ "size": 864070843,
+ "type": "FOLDER"
+ },
+ {
+ "createdByUserId": 0,
+ "id": 0,
+ "lastUpdated": 0,
+ "name": "fasel",
+ "path": "/fasel",
+ "permissionSet": {
+ "editableForGroups": [
+ "ADMIN"
+ ],
+ "editableForUsers": [
+ {
+ "groups": [
+ "ADMIN"
+ ],
+ "id": 0,
+ "username": "string"
+ }
+ ],
+ "visibleForGroups": [
+ "ADMIN"
+ ],
+ "visibleForUsers": [
+ {
+ "groups": [
+ "ADMIN"
+ ],
+ "id": 0,
+ "username": "string"
+ }
+ ]
+ },
+ "size": 1684035,
+ "type": "FOLDER"
+ }
+ ]
+}*/
diff --git a/webapp_frontend/src/background/api/filesystemTypes.ts b/webapp_frontend/src/background/api/filesystemTypes.ts
new file mode 100644
index 00000000..8ff6a879
--- /dev/null
+++ b/webapp_frontend/src/background/api/filesystemTypes.ts
@@ -0,0 +1,42 @@
+
+export interface UsersSet {
+ groups: string[];
+ id: number;
+ username: string;
+}
+
+
+export interface PermissionSet {
+ editableForGroups: string[];
+ editableForUsers: UsersSet[];
+ visibleForGroups: string[];
+ visibleForUsers: UsersSet[];
+}
+
+export interface File {
+ createdByUserId: number;
+ id: number;
+ lastUpdated: number;
+ name: string;
+ permissionSet: PermissionSet;
+ size: number;
+ type: string;
+}
+
+export interface Folder {
+ createdByUserId: number;
+ id: number;
+ lastUpdated: number;
+ name: string;
+ path: string;
+ permissionSet: PermissionSet;
+ size: number;
+ type: string;
+}
+
+export interface BackendFolderContentsData {
+ files: File[];
+ folders: Folder[];
+}
+
+
diff --git a/webapp_frontend/src/background/constants.tsx b/webapp_frontend/src/background/constants.ts
similarity index 63%
rename from webapp_frontend/src/background/constants.tsx
rename to webapp_frontend/src/background/constants.ts
index f77a3cd0..80a76f49 100644
--- a/webapp_frontend/src/background/constants.tsx
+++ b/webapp_frontend/src/background/constants.ts
@@ -11,7 +11,8 @@ const prod: constants = {
const dev: constants = {
url: {
- API_URL: 'https://cors-anywhere.herokuapp.com/http://filefighter.ddns.net:3001',
+ API_URL: 'http://filefighter.ddns.net:1081/http://filefighter.ddns.net:3001',
+ // API_URL: 'https://cors-anywhere.herokuapp.com/http://filefighter.ddns.net:3001',
// API_URL: 'http://localhost:8080',
}
};
diff --git a/webapp_frontend/src/background/methods/bytes.ts b/webapp_frontend/src/background/methods/bytes.ts
new file mode 100644
index 00000000..c4894362
--- /dev/null
+++ b/webapp_frontend/src/background/methods/bytes.ts
@@ -0,0 +1,11 @@
+export function formatBytes(bytes:number, decimals:number = 2):string {
+ if (bytes === 0) return '0 Bytes';
+
+ const k:number = 1024;
+ const dm:number = decimals < 0 ? 0 : decimals;
+ const sizes:string[] = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
+
+ const i:number = Math.floor(Math.log(bytes) / Math.log(k));
+
+ return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i];
+}
\ No newline at end of file
diff --git a/webapp_frontend/src/background/methods/cookies.tsx b/webapp_frontend/src/background/methods/cookies.ts
similarity index 100%
rename from webapp_frontend/src/background/methods/cookies.tsx
rename to webapp_frontend/src/background/methods/cookies.ts
diff --git a/webapp_frontend/src/background/methods/redirect.ts b/webapp_frontend/src/background/methods/redirect.ts
index 900b9a50..00d17183 100644
--- a/webapp_frontend/src/background/methods/redirect.ts
+++ b/webapp_frontend/src/background/methods/redirect.ts
@@ -1,15 +1,16 @@
-const internRedirect = (event: { preventDefault: () => void; }, history: any, path: string): void => {
- event.preventDefault();
- if (path) {
- const element = document.getElementById(path)
- if (element) {
- element.scrollIntoView()
- }
+const scrollToElement = (history: { push: (path:string) => void; }, id: string, event?: { preventDefault: () => void; }): void => {
+ //Replaces anchor for React
+ console.log("Scrolled to " + id)
+ event?.preventDefault();
+ if (id) {
+ const element = document.getElementById(id)
+ element?.scrollIntoView()
}
};
-const externRedirect = (event: { preventDefault: () => void; }, history: any[], path: string): void => {
- event.preventDefault();
- history.push(path);
+const redirect = (history:{ push: (path:string) => void; } , path: string, event?: { preventDefault: () => void; }): void => {
+ console.log("Redirected to " + path)
+ event?.preventDefault();
+ if (path !== window.location.pathname) history.push(path);
};
-export {externRedirect, internRedirect}
\ No newline at end of file
+export {redirect, scrollToElement}
\ No newline at end of file
diff --git a/webapp_frontend/src/background/methods/style.js b/webapp_frontend/src/background/methods/style.js
new file mode 100644
index 00000000..0287f6d3
--- /dev/null
+++ b/webapp_frontend/src/background/methods/style.js
@@ -0,0 +1,13 @@
+export function getStyleValue(element, strCssRule) {
+ //https://stackoverflow.com/questions/5227909/how-to-get-an-elements-padding-value-using-javascript
+ let strValue = "";
+ if (document.defaultView && document.defaultView.getComputedStyle) {
+ strValue = document.defaultView.getComputedStyle(element, "").getPropertyValue(strCssRule);
+ } else if (element.currentStyle) {
+ strCssRule = strCssRule.replace(/(\w)/g, function (strMatch, p1) {
+ return p1.toUpperCase();
+ });
+ strValue = element.currentStyle[strCssRule];
+ }
+ return strValue;
+}
\ No newline at end of file
diff --git a/webapp_frontend/src/background/methods/windowSize.ts b/webapp_frontend/src/background/methods/windowSize.ts
new file mode 100644
index 00000000..0c93e6cc
--- /dev/null
+++ b/webapp_frontend/src/background/methods/windowSize.ts
@@ -0,0 +1,35 @@
+export interface getWindowSize_Interface {
+ viewportWidth: number,
+ viewportHeight: number
+}
+export function getWindowSize():getWindowSize_Interface {
+
+ let viewportwidth:number;
+ let viewportheight:number;
+
+// the more standards compliant browsers (mozilla/netscape/opera/IE7) use window.innerWidth and window.innerHeight
+
+ if (typeof window.innerWidth != 'undefined') {
+ viewportwidth = window.innerWidth
+ viewportheight = window.innerHeight
+ }
+
+// IE6 in standards compliant mode (i.e. with a valid doctype as the first line in the document)
+
+ else if (typeof document.documentElement != 'undefined' &&
+ typeof document.documentElement.clientWidth != ('undefined' || 0)){
+ viewportwidth = document.documentElement.clientWidth
+ viewportheight = document.documentElement.clientHeight
+ }
+
+// older versions of IE
+
+ else {
+ viewportwidth = document.getElementsByTagName('body')[0].clientWidth
+ viewportheight = document.getElementsByTagName('body')[0].clientHeight
+ }
+ return {
+ viewportHeight: viewportheight,
+ viewportWidth: viewportwidth
+ }
+}
\ No newline at end of file
diff --git a/webapp_frontend/src/background/redux/reducers/tokens.tsx b/webapp_frontend/src/background/redux/reducers/tokens.tsx
index 7eab26c7..236fedab 100644
--- a/webapp_frontend/src/background/redux/reducers/tokens.tsx
+++ b/webapp_frontend/src/background/redux/reducers/tokens.tsx
@@ -36,7 +36,7 @@ export default function (state = initialState, action: TokenActionsTypes) {
case CHECKED_COOKIES: {
return {
refreshToken: state.refreshToken,
- accessToken: state.refreshToken,
+ accessToken: state.accessToken,
checkedCookies: action.payload
};
}
diff --git a/webapp_frontend/src/components/App.css b/webapp_frontend/src/components/App.css
index 74b5e053..673d0063 100644
--- a/webapp_frontend/src/components/App.css
+++ b/webapp_frontend/src/components/App.css
@@ -1,10 +1,5 @@
-.App {
- text-align: center;
-}
-
-.App-logo {
- height: 40vmin;
- pointer-events: none;
+main > .container {
+ padding: 60px 15px 0;
}
@media (prefers-reduced-motion: no-preference) {
@@ -13,21 +8,6 @@
}
}
-.App-header {
- background-color: #282c34;
- min-height: 100vh;
- display: flex;
- flex-direction: column;
- align-items: center;
- justify-content: center;
- font-size: calc(10px + 2vmin);
- color: white;
-}
-
-.App-link {
- color: #61dafb;
-}
-
@keyframes App-logo-spin {
from {
transform: rotate(0deg);
diff --git a/webapp_frontend/src/components/App.tsx b/webapp_frontend/src/components/App.tsx
index 57e56fce..f35de9cb 100644
--- a/webapp_frontend/src/components/App.tsx
+++ b/webapp_frontend/src/components/App.tsx
@@ -1,6 +1,5 @@
import React, {ReactElement} from 'react';
import './App.css';
-import {Container} from 'react-bootstrap';
import Header from "./basicElements/Header";
import Footer from "./basicElements/Footer";
import {BrowserRouter} from "react-router-dom";
@@ -14,12 +13,15 @@ import {SystemState} from "../background/redux/actions/sytemState";
import Login from "./basicElements/Login";
import {checkForCookie} from "../background/api/auth";
-
-
+import {TopBanner} from "./basicElements/TopBanner";
// this takes the redux store and maps everything that is needed to the function props
const mapState = (state: SystemState) => ({
- tokens: {refreshToken: state.tokens.refreshToken, accessToken: state.tokens.accessToken, checkedCookies: state.tokens.checkedCookies},
+ tokens: {
+ refreshToken: state.tokens.refreshToken,
+ accessToken: state.tokens.accessToken,
+ checkedCookies: state.tokens.checkedCookies
+ },
user: state.user
})
@@ -42,18 +44,22 @@ function App(props: Props): ReactElement {
console.log(props.tokens.refreshToken)
console.log(props.tokens)
console.log(props.user)
+ console.log("[App]---------------")
if (props.tokens.checkedCookies) {
- if (props.tokens.refreshToken && props.tokens.accessToken) {
+ if ((props.tokens.refreshToken && props.tokens.accessToken)) {
return (
-
+
+
-
-
-
+
+
+
+
+
diff --git a/webapp_frontend/src/components/Constants.tsx b/webapp_frontend/src/components/Constants.tsx
index 4a6bfc76..42a2ec9a 100644
--- a/webapp_frontend/src/components/Constants.tsx
+++ b/webapp_frontend/src/components/Constants.tsx
@@ -10,7 +10,10 @@ function Constants(): ReactElement {
// url + host of backend
- return (
);
+ return (
+
+
+ );
}
diff --git a/webapp_frontend/src/components/Health.tsx b/webapp_frontend/src/components/Health.tsx
deleted file mode 100644
index 870bcd02..00000000
--- a/webapp_frontend/src/components/Health.tsx
+++ /dev/null
@@ -1,69 +0,0 @@
-import React, {ReactElement, useEffect, useState} from "react";
-import {callBackendHealth} from "../background/api/api";
-import Header from "./basicElements/Header";
-import {Button, Container, Table} from "react-bootstrap";
-import logo from "../assets/images/logos/logo.png";
-
-function Health(): ReactElement {
-
-
- const [backendLiveTime, setBackendLiveTime] = useState
("not reachable");
- const [backendUserCount, setBackendUserCount] = useState("not reachable");
-
-
- useEffect(() => {
- callInitialBackendRequests()
- // eslint-disable-next-line react-hooks/exhaustive-deps
- }, []);
-
- function callInitialBackendRequests(): void {
- updateVariables()
- }
-
- function updateVariables(): void {
- Promise.all([callBackendHealth()])
- .then(([backendHealthData]) => {
- setBackendLiveTime(backendHealthData.uptimeInSeconds);
- setBackendUserCount(backendHealthData.userCount)
- })
- }
-
- return (
-
-
-
-
- FileFighter
-
-
-
-
-
-
-
-
-
-
-
- Backend information |
-
-
-
-
-
- Uptime |
- {backendLiveTime} |
-
-
- Usercount |
- {backendUserCount} |
-
-
-
-
-
-
- );
-}
-
-export default Health;
\ No newline at end of file
diff --git a/webapp_frontend/src/components/Router/Router.tsx b/webapp_frontend/src/components/Router/Router.tsx
index eda49ad0..cc277103 100644
--- a/webapp_frontend/src/components/Router/Router.tsx
+++ b/webapp_frontend/src/components/Router/Router.tsx
@@ -4,17 +4,23 @@ import Health from "../pages/Health";
import Error404 from "../pages/errors/Error404";
import Login from "../basicElements/Login";
import Registration from "../pages/Registration";
+import FileList from "../pages/filesytem/FileList";
+import {filesBaseUrl} from "../pages/filesytem/Filesystem";
export default function Router(): ReactElement {
return (
-
+
-
-
+
+
-
+
+
+
+
+
)
diff --git a/webapp_frontend/src/components/basicElements/Footer.tsx b/webapp_frontend/src/components/basicElements/Footer.tsx
index 8aab8e8c..0a2df7ee 100644
--- a/webapp_frontend/src/components/basicElements/Footer.tsx
+++ b/webapp_frontend/src/components/basicElements/Footer.tsx
@@ -1,17 +1,22 @@
import React, {ReactElement} from 'react';
+import {Container} from 'react-bootstrap';
+import github from "super-tiny-icons/images/svg/github.svg"
export default function Footer(): ReactElement {
return (
-
-
-
-
- Footer |
- Footer |
-
-
-
-
+
);
}
diff --git a/webapp_frontend/src/components/basicElements/Header.tsx b/webapp_frontend/src/components/basicElements/Header.tsx
index e778afb5..12150f51 100644
--- a/webapp_frontend/src/components/basicElements/Header.tsx
+++ b/webapp_frontend/src/components/basicElements/Header.tsx
@@ -1,11 +1,75 @@
import React, {ReactElement} from 'react';
-import { useHistory } from "react-router-dom";
-import {Button} from "react-bootstrap";
+import {useHistory} from "react-router-dom";
+import {redirect} from "../../background/methods/redirect";
+import logo from "../../assets/images/logos/logo.png"
+import {Nav, Navbar, NavbarBrand} from "react-bootstrap";
-function Header():ReactElement {
+export interface navBarElement_Interface {
+ name: string,
+ text: string,
+ link: string,
+ deviantVisibleLink?: string,
+ logo: string | null,
+ onClick?: (...sth: any) => any,
+}
+
+function Header(): ReactElement {
const history = useHistory();
+ const navBarElements: navBarElement_Interface[] = [
+ {
+ name: "main",
+ text: "Main",
+ link: "/",
+ deviantVisibleLink: "/start",
+ logo: null
+ },
+ {
+ name: "files",
+ text: "Files",
+ link: "/file",
+ logo: null,
+ },
+ {
+ name: "registration",
+ text: "Registration",
+ link: "/registration",
+ logo: null,
+ }
+ ]
+
+ const final: ReactElement[] = []
+ navBarElements.forEach((element) => {
+ final.push(
+ {
+ redirect(history, element.link, event);
+ if (element.onClick) element.onClick()
+ }}
+ >{element.text}
+ )
+ })
- return()
+ return (
+
+
+
+ {redirect(history, "/", event);}}>
+
+ FileFighter
+
+
+
+
+
+
+
+
+ )
}
-export default Header;
\ No newline at end of file
+export default Header;
diff --git a/webapp_frontend/src/components/basicElements/Login.tsx b/webapp_frontend/src/components/basicElements/Login.tsx
index adea9893..4f64bb30 100644
--- a/webapp_frontend/src/components/basicElements/Login.tsx
+++ b/webapp_frontend/src/components/basicElements/Login.tsx
@@ -5,7 +5,7 @@ import {loginWithUsernameAndPassword} from "../../background/api/auth";
function Login(): ReactElement {
const [userName, setUsername] = useState("");
const [password, setPassword] = useState("");
- const [stayLoggedIn, setStayLoggedIn] = useState(false);
+ const [stayLoggedIn, setStayLoggedIn] = useState(true);
const [errorMessage, setErrorMessage] = useState("");
const [loading,setLoading]=useState(false);
@@ -47,7 +47,7 @@ function Login(): ReactElement {
- setStayLoggedIn(!stayLoggedIn)}/>
+ setStayLoggedIn(!stayLoggedIn)}/>
+ )
+}
diff --git a/webapp_frontend/src/components/pages/Health.tsx b/webapp_frontend/src/components/pages/Health.tsx
index 8a193d92..9722ad3a 100644
--- a/webapp_frontend/src/components/pages/Health.tsx
+++ b/webapp_frontend/src/components/pages/Health.tsx
@@ -1,18 +1,26 @@
import React, {useEffect, useState} from "react";
import logo from "../../assets/images/logos/logo.png";
-import {Button, Table} from "react-bootstrap";
+import {Button, Table, Container} from "react-bootstrap";
import {callBackendHealth} from "../../background/api/api";
import {audioOnOff, setAudioVolumeByID} from "../../background/methods/sound"
import {logout} from "../../background/api/auth";
export default function Health() {
- const [backendLiveTime, setBackendLiveTime] = useState
("not reachable");
- const [backendUserCount, setBackendUserCount] = useState("not reachable");
+ const [backendLiveTime, setBackendLiveTime] = useState("not reachable");
+ const [backendUserCount, setBackendUserCount] = useState("not reachable");
useEffect(() => {
- updateVariables()
- }, []);
+ updateVariables();
+ }, [])
+
+ useEffect(() => {
+ const timer = setTimeout(() => {
+ updateVariables()
+ }, 60000)
+ // Clear timeout if the component is unmounted
+ return () => clearTimeout(timer);
+ });
function updateVariables(): void {
Promise.all([callBackendHealth()])
@@ -20,10 +28,14 @@ export default function Health() {
setBackendLiveTime(backendHealthData.uptimeInSeconds);
setBackendUserCount(backendHealthData.userCount)
})
+ .catch(() => {
+ setBackendLiveTime("not reachable");
+ setBackendUserCount("not reachable");
+ })
}
return (
- <>
+
FileFighter
@@ -39,8 +51,7 @@ export default function Health() {
-
-
+
Backend information |
@@ -60,6 +71,6 @@ export default function Health() {
- >
+
)
}
diff --git a/webapp_frontend/src/components/pages/Registration.tsx b/webapp_frontend/src/components/pages/Registration.tsx
index 387db29a..3b9ca39f 100644
--- a/webapp_frontend/src/components/pages/Registration.tsx
+++ b/webapp_frontend/src/components/pages/Registration.tsx
@@ -1,15 +1,19 @@
-import React, {ChangeEvent, FormEvent, ReactElement, useEffect, useState} from "react";
+import React, {ChangeEvent, FormEvent, ReactElement, useCallback, useEffect, useState} from "react";
import {Container, Row, Col, Form, FormGroup, Button, Alert} from "react-bootstrap";
import {deleteSpaces} from "../../background/methods/strings";
import {biggerMaxStrLength, notMinStrLength} from "../../background/methods/checkInput";
import info_svg from "../../assets/images/icons/material.io/info-24px.svg";
import check_svg from "../../assets/images/icons/material.io/check_circle-24px.svg";
import error_svg from "../../assets/images/icons/material.io/error-24px.svg";
+import fileFighter from "../../assets/images/logos/adventurer-run.gif";
import {registerNewUser} from "../../background/api/registration";
+import {getWindowSize, getWindowSize_Interface} from "../../background/methods/windowSize";
+import {getStyleValue} from "../../background/methods/style";
export default function Registration(): ReactElement {
const MIN_PASSWORD_LENGTH = 8;
const MAX_PASSWORD_LENGTH = 20;
+ const DEFAULT_ALERT_DURATION = 3500;
const [username, setUsername] = useState("");
const [password, setPassword] = useState("");
@@ -23,64 +27,80 @@ export default function Registration(): ReactElement {
const [alertVariant, setAlertColor] = useState<"primary" | "secondary" | "success" | "danger" | "warning" | "info" | "light" | "dark">("success");
const [alertVisibility, setAlertVisibility] = useState(false);
+ const registrationContainer = document.getElementById("registrationContainer")
+ const logoSubmit = document.getElementById("logoSubmit")
+
+ useEffect(() => {
+ function repositionSubmitLogo() {
+ const logo = document.getElementById("logoSubmit")
+ if (logo){
+ const container: HTMLElement | null = document.getElementById("registrationContainer");
+ const leftContainerOffset: number = container?.getBoundingClientRect().left ?? 0;
+
+ let containerPadding:string|number|null = getStyleValue(container, "padding-left");
+ const pxPosition = containerPadding.indexOf("px");
+ containerPadding = pxPosition === -1 ? null : Number(containerPadding.substr(0, pxPosition))
+
+ logo.style.left = -(leftContainerOffset+logo.offsetWidth*2+(containerPadding ?? 20)) + "px";
+ }
+ }
+ repositionSubmitLogo()
+ },[registrationContainer, logoSubmit])
+
+ const reviewPasswordMatch = useCallback(():void => {
+ setPasswordsMatch(password === passwordConfirmation);
+ },[password, passwordConfirmation]);
+
useEffect(() => {
reviewPasswordMatch()
- // eslint-disable-next-line
- },[passwordConfirmation, password])
+ },[reviewPasswordMatch])
const handleSubmit = async (event: FormEvent) => {
console.log("[REGISTRATION] handleSubmit")
event.preventDefault();
reviewPasswordMatch();
- if (!username){
- setAlertColor("danger");
- setAlertMessage("Error: Please choose an username.")
- handleAlertVisibility(3500)
+ if (!username) {
+ handleAlertVisibility(DEFAULT_ALERT_DURATION, "danger", "Error: Please choose an username.")
} else if (!passwordsMatch) {
- setAlertColor("danger");
- setAlertMessage("Error: Password and password confirmation must match.")
- handleAlertVisibility(3500)
- } else if (!passwordInformationNumber || !passwordInformationLowercase || !passwordInformationUppercase || !passwordInformationLength){
- setAlertColor("danger");
- setAlertMessage("Error: Please pay attention to the notes below the input field.");
- handleAlertVisibility(3500)
+ handleAlertVisibility(DEFAULT_ALERT_DURATION, "danger", "Error: Password and password confirmation must match.")
+ } else if (!passwordInformationNumber || !passwordInformationLowercase || !passwordInformationUppercase || !passwordInformationLength) {
+ handleAlertVisibility(DEFAULT_ALERT_DURATION, "danger", "Error: Please pay attention to the notes below the input fields.")
} else {
await registerNewUser(username, password, passwordConfirmation)
.then(res => {
- setAlertMessage("Worked: " + (res.outputMessage ? res.outputMessage : (res.httpStatus + " " + res.httpMessage)));
- setAlertColor("success");
- console.table(res);
+ handleAlertVisibility(DEFAULT_ALERT_DURATION, "success", "Worked: " + (res.outputMessage ? res.outputMessage : (res.httpStatus + " " + res.httpMessage)));
+ toggleSubmitLogo();
})
.catch(err => {
- setAlertColor("danger");
- setAlertMessage("Error: " + (err.outputMessage ? err.outputMessage : (err.httpStatus + " " + err.httpMessage)))
- console.table(err)
+ handleAlertVisibility(DEFAULT_ALERT_DURATION, "danger", "Error: " + (err.outputMessage ? err.outputMessage : (err.httpStatus + " " + err.httpMessage)))
})
- .finally(() => handleAlertVisibility(3500))
}
}
- const handleAlertVisibility = (duration: number) => {
+ const handleAlertVisibility = (duration: number, color: "primary" | "secondary" | "success" | "danger" | "warning" | "info" | "light" | "dark", message: string) => {
if (!alertVisibility) {
+ setAlertMessage(message);
+ setAlertColor(color);
setAlertVisibility(true);
setTimeout(() => {
- setAlertVisibility(false)
- }, duration)
+ setAlertVisibility(false);
+ }, duration);
}
}
- const makePasswordInputFitRules = (input:string):[string,boolean] => {
+ const makePasswordInputFitRules = (input: string): [string, boolean] => {
input = deleteSpaces(input);
- if (biggerMaxStrLength(input, MAX_PASSWORD_LENGTH)){
- return [input,false];
+ if (biggerMaxStrLength(input, MAX_PASSWORD_LENGTH)) {
+ handleAlertVisibility(DEFAULT_ALERT_DURATION, "warning", "Maximum password length exceeded. Input was undone.");
+ return [input, false];
}
- return [input,true];
+ return [input, true];
}
const handlePasswordChange = (event: ChangeEvent) => {
event.preventDefault();
- let value:[string,boolean]|string = makePasswordInputFitRules(event.target.value);
- if (!value[1]){
+ let value: [string, boolean] | string = makePasswordInputFitRules(event.target.value);
+ if (!value[1]) {
value = password;
} else {
value = value[0]
@@ -94,8 +114,8 @@ export default function Registration(): ReactElement {
const handlePasswordConfirmationChange = async (event: ChangeEvent) => {
event.preventDefault();
- let value:[string,boolean]|string = makePasswordInputFitRules(event.target.value);
- if (!value[1]){
+ let value: [string, boolean] | string = makePasswordInputFitRules(event.target.value);
+ if (!value[1]) {
value = passwordConfirmation;
} else {
value = value[0]
@@ -103,12 +123,8 @@ export default function Registration(): ReactElement {
setPasswordConfirmation(value);
}
- const reviewPasswordMatch = ():void => {
- setPasswordsMatch(password === passwordConfirmation);
- }
-
return (
-
+
Create new account
@@ -174,6 +190,35 @@ export default function Registration(): ReactElement {
+
)
+
+ function toggleSubmitLogo() {
+ const logo = document.getElementById("logoSubmit")
+ if (logo) {
+ const size:getWindowSize_Interface = getWindowSize();
+
+ setTimeout(() => { //run right
+ logo.style.transition = "4s";
+ logo.classList.remove("invisible")
+ logo.classList.add("visible")
+ logo.style.transform = "translateX(" + (logo.offsetWidth + size.viewportWidth) + "px)";
+ }, 1000);
+ setTimeout(() => { //turn around
+ logo.style.transition = "2s";
+ logo.style.transform = "translateX(" + (logo.offsetWidth + size.viewportWidth) + "px) scaleX(-1)";
+ }, 4000);
+ setTimeout(() => { //run left
+ logo.style.transition = "4s";
+ logo.style.transform = "scaleX(-1)";
+ }, 5000);
+ setTimeout(() => { //turn around
+ logo.style.transform = "";
+ logo.classList.add("invisible")
+ logo.classList.remove("visible")
+ }, 8000);
+ }
+ }
}
diff --git a/webapp_frontend/src/components/pages/errors/Error404.tsx b/webapp_frontend/src/components/pages/errors/Error404.tsx
index 7709ca8c..fec7e663 100644
--- a/webapp_frontend/src/components/pages/errors/Error404.tsx
+++ b/webapp_frontend/src/components/pages/errors/Error404.tsx
@@ -1,10 +1,11 @@
import React from 'react';
import { Link } from 'react-router-dom';
+import { Container } from 'react-bootstrap';
export default function Error404() {
- return ;
-}
\ No newline at end of file
+ ;
+}
diff --git a/webapp_frontend/src/components/pages/filesytem/FileList.tsx b/webapp_frontend/src/components/pages/filesytem/FileList.tsx
new file mode 100644
index 00000000..221955c7
--- /dev/null
+++ b/webapp_frontend/src/components/pages/filesytem/FileList.tsx
@@ -0,0 +1,85 @@
+import React, {ReactElement, useEffect, useState} from "react";
+import {getFolderContents} from "../../../background/api/filesystem";
+import {Folder, File, BackendFolderContentsData} from "../../../background/api/filesystemTypes";
+import {Row, Container, Col, Form} from "react-bootstrap";
+import {useLocation} from 'react-router-dom'
+import FileListFolder from "./FileListFolder";
+import FileListFile from "./FileListFile";
+import {FilesBreadcrumb} from "./FilesBreadcrumb";
+import {filesBaseUrl} from "./Filesystem";
+
+
+type Props = {}
+
+
+export default function FileList(props: Props): ReactElement {
+ let location = useLocation();
+
+ const [path, setPath] = useState(location.pathname.slice(filesBaseUrl.length) || "/")
+ const [files, setFiles] = useState(null)
+ const [folders, setFolders] = useState(null)
+ const [error, setError] = useState("");
+
+
+ console.log("[FileList path]" + path)
+
+ useEffect(() => {
+ function updateStates(): void {
+ getFolderContents(path)
+ .then(
+ (response: BackendFolderContentsData) => {
+ setFiles(response.files)
+ setFolders(response.folders)
+ setError("")
+ }
+ )
+ .catch(error => {
+ setError(error.response?.data.message)
+ setFiles([])
+ setFolders([])
+ });
+
+ }
+
+ setPath(location.pathname.slice(filesBaseUrl.length) || "/")
+ updateStates()
+
+ }, [path, location]);
+
+
+
+
+ return (
+
+
+
+
+ console.log(`selected all files` /*TODO*/)}/>
+
+ {"Type"}
+ {}
+ {"Share"}
+ {"Name"}
+ {"Owner"}
+ {"Last changes"}
+ {"Size"}
+
+
+
+
+ {error ?
+ {error} : (!folders && !files) ?
+ Nothing to see here. : null
+ }
+
+
+ {folders?.map((folder: Folder, i: number) => {
+ return ()
+ })}
+ {files?.map((file: File, i: number) => {
+ return ()
+ })}
+
+ )
+
+}
diff --git a/webapp_frontend/src/components/pages/filesytem/FileListFile.tsx b/webapp_frontend/src/components/pages/filesytem/FileListFile.tsx
new file mode 100644
index 00000000..7cecb3f1
--- /dev/null
+++ b/webapp_frontend/src/components/pages/filesytem/FileListFile.tsx
@@ -0,0 +1,28 @@
+import React, {ReactElement} from "react";
+import {File} from "../../../background/api/filesystemTypes";
+import FileListItem from "./FileListItem";
+
+type Props={
+ file:File
+}
+
+export default function FileListFile(props: Props): ReactElement {
+
+
+
+ const fileListEntity = {
+ createdByUserId: props.file.createdByUserId,
+ id: props.file.id,
+ lastUpdated: props.file.lastUpdated,
+ name: props.file.name,
+ permissionSet: props.file.permissionSet,
+ size: props.file.size,
+ type: props.file.type,
+ isFolder:false
+
+
+ };
+
+ return ()
+}
+
diff --git a/webapp_frontend/src/components/pages/filesytem/FileListFolder.tsx b/webapp_frontend/src/components/pages/filesytem/FileListFolder.tsx
new file mode 100644
index 00000000..475a7fd7
--- /dev/null
+++ b/webapp_frontend/src/components/pages/filesytem/FileListFolder.tsx
@@ -0,0 +1,30 @@
+import React, {ReactElement} from "react";
+import {Folder} from "../../../background/api/filesystemTypes";
+import FileListItem from "./FileListItem";
+
+type Props = {
+ folder: Folder
+ setPath: Function
+
+}
+
+export default function FileListFolder(props: Props): ReactElement {
+
+
+ const fileListEntity = {
+ createdByUserId: props.folder.createdByUserId,
+ id: props.folder.id,
+ lastUpdated: props.folder.lastUpdated,
+ name: props.folder.name,
+ permissionSet: props.folder.permissionSet,
+ size: props.folder.size,
+ type: props.folder.type,
+ isFolder: true,
+ path: props.folder.path,
+
+
+ };
+
+ return ()
+}
+
diff --git a/webapp_frontend/src/components/pages/filesytem/FileListItem.tsx b/webapp_frontend/src/components/pages/filesytem/FileListItem.tsx
new file mode 100644
index 00000000..6e3a6fa7
--- /dev/null
+++ b/webapp_frontend/src/components/pages/filesytem/FileListItem.tsx
@@ -0,0 +1,109 @@
+import {PermissionSet} from "../../../background/api/filesystemTypes";
+import React, {ReactElement} from "react";
+import {Col, Form} from "react-bootstrap";
+import {Link} from "react-router-dom";
+import {
+ FileEarmarkCodeIcon,
+ FileEarmarkIcon,
+ FileEarmarkImageIcon,
+ FileEarmarkLock2Icon,
+ FileEarmarkMusicIcon,
+ FileEarmarkPDFIcon,
+ FileEarmarkPlayIcon,
+ FileEarmarkRichtextIcon,
+ FileEarmarkTextIcon, FileEarmarkZipIcon,
+ FolderIcon
+} from "../../../elements/svg/SymbolFile";
+import {reverseString} from "../../../background/methods/strings";
+import {getDateAsStringFromTimestamp} from "../../../background/methods/time";
+import {formatBytes} from "../../../background/methods/bytes";
+
+type Props = {
+ fileListItem: FileListEntity;
+ setPath?: Function,
+}
+
+
+export interface FileListEntity {
+ createdByUserId: number
+ id: number
+ lastUpdated: number
+ name: string
+ permissionSet: PermissionSet
+ size: number;
+ type: string;
+ isFolder: boolean
+ path?: string
+
+
+}
+
+export default function FileListItem(props: Props): ReactElement {
+
+ const ICON_PREFERENCES = {height: "40px", width: "auto", color: "secondary"}
+
+ const FileIcon = (isFolder: boolean, name: string): ReactElement => {
+
+
+ if (isFolder) return
+
+ let positionOfPoint = reverseString(name).indexOf(".");
+ if (positionOfPoint < 0) return
+
+ const fileExtension = reverseString(reverseString(name).substr(0, positionOfPoint + 1));
+ switch (fileExtension) {
+ case ".txt" :
+ return
+ case ".jpg" :
+ return
+ case ".mp4" :
+ return
+ case ".mp3" :
+ return
+ case ".crypt" :
+ return
+ case ".pdf" :
+ return
+ case ".zip" :
+ case ".7z" :
+ return
+ case ".ts" :
+ case ".tsx" :
+ case ".js" :
+ case ".jsx" :
+ case ".java" :
+ return
+ case ".md" :
+ case ".html" :
+ return
+ default :
+ return
+ }
+ }
+
+ const onClick = () => {
+ if (props.fileListItem.isFolder && props.setPath && props.fileListItem.path) {
+ props.setPath(props.fileListItem.path)
+ }
+
+ }
+
+
+ return (
+ <>
+
+ console.log(`[files] selected ${props.fileListItem.id}`)}/>
+
+ {props.fileListItem.type}
+ {FileIcon(props.fileListItem.isFolder, props.fileListItem.name)}
+ ...
+ {props.fileListItem.name}
+
+ {props.fileListItem.createdByUserId}
+ {getDateAsStringFromTimestamp(props.fileListItem.lastUpdated)}
+ {formatBytes(props.fileListItem.size)}
+ >
+ )
+}
diff --git a/webapp_frontend/src/components/pages/filesytem/FilesBreadcrumb.tsx b/webapp_frontend/src/components/pages/filesytem/FilesBreadcrumb.tsx
new file mode 100644
index 00000000..e1539f6c
--- /dev/null
+++ b/webapp_frontend/src/components/pages/filesytem/FilesBreadcrumb.tsx
@@ -0,0 +1,22 @@
+import React, {ReactElement} from "react";
+import {Breadcrumb} from "react-bootstrap";
+import {Link} from "react-router-dom";
+import {filesBaseUrl} from "./Filesystem";
+
+
+type Props = {
+ path: string,
+ setPath: Function
+}
+
+export function FilesBreadcrumb(props: Props): ReactElement {
+
+ return (
+
+ props.setPath("/")}>root
+ {props.path.split('/').filter((s: String) => s).map((folder: string, i: number) => {
+ return ( props.setPath(props.path.split('/').slice(0, i + 2).join("/"))} key={i}>{folder} )
+ })}
+ )
+}
diff --git a/webapp_frontend/src/components/pages/filesytem/Filesystem.tsx b/webapp_frontend/src/components/pages/filesytem/Filesystem.tsx
new file mode 100644
index 00000000..f3fb49c8
--- /dev/null
+++ b/webapp_frontend/src/components/pages/filesytem/Filesystem.tsx
@@ -0,0 +1 @@
+export const filesBaseUrl = '/file';
diff --git a/webapp_frontend/src/elements/svg/SymbolFile.tsx b/webapp_frontend/src/elements/svg/SymbolFile.tsx
new file mode 100644
index 00000000..890f3852
--- /dev/null
+++ b/webapp_frontend/src/elements/svg/SymbolFile.tsx
@@ -0,0 +1,211 @@
+import * as React from "react";
+//https://reactsvgicons.com/bootstrap
+
+export function FileEarmarkIcon(props: React.SVGProps) {
+ return (
+
+ );
+}
+
+export function FileEarmarkMusicIcon(props: React.SVGProps) {
+ return (
+
+ );
+}
+
+export function FileEarmarkPlayIcon(props: React.SVGProps) {
+ return (
+
+ );
+}
+
+export function FileEarmarkTextIcon(props: React.SVGProps) {
+ return (
+
+ );
+}
+
+export function FileEarmarkImageIcon(props: React.SVGProps) {
+ return (
+
+ );
+}
+
+export function FileEarmarkRichtextIcon(props: React.SVGProps) {
+ return (
+
+ );
+}
+
+export function FileEarmarkLock2Icon(props: React.SVGProps) {
+ return (
+
+ );
+}
+
+export function FileEarmarkZipIcon(props: React.SVGProps) {
+ return (
+
+ );
+}
+
+export function FileEarmarkCodeIcon(props: React.SVGProps) {
+ return (
+
+ );
+}
+
+export function FileEarmarkPDFIcon(props: React.SVGProps) {
+ return (
+
+ );
+}
+
+
+//--------------------------------------------------------------------\\
+//--------------------------------------------------------------------\\
+//--------------------------------------------------------------------\\
+//--------------------------------------------------------------------\\
+//--------------------------------------------------------------------\\
+//--------------------------------------------------------------------\\
+
+export function FolderIcon(props: React.SVGProps) {
+ return (
+
+ );
+}
\ No newline at end of file
diff --git a/webapp_frontend/src/style/custom.scss b/webapp_frontend/src/style/custom.scss
index 2c2f4f67..1dc1a9f3 100644
--- a/webapp_frontend/src/style/custom.scss
+++ b/webapp_frontend/src/style/custom.scss
@@ -1,9 +1,13 @@
//read this: https://getbootstrap.com/docs/4.1/getting-started/theming
// Override default variables before the import (see node_modules/bootstrap/scss/_variables.scss for all)
-$body-bg: #2a313d;;
-$body-color: #FFF;
+$body-bg: #25040F;
+$body-color: #B9CAC8;
$blue: #1a4965;
+$primary: #771A18;
+$secondary: #FF6337;
+$yellow: #ffc107;
+$dark: black;
// Import Bootstrap and its default variables
@@ -26,5 +30,9 @@ $blue: #1a4965;
@import "~bootstrap/scss/forms";
@import "~bootstrap/scss/spinners";
@import "~bootstrap/scss/alert";
+@import "~bootstrap/scss/navbar";
+@import "~bootstrap/scss/nav";
+@import "~bootstrap/scss/transitions";
+@import "~bootstrap/scss/breadcrumb";