From ed223af5475270a0579f25a43aab4b49af557a8c Mon Sep 17 00:00:00 2001 From: Christoph Anderson <37236531+lupusA@users.noreply.github.com> Date: Fri, 14 Jul 2023 05:06:24 +0200 Subject: [PATCH] feat(ui): Added theming support (#150) * Commited first draft to theming in kopia. - Changed variants of buttons to unify the look and feel - Added support for themes specified in Theme.css - Added a new dependency "react-select" for selecting themes. * Minor changes. Select component now shows the correct color. * Updated bootstrap to 5.2.3. Removed bootstrap-dark from dependencies. The current theme is now synchronized with the react select component. * Added some minor code refactorings. This PR comes with the following fixes: - Pastel theme should now be darker - Added a preference tab - Font size of the selector has been reduced - Fixed css - Moved AppContext under src/contexts - Renamed themes to provide backwards compatibility * - Fixed byte representation - Added a darker background for the theme "dark" - Added stripes back to the tables - Moved css files in src/css - Removed the Themeselector as it now implemented in PreferencesView * - Fixed empty constructor in PreferencesView * Fixed some colors and the policy editor. The editor should now have the correct theme settings. Moved index.css to css folder. * Resolved merge conflict * Changed method redirect back to its original state * Minor fixes to the color settings. Tables should not be readable in dark mode --------- Co-authored-by: Christoph Anderson --- package-lock.json | 508 +++++++++++++----- package.json | 3 +- src/App.css | 215 -------- src/App.jsx | 25 +- src/DirectoryItems.jsx | 5 +- src/EstimateResults.jsx | 25 +- src/NewSnapshot.jsx | 10 +- src/PoliciesTable.jsx | 9 +- src/PolicyEditor/index.jsx | 4 +- src/PreferencesView.jsx | 39 ++ src/RepoStatus.jsx | 2 +- src/SetupRepository.jsx | 16 +- src/SnapshotsTable.jsx | 19 +- src/SourcesTable.jsx | 30 +- src/TaskDetails.jsx | 9 +- src/TaskLogs.jsx | 11 +- src/TasksTable.jsx | 4 +- src/ToggleDarkModeButton.tsx | 21 - .../AppContext.tsx} | 0 src/contexts/UIPreferencesContext.tsx | 51 +- src/css/App.css | 360 +++++++++++++ src/css/Theme.css | 70 +++ src/{ => css}/index.css | 0 src/index.jsx | 2 +- src/uiutil.jsx | 42 +- 25 files changed, 996 insertions(+), 484 deletions(-) delete mode 100644 src/App.css create mode 100644 src/PreferencesView.jsx delete mode 100644 src/ToggleDarkModeButton.tsx rename src/{AppContext.js => contexts/AppContext.tsx} (100%) create mode 100644 src/css/App.css create mode 100644 src/css/Theme.css rename src/{ => css}/index.css (100%) diff --git a/package-lock.json b/package-lock.json index 74374b0..9c98c4b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,13 +12,14 @@ "@fortawesome/free-regular-svg-icons": "^6.2.0", "@fortawesome/free-solid-svg-icons": "^6.1.1", "@fortawesome/react-fontawesome": "^0.2.0", - "bootstrap-dark-5": "^1.1.3", + "bootstrap": "^5.2.3", "http-proxy-middleware": "^2.0.6", "moment": "^2.29.3", "react": "^18.2.0", "react-bootstrap": "^2.5.0", "react-dom": "^18.2.0", "react-router-dom": "^5.3.0", + "react-select": "^5.7.2", "react-table": "^7.8.0" }, "devDependencies": { @@ -57,7 +58,6 @@ "version": "7.16.7", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz", "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==", - "dev": true, "dependencies": { "@babel/highlight": "^7.16.7" }, @@ -378,7 +378,6 @@ "version": "7.16.7", "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz", "integrity": "sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg==", - "dev": true, "dependencies": { "@babel/types": "^7.16.7" }, @@ -496,7 +495,6 @@ "version": "7.16.7", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz", "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==", - "dev": true, "engines": { "node": ">=6.9.0" } @@ -543,7 +541,6 @@ "version": "7.17.12", "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.17.12.tgz", "integrity": "sha512-7yykMVF3hfZY2jsHZEEgLc+3x4o1O+fYyULu11GynEUQNwB6lua+IIQn1FiJxNucd5UlyJryrwsOh8PL9Sn8Qg==", - "dev": true, "dependencies": { "@babel/helper-validator-identifier": "^7.16.7", "chalk": "^2.0.0", @@ -557,7 +554,6 @@ "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, "dependencies": { "color-convert": "^1.9.0" }, @@ -569,7 +565,6 @@ "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, "dependencies": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", @@ -583,7 +578,6 @@ "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, "dependencies": { "color-name": "1.1.3" } @@ -591,14 +585,12 @@ "node_modules/@babel/highlight/node_modules/color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" }, "node_modules/@babel/highlight/node_modules/escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, "engines": { "node": ">=0.8.0" } @@ -607,7 +599,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, "engines": { "node": ">=4" } @@ -616,7 +607,6 @@ "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, "dependencies": { "has-flag": "^3.0.0" }, @@ -2076,7 +2066,6 @@ "version": "7.18.4", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.18.4.tgz", "integrity": "sha512-ThN1mBcMq5pG/Vm2IcBmPPfyPXbd8S02rS+OBIDENdufvqC7Z/jHPCv9IcP01277aKtDI8g/2XysBN4hA8niiw==", - "dev": true, "dependencies": { "@babel/helper-validator-identifier": "^7.16.7", "to-fast-properties": "^2.0.0" @@ -2328,6 +2317,117 @@ "postcss-selector-parser": "^6.0.10" } }, + "node_modules/@emotion/babel-plugin": { + "version": "11.10.6", + "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.10.6.tgz", + "integrity": "sha512-p2dAqtVrkhSa7xz1u/m9eHYdLi+en8NowrmXeF/dKtJpU8lCWli8RUAati7NcSl0afsBott48pdnANuD0wh9QQ==", + "dependencies": { + "@babel/helper-module-imports": "^7.16.7", + "@babel/runtime": "^7.18.3", + "@emotion/hash": "^0.9.0", + "@emotion/memoize": "^0.8.0", + "@emotion/serialize": "^1.1.1", + "babel-plugin-macros": "^3.1.0", + "convert-source-map": "^1.5.0", + "escape-string-regexp": "^4.0.0", + "find-root": "^1.1.0", + "source-map": "^0.5.7", + "stylis": "4.1.3" + } + }, + "node_modules/@emotion/babel-plugin/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@emotion/cache": { + "version": "11.10.5", + "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.10.5.tgz", + "integrity": "sha512-dGYHWyzTdmK+f2+EnIGBpkz1lKc4Zbj2KHd4cX3Wi8/OWr5pKslNjc3yABKH4adRGCvSX4VDC0i04mrrq0aiRA==", + "dependencies": { + "@emotion/memoize": "^0.8.0", + "@emotion/sheet": "^1.2.1", + "@emotion/utils": "^1.2.0", + "@emotion/weak-memoize": "^0.3.0", + "stylis": "4.1.3" + } + }, + "node_modules/@emotion/hash": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.0.tgz", + "integrity": "sha512-14FtKiHhy2QoPIzdTcvh//8OyBlknNs2nXRwIhG904opCby3l+9Xaf/wuPvICBF0rc1ZCNBd3nKe9cd2mecVkQ==" + }, + "node_modules/@emotion/memoize": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.0.tgz", + "integrity": "sha512-G/YwXTkv7Den9mXDO7AhLWkE3q+I92B+VqAE+dYG4NGPaHZGvt3G8Q0p9vmE+sq7rTGphUbAvmQ9YpbfMQGGlA==" + }, + "node_modules/@emotion/react": { + "version": "11.10.6", + "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.10.6.tgz", + "integrity": "sha512-6HT8jBmcSkfzO7mc+N1L9uwvOnlcGoix8Zn7srt+9ga0MjREo6lRpuVX0kzo6Jp6oTqDhREOFsygN6Ew4fEQbw==", + "dependencies": { + "@babel/runtime": "^7.18.3", + "@emotion/babel-plugin": "^11.10.6", + "@emotion/cache": "^11.10.5", + "@emotion/serialize": "^1.1.1", + "@emotion/use-insertion-effect-with-fallbacks": "^1.0.0", + "@emotion/utils": "^1.2.0", + "@emotion/weak-memoize": "^0.3.0", + "hoist-non-react-statics": "^3.3.1" + }, + "peerDependencies": { + "react": ">=16.8.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@emotion/serialize": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.1.1.tgz", + "integrity": "sha512-Zl/0LFggN7+L1liljxXdsVSVlg6E/Z/olVWpfxUTxOAmi8NU7YoeWeLfi1RmnB2TATHoaWwIBRoL+FvAJiTUQA==", + "dependencies": { + "@emotion/hash": "^0.9.0", + "@emotion/memoize": "^0.8.0", + "@emotion/unitless": "^0.8.0", + "@emotion/utils": "^1.2.0", + "csstype": "^3.0.2" + } + }, + "node_modules/@emotion/sheet": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.2.1.tgz", + "integrity": "sha512-zxRBwl93sHMsOj4zs+OslQKg/uhF38MB+OMKoCrVuS0nyTkqnau+BM3WGEoOptg9Oz45T/aIGs1qbVAsEFo3nA==" + }, + "node_modules/@emotion/unitless": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.0.tgz", + "integrity": "sha512-VINS5vEYAscRl2ZUDiT3uMPlrFQupiKgHz5AA4bCH1miKBg4qtwkim1qPmJj/4WG6TreYMY111rEFsjupcOKHw==" + }, + "node_modules/@emotion/use-insertion-effect-with-fallbacks": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.0.0.tgz", + "integrity": "sha512-1eEgUGmkaljiBnRMTdksDV1W4kUnmwgp7X9G8B++9GYwl1lUdqSndSriIrTJ0N7LQaoauY9JJ2yhiOYK5+NI4A==", + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/@emotion/utils": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.2.0.tgz", + "integrity": "sha512-sn3WH53Kzpw8oQ5mgMmIzzyAaH2ZqFEbozVVBSYp538E06OSE6ytOp7pRAjNQR+Q/orwqdQYJSe2m3hCOeznkw==" + }, + "node_modules/@emotion/weak-memoize": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.3.0.tgz", + "integrity": "sha512-AHPmaAx+RYfZz0eYu6Gviiagpmiyw98ySSlQvCUhVGDRtDFe4DBS0x1bSjdF3gqUDYOczB+yYvBTtEylYSdRhg==" + }, "node_modules/@eslint/eslintrc": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.0.tgz", @@ -2393,6 +2493,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@floating-ui/core": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.2.5.tgz", + "integrity": "sha512-qrcbyfnRVziRlB6IYwjCopYhO7Vud750JlJyuljruIXcPxr22y8zdckcJGsuOdnQ639uVD1tTXddrcH3t3QYIQ==" + }, + "node_modules/@floating-ui/dom": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.2.5.tgz", + "integrity": "sha512-+sAUfpQ3Frz+VCbPCqj+cZzvEESy3fjSeT/pDWkYCWOBXYNNKZfuVsHuv8/JO2zze8+Eb/Q7a6hZVgzS81fLbQ==", + "dependencies": { + "@floating-ui/core": "^1.2.4" + } + }, "node_modules/@fortawesome/fontawesome-common-types": { "version": "6.1.1", "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.1.1.tgz", @@ -2990,9 +3103,9 @@ } }, "node_modules/@popperjs/core": { - "version": "2.11.5", - "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.5.tgz", - "integrity": "sha512-9X2obfABZuDVLCgPK9aX0a/x4jaOEweTTWE2+9sr0Qqqevj2Uv5XorvusThmc9XGYpS9yI+fhh8RTafBtGposw==", + "version": "2.11.7", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.7.tgz", + "integrity": "sha512-Cr4OjIkipTtcXKjAsm8agyleBuDHvxzeBoa1v543lbv1YaIwQjESsVcmjiWiPEbC1FIeHOG/Op9kdCmAmiS3Kw==", "funding": { "type": "opencollective", "url": "https://opencollective.com/popperjs" @@ -3702,8 +3815,7 @@ "node_modules/@types/parse-json": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", - "dev": true + "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==" }, "node_modules/@types/prettier": { "version": "2.6.3", @@ -4827,7 +4939,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==", - "dev": true, "dependencies": { "@babel/runtime": "^7.12.5", "cosmiconfig": "^7.0.0", @@ -5094,26 +5205,21 @@ "dev": true }, "node_modules/bootstrap": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.1.3.tgz", - "integrity": "sha512-fcQztozJ8jToQWXxVuEyXWW+dSo8AiXWKwiSSrKWsRB/Qt+Ewwza+JWoLKiTuQLaEPhdNAJ7+Dosc9DOIqNy7Q==", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/bootstrap" - }, - "peerDependencies": { - "@popperjs/core": "^2.10.2" - } - }, - "node_modules/bootstrap-dark-5": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/bootstrap-dark-5/-/bootstrap-dark-5-1.1.3.tgz", - "integrity": "sha512-3Paopsp8wyOM1oeaLWLFuUZThhRc3tBYKUnoF+uwrU/xN4G47MCLZlALBJNqYqAecg7dSln9vgaYK1CwPnTeBw==", - "dependencies": { - "bootstrap": "^5.1.3" - }, + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.2.3.tgz", + "integrity": "sha512-cEKPM+fwb3cT8NzQZYEu4HilJ3anCrWqh3CHAok1p9jXqMPsPTBhU25fBckEJHJ/p+tTxTFTsFQGM+gaHpi3QQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/twbs" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/bootstrap" + } + ], "peerDependencies": { - "@popperjs/core": "^2.10.2" + "@popperjs/core": "^2.11.6" } }, "node_modules/brace-expansion": { @@ -5225,7 +5331,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, "engines": { "node": ">=6" } @@ -5710,7 +5815,6 @@ "version": "1.8.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", - "dev": true, "dependencies": { "safe-buffer": "~5.1.1" } @@ -5785,7 +5889,6 @@ "version": "7.0.1", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.1.tgz", "integrity": "sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ==", - "dev": true, "dependencies": { "@types/parse-json": "^4.0.0", "import-fresh": "^3.2.1", @@ -6701,7 +6804,6 @@ "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, "dependencies": { "is-arrayish": "^0.2.1" } @@ -6809,7 +6911,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, "engines": { "node": ">=10" }, @@ -7863,6 +7964,11 @@ "url": "https://github.com/avajs/find-cache-dir?sponsor=1" } }, + "node_modules/find-root": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", + "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==" + }, "node_modules/find-up": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", @@ -8102,8 +8208,7 @@ "node_modules/function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" }, "node_modules/function.prototype.name": { "version": "1.1.5", @@ -8355,7 +8460,6 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, "dependencies": { "function-bind": "^1.1.1" }, @@ -8758,7 +8862,6 @@ "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" @@ -8774,7 +8877,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, "engines": { "node": ">=4" } @@ -8872,8 +8974,7 @@ "node_modules/is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" }, "node_modules/is-bigint": { "version": "1.0.4", @@ -8954,7 +9055,6 @@ "version": "2.9.0", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.9.0.tgz", "integrity": "sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A==", - "dev": true, "dependencies": { "has": "^1.0.3" }, @@ -10308,8 +10408,7 @@ "node_modules/json-parse-even-better-errors": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" }, "node_modules/json-schema": { "version": "0.4.0", @@ -10451,8 +10550,7 @@ "node_modules/lines-and-columns": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" }, "node_modules/loader-runner": { "version": "4.3.0", @@ -10638,6 +10736,11 @@ "node": ">= 4.0.0" } }, + "node_modules/memoize-one": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-6.0.0.tgz", + "integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==" + }, "node_modules/merge-descriptors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", @@ -11273,7 +11376,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, "dependencies": { "callsites": "^3.0.0" }, @@ -11285,7 +11387,6 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, "dependencies": { "@babel/code-frame": "^7.0.0", "error-ex": "^1.3.1", @@ -11354,8 +11455,7 @@ "node_modules/path-parse": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" }, "node_modules/path-to-regexp": { "version": "1.8.0", @@ -11369,7 +11469,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true, "engines": { "node": ">=8" } @@ -13295,6 +13394,26 @@ } } }, + "node_modules/react-select": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/react-select/-/react-select-5.7.2.tgz", + "integrity": "sha512-cTlJkQ8YjV6T/js8wW0owTzht0hHGABh29vjLscY4HfZGkv7hc3FFTmRp9NzY/Ib1uQ36GieAKEjxpHdpCFpcA==", + "dependencies": { + "@babel/runtime": "^7.12.0", + "@emotion/cache": "^11.4.0", + "@emotion/react": "^11.8.1", + "@floating-ui/dom": "^1.0.1", + "@types/react-transition-group": "^4.4.0", + "memoize-one": "^6.0.0", + "prop-types": "^15.6.0", + "react-transition-group": "^4.3.0", + "use-isomorphic-layout-effect": "^1.1.2" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/react-table": { "version": "7.8.0", "resolved": "https://registry.npmjs.org/react-table/-/react-table-7.8.0.tgz", @@ -13542,7 +13661,6 @@ "version": "1.22.0", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", - "dev": true, "dependencies": { "is-core-module": "^2.8.1", "path-parse": "^1.0.7", @@ -13754,8 +13872,7 @@ "node_modules/safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, "node_modules/safer-buffer": { "version": "2.1.2", @@ -14473,6 +14590,11 @@ "postcss": "^8.2.15" } }, + "node_modules/stylis": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.1.3.tgz", + "integrity": "sha512-GP6WDNWf+o403jrEp9c5jibKavrtLW+/qYGhFxFrG8maXhwTBI7gLLhiBb0o7uFccWN+EOS9aMO6cGHWAO07OA==" + }, "node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -14502,7 +14624,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, "engines": { "node": ">= 0.4" }, @@ -14894,7 +15015,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", - "dev": true, "engines": { "node": ">=4" } @@ -15212,6 +15332,19 @@ "punycode": "^2.1.0" } }, + "node_modules/use-isomorphic-layout-effect": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.2.tgz", + "integrity": "sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA==", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -16201,7 +16334,6 @@ "version": "1.10.2", "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", - "dev": true, "engines": { "node": ">= 6" } @@ -16267,7 +16399,6 @@ "version": "7.16.7", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz", "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==", - "dev": true, "requires": { "@babel/highlight": "^7.16.7" } @@ -16509,7 +16640,6 @@ "version": "7.16.7", "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz", "integrity": "sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg==", - "dev": true, "requires": { "@babel/types": "^7.16.7" } @@ -16599,8 +16729,7 @@ "@babel/helper-validator-identifier": { "version": "7.16.7", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz", - "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==", - "dev": true + "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==" }, "@babel/helper-validator-option": { "version": "7.16.7", @@ -16635,7 +16764,6 @@ "version": "7.17.12", "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.17.12.tgz", "integrity": "sha512-7yykMVF3hfZY2jsHZEEgLc+3x4o1O+fYyULu11GynEUQNwB6lua+IIQn1FiJxNucd5UlyJryrwsOh8PL9Sn8Qg==", - "dev": true, "requires": { "@babel/helper-validator-identifier": "^7.16.7", "chalk": "^2.0.0", @@ -16646,7 +16774,6 @@ "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, "requires": { "color-convert": "^1.9.0" } @@ -16655,7 +16782,6 @@ "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, "requires": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", @@ -16666,7 +16792,6 @@ "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, "requires": { "color-name": "1.1.3" } @@ -16674,26 +16799,22 @@ "color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" }, "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==" }, "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==" }, "supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, "requires": { "has-flag": "^3.0.0" } @@ -17676,7 +17797,6 @@ "version": "7.18.4", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.18.4.tgz", "integrity": "sha512-ThN1mBcMq5pG/Vm2IcBmPPfyPXbd8S02rS+OBIDENdufvqC7Z/jHPCv9IcP01277aKtDI8g/2XysBN4hA8niiw==", - "dev": true, "requires": { "@babel/helper-validator-identifier": "^7.16.7", "to-fast-properties": "^2.0.0" @@ -17812,6 +17932,106 @@ "dev": true, "requires": {} }, + "@emotion/babel-plugin": { + "version": "11.10.6", + "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.10.6.tgz", + "integrity": "sha512-p2dAqtVrkhSa7xz1u/m9eHYdLi+en8NowrmXeF/dKtJpU8lCWli8RUAati7NcSl0afsBott48pdnANuD0wh9QQ==", + "requires": { + "@babel/helper-module-imports": "^7.16.7", + "@babel/runtime": "^7.18.3", + "@emotion/hash": "^0.9.0", + "@emotion/memoize": "^0.8.0", + "@emotion/serialize": "^1.1.1", + "babel-plugin-macros": "^3.1.0", + "convert-source-map": "^1.5.0", + "escape-string-regexp": "^4.0.0", + "find-root": "^1.1.0", + "source-map": "^0.5.7", + "stylis": "4.1.3" + }, + "dependencies": { + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==" + } + } + }, + "@emotion/cache": { + "version": "11.10.5", + "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.10.5.tgz", + "integrity": "sha512-dGYHWyzTdmK+f2+EnIGBpkz1lKc4Zbj2KHd4cX3Wi8/OWr5pKslNjc3yABKH4adRGCvSX4VDC0i04mrrq0aiRA==", + "requires": { + "@emotion/memoize": "^0.8.0", + "@emotion/sheet": "^1.2.1", + "@emotion/utils": "^1.2.0", + "@emotion/weak-memoize": "^0.3.0", + "stylis": "4.1.3" + } + }, + "@emotion/hash": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.0.tgz", + "integrity": "sha512-14FtKiHhy2QoPIzdTcvh//8OyBlknNs2nXRwIhG904opCby3l+9Xaf/wuPvICBF0rc1ZCNBd3nKe9cd2mecVkQ==" + }, + "@emotion/memoize": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.0.tgz", + "integrity": "sha512-G/YwXTkv7Den9mXDO7AhLWkE3q+I92B+VqAE+dYG4NGPaHZGvt3G8Q0p9vmE+sq7rTGphUbAvmQ9YpbfMQGGlA==" + }, + "@emotion/react": { + "version": "11.10.6", + "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.10.6.tgz", + "integrity": "sha512-6HT8jBmcSkfzO7mc+N1L9uwvOnlcGoix8Zn7srt+9ga0MjREo6lRpuVX0kzo6Jp6oTqDhREOFsygN6Ew4fEQbw==", + "requires": { + "@babel/runtime": "^7.18.3", + "@emotion/babel-plugin": "^11.10.6", + "@emotion/cache": "^11.10.5", + "@emotion/serialize": "^1.1.1", + "@emotion/use-insertion-effect-with-fallbacks": "^1.0.0", + "@emotion/utils": "^1.2.0", + "@emotion/weak-memoize": "^0.3.0", + "hoist-non-react-statics": "^3.3.1" + } + }, + "@emotion/serialize": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.1.1.tgz", + "integrity": "sha512-Zl/0LFggN7+L1liljxXdsVSVlg6E/Z/olVWpfxUTxOAmi8NU7YoeWeLfi1RmnB2TATHoaWwIBRoL+FvAJiTUQA==", + "requires": { + "@emotion/hash": "^0.9.0", + "@emotion/memoize": "^0.8.0", + "@emotion/unitless": "^0.8.0", + "@emotion/utils": "^1.2.0", + "csstype": "^3.0.2" + } + }, + "@emotion/sheet": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.2.1.tgz", + "integrity": "sha512-zxRBwl93sHMsOj4zs+OslQKg/uhF38MB+OMKoCrVuS0nyTkqnau+BM3WGEoOptg9Oz45T/aIGs1qbVAsEFo3nA==" + }, + "@emotion/unitless": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.0.tgz", + "integrity": "sha512-VINS5vEYAscRl2ZUDiT3uMPlrFQupiKgHz5AA4bCH1miKBg4qtwkim1qPmJj/4WG6TreYMY111rEFsjupcOKHw==" + }, + "@emotion/use-insertion-effect-with-fallbacks": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.0.0.tgz", + "integrity": "sha512-1eEgUGmkaljiBnRMTdksDV1W4kUnmwgp7X9G8B++9GYwl1lUdqSndSriIrTJ0N7LQaoauY9JJ2yhiOYK5+NI4A==", + "requires": {} + }, + "@emotion/utils": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.2.0.tgz", + "integrity": "sha512-sn3WH53Kzpw8oQ5mgMmIzzyAaH2ZqFEbozVVBSYp538E06OSE6ytOp7pRAjNQR+Q/orwqdQYJSe2m3hCOeznkw==" + }, + "@emotion/weak-memoize": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.3.0.tgz", + "integrity": "sha512-AHPmaAx+RYfZz0eYu6Gviiagpmiyw98ySSlQvCUhVGDRtDFe4DBS0x1bSjdF3gqUDYOczB+yYvBTtEylYSdRhg==" + }, "@eslint/eslintrc": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.0.tgz", @@ -17861,6 +18081,19 @@ } } }, + "@floating-ui/core": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.2.5.tgz", + "integrity": "sha512-qrcbyfnRVziRlB6IYwjCopYhO7Vud750JlJyuljruIXcPxr22y8zdckcJGsuOdnQ639uVD1tTXddrcH3t3QYIQ==" + }, + "@floating-ui/dom": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.2.5.tgz", + "integrity": "sha512-+sAUfpQ3Frz+VCbPCqj+cZzvEESy3fjSeT/pDWkYCWOBXYNNKZfuVsHuv8/JO2zze8+Eb/Q7a6hZVgzS81fLbQ==", + "requires": { + "@floating-ui/core": "^1.2.4" + } + }, "@fortawesome/fontawesome-common-types": { "version": "6.1.1", "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.1.1.tgz", @@ -18306,9 +18539,9 @@ } }, "@popperjs/core": { - "version": "2.11.5", - "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.5.tgz", - "integrity": "sha512-9X2obfABZuDVLCgPK9aX0a/x4jaOEweTTWE2+9sr0Qqqevj2Uv5XorvusThmc9XGYpS9yI+fhh8RTafBtGposw==" + "version": "2.11.7", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.7.tgz", + "integrity": "sha512-Cr4OjIkipTtcXKjAsm8agyleBuDHvxzeBoa1v543lbv1YaIwQjESsVcmjiWiPEbC1FIeHOG/Op9kdCmAmiS3Kw==" }, "@react-aria/ssr": { "version": "3.3.0", @@ -18852,8 +19085,7 @@ "@types/parse-json": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", - "dev": true + "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==" }, "@types/prettier": { "version": "2.6.3", @@ -19719,7 +19951,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==", - "dev": true, "requires": { "@babel/runtime": "^7.12.5", "cosmiconfig": "^7.0.0", @@ -19944,19 +20175,11 @@ "dev": true }, "bootstrap": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.1.3.tgz", - "integrity": "sha512-fcQztozJ8jToQWXxVuEyXWW+dSo8AiXWKwiSSrKWsRB/Qt+Ewwza+JWoLKiTuQLaEPhdNAJ7+Dosc9DOIqNy7Q==", + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.2.3.tgz", + "integrity": "sha512-cEKPM+fwb3cT8NzQZYEu4HilJ3anCrWqh3CHAok1p9jXqMPsPTBhU25fBckEJHJ/p+tTxTFTsFQGM+gaHpi3QQ==", "requires": {} }, - "bootstrap-dark-5": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/bootstrap-dark-5/-/bootstrap-dark-5-1.1.3.tgz", - "integrity": "sha512-3Paopsp8wyOM1oeaLWLFuUZThhRc3tBYKUnoF+uwrU/xN4G47MCLZlALBJNqYqAecg7dSln9vgaYK1CwPnTeBw==", - "requires": { - "bootstrap": "^5.1.3" - } - }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -20034,8 +20257,7 @@ "callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==" }, "camel-case": { "version": "4.1.2", @@ -20408,7 +20630,6 @@ "version": "1.8.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", - "dev": true, "requires": { "safe-buffer": "~5.1.1" } @@ -20465,7 +20686,6 @@ "version": "7.0.1", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.1.tgz", "integrity": "sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ==", - "dev": true, "requires": { "@types/parse-json": "^4.0.0", "import-fresh": "^3.2.1", @@ -21133,7 +21353,6 @@ "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, "requires": { "is-arrayish": "^0.2.1" } @@ -21225,8 +21444,7 @@ "escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==" }, "escodegen": { "version": "2.0.0", @@ -22032,6 +22250,11 @@ "pkg-dir": "^4.1.0" } }, + "find-root": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", + "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==" + }, "find-up": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", @@ -22190,8 +22413,7 @@ "function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" }, "function.prototype.name": { "version": "1.1.5", @@ -22379,7 +22601,6 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, "requires": { "function-bind": "^1.1.1" } @@ -22686,7 +22907,6 @@ "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, "requires": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" @@ -22695,8 +22915,7 @@ "resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==" } } }, @@ -22772,8 +22991,7 @@ "is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" }, "is-bigint": { "version": "1.0.4", @@ -22819,7 +23037,6 @@ "version": "2.9.0", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.9.0.tgz", "integrity": "sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A==", - "dev": true, "requires": { "has": "^1.0.3" } @@ -23838,8 +24055,7 @@ "json-parse-even-better-errors": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" }, "json-schema": { "version": "0.4.0", @@ -23949,8 +24165,7 @@ "lines-and-columns": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" }, "loader-runner": { "version": "4.3.0", @@ -24102,6 +24317,11 @@ "fs-monkey": "1.0.3" } }, + "memoize-one": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-6.0.0.tgz", + "integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==" + }, "merge-descriptors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", @@ -24565,7 +24785,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, "requires": { "callsites": "^3.0.0" } @@ -24574,7 +24793,6 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, "requires": { "@babel/code-frame": "^7.0.0", "error-ex": "^1.3.1", @@ -24625,8 +24843,7 @@ "path-parse": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" }, "path-to-regexp": { "version": "1.8.0", @@ -24639,8 +24856,7 @@ "path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==" }, "performance-now": { "version": "2.1.0", @@ -25917,6 +26133,22 @@ "workbox-webpack-plugin": "^6.4.1" } }, + "react-select": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/react-select/-/react-select-5.7.2.tgz", + "integrity": "sha512-cTlJkQ8YjV6T/js8wW0owTzht0hHGABh29vjLscY4HfZGkv7hc3FFTmRp9NzY/Ib1uQ36GieAKEjxpHdpCFpcA==", + "requires": { + "@babel/runtime": "^7.12.0", + "@emotion/cache": "^11.4.0", + "@emotion/react": "^11.8.1", + "@floating-ui/dom": "^1.0.1", + "@types/react-transition-group": "^4.4.0", + "memoize-one": "^6.0.0", + "prop-types": "^15.6.0", + "react-transition-group": "^4.3.0", + "use-isomorphic-layout-effect": "^1.1.2" + } + }, "react-table": { "version": "7.8.0", "resolved": "https://registry.npmjs.org/react-table/-/react-table-7.8.0.tgz", @@ -26111,7 +26343,6 @@ "version": "1.22.0", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", - "dev": true, "requires": { "is-core-module": "^2.8.1", "path-parse": "^1.0.7", @@ -26251,8 +26482,7 @@ "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, "safer-buffer": { "version": "2.1.2", @@ -26809,6 +27039,11 @@ "postcss-selector-parser": "^6.0.4" } }, + "stylis": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.1.3.tgz", + "integrity": "sha512-GP6WDNWf+o403jrEp9c5jibKavrtLW+/qYGhFxFrG8maXhwTBI7gLLhiBb0o7uFccWN+EOS9aMO6cGHWAO07OA==" + }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -26831,8 +27066,7 @@ "supports-preserve-symlinks-flag": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==" }, "svg-parser": { "version": "2.0.4", @@ -27133,8 +27367,7 @@ "to-fast-properties": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", - "dev": true + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==" }, "to-regex-range": { "version": "5.0.1", @@ -27375,6 +27608,12 @@ "punycode": "^2.1.0" } }, + "use-isomorphic-layout-effect": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.2.tgz", + "integrity": "sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA==", + "requires": {} + }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -28178,8 +28417,7 @@ "yaml": { "version": "1.10.2", "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", - "dev": true + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==" }, "yargs": { "version": "16.2.0", diff --git a/package.json b/package.json index 102b845..8ae202a 100644 --- a/package.json +++ b/package.json @@ -6,13 +6,14 @@ "@fortawesome/free-regular-svg-icons": "^6.2.0", "@fortawesome/free-solid-svg-icons": "^6.1.1", "@fortawesome/react-fontawesome": "^0.2.0", - "bootstrap-dark-5": "^1.1.3", + "bootstrap": "^5.2.3", "http-proxy-middleware": "^2.0.6", "moment": "^2.29.3", "react": "^18.2.0", "react-bootstrap": "^2.5.0", "react-dom": "^18.2.0", "react-router-dom": "^5.3.0", + "react-select": "^5.7.2", "react-table": "^7.8.0" }, "scripts": { diff --git a/src/App.css b/src/App.css deleted file mode 100644 index e636f69..0000000 --- a/src/App.css +++ /dev/null @@ -1,215 +0,0 @@ -html.loading { - display: none; -} - -body { - line-height: 1; -} - -.popover { - max-width: 1000px; -} - -.elide { - text-overflow: ellipsis; -} - -.App-logo { - height: 32px; -} - -.active{ - font-weight: bold; -} - -.label-help { - padding-top: 4px; - padding-bottom: 8px; - font-size: 90%; -} - -.required { - font-weight: bold; -} - -.policyFieldColumn { - margin-top: 4px; -} - -.policyEditorHeader { - font-size: 110%; - font-weight: bold; - padding-top: 4px; - padding-bottom: 4px; -} - -.policyField { - font-weight: bold; -} - -.providerParams { - padding: 10px; -} - -.providerIcon { - width: 120px; - height: 110px; - margin: 10px; - vertical-align: middle; -} - -.advancedOptions { - background-color: #f0f0f0; - padding: 10px; - border: 1px solid #ccc; -} - -.providerSpecificParams { - background-color: #f0f0ff; - border: 2px solid #ddd; - padding: 10px; - margin-left: 0px; - margin-top: 0px; - margin-bottom: 10px; -} - -.debug-json { - font-size: 80%; -} - -.error { - color: red; -} - -.normal { - display: block; -} - -.hidden { - display: none; -} - -.accordion-button { - padding: 10px; - font-weight: bold; -} - -.accordion-button.collapsed { - padding: 10px; - font-weight: bold; - background-color: #f8f8ff; -} - -div.tab-body { - padding: 10px; - border-left: 1px solid #ccc; - border-right: 1px solid #ccc; - border-bottom: 1px solid #ccc; -} - -.policy-help { - font-size: 80%; - font-weight: normal; -} - -.new-policy-panel { - padding: 10px; -} - -#snapshot-path { - width: 400px; -} - -.version-info { - padding-left: 10px; - color: #aaa; - font-size: 80%; -} - -#mountedPath { - color: #444; - width: 30em; - background-color: #ccc; - font-size: 12pt; - padding: 4px; - border: 1px solid #aaa; -} - -.logs-table { - font-family: monospace; - font-size: 11px; - overflow: auto; - max-height: 400px; - border: 1px solid #888; -} - -.loglevel-0 { } /* debug */ -.loglevel-1 { font-weight: bold;} /* info */ -.loglevel-2 { color: rgb(169, 112, 5); font-weight: bold;} /* warning */ -.loglevel-3 { color: red; font-weight: bold; } /* error */ - -.counter-badge { - font-size: 90%; - margin: 2px; -} - -.page-title { - margin-left: 10px; - font-weight: bold; - height: 40px; - font-size: 125%; - vertical-align: text-bottom; -} - -.nested-task { - padding: 10px; - padding-left: 40px; -} - -.estimateResults { - font-size: 95%; -} - -.list-actions { - min-height: 40px; -} - -.cli-equivalent { - font-family: monospace; -} - -nav.navbar { - padding-left: 10px; - padding-right: 10px; - margin-bottom: 10px; -} - -.vpadded { - padding-top: 6px; - padding-bottom: 6px; -} - -.multiselect { - width: 20px; - padding-left: 35px; - padding-top: 0x; - margin-top: -5px; - padding-bottom: 0px; - margin-bottom: 0px; -} - -.hash-value { - font-family: 'Courier New', Courier, monospace; - font-size: 80%; - font-weight: bold; -} - -.snapshot-description { - font-size: 80%; -} - -.log-parameter { - color: #000080; - font-weight: bold; - padding-right: 10px; -} \ No newline at end of file diff --git a/src/App.jsx b/src/App.jsx index 6c92fd2..fcf7551 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -1,11 +1,10 @@ +import 'bootstrap/dist/css/bootstrap.min.css'; +import './css/Theme.css'; +import './css/App.css'; import axios from 'axios'; -import 'bootstrap-dark-5/dist/css/bootstrap-nightshade.min.css'; -import React, { Component } from 'react'; -import Container from 'react-bootstrap/Container'; -import Nav from 'react-bootstrap/Nav'; -import Navbar from 'react-bootstrap/Navbar'; +import { React, Component } from 'react'; +import { Navbar, Nav, Container } from 'react-bootstrap'; import { BrowserRouter as Router, NavLink, Redirect, Route, Switch } from 'react-router-dom'; -import './App.css'; import { BeginRestore } from './BeginRestore'; import { DirectoryObject } from "./DirectoryObject"; import { PoliciesTable } from "./PoliciesTable"; @@ -16,8 +15,8 @@ import { TaskDetails } from './TaskDetails'; import { TasksTable } from './TasksTable'; import { NewSnapshot } from './NewSnapshot'; import { PolicyEditorPage } from './PolicyEditorPage'; -import { ToggleDarkModeButton } from './ToggleDarkModeButton'; -import { AppContext } from './AppContext'; +import { PreferencesView } from './PreferencesView'; +import { AppContext } from './contexts/AppContext'; import { UIPreferenceProvider } from './contexts/UIPreferencesContext'; export default class App extends Component { @@ -51,7 +50,6 @@ export default class App extends Component { } this.fetchInitialRepositoryDescription(); - this.taskSummaryInterval = window.setInterval(this.fetchTaskSummary, 5000); } @@ -62,7 +60,7 @@ export default class App extends Component { repoDescription: result.data.description, }); } - }).catch(error => { /* ignore */}); + }).catch(error => { /* ignore */ }); } fetchTaskSummary() { @@ -115,9 +113,7 @@ export default class App extends Component { Repository - - @@ -138,8 +134,9 @@ export default class App extends Component { + - + diff --git a/src/DirectoryItems.jsx b/src/DirectoryItems.jsx index 6653cd4..5159e32 100644 --- a/src/DirectoryItems.jsx +++ b/src/DirectoryItems.jsx @@ -2,6 +2,7 @@ import React, { Component } from 'react'; import { Link } from "react-router-dom"; import MyTable from './Table'; import { objectLink, rfc3339TimestampForDisplay, sizeWithFailures } from './uiutil'; +import { UIPreferencesContext } from './contexts/UIPreferencesContext'; function objectName(name, typeID) { if (typeID === "d") { @@ -33,6 +34,7 @@ function directoryLinkOrDownload(x) { export class DirectoryItems extends Component { render() { + const { bytesStringBase2 } = this.context; const columns = [{ id: "name", Header: 'Name', @@ -49,7 +51,7 @@ export class DirectoryItems extends Component { accessor: x => sizeInfo(x), Header: "Size", width: 100, - Cell: x => sizeWithFailures(x.cell.value, x.row.original.summ), + Cell: x => sizeWithFailures(x.cell.value, x.row.original.summ, bytesStringBase2), }, { id: "files", accessor: "summ.files", @@ -65,3 +67,4 @@ export class DirectoryItems extends Component { return ; } } +DirectoryItems.contextType = UIPreferencesContext \ No newline at end of file diff --git a/src/EstimateResults.jsx b/src/EstimateResults.jsx index 9d9d5a8..de128d3 100644 --- a/src/EstimateResults.jsx +++ b/src/EstimateResults.jsx @@ -7,7 +7,8 @@ import Button from 'react-bootstrap/Button'; import Spinner from 'react-bootstrap/esm/Spinner'; import Form from 'react-bootstrap/Form'; import { TaskLogs } from './TaskLogs'; -import { cancelTask, redirectIfNotConnected, sizeDisplayName } from './uiutil'; +import { cancelTask, redirect, sizeDisplayName } from './uiutil'; +import { UIPreferencesContext } from './contexts/UIPreferencesContext'; export class EstimateResults extends Component { constructor() { @@ -55,7 +56,7 @@ export class EstimateResults extends Component { this.interval = null; } }).catch(error => { - redirectIfNotConnected(error); + redirect(error); this.setState({ error, isLoading: false @@ -87,6 +88,7 @@ export class EstimateResults extends Component { render() { const { task, isLoading, error } = this.state; + const { bytesStringBase2 } = this.context if (error) { return

{error.message}

; } @@ -97,20 +99,21 @@ export class EstimateResults extends Component { return <> {task.counters && - {this.taskStatusDescription(task)} Bytes: {sizeDisplayName(task.counters["Bytes"]?.value)} ({sizeDisplayName(task.counters["Excluded Bytes"]?.value)} excluded) + {this.taskStatusDescription(task)} Bytes: {sizeDisplayName(task.counters["Bytes"]?.value, bytesStringBase2)} ({sizeDisplayName(task.counters["Excluded Bytes"]?.value, bytesStringBase2)} excluded) Files: {task.counters["Files"]?.value} ({task.counters["Excluded Files"]?.value} excluded) Directories: {task.counters["Directories"]?.value} ({task.counters["Excluded Directories"]?.value} excluded) Errors: {task.counters["Errors"]?.value} ({task.counters["Ignored Errors"]?.value} ignored) - + } - {task.status === "RUNNING" && <> -   - } - {this.state.showLog ? <> - - - : } + {task.status === "RUNNING" && <> +   + } + {this.state.showLog ? <> + + + : } ; } } +EstimateResults.contextType = UIPreferencesContext \ No newline at end of file diff --git a/src/NewSnapshot.jsx b/src/NewSnapshot.jsx index ef53fb9..1a62fd9 100644 --- a/src/NewSnapshot.jsx +++ b/src/NewSnapshot.jsx @@ -7,7 +7,7 @@ import Row from 'react-bootstrap/Row'; import { handleChange } from './forms'; import { PolicyEditor } from './PolicyEditor'; import { EstimateResults } from './EstimateResults'; -import { CLIEquivalent, DirectorySelector, errorAlert, GoBackButton, redirectIfNotConnected } from './uiutil'; +import { CLIEquivalent, DirectorySelector, errorAlert, GoBackButton, redirect } from './uiutil'; export class NewSnapshot extends Component { constructor() { @@ -35,7 +35,7 @@ export class NewSnapshot extends Component { localHost: result.data.localHost, }); }).catch(error => { - redirectIfNotConnected(error); + redirect(error); }); } @@ -54,7 +54,7 @@ export class NewSnapshot extends Component { // while we were resolving this.maybeResolveCurrentPath(currentPath); }).catch(error => { - redirectIfNotConnected(error); + redirect(error); }); } else { this.setState({ @@ -166,7 +166,7 @@ export class NewSnapshot extends Component { size="sm" disabled={!this.state.resolvedSource?.path} title="Estimate" - variant="primary" + variant="secondary" onClick={this.estimate}>Estimate   diff --git a/src/PoliciesTable.jsx b/src/PoliciesTable.jsx index 4b4568c..c7aac11 100644 --- a/src/PoliciesTable.jsx +++ b/src/PoliciesTable.jsx @@ -11,7 +11,7 @@ import Row from 'react-bootstrap/Row'; import { Link } from 'react-router-dom'; import { handleChange } from './forms'; import MyTable from './Table'; -import { CLIEquivalent, compare, DirectorySelector, isAbsolutePath, ownerName, policyEditorURL, redirectIfNotConnected } from './uiutil'; +import { CLIEquivalent, compare, DirectorySelector, isAbsolutePath, ownerName, policyEditorURL, redirect } from './uiutil'; const applicablePolicies = "Applicable Policies" const localPolicies = "Local Path Policies" @@ -68,7 +68,7 @@ export class PoliciesTable extends Component { isLoading: false, }); }).catch(error => { - redirectIfNotConnected(error); + redirect(error); this.setState({ error, isLoading: false @@ -87,7 +87,7 @@ export class PoliciesTable extends Component { isLoading: false, }); }).catch(error => { - redirectIfNotConnected(error); + redirect(error); this.setState({ error, isLoading: false @@ -174,7 +174,6 @@ export class PoliciesTable extends Component { return

Loading ...

; } - let uniqueOwners = sources.reduce((a, d) => { const owner = ownerName(d.source); @@ -245,7 +244,7 @@ export class PoliciesTable extends Component { id: 'edit', Header: '', width: 50, - Cell: x => , + Cell: x => }] return <> diff --git a/src/PolicyEditor/index.jsx b/src/PolicyEditor/index.jsx index 307eba0..4ad970e 100644 --- a/src/PolicyEditor/index.jsx +++ b/src/PolicyEditor/index.jsx @@ -249,7 +249,7 @@ export class PolicyEditor extends Component { } return <> -
+  Snapshot Retention @@ -551,7 +551,7 @@ export class PolicyEditor extends Component { - {!this.props.embedded && } + {!this.props.embedded && } {!this.state.isNew && !this.props.embedded && <>  } diff --git a/src/PreferencesView.jsx b/src/PreferencesView.jsx new file mode 100644 index 0000000..8f80918 --- /dev/null +++ b/src/PreferencesView.jsx @@ -0,0 +1,39 @@ +import { Component } from 'react'; +import { UIPreferencesContext } from './contexts/UIPreferencesContext'; + +export class PreferencesView extends Component { + render() { + const { pageSize, theme, bytesStringBase2, setByteStringBase, setTheme } = this.context; + return <> + +
+ + + The current active theme +
+
+
+ + + Specifies the representation of bytes +
+
+
+ + + Specifies the pagination size in tables +
+
+ + } +} +PreferencesView.contextType = UIPreferencesContext diff --git a/src/RepoStatus.jsx b/src/RepoStatus.jsx index b95e324..b7dc6e2 100644 --- a/src/RepoStatus.jsx +++ b/src/RepoStatus.jsx @@ -13,7 +13,7 @@ import { cancelTask, CLIEquivalent } from './uiutil'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faCheck, faChevronCircleDown, faChevronCircleUp, faWindowClose } from '@fortawesome/free-solid-svg-icons'; import { TaskLogs } from './TaskLogs'; -import { AppContext } from './AppContext'; +import { AppContext } from './contexts/AppContext'; export class RepoStatus extends Component { constructor() { diff --git a/src/SetupRepository.jsx b/src/SetupRepository.jsx index b0cff35..d172d72 100644 --- a/src/SetupRepository.jsx +++ b/src/SetupRepository.jsx @@ -8,7 +8,7 @@ import Collapse from 'react-bootstrap/Collapse'; import Form from 'react-bootstrap/Form'; import Row from 'react-bootstrap/Row'; import Spinner from 'react-bootstrap/Spinner'; -import { AppContext } from './AppContext'; +import { AppContext } from './contexts/AppContext'; import { handleChange, validateRequiredFields } from './forms'; import { RequiredBoolean } from './forms/RequiredBoolean'; import { RequiredField } from './forms/RequiredField'; @@ -229,7 +229,7 @@ export class SetupRepository extends Component { )} @@ -313,7 +313,7 @@ export class SetupRepository extends Component { {this.connectionErrorInfo()}
- +   {this.loadingSpinner()} @@ -326,7 +326,7 @@ export class SetupRepository extends Component { const text = this.state.showAdvanced ? "Hide Advanced Options" : "Show Advanced Options"; return +   - + {this.loadingSpinner()} ; } @@ -493,9 +493,9 @@ export class SetupRepository extends Component { {this.connectionErrorInfo()}
- +   - + {this.loadingSpinner()} ; } diff --git a/src/SnapshotsTable.jsx b/src/SnapshotsTable.jsx index 54f0a55..9d89317 100644 --- a/src/SnapshotsTable.jsx +++ b/src/SnapshotsTable.jsx @@ -8,11 +8,12 @@ import Col from 'react-bootstrap/Col'; import Spinner from 'react-bootstrap/Spinner'; import { Link } from "react-router-dom"; import MyTable from './Table'; -import { CLIEquivalent, compare, errorAlert, GoBackButton, objectLink, parseQuery, redirectIfNotConnected, rfc3339TimestampForDisplay, sizeWithFailures, sourceQueryStringParams } from './uiutil'; +import { CLIEquivalent, compare, errorAlert, GoBackButton, objectLink, parseQuery, redirect, rfc3339TimestampForDisplay, sizeWithFailures, sourceQueryStringParams } from './uiutil'; import { faSync, faThumbtack } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import Modal from 'react-bootstrap/Modal'; import { faFileAlt } from '@fortawesome/free-regular-svg-icons'; +import { UIPreferencesContext } from './contexts/UIPreferencesContext'; function pillVariant(tag) { if (tag.startsWith("latest-")) { @@ -142,7 +143,7 @@ export class SnapshotsTable extends Component { this.fetchSnapshots(); } }).catch(error => { - redirectIfNotConnected(error); + redirect(error); errorAlert(error); }); @@ -164,7 +165,7 @@ export class SnapshotsTable extends Component { axios.post('/api/v1/snapshots/delete', req).then(result => { this.props.history.goBack(); }).catch(error => { - redirectIfNotConnected(error); + redirect(error); errorAlert(error); }); } @@ -307,13 +308,14 @@ export class SnapshotsTable extends Component { editingDescriptionFor: undefined, savingSnapshot: false, }); - redirectIfNotConnected(e); + redirect(e); errorAlert(e); }); } render() { let { snapshots, unfilteredCount, uniqueCount, isLoading, error } = this.state; + const { bytesStringBase2 } = this.context if (error) { return

{error.message}

; } @@ -362,7 +364,7 @@ export class SnapshotsTable extends Component { Header: 'Size', accessor: 'summary.size', width: 100, - Cell: x => sizeWithFailures(x.cell.value, x.row.original.summary), + Cell: x => sizeWithFailures(x.cell.value, x.row.original.summary, bytesStringBase2), }, { Header: 'Files', accessor: 'summary.files', @@ -450,7 +452,7 @@ export class SnapshotsTable extends Component { - + @@ -473,7 +475,7 @@ export class SnapshotsTable extends Component { {this.state.savingSnapshot && } {this.state.originalSnapshotDescription && } - + @@ -496,9 +498,10 @@ export class SnapshotsTable extends Component { {this.state.savingSnapshot && } {this.state.originalPinName && } - + ; } } +SnapshotsTable.contextType = UIPreferencesContext diff --git a/src/SourcesTable.jsx b/src/SourcesTable.jsx index 29474ff..0a730d2 100644 --- a/src/SourcesTable.jsx +++ b/src/SourcesTable.jsx @@ -12,7 +12,8 @@ import Spinner from 'react-bootstrap/Spinner'; import { Link } from 'react-router-dom'; import { handleChange } from './forms'; import MyTable from './Table'; -import { CLIEquivalent, compare, errorAlert, ownerName, policyEditorURL, redirectIfNotConnected, sizeDisplayName, sizeWithFailures, sourceQueryStringParams } from './uiutil'; +import { CLIEquivalent, compare, errorAlert, ownerName, policyEditorURL, redirect, sizeDisplayName, sizeWithFailures, sourceQueryStringParams } from './uiutil'; +import { UIPreferencesContext } from './contexts/UIPreferencesContext'; const localSnapshots = "Local Snapshots" const allSnapshots = "All Snapshots" @@ -66,7 +67,7 @@ export class SourcesTable extends Component { isRefreshing: false, }); }).catch(error => { - redirectIfNotConnected(error); + redirect(error); this.setState({ error, isRefreshing: false, @@ -96,15 +97,16 @@ export class SourcesTable extends Component { }); } - statusCell(x, parent) { + statusCell(x, parent, bytesStringBase2) { switch (x.cell.value) { case "IDLE": case "PAUSED": return <> - + -   + }}>Snapshot Now + ; case "PENDING": @@ -118,15 +120,15 @@ export class SourcesTable extends Component { let title = ""; let totals = ""; if (u) { - title = " hashed " + u.hashedFiles + " files (" + sizeDisplayName(u.hashedBytes) + ")\n" + - " cached " + u.cachedFiles + " files (" + sizeDisplayName(u.cachedBytes) + ")\n" + + title = " hashed " + u.hashedFiles + " files (" + sizeDisplayName(u.hashedBytes, bytesStringBase2) + ")\n" + + " cached " + u.cachedFiles + " files (" + sizeDisplayName(u.cachedBytes, bytesStringBase2) + ")\n" + " dir " + u.directory; const totalBytes = u.hashedBytes + u.cachedBytes; - totals = sizeDisplayName(totalBytes); + totals = sizeDisplayName(totalBytes, bytesStringBase2); if (u.estimatedBytes) { - totals += "/" + sizeDisplayName(u.estimatedBytes); + totals += "/" + sizeDisplayName(u.estimatedBytes, bytesStringBase2); const percent = Math.round(totalBytes * 1000.0 / u.estimatedBytes) / 10.0; if (percent <= 100) { @@ -185,6 +187,7 @@ export class SourcesTable extends Component { render() { let { sources, isLoading, error } = this.state; + const { bytesStringBase2 } = this.context if (error) { return

{error.message}

; } @@ -241,7 +244,7 @@ export class SourcesTable extends Component { accessor: x => x.lastSnapshot ? x.lastSnapshot.stats.totalSize : 0, Cell: x => sizeWithFailures( x.cell.value, - x.row.original.lastSnapshot && x.row.original.lastSnapshot.rootEntry ? x.row.original.lastSnapshot.rootEntry.summ : null), + x.row.original.lastSnapshot && x.row.original.lastSnapshot.rootEntry ? x.row.original.lastSnapshot.rootEntry.summ : null, bytesStringBase2), }, { id: 'lastSnapshotTime', Header: 'Last Snapshot', @@ -259,7 +262,7 @@ export class SourcesTable extends Component { Header: '', width: 300, accessor: x => x.status, - Cell: x => this.statusCell(x, this), + Cell: x => this.statusCell(x, this, bytesStringBase2), }] return <> @@ -280,7 +283,7 @@ export class SourcesTable extends Component { } - + @@ -297,3 +300,4 @@ export class SourcesTable extends Component { ; } } +SourcesTable.contextType = UIPreferencesContext \ No newline at end of file diff --git a/src/TaskDetails.jsx b/src/TaskDetails.jsx index 6f5460a..3c458c3 100644 --- a/src/TaskDetails.jsx +++ b/src/TaskDetails.jsx @@ -11,7 +11,8 @@ import Row from 'react-bootstrap/Row'; import Table from 'react-bootstrap/Table'; import Spinner from 'react-bootstrap/Spinner'; import { TaskLogs } from './TaskLogs'; -import { cancelTask, formatDuration, GoBackButton, redirectIfNotConnected, sizeDisplayName } from './uiutil'; +import { cancelTask, formatDuration, GoBackButton, redirect, sizeDisplayName } from './uiutil'; +import { UIPreferencesContext } from './contexts/UIPreferencesContext'; export class TaskDetails extends Component { constructor() { @@ -60,7 +61,7 @@ export class TaskDetails extends Component { this.interval = null; } }).catch(error => { - redirectIfNotConnected(error); + redirect(error); this.setState({ error, isLoading: false @@ -157,6 +158,7 @@ export class TaskDetails extends Component { render() { const { task, isLoading, error } = this.state; + const { bytesStringBase2 } = this.context if (error) { return

{error.message}

; } @@ -192,7 +194,7 @@ export class TaskDetails extends Component { - {this.sortedBadges(task.counters)} + {this.sortedBadges(task.counters, bytesStringBase2)} @@ -221,3 +223,4 @@ export class TaskDetails extends Component { ; } } +TaskDetails.contextType = UIPreferencesContext \ No newline at end of file diff --git a/src/TaskLogs.jsx b/src/TaskLogs.jsx index 50f19be..d2c43f4 100644 --- a/src/TaskLogs.jsx +++ b/src/TaskLogs.jsx @@ -1,9 +1,8 @@ - import axios from 'axios'; import React, { Component } from 'react'; import Table from 'react-bootstrap/Table'; import { handleChange } from './forms'; -import { redirectIfNotConnected } from './uiutil'; +import { redirect } from './uiutil'; export class TaskLogs extends Component { constructor() { @@ -54,7 +53,7 @@ export class TaskLogs extends Component { this.scrollToBottom(); } }).catch(error => { - redirectIfNotConnected(error); + redirect(error); this.setState({ error, isLoading: false @@ -83,7 +82,7 @@ export class TaskLogs extends Component { formatLogParams(entry) { // if there are any properties other than `msg, ts, level, mod` output them as JSON. - let {msg, ts, level, mod, ...parametersOnly} = entry; + let { msg, ts, level, mod, ...parametersOnly } = entry; const p = JSON.stringify(parametersOnly); if (p !== "{}") { @@ -112,11 +111,11 @@ export class TaskLogs extends Component { if (logs) { return
- {logs.map((v,ndx) => + {logs.map((v, ndx) => )}
{this.formatLogTime(v.ts)} {v.msg} {this.formatLogParams(v)}
-
+
; } diff --git a/src/TasksTable.jsx b/src/TasksTable.jsx index 69f0be6..d4a9198 100644 --- a/src/TasksTable.jsx +++ b/src/TasksTable.jsx @@ -12,7 +12,7 @@ import Row from 'react-bootstrap/Row'; import { Link } from 'react-router-dom'; import { handleChange } from './forms'; import MyTable from './Table'; -import { redirectIfNotConnected, taskStatusSymbol } from './uiutil'; +import { redirect, taskStatusSymbol } from './uiutil'; export class TasksTable extends Component { constructor() { @@ -66,7 +66,7 @@ export class TasksTable extends Component { isLoading: false, }); }).catch(error => { - redirectIfNotConnected(error); + redirect(error); this.setState({ error, isLoading: false diff --git a/src/ToggleDarkModeButton.tsx b/src/ToggleDarkModeButton.tsx deleted file mode 100644 index 0c81d6f..0000000 --- a/src/ToggleDarkModeButton.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import { faMoon, faSun } from '@fortawesome/free-solid-svg-icons'; -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { useContext } from 'react'; -import Button from 'react-bootstrap/Button'; -import { UIPreferencesContext } from './contexts/UIPreferencesContext'; - -export function ToggleDarkModeButton() { - const { theme, setTheme } = useContext(UIPreferencesContext); - - // keep html class in sync with button state. - const h = document.querySelector("html")!; - h.className = theme; - - return theme === "dark" - ? - : ; -} diff --git a/src/AppContext.js b/src/contexts/AppContext.tsx similarity index 100% rename from src/AppContext.js rename to src/contexts/AppContext.tsx diff --git a/src/contexts/UIPreferencesContext.tsx b/src/contexts/UIPreferencesContext.tsx index 28c965a..94cf1f4 100644 --- a/src/contexts/UIPreferencesContext.tsx +++ b/src/contexts/UIPreferencesContext.tsx @@ -2,36 +2,42 @@ import React, { ReactNode, useEffect, useState } from 'react'; import axios from 'axios'; export const PAGE_SIZES = [10, 20, 30, 40, 50, 100]; +export const UIPreferencesContext = React.createContext({} as UIPreferences); -export type Theme = "dark" | "light"; +const DEFAULT_PREFERENCES = { pageSize: PAGE_SIZES[0], bytesStringBase2: false, theme: getDefaultTheme() } as SerializedUIPreferences; +const PREFERENCES_URL = '/api/v1/ui-preferences'; +export type Theme = "light" | "dark" | "pastel" | "ocean"; export type PageSize = 10 | 20 | 30 | 40 | 50 | 100; export interface UIPreferences { get pageSize(): PageSize get theme(): Theme + get bytesStringBase2(): boolean setTheme: (theme: Theme) => void setPageSize: (pageSize: number) => void + setByteStringBase: (bytesStringBase2: String) => void } interface SerializedUIPreferences { pageSize?: number + bytesStringBase2?: boolean theme: Theme | undefined } -export const UIPreferencesContext = React.createContext({} as UIPreferences); - export interface UIPreferenceProviderProps { children: ReactNode, initalValue: UIPreferences | undefined } +/** + * Returns a default theme based on the user's browser settings. + * @returns Theme + */ function getDefaultTheme(): Theme { if (window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches) { - // browser supports light/dark mode and user prefers dark theme. return "dark"; } - return "light"; } @@ -48,14 +54,9 @@ function normalizePageSize(pageSize: number): PageSize { return PAGE_SIZES[index - 1] as PageSize; } } - return 100; } -const PREFERENCES_URL = '/api/v1/ui-preferences'; - -const DEFAULT_PREFERENCES = { pageSize: PAGE_SIZES[0], theme: getDefaultTheme() } as SerializedUIPreferences; - export function UIPreferenceProvider(props: UIPreferenceProviderProps) { const [preferences, setPreferences] = useState(DEFAULT_PREFERENCES); @@ -70,20 +71,37 @@ export function UIPreferenceProvider(props: UIPreferenceProviderProps) { } else { storedPreferences.pageSize = normalizePageSize(storedPreferences.pageSize); } - + syncTheme(storedPreferences.theme) setPreferences(storedPreferences); }).catch(err => console.error(err)); + }, []); useEffect(() => { if (!preferences) { return; } - - axios.put(PREFERENCES_URL, preferences).then(result => {}).catch(err => console.error(err)); + axios.put(PREFERENCES_URL, preferences).then(result => { }).catch(err => console.error(err)); }, [preferences]); + /** + * Synchronizes the selected theme with the html class + * + * @param theme + * The theme to be set + */ + const syncTheme = (theme: Theme) => { + var doc = document.querySelector("html")!; + doc.className = theme + } + + /** + * + * @param theme + * @returns + */ const setTheme = (theme: Theme) => setPreferences(oldPreferences => { + syncTheme(theme); return { ...oldPreferences, theme }; }); @@ -91,7 +109,12 @@ export function UIPreferenceProvider(props: UIPreferenceProviderProps) { return { ...oldPreferences, pageSize }; }); - const providedValue = { ...preferences, setTheme, setPageSize } as UIPreferences; + const setByteStringBase = (input: String) => setPreferences(oldPreferences => { + var bytesStringBase2 = input === "true"; + return { ...oldPreferences, bytesStringBase2 }; + }); + + const providedValue = { ...preferences, setTheme, setPageSize, setByteStringBase} as UIPreferences; return {props.children} diff --git a/src/css/App.css b/src/css/App.css new file mode 100644 index 0000000..09927cf --- /dev/null +++ b/src/css/App.css @@ -0,0 +1,360 @@ +html.loading { + display: none; +} + +body { + line-height: 1; + background-color: var(--background-color); +} + +.container-fluid { + color: var(--text-color-body); +} + +.select_theme { + font-size: 90%; +} + +.options-select { + overflow: ellipsis +} + +.btn { + color: var(--text-color); + margin-right: 5px; +} + +.btn-primary { + background-color: var(--color-primary); + border-color: var(--color-primary); +} + +.btn-secondary { + background-color: var(--color-secondary); + border-color: var(--color-secondary); +} + +.btn-submit { + background-color: var(--color-submit); + border-color: var(--color-submit); +} + +.btn-success { + background-color: var(--color-success); + border-color: var(--color-success); +} + +.btn-warning { + background-color: var(--color-warning); + border-color: var(--color-warning); +} + +.btn-danger { + background-color: var(--color-danger); + border-color: var(--color-danger); +} + +.btn-primary:hover, .btn-primary:focus, .btn-primary:active { + background-color: var(--color-primary); + border-color: var(--color-primary); + color: var(--text-color); + filter: brightness(80%); +} + +.btn-secondary:hover, .btn-secondary:focus, .btn-secondary:active { + background-color: var(--color-secondary); + border-color: var(--color-secondary); + color: var(--text-color); + filter: brightness(80%); +} + +.btn-warning:hover, .btn-warning:focus, .btn-warning:active { + background-color: var(--color-warning); + border-color: var(--color-warning); + color: var(--text-color); + filter: brightness(80%); +} + +.btn-success:hover, .btn-success:focus, .btn-success:active { + background-color: var(--color-success); + border-color: var(--color-success); + color: var(--text-color); + filter: brightness(80%); +} + +.btn-danger:hover, .btn-danger:focus, .btn-danger:active { + background-color: var(--color-danger); + border-color: var(--color-danger); + color: var(--text-color); + filter: brightness(80%); +} + +.btn-submit:hover, .btn-submit:focus, .btn-submit:active { + background-color: var(--color-submit); + border-color: var(--color-submit); + color: var(--text-color); + filter: brightness(80%); +} + +.table-striped>tbody>tr:nth-of-type(odd)>* { + color: var(--text-color-body); + background-color: var(--color-stripe); +} + +.table-striped>tbody>tr:nth-of-type(even)>* { + color: var(--text-color-body); +} + +.navbar-light .navbar-nav .nav-link { + color: var(--text-color-nav); +} + +.table { + color: var(--text-color-body); +} + +.table-hover>tbody>tr:hover>* { + color: var(--text-color-body); +} + +.navbar-light .navbar-nav .nav-link.active, .navbar-light .navbar-nav .show>.nav-link { + color: var(--text-color-nav); +} + +.nav-link:hover { + color: var(--text-color-nav) !important; + filter: brightness(80%); +} + +.accordion-body { + color: var(--text-color-body); + background-color: var(--background-color); +} + +.accordion-button:not(.collapsed) { + color: var(--text-color-body) !important; + background-color: var(--background-color) !important; +} + +.accordion-button:link, .accordion-button:visited, .accordion-button:hover, .accordion-button:active { + background-color: var(--color-select) !important; + color: var(--text-color-body) !important; +} + +.accordion-button { + background-color: var(--background-color) !important; + color: var(--text-color-body) !important; +} + +.popover { + max-width: 1000px; +} + +.elide { + text-overflow: ellipsis; +} + +.App-logo { + height: 32px; +} + +.active{ + font-weight: bold; +} + +.label-description { + padding-top: 4px; + padding-bottom: 8px; +} + +.label-help { + padding-top: 1rem; + padding-bottom: 8px; + font-size: 90%; +} + +.required { + font-weight: bold; +} + +.policyFieldColumn { + margin-top: 4px; +} + +.policyEditorHeader { + font-size: 110%; + font-weight: bold; + padding-top: 4px; + padding-bottom: 4px; +} + +.policyField { + font-weight: bold; +} + +.providerParams { + padding: 10px; +} + +.providerIcon { + width: 120px; + height: 110px; + margin: 10px; + vertical-align: middle; +} + +.advancedOptions { + background-color: #f0f0f0; + padding: 10px; + border: 1px solid #ccc; +} + +.providerSpecificParams { + background-color: #f0f0ff; + border: 2px solid #ddd; + padding: 10px; + margin-left: 0px; + margin-top: 0px; + margin-bottom: 10px; +} + +.debug-json { + font-size: 80%; +} + +.error { + color: var(--color-error); +} + +.normal { + display: block; +} + +.hidden { + display: none; +} + +.accordion-button { + padding: 10px; + font-weight: bold; +} + +.accordion-button.collapsed { + padding: 10px; + font-weight: bold; + background-color: #f8f8ff; +} + +div.tab-body { + padding: 10px; + border-left: 1px solid #ccc; + border-right: 1px solid #ccc; + border-bottom: 1px solid #ccc; +} + +.policy-help { + font-size: 80%; + font-weight: normal; +} + +.new-policy-panel { + padding: 10px; +} + +#snapshot-path { + width: 400px; +} + +.version-info { + padding-left: 10px; + color: #aaa; + font-size: 80%; +} + +#mountedPath { + color: #444; + width: 30em; + background-color: #ccc; + font-size: 12pt; + padding: 4px; + border: 1px solid #aaa; +} + +.logs-table { + font-family: monospace; + font-size: 11px; + overflow: auto; + max-height: 400px; + border: 1px solid #aaa; +} + +.loglevel-0 { color: var(--text-color-body)} /* debug */ +.loglevel-1 { font-weight: bold;} /* info */ +.loglevel-2 { color: var(--color-warning); font-weight: bold;} /* warning */ +.loglevel-3 { color: var(--color-error); font-weight: bold; } /* error */ + +.counter-badge { + font-size: 90%; + margin: 2px; +} + +.page-title { + margin-left: 10px; + font-weight: bold; + height: 40px; + font-size: 125%; + vertical-align: text-bottom; +} + +.nested-task { + padding: 10px; + padding-left: 40px; +} + +.estimateResults { + font-size: 95%; +} + +.list-actions { + min-height: 40px; +} + +.cli-equivalent { + font-family: monospace; +} + +nav.navbar { + padding-left: 10px; + padding-right: 10px; + margin-bottom: 10px; +} + +.vpadded { + padding-top: 6px; + padding-bottom: 6px; +} + +.multiselect { + width: 20px; + padding-left: 35px; + padding-top: 0x; + margin-top: -5px; + padding-bottom: 0px; + margin-bottom: 0px; +} + +.hash-value { + font-family: 'Courier New', Courier, monospace; + font-size: 80%; + font-weight: bold; +} + +.snapshot-description { + font-size: 80%; +} + +.log-parameter { + color: #000080; + font-weight: bold; + padding-right: 10px; +} \ No newline at end of file diff --git a/src/css/Theme.css b/src/css/Theme.css new file mode 100644 index 0000000..f3c068c --- /dev/null +++ b/src/css/Theme.css @@ -0,0 +1,70 @@ +/*Supported themes */ +.light { + --background-color: #ffffff; + --color-primary: #2A7FFF; + --color-secondary: #23a25a; + --color-warning: #e1704b; + --color-success: #5ea5cd; + --color-submit: #00B4D8; + --color-select: #f2f9ff; + + --text-color: #ffffff; + --text-color-body: #000000; + --text-color-nav: #000000; + + --color-error: #d2475a; + --color-danger: #d2475a; +} + +.dark { + --background-color: #222222; + --color-primary: #1162b1; + --color-secondary: #0d9aab; + --color-warning: #b30996; + --color-success: #0d9aab; + --color-submit: #00B4D8; + --color-stripe: #323232; + --color-select: #323232; + + --text-color: #cfcfcf; + --text-color-body: #cfcfcf; + --text-color-nav: #cfcfcf; + + + --color-error: #b31f04; + --color-danger: #b31f04; +} + +.pastel { + --background-color: #ffffff; + --color-primary: #9bf6ff; + --color-secondary: #bdb2ff; + --color-warning: #ffd6a5; + --color-success: #bdb2ff; + --color-submit: #a0c4ff; + --color-select: #f2f9ff; + + --text-color: #000000; + --text-color-body: #000000; + --text-color-nav: #c095e4; + + --color-error: #ffadad; + --color-danger: #ffadad; +} + +.ocean { + --background-color: #ffffff; + --color-primary: #03045E; + --color-secondary: #0077B6; + --color-warning: #ecd131; + --color-success: #0077B6; + --color-submit: #00B4D8; + --color-select: #f2f9ff; + + --text-color: #ffffff; + --text-color-body: #03045E; + --text-color-nav: #03045E; + + --color-error: #d2475a; + --color-danger: #d2475a; +} \ No newline at end of file diff --git a/src/index.css b/src/css/index.css similarity index 100% rename from src/index.css rename to src/css/index.css diff --git a/src/index.jsx b/src/index.jsx index 1bd9f79..3057d23 100644 --- a/src/index.jsx +++ b/src/index.jsx @@ -1,7 +1,7 @@ import React from 'react'; import { createRoot } from 'react-dom/client'; import App from './App'; -import './index.css'; +import './css/index.css'; const root = createRoot(document.getElementById('root')) root.render(); diff --git a/src/uiutil.jsx b/src/uiutil.jsx index 90d9b97..de58838 100644 --- a/src/uiutil.jsx +++ b/src/uiutil.jsx @@ -9,33 +9,33 @@ import InputGroup from 'react-bootstrap/InputGroup'; import Spinner from 'react-bootstrap/Spinner'; import { Link } from 'react-router-dom'; -const base10UnitPrefixes = ["", "K", "M", "G", "T"]; - // locale to use for number formatting (undefined would use default locale, but we stick to EN for now) const locale = "en-US" +const base10UnitPrefixes = ["", "K", "M", "G", "T"]; +const base2UnitPrefixes = ["", "Ki", "Mi", "Gi", "Ti"]; -function niceNumber(f) { +function formatNumber(f) { return (Math.round(f * 10) / 10.0) + ''; } function toDecimalUnitString(f, thousand, prefixes, suffix) { for (var i = 0; i < prefixes.length; i++) { if (f < 0.9 * thousand) { - return niceNumber(f) + ' ' + prefixes[i] + suffix; + return formatNumber(f) + ' ' + prefixes[i] + suffix; } f /= thousand } - return niceNumber(f) + ' ' + prefixes[prefixes.length - 1] + suffix; + return formatNumber(f) + ' ' + prefixes[prefixes.length - 1] + suffix; } -export function sizeWithFailures(size, summ) { +export function sizeWithFailures(size, summ, bytesStringBase2) { if (size === undefined) { return ""; } if (!summ || !summ.errors || !summ.numFailed) { - return {sizeDisplayName(size)} + return {sizeDisplayName(size, bytesStringBase2)} } let caption = "Encountered " + summ.numFailed + " errors:\n\n"; @@ -48,16 +48,19 @@ export function sizeWithFailures(size, summ) { caption += summ.errors.map(x => prefix + x.path + ": " + x.error).join("\n"); return - {sizeDisplayName(size)}  + {sizeDisplayName(size, bytesStringBase2)}  ; } -export function sizeDisplayName(s) { - if (s === undefined) { +export function sizeDisplayName(size, bytesStringBase2) { + if (size === undefined) { return ""; } - return toDecimalUnitString(s, 1000, base10UnitPrefixes, "B"); + if (bytesStringBase2) { + return toDecimalUnitString(size, 1024, base2UnitPrefixes, "B"); + } + return toDecimalUnitString(size, 1000, base10UnitPrefixes, "B"); } export function intervalDisplayName(v) { @@ -105,10 +108,13 @@ export function compare(a, b) { return (a < b ? -1 : (a > b ? 1 : 0)); } -export function redirectIfNotConnected(e) { +/** + * In case of an error, redirect to the repository selection + * @param {error} The error that was returned + */ +export function redirect(e) { if (e && e.response && e.response.data && e.response.data.code === "NOT_CONNECTED") { - window.location.replace("/repo"); - return; + window.location.replace("/repo") } } @@ -219,7 +225,7 @@ export function formatMagnitudesUsingMultipleUnits(magnitudes, abbreviateUnits = minimumFractionDigits: fractionDigits, maximumFractionDigits: fractionDigits, roundingMode: "trunc", - })}${fractionDigits ? (abbreviateUnits ? "s" : " seconds") : units.seconds }`); + })}${fractionDigits ? (abbreviateUnits ? "s" : " seconds") : units.seconds}`); } return parts.join(" "); @@ -293,7 +299,7 @@ export function cancelTask(tid) { } export function GoBackButton(props) { - return ; + return ; } export function PolicyTypeName(s) { @@ -403,8 +409,8 @@ export function CLIEquivalent(props) { return <> - - {visible && } + + {visible && } {visible && } ;