From c87f09684808bd08291fe986f8c91e52cd95af66 Mon Sep 17 00:00:00 2001 From: paluh Date: Fri, 24 Nov 2023 13:13:11 +0100 Subject: [PATCH] Handle wallet connection cancellation, timeouts and errors (#27) --- nix/gen/npm-deps-hash.nix | 2 +- nix/gen/spago-packages.nix | 6 +- package-lock.json | 440 ++++++++++++++++++++----- package.json | 1 + packages.dhall | 2 +- public/style.scss | 5 +- spago.dhall | 1 - src/Component/App.purs | 61 ++-- src/Component/ConnectWallet.purs | 209 +++++------- src/Component/LandingPage.purs | 82 +++-- src/Component/Widgets.purs | 24 ++ src/Contrib/Effect/Aff.purs | 18 + src/Contrib/ReactLoadingOverlayTs.js | 8 + src/Contrib/ReactLoadingOverlayTs.purs | 52 +++ 14 files changed, 624 insertions(+), 287 deletions(-) create mode 100644 src/Contrib/Effect/Aff.purs create mode 100644 src/Contrib/ReactLoadingOverlayTs.js create mode 100644 src/Contrib/ReactLoadingOverlayTs.purs diff --git a/nix/gen/npm-deps-hash.nix b/nix/gen/npm-deps-hash.nix index 2d354039..02330d99 100644 --- a/nix/gen/npm-deps-hash.nix +++ b/nix/gen/npm-deps-hash.nix @@ -1,2 +1,2 @@ # This file was generated by prefetch-npm-deps -"sha256-pZ5QQgWs5ymu+2Vieurq/B84uU1bIM2abwIcdnt0U8U=" +"sha256-3sDbVhLjIYiSICPJZfjneW6s2nNKsKSJxtkOt+xTKKQ=" diff --git a/nix/gen/spago-packages.nix b/nix/gen/spago-packages.nix index b756acd8..8d52349b 100644 --- a/nix/gen/spago-packages.nix +++ b/nix/gen/spago-packages.nix @@ -199,11 +199,11 @@ let "cardano-wallet-client" = pkgs.stdenv.mkDerivation { name = "cardano-wallet-client"; - version = "v0.1.0"; + version = "v0.1.1"; src = pkgs.fetchgit { url = "https://github.com/input-output-hk/purescript-cardano-wallet-client.git"; - rev = "a2b08694d2c9d5e55e0707a1ce7d292503ee1eca"; - sha256 = "1pin92qfjm8lvirkrc9n8i38940nsa12cfadz2m9drrzr0z45m29"; + rev = "d6c4be8bc24d285e700264ad29cf6b6b7623c6ed"; + sha256 = "09vqahbsawzp8qjcylvpcy1yrk0b489c4hd9z22jabs8mpai624r"; }; phases = "installPhase"; installPhase = "ln -s $src $out"; diff --git a/package-lock.json b/package-lock.json index d0cf69a2..8353f1de 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,6 +24,7 @@ "react-bootstrap": "^2.7.0", "react-dom": "^18.2.0", "react-icons": "^4.7.1", + "react-loading-overlay-ts": "^2.0.2", "react-markdown": "^8.0.5", "react-syntax-highlighter": "^15.5.0", "reactflow": "^11.7.2", @@ -72,7 +73,6 @@ "version": "7.22.13", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", - "dev": true, "dependencies": { "@babel/highlight": "^7.22.13", "chalk": "^2.4.2" @@ -196,8 +196,6 @@ "version": "7.22.15", "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", - "dev": true, - "peer": true, "dependencies": { "@babel/types": "^7.22.15" }, @@ -255,8 +253,6 @@ "version": "7.22.5", "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==", - "dev": true, - "peer": true, "engines": { "node": ">=6.9.0" } @@ -265,7 +261,6 @@ "version": "7.22.20", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", - "dev": true, "engines": { "node": ">=6.9.0" } @@ -299,7 +294,6 @@ "version": "7.22.20", "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", - "dev": true, "dependencies": { "@babel/helper-validator-identifier": "^7.22.20", "chalk": "^2.4.2", @@ -393,8 +387,6 @@ "version": "7.23.0", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", - "dev": true, - "peer": true, "dependencies": { "@babel/helper-string-parser": "^7.22.5", "@babel/helper-validator-identifier": "^7.22.20", @@ -418,6 +410,106 @@ "node": ">=10.0.0" } }, + "node_modules/@emotion/babel-plugin": { + "version": "11.11.0", + "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.11.0.tgz", + "integrity": "sha512-m4HEDZleaaCH+XgDDsPF15Ht6wTLsgDTeR3WYj9Q/k76JtWhrJjcP4+/XlG8LGT/Rol9qUfOIztXeA84ATpqPQ==", + "dependencies": { + "@babel/helper-module-imports": "^7.16.7", + "@babel/runtime": "^7.18.3", + "@emotion/hash": "^0.9.1", + "@emotion/memoize": "^0.8.1", + "@emotion/serialize": "^1.1.2", + "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.2.0" + } + }, + "node_modules/@emotion/babel-plugin/node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" + }, + "node_modules/@emotion/babel-plugin/node_modules/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==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@emotion/cache": { + "version": "11.11.0", + "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.11.0.tgz", + "integrity": "sha512-P34z9ssTCBi3e9EI1ZsWpNHcfY1r09ZO0rZbRO2ob3ZQMnFI35jB536qoXbkdesr5EUhYi22anuEJuyxifaqAQ==", + "dependencies": { + "@emotion/memoize": "^0.8.1", + "@emotion/sheet": "^1.2.2", + "@emotion/utils": "^1.2.1", + "@emotion/weak-memoize": "^0.3.1", + "stylis": "4.2.0" + } + }, + "node_modules/@emotion/css": { + "version": "11.10.6", + "resolved": "https://registry.npmjs.org/@emotion/css/-/css-11.10.6.tgz", + "integrity": "sha512-88Sr+3heKAKpj9PCqq5A1hAmAkoSIvwEq1O2TwDij7fUtsJpdkV4jMTISSTouFeRvsGvXIpuSuDQ4C1YdfNGXw==", + "dependencies": { + "@emotion/babel-plugin": "^11.10.6", + "@emotion/cache": "^11.10.5", + "@emotion/serialize": "^1.1.1", + "@emotion/sheet": "^1.2.1", + "@emotion/utils": "^1.2.0" + } + }, + "node_modules/@emotion/hash": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.1.tgz", + "integrity": "sha512-gJB6HLm5rYwSLI6PQa+X1t5CFGrv1J1TWG+sOyMCeKz2ojaj6Fnl/rZEspogG+cvqbt4AE/2eIyD2QfLKTBNlQ==" + }, + "node_modules/@emotion/memoize": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.1.tgz", + "integrity": "sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA==" + }, + "node_modules/@emotion/serialize": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.1.2.tgz", + "integrity": "sha512-zR6a/fkFP4EAcCMQtLOhIgpprZOwNmCldtpaISpvz348+DP4Mz8ZoKaGGCQpbzepNIUWbq4w6hNZkwDyKoS+HA==", + "dependencies": { + "@emotion/hash": "^0.9.1", + "@emotion/memoize": "^0.8.1", + "@emotion/unitless": "^0.8.1", + "@emotion/utils": "^1.2.1", + "csstype": "^3.0.2" + } + }, + "node_modules/@emotion/sheet": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.2.2.tgz", + "integrity": "sha512-0QBtGvaqtWi+nx6doRwDdBIzhNdZrXUppvTM4dtZZWEGTXL/XE/yJxLMGlDT1Gt+UHH5IX1n+jkXyytE/av7OA==" + }, + "node_modules/@emotion/unitless": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.1.tgz", + "integrity": "sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ==" + }, + "node_modules/@emotion/utils": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.2.1.tgz", + "integrity": "sha512-Y2tGf3I+XVnajdItskUCn6LX+VUDmP6lTL4fcqsXAv43dnlbZiuW4MWQW38rW/BVWSE7Q/7+XQocmpnRYILUmg==" + }, + "node_modules/@emotion/weak-memoize": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.3.1.tgz", + "integrity": "sha512-EsBwpc7hBUJWAsNPBmJy4hxWx12v6bshQsldrVmjxJoc3isbxhOrF2IcCpaXxfvq03NwkI7sbsOLXbYuqF/8Ww==" + }, "node_modules/@esbuild/android-arm": { "version": "0.15.18", "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.15.18.tgz", @@ -683,6 +775,12 @@ "react": ">=16.14.0" } }, + "node_modules/@scarf/scarf": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@scarf/scarf/-/scarf-1.1.1.tgz", + "integrity": "sha512-VGbKDbk1RFIaSmdVb0cNjjWJoRWRI/Weo23AjRCC2nryO0iAS8pzsToJfPVPtVs74WHw4L1UTADNdIYRLkirZQ==", + "hasInstallScript": true + }, "node_modules/@swc/helpers": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.2.tgz", @@ -1068,6 +1166,11 @@ "integrity": "sha512-Vvycsc9FQdwhxE3y3DzeIxuEJbWGDsnrxvMADzTDF/lcdR9/K+AQIeAghTQsHtotg/q0j3WEOYS/jQgSdWue3w==", "dev": true }, + "node_modules/@types/parse-json": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", + "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==" + }, "node_modules/@types/prop-types": { "version": "15.7.8", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.8.tgz", @@ -1515,7 +1618,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" }, @@ -1646,6 +1748,35 @@ "node": ">= 4.5.0" } }, + "node_modules/babel-plugin-macros": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", + "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==", + "dependencies": { + "@babel/runtime": "^7.12.5", + "cosmiconfig": "^7.0.0", + "resolve": "^1.19.0" + }, + "engines": { + "node": ">=10", + "npm": ">=6" + } + }, + "node_modules/babel-plugin-macros/node_modules/cosmiconfig": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", + "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/bail": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", @@ -1974,7 +2105,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" } @@ -2003,7 +2133,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", @@ -2217,7 +2346,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" } @@ -2225,8 +2353,7 @@ "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/colorette": { "version": "2.0.20", @@ -2923,7 +3050,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" } @@ -3310,7 +3436,6 @@ "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" } @@ -3774,6 +3899,11 @@ "node": ">=6" } }, + "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": "3.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", @@ -4047,7 +4177,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/has/-/has-1.0.4.tgz", "integrity": "sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ==", - "dev": true, "engines": { "node": ">= 0.4.0" } @@ -4056,7 +4185,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" } @@ -4429,7 +4557,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" @@ -4602,8 +4729,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-binary-path": { "version": "1.0.1", @@ -4643,7 +4769,6 @@ "version": "2.13.0", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.0.tgz", "integrity": "sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==", - "dev": true, "dependencies": { "has": "^1.0.3" }, @@ -4931,8 +5056,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-traverse": { "version": "0.4.1", @@ -4983,8 +5107,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/live-server": { "version": "1.2.2", @@ -6308,7 +6431,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" }, @@ -6337,7 +6459,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", @@ -6405,8 +6526,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": "0.1.7", @@ -6418,7 +6538,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" } @@ -6859,6 +6978,22 @@ "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==" }, + "node_modules/react-loading-overlay-ts": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/react-loading-overlay-ts/-/react-loading-overlay-ts-2.0.2.tgz", + "integrity": "sha512-dy1GhUOz91aPmvvuT85WUFBCG7NX1ZJBKbeHgGHSC+gss6u9/6AfpFgDnXlJLxGpv+VbbeCXye8ETy+BX3SS4A==", + "dependencies": { + "@emotion/css": "11.10.6", + "@scarf/scarf": "1.1.1", + "react-transition-group": "4.4.5" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "react": ">=17" + } + }, "node_modules/react-markdown": { "version": "8.0.7", "resolved": "https://registry.npmjs.org/react-markdown/-/react-markdown-8.0.7.tgz", @@ -7179,7 +7314,6 @@ "version": "1.22.6", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.6.tgz", "integrity": "sha512-njhxM7mV12JfufShqGy3Rz8j11RPdLy4xi15UurGJeoHLfJpVXKdh3ueuOqbYUcDZnffr6X739JBo5LzyahEsw==", - "dev": true, "dependencies": { "is-core-module": "^2.13.0", "path-parse": "^1.0.7", @@ -7217,7 +7351,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" } @@ -7993,7 +8126,6 @@ "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -8355,11 +8487,15 @@ "inline-style-parser": "0.1.1" } }, + "node_modules/stylis": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", + "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==" + }, "node_modules/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, "dependencies": { "has-flag": "^3.0.0" }, @@ -8371,7 +8507,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" }, @@ -8467,8 +8602,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, - "peer": true, "engines": { "node": ">=4" } @@ -9788,6 +9921,14 @@ "dev": true, "peer": true }, + "node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "engines": { + "node": ">= 6" + } + }, "node_modules/zustand": { "version": "4.4.3", "resolved": "https://registry.npmjs.org/zustand/-/zustand-4.4.3.tgz", @@ -9843,7 +9984,6 @@ "version": "7.22.13", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", - "dev": true, "requires": { "@babel/highlight": "^7.22.13", "chalk": "^2.4.2" @@ -9939,8 +10079,6 @@ "version": "7.22.15", "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", - "dev": true, - "peer": true, "requires": { "@babel/types": "^7.22.15" } @@ -9982,15 +10120,12 @@ "@babel/helper-string-parser": { "version": "7.22.5", "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", - "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==", - "dev": true, - "peer": true + "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==" }, "@babel/helper-validator-identifier": { "version": "7.22.20", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", - "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", - "dev": true + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==" }, "@babel/helper-validator-option": { "version": "7.22.15", @@ -10015,7 +10150,6 @@ "version": "7.22.20", "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", - "dev": true, "requires": { "@babel/helper-validator-identifier": "^7.22.20", "chalk": "^2.4.2", @@ -10085,8 +10219,6 @@ "version": "7.23.0", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", - "dev": true, - "peer": true, "requires": { "@babel/helper-string-parser": "^7.22.5", "@babel/helper-validator-identifier": "^7.22.20", @@ -10104,6 +10236,102 @@ "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", "dev": true }, + "@emotion/babel-plugin": { + "version": "11.11.0", + "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.11.0.tgz", + "integrity": "sha512-m4HEDZleaaCH+XgDDsPF15Ht6wTLsgDTeR3WYj9Q/k76JtWhrJjcP4+/XlG8LGT/Rol9qUfOIztXeA84ATpqPQ==", + "requires": { + "@babel/helper-module-imports": "^7.16.7", + "@babel/runtime": "^7.18.3", + "@emotion/hash": "^0.9.1", + "@emotion/memoize": "^0.8.1", + "@emotion/serialize": "^1.1.2", + "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.2.0" + }, + "dependencies": { + "convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" + }, + "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==" + } + } + }, + "@emotion/cache": { + "version": "11.11.0", + "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.11.0.tgz", + "integrity": "sha512-P34z9ssTCBi3e9EI1ZsWpNHcfY1r09ZO0rZbRO2ob3ZQMnFI35jB536qoXbkdesr5EUhYi22anuEJuyxifaqAQ==", + "requires": { + "@emotion/memoize": "^0.8.1", + "@emotion/sheet": "^1.2.2", + "@emotion/utils": "^1.2.1", + "@emotion/weak-memoize": "^0.3.1", + "stylis": "4.2.0" + } + }, + "@emotion/css": { + "version": "11.10.6", + "resolved": "https://registry.npmjs.org/@emotion/css/-/css-11.10.6.tgz", + "integrity": "sha512-88Sr+3heKAKpj9PCqq5A1hAmAkoSIvwEq1O2TwDij7fUtsJpdkV4jMTISSTouFeRvsGvXIpuSuDQ4C1YdfNGXw==", + "requires": { + "@emotion/babel-plugin": "^11.10.6", + "@emotion/cache": "^11.10.5", + "@emotion/serialize": "^1.1.1", + "@emotion/sheet": "^1.2.1", + "@emotion/utils": "^1.2.0" + } + }, + "@emotion/hash": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.1.tgz", + "integrity": "sha512-gJB6HLm5rYwSLI6PQa+X1t5CFGrv1J1TWG+sOyMCeKz2ojaj6Fnl/rZEspogG+cvqbt4AE/2eIyD2QfLKTBNlQ==" + }, + "@emotion/memoize": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.1.tgz", + "integrity": "sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA==" + }, + "@emotion/serialize": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.1.2.tgz", + "integrity": "sha512-zR6a/fkFP4EAcCMQtLOhIgpprZOwNmCldtpaISpvz348+DP4Mz8ZoKaGGCQpbzepNIUWbq4w6hNZkwDyKoS+HA==", + "requires": { + "@emotion/hash": "^0.9.1", + "@emotion/memoize": "^0.8.1", + "@emotion/unitless": "^0.8.1", + "@emotion/utils": "^1.2.1", + "csstype": "^3.0.2" + } + }, + "@emotion/sheet": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.2.2.tgz", + "integrity": "sha512-0QBtGvaqtWi+nx6doRwDdBIzhNdZrXUppvTM4dtZZWEGTXL/XE/yJxLMGlDT1Gt+UHH5IX1n+jkXyytE/av7OA==" + }, + "@emotion/unitless": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.1.tgz", + "integrity": "sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ==" + }, + "@emotion/utils": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.2.1.tgz", + "integrity": "sha512-Y2tGf3I+XVnajdItskUCn6LX+VUDmP6lTL4fcqsXAv43dnlbZiuW4MWQW38rW/BVWSE7Q/7+XQocmpnRYILUmg==" + }, + "@emotion/weak-memoize": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.3.1.tgz", + "integrity": "sha512-EsBwpc7hBUJWAsNPBmJy4hxWx12v6bshQsldrVmjxJoc3isbxhOrF2IcCpaXxfvq03NwkI7sbsOLXbYuqF/8Ww==" + }, "@esbuild/android-arm": { "version": "0.15.18", "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.15.18.tgz", @@ -10295,6 +10523,11 @@ } } }, + "@scarf/scarf": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@scarf/scarf/-/scarf-1.1.1.tgz", + "integrity": "sha512-VGbKDbk1RFIaSmdVb0cNjjWJoRWRI/Weo23AjRCC2nryO0iAS8pzsToJfPVPtVs74WHw4L1UTADNdIYRLkirZQ==" + }, "@swc/helpers": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.2.tgz", @@ -10680,6 +10913,11 @@ "integrity": "sha512-Vvycsc9FQdwhxE3y3DzeIxuEJbWGDsnrxvMADzTDF/lcdR9/K+AQIeAghTQsHtotg/q0j3WEOYS/jQgSdWue3w==", "dev": true }, + "@types/parse-json": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", + "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==" + }, "@types/prop-types": { "version": "15.7.8", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.8.tgz", @@ -11065,7 +11303,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" } @@ -11159,6 +11396,30 @@ "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", "dev": true }, + "babel-plugin-macros": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", + "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==", + "requires": { + "@babel/runtime": "^7.12.5", + "cosmiconfig": "^7.0.0", + "resolve": "^1.19.0" + }, + "dependencies": { + "cosmiconfig": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", + "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "requires": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + } + } + } + }, "bail": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", @@ -11414,8 +11675,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==" }, "caniuse-lite": { "version": "1.0.30001546", @@ -11427,7 +11687,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", @@ -11596,7 +11855,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" } @@ -11604,8 +11862,7 @@ "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==" }, "colorette": { "version": "2.0.20", @@ -12136,7 +12393,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" } @@ -12332,8 +12588,7 @@ "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==" }, "eslint-scope": { "version": "5.1.1", @@ -12722,6 +12977,11 @@ "pkg-dir": "^3.0.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": "3.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", @@ -12928,14 +13188,12 @@ "has": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/has/-/has-1.0.4.tgz", - "integrity": "sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ==", - "dev": true + "integrity": "sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ==" }, "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==" }, "has-proto": { "version": "1.0.1", @@ -13201,7 +13459,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" @@ -13329,8 +13586,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-binary-path": { "version": "1.0.1", @@ -13350,7 +13606,6 @@ "version": "2.13.0", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.0.tgz", "integrity": "sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==", - "dev": true, "requires": { "has": "^1.0.3" } @@ -13553,8 +13808,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-traverse": { "version": "0.4.1", @@ -13593,8 +13847,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==" }, "live-server": { "version": "1.2.2", @@ -14502,7 +14755,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" } @@ -14524,7 +14776,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", @@ -14571,8 +14822,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": "0.1.7", @@ -14583,8 +14833,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==" }, "pause-stream": { "version": "0.0.11", @@ -14891,6 +15140,16 @@ "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==" }, + "react-loading-overlay-ts": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/react-loading-overlay-ts/-/react-loading-overlay-ts-2.0.2.tgz", + "integrity": "sha512-dy1GhUOz91aPmvvuT85WUFBCG7NX1ZJBKbeHgGHSC+gss6u9/6AfpFgDnXlJLxGpv+VbbeCXye8ETy+BX3SS4A==", + "requires": { + "@emotion/css": "11.10.6", + "@scarf/scarf": "1.1.1", + "react-transition-group": "4.4.5" + } + }, "react-markdown": { "version": "8.0.7", "resolved": "https://registry.npmjs.org/react-markdown/-/react-markdown-8.0.7.tgz", @@ -15142,7 +15401,6 @@ "version": "1.22.6", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.6.tgz", "integrity": "sha512-njhxM7mV12JfufShqGy3Rz8j11RPdLy4xi15UurGJeoHLfJpVXKdh3ueuOqbYUcDZnffr6X739JBo5LzyahEsw==", - "dev": true, "requires": { "is-core-module": "^2.13.0", "path-parse": "^1.0.7", @@ -15169,8 +15427,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==" }, "resolve-url": { "version": "0.2.1", @@ -15765,8 +16022,7 @@ "source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", - "dev": true + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==" }, "source-map-js": { "version": "1.0.2", @@ -16058,11 +16314,15 @@ "inline-style-parser": "0.1.1" } }, + "stylis": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", + "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==" + }, "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" } @@ -16070,8 +16330,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==" }, "tapable": { "version": "2.2.1", @@ -16127,9 +16386,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, - "peer": true + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==" }, "to-object-path": { "version": "0.3.0", @@ -17056,6 +17313,11 @@ "dev": true, "peer": true }, + "yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==" + }, "zustand": { "version": "4.4.3", "resolved": "https://registry.npmjs.org/zustand/-/zustand-4.4.3.tgz", diff --git a/package.json b/package.json index 5a933cdd..747811ca 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "react-bootstrap": "^2.7.0", "react-dom": "^18.2.0", "react-icons": "^4.7.1", + "react-loading-overlay-ts": "^2.0.2", "react-markdown": "^8.0.5", "react-syntax-highlighter": "^15.5.0", "reactflow": "^11.7.2", diff --git a/packages.dhall b/packages.dhall index 4a8072e1..588b7089 100644 --- a/packages.dhall +++ b/packages.dhall @@ -321,7 +321,7 @@ in upstream , "web-encoding" ] "https://github.com/input-output-hk/purescript-cardano-wallet-client.git" - "v0.1.0" + "v0.1.1" -- with marlowe-runtime-client = ../purescript-marlowe-runtime-client/spago.dhall as Location with marlowe-runtime-client = diff --git a/public/style.scss b/public/style.scss index dfa50f56..f14cf868 100644 --- a/public/style.scss +++ b/public/style.scss @@ -209,6 +209,10 @@ $link-color: #511CF7; min-height: 100%; } +.min-height-250px { + min-height: 250px; +} + .shadow-bottom { box-shadow: 0 4px 2px -2px rgba(0, 0, 0, 0.1); } @@ -342,7 +346,6 @@ $link-color: #511CF7; } .blur-bg { - background: rgba(255, 255, 255, 0.7); backdrop-filter: blur(5px); } diff --git a/spago.dhall b/spago.dhall index b893eb5d..1cff2580 100644 --- a/spago.dhall +++ b/spago.dhall @@ -27,7 +27,6 @@ , "foreign-generic" , "foreign-object" , "formatters" - , "free" , "functions" , "functors" , "halogen-subscriptions" diff --git a/src/Component/App.purs b/src/Component/App.purs index 86842133..2d479f8e 100644 --- a/src/Component/App.purs +++ b/src/Component/App.purs @@ -13,10 +13,12 @@ import Component.LandingPage (mkLandingPage) import Component.MessageHub (mkMessageBox, mkMessagePreview) import Component.Testing (mkDataTestAttrs) import Component.Types (ConfigurationError(..), ContractInfo(..), ContractJsonString, MessageHub(MessageHub), MkComponentMBase, Page(..), WalletInfo(..)) +import Component.Types as MessageHub import Component.Types.ContractInfo (ContractCreated(..), ContractUpdated(..)) as ContractInfo import Component.Types.ContractInfo (SomeContractInfo) import Component.Types.ContractInfoMap as ContractInfoMap import Component.Widgets (linkWithIcon) +import Component.Widgets as Widgets import Contrib.React.Svg (svgImg) import Control.Monad.Error.Class (catchError) import Control.Monad.Loops (untilJust) @@ -37,6 +39,7 @@ import Data.String.Extra (upperCaseFirst) as String import Data.Time.Duration (Milliseconds(..)) import Data.Traversable (for, traverse) import Data.Tuple.Nested (type (/\), (/\)) +import Debug (traceM) import Effect (Effect) import Effect.Aff (Aff, delay, forkAff, launchAff_, supervise) import Effect.Class (liftEffect) @@ -60,6 +63,7 @@ import ReactBootstrap.Modal (modal, modalBody, modalHeader) import ReactBootstrap.Offcanvas (offcanvas) import ReactBootstrap.Offcanvas as Offcanvas import Record as Record +import Runner.Contrib.Effect.Aff (withTimeout, withTimeout_) import Type.Prelude (Proxy(..)) import Utils.React.Basic.Hooks (useLoopAff, useStateRef, useStateRef') import Wallet as Wallet @@ -69,18 +73,20 @@ import Web.HTML (window) -- | Debugging helpers which allow us to automatically connect wallet data WalletBrand - = Lace - | Yoroi + = Eternl + | Gero + | Lace | Nami - | Eternl | Typhon + | Yoroi instance Show WalletBrand where - show Yoroi = "Yoroi" - show Nami = "Nami" - show Lace = "Lace" show Eternl = "Eternl" + show Gero = "Gero" + show Lace = "Lace" + show Nami = "Nami" show Typhon = "Typhon" + show Yoroi = "Yoroi" autoConnectWallet :: WalletBrand -> (WalletInfo Wallet.Api -> Effect Unit) -> Aff Unit autoConnectWallet walletBrand onSuccess = liftEffect (window >>= Wallet.cardano) >>= case _ of @@ -90,12 +96,13 @@ autoConnectWallet walletBrand onSuccess = liftEffect (window >>= Wallet.cardano) Just cardano -> do let extractWallet = case walletBrand of + Eternl -> Wallet.eternl + Gero -> Wallet.gerowallet Lace -> Wallet.lace Nami -> Wallet.nami - Yoroi -> Wallet.yoroi - Eternl -> Wallet.eternl Typhon -> Wallet.typhon - liftEffect (extractWallet cardano) >>= traverse walletInfo >>= case _ of + Yoroi -> Wallet.yoroi + liftEffect (extractWallet cardano) >>= traverse walletInfo >>= join >>> case _ of Nothing -> do liftEffect $ throw $ "Unable to extract wallet " <> show walletBrand Just walletInfo@(WalletInfo { wallet }) -> do @@ -272,16 +279,19 @@ mkApp = do Nothing, Just _ -> do liftEffect $ setWalletContext Nothing Just (WalletInfo walletInfo), _ -> do - let - action = do - walletContext <- WalletContext.walletContext cardanoMultiplatformLib walletInfo.wallet - liftEffect $ setWalletContext walletContext - -- FIXME: Another work around the rounting issue. - when (isNothing pwc) do - liftEffect $ props.setPage ContractListPage - action `catchError` \_ -> do - -- FIXME: Report back (to the reporting backend) a wallet problem? - pure unit + res <- withTimeout (Milliseconds 7000.0) do + traceM "TRYING TO FETCH WALLET CONTEXT" + walletContext <- WalletContext.walletContext cardanoMultiplatformLib walletInfo.wallet + traceM "FAILED" + liftEffect $ setWalletContext walletContext + -- FIXME: Another work around the rounting issue. + when (isNothing pwc) do + liftEffect $ props.setPage ContractListPage + case res of + Nothing -> liftEffect do + msgHubProps.add $ MessageHub.Error $ DOOM.text "Wallet is not responding. Please check its configuration or try another wallet" + setWalletInfo Nothing + Just _ -> pure unit disconnectingWallet /\ setDisconnectingWallet <- useState' false checkingNotifications /\ setCheckingNotifications <- useState' false @@ -475,9 +485,12 @@ mkApp = do } , footer ] - _, _ -> DOM.div {} $ - [ topNavbar - , appError - , landingPage { setWalletInfo: setWalletInfo <<< Just } - ] + _, _ -> + Widgets.loadingOverlay { active: isJust possibleWalletInfo, showSpinner: false } + [ DOM.div {} $ + [ topNavbar + , appError + , landingPage { setWalletInfo: setWalletInfo <<< Just } + ] + ] diff --git a/src/Component/ConnectWallet.purs b/src/Component/ConnectWallet.purs index e226b2ca..9e386a7b 100644 --- a/src/Component/ConnectWallet.purs +++ b/src/Component/ConnectWallet.purs @@ -3,23 +3,26 @@ module Component.ConnectWallet where import Prelude import Component.Types (MkComponentM, WalletInfo(..)) -import Component.Widgets (link) +import Component.Widgets (SpinnerOverlayHeight(..), link, spinnerOverlay) +import Component.Widgets as Widgets import Component.Widgets.Form (mkSingleChoiceField) import Component.Widgets.Form as Form import Contrib.React.Svg (loadingSpinnerLogo) import Data.Array as Array import Data.Array.ArrayAL (ArrayAL) import Data.Array.ArrayAL as ArrayAL +import Data.Either (Either(..), fromRight) import Data.Map (Map) import Data.Maybe (Maybe(..), fromMaybe) import Data.Newtype (un, unwrap) import Data.Newtype as Newtype import Data.String.Extra as String +import Data.Time.Duration (Milliseconds(..)) import Data.Traversable (traverse) +import Data.Variant (Variant, on) import Effect (Effect) -import Effect.Aff (Aff, catchError, launchAff_) +import Effect.Aff (Aff, launchAff_) import Effect.Class (liftEffect) -import Effect.Exception (Error) import Foreign.Object as Object import React.Basic (JSX) import React.Basic (fragment) as DOOM @@ -30,32 +33,46 @@ import React.Basic.Hooks (component, useEffectOnce, useState', (/\)) import React.Basic.Hooks as React import ReactBootstrap.Modal (modal, modalBody, modalFooter, modalHeader) import Record as Record +import Runner.Contrib.Effect.Aff (withTimeout) +import Runner.Contrib.ReactLoadingOverlayTs (loadingOverlay) +import Runner.Contrib.ReactLoadingOverlayTs as LoadingOverlay import Type.Prelude (Proxy(..)) +import Type.Row (type (+)) import Wallet (Wallet) import Wallet as Wallet import Web.HTML (window) type Wallets = Map String Wallet -walletInfo :: Wallet -> Aff (WalletInfo Wallet) -walletInfo wallet = WalletInfo <$> ado +walletInfo :: Wallet -> Aff (Maybe (WalletInfo Wallet)) +walletInfo wallet = withTimeout (Milliseconds 7000.0) $ WalletInfo <$> ado name <- liftEffect (Wallet.name wallet) icon <- liftEffect (Wallet.icon wallet) - isEnabled <- Wallet.isEnabled_ wallet + isEnabled <- Wallet.isEnabled wallet <#> fromRight false apiVersion <- liftEffect (Wallet.apiVersion wallet) in { name, icon, isEnabled, apiVersion, wallet } -data Response +-- Version of ApiError without rejection because we handle it using `onDismiss`. +type ApiError' r = + ( invalidRequest :: String + , internalError :: String + , accountChange :: String + | r + ) + +data ConnectionError = NoWallets - | ConnectionError Error - | Connected (WalletInfo Wallet.Api) + | ConnectionError (Variant (ApiError' + Wallet.ApiForeignErrors + Wallet.UnknownError + ())) + | TimeoutReached + +type Result = WalletInfo Wallet.Api type Props = { currentlyConnected :: Maybe (WalletInfo Wallet.Api) , onDismiss :: Effect Unit - , onWalletConnect :: Response -> Effect Unit - , inModal :: Boolean + , onWalletConnect :: Result -> Effect Unit + , onError :: ConnectionError -> Effect Unit } formatName :: String -> String @@ -89,12 +106,10 @@ data AvailableWallets mkConnectWallet :: MkComponentM (Props -> JSX) mkConnectWallet = do - singleChoiceField <- liftEffect mkSingleChoiceField - -- modal <- liftEffect mkModal - liftEffect $ component "Wallet" \{ currentlyConnected, onWalletConnect, onDismiss, inModal } -> React.do + liftEffect $ component "Wallet" \{ currentlyConnected, onWalletConnect, onError, onDismiss } -> React.do possibleWallets /\ setWallets <- useState' FetchingWalletList - selectedWallet /\ setSelectedWallet <- useState' $ Nothing + connecting /\ setConnecting <- useState' false useEffectOnce do liftEffect (Wallet.cardano =<< window) >>= case _ of @@ -108,135 +123,63 @@ mkConnectWallet = do nami <- liftEffect (Wallet.nami cardano) >>= traverse walletInfo yoroi <- liftEffect (Wallet.yoroi cardano) >>= traverse walletInfo typhon <- liftEffect (Wallet.typhon cardano) >>= traverse walletInfo - case ArrayAL.fromArray (Proxy :: Proxy 1) (Array.catMaybes [ eternl, gerowallet, lace, nami, typhon, yoroi ]) of + case ArrayAL.fromArray (Proxy :: Proxy 1) (Array.catMaybes $ map join [ eternl, gerowallet, lace, nami, typhon, yoroi ]) of Nothing -> liftEffect $ do setWallets NoWalletsAvailable - onWalletConnect NoWallets + onError NoWallets Just wallets -> liftEffect $ do setWallets $ WalletList wallets - setSelectedWallet $ do - { name } <- un WalletInfo <$> currentlyConnected - Array.find (\(WalletInfo wallet) -> wallet.name == name) (ArrayAL.toArray wallets) pure (pure unit) let submit w = case w of Just selected@(WalletInfo s) -> if Just s.name == (_.name <<< unwrap <$> currentlyConnected) then onDismiss - else launchAff_ do - possibleApi <- (Just <$> Wallet.enable_ s.wallet) `catchError` \error -> do - liftEffect $ onWalletConnect (ConnectionError error) - pure Nothing - case possibleApi of - Just (walletApi :: Wallet.Api) -> do - let - selected' = Newtype.over WalletInfo (Record.set (Proxy :: Proxy "wallet") walletApi) selected - liftEffect $ onWalletConnect (Connected selected') - Nothing -> do - -- FIXME: Error handling - liftEffect $ onDismiss - Nothing -> onDismiss - onSubmit = submit selectedWallet - - pure - if inModal then do - let - { formBody, formActions } = case possibleWallets of - WalletList wallets -> do - let - choices = wallets <#> \(WalletInfo { icon, name }) -> do + else do + setConnecting true + launchAff_ do + withTimeout (Milliseconds 30000.0) (Wallet.enable s.wallet) >>= case _ of + Nothing -> liftEffect $ onError TimeoutReached + Just (Right (walletApi :: Wallet.Api)) -> do let - label = DOM.span { className: "h5" } - [ DOOM.img { src: icon, alt: name, className: "w-2rem me-2" } - , DOOM.span_ [ DOOM.text name ] - ] - -- We know that only Nami is working - should we disable all the other wallets? - name /\ label /\ false - - { formBody: singleChoiceField - { initialValue: fromMaybe "" (_.name <<< unwrap <$> selectedWallet) - , onValueChange: \walletName -> do - setSelectedWallet $ Array.find (\(WalletInfo wallet) -> wallet.name == walletName) (ArrayAL.toArray wallets) - , type: Form.RadioButtonField choices - } - , formActions: DOOM.fragment - if inModal then - [ link { label: DOOM.text "Cancel", onClick: onDismiss, showBorders: true } - , DOOM.button do - let - _name :: forall wallet. Maybe (WalletInfo wallet) -> Maybe String - _name = map $ (_.name <<< unwrap) - selectedIsConnected = _name selectedWallet == _name currentlyConnected - - { type: "button" - , className: "btn btn-primary" - , onClick: handler_ onSubmit - , disabled: selectedIsConnected - , children: [ DOOM.text "Connect wallet" ] - } - ] - else - [ DOOM.button do - let - _name :: forall wallet. Maybe (WalletInfo wallet) -> Maybe String - _name = map $ (_.name <<< unwrap) - selectedIsConnected = _name selectedWallet == _name currentlyConnected - - { type: "button" - , className: "btn btn-primary mt-3" - , onClick: handler_ onSubmit - , disabled: selectedIsConnected - , children: [ DOM.p { className: "h4 font-weight-bold" } [ DOOM.text "Connect wallet" ] ] - } + selected' = Newtype.over WalletInfo (Record.set (Proxy :: Proxy "wallet") walletApi) selected + liftEffect $ onWalletConnect selected' + Just (Left walletError) -> do + let + _refused :: Proxy "refused" + _refused = Proxy + handler = + (ConnectionError >>> onError) + # on _refused \_ -> liftEffect onDismiss + liftEffect $ handler walletError + liftEffect $ setConnecting false + Nothing -> onDismiss + overlayActive = connecting || case possibleWallets of + FetchingWalletList -> true + _ -> false + + pure $ Widgets.loadingOverlay { active: overlayActive } $ Array.singleton $ DOM.div { className: "container" } $ DOM.div { className: "row justify-content-center mt-4" } + [ DOM.div { className: "col-12 shadow-sm rounded p-5 min-height-250px" } do + let + renderWallets maybeWallets = do + [ DOM.div { className: "row" } $ + DOM.div { className: "col-12" } + [ DOM.h5 { className: "card-title font-weight-bold text-left" } [ DOOM.text "Choose a wallet" ] + , DOM.p { className: "card-help-text text-muted text-left" } [ DOOM.text "Please select a wallet to deploy a contract." ] ] - } - _ -> do - { formBody: DOM.div { className: "d-flex justify-content-center" } $ loadingSpinnerLogo {} - , formActions: mempty - } - - modal - { onHide: onDismiss -- : setConfiguringWallet false - -- , footer: formActions - -- , body: formBody - -- , title: DOOM.text "Connect wallet" - , show: true - } - [ modalHeader {} $ DOOM.text "Choose a wallet" - , modalBody {} formBody - , modalFooter {} formActions - ] - else - DOM.div { className: "container" } $ DOM.div { className: "row justify-content-center mt-4" } - [ DOM.div { className: "col-12 shadow-sm rounded p-5" } do - let - renderWallets maybeWallets = do - [ DOM.div { className: "row" } $ - DOM.div { className: "col-12" } - [ DOM.h5 { className: "card-title font-weight-bold text-left" } [ DOOM.text "Choose a wallet" ] - , DOM.p { className: "card-help-text text-muted text-left" } [ DOOM.text "Please select a wallet to deploy a contract." ] - ] - ] <> case maybeWallets of - Just wallets -> (ArrayAL.toArray wallets) <#> \wallet -> do - renderWallet (submit $ Just wallet) wallet - Nothing -> - [ DOM.div { className: "d-flex justify-content-center" } $ loadingSpinnerLogo {} ] - -- <> - -- [ DOM.div { className: "row mt-4" } - -- [ DOM.div { className: "col-6 text-left p-0" } [ DOM.a { href: "#" } [ DOOM.text "Learn more" ] ] - -- , DOM.div { className: "col-6 p-0" } [ DOM.a { href: "#", className: "text-muted text-right text-decoration-none" } [ DOOM.text "I don't have a wallet" ] ] - -- ] - -- ] - case possibleWallets of - NoWalletsAvailable -> - [ DOM.div { className: "row" } - [ DOM.div { className: "col-12" } - [ DOM.h5 { className: "card-title font-weight-bold text-left mb-3" } [ DOOM.text "Looks like you don't have a wallet extension installed." ] - , DOM.p { className: "card-help-text text-muted text-left" } [ DOOM.text "Please install a cardano wallet extension, such as Lace, Nami or Eternl in order to proceed and start running Marlowe contracts." ] - ] + ] <> case maybeWallets of + Just wallets -> (ArrayAL.toArray wallets) <#> \wallet -> do + renderWallet (submit $ Just wallet) wallet + Nothing -> mempty + case possibleWallets of + NoWalletsAvailable -> + [ DOM.div { className: "row" } + [ DOM.div { className: "col-12" } + [ DOM.h5 { className: "card-title font-weight-bold text-left mb-3" } [ DOOM.text "Looks like you don't have a wallet extension installed." ] + , DOM.p { className: "card-help-text text-muted text-left" } [ DOOM.text "Please install a cardano wallet extension, such as Lace, Nami or Eternl in order to proceed and start running Marlowe contracts." ] ] ] - WalletList wallets -> renderWallets (Just wallets) - _ -> renderWallets Nothing - - ] + ] + WalletList wallets -> renderWallets (Just wallets) + _ -> renderWallets Nothing + ] diff --git a/src/Component/LandingPage.purs b/src/Component/LandingPage.purs index 02b785fc..a17df069 100644 --- a/src/Component/LandingPage.purs +++ b/src/Component/LandingPage.purs @@ -2,24 +2,26 @@ module Component.LandingPage where import Prelude +import Component.BodyLayout as BodyLayout import Component.ConnectWallet (mkConnectWallet) import Component.ConnectWallet as ConnectWallet -import Component.Types (ContractInfo, MkComponentMBase, WalletInfo) -import Component.BodyLayout as BodyLayout +import Component.MessageHub (mkMessageBox) +import Component.Types (ContractInfo, MessageHub(..), MkComponentMBase, WalletInfo) +import Component.Types as MessageHub import Contrib.React.Svg (SvgUrl(..)) +import Control.Monad.Reader.Class (asks) import Data.Map (Map) import Data.Maybe (Maybe(..)) -import Data.Tuple.Nested ((/\)) +import Data.Variant (Variant) import Effect (Effect) import Effect.Class (liftEffect) -import Effect.Exception (Error) import JS.Unsafe.Stringify (unsafeStringify) import Marlowe.Runtime.Web.Types as Runtime import React.Basic (JSX) import React.Basic.DOM (text, img) as DOOM import React.Basic.DOM.Simplified.Generated as DOM -import React.Basic.Hooks (component, useState') -import React.Basic.Hooks as React +import React.Basic.Hooks (component) +import Type.Row (type (+)) import Wallet as Wallet import WalletContext (WalletContext) @@ -43,41 +45,53 @@ type Props = data ConnectionErrors = NoWallets - | ConnectionError Error + | ConnectionError (Variant (ConnectWallet.ApiError' + Wallet.ApiForeignErrors + Wallet.UnknownError + ())) mkLandingPage :: MkComponentMBase () (Props -> JSX) mkLandingPage = do connectWallet <- mkConnectWallet + msgHub@(MessageHub msgHubProps) <- asks _.msgHub + messageBox <- liftEffect $ mkMessageBox liftEffect $ component "LandingPage" \{ setWalletInfo } -> React.do - possibleErrors /\ setErrors <- useState' Nothing - pure $ BodyLayout.component - { title: DOM.div { className: "pe-4 fw-bold" } + let + title = + DOM.div { className: "pe-4 fw-bold" } [ DOOM.img { src: "/images/twotone_wallet.svg" } , DOM.h3 { className: "fw-bold" } $ DOOM.text "Choose a wallet to deploy a Marlowe smart contract" ] - , description: - DOM.div { className: "pe-4" } - [ DOM.p {} [ DOOM.text "Selecting a wallet is your first step in deploying a smart contract, your choice should be compatible with the blockchain network you want to deploy your contract on." ] - ] - , content: DOM.div {} $ - [ DOM.div { className: "container-fluid" } - $ DOM.div { className: "row justify-content-center" } - $ DOM.div { className: "col-xl-7 col-lg-10 col-12" } - [ case possibleErrors of - Just NoWallets -> DOOM.text "It seems that you have no cardano wallets..." - Just (ConnectionError err) -> DOOM.text $ unsafeStringify err - Nothing -> connectWallet - { currentlyConnected: Nothing - , onWalletConnect: case _ of - ConnectWallet.Connected walletInfo -> setWalletInfo walletInfo - ConnectWallet.NoWallets -> setErrors $ Just NoWallets - ConnectWallet.ConnectionError err -> setErrors $ Just $ ConnectionError err - , onDismiss: pure unit - , inModal: false - } - ] + description = + DOM.div { className: "pe-4" } + $ DOM.p {} [ DOOM.text "Selecting a wallet is your first step in deploying a smart contract, your choice should be compatible with the blockchain network you want to deploy your contract on." ] + + content = + DOM.div { className: "container-fluid" } + $ DOM.div { className: "row justify-content-center" } + $ DOM.div { className: "col-xl-7 col-lg-10 col-12" } + $ connectWallet + { currentlyConnected: Nothing + , onWalletConnect: setWalletInfo + , onError: case _ of + ConnectWallet.NoWallets -> pure unit -- setErrors $ Just NoWallets + ConnectWallet.ConnectionError _ -> + msgHubProps.add $ MessageHub.Error $ DOOM.text $ "Wallet connection failed with unknown error. Please try another wallet" + ConnectWallet.TimeoutReached -> + msgHubProps.add $ MessageHub.Error $ DOOM.text "Timeout reached while connecting to wallet" + , onDismiss: pure unit + } + + pure $ DOM.div { className: "container" } $ do + [ DOM.div { className: "row justify-content-center" } + [ DOM.div { className: "col-3 background-color-primary-light" } ([] :: Array JSX) + , DOM.div { className: "col-9 overflow-auto bg-white" } + $ DOM.div { className: "mx-5" } + $ messageBox msgHub + ] + , DOM.div { className: "row min-height-100vh d-flex flex-row align-items-stretch no-gutters" } $ + [ DOM.div { className: "pe-3 col-3 background-color-primary-light overflow-auto d-flex flex-column justify-content-center mb-3 pb-3" } $ + [ DOM.div { className: "fw-bold font-size-2rem my-3" } $ title + , DOM.div { className: "font-size-1rem" } $ description + ] + , DOM.div { className: "ps-3 col-9 bg-white position-relative" } content ] - } + ] -marloweLogoUrl :: SvgUrl -marloweLogoUrl = SvgUrl "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTYwIiBoZWlnaHQ9IjQyIiB2aWV3Qm94PSIwIDAgMTYwIDQyIiBmaWxsPSJub25lIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGRhdGEtbG9nbz0idHJ1ZSI+PGcgY2xpcC1wYXRoPSJ1cmwoI2xvZ29fX2EpIj48cGF0aCBkPSJNNjkuNzEgMjIuMzUydjkuMTJoLTIuOXYtOC43MzRjMC0yLjgzNi0xLjg2OS0zLjc3Mi0zLjQ0OS0zLjc3Mi0xLjU4IDAtMy40MTcuOTM2LTMuNDE3IDMuNzcydjguNzM1aC0yLjkwMXYtOC43MzVjMC0yLjgzNi0xLjg2OS0zLjc3Mi0zLjQ4LTMuNzcyLTEuNjEgMC0zLjQxNy45MzYtMy40MTcgMy43NzJ2OC43MzVoLTIuOTAxVjE2LjY0NmgyLjkwMXYxLjc3MmMxLjA2My0xLjM4NyAyLjY3NC0yIDQuMjU0LTIgMS44NjggMCAzLjgwMy43MSA0LjggMi42MTMgMS4xMy0xLjkzNSAzLjE2LTIuNjEzIDQuOTk4LTIuNjEzIDIuNzA4IDAgNS41MSAxLjQ4NCA1LjUxIDUuOTNsLjAwMy4wMDNaTTg3LjQ2OSAxNi42NXYxNC44MjZoLTIuOTAxdi0yLjI4OWMtMS4wOTUgMS41OC0yLjgwNSAyLjU0Ny01LjA5NCAyLjU0Ny00LjE4OCAwLTcuMTg1LTMuMjU2LTcuMTg1LTcuNjcxIDAtNC40MTUgMi45OTctNy42NCA3LjE4NS03LjY0IDIuMjg5IDAgMy45OTYuOTY3IDUuMDk0IDIuNTEydi0yLjI4OGgyLjkwMXYuMDAzWm0tMi45MDEgNy40MTNjMC0yLjg2Ny0xLjg2OS00Ljg5Ny00LjcwNS00Ljg5Ny0yLjgzNSAwLTQuNzM5IDIuMDMtNC43MzkgNC44OTcgMCAyLjg2NyAxLjg3IDQuOTMyIDQuNzQgNC45MzJzNC43MDQtMi4wOTYgNC43MDQtNC45MzJaTTk4LjY1IDE2LjQyM3YyLjc0Yy0yIC4wMy01LjIyLjktNS4yMiA0LjcwNHY3LjYwNWgtMi45MDJWMTYuNjQ2aDIuOTAydjIuNzRjMS4xNi0yLjAzIDMuMTU5LTIuOTMyIDUuMjItMi45Njd2LjAwNFpNMTAwLjc0NiAzMS40NzZWMTAuNTI0aDIuOTMybC0uMDMxIDIwLjk0OWgtMi45MDF2LjAwM1pNMTA1Ljk1MyAyNC4wNjNjMC00LjQ4IDMuMTI1LTcuNzAyIDcuNjA2LTcuNzAyczcuNTQgMy4yMjQgNy41NCA3LjcwMmMwIDQuNDc3LTMuMDk0IDcuNzAyLTcuNTQgNy43MDJzLTcuNjA2LTMuMjg3LTcuNjA2LTcuNzAyWm0xMi4yOCAwYzAtMi44MzYtMS44NjktNC44OTctNC42NzQtNC44OTctMi44MDUgMC00LjcwNSAyLjA2MS00LjcwNSA0Ljg5NyAwIDIuODM2IDEuODY5IDQuOTMyIDQuNzA1IDQuOTMyIDIuODM2IDAgNC42NzQtMi4xMjcgNC42NzQtNC45MzJaTTE0NC4yODEgMTYuNjVsLTQuOTMxIDE0LjgyNmgtMi44NjdsLTMuNDgtMTAuMjQ5LTMuNTEzIDEwLjI0OWgtMi44NjdsLTQuODY2LTE0LjgyNmgzLjAyOGwzLjQ0OCAxMC43MzQgMy43MzgtMTAuNzM0aDIuMTI3bDMuNjc1IDEwLjczNCAzLjQ4LTEwLjczNGgzLjAyOFpNMTU5LjI0NSAyNC4wNjN2LjgzNmgtMTEuNjY3Yy4yODkgMi42NDMgMi4xNTggNC4zNSA0LjczOSA0LjM1IDIuMTI3IDAgMy40NzktLjk2NyA0LjE4OC0ybDIuMDMxIDEuNDVjLTEuMjkxIDEuODY4LTMuNTE0IDMuMDYzLTYuMjE5IDMuMDYzLTQuNTEyIDAtNy41NC0zLjI4Ny03LjU0LTcuNzAzIDAtNC40MTUgMi45MDEtNy42NyA3LjM0Ny03LjY3IDQuNDQ3IDAgNy4xMjQgMy4yNTUgNy4xMjQgNy42N2wtLjAwMy4wMDRaTTE0Ny41NzggMjNoOC45NThjLS4zNTQtMi40ODItMS45MzQtNC4yODktNC40MTUtNC4yODlzLTQuMTg4IDEuNzA3LTQuNTQzIDQuMjg5WiIgZmlsbD0idmFyKC0tdGV4dC1jb2xvciwjMUMxQzFDKSI+PC9wYXRoPjxwYXRoIGQ9Ik0yMS4yMTcgMS43NDggMTguMTg1IDAgMCAxMC41djIxbC42OTkuNDAzIDIuMzMzIDEuMzQ1TDE4LjE4NSA0Mmw2LjA2NC0zLjV2LTIxbC0xMi4xMjUtNy0zLjAzMiAxLjc0OCAxMi4xMjUgN3YxNy41TDE4LjE4NSAzOC41IDMuMDMyIDI5Ljc0OHYtMTcuNUwxOC4xODUgMy41bDE1LjE1NiA4Ljc0OHYyMWwzLjAzMi0xLjc0OHYtMjFMMjEuMjE3IDEuNzQ4WiIgZmlsbD0iIzUxMUNGNyI+PC9wYXRoPjxwYXRoIGQ9Im0xNS4xNTYgOC43NDggMTIuMTIxIDd2MjFMMzAuMzEgMzVWMTRMMTguMTg1IDdsLTMuMDI5IDEuNzQ4WiIgZmlsbD0iIzUxMUNGNyI+PC9wYXRoPjwvZz48ZGVmcz48Y2xpcFBhdGggaWQ9ImxvZ29fX2EiPjxwYXRoIGZpbGw9IiNmZmYiIGQ9Ik0wIDBoMTU5LjI0NXY0MkgweiI+PC9wYXRoPjwvY2xpcFBhdGg+PC9kZWZzPjwvc3ZnPg==" diff --git a/src/Component/Widgets.purs b/src/Component/Widgets.purs index e844a675..5d02250d 100644 --- a/src/Component/Widgets.purs +++ b/src/Component/Widgets.purs @@ -11,6 +11,7 @@ import Data.Undefined.NoProblem (fromMaybe, toMaybe) as NoProblem import Data.Undefined.NoProblem.Closed (class Coerce, coerce) as NoProblem import Effect (Effect) import Effect.Uncurried (EffectFn1) +import Foreign.Object as Object import Language.Marlowe.Core.V1.Semantics.Types as V1 import Prim.Row as Row import React.Basic (JSX) @@ -24,6 +25,7 @@ import ReactBootstrap.Icons as Icons import ReactBootstrap.Tooltip (TooltipPropsRow) import ReactBootstrap.Types (Placement) import Record as Record +import Runner.Contrib.ReactLoadingOverlayTs as LoadingOverlay import Type.Proxy (Proxy(..)) spinner :: Maybe JSX -> JSX @@ -297,3 +299,25 @@ backToContractListLink onDismiss = do } ] +type LoadingOverlayProps = + { active :: Opt Boolean, showSpinner :: Opt Boolean } + +loadingOverlay :: forall props. NoProblem.Coerce props LoadingOverlayProps => props -> Array JSX -> JSX +loadingOverlay props body = do + let + props' :: LoadingOverlayProps + props' = NoProblem.coerce props + overlaySpinner = + if fromOpt true props'.showSpinner then LoadingOverlay.spinner.jsx $ loadingSpinnerLogo {} + else LoadingOverlay.spinner.boolean false + overlayStyles = do + let + overlay orig = do + let + new = Object.fromHomogeneous { "background-color": "rgba(255, 255, 255, 0.9) !important" } + override = Object.unionWith (\_ n -> n) + orig `override` new + { overlay } + LoadingOverlay.loadingOverlay + { className: "blur-bg rounded", active: props'.active, spinner: overlaySpinner, styles: overlayStyles } + body diff --git a/src/Contrib/Effect/Aff.purs b/src/Contrib/Effect/Aff.purs new file mode 100644 index 00000000..b3dab73d --- /dev/null +++ b/src/Contrib/Effect/Aff.purs @@ -0,0 +1,18 @@ +module Runner.Contrib.Effect.Aff where + +import Prelude + +import Control.Alt ((<|>)) +import Control.Parallel (parallel, sequential) +import Data.Maybe (Maybe(..)) +import Data.Time.Duration (Milliseconds) +import Effect.Aff (Aff, delay) + +withTimeout :: forall a. Milliseconds -> Aff a -> Aff (Maybe a) +withTimeout milliseconds action = do + sequential $ parallel (delay milliseconds $> Nothing) <|> parallel (Just <$> action) + +-- Ignore the fact if the action timed out or not +withTimeout_ :: Milliseconds -> Aff Unit -> Aff Unit +withTimeout_ milliseconds action = do + sequential $ parallel action <|> parallel (delay milliseconds) diff --git a/src/Contrib/ReactLoadingOverlayTs.js b/src/Contrib/ReactLoadingOverlayTs.js new file mode 100644 index 00000000..5b2eeabf --- /dev/null +++ b/src/Contrib/ReactLoadingOverlayTs.js @@ -0,0 +1,8 @@ +import React from "react"; +import LoadingOverlay from "react-loading-overlay-ts"; + +export const loadingOverlayImpl = function(props) { + return function(children) { + return React.createElement(LoadingOverlay, props, ...children); + }; +}; diff --git a/src/Contrib/ReactLoadingOverlayTs.purs b/src/Contrib/ReactLoadingOverlayTs.purs new file mode 100644 index 00000000..4cd80a06 --- /dev/null +++ b/src/Contrib/ReactLoadingOverlayTs.purs @@ -0,0 +1,52 @@ +module Runner.Contrib.ReactLoadingOverlayTs where + +import Data.Nullable (Nullable) +import Data.Undefined.NoProblem (Opt) +import Data.Undefined.NoProblem.Closed as NoProblem +import Foreign.Object (Object) +import React.Basic (JSX) +import React.Basic.Events (EventHandler) +import Unsafe.Coerce (unsafeCoerce) +import Web.DOM as DOM + +foreign import data LoadingOverlay_ :: Type + +-- | Type and safe constructors for spinner sum type: `boolean | react node` +foreign import data Spinner :: Type + +spinner :: { boolean :: Boolean -> Spinner, jsx :: JSX -> Spinner } +spinner = { boolean: unsafeCoerce, jsx: unsafeCoerce } + +type SetStyles = Object String -> Object String + +type Styles = + { overlay :: Opt SetStyles + , content :: Opt SetStyles + , spinner :: Opt SetStyles + , wrapper :: Opt SetStyles + } + +type Props = + { active :: Opt Boolean + , fadeSpeed :: Opt Int + , onClick :: Opt (EventHandler) + , className :: Opt String + , classNamePrefix :: Opt String + , spinner :: Opt Spinner + , text :: Opt JSX + , styles :: Opt Styles + , ref :: Opt (Nullable DOM.Node) + } + +foreign import loadingOverlayImpl :: Props -> Array JSX -> JSX + +loadingOverlay + :: forall props + . NoProblem.Coerce { | props } Props + => { | props } + -> Array JSX + -> JSX +loadingOverlay props children = do + let + props' = NoProblem.coerce props + loadingOverlayImpl props' children