diff --git a/README.md b/README.md index ad9456b..2d0db25 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ -# Welcom to Sui Simulator Extension +# Welcome to Sui Simulator Extension ## Introduction In the spirit to develop a strong developer community, Weminal lab build an open-source IDE to simplify the development of SUI smart contracts. @@ -23,4 +23,4 @@ Sui Simulator requires the following: Ensure that you've read through the extensions guidelines and follow the best practices for creating your extension. -* [Extension Guidelines](https://code.visualstudio.com/api/references/extension-guidelines) \ No newline at end of file +* [Extension Guidelines](https://code.visualstudio.com/api/references/extension-guidelines) diff --git a/package-lock.json b/package-lock.json index 027bca1..3f7b8eb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,21 +1,24 @@ { "name": "sui-simulator-vscode", - "version": "0.0.1", + "version": "0.2.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "sui-simulator-vscode", - "version": "0.0.1", + "version": "0.2.0", "devDependencies": { "@estruyf/vscode": "^1.1.0", "@mysten/dapp-kit": "^0.12.5", "@mysten/sui.js": "^0.51.0", "@tanstack/react-query": "^5.28.6", + "@types/css-modules": "^1.0.5", "@types/mocha": "^10.0.6", "@types/node": "18.x", "@types/react": "^18.2.67", "@types/react-dom": "^18.2.22", + "@types/react-modal": "^3.16.3", + "@types/react-toggle": "^4.0.5", "@types/vscode": "^1.87.0", "@types/webpack": "^5.28.5", "@types/webpack-dev-server": "^4.7.2", @@ -23,14 +26,20 @@ "@typescript-eslint/parser": "^7.0.2", "@vscode/test-cli": "^0.0.6", "@vscode/test-electron": "^2.3.9", + "autoprefixer": "^10.4.19", "css-loader": "^6.10.0", "eslint": "^8.56.0", "npm-run-all": "^4.1.5", + "postcss": "^8.4.38", "postcss-loader": "^8.1.1", "react": "^18.2.0", + "react-collapsible": "^2.10.0", "react-dom": "^18.2.0", + "react-modal": "^3.16.1", + "react-toggle": "^4.1.3", "rimraf": "^5.0.5", "style-loader": "^3.3.4", + "tailwindcss": "^3.4.3", "ts-loader": "^9.5.1", "typescript": "^5.3.3", "webpack": "^5.90.3", @@ -64,6 +73,18 @@ "node": ">=0.10.0" } }, + "node_modules/@alloc/quick-lru": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", + "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/@babel/code-frame": { "version": "7.24.2", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.2.tgz", @@ -1404,6 +1425,12 @@ "@types/node": "*" } }, + "node_modules/@types/css-modules": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/css-modules/-/css-modules-1.0.5.tgz", + "integrity": "sha512-oeKafs/df9lwOvtfiXVliZsocFVOexK9PZtLQWuPeuVCFR7jwiqlg60lu80JTe5NFNtH3tnV6Fs/ySR8BUPHAw==", + "dev": true + }, "node_modules/@types/eslint": { "version": "8.56.6", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.6.tgz", @@ -1549,6 +1576,24 @@ "@types/react": "*" } }, + "node_modules/@types/react-modal": { + "version": "3.16.3", + "resolved": "https://registry.npmjs.org/@types/react-modal/-/react-modal-3.16.3.tgz", + "integrity": "sha512-xXuGavyEGaFQDgBv4UVm8/ZsG+qxeQ7f77yNrW3n+1J6XAstUy5rYHeIHPh1KzsGc6IkCIdu6lQ2xWzu1jBTLg==", + "dev": true, + "dependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/react-toggle": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/@types/react-toggle/-/react-toggle-4.0.5.tgz", + "integrity": "sha512-MHHEDe7GnF/EhLtI5sT70Dqab8rwlgjRZtu/u6gmfbYd+HeYxWiUSRog16+1BCfkz7Wy2VU6+TPU2oCsDtqDzA==", + "dev": true, + "dependencies": { + "@types/react": "*" + } + }, "node_modules/@types/retry": { "version": "0.12.2", "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.2.tgz", @@ -2357,6 +2402,12 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", + "dev": true + }, "node_modules/anymatch": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", @@ -2370,6 +2421,12 @@ "node": ">= 8" } }, + "node_modules/arg": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", + "dev": true + }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -2441,6 +2498,43 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/autoprefixer": { + "version": "10.4.19", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.19.tgz", + "integrity": "sha512-BaENR2+zBZ8xXhM4pUaKUxlVdxZ0EZhjvbopwnXmxRUfqDmwSpC2lAi/QXvx7NRdPCo1WKEcEF6mV64si1z4Ew==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "browserslist": "^4.23.0", + "caniuse-lite": "^1.0.30001599", + "fraction.js": "^4.3.7", + "normalize-range": "^0.1.2", + "picocolors": "^1.0.0", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, "node_modules/available-typed-arrays": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", @@ -2713,6 +2807,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/camelcase-css": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", + "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, "node_modules/caniuse-lite": { "version": "1.0.30001599", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001599.tgz", @@ -2794,6 +2897,12 @@ "node": ">=6.0" } }, + "node_modules/classnames": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz", + "integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==", + "dev": true + }, "node_modules/cliui": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", @@ -3349,6 +3458,12 @@ "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==", "dev": true }, + "node_modules/didyoumean": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", + "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", + "dev": true + }, "node_modules/diff": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", @@ -3370,6 +3485,12 @@ "node": ">=8" } }, + "node_modules/dlv": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", + "dev": true + }, "node_modules/dns-packet": { "version": "5.6.1", "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.1.tgz", @@ -3856,6 +3977,12 @@ "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", "dev": true }, + "node_modules/exenv": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/exenv/-/exenv-1.2.2.tgz", + "integrity": "sha512-Z+ktTxTwv9ILfgKCk32OX3n/doe+OcLTRtqK9pcL+JsP3J1/VW8Uvl4ZjLlKqeW4rzK4oesDOGMEMRIZqtP4Iw==", + "dev": true + }, "node_modules/express": { "version": "4.19.1", "resolved": "https://registry.npmjs.org/express/-/express-4.19.1.tgz", @@ -4210,6 +4337,19 @@ "node": ">= 0.6" } }, + "node_modules/fraction.js": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", + "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", + "dev": true, + "engines": { + "node": "*" + }, + "funding": { + "type": "patreon", + "url": "https://github.com/sponsors/rawify" + } + }, "node_modules/fresh": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", @@ -5487,6 +5627,15 @@ "immediate": "~3.0.5" } }, + "node_modules/lilconfig": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", + "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", + "dev": true, + "engines": { + "node": ">=10" + } + }, "node_modules/lines-and-columns": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", @@ -5981,6 +6130,17 @@ "multicast-dns": "cli.js" } }, + "node_modules/mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "dev": true, + "dependencies": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, "node_modules/nanoid": { "version": "3.3.7", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", @@ -6086,6 +6246,15 @@ "node": ">=0.10.0" } }, + "node_modules/normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/npm-run-all": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/npm-run-all/-/npm-run-all-4.1.5.tgz", @@ -6283,6 +6452,24 @@ "node": ">=8" } }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-hash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", + "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, "node_modules/object-inspect": { "version": "1.13.1", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", @@ -6615,6 +6802,15 @@ "node": ">=4" } }, + "node_modules/pirates": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", + "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, "node_modules/pkg-dir": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", @@ -6716,6 +6912,89 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/postcss-import": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", + "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.0.0", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "node_modules/postcss-js": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz", + "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==", + "dev": true, + "dependencies": { + "camelcase-css": "^2.0.1" + }, + "engines": { + "node": "^12 || ^14 || >= 16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": "^8.4.21" + } + }, + "node_modules/postcss-load-config": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.2.tgz", + "integrity": "sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "lilconfig": "^3.0.0", + "yaml": "^2.3.4" + }, + "engines": { + "node": ">= 14" + }, + "peerDependencies": { + "postcss": ">=8.0.9", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "postcss": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/postcss-load-config/node_modules/lilconfig": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.1.tgz", + "integrity": "sha512-O18pf7nyvHTckunPWCV1XUNXU1piu01y2b7ATJ0ppkUkk8ocqVWBrYjJBCwHDjD/ZWcfyrA0P4gKhzWGi5EINQ==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, "node_modules/postcss-loader": { "version": "8.1.1", "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-8.1.1.tgz", @@ -6806,6 +7085,25 @@ "postcss": "^8.1.0" } }, + "node_modules/postcss-nested": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.0.1.tgz", + "integrity": "sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.11" + }, + "engines": { + "node": ">=12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": "^8.2.14" + } + }, "node_modules/postcss-selector-parser": { "version": "6.0.16", "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.16.tgz", @@ -6840,6 +7138,17 @@ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", "dev": true }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "dev": true, + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, "node_modules/proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -6960,6 +7269,16 @@ "node": ">=0.10.0" } }, + "node_modules/react-collapsible": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/react-collapsible/-/react-collapsible-2.10.0.tgz", + "integrity": "sha512-kEVsmlFfXBMTCnU5gwIv19MdmPAhbIPzz5Er37TiJSzRKS0IHrqAKQyQeHEmtoGIQMTcVI46FzE4z3NlVTx77A==", + "dev": true, + "peerDependencies": { + "react": "~15 || ~16 || ~17 || ~18", + "react-dom": "~15 || ~16 || ~17 || ~18" + } + }, "node_modules/react-dom": { "version": "18.2.0", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", @@ -6973,6 +7292,37 @@ "react": "^18.2.0" } }, + "node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "dev": true + }, + "node_modules/react-lifecycles-compat": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", + "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==", + "dev": true + }, + "node_modules/react-modal": { + "version": "3.16.1", + "resolved": "https://registry.npmjs.org/react-modal/-/react-modal-3.16.1.tgz", + "integrity": "sha512-VStHgI3BVcGo7OXczvnJN7yT2TWHJPDXZWyI/a0ssFNhGZWsPmB8cF0z33ewDXq4VfYMO1vXgiv/g8Nj9NDyWg==", + "dev": true, + "dependencies": { + "exenv": "^1.2.0", + "prop-types": "^15.7.2", + "react-lifecycles-compat": "^3.0.0", + "warning": "^4.0.3" + }, + "engines": { + "node": ">=8" + }, + "peerDependencies": { + "react": "^0.14.0 || ^15.0.0 || ^16 || ^17 || ^18", + "react-dom": "^0.14.0 || ^15.0.0 || ^16 || ^17 || ^18" + } + }, "node_modules/react-remove-scroll": { "version": "2.5.5", "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.5.5.tgz", @@ -7043,6 +7393,38 @@ } } }, + "node_modules/react-toggle": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/react-toggle/-/react-toggle-4.1.3.tgz", + "integrity": "sha512-WoPrvbwfQSvoagbrDnXPrlsxwzuhQIrs+V0I162j/s+4XPgY/YDAUmHSeWiroznfI73wj+MBydvW95zX8ABbSg==", + "dev": true, + "dependencies": { + "classnames": "^2.2.5" + }, + "peerDependencies": { + "prop-types": ">= 15.3.0 < 19", + "react": ">= 15.3.0 < 19", + "react-dom": ">= 15.3.0 < 19" + } + }, + "node_modules/read-cache": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", + "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", + "dev": true, + "dependencies": { + "pify": "^2.3.0" + } + }, + "node_modules/read-cache/node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/read-pkg": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", @@ -8014,6 +8396,37 @@ "webpack": "^5.0.0" } }, + "node_modules/sucrase": { + "version": "3.35.0", + "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz", + "integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.2", + "commander": "^4.0.0", + "glob": "^10.3.10", + "lines-and-columns": "^1.1.6", + "mz": "^2.7.0", + "pirates": "^4.0.1", + "ts-interface-checker": "^0.1.9" + }, + "bin": { + "sucrase": "bin/sucrase", + "sucrase-node": "bin/sucrase-node" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/sucrase/node_modules/commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, "node_modules/superstruct": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/superstruct/-/superstruct-1.0.4.tgz", @@ -8047,6 +8460,55 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/tailwindcss": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.3.tgz", + "integrity": "sha512-U7sxQk/n397Bmx4JHbJx/iSOOv5G+II3f1kpLpY2QeUv5DcPdcTsYLlusZfq1NthHS1c1cZoyFmmkex1rzke0A==", + "dev": true, + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "arg": "^5.0.2", + "chokidar": "^3.5.3", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.3.0", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "jiti": "^1.21.0", + "lilconfig": "^2.1.0", + "micromatch": "^4.0.5", + "normalize-path": "^3.0.0", + "object-hash": "^3.0.0", + "picocolors": "^1.0.0", + "postcss": "^8.4.23", + "postcss-import": "^15.1.0", + "postcss-js": "^4.0.1", + "postcss-load-config": "^4.0.1", + "postcss-nested": "^6.0.1", + "postcss-selector-parser": "^6.0.11", + "resolve": "^1.22.2", + "sucrase": "^3.32.0" + }, + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tailwindcss/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, "node_modules/tapable": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", @@ -8179,6 +8641,27 @@ "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", "dev": true }, + "node_modules/thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "dev": true, + "dependencies": { + "any-promise": "^1.0.0" + } + }, + "node_modules/thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "dev": true, + "dependencies": { + "thenify": ">= 3.1.0 < 4" + }, + "engines": { + "node": ">=0.8" + } + }, "node_modules/thunky": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", @@ -8218,6 +8701,12 @@ "typescript": ">=4.2.0" } }, + "node_modules/ts-interface-checker": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", + "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", + "dev": true + }, "node_modules/ts-loader": { "version": "9.5.1", "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.5.1.tgz", @@ -8557,6 +9046,15 @@ "node": ">= 0.8" } }, + "node_modules/warning": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz", + "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==", + "dev": true, + "dependencies": { + "loose-envify": "^1.0.0" + } + }, "node_modules/watchpack": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.1.tgz", @@ -9140,6 +9638,18 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true }, + "node_modules/yaml": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.1.tgz", + "integrity": "sha512-pIXzoImaqmfOrL7teGUBt/T7ZDnyeGBWyXQBvOVhLkWLN37GXv8NMLK406UY6dS51JfcQHsmcW5cJ441bHg6Lg==", + "dev": true, + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/yargs": { "version": "17.7.2", "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", diff --git a/package.json b/package.json index 6a3b122..ffb6444 100644 --- a/package.json +++ b/package.json @@ -71,10 +71,13 @@ "@mysten/dapp-kit": "^0.12.5", "@mysten/sui.js": "^0.51.0", "@tanstack/react-query": "^5.28.6", + "@types/css-modules": "^1.0.5", "@types/mocha": "^10.0.6", "@types/node": "18.x", "@types/react": "^18.2.67", "@types/react-dom": "^18.2.22", + "@types/react-modal": "^3.16.3", + "@types/react-toggle": "^4.0.5", "@types/vscode": "^1.87.0", "@types/webpack": "^5.28.5", "@types/webpack-dev-server": "^4.7.2", @@ -82,18 +85,24 @@ "@typescript-eslint/parser": "^7.0.2", "@vscode/test-cli": "^0.0.6", "@vscode/test-electron": "^2.3.9", + "autoprefixer": "^10.4.19", "css-loader": "^6.10.0", "eslint": "^8.56.0", "npm-run-all": "^4.1.5", + "postcss": "^8.4.38", "postcss-loader": "^8.1.1", "react": "^18.2.0", + "react-collapsible": "^2.10.0", "react-dom": "^18.2.0", + "react-modal": "^3.16.1", + "react-toggle": "^4.1.3", "rimraf": "^5.0.5", "style-loader": "^3.3.4", + "tailwindcss": "^3.4.3", "ts-loader": "^9.5.1", "typescript": "^5.3.3", "webpack": "^5.90.3", "webpack-cli": "^5.1.4", "webpack-dev-server": "^5.0.4" } -} \ No newline at end of file +} diff --git a/src/enums/index.ts b/src/enums/index.ts index 99fb10b..60e1da9 100644 --- a/src/enums/index.ts +++ b/src/enums/index.ts @@ -17,4 +17,13 @@ export enum MoveCallActionType { ADD_ARG = "ADD_ARG", SET_VALUE_TO_ARG = "SET_VALUE_TO_ARG", SET_RESPONSE = "SET_RESPONSE", -}; \ No newline at end of file +}; + +export enum SuiCommand { + GET_ADDRESSES = "GET_ADDRESSES", + GET_GAS_OBJECTS = "GET_GAS_OBJECTS", + SWITCH_ADDRESS = "SWITCH_ADDRESS", + SWITCH_NETWORK = "SWITCH_NETWORK", + GET_NETWORKS = "GET_NETWORKS", + PUBLISH_PACKAGE = "PUBLISH_PACKAGE", +} \ No newline at end of file diff --git a/src/extension.ts b/src/extension.ts index b70fa69..8e24267 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -5,11 +5,17 @@ import { join } from 'path'; import { MessageHandlerData } from '@estruyf/vscode'; import { build, publish, executeCommand } from './suiCommand'; import { SidebarProvider } from './SidebarProvider'; +import { exec } from "child_process"; +import { promisify } from "util"; +import { MyCustomTerminalResponse } from './types'; +import { SuiCommand } from './enums'; // This method is called when your extension is activated // Your extension is activated the very first time the command is executed export function activate(context: vscode.ExtensionContext) { + const execNew = promisify(exec); + // Use the console to output diagnostic information (console.log) and errors (console.error) // This line of code will only be executed once when your extension is activated console.log('Congratulations, your extension "sui-simulator-vscode" is now active!'); @@ -44,19 +50,121 @@ export function activate(context: vscode.ExtensionContext) { } ); - panel.webview.onDidReceiveMessage(message => { + panel.webview.onDidReceiveMessage(async message => { const { command, requestId, payload } = message; - switch (command) { - case "GET_DATA": + case "SUI_TERMINAL": + let resp = { + stderr: "", + stdout: "" + }; + + let finalResp = { + stderr: { + message: "", + isError: false, + }, + stdout: "" + }; + // console.log(payload); + switch (payload.cmd) { + case SuiCommand.GET_ADDRESSES: + + resp = await execNew("sui client addresses --json"); + + finalResp = { + stderr: { + message: resp.stderr, + isError: false + }, + stdout: resp.stdout + }; + break; + case SuiCommand.GET_GAS_OBJECTS: + try { + resp = await execNew("sui client gas --json"); + + finalResp = { + stderr: { + message: resp.stderr, + isError: false + }, + stdout: resp.stdout + }; + } catch(err: any) { + console.log(err.message); + } + + break; + case SuiCommand.SWITCH_ADDRESS: + resp = await execNew(`sui client switch --address ${payload.address}`); + + finalResp = { + stderr: { + message: resp.stderr, + isError: false + }, + stdout: resp.stdout + }; + break; + case SuiCommand.GET_NETWORKS: + resp = await execNew("sui client envs --json"); + + finalResp = { + stderr: { + message: resp.stderr, + isError: false + }, + stdout: resp.stdout + }; + break; + case SuiCommand.SWITCH_NETWORK: + resp = await execNew(`sui client switch --env ${payload.network}`); + + finalResp = { + stderr: { + message: resp.stderr, + isError: false + }, + stdout: resp.stdout + }; + break; + case SuiCommand.PUBLISH_PACKAGE: + try { + resp = await execNew(`sui client publish --gas ${payload.gasObjectId} --gas-budget ${payload.gasBudget} ${vscode.workspace.workspaceFolders?.[0].uri.path} --json`); + + finalResp = { + stderr: { + message: resp.stderr, + isError: false + }, + stdout: resp.stdout + }; + + console.log(finalResp); + } catch (err: any) { + console.log(err.message); + finalResp = { + stderr: { + message: err.message, + isError: true + }, + stdout: "" + }; + + } + + break; + } + // Do something with the payload // Send a response back to the webview panel.webview.postMessage({ command, requestId, // The requestId is used to identify the response - payload: `Hello from the extension!` - } as MessageHandlerData); + payload: finalResp + } as MessageHandlerData); break; case "GET_DATA_ERROR": @@ -72,9 +180,9 @@ export function activate(context: vscode.ExtensionContext) { test(payload.data); break; - case "SUI_TERMINAL": - executeCommand(payload.command, payload.suiPath); - break; + // case "SUI_TERMINAL": + // executeCommand(payload.command, payload.suiPath); + // break; case "BUILD": build(payload.packagePath, payload.suiPath); @@ -106,6 +214,14 @@ export function activate(context: vscode.ExtensionContext) { const terminal = vscode.window.createTerminal("Sui Simulator"); terminal.sendText("sui client objects"); terminal.show(); + + // get active editor + // console.log(vscode.window.activeTextEditor?.document.uri); + + // get folders path in workspace + // vscode.workspace.workspaceFolders[0].uri.path + // vscode.workspace.workspaceFolders[0].uri.fsPath + })); } @@ -131,6 +247,8 @@ const getWebviewContent = (context: vscode.ExtensionContext, webview: vscode.Web + + ${isProduction ? `` : ''} diff --git a/src/types/index.ts b/src/types/index.ts index 42d384d..07a66fd 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -2,22 +2,34 @@ import { SuiMoveNormalizedFunction } from "@mysten/sui.js/client"; import { MoveCallStatus } from "../enums"; export interface ActionType { - type: string, - payload: any -}; + type: string; + payload: any; +} export interface MoveCallState { - mnemonics: string, - status: MoveCallStatus, - packageId: string, - modules: string[], - currentModule: string, - functions: { - [key: string]: SuiMoveNormalizedFunction; - }, - currentFunction: string; - args: string[], - argsUserInput: string[], - error: string, - response: string, -} \ No newline at end of file + mnemonics: string; + status: MoveCallStatus; + packageId: string; + modules: string[]; + currentModule: string; + functions: { + [key: string]: SuiMoveNormalizedFunction; + }; + currentFunction: string; + args: string[]; + argsUserInput: string[]; + error: string; + response: string; +} + +export interface FileWithPath extends File { + path: string; +} + +export interface MyCustomTerminalResponse { + stdout: string; + stderr: { + message: string; + isError: boolean; + }; +} diff --git a/src/webview/App.tsx b/src/webview/App.tsx index cfd3e0d..c74f6d6 100644 --- a/src/webview/App.tsx +++ b/src/webview/App.tsx @@ -4,10 +4,15 @@ import { useSuiClient, useSuiClientContext } from "@mysten/dapp-kit"; import { Input } from "./components/Input"; import { Button } from "./components/Button"; import { Aliases } from './components/Aliases'; -import { sendMessage } from "./utils/wv_communicate_ext"; import { ActionType, MoveCallState } from "../types"; import { MoveCallActionType, MoveCallStatus } from "../enums"; import { MoveCall } from "./features/moveCall/v2"; +import { SuiConfig } from "./features/suiConfig/v2"; +import { messageHandler } from "@estruyf/vscode/dist/client"; +import { SuiConfigProvider } from "./context/SuiConfigProvider"; +import { GasAddress } from "./features/gasAddress"; +import { BuildTestPublish } from "./features/buildTestPublish"; +import { MySuiAccountProvider } from "./context/MySuiAccountProvider"; const initialState: MoveCallState = { mnemonics: "mouse hood crucial soup report axis awful point stairs guess scrap winter", @@ -105,6 +110,10 @@ const reducer = (state: MoveCallState, action: ActionType): MoveCallState => { } }; +const sendMessage = (action: string, payload: any) => { + messageHandler.send(action, payload); // action, payload like redux + }; + export interface IAppProps { } export const App: React.FunctionComponent = ({ }: React.PropsWithChildren) => { @@ -123,34 +132,33 @@ export const App: React.FunctionComponent = ({ }: React.PropsWithChil return ( <> -

Sui Simulator

-
-

- Setup Sui -

- setSuiPath(e.target.value)} /> -

Network

- -
-

Build

- setBuildPath(e.target.value)} /> - -

Publish

- setPublishPath(e.target.value)} /> - -
- - - -
- + + +

Sui Simulator

+
+ +
+ +
+ + {/*

Build

+ setBuildPath(e.target.value)} /> + +

Publish

+ setPublishPath(e.target.value)} /> + */} +
+ + + +
+ +
+
); }; \ No newline at end of file diff --git a/src/webview/configs/networkConfig.ts b/src/webview/configs/networkConfig.ts index 25ac63b..b9cdaa6 100644 --- a/src/webview/configs/networkConfig.ts +++ b/src/webview/configs/networkConfig.ts @@ -3,6 +3,9 @@ import { createNetworkConfig } from "@mysten/dapp-kit"; const { networkConfig, useNetworkVariable, useNetworkVariables } = createNetworkConfig({ + localnet: { + url: getFullnodeUrl("localnet") + }, devnet: { url: getFullnodeUrl("devnet") }, diff --git a/src/webview/context/MySuiAccountProvider.tsx b/src/webview/context/MySuiAccountProvider.tsx new file mode 100644 index 0000000..ce7ad21 --- /dev/null +++ b/src/webview/context/MySuiAccountProvider.tsx @@ -0,0 +1,51 @@ +import React, { useState } from "react"; +import { createContext, useContext } from "react"; + +export type MySuiAccountContextType = { + addresses: string[]; + setAddresses: (addresses: string[]) => void; + currentAddress: string; + setCurrentAddress: (address: string) => void; + gasObjects: any[]; + setGasObjects: (gasObjects: any[]) => void; + currentGasObject: any; + setCurrentGasObject: (gasObject: any) => void; +}; + +const MySuiAccountContext = createContext(null); + +export const MySuiAccountProvider: React.FC<{ children: React.ReactNode }> = ({ + children, +}) => { + const [addresses, setAddresses] = useState([]); + const [currentAddress, setCurrentAddress] = useState(""); + const [gasObjects, setGasObjects] = useState([]); + const [currentGasObject, setCurrentGasObject] = useState(null); + + return ( + + {children} + + ); +}; + +export const useMySuiAccount = () => { + const context = useContext(MySuiAccountContext); + if (context === undefined) { + throw new Error( + "useMySuiAccount must be used within a MySuiAccountProvider" + ); + } + return context as MySuiAccountContextType; +}; diff --git a/src/webview/context/SuiConfigProvider.tsx b/src/webview/context/SuiConfigProvider.tsx new file mode 100644 index 0000000..236506b --- /dev/null +++ b/src/webview/context/SuiConfigProvider.tsx @@ -0,0 +1,34 @@ +import React, { useState } from "react"; +import { createContext, useContext } from "react"; + +export type SuiConfigContextType = { + isSuiCargo: boolean; + setIsSuiCargo: React.Dispatch>; + suiPath: string; + setSuiPath: React.Dispatch>; +}; + +const SuiConfigContext = createContext(null); + +export const SuiConfigProvider: React.FC<{ children: React.ReactNode }> = ({ + children, +}) => { + const [isSuiCargo, setIsSuiCargo] = useState(false); + const [suiPath, setSuiPath] = useState(""); + + return ( + + {children} + + ); +}; + +export const useSuiConfig = () => { + const context = useContext(SuiConfigContext); + if (context === undefined) { + throw new Error('useSuiConfig must be used within a SuiConfigProvider'); + } + return context as SuiConfigContextType;; +}; diff --git a/src/webview/features/buildTestPublish/index.tsx b/src/webview/features/buildTestPublish/index.tsx new file mode 100644 index 0000000..db501dd --- /dev/null +++ b/src/webview/features/buildTestPublish/index.tsx @@ -0,0 +1,211 @@ +import React, { useState } from "react"; +import Collapsible from "react-collapsible"; +import { useMySuiAccount } from "../../context/MySuiAccountProvider"; +import { requestDataFromTerminal } from "../../utils/wv_communicate_ext"; +import { SuiCommand } from "../../../enums"; +import Modal from "react-modal"; + +export const BuildTestPublish = () => { + const { currentAddress, currentGasObject } = useMySuiAccount(); + const [gasBudget, setGasBudget] = useState(100000000); + const [isLoading, setIsLoading] = useState(false); + const [currentDigest, setCurrentDigest] = useState(""); + const [isOpen, setIsOpen] = useState(false); + const [isError, setIsError] = useState(false); + const [error, setError] = useState(""); + const [objects, setObjects] = useState([]); // set type later + + function openModal() { + setIsOpen(true); + } + + function closeModal() { + setIsOpen(false); + } + + const handlePublish = async () => { + setIsLoading(true); + const resp = await requestDataFromTerminal({ + cmd: SuiCommand.PUBLISH_PACKAGE, + gasBudget, + gasObjectId: currentGasObject, + }); + console.log(resp); + + const { stdout, stderr } = resp; + // need to handle error case + + if (stderr.isError) { + setError(stderr.message); + setIsError(true); + setIsLoading(false); + } else { + const { digest, objectChanges } = JSON.parse(stdout); + setCurrentDigest(digest); + console.log(digest); + console.log(objectChanges); + setIsLoading(false); + setObjects(objectChanges); + } + }; + + // const packageId = objects.find((obj) => obj.type === "published")?.packageId; + // const modules = objects.map(obj => { + // const { objectId, objectType, type } = obj; + // if (type !== "published") { + // let moduleName = objectType + // return + // } + // }); + + const packages = objects + .map((obj) => { + if (obj.type !== "published") { + const packageName = obj.objectType.split("::")[0]; + return packageName; + } + }) + .filter((item) => item !== undefined); + + let uniquePackages = [...new Set(packages)]; + + uniquePackages = uniquePackages.map((pkg) => { + return { + packageName: pkg, + modules: [], + }; + }); + + const getModulesOfPackage = (packageName: string) => { + console.log(packageName); + const modules = objects + .map((obj) => { + const { objectType, type } = obj; + if (type !== "published") { + console.log(objectType); + if (objectType.startsWith(packageName)) { + console.log(objectType.split("::")); + return objectType.split("::")[1]; + } + } + }) + .filter((item) => item !== undefined); + const uniqueModules = [...new Set(modules)]; + console.log(uniqueModules); + return uniqueModules; + }; + + const getObjectsOfModule = (packageName: string, moduleName: string) => { + const objectOfModule = objects + .map((obj) => { + if (obj.type !== "published") { + if ( + obj.objectType.startsWith(packageName) && + obj.objectType.split("::")[1] === moduleName + ) { + return obj; + } + } + }) + .filter((item) => item !== undefined); + return objectOfModule; + }; + + return ( + <> + +
+
+ +
+
+ +
+ Output: +
+
+
+ +
+ setGasBudget(Number(e.target.value))} + /> + Publisher {currentAddress} + Gas Object {currentGasObject} +
+
+ {isLoading ? ( + "Publishing...." + ) : ( + <> + {isError &&
Error {error}
} + {!isError && ( + <> +
Transaction: {currentDigest}
+
Error
+ + +

Effects:

+ {/* Package id: {packageId} */} + + {uniquePackages.map((pkg) => { + return ( + <> +
+
Package: {pkg.packageName}
+ {getModulesOfPackage(pkg.packageName).map( + (module) => { + return ( +
+
Module: {module}
+ {getObjectsOfModule( + pkg.packageName, + module + ).map((obj) => { + return ( +
+
Object id: {obj.objectId}
+
+ Object type: {obj.objectType} +
+
+ ); + })} +
+ ); + } + )} +
+ + ); + })} + + {/* {objects.map((obj) => { + if (obj.type !== "published") { + return ( + <> +
+
Object id: {obj.objectId}
+
Object type: {obj.objectType}
+
+ + ); + } + })} */} +
+ + )} + + )} +
+
+ + ); +}; diff --git a/src/webview/features/gasAddress/address.module.css b/src/webview/features/gasAddress/address.module.css new file mode 100644 index 0000000..d2ce7de --- /dev/null +++ b/src/webview/features/gasAddress/address.module.css @@ -0,0 +1,4 @@ +.activeAddress { + font-weight: bold; + color: red; +} \ No newline at end of file diff --git a/src/webview/features/gasAddress/address.tsx b/src/webview/features/gasAddress/address.tsx new file mode 100644 index 0000000..f47b563 --- /dev/null +++ b/src/webview/features/gasAddress/address.tsx @@ -0,0 +1,92 @@ +import React, { useEffect, useState } from "react"; +import Modal from "react-modal"; +import { requestDataFromTerminal } from "../../utils/wv_communicate_ext"; +import { SuiCommand } from "../../../enums"; +import styles from "./address.module.css"; +import { useSuiClientContext } from "@mysten/dapp-kit"; +import { useMySuiAccount } from "../../context/MySuiAccountProvider"; + +export const Address = () => { + // remember that then change UI in here need to call to terminal + const { network } = useSuiClientContext(); + const { addresses, currentAddress, setCurrentAddress, setAddresses } = + useMySuiAccount(); + + const [isOpen, setIsOpen] = useState(false); + const [isLoading, setIsLoading] = useState(false); + + function openModal() { + setIsOpen(true); + } + + function closeModal() { + setIsOpen(false); + } + + const switchAddress = async (e: React.ChangeEvent) => { + setIsLoading(true); + const resp = await requestDataFromTerminal({ + cmd: SuiCommand.SWITCH_ADDRESS, + address: e.target.value, + }); + const { stdout, stderr } = resp; + setCurrentAddress(e.target.value); + console.log(stdout); + setIsLoading(false); + }; + + useEffect(() => { + async function getAddresses() { + setIsLoading(true); + const resp = await requestDataFromTerminal({ + cmd: SuiCommand.GET_ADDRESSES, + }); + const { stdout, stderr } = resp; + const objects = JSON.parse(stdout); + const { activeAddress, addresses } = objects; + setCurrentAddress(activeAddress); + setAddresses(addresses); + setIsLoading(false); + // console.log(objects); + } + getAddresses(); + }, [network]); + + return ( + <> + + the Addresses managed by the client + {currentAddress ? currentAddress : ""} + + + {isLoading ? ( +

Loading...

+ ) : ( + + )} + +
+ +
+
+ + ); +}; diff --git a/src/webview/features/gasAddress/gas.tsx b/src/webview/features/gasAddress/gas.tsx new file mode 100644 index 0000000..3db29b0 --- /dev/null +++ b/src/webview/features/gasAddress/gas.tsx @@ -0,0 +1,83 @@ +import React, { useEffect, useState } from "react"; +import Modal from "react-modal"; +import { requestDataFromTerminal } from "../../utils/wv_communicate_ext"; +import { SuiCommand } from "../../../enums"; +import { useSuiClientContext } from "@mysten/dapp-kit"; +import { useMySuiAccount } from "../../context/MySuiAccountProvider"; + +export interface GasObject { + gasCoinId: string; + suiBalance: number; +} + +export const Gas = () => { + // remember that then change UI in here need to call to terminal + const { network } = useSuiClientContext(); + const { currentAddress, currentGasObject, gasObjects, setCurrentGasObject, setGasObjects } = + useMySuiAccount(); + + const [isOpen, setIsOpen] = useState(false); + const [isLoading, setIsLoading] = useState(false); + + function openModal() { + setIsOpen(true); + } + + function closeModal() { + setIsOpen(false); + } + + const requestFaucet = () => {}; + + useEffect(() => { + async function getGasObjects() { + setIsLoading(true); + const resp = await requestDataFromTerminal({ + cmd: SuiCommand.GET_GAS_OBJECTS, + }); + const { stdout, stderr } = resp; + const objects = JSON.parse(stdout); + setGasObjects(objects); + setIsLoading(false); + // console.log(objects); + } + getGasObjects(); + }, [network, currentAddress]); + + const balanceOfCurrentGasObject = gasObjects.find((gasObject) => gasObject.gasCoinId === currentGasObject)?.suiBalance; + + console.log(currentGasObject); + + return ( + <> + + The gas objects owned by the address + {currentGasObject ? currentGasObject : ""} + + + {isLoading ? ( +

Loading...

+ ) : ( + + )} + {balanceOfCurrentGasObject} + +
+ +
+
+ + ); +}; diff --git a/src/webview/features/gasAddress/index.tsx b/src/webview/features/gasAddress/index.tsx new file mode 100644 index 0000000..4de545e --- /dev/null +++ b/src/webview/features/gasAddress/index.tsx @@ -0,0 +1,19 @@ +import React from "react"; +import Collapsible from "react-collapsible"; +import { Address } from "./address"; +import { Gas } from "./gas"; + +export const GasAddress = () => { + return ( + <> + +
+
+
+
+ +
+
+ + ); +}; diff --git a/src/webview/features/suiConfig/v1/index.tsx b/src/webview/features/suiConfig/v1/index.tsx new file mode 100644 index 0000000..6e1c00c --- /dev/null +++ b/src/webview/features/suiConfig/v1/index.tsx @@ -0,0 +1,28 @@ +import React, { useState } from "react"; +import { Input } from "../../../components/Input"; +import { useSuiClientContext } from "@mysten/dapp-kit"; + +export default function index() { + const { network, selectNetwork } = useSuiClientContext(); + const [suiPath, setSuiPath] = useState(""); + + const handleNetworkChange = (e: React.ChangeEvent) => { + selectNetwork(e.target.value); + }; + + return ( + <> +

Setup Sui

+ setSuiPath(e.target.value)} + /> +

Network

+ + + ); +} diff --git a/src/webview/features/suiConfig/v2/index.tsx b/src/webview/features/suiConfig/v2/index.tsx new file mode 100644 index 0000000..f676599 --- /dev/null +++ b/src/webview/features/suiConfig/v2/index.tsx @@ -0,0 +1,99 @@ +import React, { useEffect, useRef, useState } from "react"; +import Toggle from "react-toggle"; +import "react-toggle/style.css"; +import { convertWindowsToUnixPath } from "../../../utils"; +import { FileWithPath } from "../../../../types"; +import { useSuiClientContext } from "@mysten/dapp-kit"; +import Collapsible from "react-collapsible"; +import { useSuiConfig } from "../../../context/SuiConfigProvider"; +import { requestDataFromTerminal } from "../../../utils/wv_communicate_ext"; +import { SuiCommand } from "../../../../enums"; + +export const SuiConfig = () => { + const { network, selectNetwork } = useSuiClientContext(); + const { isSuiCargo, setIsSuiCargo, suiPath, setSuiPath } = useSuiConfig(); + const [userNetworks, setUserNetworks] = useState([]); // type later + const [isLoading, setIsLoading] = useState(false); + + const handleNetworkChange = async (e: React.ChangeEvent) => { + setIsLoading(true); + const resp = await requestDataFromTerminal({ + cmd: SuiCommand.SWITCH_NETWORK, + network: e.target.value, + }); + const { stdout, stderr } = resp; + console.log(stdout); + selectNetwork(e.target.value); + setIsLoading(false); + }; + + const fileInputRef = useRef(null); + + useEffect(() => { + async function getUserNetworks() { + setIsLoading(true); + const resp = await requestDataFromTerminal({ + cmd: SuiCommand.GET_NETWORKS, + }); + const { stdout, stderr } = resp; + const result = JSON.parse(stdout); + const networks = result[0]; + const currentNetwork = result[1]; + console.log(JSON.parse(stdout)); + setUserNetworks(networks); + selectNetwork(currentNetwork); + setIsLoading(false); + } + getUserNetworks(); + }, []); + + useEffect(() => { + // fileInputRef?.current?.setAttribute("directory", ""); + // fileInputRef?.current?.setAttribute("webkitdirectory", ""); + + fileInputRef.current?.addEventListener("change", () => { + setSuiPath( + convertWindowsToUnixPath( + (fileInputRef.current?.files?.item(0) as FileWithPath)?.path + ) + ); + console.log(fileInputRef.current?.files); + console.log( + convertWindowsToUnixPath( + (fileInputRef.current?.files?.item(0) as FileWithPath)?.path + ) + ); + }); + }, [fileInputRef]); + + return ( + <> + + + {!isSuiCargo && ( + <> + + {suiPath &&

{suiPath}

} + + )} + {isLoading ? ( + "Loading" + ) : ( + + )} + +
+ + ); +}; diff --git a/src/webview/index.css b/src/webview/index.css new file mode 100644 index 0000000..bd6213e --- /dev/null +++ b/src/webview/index.css @@ -0,0 +1,3 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; \ No newline at end of file diff --git a/src/webview/utils/index.ts b/src/webview/utils/index.ts index 7b57cb2..0d3e6ea 100644 --- a/src/webview/utils/index.ts +++ b/src/webview/utils/index.ts @@ -3,3 +3,13 @@ export const copyToClipBoard = async (text: string) => { await navigator.clipboard.writeText(text); } catch (err) {} }; + +export const convertWindowsToUnixPath = (windowsPath: string) => { + // Replace double backslashes with single backslashes + let singleBackslashes = windowsPath.replace(/\\\\/g, "\\"); + // Replace backslashes with forward slashes + let unixPath = singleBackslashes.replace(/\\/g, "/"); + // Remove the initial part of the path up to "Ubuntu" + unixPath = unixPath.substring(unixPath.indexOf("Ubuntu") + "Ubuntu".length); + return unixPath; +}; diff --git a/src/webview/utils/wv_communicate_ext.ts b/src/webview/utils/wv_communicate_ext.ts index 0fd7418..3dda514 100644 --- a/src/webview/utils/wv_communicate_ext.ts +++ b/src/webview/utils/wv_communicate_ext.ts @@ -1,15 +1,6 @@ import { messageHandler } from "@estruyf/vscode/dist/client"; +import { MyCustomTerminalResponse } from "../../types"; -// webview send data to extension -export const sendMessage = (action: string, payload: any) => { - messageHandler.send(action, payload); // action, payload like redux -}; - -// webview request data from extension then extension send data to webview -export const requestData = async (action: string) => { - return messageHandler.request(action); -}; - -export const requestWithErrorData = async (action: string) => { - return messageHandler.request(action); +export const requestDataFromTerminal = async (payload: any) => { + return messageHandler.request("SUI_TERMINAL", payload); }; diff --git a/tailwind.config.js b/tailwind.config.js new file mode 100644 index 0000000..70c907d --- /dev/null +++ b/tailwind.config.js @@ -0,0 +1,11 @@ +/** @type {import('tailwindcss').Config} */ +module.exports = { + content: [ + "./src/**/*.{js,jsx,ts,tsx}", + ], + theme: { + extend: {}, + }, + plugins: [], +}; +