diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 13a22bf2ae1c1c3bf4432215639bbeecde193af5..239e44a8ec296809c16f4b11f06d941b79fa5aca 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -76,7 +76,7 @@ desktop_extension:package:release: script: - ./build-desktop.sh prod rules: - - if: $CI_COMMIT_BRANCH == "master" && $CI_COMMIT_TAG =~ /^(?:\d+\.){2}(?:\d+)$/ + - if: $CI_COMMIT_BRANCH == "master" && $CI_COMMIT_TAG =~ "/^(?:\d+\.){2}(?:\d+)$/" desktop_extension:publish:release: stage: publish @@ -93,4 +93,4 @@ desktop_extension:publish:release: - cd $EXTENSION_PATH - npm run vsce-publish -- -p $VSCODE_EXTENSION_MARKET_PLACE_ACCESS_TOKEN rules: - - if: $CI_COMMIT_BRANCH == "master" && $CI_COMMIT_TAG =~ /^(?:\d+\.){2}(?:\d+)$/ + - if: $CI_COMMIT_BRANCH == "master" && $CI_COMMIT_TAG =~ "/^(?:\d+\.){2}(?:\d+)$/" diff --git a/deadlock-plugins/deadlock-extension/package-lock.json b/deadlock-plugins/deadlock-extension/package-lock.json index 5138863c0a71561d260f1100dc8bd5c200f9277c..83d3d20289067b19686a81c92f2a05633e1fb5d8 100644 --- a/deadlock-plugins/deadlock-extension/package-lock.json +++ b/deadlock-plugins/deadlock-extension/package-lock.json @@ -9,7 +9,6 @@ "version": "0.1.11", "dependencies": { "@types/tar": "^6.1.1", - "@types/yaml": "^1.9.7", "@vscode/webview-ui-toolkit": "^1.0.0", "async": "^3.2.2", "axios": "^0.27.2", @@ -28,7 +27,6 @@ "@types/node-fetch": "^2.6.1", "@types/vscode": "^1.66.0", "@types/webpack": "^5.28.0", - "@types/webpack-dev-server": "^4.7.2", "@typescript-eslint/eslint-plugin": "^3.10.1", "@typescript-eslint/parser": "^3.10.1", "auto-changelog": "^2.4.0", @@ -41,8 +39,9 @@ "ts-loader": "^9.3.1", "typescript": "^4.7.2", "vsce": "^2.9.2", - "webpack": "^5.70.0", - "webpack-cli": "^4.10.0" + "webpack": "^5.73.0", + "webpack-cli": "^4.10.0", + "webpack-dev-server": "^4.9.3" }, "engines": { "vscode": ">=1.66.0" @@ -1454,9 +1453,9 @@ } }, "node_modules/@types/express-serve-static-core": { - "version": "4.17.28", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.28.tgz", - "integrity": "sha512-P1BJAEAW3E2DJUlkgq4tOL3RyMunoWXqbSCygWo5ZIWTjUgN1YnaXWW4VWl/oc8vs/XoYibEGBKP0uZyF4AHig==", + "version": "4.17.29", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.29.tgz", + "integrity": "sha512-uMd++6dMKS32EOuw1Uli3e3BPgdLIXmezcfHv7N4c1s3gkhikBplORPpMq3fuWkxncZN1reb16d5n8yhQ80x7Q==", "dev": true, "dependencies": { "@types/node": "*", @@ -1656,16 +1655,6 @@ "webpack": "^5" } }, - "node_modules/@types/webpack-dev-server": { - "version": "4.7.2", - "resolved": "https://registry.npmjs.org/@types/webpack-dev-server/-/webpack-dev-server-4.7.2.tgz", - "integrity": "sha512-Y3p0Fmfvp0MHBDoCzo+xFJaWTw0/z37mWIo6P15j+OtmUDLvznJWdZNeD7Q004R+MpQlys12oXbXsrXRmxwg4Q==", - "deprecated": "This is a stub types definition. webpack-dev-server provides its own type definitions, so you do not need this installed.", - "dev": true, - "dependencies": { - "webpack-dev-server": "*" - } - }, "node_modules/@types/ws": { "version": "8.5.3", "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.3.tgz", @@ -1675,15 +1664,6 @@ "@types/node": "*" } }, - "node_modules/@types/yaml": { - "version": "1.9.7", - "resolved": "https://registry.npmjs.org/@types/yaml/-/yaml-1.9.7.tgz", - "integrity": "sha512-8WMXRDD1D+wCohjfslHDgICd2JtMATZU8CkhH8LVJqcJs6dyYj5TGptzP8wApbmEullGBSsCEzzap73DQ1HJaA==", - "deprecated": "This is a stub types definition. yaml provides its own type definitions, so you do not need this installed.", - "dependencies": { - "yaml": "*" - } - }, "node_modules/@types/yargs": { "version": "17.0.10", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.10.tgz", @@ -2604,15 +2584,15 @@ "dev": true }, "node_modules/bonjour-service": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.0.12.tgz", - "integrity": "sha512-pMmguXYCu63Ug37DluMKEHdxc+aaIf/ay4YbF8Gxtba+9d3u+rmEWy61VK3Z3hp8Rskok3BunHYnG0dUHAsblw==", + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.0.13.tgz", + "integrity": "sha512-LWKRU/7EqDUC9CTAQtuZl5HzBALoCYwtLhffW3et7vZMwv3bWLpJf8bRYlMD5OCcDpTfnPgNCV4yo9ZIaJGMiA==", "dev": true, "dependencies": { "array-flatten": "^2.1.2", "dns-equal": "^1.0.0", "fast-deep-equal": "^3.1.3", - "multicast-dns": "^7.2.4" + "multicast-dns": "^7.2.5" } }, "node_modules/boolbase": { @@ -3158,9 +3138,9 @@ "dev": true }, "node_modules/connect-history-api-fallback": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz", - "integrity": "sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", + "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==", "dev": true, "engines": { "node": ">=0.8" @@ -3466,9 +3446,9 @@ "dev": true }, "node_modules/dns-packet": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.3.1.tgz", - "integrity": "sha512-spBwIj0TK0Ey3666GwIdWVfUpLyubpU53BTCu8iPn4r4oXd9O14Hjg3EHw3ts2oed77/SeckunUYCyRlSngqHw==", + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.4.0.tgz", + "integrity": "sha512-EgqGeaBB8hLiHLZtp/IbaDQTL8pZ0+IvwzSHA6d7VyMDM+B9hgddEMa9xjK5oYnw0ci0JQ6g2XCD7/f6cafU6g==", "dev": true, "dependencies": { "@leichtgewicht/ip-codec": "^2.0.1" @@ -4815,9 +4795,9 @@ } }, "node_modules/http-parser-js": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.6.tgz", - "integrity": "sha512-vDlkRPDJn93swjcjqMSaGSPABbIarsr1TLAui/gLDXzV5VsJNdXNzMYDyNBLQkjWQCJ1uizu8T2oDMhmGt0PRA==", + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", + "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==", "dev": true }, "node_modules/http-proxy": { @@ -5045,6 +5025,21 @@ "url": "https://github.com/sponsors/ljharb" } }, + "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, + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -5168,21 +5163,6 @@ "node": ">=8" } }, - "node_modules/is-wsl/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, - "bin": { - "is-docker": "cli.js" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", @@ -6622,12 +6602,12 @@ } }, "node_modules/memfs": { - "version": "3.4.4", - "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.4.4.tgz", - "integrity": "sha512-W4gHNUE++1oSJVn8Y68jPXi+mkx3fXR5ITE/Ubz6EQ3xRpCN5k2CQ4AUR8094Z7211F876TyoBACGsIveqgiGA==", + "version": "3.4.7", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.4.7.tgz", + "integrity": "sha512-ygaiUSNalBX85388uskeCyhSAoOSgzBbtVCr9jA2RROssFL9Q19/ZXFqS+2Th2sr1ewNIWgFdLzLC3Yl1Zv+lw==", "dev": true, "dependencies": { - "fs-monkey": "1.0.3" + "fs-monkey": "^1.0.3" }, "engines": { "node": ">= 4.0.0" @@ -7182,21 +7162,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/open/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, - "bin": { - "is-docker": "cli.js" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/optionator": { "version": "0.9.1", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", @@ -7804,7 +7769,7 @@ "node_modules/requires-port": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", "dev": true }, "node_modules/resolve": { @@ -7973,7 +7938,7 @@ "node_modules/select-hose": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", - "integrity": "sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo=", + "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==", "dev": true }, "node_modules/selfsigned": { @@ -8060,7 +8025,7 @@ "node_modules/serve-index": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", - "integrity": "sha1-03aNabHn2C5c4FD/9bRTvqEqkjk=", + "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==", "dev": true, "dependencies": { "accepts": "~1.3.4", @@ -8129,7 +8094,7 @@ "node_modules/serve-index/node_modules/statuses": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", "dev": true, "engines": { "node": ">= 0.6" @@ -9100,7 +9065,7 @@ "node_modules/unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", "dev": true, "engines": { "node": ">= 0.8" @@ -9130,7 +9095,7 @@ "node_modules/utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", "dev": true, "engines": { "node": ">= 0.4.0" @@ -9176,7 +9141,7 @@ "node_modules/vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", "dev": true, "engines": { "node": ">= 0.8" @@ -9303,9 +9268,9 @@ "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=" }, "node_modules/webpack": { - "version": "5.72.1", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.72.1.tgz", - "integrity": "sha512-dXG5zXCLspQR4krZVR6QgajnZOjW2K/djHvdcRaDQvsjV9z9vaW6+ja5dZOYbqBBjF6kGXka/2ZyxNdc+8Jung==", + "version": "5.73.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.73.0.tgz", + "integrity": "sha512-svjudQRPPa0YiOYa2lM/Gacw0r6PvxptHj4FuEKQ2kX05ZLkjbVc5MnPs6its5j7IZljnIqSVo/OsY2X0IpHGA==", "dev": true, "dependencies": { "@types/eslint-scope": "^3.7.3", @@ -9482,15 +9447,16 @@ } }, "node_modules/webpack-dev-server": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.9.1.tgz", - "integrity": "sha512-CTMfu2UMdR/4OOZVHRpdy84pNopOuigVIsRbGX3LVDMWNP8EUgC5mUBMErbwBlHTEX99ejZJpVqrir6EXAEajA==", + "version": "4.9.3", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.9.3.tgz", + "integrity": "sha512-3qp/eoboZG5/6QgiZ3llN8TUzkSpYg1Ko9khWX1h40MIEUNS2mDoIa8aXsPfskER+GbTvs/IJZ1QTBBhhuetSw==", "dev": true, "dependencies": { "@types/bonjour": "^3.5.9", "@types/connect-history-api-fallback": "^1.3.5", "@types/express": "^4.17.13", "@types/serve-index": "^1.9.1", + "@types/serve-static": "^1.13.10", "@types/sockjs": "^0.3.33", "@types/ws": "^8.5.1", "ansi-html-community": "^0.0.8", @@ -9498,7 +9464,7 @@ "chokidar": "^3.5.3", "colorette": "^2.0.10", "compression": "^1.7.4", - "connect-history-api-fallback": "^1.6.0", + "connect-history-api-fallback": "^2.0.0", "default-gateway": "^6.0.3", "express": "^4.17.3", "graceful-fs": "^4.2.6", @@ -9522,6 +9488,10 @@ "engines": { "node": ">= 12.13.0" }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, "peerDependencies": { "webpack": "^4.37.0 || ^5.0.0" }, @@ -9753,9 +9723,9 @@ } }, "node_modules/ws": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.7.0.tgz", - "integrity": "sha512-c2gsP0PRwcLFzUiA8Mkr37/MI7ilIlHQxaEAtd0uNMbVMoy8puJyafRlm0bV9MbGSabUPeLrRRaqIBcFcA2Pqg==", + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.8.0.tgz", + "integrity": "sha512-JDAgSYQ1ksuwqfChJusw1LSJ8BizJ2e/vVu5Lxjq3YvNJNlROv1ui4i+c/kUUrPheBvQl4c5UbERhTwKa6QBJQ==", "dev": true, "engines": { "node": ">=10.0.0" @@ -11034,9 +11004,9 @@ } }, "@types/express-serve-static-core": { - "version": "4.17.28", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.28.tgz", - "integrity": "sha512-P1BJAEAW3E2DJUlkgq4tOL3RyMunoWXqbSCygWo5ZIWTjUgN1YnaXWW4VWl/oc8vs/XoYibEGBKP0uZyF4AHig==", + "version": "4.17.29", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.29.tgz", + "integrity": "sha512-uMd++6dMKS32EOuw1Uli3e3BPgdLIXmezcfHv7N4c1s3gkhikBplORPpMq3fuWkxncZN1reb16d5n8yhQ80x7Q==", "dev": true, "requires": { "@types/node": "*", @@ -11236,15 +11206,6 @@ "webpack": "^5" } }, - "@types/webpack-dev-server": { - "version": "4.7.2", - "resolved": "https://registry.npmjs.org/@types/webpack-dev-server/-/webpack-dev-server-4.7.2.tgz", - "integrity": "sha512-Y3p0Fmfvp0MHBDoCzo+xFJaWTw0/z37mWIo6P15j+OtmUDLvznJWdZNeD7Q004R+MpQlys12oXbXsrXRmxwg4Q==", - "dev": true, - "requires": { - "webpack-dev-server": "*" - } - }, "@types/ws": { "version": "8.5.3", "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.3.tgz", @@ -11254,14 +11215,6 @@ "@types/node": "*" } }, - "@types/yaml": { - "version": "1.9.7", - "resolved": "https://registry.npmjs.org/@types/yaml/-/yaml-1.9.7.tgz", - "integrity": "sha512-8WMXRDD1D+wCohjfslHDgICd2JtMATZU8CkhH8LVJqcJs6dyYj5TGptzP8wApbmEullGBSsCEzzap73DQ1HJaA==", - "requires": { - "yaml": "*" - } - }, "@types/yargs": { "version": "17.0.10", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.10.tgz", @@ -11973,15 +11926,15 @@ } }, "bonjour-service": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.0.12.tgz", - "integrity": "sha512-pMmguXYCu63Ug37DluMKEHdxc+aaIf/ay4YbF8Gxtba+9d3u+rmEWy61VK3Z3hp8Rskok3BunHYnG0dUHAsblw==", + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.0.13.tgz", + "integrity": "sha512-LWKRU/7EqDUC9CTAQtuZl5HzBALoCYwtLhffW3et7vZMwv3bWLpJf8bRYlMD5OCcDpTfnPgNCV4yo9ZIaJGMiA==", "dev": true, "requires": { "array-flatten": "^2.1.2", "dns-equal": "^1.0.0", "fast-deep-equal": "^3.1.3", - "multicast-dns": "^7.2.4" + "multicast-dns": "^7.2.5" } }, "boolbase": { @@ -12391,9 +12344,9 @@ "dev": true }, "connect-history-api-fallback": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz", - "integrity": "sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", + "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==", "dev": true }, "console-control-strings": { @@ -12622,9 +12575,9 @@ "dev": true }, "dns-packet": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.3.1.tgz", - "integrity": "sha512-spBwIj0TK0Ey3666GwIdWVfUpLyubpU53BTCu8iPn4r4oXd9O14Hjg3EHw3ts2oed77/SeckunUYCyRlSngqHw==", + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.4.0.tgz", + "integrity": "sha512-EgqGeaBB8hLiHLZtp/IbaDQTL8pZ0+IvwzSHA6d7VyMDM+B9hgddEMa9xjK5oYnw0ci0JQ6g2XCD7/f6cafU6g==", "dev": true, "requires": { "@leichtgewicht/ip-codec": "^2.0.1" @@ -13671,9 +13624,9 @@ } }, "http-parser-js": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.6.tgz", - "integrity": "sha512-vDlkRPDJn93swjcjqMSaGSPABbIarsr1TLAui/gLDXzV5VsJNdXNzMYDyNBLQkjWQCJ1uizu8T2oDMhmGt0PRA==", + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", + "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==", "dev": true }, "http-proxy": { @@ -13834,6 +13787,12 @@ "has": "^1.0.3" } }, + "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 + }, "is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -13913,14 +13872,6 @@ "dev": true, "requires": { "is-docker": "^2.0.0" - }, - "dependencies": { - "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 - } } }, "isarray": { @@ -15031,12 +14982,12 @@ "dev": true }, "memfs": { - "version": "3.4.4", - "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.4.4.tgz", - "integrity": "sha512-W4gHNUE++1oSJVn8Y68jPXi+mkx3fXR5ITE/Ubz6EQ3xRpCN5k2CQ4AUR8094Z7211F876TyoBACGsIveqgiGA==", + "version": "3.4.7", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.4.7.tgz", + "integrity": "sha512-ygaiUSNalBX85388uskeCyhSAoOSgzBbtVCr9jA2RROssFL9Q19/ZXFqS+2Th2sr1ewNIWgFdLzLC3Yl1Zv+lw==", "dev": true, "requires": { - "fs-monkey": "1.0.3" + "fs-monkey": "^1.0.3" } }, "merge-descriptors": { @@ -15440,14 +15391,6 @@ "define-lazy-prop": "^2.0.0", "is-docker": "^2.1.1", "is-wsl": "^2.2.0" - }, - "dependencies": { - "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 - } } }, "optionator": { @@ -15913,7 +15856,7 @@ "requires-port": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", "dev": true }, "resolve": { @@ -16035,7 +15978,7 @@ "select-hose": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", - "integrity": "sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo=", + "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==", "dev": true }, "selfsigned": { @@ -16114,7 +16057,7 @@ "serve-index": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", - "integrity": "sha1-03aNabHn2C5c4FD/9bRTvqEqkjk=", + "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==", "dev": true, "requires": { "accepts": "~1.3.4", @@ -16174,7 +16117,7 @@ "statuses": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", "dev": true } } @@ -16893,7 +16836,7 @@ "unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", "dev": true }, "uri-js": { @@ -16920,7 +16863,7 @@ "utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", "dev": true }, "uuid": { @@ -16957,7 +16900,7 @@ "vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", "dev": true }, "vsce": { @@ -17062,9 +17005,9 @@ "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=" }, "webpack": { - "version": "5.72.1", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.72.1.tgz", - "integrity": "sha512-dXG5zXCLspQR4krZVR6QgajnZOjW2K/djHvdcRaDQvsjV9z9vaW6+ja5dZOYbqBBjF6kGXka/2ZyxNdc+8Jung==", + "version": "5.73.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.73.0.tgz", + "integrity": "sha512-svjudQRPPa0YiOYa2lM/Gacw0r6PvxptHj4FuEKQ2kX05ZLkjbVc5MnPs6its5j7IZljnIqSVo/OsY2X0IpHGA==", "dev": true, "requires": { "@types/eslint-scope": "^3.7.3", @@ -17176,15 +17119,16 @@ } }, "webpack-dev-server": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.9.1.tgz", - "integrity": "sha512-CTMfu2UMdR/4OOZVHRpdy84pNopOuigVIsRbGX3LVDMWNP8EUgC5mUBMErbwBlHTEX99ejZJpVqrir6EXAEajA==", + "version": "4.9.3", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.9.3.tgz", + "integrity": "sha512-3qp/eoboZG5/6QgiZ3llN8TUzkSpYg1Ko9khWX1h40MIEUNS2mDoIa8aXsPfskER+GbTvs/IJZ1QTBBhhuetSw==", "dev": true, "requires": { "@types/bonjour": "^3.5.9", "@types/connect-history-api-fallback": "^1.3.5", "@types/express": "^4.17.13", "@types/serve-index": "^1.9.1", + "@types/serve-static": "^1.13.10", "@types/sockjs": "^0.3.33", "@types/ws": "^8.5.1", "ansi-html-community": "^0.0.8", @@ -17192,7 +17136,7 @@ "chokidar": "^3.5.3", "colorette": "^2.0.10", "compression": "^1.7.4", - "connect-history-api-fallback": "^1.6.0", + "connect-history-api-fallback": "^2.0.0", "default-gateway": "^6.0.3", "express": "^4.17.3", "graceful-fs": "^4.2.6", @@ -17384,9 +17328,9 @@ } }, "ws": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.7.0.tgz", - "integrity": "sha512-c2gsP0PRwcLFzUiA8Mkr37/MI7ilIlHQxaEAtd0uNMbVMoy8puJyafRlm0bV9MbGSabUPeLrRRaqIBcFcA2Pqg==", + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.8.0.tgz", + "integrity": "sha512-JDAgSYQ1ksuwqfChJusw1LSJ8BizJ2e/vVu5Lxjq3YvNJNlROv1ui4i+c/kUUrPheBvQl4c5UbERhTwKa6QBJQ==", "dev": true, "requires": {} }, diff --git a/deadlock-plugins/deadlock-extension/package.json b/deadlock-plugins/deadlock-extension/package.json index 7b58b5ba4cc7fe53111d747680eff2b47617df80..fa446a0418c18ca882be8e71a29ee6499939a0f8 100644 --- a/deadlock-plugins/deadlock-extension/package.json +++ b/deadlock-plugins/deadlock-extension/package.json @@ -98,7 +98,6 @@ }, "dependencies": { "@types/tar": "^6.1.1", - "@types/yaml": "^1.9.7", "@vscode/webview-ui-toolkit": "^1.0.0", "async": "^3.2.2", "axios": "^0.27.2", @@ -117,7 +116,6 @@ "@types/node-fetch": "^2.6.1", "@types/vscode": "^1.66.0", "@types/webpack": "^5.28.0", - "@types/webpack-dev-server": "^4.7.2", "@typescript-eslint/eslint-plugin": "^3.10.1", "@typescript-eslint/parser": "^3.10.1", "auto-changelog": "^2.4.0", @@ -130,8 +128,9 @@ "ts-loader": "^9.3.1", "typescript": "^4.7.2", "vsce": "^2.9.2", - "webpack": "^5.70.0", - "webpack-cli": "^4.10.0" + "webpack": "^5.73.0", + "webpack-cli": "^4.10.0", + "webpack-dev-server": "^4.9.3" }, "extensionPack": [ "ms-vscode-remote.remote-containers" diff --git a/deadlock-plugins/deadlock-extension/src/core/api.service.ts b/deadlock-plugins/deadlock-extension/src/core/api.service.ts index 116dfceb286b9e29019acedd9a29b01ea2ba1745..736867962bf0dffa2535cfe081be119b7d1784e7 100644 --- a/deadlock-plugins/deadlock-extension/src/core/api.service.ts +++ b/deadlock-plugins/deadlock-extension/src/core/api.service.ts @@ -7,15 +7,20 @@ import Controller from './controller'; import ExtensionStore from './extensionStore'; import KeycloakOAuth2DeviceFlowConnection from './keycloakOAuth2DeviceFlowConnection'; import { MissionUser } from './mission/model/missionUser'; -import { User } from './mission/model/userMission'; +import UserMission, { User } from './mission/model/userMission'; export default class ApiService { private axiosInstance: AxiosInstance; - constructor( - private keycloackConnection: KeycloakOAuth2DeviceFlowConnection, - private extensionStore: ExtensionStore, - private controller: Controller, - ) { + private static _instance: ApiService; + + static getInstance(): ApiService { + if (!ApiService._instance) { + ApiService._instance = new ApiService(); + } + return ApiService._instance; + } + + private constructor() { this.axiosInstance = axios.create({ baseURL: API_URL, headers: { @@ -27,6 +32,18 @@ export default class ApiService { this.initApiInterceptor(); } + private get controller(): Controller { + return Controller.getInstance(); + } + + private get extensionStore(): ExtensionStore { + return ExtensionStore.getInstance(); + } + + private get keycloackConnection(): KeycloakOAuth2DeviceFlowConnection { + return KeycloakOAuth2DeviceFlowConnection.getInstance(); + } + initApiInterceptor() { this.initRequestInterceptor(); this.initResponseInterceptor(); @@ -140,19 +157,25 @@ export default class ApiService { .then((res) => res.status); } - async pingUpdateWorkTime(userId: string, missionId: string): Promise<MissionUser> { + async pingUpdateWorkTime(): Promise<MissionUser> { return this.axiosInstance - .post<MissionUser>(`users/${userId}/missions/${missionId}/worktime`, { - action: 'PING', - }) + .post<MissionUser>( + `users/${(await this.getCurrentUser()).id}/missions/${UserMission.getInstance().missionId}/worktime`, + { + action: 'PING', + }, + ) .then((res) => res.data); } - async startUpdateWorkTime(userId: string, missionId: string): Promise<MissionUser> { + async startUpdateWorkTime(): Promise<MissionUser> { return this.axiosInstance - .post<MissionUser>(`users/${userId}/missions/${missionId}/worktime`, { - action: 'START', - }) + .post<MissionUser>( + `users/${(await this.getCurrentUser()).id}/missions/${UserMission.getInstance().missionId}/worktime`, + { + action: 'START', + }, + ) .then((res) => res.data); } } diff --git a/deadlock-plugins/deadlock-extension/src/core/commandHandler.ts b/deadlock-plugins/deadlock-extension/src/core/commandHandler.ts index cf1e95717c0fda9cb5ca9382790fa8a501c80039..6dde3a57fc7f225dabfdafd7b9cc27ad107ce2c9 100644 --- a/deadlock-plugins/deadlock-extension/src/core/commandHandler.ts +++ b/deadlock-plugins/deadlock-extension/src/core/commandHandler.ts @@ -1,5 +1,4 @@ -import { commands } from 'vscode'; -import { VsCommand } from '../theia/command'; +import { Command, commands } from 'vscode'; import Controller from './controller'; export class CommandHandler { constructor(private controller: Controller) { @@ -7,11 +6,11 @@ export class CommandHandler { } initCommandHandler() { - commands.registerCommand(disconnectCommand.cmd, this.controller.disconnect.bind(this.controller)); - commands.registerCommand(authenticateCommand.cmd, this.controller.authenticate.bind(this.controller)); + commands.registerCommand(disconnectCommand.command, this.controller.disconnect.bind(this.controller)); + commands.registerCommand(authenticateCommand.command, this.controller.authenticate.bind(this.controller)); } } -export const disconnectCommand = new VsCommand('Disconnect', 'deadlock.disconnect'); -export const authenticateCommand = new VsCommand('Authenticate', 'deadlock.authenticate'); -export const openUrlInBrowserCommand = new VsCommand('Open url in browser', 'vscode.open'); +export const disconnectCommand: Command = { title: 'Disconnect', command: 'deadlock.disconnect' }; +export const authenticateCommand: Command = { title: 'Authenticate', command: 'deadlock.authenticate' }; +export const openUrlInBrowserCommand: Command = { title: 'Open url in browser', command: 'vscode.open' }; diff --git a/deadlock-plugins/deadlock-extension/src/core/config.ts b/deadlock-plugins/deadlock-extension/src/core/config.ts index 50d2bb53c07b28a229e2729de7d57efe727f38b9..7c9e0f06f4494aec60d6e282b0f170be66f77970 100644 --- a/deadlock-plugins/deadlock-extension/src/core/config.ts +++ b/deadlock-plugins/deadlock-extension/src/core/config.ts @@ -1,37 +1,30 @@ -import * as os from 'os'; -import * as path from 'path'; +import { homedir } from 'os'; +import { join } from 'path'; import isDocker from './utils/isdocker'; -const homeDir = os.homedir(); // if we are on container, means the directory will depend differently const onContainer = isDocker(); -// TODO: remove this next line -const deadlockExtensionPath = path.join(homeDir, 'deadlock-extension'); +const deadlockConfigPath = join(homedir(), '.deadlock'); -const deadlockConfigPath = path.join(homeDir, '.deadlock'); -export const userSshKeyFolderPath = path.join(deadlockConfigPath, '.ssh'); -export const missionWorkdir = path.join(deadlockConfigPath, 'workspace'); +export const userSshKeyFolderPath = join(deadlockConfigPath, '.ssh'); -export const PROJECT_SRC_PATH = onContainer ? '/project' : path.join(homeDir, 'deadlock-extension', '/project'); +export const DOCS_PATH_IC = `${homedir()}/docs`; -// TODO: remove this next line (theia????) -export const PROJECT_DEADLOCK_DESKTOP_PATH = onContainer - ? path.join('/home/deadlock/mission') - : path.join(deadlockExtensionPath, 'project-theia'); +export const missionWorkdir = join(deadlockConfigPath, 'workspace'); -export const DOCS_PATH = path.join(path.join(onContainer ? '/home/deadlock' : deadlockExtensionPath), 'docs'); +export const GITEA_PATH_IC = '/project'; -export const DEADLOCK_WORKDIR_PATH = onContainer ? '/deadlock' : deadlockConfigPath; +export const MISSION_PATH_IC = `${homedir()}/mission`; -export const CONFIG_PATH = onContainer ? '/home/config/' : path.join(deadlockExtensionPath, 'config'); +export const DEADLOCK_WORKDIR_PATH = onContainer ? '/deadlock' : deadlockConfigPath; -export const USER_CHALLENGE_PATH = path.join(CONFIG_PATH, 'user-challenge.json'); +export const USER_MISSION_PATH = join('/home/config/user-challenge.json'); export const BRIEFING_FILE_NAME = 'briefing.md'; -export const ENV_FILE_PATH = path.join(PROJECT_DEADLOCK_DESKTOP_PATH, '/.env'); +export const ENV_FILE_PATH = join(MISSION_PATH_IC, '.env'); -export const BASHRC_PATH = path.join(homeDir, '/.bashrc'); +export const BASHRC_PATH = join(homedir(), '.bashrc'); -export const SERVICES_PATHS_PATH = path.join(PROJECT_DEADLOCK_DESKTOP_PATH, '/paths.json'); +export const SERVICES_PATHS_PATH = join(MISSION_PATH_IC, 'paths.json'); diff --git a/deadlock-plugins/deadlock-extension/src/core/controller.ts b/deadlock-plugins/deadlock-extension/src/core/controller.ts index 55e4fd2fd8459c44d86d070f15d06655a37db636..8f7f779fb93f4c2e56b0e5e2f737df5f80670231 100644 --- a/deadlock-plugins/deadlock-extension/src/core/controller.ts +++ b/deadlock-plugins/deadlock-extension/src/core/controller.ts @@ -1,57 +1,48 @@ -import { KEYCLOAK_DEVICE_AUTH_URL, KEYCLOAK_TOKEN_CREATE_URL, KEYCLOAK_USER_INFO_URL } from '../config'; import BriefingView from '../view/briefingView'; import QuickSetupView from '../view/quickSetupView'; import { CommandHandler, openUrlInBrowserCommand } from './commandHandler'; import ExtensionStore from './extensionStore'; import KeycloakOAuth2DeviceFlowConnection from './keycloakOAuth2DeviceFlowConnection'; -import ApiService from './api.service'; -import { GiteaPublicProperties } from '../model/giteaPublicProperties.model'; import { MissionDevContainer } from './mission/missionDevContainer'; import { extensionError, extensionLog as log, extensionWarn } from '../recorder/utils/log'; -import { commands, ExtensionContext, Uri, window } from 'vscode'; +import { Command, commands, ExtensionContext, Uri, window } from 'vscode'; import { createSshKeyFiles } from './sshKeyManager'; import { emptyDirectories, removeFilesOrDirectories } from '../recorder/utils/workdir'; import { missionWorkdir, userSshKeyFolderPath } from './config'; import { hasStatusNumber } from './utils/typeguards'; -import { User } from './mission/model/userMission'; -import { existsSync, mkdirSync, writeFileSync } from 'fs'; +import { existsSync, mkdirSync, readdirSync, renameSync, rmSync, writeFileSync } from 'fs'; import { extract } from 'tar'; import { parse } from 'yaml'; import isDocker from './utils/isdocker'; -import * as fs from 'fs'; import { getReviewedStudentWorkdirPath } from './utils/mission.utils'; import { join } from 'path'; import Mission from '../model/mission'; +import ApiService from './api.service'; export default class Controller { private static instance: Controller; - public connection: KeycloakOAuth2DeviceFlowConnection; private commandHandler: CommandHandler; private briefingView: BriefingView; private quickSetupView: QuickSetupView; - private _apiService: ApiService; private _extensionStore: ExtensionStore; public get extensionStore() { return this._extensionStore; } - public get apiService() { - return this._apiService; + private get connection(): KeycloakOAuth2DeviceFlowConnection { + return KeycloakOAuth2DeviceFlowConnection.getInstance(); } - private constructor(context: ExtensionContext) { + private get apiService(): ApiService { + return ApiService.getInstance(); + } + + private constructor(public readonly context: ExtensionContext) { this._extensionStore = ExtensionStore.getInstance(context); this.briefingView = new BriefingView(); this.quickSetupView = new QuickSetupView(context.extensionUri); this.commandHandler = new CommandHandler(this); - this.connection = new KeycloakOAuth2DeviceFlowConnection( - KEYCLOAK_DEVICE_AUTH_URL, - KEYCLOAK_TOKEN_CREATE_URL, - KEYCLOAK_USER_INFO_URL, - ); - - this._apiService = new ApiService(this.connection, this._extensionStore, this); this.init(); } @@ -74,13 +65,13 @@ export default class Controller { public async getSolution(missionId: string, reviewedId: string) { try { - const solution = await this._apiService.getSolution(missionId); + const solution = await this.apiService.getSolution(missionId); const solutionFolder = join(getReviewedStudentWorkdirPath(reviewedId), missionId, '.solution'); const tarName = 'solution.tar.gz'; const tarPath = join(solutionFolder, tarName); if (existsSync(solutionFolder)) { - fs.rmSync(solutionFolder, { recursive: true }); + rmSync(solutionFolder, { recursive: true }); } mkdirSync(solutionFolder, { recursive: true }); @@ -89,10 +80,10 @@ export default class Controller { extract({ sync: true, file: `${solutionFolder}/${tarName}`, cwd: solutionFolder }); await removeFilesOrDirectories(`${solutionFolder}/${tarName}`); // list files in the folder - fs.readdirSync(solutionFolder).forEach((file) => { + readdirSync(solutionFolder).forEach((file) => { const tmpSolutionPath = join(solutionFolder, file); - fs.readdirSync(tmpSolutionPath).map((f) => fs.renameSync(join(tmpSolutionPath, f), join(solutionFolder, f))); - fs.rmSync(tmpSolutionPath, { recursive: true }); + readdirSync(tmpSolutionPath).map((f) => renameSync(join(tmpSolutionPath, f), join(solutionFolder, f))); + rmSync(tmpSolutionPath, { recursive: true }); }); } catch (e) { window.showErrorMessage(`Une erreur est survenue lors de la récupération de la solution`); @@ -154,7 +145,7 @@ export default class Controller { } public async createSshKeyPair() { - const { publicKey, privateKey } = await this._apiService.getUserSshKey(); + const { publicKey, privateKey } = await this.apiService.getUserSshKey(); await createSshKeyFiles(publicKey, privateKey); } @@ -168,10 +159,10 @@ export default class Controller { } public static openBrowserWithUrl(url: string) { - commands.executeCommand(openUrlInBrowserCommand.cmd, Uri.parse(url)); + commands.executeCommand(openUrlInBrowserCommand.command, Uri.parse(url)); } - public async launchMission(missionId: string, missionVersion: string, userId?: string) { + public async launchMission(missionId: string, missionVersion: string, revieweeId?: string) { window.showInformationMessage(`vous lancez la mission ${missionId}`); const hadBeenConnected = (await this._extensionStore.getAccessToken()) !== undefined; @@ -181,13 +172,11 @@ export default class Controller { window.showInformationMessage('Connexion validée'); } - const currentUser = await this.apiService.getCurrentUser(); + const reviewer = await this.apiService.getCurrentUser(); - const user: User = userId ? await this._apiService.getUser(userId) : currentUser; - - if (!!userId && userId !== currentUser.id) { + if (!!revieweeId && revieweeId !== reviewer.id) { try { - await this._apiService.grantAccessToRepository(user.id, missionId); + await this.apiService.grantAccessToRepository(revieweeId, missionId); } catch (e) { if (hasStatusNumber(e)) { if (e.status === 403) { @@ -199,22 +188,14 @@ export default class Controller { } } try { - await Controller.getInstance().getSolution(missionId, user.id); + await Controller.getInstance().getSolution(missionId, revieweeId); } catch (e) { window.showErrorMessage(`Une erreur est survenue lors de la récupération de la solution`); extensionError(e); } } - const giteaPublicProperties: GiteaPublicProperties = await this._apiService.getGiteaPublicProperties(); - - const missionDevcontainer = new MissionDevContainer( - user, - currentUser, - missionId, - missionVersion, - giteaPublicProperties, - ); + const missionDevcontainer = new MissionDevContainer(missionId, missionVersion, revieweeId); try { await missionDevcontainer.open(); @@ -223,3 +204,13 @@ export default class Controller { } } } + +export const openBriefingCommand: Command = { + title: 'Open Briefing', + command: 'deadlock.openBriefing', +}; + +export const openQuickSetupCommand: Command = { + title: 'Open Deadlock quick setup page', + command: 'deadlock.openQuickSetup', +}; diff --git a/deadlock-plugins/deadlock-extension/src/core/gitMission.ts b/deadlock-plugins/deadlock-extension/src/core/gitMission.ts index ae085a23b6a5c2a722fced9b12a914d87fc55c13..090179977aee35aefc74bf80699ab398e71576ab 100644 --- a/deadlock-plugins/deadlock-extension/src/core/gitMission.ts +++ b/deadlock-plugins/deadlock-extension/src/core/gitMission.ts @@ -1,27 +1,24 @@ import { exec as execCallback } from 'child_process'; import simpleGit, { SimpleGit, SimpleGitOptions } from 'simple-git'; -import { PROJECT_SRC_PATH } from './config'; -import UserConfig from './userConfig'; +import { GITEA_PATH_IC } from './config'; import { log as customizableLog, error as customizableError } from '../recorder/utils/log'; import { promisify } from 'util'; +import UserMission from './mission/model/userMission'; +import ApiService from './api.service'; const exec = promisify(execCallback); const defaultRemote = 'origin'; -export enum Branch { - MASTER = 'master', - DEFAULT = MASTER, - LIVE = 'live', -} +type Branch = 'master' | 'live'; export default class GitMission { private prefix = 'DEADLOCK-RECORDER'; private git: SimpleGit; - constructor(private userConfig: UserConfig) { + constructor() { const options: Partial<SimpleGitOptions> = { - baseDir: PROJECT_SRC_PATH, + baseDir: GITEA_PATH_IC, binary: 'git', maxConcurrentProcesses: 2, }; @@ -39,10 +36,9 @@ export default class GitMission { async setupSshAgent() { try { + const gitea = await ApiService.getInstance().getGiteaPublicProperties(); await exec(`ssh-add /tmp/.ssh/id_rsa`); - await exec( - `eval "$(ssh-agent -s)" && ssh-keyscan -p ${this.userConfig.userConfigJson.giteaSshPort} -H ${this.userConfig.userConfigJson.giteaHost} >> ~/.ssh/known_hosts`, - ); + await exec(`eval "$(ssh-agent -s)" && ssh-keyscan -p ${gitea.sshPort} -H ${gitea.sshHost} >> ~/.ssh/known_hosts`); } catch (err) { this.log(err); if (err instanceof Error) { @@ -57,8 +53,8 @@ export default class GitMission { } } - get author() { - return this.userConfig.userConfigJson.username; + async getAuthor(): Promise<string> { + return (await UserMission.getInstance().getGiteaUser()).username; } async init() { @@ -73,22 +69,17 @@ export default class GitMission { return Promise.resolve(this); } - const remotePath = this.getRemotePath(); + const giteaUser = await UserMission.getInstance().getGiteaUser(); - await this.git.addRemote(defaultRemote, remotePath); - await this.git.addConfig('user.email', this.userConfig.userConfigJson.email, false, 'local'); + await this.git.addRemote(defaultRemote, await this.getRemotePath()); + await this.git.addConfig('user.email', await UserMission.getInstance().getEmail(), false, 'local'); await this.git.addConfig( 'user.name', - `${this.userConfig.userConfigJson.currentUserDetails.lastName} ${this.userConfig.userConfigJson.currentUserDetails.firstName}`, + `${giteaUser.details.lastName} ${giteaUser.details.firstName}`, false, 'local', ); - await this.git.addConfig( - 'core.excludesFile', - `user-git-${this.userConfig!.userConfigJson.username}/\n`, - true, - 'local', - ); + await this.git.addConfig('core.excludesFile', `user-git-${giteaUser.username}/\n`, true, 'local'); return Promise.resolve(this); } catch (e) { @@ -97,8 +88,11 @@ export default class GitMission { } } - private getRemotePath() { - return `ssh://git@${this.userConfig.userConfigJson.giteaHost}:${this.userConfig.userConfigJson.giteaSshPort}/${this.userConfig.userConfigJson.remoteGitUsername}/${this.userConfig.userConfigJson.missionId}`; + private async getRemotePath() { + const giteaConfig = await ApiService.getInstance().getGiteaPublicProperties(); + return `ssh://git@${giteaConfig.sshHost}:${giteaConfig.sshPort}/${ + (await UserMission.getInstance().getGiteaUser()).username + }/${UserMission.getInstance().missionId}`; } async readRemote() { @@ -114,8 +108,8 @@ export default class GitMission { return this.git.fetch(defaultRemote); } - pull(branch?: string) { - return this.git.pull(defaultRemote, branch ?? Branch.DEFAULT, { '--rebase': 'true' }); + pull(branch: Branch = 'master') { + return this.git.pull(defaultRemote, branch, { '--rebase': 'true' }); } addAll() { @@ -130,26 +124,26 @@ export default class GitMission { return this.git.push(defaultRemote); } - createLocalBranch(branch: string) { + createLocalBranch(branch: Branch = 'master') { return this.git.checkout(['-b', branch]); } - createRemoteBranch(branch: string) { + createRemoteBranch(branch: Branch = 'master') { return this.git.push(['-u', defaultRemote, branch]); } - setUpstream(branch: string) { + setUpstream(branch: Branch = 'master') { return this.git.branch(['-u', defaultRemote, branch]); } - createBranch(branch: string) { + createBranch(branch: Branch = 'master') { const createBranchLocally = this.createLocalBranch(branch); const createRemoteBranch = this.createRemoteBranch(branch); return Promise.all([createBranchLocally, createRemoteBranch]); } - checkout(branch: string) { + checkout(branch: Branch = 'master') { return this.git.checkout(branch); } diff --git a/deadlock-plugins/deadlock-extension/src/core/keycloakOAuth2DeviceFlowConnection.test.ts b/deadlock-plugins/deadlock-extension/src/core/keycloakOAuth2DeviceFlowConnection.test.ts index 3d97d9aaaf128e86afed34ff20533a39992a95ad..5f690680e760fcd019286f66df71552ae885f15d 100644 --- a/deadlock-plugins/deadlock-extension/src/core/keycloakOAuth2DeviceFlowConnection.test.ts +++ b/deadlock-plugins/deadlock-extension/src/core/keycloakOAuth2DeviceFlowConnection.test.ts @@ -1,5 +1,4 @@ import { Response } from 'node-fetch'; -import { KEYCLOAK_DEVICE_AUTH_URL, KEYCLOAK_TOKEN_CREATE_URL, KEYCLOAK_USER_INFO_URL } from '../config'; import KeycloakOAuth2DeviceFlowConnection from '../core/keycloakOAuth2DeviceFlowConnection'; import { setConnected, setPending, setRefused, test_token } from '../test/service/mocks/handlers'; @@ -51,10 +50,6 @@ describe('KeycloakOAuth2DeviceFlowConnection', () => { }); beforeEach(async () => { - connection = new KeycloakOAuth2DeviceFlowConnection( - KEYCLOAK_DEVICE_AUTH_URL, - KEYCLOAK_TOKEN_CREATE_URL, - KEYCLOAK_USER_INFO_URL, - ); + connection = new KeycloakOAuth2DeviceFlowConnection(); }); }); diff --git a/deadlock-plugins/deadlock-extension/src/core/keycloakOAuth2DeviceFlowConnection.ts b/deadlock-plugins/deadlock-extension/src/core/keycloakOAuth2DeviceFlowConnection.ts index c31dd69b76ecff4f0d91abbfa400393fbf526aa2..587f973416f5976fa3af5c2e99b1ba62b31791d3 100644 --- a/deadlock-plugins/deadlock-extension/src/core/keycloakOAuth2DeviceFlowConnection.ts +++ b/deadlock-plugins/deadlock-extension/src/core/keycloakOAuth2DeviceFlowConnection.ts @@ -1,7 +1,12 @@ import * as https from 'https'; import { Response } from 'node-fetch'; import fetch from 'node-fetch'; -import { REJECT_UNAUTHORIZED } from '../config'; +import { + KEYCLOAK_DEVICE_AUTH_URL, + KEYCLOAK_TOKEN_CREATE_URL, + KEYCLOAK_USER_INFO_URL, + REJECT_UNAUTHORIZED, +} from '../config'; import { HttpStatusCode } from '../customTypings/HttpStatusCode'; import { TokenFetchErrorCode } from '../customTypings/KeycloakAPITypes'; import { extensionError as err, extensionLog as log } from '../recorder/utils/log'; @@ -13,8 +18,9 @@ export default class KeycloakOAuth2DeviceFlowConnection { private accessToken: string; private refreshToken: string; private deviceAuthorizationRequestResponse: DeviceAuthorizationRequestResponse; + private static _instance: KeycloakOAuth2DeviceFlowConnection; - constructor(private deviceUrl: string, private tokenUrl: string, private userInfoUrl: string) { + constructor() { /* * Arbitrary durations to wait in seconds \ * Waiting time between requests should be increasing @@ -29,6 +35,13 @@ export default class KeycloakOAuth2DeviceFlowConnection { this.deviceAuthorizationRequestResponse = {}; } + public static getInstance(): KeycloakOAuth2DeviceFlowConnection { + if (!KeycloakOAuth2DeviceFlowConnection._instance) { + KeycloakOAuth2DeviceFlowConnection._instance = new KeycloakOAuth2DeviceFlowConnection(); + } + return KeycloakOAuth2DeviceFlowConnection._instance; + } + /** * @param accessToken * @returns Promise @@ -37,7 +50,8 @@ export default class KeycloakOAuth2DeviceFlowConnection { if (!accessToken) { return Promise.resolve(false); } - const tokenValidationRequestResponse: Response = await fetch(this.userInfoUrl, { + + const tokenValidationRequestResponse: Response = await fetch(KEYCLOAK_USER_INFO_URL, { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', @@ -71,7 +85,7 @@ export default class KeycloakOAuth2DeviceFlowConnection { if (refreshToken !== undefined) { await this.createUserAuthentication( { - url: this.tokenUrl, + url: KEYCLOAK_TOKEN_CREATE_URL, body: (() => { const params = new URLSearchParams(); params.append('response_type', 'token'); @@ -93,7 +107,7 @@ export default class KeycloakOAuth2DeviceFlowConnection { openLink(this.deviceAuthorizationRequestResponse.verification_uri_complete!); await this.createUserAuthentication( { - url: this.tokenUrl, + url: KEYCLOAK_TOKEN_CREATE_URL, body: (() => { const params = new URLSearchParams(); params.append('response_type', 'token'); @@ -118,7 +132,7 @@ export default class KeycloakOAuth2DeviceFlowConnection { public async registerDevice() { log('Device not registered. Registering ...'); const deviceAuthorizationRequestResponse: Response = await this.createDeviceAuthorization({ - url: this.deviceUrl, + url: KEYCLOAK_DEVICE_AUTH_URL, body: (() => { const params = new URLSearchParams(); params.append('client_id', 'deadlock-desktop'); diff --git a/deadlock-plugins/deadlock-extension/src/core/mission/missionDevContainer.ts b/deadlock-plugins/deadlock-extension/src/core/mission/missionDevContainer.ts index 0dddfb60b0b3e96a7d31cf43ac2eeab878a58280..edfbe815bd98fc8cfa9530a9fa359d3e751aca67 100644 --- a/deadlock-plugins/deadlock-extension/src/core/mission/missionDevContainer.ts +++ b/deadlock-plugins/deadlock-extension/src/core/mission/missionDevContainer.ts @@ -1,15 +1,16 @@ import { missionWorkdir, userSshKeyFolderPath } from '../config'; import { Base, DockerfileSpecific, LifecycleScripts, VSCodespecific } from './model/devContainer'; -import { mkdir, writeFile } from 'fs/promises'; -import { GiteaPublicProperties } from '../../model/giteaPublicProperties.model'; +import { writeFile } from 'fs/promises'; import { commands, Uri, window } from 'vscode'; import { existsSync, copyFileSync } from 'fs'; import { join } from 'path'; -import assert = require('assert'); -import UserMission, { User } from './model/userMission'; +import UserMission from './model/userMission'; import { REGISTRY_MISSION_URL } from '../../config'; import { getReviewedStudentWorkdirPath } from '../utils/mission.utils'; +import { homedir } from 'os'; +import { extensionError } from '../../recorder/utils/log'; +import { createDirectories } from '../../recorder/utils/workdir'; const remoteUserHomeDir = '/home/deadlock'; const remoteMissionDir = `${remoteUserHomeDir}/mission/`; @@ -30,31 +31,27 @@ export class MissionDevContainer { private readonly dirs: { missionWorkdir: string; - config: string; devcontainer: string; mounted: string; solution: string; }; constructor( - private readonly user: User, - private readonly currentUser: User, private readonly missionId: string, private readonly missionVersion: string, - private readonly giteaProperties: GiteaPublicProperties, + private readonly revieweeId?: string, ) { let prefix: string; - if (this.isReviewingStudent()) { - prefix = getReviewedStudentWorkdirPath(this.user.id); + if (revieweeId) { + prefix = getReviewedStudentWorkdirPath(revieweeId); } else { prefix = `${missionWorkdir}`; } this.dirs = { - missionWorkdir: `${prefix}/${this.missionId}`, - config: `${prefix}/${this.missionId}/.config`, - devcontainer: `${prefix}/${this.missionId}/.devcontainer`, - mounted: `${prefix}/${this.missionId}/mounted`, - solution: `${prefix}/${this.missionId}/.solution`, + missionWorkdir: `${prefix}/${missionId}`, + devcontainer: `${prefix}/${missionId}/.devcontainer`, + mounted: `${prefix}/${missionId}/mounted`, + solution: `${prefix}/${missionId}/.solution`, }; if (process.env.DL_MOUNT_EXTENSION === 'true') { this.extentionPath = '/injected-extension/extension.vsix'; @@ -67,7 +64,6 @@ export class MissionDevContainer { if (!this.isInit) { await this.init(); } - assert(existsSync(this.dirs.missionWorkdir)); await commands.executeCommand('remote-containers.openFolder', Uri.file(this.dirs.missionWorkdir)); } @@ -77,7 +73,7 @@ export class MissionDevContainer { } this.isInit = true; try { - await this.createDirectories(...Object.values(this.dirs)); + await createDirectories(...Object.values(this.dirs)); await this.createDevContainerFile(); await this.createUserChallengeJsonFile(); } catch (e) { @@ -86,40 +82,19 @@ export class MissionDevContainer { } } - private isReviewingStudent() { - return this.currentUser.id !== this.user.id; - } - private async createUserChallengeJsonFile() { - return writeFile( - `${this.dirs.config}/user-challenge.json`, - (() => { - const username = this.user.id.split('-').join(''); - const userChallengeJson: UserMission = { - giteaHost: this.giteaProperties.sshHost, - userId: this.user.id, - giteaSshPort: this.giteaProperties.sshPort, - username, - email: `${username}@deadlock.io`, - missionId: this.missionId, - missionVersion: this.missionVersion, - remoteGitUsername: username, - currentUserDetails: this.currentUser.details, - currentUserId: this.currentUser.id, - remoteUserDetails: this.user.details, - }; - return JSON.stringify(userChallengeJson, null, 2); - })(), - ); + try { + await UserMission.writeFile(this.missionId, this.missionVersion, this.revieweeId); + } catch (e) { + extensionError(e); + window.showErrorMessage(`Une erreur est survenue lors de la création du fichier userChallenge.json`); + } } private addInMountRCs(tempFolder: string, ...rcs: string[]): void { - if (process.env.HOME === undefined) { - throw new Error('HOME environment variable is not defined'); - } for (const rc of rcs) { if (existsSync(rc)) { - const rcPath = join(process.env.HOME, rc); + const rcPath = join(homedir(), rc); const tempRC = join(tempFolder, rc); const mountRC = join(remoteUserHomeDir, rc); copyFileSync(rcPath, tempRC); @@ -132,14 +107,17 @@ export class MissionDevContainer { this.mounts.splice(0, this.mounts.length); this.mounts.push( `source=${userSshKeyFolderPath},target=/tmp/.ssh,type=bind,consistency=cached,readonly`, - `source=${this.dirs.config},target=/home/config/,type=bind,consistency=cached,readonly`, + `source=${UserMission.getMissionUserFolder( + this.missionId, + this.revieweeId, + )},target=/home/config/,type=bind,consistency=cached,readonly`, 'source=/etc/hosts,target=/etc/hosts,type=bind,consistency=cached,readonly', ); if (process.env.DL_MOUNT_EXTENSION === 'true') { this.mounts.push(`source=${process.env.EXTENSION_PATH},target=${this.extentionPath},type=bind`); } this.addInMountRCs(this.dirs.missionWorkdir, '.bashrc', '.zshrc'); - if (this.isReviewingStudent()) { + if (this.revieweeId) { this.mounts.push(`source=${this.dirs.solution},target=${remoteMissionDir}/solution,type=bind`); } } @@ -175,8 +153,4 @@ export class MissionDevContainer { })(), ); } - - private createDirectories(...directoryPaths: string[]) { - return Promise.all(directoryPaths.map((directoryPath) => mkdir(directoryPath, { recursive: true }))); - } } diff --git a/deadlock-plugins/deadlock-extension/src/core/mission/model/userMission.ts b/deadlock-plugins/deadlock-extension/src/core/mission/model/userMission.ts index 063223991ec168e14fe2feb0a44130cead1d8683..95676b0972a3fe69774190b7e30d25c6ee892775 100644 --- a/deadlock-plugins/deadlock-extension/src/core/mission/model/userMission.ts +++ b/deadlock-plugins/deadlock-extension/src/core/mission/model/userMission.ts @@ -1,18 +1,82 @@ -interface UserMission { - giteaHost: string; - giteaSshPort: number; - userId: string; - username: string; - currentUserId: string; - email: string; +import { readFileSync } from 'fs'; +import { writeFile } from 'fs/promises'; +import { join } from 'path'; +import { createDirectories } from '../../../recorder/utils/workdir'; +import ApiService from '../../api.service'; +import { missionWorkdir, USER_MISSION_PATH } from '../../config'; +import { getReviewedStudentWorkdirPath } from '../../utils/mission.utils'; + +interface UserMissionModel { missionId: string; missionVersion: string; - remoteGitUsername: string; - currentUserDetails: UserDetails; - remoteUserDetails: UserDetails; + reviewee?: User; } -export default UserMission; +export default class UserMission implements UserMissionModel { + private static _instance: UserMission; + + private constructor(userMission: UserMissionModel) { + this.missionId = userMission.missionId; + this.missionVersion = userMission.missionVersion; + this.reviewee = userMission.reviewee; + UserMission._instance = this; + } + + public static getInstance(): UserMission { + if (!UserMission._instance) { + return (this._instance = new UserMission(JSON.parse(readFileSync(USER_MISSION_PATH, 'utf8')))); + } + return UserMission._instance; + } + + private get apiService(): ApiService { + return ApiService.getInstance(); + } + + public async getGiteaUser(): Promise<User & { username: string }> { + const giteaUser: User & { username?: string } = this.reviewee ?? (await this.apiService.getCurrentUser()); + return { ...giteaUser, username: giteaUser.id.split('-').join('') }; + } + + public async getEmail(): Promise<string> { + return `${(await this.getGiteaUser()).username}@deadlock.io`; + } + + public readonly missionId: string; + public readonly missionVersion: string; + public readonly reviewee?: User; + + public static getMissionUserFolder(missionId: string, revieweeId?: string): string { + return join(revieweeId ? getReviewedStudentWorkdirPath(revieweeId) : missionWorkdir, missionId, '.config'); + } + + public static async writeFile(missionId: string, missionVersion: string, revieweeId?: string): Promise<void> { + const workdir = this.getMissionUserFolder(missionId, revieweeId); + await createDirectories(workdir); + const user = await ApiService.getInstance().getCurrentUser(); + const username = (revieweeId ?? user.id).split('-').join(''); + const path = join(workdir, 'user-challenge.json'); + await writeFile( + path, + JSON.stringify( + { + username, + email: `${username}@deadlock.io`, + missionId, + missionVersion, + remoteGitUsername: username, + reviewee: revieweeId ? await ApiService.getInstance().getUser(revieweeId) : undefined, + } as UserMissionModel, + null, + 2, + ), + ); + } + + public isReviewing(): boolean { + return !!this.reviewee; + } +} export interface UserDetails { id: string; @@ -31,10 +95,3 @@ export interface User { id: string; details: UserDetails; } - -export function isReviewingStudent(userMission: UserMission) { - return ( - userMission.remoteGitUsername !== userMission.username && - (userMission.currentUserDetails.roles.has('PROFESSOR') || userMission.currentUserDetails.roles.has('ADMIN')) - ); -} diff --git a/deadlock-plugins/deadlock-extension/src/core/userConfig.ts b/deadlock-plugins/deadlock-extension/src/core/userConfig.ts deleted file mode 100644 index 30f705760515891e7b104daf7ae1ae4290ab2701..0000000000000000000000000000000000000000 --- a/deadlock-plugins/deadlock-extension/src/core/userConfig.ts +++ /dev/null @@ -1,38 +0,0 @@ -/** - * Example: - * { - * "paths": { - * "9090":"HXW3fnKwUULrfKS1-cdb", - * "3000":"HXW3fnKwUULrfKS1-web", - * "8080":"HXW3fnKwUULrfKS1-angular" - * }, - * "host":"dev.deadlock.io", - * "token":"e75da487-9576-4427-be2d-8da4059adc7d", - * "giteaHost":"deadlock.minikube", - * "giteaSshPort":32000, - * "username":"slayug", - * "missionId":"code_persist_cdb_crud" - * } - */ -import { Uri, workspace } from 'vscode'; -import { recorderError as error } from '../recorder/utils/log'; -import { USER_CHALLENGE_PATH } from './config'; -import UserMission from './mission/model/userMission'; - -export default class UserConfig { - private _userConfigJson?: UserMission; - - async init() { - try { - const textDocument = await workspace.openTextDocument(Uri.parse(USER_CHALLENGE_PATH)); - this._userConfigJson = JSON.parse(textDocument.getText()); - } catch (e) { - error(`Error loading user config: ${e}`); - throw e; - } - } - - get userConfigJson(): UserMission { - return this._userConfigJson!; - } -} diff --git a/deadlock-plugins/deadlock-extension/src/core/utils/mission.utils.ts b/deadlock-plugins/deadlock-extension/src/core/utils/mission.utils.ts index edb8400ddb479d80c011c594a022b6de4b9020ce..8238c3a78c585139b4badc5f00fbcb2132b9c52c 100644 --- a/deadlock-plugins/deadlock-extension/src/core/utils/mission.utils.ts +++ b/deadlock-plugins/deadlock-extension/src/core/utils/mission.utils.ts @@ -1,6 +1,6 @@ import { PathLike, readFileSync } from 'fs'; import { join } from 'path'; -import { missionWorkdir, USER_CHALLENGE_PATH } from '../config'; +import { missionWorkdir, USER_MISSION_PATH } from '../config'; import UserMission from '../mission/model/userMission'; import isDocker from './isdocker'; @@ -11,7 +11,7 @@ export function getReviewedStudentWorkdirPath(userId: string): string { export function getUserChallenge(userId: string, missionid: string, isReviewing = false): UserMission { let path: number | PathLike; if (isDocker()) { - path = USER_CHALLENGE_PATH; + path = USER_MISSION_PATH; } else if (isReviewing) { path = join(getReviewedStudentWorkdirPath(userId), missionid, '.config', 'userChallenge.json'); } else { diff --git a/deadlock-plugins/deadlock-extension/src/extension.ts b/deadlock-plugins/deadlock-extension/src/extension.ts index 4a2b288c90a43cf0846aaf7cf5870665972a917b..29abd15f0646e09b24554bea29ee9ba38003652d 100644 --- a/deadlock-plugins/deadlock-extension/src/extension.ts +++ b/deadlock-plugins/deadlock-extension/src/extension.ts @@ -1,28 +1,12 @@ import { window, ExtensionContext, workspace, commands } from 'vscode'; import Controller from './core/controller'; -import UserConfig from './core/userConfig'; import isDocker from './core/utils/isdocker'; -import Recorder from './recorder/recorder'; +import Recorder, { runTimer } from './recorder/recorder'; import { extensionError as error } from './recorder/utils/log'; -import { DepNodeProvider } from './theia/deadlockPanel'; +import { DepNodeProvider } from './view/deadlockPanel'; import { CommandTreeProvider } from './view/CommandTree'; import StartedMissionsView from './view/startedMissionsView'; -export const userConfig = new UserConfig(); - -export async function runTimer(userId: string, missionId: string, context: ExtensionContext) { - const apiService = Controller.getInstance(context).apiService; - try { - await apiService.startUpdateWorkTime(userId, missionId); - setInterval(async () => { - await apiService.pingUpdateWorkTime(userId, missionId); - }, 60000); // 1 minute - } catch (e) { - window.showErrorMessage(`Erreur lors de l'enregistrement du temps de travail`); - error(JSON.stringify(e)); - } -} - export async function activate(context: ExtensionContext) { window.showInformationMessage('Bienvenue sur Deadlock!'); Controller.getInstance(context); @@ -39,12 +23,6 @@ export async function activate(context: ExtensionContext) { } else { commands.executeCommand('setContext', 'deadlock.inContainer', false); } - try { - await userConfig.init(); - } catch (e) { - error(JSON.stringify(e)); - error('Cannot init userConfig'); - } if (isDocker()) { try { Recorder.instance.run(); @@ -53,6 +31,6 @@ export async function activate(context: ExtensionContext) { error(JSON.stringify(e)); window.showErrorMessage("Le recorder n'a pas pu être lancé"); } - runTimer(userConfig.userConfigJson.currentUserId, userConfig.userConfigJson.missionId, context); + runTimer(); } } diff --git a/deadlock-plugins/deadlock-extension/src/recorder/recorder.ts b/deadlock-plugins/deadlock-extension/src/recorder/recorder.ts index 192ff3235d9ae4fdcc8b2aaf6930509c17d928d1..a1fe2de133dc9ab5a3b25543a3d09551e465ce78 100644 --- a/deadlock-plugins/deadlock-extension/src/recorder/recorder.ts +++ b/deadlock-plugins/deadlock-extension/src/recorder/recorder.ts @@ -1,19 +1,22 @@ -import { Branch } from '../core/gitMission'; import { ENABLE_AUTOMATIC_SAVE } from '../config'; import GitMission from '../core/gitMission'; -import UserConfigNode from './userConfigNode'; -import { PROJECT_DEADLOCK_DESKTOP_PATH, PROJECT_SRC_PATH } from '../core/config'; +import { MISSION_PATH_IC, GITEA_PATH_IC } from '../core/config'; import { recorderError as error } from './utils/log'; -import UserConfig from '../core/userConfig'; import AutomaticSave from './services/automatic-save'; import { clearFilesExceptGit, copyProjectSources, renameTempToUserGitFiles } from './utils/workdir'; import aquirePermissions from './utils/permission'; -import { isReviewingStudent } from '../core/mission/model/userMission'; +import UserMission from '../core/mission/model/userMission'; +import ApiService from '../core/api.service'; +import { window } from 'vscode'; + export default class Recorder { private _gitMission?: GitMission; - private userConfig?: UserConfigNode; private static _instance?: Recorder; + private get userMission(): UserMission { + return UserMission.getInstance(); + } + private constructor() { Recorder._instance = this; } @@ -26,26 +29,18 @@ export default class Recorder { } public get gitMission(): GitMission { - // TODO refactor remove ! return this._gitMission!; } - async setupProject(userConfig: UserConfig, gitMission?: GitMission) { - if (!isReviewingStudent(userConfig.userConfigJson)) { - await copyProjectSources(PROJECT_SRC_PATH, PROJECT_DEADLOCK_DESKTOP_PATH, [ - '.git/', - `user-git-${userConfig.userConfigJson.username}`, - ]); - - if (gitMission) { - renameTempToUserGitFiles(PROJECT_DEADLOCK_DESKTOP_PATH, gitMission.author); - } else { - error('Cannot start command recorder, gitMission not found'); - } - } else { - await copyProjectSources(PROJECT_SRC_PATH, PROJECT_DEADLOCK_DESKTOP_PATH, [ - `user-git-${userConfig.userConfigJson.username}`, - ]); + async setupProject(gitMission: GitMission) { + await copyProjectSources( + GITEA_PATH_IC, + MISSION_PATH_IC, + '.git', + `user-git-${(await this.userMission.getGiteaUser()).username}`, + ); + if (!this.userMission.isReviewing()) { + renameTempToUserGitFiles(MISSION_PATH_IC, await gitMission.getAuthor()); } } @@ -53,30 +48,27 @@ export default class Recorder { const isRemoteRepoExist = await gitMission.isRemoteRepoExist(); if (isRemoteRepoExist) { // rm all except git directory pull remote code and setup - await clearFilesExceptGit(PROJECT_SRC_PATH); + await clearFilesExceptGit(GITEA_PATH_IC); await gitMission.fetch(); - await gitMission.checkout(Branch.MASTER); - await gitMission.checkout(Branch.LIVE); + await gitMission.checkout('master'); + await gitMission.checkout('live'); } else { await gitMission.commit('initial commit', ['--allow-empty']); - await gitMission.createRemoteBranch(Branch.DEFAULT); - await gitMission.createBranch(Branch.LIVE); + await gitMission.createRemoteBranch(); + await gitMission.createBranch('live'); } } async run() { - this.userConfig = new UserConfigNode(); - try { await aquirePermissions(); // TODO refactor remove this - await this.userConfig.init(); - this._gitMission = await new GitMission(this.userConfig).init(); + this._gitMission = await new GitMission().init(); await this.setupFromRemoteRepo(this._gitMission); - await this.setupProject(this.userConfig, this._gitMission); + await this.setupProject(this._gitMission); try { - if (ENABLE_AUTOMATIC_SAVE) new AutomaticSave(PROJECT_DEADLOCK_DESKTOP_PATH, this._gitMission); + if (ENABLE_AUTOMATIC_SAVE) new AutomaticSave(MISSION_PATH_IC, this._gitMission); } catch (e) { error('Error while setup automatic save'); error(e); @@ -87,3 +79,16 @@ export default class Recorder { } } } + +export async function runTimer() { + const apiService = ApiService.getInstance(); + try { + await apiService.startUpdateWorkTime(); + setInterval(async () => { + await apiService.pingUpdateWorkTime(); + }, 60000); // 1 minute + } catch (e) { + window.showErrorMessage(`Erreur lors de l'enregistrement du temps de travail`); + error(JSON.stringify(e)); + } +} diff --git a/deadlock-plugins/deadlock-extension/src/recorder/userConfigNode.ts b/deadlock-plugins/deadlock-extension/src/recorder/userConfigNode.ts deleted file mode 100644 index 025deb64fa4404ca13b7c0924a24a21fc38dcdb9..0000000000000000000000000000000000000000 --- a/deadlock-plugins/deadlock-extension/src/recorder/userConfigNode.ts +++ /dev/null @@ -1,11 +0,0 @@ -import UserConfig from '../core/userConfig'; -import { USER_CHALLENGE_PATH } from '../core/config'; -import { readFileSync } from 'fs'; - -export default class UserConfigNode extends UserConfig { - async loadText(): Promise<string> { - const text = readFileSync(USER_CHALLENGE_PATH, 'utf8'); - - return Promise.resolve(text); - } -} diff --git a/deadlock-plugins/deadlock-extension/src/recorder/utils/gitea.ts b/deadlock-plugins/deadlock-extension/src/recorder/utils/gitea.ts index 0a600f631ffa712caea3a09281c7fcbeeb7236cd..c0b98092c7a415dcba2e5af4bdd12da0fd87a3aa 100644 --- a/deadlock-plugins/deadlock-extension/src/recorder/utils/gitea.ts +++ b/deadlock-plugins/deadlock-extension/src/recorder/utils/gitea.ts @@ -1,6 +1,5 @@ -import { Branch } from '../../core/gitMission'; import GitMission from '../../core/gitMission'; -import { DEADLOCK_WORKDIR_PATH, PROJECT_DEADLOCK_DESKTOP_PATH, PROJECT_SRC_PATH } from '../../core/config'; +import { DEADLOCK_WORKDIR_PATH, MISSION_PATH_IC, GITEA_PATH_IC } from '../../core/config'; import { format } from 'date-fns'; import { execSync } from 'child_process'; import { existsSync, promises } from 'fs'; @@ -31,15 +30,13 @@ export async function commitAndPushOnQueue(gitMission: GitMission, from: 'Run' | async function commitAndPushCode(gitMission: GitMission) { try { - await gitMission.checkout(Branch.LIVE); - await clearFilesExceptGit(PROJECT_SRC_PATH); + await gitMission.checkout('live'); + await clearFilesExceptGit(GITEA_PATH_IC); - copyGitUserFiles(PROJECT_DEADLOCK_DESKTOP_PATH, PROJECT_SRC_PATH, gitMission.author); - execSync( - `rsync -r --exclude .git --exclude node_modules --exclude target ${PROJECT_DEADLOCK_DESKTOP_PATH}/* ${PROJECT_SRC_PATH}`, - ); + copyGitUserFiles(MISSION_PATH_IC, GITEA_PATH_IC, await gitMission.getAuthor()); + execSync(`rsync -r --exclude .git --exclude node_modules --exclude target ${MISSION_PATH_IC}/* ${GITEA_PATH_IC}`); if (existsSync(join(DEADLOCK_WORKDIR_PATH, '.gitignore'))) { - await copyFile(join(DEADLOCK_WORKDIR_PATH, '.gitignore'), join(PROJECT_SRC_PATH, '.gitignore')); + await copyFile(join(DEADLOCK_WORKDIR_PATH, '.gitignore'), join(GITEA_PATH_IC, '.gitignore')); } const currentDate = format(new Date(), "HH'H'mm'_'dd/LL/y"); @@ -65,12 +62,12 @@ async function mergeMaster(gitMission: GitMission) { const currentDate = format(new Date(), "HH'H'mm'_'dd/LL/y"); - await gitMission.checkout(Branch.DEFAULT); - await gitMission.merge(['--squash', '-X', 'theirs', Branch.LIVE]); + await gitMission.checkout(); + await gitMission.merge(['--squash', '-X', 'theirs', 'live']); await gitMission.commit(currentDate); await gitMission.push(); log('Merge to master done'); - await gitMission.checkout(Branch.LIVE); + await gitMission.checkout('live'); } catch (e) { if (e instanceof GitError) { error(`[${e.task?.commands}] cannot commitAndPush`); diff --git a/deadlock-plugins/deadlock-extension/src/recorder/utils/permission.ts b/deadlock-plugins/deadlock-extension/src/recorder/utils/permission.ts index 2d507d5af6e93ea25dc6d86a2be3e6d56404f9fc..6ad541f556114e89549dda294079b4c6dbaa7dbd 100644 --- a/deadlock-plugins/deadlock-extension/src/recorder/utils/permission.ts +++ b/deadlock-plugins/deadlock-extension/src/recorder/utils/permission.ts @@ -1,10 +1,10 @@ import { exec as execCallback } from 'child_process'; import { userInfo } from 'os'; import { promisify } from 'util'; -import { PROJECT_SRC_PATH } from '../../core/config'; +import { GITEA_PATH_IC } from '../../core/config'; const exec = promisify(execCallback); export default async function aquirePermissions() { - await exec(`sudo chown -R ${userInfo().username} ${PROJECT_SRC_PATH}`); + await exec(`sudo chown -R ${userInfo().username} ${GITEA_PATH_IC}`); } diff --git a/deadlock-plugins/deadlock-extension/src/recorder/utils/workdir.ts b/deadlock-plugins/deadlock-extension/src/recorder/utils/workdir.ts index c446bebaa442c49776c19486b48208ed9fddf1f1..acb35be4f28d154d6ed6db0078c3f4271c70ad80 100644 --- a/deadlock-plugins/deadlock-extension/src/recorder/utils/workdir.ts +++ b/deadlock-plugins/deadlock-extension/src/recorder/utils/workdir.ts @@ -8,15 +8,9 @@ import { mkdir, rm } from 'fs/promises'; const exec = promisify(execCallback); const PREFIX = '[DEADLOCK-RECORDER]'; -export async function copyProjectSources( - srcPath: string, - userMissionWorkdirPath: string, - excludes: Array<string> = [], -) { +export async function copyProjectSources(src: string, target: string, ...excludes: Array<string>) { const excludeCmd = excludes.map((current) => `--exclude ${current}`).join(' '); - return await exec( - `sudo rsync -a ${srcPath}/ ${userMissionWorkdirPath} ${excludeCmd} && sudo chown -R deadlock:deadlock /home/deadlock`, - ); + return await exec(`sudo rsync -a ${src}/ ${target} ${excludeCmd} && sudo chown -R deadlock:deadlock /home/deadlock`); } export async function clearFilesExceptGit(path: string) { @@ -57,11 +51,11 @@ function copyFolderIfExistsSync(srcPath: PathLike, destPath: PathLike) { * Rename temporary git files back to actual git files. * * @param path Path of the folder containing user's temporary git project files. - * @param userId Identifier used to create the temporary files name + * @param username Identifier used to create the temporary files name */ -export function renameTempToUserGitFiles(path: string, userId: string) { - renameIfExistsSync(join(path, `user-git-${userId}`), join(path, '.git')); - renameIfExistsSync(join(path, `user-gitignore-${userId}`), join(path, '.gitignore')); +export function renameTempToUserGitFiles(path: string, username: string) { + renameIfExistsSync(join(path, `user-git-${username}`), join(path, '.git')); + renameIfExistsSync(join(path, `user-gitignore-${username}`), join(path, '.gitignore')); } /** @@ -71,11 +65,11 @@ export function renameTempToUserGitFiles(path: string, userId: string) { * * @param srcPath Path of the folder containing user's git project files to be saved. * @param destPath Path where the user's git project files should be pasted. - * @param userId Identifier used to create the temporary files name + * @param username Identifier used to create the temporary files name */ -export function copyGitUserFiles(srcPath: string, destPath: string, userId: string) { - copyFolderIfExistsSync(join(srcPath, '.git'), join(destPath, `user-git-${userId}`)); - copyFileIfExistsSync(join(srcPath, '.gitignore'), join(destPath, `user-gitignore-${userId}`)); +export function copyGitUserFiles(srcPath: string, destPath: string, username: string) { + copyFolderIfExistsSync(join(srcPath, '.git'), join(destPath, `user-git-${username}`)); + copyFileIfExistsSync(join(srcPath, '.gitignore'), join(destPath, `user-gitignore-${username}`)); } export async function removeFilesOrDirectories(...paths: string[]) { @@ -90,3 +84,7 @@ export async function emptyDirectories(...directoryPaths: string[]) { await mkdir(directoryPath); } } + +export async function createDirectories(...directoryPaths: string[]) { + return Promise.all(directoryPaths.map((directoryPath) => mkdir(directoryPath, { recursive: true }))); +} diff --git a/deadlock-plugins/deadlock-extension/src/theia/command.ts b/deadlock-plugins/deadlock-extension/src/theia/command.ts deleted file mode 100644 index f785eb10101000de8879e5fd68626b5c6a74d388..0000000000000000000000000000000000000000 --- a/deadlock-plugins/deadlock-extension/src/theia/command.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { Command as VscodeComand } from 'vscode'; - -export class VsCommand { - constructor(private _title: string, private command: string) {} - - get title() { - return this._title; - } - - get cmd() { - return this.command; - } - - asVsCodeCommand(): VscodeComand { - return { title: this.title, command: this.cmd }; - } -} - -export const openBriefingCommand = new VsCommand('Open Briefing', 'deadlock.openBriefing'); -export const openQuickSetupCommand = new VsCommand('Open Deadlock quick setup page', 'deadlock.openQuickSetup'); diff --git a/deadlock-plugins/deadlock-extension/src/view/CommandTree.ts b/deadlock-plugins/deadlock-extension/src/view/CommandTree.ts index 9edb00cea6ccc2aebc732af93831eaad24d17702..78640e7889efbfe3db1e54da7a603bb6321fa473 100644 --- a/deadlock-plugins/deadlock-extension/src/view/CommandTree.ts +++ b/deadlock-plugins/deadlock-extension/src/view/CommandTree.ts @@ -50,11 +50,13 @@ class CommandItem extends TreeItem { }; commands.registerCommand(missionCommand.name, () => { if (missionCommand.type === 'submit') { - window.showInformationMessage('Êtes-vous sûr de soumettre votre solution ?', 'Oui', 'Non').then((answer) => { - if (answer === 'Oui') { - this.apply(); - } - }); + window + .showInformationMessage('Êtes-vous sûr de soumettre votre solution ?', { modal: true }, 'Oui', 'Non') + .then((answer) => { + if (answer === 'Oui') { + this.apply(); + } + }); } else { this.apply(); } diff --git a/deadlock-plugins/deadlock-extension/src/view/briefingView.ts b/deadlock-plugins/deadlock-extension/src/view/briefingView.ts index 9d8b40c2b454d4bf0749b91da81979c0795ec814..ae6dfaf5a7f4b25dd89388998e0831c778a18274 100644 --- a/deadlock-plugins/deadlock-extension/src/view/briefingView.ts +++ b/deadlock-plugins/deadlock-extension/src/view/briefingView.ts @@ -3,11 +3,11 @@ import { marked } from 'marked'; import { join } from 'path'; import { setInterval } from 'timers'; import { Uri, workspace } from 'vscode'; -import { BRIEFING_FILE_NAME, DOCS_PATH } from '../core/config'; -import { isReviewingStudent } from '../core/mission/model/userMission'; +import ApiService from '../core/api.service'; +import { BRIEFING_FILE_NAME, DOCS_PATH_IC } from '../core/config'; +import { openBriefingCommand } from '../core/controller'; +import UserMission from '../core/mission/model/userMission'; import isDocker from '../core/utils/isdocker'; -import { userConfig } from '../extension'; -import { openBriefingCommand } from '../theia/command'; import { WebviewBase } from './webviewBase'; export const briefingId = 'brefingView'; @@ -23,7 +23,7 @@ export default class BriefingView extends WebviewBase { } toBase64(file: string) { - const result = readFileSync(join(DOCS_PATH, file), { + const result = readFileSync(join(DOCS_PATH_IC, file), { encoding: 'base64', }); return result; @@ -47,7 +47,7 @@ export default class BriefingView extends WebviewBase { this.loadingBriefing = true; clearInterval(intervalId); - workspace.openTextDocument(Uri.parse(join(DOCS_PATH, BRIEFING_FILE_NAME))).then( + workspace.openTextDocument(Uri.parse(join(DOCS_PATH_IC, BRIEFING_FILE_NAME))).then( (document) => { try { this.briefingContent = this.setupImages(document.getText()); @@ -66,13 +66,17 @@ export default class BriefingView extends WebviewBase { }, 500); } - render() { + async render() { let output = ''; - if (isReviewingStudent(userConfig.userConfigJson)) { + const missionUser = UserMission.getInstance(); + + if (missionUser.isReviewing()) { + const user = await ApiService.getInstance().getCurrentUser(); + const giteaUser = await missionUser.getGiteaUser(); output += ` <h2>Professeur</h2> - Bonjour ${userConfig.userConfigJson.currentUserDetails.lastName} ${userConfig.userConfigJson.currentUserDetails.firstName} vous êtes actuellement entrain de relire le code de <b>${userConfig.userConfigJson.currentUserDetails.lastName} ${userConfig.userConfigJson.currentUserDetails.firstName}</b>.<br /> + Bonjour <b>${user.details.lastName} ${user.details.firstName}</b> vous êtes actuellement entrain de relire le code de <b>${giteaUser.details.lastName} ${giteaUser.details.firstName}</b>.<br /> Vous pouvez consulter chaque exécution de son code dans l'onglet à gauche de GitLens. Chaque commit sur <b>master</b> représente une exécution. <br /> `; diff --git a/deadlock-plugins/deadlock-extension/src/theia/deadlockPanel.ts b/deadlock-plugins/deadlock-extension/src/view/deadlockPanel.ts similarity index 88% rename from deadlock-plugins/deadlock-extension/src/theia/deadlockPanel.ts rename to deadlock-plugins/deadlock-extension/src/view/deadlockPanel.ts index f8a48cb423f5f66be71746cf96d8a2895190aef4..d41de08c45ec1750239b072c45f3587de90266e2 100644 --- a/deadlock-plugins/deadlock-extension/src/theia/deadlockPanel.ts +++ b/deadlock-plugins/deadlock-extension/src/view/deadlockPanel.ts @@ -1,6 +1,6 @@ import { join } from 'path'; import { Command, Event, EventEmitter, TreeDataProvider, TreeItem, TreeItemCollapsibleState } from 'vscode'; -import { openBriefingCommand } from './command'; +import { openBriefingCommand } from '../core/controller'; const documentationLabel = 'Documentation'; @@ -25,9 +25,7 @@ export class DepNodeProvider implements TreeDataProvider<Action> { if (!element) { return Promise.resolve(this.root()); } else if (element.label === documentationLabel) { - return Promise.resolve([ - new Action('Briefing', TreeItemCollapsibleState.None, 'document', openBriefingCommand.asVsCodeCommand()), - ]); + return Promise.resolve([new Action('Briefing', TreeItemCollapsibleState.None, 'document', openBriefingCommand)]); } return Promise.resolve([]); diff --git a/deadlock-plugins/deadlock-extension/src/view/quickSetupView.ts b/deadlock-plugins/deadlock-extension/src/view/quickSetupView.ts index 7610ca20533dafa02126fc298cddd22e84ad7a8a..0c3ec6a80c8760db1e4c03eca115fbbe5bc07c81 100644 --- a/deadlock-plugins/deadlock-extension/src/view/quickSetupView.ts +++ b/deadlock-plugins/deadlock-extension/src/view/quickSetupView.ts @@ -1,8 +1,8 @@ import { commands, Uri } from 'vscode'; import { authenticateCommand, disconnectCommand } from '../core/commandHandler'; +import { openQuickSetupCommand } from '../core/controller'; import ExtensionStore from '../core/extensionStore'; import { extensionLog as log } from '../recorder/utils/log'; -import { openQuickSetupCommand } from '../theia/command'; import { WebviewBase } from './webviewBase'; export const quickSetupId = 'quickSetup'; @@ -26,7 +26,7 @@ export default class QuickSetupView extends WebviewBase { } } - render(): string { + async render(): Promise<string> { return ` <head> ${this.renderHeaderHtml()} @@ -114,10 +114,10 @@ export default class QuickSetupView extends WebviewBase { onMessageReceive(message: any): void { switch (message.command) { case 'openAuthenticationPageAction': - commands.executeCommand(authenticateCommand.cmd); + commands.executeCommand(authenticateCommand.command); return; case 'disconnectUserAction': - commands.executeCommand(disconnectCommand.cmd); + commands.executeCommand(disconnectCommand.command); return; } } diff --git a/deadlock-plugins/deadlock-extension/src/view/webviewBase.ts b/deadlock-plugins/deadlock-extension/src/view/webviewBase.ts index ebfbe6836aba9e3d46ae7b7c6d2e0b62672846ae..a2a62417a14fafdf86c917acca48502ea06bd0e4 100644 --- a/deadlock-plugins/deadlock-extension/src/view/webviewBase.ts +++ b/deadlock-plugins/deadlock-extension/src/view/webviewBase.ts @@ -1,5 +1,6 @@ 'use strict'; import { + Command, commands, Disposable, Uri, @@ -9,7 +10,6 @@ import { WebviewPanelOnDidChangeViewStateEvent, window, } from 'vscode'; -import { VsCommand } from '../theia/command'; const emptyCommands: Disposable[] = [ { @@ -28,8 +28,8 @@ export abstract class WebviewBase implements Disposable { private disposablePanel: Disposable | undefined; protected panel: WebviewPanel | undefined; - constructor(private id: string, private title: string, command: VsCommand, private readonly _column?: ViewColumn) { - this.disposable = Disposable.from(commands.registerCommand(command.cmd, this.onShowCommand, this)); + constructor(private id: string, private title: string, command: Command, private readonly _column?: ViewColumn) { + this.disposable = Disposable.from(commands.registerCommand(command.command, this.onShowCommand, this)); this.load(); } @@ -130,13 +130,13 @@ export abstract class WebviewBase implements Disposable { /** * Must return the content displayed within the webViewPanel */ - abstract render(): string; + abstract render(): Promise<string>; /** * Method called at the end of first render */ abstract load(): void; private async getHtml(): Promise<string> { - return this.render(); + return await this.render(); } }