diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100644 index 0000000..509f4b5 --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1,4 @@ +#!/bin/sh +. "$(dirname "$0")/_/husky.sh" + +npx lint-staged \ No newline at end of file diff --git a/index.html b/index.html index 11b7ef1..49e9957 100644 --- a/index.html +++ b/index.html @@ -9,7 +9,6 @@ - diff --git a/package-lock.json b/package-lock.json index 80b46e6..b6416bd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,6 +15,7 @@ "@arweave-wallet-kit/react": "^0.3.2", "@arweave-wallet-kit/styles": "^0.1.1", "@arweave-wallet-kit/wander-strategy": "^0.1.2", + "@egjs/hammerjs": "^2.0.17", "@emotion/react": "^11.14.0", "@emotion/styled": "^11.14.0", "@fontsource/dm-sans": "^5.0.21", @@ -30,26 +31,34 @@ "@popperjs/core": "^2.11.8", "@supabase/supabase-js": "^2.39.0", "@tanstack/react-query": "^5.56.2", + "@types/hammerjs": "^2.0.46", "@vela-ventures/aosync-strategy": "^1.0.11", "@vitejs/plugin-react": "^4.3.1", "ansi-to-html": "^0.7.2", "clsx": "^2.1.0", + "component-emitter": "^1.3.1", "d3": "^7.9.0", "date-fns": "^3.3.1", "dayjs": "^1.11.10", "highcharts": "^11.3.0", "highcharts-react-official": "^3.2.1", + "keycharm": "^0.4.0", "lodash-es": "^4.17.21", "mixpanel": "^0.18.0", "mixpanel-browser": "^2.49.0", + "monaco-editor": "^0.52.2", "nanostores": "^0.10.3", "react": "^18", "react-dom": "^18", + "react-error-boundary": "^4.1.2", "react-router-dom": "^6.23.1", "react-syntax-highlighter": "^15.5.0", "react-vis-graph-wrapper": "^0.1.3", + "react-window": "^1.8.7", "tailwind-merge": "^2.2.1", - "urql": "^4.1.0" + "urql": "^4.1.0", + "uuid": "^9.0.1", + "vis-util": "^5.0.7" }, "devDependencies": { "@irys/sdk": "0.2.10", @@ -61,6 +70,7 @@ "@types/react": "^18", "@types/react-dom": "^18", "@types/react-syntax-highlighter": "^15.5.13", + "@types/react-window": "^1.8.5", "@typescript-eslint/eslint-plugin": "^6.21.0", "@typescript-eslint/parser": "^6.21.0", "arweavekit": "^1.5.1", @@ -73,9 +83,12 @@ "eslint-plugin-prettier": "^5.1.3", "eslint-plugin-simple-import-sort": "^10.0.0", "eslint-plugin-unused-imports": "^3.0.0", + "husky": "^8.0.3", + "lint-staged": "^15.2.0", "permaweb-deploy": "^1.1.7", "postcss": "^8", "prettier": "^3.2.5", + "rollup-plugin-visualizer": "^5.9.0", "tailwindcss": "^3.3.0", "typescript": "^5", "vite": "^5.2.13", @@ -241,6 +254,19 @@ "node": ">=18" } }, + "node_modules/@ar.io/sdk/node_modules/uuid": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.1.0.tgz", + "integrity": "sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/esm/bin/uuid" + } + }, "node_modules/@ardrive/turbo-sdk": { "version": "1.26.0", "dev": true, @@ -1025,8 +1051,9 @@ }, "node_modules/@egjs/hammerjs": { "version": "2.0.17", + "resolved": "https://registry.npmjs.org/@egjs/hammerjs/-/hammerjs-2.0.17.tgz", + "integrity": "sha512-XQsZgjm2EcVUiZQf11UBJQfmZeEmOW8DpI1gsFeln6w0ae0ii4dMQEQ0kjl6DspdWX1aGY1/loyXnP0JS06e/A==", "license": "MIT", - "peer": true, "dependencies": { "@types/hammerjs": "^2.0.36" }, @@ -3847,8 +3874,9 @@ }, "node_modules/@types/hammerjs": { "version": "2.0.46", - "license": "MIT", - "peer": true + "resolved": "https://registry.npmjs.org/@types/hammerjs/-/hammerjs-2.0.46.tgz", + "integrity": "sha512-ynRvcq6wvqexJ9brDMS4BnBLzmr0e14d6ZJTEShTBWKymQiHwlAyGu0ZPEFI2Fh1U53F7tN9ufClWM5KvqkKOw==", + "license": "MIT" }, "node_modules/@types/hast": { "version": "2.3.10", @@ -3952,6 +3980,16 @@ "@types/react": "*" } }, + "node_modules/@types/react-window": { + "version": "1.8.8", + "resolved": "https://registry.npmjs.org/@types/react-window/-/react-window-1.8.8.tgz", + "integrity": "sha512-8Ls660bHR1AUA2kuRvVG9D/4XpRC6wjAaPT9dil7Ckc76eP9TKWZwwmgfq8Q1LANX3QNDnoU4Zp48A3w+zK69Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/react": "*" + } + }, "node_modules/@types/readable-stream": { "version": "4.0.21", "license": "MIT", @@ -4227,6 +4265,19 @@ "uuid": "^11.0.3" } }, + "node_modules/@vela-ventures/ao-sync-sdk/node_modules/uuid": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.1.0.tgz", + "integrity": "sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/esm/bin/uuid" + } + }, "node_modules/@vela-ventures/aosync-strategy": { "version": "1.0.12", "license": "MIT", @@ -5935,6 +5986,77 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/cli-truncate": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-4.0.0.tgz", + "integrity": "sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==", + "dev": true, + "license": "MIT", + "dependencies": { + "slice-ansi": "^5.0.0", + "string-width": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-truncate/node_modules/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/cli-truncate/node_modules/emoji-regex": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz", + "integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==", + "dev": true, + "license": "MIT" + }, + "node_modules/cli-truncate/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-truncate/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, "node_modules/cli-width": { "version": "3.0.0", "dev": true, @@ -6046,6 +6168,13 @@ "simple-swizzle": "^0.2.2" } }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "dev": true, + "license": "MIT" + }, "node_modules/colorspace": { "version": "1.1.4", "license": "MIT", @@ -6085,8 +6214,9 @@ }, "node_modules/component-emitter": { "version": "1.3.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.1.tgz", + "integrity": "sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==", "license": "MIT", - "peer": true, "funding": { "url": "https://github.com/sponsors/sindresorhus" } @@ -6984,6 +7114,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/define-lazy-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", + "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/define-properties": { "version": "1.2.1", "dev": true, @@ -7219,6 +7359,19 @@ "url": "https://github.com/fb55/entities?sponsor=1" } }, + "node_modules/environment": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz", + "integrity": "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/err-code": { "version": "3.0.1", "dev": true, @@ -8551,6 +8704,85 @@ "safe-buffer": "^5.1.1" } }, + "node_modules/execa": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", + "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^8.0.1", + "human-signals": "^5.0.0", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^4.1.0", + "strip-final-newline": "^3.0.0" + }, + "engines": { + "node": ">=16.17" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/execa/node_modules/get-stream": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", + "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/execa/node_modules/is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/execa/node_modules/mimic-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/execa/node_modules/onetime": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/exponential-backoff": { "version": "3.1.2", "license": "Apache-2.0", @@ -9059,6 +9291,19 @@ "node": "6.* || 8.* || >= 10.*" } }, + "node_modules/get-east-asian-width": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.3.0.tgz", + "integrity": "sha512-vpeMIQKxczTD/0s2CdEWHcb0eeJe6TFjxb+J5xgX7hScxqrGuyjmv4c1D4A/gelKfyox0gJJwIHF+fLjeaM8kQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/get-intrinsic": { "version": "1.3.0", "license": "MIT", @@ -9563,6 +9808,16 @@ "pify": "^4.0.1" } }, + "node_modules/human-signals": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", + "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=16.17.0" + } + }, "node_modules/humanize-ms": { "version": "1.2.1", "dev": true, @@ -9575,6 +9830,22 @@ "version": "0.0.2", "dev": true }, + "node_modules/husky": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/husky/-/husky-8.0.3.tgz", + "integrity": "sha512-+dQSyqPh4x1hlO1swXBiNb2HzTDN1I2IGLQx1GrBuiqFJfoMrnZWwVmatvSiO+Iz8fBUnf+lekwNo4c2LlXItg==", + "dev": true, + "license": "MIT", + "bin": { + "husky": "lib/bin.js" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/typicode" + } + }, "node_modules/hyper-async": { "version": "1.1.2", "license": "MIT" @@ -9971,6 +10242,22 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "dev": true, + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-extendable": { "version": "1.0.1", "license": "MIT", @@ -10295,6 +10582,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/isarray": { "version": "1.0.0", "dev": true, @@ -10679,8 +10979,9 @@ }, "node_modules/keycharm": { "version": "0.4.0", - "license": "(Apache-2.0 OR MIT)", - "peer": true + "resolved": "https://registry.npmjs.org/keycharm/-/keycharm-0.4.0.tgz", + "integrity": "sha512-TyQTtsabOVv3MeOpR92sIKk/br9wxS+zGj4BG7CR8YbK4jM3tyIBaF0zhzeBUMx36/Q/iQLOKKOT+3jOQtemRQ==", + "license": "(Apache-2.0 OR MIT)" }, "node_modules/keypair": { "version": "1.0.4", @@ -10880,43 +11181,184 @@ "version": "1.2.4", "license": "MIT" }, - "node_modules/locate-path": { - "version": "6.0.0", + "node_modules/lint-staged": { + "version": "15.5.2", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-15.5.2.tgz", + "integrity": "sha512-YUSOLq9VeRNAo/CTaVmhGDKG+LBtA8KF1X4K5+ykMSwWST1vDxJRB2kv2COgLb1fvpCo+A/y9A0G0znNVmdx4w==", + "dev": true, "license": "MIT", "dependencies": { - "p-locate": "^5.0.0" + "chalk": "^5.4.1", + "commander": "^13.1.0", + "debug": "^4.4.0", + "execa": "^8.0.1", + "lilconfig": "^3.1.3", + "listr2": "^8.2.5", + "micromatch": "^4.0.8", + "pidtree": "^0.6.0", + "string-argv": "^0.3.2", + "yaml": "^2.7.0" + }, + "bin": { + "lint-staged": "bin/lint-staged.js" }, "engines": { - "node": ">=10" + "node": ">=18.12.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://opencollective.com/lint-staged" } }, - "node_modules/lodash": { - "version": "4.17.21", - "license": "MIT" + "node_modules/lint-staged/node_modules/commander": { + "version": "13.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-13.1.0.tgz", + "integrity": "sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } }, - "node_modules/lodash-es": { - "version": "4.17.21", - "license": "MIT" + "node_modules/listr2": { + "version": "8.3.3", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-8.3.3.tgz", + "integrity": "sha512-LWzX2KsqcB1wqQ4AHgYb4RsDXauQiqhjLk+6hjbaeHG4zpjjVAB6wC/gz6X0l+Du1cN3pUB5ZlrvTbhGSNnUQQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "cli-truncate": "^4.0.0", + "colorette": "^2.0.20", + "eventemitter3": "^5.0.1", + "log-update": "^6.1.0", + "rfdc": "^1.4.1", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=18.0.0" + } }, - "node_modules/lodash.defaults": { - "version": "4.2.0", + "node_modules/listr2/node_modules/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", "dev": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } }, - "node_modules/lodash.difference": { - "version": "4.5.0", + "node_modules/listr2/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", "dev": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } }, - "node_modules/lodash.flatten": { - "version": "4.4.0", + "node_modules/listr2/node_modules/emoji-regex": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz", + "integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==", "dev": true, "license": "MIT" }, - "node_modules/lodash.isplainobject": { + "node_modules/listr2/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/listr2/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/listr2/node_modules/wrap-ansi": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.0.tgz", + "integrity": "sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "license": "MIT" + }, + "node_modules/lodash-es": { + "version": "4.17.21", + "license": "MIT" + }, + "node_modules/lodash.defaults": { + "version": "4.2.0", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.difference": { + "version": "4.5.0", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.flatten": { + "version": "4.4.0", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.isplainobject": { "version": "4.0.6", "dev": true, "license": "MIT" @@ -10972,6 +11414,209 @@ "node": ">=8" } }, + "node_modules/log-update": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-6.1.0.tgz", + "integrity": "sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-escapes": "^7.0.0", + "cli-cursor": "^5.0.0", + "slice-ansi": "^7.1.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/ansi-escapes": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.0.0.tgz", + "integrity": "sha512-GdYO7a61mR0fOlAsvC9/rIHf7L96sBc6dEWzeOu+KAea5bZyQRPIpojrVoI4AXGJS/ycu/fBTdLrUkA4ODrvjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "environment": "^1.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/log-update/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/log-update/node_modules/cli-cursor": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", + "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", + "dev": true, + "license": "MIT", + "dependencies": { + "restore-cursor": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/emoji-regex": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz", + "integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==", + "dev": true, + "license": "MIT" + }, + "node_modules/log-update/node_modules/is-fullwidth-code-point": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.0.0.tgz", + "integrity": "sha512-OVa3u9kkBbw7b8Xw5F9P+D/T9X+Z4+JruYVNapTjPYZYUznQ5YfWeFkOj606XYYW8yugTfC8Pj0hYqvi4ryAhA==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-east-asian-width": "^1.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/onetime": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", + "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-function": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/restore-cursor": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", + "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==", + "dev": true, + "license": "MIT", + "dependencies": { + "onetime": "^7.0.0", + "signal-exit": "^4.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/slice-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.0.tgz", + "integrity": "sha512-bSiSngZ/jWeX93BqeIAbImyTbEihizcwNjFoRUIY/T1wWQsfsm2Vw1agPKylXvQTU7iASGdHhyqRlqQzfz+Htg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "is-fullwidth-code-point": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/log-update/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/log-update/node_modules/wrap-ansi": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.0.tgz", + "integrity": "sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/logform": { "version": "2.7.0", "license": "MIT", @@ -11071,6 +11716,12 @@ "safe-buffer": "^5.1.2" } }, + "node_modules/memoize-one": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz", + "integrity": "sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==", + "license": "MIT" + }, "node_modules/memory-level": { "version": "1.0.0", "dev": true, @@ -11084,6 +11735,13 @@ "node": ">=12" } }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true, + "license": "MIT" + }, "node_modules/merge2": { "version": "1.4.1", "dev": true, @@ -11146,6 +11804,19 @@ "node": ">=6" } }, + "node_modules/mimic-function": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", + "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/mimic-response": { "version": "1.0.1", "dev": true, @@ -11264,8 +11935,9 @@ }, "node_modules/monaco-editor": { "version": "0.52.2", - "license": "MIT", - "peer": true + "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.52.2.tgz", + "integrity": "sha512-GEQWEZmfkOGLdd3XK8ryrfWz3AIP8YymVXiPHEdewrUq7mh0qrKrfHLNCXcbB6sTnMLnOZ3ztSiKcciFUkIJwQ==", + "license": "MIT" }, "node_modules/mqtt": { "version": "5.13.1", @@ -11785,6 +12457,35 @@ "npm-normalize-package-bin": "^1.0.1" } }, + "node_modules/npm-run-path": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz", + "integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm-run-path/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/npmlog": { "version": "4.1.2", "dev": true, @@ -11984,6 +12685,24 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/open": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", + "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/optionator": { "version": "0.9.4", "dev": true, @@ -12472,6 +13191,19 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/pidtree": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.6.0.tgz", + "integrity": "sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==", + "dev": true, + "license": "MIT", + "bin": { + "pidtree": "bin/pidtree.js" + }, + "engines": { + "node": ">=0.10" + } + }, "node_modules/pify": { "version": "4.0.1", "dev": true, @@ -13059,6 +13791,18 @@ "react": "^18.3.1" } }, + "node_modules/react-error-boundary": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/react-error-boundary/-/react-error-boundary-4.1.2.tgz", + "integrity": "sha512-GQDxZ5Jd+Aq/qUxbCm1UtzmL/s++V7zKgE8yMktJiCQXCCFZnMZh9ng+6/Ne6PjNSXH0L9CjeOEREfRnq6Duag==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.12.5" + }, + "peerDependencies": { + "react": ">=16.13.1" + } + }, "node_modules/react-fast-compare": { "version": "3.2.2", "license": "MIT" @@ -13175,18 +13919,6 @@ "react": ">=16" } }, - "node_modules/react-vis-graph-wrapper/node_modules/uuid": { - "version": "9.0.1", - "funding": [ - "https://github.com/sponsors/broofa", - "https://github.com/sponsors/ctavan" - ], - "license": "MIT", - "peer": true, - "bin": { - "uuid": "dist/bin/uuid" - } - }, "node_modules/react-vis-graph-wrapper/node_modules/vis-data": { "version": "7.1.9", "license": "(Apache-2.0 OR MIT)", @@ -13215,6 +13947,23 @@ "vis-util": "^5.0.1" } }, + "node_modules/react-window": { + "version": "1.8.11", + "resolved": "https://registry.npmjs.org/react-window/-/react-window-1.8.11.tgz", + "integrity": "sha512-+SRbUVT2scadgFSWx+R1P754xHPEqvcfSfVX10QYg6POOz+WNgkN48pS+BtZNIMGiL1HYrSEiCkwsMS15QogEQ==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.0.0", + "memoize-one": ">=3.1.1 <6" + }, + "engines": { + "node": ">8.0.0" + }, + "peerDependencies": { + "react": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, "node_modules/read-cache": { "version": "1.0.0", "dev": true, @@ -13559,6 +14308,60 @@ "fsevents": "~2.3.2" } }, + "node_modules/rollup-plugin-visualizer": { + "version": "5.14.0", + "resolved": "https://registry.npmjs.org/rollup-plugin-visualizer/-/rollup-plugin-visualizer-5.14.0.tgz", + "integrity": "sha512-VlDXneTDaKsHIw8yzJAFWtrzguoJ/LnQ+lMpoVfYJ3jJF4Ihe5oYLAqLklIK/35lgUY+1yEzCkHyZ1j4A5w5fA==", + "dev": true, + "license": "MIT", + "dependencies": { + "open": "^8.4.0", + "picomatch": "^4.0.2", + "source-map": "^0.7.4", + "yargs": "^17.5.1" + }, + "bin": { + "rollup-plugin-visualizer": "dist/bin/cli.js" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "rolldown": "1.x", + "rollup": "2.x || 3.x || 4.x" + }, + "peerDependenciesMeta": { + "rolldown": { + "optional": true + }, + "rollup": { + "optional": true + } + } + }, + "node_modules/rollup-plugin-visualizer/node_modules/picomatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/rollup-plugin-visualizer/node_modules/source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">= 8" + } + }, "node_modules/rollup/node_modules/@rollup/rollup-android-arm-eabi": { "version": "4.41.1", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.41.1.tgz", @@ -14280,6 +15083,49 @@ "node": ">=8" } }, + "node_modules/slice-ansi": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz", + "integrity": "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.0.0", + "is-fullwidth-code-point": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/slice-ansi/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/slice-ansi/node_modules/is-fullwidth-code-point": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", + "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/smart-buffer": { "version": "4.2.0", "license": "MIT", @@ -14512,6 +15358,16 @@ "version": "5.1.2", "license": "MIT" }, + "node_modules/string-argv": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz", + "integrity": "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.6.19" + } + }, "node_modules/string-width": { "version": "4.2.3", "license": "MIT", @@ -14678,6 +15534,19 @@ "node": ">=4" } }, + "node_modules/strip-final-newline": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/strip-json-comments": { "version": "3.1.1", "dev": true, @@ -15722,14 +16591,16 @@ } }, "node_modules/uuid": { - "version": "11.1.0", + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", "funding": [ "https://github.com/sponsors/broofa", "https://github.com/sponsors/ctavan" ], "license": "MIT", "bin": { - "uuid": "dist/esm/bin/uuid" + "uuid": "dist/bin/uuid" } }, "node_modules/uzip-module": { @@ -15747,8 +16618,9 @@ }, "node_modules/vis-util": { "version": "5.0.7", + "resolved": "https://registry.npmjs.org/vis-util/-/vis-util-5.0.7.tgz", + "integrity": "sha512-E3L03G3+trvc/X4LXvBfih3YIHcKS2WrP0XTdZefr6W6Qi/2nNCqZfe4JFfJU6DcQLm6Gxqj2Pfl+02859oL5A==", "license": "(Apache-2.0 OR MIT)", - "peer": true, "engines": { "node": ">=8" }, diff --git a/package.json b/package.json index 144713e..2425744 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ "check-types": "tsc --noEmit", "lint": "eslint .", "lint:fix": "npm run lint -- --fix", + "prepare": "husky install", "predeploy": "rm -rf ./dist-* && npm run build", "deploy": "permaweb-deploy --ant-process My3zjcGNtaOaZntPCLXZjIKAzOqluRRHCIUh9mUzzAo" }, @@ -19,6 +20,7 @@ "@arweave-wallet-kit/react": "^0.3.2", "@arweave-wallet-kit/styles": "^0.1.1", "@arweave-wallet-kit/wander-strategy": "^0.1.2", + "@egjs/hammerjs": "^2.0.17", "@emotion/react": "^11.14.0", "@emotion/styled": "^11.14.0", "@fontsource/dm-sans": "^5.0.21", @@ -34,26 +36,34 @@ "@popperjs/core": "^2.11.8", "@supabase/supabase-js": "^2.39.0", "@tanstack/react-query": "^5.56.2", + "@types/hammerjs": "^2.0.46", "@vela-ventures/aosync-strategy": "^1.0.11", "@vitejs/plugin-react": "^4.3.1", "ansi-to-html": "^0.7.2", "clsx": "^2.1.0", + "component-emitter": "^1.3.1", "d3": "^7.9.0", "date-fns": "^3.3.1", "dayjs": "^1.11.10", "highcharts": "^11.3.0", "highcharts-react-official": "^3.2.1", + "keycharm": "^0.4.0", "lodash-es": "^4.17.21", "mixpanel": "^0.18.0", "mixpanel-browser": "^2.49.0", + "monaco-editor": "^0.52.2", "nanostores": "^0.10.3", "react": "^18", "react-dom": "^18", + "react-error-boundary": "^4.1.2", "react-router-dom": "^6.23.1", "react-syntax-highlighter": "^15.5.0", "react-vis-graph-wrapper": "^0.1.3", + "react-window": "^1.8.7", "tailwind-merge": "^2.2.1", - "urql": "^4.1.0" + "urql": "^4.1.0", + "uuid": "^9.0.1", + "vis-util": "^5.0.7" }, "devDependencies": { "@irys/sdk": "0.2.10", @@ -65,6 +75,7 @@ "@types/react": "^18", "@types/react-dom": "^18", "@types/react-syntax-highlighter": "^15.5.13", + "@types/react-window": "^1.8.5", "@typescript-eslint/eslint-plugin": "^6.21.0", "@typescript-eslint/parser": "^6.21.0", "arweavekit": "^1.5.1", @@ -77,13 +88,22 @@ "eslint-plugin-prettier": "^5.1.3", "eslint-plugin-simple-import-sort": "^10.0.0", "eslint-plugin-unused-imports": "^3.0.0", + "husky": "^8.0.3", + "lint-staged": "^15.2.0", "permaweb-deploy": "^1.1.7", "postcss": "^8", "prettier": "^3.2.5", + "rollup-plugin-visualizer": "^5.9.0", "tailwindcss": "^3.3.0", "typescript": "^5", "vite": "^5.2.13", "warp-arbundles": "^1.0.4" }, - "packageManager": "yarn@1.22.22+sha1.ac34549e6aa8e7ead463a7407e1c7390f61a6610" + "packageManager": "yarn@1.22.22+sha1.ac34549e6aa8e7ead463a7407e1c7390f61a6610", + "lint-staged": { + "*.{ts,tsx,js,jsx,json,css,md}": [ + "prettier --write", + "eslint --fix" + ] + } } diff --git a/src/app/HomePage.tsx b/src/app/HomePage.tsx index 94bc34a..6932a3f 100644 --- a/src/app/HomePage.tsx +++ b/src/app/HomePage.tsx @@ -1,9 +1,10 @@ "use client" +import React, { useEffect, useMemo, useState } from "react" +import PageWrapper from "@/components/PageWrapper" import { Box, Skeleton, Stack } from "@mui/material" import Grid2 from "@mui/material/Unstable_Grid2/Grid2" -import { useEffect, useMemo, useState } from "react" import { AllMessagesTable } from "./AllMessagesTable" import { AreaChart } from "@/components/Charts/AreaChart" @@ -15,7 +16,7 @@ import { HighchartAreaData, NetworkStat } from "@/types" import { formatAbsString } from "@/utils/date-utils" import { wait } from "@/utils/utils" -export default function HomePage() { +function HomePageContent() { const [stats, setStats] = useState() useEffect(() => { @@ -67,42 +68,50 @@ export default function HomePage() { ) return ( - + {!stats ? ( - - + + - + - + - + ) : ( - - + + - + - + - + )} - + {/* Adjust negative margin for mobile */} ) } + +export default function HomePage() { + return ( + + + + ) +} diff --git a/src/app/SearchBar.tsx b/src/app/SearchBar.tsx index df91cd0..911c70e 100644 --- a/src/app/SearchBar.tsx +++ b/src/app/SearchBar.tsx @@ -212,7 +212,19 @@ const SearchBar = () => { const navigate = useNavigate() return ( - + page.items) ?? [] const totalItems = data?.pages[0]?.totalItems ?? 0 - if (isError) { - return ( - - - Error loading ArNS records: {error?.message} - - - ) - } + if (isError) return - return ( + const content = ( 0 ? totalItems : undefined} /> @@ -53,10 +47,12 @@ export default function ArnsPage() { {isLoading ? ( - + ) : ( - + + + {/* Load More Button */} {hasNextPage && ( @@ -76,4 +72,6 @@ export default function ArnsPage() { ) + + return {content} } diff --git a/src/app/block/[slug]/BlockPage.tsx b/src/app/block/[slug]/BlockPage.tsx index 236fea3..20fbd45 100644 --- a/src/app/block/[slug]/BlockPage.tsx +++ b/src/app/block/[slug]/BlockPage.tsx @@ -1,9 +1,8 @@ "use client" +import React, { useState } from "react" import { Box, Stack, Tabs } from "@mui/material" -import { useState } from "react" - import { useParams } from "react-router-dom" import { BlockMessagesTable } from "./BlockMessagesTable" @@ -13,6 +12,7 @@ import { Subheading } from "@/components/Subheading" import { TabWithCount } from "@/components/TabWithCount" import { formatNumber } from "@/utils/number-utils" +import PageWrapper from "@/components/PageWrapper" export default function BlockPage() { const params = useParams() @@ -26,19 +26,21 @@ export default function BlockPage() { const [messagesCount, setMessagesCount] = useState() return ( - - } - /> -
- - - - - - -
-
+ + + } + /> +
+ + + + + + +
+
+
) } diff --git a/src/app/blocks/BlocksPage.tsx b/src/app/blocks/BlocksPage.tsx index 9cc9883..c2037a7 100644 --- a/src/app/blocks/BlocksPage.tsx +++ b/src/app/blocks/BlocksPage.tsx @@ -1,17 +1,21 @@ "use client" import { Box, Stack } from "@mui/material" +import React from "react" +import PageWrapper from "@/components/PageWrapper" import { AllBlocks } from "./AllBlocks" import { Subheading } from "@/components/Subheading" export default function BlocksPage() { return ( - - - - - - + + + + + + + + ) } diff --git a/src/app/entity/[slug]/EntityMessagesTable.tsx b/src/app/entity/[slug]/EntityMessagesTable.tsx index be999a2..04d8fa9 100644 --- a/src/app/entity/[slug]/EntityMessagesTable.tsx +++ b/src/app/entity/[slug]/EntityMessagesTable.tsx @@ -127,6 +127,7 @@ export function EntityMessagesTable(props: EntityMessagesTableProps) { return ( isArweaveId(String(entityId)), [entityId]) @@ -48,3 +49,11 @@ export default function EntityPage() { return } + +export default function EntityPage() { + return ( + + + + ) +} diff --git a/src/app/entity/[slug]/ProcessPage.tsx b/src/app/entity/[slug]/ProcessPage.tsx index 49ca655..5ee68e7 100644 --- a/src/app/entity/[slug]/ProcessPage.tsx +++ b/src/app/entity/[slug]/ProcessPage.tsx @@ -118,12 +118,19 @@ export function ProcessPage(props: ProcessPageProps) { }, [outgoingMessages, entities]) return ( - + } /> - - + + {graphData === null ? ( @@ -177,7 +184,14 @@ export function ProcessPage(props: ProcessPageProps) { - + @@ -187,7 +201,7 @@ export function ProcessPage(props: ProcessPageProps) { - + {/* Adjust negative margin for mobile */}
- + diff --git a/src/app/globals.css b/src/app/globals.css index b963277..0355ac8 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -98,3 +98,24 @@ body * { body .a1osnke6 > div:not(:nth-child(1)) { display: none; } + +/* --- Responsive helpers -------------------------------------------------- */ +@media (max-width: 600px) { + table, + pre { + display: block; + overflow-x: auto; + -webkit-overflow-scrolling: touch; + } +} + +img, +video { + max-width: 100%; + height: auto; +} + +input, +button { + touch-action: manipulation; +} diff --git a/src/app/message/[slug]/CombinedMessagesTable.tsx b/src/app/message/[slug]/CombinedMessagesTable.tsx new file mode 100644 index 0000000..f6d2964 --- /dev/null +++ b/src/app/message/[slug]/CombinedMessagesTable.tsx @@ -0,0 +1,129 @@ +import { ArrowLeft, ArrowRight } from "@phosphor-icons/react" +import React, { memo } from "react" + +import { AsyncTable, AsyncTableProps } from "@/components/AsyncTable" +import { IdBlock } from "@/components/IdBlock" +import { TypeBadge } from "@/components/TypeBadge" +import { getLinkedMessages, getResultingMessages } from "@/services/messages-api" +import { AoMessage } from "@/types" +import { truncateId } from "@/utils/data-utils" +import { formatFullDate, formatRelative } from "@/utils/date-utils" +import { TableRow, TableCell } from "@mui/material" +import { useNavigate } from "react-router-dom" + +interface Props { + message: AoMessage + computeResult: any + pageSize: number + onCountReady?: (c: number) => void + onDataReady?: (d: AoMessage[]) => void +} + +// add flag indicating direction +interface DirMessage extends AoMessage { + _dir: "in" | "out" +} + +function BaseCombinedTable(props: Props) { + const { message, computeResult, pageSize, onCountReady, onDataReady } = props + const pushedFor = message.tags["Pushed-For"] + + const navigate = useNavigate() + + // Keep track of message ids already sent to the table to avoid duplicates which can + // cause the infinite-fetch loop (observer sees loader immediately because list height + // doesn't grow when we repeatedly get the same items). + const seenIdsRef = React.useRef>(new Set()) + + return ( + { + // On first call we need both resulting and first page of linked. + + const linkedCursor = last?._dir === "in" ? last.cursor : undefined + + const [linkedCountRaw, linked] = await getLinkedMessages( + pageSize, + linkedCursor, + ascending, + pushedFor || message.id, + ) + + let resulting: AoMessage[] = [] + let resultingCount = 0 + if (offset === 0) { + const res = await getResultingMessages( + pageSize, + undefined, + ascending, + pushedFor || message.id, + message.to, + [], + false, + ) + resultingCount = res[0] ?? 0 + resulting = res[1] + } + + const linkedCount = linkedCountRaw || 0 + const totalCount = linkedCount + resultingCount + if (onCountReady) onCountReady(totalCount) + + const mergedRaw: DirMessage[] = [ + ...resulting.map((m) => ({ ...(m as any), _dir: "out" })), + ...linked.map((m) => ({ ...(m as any), _dir: "in" })), + ] + + // Deduplicate across fetches + const merged: DirMessage[] = [] + mergedRaw.forEach((item) => { + if (!seenIdsRef.current.has(item.id)) { + seenIdsRef.current.add(item.id) + merged.push(item) + } + }) + + // If no new items were added, signal end. + if (merged.length === 0) return [] + + if (onDataReady && offset === 0) onDataReady(merged) + return merged + }} + renderRow={(row: DirMessage) => { + return ( + navigate(`/message/${row.id}`)} + > + + {row._dir === "out" ? : } + + + + + + + + + {row.ingestedAt ? formatRelative(row.ingestedAt) : "-"} + + + ) + }} + virtualize + /> + ) +} + +export const CombinedMessagesTable = memo(BaseCombinedTable) \ No newline at end of file diff --git a/src/app/message/[slug]/MessagePage.tsx b/src/app/message/[slug]/MessagePage.tsx index d822c29..8f45c0f 100644 --- a/src/app/message/[slug]/MessagePage.tsx +++ b/src/app/message/[slug]/MessagePage.tsx @@ -93,7 +93,9 @@ export function MessagePage() { Promise.all(entityIds.map(getMessageById)).then((entitiesArray) => { const newEntities = Object.fromEntries( - entitiesArray.filter((x): x is AoMessage => x !== undefined).map((x) => [x.id, x]), + entitiesArray + .filter((x): x is AoMessage => x !== undefined && x !== null) + .map((x) => [x.id, x]), ) setEntities((prev) => ({ ...prev, ...newEntities })) @@ -169,7 +171,7 @@ export function MessagePage() { - + {graphData === null ? ( diff --git a/src/app/message/[slug]/TransactionDetailsTabs.tsx b/src/app/message/[slug]/TransactionDetailsTabs.tsx new file mode 100644 index 0000000..041d9f4 --- /dev/null +++ b/src/app/message/[slug]/TransactionDetailsTabs.tsx @@ -0,0 +1,89 @@ +import React, { Suspense, lazy, useState } from "react" +import { Box, CircularProgress, Tabs } from "@mui/material" +import { TabWithCount } from "@/components/TabWithCount" +import { AoMessage } from "@/types" +import { CombinedMessagesTable } from "./CombinedMessagesTable" +import { MessageData } from "./MessageData" +import { ComputeResult } from "./ComputeResult" +import { TagsSection } from "@/components/TagsSection" + +const GraphTab = lazy(() => import("@/components/Graph").then((m) => ({ default: m.Graph }))) + +interface Props { + message: AoMessage + pushedFor?: string + computeResult: any + totalCount?: number + onCount: (total: number | undefined) => void + onGraphData: (data: AoMessage[]) => void +} + +export default function TransactionDetailsTabs(props: Props) { + const { + message, + pushedFor, + computeResult, + totalCount, + onCount, + onGraphData, + } = props + + const [tab, setTab] = useState("messages") + const [localCount, setLocalCount] = useState() + + return ( + + setTab(v)} + textColor="primary" + variant="scrollable" + scrollButtons="auto" + allowScrollButtonsMobile + > + + + + + + {tab === "messages" && ( + { + setLocalCount(c) + onCount(c) + }} + onDataReady={onGraphData} + /> + )} + + {tab === "details" && ( + + + + null} + /> + + + )} + + {tab === "graph" && ( + + + + } + > + + + )} + + ) +} \ No newline at end of file diff --git a/src/app/message/[slug]/TransactionHero.tsx b/src/app/message/[slug]/TransactionHero.tsx new file mode 100644 index 0000000..0130539 --- /dev/null +++ b/src/app/message/[slug]/TransactionHero.tsx @@ -0,0 +1,96 @@ +import { Paper, Stack, Typography, Tooltip } from "@mui/material" +import { formatFullDate, formatRelative } from "@/utils/date-utils" +import { formatNumber } from "@/utils/number-utils" +import { truncateId } from "@/utils/data-utils" +import { AoMessage } from "@/types" +import { IdBlock } from "@/components/IdBlock" +import { EntityBlock } from "@/components/EntityBlock" + +interface Props { + message: AoMessage + pushedFor?: string +} + +export default function TransactionHero(props: Props) { + const { message, pushedFor } = props + const { id, type, from, to, blockHeight, ingestedAt } = message + + return ( + + + + {type.toUpperCase()} + + + + + + + From + + + {to && ( + <> + + → To + + + + )} + + + + + Block + + {blockHeight === null ? ( + Processing + ) : ( + + )} + + + + + Seen + + {ingestedAt ? ( + + {formatRelative(ingestedAt)} + + ) : ( + Processing + )} + + + {pushedFor && ( + + + Pushed for + + + + )} + + ) +} \ No newline at end of file diff --git a/src/app/modules/ModulesPage.tsx b/src/app/modules/ModulesPage.tsx index 5b4142d..176f2c5 100644 --- a/src/app/modules/ModulesPage.tsx +++ b/src/app/modules/ModulesPage.tsx @@ -1,8 +1,8 @@ "use client" import { Box, Stack } from "@mui/material" - -import { useState } from "react" +import React, { useState } from "react" +import PageWrapper from "@/components/PageWrapper" import { AllModules } from "./AllModules" import { Subheading } from "@/components/Subheading" @@ -13,11 +13,13 @@ export default function ModulesPage() { const [totalCount, setTotalCount] = useState() return ( - - - - - - + + + + + + + + ) } diff --git a/src/app/processes/ProcessesPage.tsx b/src/app/processes/ProcessesPage.tsx index 32a8d2f..c26d07b 100644 --- a/src/app/processes/ProcessesPage.tsx +++ b/src/app/processes/ProcessesPage.tsx @@ -1,8 +1,8 @@ "use client" import { Box, Stack } from "@mui/material" - -import { useState } from "react" +import React, { useState } from "react" +import PageWrapper from "@/components/PageWrapper" import { AllProcesses } from "./AllProcesses" import { Subheading } from "@/components/Subheading" @@ -13,11 +13,13 @@ export default function ProcessesPage() { const [totalCount, setTotalCount] = useState() return ( - - - - - - + + + + + + + + ) } diff --git a/src/app/swap/SwapPage.tsx b/src/app/swap/SwapPage.tsx index 32a9503..5ba05d3 100644 --- a/src/app/swap/SwapPage.tsx +++ b/src/app/swap/SwapPage.tsx @@ -1,6 +1,7 @@ +import React, { Fragment } from "react" +import PageWrapper from "@/components/PageWrapper" import { Avatar, Box, Divider, Skeleton, Stack, Typography } from "@mui/material" import { Wallet, ArrowUpRight, ArrowDownLeft } from "@phosphor-icons/react" -import { Fragment } from "react" import { useParams } from "react-router-dom" import { EntityBlock } from "@/components/EntityBlock" @@ -13,29 +14,11 @@ interface SwapTransferProps { } function SwapTransfer({ t }: SwapTransferProps) { - // const [isRepushing, setIsRepushing] = useState(false) - const amount = (Number(t.amount) / 10 ** (t.tokenInfo?.denomination ?? 1)).toLocaleString( "en-US", { maximumFractionDigits: 6 }, ) - // const repushMessage = async () => { - // if (isRepushing) return - - // setIsRepushing(true) - - // try { - // await fetch(`https://mu6.ao-testnet.xyz/push/${t.message.id}/3?process-id=${t.process}`, { - // method: "POST", - // }) - // } catch (err) { - // console.error("Failed to repush", err) - // } - - // setIsRepushing(false) - // } - return ( ({t.timestamp?.toLocaleString() ?? ""}) - {/* {t.repushable && ( - - )} */} @@ -98,7 +76,7 @@ function SwapTransfer({ t }: SwapTransferProps) { ) } -export function SwapPage() { +function SwapPageContent() { const { messageId = "" } = useParams() const { swap, isLoading } = useSwap(messageId) @@ -142,3 +120,11 @@ export function SwapPage() { ) } + +export function SwapPage() { + return ( + + + + ) +} diff --git a/src/app/token/[slug]/TokenPage.tsx b/src/app/token/[slug]/TokenPage.tsx index f98dbb4..f33ae64 100644 --- a/src/app/token/[slug]/TokenPage.tsx +++ b/src/app/token/[slug]/TokenPage.tsx @@ -14,11 +14,13 @@ import Grid2 from "@mui/material/Unstable_Grid2/Grid2" import { ArrowSquareOut } from "@phosphor-icons/react" import React, { useEffect, useMemo, useState } from "react" import { useParams, useSearchParams } from "react-router-dom" +import PageWrapper from "@/components/PageWrapper" import { TokenHolderChart } from "./TokenHolderChart" import { TokenHolderTable } from "./TokenHolderTable" import { IdBlock } from "@/components/IdBlock" -import { LoadingSkeletons } from "@/components/LoadingSkeletons" +import PageSkeleton from "@/components/PageSkeleton" +import ErrorView from "@/components/ErrorView" import { SectionInfo } from "@/components/SectionInfo" import { Subheading } from "@/components/Subheading" import { TokenAmountBlock } from "@/components/TokenAmountBlock" @@ -62,100 +64,97 @@ export default function TokenPage() { }, [tokenId, tokenInfo]) if (!tokenId || tokenInfo === null || errorMessage) { - return ( - - } /> - {errorMessage} - - ) + return } return ( - - } /> - - - {tokenInfo === undefined ? ( - - ) : ( - - - - - - {tokenInfo.name} - - - - - {tokenInfo.ticker} - - + + + } /> + + + {tokenInfo === undefined ? ( + + ) : ( + + + + + + {tokenInfo.name} + + + + + {tokenInfo.ticker} + + + - - )} - - - {tokenHolders === undefined ? ( - - ) : ( - - - acc + holder.balance, 0)} - tokenInfo={tokenInfo} - /> - } - /> - - )} + )} + + + {tokenHolders === undefined ? ( + + ) : ( + + + acc + holder.balance, 0)} + tokenInfo={tokenInfo} + /> + } + /> + + )} + - -
- - - - - - - {tokenHolders === undefined || !tokenInfo ? ( - - ) : ( - - {activeTab === "table" && ( - - )} - {activeTab === "chart" && ( - - )} - - )} - -
- +
+ + + + + + + {tokenHolders === undefined || !tokenInfo ? ( + + ) : ( + + {activeTab === "table" && ( + + )} + {activeTab === "chart" && ( + + )} + + )} + +
+ + ) } diff --git a/src/components/AsyncTable.tsx b/src/components/AsyncTable.tsx index 2ffe64f..afdec9f 100644 --- a/src/components/AsyncTable.tsx +++ b/src/components/AsyncTable.tsx @@ -14,6 +14,7 @@ import { Typography, } from "@mui/material" import React, { ReactNode, useEffect, useRef, useState } from "react" +import { FixedSizeList, ListChildComponentProps } from "react-window" import { ErrorBoundary } from "./ErrorBoundary" import { LoadingSkeletons } from "./LoadingSkeletons" @@ -41,6 +42,7 @@ export type AsyncTableProps = Omit & extraFilters?: Record, ) => Promise extraFilters?: Record + virtualize?: boolean } export function AsyncTable(props: AsyncTableProps) { @@ -53,6 +55,7 @@ export function AsyncTable(props: AsyncTableProps) { fetchFunction, component, extraFilters, + virtualize, ...rest } = props @@ -130,15 +133,28 @@ export function AsyncTable(props: AsyncTableProps) { return ( - - - + +
+ + {headerCells.map((cell, index) => ( @@ -164,31 +180,42 @@ export function AsyncTable(props: AsyncTableProps) { - - - {loading ? ( - - ) : ( - + {virtualize && data.length > pageSize * 3 ? ( + + ) : ( + <> + + + {loading ? ( + + ) : ( + + )} + + + {data.map((row, index) => ( + Something went wrong}> + {renderRow(row, index)} + + ))} + {data.length === 0 && endReached && ( + + + + No data available. + + + )} - - - {data.map((row, index) => ( - Something went wrong}> - {renderRow(row, index)} - - ))} - {data.length === 0 && endReached && ( - - - - No data available. - - - + )}
+ {/* Close the Box component that wraps the Table */} {!endReached && data.length > 0 && ( ) } + +// virtual rows component +function VirtualRows({ + data, + rowRenderer, + rowHeight, +}: { + data: T[] + rowRenderer: (row: T, idx: number) => React.ReactNode + rowHeight: number +}) { + const itemData = React.useMemo(() => ({ data, rowRenderer }), [data, rowRenderer]) + + const Row = ({ index, style }: ListChildComponentProps) => { + const { data, rowRenderer } = itemData as any + return
{rowRenderer(data[index], index)}
+ } + + const height = Math.min(400, data.length * rowHeight) + + return ( + + {Row} + + ) +} diff --git a/src/components/Charts/AreaChart.tsx b/src/components/Charts/AreaChart.tsx index 3bb8bf5..59ad8f6 100644 --- a/src/components/Charts/AreaChart.tsx +++ b/src/components/Charts/AreaChart.tsx @@ -1,7 +1,10 @@ "use client" +import { useMediaQuery } from "@mui/material" import { Highchart, HighchartOptions } from "./Highchart" import { createOptionsForStat } from "@/components/Charts/defaultOptions" +import { theme } from "../RootLayout/theme" // Import theme for breakpoints + import { HighchartAreaData } from "@/types" @@ -12,12 +15,16 @@ type AreaChartProps = { } export const AreaChart = ({ data, titleText, overrideValue }: AreaChartProps) => { + const isSmallChart = useMediaQuery(theme.breakpoints.down("sm")) // Use sm breakpoint for "small" variant + const options: HighchartOptions = createOptionsForStat( titleText, - 150, - undefined, + 150, // Chart height remains fixed for these stat charts + undefined, // Chart width is responsive by default data, overrideValue, + false, // exportServer + isSmallChart ? "small" : "normal", // Pass sizeVariant ) return diff --git a/src/components/Charts/defaultOptions.ts b/src/components/Charts/defaultOptions.ts index 762bc5e..99f58f7 100644 --- a/src/components/Charts/defaultOptions.ts +++ b/src/components/Charts/defaultOptions.ts @@ -134,15 +134,18 @@ export function createOptionsForStat( data: HighchartAreaData[], overrideValue: number | undefined, exportServer = false, + sizeVariant: "normal" | "small" = "normal", // New parameter ): HighchartOptions { const fontColor = exportServer ? "rgb(255, 255, 255)" : "var(--mui-palette-text-primary)" const backgroundColor = exportServer ? "#252424" : "transparent" const fontSizes = { - title: exportServer ? "36px" : "12px", - value: exportServer ? "96px" : "32px", + title: exportServer ? "36px" : (sizeVariant === "small" ? "11px" : "12px"), // Slightly smaller title for small + value: exportServer ? "96px" : (sizeVariant === "small" ? "24px" : "32px"), // Adjusted value font size } + const valueYPosition = exportServer ? 208 : (sizeVariant === "small" ? 98 : 104); // Adjust Y position slightly for smaller font + return { title: { align: "left", @@ -190,7 +193,7 @@ export function createOptionsForStat( { point: { x: 0, - y: exportServer ? 208 : 104, + y: valueYPosition, // Use the calculated Y position xAxis: null, yAxis: null, }, diff --git a/src/components/CopyToClipboard.tsx b/src/components/CopyToClipboard.tsx index 79b76a6..0dac67f 100644 --- a/src/components/CopyToClipboard.tsx +++ b/src/components/CopyToClipboard.tsx @@ -1,47 +1,92 @@ "use client" -import { Box, Tooltip } from "@mui/material" +import { Tooltip, IconButton } from "@mui/material" import { Check, Copy } from "@phosphor-icons/react" import React from "react" +// Add CSS for hover/touch behavior +const styles = ` +.copy-container { + position: relative; + display: inline-flex; + align-items: center; +} +.copy-btn { + opacity: 0; + transition: opacity 0.2s; + pointer-events: none; +} +.copy-container:hover .copy-btn, +.copy-container:focus-within .copy-btn, +.copy-container.show-copy .copy-btn { + opacity: 1; + pointer-events: auto; +} +`; + +// Inject the style tag once +if (typeof window !== "undefined" && !document.getElementById("copy-to-clipboard-style")) { + const style = document.createElement("style"); + style.id = "copy-to-clipboard-style"; + style.innerHTML = styles; + document.head.appendChild(style); +} + type CopyToClipboardProps = { value: string } export function CopyToClipboard(props: CopyToClipboardProps) { const { value } = props - const [copied, setCopied] = React.useState(false) + const [showCopy, setShowCopy] = React.useState(false) + const touchTimeout = React.useRef(null) if (!value) return null + // Show copy button for a short time on touch (mobile) + const handleTouchStart = (_e: React.TouchEvent) => { + setShowCopy(true) + if (touchTimeout.current) clearTimeout(touchTimeout.current) + touchTimeout.current = setTimeout(() => setShowCopy(false), 2000) + } + return ( - - { - event.stopPropagation() - navigator.clipboard.writeText(value) - - setCopied(true) - - setTimeout(() => { - setCopied(false) - }, 1000) - }} - > - {copied ? ( - - ) : ( - - )} - - + + + + { + event.stopPropagation() + navigator.clipboard.writeText(value) + setCopied(true) + setTimeout(() => { + setCopied(false) + }, 1500) + }} + sx={{ + color: "var(--mui-palette-text-primary)", + "& .MuiSvgIcon-root": { + fontSize: 18, + } + }} + aria-label="Copy to clipboard" + > + {copied ? ( + + ) : ( + + )} + + + + ) } diff --git a/src/components/ErrorView.tsx b/src/components/ErrorView.tsx new file mode 100644 index 0000000..d35fdb7 --- /dev/null +++ b/src/components/ErrorView.tsx @@ -0,0 +1,23 @@ +import { Alert, AlertTitle, Button, Stack } from "@mui/material" +import React from "react" + +interface Props { + message?: string + onRetry?: () => void +} + +export default function ErrorView({ message = "Something went wrong.", onRetry }: Props) { + return ( + + + Error + {message} + {onRetry && ( + + )} + + + ) +} \ No newline at end of file diff --git a/src/components/Footer.tsx b/src/components/Footer.tsx index 6ed45ec..5087296 100644 --- a/src/components/Footer.tsx +++ b/src/components/Footer.tsx @@ -23,8 +23,17 @@ export function Footer() { borderTopRightRadius: 8, }} > - - + + - + {/* Spacer for mobile */} + + Powered by @@ -187,4 +198,4 @@ export function Footer() { ) -} +} \ No newline at end of file diff --git a/src/components/Header.tsx b/src/components/Header.tsx index f869092..79e89e2 100644 --- a/src/components/Header.tsx +++ b/src/components/Header.tsx @@ -12,27 +12,33 @@ import { Link as MuiLink, useScrollTrigger, Box, + useMediaQuery, + Drawer, + List, + ListItem, + ListItemButton, + ListItemText, + ListItemIcon, + InputAdornment, + TextField, } from "@mui/material" -import { Moon, Sun } from "@phosphor-icons/react" - -import { Link } from "react-router-dom" +import { Moon, Sun, List as MenuIcon, XCircle, MagnifyingGlass, ArrowLeft } from "@phosphor-icons/react" +import { Link, useNavigate } from "react-router-dom" +import { useState, useCallback } from "react" // Imported useCallback import { Logo } from "./Logo" import { MainFontFF } from "./RootLayout/fonts" import SearchBar from "@/app/SearchBar" import { usePrimaryArnsName } from "@/hooks/usePrimaryArnsName" import { useArnsLogo } from "@/hooks/useArnsLogo" +import { theme } from "./RootLayout/theme" // Import theme for breakpoints const ProfileButton = () => { const activeAddress = useActiveAddress() const { data: arnsName, isLoading: isLoadingName } = usePrimaryArnsName(activeAddress || "") const { data: logoTxId, isLoading: isLoadingLogo } = useArnsLogo(arnsName || "") - // Debug logging - console.log("Profile Debug:", { activeAddress, arnsName, logoTxId, isLoadingName, isLoadingLogo }) - const handleProfileClick = () => { - // Find and click the hidden ConnectButton to trigger its modal const connectButton = document.getElementById('hidden-connect-button') if (connectButton) { connectButton.click() @@ -134,8 +140,20 @@ const ProfileButton = () => { ) } +const navItems = [ + { label: "PROCESSES", path: "/processes" }, + { label: "MODULES", path: "/modules" }, + { label: "BLOCKS", path: "/blocks" }, + { label: "ARNS", path: "/arns" }, +] + const Header = () => { const { mode = "dark", setMode } = useColorScheme() + const navigate = useNavigate() + const [drawerOpen, setDrawerOpen] = useState(false) + const [mobileSearchActive, setMobileSearchActive] = useState(false) // State for mobile search visibility + const isMobile = useMediaQuery(theme.breakpoints.down("md")) + const isLargeScreen = useMediaQuery(theme.breakpoints.up("lg")) const elevated = useScrollTrigger({ disableHysteresis: true, @@ -143,153 +161,189 @@ const Header = () => { target: typeof window !== "undefined" ? window : undefined, }) - return ( - (event: React.KeyboardEvent | React.MouseEvent) => { + if ( + event.type === "keydown" && + ((event as React.KeyboardEvent).key === "Tab" || (event as React.KeyboardEvent).key === "Shift") + ) { + return + } + setDrawerOpen(open) + }, [setDrawerOpen]) // Added setDrawerOpen to dependency array, though empty [] might also work if setDrawerOpen is guaranteed stable + + const drawerContent = ( + - - - - - - - PROCESSES - - - MODULES - - - BLOCKS - - - ARNS - - - - - button > div": { - height: "fit-content", - padding: 0, - }, - "&.MuiBox-root button": { - height: "100%", - borderRadius: 1, - border: "1px solid var(--mui-palette-divider)", - paddingX: 2.5, - paddingY: 1, - color: "var(--mui-palette-primary-main)", - background: "none", - }, - "&.MuiBox-root button:active": { - transform: "scale(0.98) !important", - }, - "& button:hover": { - transform: "none !important", - boxShadow: "none !important", - }, - "& button > *": { - fontWeight: 500, - fontFamily: MainFontFF, - textTransform: "none", - lineHeight: 1, - fontSize: "0.8125rem", - padding: 0, - }, - "& button svg": { - marginY: -1, - }, - }} - > - - - { - const nextMode = mode === "dark" ? "light" : "dark" - setMode(nextMode) - }} + + + + + + + {navItems.map((item) => ( + + navigate(item.path)}> + + + + ))} + + + ) + + return ( + <> + + + + {isMobile && mobileSearchActive ? ( + + setMobileSearchActive(false)} color="inherit" sx={{ mr: 1, color: 'var(--mui-palette-text-primary)' }}> + + + + + + + ) : ( + - {mode === "dark" ? : } - - - - - - + + + {!isMobile && ( + + {navItems.map((item) => ( + + {item.label} + + ))} + + )} + + {/* Reduced gap for mobile icons */} + {isLargeScreen && } + {!isLargeScreen && ( + <> + setMobileSearchActive(true)} + sx={{ color: 'var(--mui-palette-text-primary)' }} + > + + + + + + + )} + button > div": { + height: "fit-content", + padding: 0, + }, + "&.MuiBox-root button": { + height: "100%", + borderRadius: 1, + border: "1px solid var(--mui-palette-divider)", + paddingX: { xs: 1.5, sm: 2.5 }, + paddingY: 1, + color: "var(--mui-palette-primary-main)", + background: "none", + }, + "&.MuiBox-root button:active": { + transform: "scale(0.98) !important", + }, + "& button:hover": { + transform: "none !important", + boxShadow: "none !important", + }, + "& button > *": { + fontWeight: 500, + fontFamily: MainFontFF, + textTransform: "none", + lineHeight: 1, + fontSize: "0.8125rem", + padding: 0, + }, + "& button svg": { + marginY: -1, + }, + }} + > + + + {/* Minimal IconButton for testing TS1005 error */} + { + const nextMode = mode === "dark" ? "light" : "dark"; + setMode(nextMode); + }} // Added back original onClick logic + size="large" + sx={{ fontSize: "1.125rem" }} + > + {mode === "dark" ? : } + + + + )} + + + + + {drawerContent} + + ) } diff --git a/src/components/IdBlock.tsx b/src/components/IdBlock.tsx index 6c60351..47868a1 100644 --- a/src/components/IdBlock.tsx +++ b/src/components/IdBlock.tsx @@ -25,7 +25,9 @@ export function IdBlock(props: IdBlockProps) { display="flex" alignItems="center" sx={{ - fill: "none", + whiteSpace: "nowrap", + overflow: "hidden", + textOverflow: "ellipsis", "&:hover": { fill: "var(--mui-palette-text-secondary)" }, }} > @@ -55,7 +57,9 @@ export function IdBlock(props: IdBlockProps) { return ( diff --git a/src/components/InMemoryTable.tsx b/src/components/InMemoryTable.tsx index dab766a..a86e24a 100644 --- a/src/components/InMemoryTable.tsx +++ b/src/components/InMemoryTable.tsx @@ -106,64 +106,66 @@ export function InMemoryTable(props: InMemoryTableProps) { return ( - - - - {headerCells.map((cell, index) => ( - - {cell.sortable ? ( - { - if (sortField !== cell.field) { - setSortField(cell.field as string) - } else { - setSortAscending(!sortAscending) - } - }} - > - {cell.label} - + +
+ + + {headerCells.map((cell, index) => ( + + {cell.sortable ? ( + { + if (sortField !== cell.field) { + setSortField(cell.field as string) + } else { + setSortAscending(!sortAscending) + } + }} + > + {cell.label} + + ) : ( + cell.label + )} + + ))} + + + + + + {loading ? ( + ) : ( - cell.label + )} - ))} - - - - - - {loading ? ( - - ) : ( - - )} - - - {visibleRows.map(renderRow)} - {data.length === 0 && !loading && ( - - - - No data available. - - - )} - -
+ {visibleRows.map(renderRow)} + {data.length === 0 && !loading && ( + + + + No data available. + + + + )} + + +
{!endReached && data.length > 0 && ( + + + + + ) +} \ No newline at end of file diff --git a/src/components/PageWrapper.tsx b/src/components/PageWrapper.tsx new file mode 100644 index 0000000..26e9292 --- /dev/null +++ b/src/components/PageWrapper.tsx @@ -0,0 +1,16 @@ +import React, { Suspense } from "react" +import { ErrorBoundary } from "react-error-boundary" +import PageSkeleton from "./PageSkeleton" +import ErrorView from "./ErrorView" + +interface PageWrapperProps { + children: React.ReactNode +} + +export default function PageWrapper({ children }: PageWrapperProps) { + return ( + }> + }>{children} + + ) +} \ No newline at end of file diff --git a/src/components/RequestHistoryPanel.tsx b/src/components/RequestHistoryPanel.tsx index 2880f03..bd34543 100644 --- a/src/components/RequestHistoryPanel.tsx +++ b/src/components/RequestHistoryPanel.tsx @@ -1,4 +1,4 @@ -import React, { useState } from "react" +import React, { useState, lazy, Suspense } from "react" import { Accordion, AccordionSummary, @@ -10,7 +10,6 @@ import { Typography, } from "@mui/material" import Grid2 from "@mui/material/Unstable_Grid2/Grid2" -import { CodeEditor } from "@/components/CodeEditor" import { useActiveAddress } from "@arweave-wallet-kit/react" import { persistentAtom } from "@nanostores/persistent" import { useStore } from "@nanostores/react" @@ -42,6 +41,8 @@ interface RequestHistoryPanelProps { onSelect: (payload: string) => void } +const CodeEditor = lazy(() => import("./CodeEditor").then(m=>({default:m.CodeEditor}))) + export function RequestHistoryPanel({ onSelect }: RequestHistoryPanelProps) { const address = useActiveAddress() const history = useStore(dryRunHistoryStore) @@ -204,12 +205,14 @@ export function RequestHistoryPanel({ onSelect }: RequestHistoryPanelProps) { Query - + Loading editor...
}> + + @@ -217,12 +220,14 @@ export function RequestHistoryPanel({ onSelect }: RequestHistoryPanelProps) { Result - + Loading editor...}> + + diff --git a/src/components/RootLayout/RootLayoutUI.tsx b/src/components/RootLayout/RootLayoutUI.tsx index 5d041ae..40b7714 100644 --- a/src/components/RootLayout/RootLayoutUI.tsx +++ b/src/components/RootLayout/RootLayoutUI.tsx @@ -13,7 +13,14 @@ import { Footer } from "../Footer" import Header from "../Header" import { NavigationEvents } from "../NavigationEvents" -const queryClient = new QueryClient() +const queryClient = new QueryClient({ + defaultOptions: { + queries: { + staleTime: 5 * 60 * 1000, // 5 minutes + gcTime: 10 * 60 * 1000, + }, + }, +}) export default function RootLayoutUI({ children }: { children: React.ReactNode }) { return ( @@ -24,7 +31,13 @@ export default function RootLayoutUI({ children }: { children: React.ReactNode }
- + {children}